summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorGravatar Christopher <4Christopher@gmx.de> 2013-04-13 21:06:34 +0200
committerGravatar Christopher <4Christopher@gmx.de> 2013-04-13 21:06:34 +0200
commit0b2e9ddcafed94fb780ea8d07ea23f6f14612830 (patch)
tree36f60fb82cc61cf17947cbe7dcbbc719994e234c /module
parentCleanup. (diff)
parentMBLinkInfo: updated pattern (diff)
downloadpyload-0b2e9ddcafed94fb780ea8d07ea23f6f14612830.tar.xz
Merge branch 'stable' of git://github.com/pyload/pyload into stable
Diffstat (limited to 'module')
-rw-r--r--module/plugins/accounts/DebridItaliaCom.py15
-rw-r--r--module/plugins/accounts/MultiDebridCom.py47
-rw-r--r--module/plugins/accounts/RarefileNet.py4
-rw-r--r--module/plugins/crypter/DataHuFolder.py55
-rw-r--r--module/plugins/crypter/GooGl.py41
-rw-r--r--module/plugins/crypter/MBLinkInfo.py27
-rw-r--r--module/plugins/crypter/NetfolderIn.py48
-rw-r--r--module/plugins/crypter/SpeedLoadOrgFolder.py15
-rw-r--r--module/plugins/crypter/UlozToFolder.py2
-rw-r--r--module/plugins/crypter/UploadedToFolder.py37
-rw-r--r--module/plugins/crypter/YoutubeBatch.py35
-rw-r--r--module/plugins/hooks/DebridItaliaCom.py20
-rw-r--r--module/plugins/hooks/DownloadScheduler.py72
-rw-r--r--module/plugins/hooks/LinkdecrypterCom.py4
-rw-r--r--module/plugins/hooks/MultiDebridCom.py42
-rw-r--r--module/plugins/hoster/ARD.py80
-rw-r--r--module/plugins/hoster/DataHu.py53
-rw-r--r--module/plugins/hoster/DebridItaliaCom.py22
-rw-r--r--module/plugins/hoster/EgoFilesCom.py38
-rw-r--r--module/plugins/hoster/FilefactoryCom.py216
-rw-r--r--module/plugins/hoster/FilerNet.py103
-rw-r--r--module/plugins/hoster/MegaNz.py6
-rw-r--r--module/plugins/hoster/MultiDebridCom.py57
-rw-r--r--module/plugins/hoster/OneFichierCom.py7
-rw-r--r--module/plugins/hoster/PutlockerCom.py157
-rw-r--r--module/plugins/hoster/RarefileNet.py20
-rw-r--r--module/plugins/hoster/UploadedTo.py61
-rw-r--r--module/plugins/hoster/XVideosCom.py19
-rw-r--r--module/plugins/hoster/YoutubeCom.py2
-rw-r--r--module/plugins/internal/SimpleCrypter.py10
-rw-r--r--module/plugins/internal/SimpleHoster.py4
-rw-r--r--module/plugins/internal/UnRar.py34
32 files changed, 968 insertions, 385 deletions
diff --git a/module/plugins/accounts/DebridItaliaCom.py b/module/plugins/accounts/DebridItaliaCom.py
index d68f1c8a8..91dd3787f 100644
--- a/module/plugins/accounts/DebridItaliaCom.py
+++ b/module/plugins/accounts/DebridItaliaCom.py
@@ -1,5 +1,20 @@
# -*- coding: utf-8 -*-
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
import re
import _strptime
import time
diff --git a/module/plugins/accounts/MultiDebridCom.py b/module/plugins/accounts/MultiDebridCom.py
new file mode 100644
index 000000000..904be5ee7
--- /dev/null
+++ b/module/plugins/accounts/MultiDebridCom.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+from time import time
+
+from module.plugins.Account import Account
+from module.common.json_layer import json_loads
+
+
+class MultiDebridCom(Account):
+ __name__ = "MultiDebridCom"
+ __version__ = "0.01"
+ __type__ = "account"
+ __description__ = """Multi-debrid.com account plugin"""
+ __author_name__ = ("stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ def loadAccountInfo(self, user, req):
+ if 'days_left' in self.json_data:
+ validuntil = int(time() + self.json_data['days_left'] * 86400)
+ return {"premium": True, "validuntil": validuntil, "trafficleft": -1}
+ else:
+ self.logError('Unable to get account information')
+
+ def login(self, user, data, req):
+ # Password to use is the API-Password written in http://multi-debrid.com/myaccount
+ self.html = req.load("http://multi-debrid.com/api.php",
+ get={"user": user, "pass": data["password"]})
+ self.logDebug('JSON data: ' + self.html)
+ self.json_data = json_loads(self.html)
+ if self.json_data['status'] != 'ok':
+ self.logError('Invalid login. The password to use is the API-Password you find in your "My Account" page')
+ self.wrongPassword()
diff --git a/module/plugins/accounts/RarefileNet.py b/module/plugins/accounts/RarefileNet.py
index 57f293c55..90ad02d43 100644
--- a/module/plugins/accounts/RarefileNet.py
+++ b/module/plugins/accounts/RarefileNet.py
@@ -3,10 +3,10 @@ from module.plugins.internal.XFSPAccount import XFSPAccount
class RarefileNet(XFSPAccount):
__name__ = "RarefileNet"
- __version__ = "0.01"
+ __version__ = "0.02"
__type__ = "account"
__description__ = """RareFile.net account plugin"""
__author_name__ = ("zoidberg")
__author_mail__ = ("zoidberg@mujmail.cz")
- MAIN_PAGE = "http://rarefile.in/" \ No newline at end of file
+ MAIN_PAGE = "http://rarefile.net/"
diff --git a/module/plugins/crypter/DataHuFolder.py b/module/plugins/crypter/DataHuFolder.py
new file mode 100644
index 000000000..f710f60d7
--- /dev/null
+++ b/module/plugins/crypter/DataHuFolder.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+import re
+
+from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+
+class DataHuFolder(SimpleCrypter):
+ __name__ = "DataHuFolder"
+ __type__ = "crypter"
+ __pattern__ = r"http://(www\.)?data.hu/dir/\w+"
+ __version__ = "0.03"
+ __description__ = """Data.hu Folder Plugin"""
+ __author_name__ = ("crash", "stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ LINK_PATTERN = r"<a href='(http://data\.hu/get/.+)' target='_blank'>\1</a>"
+ TITLE_PATTERN = ur'<title>(?P<title>.+) Let\xf6lt\xe9se</title>'
+
+ def decrypt(self, pyfile):
+ self.html = self.load(pyfile.url, decode=True)
+
+ if u'K\xe9rlek add meg a jelsz\xf3t' in self.html: # Password protected
+ password = self.getPassword()
+ if password is '':
+ self.fail("No password specified, please set right password on Add package form and retry")
+ self.logDebug('The folder is password protected', 'Using password: ' + password)
+ self.html = self.load(pyfile.url, post={'mappa_pass': password}, decode=True)
+ if u'Hib\xe1s jelsz\xf3' in self.html: # Wrong password
+ self.fail("Incorrect password, please set right password on Add package form and retry")
+
+ package_name, folder_name = self.getPackageNameAndFolder()
+
+ package_links = re.findall(self.LINK_PATTERN, self.html)
+ self.logDebug('Package has %d links' % len(package_links))
+
+ if package_links:
+ self.packages = [(package_name, package_links, folder_name)]
+ else:
+ self.fail('Could not extract any links')
diff --git a/module/plugins/crypter/GooGl.py b/module/plugins/crypter/GooGl.py
new file mode 100644
index 000000000..bcb1d7494
--- /dev/null
+++ b/module/plugins/crypter/GooGl.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+from module.plugins.Crypter import Crypter
+from module.common.json_layer import json_loads
+
+
+class GooGl(Crypter):
+ __name__ = "GooGl"
+ __type__ = "crypter"
+ __pattern__ = r"https?://(www\.)?goo\.gl/\w+"
+ __version__ = "0.01"
+ __description__ = """Goo.gl Crypter Plugin"""
+ __author_name__ = ("stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ API_URL = 'https://www.googleapis.com/urlshortener/v1/url'
+
+ def decrypt(self, pyfile):
+ rep = self.load(self.API_URL, get={'shortUrl': pyfile.url})
+ self.logDebug('JSON data: ' + rep)
+ rep = json_loads(rep)
+
+ if 'longUrl' in rep:
+ self.core.files.addLinks([rep['longUrl']], self.pyfile.package().id)
+ else:
+ self.fail('Unable to expand shortened link')
diff --git a/module/plugins/crypter/MBLinkInfo.py b/module/plugins/crypter/MBLinkInfo.py
new file mode 100644
index 000000000..e266c7722
--- /dev/null
+++ b/module/plugins/crypter/MBLinkInfo.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+
+import re
+
+from module.plugins.Crypter import Crypter
+
+
+class MBLinkInfo(Crypter):
+ __name__ = "MBLinkInfo"
+ __type__ = "container"
+ __pattern__ = r"http://(?:www\.)?mblink\.info/?\?id=(\d+)"
+ __version__ = "0.02"
+ __description__ = """MBLink.Info Container Plugin"""
+ __author_name__ = ("Gummibaer", "stickell")
+ __author_mail__ = ("Gummibaer@wiki-bierkiste.de", "l.stickell@yahoo.it")
+
+ URL_PATTERN = r'<meta[^;]+; URL=(.*)["\']>'
+
+ def decrypt(self, pyfile):
+ src = self.load(pyfile.url)
+ found = re.search(self.URL_PATTERN, src)
+ if found:
+ link = found.group(1)
+ self.logDebug("Redirected to " + link)
+ self.core.files.addLinks([link], self.pyfile.package().id)
+ else:
+ self.fail('Unable to detect valid link')
diff --git a/module/plugins/crypter/NetfolderIn.py b/module/plugins/crypter/NetfolderIn.py
index d71a73d0a..c5c602c27 100644
--- a/module/plugins/crypter/NetfolderIn.py
+++ b/module/plugins/crypter/NetfolderIn.py
@@ -1,22 +1,25 @@
# -*- coding: utf-8 -*-
-from module.plugins.Crypter import Crypter
import re
-class NetfolderIn(Crypter):
+from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+
+class NetfolderIn(SimpleCrypter):
__name__ = "NetfolderIn"
__type__ = "crypter"
__pattern__ = r"http://(?:www\.)?netfolder.in/((?P<id1>\w+)/\w+|folder.php\?folder_id=(?P<id2>\w+))"
- __version__ = "0.4"
+ __version__ = "0.6"
__description__ = """NetFolder Crypter Plugin"""
__author_name__ = ("RaNaN", "fragonib")
__author_mail__ = ("RaNaN@pyload.org", "fragonib[AT]yahoo[DOT]es")
+ TITLE_PATTERN = r'<div class="Text">Inhalt des Ordners <span(.*)>(?P<title>.+)</span></div>'
+
def decrypt(self, pyfile):
-
# Request package
self.html = self.load(pyfile.url)
-
+
# Check for password protection
if self.isPasswordProtected():
self.html = self.submitPassword()
@@ -31,54 +34,37 @@ class NetfolderIn(Crypter):
# Set package
self.packages = [(package_name, package_links, folder_name)]
-
-
+
def isPasswordProtected(self):
-
+
if '<input type="password" name="password"' in self.html:
self.logDebug("Links are password protected")
return True
return False
-
def submitPassword(self):
# Gather data
try:
m = re.match(self.__pattern__, self.pyfile.url)
- id = max(m.group('id1'), m.group('id2'))
+ id = max(m.group('id1'), m.group('id2'))
except AttributeError:
self.logDebug("Unable to get package id from url [%s]" % self.pyfile.url)
return
url = "http://netfolder.in/folder.php?folder_id=" + id
password = self.getPassword()
-
+
# Submit package password
- post = { 'password' : password, 'save' : 'Absenden' }
+ post = {'password': password, 'save': 'Absenden'}
self.logDebug("Submitting password [%s] for protected links with id [%s]" % (password, id))
html = self.load(url, {}, post)
-
+
# Check for invalid password
if '<div class="InPage_Error">' in html:
self.logDebug("Incorrect password, please set right password on Edit package form and retry")
return None
-
- return html
-
-
- def getPackageNameAndFolder(self):
- title_re = r'<div class="Text">Inhalt des Ordners <span(.*)>(?P<title>.+)</span></div>'
- m = re.search(title_re, self.html)
- if m is not None:
- name = folder = m.group('title')
- self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder))
- return name, folder
- else:
- name = self.pyfile.package().name
- folder = self.pyfile.package().folder
- self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
- return name, folder
-
-
+
+ return html
+
def getLinks(self):
links = re.search(r'name="list" value="(.*?)"', self.html).group(1).split(",")
self.logDebug("Package has %d links" % len(links))
diff --git a/module/plugins/crypter/SpeedLoadOrgFolder.py b/module/plugins/crypter/SpeedLoadOrgFolder.py
index 5b350787f..f85ede6f3 100644
--- a/module/plugins/crypter/SpeedLoadOrgFolder.py
+++ b/module/plugins/crypter/SpeedLoadOrgFolder.py
@@ -1,5 +1,20 @@
# -*- coding: utf-8 -*-
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
from module.plugins.internal.SimpleCrypter import SimpleCrypter
class SpeedLoadOrgFolder(SimpleCrypter):
diff --git a/module/plugins/crypter/UlozToFolder.py b/module/plugins/crypter/UlozToFolder.py
index c6672ea8c..814d5240d 100644
--- a/module/plugins/crypter/UlozToFolder.py
+++ b/module/plugins/crypter/UlozToFolder.py
@@ -7,7 +7,7 @@ class UlozToFolder(Crypter):
__name__ = "UlozToFolder"
__type__ = "crypter"
__pattern__ = r"http://.*(uloz\.to|ulozto\.(cz|sk|net)|bagruj.cz|zachowajto.pl)/(m|soubory)/.*"
- __version__ = "0.1a"
+ __version__ = "0.2"
__description__ = """Uloz.to Folder Plugin"""
__author_name__ = ("zoidberg")
__author_mail__ = ("zoidberg@mujmail.cz")
diff --git a/module/plugins/crypter/UploadedToFolder.py b/module/plugins/crypter/UploadedToFolder.py
index d4534297e..c514f23d0 100644
--- a/module/plugins/crypter/UploadedToFolder.py
+++ b/module/plugins/crypter/UploadedToFolder.py
@@ -1,13 +1,30 @@
# -*- coding: utf-8 -*-
-from module.plugins.Crypter import Crypter
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
import re
-class UploadedToFolder(Crypter):
+from module.plugins.internal.SimpleCrypter import SimpleCrypter
+
+
+class UploadedToFolder(SimpleCrypter):
__name__ = "UploadedToFolder"
__type__ = "crypter"
- __pattern__ = r"http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|list)/(?P<id>\w+)"
- __version__ = "0.1"
+ __pattern__ = r"http://(?:www\.)?(uploaded|ul)\.(to|net)/(f|folder|list)/(?P<id>\w+)"
+ __version__ = "0.3"
__description__ = """UploadedTo Crypter Plugin"""
__author_name__ = ("stickell")
__author_mail__ = ("l.stickell@yahoo.it")
@@ -31,15 +48,3 @@ class UploadedToFolder(Crypter):
self.logDebug('Package has %d links' % len(package_links))
self.packages = [(package_name, package_links, folder_name)]
-
- def getPackageNameAndFolder(self):
- m = re.search(self.TITLE_PATTERN, self.html)
- if m:
- name = folder = m.group('title')
- self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder))
- return name, folder
- else:
- name = self.pyfile.package().name
- folder = self.pyfile.package().folder
- self.logDebug("Package info not found, defaulting to pyfile name [%s] and folder [%s]" % (name, folder))
- return name, folder
diff --git a/module/plugins/crypter/YoutubeBatch.py b/module/plugins/crypter/YoutubeBatch.py
index 2e68dfe02..567191bb9 100644
--- a/module/plugins/crypter/YoutubeBatch.py
+++ b/module/plugins/crypter/YoutubeBatch.py
@@ -2,26 +2,41 @@
# -*- coding: utf-8 -*-
import re
+import json
from module.plugins.Crypter import Crypter
+API_KEY = "AIzaSyCKnWLNlkX-L4oD1aEzqqhRw1zczeD6_k0"
+
class YoutubeBatch(Crypter):
__name__ = "YoutubeBatch"
__type__ = "container"
- __pattern__ = r"http://(?:[^/]*?)youtube\.com/((?:view_play_list|playlist|.*?feature=PlayList).*?[\?&](?:list|p)=|user/)(\w+)"
+ __pattern__ = r"http://(?:[^/]*?)youtube\.com/((?:view_play_list|playlist|.*?feature=PlayList).*?[\?&](?:list|p)=)([a-zA-Z0-9-_]+)"
__version__ = "0.92"
__description__ = """Youtube.com Channel Download Plugin"""
- __author_name__ = ("RaNaN", "Spoob", "zoidberg")
- __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "zoidberg@mujmail.cz")
+ __author_name__ = ("RaNaN", "Spoob", "zoidberg", "roland")
+ __author_mail__ = ("RaNaN@pyload.org", "spoob@pyload.org", "zoidberg@mujmail.cz", "roland@enkore.de")
+
+ def get_videos(self, playlist_id, token=None):
+ url = "https://www.googleapis.com/youtube/v3/playlistItems?playlistId=%s&part=snippet&key=%s&maxResults=50" % (playlist_id, API_KEY)
+ if token:
+ url += "&pageToken=" + token
+
+ response = json.loads(self.load(url))
+
+ for item in response["items"]:
+ if item["kind"] == "youtube#playlistItem" and item["snippet"]["resourceId"]["kind"] == "youtube#video":
+ yield "http://youtube.com/watch?v=" + item["snippet"]["resourceId"]["videoId"]
+
+ if "nextPageToken" in response:
+ for item in self.get_videos(playlist_id, response["nextPageToken"]):
+ yield item
def decrypt(self, pyfile):
match_id = re.match(self.__pattern__, self.pyfile.url)
- if match_id.group(1) == "user/":
- url = "http://gdata.youtube.com/feeds/api/users/%s/uploads?v=2" % match_id.group(2)
- else:
- url = "http://gdata.youtube.com/feeds/api/playlists/%s?v=2" % match_id.group(2)
-
- rep = self.load(url)
new_links = []
- new_links.extend(re.findall(r"href\='(http:\/\/www.youtube.com\/watch\?v\=[^']+)&", rep))
+ playlist_id = match_id.group(2)
+
+ new_links.extend(self.get_videos(playlist_id))
+
self.packages.append((self.pyfile.package().name, new_links, self.pyfile.package().name))
diff --git a/module/plugins/hooks/DebridItaliaCom.py b/module/plugins/hooks/DebridItaliaCom.py
index 8cd997f4d..d570eebe3 100644
--- a/module/plugins/hooks/DebridItaliaCom.py
+++ b/module/plugins/hooks/DebridItaliaCom.py
@@ -1,11 +1,26 @@
# -*- coding: utf-8 -*-
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
from module.plugins.internal.MultiHoster import MultiHoster
class DebridItaliaCom(MultiHoster):
__name__ = "DebridItaliaCom"
- __version__ = "0.01"
+ __version__ = "0.03"
__type__ = "hook"
__config__ = [("activated", "bool", "Activated", "False"),
("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
@@ -22,4 +37,5 @@ class DebridItaliaCom(MultiHoster):
"uploading.com", "megashares.com", "crocko.com", "filepost.com",
"bitshare.com", "share-links.biz", "putlocker.com", "uploaded.to",
"speedload.org", "rapidgator.net", "likeupload.net", "cyberlocker.ch",
- "depositfiles.com", "extabit.com", "filefactory.com", "sharefiles.co"]
+ "depositfiles.com", "extabit.com", "filefactory.com", "sharefiles.co",
+ "ryushare.com", "tusfiles.net", "nowvideo.co"]
diff --git a/module/plugins/hooks/DownloadScheduler.py b/module/plugins/hooks/DownloadScheduler.py
index 7cadede38..4049d71c5 100644
--- a/module/plugins/hooks/DownloadScheduler.py
+++ b/module/plugins/hooks/DownloadScheduler.py
@@ -18,61 +18,69 @@
import re
from time import localtime
+
from module.plugins.Hook import Hook
+
class DownloadScheduler(Hook):
__name__ = "DownloadScheduler"
- __version__ = "0.20"
+ __version__ = "0.21"
__description__ = """Download Scheduler"""
- __config__ = [("activated", "bool", "Activated", "False"),
- ("timetable", "str", "List time periods as hh:mm full or number(kB/s)", "0:00 full, 7:00 250, 10:00 0, 17:00 150")]
- __author_name__ = ("zoidberg")
- __author_mail__ = ("zoidberg@mujmail.cz")
-
+ __config__ = [("activated", "bool", "Activated", "False"),
+ ("timetable", "str", "List time periods as hh:mm full or number(kB/s)",
+ "0:00 full, 7:00 250, 10:00 0, 17:00 150"),
+ ("abort", "bool", "Abort active downloads when start period with speed 0", "False")]
+ __author_name__ = ("zoidberg", "stickell")
+ __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it")
+
def setup(self):
- self.cb = None # callback to scheduler job; will be by removed hookmanager when hook unloaded
-
+ self.cb = None # callback to scheduler job; will be by removed hookmanager when hook unloaded
+
def coreReady(self):
self.updateSchedule()
-
- def updateSchedule(self, schedule = None):
- if schedule is None:
- schedule = self.getConfig("timetable")
-
- schedule = re.findall("(\d{1,2}):(\d{2})[\s]*(-?\d+)", schedule.lower().replace("full", "-1").replace("none", "0"))
+
+ def updateSchedule(self, schedule=None):
+ if schedule is None:
+ schedule = self.getConfig("timetable")
+
+ schedule = re.findall("(\d{1,2}):(\d{2})[\s]*(-?\d+)",
+ schedule.lower().replace("full", "-1").replace("none", "0"))
if not schedule:
self.logError("Invalid schedule")
return
-
+
t0 = localtime()
now = (t0.tm_hour, t0.tm_min, t0.tm_sec, "X")
schedule = sorted([(int(x[0]), int(x[1]), 0, int(x[2])) for x in schedule] + [now])
-
- self.logDebug("Schedule", schedule)
-
+
+ self.logDebug("Schedule", schedule)
+
for i, v in enumerate(schedule):
if v[3] == "X":
- last, next = schedule[i-1], schedule[(i+1) % len(schedule)]
+ last, next = schedule[i - 1], schedule[(i + 1) % len(schedule)]
self.logDebug("Now/Last/Next", now, last, next)
-
- self.setDownloadSpeed(last[3])
-
- next_time = (((24 + next[0] - now[0])* 60 + next[1] - now[1]) * 60 + next[2] - now[2]) % 86400
+
+ self.setDownloadSpeed(last[3])
+
+ next_time = (((24 + next[0] - now[0]) * 60 + next[1] - now[1]) * 60 + next[2] - now[2]) % 86400
self.core.scheduler.removeJob(self.cb)
- self.cb = self.core.scheduler.addJob(next_time, self.updateSchedule, threaded=False)
-
- def setDownloadSpeed(self, speed):
+ self.cb = self.core.scheduler.addJob(next_time, self.updateSchedule, threaded=False)
+
+ def setDownloadSpeed(self, speed):
if speed == 0:
- self.logInfo("Stopping download server. (Running downloads will not be aborted.)")
+ abort = self.getConfig("abort")
+ self.logInfo("Stopping download server. (Running downloads will %sbe aborted.)" % ('' if abort else 'not '))
self.core.api.pauseServer()
+ if abort:
+ self.core.api.stopAllDownloads()
else:
self.core.api.unpauseServer()
-
+
if speed > 0:
self.logInfo("Setting download speed to %d kB/s" % speed)
- self.core.api.setConfigValue("download","limit_speed",1)
- self.core.api.setConfigValue("download","max_speed",speed)
+ self.core.api.setConfigValue("download", "limit_speed", 1)
+ self.core.api.setConfigValue("download", "max_speed", speed)
else:
self.logInfo("Setting download speed to FULL")
- self.core.api.setConfigValue("download","limit_speed",0)
- self.core.api.setConfigValue("download","max_speed",-1) \ No newline at end of file
+ self.core.api.setConfigValue("download", "limit_speed", 0)
+ self.core.api.setConfigValue("download", "max_speed", -1)
diff --git a/module/plugins/hooks/LinkdecrypterCom.py b/module/plugins/hooks/LinkdecrypterCom.py
index 2cb91d120..d3d6bce68 100644
--- a/module/plugins/hooks/LinkdecrypterCom.py
+++ b/module/plugins/hooks/LinkdecrypterCom.py
@@ -24,7 +24,7 @@ from module.utils import remove_chars
class LinkdecrypterCom(Hook):
__name__ = "LinkdecrypterCom"
- __version__ = "0.16"
+ __version__ = "0.17"
__description__ = """linkdecrypter.com - regexp loader"""
__config__ = [ ("activated", "bool", "Activated" , "True") ]
__author_name__ = ("zoidberg")
@@ -50,7 +50,7 @@ class LinkdecrypterCom(Hook):
self.logError(_("Crypter list is empty"))
return
- regexp = r"http://([^.]+\.)*?(%s)/.*" % "|".join(online)
+ regexp = r"https?://([^.]+\.)*?(%s)/.*" % "|".join(online)
dict = self.core.pluginManager.crypterPlugins[self.__name__]
dict["pattern"] = regexp
diff --git a/module/plugins/hooks/MultiDebridCom.py b/module/plugins/hooks/MultiDebridCom.py
new file mode 100644
index 000000000..c95138648
--- /dev/null
+++ b/module/plugins/hooks/MultiDebridCom.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+from module.plugins.internal.MultiHoster import MultiHoster
+from module.network.RequestFactory import getURL
+from module.common.json_layer import json_loads
+
+
+class MultiDebridCom(MultiHoster):
+ __name__ = "MultiDebridCom"
+ __version__ = "0.01"
+ __type__ = "hook"
+ __config__ = [("activated", "bool", "Activated", "False"),
+ ("hosterListMode", "all;listed;unlisted", "Use for hosters (if supported)", "all"),
+ ("hosterList", "str", "Hoster list (comma separated)", ""),
+ ("unloadFailing", "bool", "Revert to standard download if download fails", "False"),
+ ("interval", "int", "Reload interval in hours (0 to disable)", "24")]
+
+ __description__ = """Multi-debrid.com hook plugin"""
+ __author_name__ = ("stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ def getHoster(self):
+ json_data = getURL('http://multi-debrid.com/api.php?hosts', decode=True)
+ self.logDebug('JSON data: ' + json_data)
+ json_data = json_loads(json_data)
+
+ return json_data['hosts']
diff --git a/module/plugins/hoster/ARD.py b/module/plugins/hoster/ARD.py
new file mode 100644
index 000000000..5ab65cd4b
--- /dev/null
+++ b/module/plugins/hoster/ARD.py
@@ -0,0 +1,80 @@
+
+import subprocess
+import re
+import os.path
+import os
+
+from module.utils import save_join, save_path
+from module.plugins.Hoster import Hoster
+
+# Requires rtmpdump
+# by Roland Beermann
+
+class RTMP:
+ # TODO: Port to some RTMP-library like rtmpy or similar
+ # TODO?: Integrate properly into the API of pyLoad
+
+ command = "rtmpdump"
+
+ @classmethod
+ def download_rtmp_stream(cls, url, output_file, playpath=None):
+ opts = [
+ "-r", url,
+ "-o", output_file,
+ ]
+ if playpath:
+ opts.append("--playpath")
+ opts.append(playpath)
+
+ cls._invoke_rtmpdump(opts)
+
+ @classmethod
+ def _invoke_rtmpdump(cls, opts):
+ args = [
+ cls.command
+ ]
+ args.extend(opts)
+
+ return subprocess.check_call(args)
+
+class ARD(Hoster):
+ __name__ = "ARD Mediathek"
+ __version__ = "0.1"
+ __pattern__ = r"http://www\.ardmediathek\.de/.*"
+ __config__ = []
+
+ def process(self, pyfile):
+ site = self.load(pyfile.url)
+
+ avail_videos = re.findall(r"""mediaCollection.addMediaStream\(0, ([0-9]*), "([^\"]*)", "([^\"]*)", "[^\"]*"\);""", site)
+ avail_videos.sort(key=lambda videodesc: int(videodesc[0]), reverse=True) # The higher the number, the better the quality
+
+ quality, url, playpath = avail_videos[0]
+
+ pyfile.name = re.search(r"<h1>([^<]*)</h1>", site).group(1)
+
+ if url.startswith("http"):
+ # Best quality is available over HTTP. Very rare.
+ self.download(url)
+ else:
+ pyfile.setStatus("downloading")
+
+ download_folder = self.config['general']['download_folder']
+
+ location = save_join(download_folder, pyfile.package().folder)
+
+ if not os.path.exists(location):
+ os.makedirs(location, int(self.core.config["permission"]["folder"], 8))
+
+ if self.core.config["permission"]["change_dl"] and os.name != "nt":
+ try:
+ uid = getpwnam(self.config["permission"]["user"])[2]
+ gid = getgrnam(self.config["permission"]["group"])[2]
+
+ chown(location, uid, gid)
+ except Exception, e:
+ self.log.warning(_("Setting User and Group failed: %s") % str(e))
+
+ output_file = save_join(location, save_path(pyfile.name)) + os.path.splitext(playpath)[1]
+
+ RTMP.download_rtmp_stream(url, playpath=playpath, output_file=output_file)
diff --git a/module/plugins/hoster/DataHu.py b/module/plugins/hoster/DataHu.py
new file mode 100644
index 000000000..7abd93d1f
--- /dev/null
+++ b/module/plugins/hoster/DataHu.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+# Test links (random.bin):
+# http://data.hu/get/6381232/random.bin
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+
+
+class DataHu(SimpleHoster):
+ __name__ = "DataHu"
+ __type__ = "hoster"
+ __pattern__ = r"http://(www\.)?data.hu/get/\w+"
+ __version__ = "0.01"
+ __description__ = """Data.hu Download Hoster"""
+ __author_name__ = ("crash", "stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ FILE_INFO_PATTERN = ur'<title>(?P<N>.*) \((?P<S>[^)]+)\) let\xf6lt\xe9se</title>'
+ FILE_OFFLINE_PATTERN = ur'Az adott f\xe1jl nem l\xe9tezik'
+ DIRECT_LINK_PATTERN = r'<div class="download_box_button"><a href="([^"]+)">'
+
+ def handleFree(self):
+ self.resumeDownload = True
+ self.html = self.load(self.pyfile.url, decode=True)
+
+ m = re.search(self.DIRECT_LINK_PATTERN, self.html)
+ if m:
+ url = m.group(1)
+ self.logDebug('Direct link: ' + url)
+ else:
+ self.parseError('Unable to get direct link')
+
+ self.download(url, disposition=True)
+
+
+getInfo = create_getInfo(DataHu)
diff --git a/module/plugins/hoster/DebridItaliaCom.py b/module/plugins/hoster/DebridItaliaCom.py
index a8f7dd57e..470c4ae5d 100644
--- a/module/plugins/hoster/DebridItaliaCom.py
+++ b/module/plugins/hoster/DebridItaliaCom.py
@@ -1,5 +1,20 @@
# -*- coding: utf-8 -*-
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
import re
from module.plugins.Hoster import Hoster
@@ -7,7 +22,7 @@ from module.plugins.Hoster import Hoster
class DebridItaliaCom(Hoster):
__name__ = "DebridItaliaCom"
- __version__ = "0.02"
+ __version__ = "0.03"
__type__ = "hoster"
__pattern__ = r"https?://.*debriditalia\.com"
__description__ = """Debriditalia.com hoster plugin"""
@@ -31,7 +46,10 @@ class DebridItaliaCom(Hoster):
page = self.load(url)
self.logDebug("XML data: %s" % page)
- new_url = re.search(r'<a href="(?:[^"]+)">(?P<direct>[^<]+)</a>', page).group('direct')
+ if 'File not available' in page:
+ self.fail('File not available')
+ else:
+ new_url = re.search(r'<a href="(?:[^"]+)">(?P<direct>[^<]+)</a>', page).group('direct')
self.logDebug("New URL: %s" % new_url)
diff --git a/module/plugins/hoster/EgoFilesCom.py b/module/plugins/hoster/EgoFilesCom.py
index b27abb416..4e78a5b9a 100644
--- a/module/plugins/hoster/EgoFilesCom.py
+++ b/module/plugins/hoster/EgoFilesCom.py
@@ -1,20 +1,39 @@
# -*- coding: utf-8 -*-
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+# Test link (random.bin):
+# http://egofiles.com/mOZfMI1WLZ6HBkGG/random.bin
+
+import re
+
from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
from module.plugins.ReCaptcha import ReCaptcha
-import re
class EgoFilesCom(SimpleHoster):
__name__ = "EgoFilesCom"
__type__ = "hoster"
__pattern__ = r"https?://(www\.)?egofiles.com/(\w+)"
- __version__ = "0.10"
+ __version__ = "0.12"
__description__ = """Egofiles.com Download Hoster"""
__author_name__ = ("stickell")
__author_mail__ = ("l.stickell@yahoo.it")
- FILE_INFO_PATTERN = r'<div class="down-file">\s+(?P<N>\S+)\s+<div class="file-properties">\s+(File size|Rozmiar): (?P<S>[\w.]+) (?P<U>\w+) \|'
+ FILE_INFO_PATTERN = r'<div class="down-file">\s+(?P<N>.+)\s+<div class="file-properties">\s+(File size|Rozmiar): (?P<S>[\w.]+) (?P<U>\w+) \|'
FILE_OFFLINE_PATTERN = r'(File size|Rozmiar): 0 KB'
WAIT_TIME_PATTERN = r'For next free download you have to wait <strong>((?P<m>\d*)m)? ?((?P<s>\d+)s)?</strong>'
DIRECT_LINK_PATTERN = r'<a href="(?P<link>[^"]+)">Download ></a>'
@@ -25,8 +44,15 @@ class EgoFilesCom(SimpleHoster):
# Set English language
self.load("https://egofiles.com/ajax/lang.php?lang=en", just_header=True)
+ def process(self, pyfile):
+ if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
+ self.handlePremium()
+ else:
+ self.handleFree()
+
def handleFree(self):
self.html = self.load(self.pyfile.url, decode=True)
+ self.getFileInfo()
# Wait time between free downloads
if 'For next free download you have to wait' in self.html:
@@ -56,7 +82,7 @@ class EgoFilesCom(SimpleHoster):
if not downloadURL:
self.fail("No Download url retrieved/all captcha attempts failed")
- self.download(downloadURL)
+ self.download(downloadURL, disposition=True)
def handlePremium(self):
header = self.load(self.pyfile.url, just_header=True)
@@ -65,11 +91,13 @@ class EgoFilesCom(SimpleHoster):
self.download(header['location'])
else:
self.html = self.load(self.pyfile.url, decode=True)
+ self.getFileInfo()
m = re.search(r'<a href="(?P<link>[^"]+)">Download ></a>', self.html)
if not m:
self.parseError('Unable to detect direct download url')
else:
self.logDebug('DIRECT URL from html: ' + m.group('link'))
- self.download(m.group('link'))
+ self.download(m.group('link'), disposition=True)
+
getInfo = create_getInfo(EgoFilesCom)
diff --git a/module/plugins/hoster/FilefactoryCom.py b/module/plugins/hoster/FilefactoryCom.py
index 66d26c999..aebf0f38d 100644
--- a/module/plugins/hoster/FilefactoryCom.py
+++ b/module/plugins/hoster/FilefactoryCom.py
@@ -1,149 +1,121 @@
# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+# Test links (random.bin):
+# http://www.filefactory.com/file/ymxkmdud2o3/n/random.bin
+
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster
from module.network.RequestFactory import getURL
-from module.plugins.Hoster import Hoster
-from module.plugins.ReCaptcha import ReCaptcha
from module.utils import parseFileSize
-from module.plugins.Plugin import chunks
-from module.common.json_layer import json_loads
-import re
-def checkFile(plugin, urls):
- url_dict = {}
-
+def getInfo(urls):
+ file_info = list()
+ list_ids = dict()
+
+ # Create a dict id:url. Will be used to retrieve original url
for url in urls:
- url_dict[re.search(plugin.__pattern__, url).group('id')] = (url, 0, 0, url)
- url_ids = url_dict.keys()
- urls = map(lambda url_id: 'http://www.filefactory.com/file/' + url_id, url_ids)
-
- html = getURL("http://www.filefactory.com/tool/links.php", post = {"func": "links", "links": "\n".join(urls)}, decode=True)
-
- for m in re.finditer(plugin.LC_INFO_PATTERN, html):
- if m.group('id') in url_ids:
- url_dict[m.group('id')] = (m.group('name'), parseFileSize(m.group('size')), 2, url_dict[m.group('id')][3])
-
- for m in re.finditer(plugin.LC_OFFLINE_PATTERN, html):
- if m.group('id') in url_ids:
- url_dict[m.group('id')] = (url_dict[m.group('id')][0], 0, 1, url_dict[m.group('id')][3])
-
- file_info = url_dict.values()
-
+ m = re.search(FilefactoryCom.__pattern__, url)
+ list_ids[m.group('id')] = url
+
+ # WARN: There could be a limit of urls for request
+ post_data = {'func': 'links', 'links': '\n'.join(urls)}
+ rep = getURL('http://www.filefactory.com/tool/links.php', post=post_data, decode=True)
+
+ # Online links
+ for m in re.finditer(
+ r'innerText">\s*<h1 class="name">(?P<N>.+) \((?P<S>[\w.]+) (?P<U>\w+)\)</h1>\s*<p>http://www.filefactory.com/file/(?P<ID>\w+).*</p>\s*<p class="hidden size">',
+ rep):
+ file_info.append((m.group('N'), parseFileSize(m.group('S'), m.group('U')), 2, list_ids[m.group('ID')]))
+
+ # Offline links
+ for m in re.finditer(
+ r'innerText">\s*<h1>(http://www.filefactory.com/file/(?P<ID>\w+)/)</h1>\s*<p>\1</p>\s*<p class="errorResponse">Error: file not found</p>',
+ rep):
+ file_info.append((list_ids[m.group('ID')], 0, 1, list_ids[m.group('ID')]))
+
return file_info
-
-class FilefactoryCom(Hoster):
+
+
+class FilefactoryCom(SimpleHoster):
__name__ = "FilefactoryCom"
__type__ = "hoster"
- __pattern__ = r"http://(?:www\.)?filefactory\.com/file/(?P<id>[a-zA-Z0-9]+).*" # URLs given out are often longer but this is the requirement
- __version__ = "0.36"
+ __pattern__ = r"https?://(?:www\.)?filefactory\.com/file/(?P<id>[a-zA-Z0-9]+)"
+ __version__ = "0.39"
__description__ = """Filefactory.Com File Download Hoster"""
- __author_name__ = ("paulking", "zoidberg")
-
- LC_INFO_PATTERN = r'<h1 class="name">(?P<name>[^<]+) \((?P<size>[0-9.]+ \w+)\)</h1>\s*<p>http://www.filefactory.com/file/(?P<id>\w+)/'
- LC_OFFLINE_PATTERN = r'<p>http://www.filefactory.com/file/(?P<id>\w+)/</p>\s*<p class="errorResponse">'
-
- FILE_OFFLINE_PATTERN = r'<title>File Not Found'
- FILE_NAME_PATTERN = r'<span class="last">(?P<name>.*?)</span>'
- FILE_INFO_PATTERN = r'<span>(?P<size>\d(\d|\.)*) (?P<units>..) file uploaded'
-
- FILE_CHECK_PATTERN = r'check:\s*\'(?P<check>.*?)\''
- CAPTCHA_KEY_PATTERN = r'Recaptcha.create\(\s*"(.*?)",'
- WAIT_PATTERN = r'id="startWait" value="(?P<wait>\d+)"'
- FILE_URL_PATTERN = r'<p[^>]*?id="downloadLinkTarget"[^>]*>\s*<a href="(?P<url>.*?)"'
-
- def setup(self):
- self.multiDL = self.resumeDownloads = self.premium
+ __author_name__ = ("stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
def process(self, pyfile):
- # Check file
- pyfile.name, pyfile.size, status, self.url = checkFile(self, [pyfile.url])[0]
- if status != 2: self.offline()
- self.logDebug("File Name: %s Size: %d" % (pyfile.name, pyfile.size))
-
- # Handle downloading
- url = self.checkDirectDownload(pyfile.url)
- if url:
- self.download(url)
- else:
- self.html = self.load(pyfile.url, decode = True)
-
- if self.premium:
- self.handlePremium()
- else:
- self.handleFree()
-
- def checkDirectDownload(self, url):
- for i in range(5):
- header = self.load(url, just_header = True)
- if 'location' in header:
- url = header['location'].strip()
- if not url.startswith("http://"):
- url = "http://www.filefactory.com" + url
- self.logDebug('URL: ' + url)
- elif 'content-disposition' in header:
- return url
-
- return False
-
+ if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
+ self.handlePremium()
+ else:
+ self.handleFree()
+
def handleFree(self):
+ self.html = self.load(self.pyfile.url, decode=True)
if "Currently only Premium Members can download files larger than" in self.html:
self.fail("File too large for free download")
elif "All free download slots on this server are currently in use" in self.html:
self.retry(50, 900, "All free slots are busy")
-
- # Check Id
- self.check = re.search(self.FILE_CHECK_PATTERN, self.html).group('check')
- self.logDebug("File check code is [%s]" % self.check)
-
- # Resolve captcha
- found = re.search(self.CAPTCHA_KEY_PATTERN, self.html)
- recaptcha_key = found.group(1) if found else "6LeN8roSAAAAAPdC1zy399Qei4b1BwmSBSsBN8zm"
- recaptcha = ReCaptcha(self)
-
- # Try up to 5 times
- for i in range(5):
- challenge, code = recaptcha.challenge(recaptcha_key)
- response = json_loads(self.load("http://www.filefactory.com/file/checkCaptcha.php",
- post={"check" : self.check, "recaptcha_challenge_field" : challenge, "recaptcha_response_field" : code}))
- if response['status'] == 'ok':
- self.correctCaptcha()
- break
- else:
- self.invalidCaptcha()
- else:
- self.fail("No valid captcha after 5 attempts")
-
- # This will take us to a wait screen
- waiturl = "http://www.filefactory.com" + response['path']
- self.logDebug("Fetching wait with url [%s]" % waiturl)
- waithtml = self.load(waiturl, decode=True)
- found = re.search(r'<a href="(http://www.filefactory.com/dlf/.*?)"', waithtml)
- waithtml = self.load(found.group(1), decode=True)
-
- # Find the wait value and wait
- wait = int(re.search(self.WAIT_PATTERN, waithtml).group('wait'))
- self.logDebug("Waiting %d seconds." % wait)
- self.setWait(wait, True)
+
+ # Load the page that contains the direct link
+ url = re.search(r"document\.location\.host \+\s*'(.+)';", self.html)
+ if not url:
+ self.parseError('Unable to detect free link')
+ url = 'http://www.filefactory.com' + url.group(1)
+ self.html = self.load(url, decode=True)
+
+ # Free downloads wait time
+ waittime = re.search(r'id="startWait" value="(\d+)"', self.html)
+ if not waittime:
+ self.parseError('Unable to detect wait time')
+ self.setWait(int(waittime.group(1)))
self.wait()
- # Now get the real download url and retrieve the file
- url = re.search(self.FILE_URL_PATTERN,waithtml).group('url')
- # this may either download our file or forward us to an error page
- self.logDebug("Download URL: %s" % url)
- self.download(url)
-
+ # Parse the direct link and download it
+ direct = re.search(r'data-href-direct="(.*)" class="button', self.html)
+ if not direct:
+ self.parseError('Unable to detect free direct link')
+ direct = direct.group(1)
+ self.logDebug('DIRECT LINK: ' + direct)
+ self.download(direct, disposition=True)
+
check = self.checkDownload({"multiple": "You are currently downloading too many files at once.",
"error": '<div id="errorMessage">'})
if check == "multiple":
- self.setWait(15*60)
self.logDebug("Parallel downloads detected; waiting 15 minutes")
- self.wait()
- self.retry()
+ self.retry(wait_time=15 * 60, reason='Parallel downloads')
elif check == "error":
self.fail("Unknown error")
-
+
def handlePremium(self):
- self.fail('Please enable direct downloads')
-
-def getInfo(urls):
- for chunk in chunks(urls, 100): yield checkFile(FilefactoryCom, chunk)
+ header = self.load(self.pyfile.url, just_header=True)
+ if 'location' in header:
+ url = header['location'].strip()
+ if not url.startswith("http://"):
+ url = "http://www.filefactory.com" + url
+ elif 'content-disposition' in header:
+ url = self.pyfile.url
+ else:
+ self.parseError('Unable to detect premium direct link')
+
+ self.logDebug('DIRECT PREMIUM LINK: ' + url)
+ self.download(url, disposition=True)
diff --git a/module/plugins/hoster/FilerNet.py b/module/plugins/hoster/FilerNet.py
new file mode 100644
index 000000000..9693723f9
--- /dev/null
+++ b/module/plugins/hoster/FilerNet.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+# Test links (random.bin):
+# http://filer.net/get/ivgf5ztw53et3ogd
+# http://filer.net/get/hgo14gzcng3scbvv
+
+import pycurl
+import re
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+from module.plugins.ReCaptcha import ReCaptcha
+
+
+class FilerNet(SimpleHoster):
+ __name__ = "FilerNet"
+ __type__ = "hoster"
+ __pattern__ = r"https?://(www\.)?filer\.net/get/(\w+)"
+ __version__ = "0.01"
+ __description__ = """Filer.net Download Hoster"""
+ __author_name__ = ("stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ FILE_INFO_PATTERN = r'<h1 class="page-header">Free Download (?P<N>\S+) <small>(?P<S>[\w.]+) (?P<U>\w+)</small></h1>'
+ FILE_OFFLINE_PATTERN = r'Nicht gefunden'
+ RECAPTCHA_KEY = '6LcFctISAAAAAAgaeHgyqhNecGJJRnxV1m_vAz3V'
+
+ def process(self, pyfile):
+ self.req.setOption("timeout", 120)
+ self.html = self.load(pyfile.url, decode=not self.SH_BROKEN_ENCODING, cookies=self.SH_COOKIES)
+
+ # Wait between downloads
+ m = re.search(r'musst du <span id="time">(\d+)</span> Sekunden warten', self.html)
+ if m:
+ waittime = int(m.group(1))
+ self.retry(3, waittime, 'Wait between free downloads')
+
+ self.getFileInfo()
+ if self.premium and (not self.SH_CHECK_TRAFFIC or self.checkTrafficLeft()):
+ self.handlePremium()
+ else:
+ self.handleFree()
+
+ def handleFree(self):
+ self.html = self.load(self.pyfile.url, decode=True)
+
+ inputs = self.parseHtmlForm(input_names='token')[1]
+ if 'token' not in inputs:
+ self.parseError('Unable to detect token')
+ token = inputs['token']
+ self.logDebug('Token: ' + token)
+
+ self.html = self.load(self.pyfile.url, post={'token': token}, decode=True)
+
+ inputs = self.parseHtmlForm(input_names='hash')[1]
+ if 'hash' not in inputs:
+ self.parseError('Unable to detect hash')
+ hash_data = inputs['hash']
+ self.logDebug('Hash: ' + hash_data)
+
+ downloadURL = ''
+ recaptcha = ReCaptcha(self)
+ for i in xrange(5):
+ challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
+ post_data = {'recaptcha_challenge_field': challenge,
+ 'recaptcha_response_field': response,
+ 'hash': hash_data}
+
+ # Workaround for 0.4.9 just_header issue. In 0.5 clean the code using just_header
+ self.req.http.c.setopt(pycurl.FOLLOWLOCATION, 0)
+ self.load(self.pyfile.url, post=post_data)
+ self.req.http.c.setopt(pycurl.FOLLOWLOCATION, 1)
+
+ if 'location' in self.req.http.header:
+ location = re.search(r'location: (\S+)', self.req.http.header).group(1)
+ downloadURL = 'http://filer.net' + location
+ self.correctCaptcha()
+ break
+ else:
+ self.logInfo('Wrong captcha')
+ self.invalidCaptcha()
+
+ if not downloadURL:
+ self.fail("No Download url retrieved/all captcha attempts failed")
+
+ self.download(downloadURL, disposition=True)
+
+
+getInfo = create_getInfo(FilerNet)
diff --git a/module/plugins/hoster/MegaNz.py b/module/plugins/hoster/MegaNz.py
index a28ddca9d..e5be4eeb7 100644
--- a/module/plugins/hoster/MegaNz.py
+++ b/module/plugins/hoster/MegaNz.py
@@ -19,7 +19,7 @@ class MegaNz(Hoster):
__name__ = "MegaNz"
__type__ = "hoster"
__pattern__ = r"https?://([a-z0-9]+\.)?mega\.co\.nz/#!([a-zA-Z0-9!_\-]+)"
- __version__ = "0.11"
+ __version__ = "0.12"
__description__ = """mega.co.nz hoster plugin"""
__author_name__ = ("RaNaN", )
__author_mail__ = ("ranan@pyload.org", )
@@ -34,7 +34,7 @@ class MegaNz(Hoster):
def getCipherKey(self, key):
""" Construct the cipher key from the given data """
a = array("I", key)
- key_array = array("I", [a[0] ^ a[4], a[1] ^a[5], a[2] ^ a[6], a[3] ^a[7]])
+ key_array = array("I", [a[0] ^ a[4], a[1] ^ a[5], a[2] ^ a[6], a[3] ^ a[7]])
return key_array
def callApi(self, **kwargs):
@@ -69,7 +69,7 @@ class MegaNz(Hoster):
self.pyfile.setStatus("decrypting")
f = open(self.lastDownload, "rb")
- df = open(self.lastDownload.rstrip(self.FILE_SUFFIX), "wb")
+ df = open(self.lastDownload.rsplit(self.FILE_SUFFIX)[0], "wb")
# TODO: calculate CBC-MAC for checksum
diff --git a/module/plugins/hoster/MultiDebridCom.py b/module/plugins/hoster/MultiDebridCom.py
new file mode 100644
index 000000000..ca98e8a0e
--- /dev/null
+++ b/module/plugins/hoster/MultiDebridCom.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+
+############################################################################
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU Affero General Public License as #
+# published by the Free Software Foundation, either version 3 of the #
+# License, or (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU Affero General Public License for more details. #
+# #
+# You should have received a copy of the GNU Affero General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+############################################################################
+
+import re
+
+from module.plugins.Hoster import Hoster
+from module.common.json_layer import json_loads
+
+
+class MultiDebridCom(Hoster):
+ __name__ = "MultiDebridCom"
+ __version__ = "0.01"
+ __type__ = "hoster"
+ __pattern__ = r"http://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/dl/"
+ __description__ = """Multi-debrid.com hoster plugin"""
+ __author_name__ = ("stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ def init(self):
+ self.chunkLimit = -1
+ self.resumeDownload = True
+
+ def process(self, pyfile):
+ if not self.account:
+ self.logError("Please enter your Multi-debrid.com account or deactivate this plugin")
+ self.fail("No Multi-debrid.com account provided")
+
+ self.logDebug("Original URL: %s" % pyfile.url)
+ if re.match(self.__pattern__, pyfile.url):
+ new_url = pyfile.url
+ else:
+ page = self.req.load('http://multi-debrid.com/api.php',
+ get={'user': self.user, 'pass': self.account.getAccountData(self.user)['password'],
+ 'link': pyfile.url})
+ self.logDebug("JSON data: " + page)
+ page = json_loads(page)
+ if page['status'] != 'ok':
+ self.fail('Unable to unrestrict link')
+ new_url = page['link']
+
+ self.logDebug("Unrestricted URL: " + new_url)
+
+ self.download(new_url, disposition=True)
diff --git a/module/plugins/hoster/OneFichierCom.py b/module/plugins/hoster/OneFichierCom.py
index 46323d829..5d7e14f1e 100644
--- a/module/plugins/hoster/OneFichierCom.py
+++ b/module/plugins/hoster/OneFichierCom.py
@@ -7,11 +7,10 @@ class OneFichierCom(SimpleHoster):
__name__ = "OneFichierCom"
__type__ = "hoster"
__pattern__ = r"(http://(\w+)\.((1fichier|d(es)?fichiers|pjointe)\.(com|fr|net|org)|(cjoint|mesfichiers|piecejointe|oi)\.(org|net)|tenvoi\.(com|org|net)|dl4free\.com|alterupload\.com|megadl.fr))"
- __version__ = "0.45"
+ __version__ = "0.46"
__description__ = """1fichier.com download hoster"""
__author_name__ = ("fragonib", "the-razer", "zoidberg","imclem")
- __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "daniel_ AT gmx DOT net",
- "zoidberg@mujmail.cz","imclem on github")
+ __author_mail__ = ("fragonib[AT]yahoo[DOT]es", "daniel_ AT gmx DOT net", "zoidberg@mujmail.cz","imclem on github")
FILE_NAME_PATTERN = r'">File name :</th>\s*<td>(?P<N>[^<]+)</td>'
FILE_SIZE_PATTERN = r'<th>File size :</th>\s*<td>(?P<S>[^<]+)</td>'
@@ -20,7 +19,7 @@ class OneFichierCom(SimpleHoster):
DOWNLOAD_LINK_PATTERN = r'<br/>&nbsp;<br/>&nbsp;<br/>&nbsp;\s+<a href="(?P<url>http://.*?)"'
PASSWORD_PROTECTED_TOKEN = "protected by password"
- WAITING_PATTERN = "Warning ! Without premium status, you can download only one file at a time and you must wait at least (\d+) minutes between each downloads."
+ WAITING_PATTERN = "Warning ! Without premium status, you can download only one file at a time and you must wait up to (\d+) minutes between each downloads."
def process(self, pyfile):
found = re.search(self.__pattern__, pyfile.url)
file_id = found.group(2)
diff --git a/module/plugins/hoster/PutlockerCom.py b/module/plugins/hoster/PutlockerCom.py
index ca5336231..9eff0dc2b 100644
--- a/module/plugins/hoster/PutlockerCom.py
+++ b/module/plugins/hoster/PutlockerCom.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+
"""
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,114 +17,60 @@
@author: jeix
"""
+# http://www.putlocker.com/file/83C174C844583CF7
+
import re
-from module.plugins.Hoster import Hoster
-from module.network.RequestFactory import getURL
-
-def getInfo(urls):
- result = []
-
- for url in urls:
-
- html = getURL(url)
- if re.search(PutlockerCom.PATTERN_OFFLINE, html):
- result.append((url, 0, 1, url))
- else:
- name = re.search(PutlockerCom.PATTERN_FILENAME_1, html)
- if name is None:
- name = re.search(PutlockerCom.PATTERN_FILENAME_2, html)
- if name is None:
- result.append((url, 0, 1, url))
- continue
-
- name = name.group(1)
-
- # size = re.search(PutlockerCom.PATTERN_FILESIZE, html)
- # if size is None:
- # result.append((url, 0, 1, url))
- # continue
-
- # size = size.group(1)
-
- result.append((name, 0, 2, url))
- yield result
-
-class PutlockerCom(Hoster):
+
+from module.plugins.internal.SimpleHoster import SimpleHoster
+
+
+class PutlockerCom(SimpleHoster):
__name__ = "PutlockerCom"
__type__ = "hoster"
__pattern__ = r'http://(www\.)?putlocker\.com/(file|embed)/[A-Z0-9]+'
- __version__ = "0.21"
+ __version__ = "0.24"
__description__ = """Putlocker.Com"""
- __author_name__ = ("jeix")
-
- PATTERN_OFFLINE = r"This file doesn't exist, or has been removed."
- PATTERN_FILENAME_1 = "site-content.*?<h1>(.*?)<strong"
- PATTERN_FILENAME_2 = "<title>(.*?) \|"
- PATTERN_FILESIZE = "site-content.*?<h1>.*?<strong>\\((.*?)\\)"
-
-
- def process(self, pyfile):
-
- self.pyfile = pyfile
- self.html = self.load(pyfile.url, decode=True)
-
- if not self._checkOnline():
- self.offline()
-
- self.pyfile.name = self._getName()
-
- self.link = self._getLink()
- if not self.link.startswith('http://'):
- self.link = "http://www.putlocker.com" + self.link
- self.download( self.link )
-
- def _checkOnline(self):
- if re.search(self.PATTERN_OFFLINE, self.html):
- return False
- else:
- return True
-
- def _getName(self):
- name = re.search(self.PATTERN_FILENAME_1, self.html)
- if name is None:
- name = re.search(self.PATTERN_FILENAME_2, self.html)
- # if name is None:
- # self.fail("%s: Plugin broken." % self.__name__)
-
- return name.group(1)
-
+ __author_name__ = ("jeix", "stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ FILE_OFFLINE_PATTERN = r"This file doesn't exist, or has been removed."
+ FILE_INFO_PATTERN = r'site-content">\s*<h1>(?P<N>.+)<strong>\( (?P<S>[^)]+) \)</strong></h1>'
+
+ def handleFree(self):
+ self.html = self.load(self.pyfile.url, decode=True)
+
+ link = self._getLink()
+ if not link.startswith('http://'):
+ link = "http://www.putlocker.com" + link
+ self.download(link, disposition=True)
+
def _getLink(self):
- self.hash = re.search("<input type=\"hidden\" value=\"([a-z0-9]+)\" name=\"hash\">", self.html)
- # if self.hash is None:
- # self.fail("%s: Plugin broken." % self.__name__)
-
- self.param = "hash=" + self.hash.group(1) + "&confirm=Continue+as+Free+User"
- self.html2 = self.load(self.pyfile.url, post=self.param)
- if ">You have exceeded the daily stream limit for your country\\. You can wait until tomorrow" in self.html2 or "(>This content server has been temporarily disabled for upgrades|Try again soon\\. You can still download it below\\.<)" in self.html2:
- self.waittime = 2 * 60 * 60
- self.retry(wait_time=self.waittime, reason="Waiting %s seconds" % self.waittime)
-
- self.link = re.search("<a href=\"/gopro\\.php\">Tired of ads and waiting\\? Go Pro\\!</a>[\t\n\rn ]+</div>[\t\n\rn ]+<a href=\"(/.*?)\"", self.html2)
- if self.link is None:
- self.link = re.search("\"(/get_file\\.php\\?download=[A-Z0-9]+\\&key=[a-z0-9]+)\"", self.html2)
-
- if self.link is None:
- self.link = re.search("\"(/get_file\\.php\\?download=[A-Z0-9]+\\&key=[a-z0-9]+&original=1)\"", self.html2)
-
- if self.link is None:
- self.link = re.search("\"(/get_file\\.php\\?id=[A-Z0-9]+\\&key=[A-Za-z0-9=]+\\&original=1)\"", self.html2)
-
- if self.link is None:
- self.link = re.search("playlist: \\'(/get_file\\.php\\?stream=[A-Za-z0-9=]+)\\'", self.html2)
- if not self.link is None:
- self.html3 = self.load("http://www.putlocker.com" + self.link.group(1))
- self.link = re.search("media:content url=\"(http://.*?)\"", self.html3)
- if self.link is None:
- self.link = re.search("\"(http://media\\-b\\d+\\.putlocker\\.com/download/\\d+/.*?)\"", self.html3)
-
- # if link is None:
- # self.fail("%s: Plugin broken." % self.__name__)
-
- return self.link.group(1).replace("&amp;", "&")
-
-
+ hash_data = re.search(r'<input type="hidden" value="([a-z0-9]+)" name="hash">', self.html)
+ if not hash_data:
+ self.parseError('Unable to detect hash')
+
+ post_data = {"hash": hash_data.group(1), "confirm": "Continue+as+Free+User"}
+ self.html = self.load(self.pyfile.url, post=post_data)
+ if ">You have exceeded the daily stream limit for your country\\. You can wait until tomorrow" in self.html or \
+ "(>This content server has been temporarily disabled for upgrades|Try again soon\\. You can still download it below\\.<)" in self.html:
+ self.retry(wait_time=2 * 60 * 60, reason="Download limit exceeded or server disabled")
+
+ patterns = (r'(/get_file\.php\?id=[A-Z0-9]+&key=[A-Za-z0-9=]+&original=1)',
+ r"(/get_file\.php\?download=[A-Z0-9]+&key=[a-z0-9]+)",
+ r"(/get_file\.php\?download=[A-Z0-9]+&key=[a-z0-9]+&original=1)",
+ r'<a href="/gopro\.php">Tired of ads and waiting\? Go Pro!</a>[\t\n\rn ]+</div>[\t\n\rn ]+<a href="(/.*?)"')
+ for pattern in patterns:
+ link = re.search(pattern, self.html)
+ if link:
+ break
+ else:
+ link = re.search(r"playlist: '(/get_file\.php\?stream=[A-Za-z0-9=]+)'", self.html)
+ if link:
+ self.html = self.load("http://www.putlocker.com" + link.group(1))
+ link = re.search(r'media:content url="(http://.*?)"', self.html)
+ if not link:
+ link = re.search("\"(http://media\\-b\\d+\\.putlocker\\.com/download/\\d+/.*?)\"", self.html)
+ else:
+ self.parseError('Unable to detect a download link')
+
+ return link.group(1).replace("&amp;", "&")
diff --git a/module/plugins/hoster/RarefileNet.py b/module/plugins/hoster/RarefileNet.py
index 7c5543cc8..a0f5930b5 100644
--- a/module/plugins/hoster/RarefileNet.py
+++ b/module/plugins/hoster/RarefileNet.py
@@ -1,30 +1,34 @@
# -*- coding: utf-8 -*-
+
import re
+
from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo
from module.utils import html_unescape
+
class RarefileNet(XFileSharingPro):
__name__ = "RarefileNet"
__type__ = "hoster"
__pattern__ = r"http://(?:\w*\.)*rarefile.net/\w{12}"
- __version__ = "0.02"
+ __version__ = "0.03"
__description__ = """Rarefile.net hoster plugin"""
__author_name__ = ("zoidberg")
__author_mail__ = ("zoidberg@mujmail.cz")
-
+
FILE_NAME_PATTERN = r'<td><font color="red">(?P<N>.*?)</font></td>'
FILE_SIZE_PATTERN = r'<td>Size : (?P<S>.+?)&nbsp;'
+ DIRECT_LINK_PATTERN = r'<a href="(?P<link>[^"]+)">(?P=link)</a>'
HOSTER_NAME = "rarefile.net"
-
+
def setup(self):
- self.resumeDownload = self.multiDL = self.premium
-
+ self.resumeDownload = self.multiDL = self.premium
+
def handleCaptcha(self, inputs):
captcha_div = re.search(r'<b>Enter code.*?<div.*?>(.*?)</div>', self.html, re.S).group(1)
- self.logDebug(captcha_div)
+ self.logDebug(captcha_div)
numerals = re.findall('<span.*?padding-left\s*:\s*(\d+).*?>(\d)</span>', html_unescape(captcha_div))
inputs['code'] = "".join([a[1] for a in sorted(numerals, key = lambda num: int(num[0]))])
- self.logDebug("CAPTCHA", inputs['code'], numerals)
+ self.logDebug("CAPTCHA", inputs['code'], numerals)
return 3
-getInfo = create_getInfo(RarefileNet) \ No newline at end of file
+getInfo = create_getInfo(RarefileNet)
diff --git a/module/plugins/hoster/UploadedTo.py b/module/plugins/hoster/UploadedTo.py
index a2134ecb5..c7ce5846e 100644
--- a/module/plugins/hoster/UploadedTo.py
+++ b/module/plugins/hoster/UploadedTo.py
@@ -1,5 +1,9 @@
# -*- coding: utf-8 -*-
+# Test links (random.bin):
+# http://ul.to/044yug9o
+# http://ul.to/gzfhd0xs
+
import re
from module.utils import html_unescape, parseFileSize
@@ -11,34 +15,37 @@ from module.plugins.ReCaptcha import ReCaptcha
key = "bGhGMkllZXByd2VEZnU5Y2NXbHhYVlZ5cEE1bkEzRUw=".decode('base64')
+
def getID(url):
""" returns id from file url"""
- m = re.match(r"http://[\w\.-]*?(uploaded\.(to|net)(/file/|/?\?id=|.*?&id=)|ul\.to/)(?P<ID>\w+)", url)
+ m = re.match(UploadedTo.__pattern__, url)
return m.group('ID')
+
def getAPIData(urls):
- post = {"apikey" : key}
+ post = {"apikey": key}
- idMap = {}
+ idMap = {}
- for i, url in enumerate(urls):
- id = getID(url)
- post["id_%s" % i] = id
- idMap[id] = url
+ for i, url in enumerate(urls):
+ id = getID(url)
+ post["id_%s" % i] = id
+ idMap[id] = url
- api = unicode(getURL("http://uploaded.net/api/filemultiple", post=post, decode=False), 'iso-8859-1')
+ api = unicode(getURL("http://uploaded.net/api/filemultiple", post=post, decode=False), 'iso-8859-1')
- result = {}
+ result = {}
- if api:
- for line in api.splitlines():
- data = line.split(",", 4)
- if data[1] in idMap:
- result[data[1]] = (data[0], data[2], data[4], data[3], idMap[data[1]])
+ if api:
+ for line in api.splitlines():
+ data = line.split(",", 4)
+ if data[1] in idMap:
+ result[data[1]] = (data[0], data[2], data[4], data[3], idMap[data[1]])
- return result
+ return result
-def parseFileInfo(self, url = '', html = ''):
+
+def parseFileInfo(self, url='', html=''):
if not html and hasattr(self, "html"): html = self.html
name, size, status, found, fileid = url, 0, 3, None, None
@@ -54,6 +61,7 @@ def parseFileInfo(self, url = '', html = ''):
return name, size, status, fileid
+
def getInfo(urls):
for chunk in chunks(urls, 80):
result = []
@@ -73,8 +81,8 @@ def getInfo(urls):
class UploadedTo(Hoster):
__name__ = "UploadedTo"
__type__ = "hoster"
- __pattern__ = r"http://[\w\.-]*?(uploaded\.(to|net)(/file/|/?\?id=|.*?&id=)|ul\.to/)\w+"
- __version__ = "0.64"
+ __pattern__ = r"https?://[\w\.-]*?(uploaded\.(to|net)|ul\.to)(/file/|/?\?id=|.*?&id=|/)(?P<ID>\w+)"
+ __version__ = "0.67"
__description__ = """Uploaded.net Download Hoster"""
__author_name__ = ("spoob", "mkaay", "zoidberg", "netpok", "stickell")
__author_mail__ = ("spoob@pyload.org", "mkaay@mkaay.de", "zoidberg@mujmail.cz", "netpok@gmail.com", "l.stickell@yahoo.it")
@@ -88,7 +96,7 @@ class UploadedTo(Hoster):
self.multiDL = False
self.resumeDownload = False
self.url = False
- self.chunkLimit = 1 # critical problems with more chunks
+ self.chunkLimit = 1 # critical problems with more chunks
if self.account:
self.premium = self.account.getAccountInfo(self.user)["premium"]
if self.premium:
@@ -108,7 +116,7 @@ class UploadedTo(Hoster):
if not api:
self.logWarning("No response for API call")
- self.html = unicode(self.load(pyfile.url, decode = False), 'iso-8859-1')
+ self.html = unicode(self.load(pyfile.url, decode=False), 'iso-8859-1')
name, size, status, self.fileID = parseFileInfo(self)
self.logDebug(name, size, status, self.fileID)
if status == 1:
@@ -140,8 +148,9 @@ class UploadedTo(Hoster):
def handlePremium(self):
info = self.account.getAccountInfo(self.user, True)
- self.log.debug("%(name)s: Use Premium Account (%(left)sGB left)" % {"name" :self.__name__, "left" : info["trafficleft"]/1024/1024})
- if int(self.data[1])/1024 > info["trafficleft"]:
+ self.log.debug("%(name)s: Use Premium Account (%(left)sGB left)" % {"name": self.__name__,
+ "left": info["trafficleft"] / 1024 / 1024})
+ if int(self.data[1]) / 1024 > info["trafficleft"]:
self.log.info(_("%s: Not enough traffic left" % self.__name__))
self.account.empty(self.user)
self.resetAccount()
@@ -185,7 +194,7 @@ class UploadedTo(Hoster):
#self.req.lastURL = str(self.url)
re_captcha = ReCaptcha(self)
challenge, result = re_captcha.challenge(challengeId.group(1))
- options = {"recaptcha_challenge_field" : challenge, "recaptcha_response_field": result}
+ options = {"recaptcha_challenge_field": challenge, "recaptcha_response_field": result}
self.wait()
result = self.load(url, post=options)
@@ -193,13 +202,13 @@ class UploadedTo(Hoster):
if "limit-size" in result:
self.fail("File too big for free download")
- elif "limit-slot" in result: # Temporary restriction so just wait a bit
+ elif "limit-slot" in result: # Temporary restriction so just wait a bit
self.setWait(30 * 60, True)
self.wait()
self.retry()
elif "limit-parallel" in result:
self.fail("Cannot download in parallel")
- elif self.DL_LIMIT_PATTERN in result: # limit-dl
+ elif self.DL_LIMIT_PATTERN in result: # limit-dl
self.setWait(60 * 60, True)
self.wait()
self.retry()
@@ -216,7 +225,7 @@ class UploadedTo(Hoster):
if not downloadURL:
self.fail("No Download url retrieved/all captcha attempts failed")
- self.download(downloadURL)
+ self.download(downloadURL, disposition=True)
check = self.checkDownload({"limit-dl": self.DL_LIMIT_PATTERN})
if check == "limit-dl":
self.setWait(60 * 60, True)
diff --git a/module/plugins/hoster/XVideosCom.py b/module/plugins/hoster/XVideosCom.py
new file mode 100644
index 000000000..b7f3f7b58
--- /dev/null
+++ b/module/plugins/hoster/XVideosCom.py
@@ -0,0 +1,19 @@
+
+import re
+import urllib
+
+from module.plugins.Hoster import Hoster
+
+class XVideosCom(Hoster):
+ __name__ = "XVideos.com"
+ __version__ = "0.1"
+ __pattern__ = r"http://www\.xvideos\.com/video([0-9]+)/.*"
+ __config__ = []
+
+ def process(self, pyfile):
+ site = self.load(pyfile.url)
+ pyfile.name = "%s (%s).flv" %(
+ re.search(r"<h2>([^<]+)<span", site).group(1),
+ re.search(self.__pattern__, pyfile.url).group(1),
+ )
+ self.download(urllib.unquote(re.search(r"flv_url=([^&]+)&", site).group(1)))
diff --git a/module/plugins/hoster/YoutubeCom.py b/module/plugins/hoster/YoutubeCom.py
index 8b8764367..2fb1e5264 100644
--- a/module/plugins/hoster/YoutubeCom.py
+++ b/module/plugins/hoster/YoutubeCom.py
@@ -34,7 +34,7 @@ class YoutubeCom(Hoster):
__name__ = "YoutubeCom"
__type__ = "hoster"
__pattern__ = r"(http|https)://(www\.)?(de\.)?\youtube\.com/watch\?v=.*"
- __version__ = "0.29"
+ __version__ = "0.30"
__config__ = [("quality", "sd;hd;fullhd;240p;360p;480p;720p;1080p;3072p", "Quality Setting", "hd"),
("fmt", "int", "FMT/ITAG Number (5-102, 0 for auto)", 0),
(".mp4", "bool", "Allow .mp4", True),
diff --git a/module/plugins/internal/SimpleCrypter.py b/module/plugins/internal/SimpleCrypter.py
index b8942c724..c9e350e86 100644
--- a/module/plugins/internal/SimpleCrypter.py
+++ b/module/plugins/internal/SimpleCrypter.py
@@ -18,18 +18,20 @@
"""
import re
+
from module.plugins.Crypter import Crypter
+
class SimpleCrypter(Crypter):
__name__ = "SimpleCrypter"
- __version__ = "0.03"
+ __version__ = "0.04"
__pattern__ = None
__type__ = "crypter"
__description__ = """Base crypter plugin"""
__author_name__ = ("stickell", "zoidberg")
__author_mail__ = ("l.stickell@yahoo.it", "zoidberg@mujmail.cz")
"""
- These patterns should be defined by each hoster:
+ These patterns should be defined by each crypter:
LINK_PATTERN: group(1) must be a download link
example: <div class="link"><a href="(http://speedload.org/\w+)
@@ -39,7 +41,7 @@ class SimpleCrypter(Crypter):
"""
def decrypt(self, pyfile):
- self.html = self.load(pyfile.url)
+ self.html = self.load(pyfile.url, decode=True)
package_name, folder_name = self.getPackageNameAndFolder()
@@ -55,7 +57,7 @@ class SimpleCrypter(Crypter):
if hasattr(self, 'TITLE_PATTERN'):
m = re.search(self.TITLE_PATTERN, self.html)
if m:
- name = folder = m.group('title')
+ name = folder = m.group('title').strip()
self.logDebug("Found name [%s] and folder [%s] in package info" % (name, folder))
return name, folder
diff --git a/module/plugins/internal/SimpleHoster.py b/module/plugins/internal/SimpleHoster.py
index cfc9f2b43..69ed57ff8 100644
--- a/module/plugins/internal/SimpleHoster.py
+++ b/module/plugins/internal/SimpleHoster.py
@@ -155,8 +155,8 @@ class SimpleHoster(Hoster):
"""
These patterns should be defined by each hoster:
FILE_INFO_PATTERN = r'(?P<N>file_name) (?P<S>file_size) (?P<U>units)'
- or FILE_NAME_INFO = r'(?P<N>file_name)'
- and FILE_SIZE_INFO = r'(?P<S>file_size) (?P<U>units)'
+ or FILE_NAME_PATTERN = r'(?P<N>file_name)'
+ and FILE_SIZE_PATTERN = r'(?P<S>file_size) (?P<U>units)'
FILE_OFFLINE_PATTERN = r'File (deleted|not found)'
TEMP_OFFLINE_PATTERN = r'Server maintainance'
"""
diff --git a/module/plugins/internal/UnRar.py b/module/plugins/internal/UnRar.py
index 240dc0233..da8e7cf3d 100644
--- a/module/plugins/internal/UnRar.py
+++ b/module/plugins/internal/UnRar.py
@@ -22,18 +22,20 @@ import re
from os.path import join
from glob import glob
from subprocess import Popen, PIPE
+from string import digits
from module.utils import save_join, decode
from module.plugins.internal.AbstractExtractor import AbtractExtractor, WrongPassword, ArchiveError, CRCError
class UnRar(AbtractExtractor):
__name__ = "UnRar"
- __version__ = "0.11"
+ __version__ = "0.13"
# there are some more uncovered rar formats
- re_splitfile = re.compile(r"(.*)\.part(\d+)\.rar$")
+ re_splitfile = re.compile(r"(.*)\.part(\d+)\.rar$", re.I)
+ re_partfiles = re.compile(r".*\.(rar|r[0-9]+)", re.I)
re_filelist = re.compile(r"(.+)\s+(\d+)\s+(\d+)\s+")
- re_wrongpwd = re.compile("(Corrupt file or wrong password|password incorrect)")
+ re_wrongpwd = re.compile("(Corrupt file or wrong password|password incorrect)", re.I)
CMD = "unrar"
@staticmethod
@@ -113,15 +115,31 @@ class UnRar(AbtractExtractor):
def extract(self, progress, password=None):
command = "x" if self.fullpath else "e"
- # popen thinks process is still alive (just like pexpect) - very strange behavior
- # so for now progress can not be determined correctly
p = self.call_unrar(command, self.file, self.out, password=password)
renice(p.pid, self.renice)
progress(0)
- out, err = p.communicate() #wait for process
+ progressstring = ""
+ while True:
+ c = p.stdout.read(1)
+ # quit loop on eof
+ if not c:
+ break
+ # reading a percentage sign -> set progress and restart
+ if c == '%':
+ progress(int(progressstring))
+ progressstring = ""
+ # not reading a digit -> therefore restart
+ elif c not in digits:
+ progressstring = ""
+ # add digit to progressstring
+ else:
+ progressstring = progressstring + c
progress(100)
+ # retrieve stderr
+ err = p.stderr.read()
+
if "CRC failed" in err and not password and not self.passwordProtected:
raise CRCError
elif "CRC failed" in err:
@@ -139,7 +157,9 @@ class UnRar(AbtractExtractor):
def getDeleteFiles(self):
if ".part" in self.file:
return glob(re.sub("(?<=\.part)([01]+)", "*", self.file, re.IGNORECASE))
- return [self.file]
+ # get files which matches .r* and filter unsuited files out
+ parts = glob(re.sub(r"(?<=\.r)ar$", "*", self.file, re.IGNORECASE))
+ return filter(lambda x: self.re_partfiles.match(x), parts)
def listContent(self):
command = "vb" if self.fullpath else "lb"