Merge branch 'master' into fix.25.12.2018
# Conflicts: # youtube_dl/version.py
This commit is contained in:
commit
0a73b49fd2
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 *2019.03.09*. If it's not, read [this FAQ entry](https://github.com/ytdl-org/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 *2019.03.18*. If it's not, read [this FAQ entry](https://github.com/ytdl-org/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 **2019.03.09**
|
- [ ] I've **verified** and **I assure** that I'm running youtube-dl **2019.03.18**
|
||||||
|
|
||||||
### Before submitting an *issue* make sure you have:
|
### Before submitting an *issue* make sure you have:
|
||||||
- [ ] At least skimmed through the [README](https://github.com/ytdl-org/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/ytdl-org/youtube-dl#faq) and [BUGS](https://github.com/ytdl-org/youtube-dl#bugs) sections
|
- [ ] At least skimmed through the [README](https://github.com/ytdl-org/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/ytdl-org/youtube-dl#faq) and [BUGS](https://github.com/ytdl-org/youtube-dl#bugs) sections
|
||||||
@ -36,7 +36,7 @@ Add the `-v` flag to **your command line** you run youtube-dl with (`youtube-dl
|
|||||||
[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 2019.03.09
|
[debug] youtube-dl version 2019.03.18
|
||||||
[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: {}
|
||||||
|
34
ChangeLog
34
ChangeLog
@ -1,3 +1,37 @@
|
|||||||
|
version 2019.03.18
|
||||||
|
|
||||||
|
Core
|
||||||
|
* [extractor/common] Improve HTML5 entries extraction
|
||||||
|
+ [utils] Introduce parse_bitrate
|
||||||
|
* [update] Hide update URLs behind redirect
|
||||||
|
* [extractor/common] Fix url meta field for unfragmented DASH formats (#20346)
|
||||||
|
|
||||||
|
Extractors
|
||||||
|
+ [yandexvideo] Add extractor
|
||||||
|
* [openload] Improve embed detection
|
||||||
|
+ [corus] Add support for bigbrothercanada.ca (#20357)
|
||||||
|
+ [orf:radio] Extract series (#20012)
|
||||||
|
+ [cbc:watch] Add support for gem.cbc.ca (#20251, #20359)
|
||||||
|
- [anysex] Remove extractor (#19279)
|
||||||
|
+ [ciscolive] Add support for new URL schema (#20320, #20351)
|
||||||
|
+ [youtube] Add support for invidiou.sh (#20309)
|
||||||
|
- [anitube] Remove extractor (#20334)
|
||||||
|
- [ruleporn] Remove extractor (#15344, #20324)
|
||||||
|
* [npr] Fix extraction (#10793, #13440)
|
||||||
|
* [biqle] Fix extraction (#11471, #15313)
|
||||||
|
* [viddler] Modernize
|
||||||
|
* [moevideo] Fix extraction
|
||||||
|
* [primesharetv] Remove extractor
|
||||||
|
* [hypem] Modernize and extract more metadata (#15320)
|
||||||
|
* [veoh] Fix extraction
|
||||||
|
* [escapist] Modernize
|
||||||
|
- [videomega] Remove extractor (#10108)
|
||||||
|
+ [beeg] Add support for beeg.porn (#20306)
|
||||||
|
* [vimeo:review] Improve config url extraction and extract original format
|
||||||
|
(#20305)
|
||||||
|
* [fox] Detect geo restriction and authentication errors (#20208)
|
||||||
|
|
||||||
|
|
||||||
version 2019.03.09
|
version 2019.03.09
|
||||||
|
|
||||||
Core
|
Core
|
||||||
|
@ -44,9 +44,7 @@
|
|||||||
- **AmericasTestKitchen**
|
- **AmericasTestKitchen**
|
||||||
- **anderetijden**: npo.nl, ntr.nl, omroepwnl.nl, zapp.nl and npo3.nl
|
- **anderetijden**: npo.nl, ntr.nl, omroepwnl.nl, zapp.nl and npo3.nl
|
||||||
- **AnimeOnDemand**
|
- **AnimeOnDemand**
|
||||||
- **anitube.se**
|
|
||||||
- **Anvato**
|
- **Anvato**
|
||||||
- **AnySex**
|
|
||||||
- **APA**
|
- **APA**
|
||||||
- **Aparat**
|
- **Aparat**
|
||||||
- **AppleConnect**
|
- **AppleConnect**
|
||||||
@ -698,7 +696,6 @@
|
|||||||
- **PornoXO**
|
- **PornoXO**
|
||||||
- **PornTube**
|
- **PornTube**
|
||||||
- **PressTV**
|
- **PressTV**
|
||||||
- **PrimeShareTV**
|
|
||||||
- **PromptFile**
|
- **PromptFile**
|
||||||
- **prosiebensat1**: ProSiebenSat.1 Digital
|
- **prosiebensat1**: ProSiebenSat.1 Digital
|
||||||
- **puhutv**
|
- **puhutv**
|
||||||
@ -718,7 +715,7 @@
|
|||||||
- **radio.de**
|
- **radio.de**
|
||||||
- **radiobremen**
|
- **radiobremen**
|
||||||
- **radiocanada**
|
- **radiocanada**
|
||||||
- **RadioCanadaAudioVideo**
|
- **radiocanada:audiovideo**
|
||||||
- **radiofrance**
|
- **radiofrance**
|
||||||
- **RadioJavan**
|
- **RadioJavan**
|
||||||
- **Rai**
|
- **Rai**
|
||||||
@ -765,7 +762,6 @@
|
|||||||
- **RTVS**
|
- **RTVS**
|
||||||
- **Rudo**
|
- **Rudo**
|
||||||
- **RUHD**
|
- **RUHD**
|
||||||
- **RulePorn**
|
|
||||||
- **rutube**: Rutube videos
|
- **rutube**: Rutube videos
|
||||||
- **rutube:channel**: Rutube channels
|
- **rutube:channel**: Rutube channels
|
||||||
- **rutube:embed**: Rutube embedded videos
|
- **rutube:embed**: Rutube embedded videos
|
||||||
@ -1010,7 +1006,6 @@
|
|||||||
- **video.mit.edu**
|
- **video.mit.edu**
|
||||||
- **VideoDetective**
|
- **VideoDetective**
|
||||||
- **videofy.me**
|
- **videofy.me**
|
||||||
- **VideoMega**
|
|
||||||
- **videomore**
|
- **videomore**
|
||||||
- **videomore:season**
|
- **videomore:season**
|
||||||
- **videomore:video**
|
- **videomore:video**
|
||||||
@ -1127,6 +1122,7 @@
|
|||||||
- **yandexmusic:album**: Яндекс.Музыка - Альбом
|
- **yandexmusic:album**: Яндекс.Музыка - Альбом
|
||||||
- **yandexmusic:playlist**: Яндекс.Музыка - Плейлист
|
- **yandexmusic:playlist**: Яндекс.Музыка - Плейлист
|
||||||
- **yandexmusic:track**: Яндекс.Музыка - Трек
|
- **yandexmusic:track**: Яндекс.Музыка - Трек
|
||||||
|
- **YandexVideo**
|
||||||
- **YapFiles**
|
- **YapFiles**
|
||||||
- **YesJapan**
|
- **YesJapan**
|
||||||
- **yinyuetai:video**: 音悦Tai
|
- **yinyuetai:video**: 音悦Tai
|
||||||
|
@ -33,11 +33,13 @@ from youtube_dl.utils import (
|
|||||||
ExtractorError,
|
ExtractorError,
|
||||||
find_xpath_attr,
|
find_xpath_attr,
|
||||||
fix_xml_ampersands,
|
fix_xml_ampersands,
|
||||||
|
float_or_none,
|
||||||
get_element_by_class,
|
get_element_by_class,
|
||||||
get_element_by_attribute,
|
get_element_by_attribute,
|
||||||
get_elements_by_class,
|
get_elements_by_class,
|
||||||
get_elements_by_attribute,
|
get_elements_by_attribute,
|
||||||
InAdvancePagedList,
|
InAdvancePagedList,
|
||||||
|
int_or_none,
|
||||||
intlist_to_bytes,
|
intlist_to_bytes,
|
||||||
is_html,
|
is_html,
|
||||||
js_to_json,
|
js_to_json,
|
||||||
@ -468,6 +470,21 @@ class TestUtil(unittest.TestCase):
|
|||||||
shell_quote(args),
|
shell_quote(args),
|
||||||
"""ffmpeg -i 'ñ€ß'"'"'.mp4'""" if compat_os_name != 'nt' else '''ffmpeg -i "ñ€ß'.mp4"''')
|
"""ffmpeg -i 'ñ€ß'"'"'.mp4'""" if compat_os_name != 'nt' else '''ffmpeg -i "ñ€ß'.mp4"''')
|
||||||
|
|
||||||
|
def test_float_or_none(self):
|
||||||
|
self.assertEqual(float_or_none('42.42'), 42.42)
|
||||||
|
self.assertEqual(float_or_none('42'), 42.0)
|
||||||
|
self.assertEqual(float_or_none(''), None)
|
||||||
|
self.assertEqual(float_or_none(None), None)
|
||||||
|
self.assertEqual(float_or_none([]), None)
|
||||||
|
self.assertEqual(float_or_none(set()), None)
|
||||||
|
|
||||||
|
def test_int_or_none(self):
|
||||||
|
self.assertEqual(int_or_none('42'), 42)
|
||||||
|
self.assertEqual(int_or_none(''), None)
|
||||||
|
self.assertEqual(int_or_none(None), None)
|
||||||
|
self.assertEqual(int_or_none([]), None)
|
||||||
|
self.assertEqual(int_or_none(set()), None)
|
||||||
|
|
||||||
def test_str_to_int(self):
|
def test_str_to_int(self):
|
||||||
self.assertEqual(str_to_int('123,456'), 123456)
|
self.assertEqual(str_to_int('123,456'), 123456)
|
||||||
self.assertEqual(str_to_int('123.456'), 123456)
|
self.assertEqual(str_to_int('123.456'), 123456)
|
||||||
|
@ -166,6 +166,8 @@ def _real_main(argv=None):
|
|||||||
if opts.max_sleep_interval is not None:
|
if opts.max_sleep_interval is not None:
|
||||||
if opts.max_sleep_interval < 0:
|
if opts.max_sleep_interval < 0:
|
||||||
parser.error('max sleep interval must be positive or 0')
|
parser.error('max sleep interval must be positive or 0')
|
||||||
|
if opts.sleep_interval is None:
|
||||||
|
parser.error('min sleep interval must be specified, use --min-sleep-interval')
|
||||||
if opts.max_sleep_interval < opts.sleep_interval:
|
if opts.max_sleep_interval < opts.sleep_interval:
|
||||||
parser.error('max sleep interval must be greater than or equal to min sleep interval')
|
parser.error('max sleep interval must be greater than or equal to min sleep interval')
|
||||||
else:
|
else:
|
||||||
|
@ -79,7 +79,7 @@ class CWTVIE(InfoExtractor):
|
|||||||
season = str_or_none(video_data.get('season'))
|
season = str_or_none(video_data.get('season'))
|
||||||
episode = str_or_none(video_data.get('episode'))
|
episode = str_or_none(video_data.get('episode'))
|
||||||
if episode and season:
|
if episode and season:
|
||||||
episode = episode.lstrip(season)
|
episode = episode[len(season):]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'_type': 'url_transparent',
|
'_type': 'url_transparent',
|
||||||
|
@ -1,36 +1,83 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
determine_ext,
|
||||||
|
int_or_none,
|
||||||
|
strip_or_none,
|
||||||
|
xpath_attr,
|
||||||
|
xpath_text,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class InaIE(InfoExtractor):
|
class InaIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?ina\.fr/video/(?P<id>I?[A-Z0-9]+)'
|
_VALID_URL = r'https?://(?:www\.)?ina\.fr/(?:video|audio)/(?P<id>[A-Z0-9_]+)'
|
||||||
_TEST = {
|
_TESTS = [{
|
||||||
'url': 'http://www.ina.fr/video/I12055569/francois-hollande-je-crois-que-c-est-clair-video.html',
|
'url': 'http://www.ina.fr/video/I12055569/francois-hollande-je-crois-que-c-est-clair-video.html',
|
||||||
'md5': 'a667021bf2b41f8dc6049479d9bb38a3',
|
'md5': 'a667021bf2b41f8dc6049479d9bb38a3',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'I12055569',
|
'id': 'I12055569',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'François Hollande "Je crois que c\'est clair"',
|
'title': 'François Hollande "Je crois que c\'est clair"',
|
||||||
|
'description': 'md5:3f09eb072a06cb286b8f7e4f77109663',
|
||||||
}
|
}
|
||||||
}
|
}, {
|
||||||
|
'url': 'https://www.ina.fr/video/S806544_001/don-d-organes-des-avancees-mais-d-importants-besoins-video.html',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.ina.fr/audio/P16173408',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'https://www.ina.fr/video/P16173408-video.html',
|
||||||
|
'only_matching': True,
|
||||||
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
video_id = self._match_id(url)
|
||||||
|
info_doc = self._download_xml(
|
||||||
|
'http://player.ina.fr/notices/%s.mrss' % video_id, video_id)
|
||||||
|
item = info_doc.find('channel/item')
|
||||||
|
title = xpath_text(item, 'title', fatal=True)
|
||||||
|
media_ns_xpath = lambda x: self._xpath_ns(x, 'http://search.yahoo.com/mrss/')
|
||||||
|
content = item.find(media_ns_xpath('content'))
|
||||||
|
|
||||||
video_id = mobj.group('id')
|
get_furl = lambda x: xpath_attr(content, media_ns_xpath(x), 'url')
|
||||||
mrss_url = 'http://player.ina.fr/notices/%s.mrss' % video_id
|
formats = []
|
||||||
info_doc = self._download_xml(mrss_url, video_id)
|
for q, w, h in (('bq', 400, 300), ('mq', 512, 384), ('hq', 768, 576)):
|
||||||
|
q_url = get_furl(q)
|
||||||
|
if not q_url:
|
||||||
|
continue
|
||||||
|
formats.append({
|
||||||
|
'format_id': q,
|
||||||
|
'url': q_url,
|
||||||
|
'width': w,
|
||||||
|
'height': h,
|
||||||
|
})
|
||||||
|
if not formats:
|
||||||
|
furl = get_furl('player') or content.attrib['url']
|
||||||
|
ext = determine_ext(furl)
|
||||||
|
formats = [{
|
||||||
|
'url': furl,
|
||||||
|
'vcodec': 'none' if ext == 'mp3' else None,
|
||||||
|
'ext': ext,
|
||||||
|
}]
|
||||||
|
|
||||||
self.report_extraction(video_id)
|
thumbnails = []
|
||||||
|
for thumbnail in content.findall(media_ns_xpath('thumbnail')):
|
||||||
video_url = info_doc.find('.//{http://search.yahoo.com/mrss/}player').attrib['url']
|
thumbnail_url = thumbnail.get('url')
|
||||||
|
if not thumbnail_url:
|
||||||
|
continue
|
||||||
|
thumbnails.append({
|
||||||
|
'url': thumbnail_url,
|
||||||
|
'height': int_or_none(thumbnail.get('height')),
|
||||||
|
'width': int_or_none(thumbnail.get('width')),
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
'url': video_url,
|
'formats': formats,
|
||||||
'title': info_doc.find('.//title').text,
|
'title': title,
|
||||||
|
'description': strip_or_none(xpath_text(item, 'description')),
|
||||||
|
'thumbnails': thumbnails,
|
||||||
}
|
}
|
||||||
|
@ -181,10 +181,7 @@ class NPOIE(NPOBaseIE):
|
|||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
try:
|
return self._get_info(url, video_id) or self._get_old_info(video_id)
|
||||||
return self._get_info(url, video_id)
|
|
||||||
except ExtractorError:
|
|
||||||
return self._get_old_info(video_id)
|
|
||||||
|
|
||||||
def _get_info(self, url, video_id):
|
def _get_info(self, url, video_id):
|
||||||
token = self._download_json(
|
token = self._download_json(
|
||||||
@ -206,6 +203,7 @@ class NPOIE(NPOBaseIE):
|
|||||||
|
|
||||||
player_token = player['token']
|
player_token = player['token']
|
||||||
|
|
||||||
|
drm = False
|
||||||
format_urls = set()
|
format_urls = set()
|
||||||
formats = []
|
formats = []
|
||||||
for profile in ('hls', 'dash-widevine', 'dash-playready', 'smooth'):
|
for profile in ('hls', 'dash-widevine', 'dash-playready', 'smooth'):
|
||||||
@ -227,7 +225,8 @@ class NPOIE(NPOBaseIE):
|
|||||||
if not stream_url or stream_url in format_urls:
|
if not stream_url or stream_url in format_urls:
|
||||||
continue
|
continue
|
||||||
format_urls.add(stream_url)
|
format_urls.add(stream_url)
|
||||||
if stream.get('protection') is not None:
|
if stream.get('protection') is not None or stream.get('keySystemOptions') is not None:
|
||||||
|
drm = True
|
||||||
continue
|
continue
|
||||||
stream_type = stream.get('type')
|
stream_type = stream.get('type')
|
||||||
stream_ext = determine_ext(stream_url)
|
stream_ext = determine_ext(stream_url)
|
||||||
@ -246,6 +245,11 @@ class NPOIE(NPOBaseIE):
|
|||||||
'url': stream_url,
|
'url': stream_url,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if not formats:
|
||||||
|
if drm:
|
||||||
|
raise ExtractorError('This video is DRM protected.', expected=True)
|
||||||
|
return
|
||||||
|
|
||||||
self._sort_formats(formats)
|
self._sort_formats(formats)
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
|
@ -14,6 +14,7 @@ from ..compat import (
|
|||||||
)
|
)
|
||||||
from .openload import PhantomJSwrapper
|
from .openload import PhantomJSwrapper
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
|
determine_ext,
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
orderedSet,
|
orderedSet,
|
||||||
@ -275,6 +276,10 @@ class PornHubIE(PornHubBaseIE):
|
|||||||
r'/(\d{6}/\d{2})/', video_url, 'upload data', default=None)
|
r'/(\d{6}/\d{2})/', video_url, 'upload data', default=None)
|
||||||
if upload_date:
|
if upload_date:
|
||||||
upload_date = upload_date.replace('/', '')
|
upload_date = upload_date.replace('/', '')
|
||||||
|
if determine_ext(video_url) == 'mpd':
|
||||||
|
formats.extend(self._extract_mpd_formats(
|
||||||
|
video_url, video_id, mpd_id='dash', fatal=False))
|
||||||
|
continue
|
||||||
tbr = None
|
tbr = None
|
||||||
mobj = re.search(r'(?P<height>\d+)[pP]?_(?P<tbr>\d+)[kK]', video_url)
|
mobj = re.search(r'(?P<height>\d+)[pP]?_(?P<tbr>\d+)[kK]', video_url)
|
||||||
if mobj:
|
if mobj:
|
||||||
|
@ -185,7 +185,7 @@ class SVTPlayIE(SVTPlayBaseIE):
|
|||||||
|
|
||||||
def _extract_by_video_id(self, video_id, webpage=None):
|
def _extract_by_video_id(self, video_id, webpage=None):
|
||||||
data = self._download_json(
|
data = self._download_json(
|
||||||
'https://api.svt.se/videoplayer-api/video/%s' % video_id,
|
'https://api.svt.se/video/%s' % video_id,
|
||||||
video_id, headers=self.geo_verification_headers())
|
video_id, headers=self.geo_verification_headers())
|
||||||
info_dict = self._extract_video(data, video_id)
|
info_dict = self._extract_video(data, video_id)
|
||||||
if not info_dict.get('title'):
|
if not info_dict.get('title'):
|
||||||
|
@ -1922,7 +1922,7 @@ def int_or_none(v, scale=1, default=None, get_attr=None, invscale=1):
|
|||||||
return default
|
return default
|
||||||
try:
|
try:
|
||||||
return int(v) * invscale // scale
|
return int(v) * invscale // scale
|
||||||
except ValueError:
|
except (ValueError, TypeError):
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
@ -1943,7 +1943,7 @@ def float_or_none(v, scale=1, invscale=1, default=None):
|
|||||||
return default
|
return default
|
||||||
try:
|
try:
|
||||||
return float(v) * invscale / scale
|
return float(v) * invscale / scale
|
||||||
except ValueError:
|
except (ValueError, TypeError):
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = 'vc.2019.03.17'
|
__version__ = 'vc.2019.03.28'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user