mirror of https://github.com/yt-dlp/yt-dlp
Merge remote-tracking branch 'upstream/master'
commit
90d3989b99
@ -1,79 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# Allow direct execution
|
|
||||||
import os
|
|
||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
||||||
|
|
||||||
from youtube_dl.extractor.youtube import YoutubeIE
|
|
||||||
from helper import FakeYDL
|
|
||||||
|
|
||||||
ie = YoutubeIE(FakeYDL())
|
|
||||||
sig = ie._decrypt_signature
|
|
||||||
sig_age_gate = ie._decrypt_signature_age_gate
|
|
||||||
|
|
||||||
class TestYoutubeSig(unittest.TestCase):
|
|
||||||
def test_92(self):
|
|
||||||
wrong = "F9F9B6E6FD47029957AB911A964CC20D95A181A5D37A2DBEFD67D403DB0E8BE4F4910053E4E8A79.0B70B.0B80B8"
|
|
||||||
right = "69B6E6FD47029957AB911A9F4CC20D95A181A5D3.A2DBEFD67D403DB0E8BE4F4910053E4E8A7980B7"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_90(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[]}|:;?/>.<'`"
|
|
||||||
right = "mrtyuioplkjhgfdsazxcvbne1234567890QWER[YUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={`]}|"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_88(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[]}|:;?/>.<"
|
|
||||||
right = "J:|}][{=+-_)(*&;%$#@>MNBVCXZASDFGH^KLPOIUYTREWQ0987654321mnbvcxzasdfghrklpoiuytej"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_87(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$^&*()_-+={[]}|:;?/>.<"
|
|
||||||
right = "tyuioplkjhgfdsazxcv<nm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$^&*()_-+={[]}|:;?/>"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_86(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[|};?/>.<"
|
|
||||||
right = ">.1}|[{=+-_)(*&^%$#@!MNBVCXZASDFGHJK<POIUYTREW509876L432/mnbvcxzasdfghjklpoiuytre"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_85(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?/>.<"
|
|
||||||
right = "ertyuiqplkjhgfdsazx$vbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#<%^&*()_-+={[};?/c"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_84(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?>.<"
|
|
||||||
right = "<.>?;}[{=+-_)(*&^%$#@!MNBVCXZASDFGHJKLPOIUYTREWe098765432rmnbvcxzasdfghjklpoiuyt1"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_83(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!#$%^&*()_+={[};?/>.<"
|
|
||||||
right = "urty8ioplkjhgfdsazxcvbqm1234567S90QWERTYUIOPLKJHGFDnAZXCVBNM!#$%^&*()_+={[};?/>.<"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_82(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKHGFDSAZXCVBNM!@#$%^&*(-+={[};?/>.<"
|
|
||||||
right = "Q>/?;}[{=+-(*<^%$#@!MNBVCXZASDFGHKLPOIUY8REWT0q&7654321mnbvcxzasdfghjklpoiuytrew9"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_81(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKHGFDSAZXCVBNM!@#$%^&*(-+={[};?/>."
|
|
||||||
right = "C>/?;}[{=+-(*&^%$#@!MNBVYXZASDFGHKLPOIU.TREWQ0q87659321mnbvcxzasdfghjkl4oiuytrewp"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_79(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKHGFDSAZXCVBNM!@#$%^&*(-+={[};?/"
|
|
||||||
right = "Z?;}[{=+-(*&^%$#@!MNBVCXRASDFGHKLPOIUYT/EWQ0q87659321mnbvcxzasdfghjkl4oiuytrewp"
|
|
||||||
self.assertEqual(sig(wrong), right)
|
|
||||||
|
|
||||||
def test_86_age_gate(self):
|
|
||||||
wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[|};?/>.<"
|
|
||||||
right = "ertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!/#$%^&*()_-+={[|};?@"
|
|
||||||
self.assertEqual(sig_age_gate(wrong), right)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
@ -0,0 +1,64 @@
|
|||||||
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
compat_urllib_parse,
|
||||||
|
determine_ext,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class MuzuTVIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://www.muzu.tv/(.+?)/(.+?)/(?P<id>\d+)'
|
||||||
|
IE_NAME = u'muzu.tv'
|
||||||
|
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.muzu.tv/defected/marcashken-featuring-sos-cat-walk-original-mix-music-video/1981454/',
|
||||||
|
u'file': u'1981454.mp4',
|
||||||
|
u'md5': u'98f8b2c7bc50578d6a0364fff2bfb000',
|
||||||
|
u'info_dict': {
|
||||||
|
u'title': u'Cat Walk (Original Mix)',
|
||||||
|
u'description': u'md5:90e868994de201b2570e4e5854e19420',
|
||||||
|
u'uploader': u'MarcAshken featuring SOS',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group('id')
|
||||||
|
|
||||||
|
info_data = compat_urllib_parse.urlencode({'format': 'json',
|
||||||
|
'url': url,
|
||||||
|
})
|
||||||
|
video_info_page = self._download_webpage('http://www.muzu.tv/api/oembed/?%s' % info_data,
|
||||||
|
video_id, u'Downloading video info')
|
||||||
|
info = json.loads(video_info_page)
|
||||||
|
|
||||||
|
player_info_page = self._download_webpage('http://player.muzu.tv/player/playerInit?ai=%s' % video_id,
|
||||||
|
video_id, u'Downloading player info')
|
||||||
|
video_info = json.loads(player_info_page)['videos'][0]
|
||||||
|
for quality in ['1080' , '720', '480', '360']:
|
||||||
|
if video_info.get('v%s' % quality):
|
||||||
|
break
|
||||||
|
|
||||||
|
data = compat_urllib_parse.urlencode({'ai': video_id,
|
||||||
|
# Even if each time you watch a video the hash changes,
|
||||||
|
# it seems to work for different videos, and it will work
|
||||||
|
# even if you use any non empty string as a hash
|
||||||
|
'viewhash': 'VBNff6djeV4HV5TRPW5kOHub2k',
|
||||||
|
'device': 'web',
|
||||||
|
'qv': quality,
|
||||||
|
})
|
||||||
|
video_url_page = self._download_webpage('http://player.muzu.tv/player/requestVideo?%s' % data,
|
||||||
|
video_id, u'Downloading video url')
|
||||||
|
video_url_info = json.loads(video_url_page)
|
||||||
|
video_url = video_url_info['url']
|
||||||
|
|
||||||
|
return {'id': video_id,
|
||||||
|
'title': info['title'],
|
||||||
|
'url': video_url,
|
||||||
|
'ext': determine_ext(video_url),
|
||||||
|
'thumbnail': info['thumbnail_url'],
|
||||||
|
'description': info['description'],
|
||||||
|
'uploader': info['author_name'],
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import unescapeHTML
|
||||||
|
|
||||||
|
class OoyalaIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://.+?\.ooyala\.com/.*?embedCode=(?P<id>.+?)(&|$)'
|
||||||
|
|
||||||
|
_TEST = {
|
||||||
|
# From http://it.slashdot.org/story/13/04/25/178216/recovering-data-from-broken-hard-drives-and-ssds-video
|
||||||
|
u'url': u'http://player.ooyala.com/player.js?embedCode=pxczE2YjpfHfn1f3M-ykG_AmJRRn0PD8',
|
||||||
|
u'file': u'pxczE2YjpfHfn1f3M-ykG_AmJRRn0PD8.mp4',
|
||||||
|
u'md5': u'3f5cceb3a7bf461d6c29dc466cf8033c',
|
||||||
|
u'info_dict': {
|
||||||
|
u'title': u'Explaining Data Recovery from Hard Drives and SSDs',
|
||||||
|
u'description': u'How badly damaged does a drive have to be to defeat Russell and his crew? Apparently, smashed to bits.',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def _extract_result(self, info, more_info):
|
||||||
|
return {'id': info['embedCode'],
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': unescapeHTML(info['title']),
|
||||||
|
'url': info['url'],
|
||||||
|
'description': unescapeHTML(more_info['description']),
|
||||||
|
'thumbnail': more_info['promo'],
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
embedCode = mobj.group('id')
|
||||||
|
player_url = 'http://player.ooyala.com/player.js?embedCode=%s' % embedCode
|
||||||
|
player = self._download_webpage(player_url, embedCode)
|
||||||
|
mobile_url = self._search_regex(r'mobile_player_url="(.+?)&device="',
|
||||||
|
player, u'mobile player url')
|
||||||
|
mobile_player = self._download_webpage(mobile_url, embedCode)
|
||||||
|
videos_info = self._search_regex(r'eval\("\((\[{.*?stream_redirect.*?}\])\)"\);', mobile_player, u'info').replace('\\"','"')
|
||||||
|
videos_more_info = self._search_regex(r'eval\("\(({.*?\\"promo\\".*?})\)"', mobile_player, u'more info').replace('\\"','"')
|
||||||
|
videos_info = json.loads(videos_info)
|
||||||
|
videos_more_info =json.loads(videos_more_info)
|
||||||
|
|
||||||
|
if videos_more_info.get('lineup'):
|
||||||
|
videos = [self._extract_result(info, more_info) for (info, more_info) in zip(videos_info, videos_more_info['lineup'])]
|
||||||
|
return {'_type': 'playlist',
|
||||||
|
'id': embedCode,
|
||||||
|
'title': unescapeHTML(videos_more_info['title']),
|
||||||
|
'entries': videos,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return self._extract_result(videos_info[0], videos_more_info)
|
||||||
|
|
@ -0,0 +1,100 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import ExtractorError
|
||||||
|
|
||||||
|
class RTLnowIE(InfoExtractor):
|
||||||
|
"""Information Extractor for RTLnow, RTL2now and VOXnow"""
|
||||||
|
_VALID_URL = r'(?:http://)?(?P<url>(?P<base_url>rtl(?:(?P<is_rtl2>2)|-)now\.rtl(?(is_rtl2)2|)\.de/|(?:www\.)?voxnow\.de/)[a-zA-Z0-9-]+/[a-zA-Z0-9-]+\.php\?(?:container_id|film_id)=(?P<video_id>[0-9]+)&player=1(?:&season=[0-9]+)?(?:&.*)?)'
|
||||||
|
_TESTS = [{
|
||||||
|
u'url': u'http://rtl-now.rtl.de/ahornallee/folge-1.php?film_id=90419&player=1&season=1',
|
||||||
|
u'file': u'90419.flv',
|
||||||
|
u'info_dict': {
|
||||||
|
u'upload_date': u'20070416',
|
||||||
|
u'title': u'Ahornallee - Folge 1 - Der Einzug',
|
||||||
|
u'description': u'Folge 1 - Der Einzug',
|
||||||
|
},
|
||||||
|
u'params': {
|
||||||
|
u'skip_download': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u'url': u'http://rtl2now.rtl2.de/aerger-im-revier/episode-15-teil-1.php?film_id=69756&player=1&season=2&index=5',
|
||||||
|
u'file': u'69756.flv',
|
||||||
|
u'info_dict': {
|
||||||
|
u'upload_date': u'20120519',
|
||||||
|
u'title': u'Ärger im Revier - Ein junger Ladendieb, ein handfester Streit...',
|
||||||
|
u'description': u'Ärger im Revier - Ein junger Ladendieb, ein handfester Streit u.a.',
|
||||||
|
u'thumbnail': u'http://autoimg.static-fra.de/rtl2now/219850/1500x1500/image2.jpg',
|
||||||
|
},
|
||||||
|
u'params': {
|
||||||
|
u'skip_download': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
u'url': u'www.voxnow.de/voxtours/suedafrika-reporter-ii.php?film_id=13883&player=1&season=17',
|
||||||
|
u'file': u'13883.flv',
|
||||||
|
u'info_dict': {
|
||||||
|
u'upload_date': u'20090627',
|
||||||
|
u'title': u'Voxtours - Südafrika-Reporter II',
|
||||||
|
u'description': u'Südafrika-Reporter II',
|
||||||
|
},
|
||||||
|
u'params': {
|
||||||
|
u'skip_download': True,
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _real_extract(self,url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
|
||||||
|
webpage_url = u'http://' + mobj.group('url')
|
||||||
|
video_page_url = u'http://' + mobj.group('base_url')
|
||||||
|
video_id = mobj.group(u'video_id')
|
||||||
|
|
||||||
|
webpage = self._download_webpage(webpage_url, video_id)
|
||||||
|
video_title = self._html_search_regex(r'<title>(?P<title>[^<]+)</title>',
|
||||||
|
webpage, u'title')
|
||||||
|
playerdata_url = self._html_search_regex(r'\'playerdata\': \'(?P<playerdata_url>[^\']+)\'',
|
||||||
|
webpage, u'playerdata_url')
|
||||||
|
|
||||||
|
playerdata = self._download_webpage(playerdata_url, video_id)
|
||||||
|
mobj = re.search(r'<title><!\[CDATA\[(?P<description>.+?)\s+- (?:Sendung )?vom (?P<upload_date_d>[0-9]{2})\.(?P<upload_date_m>[0-9]{2})\.(?:(?P<upload_date_Y>[0-9]{4})|(?P<upload_date_y>[0-9]{2})) [0-9]{2}:[0-9]{2} Uhr\]\]></title>', playerdata)
|
||||||
|
if mobj:
|
||||||
|
video_description = mobj.group(u'description')
|
||||||
|
if mobj.group('upload_date_Y'):
|
||||||
|
video_upload_date = mobj.group('upload_date_Y')
|
||||||
|
else:
|
||||||
|
video_upload_date = u'20' + mobj.group('upload_date_y')
|
||||||
|
video_upload_date += mobj.group('upload_date_m')+mobj.group('upload_date_d')
|
||||||
|
else:
|
||||||
|
video_description = None
|
||||||
|
video_upload_date = None
|
||||||
|
self._downloader.report_warning(u'Unable to extract description and upload date')
|
||||||
|
|
||||||
|
# Thumbnail: not every video has an thumbnail
|
||||||
|
mobj = re.search(r'<meta property="og:image" content="(?P<thumbnail>[^"]+)">', webpage)
|
||||||
|
if mobj:
|
||||||
|
video_thumbnail = mobj.group(u'thumbnail')
|
||||||
|
else:
|
||||||
|
video_thumbnail = None
|
||||||
|
|
||||||
|
mobj = re.search(r'<filename [^>]+><!\[CDATA\[(?P<url>rtmpe://(?:[^/]+/){2})(?P<play_path>[^\]]+)\]\]></filename>', playerdata)
|
||||||
|
if mobj is None:
|
||||||
|
raise ExtractorError(u'Unable to extract media URL')
|
||||||
|
video_url = mobj.group(u'url')
|
||||||
|
video_play_path = u'mp4:' + mobj.group(u'play_path')
|
||||||
|
video_player_url = video_page_url + u'includes/vodplayer.swf'
|
||||||
|
|
||||||
|
return [{
|
||||||
|
'id': video_id,
|
||||||
|
'url': video_url,
|
||||||
|
'play_path': video_play_path,
|
||||||
|
'page_url': video_page_url,
|
||||||
|
'player_url': video_player_url,
|
||||||
|
'ext': 'flv',
|
||||||
|
'title': video_title,
|
||||||
|
'description': video_description,
|
||||||
|
'upload_date': video_upload_date,
|
||||||
|
'thumbnail': video_thumbnail,
|
||||||
|
}]
|
@ -0,0 +1,49 @@
|
|||||||
|
import re
|
||||||
|
import xml.etree.ElementTree
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
find_xpath_attr,
|
||||||
|
determine_ext,
|
||||||
|
)
|
||||||
|
|
||||||
|
class VideofyMeIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(www.videofy.me/.+?|p.videofy.me/v)/(?P<id>\d+)(&|#|$)'
|
||||||
|
IE_NAME = u'videofy.me'
|
||||||
|
|
||||||
|
_TEST = {
|
||||||
|
u'url': u'http://www.videofy.me/thisisvideofyme/1100701',
|
||||||
|
u'file': u'1100701.mp4',
|
||||||
|
u'md5': u'2046dd5758541d630bfa93e741e2fd79',
|
||||||
|
u'info_dict': {
|
||||||
|
u'title': u'This is VideofyMe',
|
||||||
|
u'description': None,
|
||||||
|
u'uploader': u'VideofyMe',
|
||||||
|
u'uploader_id': u'thisisvideofyme',
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = re.match(self._VALID_URL, url)
|
||||||
|
video_id = mobj.group('id')
|
||||||
|
config_xml = self._download_webpage('http://sunshine.videofy.me/?videoId=%s' % video_id,
|
||||||
|
video_id)
|
||||||
|
config = xml.etree.ElementTree.fromstring(config_xml.encode('utf-8'))
|
||||||
|
video = config.find('video')
|
||||||
|
sources = video.find('sources')
|
||||||
|
url_node = find_xpath_attr(sources, 'source', 'id', 'HQ on')
|
||||||
|
if url_node is None:
|
||||||
|
url_node = find_xpath_attr(sources, 'source', 'id', 'HQ off')
|
||||||
|
video_url = url_node.find('url').text
|
||||||
|
|
||||||
|
return {'id': video_id,
|
||||||
|
'title': video.find('title').text,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': determine_ext(video_url),
|
||||||
|
'thumbnail': video.find('thumb').text,
|
||||||
|
'description': video.find('description').text,
|
||||||
|
'uploader': config.find('blog/name').text,
|
||||||
|
'uploader_id': video.find('identifier').text,
|
||||||
|
'view_count': re.search(r'\d+', video.find('views').text).group(),
|
||||||
|
}
|
@ -1,2 +1,2 @@
|
|||||||
|
|
||||||
__version__ = '2013.07.31'
|
__version__ = '2013.08.17'
|
||||||
|
Loading…
Reference in New Issue