Merge branch 'master' into BlenderCloud-issue-13282
This commit is contained in:
commit
ca5317578a
6
.github/ISSUE_TEMPLATE.md
vendored
6
.github/ISSUE_TEMPLATE.md
vendored
@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2017.06.18*. If it's not read [this FAQ entry](https://github.com/rg3/youtube-dl/blob/master/README.md#how-do-i-update-youtube-dl) and update. Issues with outdated version will be rejected.
|
### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2017.06.23*. If it's not read [this FAQ entry](https://github.com/rg3/youtube-dl/blob/master/README.md#how-do-i-update-youtube-dl) and update. Issues with outdated version will be rejected.
|
||||||
- [ ] I've **verified** and **I assure** that I'm running youtube-dl **2017.06.18**
|
- [ ] I've **verified** and **I assure** that I'm running youtube-dl **2017.06.23**
|
||||||
|
|
||||||
### Before submitting an *issue* make sure you have:
|
### Before submitting an *issue* make sure you have:
|
||||||
- [ ] At least skimmed through [README](https://github.com/rg3/youtube-dl/blob/master/README.md) and **most notably** [FAQ](https://github.com/rg3/youtube-dl#faq) and [BUGS](https://github.com/rg3/youtube-dl#bugs) sections
|
- [ ] At least skimmed through [README](https://github.com/rg3/youtube-dl/blob/master/README.md) and **most notably** [FAQ](https://github.com/rg3/youtube-dl#faq) and [BUGS](https://github.com/rg3/youtube-dl#bugs) sections
|
||||||
@ -35,7 +35,7 @@ $ youtube-dl -v <your command line>
|
|||||||
[debug] User config: []
|
[debug] User config: []
|
||||||
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
|
||||||
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
|
||||||
[debug] youtube-dl version 2017.06.18
|
[debug] youtube-dl version 2017.06.23
|
||||||
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
|
||||||
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
|
||||||
[debug] Proxy map: {}
|
[debug] Proxy map: {}
|
||||||
|
17
ChangeLog
17
ChangeLog
@ -1,7 +1,22 @@
|
|||||||
version <unreleased>
|
version 2017.06.23
|
||||||
|
|
||||||
|
Core
|
||||||
|
* [adobepass] Fix extraction on older python 2.6
|
||||||
|
|
||||||
Extractors
|
Extractors
|
||||||
|
* [youtube] Adapt to new automatic captions rendition (#13467)
|
||||||
|
* [hgtv.com:show] Relax video config regular expression (#13279, #13461)
|
||||||
|
* [drtuber] Fix formats extraction (#12058)
|
||||||
|
* [youporn] Fix upload date extraction
|
||||||
|
* [youporn] Improve formats extraction
|
||||||
|
* [youporn] Fix title extraction (#13456)
|
||||||
|
* [googledrive] Fix formats sorting (#13443)
|
||||||
|
* [watchindianporn] Fix extraction (#13411, #13415)
|
||||||
|
+ [vimeo] Add fallback mp4 extension for original format
|
||||||
|
+ [ruv] Add support for ruv.is (#13396)
|
||||||
|
* [viu] Fix extraction on older python 2.6
|
||||||
* [pandora.tv] Fix upload_date extraction (#12846)
|
* [pandora.tv] Fix upload_date extraction (#12846)
|
||||||
|
+ [asiancrush] Add support for asiancrush.com (#13420)
|
||||||
|
|
||||||
|
|
||||||
version 2017.06.18
|
version 2017.06.18
|
||||||
|
@ -67,6 +67,8 @@
|
|||||||
- **arte.tv:info**
|
- **arte.tv:info**
|
||||||
- **arte.tv:magazine**
|
- **arte.tv:magazine**
|
||||||
- **arte.tv:playlist**
|
- **arte.tv:playlist**
|
||||||
|
- **AsianCrush**
|
||||||
|
- **AsianCrushPlaylist**
|
||||||
- **AtresPlayer**
|
- **AtresPlayer**
|
||||||
- **ATTTechChannel**
|
- **ATTTechChannel**
|
||||||
- **ATVAt**
|
- **ATVAt**
|
||||||
@ -686,6 +688,7 @@
|
|||||||
- **rutube:person**: Rutube person videos
|
- **rutube:person**: Rutube person videos
|
||||||
- **RUTV**: RUTV.RU
|
- **RUTV**: RUTV.RU
|
||||||
- **Ruutu**
|
- **Ruutu**
|
||||||
|
- **Ruv**
|
||||||
- **safari**: safaribooksonline.com online video
|
- **safari**: safaribooksonline.com online video
|
||||||
- **safari:api**
|
- **safari:api**
|
||||||
- **safari:course**: safaribooksonline.com online courses
|
- **safari:course**: safaribooksonline.com online courses
|
||||||
|
@ -1448,17 +1448,25 @@ class YoutubeDL(object):
|
|||||||
if not formats:
|
if not formats:
|
||||||
raise ExtractorError('No video formats found!')
|
raise ExtractorError('No video formats found!')
|
||||||
|
|
||||||
|
def is_wellformed(f):
|
||||||
|
url = f.get('url')
|
||||||
|
valid_url = url and isinstance(url, compat_str)
|
||||||
|
if not valid_url:
|
||||||
|
self.report_warning(
|
||||||
|
'"url" field is missing or empty - skipping format, '
|
||||||
|
'there is an error in extractor')
|
||||||
|
return valid_url
|
||||||
|
|
||||||
|
# Filter out malformed formats for better extraction robustness
|
||||||
|
formats = list(filter(is_wellformed, formats))
|
||||||
|
|
||||||
formats_dict = {}
|
formats_dict = {}
|
||||||
|
|
||||||
# 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 'url' not in format:
|
|
||||||
raise ExtractorError('Missing "url" key in result (index %d)' % i)
|
|
||||||
|
|
||||||
sanitize_string_field(format, 'format_id')
|
sanitize_string_field(format, 'format_id')
|
||||||
sanitize_numeric_fields(format)
|
sanitize_numeric_fields(format)
|
||||||
format['url'] = sanitize_url(format['url'])
|
format['url'] = sanitize_url(format['url'])
|
||||||
|
|
||||||
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)
|
||||||
else:
|
else:
|
||||||
|
@ -44,8 +44,23 @@ class DrTuberIE(InfoExtractor):
|
|||||||
webpage = self._download_webpage(
|
webpage = self._download_webpage(
|
||||||
'http://www.drtuber.com/video/%s' % video_id, display_id)
|
'http://www.drtuber.com/video/%s' % video_id, display_id)
|
||||||
|
|
||||||
video_url = self._html_search_regex(
|
video_data = self._download_json(
|
||||||
r'<source src="([^"]+)"', webpage, 'video URL')
|
'http://www.drtuber.com/player_config_json/', video_id, query={
|
||||||
|
'vid': video_id,
|
||||||
|
'embed': 0,
|
||||||
|
'aid': 0,
|
||||||
|
'domain_id': 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
formats = []
|
||||||
|
for format_id, video_url in video_data['files'].items():
|
||||||
|
if video_url:
|
||||||
|
formats.append({
|
||||||
|
'format_id': format_id,
|
||||||
|
'quality': 2 if format_id == 'hq' else 1,
|
||||||
|
'url': video_url
|
||||||
|
})
|
||||||
|
self._sort_formats(formats)
|
||||||
|
|
||||||
title = self._html_search_regex(
|
title = self._html_search_regex(
|
||||||
(r'class="title_watch"[^>]*><(?:p|h\d+)[^>]*>([^<]+)<',
|
(r'class="title_watch"[^>]*><(?:p|h\d+)[^>]*>([^<]+)<',
|
||||||
@ -75,7 +90,7 @@ class DrTuberIE(InfoExtractor):
|
|||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'display_id': display_id,
|
'display_id': display_id,
|
||||||
'url': video_url,
|
'formats': formats,
|
||||||
'title': title,
|
'title': title,
|
||||||
'thumbnail': thumbnail,
|
'thumbnail': thumbnail,
|
||||||
'like_count': like_count,
|
'like_count': like_count,
|
||||||
|
@ -7,14 +7,19 @@ from .common import InfoExtractor
|
|||||||
class HGTVComShowIE(InfoExtractor):
|
class HGTVComShowIE(InfoExtractor):
|
||||||
IE_NAME = 'hgtv.com:show'
|
IE_NAME = 'hgtv.com:show'
|
||||||
_VALID_URL = r'https?://(?:www\.)?hgtv\.com/shows/[^/]+/(?P<id>[^/?#&]+)'
|
_VALID_URL = r'https?://(?:www\.)?hgtv\.com/shows/[^/]+/(?P<id>[^/?#&]+)'
|
||||||
_TEST = {
|
_TESTS = [{
|
||||||
'url': 'http://www.hgtv.com/shows/flip-or-flop/flip-or-flop-full-episodes-videos',
|
# data-module="video"
|
||||||
|
'url': 'http://www.hgtv.com/shows/flip-or-flop/flip-or-flop-full-episodes-season-4-videos',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'flip-or-flop-full-episodes-videos',
|
'id': 'flip-or-flop-full-episodes-season-4-videos',
|
||||||
'title': 'Flip or Flop Full Episodes',
|
'title': 'Flip or Flop Full Episodes',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 15,
|
'playlist_mincount': 15,
|
||||||
}
|
}, {
|
||||||
|
# data-deferred-module="video"
|
||||||
|
'url': 'http://www.hgtv.com/shows/good-bones/episodes/an-old-victorian-house-gets-a-new-facelift',
|
||||||
|
'only_matching': True,
|
||||||
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
display_id = self._match_id(url)
|
display_id = self._match_id(url)
|
||||||
@ -23,7 +28,7 @@ class HGTVComShowIE(InfoExtractor):
|
|||||||
|
|
||||||
config = self._parse_json(
|
config = self._parse_json(
|
||||||
self._search_regex(
|
self._search_regex(
|
||||||
r'(?s)data-module=["\']video["\'][^>]*>.*?<script[^>]+type=["\']text/x-config["\'][^>]*>(.+?)</script',
|
r'(?s)data-(?:deferred-)?module=["\']video["\'][^>]*>.*?<script[^>]+type=["\']text/x-config["\'][^>]*>(.+?)</script',
|
||||||
webpage, 'video config'),
|
webpage, 'video config'),
|
||||||
display_id)['channels'][0]
|
display_id)['channels'][0]
|
||||||
|
|
||||||
|
@ -3,12 +3,14 @@ import re
|
|||||||
import base64
|
import base64
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
|
from ..compat import compat_str
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
int_or_none,
|
|
||||||
float_or_none,
|
|
||||||
ExtractorError,
|
|
||||||
unsmuggle_url,
|
|
||||||
determine_ext,
|
determine_ext,
|
||||||
|
ExtractorError,
|
||||||
|
float_or_none,
|
||||||
|
int_or_none,
|
||||||
|
try_get,
|
||||||
|
unsmuggle_url,
|
||||||
)
|
)
|
||||||
from ..compat import compat_urllib_parse_urlencode
|
from ..compat import compat_urllib_parse_urlencode
|
||||||
|
|
||||||
@ -39,13 +41,15 @@ class OoyalaBaseIE(InfoExtractor):
|
|||||||
formats = []
|
formats = []
|
||||||
if cur_auth_data['authorized']:
|
if cur_auth_data['authorized']:
|
||||||
for stream in cur_auth_data['streams']:
|
for stream in cur_auth_data['streams']:
|
||||||
s_url = base64.b64decode(
|
url_data = try_get(stream, lambda x: x['url']['data'], compat_str)
|
||||||
stream['url']['data'].encode('ascii')).decode('utf-8')
|
if not url_data:
|
||||||
if s_url in urls:
|
continue
|
||||||
|
s_url = base64.b64decode(url_data.encode('ascii')).decode('utf-8')
|
||||||
|
if not s_url or s_url in urls:
|
||||||
continue
|
continue
|
||||||
urls.append(s_url)
|
urls.append(s_url)
|
||||||
ext = determine_ext(s_url, None)
|
ext = determine_ext(s_url, None)
|
||||||
delivery_type = stream['delivery_type']
|
delivery_type = stream.get('delivery_type')
|
||||||
if delivery_type == 'hls' or ext == 'm3u8':
|
if delivery_type == 'hls' or ext == 'm3u8':
|
||||||
formats.extend(self._extract_m3u8_formats(
|
formats.extend(self._extract_m3u8_formats(
|
||||||
re.sub(r'/ip(?:ad|hone)/', '/all/', s_url), embed_code, 'mp4', 'm3u8_native',
|
re.sub(r'/ip(?:ad|hone)/', '/all/', s_url), embed_code, 'mp4', 'm3u8_native',
|
||||||
@ -65,7 +69,7 @@ class OoyalaBaseIE(InfoExtractor):
|
|||||||
else:
|
else:
|
||||||
formats.append({
|
formats.append({
|
||||||
'url': s_url,
|
'url': s_url,
|
||||||
'ext': ext or stream.get('delivery_type'),
|
'ext': ext or delivery_type,
|
||||||
'vcodec': stream.get('video_codec'),
|
'vcodec': stream.get('video_codec'),
|
||||||
'format_id': delivery_type,
|
'format_id': delivery_type,
|
||||||
'width': int_or_none(stream.get('width')),
|
'width': int_or_none(stream.get('width')),
|
||||||
@ -136,6 +140,11 @@ class OoyalaIE(OoyalaBaseIE):
|
|||||||
'title': 'Divide Tool Path.mp4',
|
'title': 'Divide Tool Path.mp4',
|
||||||
'duration': 204.405,
|
'duration': 204.405,
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# empty stream['url']['data']
|
||||||
|
'url': 'http://player.ooyala.com/player.js?embedCode=w2bnZtYjE6axZ_dw1Cd0hQtXd_ige2Is',
|
||||||
|
'only_matching': True,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1269,37 +1269,57 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
sub_lang_list[sub_lang] = sub_formats
|
sub_lang_list[sub_lang] = sub_formats
|
||||||
return sub_lang_list
|
return sub_lang_list
|
||||||
|
|
||||||
|
def make_captions(sub_url, sub_langs):
|
||||||
|
parsed_sub_url = compat_urllib_parse_urlparse(sub_url)
|
||||||
|
caption_qs = compat_parse_qs(parsed_sub_url.query)
|
||||||
|
captions = {}
|
||||||
|
for sub_lang in sub_langs:
|
||||||
|
sub_formats = []
|
||||||
|
for ext in self._SUBTITLE_FORMATS:
|
||||||
|
caption_qs.update({
|
||||||
|
'tlang': [sub_lang],
|
||||||
|
'fmt': [ext],
|
||||||
|
})
|
||||||
|
sub_url = compat_urlparse.urlunparse(parsed_sub_url._replace(
|
||||||
|
query=compat_urllib_parse_urlencode(caption_qs, True)))
|
||||||
|
sub_formats.append({
|
||||||
|
'url': sub_url,
|
||||||
|
'ext': ext,
|
||||||
|
})
|
||||||
|
captions[sub_lang] = sub_formats
|
||||||
|
return captions
|
||||||
|
|
||||||
|
# New captions format as of 22.06.2017
|
||||||
|
player_response = args.get('player_response')
|
||||||
|
if player_response and isinstance(player_response, compat_str):
|
||||||
|
player_response = self._parse_json(
|
||||||
|
player_response, video_id, fatal=False)
|
||||||
|
if player_response:
|
||||||
|
renderer = player_response['captions']['playerCaptionsTracklistRenderer']
|
||||||
|
base_url = renderer['captionTracks'][0]['baseUrl']
|
||||||
|
sub_lang_list = []
|
||||||
|
for lang in renderer['translationLanguages']:
|
||||||
|
lang_code = lang.get('languageCode')
|
||||||
|
if lang_code:
|
||||||
|
sub_lang_list.append(lang_code)
|
||||||
|
return make_captions(base_url, sub_lang_list)
|
||||||
|
|
||||||
# Some videos don't provide ttsurl but rather caption_tracks and
|
# Some videos don't provide ttsurl but rather caption_tracks and
|
||||||
# caption_translation_languages (e.g. 20LmZk1hakA)
|
# caption_translation_languages (e.g. 20LmZk1hakA)
|
||||||
|
# Does not used anymore as of 22.06.2017
|
||||||
caption_tracks = args['caption_tracks']
|
caption_tracks = args['caption_tracks']
|
||||||
caption_translation_languages = args['caption_translation_languages']
|
caption_translation_languages = args['caption_translation_languages']
|
||||||
caption_url = compat_parse_qs(caption_tracks.split(',')[0])['u'][0]
|
caption_url = compat_parse_qs(caption_tracks.split(',')[0])['u'][0]
|
||||||
parsed_caption_url = compat_urllib_parse_urlparse(caption_url)
|
sub_lang_list = []
|
||||||
caption_qs = compat_parse_qs(parsed_caption_url.query)
|
|
||||||
|
|
||||||
sub_lang_list = {}
|
|
||||||
for lang in caption_translation_languages.split(','):
|
for lang in caption_translation_languages.split(','):
|
||||||
lang_qs = compat_parse_qs(compat_urllib_parse_unquote_plus(lang))
|
lang_qs = compat_parse_qs(compat_urllib_parse_unquote_plus(lang))
|
||||||
sub_lang = lang_qs.get('lc', [None])[0]
|
sub_lang = lang_qs.get('lc', [None])[0]
|
||||||
if not sub_lang:
|
if sub_lang:
|
||||||
continue
|
sub_lang_list.append(sub_lang)
|
||||||
sub_formats = []
|
return make_captions(caption_url, sub_lang_list)
|
||||||
for ext in self._SUBTITLE_FORMATS:
|
|
||||||
caption_qs.update({
|
|
||||||
'tlang': [sub_lang],
|
|
||||||
'fmt': [ext],
|
|
||||||
})
|
|
||||||
sub_url = compat_urlparse.urlunparse(parsed_caption_url._replace(
|
|
||||||
query=compat_urllib_parse_urlencode(caption_qs, True)))
|
|
||||||
sub_formats.append({
|
|
||||||
'url': sub_url,
|
|
||||||
'ext': ext,
|
|
||||||
})
|
|
||||||
sub_lang_list[sub_lang] = sub_formats
|
|
||||||
return sub_lang_list
|
|
||||||
# An extractor error can be raise by the download process if there are
|
# An extractor error can be raise by the download process if there are
|
||||||
# no automatic captions but there are subtitles
|
# no automatic captions but there are subtitles
|
||||||
except (KeyError, ExtractorError):
|
except (KeyError, IndexError, ExtractorError):
|
||||||
self._downloader.report_warning(err_msg)
|
self._downloader.report_warning(err_msg)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '2017.06.18'
|
__version__ = '2017.06.23'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user