Compare commits
20 Commits
2013.09.06
...
2013.11.09
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1f7dc42cd0 | ||
![]() |
aa8f2641da | ||
![]() |
648d25d43d | ||
![]() |
df3e61003a | ||
![]() |
6b361ad5ee | ||
![]() |
5d8afe69f7 | ||
![]() |
a1ab553858 | ||
![]() |
07463ea162 | ||
![]() |
6d2d21f713 | ||
![]() |
061b2889a9 | ||
![]() |
8963d9c266 | ||
![]() |
890f62e868 | ||
![]() |
8f362589a5 | ||
![]() |
a27a2470cd | ||
![]() |
a7130543fa | ||
![]() |
a490fda746 | ||
![]() |
7e77275293 | ||
![]() |
e3ea479087 | ||
![]() |
faab1d3836 | ||
![]() |
8851a574a3 |
@@ -3,7 +3,8 @@
|
||||
import json
|
||||
import sys
|
||||
import hashlib
|
||||
import urllib.request
|
||||
import os.path
|
||||
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
print('Specify the version number as parameter')
|
||||
@@ -25,6 +26,7 @@ filenames = {
|
||||
'tar': 'youtube-dl-%s.tar.gz' % version}
|
||||
build_dir = os.path.join('..', '..', 'build', version)
|
||||
for key, filename in filenames.items():
|
||||
url = 'https://yt-dl.org/downloads/%s/%s' % (version, filename)
|
||||
fn = os.path.join(build_dir, filename)
|
||||
with open(fn, 'rb') as f:
|
||||
data = f.read()
|
||||
|
@@ -23,9 +23,9 @@ tests = [
|
||||
# 86 - vfluy6kdb 2013/09/06
|
||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[|};?/>.<",
|
||||
"yuioplkjhgfdsazxcvbnm12345678q0QWrRTYUIOELKJHGFD-AZXCVBNM!@#$%^&*()_<+={[|};?/>.S"),
|
||||
# 85
|
||||
# 85 - vflkuzxcs 2013/09/11
|
||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?/>.<",
|
||||
".>/?;}[{=+-_)(*&^%$#@!MNBVCXZASDFGHJKLPOIUYTREWQ0q876543r1mnbvcx9asdfghjklpoiuyt2"),
|
||||
"T>/?;}[{=+-_)(*&^%$#@!MNBVCXZASDFGHJKLPOvUY.REWQ0987654321mnbqcxzasdfghjklpoiuytr"),
|
||||
# 84 - vflg0g8PQ 2013/08/29 (sporadic)
|
||||
("qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?>.<",
|
||||
">?;}[{=+-_)(*&^%$#@!MNBVCXZASDFGHJKLPOIUYTREWq0987654321mnbvcxzasdfghjklpoiuytr"),
|
||||
|
@@ -21,14 +21,15 @@ class TestAllURLsMatching(unittest.TestCase):
|
||||
self.assertEqual(self.matching_ies(url), ie_list)
|
||||
|
||||
def test_youtube_playlist_matching(self):
|
||||
self.assertTrue(YoutubePlaylistIE.suitable(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8'))
|
||||
self.assertTrue(YoutubePlaylistIE.suitable(u'UUBABnxM4Ar9ten8Mdjj1j0Q')) #585
|
||||
self.assertTrue(YoutubePlaylistIE.suitable(u'PL63F0C78739B09958'))
|
||||
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q'))
|
||||
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8'))
|
||||
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC'))
|
||||
self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) #668
|
||||
self.assertFalse(YoutubePlaylistIE.suitable(u'PLtS2H6bU1M'))
|
||||
assertPlaylist = lambda url: self.assertMatch(url, ['youtube:playlist'])
|
||||
assertPlaylist(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||
assertPlaylist(u'UUBABnxM4Ar9ten8Mdjj1j0Q') #585
|
||||
assertPlaylist(u'PL63F0C78739B09958')
|
||||
assertPlaylist(u'https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')
|
||||
assertPlaylist(u'https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')
|
||||
assertPlaylist(u'https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')
|
||||
assertPlaylist(u'https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012') #668
|
||||
self.assertFalse('youtube:playlist' in self.matching_ies(u'PLtS2H6bU1M'))
|
||||
|
||||
def test_youtube_matching(self):
|
||||
self.assertTrue(YoutubeIE.suitable(u'PLtS2H6bU1M'))
|
||||
@@ -37,13 +38,23 @@ class TestAllURLsMatching(unittest.TestCase):
|
||||
self.assertMatch('http://www.youtube.com/v/BaW_jenozKc', ['youtube'])
|
||||
|
||||
def test_youtube_channel_matching(self):
|
||||
self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM'))
|
||||
self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM?feature=gb_ch_rec'))
|
||||
self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM/videos'))
|
||||
assertChannel = lambda url: self.assertMatch(url, ['youtube:channel'])
|
||||
assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM')
|
||||
assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM?feature=gb_ch_rec')
|
||||
assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM/videos')
|
||||
|
||||
def test_youtube_user_matching(self):
|
||||
self.assertMatch('www.youtube.com/NASAgovVideo/videos', ['youtube:user'])
|
||||
|
||||
def test_youtube_feeds(self):
|
||||
self.assertMatch('https://www.youtube.com/feed/watch_later', ['youtube:watch_later'])
|
||||
self.assertMatch('https://www.youtube.com/feed/subscriptions', ['youtube:subscriptions'])
|
||||
self.assertMatch('https://www.youtube.com/feed/recommended', ['youtube:recommended'])
|
||||
self.assertMatch('https://www.youtube.com/my_favorites', ['youtube:favorites'])
|
||||
|
||||
def test_youtube_show_matching(self):
|
||||
self.assertMatch('http://www.youtube.com/show/airdisasters', ['youtube:show'])
|
||||
|
||||
def test_justin_tv_channelid_matching(self):
|
||||
self.assertTrue(JustinTVIE.suitable(u"justin.tv/vanillatv"))
|
||||
self.assertTrue(JustinTVIE.suitable(u"twitch.tv/vanillatv"))
|
||||
@@ -61,10 +72,13 @@ class TestAllURLsMatching(unittest.TestCase):
|
||||
self.assertTrue(JustinTVIE.suitable(u"http://www.twitch.tv/tsm_theoddone/c/2349361"))
|
||||
|
||||
def test_youtube_extract(self):
|
||||
self.assertEqual(YoutubeIE()._extract_id('http://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||
self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch_popup?v=BaW_jenozKc'), 'BaW_jenozKc')
|
||||
assertExtractId = lambda url, id: self.assertEqual(YoutubeIE()._extract_id(url), id)
|
||||
assertExtractId('http://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('https://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('https://www.youtube.com/watch_popup?v=BaW_jenozKc', 'BaW_jenozKc')
|
||||
assertExtractId('http://www.youtube.com/watch?v=BaW_jenozKcsharePLED17F32AD9753930', 'BaW_jenozKc')
|
||||
assertExtractId('BaW_jenozKc', 'BaW_jenozKc')
|
||||
|
||||
def test_no_duplicates(self):
|
||||
ies = gen_extractors()
|
||||
|
@@ -66,7 +66,7 @@ class FileDownloader(object):
|
||||
@staticmethod
|
||||
def format_seconds(seconds):
|
||||
(mins, secs) = divmod(seconds, 60)
|
||||
(hours, eta_mins) = divmod(mins, 60)
|
||||
(hours, mins) = divmod(mins, 60)
|
||||
if hours > 99:
|
||||
return '--:--:--'
|
||||
if hours == 0:
|
||||
|
@@ -29,6 +29,10 @@ from .escapist import EscapistIE
|
||||
from .exfm import ExfmIE
|
||||
from .facebook import FacebookIE
|
||||
from .flickr import FlickrIE
|
||||
from .francetv import (
|
||||
PluzzIE,
|
||||
FranceTvInfoIE,
|
||||
)
|
||||
from .freesound import FreesoundIE
|
||||
from .funnyordie import FunnyOrDieIE
|
||||
from .gamespot import GameSpotIE
|
||||
@@ -52,6 +56,7 @@ from .keek import KeekIE
|
||||
from .liveleak import LiveLeakIE
|
||||
from .livestream import LivestreamIE
|
||||
from .metacafe import MetacafeIE
|
||||
from .metacritic import MetacriticIE
|
||||
from .mit import TechTVMITIE, MITIE
|
||||
from .mixcloud import MixcloudIE
|
||||
from .mtv import MTVIE
|
||||
@@ -74,6 +79,7 @@ from .roxwel import RoxwelIE
|
||||
from .rtlnow import RTLnowIE
|
||||
from .sina import SinaIE
|
||||
from .slashdot import SlashdotIE
|
||||
from .slideshare import SlideshareIE
|
||||
from .sohu import SohuIE
|
||||
from .soundcloud import SoundcloudIE, SoundcloudSetIE
|
||||
from .spiegel import SpiegelIE
|
||||
|
@@ -5,7 +5,7 @@ from .common import InfoExtractor
|
||||
|
||||
|
||||
class Canalc2IE(InfoExtractor):
|
||||
_IE_NAME = 'canalc2.tv'
|
||||
IE_NAME = 'canalc2.tv'
|
||||
_VALID_URL = r'http://.*?\.canalc2\.tv/video\.asp\?idVideo=(\d+)&voir=oui'
|
||||
|
||||
_TEST = {
|
||||
|
@@ -14,7 +14,7 @@ from ..utils import (
|
||||
class DailymotionIE(InfoExtractor):
|
||||
"""Information Extractor for Dailymotion"""
|
||||
|
||||
_VALID_URL = r'(?i)(?:https?://)?(?:www\.)?dailymotion\.[a-z]{2,3}/video/([^/]+)'
|
||||
_VALID_URL = r'(?i)(?:https?://)?(?:www\.)?dailymotion\.[a-z]{2,3}/(?:embed/)?video/([^/]+)'
|
||||
IE_NAME = u'dailymotion'
|
||||
_TEST = {
|
||||
u'url': u'http://www.dailymotion.com/video/x33vw9_tutoriel-de-youtubeur-dl-des-video_tech',
|
||||
@@ -33,6 +33,7 @@ class DailymotionIE(InfoExtractor):
|
||||
video_id = mobj.group(1).split('_')[0].split('?')[0]
|
||||
|
||||
video_extension = 'mp4'
|
||||
url = 'http://www.dailymotion.com/video/%s' % video_id
|
||||
|
||||
# Retrieve video webpage to extract further information
|
||||
request = compat_urllib_request.Request(url)
|
||||
|
77
youtube_dl/extractor/francetv.py
Normal file
77
youtube_dl/extractor/francetv.py
Normal file
@@ -0,0 +1,77 @@
|
||||
# encoding: utf-8
|
||||
import re
|
||||
import xml.etree.ElementTree
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
compat_urlparse,
|
||||
)
|
||||
|
||||
|
||||
class FranceTVBaseInfoExtractor(InfoExtractor):
|
||||
def _extract_video(self, video_id):
|
||||
xml_desc = self._download_webpage(
|
||||
'http://www.francetvinfo.fr/appftv/webservices/video/'
|
||||
'getInfosOeuvre.php?id-diffusion='
|
||||
+ video_id, video_id, 'Downloading XML config')
|
||||
info = xml.etree.ElementTree.fromstring(xml_desc.encode('utf-8'))
|
||||
|
||||
manifest_url = info.find('videos/video/url').text
|
||||
video_url = manifest_url.replace('manifest.f4m', 'index_2_av.m3u8')
|
||||
video_url = video_url.replace('/z/', '/i/')
|
||||
thumbnail_path = info.find('image').text
|
||||
|
||||
return {'id': video_id,
|
||||
'ext': 'mp4',
|
||||
'url': video_url,
|
||||
'title': info.find('titre').text,
|
||||
'thumbnail': compat_urlparse.urljoin('http://pluzz.francetv.fr', thumbnail_path),
|
||||
'description': info.find('synopsis').text,
|
||||
}
|
||||
|
||||
|
||||
class PluzzIE(FranceTVBaseInfoExtractor):
|
||||
IE_NAME = u'pluzz.francetv.fr'
|
||||
_VALID_URL = r'https?://pluzz\.francetv\.fr/videos/(.*?)\.html'
|
||||
|
||||
_TEST = {
|
||||
u'url': u'http://pluzz.francetv.fr/videos/allo_rufo_saison5_,88439064.html',
|
||||
u'file': u'88439064.mp4',
|
||||
u'info_dict': {
|
||||
u'title': u'Allô Rufo',
|
||||
u'description': u'md5:d909f1ebdf963814b65772aea250400e',
|
||||
},
|
||||
u'params': {
|
||||
u'skip_download': True,
|
||||
},
|
||||
}
|
||||
|
||||
def _real_extract(self, url):
|
||||
title = re.match(self._VALID_URL, url).group(1)
|
||||
webpage = self._download_webpage(url, title)
|
||||
video_id = self._search_regex(
|
||||
r'data-diffusion="(\d+)"', webpage, 'ID')
|
||||
return self._extract_video(video_id)
|
||||
|
||||
|
||||
class FranceTvInfoIE(FranceTVBaseInfoExtractor):
|
||||
IE_NAME = u'francetvinfo.fr'
|
||||
_VALID_URL = r'https?://www\.francetvinfo\.fr/replay.*/(?P<title>.+).html'
|
||||
|
||||
_TEST = {
|
||||
u'url': u'http://www.francetvinfo.fr/replay-jt/france-3/soir-3/jt-grand-soir-3-lundi-26-aout-2013_393427.html',
|
||||
u'file': u'84981923.mp4',
|
||||
u'info_dict': {
|
||||
u'title': u'Soir 3',
|
||||
},
|
||||
u'params': {
|
||||
u'skip_download': True,
|
||||
},
|
||||
}
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = re.match(self._VALID_URL, url)
|
||||
page_title = mobj.group('title')
|
||||
webpage = self._download_webpage(url, page_title)
|
||||
video_id = self._search_regex(r'id-video=(\d+?)"', webpage, u'video id')
|
||||
return self._extract_video(video_id)
|
@@ -109,6 +109,11 @@ class GenericIE(InfoExtractor):
|
||||
return new_url
|
||||
|
||||
def _real_extract(self, url):
|
||||
parsed_url = compat_urlparse.urlparse(url)
|
||||
if not parsed_url.scheme:
|
||||
self._downloader.report_warning('The url doesn\'t specify the protocol, trying with http')
|
||||
return self.url_result('http://' + url)
|
||||
|
||||
try:
|
||||
new_url = self._test_redirect(url)
|
||||
if new_url:
|
||||
|
55
youtube_dl/extractor/metacritic.py
Normal file
55
youtube_dl/extractor/metacritic.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import re
|
||||
import xml.etree.ElementTree
|
||||
import operator
|
||||
|
||||
from .common import InfoExtractor
|
||||
|
||||
|
||||
class MetacriticIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://www\.metacritic\.com/.+?/trailers/(?P<id>\d+)'
|
||||
|
||||
_TEST = {
|
||||
u'url': u'http://www.metacritic.com/game/playstation-4/infamous-second-son/trailers/3698222',
|
||||
u'file': u'3698222.mp4',
|
||||
u'info_dict': {
|
||||
u'title': u'inFamous: Second Son - inSide Sucker Punch: Smoke & Mirrors',
|
||||
u'description': u'Take a peak behind-the-scenes to see how Sucker Punch brings smoke into the universe of inFAMOUS Second Son on the PS4.',
|
||||
u'duration': 221,
|
||||
},
|
||||
}
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = re.match(self._VALID_URL, url)
|
||||
video_id = mobj.group('id')
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
# The xml is not well formatted, there are raw '&'
|
||||
info_xml = self._download_webpage('http://www.metacritic.com/video_data?video=' + video_id,
|
||||
video_id, u'Downloading info xml').replace('&', '&')
|
||||
info = xml.etree.ElementTree.fromstring(info_xml.encode('utf-8'))
|
||||
|
||||
clip = next(c for c in info.findall('playList/clip') if c.find('id').text == video_id)
|
||||
formats = []
|
||||
for videoFile in clip.findall('httpURI/videoFile'):
|
||||
rate_str = videoFile.find('rate').text
|
||||
video_url = videoFile.find('filePath').text
|
||||
formats.append({
|
||||
'url': video_url,
|
||||
'ext': 'mp4',
|
||||
'format_id': rate_str,
|
||||
'rate': int(rate_str),
|
||||
})
|
||||
formats.sort(key=operator.itemgetter('rate'))
|
||||
|
||||
description = self._html_search_regex(r'<b>Description:</b>(.*?)</p>',
|
||||
webpage, u'description', flags=re.DOTALL)
|
||||
|
||||
info = {
|
||||
'id': video_id,
|
||||
'title': clip.find('title').text,
|
||||
'formats': formats,
|
||||
'description': description,
|
||||
'duration': int(clip.find('duration').text),
|
||||
}
|
||||
# TODO: Remove when #980 has been merged
|
||||
info.update(formats[-1])
|
||||
return info
|
47
youtube_dl/extractor/slideshare.py
Normal file
47
youtube_dl/extractor/slideshare.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import re
|
||||
import json
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
compat_urlparse,
|
||||
ExtractorError,
|
||||
)
|
||||
|
||||
|
||||
class SlideshareIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://www\.slideshare\.net/[^/]+?/(?P<title>.+?)($|\?)'
|
||||
|
||||
_TEST = {
|
||||
u'url': u'http://www.slideshare.net/Dataversity/keynote-presentation-managing-scale-and-complexity',
|
||||
u'file': u'25665706.mp4',
|
||||
u'info_dict': {
|
||||
u'title': u'Managing Scale and Complexity',
|
||||
u'description': u'This was a keynote presentation at the NoSQL Now! 2013 Conference & Expo (http://www.nosqlnow.com). This presentation was given by Adrian Cockcroft from Netflix',
|
||||
},
|
||||
}
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = re.match(self._VALID_URL, url)
|
||||
page_title = mobj.group('title')
|
||||
webpage = self._download_webpage(url, page_title)
|
||||
slideshare_obj = self._search_regex(
|
||||
r'var slideshare_object = ({.*?}); var user_info =',
|
||||
webpage, u'slideshare object')
|
||||
info = json.loads(slideshare_obj)
|
||||
if info['slideshow']['type'] != u'video':
|
||||
raise ExtractorError(u'Webpage type is "%s": only video extraction is supported for Slideshare' % info['slideshow']['type'], expected=True)
|
||||
|
||||
doc = info['doc']
|
||||
bucket = info['jsplayer']['video_bucket']
|
||||
ext = info['jsplayer']['video_extension']
|
||||
video_url = compat_urlparse.urljoin(bucket, doc + '-SD.' + ext)
|
||||
|
||||
return {
|
||||
'_type': 'video',
|
||||
'id': info['slideshow']['id'],
|
||||
'title': info['slideshow']['title'],
|
||||
'ext': ext,
|
||||
'url': video_url,
|
||||
'thumbnail': info['slideshow']['pin_image_url'],
|
||||
'description': self._og_search_description(webpage),
|
||||
}
|
@@ -8,7 +8,7 @@ from ..utils import ExtractorError
|
||||
|
||||
|
||||
class SohuIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://tv\.sohu\.com/\d+?/n(?P<id>\d+)\.shtml.*?'
|
||||
_VALID_URL = r'https?://(?P<mytv>my\.)?tv\.sohu\.com/.+?/(?(mytv)|n)(?P<id>\d+)\.shtml.*?'
|
||||
|
||||
_TEST = {
|
||||
u'url': u'http://tv.sohu.com/20130724/n382479172.shtml#super',
|
||||
@@ -21,8 +21,11 @@ class SohuIE(InfoExtractor):
|
||||
|
||||
def _real_extract(self, url):
|
||||
|
||||
def _fetch_data(vid_id):
|
||||
base_data_url = u'http://hot.vrs.sohu.com/vrs_flash.action?vid='
|
||||
def _fetch_data(vid_id, mytv=False):
|
||||
if mytv:
|
||||
base_data_url = 'http://my.tv.sohu.com/play/videonew.do?vid='
|
||||
else:
|
||||
base_data_url = u'http://hot.vrs.sohu.com/vrs_flash.action?vid='
|
||||
data_url = base_data_url + str(vid_id)
|
||||
data_json = self._download_webpage(
|
||||
data_url, video_id,
|
||||
@@ -31,15 +34,16 @@ class SohuIE(InfoExtractor):
|
||||
|
||||
mobj = re.match(self._VALID_URL, url)
|
||||
video_id = mobj.group('id')
|
||||
mytv = mobj.group('mytv') is not None
|
||||
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
raw_title = self._html_search_regex(r'(?s)<title>(.+?)</title>',
|
||||
webpage, u'video title')
|
||||
title = raw_title.partition('-')[0].strip()
|
||||
|
||||
vid = self._html_search_regex(r'var vid="(\d+)"', webpage,
|
||||
vid = self._html_search_regex(r'var vid ?= ?["\'](\d+)["\']', webpage,
|
||||
u'video path')
|
||||
data = _fetch_data(vid)
|
||||
data = _fetch_data(vid, mytv)
|
||||
|
||||
QUALITIES = ('ori', 'super', 'high', 'nor')
|
||||
vid_ids = [data['data'][q + 'Vid']
|
||||
@@ -51,7 +55,7 @@ class SohuIE(InfoExtractor):
|
||||
# For now, we just pick the highest available quality
|
||||
vid_id = vid_ids[-1]
|
||||
|
||||
format_data = data if vid == vid_id else _fetch_data(vid_id)
|
||||
format_data = data if vid == vid_id else _fetch_data(vid_id, mytv)
|
||||
part_count = format_data['data']['totalBlocks']
|
||||
allot = format_data['allot']
|
||||
prot = format_data['prot']
|
||||
|
@@ -150,7 +150,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
||||
|youtu\.be/ # just youtu.be/xxxx
|
||||
)
|
||||
)? # all until now is optional -> you can pass the naked ID
|
||||
([0-9A-Za-z_-]+) # here is it! the YouTube video ID
|
||||
([0-9A-Za-z_-]{11}) # here is it! the YouTube video ID
|
||||
(?(1).+)? # if we found the ID, everything can follow
|
||||
$"""
|
||||
_NEXT_URL_RE = r'[\?&]next_url=([^&]+)'
|
||||
@@ -386,7 +386,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
||||
@classmethod
|
||||
def suitable(cls, url):
|
||||
"""Receives a URL and returns True if suitable for this IE."""
|
||||
if YoutubePlaylistIE.suitable(url) or YoutubeSubscriptionsIE.suitable(url): return False
|
||||
if YoutubePlaylistIE.suitable(url): return False
|
||||
return re.match(cls._VALID_URL, url, re.VERBOSE) is not None
|
||||
|
||||
def report_video_webpage_download(self, video_id):
|
||||
@@ -438,7 +438,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
||||
elif len(s) == 86:
|
||||
return s[5:34] + s[0] + s[35:38] + s[3] + s[39:45] + s[38] + s[46:53] + s[73] + s[54:73] + s[85] + s[74:85] + s[53]
|
||||
elif len(s) == 85:
|
||||
return s[83:34:-1] + s[0] + s[33:27:-1] + s[3] + s[26:19:-1] + s[34] + s[18:3:-1] + s[27]
|
||||
return s[40] + s[82:43:-1] + s[22] + s[42:40:-1] + s[83] + s[39:22:-1] + s[0] + s[21:2:-1]
|
||||
elif len(s) == 84:
|
||||
return s[81:36:-1] + s[0] + s[35:2:-1]
|
||||
elif len(s) == 83:
|
||||
@@ -643,7 +643,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
||||
manifest = self._download_webpage(manifest_url, video_id, u'Downloading formats manifest')
|
||||
formats_urls = _get_urls(manifest)
|
||||
for format_url in formats_urls:
|
||||
itag = self._search_regex(r'itag%3D(\d+?)/', format_url, 'itag')
|
||||
itag = self._search_regex(r'itag/(\d+?)/', format_url, 'itag')
|
||||
url_map[itag] = format_url
|
||||
return url_map
|
||||
|
||||
@@ -1015,14 +1015,18 @@ class YoutubeChannelIE(InfoExtractor):
|
||||
|
||||
class YoutubeUserIE(InfoExtractor):
|
||||
IE_DESC = u'YouTube.com user videos (URL or "ytuser" keyword)'
|
||||
_VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?youtube\.com/(?:user/)?)|ytuser:)([A-Za-z0-9_-]+)'
|
||||
_VALID_URL = r'(?:(?:(?:https?://)?(?:\w+\.)?youtube\.com/(?:user/)?)|ytuser:)(?!feed/)([A-Za-z0-9_-]+)'
|
||||
_TEMPLATE_URL = 'http://gdata.youtube.com/feeds/api/users/%s'
|
||||
_GDATA_PAGE_SIZE = 50
|
||||
_GDATA_URL = 'http://gdata.youtube.com/feeds/api/users/%s/uploads?max-results=%d&start-index=%d&alt=json'
|
||||
IE_NAME = u'youtube:user'
|
||||
|
||||
@classmethod
|
||||
def suitable(cls, url):
|
||||
if YoutubeIE.suitable(url): return False
|
||||
# Don't return True if the url can be extracted with other youtube
|
||||
# extractor, the regex would is too permissive and it would match.
|
||||
other_ies = iter(klass for (name, klass) in globals().items() if name.endswith('IE') and klass is not cls)
|
||||
if any(ie.suitable(url) for ie in other_ies): return False
|
||||
else: return super(YoutubeUserIE, cls).suitable(url)
|
||||
|
||||
def _real_extract(self, url):
|
||||
|
@@ -1,2 +1,2 @@
|
||||
|
||||
__version__ = '2013.09.06.1'
|
||||
__version__ = '2013.11.09'
|
||||
|
Reference in New Issue
Block a user