diff options
Diffstat (limited to 'module/plugins/hoster')
-rw-r--r-- | module/plugins/hoster/AlldebridCom.py | 37 | ||||
-rw-r--r-- | module/plugins/hoster/DebridItaliaCom.py | 43 | ||||
-rw-r--r-- | module/plugins/hoster/EgoFilesCom.py | 19 | ||||
-rw-r--r-- | module/plugins/hoster/FilebeerInfo.py | 93 | ||||
-rw-r--r-- | module/plugins/hoster/LuckyShareNet.py | 72 | ||||
-rw-r--r-- | module/plugins/hoster/NetloadIn.py | 4 | ||||
-rw-r--r-- | module/plugins/hoster/RapidgatorNet.py | 4 | ||||
-rw-r--r-- | module/plugins/hoster/RyushareCom.py | 14 | ||||
-rw-r--r-- | module/plugins/hoster/X7To.py | 2 | ||||
-rw-r--r-- | module/plugins/hoster/YoutubeCom.py | 52 | ||||
-rw-r--r-- | module/plugins/hoster/ZDF.py | 46 |
11 files changed, 245 insertions, 141 deletions
diff --git a/module/plugins/hoster/AlldebridCom.py b/module/plugins/hoster/AlldebridCom.py index fe58ff0a7..efc96ff28 100644 --- a/module/plugins/hoster/AlldebridCom.py +++ b/module/plugins/hoster/AlldebridCom.py @@ -1,19 +1,16 @@ -#!/usr/nv python
# -*- coding: utf-8 -*-
import re
-from urllib import quote, unquote
+from urllib import unquote
from random import randrange
-from os import stat
-
from module.plugins.Hoster import Hoster
from module.common.json_layer import json_loads
-from module.utils import parseFileSize, fs_encode
+from module.utils import parseFileSize
class AlldebridCom(Hoster):
__name__ = "AlldebridCom"
- __version__ = "0.3"
+ __version__ = "0.31"
__type__ = "hoster"
__pattern__ = r"https?://.*alldebrid\..*"
@@ -27,7 +24,7 @@ class AlldebridCom(Hoster): except IndexError:
name = "Unknown_Filename..."
if name.endswith("..."): #incomplete filename, append random stuff
- name += "%s.tmp" % randrange(100,999)
+ name += "%s.tmp" % randrange(100, 999)
return name
def init(self):
@@ -35,10 +32,9 @@ class AlldebridCom(Hoster): self.chunkLimit = 3
self.resumeDownload = True
-
- def process(self, pyfile):
+ def process(self, pyfile):
if not self.account:
- self.logError(_("Please enter your AllDebrid account or deactivate this plugin"))
+ self.logError("Please enter your AllDebrid account or deactivate this plugin")
self.fail("No AllDebrid account provided")
self.log.debug("AllDebrid: Old URL: %s" % pyfile.url)
@@ -46,14 +42,13 @@ class AlldebridCom(Hoster): new_url = pyfile.url
else:
password = self.getPassword().splitlines()
- if not password: password = ""
- else: password = password[0]
+ password = "" if not password else password[0]
- url = "http://www.alldebrid.com/service.php?link=%s&json=true&pw=%s" %(pyfile.url, password)
+ url = "http://www.alldebrid.com/service.php?link=%s&json=true&pw=%s" % (pyfile.url, password)
page = self.load(url)
data = json_loads(page)
-
- self.log.debug("Json data: %s" % str(data))
+
+ self.logDebug("Json data: %s" % str(data))
if data["error"]:
if data["error"] == "This link isn't available on the hoster website.":
@@ -72,7 +67,7 @@ class AlldebridCom(Hoster): else:
new_url = new_url.replace("https://", "http://")
- self.log.debug("AllDebrid: New URL: %s" % new_url)
+ self.logDebug("AllDebrid: New URL: %s" % new_url)
if pyfile.name.startswith("http") or pyfile.name.startswith("Unknown"):
#only use when name wasnt already set
@@ -80,12 +75,10 @@ class AlldebridCom(Hoster): self.download(new_url, disposition=True)
- check = self.checkDownload(
- {"error": "<title>An error occured while processing your request</title>","empty": re.compile(r"^$")})
+ check = self.checkDownload({"error": "<title>An error occured while processing your request</title>",
+ "empty": re.compile(r"^$")})
if check == "error":
self.retry(reason="An error occured while generating link.", wait_time=60)
- else:
- if check == "empty":
- self.retry(reason="Downloaded File was empty.", wait_time=60)
-
+ elif check == "empty":
+ self.retry(reason="Downloaded File was empty.", wait_time=60)
diff --git a/module/plugins/hoster/DebridItaliaCom.py b/module/plugins/hoster/DebridItaliaCom.py new file mode 100644 index 000000000..a8f7dd57e --- /dev/null +++ b/module/plugins/hoster/DebridItaliaCom.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +import re + +from module.plugins.Hoster import Hoster + + +class DebridItaliaCom(Hoster): + __name__ = "DebridItaliaCom" + __version__ = "0.02" + __type__ = "hoster" + __pattern__ = r"https?://.*debriditalia\.com" + __description__ = """Debriditalia.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 DebridItalia account or deactivate this plugin") + self.fail("No DebridItalia account provided") + + self.logDebug("Old URL: %s" % pyfile.url) + if re.match(self.__pattern__, pyfile.url): + new_url = pyfile.url + else: + url = "http://debriditalia.com/linkgen2.php?xjxfun=convertiLink&xjxargs[]=S<![CDATA[%s]]>" % pyfile.url + page = self.load(url) + self.logDebug("XML data: %s" % page) + + new_url = re.search(r'<a href="(?:[^"]+)">(?P<direct>[^<]+)</a>', page).group('direct') + + self.logDebug("New URL: %s" % new_url) + + self.download(new_url, disposition=True) + + check = self.checkDownload({"empty": re.compile(r"^$")}) + + if check == "empty": + self.retry(5, 120, 'Empty file downloaded') diff --git a/module/plugins/hoster/EgoFilesCom.py b/module/plugins/hoster/EgoFilesCom.py index 24e26c7f5..b27abb416 100644 --- a/module/plugins/hoster/EgoFilesCom.py +++ b/module/plugins/hoster/EgoFilesCom.py @@ -4,22 +4,18 @@ from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo from module.plugins.ReCaptcha import ReCaptcha
import re
-def to_seconds(m):
- minutes = int(m['m']) if m['m'] else 0
- seconds = int(m['s']) if m['s'] else 0
- return minutes * 60 + seconds
class EgoFilesCom(SimpleHoster):
__name__ = "EgoFilesCom"
__type__ = "hoster"
__pattern__ = r"https?://(www\.)?egofiles.com/(\w+)"
- __version__ = "0.07"
+ __version__ = "0.10"
__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_OFFLINE_PATTERN = r'File size: 0 KB'
+ 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>'
RECAPTCHA_KEY = '6LeXatQSAAAAAHezcjXyWAni-4t302TeYe7_gfvX'
@@ -29,19 +25,14 @@ 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:
- self.handlePremium()
- else:
- self.handleFree()
-
def handleFree(self):
self.html = self.load(self.pyfile.url, decode=True)
# Wait time between free downloads
if 'For next free download you have to wait' in self.html:
- m = re.search(self.WAIT_TIME_PATTERN, self.html)
- self.setWait(to_seconds(m.groupdict()), True)
+ m = re.search(self.WAIT_TIME_PATTERN, self.html).groupdict('0')
+ waittime = int(m['m']) * 60 + int(m['s'])
+ self.setWait(waittime, True)
self.wait()
downloadURL = ''
diff --git a/module/plugins/hoster/FilebeerInfo.py b/module/plugins/hoster/FilebeerInfo.py index a51f70a09..216ecfbca 100644 --- a/module/plugins/hoster/FilebeerInfo.py +++ b/module/plugins/hoster/FilebeerInfo.py @@ -1,100 +1,15 @@ # -*- 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 - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. +from module.plugins.internal.DeadHoster import DeadHoster, create_getInfo - 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 General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. - - @author: zoidberg -""" - -import re -from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo -from module.plugins.ReCaptcha import ReCaptcha -from pycurl import FOLLOWLOCATION - -class FilebeerInfo(SimpleHoster): +class FilebeerInfo(DeadHoster): __name__ = "FilebeerInfo" __type__ = "hoster" __pattern__ = r"http://(?:www\.)?filebeer\.info/(?!\d*~f)(?P<ID>\w+).*" - __version__ = "0.02" + __version__ = "0.03" __description__ = """Filebeer.info plugin""" __author_name__ = ("zoidberg") __author_mail__ = ("zoidberg@mujmail.cz") - FILE_NAME_PATTERN = r'Filename:\s*</td>\s*<td>\s*(?P<N>.+?) ' - FILE_SIZE_PATTERN = r'Filesize:\s*</td>\s*<td>\s*(?P<S>[0-9.]+) (?P<U>[kKMG])i?B' - FILE_INFO_PATTERN = r'<strong>\s*(?P<N>.+?) \((?P<S>[0-9.]+) (?P<U>[kKMG])i?B\)(<br/>\s*)?</strong>' - FILE_OFFLINE_PATTERN = r'<title>Upload Files - FileBeer.info</title>' - - FILE_URL_REPLACEMENTS = [(__pattern__, 'http://filebeer.info/\g<ID>~i')] - - RECAPTCHA_KEY_PATTERN = r'http://www.google.com/recaptcha/api/(?:challenge|noscript)?k=(\w+)' - DOWNLOAD_URL_PATTERN = r"\[url\](.+?)\[/url\]" - WAIT_TIME_PATTERN = r"\(\'\.download-timer-seconds\'\)\.html\((\d+)\)" - - def setup(self): - self.resumeDownload = True - self.multiDL = self.premium - - def handleFree(self): - url = self.getDownloadUrl() - - for i in range(5): - self.html = self.load(url) - if i == 4 or 'id="form-join"' in self.html: - break - else: - found = re.search(self.WAIT_TIME_PATTERN, self.html) - self.setWait(int(found.group(1)) +1 if found else 61) - self.wait() - - action, inputs = self.parseHtmlForm('form-join') - if not action: - self.fail('Form not found') - - found = re.search(self.RECAPTCHA_KEY_PATTERN, self.html) - recaptcha_key = found.group(1) if found else '6LeuAc4SAAAAAOSry8eo2xW64K1sjHEKsQ5CaS10' - - recaptcha = ReCaptcha(self) - for i in range(5): - inputs['recaptcha_challenge_field'], inputs['recaptcha_response_field'] = recaptcha.challenge(recaptcha_key) - - self.req.http.c.setopt(FOLLOWLOCATION, 0) - self.html = self.load(action, post = inputs) - self.header = self.req.http.header - self.req.http.c.setopt(FOLLOWLOCATION, 1) - - found = re.search("Location\s*:\s*(.*)", self.header, re.I) - if found: - download_url = found.group(1).strip() - self.correctCaptcha() - break - elif 'Captcha confirmation text is invalid' in self.html: - self.invalidCaptcha() - else: - self.parseError('download url') - - else: self.fail("No valid captcha solution received") - - self.multiDL = True - - self.req.http.lastURL = action - self.download(download_url) - - def handlePremium(self): - self.download(self.getDownloadUrl()) - - def getDownloadUrl(self): - found = re.search(self.DOWNLOAD_URL_PATTERN, self.html) - return ("%s?d=1" % found.group(1)) if found else ("http://filebeer.info/%s?d=1" % self.file_info['ID']) - + getInfo = create_getInfo(FilebeerInfo)
\ No newline at end of file diff --git a/module/plugins/hoster/LuckyShareNet.py b/module/plugins/hoster/LuckyShareNet.py new file mode 100644 index 000000000..a1e866089 --- /dev/null +++ b/module/plugins/hoster/LuckyShareNet.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*-
+
+import re
+from module.lib.bottle import json_loads
+
+from module.plugins.internal.SimpleHoster import SimpleHoster, create_getInfo
+from module.plugins.ReCaptcha import ReCaptcha
+
+
+class LuckyShareNet(SimpleHoster):
+ __name__ = "LuckyShareNet"
+ __type__ = "hoster"
+ __pattern__ = r"https?://(www\.)?luckyshare.net/(?P<ID>\d{10,})"
+ __version__ = "0.02"
+ __description__ = """LuckyShare.net Download Hoster"""
+ __author_name__ = ("stickell")
+ __author_mail__ = ("l.stickell@yahoo.it")
+
+ FILE_INFO_PATTERN = r"<h1 class='file_name'>(?P<N>\S+)</h1>\s*<span class='file_size'>Filesize: (?P<S>[\d.]+)(?P<U>\w+)</span>"
+ FILE_OFFLINE_PATTERN = 'There is no such file available'
+ RECAPTCHA_KEY = '6LdivsgSAAAAANWh-d7rPE1mus4yVWuSQIJKIYNw'
+
+ def parseJson(self, rep):
+ if 'AJAX Error' in rep:
+ html = self.load(self.pyfile.url, decode=True)
+ m = re.search(r"waitingtime = (\d+);", html)
+ if m:
+ waittime = int(m.group(1))
+ self.logDebug('You have to wait %d seconds between free downloads' % waittime)
+ self.retry(wait_time=waittime)
+ else:
+ self.parseError('Unable to detect wait time between free downloads')
+ elif 'Hash expired' in rep:
+ self.retry(reason='Hash expired')
+ return json_loads(rep)
+
+ # TODO: There should be a filesize limit for free downloads
+ # TODO: Some files could not be downloaded in free mode
+ def handleFree(self):
+ file_id = re.search(self.__pattern__, self.pyfile.url).group('ID')
+ self.logDebug('File ID: ' + file_id)
+ rep = self.load(r"http://luckyshare.net/download/request/type/time/file/" + file_id, decode=True)
+ self.logDebug('JSON: ' + rep)
+ json = self.parseJson(rep)
+
+ self.setWait(int(json['time']))
+ self.wait()
+
+ recaptcha = ReCaptcha(self)
+ for i in xrange(5):
+ challenge, response = recaptcha.challenge(self.RECAPTCHA_KEY)
+ rep = self.load(r"http://luckyshare.net/download/verify/challenge/%s/response/%s/hash/%s" %
+ (challenge, response, json['hash']), decode=True)
+ self.logDebug('JSON: ' + rep)
+ if 'link' in rep:
+ json.update(self.parseJson(rep))
+ self.correctCaptcha()
+ break
+ elif 'Verification failed' in rep:
+ self.logInfo('Wrong captcha')
+ self.invalidCaptcha()
+ else:
+ self.parseError('Unable to get downlaod link')
+
+ if not json['link']:
+ self.fail("No Download url retrieved/all captcha attempts failed")
+
+ self.logDebug('Direct URL: ' + json['link'])
+ self.download(json['link'])
+
+
+getInfo = create_getInfo(LuckyShareNet)
diff --git a/module/plugins/hoster/NetloadIn.py b/module/plugins/hoster/NetloadIn.py index d2bf37d70..e616badc2 100644 --- a/module/plugins/hoster/NetloadIn.py +++ b/module/plugins/hoster/NetloadIn.py @@ -54,8 +54,8 @@ def getInfo(urls): class NetloadIn(Hoster): __name__ = "NetloadIn" __type__ = "hoster" - __pattern__ = r"http://.*netload\.in/(?:datei(.*?)(?:\.htm|/)|index.php?id=10&file_id=)" - __version__ = "0.41" + __pattern__ = r"https?://.*netload\.in/(?:datei(.*?)(?:\.htm|/)|index.php?id=10&file_id=)" + __version__ = "0.42" __description__ = """Netload.in Download Hoster""" __author_name__ = ("spoob", "RaNaN", "Gregy") __author_mail__ = ("spoob@pyload.org", "ranan@pyload.org", "gregy@gregy.cz") diff --git a/module/plugins/hoster/RapidgatorNet.py b/module/plugins/hoster/RapidgatorNet.py index 6c1c231fe..1cc3ff8ae 100644 --- a/module/plugins/hoster/RapidgatorNet.py +++ b/module/plugins/hoster/RapidgatorNet.py @@ -28,8 +28,8 @@ from module.network.HTTPRequest import BadHeader class RapidgatorNet(SimpleHoster): __name__ = "RapidgatorNet" __type__ = "hoster" - __pattern__ = r"http://(?:www\.)?(rapidgator.net)/file/(\d+)" - __version__ = "0.15" + __pattern__ = r"http://(?:www\.)?(rapidgator.net)/file/(\w+)" + __version__ = "0.16" __description__ = """rapidgator.net""" __author_name__ = ("zoidberg","chrox") diff --git a/module/plugins/hoster/RyushareCom.py b/module/plugins/hoster/RyushareCom.py index 19f17b531..c2ff54e0c 100644 --- a/module/plugins/hoster/RyushareCom.py +++ b/module/plugins/hoster/RyushareCom.py @@ -2,16 +2,12 @@ from module.plugins.hoster.XFileSharingPro import XFileSharingPro, create_getInfo import re -def to_seconds(m): - minutes = int(m['min']) if m['min'] else 0 - seconds = int(m['sec']) if m['sec'] else 0 - return minutes * 60 + seconds class RyushareCom(XFileSharingPro): __name__ = "RyushareCom" __type__ = "hoster" __pattern__ = r"http://(?:\w*\.)*?ryushare.com/\w{11,}" - __version__ = "0.07" + __version__ = "0.10" __description__ = """ryushare.com hoster plugin""" __author_name__ = ("zoidberg", "stickell") __author_mail__ = ("zoidberg@mujmail.cz", "l.stickell@yahoo.it") @@ -19,6 +15,7 @@ class RyushareCom(XFileSharingPro): HOSTER_NAME = "ryushare.com" WAIT_PATTERN = r'(?:You have to|Please) wait (?:(?P<min>\d+) minutes, )?(?:<span id="[^"]+">)?(?P<sec>\d+)(?:</span>)? seconds' + DIRECT_LINK_PATTERN = r'<a href="([^"]+)">Click here to download</a>' def setup(self): self.resumeDownload = self.multiDL = self.premium @@ -41,13 +38,14 @@ class RyushareCom(XFileSharingPro): if 'You have reached the download-limit!!!' in self.html: self.setWait(3600, True) else: - m = re.search(self.WAIT_PATTERN, self.html) - self.setWait(to_seconds(m.groupdict())) + m = re.search(self.WAIT_PATTERN, self.html).groupdict('0') + waittime = int(m['min']) * 60 + int(m['sec']) + self.setWait(waittime) self.wait() self.html = self.load(self.pyfile.url, post = inputs) if 'Click here to download' in self.html: - m = re.search(r'<a href="([^"]+)">Click here to download</a>', self.html) + m = re.search(self.DIRECT_LINK_PATTERN, self.html) return m.group(1) self.parseError('No direct link within 10 retries') diff --git a/module/plugins/hoster/X7To.py b/module/plugins/hoster/X7To.py index 51f8e6cd4..79adf2a3f 100644 --- a/module/plugins/hoster/X7To.py +++ b/module/plugins/hoster/X7To.py @@ -55,7 +55,7 @@ class X7To(Hoster): file_id = re.search(r"var dlID = '(.*?)'", self.html)
if not file_id:
self.fail("Free download id not found")
-
+
file_url = "http://x7.to/james/ticket/dl/" + file_id.group(1)
self.logDebug("download id %s" % file_id.group(1))
diff --git a/module/plugins/hoster/YoutubeCom.py b/module/plugins/hoster/YoutubeCom.py index a9fed5638..8b8764367 100644 --- a/module/plugins/hoster/YoutubeCom.py +++ b/module/plugins/hoster/YoutubeCom.py @@ -2,11 +2,34 @@ # -*- coding: utf-8 -*- import re +import subprocess +import os +import os.path from urllib import unquote from module.utils import html_unescape from module.plugins.Hoster import Hoster +def which(program): + """Works exactly like the unix command which + + Courtesy of http://stackoverflow.com/a/377028/675646""" + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + for path in os.environ["PATH"].split(os.pathsep): + path = path.strip('"') + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + + return None + class YoutubeCom(Hoster): __name__ = "YoutubeCom" __type__ = "hoster" @@ -112,7 +135,30 @@ class YoutubeCom(Hoster): #set file name file_suffix = self.formats[fmt][0] if fmt in self.formats else ".flv" file_name_pattern = '<meta name="title" content="(.+?)">' - name = re.search(file_name_pattern, html).group(1).replace("/", "") + file_suffix + name = re.search(file_name_pattern, html).group(1).replace("/", "") pyfile.name = html_unescape(name) - - self.download(url)
\ No newline at end of file + + time = re.search(r"t=((\d+)m)?(\d+)s", pyfile.url) + ffmpeg = which("ffmpeg") + if ffmpeg and time: + m, s = time.groups()[1:] + if not m: + m = "0" + + pyfile.name += " (starting at %s:%s)" % (m, s) + pyfile.name += file_suffix + + filename = self.download(url) + + if ffmpeg and time: + inputfile = filename + "_" + os.rename(filename, inputfile) + + subprocess.call([ + ffmpeg, + "-ss", "00:%s:%s" % (m, s), + "-i", inputfile, + "-vcodec", "copy", + "-acodec", "copy", + filename]) + os.remove(inputfile) diff --git a/module/plugins/hoster/ZDF.py b/module/plugins/hoster/ZDF.py new file mode 100644 index 000000000..ea45f4fd8 --- /dev/null +++ b/module/plugins/hoster/ZDF.py @@ -0,0 +1,46 @@ + +import re +from xml.etree.ElementTree import fromstring + +from module.plugins.Hoster import Hoster + +XML_API = "http://www.zdf.de/ZDFmediathek/xmlservice/web/beitragsDetails?id=%i" + +class ZDF(Hoster): + # Based on zdfm by Roland Beermann + # http://github.com/enkore/zdfm/ + __name__ = "ZDF Mediathek" + __version__ = "0.7" + __pattern__ = r"http://www\.zdf\.de/ZDFmediathek/[^0-9]*([0-9]+)[^0-9]*" + __config__ = [] + + @staticmethod + def video_key(video): + return ( + int(video.findtext("videoBitrate", "0")), + any(f.text == "progressive" for f in video.iter("facet")), + ) + + @staticmethod + def video_valid(video): + return (video.findtext("url").startswith("http") and video.findtext("url").endswith(".mp4")) + + @staticmethod + def get_id(url): + return int(re.search(r"[^0-9]*([0-9]+)[^0-9]*", url).group(1)) + + def process(self, pyfile): + xml = fromstring(self.load(XML_API % self.get_id(pyfile.url))) + + status = xml.findtext("./status/statuscode") + if status != "ok": + self.fail("Error retrieving manifest.") + + video = xml.find("video") + title = video.findtext("information/title") + + pyfile.name = title + + target_url = sorted((v for v in video.iter("formitaet") if self.video_valid(v)), key=self.video_key)[-1].findtext("url") + + self.download(target_url) |