This commit is contained in:
codelol 2014-05-31 00:21:40 -07:00
commit 97333bbb4e
12 changed files with 149 additions and 85 deletions

View File

@ -77,6 +77,6 @@ youtube-dl.tar.gz: youtube-dl README.md README.txt youtube-dl.1 youtube-dl.bash-
--exclude 'docs/_build' \ --exclude 'docs/_build' \
-- \ -- \
bin devscripts test youtube_dl docs \ bin devscripts test youtube_dl docs \
CHANGELOG LICENSE README.md README.txt \ LICENSE README.md README.txt \
Makefile MANIFEST.in youtube-dl.1 youtube-dl.bash-completion setup.py \ Makefile MANIFEST.in youtube-dl.1 youtube-dl.bash-completion setup.py \
youtube-dl youtube-dl

View File

@ -45,9 +45,9 @@ fi
/bin/echo -e "\n### Changing version in version.py..." /bin/echo -e "\n### Changing version in version.py..."
sed -i "s/__version__ = '.*'/__version__ = '$version'/" youtube_dl/version.py sed -i "s/__version__ = '.*'/__version__ = '$version'/" youtube_dl/version.py
/bin/echo -e "\n### Committing CHANGELOG README.md and youtube_dl/version.py..." /bin/echo -e "\n### Committing README.md and youtube_dl/version.py..."
make README.md make README.md
git add CHANGELOG README.md youtube_dl/version.py git add README.md youtube_dl/version.py
git commit -m "release $version" git commit -m "release $version"
/bin/echo -e "\n### Now tagging, signing and pushing..." /bin/echo -e "\n### Now tagging, signing and pushing..."

View File

@ -209,20 +209,20 @@ class TestPlaylists(unittest.TestCase):
def test_ivi_compilation(self): def test_ivi_compilation(self):
dl = FakeYDL() dl = FakeYDL()
ie = IviCompilationIE(dl) ie = IviCompilationIE(dl)
result = ie.extract('http://www.ivi.ru/watch/dezhurnyi_angel') result = ie.extract('http://www.ivi.ru/watch/dvoe_iz_lartsa')
self.assertIsPlaylist(result) self.assertIsPlaylist(result)
self.assertEqual(result['id'], 'dezhurnyi_angel') self.assertEqual(result['id'], 'dvoe_iz_lartsa')
self.assertEqual(result['title'], 'Дежурный ангел (2010 - 2012)') self.assertEqual(result['title'], 'Двое из ларца (2006 - 2008)')
self.assertTrue(len(result['entries']) >= 16) self.assertTrue(len(result['entries']) >= 24)
def test_ivi_compilation_season(self): def test_ivi_compilation_season(self):
dl = FakeYDL() dl = FakeYDL()
ie = IviCompilationIE(dl) ie = IviCompilationIE(dl)
result = ie.extract('http://www.ivi.ru/watch/dezhurnyi_angel/season1') result = ie.extract('http://www.ivi.ru/watch/dvoe_iz_lartsa/season1')
self.assertIsPlaylist(result) self.assertIsPlaylist(result)
self.assertEqual(result['id'], 'dezhurnyi_angel/season1') self.assertEqual(result['id'], 'dvoe_iz_lartsa/season1')
self.assertEqual(result['title'], 'Дежурный ангел (2010 - 2012) 1 сезон') self.assertEqual(result['title'], 'Двое из ларца (2006 - 2008) 1 сезон')
self.assertTrue(len(result['entries']) >= 16) self.assertTrue(len(result['entries']) >= 12)
def test_imdb_list(self): def test_imdb_list(self):
dl = FakeYDL() dl = FakeYDL()

View File

@ -38,7 +38,9 @@ class ARDIE(InfoExtractor):
webpage = self._download_webpage(url, video_id) webpage = self._download_webpage(url, video_id)
title = self._html_search_regex( title = self._html_search_regex(
r'<h1(?:\s+class="boxTopHeadline")?>(.*?)</h1>', webpage, 'title') [r'<h1(?:\s+class="boxTopHeadline")?>(.*?)</h1>',
r'<h4 class="headline">(.*?)</h4>'],
webpage, 'title')
description = self._html_search_meta( description = self._html_search_meta(
'dcterms.abstract', webpage, 'description') 'dcterms.abstract', webpage, 'description')
thumbnail = self._og_search_thumbnail(webpage) thumbnail = self._og_search_thumbnail(webpage)

View File

@ -1,10 +1,12 @@
# encoding: utf-8 # encoding: utf-8
from __future__ import unicode_literals from __future__ import unicode_literals
import re import re
from .common import InfoExtractor from .common import InfoExtractor
from ..utils import ( from ..utils import (
ExtractorError, ExtractorError,
int_or_none,
) )
@ -13,9 +15,10 @@ class CinemassacreIE(InfoExtractor):
_TESTS = [ _TESTS = [
{ {
'url': 'http://cinemassacre.com/2012/11/10/avgn-the-movie-trailer/', 'url': 'http://cinemassacre.com/2012/11/10/avgn-the-movie-trailer/',
'file': '19911.mp4', 'md5': 'fde81fbafaee331785f58cd6c0d46190',
'md5': '782f8504ca95a0eba8fc9177c373eec7',
'info_dict': { 'info_dict': {
'id': '19911',
'ext': 'mp4',
'upload_date': '20121110', 'upload_date': '20121110',
'title': '“Angry Video Game Nerd: The Movie” Trailer', 'title': '“Angry Video Game Nerd: The Movie” Trailer',
'description': 'md5:fb87405fcb42a331742a0dce2708560b', 'description': 'md5:fb87405fcb42a331742a0dce2708560b',
@ -23,9 +26,10 @@ class CinemassacreIE(InfoExtractor):
}, },
{ {
'url': 'http://cinemassacre.com/2013/10/02/the-mummys-hand-1940', 'url': 'http://cinemassacre.com/2013/10/02/the-mummys-hand-1940',
'file': '521be8ef82b16.mp4', 'md5': 'd72f10cd39eac4215048f62ab477a511',
'md5': 'dec39ee5118f8d9cc067f45f9cbe3a35',
'info_dict': { 'info_dict': {
'id': '521be8ef82b16',
'ext': 'mp4',
'upload_date': '20131002', 'upload_date': '20131002',
'title': 'The Mummys Hand (1940)', 'title': 'The Mummys Hand (1940)',
}, },
@ -50,29 +54,40 @@ class CinemassacreIE(InfoExtractor):
r'<div class="entry-content">(?P<description>.+?)</div>', r'<div class="entry-content">(?P<description>.+?)</div>',
webpage, 'description', flags=re.DOTALL, fatal=False) webpage, 'description', flags=re.DOTALL, fatal=False)
playerdata = self._download_webpage(playerdata_url, video_id) playerdata = self._download_webpage(playerdata_url, video_id, 'Downloading player webpage')
video_thumbnail = self._search_regex(
r'image: \'(?P<thumbnail>[^\']+)\'', playerdata, 'thumbnail', fatal=False)
sd_url = self._search_regex(r'file: \'([^\']+)\', label: \'SD\'', playerdata, 'sd_file')
videolist_url = self._search_regex(r'file: \'([^\']+\.smil)\'}', playerdata, 'videolist_url')
sd_url = self._html_search_regex(r'file: \'([^\']+)\', label: \'SD\'', playerdata, 'sd_file') videolist = self._download_xml(videolist_url, video_id, 'Downloading videolist XML')
hd_url = self._html_search_regex(
r'file: \'([^\']+)\', label: \'HD\'', playerdata, 'hd_file',
default=None)
video_thumbnail = self._html_search_regex(r'image: \'(?P<thumbnail>[^\']+)\'', playerdata, 'thumbnail', fatal=False)
formats = [{ formats = []
'url': sd_url, baseurl = sd_url[:sd_url.rfind('/')+1]
'ext': 'mp4', for video in videolist.findall('.//video'):
'format': 'sd', src = video.get('src')
'format_id': 'sd', if not src:
'quality': 1, continue
}] file_ = src.partition(':')[-1]
if hd_url: width = int_or_none(video.get('width'))
formats.append({ height = int_or_none(video.get('height'))
'url': hd_url, bitrate = int_or_none(video.get('system-bitrate'))
'ext': 'mp4', format = {
'format': 'hd', 'url': baseurl + file_,
'format_id': 'hd', 'format_id': src.rpartition('.')[0].rpartition('_')[-1],
'quality': 2, }
if width or height:
format.update({
'tbr': bitrate // 1000 if bitrate else None,
'width': width,
'height': height,
}) })
else:
format.update({
'abr': bitrate // 1000 if bitrate else None,
'vcodec': 'none',
})
formats.append(format)
self._sort_formats(formats) self._sort_formats(formats)
return { return {

View File

@ -188,7 +188,7 @@ class ComedyCentralShowsIE(InfoExtractor):
}) })
formats.append({ formats.append({
'format_id': 'rtmp-%s' % format, 'format_id': 'rtmp-%s' % format,
'url': rtmp_video_url, 'url': rtmp_video_url.replace('viacomccstrm', 'viacommtvstrm'),
'ext': self._video_extensions.get(format, 'mp4'), 'ext': self._video_extensions.get(format, 'mp4'),
'height': h, 'height': h,
'width': w, 'width': w,

View File

@ -33,14 +33,14 @@ class IviIE(InfoExtractor):
}, },
# Serial's serie # Serial's serie
{ {
'url': 'http://www.ivi.ru/watch/dezhurnyi_angel/74791', 'url': 'http://www.ivi.ru/watch/dvoe_iz_lartsa/9549',
'md5': '3e6cc9a848c1d2ebcc6476444967baa9', 'md5': '221f56b35e3ed815fde2df71032f4b3e',
'info_dict': { 'info_dict': {
'id': '74791', 'id': '9549',
'ext': 'mp4', 'ext': 'mp4',
'title': 'Дежурный ангел - 1 серия', 'title': 'Двое из ларца - Серия 1',
'duration': 2490, 'duration': 2655,
'thumbnail': 'http://thumbs.ivi.ru/f7.vcp.digitalaccess.ru/contents/8/e/bc2f6c2b6e5d291152fdd32c059141.jpg', 'thumbnail': 'http://thumbs.ivi.ru/f15.vcp.digitalaccess.ru/contents/8/4/0068dc0677041f3336b7c2baad8fc0.jpg',
}, },
'skip': 'Only works from Russia', 'skip': 'Only works from Russia',
} }

View File

@ -1,6 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import re import re
import json
from .common import InfoExtractor from .common import InfoExtractor
from ..utils import find_xpath_attr, compat_str from ..utils import find_xpath_attr, compat_str
@ -31,9 +32,13 @@ class NBCIE(InfoExtractor):
class NBCNewsIE(InfoExtractor): class NBCNewsIE(InfoExtractor):
_VALID_URL = r'https?://www\.nbcnews\.com/video/.+?/(?P<id>\d+)' _VALID_URL = r'''(?x)https?://www\.nbcnews\.com/
((video/.+?/(?P<id>\d+))|
(feature/[^/]+/(?P<title>.+)))
'''
_TEST = { _TESTS = [
{
'url': 'http://www.nbcnews.com/video/nbc-news/52753292', 'url': 'http://www.nbcnews.com/video/nbc-news/52753292',
'md5': '47abaac93c6eaf9ad37ee6c4463a5179', 'md5': '47abaac93c6eaf9ad37ee6c4463a5179',
'info_dict': { 'info_dict': {
@ -42,11 +47,24 @@ class NBCNewsIE(InfoExtractor):
'title': 'Crew emerges after four-month Mars food study', 'title': 'Crew emerges after four-month Mars food study',
'description': 'md5:24e632ffac72b35f8b67a12d1b6ddfc1', 'description': 'md5:24e632ffac72b35f8b67a12d1b6ddfc1',
}, },
} },
{
'url': 'http://www.nbcnews.com/feature/edward-snowden-interview/how-twitter-reacted-snowden-interview-n117236',
'md5': 'b2421750c9f260783721d898f4c42063',
'info_dict': {
'id': 'I1wpAI_zmhsQ',
'ext': 'flv',
'title': 'How Twitter Reacted To The Snowden Interview',
'description': 'md5:65a0bd5d76fe114f3c2727aa3a81fe64',
},
'add_ie': ['ThePlatform'],
},
]
def _real_extract(self, url): def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url) mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id') video_id = mobj.group('id')
if video_id is not None:
all_info = self._download_xml('http://www.nbcnews.com/id/%s/displaymode/1219' % video_id, video_id) all_info = self._download_xml('http://www.nbcnews.com/id/%s/displaymode/1219' % video_id, video_id)
info = all_info.find('video') info = all_info.find('video')
@ -58,3 +76,24 @@ class NBCNewsIE(InfoExtractor):
'description': compat_str(info.find('caption').text), 'description': compat_str(info.find('caption').text),
'thumbnail': find_xpath_attr(info, 'media', 'type', 'thumbnail').text, 'thumbnail': find_xpath_attr(info, 'media', 'type', 'thumbnail').text,
} }
else:
# "feature" pages use theplatform.com
title = mobj.group('title')
webpage = self._download_webpage(url, title)
bootstrap_json = self._search_regex(
r'var bootstrapJson = ({.+})\s*$', webpage, 'bootstrap json',
flags=re.MULTILINE)
bootstrap = json.loads(bootstrap_json)
info = bootstrap['results'][0]['video']
playlist_url = info['fallbackPlaylistUrl'] + '?form=MPXNBCNewsAPI'
mpxid = info['mpxId']
all_videos = self._download_json(playlist_url, title)['videos']
# The response contains additional videos
info = next(v for v in all_videos if v['mpxId'] == mpxid)
return {
'_type': 'url',
# We get the best quality video
'url': info['videoAssets'][-1]['publicUrl'],
'ie_key': 'ThePlatform',
}

View File

@ -30,7 +30,7 @@ class NuvidIE(InfoExtractor):
webpage, 'title').strip() webpage, 'title').strip()
url_end = self._html_search_regex( url_end = self._html_search_regex(
r'href="(/mp4/[^"]+)"[^>]*data-link_type="mp4"', r'href="(/[^"]+)"[^>]*data-link_type="mp4"',
webpage, 'video_url') webpage, 'video_url')
video_url = 'http://m.nuvid.com' + url_end video_url = 'http://m.nuvid.com' + url_end

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals
import re import re
import json import json
@ -18,17 +20,17 @@ class ThePlatformIE(InfoExtractor):
_TEST = { _TEST = {
# from http://www.metacafe.com/watch/cb-e9I_cZgTgIPd/blackberrys_big_bold_z30/ # from http://www.metacafe.com/watch/cb-e9I_cZgTgIPd/blackberrys_big_bold_z30/
u'url': u'http://link.theplatform.com/s/dJ5BDC/e9I_cZgTgIPd/meta.smil?format=smil&Tracking=true&mbr=true', 'url': 'http://link.theplatform.com/s/dJ5BDC/e9I_cZgTgIPd/meta.smil?format=smil&Tracking=true&mbr=true',
u'info_dict': { 'info_dict': {
u'id': u'e9I_cZgTgIPd', 'id': 'e9I_cZgTgIPd',
u'ext': u'flv', 'ext': 'flv',
u'title': u'Blackberry\'s big, bold Z30', 'title': 'Blackberry\'s big, bold Z30',
u'description': u'The Z30 is Blackberry\'s biggest, baddest mobile messaging device yet.', 'description': 'The Z30 is Blackberry\'s biggest, baddest mobile messaging device yet.',
u'duration': 247, 'duration': 247,
}, },
u'params': { 'params': {
# rtmp download # rtmp download
u'skip_download': True, 'skip_download': True,
}, },
} }
@ -39,7 +41,7 @@ class ThePlatformIE(InfoExtractor):
error_msg = next( error_msg = next(
n.attrib['abstract'] n.attrib['abstract']
for n in meta.findall(_x('.//smil:ref')) for n in meta.findall(_x('.//smil:ref'))
if n.attrib.get('title') == u'Geographic Restriction') if n.attrib.get('title') == 'Geographic Restriction')
except StopIteration: except StopIteration:
pass pass
else: else:
@ -101,8 +103,7 @@ class ThePlatformIE(InfoExtractor):
config_url = url+ '&form=json' config_url = url+ '&form=json'
config_url = config_url.replace('swf/', 'config/') config_url = config_url.replace('swf/', 'config/')
config_url = config_url.replace('onsite/', 'onsite/config/') config_url = config_url.replace('onsite/', 'onsite/config/')
config_json = self._download_webpage(config_url, video_id, u'Downloading config') config = self._download_json(config_url, video_id, 'Downloading config')
config = json.loads(config_json)
smil_url = config['releaseUrl'] + '&format=SMIL&formats=MPEG4&manifest=f4m' smil_url = config['releaseUrl'] + '&format=SMIL&formats=MPEG4&manifest=f4m'
else: else:
smil_url = ('http://link.theplatform.com/s/dJ5BDC/{0}/meta.smil?' smil_url = ('http://link.theplatform.com/s/dJ5BDC/{0}/meta.smil?'

View File

@ -11,29 +11,36 @@ from ..utils import (
class UstreamIE(InfoExtractor): class UstreamIE(InfoExtractor):
_VALID_URL = r'https?://www\.ustream\.tv/(?P<type>recorded|embed)/(?P<videoID>\d+)' _VALID_URL = r'https?://www\.ustream\.tv/(?P<type>recorded|embed|embed/recorded)/(?P<videoID>\d+)'
IE_NAME = 'ustream' IE_NAME = 'ustream'
_TEST = { _TEST = {
'url': 'http://www.ustream.tv/recorded/20274954', 'url': 'http://www.ustream.tv/recorded/20274954',
'file': '20274954.flv',
'md5': '088f151799e8f572f84eb62f17d73e5c', 'md5': '088f151799e8f572f84eb62f17d73e5c',
'info_dict': { 'info_dict': {
"uploader": "Young Americans for Liberty", 'id': '20274954',
"title": "Young Americans for Liberty February 7, 2012 2:28 AM", 'ext': 'flv',
'uploader': 'Young Americans for Liberty',
'title': 'Young Americans for Liberty February 7, 2012 2:28 AM',
}, },
} }
def _real_extract(self, url): def _real_extract(self, url):
m = re.match(self._VALID_URL, url) m = re.match(self._VALID_URL, url)
video_id = m.group('videoID')
# some sites use this embed format (see: http://github.com/rg3/youtube-dl/issues/2990)
if m.group('type') == 'embed/recorded':
video_id = m.group('videoID')
desktop_url = 'http://www.ustream.tv/recorded/' + video_id
return self.url_result(desktop_url, 'Ustream')
if m.group('type') == 'embed': if m.group('type') == 'embed':
video_id = m.group('videoID') video_id = m.group('videoID')
webpage = self._download_webpage(url, video_id) webpage = self._download_webpage(url, video_id)
desktop_video_id = self._html_search_regex(r'ContentVideoIds=\["([^"]*?)"\]', webpage, 'desktop_video_id') desktop_video_id = self._html_search_regex(
r'ContentVideoIds=\["([^"]*?)"\]', webpage, 'desktop_video_id')
desktop_url = 'http://www.ustream.tv/recorded/' + desktop_video_id desktop_url = 'http://www.ustream.tv/recorded/' + desktop_video_id
return self.url_result(desktop_url, 'Ustream') return self.url_result(desktop_url, 'Ustream')
video_id = m.group('videoID')
video_url = 'http://tcdn.ustream.tv/video/%s' % video_id video_url = 'http://tcdn.ustream.tv/video/%s' % video_id
webpage = self._download_webpage(url, video_id) webpage = self._download_webpage(url, video_id)

View File

@ -1,2 +1,2 @@
__version__ = '2014.05.19' __version__ = '2014.05.30.1'