Merge remote-tracking branch 'origin/master'

Conflicts:
	youtube_dl/YoutubeDL.py
This commit is contained in:
Philipp Hagemeister 2013-10-22 22:30:06 +02:00
commit 7853cc5ae1
10 changed files with 162 additions and 102 deletions

View File

@ -94,6 +94,40 @@ def test_format_limit(self):
downloaded = ydl.downloaded_info_dicts[0] downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded[u'format_id'], u'excellent') self.assertEqual(downloaded[u'format_id'], u'excellent')
def test_format_selection(self):
formats = [
{u'format_id': u'35', u'ext': u'mp4'},
{u'format_id': u'45', u'ext': u'webm'},
{u'format_id': u'47', u'ext': u'webm'},
{u'format_id': u'2', u'ext': u'flv'},
]
info_dict = {u'formats': formats, u'extractor': u'test'}
ydl = YDL({'format': u'20/47'})
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], u'47')
ydl = YDL({'format': u'20/71/worst'})
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], u'35')
ydl = YDL()
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], u'2')
ydl = YDL({'format': u'webm/mp4'})
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], u'47')
ydl = YDL({'format': u'3gp/40/mp4'})
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], u'35')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -91,7 +91,7 @@ class YoutubeDL(object):
downloadarchive: File name of a file where all downloads are recorded. downloadarchive: File name of a file where all downloads are recorded.
Videos already present in the file are not downloaded Videos already present in the file are not downloaded
again. again.
The following parameters are not used by YoutubeDL itself, they are used by The following parameters are not used by YoutubeDL itself, they are used by
the FileDownloader: the FileDownloader:
nopart, updatetime, buffersize, ratelimit, min_filesize, max_filesize, test, nopart, updatetime, buffersize, ratelimit, min_filesize, max_filesize, test,
@ -216,10 +216,10 @@ def report_warning(self, message):
If stderr is a tty file the 'WARNING:' will be colored If stderr is a tty file the 'WARNING:' will be colored
''' '''
if sys.stderr.isatty() and os.name != 'nt': if sys.stderr.isatty() and os.name != 'nt':
_msg_header=u'\033[0;33mWARNING:\033[0m' _msg_header = u'\033[0;33mWARNING:\033[0m'
else: else:
_msg_header=u'WARNING:' _msg_header = u'WARNING:'
warning_message=u'%s %s' % (_msg_header,message) warning_message = u'%s %s' % (_msg_header, message)
self.to_stderr(warning_message) self.to_stderr(warning_message)
def report_error(self, message, tb=None): def report_error(self, message, tb=None):
@ -234,19 +234,6 @@ def report_error(self, message, tb=None):
error_message = u'%s %s' % (_msg_header, message) error_message = u'%s %s' % (_msg_header, message)
self.trouble(error_message, tb) self.trouble(error_message, tb)
def slow_down(self, start_time, byte_counter):
"""Sleep if the download speed is over the rate limit."""
rate_limit = self.params.get('ratelimit', None)
if rate_limit is None or byte_counter == 0:
return
now = time.time()
elapsed = now - start_time
if elapsed <= 0.0:
return
speed = float(byte_counter) / elapsed
if speed > rate_limit:
time.sleep((byte_counter - rate_limit * (now - start_time)) / rate_limit)
def report_writedescription(self, descfn): def report_writedescription(self, descfn):
""" Report that the description file is being written """ """ Report that the description file is being written """
self.to_screen(u'[info] Writing video description to: ' + descfn) self.to_screen(u'[info] Writing video description to: ' + descfn)
@ -330,14 +317,14 @@ def _match_entry(self, info_dict):
return (u'%(title)s has already been recorded in archive' return (u'%(title)s has already been recorded in archive'
% info_dict) % info_dict)
return None return None
def extract_info(self, url, download=True, ie_key=None, extra_info={}): def extract_info(self, url, download=True, ie_key=None, extra_info={}):
''' '''
Returns a list with a dictionary for each video we find. Returns a list with a dictionary for each video we find.
If 'download', also downloads the videos. If 'download', also downloads the videos.
extra_info is a dict containing the extra values to add to each result extra_info is a dict containing the extra values to add to each result
''' '''
if ie_key: if ie_key:
ies = [self.get_info_extractor(ie_key)] ies = [self.get_info_extractor(ie_key)]
else: else:
@ -379,7 +366,7 @@ def extract_info(self, url, download=True, ie_key=None, extra_info={}):
raise raise
else: else:
self.report_error(u'no suitable InfoExtractor: %s' % url) self.report_error(u'no suitable InfoExtractor: %s' % url)
def process_ie_result(self, ie_result, download=True, extra_info={}): def process_ie_result(self, ie_result, download=True, extra_info={}):
""" """
Take the result of the ie(may be modified) and resolve all unresolved Take the result of the ie(may be modified) and resolve all unresolved
@ -403,7 +390,7 @@ def process_ie_result(self, ie_result, download=True, extra_info={}):
elif result_type == 'playlist': elif result_type == 'playlist':
# We process each entry in the playlist # We process each entry in the playlist
playlist = ie_result.get('title', None) or ie_result.get('id', None) playlist = ie_result.get('title', None) or ie_result.get('id', None)
self.to_screen(u'[download] Downloading playlist: %s' % playlist) self.to_screen(u'[download] Downloading playlist: %s' % playlist)
playlist_results = [] playlist_results = []
@ -421,12 +408,12 @@ def process_ie_result(self, ie_result, download=True, extra_info={}):
self.to_screen(u"[%s] playlist '%s': Collected %d video ids (downloading %d of them)" % self.to_screen(u"[%s] playlist '%s': Collected %d video ids (downloading %d of them)" %
(ie_result['extractor'], playlist, n_all_entries, n_entries)) (ie_result['extractor'], playlist, n_all_entries, n_entries))
for i,entry in enumerate(entries,1): for i, entry in enumerate(entries, 1):
self.to_screen(u'[download] Downloading video #%s of %s' %(i, n_entries)) self.to_screen(u'[download] Downloading video #%s of %s' % (i, n_entries))
extra = { extra = {
'playlist': playlist, 'playlist': playlist,
'playlist_index': i + playliststart, 'playlist_index': i + playliststart,
} }
if not 'extractor' in entry: if not 'extractor' in entry:
# We set the extractor, if it's an url it will be set then to # We set the extractor, if it's an url it will be set then to
# the new extractor, but if it's already a video we must make # the new extractor, but if it's already a video we must make
@ -450,6 +437,22 @@ def _fixup(r):
else: else:
raise Exception('Invalid result type: %s' % result_type) raise Exception('Invalid result type: %s' % result_type)
def select_format(self, format_spec, available_formats):
if format_spec == 'best' or format_spec is None:
return available_formats[-1]
elif format_spec == 'worst':
return available_formats[0]
else:
extensions = [u'mp4', u'flv', u'webm', u'3gp']
if format_spec in extensions:
filter_f = lambda f: f['ext'] == format_spec
else:
filter_f = lambda f: f['format_id'] == format_spec
matches = list(filter(filter_f, available_formats))
if matches:
return matches[-1]
return None
def process_video_result(self, info_dict, download=True): def process_video_result(self, info_dict, download=True):
assert info_dict.get('_type', 'video') == 'video' assert info_dict.get('_type', 'video') == 'video'
@ -460,7 +463,8 @@ def process_video_result(self, info_dict, download=True):
# This extractors handle format selection themselves # This extractors handle format selection themselves
if info_dict['extractor'] in [u'youtube', u'Youku', u'YouPorn', u'mixcloud']: if info_dict['extractor'] in [u'youtube', u'Youku', u'YouPorn', u'mixcloud']:
self.process_info(info_dict) if download:
self.process_info(info_dict)
return info_dict return info_dict
# We now pick which formats have to be downloaded # We now pick which formats have to be downloaded
@ -472,17 +476,14 @@ def process_video_result(self, info_dict, download=True):
# We check that all the formats have the format and format_id fields # We check that all the formats have the format and format_id fields
for (i, format) in enumerate(formats): for (i, format) in enumerate(formats):
if format.get('format') is None:
if format.get('height') is not None:
if format.get('width') is not None:
format_desc = u'%sx%s' % (format['width'], format['height'])
else:
format_desc = u'%sp' % format['height']
else:
format_desc = '???'
format['format'] = format_desc
if format.get('format_id') is None: if format.get('format_id') is None:
format['format_id'] = compat_str(i) format['format_id'] = compat_str(i)
if format.get('format') is None:
format['format'] = u'{id} - {res}{note}'.format(
id=format['format_id'],
res=self.format_resolution(format),
note=u' ({})'.format(format['format_note']) if format.get('format_note') is not None else '',
)
if self.params.get('listformats', None): if self.params.get('listformats', None):
self.list_formats(info_dict) self.list_formats(info_dict)
@ -504,22 +505,20 @@ def _free_formats_key(f):
formats = sorted(formats, key=_free_formats_key) formats = sorted(formats, key=_free_formats_key)
req_format = self.params.get('format', 'best') req_format = self.params.get('format', 'best')
if req_format is None:
req_format = 'best'
formats_to_download = [] formats_to_download = []
if req_format == 'best' or req_format is None:
formats_to_download = [formats[-1]]
elif req_format == 'worst':
formats_to_download = [formats[0]]
# The -1 is for supporting YoutubeIE # The -1 is for supporting YoutubeIE
elif req_format in ('-1', 'all'): if req_format in ('-1', 'all'):
formats_to_download = formats formats_to_download = formats
else: else:
# We can accept formats requestd in the format: 34/10/5, we pick # We can accept formats requestd in the format: 34/5/best, we pick
# the first that is available, starting from left # the first that is available, starting from left
req_formats = req_format.split('/') req_formats = req_format.split('/')
for rf in req_formats: for rf in req_formats:
matches = filter(lambda f:f['format_id'] == rf ,formats) selected_format = self.select_format(rf, formats)
if matches: if selected_format is not None:
formats_to_download = [matches[0]] formats_to_download = [selected_format]
break break
if not formats_to_download: if not formats_to_download:
raise ExtractorError(u'requested format not available') raise ExtractorError(u'requested format not available')
@ -610,20 +609,20 @@ def process_info(self, info_dict):
if self.params.get('writeannotations', False): if self.params.get('writeannotations', False):
try: try:
annofn = filename + u'.annotations.xml' annofn = filename + u'.annotations.xml'
self.report_writeannotations(annofn) self.report_writeannotations(annofn)
with io.open(encodeFilename(annofn), 'w', encoding='utf-8') as annofile: with io.open(encodeFilename(annofn), 'w', encoding='utf-8') as annofile:
annofile.write(info_dict['annotations']) annofile.write(info_dict['annotations'])
except (KeyError, TypeError): except (KeyError, TypeError):
self.report_warning(u'There are no annotations to write.') self.report_warning(u'There are no annotations to write.')
except (OSError, IOError): except (OSError, IOError):
self.report_error(u'Cannot write annotations file: ' + annofn) self.report_error(u'Cannot write annotations file: ' + annofn)
return return
subtitles_are_requested = any([self.params.get('writesubtitles', False), subtitles_are_requested = any([self.params.get('writesubtitles', False),
self.params.get('writeautomaticsub')]) self.params.get('writeautomaticsub')])
if subtitles_are_requested and 'subtitles' in info_dict and info_dict['subtitles']: if subtitles_are_requested and 'subtitles' in info_dict and info_dict['subtitles']:
# subtitles download errors are already managed as troubles in relevant IE # subtitles download errors are already managed as troubles in relevant IE
# that way it will silently go on when used with unsupporting IE # that way it will silently go on when used with unsupporting IE
subtitles = info_dict['subtitles'] subtitles = info_dict['subtitles']
@ -645,7 +644,7 @@ def process_info(self, info_dict):
infofn = filename + u'.info.json' infofn = filename + u'.info.json'
self.report_writeinfojson(infofn) self.report_writeinfojson(infofn)
try: try:
json_info_dict = dict((k, v) for k,v in info_dict.items() if not k in ['urlhandle']) json_info_dict = dict((k, v) for k, v in info_dict.items() if not k in ['urlhandle'])
write_json_file(json_info_dict, encodeFilename(infofn)) write_json_file(json_info_dict, encodeFilename(infofn))
except (OSError, IOError): except (OSError, IOError):
self.report_error(u'Cannot write metadata to JSON file ' + infofn) self.report_error(u'Cannot write metadata to JSON file ' + infofn)
@ -715,7 +714,7 @@ def post_process(self, filename, ie_info):
keep_video = None keep_video = None
for pp in self._pps: for pp in self._pps:
try: try:
keep_video_wish,new_info = pp.run(info) keep_video_wish, new_info = pp.run(info)
if keep_video_wish is not None: if keep_video_wish is not None:
if keep_video_wish: if keep_video_wish:
keep_video = keep_video_wish keep_video = keep_video_wish
@ -754,16 +753,31 @@ def record_download_archive(self, info_dict):
with locked_file(fn, 'a', encoding='utf-8') as archive_file: with locked_file(fn, 'a', encoding='utf-8') as archive_file:
archive_file.write(vid_id + u'\n') archive_file.write(vid_id + u'\n')
@staticmethod
def format_resolution(format):
if format.get('height') is not None:
if format.get('width') is not None:
res = u'%sx%s' % (format['width'], format['height'])
else:
res = u'%sp' % format['height']
else:
res = '???'
return res
def list_formats(self, info_dict): def list_formats(self, info_dict):
formats_s = [] formats_s = []
for format in info_dict.get('formats', [info_dict]): for format in info_dict.get('formats', [info_dict]):
formats_s.append("%s\t:\t%s\t[%s]" % (format['format_id'], formats_s.append(u'%-15s: %-5s %-15s[%s]' % (
format['ext'], format['format_id'],
format.get('format', '???'), format['ext'],
) format.get('format_note') or '-',
) self.format_resolution(format),
)
)
if len(formats_s) != 1: if len(formats_s) != 1:
formats_s[0] += ' (worst)' formats_s[0] += ' (worst)'
formats_s[-1] += ' (best)' formats_s[-1] += ' (best)'
formats_s = "\n".join(formats_s) formats_s = "\n".join(formats_s)
self.to_screen(u"[info] Available formats for %s:\nformat code\textension\n%s" % (info_dict['id'], formats_s)) self.to_screen(u'[info] Available formats for %s:\n'
u'format code extension note resolution\n%s' % (
info_dict['id'], formats_s))

View File

@ -174,12 +174,27 @@ def _match_lang(f):
# Some formats use the m3u8 protocol # Some formats use the m3u8 protocol
formats = filter(lambda f: f.get('videoFormat') != 'M3U8', formats) formats = filter(lambda f: f.get('videoFormat') != 'M3U8', formats)
# We order the formats by quality # We order the formats by quality
formats = sorted(formats, key=lambda f: int(f.get('height',-1))) formats = list(formats) # in python3 filter returns an iterator
if re.match(r'[A-Z]Q', formats[0]['quality']) is not None:
sort_key = lambda f: ['HQ', 'MQ', 'EQ', 'SQ'].index(f['quality'])
else:
sort_key = lambda f: int(f.get('height',-1))
formats = sorted(formats, key=sort_key)
# Prefer videos without subtitles in the same language # Prefer videos without subtitles in the same language
formats = sorted(formats, key=lambda f: re.match(r'VO(F|A)-STM\1', f.get('versionCode', '')) is None) formats = sorted(formats, key=lambda f: re.match(r'VO(F|A)-STM\1', f.get('versionCode', '')) is None)
# Pick the best quality # Pick the best quality
def _format(format_info): def _format(format_info):
quality = format_info['quality']
m_quality = re.match(r'\w*? - (\d*)p', quality)
if m_quality is not None:
quality = m_quality.group(1)
if format_info.get('versionCode') is not None:
format_id = u'%s-%s' % (quality, format_info['versionCode'])
else:
format_id = quality
info = { info = {
'format_id': format_id,
'format_note': format_info.get('versionLibelle'),
'width': format_info.get('width'), 'width': format_info.get('width'),
'height': format_info.get('height'), 'height': format_info.get('height'),
} }
@ -192,8 +207,6 @@ def _format(format_info):
info['ext'] = determine_ext(info['url']) info['ext'] = determine_ext(info['url'])
return info return info
info_dict['formats'] = [_format(f) for f in formats] info_dict['formats'] = [_format(f) for f in formats]
# TODO: Remove when #980 has been merged
info_dict.update(info_dict['formats'][-1])
return info_dict return info_dict
@ -207,7 +220,7 @@ class ArteTVCreativeIE(ArteTVPlus7IE):
u'url': u'http://creative.arte.tv/de/magazin/agentur-amateur-corporate-design', u'url': u'http://creative.arte.tv/de/magazin/agentur-amateur-corporate-design',
u'file': u'050489-002.mp4', u'file': u'050489-002.mp4',
u'info_dict': { u'info_dict': {
u'title': u'Agentur Amateur #2 - Corporate Design', u'title': u'Agentur Amateur / Agence Amateur #2 : Corporate Design',
}, },
} }

View File

@ -61,9 +61,12 @@ class InfoExtractor(object):
* ext Will be calculated from url if missing * ext Will be calculated from url if missing
* format A human-readable description of the format * format A human-readable description of the format
("mp4 container with h264/opus"). ("mp4 container with h264/opus").
Calculated from width and height if missing. Calculated from the format_id, width, height
and format_note fields if missing.
* format_id A short description of the format * format_id A short description of the format
("mp4_h264_opus" or "19") ("mp4_h264_opus" or "19")
* format_note Additional info about the format
("3D" or "DASH video")
* width Width of the video, if known * width Width of the video, if known
* height Height of the video, if known * height Height of the video, if known

View File

@ -41,9 +41,9 @@ def _real_extract(self, url):
# Extract update date # Extract update date
upload_date = self._html_search_regex( upload_date = self._html_search_regex(
r'''(?x)<a.+?class="o-T-s\s[^"]+"\s+style="display:\s*none"\s*> r'''(?x)<a.+?class="o-U-s\s[^"]+"\s+style="display:\s*none"\s*>
([0-9]{4}-[0-9]{2}-[0-9]{2})</a>''', ([0-9]{4}-[0-9]{2}-[0-9]{2})</a>''',
webpage, u'upload date', fatal=False) webpage, u'upload date', fatal=False, flags=re.VERBOSE)
if upload_date: if upload_date:
# Convert timestring to a format suitable for filename # Convert timestring to a format suitable for filename
upload_date = datetime.datetime.strptime(upload_date, "%Y-%m-%d") upload_date = datetime.datetime.strptime(upload_date, "%Y-%m-%d")

View File

@ -19,7 +19,7 @@ class InternetVideoArchiveIE(InfoExtractor):
u'info_dict': { u'info_dict': {
u'title': u'SKYFALL', u'title': u'SKYFALL',
u'description': u'In SKYFALL, Bond\'s loyalty to M is tested as her past comes back to haunt her. As MI6 comes under attack, 007 must track down and destroy the threat, no matter how personal the cost.', u'description': u'In SKYFALL, Bond\'s loyalty to M is tested as her past comes back to haunt her. As MI6 comes under attack, 007 must track down and destroy the threat, no matter how personal the cost.',
u'duration': 156, u'duration': 153,
}, },
} }
@ -74,7 +74,7 @@ def _bp(p):
}) })
formats = sorted(formats, key=lambda f: f['bitrate']) formats = sorted(formats, key=lambda f: f['bitrate'])
info = { return {
'id': video_id, 'id': video_id,
'title': item.find('title').text, 'title': item.find('title').text,
'formats': formats, 'formats': formats,
@ -82,6 +82,3 @@ def _bp(p):
'description': item.find('description').text, 'description': item.find('description').text,
'duration': int(attr['duration']), 'duration': int(attr['duration']),
} }
# TODO: Remove when #980 has been merged
info.update(formats[-1])
return info

View File

@ -90,8 +90,8 @@ def _real_extract(self, url):
r'{statusIndex:0,index:0,.*?id:(.*?),'], r'{statusIndex:0,index:0,.*?id:(.*?),'],
webpage, u'category id') webpage, u'category id')
playlist_title = self._html_search_regex( playlist_title = self._html_search_regex(
r'\?catid=%s">(.*?)</a>' % cat_id, r'tab0"[^>]*?>(.*?)</td>',
webpage, u'playlist title', flags=re.DOTALL) webpage, u'playlist title', flags=re.DOTALL).lower().capitalize()
data = compat_urllib_parse.urlencode({ data = compat_urllib_parse.urlencode({
'cid': cat_id, 'cid': cat_id,

View File

@ -16,7 +16,7 @@ class VideoDetectiveIE(InfoExtractor):
u'info_dict': { u'info_dict': {
u'title': u'KICK-ASS 2', u'title': u'KICK-ASS 2',
u'description': u'md5:65ba37ad619165afac7d432eaded6013', u'description': u'md5:65ba37ad619165afac7d432eaded6013',
u'duration': 138, u'duration': 135,
}, },
} }

View File

@ -179,46 +179,45 @@ def _real_extract(self, url, new_video=True):
# Vimeo specific: extract video codec and quality information # Vimeo specific: extract video codec and quality information
# First consider quality, then codecs, then take everything # First consider quality, then codecs, then take everything
# TODO bind to format param codecs = [('vp6', 'flv'), ('vp8', 'flv'), ('h264', 'mp4')]
codecs = [('h264', 'mp4'), ('vp8', 'flv'), ('vp6', 'flv')]
files = { 'hd': [], 'sd': [], 'other': []} files = { 'hd': [], 'sd': [], 'other': []}
config_files = config["video"].get("files") or config["request"].get("files") config_files = config["video"].get("files") or config["request"].get("files")
for codec_name, codec_extension in codecs: for codec_name, codec_extension in codecs:
if codec_name in config_files: for quality in config_files.get(codec_name, []):
if 'hd' in config_files[codec_name]: format_id = '-'.join((codec_name, quality)).lower()
files['hd'].append((codec_name, codec_extension, 'hd')) key = quality if quality in files else 'other'
elif 'sd' in config_files[codec_name]: video_url = None
files['sd'].append((codec_name, codec_extension, 'sd')) if isinstance(config_files[codec_name], dict):
file_info = config_files[codec_name][quality]
video_url = file_info.get('url')
else: else:
files['other'].append((codec_name, codec_extension, config_files[codec_name][0])) file_info = {}
if video_url is None:
video_url = "http://player.vimeo.com/play_redirect?clip_id=%s&sig=%s&time=%s&quality=%s&codecs=%s&type=moogaloop_local&embed_location=" \
%(video_id, sig, timestamp, quality, codec_name.upper())
for quality in ('hd', 'sd', 'other'): files[key].append({
if len(files[quality]) > 0: 'ext': codec_extension,
video_quality = files[quality][0][2] 'url': video_url,
video_codec = files[quality][0][0] 'format_id': format_id,
video_extension = files[quality][0][1] 'width': file_info.get('width'),
self.to_screen(u'%s: Downloading %s file at %s quality' % (video_id, video_codec.upper(), video_quality)) 'height': file_info.get('height'),
break })
else: formats = []
for key in ('other', 'sd', 'hd'):
formats += files[key]
if len(formats) == 0:
raise ExtractorError(u'No known codec found') raise ExtractorError(u'No known codec found')
video_url = None
if isinstance(config_files[video_codec], dict):
video_url = config_files[video_codec][video_quality].get("url")
if video_url is None:
video_url = "http://player.vimeo.com/play_redirect?clip_id=%s&sig=%s&time=%s&quality=%s&codecs=%s&type=moogaloop_local&embed_location=" \
%(video_id, sig, timestamp, video_quality, video_codec.upper())
return [{ return [{
'id': video_id, 'id': video_id,
'url': video_url,
'uploader': video_uploader, 'uploader': video_uploader,
'uploader_id': video_uploader_id, 'uploader_id': video_uploader_id,
'upload_date': video_upload_date, 'upload_date': video_upload_date,
'title': video_title, 'title': video_title,
'ext': video_extension,
'thumbnail': video_thumbnail, 'thumbnail': video_thumbnail,
'description': video_description, 'description': video_description,
'formats': formats,
}] }]

View File

@ -1150,7 +1150,7 @@ def _get_available_automatic_caption(self, video_id, webpage):
list_page = self._download_webpage(list_url, video_id) list_page = self._download_webpage(list_url, video_id)
caption_list = xml.etree.ElementTree.fromstring(list_page.encode('utf-8')) caption_list = xml.etree.ElementTree.fromstring(list_page.encode('utf-8'))
original_lang_node = caption_list.find('track') original_lang_node = caption_list.find('track')
if not original_lang_node or original_lang_node.attrib.get('kind') != 'asr' : if original_lang_node is None or original_lang_node.attrib.get('kind') != 'asr' :
self._downloader.report_warning(u'Video doesn\'t have automatic captions') self._downloader.report_warning(u'Video doesn\'t have automatic captions')
return {} return {}
original_lang = original_lang_node.attrib['lang_code'] original_lang = original_lang_node.attrib['lang_code']