@ -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' |