Compare commits
25 Commits
2016.10.21
...
2016.10.26
Author | SHA1 | Date | |
---|---|---|---|
88839f4380 | |||
83e9374464 | |||
773017c648 | |||
777d90dc28 | |||
3791d84acc | |||
9305a0dc60 | |||
94e08950e3 | |||
ee824a8d06 | |||
d3b6b3b95b | |||
b17422753f | |||
b0b28b8241 | |||
81cb7a5978 | |||
d2e96a8ed4 | |||
2e7c8cab55 | |||
d7d4481c6a | |||
5ace137bf4 | |||
9dde0e04e6 | |||
f16f8505b1 | |||
9dc13a6780 | |||
9aa929d337 | |||
425f3fdfcb | |||
e034cbc581 | |||
5378f8ce0d | |||
b64d04c119 | |||
00ca755231 |
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 *2016.10.21.1*. 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 *2016.10.26*. 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 **2016.10.21.1**
|
- [ ] I've **verified** and **I assure** that I'm running youtube-dl **2016.10.26**
|
||||||
|
|
||||||
### 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 2016.10.21.1
|
[debug] youtube-dl version 2016.10.26
|
||||||
[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: {}
|
||||||
|
1
AUTHORS
1
AUTHORS
@ -188,3 +188,4 @@ Xie Yanbo
|
|||||||
Philip Xu
|
Philip Xu
|
||||||
John Hawkinson
|
John Hawkinson
|
||||||
Rich Leeper
|
Rich Leeper
|
||||||
|
Zhong Jianxin
|
||||||
|
24
ChangeLog
24
ChangeLog
@ -1,3 +1,27 @@
|
|||||||
|
version 2016.10.26
|
||||||
|
|
||||||
|
Extractors
|
||||||
|
+ [rentv] Add support for ren.tv (#10620)
|
||||||
|
+ [ard] Detect unavailable videos (#11018)
|
||||||
|
* [vk] Fix extraction (#11022)
|
||||||
|
|
||||||
|
|
||||||
|
version 2016.10.25
|
||||||
|
|
||||||
|
Core
|
||||||
|
* Running youtube-dl in the background is fixed (#10996, #10706, #955)
|
||||||
|
|
||||||
|
Extractors
|
||||||
|
+ [jamendo] Add support for jamendo.com (#10132, #10736)
|
||||||
|
+ [pandatv] Add support for panda.tv (#10736)
|
||||||
|
+ [dotsub] Support Vimeo embed (#10964)
|
||||||
|
* [litv] Fix extraction
|
||||||
|
+ [vimeo] Delegate ondemand redirects to ondemand extractor (#10994)
|
||||||
|
* [vivo] Fix extraction (#11003)
|
||||||
|
+ [twitch:stream] Add support for rebroadcasts (#10995)
|
||||||
|
* [pluralsight] Fix subtitles conversion (#10990)
|
||||||
|
|
||||||
|
|
||||||
version 2016.10.21.1
|
version 2016.10.21.1
|
||||||
|
|
||||||
Extractors
|
Extractors
|
||||||
|
@ -332,6 +332,8 @@
|
|||||||
- **ivideon**: Ivideon TV
|
- **ivideon**: Ivideon TV
|
||||||
- **Iwara**
|
- **Iwara**
|
||||||
- **Izlesene**
|
- **Izlesene**
|
||||||
|
- **Jamendo**
|
||||||
|
- **JamendoAlbum**
|
||||||
- **JeuxVideo**
|
- **JeuxVideo**
|
||||||
- **Jove**
|
- **Jove**
|
||||||
- **jpopsuki.tv**
|
- **jpopsuki.tv**
|
||||||
@ -527,6 +529,7 @@
|
|||||||
- **orf:iptv**: iptv.ORF.at
|
- **orf:iptv**: iptv.ORF.at
|
||||||
- **orf:oe1**: Radio Österreich 1
|
- **orf:oe1**: Radio Österreich 1
|
||||||
- **orf:tvthek**: ORF TVthek
|
- **orf:tvthek**: ORF TVthek
|
||||||
|
- **PandaTV**: 熊猫TV
|
||||||
- **pandora.tv**: 판도라TV
|
- **pandora.tv**: 판도라TV
|
||||||
- **parliamentlive.tv**: UK parliament videos
|
- **parliamentlive.tv**: UK parliament videos
|
||||||
- **Patreon**
|
- **Patreon**
|
||||||
@ -586,6 +589,8 @@
|
|||||||
- **RDS**: RDS.ca
|
- **RDS**: RDS.ca
|
||||||
- **RedTube**
|
- **RedTube**
|
||||||
- **RegioTV**
|
- **RegioTV**
|
||||||
|
- **RENTV**
|
||||||
|
- **RENTVArticle**
|
||||||
- **Restudy**
|
- **Restudy**
|
||||||
- **Reuters**
|
- **Reuters**
|
||||||
- **ReverbNation**
|
- **ReverbNation**
|
||||||
@ -641,7 +646,7 @@
|
|||||||
- **ServingSys**
|
- **ServingSys**
|
||||||
- **Sexu**
|
- **Sexu**
|
||||||
- **Shahid**
|
- **Shahid**
|
||||||
- **Shared**: shared.sx and vivo.sx
|
- **Shared**: shared.sx
|
||||||
- **ShareSix**
|
- **ShareSix**
|
||||||
- **Sina**
|
- **Sina**
|
||||||
- **SixPlay**
|
- **SixPlay**
|
||||||
@ -848,6 +853,7 @@
|
|||||||
- **Vimple**: Vimple - one-click video hosting
|
- **Vimple**: Vimple - one-click video hosting
|
||||||
- **Vine**
|
- **Vine**
|
||||||
- **vine:user**
|
- **vine:user**
|
||||||
|
- **Vivo**: vivo.sx
|
||||||
- **vk**: VK
|
- **vk**: VK
|
||||||
- **vk:uservideos**: VK - User's Videos
|
- **vk:uservideos**: VK - User's Videos
|
||||||
- **vk:wallpost**
|
- **vk:wallpost**
|
||||||
|
@ -174,11 +174,17 @@ class ARDMediathekIE(InfoExtractor):
|
|||||||
|
|
||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
|
||||||
if '>Der gewünschte Beitrag ist nicht mehr verfügbar.<' in webpage:
|
ERRORS = (
|
||||||
raise ExtractorError('Video %s is no longer available' % video_id, expected=True)
|
('>Leider liegt eine Störung vor.', 'Video %s is unavailable'),
|
||||||
|
('>Der gewünschte Beitrag ist nicht mehr verfügbar.<',
|
||||||
|
'Video %s is no longer available'),
|
||||||
|
('Diese Sendung ist für Jugendliche unter 12 Jahren nicht geeignet. Der Clip ist deshalb nur von 20 bis 6 Uhr verfügbar.',
|
||||||
|
'This program is only suitable for those aged 12 and older. Video %s is therefore only available between 20 pm and 6 am.'),
|
||||||
|
)
|
||||||
|
|
||||||
if 'Diese Sendung ist für Jugendliche unter 12 Jahren nicht geeignet. Der Clip ist deshalb nur von 20 bis 6 Uhr verfügbar.' in webpage:
|
for pattern, message in ERRORS:
|
||||||
raise ExtractorError('This program is only suitable for those aged 12 and older. Video %s is therefore only available between 20 pm and 6 am.' % video_id, expected=True)
|
if pattern in webpage:
|
||||||
|
raise ExtractorError(message % video_id, expected=True)
|
||||||
|
|
||||||
if re.search(r'[\?&]rss($|[=&])', url):
|
if re.search(r'[\?&]rss($|[=&])', url):
|
||||||
doc = compat_etree_fromstring(webpage.encode('utf-8'))
|
doc = compat_etree_fromstring(webpage.encode('utf-8'))
|
||||||
|
@ -9,7 +9,7 @@ from ..utils import (
|
|||||||
|
|
||||||
class DotsubIE(InfoExtractor):
|
class DotsubIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www\.)?dotsub\.com/view/(?P<id>[^/]+)'
|
_VALID_URL = r'https?://(?:www\.)?dotsub\.com/view/(?P<id>[^/]+)'
|
||||||
_TEST = {
|
_TESTS = [{
|
||||||
'url': 'https://dotsub.com/view/9c63db2a-fa95-4838-8e6e-13deafe47f09',
|
'url': 'https://dotsub.com/view/9c63db2a-fa95-4838-8e6e-13deafe47f09',
|
||||||
'md5': '21c7ff600f545358134fea762a6d42b6',
|
'md5': '21c7ff600f545358134fea762a6d42b6',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
@ -24,7 +24,24 @@ class DotsubIE(InfoExtractor):
|
|||||||
'upload_date': '20131130',
|
'upload_date': '20131130',
|
||||||
'view_count': int,
|
'view_count': int,
|
||||||
}
|
}
|
||||||
}
|
}, {
|
||||||
|
'url': 'https://dotsub.com/view/747bcf58-bd59-45b7-8c8c-ac312d084ee6',
|
||||||
|
'md5': '2bb4a83896434d5c26be868c609429a3',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '168006778',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Apartments and flats in Raipur the white symphony',
|
||||||
|
'description': 'md5:784d0639e6b7d1bc29530878508e38fe',
|
||||||
|
'thumbnail': 're:^https?://dotsub.com/media/747bcf58-bd59-45b7-8c8c-ac312d084ee6/p',
|
||||||
|
'duration': 290,
|
||||||
|
'timestamp': 1476767794.2809999,
|
||||||
|
'upload_date': '20160525',
|
||||||
|
'uploader': 'parthivi001',
|
||||||
|
'uploader_id': 'user52596202',
|
||||||
|
'view_count': int,
|
||||||
|
},
|
||||||
|
'add_ie': ['Vimeo'],
|
||||||
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
video_id = self._match_id(url)
|
video_id = self._match_id(url)
|
||||||
@ -37,12 +54,23 @@ class DotsubIE(InfoExtractor):
|
|||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
video_url = self._search_regex(
|
video_url = self._search_regex(
|
||||||
[r'<source[^>]+src="([^"]+)"', r'"file"\s*:\s*\'([^\']+)'],
|
[r'<source[^>]+src="([^"]+)"', r'"file"\s*:\s*\'([^\']+)'],
|
||||||
webpage, 'video url')
|
webpage, 'video url', default=None)
|
||||||
|
info_dict = {
|
||||||
|
'id': video_id,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': 'flv',
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
if not video_url:
|
||||||
'id': video_id,
|
setup_data = self._parse_json(self._html_search_regex(
|
||||||
'url': video_url,
|
r'(?s)data-setup=([\'"])(?P<content>(?!\1).+?)\1',
|
||||||
'ext': 'flv',
|
webpage, 'setup data', group='content'), video_id)
|
||||||
|
info_dict = {
|
||||||
|
'_type': 'url_transparent',
|
||||||
|
'url': setup_data['src'],
|
||||||
|
}
|
||||||
|
|
||||||
|
info_dict.update({
|
||||||
'title': info['title'],
|
'title': info['title'],
|
||||||
'description': info.get('description'),
|
'description': info.get('description'),
|
||||||
'thumbnail': info.get('screenshotURI'),
|
'thumbnail': info.get('screenshotURI'),
|
||||||
@ -50,4 +78,6 @@ class DotsubIE(InfoExtractor):
|
|||||||
'uploader': info.get('user'),
|
'uploader': info.get('user'),
|
||||||
'timestamp': float_or_none(info.get('dateCreated'), 1000),
|
'timestamp': float_or_none(info.get('dateCreated'), 1000),
|
||||||
'view_count': int_or_none(info.get('numberOfViews')),
|
'view_count': int_or_none(info.get('numberOfViews')),
|
||||||
}
|
})
|
||||||
|
|
||||||
|
return info_dict
|
||||||
|
@ -408,6 +408,10 @@ from .ivi import (
|
|||||||
from .ivideon import IvideonIE
|
from .ivideon import IvideonIE
|
||||||
from .iwara import IwaraIE
|
from .iwara import IwaraIE
|
||||||
from .izlesene import IzleseneIE
|
from .izlesene import IzleseneIE
|
||||||
|
from .jamendo import (
|
||||||
|
JamendoIE,
|
||||||
|
JamendoAlbumIE,
|
||||||
|
)
|
||||||
from .jeuxvideo import JeuxVideoIE
|
from .jeuxvideo import JeuxVideoIE
|
||||||
from .jove import JoveIE
|
from .jove import JoveIE
|
||||||
from .jwplatform import JWPlatformIE
|
from .jwplatform import JWPlatformIE
|
||||||
@ -667,6 +671,7 @@ from .orf import (
|
|||||||
ORFFM4IE,
|
ORFFM4IE,
|
||||||
ORFIPTVIE,
|
ORFIPTVIE,
|
||||||
)
|
)
|
||||||
|
from .pandatv import PandaTVIE
|
||||||
from .pandoratv import PandoraTVIE
|
from .pandoratv import PandoraTVIE
|
||||||
from .parliamentliveuk import ParliamentLiveUKIE
|
from .parliamentliveuk import ParliamentLiveUKIE
|
||||||
from .patreon import PatreonIE
|
from .patreon import PatreonIE
|
||||||
@ -740,6 +745,10 @@ from .rbmaradio import RBMARadioIE
|
|||||||
from .rds import RDSIE
|
from .rds import RDSIE
|
||||||
from .redtube import RedTubeIE
|
from .redtube import RedTubeIE
|
||||||
from .regiotv import RegioTVIE
|
from .regiotv import RegioTVIE
|
||||||
|
from .rentv import (
|
||||||
|
RENTVIE,
|
||||||
|
RENTVArticleIE,
|
||||||
|
)
|
||||||
from .restudy import RestudyIE
|
from .restudy import RestudyIE
|
||||||
from .reuters import ReutersIE
|
from .reuters import ReutersIE
|
||||||
from .reverbnation import ReverbNationIE
|
from .reverbnation import ReverbNationIE
|
||||||
@ -796,7 +805,10 @@ from .sendtonews import SendtoNewsIE
|
|||||||
from .servingsys import ServingSysIE
|
from .servingsys import ServingSysIE
|
||||||
from .sexu import SexuIE
|
from .sexu import SexuIE
|
||||||
from .shahid import ShahidIE
|
from .shahid import ShahidIE
|
||||||
from .shared import SharedIE
|
from .shared import (
|
||||||
|
SharedIE,
|
||||||
|
VivoIE,
|
||||||
|
)
|
||||||
from .sharesix import ShareSixIE
|
from .sharesix import ShareSixIE
|
||||||
from .sina import SinaIE
|
from .sina import SinaIE
|
||||||
from .sixplay import SixPlayIE
|
from .sixplay import SixPlayIE
|
||||||
|
@ -1208,20 +1208,6 @@ class GenericIE(InfoExtractor):
|
|||||||
'duration': 51690,
|
'duration': 51690,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
# JWPlayer with M3U8
|
|
||||||
{
|
|
||||||
'url': 'http://ren.tv/novosti/2015-09-25/sluchaynyy-prohozhiy-poymal-avtougonshchika-v-murmanske-video',
|
|
||||||
'info_dict': {
|
|
||||||
'id': 'playlist',
|
|
||||||
'ext': 'mp4',
|
|
||||||
'title': 'Случайный прохожий поймал автоугонщика в Мурманске. ВИДЕО | РЕН ТВ',
|
|
||||||
'uploader': 'ren.tv',
|
|
||||||
},
|
|
||||||
'params': {
|
|
||||||
# m3u8 downloads
|
|
||||||
'skip_download': True,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
# Brightcove embed, with no valid 'renditions' but valid 'IOSRenditions'
|
# Brightcove embed, with no valid 'renditions' but valid 'IOSRenditions'
|
||||||
# This video can't be played in browsers if Flash disabled and UA set to iPhone, which is actually a false alarm
|
# This video can't be played in browsers if Flash disabled and UA set to iPhone, which is actually a false alarm
|
||||||
{
|
{
|
||||||
|
107
youtube_dl/extractor/jamendo.py
Normal file
107
youtube_dl/extractor/jamendo.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from ..compat import compat_urlparse
|
||||||
|
from .common import InfoExtractor
|
||||||
|
|
||||||
|
|
||||||
|
class JamendoIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?jamendo\.com/track/(?P<id>[0-9]+)/(?P<display_id>[^/?#&]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'https://www.jamendo.com/track/196219/stories-from-emona-i',
|
||||||
|
'md5': '6e9e82ed6db98678f171c25a8ed09ffd',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '196219',
|
||||||
|
'display_id': 'stories-from-emona-i',
|
||||||
|
'ext': 'flac',
|
||||||
|
'title': 'Stories from Emona I',
|
||||||
|
'thumbnail': 're:^https?://.*\.jpg'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = self._VALID_URL_RE.match(url)
|
||||||
|
track_id = mobj.group('id')
|
||||||
|
display_id = mobj.group('display_id')
|
||||||
|
|
||||||
|
webpage = self._download_webpage(url, display_id)
|
||||||
|
|
||||||
|
title = self._html_search_meta('name', webpage, 'title')
|
||||||
|
|
||||||
|
formats = [{
|
||||||
|
'url': 'https://%s.jamendo.com/?trackid=%s&format=%s&from=app-97dab294'
|
||||||
|
% (sub_domain, track_id, format_id),
|
||||||
|
'format_id': format_id,
|
||||||
|
'ext': ext,
|
||||||
|
'quality': quality,
|
||||||
|
} for quality, (format_id, sub_domain, ext) in enumerate((
|
||||||
|
('mp31', 'mp3l', 'mp3'),
|
||||||
|
('mp32', 'mp3d', 'mp3'),
|
||||||
|
('ogg1', 'ogg', 'ogg'),
|
||||||
|
('flac', 'flac', 'flac'),
|
||||||
|
))]
|
||||||
|
self._sort_formats(formats)
|
||||||
|
|
||||||
|
thumbnail = self._html_search_meta(
|
||||||
|
'image', webpage, 'thumbnail', fatal=False)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': track_id,
|
||||||
|
'display_id': display_id,
|
||||||
|
'thumbnail': thumbnail,
|
||||||
|
'title': title,
|
||||||
|
'formats': formats
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class JamendoAlbumIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?jamendo\.com/album/(?P<id>[0-9]+)/(?P<display_id>[\w-]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'https://www.jamendo.com/album/121486/duck-on-cover',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '121486',
|
||||||
|
'title': 'Duck On Cover'
|
||||||
|
},
|
||||||
|
'playlist': [{
|
||||||
|
'md5': 'e1a2fcb42bda30dfac990212924149a8',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '1032333',
|
||||||
|
'ext': 'flac',
|
||||||
|
'title': 'Warmachine'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
'md5': '1f358d7b2f98edfe90fd55dac0799d50',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '1032330',
|
||||||
|
'ext': 'flac',
|
||||||
|
'title': 'Without Your Ghost'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
'params': {
|
||||||
|
'playlistend': 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
mobj = self._VALID_URL_RE.match(url)
|
||||||
|
album_id = mobj.group('id')
|
||||||
|
|
||||||
|
webpage = self._download_webpage(url, mobj.group('display_id'))
|
||||||
|
|
||||||
|
title = self._html_search_meta('name', webpage, 'title')
|
||||||
|
|
||||||
|
entries = [
|
||||||
|
self.url_result(
|
||||||
|
compat_urlparse.urljoin(url, m.group('path')),
|
||||||
|
ie=JamendoIE.ie_key(),
|
||||||
|
video_id=self._search_regex(
|
||||||
|
r'/track/(\d+)', m.group('path'),
|
||||||
|
'track id', default=None))
|
||||||
|
for m in re.finditer(
|
||||||
|
r'<a[^>]+href=(["\'])(?P<path>(?:(?!\1).)+)\1[^>]+class=["\'][^>]*js-trackrow-albumpage-link',
|
||||||
|
webpage)
|
||||||
|
]
|
||||||
|
|
||||||
|
return self.playlist_result(entries, album_id, title)
|
@ -2,7 +2,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import re
|
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
@ -52,8 +51,8 @@ class LiTVIE(InfoExtractor):
|
|||||||
'skip': 'Georestricted to Taiwan',
|
'skip': 'Georestricted to Taiwan',
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def _extract_playlist(self, season_list, video_id, vod_data, view_data, prompt=True):
|
def _extract_playlist(self, season_list, video_id, program_info, prompt=True):
|
||||||
episode_title = view_data['title']
|
episode_title = program_info['title']
|
||||||
content_id = season_list['contentId']
|
content_id = season_list['contentId']
|
||||||
|
|
||||||
if prompt:
|
if prompt:
|
||||||
@ -61,7 +60,7 @@ class LiTVIE(InfoExtractor):
|
|||||||
|
|
||||||
all_episodes = [
|
all_episodes = [
|
||||||
self.url_result(smuggle_url(
|
self.url_result(smuggle_url(
|
||||||
self._URL_TEMPLATE % (view_data['contentType'], episode['contentId']),
|
self._URL_TEMPLATE % (program_info['contentType'], episode['contentId']),
|
||||||
{'force_noplaylist': True})) # To prevent infinite recursion
|
{'force_noplaylist': True})) # To prevent infinite recursion
|
||||||
for episode in season_list['episode']]
|
for episode in season_list['episode']]
|
||||||
|
|
||||||
@ -80,19 +79,15 @@ class LiTVIE(InfoExtractor):
|
|||||||
|
|
||||||
webpage = self._download_webpage(url, video_id)
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
|
||||||
view_data = dict(map(lambda t: (t[0], t[2]), re.findall(
|
program_info = self._parse_json(self._search_regex(
|
||||||
r'viewData\.([a-zA-Z]+)\s*=\s*(["\'])([^"\']+)\2',
|
'var\s+programInfo\s*=\s*([^;]+)', webpage, 'VOD data', default='{}'),
|
||||||
webpage)))
|
|
||||||
|
|
||||||
vod_data = self._parse_json(self._search_regex(
|
|
||||||
'var\s+vod\s*=\s*([^;]+)', webpage, 'VOD data', default='{}'),
|
|
||||||
video_id)
|
video_id)
|
||||||
|
|
||||||
season_list = list(vod_data.get('seasonList', {}).values())
|
season_list = list(program_info.get('seasonList', {}).values())
|
||||||
if season_list:
|
if season_list:
|
||||||
if not noplaylist:
|
if not noplaylist:
|
||||||
return self._extract_playlist(
|
return self._extract_playlist(
|
||||||
season_list[0], video_id, vod_data, view_data,
|
season_list[0], video_id, program_info,
|
||||||
prompt=noplaylist_prompt)
|
prompt=noplaylist_prompt)
|
||||||
|
|
||||||
if noplaylist_prompt:
|
if noplaylist_prompt:
|
||||||
@ -102,8 +97,8 @@ class LiTVIE(InfoExtractor):
|
|||||||
# endpoint gives the same result as the data embedded in the webpage.
|
# endpoint gives the same result as the data embedded in the webpage.
|
||||||
# If georestricted, there are no embedded data, so an extra request is
|
# If georestricted, there are no embedded data, so an extra request is
|
||||||
# necessary to get the error code
|
# necessary to get the error code
|
||||||
if 'assetId' not in view_data:
|
if 'assetId' not in program_info:
|
||||||
view_data = self._download_json(
|
program_info = self._download_json(
|
||||||
'https://www.litv.tv/vod/ajax/getProgramInfo', video_id,
|
'https://www.litv.tv/vod/ajax/getProgramInfo', video_id,
|
||||||
query={'contentId': video_id},
|
query={'contentId': video_id},
|
||||||
headers={'Accept': 'application/json'})
|
headers={'Accept': 'application/json'})
|
||||||
@ -112,9 +107,9 @@ class LiTVIE(InfoExtractor):
|
|||||||
webpage, 'video data', default='{}'), video_id)
|
webpage, 'video data', default='{}'), video_id)
|
||||||
if not video_data:
|
if not video_data:
|
||||||
payload = {
|
payload = {
|
||||||
'assetId': view_data['assetId'],
|
'assetId': program_info['assetId'],
|
||||||
'watchDevices': view_data['watchDevices'],
|
'watchDevices': program_info['watchDevices'],
|
||||||
'contentType': view_data['contentType'],
|
'contentType': program_info['contentType'],
|
||||||
}
|
}
|
||||||
video_data = self._download_json(
|
video_data = self._download_json(
|
||||||
'https://www.litv.tv/vod/getMainUrl', video_id,
|
'https://www.litv.tv/vod/getMainUrl', video_id,
|
||||||
@ -136,11 +131,11 @@ class LiTVIE(InfoExtractor):
|
|||||||
# LiTV HLS segments doesn't like compressions
|
# LiTV HLS segments doesn't like compressions
|
||||||
a_format.setdefault('http_headers', {})['Youtubedl-no-compression'] = True
|
a_format.setdefault('http_headers', {})['Youtubedl-no-compression'] = True
|
||||||
|
|
||||||
title = view_data['title'] + view_data.get('secondaryMark', '')
|
title = program_info['title'] + program_info.get('secondaryMark', '')
|
||||||
description = view_data.get('description')
|
description = program_info.get('description')
|
||||||
thumbnail = view_data.get('imageFile')
|
thumbnail = program_info.get('imageFile')
|
||||||
categories = [item['name'] for item in vod_data.get('category', [])]
|
categories = [item['name'] for item in program_info.get('category', [])]
|
||||||
episode = int_or_none(view_data.get('episode'))
|
episode = int_or_none(program_info.get('episode'))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': video_id,
|
||||||
|
@ -11,7 +11,7 @@ from ..utils import (
|
|||||||
|
|
||||||
|
|
||||||
class MovieClipsIE(InfoExtractor):
|
class MovieClipsIE(InfoExtractor):
|
||||||
_VALID_URL = r'https?://(?:www.)?movieclips\.com/videos/.+-(?P<id>\d+)(?:\?|$)'
|
_VALID_URL = r'https?://(?:www\.)?movieclips\.com/videos/.+-(?P<id>\d+)(?:\?|$)'
|
||||||
_TEST = {
|
_TEST = {
|
||||||
'url': 'http://www.movieclips.com/videos/warcraft-trailer-1-561180739597',
|
'url': 'http://www.movieclips.com/videos/warcraft-trailer-1-561180739597',
|
||||||
'md5': '42b5a0352d4933a7bd54f2104f481244',
|
'md5': '42b5a0352d4933a7bd54f2104f481244',
|
||||||
|
91
youtube_dl/extractor/pandatv.py
Normal file
91
youtube_dl/extractor/pandatv.py
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
ExtractorError,
|
||||||
|
qualities,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PandaTVIE(InfoExtractor):
|
||||||
|
IE_DESC = '熊猫TV'
|
||||||
|
_VALID_URL = r'http://(?:www\.)?panda\.tv/(?P<id>[0-9]+)'
|
||||||
|
_TEST = {
|
||||||
|
'url': 'http://www.panda.tv/10091',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '10091',
|
||||||
|
'title': 're:.+',
|
||||||
|
'uploader': '囚徒',
|
||||||
|
'ext': 'flv',
|
||||||
|
'is_live': True,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
'skip': 'Live stream is offline',
|
||||||
|
}
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
|
config = self._download_json(
|
||||||
|
'http://www.panda.tv/api_room?roomid=%s' % video_id, video_id)
|
||||||
|
|
||||||
|
error_code = config.get('errno', 0)
|
||||||
|
if error_code is not 0:
|
||||||
|
raise ExtractorError(
|
||||||
|
'%s returned error %s: %s'
|
||||||
|
% (self.IE_NAME, error_code, config['errmsg']),
|
||||||
|
expected=True)
|
||||||
|
|
||||||
|
data = config['data']
|
||||||
|
video_info = data['videoinfo']
|
||||||
|
|
||||||
|
# 2 = live, 3 = offline
|
||||||
|
if video_info.get('status') != '2':
|
||||||
|
raise ExtractorError(
|
||||||
|
'Live stream is offline', expected=True)
|
||||||
|
|
||||||
|
title = data['roominfo']['name']
|
||||||
|
uploader = data.get('hostinfo', {}).get('name')
|
||||||
|
room_key = video_info['room_key']
|
||||||
|
stream_addr = video_info.get(
|
||||||
|
'stream_addr', {'OD': '1', 'HD': '1', 'SD': '1'})
|
||||||
|
|
||||||
|
# Reverse engineered from web player swf
|
||||||
|
# (http://s6.pdim.gs/static/07153e425f581151.swf at the moment of
|
||||||
|
# writing).
|
||||||
|
plflag0, plflag1 = video_info['plflag'].split('_')
|
||||||
|
plflag0 = int(plflag0) - 1
|
||||||
|
if plflag1 == '21':
|
||||||
|
plflag0 = 10
|
||||||
|
plflag1 = '4'
|
||||||
|
live_panda = 'live_panda' if plflag0 < 1 else ''
|
||||||
|
|
||||||
|
quality_key = qualities(['OD', 'HD', 'SD'])
|
||||||
|
suffix = ['_small', '_mid', '']
|
||||||
|
formats = []
|
||||||
|
for k, v in stream_addr.items():
|
||||||
|
if v != '1':
|
||||||
|
continue
|
||||||
|
quality = quality_key(k)
|
||||||
|
if quality <= 0:
|
||||||
|
continue
|
||||||
|
for pref, (ext, pl) in enumerate((('m3u8', '-hls'), ('flv', ''))):
|
||||||
|
formats.append({
|
||||||
|
'url': 'http://pl%s%s.live.panda.tv/live_panda/%s%s%s.%s'
|
||||||
|
% (pl, plflag1, room_key, live_panda, suffix[quality], ext),
|
||||||
|
'format_id': '%s-%s' % (k, ext),
|
||||||
|
'quality': quality,
|
||||||
|
'source_preference': pref,
|
||||||
|
})
|
||||||
|
self._sort_formats(formats)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': video_id,
|
||||||
|
'title': self._live_title(title),
|
||||||
|
'uploader': uploader,
|
||||||
|
'formats': formats,
|
||||||
|
'is_live': True,
|
||||||
|
}
|
@ -11,6 +11,7 @@ from ..compat import (
|
|||||||
compat_urlparse,
|
compat_urlparse,
|
||||||
)
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
|
dict_get,
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
float_or_none,
|
float_or_none,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
@ -119,14 +120,17 @@ class PluralsightIE(PluralsightBaseIE):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _convert_subtitles(duration, subs):
|
def _convert_subtitles(duration, subs):
|
||||||
srt = ''
|
srt = ''
|
||||||
|
TIME_OFFSET_KEYS = ('displayTimeOffset', 'DisplayTimeOffset')
|
||||||
|
TEXT_KEYS = ('text', 'Text')
|
||||||
for num, current in enumerate(subs):
|
for num, current in enumerate(subs):
|
||||||
current = subs[num]
|
current = subs[num]
|
||||||
start, text = float_or_none(
|
start, text = (
|
||||||
current.get('DisplayTimeOffset')), current.get('Text')
|
float_or_none(dict_get(current, TIME_OFFSET_KEYS)),
|
||||||
|
dict_get(current, TEXT_KEYS))
|
||||||
if start is None or text is None:
|
if start is None or text is None:
|
||||||
continue
|
continue
|
||||||
end = duration if num == len(subs) - 1 else float_or_none(
|
end = duration if num == len(subs) - 1 else float_or_none(
|
||||||
subs[num + 1].get('DisplayTimeOffset'))
|
dict_get(subs[num + 1], TIME_OFFSET_KEYS))
|
||||||
if end is None:
|
if end is None:
|
||||||
continue
|
continue
|
||||||
srt += os.linesep.join(
|
srt += os.linesep.join(
|
||||||
|
76
youtube_dl/extractor/rentv.py
Normal file
76
youtube_dl/extractor/rentv.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# coding: utf-8
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from .jwplatform import JWPlatformBaseIE
|
||||||
|
from ..compat import compat_str
|
||||||
|
|
||||||
|
|
||||||
|
class RENTVIE(JWPlatformBaseIE):
|
||||||
|
_VALID_URL = r'(?:rentv:|https?://(?:www\.)?ren\.tv/(?:player|video/epizod)/)(?P<id>\d+)'
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'http://ren.tv/video/epizod/118577',
|
||||||
|
'md5': 'd91851bf9af73c0ad9b2cdf76c127fbb',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '118577',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Документальный спецпроект: "Промывка мозгов. Технологии XXI века"'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
'url': 'http://ren.tv/player/118577',
|
||||||
|
'only_matching': True,
|
||||||
|
}, {
|
||||||
|
'url': 'rentv:118577',
|
||||||
|
'only_matching': True,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
video_id = self._match_id(url)
|
||||||
|
webpage = self._download_webpage('http://ren.tv/player/' + video_id, video_id)
|
||||||
|
jw_config = self._parse_json(self._search_regex(
|
||||||
|
r'config\s*=\s*({.+});', webpage, 'jw config'), video_id)
|
||||||
|
return self._parse_jwplayer_data(jw_config, video_id, m3u8_id='hls')
|
||||||
|
|
||||||
|
|
||||||
|
class RENTVArticleIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?ren\.tv/novosti/\d{4}-\d{2}-\d{2}/(?P<id>[^/?#]+)'
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'http://ren.tv/novosti/2016-10-26/video-mikroavtobus-popavshiy-v-dtp-s-gruzovikami-v-podmoskove-prevratilsya-v',
|
||||||
|
'md5': 'ebd63c4680b167693745ab91343df1d6',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '136472',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Видео: микроавтобус, попавший в ДТП с грузовиками в Подмосковье, превратился в груду металла',
|
||||||
|
'description': 'Жертвами столкновения двух фур и микроавтобуса, по последним данным, стали семь человек.',
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
# TODO: invalid m3u8
|
||||||
|
'url': 'http://ren.tv/novosti/2015-09-25/sluchaynyy-prohozhiy-poymal-avtougonshchika-v-murmanske-video',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'playlist',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'Случайный прохожий поймал автоугонщика в Мурманске. ВИДЕО | РЕН ТВ',
|
||||||
|
'uploader': 'ren.tv',
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
# m3u8 downloads
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
'skip': True,
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
display_id = self._match_id(url)
|
||||||
|
webpage = self._download_webpage(url, display_id)
|
||||||
|
drupal_settings = self._parse_json(self._search_regex(
|
||||||
|
r'jQuery\.extend\(Drupal\.settings\s*,\s*({.+?})\);',
|
||||||
|
webpage, 'drupal settings'), display_id)
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
for config_profile in drupal_settings.get('ren_jwplayer', {}).values():
|
||||||
|
media_id = config_profile.get('mediaid')
|
||||||
|
if not media_id:
|
||||||
|
continue
|
||||||
|
media_id = compat_str(media_id)
|
||||||
|
entries.append(self.url_result('rentv:' + media_id, 'RENTV', media_id))
|
||||||
|
return self.playlist_result(entries, display_id)
|
@ -10,11 +10,38 @@ from ..utils import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SharedIE(InfoExtractor):
|
class SharedBaseIE(InfoExtractor):
|
||||||
IE_DESC = 'shared.sx and vivo.sx'
|
def _real_extract(self, url):
|
||||||
_VALID_URL = r'https?://(?:shared|vivo)\.sx/(?P<id>[\da-z]{10})'
|
video_id = self._match_id(url)
|
||||||
|
|
||||||
_TESTS = [{
|
webpage, urlh = self._download_webpage_handle(url, video_id)
|
||||||
|
|
||||||
|
if self._FILE_NOT_FOUND in webpage:
|
||||||
|
raise ExtractorError(
|
||||||
|
'Video %s does not exist' % video_id, expected=True)
|
||||||
|
|
||||||
|
video_url = self._extract_video_url(webpage, video_id, url)
|
||||||
|
|
||||||
|
title = base64.b64decode(self._html_search_meta(
|
||||||
|
'full:title', webpage, 'title').encode('utf-8')).decode('utf-8')
|
||||||
|
filesize = int_or_none(self._html_search_meta(
|
||||||
|
'full:size', webpage, 'file size', fatal=False))
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': video_id,
|
||||||
|
'url': video_url,
|
||||||
|
'ext': 'mp4',
|
||||||
|
'filesize': filesize,
|
||||||
|
'title': title,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SharedIE(SharedBaseIE):
|
||||||
|
IE_DESC = 'shared.sx'
|
||||||
|
_VALID_URL = r'https?://shared\.sx/(?P<id>[\da-z]{10})'
|
||||||
|
_FILE_NOT_FOUND = '>File does not exist<'
|
||||||
|
|
||||||
|
_TEST = {
|
||||||
'url': 'http://shared.sx/0060718775',
|
'url': 'http://shared.sx/0060718775',
|
||||||
'md5': '106fefed92a8a2adb8c98e6a0652f49b',
|
'md5': '106fefed92a8a2adb8c98e6a0652f49b',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
@ -23,7 +50,32 @@ class SharedIE(InfoExtractor):
|
|||||||
'title': 'Bmp4',
|
'title': 'Bmp4',
|
||||||
'filesize': 1720110,
|
'filesize': 1720110,
|
||||||
},
|
},
|
||||||
}, {
|
}
|
||||||
|
|
||||||
|
def _extract_video_url(self, webpage, video_id, url):
|
||||||
|
download_form = self._hidden_inputs(webpage)
|
||||||
|
|
||||||
|
video_page = self._download_webpage(
|
||||||
|
url, video_id, 'Downloading video page',
|
||||||
|
data=urlencode_postdata(download_form),
|
||||||
|
headers={
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
'Referer': url,
|
||||||
|
})
|
||||||
|
|
||||||
|
video_url = self._html_search_regex(
|
||||||
|
r'data-url=(["\'])(?P<url>(?:(?!\1).)+)\1',
|
||||||
|
video_page, 'video URL', group='url')
|
||||||
|
|
||||||
|
return video_url
|
||||||
|
|
||||||
|
|
||||||
|
class VivoIE(SharedBaseIE):
|
||||||
|
IE_DESC = 'vivo.sx'
|
||||||
|
_VALID_URL = r'https?://vivo\.sx/(?P<id>[\da-z]{10})'
|
||||||
|
_FILE_NOT_FOUND = '>The file you have requested does not exists or has been removed'
|
||||||
|
|
||||||
|
_TEST = {
|
||||||
'url': 'http://vivo.sx/d7ddda0e78',
|
'url': 'http://vivo.sx/d7ddda0e78',
|
||||||
'md5': '15b3af41be0b4fe01f4df075c2678b2c',
|
'md5': '15b3af41be0b4fe01f4df075c2678b2c',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
@ -32,43 +84,13 @@ class SharedIE(InfoExtractor):
|
|||||||
'title': 'Chicken',
|
'title': 'Chicken',
|
||||||
'filesize': 528031,
|
'filesize': 528031,
|
||||||
},
|
},
|
||||||
}]
|
}
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _extract_video_url(self, webpage, video_id, *args):
|
||||||
video_id = self._match_id(url)
|
return self._parse_json(
|
||||||
|
self._search_regex(
|
||||||
webpage, urlh = self._download_webpage_handle(url, video_id)
|
r'InitializeStream\s*\(\s*(["\'])(?P<url>(?:(?!\1).)+)\1',
|
||||||
|
webpage, 'stream', group='url'),
|
||||||
if '>File does not exist<' in webpage:
|
video_id,
|
||||||
raise ExtractorError(
|
transform_source=lambda x: base64.b64decode(
|
||||||
'Video %s does not exist' % video_id, expected=True)
|
x.encode('ascii')).decode('utf-8'))[0]
|
||||||
|
|
||||||
download_form = self._hidden_inputs(webpage)
|
|
||||||
|
|
||||||
video_page = self._download_webpage(
|
|
||||||
urlh.geturl(), video_id, 'Downloading video page',
|
|
||||||
data=urlencode_postdata(download_form),
|
|
||||||
headers={
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
'Referer': urlh.geturl(),
|
|
||||||
})
|
|
||||||
|
|
||||||
video_url = self._html_search_regex(
|
|
||||||
r'data-url=(["\'])(?P<url>(?:(?!\1).)+)\1',
|
|
||||||
video_page, 'video URL', group='url')
|
|
||||||
title = base64.b64decode(self._html_search_meta(
|
|
||||||
'full:title', webpage, 'title').encode('utf-8')).decode('utf-8')
|
|
||||||
filesize = int_or_none(self._html_search_meta(
|
|
||||||
'full:size', webpage, 'file size', fatal=False))
|
|
||||||
thumbnail = self._html_search_regex(
|
|
||||||
r'data-poster=(["\'])(?P<url>(?:(?!\1).)+)\1',
|
|
||||||
video_page, 'thumbnail', default=None, group='url')
|
|
||||||
|
|
||||||
return {
|
|
||||||
'id': video_id,
|
|
||||||
'url': video_url,
|
|
||||||
'ext': 'mp4',
|
|
||||||
'filesize': filesize,
|
|
||||||
'title': title,
|
|
||||||
'thumbnail': thumbnail,
|
|
||||||
}
|
|
||||||
|
@ -398,7 +398,7 @@ class TwitchStreamIE(TwitchBaseIE):
|
|||||||
channel_id = self._match_id(url)
|
channel_id = self._match_id(url)
|
||||||
|
|
||||||
stream = self._call_api(
|
stream = self._call_api(
|
||||||
'kraken/streams/%s' % channel_id, channel_id,
|
'kraken/streams/%s?stream_type=all' % channel_id, channel_id,
|
||||||
'Downloading stream JSON').get('stream')
|
'Downloading stream JSON').get('stream')
|
||||||
|
|
||||||
if not stream:
|
if not stream:
|
||||||
@ -417,6 +417,7 @@ class TwitchStreamIE(TwitchBaseIE):
|
|||||||
query = {
|
query = {
|
||||||
'allow_source': 'true',
|
'allow_source': 'true',
|
||||||
'allow_audio_only': 'true',
|
'allow_audio_only': 'true',
|
||||||
|
'allow_spectre': 'true',
|
||||||
'p': random.randint(1000000, 10000000),
|
'p': random.randint(1000000, 10000000),
|
||||||
'player': 'twitchweb',
|
'player': 'twitchweb',
|
||||||
'segment_preference': '4',
|
'segment_preference': '4',
|
||||||
|
@ -322,6 +322,22 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
|||||||
},
|
},
|
||||||
'expected_warnings': ['Unable to download JSON metadata'],
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
# redirects to ondemand extractor and should be passed throught it
|
||||||
|
# for successful extraction
|
||||||
|
'url': 'https://vimeo.com/73445910',
|
||||||
|
'info_dict': {
|
||||||
|
'id': '73445910',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'The Reluctant Revolutionary',
|
||||||
|
'uploader': '10Ft Films',
|
||||||
|
'uploader_url': 're:https?://(?:www\.)?vimeo\.com/tenfootfilms',
|
||||||
|
'uploader_id': 'tenfootfilms',
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'skip_download': True,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'url': 'http://vimeo.com/moogaloop.swf?clip_id=2539741',
|
'url': 'http://vimeo.com/moogaloop.swf?clip_id=2539741',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
@ -414,7 +430,12 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
|||||||
# Retrieve video webpage to extract further information
|
# Retrieve video webpage to extract further information
|
||||||
request = sanitized_Request(url, headers=headers)
|
request = sanitized_Request(url, headers=headers)
|
||||||
try:
|
try:
|
||||||
webpage = self._download_webpage(request, video_id)
|
webpage, urlh = self._download_webpage_handle(request, video_id)
|
||||||
|
# Some URLs redirect to ondemand can't be extracted with
|
||||||
|
# this extractor right away thus should be passed through
|
||||||
|
# ondemand extractor (e.g. https://vimeo.com/73445910)
|
||||||
|
if VimeoOndemandIE.suitable(urlh.geturl()):
|
||||||
|
return self.url_result(urlh.geturl(), VimeoOndemandIE.ie_key())
|
||||||
except ExtractorError as ee:
|
except ExtractorError as ee:
|
||||||
if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 403:
|
if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 403:
|
||||||
errmsg = ee.cause.read()
|
errmsg = ee.cause.read()
|
||||||
|
@ -3,7 +3,6 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import collections
|
import collections
|
||||||
import re
|
import re
|
||||||
import json
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .common import InfoExtractor
|
from .common import InfoExtractor
|
||||||
@ -369,8 +368,18 @@ class VKIE(VKBaseIE):
|
|||||||
opts_url = 'http:' + opts_url
|
opts_url = 'http:' + opts_url
|
||||||
return self.url_result(opts_url)
|
return self.url_result(opts_url)
|
||||||
|
|
||||||
data_json = self._search_regex(r'var\s+vars\s*=\s*({.+?});', info_page, 'vars')
|
# vars does not look to be served anymore since 24.10.2016
|
||||||
data = json.loads(data_json)
|
data = self._parse_json(
|
||||||
|
self._search_regex(
|
||||||
|
r'var\s+vars\s*=\s*({.+?});', info_page, 'vars', default='{}'),
|
||||||
|
video_id, fatal=False)
|
||||||
|
|
||||||
|
# <!json> is served instead
|
||||||
|
if not data:
|
||||||
|
data = self._parse_json(
|
||||||
|
self._search_regex(
|
||||||
|
r'<!json>\s*({.+?})\s*<!>', info_page, 'json'),
|
||||||
|
video_id)['player']['params'][0]
|
||||||
|
|
||||||
title = unescapeHTML(data['md_title'])
|
title = unescapeHTML(data['md_title'])
|
||||||
|
|
||||||
|
@ -1818,8 +1818,12 @@ def get_exe_version(exe, args=['--version'],
|
|||||||
""" Returns the version of the specified executable,
|
""" Returns the version of the specified executable,
|
||||||
or False if the executable is not present """
|
or False if the executable is not present """
|
||||||
try:
|
try:
|
||||||
|
# STDIN should be redirected too. On UNIX-like systems, ffmpeg triggers
|
||||||
|
# SIGTTOU if youtube-dl is run in the background.
|
||||||
|
# See https://github.com/rg3/youtube-dl/issues/955#issuecomment-209789656
|
||||||
out, _ = subprocess.Popen(
|
out, _ = subprocess.Popen(
|
||||||
[encodeArgument(exe)] + args,
|
[encodeArgument(exe)] + args,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT).communicate()
|
||||||
except OSError:
|
except OSError:
|
||||||
return False
|
return False
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '2016.10.21.1'
|
__version__ = '2016.10.26'
|
||||||
|
Reference in New Issue
Block a user