diff options
-rw-r--r-- | test/test_YoutubeDL.py | 4 | ||||
-rw-r--r-- | test/test_playlists.py | 10 | ||||
-rw-r--r-- | youtube_dl/extractor/__init__.py | 6 | ||||
-rw-r--r-- | youtube_dl/extractor/empflix.py | 22 | ||||
-rw-r--r-- | youtube_dl/extractor/ndr.py | 15 | ||||
-rw-r--r-- | youtube_dl/extractor/nrk.py | 80 | ||||
-rw-r--r-- | youtube_dl/extractor/nuvid.py | 2 | ||||
-rw-r--r-- | youtube_dl/extractor/pornhub.py | 2 | ||||
-rw-r--r-- | youtube_dl/extractor/streamcz.py | 22 | ||||
-rw-r--r-- | youtube_dl/extractor/swrmediathek.py | 104 |
10 files changed, 237 insertions, 30 deletions
diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py index 8735013f7..e794cc97f 100644 --- a/test/test_YoutubeDL.py +++ b/test/test_YoutubeDL.py @@ -67,7 +67,7 @@ class TestFormatSelection(unittest.TestCase): downloaded = ydl.downloaded_info_dicts[0] self.assertEqual(downloaded['ext'], 'mp4') - # No prefer_free_formats => prefer mp4 and flv for greater compatibilty + # No prefer_free_formats => prefer mp4 and flv for greater compatibility ydl = YDL() ydl.params['prefer_free_formats'] = False formats = [ @@ -279,7 +279,7 @@ class TestFormatSelection(unittest.TestCase): self.assertEqual(ydl._format_note({}), '') assertRegexpMatches(self, ydl._format_note({ 'vbr': 10, - }), '^x\s*10k$') + }), '^\s*10k$') if __name__ == '__main__': unittest.main() diff --git a/test/test_playlists.py b/test/test_playlists.py index cc871698a..63d31db8c 100644 --- a/test/test_playlists.py +++ b/test/test_playlists.py @@ -213,16 +213,16 @@ class TestPlaylists(unittest.TestCase): self.assertIsPlaylist(result) self.assertEqual(result['id'], 'dezhurnyi_angel') self.assertEqual(result['title'], 'Дежурный ангел (2010 - 2012)') - self.assertTrue(len(result['entries']) >= 23) + self.assertTrue(len(result['entries']) >= 16) def test_ivi_compilation_season(self): dl = FakeYDL() ie = IviCompilationIE(dl) - result = ie.extract('http://www.ivi.ru/watch/dezhurnyi_angel/season2') + result = ie.extract('http://www.ivi.ru/watch/dezhurnyi_angel/season1') self.assertIsPlaylist(result) - self.assertEqual(result['id'], 'dezhurnyi_angel/season2') - self.assertEqual(result['title'], 'Дежурный ангел (2010 - 2012) 2 сезон') - self.assertTrue(len(result['entries']) >= 7) + self.assertEqual(result['id'], 'dezhurnyi_angel/season1') + self.assertEqual(result['title'], 'Дежурный ангел (2010 - 2012) 1 сезон') + self.assertTrue(len(result['entries']) >= 16) def test_imdb_list(self): dl = FakeYDL() diff --git a/youtube_dl/extractor/__init__.py b/youtube_dl/extractor/__init__.py index 3503c76b7..def58f1d6 100644 --- a/youtube_dl/extractor/__init__.py +++ b/youtube_dl/extractor/__init__.py @@ -194,7 +194,10 @@ from .normalboots import NormalbootsIE from .novamov import NovaMovIE from .nowness import NownessIE from .nowvideo import NowVideoIE -from .nrk import NRKIE +from .nrk import ( + NRKIE, + NRKTVIE, +) from .ntv import NTVIE from .nytimes import NYTimesIE from .nuvid import NuvidIE @@ -260,6 +263,7 @@ from .stanfordoc import StanfordOpenClassroomIE from .steam import SteamIE from .streamcloud import StreamcloudIE from .streamcz import StreamCZIE +from .swrmediathek import SWRMediathekIE from .syfy import SyfyIE from .sztvhu import SztvHuIE from .teamcoco import TeamcocoIE diff --git a/youtube_dl/extractor/empflix.py b/youtube_dl/extractor/empflix.py index eaeee5a51..e6952588f 100644 --- a/youtube_dl/extractor/empflix.py +++ b/youtube_dl/extractor/empflix.py @@ -3,20 +3,18 @@ from __future__ import unicode_literals import re from .common import InfoExtractor -from ..utils import ( - ExtractorError, -) class EmpflixIE(InfoExtractor): _VALID_URL = r'^https?://www\.empflix\.com/videos/.*?-(?P<id>[0-9]+)\.html' _TEST = { 'url': 'http://www.empflix.com/videos/Amateur-Finger-Fuck-33051.html', - 'md5': '5e5cc160f38ca9857f318eb97146e13e', + 'md5': 'b1bc15b6412d33902d6e5952035fcabc', 'info_dict': { 'id': '33051', - 'ext': 'flv', + 'ext': 'mp4', 'title': 'Amateur Finger Fuck', + 'description': 'Amateur solo finger fucking.', 'age_limit': 18, } } @@ -30,6 +28,8 @@ class EmpflixIE(InfoExtractor): video_title = self._html_search_regex( r'name="title" value="(?P<title>[^"]*)"', webpage, 'title') + video_description = self._html_search_regex( + r'name="description" value="([^"]*)"', webpage, 'description', fatal=False) cfg_url = self._html_search_regex( r'flashvars\.config = escape\("([^"]+)"', @@ -37,12 +37,18 @@ class EmpflixIE(InfoExtractor): cfg_xml = self._download_xml( cfg_url, video_id, note='Downloading metadata') - video_url = cfg_xml.find('videoLink').text + + formats = [ + { + 'url': item.find('videoLink').text, + 'format_id': item.find('res').text, + } for item in cfg_xml.findall('./quality/item') + ] return { 'id': video_id, - 'url': video_url, - 'ext': 'flv', 'title': video_title, + 'description': video_description, + 'formats': formats, 'age_limit': age_limit, } diff --git a/youtube_dl/extractor/ndr.py b/youtube_dl/extractor/ndr.py index 53b34f5e6..3d6096e46 100644 --- a/youtube_dl/extractor/ndr.py +++ b/youtube_dl/extractor/ndr.py @@ -7,6 +7,7 @@ from .common import InfoExtractor from ..utils import ( ExtractorError, int_or_none, + qualities, ) @@ -57,7 +58,7 @@ class NDRIE(InfoExtractor): formats = [] - mp3_url = re.search(r'''{src:'(?P<audio>[^']+)', type:"audio/mp3"},''', page) + mp3_url = re.search(r'''\{src:'(?P<audio>[^']+)', type:"audio/mp3"},''', page) if mp3_url: formats.append({ 'url': mp3_url.group('audio'), @@ -66,15 +67,15 @@ class NDRIE(InfoExtractor): thumbnail = None - video_url = re.search(r'''3: {src:'(?P<video>.+?)\.hi\.mp4', type:"video/mp4"},''', page) + video_url = re.search(r'''3: \{src:'(?P<video>.+?)\.hi\.mp4', type:"video/mp4"},''', page) if video_url: - thumbnails = re.findall(r'''\d+: {src: "([^"]+)"(?: \|\| '[^']+')?, quality: '([^']+)'}''', page) + thumbnails = re.findall(r'''\d+: \{src: "([^"]+)"(?: \|\| '[^']+')?, quality: '([^']+)'}''', page) if thumbnails: - QUALITIES = ['xs', 's', 'm', 'l', 'xl'] - thumbnails.sort(key=lambda thumb: QUALITIES.index(thumb[1]) if thumb[1] in QUALITIES else -1) - thumbnail = 'http://www.ndr.de' + thumbnails[-1][0] + quality_key = qualities(['xs', 's', 'm', 'l', 'xl']) + largest = max(thumbnails, key=lambda thumb: quality_key(thumb[1])) + thumbnail = 'http://www.ndr.de' + largest[0] - for format_id in ['lo', 'hi', 'hq']: + for format_id in 'lo', 'hi', 'hq': formats.append({ 'url': '%s.%s.mp4' % (video_url.group('video'), format_id), 'format_id': format_id, diff --git a/youtube_dl/extractor/nrk.py b/youtube_dl/extractor/nrk.py index e6d68b836..f5117d7b3 100644 --- a/youtube_dl/extractor/nrk.py +++ b/youtube_dl/extractor/nrk.py @@ -4,7 +4,11 @@ from __future__ import unicode_literals import re from .common import InfoExtractor -from ..utils import ExtractorError +from ..utils import ( + ExtractorError, + int_or_none, + unified_strdate, +) class NRKIE(InfoExtractor): @@ -64,4 +68,78 @@ class NRKIE(InfoExtractor): 'title': data['title'], 'description': data['description'], 'thumbnail': thumbnail, + } + + +class NRKTVIE(InfoExtractor): + _VALID_URL = r'http://tv\.nrk\.no/(?:serie/[^/]+|program)/(?P<id>[a-z]{4}\d{8})' + + _TESTS = [ + { + 'url': 'http://tv.nrk.no/serie/20-spoersmaal-tv/muhh48000314/23-05-2014', + 'md5': '7b96112fbae1faf09a6f9ae1aff6cb84', + 'info_dict': { + 'id': 'muhh48000314', + 'ext': 'flv', + 'title': '20 spørsmål', + 'description': 'md5:bdea103bc35494c143c6a9acdd84887a', + 'upload_date': '20140523', + 'duration': 1741.52, + } + }, + { + 'url': 'http://tv.nrk.no/program/mdfp15000514', + 'md5': '383650ece2b25ecec996ad7b5bb2a384', + 'info_dict': { + 'id': 'mdfp15000514', + 'ext': 'flv', + 'title': 'Kunnskapskanalen: Grunnlovsjubiléet - Stor ståhei for ingenting', + 'description': 'md5:654c12511f035aed1e42bdf5db3b206a', + 'upload_date': '20140524', + 'duration': 4605.0, + } + }, + ] + + def _real_extract(self, url): + mobj = re.match(self._VALID_URL, url) + video_id = mobj.group('id') + + page = self._download_webpage(url, video_id) + + title = self._html_search_meta('title', page, 'title') + description = self._html_search_meta('description', page, 'description') + thumbnail = self._html_search_regex(r'data-posterimage="([^"]+)"', page, 'thumbnail', fatal=False) + upload_date = unified_strdate(self._html_search_meta('rightsfrom', page, 'upload date', fatal=False)) + duration = self._html_search_regex(r'data-duration="([^"]+)"', page, 'duration', fatal=False) + if duration: + duration = float(duration) + + formats = [] + + f4m_url = re.search(r'data-media="([^"]+)"', page) + if f4m_url: + formats.append({ + 'url': f4m_url.group(1) + '?hdcore=3.1.1&plugin=aasp-3.1.1.69.124', + 'format_id': 'f4m', + 'ext': 'flv', + }) + + m3u8_url = re.search(r'data-hls-media="([^"]+)"', page) + if m3u8_url: + formats.append({ + 'url': m3u8_url.group(1), + 'format_id': 'm3u8', + }) + + self._sort_formats(formats) + + return { + 'id': video_id, + 'title': title, + 'description': description, + 'thumbnail': thumbnail, + 'upload_date': upload_date, + 'duration': duration, + 'formats': formats, }
\ No newline at end of file diff --git a/youtube_dl/extractor/nuvid.py b/youtube_dl/extractor/nuvid.py index f0befa116..e3db9fe8c 100644 --- a/youtube_dl/extractor/nuvid.py +++ b/youtube_dl/extractor/nuvid.py @@ -30,7 +30,7 @@ class NuvidIE(InfoExtractor): webpage, 'title').strip() url_end = self._html_search_regex( - r'href="(/mp4/[^"]+)"[^>]*data-link_type="mp4"', + r'href="(/[^"]+)"[^>]*data-link_type="mp4"', webpage, 'video_url') video_url = 'http://m.nuvid.com' + url_end diff --git a/youtube_dl/extractor/pornhub.py b/youtube_dl/extractor/pornhub.py index 7dd3dca0d..4118ee956 100644 --- a/youtube_dl/extractor/pornhub.py +++ b/youtube_dl/extractor/pornhub.py @@ -45,7 +45,7 @@ class PornHubIE(InfoExtractor): video_title = self._html_search_regex(r'<h1 [^>]+>([^<]+)', webpage, 'title') video_uploader = self._html_search_regex( - r'(?s)<div class="video-info-row">\s*From: .+?<(?:a href="/users/|<span class="username)[^>]+>(.+?)<', + r'(?s)From: .+?<(?:a href="/users/|<span class="username)[^>]+>(.+?)<', webpage, 'uploader', fatal=False) thumbnail = self._html_search_regex(r'"image_url":"([^"]+)', webpage, 'thumbnail', fatal=False) if thumbnail: diff --git a/youtube_dl/extractor/streamcz.py b/youtube_dl/extractor/streamcz.py index 7362904db..73efe9542 100644 --- a/youtube_dl/extractor/streamcz.py +++ b/youtube_dl/extractor/streamcz.py @@ -5,13 +5,16 @@ import re import json from .common import InfoExtractor -from ..utils import int_or_none +from ..utils import ( + int_or_none, + compat_str, +) class StreamCZIE(InfoExtractor): _VALID_URL = r'https?://(?:www\.)?stream\.cz/.+/(?P<videoid>.+)' - _TEST = { + _TESTS = [{ 'url': 'http://www.stream.cz/peklonataliri/765767-ecka-pro-deti', 'md5': '6d3ca61a8d0633c9c542b92fcb936b0c', 'info_dict': { @@ -22,7 +25,18 @@ class StreamCZIE(InfoExtractor): 'thumbnail': 'http://im.stream.cz/episode/52961d7e19d423f8f06f0100', 'duration': 256, }, - } + }, { + 'url': 'http://www.stream.cz/blanik/10002447-tri-roky-pro-mazanka', + 'md5': '246272e753e26bbace7fcd9deca0650c', + 'info_dict': { + 'id': '10002447', + 'ext': 'mp4', + 'title': 'Kancelář Blaník: Tři roky pro Mazánka', + 'description': 'md5:9177695a8b756a0a8ab160de4043b392', + 'thumbnail': 'http://im.stream.cz/episode/537f838c50c11f8d21320000', + 'duration': 368, + }, + }] def _real_extract(self, url): mobj = re.match(self._VALID_URL, url) @@ -57,7 +71,7 @@ class StreamCZIE(InfoExtractor): self._sort_formats(formats) return { - 'id': str(jsonData['id']), + 'id': compat_str(jsonData['episode_id']), 'title': self._og_search_title(webpage), 'thumbnail': jsonData['episode_image_original_url'].replace('//', 'http://'), 'formats': formats, diff --git a/youtube_dl/extractor/swrmediathek.py b/youtube_dl/extractor/swrmediathek.py new file mode 100644 index 000000000..6c688c520 --- /dev/null +++ b/youtube_dl/extractor/swrmediathek.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import re + +from .common import InfoExtractor +from ..utils import parse_duration + + +class SWRMediathekIE(InfoExtractor): + _VALID_URL = r'https?://(?:www\.)?swrmediathek\.de/player\.htm\?show=(?P<id>[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12})' + + _TESTS = [{ + 'url': 'http://swrmediathek.de/player.htm?show=849790d0-dab8-11e3-a953-0026b975f2e6', + 'md5': '8c5f6f0172753368547ca8413a7768ac', + 'info_dict': { + 'id': '849790d0-dab8-11e3-a953-0026b975f2e6', + 'ext': 'mp4', + 'title': 'SWR odysso', + 'description': 'md5:2012e31baad36162e97ce9eb3f157b8a', + 'thumbnail': 're:^http:.*\.jpg$', + 'duration': 2602, + 'upload_date': '20140515', + 'uploader': 'SWR Fernsehen', + 'uploader_id': '990030', + }, + }, { + 'url': 'http://swrmediathek.de/player.htm?show=0e1a8510-ddf2-11e3-9be3-0026b975f2e6', + 'md5': 'b10ab854f912eecc5a6b55cd6fc1f545', + 'info_dict': { + 'id': '0e1a8510-ddf2-11e3-9be3-0026b975f2e6', + 'ext': 'mp4', + 'title': 'Nachtcafé - Alltagsdroge Alkohol - zwischen Sektempfang und Komasaufen', + 'description': 'md5:e0a3adc17e47db2c23aab9ebc36dbee2', + 'thumbnail': 're:http://.*\.jpg', + 'duration': 5305, + 'upload_date': '20140516', + 'uploader': 'SWR Fernsehen', + 'uploader_id': '990030', + }, + }, { + 'url': 'http://swrmediathek.de/player.htm?show=bba23e10-cb93-11e3-bf7f-0026b975f2e6', + 'md5': '4382e4ef2c9d7ce6852535fa867a0dd3', + 'info_dict': { + 'id': 'bba23e10-cb93-11e3-bf7f-0026b975f2e6', + 'ext': 'mp3', + 'title': 'Saša Stanišic: Vor dem Fest', + 'description': 'md5:5b792387dc3fbb171eb709060654e8c9', + 'thumbnail': 're:http://.*\.jpg', + 'duration': 3366, + 'upload_date': '20140520', + 'uploader': 'SWR 2', + 'uploader_id': '284670', + } + }] + + def _real_extract(self, url): + mobj = re.match(self._VALID_URL, url) + video_id = mobj.group('id') + + video = self._download_json( + 'http://swrmediathek.de/AjaxEntry?ekey=%s' % video_id, video_id, 'Downloading video JSON') + + attr = video['attr'] + media_type = attr['entry_etype'] + + formats = [] + for entry in video['sub']: + if entry['name'] != 'entry_media': + continue + + entry_attr = entry['attr'] + codec = entry_attr['val0'] + quality = int(entry_attr['val1']) + + fmt = { + 'url': entry_attr['val2'], + 'quality': quality, + } + + if media_type == 'Video': + fmt.update({ + 'format_note': ['144p', '288p', '544p'][quality-1], + 'vcodec': codec, + }) + elif media_type == 'Audio': + fmt.update({ + 'acodec': codec, + }) + formats.append(fmt) + + self._sort_formats(formats) + + return { + 'id': video_id, + 'title': attr['entry_title'], + 'description': attr['entry_descl'], + 'thumbnail': attr['entry_image_16_9'], + 'duration': parse_duration(attr['entry_durat']), + 'upload_date': attr['entry_pdatet'][:-4], + 'uploader': attr['channel_title'], + 'uploader_id': attr['channel_idkey'], + 'formats': formats, + }
\ No newline at end of file |