Compare commits

...

28 Commits

Author SHA1 Message Date
Philipp Hagemeister
cd3063f3fa release 2015.01.10.2 2015-01-10 21:03:00 +01:00
Philipp Hagemeister
58b1f00d19 [YoutubeDL] Add new --call-home option for debugging 2015-01-10 21:02:27 +01:00
Philipp Hagemeister
149f05c7b6 release 2015.01.10.1 2015-01-10 20:06:13 +01:00
Philipp Hagemeister
8a1b9b068e Merge remote-tracking branch 'origin/master' 2015-01-10 20:06:01 +01:00
Philipp Hagemeister
c5a59d9391 [utils] Fix call to _create_http_connection
Avoid confusion over args/kwargs.
2015-01-10 20:05:30 +01:00
Philipp Hagemeister
500b8b41c1 [options] Add -4 and -6 options
Fixes #520, fixes #3626.
2015-01-10 20:02:02 +01:00
Philipp Hagemeister
be4a824d74 Add new option --source-address
Closes #3618, fixes #721, fixes #2481, fixes #4551, closes #1020.
2015-01-10 19:56:51 +01:00
Sergey M․
ed3958d714 [collegerama] Add extractor (#4540) 2015-01-11 00:40:46 +06:00
Philipp Hagemeister
6ce08764a1 Credit @dinesh for rte.ie (#4015) 2015-01-10 18:58:03 +01:00
Philipp Hagemeister
c80ede5f13 [karaoketv] Simplify (#3853) 2015-01-10 18:03:36 +01:00
Philipp Hagemeister
bc694039e4 Merge remote-tracking branch 'lenaten/karaoketv' 2015-01-10 17:59:35 +01:00
Philipp Hagemeister
3462af03e6 [rte] PEP8 2015-01-10 17:59:07 +01:00
Philipp Hagemeister
ea1d5bdcdd [rte] Make more robust and add a new testcase (#4015) 2015-01-10 17:57:21 +01:00
Philipp Hagemeister
121c09c7be Merge remote-tracking branch 'Dineshs91/f4m-2.0' 2015-01-10 17:51:52 +01:00
Philipp Hagemeister
76bfaf6daf [nrk] Improve subtitle support (#3092) 2015-01-10 17:46:01 +01:00
Sergey M․
d89c6e336a [atttechchannel] Add extractor (Closes #3938) 2015-01-10 19:44:29 +06:00
Sergey M․
776dc3992a [utils] Clarify more day-month-first ambiguous formats 2015-01-10 19:43:52 +06:00
Philipp Hagemeister
27ca82ebc6 [orf:oe1] Add konsole URL schema (Fixes #4675) 2015-01-10 14:27:27 +01:00
Philipp Hagemeister
385f8ae468 [eighttracks] PEP8 2015-01-10 14:25:11 +01:00
Philipp Hagemeister
b9f030cc26 [orf] Fix typo 2015-01-10 14:23:54 +01:00
Philipp Hagemeister
52afb2ac1b [ffmpeg] Call encodeFilename on filenames 2015-01-10 06:13:18 +01:00
Philipp Hagemeister
43bc88903d Merge remote-tracking branch 'ivan/muxed-mtime' 2015-01-10 06:10:18 +01:00
Ivan Kozik
0cd64bd077 Copy the mtime from the oldest source file to the file created by ffmpeg
Fixes #4245
2014-11-20 06:39:07 +00:00
dinesh
0551a02b82 [Rte] Improve extractor 2014-10-27 01:08:51 +05:30
dinesh
25fadd06d0 [Rte] New extractor added 2014-10-24 09:49:01 +05:30
dinesh
7a47d07c6d [extractor/common] href attribute added 2014-10-24 09:47:39 +05:30
dinesh
34e48bed3b [extractor/common] Added support for f4m manifest Version 2.0 2014-10-24 02:41:10 +05:30
net
c816336cbd [karaoketv] Add new extractor 2014-09-29 21:58:42 +03:00
19 changed files with 462 additions and 38 deletions

View File

@@ -101,3 +101,4 @@ Thijs Vermeir
Joel Leclerc Joel Leclerc
Christopher Krooss Christopher Krooss
Ondřej Caletka Ondřej Caletka
Dinesh S

View File

@@ -60,10 +60,6 @@ which means you can modify it, redistribute it or use it however you like.
they would handle they would handle
--extractor-descriptions Output descriptions of all supported --extractor-descriptions Output descriptions of all supported
extractors extractors
--proxy URL Use the specified HTTP/HTTPS proxy. Pass in
an empty string (--proxy "") for direct
connection
--socket-timeout None Time to wait before giving up, in seconds
--default-search PREFIX Use this prefix for unqualified URLs. For --default-search PREFIX Use this prefix for unqualified URLs. For
example "gvsearch2:" downloads two videos example "gvsearch2:" downloads two videos
from google videos for youtube-dl "large from google videos for youtube-dl "large
@@ -82,6 +78,18 @@ which means you can modify it, redistribute it or use it however you like.
--flat-playlist Do not extract the videos of a playlist, --flat-playlist Do not extract the videos of a playlist,
only list them. only list them.
## Network Options:
--proxy URL Use the specified HTTP/HTTPS proxy. Pass in
an empty string (--proxy "") for direct
connection
--socket-timeout SECONDS Time to wait before giving up, in seconds
--source-address IP Client-side IP address to bind to
(experimental)
-4, --force-ipv4 Make all connections via IPv4
(experimental)
-6, --force-ipv6 Make all connections via IPv6
(experimental)
## Video Selection: ## Video Selection:
--playlist-start NUMBER playlist video to start at (default is 1) --playlist-start NUMBER playlist video to start at (default is 1)
--playlist-end NUMBER playlist video to end at (default is last) --playlist-end NUMBER playlist video to end at (default is last)
@@ -231,6 +239,8 @@ which means you can modify it, redistribute it or use it however you like.
files in the current directory to debug files in the current directory to debug
problems problems
--print-traffic Display sent and read HTTP traffic --print-traffic Display sent and read HTTP traffic
-C, --call-home Contact the youtube-dl server for
debugging. (Experimental)
## Workarounds: ## Workarounds:
--encoding ENCODING Force the specified encoding (experimental) --encoding ENCODING Force the specified encoding (experimental)

View File

@@ -58,6 +58,7 @@ from .utils import (
takewhile_inclusive, takewhile_inclusive,
UnavailableVideoError, UnavailableVideoError,
url_basename, url_basename,
version_tuple,
write_json_file, write_json_file,
write_string, write_string,
YoutubeDLHandler, YoutubeDLHandler,
@@ -211,6 +212,9 @@ class YoutubeDL(object):
- "warn": only emit a warning - "warn": only emit a warning
- "detect_or_warn": check whether we can do anything - "detect_or_warn": check whether we can do anything
about it, warn otherwise about it, warn otherwise
source_address: (Experimental) Client-side IP address to bind to.
call_home: (Experimental) Boolean, true iff we are allowed to
contact the youtube-dl servers for debugging.
The following parameters are not used by YoutubeDL itself, they are used by The following parameters are not used by YoutubeDL itself, they are used by
@@ -1463,6 +1467,17 @@ class YoutubeDL(object):
proxy_map.update(handler.proxies) proxy_map.update(handler.proxies)
self._write_string('[debug] Proxy map: ' + compat_str(proxy_map) + '\n') self._write_string('[debug] Proxy map: ' + compat_str(proxy_map) + '\n')
if self.params.get('call_home', False):
ipaddr = self.urlopen('https://yt-dl.org/ip').read().decode('utf-8')
self._write_string('[debug] Public IP address: %s\n' % ipaddr)
latest_version = self.urlopen(
'https://yt-dl.org/latest/version').read().decode('utf-8')
if version_tuple(latest_version) > version_tuple(__version__):
self.report_warning(
'You are using an outdated version (newest version: %s)! '
'See https://yt-dl.org/update if you need help updating.' %
latest_version)
def _setup_opener(self): def _setup_opener(self):
timeout_val = self.params.get('socket_timeout') timeout_val = self.params.get('socket_timeout')
self._socket_timeout = 600 if timeout_val is None else float(timeout_val) self._socket_timeout = 600 if timeout_val is None else float(timeout_val)
@@ -1493,9 +1508,8 @@ class YoutubeDL(object):
proxy_handler = compat_urllib_request.ProxyHandler(proxies) proxy_handler = compat_urllib_request.ProxyHandler(proxies)
debuglevel = 1 if self.params.get('debug_printtraffic') else 0 debuglevel = 1 if self.params.get('debug_printtraffic') else 0
https_handler = make_HTTPS_handler( https_handler = make_HTTPS_handler(self.params, debuglevel=debuglevel)
self.params.get('nocheckcertificate', False), debuglevel=debuglevel) ydlh = YoutubeDLHandler(self.params, debuglevel=debuglevel)
ydlh = YoutubeDLHandler(debuglevel=debuglevel)
opener = compat_urllib_request.build_opener( opener = compat_urllib_request.build_opener(
https_handler, proxy_handler, cookie_processor, ydlh) https_handler, proxy_handler, cookie_processor, ydlh)
# Delete the default user-agent header, which would otherwise apply in # Delete the default user-agent header, which would otherwise apply in

View File

@@ -327,6 +327,8 @@ def _real_main(argv=None):
'merge_output_format': opts.merge_output_format, 'merge_output_format': opts.merge_output_format,
'postprocessors': postprocessors, 'postprocessors': postprocessors,
'fixup': opts.fixup, 'fixup': opts.fixup,
'source_address': opts.source_address,
'call_home': opts.call_home,
} }
with YoutubeDL(ydl_opts) as ydl: with YoutubeDL(ydl_opts) as ydl:

View File

@@ -4,6 +4,7 @@ import getpass
import optparse import optparse
import os import os
import re import re
import socket
import subprocess import subprocess
import sys import sys
@@ -307,6 +308,32 @@ else:
compat_kwargs = lambda kwargs: kwargs compat_kwargs = lambda kwargs: kwargs
if sys.version_info < (2, 7):
def compat_socket_create_connection(address, timeout, source_address=None):
host, port = address
err = None
for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
sock = None
try:
sock = socket.socket(af, socktype, proto)
sock.settimeout(timeout)
if source_address:
sock.bind(source_address)
sock.connect(sa)
return sock
except socket.error as _:
err = _
if sock is not None:
sock.close()
if err is not None:
raise err
else:
raise error("getaddrinfo returns an empty list")
else:
compat_socket_create_connection = socket.create_connection
# Fix https://github.com/rg3/youtube-dl/issues/4223 # Fix https://github.com/rg3/youtube-dl/issues/4223
# See http://bugs.python.org/issue9161 for what is broken # See http://bugs.python.org/issue9161 for what is broken
def workaround_optparse_bug9161(): def workaround_optparse_bug9161():
@@ -343,6 +370,7 @@ __all__ = [
'compat_parse_qs', 'compat_parse_qs',
'compat_print', 'compat_print',
'compat_str', 'compat_str',
'compat_socket_create_connection',
'compat_subprocess_get_DEVNULL', 'compat_subprocess_get_DEVNULL',
'compat_urllib_error', 'compat_urllib_error',
'compat_urllib_parse', 'compat_urllib_parse',

View File

@@ -26,6 +26,7 @@ from .arte import (
ArteTVEmbedIE, ArteTVEmbedIE,
) )
from .atresplayer import AtresPlayerIE from .atresplayer import AtresPlayerIE
from .atttechchannel import ATTTechChannelIE
from .audiomack import AudiomackIE, AudiomackAlbumIE from .audiomack import AudiomackIE, AudiomackAlbumIE
from .auengine import AUEngineIE from .auengine import AUEngineIE
from .azubu import AzubuIE from .azubu import AzubuIE
@@ -69,6 +70,7 @@ from .cnn import (
CNNArticleIE, CNNArticleIE,
) )
from .collegehumor import CollegeHumorIE from .collegehumor import CollegeHumorIE
from .collegerama import CollegeRamaIE
from .comedycentral import ComedyCentralIE, ComedyCentralShowsIE from .comedycentral import ComedyCentralIE, ComedyCentralShowsIE
from .comcarcoff import ComCarCoffIE from .comcarcoff import ComCarCoffIE
from .commonmistakes import CommonMistakesIE from .commonmistakes import CommonMistakesIE
@@ -206,6 +208,7 @@ from .jove import JoveIE
from .jukebox import JukeboxIE from .jukebox import JukeboxIE
from .jpopsukitv import JpopsukiIE from .jpopsukitv import JpopsukiIE
from .kankan import KankanIE from .kankan import KankanIE
from .karaoketv import KaraoketvIE
from .keezmovies import KeezMoviesIE from .keezmovies import KeezMoviesIE
from .khanacademy import KhanAcademyIE from .khanacademy import KhanAcademyIE
from .kickstarter import KickStarterIE from .kickstarter import KickStarterIE
@@ -339,6 +342,7 @@ from .ro220 import Ro220IE
from .rottentomatoes import RottenTomatoesIE from .rottentomatoes import RottenTomatoesIE
from .roxwel import RoxwelIE from .roxwel import RoxwelIE
from .rtbf import RTBFIE from .rtbf import RTBFIE
from .rte import RteIE
from .rtlnl import RtlXlIE from .rtlnl import RtlXlIE
from .rtlnow import RTLnowIE from .rtlnow import RTLnowIE
from .rtp import RTPIE from .rtp import RTPIE

View File

@@ -0,0 +1,55 @@
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import unified_strdate
class ATTTechChannelIE(InfoExtractor):
_VALID_URL = r'https?://techchannel\.att\.com/play-video\.cfm/([^/]+/)*(?P<id>.+)'
_TEST = {
'url': 'http://techchannel.att.com/play-video.cfm/2014/1/27/ATT-Archives-The-UNIX-System-Making-Computers-Easier-to-Use',
'info_dict': {
'id': '11316',
'display_id': 'ATT-Archives-The-UNIX-System-Making-Computers-Easier-to-Use',
'ext': 'flv',
'title': 'AT&T Archives : The UNIX System: Making Computers Easier to Use',
'description': 'A 1982 film about UNIX is the foundation for software in use around Bell Labs and AT&T.',
'thumbnail': 're:^https?://.*\.jpg$',
'upload_date': '20140127',
},
'params': {
# rtmp download
'skip_download': True,
},
}
def _real_extract(self, url):
display_id = self._match_id(url)
webpage = self._download_webpage(url, display_id)
video_url = self._search_regex(
r"url\s*:\s*'(rtmp://[^']+)'",
webpage, 'video URL')
video_id = self._search_regex(
r'mediaid\s*=\s*(\d+)',
webpage, 'video id', fatal=False)
title = self._og_search_title(webpage)
description = self._og_search_description(webpage)
thumbnail = self._og_search_thumbnail(webpage)
upload_date = unified_strdate(self._search_regex(
r'[Rr]elease\s+date:\s*(\d{1,2}/\d{1,2}/\d{4})',
webpage, 'upload date', fatal=False), False)
return {
'id': video_id,
'display_id': display_id,
'url': video_url,
'ext': 'flv',
'title': title,
'description': description,
'thumbnail': thumbnail,
'upload_date': upload_date,
}

View File

@@ -0,0 +1,92 @@
from __future__ import unicode_literals
import json
from .common import InfoExtractor
from ..compat import compat_urllib_request
from ..utils import (
float_or_none,
int_or_none,
)
class CollegeRamaIE(InfoExtractor):
_VALID_URL = r'https?://collegerama\.tudelft\.nl/Mediasite/Play/(?P<id>[\da-f]+)'
_TESTS = [
{
'url': 'https://collegerama.tudelft.nl/Mediasite/Play/585a43626e544bdd97aeb71a0ec907a01d',
'md5': '481fda1c11f67588c0d9d8fbdced4e39',
'info_dict': {
'id': '585a43626e544bdd97aeb71a0ec907a01d',
'ext': 'mp4',
'title': 'Een nieuwe wereld: waarden, bewustzijn en techniek van de mensheid 2.0.',
'description': '',
'thumbnail': 're:^https?://.*\.jpg$',
'duration': 7713.088,
'timestamp': 1413309600,
'upload_date': '20141014',
},
},
{
'url': 'https://collegerama.tudelft.nl/Mediasite/Play/86a9ea9f53e149079fbdb4202b521ed21d?catalog=fd32fd35-6c99-466c-89d4-cd3c431bc8a4',
'md5': 'ef1fdded95bdf19b12c5999949419c92',
'info_dict': {
'id': '86a9ea9f53e149079fbdb4202b521ed21d',
'ext': 'wmv',
'title': '64ste Vakantiecursus: Afvalwater',
'description': 'md5:7fd774865cc69d972f542b157c328305',
'duration': 10853,
'timestamp': 1326446400,
'upload_date': '20120113',
},
},
]
def _real_extract(self, url):
video_id = self._match_id(url)
player_options_request = {
"getPlayerOptionsRequest": {
"ResourceId": video_id,
"QueryString": "",
}
}
request = compat_urllib_request.Request(
'http://collegerama.tudelft.nl/Mediasite/PlayerService/PlayerService.svc/json/GetPlayerOptions',
json.dumps(player_options_request))
request.add_header('Content-Type', 'application/json')
player_options = self._download_json(request, video_id)
presentation = player_options['d']['Presentation']
title = presentation['Title']
description = presentation.get('Description')
thumbnail = None
duration = float_or_none(presentation.get('Duration'), 1000)
timestamp = int_or_none(presentation.get('UnixTime'), 1000)
formats = []
for stream in presentation['Streams']:
for video in stream['VideoUrls']:
thumbnail_url = stream.get('ThumbnailUrl')
if thumbnail_url:
thumbnail = 'http://collegerama.tudelft.nl' + thumbnail_url
format_id = video['MediaType']
if format_id == 'SS':
continue
formats.append({
'url': video['Location'],
'format_id': format_id,
})
self._sort_formats(formats)
return {
'id': video_id,
'title': title,
'description': description,
'thumbnail': thumbnail,
'duration': duration,
'timestamp': timestamp,
'formats': formats,
}

View File

@@ -742,8 +742,14 @@ class InfoExtractor(object):
'Unable to download f4m manifest') 'Unable to download f4m manifest')
formats = [] formats = []
manifest_version = '1.0'
media_nodes = manifest.findall('{http://ns.adobe.com/f4m/1.0}media') media_nodes = manifest.findall('{http://ns.adobe.com/f4m/1.0}media')
if not media_nodes:
manifest_version = '2.0'
media_nodes = manifest.findall('{http://ns.adobe.com/f4m/2.0}media')
for i, media_el in enumerate(media_nodes): for i, media_el in enumerate(media_nodes):
if manifest_version == '2.0':
manifest_url = '/'.join(manifest_url.split('/')[:-1]) + '/' + media_el.attrib.get('href')
tbr = int_or_none(media_el.attrib.get('bitrate')) tbr = int_or_none(media_el.attrib.get('bitrate'))
format_id = 'f4m-%d' % (i if tbr is None else tbr) format_id = 'f4m-%d' % (i if tbr is None else tbr)
formats.append({ formats.append({

View File

@@ -122,7 +122,6 @@ class EightTracksIE(InfoExtractor):
entries = [] entries = []
for i in range(track_count): for i in range(track_count):
api_json = None api_json = None
download_tries = 0 download_tries = 0

View File

@@ -0,0 +1,41 @@
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
from ..compat import compat_urllib_parse
from ..utils import (
ExtractorError,
js_to_json,
)
class KaraoketvIE(InfoExtractor):
_VALID_URL = r'http://karaoketv\.co\.il/\?container=songs&id=(?P<id>[0-9]+)'
_TEST = {
'url': 'http://karaoketv.co.il/?container=songs&id=171568',
'info_dict': {
'id': '171568',
'ext': 'mp4',
'title': 'אל העולם שלך - רותם כהן - שרים קריוקי',
}
}
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
page_video_url = self._og_search_video_url(webpage, video_id)
config_json = compat_urllib_parse.unquote_plus(self._search_regex(
r'config=(.*)', page_video_url, 'configuration'))
urls_info_json = self._download_json(
config_json, video_id, 'Downloading configuration',
transform_source=js_to_json)
url = urls_info_json['playlist'][0]['url']
return {
'id': video_id,
'title': self._og_search_title(webpage),
'url': url,
}

View File

@@ -7,8 +7,10 @@ from .common import InfoExtractor
from ..utils import ( from ..utils import (
ExtractorError, ExtractorError,
float_or_none, float_or_none,
parse_duration,
unified_strdate, unified_strdate,
) )
from .subtitles import SubtitlesInfoExtractor
class NRKIE(InfoExtractor): class NRKIE(InfoExtractor):
@@ -71,8 +73,8 @@ class NRKIE(InfoExtractor):
} }
class NRKTVIE(InfoExtractor): class NRKTVIE(SubtitlesInfoExtractor):
_VALID_URL = r'http://tv\.nrk(?:super)?\.no/(?:serie/[^/]+|program)/(?P<id>[a-zA-Z]{4}\d{8})(?:/\d{2}-\d{2}-\d{4})?(?:#del=(?P<part_id>\d+))?' _VALID_URL = r'(?P<baseurl>http://tv\.nrk(?:super)?\.no/)(?:serie/[^/]+|program)/(?P<id>[a-zA-Z]{4}\d{8})(?:/\d{2}-\d{2}-\d{4})?(?:#del=(?P<part_id>\d+))?'
_TESTS = [ _TESTS = [
{ {
@@ -147,6 +149,29 @@ class NRKTVIE(InfoExtractor):
} }
] ]
def _seconds2str(self, s):
return '%02d:%02d:%02d.%03d' % (s / 3600, (s % 3600) / 60, s % 60, (s % 1) * 1000)
def _debug_print(self, txt):
if self._downloader.params.get('verbose', False):
self.to_screen('[debug] %s' % txt)
def _extract_captions(self, subtitlesurl, video_id, baseurl):
url = "%s%s" % (baseurl, subtitlesurl)
self._debug_print('%s: Subtitle url: %s' % (video_id, url))
captions = self._download_xml(url, video_id, 'Downloading subtitles')
lang = captions.get('lang', 'no')
ps = captions.findall('./{0}body/{0}div/{0}p'.format('{http://www.w3.org/ns/ttml}'))
srt = ''
for pos, p in enumerate(ps):
begin = parse_duration(p.get('begin'))
duration = parse_duration(p.get('dur'))
starttime = self._seconds2str(begin)
endtime = self._seconds2str(begin + duration)
text = '\n'.join(p.itertext())
srt += '%s\r\n%s --> %s\r\n%s\r\n\r\n' % (str(pos), starttime, endtime, text)
return {lang: srt}
def _extract_f4m(self, manifest_url, video_id): def _extract_f4m(self, manifest_url, video_id):
return self._extract_f4m_formats(manifest_url + '?hdcore=3.1.1&plugin=aasp-3.1.1.69.124', video_id) return self._extract_f4m_formats(manifest_url + '?hdcore=3.1.1&plugin=aasp-3.1.1.69.124', video_id)
@@ -154,6 +179,7 @@ class NRKTVIE(InfoExtractor):
mobj = re.match(self._VALID_URL, url) mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id') video_id = mobj.group('id')
part_id = mobj.group('part_id') part_id = mobj.group('part_id')
baseurl = mobj.group('baseurl')
webpage = self._download_webpage(url, video_id) webpage = self._download_webpage(url, video_id)
@@ -210,9 +236,18 @@ class NRKTVIE(InfoExtractor):
m3u8_url = re.search(r'data-hls-media="([^"]+)"', webpage) m3u8_url = re.search(r'data-hls-media="([^"]+)"', webpage)
if m3u8_url: if m3u8_url:
formats.extend(self._extract_m3u8_formats(m3u8_url.group(1), video_id, 'mp4')) formats.extend(self._extract_m3u8_formats(m3u8_url.group(1), video_id, 'mp4'))
self._sort_formats(formats) self._sort_formats(formats)
subtitles_url = self._html_search_regex(
r'data-subtitlesurl[ ]*=[ ]*"([^"]+)"',
webpage, 'subtitle URL', default=None)
subtitles = None
if subtitles_url:
subtitles = self._extract_captions(subtitles_url, video_id, baseurl)
if self._downloader.params.get('listsubtitles', False):
self._list_available_subtitles(video_id, subtitles)
return
return { return {
'id': video_id, 'id': video_id,
'title': title, 'title': title,
@@ -221,4 +256,5 @@ class NRKTVIE(InfoExtractor):
'upload_date': upload_date, 'upload_date': upload_date,
'duration': duration, 'duration': duration,
'formats': formats, 'formats': formats,
'subtitles': subtitles,
} }

View File

@@ -128,13 +128,16 @@ class ORFTVthekIE(InfoExtractor):
} }
# Audios on ORF radio are only available for 7 days, so we can't add tests.
class ORFOE1IE(InfoExtractor): class ORFOE1IE(InfoExtractor):
IE_NAME = 'orf:oe1' IE_NAME = 'orf:oe1'
IE_DESC = 'Radio Österreich 1' IE_DESC = 'Radio Österreich 1'
_VALID_URL = r'http://oe1\.orf\.at/programm/(?P<id>[0-9]+)' _VALID_URL = r'http://oe1\.orf\.at/(?:programm/|konsole.*?#\?track_id=)(?P<id>[0-9]+)'
# Audios on ORF radio are only available for 7 days, so we can't add tests.
_TEST = {
'url': 'http://oe1.orf.at/konsole?show=on_demand#?track_id=394211',
'only_matching': True,
}
def _real_extract(self, url): def _real_extract(self, url):
show_id = self._match_id(url) show_id = self._match_id(url)
@@ -160,7 +163,7 @@ class ORFOE1IE(InfoExtractor):
class ORFFM4IE(InfoExtractor): class ORFFM4IE(InfoExtractor):
IE_DESC = 'orf:fm4' IE_NAME = 'orf:fm4'
IE_DESC = 'radio FM4' IE_DESC = 'radio FM4'
_VALID_URL = r'http://fm4\.orf\.at/7tage/?#(?P<date>[0-9]+)/(?P<show>\w+)' _VALID_URL = r'http://fm4\.orf\.at/7tage/?#(?P<date>[0-9]+)/(?P<show>\w+)'

View File

@@ -0,0 +1,62 @@
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import (
float_or_none,
)
class RteIE(InfoExtractor):
_VALID_URL = r'http?://(?:www\.)?rte\.ie/player/[^/]{2,3}/show/(?P<id>[0-9]+)/'
_TEST = {
'url': 'http://www.rte.ie/player/de/show/10363114/',
'info_dict': {
'id': '10363114',
'ext': 'mp4',
'title': 'One News',
'thumbnail': 're:^https?://.*\.jpg$',
'description': 'The One O\'Clock News followed by Weather.',
'duration': 436.844,
},
'params': {
'skip_download': 'f4m fails with --test atm'
}
}
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
title = self._og_search_title(webpage)
description = self._html_search_meta('description', webpage, 'description')
duration = float_or_none(self._html_search_meta(
'duration', webpage, 'duration', fatal=False), 1000)
thumbnail_id = self._search_regex(
r'<meta name="thumbnail" content="uri:irus:(.*?)" />', webpage, 'thumbnail')
thumbnail = 'http://img.rasset.ie/' + thumbnail_id + '.jpg'
feeds_url = self._html_search_meta("feeds-prefix", webpage, 'feeds url') + video_id
json_string = self._download_json(feeds_url, video_id)
# f4m_url = server + relative_url
f4m_url = json_string['shows'][0]['media:group'][0]['rte:server'] + json_string['shows'][0]['media:group'][0]['url']
f4m_formats = self._extract_f4m_formats(f4m_url, video_id)
f4m_formats = [{
'format_id': f['format_id'],
'url': f['url'],
'ext': 'mp4',
'width': f['width'],
'height': f['height'],
} for f in f4m_formats]
return {
'id': video_id,
'title': title,
'formats': f4m_formats,
'description': description,
'thumbnail': thumbnail,
'duration': duration,
}

View File

@@ -148,14 +148,6 @@ def parseOpts(overrideArguments=None):
'--extractor-descriptions', '--extractor-descriptions',
action='store_true', dest='list_extractor_descriptions', default=False, action='store_true', dest='list_extractor_descriptions', default=False,
help='Output descriptions of all supported extractors') help='Output descriptions of all supported extractors')
general.add_option(
'--proxy', dest='proxy',
default=None, metavar='URL',
help='Use the specified HTTP/HTTPS proxy. Pass in an empty string (--proxy "") for direct connection')
general.add_option(
'--socket-timeout',
dest='socket_timeout', type=float, default=None,
help='Time to wait before giving up, in seconds')
general.add_option( general.add_option(
'--default-search', '--default-search',
dest='default_search', metavar='PREFIX', dest='default_search', metavar='PREFIX',
@@ -173,6 +165,31 @@ def parseOpts(overrideArguments=None):
default=False, default=False,
help='Do not extract the videos of a playlist, only list them.') help='Do not extract the videos of a playlist, only list them.')
network = optparse.OptionGroup(parser, 'Network Options')
network.add_option(
'--proxy', dest='proxy',
default=None, metavar='URL',
help='Use the specified HTTP/HTTPS proxy. Pass in an empty string (--proxy "") for direct connection')
network.add_option(
'--socket-timeout',
dest='socket_timeout', type=float, default=None, metavar='SECONDS',
help='Time to wait before giving up, in seconds')
network.add_option(
'--source-address',
metavar='IP', dest='source_address', default=None,
help='Client-side IP address to bind to (experimental)',
)
network.add_option(
'-4', '--force-ipv4',
action='store_const', const='0.0.0.0', dest='source_address',
help='Make all connections via IPv4 (experimental)',
)
network.add_option(
'-6', '--force-ipv6',
action='store_const', const='::', dest='source_address',
help='Make all connections via IPv6 (experimental)',
)
selection = optparse.OptionGroup(parser, 'Video Selection') selection = optparse.OptionGroup(parser, 'Video Selection')
selection.add_option( selection.add_option(
'--playlist-start', '--playlist-start',
@@ -488,6 +505,10 @@ def parseOpts(overrideArguments=None):
'--print-traffic', '--print-traffic',
dest='debug_printtraffic', action='store_true', default=False, dest='debug_printtraffic', action='store_true', default=False,
help='Display sent and read HTTP traffic') help='Display sent and read HTTP traffic')
verbosity.add_option(
'-C', '--call-home',
dest='call_home', action='store_true', default=False,
help='Contact the youtube-dl server for debugging. (Experimental)')
filesystem = optparse.OptionGroup(parser, 'Filesystem Options') filesystem = optparse.OptionGroup(parser, 'Filesystem Options')
filesystem.add_option( filesystem.add_option(
@@ -652,6 +673,7 @@ def parseOpts(overrideArguments=None):
help='Execute a command on the file after downloading, similar to find\'s -exec syntax. Example: --exec \'adb push {} /sdcard/Music/ && rm {}\'') help='Execute a command on the file after downloading, similar to find\'s -exec syntax. Example: --exec \'adb push {} /sdcard/Music/ && rm {}\'')
parser.add_option_group(general) parser.add_option_group(general)
parser.add_option_group(network)
parser.add_option_group(selection) parser.add_option_group(selection)
parser.add_option_group(downloader) parser.add_option_group(downloader)
parser.add_option_group(filesystem) parser.add_option_group(filesystem)

View File

@@ -82,12 +82,15 @@ class FFmpegPostProcessor(PostProcessor):
def run_ffmpeg_multiple_files(self, input_paths, out_path, opts): def run_ffmpeg_multiple_files(self, input_paths, out_path, opts):
self.check_version() self.check_version()
oldest_mtime = min(
os.stat(encodeFilename(path)).st_mtime for path in input_paths)
files_cmd = [] files_cmd = []
for path in input_paths: for path in input_paths:
files_cmd.extend([encodeArgument('-i'), encodeFilename(path, True)]) files_cmd.extend([encodeArgument('-i'), encodeFilename(path, True)])
cmd = ([encodeFilename(self._executable, True), encodeArgument('-y')] + cmd = ([encodeFilename(self._executable, True), encodeArgument('-y')] +
files_cmd files_cmd +
+ [encodeArgument(o) for o in opts] + [encodeArgument(o) for o in opts] +
[encodeFilename(self._ffmpeg_filename_argument(out_path), True)]) [encodeFilename(self._ffmpeg_filename_argument(out_path), True)])
if self._downloader.params.get('verbose', False): if self._downloader.params.get('verbose', False):
@@ -98,6 +101,7 @@ class FFmpegPostProcessor(PostProcessor):
stderr = stderr.decode('utf-8', 'replace') stderr = stderr.decode('utf-8', 'replace')
msg = stderr.strip().split('\n')[-1] msg = stderr.strip().split('\n')[-1]
raise FFmpegPostProcessorError(msg) raise FFmpegPostProcessorError(msg)
os.utime(encodeFilename(out_path), (oldest_mtime, oldest_mtime))
if self._deletetempfiles: if self._deletetempfiles:
for ipath in input_paths: for ipath in input_paths:
os.remove(ipath) os.remove(ipath)

View File

@@ -59,7 +59,7 @@ def update_self(to_screen, verbose):
to_screen('It looks like you installed youtube-dl with a package manager, pip, setup.py or a tarball. Please use that to update.') to_screen('It looks like you installed youtube-dl with a package manager, pip, setup.py or a tarball. Please use that to update.')
return return
https_handler = make_HTTPS_handler(False) https_handler = make_HTTPS_handler({})
opener = compat_urllib_request.build_opener(https_handler) opener = compat_urllib_request.build_opener(https_handler)
# Check if there is a new version # Check if there is a new version

View File

@@ -10,6 +10,7 @@ import ctypes
import datetime import datetime
import email.utils import email.utils
import errno import errno
import functools
import gzip import gzip
import itertools import itertools
import io import io
@@ -34,7 +35,9 @@ from .compat import (
compat_chr, compat_chr,
compat_getenv, compat_getenv,
compat_html_entities, compat_html_entities,
compat_http_client,
compat_parse_qs, compat_parse_qs,
compat_socket_create_connection,
compat_str, compat_str,
compat_urllib_error, compat_urllib_error,
compat_urllib_parse, compat_urllib_parse,
@@ -391,13 +394,14 @@ def formatSeconds(secs):
return '%d' % secs return '%d' % secs
def make_HTTPS_handler(opts_no_check_certificate, **kwargs): def make_HTTPS_handler(params, **kwargs):
opts_no_check_certificate = params.get('nocheckcertificate', False)
if hasattr(ssl, 'create_default_context'): # Python >= 3.4 or 2.7.9 if hasattr(ssl, 'create_default_context'): # Python >= 3.4 or 2.7.9
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
if opts_no_check_certificate: if opts_no_check_certificate:
context.verify_mode = ssl.CERT_NONE context.verify_mode = ssl.CERT_NONE
try: try:
return compat_urllib_request.HTTPSHandler(context=context, **kwargs) return YoutubeDLHTTPSHandler(params, context=context, **kwargs)
except TypeError: except TypeError:
# Python 2.7.8 # Python 2.7.8
# (create_default_context present but HTTPSHandler has no context=) # (create_default_context present but HTTPSHandler has no context=)
@@ -420,17 +424,14 @@ def make_HTTPS_handler(opts_no_check_certificate, **kwargs):
except ssl.SSLError: except ssl.SSLError:
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23) self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23)
class HTTPSHandlerV3(compat_urllib_request.HTTPSHandler): return YoutubeDLHTTPSHandler(params, https_conn_class=HTTPSConnectionV3, **kwargs)
def https_open(self, req):
return self.do_open(HTTPSConnectionV3, req)
return HTTPSHandlerV3(**kwargs)
else: # Python < 3.4 else: # Python < 3.4
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.verify_mode = (ssl.CERT_NONE context.verify_mode = (ssl.CERT_NONE
if opts_no_check_certificate if opts_no_check_certificate
else ssl.CERT_REQUIRED) else ssl.CERT_REQUIRED)
context.set_default_verify_paths() context.set_default_verify_paths()
return compat_urllib_request.HTTPSHandler(context=context, **kwargs) return YoutubeDLHTTPSHandler(params, context=context, **kwargs)
class ExtractorError(Exception): class ExtractorError(Exception):
@@ -544,6 +545,26 @@ class ContentTooShortError(Exception):
self.expected = expected self.expected = expected
def _create_http_connection(ydl_handler, http_class, is_https, *args, **kwargs):
hc = http_class(*args, **kwargs)
source_address = ydl_handler._params.get('source_address')
if source_address is not None:
sa = (source_address, 0)
if hasattr(hc, 'source_address'): # Python 2.7+
hc.source_address = sa
else: # Python 2.6
def _hc_connect(self, *args, **kwargs):
sock = compat_socket_create_connection(
(self.host, self.port), self.timeout, sa)
if is_https:
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file)
else:
self.sock = sock
hc.connect = functools.partial(_hc_connect, hc)
return hc
class YoutubeDLHandler(compat_urllib_request.HTTPHandler): class YoutubeDLHandler(compat_urllib_request.HTTPHandler):
"""Handler for HTTP requests and responses. """Handler for HTTP requests and responses.
@@ -562,6 +583,15 @@ class YoutubeDLHandler(compat_urllib_request.HTTPHandler):
public domain. public domain.
""" """
def __init__(self, params, *args, **kwargs):
compat_urllib_request.HTTPHandler.__init__(self, *args, **kwargs)
self._params = params
def http_open(self, req):
return self.do_open(functools.partial(
_create_http_connection, self, compat_http_client.HTTPConnection, False),
req)
@staticmethod @staticmethod
def deflate(data): def deflate(data):
try: try:
@@ -631,6 +661,18 @@ class YoutubeDLHandler(compat_urllib_request.HTTPHandler):
https_response = http_response https_response = http_response
class YoutubeDLHTTPSHandler(compat_urllib_request.HTTPSHandler):
def __init__(self, params, https_conn_class=None, *args, **kwargs):
compat_urllib_request.HTTPSHandler.__init__(self, *args, **kwargs)
self._https_conn_class = https_conn_class or compat_http_client.HTTPSConnection
self._params = params
def https_open(self, req):
return self.do_open(functools.partial(
_create_http_connection, self, self._https_conn_class, True),
req)
def parse_iso8601(date_str, delimiter='T'): def parse_iso8601(date_str, delimiter='T'):
""" Return a UNIX timestamp from the given date """ """ Return a UNIX timestamp from the given date """
@@ -679,9 +721,6 @@ def unified_strdate(date_str, day_first=True):
'%b %dth %Y %I:%M%p', '%b %dth %Y %I:%M%p',
'%Y-%m-%d', '%Y-%m-%d',
'%Y/%m/%d', '%Y/%m/%d',
'%d.%m.%Y',
'%d/%m/%Y',
'%d/%m/%y',
'%Y/%m/%d %H:%M:%S', '%Y/%m/%d %H:%M:%S',
'%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M:%S',
'%Y-%m-%d %H:%M:%S.%f', '%Y-%m-%d %H:%M:%S.%f',
@@ -696,10 +735,16 @@ def unified_strdate(date_str, day_first=True):
] ]
if day_first: if day_first:
format_expressions.extend([ format_expressions.extend([
'%d.%m.%Y',
'%d/%m/%Y',
'%d/%m/%y',
'%d/%m/%Y %H:%M:%S', '%d/%m/%Y %H:%M:%S',
]) ])
else: else:
format_expressions.extend([ format_expressions.extend([
'%m.%d.%Y',
'%m/%d/%Y',
'%m/%d/%y',
'%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M:%S',
]) ])
for expression in format_expressions: for expression in format_expressions:

View File

@@ -1,3 +1,3 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__version__ = '2015.01.10' __version__ = '2015.01.10.2'