mirror of
https://gitlab.com/ytdl-org/youtube-dl.git
synced 2026-04-28 00:00:09 -04:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18ece70c4d | |||
| 9ed3495eae | |||
| 6c20a0bb99 | |||
| f43795e56b | |||
| 7441915b1e | |||
| 283d1c6a8b | |||
| 875ddd7409 | |||
| 4afa4ff223 | |||
| 3ed81714d8 | |||
| 4bd7d9d4ae | |||
| 9b5288c92a | |||
| 8344296619 | |||
| a94e7f4a0c | |||
| d17bfe4095 | |||
| 98b08f94b1 |
@@ -6,8 +6,8 @@
|
||||
|
||||
---
|
||||
|
||||
### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2016.12.01*. 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.12.01**
|
||||
### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2016.12.09*. 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.12.09**
|
||||
|
||||
### 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
|
||||
@@ -35,7 +35,7 @@ $ youtube-dl -v <your command line>
|
||||
[debug] User config: []
|
||||
[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] youtube-dl version 2016.12.01
|
||||
[debug] youtube-dl version 2016.12.09
|
||||
[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] Proxy map: {}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
version 2016.12.09
|
||||
|
||||
Core
|
||||
* [socks] Fix error reporting (#11355)
|
||||
|
||||
Extractors
|
||||
* [openload] Fix extraction (#10408)
|
||||
* [pandoratv] Fix extraction (#11023)
|
||||
+ [telebruxelles] Add support for emission URLs
|
||||
* [telebruxelles] Extract all formats
|
||||
+ [bloomberg] Add another video id regular expression (#11371)
|
||||
* [fusion] Update ooyala id regular expression (#11364)
|
||||
+ [1tv] Add support for playlists (#11335)
|
||||
* [1tv] Improve extraction (#11335)
|
||||
+ [aenetworks] Extract more formats (#11321)
|
||||
+ [thisoldhouse] Recognize /tv-episode/ URLs (#11271)
|
||||
|
||||
version 2016.12.01
|
||||
|
||||
Extractors
|
||||
|
||||
@@ -664,7 +664,7 @@ $ youtube-dl -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'
|
||||
# Download best format available but not better that 480p
|
||||
$ youtube-dl -f 'bestvideo[height<=480]+bestaudio/best[height<=480]'
|
||||
|
||||
# Download best video only format but no bigger that 50 MB
|
||||
# Download best video only format but no bigger than 50 MB
|
||||
$ youtube-dl -f 'best[filesize<50M]'
|
||||
|
||||
# Download best format available via direct link over HTTP/HTTPS protocol
|
||||
|
||||
@@ -26,7 +26,7 @@ class AENetworksIE(AENetworksBaseIE):
|
||||
_VALID_URL = r'https?://(?:www\.)?(?P<domain>(?:history|aetv|mylifetime)\.com|fyi\.tv)/(?:shows/(?P<show_path>[^/]+(?:/[^/]+){0,2})|movies/(?P<movie_display_id>[^/]+)/full-movie)'
|
||||
_TESTS = [{
|
||||
'url': 'http://www.history.com/shows/mountain-men/season-1/episode-1',
|
||||
'md5': '8ff93eb073449f151d6b90c0ae1ef0c7',
|
||||
'md5': 'a97a65f7e823ae10e9244bc5433d5fe6',
|
||||
'info_dict': {
|
||||
'id': '22253814',
|
||||
'ext': 'mp4',
|
||||
@@ -99,7 +99,7 @@ class AENetworksIE(AENetworksBaseIE):
|
||||
|
||||
query = {
|
||||
'mbr': 'true',
|
||||
'assetTypes': 'medium_video_s3'
|
||||
'assetTypes': 'high_video_s3'
|
||||
}
|
||||
video_id = self._html_search_meta('aetn:VideoID', webpage)
|
||||
media_url = self._search_regex(
|
||||
@@ -155,7 +155,7 @@ class HistoryTopicIE(AENetworksBaseIE):
|
||||
'id': 'world-war-i-history',
|
||||
'title': 'World War I History',
|
||||
},
|
||||
'playlist_mincount': 24,
|
||||
'playlist_mincount': 23,
|
||||
}, {
|
||||
'url': 'http://www.history.com/topics/world-war-i-history/videos',
|
||||
'only_matching': True,
|
||||
@@ -193,7 +193,8 @@ class HistoryTopicIE(AENetworksBaseIE):
|
||||
return self.theplatform_url_result(
|
||||
release_url, video_id, {
|
||||
'mbr': 'true',
|
||||
'switch': 'hls'
|
||||
'switch': 'hls',
|
||||
'assetTypes': 'high_video_ak',
|
||||
})
|
||||
else:
|
||||
webpage = self._download_webpage(url, topic_id)
|
||||
@@ -203,6 +204,7 @@ class HistoryTopicIE(AENetworksBaseIE):
|
||||
entries.append(self.theplatform_url_result(
|
||||
video_attributes['data-release-url'], video_attributes['data-id'], {
|
||||
'mbr': 'true',
|
||||
'switch': 'hls'
|
||||
'switch': 'hls',
|
||||
'assetTypes': 'high_video_ak',
|
||||
}))
|
||||
return self.playlist_result(entries, topic_id, get_element_by_attribute('class', 'show-title', webpage))
|
||||
|
||||
@@ -45,7 +45,8 @@ class BloombergIE(InfoExtractor):
|
||||
name = self._match_id(url)
|
||||
webpage = self._download_webpage(url, name)
|
||||
video_id = self._search_regex(
|
||||
r'["\']bmmrId["\']\s*:\s*(["\'])(?P<url>.+?)\1',
|
||||
(r'["\']bmmrId["\']\s*:\s*(["\'])(?P<url>(?:(?!\1).)+)\1',
|
||||
r'videoId\s*:\s*(["\'])(?P<url>(?:(?!\1).)+)\1'),
|
||||
webpage, 'id', group='url', default=None)
|
||||
if not video_id:
|
||||
bplayer_data = self._parse_json(self._search_regex(
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..compat import compat_urlparse
|
||||
from ..compat import (
|
||||
compat_str,
|
||||
compat_urlparse,
|
||||
)
|
||||
from ..utils import (
|
||||
int_or_none,
|
||||
qualities,
|
||||
@@ -22,8 +25,7 @@ class FirstTVIE(InfoExtractor):
|
||||
'info_dict': {
|
||||
'id': '40049',
|
||||
'ext': 'mp4',
|
||||
'title': 'Гость Людмила Сенчина. Наедине со всеми. Выпуск от 12.02.2015',
|
||||
'description': 'md5:36a39c1d19618fec57d12efe212a8370',
|
||||
'title': 'Гость Людмила Сенчина. Наедине со всеми. Выпуск от 12.02.2015',
|
||||
'thumbnail': 're:^https?://.*\.(?:jpg|JPG)$',
|
||||
'upload_date': '20150212',
|
||||
'duration': 2694,
|
||||
@@ -34,8 +36,7 @@ class FirstTVIE(InfoExtractor):
|
||||
'info_dict': {
|
||||
'id': '364746',
|
||||
'ext': 'mp4',
|
||||
'title': 'Весенняя аллергия. Доброе утро. Фрагмент выпуска от 07.04.2016',
|
||||
'description': 'md5:a242eea0031fd180a4497d52640a9572',
|
||||
'title': 'Весенняя аллергия. Доброе утро. Фрагмент выпуска от 07.04.2016',
|
||||
'thumbnail': 're:^https?://.*\.(?:jpg|JPG)$',
|
||||
'upload_date': '20160407',
|
||||
'duration': 179,
|
||||
@@ -44,6 +45,17 @@ class FirstTVIE(InfoExtractor):
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}, {
|
||||
'url': 'http://www.1tv.ru/news/issue/2016-12-01/14:00',
|
||||
'info_dict': {
|
||||
'id': '14:00',
|
||||
'title': 'Выпуск новостей в 14:00 1 декабря 2016 года. Новости. Первый канал',
|
||||
'description': 'md5:2e921b948f8c1ff93901da78ebdb1dfd',
|
||||
},
|
||||
'playlist_count': 13,
|
||||
}, {
|
||||
'url': 'http://www.1tv.ru/shows/tochvtoch-supersezon/vystupleniya/evgeniy-dyatlov-vladimir-vysockiy-koni-priveredlivye-toch-v-toch-supersezon-fragment-vypuska-ot-06-11-2016',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
@@ -51,43 +63,66 @@ class FirstTVIE(InfoExtractor):
|
||||
|
||||
webpage = self._download_webpage(url, display_id)
|
||||
playlist_url = compat_urlparse.urljoin(url, self._search_regex(
|
||||
r'data-playlist-url="([^"]+)', webpage, 'playlist url'))
|
||||
r'data-playlist-url=(["\'])(?P<url>(?:(?!\1).)+)\1',
|
||||
webpage, 'playlist url', group='url'))
|
||||
|
||||
item = self._download_json(playlist_url, display_id)[0]
|
||||
video_id = item['id']
|
||||
quality = qualities(('ld', 'sd', 'hd', ))
|
||||
formats = []
|
||||
for f in item.get('mbr', []):
|
||||
src = f.get('src')
|
||||
if not src:
|
||||
continue
|
||||
fname = f.get('name')
|
||||
formats.append({
|
||||
'url': src,
|
||||
'format_id': fname,
|
||||
'quality': quality(fname),
|
||||
parsed_url = compat_urlparse.urlparse(playlist_url)
|
||||
qs = compat_urlparse.parse_qs(parsed_url.query)
|
||||
item_ids = qs.get('videos_ids[]') or qs.get('news_ids[]')
|
||||
|
||||
items = self._download_json(playlist_url, display_id)
|
||||
|
||||
if item_ids:
|
||||
items = [
|
||||
item for item in items
|
||||
if item.get('uid') and compat_str(item['uid']) in item_ids]
|
||||
else:
|
||||
items = [items[0]]
|
||||
|
||||
entries = []
|
||||
QUALITIES = ('ld', 'sd', 'hd', )
|
||||
|
||||
for item in items:
|
||||
title = item['title']
|
||||
quality = qualities(QUALITIES)
|
||||
formats = []
|
||||
for f in item.get('mbr', []):
|
||||
src = f.get('src')
|
||||
if not src or not isinstance(src, compat_str):
|
||||
continue
|
||||
tbr = int_or_none(self._search_regex(
|
||||
r'_(\d{3,})\.mp4', src, 'tbr', default=None))
|
||||
formats.append({
|
||||
'url': src,
|
||||
'format_id': f.get('name'),
|
||||
'tbr': tbr,
|
||||
'quality': quality(f.get('name')),
|
||||
})
|
||||
self._sort_formats(formats)
|
||||
|
||||
thumbnail = item.get('poster') or self._og_search_thumbnail(webpage)
|
||||
duration = int_or_none(item.get('duration') or self._html_search_meta(
|
||||
'video:duration', webpage, 'video duration', fatal=False))
|
||||
upload_date = unified_strdate(self._html_search_meta(
|
||||
'ya:ovs:upload_date', webpage, 'upload date', default=None))
|
||||
|
||||
entries.append({
|
||||
'id': compat_str(item.get('id') or item['uid']),
|
||||
'thumbnail': thumbnail,
|
||||
'title': title,
|
||||
'upload_date': upload_date,
|
||||
'duration': int_or_none(duration),
|
||||
'formats': formats
|
||||
})
|
||||
self._sort_formats(formats)
|
||||
|
||||
title = self._html_search_regex(
|
||||
(r'<div class="tv_translation">\s*<h1><a href="[^"]+">([^<]*)</a>',
|
||||
r"'title'\s*:\s*'([^']+)'"),
|
||||
webpage, 'title', default=None) or item['title']
|
||||
webpage, 'title', default=None) or self._og_search_title(
|
||||
webpage, default=None)
|
||||
description = self._html_search_regex(
|
||||
r'<div class="descr">\s*<div> </div>\s*<p>([^<]*)</p></div>',
|
||||
webpage, 'description', default=None) or self._html_search_meta(
|
||||
'description', webpage, 'description')
|
||||
duration = int_or_none(self._html_search_meta(
|
||||
'video:duration', webpage, 'video duration', fatal=False))
|
||||
upload_date = unified_strdate(self._html_search_meta(
|
||||
'ya:ovs:upload_date', webpage, 'upload date', fatal=False))
|
||||
'description', webpage, 'description', default=None)
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'thumbnail': item.get('poster') or self._og_search_thumbnail(webpage),
|
||||
'title': title,
|
||||
'description': description,
|
||||
'upload_date': upload_date,
|
||||
'duration': int_or_none(duration),
|
||||
'formats': formats
|
||||
}
|
||||
return self.playlist_result(entries, display_id, title, description)
|
||||
|
||||
@@ -29,7 +29,7 @@ class FusionIE(InfoExtractor):
|
||||
webpage = self._download_webpage(url, display_id)
|
||||
|
||||
ooyala_code = self._search_regex(
|
||||
r'data-video-id=(["\'])(?P<code>.+?)\1',
|
||||
r'data-ooyala-id=(["\'])(?P<code>(?:(?!\1).)+)\1',
|
||||
webpage, 'ooyala code', group='code')
|
||||
|
||||
return OoyalaIE._build_url_result(ooyala_code)
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
# coding: utf-8
|
||||
from __future__ import unicode_literals, division
|
||||
|
||||
import re
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..compat import (
|
||||
compat_chr,
|
||||
compat_ord,
|
||||
)
|
||||
from ..compat import compat_chr
|
||||
from ..utils import (
|
||||
determine_ext,
|
||||
ExtractorError,
|
||||
)
|
||||
from ..jsinterp import (
|
||||
JSInterpreter,
|
||||
_NAME_RE
|
||||
)
|
||||
|
||||
|
||||
class OpenloadIE(InfoExtractor):
|
||||
@@ -62,44 +53,6 @@ class OpenloadIE(InfoExtractor):
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
def openload_decode(self, txt):
|
||||
symbol_dict = {
|
||||
'(゚Д゚) [゚Θ゚]': '_',
|
||||
'(゚Д゚) [゚ω゚ノ]': 'a',
|
||||
'(゚Д゚) [゚Θ゚ノ]': 'b',
|
||||
'(゚Д゚) [\'c\']': 'c',
|
||||
'(゚Д゚) [゚ー゚ノ]': 'd',
|
||||
'(゚Д゚) [゚Д゚ノ]': 'e',
|
||||
'(゚Д゚) [1]': 'f',
|
||||
'(゚Д゚) [\'o\']': 'o',
|
||||
'(o゚ー゚o)': 'u',
|
||||
'(゚Д゚) [\'c\']': 'c',
|
||||
'((゚ー゚) + (o^_^o))': '7',
|
||||
'((o^_^o) +(o^_^o) +(c^_^o))': '6',
|
||||
'((゚ー゚) + (゚Θ゚))': '5',
|
||||
'(-~3)': '4',
|
||||
'(-~-~1)': '3',
|
||||
'(-~1)': '2',
|
||||
'(-~0)': '1',
|
||||
'((c^_^o)-(c^_^o))': '0',
|
||||
}
|
||||
delim = '(゚Д゚)[゚ε゚]+'
|
||||
end_token = '(゚Д゚)[゚o゚]'
|
||||
symbols = '|'.join(map(re.escape, symbol_dict.keys()))
|
||||
txt = re.sub('(%s)\+\s?' % symbols, lambda m: symbol_dict[m.group(1)], txt)
|
||||
ret = ''
|
||||
for aacode in re.findall(r'{0}\+\s?{1}(.*?){0}'.format(re.escape(end_token), re.escape(delim)), txt):
|
||||
for aachar in aacode.split(delim):
|
||||
if aachar.isdigit():
|
||||
ret += compat_chr(int(aachar, 8))
|
||||
else:
|
||||
m = re.match(r'^u([\da-f]{4})$', aachar)
|
||||
if m:
|
||||
ret += compat_chr(int(m.group(1), 16))
|
||||
else:
|
||||
self.report_warning("Cannot decode: %s" % aachar)
|
||||
return ret
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
webpage = self._download_webpage('https://openload.co/embed/%s/' % video_id, video_id)
|
||||
@@ -107,36 +60,20 @@ class OpenloadIE(InfoExtractor):
|
||||
if 'File not found' in webpage or 'deleted by the owner' in webpage:
|
||||
raise ExtractorError('File not found', expected=True)
|
||||
|
||||
# The following decryption algorithm is written by @yokrysty and
|
||||
# declared to be freely used in youtube-dl
|
||||
# See https://github.com/rg3/youtube-dl/issues/10408
|
||||
enc_data = self._html_search_regex(
|
||||
r'<span[^>]*>([^<]+)</span>\s*<span[^>]*>[^<]+</span>\s*<span[^>]+id="streamurl"',
|
||||
webpage, 'encrypted data')
|
||||
ol_id = self._search_regex(
|
||||
'<span[^>]+id="[a-zA-Z0-9]+x"[^>]*>([0-9]+)</span>',
|
||||
webpage, 'openload ID')
|
||||
|
||||
enc_code = self._html_search_regex(r'<script[^>]+>(゚ω゚[^<]+)</script>',
|
||||
webpage, 'encrypted code')
|
||||
first_two_chars = int(float(ol_id[0:][:2]))
|
||||
urlcode = ''
|
||||
num = 2
|
||||
|
||||
js_code = self.openload_decode(enc_code)
|
||||
jsi = JSInterpreter(js_code)
|
||||
while num < len(ol_id):
|
||||
urlcode += compat_chr(int(float(ol_id[num:][:3])) -
|
||||
first_two_chars * int(float(ol_id[num + 3:][:2])))
|
||||
num += 5
|
||||
|
||||
m_offset_fun = self._search_regex(r'slice\(0\s*-\s*(%s)\(\)' % _NAME_RE, js_code, 'javascript offset function')
|
||||
m_diff_fun = self._search_regex(r'charCodeAt\(0\)\s*\+\s*(%s)\(\)' % _NAME_RE, js_code, 'javascript diff function')
|
||||
|
||||
offset = jsi.call_function(m_offset_fun)
|
||||
diff = jsi.call_function(m_diff_fun)
|
||||
|
||||
video_url_chars = []
|
||||
|
||||
for idx, c in enumerate(enc_data):
|
||||
j = compat_ord(c)
|
||||
if j >= 33 and j <= 126:
|
||||
j = ((j + 14) % 94) + 33
|
||||
if idx == len(enc_data) - offset:
|
||||
j += diff
|
||||
video_url_chars += compat_chr(j)
|
||||
|
||||
video_url = 'https://openload.co/stream/%s?mime=true' % ''.join(video_url_chars)
|
||||
video_url = 'https://openload.co/stream/' + urlcode
|
||||
|
||||
title = self._og_search_title(webpage, default=None) or self._search_regex(
|
||||
r'<span[^>]+class=["\']title["\'][^>]*>([^<]+)', webpage,
|
||||
@@ -155,5 +92,4 @@ class OpenloadIE(InfoExtractor):
|
||||
'ext': determine_ext(title),
|
||||
'subtitles': subtitles,
|
||||
}
|
||||
|
||||
return info_dict
|
||||
|
||||
@@ -11,6 +11,7 @@ from ..utils import (
|
||||
float_or_none,
|
||||
parse_duration,
|
||||
str_to_int,
|
||||
urlencode_postdata,
|
||||
)
|
||||
|
||||
|
||||
@@ -56,6 +57,22 @@ class PandoraTVIE(InfoExtractor):
|
||||
r'^v(\d+)[Uu]rl$', format_id, 'height', default=None)
|
||||
if not height:
|
||||
continue
|
||||
|
||||
play_url = self._download_json(
|
||||
'http://m.pandora.tv/?c=api&m=play_url', video_id,
|
||||
data=urlencode_postdata({
|
||||
'prgid': video_id,
|
||||
'runtime': info.get('runtime'),
|
||||
'vod_url': format_url,
|
||||
}),
|
||||
headers={
|
||||
'Origin': url,
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
})
|
||||
format_url = play_url.get('url')
|
||||
if not format_url:
|
||||
continue
|
||||
|
||||
formats.append({
|
||||
'format_id': '%sp' % height,
|
||||
'url': format_url,
|
||||
|
||||
@@ -7,33 +7,30 @@ from .common import InfoExtractor
|
||||
|
||||
|
||||
class TeleBruxellesIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?(?:telebruxelles|bx1)\.be/(news|sport|dernier-jt)/?(?P<id>[^/#?]+)'
|
||||
_VALID_URL = r'https?://(?:www\.)?(?:telebruxelles|bx1)\.be/(news|sport|dernier-jt|emission)/?(?P<id>[^/#?]+)'
|
||||
_TESTS = [{
|
||||
'url': 'http://www.telebruxelles.be/news/auditions-devant-parlement-francken-galant-tres-attendus/',
|
||||
'md5': '59439e568c9ee42fb77588b2096b214f',
|
||||
'url': 'http://bx1.be/news/que-risque-lauteur-dune-fausse-alerte-a-la-bombe/',
|
||||
'md5': 'a2a67a5b1c3e8c9d33109b902f474fd9',
|
||||
'info_dict': {
|
||||
'id': '11942',
|
||||
'display_id': 'auditions-devant-parlement-francken-galant-tres-attendus',
|
||||
'ext': 'flv',
|
||||
'title': 'Parlement : Francken et Galant répondent aux interpellations de l’opposition',
|
||||
'description': 're:Les auditions des ministres se poursuivent*'
|
||||
},
|
||||
'params': {
|
||||
'skip_download': 'requires rtmpdump'
|
||||
'id': '158856',
|
||||
'display_id': 'que-risque-lauteur-dune-fausse-alerte-a-la-bombe',
|
||||
'ext': 'mp4',
|
||||
'title': 'Que risque l’auteur d’une fausse alerte à la bombe ?',
|
||||
'description': 'md5:3cf8df235d44ebc5426373050840e466',
|
||||
},
|
||||
}, {
|
||||
'url': 'http://www.telebruxelles.be/sport/basket-brussels-bat-mons-80-74/',
|
||||
'md5': '181d3fbdcf20b909309e5aef5c6c6047',
|
||||
'url': 'http://bx1.be/sport/futsal-schaerbeek-sincline-5-3-a-thulin/',
|
||||
'md5': 'dfe07ecc9c153ceba8582ac912687675',
|
||||
'info_dict': {
|
||||
'id': '10091',
|
||||
'display_id': 'basket-brussels-bat-mons-80-74',
|
||||
'ext': 'flv',
|
||||
'title': 'Basket : le Brussels bat Mons 80-74',
|
||||
'description': 're:^Ils l\u2019on fait ! En basket, le B*',
|
||||
},
|
||||
'params': {
|
||||
'skip_download': 'requires rtmpdump'
|
||||
'id': '158433',
|
||||
'display_id': 'futsal-schaerbeek-sincline-5-3-a-thulin',
|
||||
'ext': 'mp4',
|
||||
'title': 'Futsal : Schaerbeek s’incline 5-3 à Thulin',
|
||||
'description': 'md5:fd013f1488d5e2dceb9cebe39e2d569b',
|
||||
},
|
||||
}, {
|
||||
'url': 'http://bx1.be/emission/bxenf1-gastronomie/',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
@@ -50,13 +47,13 @@ class TeleBruxellesIE(InfoExtractor):
|
||||
r'file\s*:\s*"(rtmp://[^/]+/vod/mp4:"\s*\+\s*"[^"]+"\s*\+\s*".mp4)"',
|
||||
webpage, 'RTMP url')
|
||||
rtmp_url = re.sub(r'"\s*\+\s*"', '', rtmp_url)
|
||||
formats = self._extract_wowza_formats(rtmp_url, article_id or display_id)
|
||||
self._sort_formats(formats)
|
||||
|
||||
return {
|
||||
'id': article_id or display_id,
|
||||
'display_id': display_id,
|
||||
'title': title,
|
||||
'description': description,
|
||||
'url': rtmp_url,
|
||||
'ext': 'flv',
|
||||
'rtmp_live': True # if rtmpdump is not called with "--live" argument, the download is blocked and can be completed
|
||||
'formats': formats,
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ from .common import InfoExtractor
|
||||
|
||||
|
||||
class ThisOldHouseIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?thisoldhouse\.com/(?:watch|how-to)/(?P<id>[^/?#]+)'
|
||||
_VALID_URL = r'https?://(?:www\.)?thisoldhouse\.com/(?:watch|how-to|tv-episode)/(?P<id>[^/?#]+)'
|
||||
_TESTS = [{
|
||||
'url': 'https://www.thisoldhouse.com/how-to/how-to-build-storage-bench',
|
||||
'md5': '568acf9ca25a639f0c4ff905826b662f',
|
||||
'md5': '946f05bbaa12a33f9ae35580d2dfcfe3',
|
||||
'info_dict': {
|
||||
'id': '2REGtUDQ',
|
||||
'ext': 'mp4',
|
||||
@@ -20,6 +20,9 @@ class ThisOldHouseIE(InfoExtractor):
|
||||
}, {
|
||||
'url': 'https://www.thisoldhouse.com/watch/arlington-arts-crafts-arts-and-crafts-class-begins',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'https://www.thisoldhouse.com/tv-episode/ask-toh-shelf-rough-electric',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
|
||||
+3
-3
@@ -55,12 +55,12 @@ class Socks5AddressType(object):
|
||||
ATYP_IPV6 = 0x04
|
||||
|
||||
|
||||
class ProxyError(IOError):
|
||||
class ProxyError(socket.error):
|
||||
ERR_SUCCESS = 0x00
|
||||
|
||||
def __init__(self, code=None, msg=None):
|
||||
if code is not None and msg is None:
|
||||
msg = self.CODES.get(code) and 'unknown error'
|
||||
msg = self.CODES.get(code) or 'unknown error'
|
||||
super(ProxyError, self).__init__(code, msg)
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ class sockssocket(socket.socket):
|
||||
while len(data) < cnt:
|
||||
cur = self.recv(cnt - len(data))
|
||||
if not cur:
|
||||
raise IOError('{0} bytes missing'.format(cnt - len(data)))
|
||||
raise EOFError('{0} bytes missing'.format(cnt - len(data)))
|
||||
data += cur
|
||||
return data
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__version__ = '2016.12.01'
|
||||
__version__ = '2016.12.09'
|
||||
|
||||
Reference in New Issue
Block a user