Compare commits

...

2164 Commits

Author SHA1 Message Date
3eb5fdb581 release 2015.08.06 2015-08-06 22:55:43 +02:00
9663bd3abb [southpark:de] Enable non-ASCII redirect URL test 2015-08-07 01:27:07 +06:00
5a4d9ddb21 [utils] Percent-encode redirect URL of Location header (Closes #6457) 2015-08-07 01:26:40 +06:00
671302b5c0 [YoutubeDL] Remove unused imports 2015-08-07 00:08:11 +06:00
4f34cdb0a8 [southpark:de] Skip test 2015-08-06 23:56:44 +06:00
bd690a9f93 [southpark:de] Add test for non-ASCII in URLs 2015-08-06 22:01:31 +06:00
51f267d9d4 [YoutubeDL:utils] Move percent encode non-ASCII URLs workaround to http_request and simplify (Closes #6457) 2015-08-06 22:01:01 +06:00
47f53ad958 Merge pull request #6463 from jaimeMF/format_spec_fix_dashes
[YoutubeDL] format spec: correctly handle dashes and other unused operators
2015-08-06 00:04:40 +06:00
c73cdd800f [xhamster] flake8 2015-08-05 23:08:55 +06:00
f535ec8278 [xhamster] Remove unused import 2015-08-05 23:08:26 +06:00
238755752f [tudou] Extract player URL from the webpage 2015-08-05 23:07:52 +06:00
c71a3195af [tudou] Fix extracion 2015-08-05 23:04:49 +06:00
54a9328b20 [generic] Expand jwplayer support 2015-08-05 21:19:52 +06:00
3e48522477 [xhamster] Fix uploader extraction 2015-08-05 20:41:40 +06:00
251a44b776 [xhamster] Fix thumbnail extraction 2015-08-05 20:36:37 +06:00
be7a8379b4 [xhamster] Make more robust 2015-08-05 20:32:44 +06:00
defce60385 Merge pull request #6467 from vijayanandnandam/master
fixing xhamster file extraction
2015-08-05 20:21:19 +06:00
354b4b8604 fixing xhamster file extraction 2015-08-05 19:37:59 +05:30
5b7dab2dd6 [lynda] Make login more robust 2015-08-05 20:06:48 +06:00
8a5601e42f [lynda] Fix login (Closes #6462) 2015-08-05 19:52:04 +06:00
232541df44 [YoutubeDL] format spec: correctly handle dashes and other unused operators
'mp4-baseline-16x9' must be handled as a single string, but the '-' was treated as an operator.
2015-08-04 22:29:23 +02:00
a346b1ff57 [bbc] Add support for vxp-playlist-data embeds (Closes #6453) 2015-08-04 20:44:22 +06:00
d96d604e53 YoutubeDL: format spec: don't accept a bare '/' (#6124) 2015-08-03 23:04:11 +02:00
e704f87f86 [twitch] Parse start_time from 't' (closes #6441)
Eg. for VOD links like http://www.twitch.tv/gamesdonequick/v/9136645?t=14h29m15s
2015-08-03 20:07:23 +02:00
8f5639afcb [pornhub] Improve video quality regex 2015-08-03 19:37:48 +06:00
03950c90f7 Merge remote-tracking branch 'jaimemf/format_spec_groups' (closes #6124) 2015-08-03 15:22:51 +02:00
47a8b7c14a [mdr] Change XPath to make it work in python 2.6 (fixes #6443)
The 'progressiveDownloadUrl' element is a direct child, so they should be equivalent.
2015-08-03 12:00:08 +02:00
2a04d2c799 Merge pull request #6439 from remitamine/facebook
[facebook] extract uploader
2015-08-03 05:43:01 +06:00
8de922724b [README.md] Clarify using cookies 2015-08-03 05:36:17 +06:00
67b8a28a2f [facebook] add uploader value to the tests 2015-08-03 00:09:21 +01:00
51a575159a [facebook] extract uploader 2015-08-02 22:52:12 +01:00
524229a297 [pornhub] Improve 2015-08-03 02:41:17 +06:00
754e70cf3e [pornhub] Fix video url regular expression.
PornHub seems to have subtly changed their JavaScript. Before, video URL strings were embedded directly in the video's `flashvars_*` object, but they are now assigned to variables of the form `player_quality_*`, which are then added to this object later under the relevant quality key.
2015-08-03 02:35:06 +06:00
84bc4dcb0f [downloader/http] Clarify rationale for Content-Range check (#6426) 2015-08-03 02:27:47 +06:00
10eaa8ef1d [downloader/http] Report unable to resume 2015-08-03 02:25:40 +06:00
c3124c3085 [downloader/http] Simplify 2015-08-03 02:25:08 +06:00
8d5b8b477e [utils] import re 2015-08-03 02:23:35 +06:00
d7d2a9a3db [utils] restart download if server does not support byte ranges 2015-08-03 02:23:31 +06:00
25a4c5a9ed [dailymotion:playlist] Use an iterator for the entries
So that using '--playlist-end' only downloads the required pages (reported in #2175).
2015-08-02 15:19:57 +02:00
5c45bbe57b [nowtv] Remove unused import 2015-08-02 15:19:30 +02:00
e422d7f4f7 [nowtv] Expand _VALID_URL 2015-08-02 04:26:59 +06:00
cdc682d5a4 [nowtv] Fix extraction (Closes #6357) 2015-08-02 04:21:16 +06:00
9cc93c64aa [screenwavemedia] Use the IP for the videoserver (fixes #6397)
For http://cinemassacre.com/2015/07/28/avgn-seaman-for-dreamcast/ the other server returns a 403 error.
2015-08-01 22:17:19 +02:00
fa7a1cc5ef [screenwavemedia] fix info extraction (fixes #6270)
Closes #6330.
2015-08-01 22:13:10 +02:00
55eae65b39 Credit @cyb3r for the ir90tv extractor 2015-08-02 00:42:23 +08:00
3f125c8c70 [nbcnews] Extend _VALID_URL 2015-08-01 21:43:33 +06:00
75e8b2ac87 Merge pull request #6392 from dstftw/generalized-fragmented-fd
Generalized fragmented media file downloader
2015-08-01 20:22:49 +06:00
ee114368ad [utils] Make value optional for find_xpath_attr
This allows selecting particular attributes by name but without specifying the value and similar to xpath syntax `[@attrib]`
2015-08-01 20:22:13 +06:00
525a87f58e [gdcvault] Fix typo: xml_decription_url -> xml_description_url 2015-08-01 11:40:34 +02:00
44cae2fb2e [gdcvault] Add support for audio extraction (fixes #5784)
Closes #6412.
2015-08-01 11:39:50 +02:00
30a453884e [viewster] use head request to extract api token
Closes #6419.
2015-08-01 11:06:26 +02:00
3b58d94f71 [vidme] Make uploader optional and add test 2015-08-01 04:03:52 +06:00
8abb86fec4 Merge pull request #6421 from remitamine/vidme
[vidme] extract the uploader
2015-08-01 03:55:52 +06:00
16a089780e [soundcloud] Clean up _VALID_URLs 2015-08-01 03:50:03 +06:00
09b6468d30 [vidme] extract the uploader 2015-07-31 21:28:59 +01:00
80fb6d4aa4 [soundcloud:user] Rework extractor (Closes #6399) 2015-07-31 00:54:26 +06:00
1f04873517 [viewster] Use 'compat_urllib_parse_unquote' 2015-07-30 19:12:37 +02:00
799207e838 [viewster] extract the api auth token
Closes #6406.
2015-07-30 12:55:48 +02:00
34866b4836 Merge remote-tracking branch 'dstftw/multifeed-videos' (closes #6360) 2015-07-29 21:55:20 +02:00
be530dfea2 Merge branch 'atomicdryad-pr-fix_bbc_mediaselector' 2015-07-30 00:55:43 +06:00
d12a1a47d5 [bbc] Improve work with mediaselection URLs 2015-07-30 00:55:06 +06:00
8d42e3501e Merge branch 'pr-fix_bbc_mediaselector' of https://github.com/atomicdryad/youtube-dl into atomicdryad-pr-fix_bbc_mediaselector 2015-07-29 23:55:40 +06:00
2711e41bcd Credit slangangular for the sportschau extractor (#6199) 2015-07-29 18:47:20 +02:00
5e1eddb939 [youtube] Show info message for multifeed videos according to noplaylist option 2015-07-29 21:18:16 +06:00
23e7f53bd3 Merge branch 'purdeaandrei-save_tags_simpler_only_saves_tags_to_info_json' 2015-07-29 03:43:55 +06:00
000b6b5ae5 [youtube] Improve tags extraction and add test 2015-07-29 03:43:32 +06:00
864f24bd2c [extractor/common] Add _meta_regex and clarify tags field 2015-07-29 03:43:03 +06:00
5d8df28d27 Merge pull request #6372 from raphaelm/patch-1
Remove redundant (and wrong) class parameters
2015-07-29 02:46:53 +06:00
f9a5affad9 [hls] Implement hlsnative fd in terms of fragment fd 2015-07-29 02:28:30 +06:00
ab81ef8fa7 [f4m] Implement f4m fd in terms of fragment fd 2015-07-29 02:27:50 +06:00
95d8f7ea12 [fragment] Generalize fragmented media file downloader 2015-07-29 02:26:16 +06:00
5316bf7487 Documented tags as a possible dict key 2015-07-28 18:30:42 +03:00
a6f774e901 [youtube]: tags key in info jason is now a list 2015-07-28 18:29:13 +03:00
f171bc8b59 [youtube] save keywords in info jason when --write-info-json is used 2015-07-28 18:14:06 +03:00
289bbb350e release 2015.07.28 2015-07-28 11:28:33 +02:00
d247a2c8bf [bbc] Fix regex 2015-07-28 02:06:27 +06:00
88ed52aec9 [bbc] Add support for direct bbc.co.uk embeds 2015-07-27 22:05:51 +06:00
cb23bcba29 BBCIE: Fix missing .mp4 formats on news sites
Prior to merge BBCNewsIE from pr #6026 was rewritten into BBCIE in 9afa177. Support was added for non-news
sites (/travel, /sports), however support for the news mediaselector was removed to support these sites.
This removed support for .mp4.

    pr #6026 ( news site, news mediaseletor : http://open.live.bbc.co.uk/mediaselector/4/mtis/stream/ )
    format code                                          extension  resolution note
    journalism_nonuk_stream_h264_flv_200_akamai          flv        400x224    h264@ 176k, 1001.77KiB
    journalism_nonuk_stream_h264_flv_400_akamai          flv        400x224    h264@ 512k, 2.85MiB
    journalism_nonuk_stream_h264_flv_med_akamai          flv        640x360    h264@ 800k, 4.43MiB
    journalism_nonuk_stream_h264_flv_hi_akamai           flv        688x384    h264@1500k, 8.34MiB
    journalism_world_stream_h264_http_200_sis_news_http  mp4        400x224    h264@ 176k, 1001.77KiB
    journalism_world_stream_h264_http_400_sis_news_http  mp4        400x224    h264@ 512k, 2.85MiB
    journalism_world_stream_h264_http_hi_sis_news_http   mp4        688x384    h264@1500k, 8.34MiB (best)

    # 9afa177 ( same url, non-news mediaselector: http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/mediaset/journalism-pc/vpid/ )
    format code                                  extension  resolution note
    journalism_nonuk_stream_h264_flv_lo_akamai   flv        384x216    h264@ 496k, 2.76MiB
    journalism_nonuk_stream_h264_flv_med_akamai  flv        640x360    h264@ 800k, 4.43MiB
    journalism_nonuk_stream_h264_flv_hi_akamai   flv        688x384    h264@1500k, 8.34MiB (best)

This change corrects the above, by trying /mediaselector/5 if /mediaselector/4 fails.
2015-07-27 04:24:04 -05:00
2c7ed24796 Remove redundant (and wrong) class parameters 2015-07-26 16:37:51 +02:00
4c6bd5b5b6 [youtube] Use 'vp8' and 'vp9' in lowercase (fixes #6358)
That's how YouTube reports them in their DASH manifest.
2015-07-26 14:14:28 +02:00
aeb7b41d44 [spiegel] Accept iframe urls
Closes #6370.
2015-07-26 14:00:56 +02:00
5bdec59de1 [comcarcoff] Add support for singleshots (Closes #6366) 2015-07-26 09:51:54 +06:00
7a89681722 [bbc] Skip DASH until supported 2015-07-25 22:32:54 +06:00
51da40e621 [bbc] PEP8 2015-07-25 22:19:54 +06:00
d8f0a9ecea [youtube] Respect noplaylist for multifeed videos 2015-07-25 22:17:06 +06:00
cf7e015f25 [youtube] Add support for multifeed videos 2015-07-25 21:30:34 +06:00
1af330f29f Merge branch 'atomicdryad-pr-bbcnews' 2015-07-25 20:22:13 +06:00
9afa1770d1 [bbc] Improve playlist extraction, refactor, expand support and document 2015-07-25 20:21:42 +06:00
3ebbcce1c7 Merge branch 'cyb3r-ir90tv' 2015-07-25 18:49:24 +08:00
2c7c721933 [ir90tv] Optional fields should be non-fatal 2015-07-25 18:48:00 +08:00
7523647391 [ir90tv] PEP8 2015-07-25 18:43:07 +08:00
9700cd9097 [ir90tv] Improve title extraction 2015-07-25 18:42:40 +08:00
eab7faa0c1 [ir90tv] Test (?:www\.)? part in _VALID_URL 2015-07-25 18:39:01 +08:00
a56c1e38c7 Merge branch 'ir90tv' of https://github.com/cyb3r/youtube-dl into cyb3r-ir90tv 2015-07-25 18:36:04 +08:00
40a2d17052 [soundcloud:playlist] Defer download link resolve 2015-07-25 15:48:44 +06:00
b14fa8e687 [soundcloud:set] Defer download link resolve (Closes #6354) 2015-07-25 15:47:53 +06:00
678e436f2e [youtube] Handle empty allowed regions (Closes #6351) 2015-07-25 02:09:34 +06:00
ff81c4c99c Merge branch 'pr-bbcnews' of https://github.com/atomicdryad/youtube-dl into atomicdryad-pr-bbcnews 2015-07-24 20:21:48 +06:00
420658e6cb Merge pull request #6350 from remitamine/letv
[letv] fix height
2015-07-24 20:03:44 +06:00
593ddd851b [letv] fix height 2015-07-24 14:46:45 +01:00
1243402657 [dailymotion:playlist] Detect problematic redirection (fixes #6347) 2015-07-24 21:29:44 +08:00
2b2ee140c3 [dailymotion:user] Fix _VALID_URL (Closes #6346) 2015-07-24 03:40:24 +06:00
d97f5cd795 [bbccouk] Make more robust (Closes #6345) 2015-07-24 02:56:54 +06:00
f3f0b8e403 [canalplus] Modernize 2015-07-24 00:21:13 +06:00
660f9459da [canalplus] Fix m3u8 videos extension 2015-07-24 00:17:36 +06:00
10952eb2cf [extractor/common] Consistent URL spelling 2015-07-23 23:37:45 +06:00
cdad742700 Merge pull request #6306 from jaimeMF/extract_start_time
[youtube] Extract start_time
2015-07-23 23:33:54 +06:00
a9e8f60ef6 [rtlnl] Update unencrypted streams comment (#6337) 2015-07-23 23:20:24 +06:00
a8b7b26068 Undo adaptive -> flash workaround
For a couple of days now rtlXL's non-DRM adaptive (m3u8) streams don't work anymore. By undoing the adaptive -> flash workaround youtube-dl returns the DRM streams again. Too bad for foreigners (geoblock).
The progressive streams still work fine.
2015-07-23 23:08:39 +06:00
ba911137fa [rts] Add support for articles with videos on rhs (Closes #6332) 2015-07-23 22:50:59 +06:00
d3f007af18 [daylimotion] Adapt to player v5 and modernize (Closes #6151, closes #6250) 2015-07-23 22:04:47 +06:00
2929fa0e79 [youtube] Also look into the 'start' field for start_time 2015-07-23 13:21:18 +02:00
297a564bee [youtube] Extract end_time 2015-07-23 13:20:21 +02:00
53b8247cb5 NationalGeographic._VALID_URL: work site-wide
Closes #6343.
2015-07-23 12:21:41 +02:00
59db9f8018 [downloader/dash] Improve 'combine_url' (fixes #6341)
In some videos the base_url already ends with '/'.
2015-07-23 12:09:30 +02:00
b73b14f72c [viki] Rewrite dict selection codes 2015-07-23 14:02:19 +08:00
41597d9bed [viki] Fix description extraction (closes #6339) 2015-07-23 13:39:19 +08:00
b37317d8b0 [generic] Unescape HTML escape sequences in redirect urls (fixes #6311) 2015-07-22 23:33:49 +02:00
87dc451108 [youtube] Don't use the DASH manifest from 'get_video_info' if 'use_cipher_signature' is True (#5118)
Currently they give a 403 Forbidden error.
2015-07-22 23:27:41 +02:00
ca4456eda8 [tagesschau] Remove unused import 2015-07-22 23:23:38 +02:00
993df6bc22 [prosiebensat1] Modernize 2015-07-23 03:05:16 +06:00
61be92e26a [prosiebensat1] Recognize DRM protected videos (#6334) 2015-07-23 03:04:23 +06:00
c59b61c0da [viki] Fix height (Closes #6333) 2015-07-23 02:13:51 +06:00
3e214851a4 [tagesschau] Improve tests 2015-07-23 01:01:35 +06:00
a47b602b08 [tagesschau] Add support for audio 2015-07-23 01:01:04 +06:00
a083b859e4 Merge branch 'rohieb-patch/enhance-tagesschau-regex' 2015-07-23 00:31:09 +06:00
948199deac [tagesschau] Relax _VALID_URL and simplify 2015-07-23 00:30:48 +06:00
c356620ec1 Merge branch 'patch/enhance-tagesschau-regex' of https://github.com/rohieb/youtube-dl into rohieb-patch/enhance-tagesschau-regex 2015-07-23 00:12:46 +06:00
f79ebf09a2 Credit @nichdu for Lecture2Go extractor 2015-07-23 01:56:55 +08:00
c7620992d2 [pbs] No need to escape colon 2015-07-22 23:49:55 +06:00
ce1bafdce9 [pbs] Clean up title construction rationale 2015-07-22 23:49:08 +06:00
9872e588c8 Merge pull request #6292 from atomicdryad/pr-fix_pbs_titles
pbs: fix vague 'Full Episode' titles; prepend name of show
2015-07-22 23:42:19 +06:00
d609edf4f1 [udemy] Handle already-logged-in scenario (Closes #6327) 2015-07-22 22:49:00 +06:00
3a99d321a8 Merge pull request #6303 from jaimeMF/dash_no_live
[YoutubeDL] don't default to 'bestvideo+bestaudio/best' for live videos
2015-07-23 00:39:44 +08:00
4bb3d999ac Merge branch 'nichdu-lecture2go' 2015-07-22 23:33:28 +08:00
40101dc311 [lecture2go] Make optional fields non-fatal 2015-07-22 23:25:32 +08:00
e9c6deffee [lecture2go] Add more metadata fields 2015-07-22 23:22:19 +08:00
9c29bc69f7 [utils] Improve parse_duration
Now dots are parsed. For example '87 Min.'
2015-07-22 23:15:22 +08:00
1e12429564 [lecture2go] Update _TEST 2015-07-22 23:05:14 +08:00
795704f0f1 [lecture2go] Support more formats 2015-07-22 22:39:46 +08:00
981b9cdc8c [lecture2go] Improve some regular expressions 2015-07-22 22:09:01 +08:00
3f724339db Merge branch 'lecture2go' of https://github.com/nichdu/youtube-dl into nichdu-lecture2go 2015-07-22 20:10:45 +08:00
70c857b728 Credit Zach Bruggeman for the appleconnect extractor (#6190) 2015-07-22 11:49:54 +02:00
c84683c88b [viewster] Strip titles 2015-07-22 02:08:25 +06:00
b68a2613f8 [viewster] Rewrite for new API (Closes #6317) 2015-07-22 02:00:21 +06:00
28afa6e77a [snagfilms] Don't use '_' as a variable that is used 2015-07-21 20:50:02 +02:00
496ce6b349 [snagfilms] Improve m3u8 extraction (Closes #6309) 2015-07-21 23:54:31 +06:00
ce9512b78b release 2015.07.21 2015-07-21 17:20:54 +02:00
4eb59a6b1c [options] Fix a typo (#6307) 2015-07-21 09:11:23 +06:00
80b1ee0a4c Merge pull request #6307 from jwilk/spelling
README: fix a typo
2015-07-21 09:09:55 +06:00
f993afb26d README: fix a typo 2015-07-20 23:10:29 +02:00
7c80519cbf [youtube] Extract start_time
From the 't=*' in the url.
Currently youtube-dl doesn't use the value, but it was requested for the mpv plugin.
2015-07-20 21:10:28 +02:00
8250c32f49 [YoutubeDL] don't default to 'bestvideo+bestaudio/best' for live videos
Doesn't work currently.
2015-07-20 20:25:53 +02:00
2fe1ff8582 [youtube] Set 'is_live' 2015-07-20 20:14:20 +02:00
17ee98e1a5 [youtube] Fix upload_date in test 2015-07-20 19:48:50 +02:00
2ee8f5d80f Merge remote-tracking branch 'yan12125/download-dash-segments' (#5886) 2015-07-20 19:34:24 +02:00
3f302bca8c [tumblr] Improve downloading notes 2015-07-20 18:54:47 +08:00
c909e5820e [tumblr] Delegate to GenericIE for non-tumblr videos
Fixes #6162
2015-07-20 18:51:25 +08:00
a1b85269a4 [extractor/generic] Support vid.me embeds 2015-07-20 18:49:53 +08:00
faa1f83ab4 [twitch:stream] Improve _VALID_URL (Closes #6294) 2015-07-20 02:16:07 +06:00
308c505c3d [francetv] Improve _VALID_URL 2015-07-20 01:03:43 +06:00
0eacd2aaae less clunky if statement 2015-07-19 13:59:12 -05:00
18ae46ad4b [vice] Modernize 2015-07-20 00:42:25 +06:00
65c2b21df1 [vice] Make test only matching 2015-07-20 00:40:43 +06:00
772acaf31f [vice] Do not capture unused groups in _VALID_URL 2015-07-20 00:39:55 +06:00
f8d0745e27 Merge pull request #6291 from atomicdryad/pr-fixvice
fix/support news.vice.com
2015-07-20 00:39:16 +06:00
d719c6a5ab [ard:mediathek] Add test for direct mp4 2015-07-20 00:13:39 +06:00
769efa16af [ard:mediathek] Remove dead test 2015-07-20 00:08:21 +06:00
86b4e98ac6 [ard:mediathek] Add audio test 2015-07-20 00:05:10 +06:00
3bf8c316a6 [sportschau] Reimplement in terms of ard extractor 2015-07-20 00:01:22 +06:00
e37c92ec6d [ard] Extract all formats 2015-07-19 23:59:50 +06:00
a5dd9a0c5d pbs: fix vague 'Full Episode' titles; prepend name of show
Many videos are given the title 'Full Episode' or 'Episode x', etc;
in the info json 'title' is the episode title (for oneshots this is
'Full Episode') while the program name is 'program':{'title'. This
changes the title from '(episode title)' to
 '(program name) - (episode title)'

The following urls demonstrate useless titles

    http://video.pbs.org/video/2365367186/
    http://video.pbs.org/video/2365519307/
    http://video.pbs.org/video/2365527039/
    http://video.pbs.org/video/2365530605/

Before change

    Full Episode
    Episode 5 | Preview
    Season 3 | Episode 4 Preview
    July 17, 2015

After change

    To Catch A Comet - Full Episode
    The Crimson Field - Episode 5 | Preview
    Last Tango in Halifax - Season 3 | Episode 4 Preview
    Charlie Rose The Week - July 17, 2015
2015-07-19 11:47:58 -05:00
7a4a945f13 fix/support news.vice.com 2015-07-19 11:33:02 -05:00
1d18e26eca [francetv] Remove unused import 2015-07-19 21:54:12 +06:00
ac4b8df5e4 [francetv] Fix embed test 2015-07-19 21:53:54 +06:00
3bc9fb5889 [francetv] Update jt test 2015-07-19 21:53:09 +06:00
632cbb8efa [francetv] Fix f4m extraction completely 2015-07-19 21:51:06 +06:00
789a12aaaf [francetv] Restore support for jt videos 2015-07-19 21:50:25 +06:00
ecdbe09e10 [francetv] Fix f4m extraction 2015-07-19 21:45:49 +06:00
1dc31c2786 [appleconnect] Add new extractor (fixes #6189)
Closes #6190.
2015-07-19 13:00:30 +02:00
32470bf619 [sportschau] Improve title extraction
The html '<title>' ends with '- sportschau.de', which shouldn't be part of the title.
2015-07-19 11:27:12 +02:00
8b61bfd638 [sportschau] skip download in test 2015-07-19 11:27:12 +02:00
8a7a208905 [sportschau] Add support for sportschau.de
Closes #6199.
2015-07-19 11:25:51 +02:00
0215103e92 [francetv] Remove unused import 2015-07-19 11:13:27 +02:00
c2d1be8981 [iqiyi] Add skip_download to reduce network traffic
MD5 checksums are commented out in
36068ae019, and actual downloads are not
necessary anymore.
2015-07-19 11:20:05 +08:00
4951c9f821 Credit @sceext2 for fixing iQiyi extractor (#6266) 2015-07-19 11:16:29 +08:00
726adc43ec [tagesschau] set description=None for empty descriptions 2015-07-19 05:09:29 +02:00
3c6ae8b59e [tagesschau] add support for Bericht aus Berlin videos 2015-07-19 04:28:00 +02:00
605be3f7f8 Merge pull request #6283 from rohieb/patch/fix-tagesschau-tests
[tagesschau] fix test which links to nonexisting video
2015-07-19 08:01:22 +06:00
c51bc70e0f [tagesschau] fix test which links to nonexisting video 2015-07-19 03:52:58 +02:00
e89d7e3029 [tagesschau] add support for more video types
I found that currently only tagesschau videos are played. There are some
more shows hosted on tagesschau.de (see [0] for example) which are
easily playable by adjusting the regex. So this patch adds support for:
* tagesthemen
* tagesschau vor 20 Jahren
* tagesschau (mit Gebärdensprache)
* nachtmagazin

Note that some videos don't provide a description, so in order for the
tests to succeed, an ExtractorError needs to get caught.

[0]: http://www.tagesschau.de/multimedia/video/videoarchiv2~_date-20150714.html
2015-07-19 03:44:16 +02:00
4b0f45f667 Merge branch 'sceext2-fix-iqiyi-2015-07-17' 2015-07-19 03:57:36 +08:00
36068ae019 [iqiyi] Comment out some MD5 sums
The value is different on Travis CI server
2015-07-19 03:54:59 +08:00
761ee0d827 [iqiyi] Remove unused imports 2015-07-19 02:28:43 +08:00
fb8bc3f818 Merge branch 'fix-iqiyi-2015-07-17' of https://github.com/sceext2/youtube_dl into sceext2-fix-iqiyi-2015-07-17 2015-07-19 02:27:59 +08:00
826a7da808 [rtlnl] Avoid episodes completely (Closes #6275) 2015-07-19 00:27:23 +06:00
cbd55ade68 [extractor/generic] Add support for francetv embeds 2015-07-18 22:56:00 +06:00
5705ee6ef8 [francetv] Fix duration extraction 2015-07-18 22:43:42 +06:00
3f5c6d0c1b [francetv] Add support for embeds and clean up _VALID_URL 2015-07-18 22:41:34 +06:00
e58066e244 [vk] Add age restricted video test for reference 2015-07-18 19:25:06 +06:00
ee48b6a88f [vk] Capture error message 2015-07-18 19:15:20 +06:00
9ac09ed4de [bliptv] Remove unused import 2015-07-18 19:13:10 +06:00
22603348aa [compat] Fix _asciire 2015-07-18 18:32:52 +06:00
fec73daaa3 [vk:uservideos] Revert orderedSet 2015-07-18 18:23:35 +06:00
c6b68648f4 [bilibili] Show georestriction error 2015-07-18 17:36:46 +06:00
1ecb5d1d83 [vk] Clarify extractor names 2015-07-18 17:23:33 +06:00
dc786d3db5 [vk:uservideos] Improve extraction 2015-07-18 17:22:25 +06:00
74fe23ec35 [extractor/common] Style 2015-07-18 16:35:28 +06:00
b0bff54b08 release 2015.07.18 2015-07-18 11:59:45 +02:00
1b541d8d6e [iqiyi] fix iqiyi (2015-07-17), update the md5 salt (enc_key) to iqiyi latest (2015-07-17) flash player. 2015-07-18 12:34:26 +08:00
f29ac588dd [nationalgeographics] Fix extraction (Closes #6262) 2015-07-18 06:33:50 +06:00
0696667734 [twitch:stream] Clarify channel_id reassignment rationale (#6263) 2015-07-18 06:27:45 +06:00
1793d71db6 [twitch:stream] Fix channel_id in different case (Closes #6263) 2015-07-18 06:18:03 +06:00
4211e1941b [videomega] Add shortcut to _VALID_URL 2015-07-18 04:27:09 +06:00
4bdfef5a18 [videomega] Add tests 2015-07-18 04:25:30 +06:00
8a37f53685 [videomega] Revert iframe URL 2015-07-18 04:25:10 +06:00
4e1ad6e9a8 [videomega] Extend _VALID_URL and improve extraction (Closes #6260) 2015-07-18 04:13:45 +06:00
fb10e1aa57 Merge branch 'seamusphelan-sbs_website_changes' 2015-07-18 02:43:44 +06:00
3c283a381e [sbs] Simplify 2015-07-18 02:43:18 +06:00
dac4d5be12 Merge branch 'sbs_website_changes' of https://github.com/seamusphelan/youtube-dl into seamusphelan-sbs_website_changes 2015-07-18 02:13:55 +06:00
530857182d [bliptv] Add test with missing duration 2015-07-18 01:45:54 +06:00
9441f77faa [bliptv] Use xpath for extraction and fix test 2015-07-18 01:45:36 +06:00
3cc8b4c327 [compat] Fix missing _asciire on python 2.6 2015-07-18 00:24:39 +06:00
6b19647d57 [veehd] Use compat_urllib_parse_unquote 2015-07-18 00:04:25 +06:00
7bd42d0d96 [openfilm] Fix compat_urllib_parse_unquote_plus import 2015-07-17 23:56:27 +06:00
c60e8cfaf7 [ehow] Simplify 2015-07-17 23:54:38 +06:00
7fd002c006 [youtube] Use compat_urllib_parse_unquote and compat_urllib_parse_unquote_plus 2015-07-17 23:51:57 +06:00
db6c50f109 [ynet] Use compat_urllib_parse_unquote_plus 2015-07-17 23:50:52 +06:00
aa4789d632 [xvideos] Use compat_urllib_parse_unquote 2015-07-17 23:50:25 +06:00
ee8de13e14 [xtube] Use compat_urllib_parse_unquote 2015-07-17 23:50:02 +06:00
7dde5f6a8d [xnxx] Use compat_urllib_parse_unquote 2015-07-17 23:49:38 +06:00
736f003f2e [xbef] Use compat_urllib_parse_unquote 2015-07-17 23:49:14 +06:00
47af21e8f1 [spankwire] Use compat_urllib_parse_unquote 2015-07-17 23:47:51 +06:00
605cbef653 [pornhub] Use compat_urllib_parse_unquote and compat_urllib_parse_unquote_plus 2015-07-17 23:47:23 +06:00
388ad0c05c [playvid] Use compat_urllib_parse_unquote and compat_urllib_parse_unquote_plus 2015-07-17 23:46:33 +06:00
2ebbb6f1f7 [photobucket] Use compat_urllib_parse_unquote 2015-07-17 23:45:55 +06:00
d54f1c7477 [openfilm] Use compat_urllib_parse_unquote_plus 2015-07-17 23:45:26 +06:00
b78f5ec4c3 [odnoklassniki] Use compat_urllib_parse_unquote 2015-07-17 23:45:00 +06:00
9fd3bf04b7 [myvideo] Use compat_urllib_parse_unquote 2015-07-17 23:44:38 +06:00
e97bb3de83 [mofosex] Use compat_urllib_parse_unquote 2015-07-17 23:43:36 +06:00
c2daf8dfa4 [mixcloud] Use compat_urllib_parse_unquote 2015-07-17 23:42:43 +06:00
09b718c439 [mitele] Use compat_urllib_parse_unquote 2015-07-17 23:42:11 +06:00
c177bb3a50 [metacafe] Use compat_urllib_parse_unquote 2015-07-17 23:41:47 +06:00
977a247a06 [malemotion] Use compat_urllib_parse_unquote 2015-07-17 23:41:14 +06:00
899a3e2f13 [karaoketv] Use compat_urllib_parse_unquote_plus 2015-07-17 23:40:35 +06:00
8ee4ecb48d [infoq] Use compat_urllib_parse_unquote 2015-07-17 23:39:54 +06:00
f7e6f7fa23 [extractor/generic] Use compat_urllib_parse_unquote 2015-07-17 23:39:32 +06:00
1f80e360fc [gamespot] Use compat_urllib_parse_unquote 2015-07-17 23:38:30 +06:00
d7011316d0 [facebook] Use compat_urllib_parse_unquote 2015-07-17 23:37:56 +06:00
d3671b344f [ehow] Use compat_urllib_parse_unquote 2015-07-17 23:37:23 +06:00
a60cccbf9f [crunchyroll] Use compat_urllib_parse_unquote 2015-07-17 23:36:58 +06:00
3e72f5f10e [ceskatelevize] Use compat_urllib_parse_unquote 2015-07-17 23:36:11 +06:00
b94b78971c [bet] Use compat_urllib_parse_unquote 2015-07-17 23:35:14 +06:00
4d08161ac2 [compat] Mention unquote_plus 2015-07-17 23:32:43 +06:00
8954e48140 [test_compat] Add tests for compat_urllib_parse_unquote_plus 2015-07-17 23:31:23 +06:00
aa99aa4e85 [compat] Add compat_urllib_parse_unquote_plus 2015-07-17 23:28:34 +06:00
d79febcd06 [test_compat] Remove redundant test 2015-07-17 23:09:56 +06:00
13fc7f3a05 Merge branch 'atomicdryad-pr-crashfix_compat_urllib_unquote' 2015-07-17 22:59:17 +06:00
14309e1ddc [test_compat] Make tests more idiomatic 2015-07-17 22:58:39 +06:00
5513967926 [compat] Simplify and use latest cpython 3 code 2015-07-17 22:58:13 +06:00
eacd875f3b Merge pull request #6259 from remitamine/howstuffworks
[howstuffwoks] fix _VALID_URL regex
2015-07-17 22:08:40 +06:00
c4fe07c7af match only the test url 2015-07-17 17:07:55 +01:00
1186e3f91a do not capture a group 2015-07-17 16:45:53 +01:00
f354385bf5 Add test for urls without a number 2015-07-17 16:43:27 +01:00
cabe001590 [howstuffwoks] fix _VALID_URL regex 2015-07-17 16:18:33 +01:00
89f691e141 Merge branch 'pr-crashfix_compat_urllib_unquote' of https://github.com/atomicdryad/youtube-dl into atomicdryad-pr-crashfix_compat_urllib_unquote 2015-07-17 21:15:55 +06:00
4a63291144 Add tests for compat_urllib_parse_unquote 2015-07-17 09:46:08 -05:00
593b77064c Don't forget trailing '%' 2015-07-17 09:45:49 -05:00
9fefc88656 fix TestCompat test_all_present 2015-07-17 07:24:07 -05:00
a3bfddfa5e bbc.py: correct syntax 2015-07-17 02:47:02 -05:00
36da48798a handle titles and captions set to '' 2015-07-17 02:27:50 -05:00
a0f28f90fa remove kebab 2015-07-17 01:50:43 -05:00
851229a01f remove debugprint 2015-07-17 01:49:55 -05:00
c9c854cea7 replace old compat_urllib_parse_unquote with backport from python3's function
* required unquote_to_bytes function ported as well
    (uses .decode('hex') instead of dynamically populated _hextobyte global)
  * required implicit conversion to bytes and/or unicode in places due to
    differing type assumptions in p3
2015-07-17 01:31:29 -05:00
a38436e889 [extractor/common] Add 'transform_source' parameter to _extract_f4m_formats() 2015-07-17 12:02:49 +08:00
23fc384f2c [npo] Compound title 2015-07-17 01:28:52 +06:00
1540119723 [npo] Remove unused imports 2015-07-17 00:54:05 +06:00
574f42d79a [vpro] Improve playlist extraction 2015-07-17 00:53:12 +06:00
536b0700b0 [npo] Allow missing description 2015-07-17 00:40:04 +06:00
5ba761eb85 [npo] Prefer aflevering_titel over titel 2015-07-17 00:39:22 +06:00
611ac379bb [vpro] Fix extraction and add support for vpro playlists 2015-07-17 00:34:24 +06:00
03f32a7ead [wnl] Add extractor for omroepwnl playlists 2015-07-17 00:14:38 +06:00
50ea2bb20d [npo] Update test 2015-07-16 23:56:57 +06:00
525daedd5a [npo] Add support for omroepwnl fragments 2015-07-16 23:54:43 +06:00
e118031ef8 [npo] Extend _VALID_URL to support ntr.nl (Closes #6248) 2015-07-16 23:21:04 +06:00
45eedbe58c Generic: use compat_urllib_parse_unquote to prevent utf8 mangling
of the entire page in python 2.

-requires- fixed compat_urllib_parse_unquote

example - the following will save with a mangled playlist title,
 instead of the kanji for 'tsunami'. This affects all utf8encoded
 urls as well

youtube-dl -f18 -o '%(playlist_title)s-%(title)s.%(ext)s' \
  61c14c1e3a/tsunami.html
2015-07-15 15:30:47 -05:00
e37c932fca compat_urllib_parse_unquote: crash fix: only decode valid hex
on python 2 the following has a { "crash_rate": "100%" } of the time
as it tries to parse '" ' as hex.
2015-07-15 15:28:50 -05:00
5eb778bf4d Merge pull request #6242 from dstftw/f4m-improvements
[f4m] Improvements
2015-07-16 02:23:26 +06:00
ab9b890b52 [prosiebensat1] Clarify test purpose 2015-07-16 02:23:07 +06:00
31c746e5dc [extractor/common] Keep going in some media_url is missing 2015-07-16 01:25:33 +06:00
f01f731107 [prosiebensat1] Use generic f4m manifest extraction 2015-07-16 01:15:47 +06:00
70f0f5a8ca [extractor/common] Recursively extract child f4m manifests 2015-07-16 01:15:15 +06:00
cc357c4db8 [extractor/common] Properly handle full URLs 2015-07-16 01:14:52 +06:00
97f4aecfc1 [extractor/common] Handle malformed f4m manifests 2015-07-16 01:14:08 +06:00
2af0f87c8b [prosiebensat1] Fix extraction (Closes #6215) 2015-07-15 23:32:52 +06:00
b062d94eef [README.md] Clarify authentication with .netrc file 2015-07-15 03:08:36 +06:00
6c1b0c0ed2 [dfb] Extract formats 2015-07-15 00:01:41 +06:00
ddcdc684e2 [dfb] Extract display_id and modernize 2015-07-14 23:59:21 +06:00
eae89f92e6 [dfb] Update test 2015-07-14 23:54:13 +06:00
01d115b06b [jeuxvideo] Relax _VALID_URL (fixes #6230) 2015-07-14 19:07:40 +02:00
79057965a8 [udemy] Remove superfluous field 2015-07-14 22:46:26 +06:00
dcd4d95c8e [udemy] Fix authentication (Closes #6224) 2015-07-14 22:39:41 +06:00
cf61d96df0 [extractor/common] Add _form_hidden_inputs 2015-07-14 22:38:10 +06:00
f8da79f828 [extractor/common] Improve _form_hidden_inputs and rename to _hidden_inputs 2015-07-14 22:36:30 +06:00
9750e7d70e [postprocessor/ffmpeg] Don't use '[youtube] ...' in messages
Because it can be used for other extractors.
2015-07-14 12:56:32 +02:00
50aa2bb6b9 [dailymotion] Extract duration (closes #6221) 2015-07-14 12:50:34 +02:00
1d1dd597ed [dramafever] Extract srt (Closes #6207) 2015-07-14 01:35:44 +06:00
cfe5537ee5 [myspass] Fix extraction (closes #6206) 2015-07-14 00:23:50 +08:00
7869eb3fc4 Credit Bernhard Minks for nowtv patch 2015-07-13 22:21:35 +06:00
6dfa0602f0 [nowtv] Fix extraction (Closes #6169) 2015-07-13 22:11:05 +06:00
75a40b2251 [SBS] fixes due to website changes 2015-07-13 22:35:45 +10:00
28fb109ed0 [rds] Improve _VALID_URL 2015-07-12 23:45:47 +06:00
48607afac5 Merge branch 'fstirlitz-rdsca' 2015-07-12 23:36:32 +06:00
b6ea9ef21a [rds] Improve 2015-07-12 23:35:56 +06:00
b8dd44baa9 Merge branch 'rdsca' of https://github.com/fstirlitz/youtube-dl into fstirlitz-rdsca 2015-07-12 21:34:32 +06:00
c4f1fde75b [nrk:tv] Add format id prefixes 2015-07-12 20:42:18 +06:00
667170e2c7 [nrk:tv] Add support for radio URLs (Closes #6200) 2015-07-12 20:40:00 +06:00
53429e6551 [onionstudios] Fix extraction 2015-07-12 12:53:15 +06:00
ac8f97f2b3 [rdsca] New extractor 2015-07-11 19:05:17 +02:00
41c0d2f8cb Credit @aurium for avi recode and postprocessort args (#5942) 2015-07-11 23:00:19 +06:00
1f3a43dbe6 Merge branch 'aurium-master' 2015-07-11 22:59:18 +06:00
369e195a44 Handle postprocessor_args similarly to external_downloader_args 2015-07-11 22:43:02 +06:00
15006fedb9 [postprocessor/ffmpeg] Spread postprocessor args usage on all ffmpeg extractors 2015-07-11 22:42:03 +06:00
e35b23f54d [postprocessor/common] Improve postprocessor args fetching and clarify doc 2015-07-11 22:41:33 +06:00
f72b0a6032 Revert xvid to avi and make docs to be similar to existing external downloader option 2015-07-11 22:15:16 +06:00
ac9ed061ec Merge branch 'master' of https://github.com/aurium/youtube-dl into aurium-master 2015-07-11 21:58:12 +06:00
d919fa3344 [vk] Handle access denied error 2015-07-11 21:26:03 +06:00
79913fde35 [vk] Add list id to info_url 2015-07-11 21:23:49 +06:00
da634d0a8b Merge branch 'dufferzafar-webofstories' 2015-07-11 04:43:55 +06:00
fac54cb426 [webofstories:playlist] Improve and add test 2015-07-11 04:43:29 +06:00
3f19b9b7c1 Merge branch 'webofstories' of https://github.com/dufferzafar/youtube-dl into dufferzafar-webofstories 2015-07-11 04:17:54 +06:00
dc48695ab9 Document how to group format selectors 2015-07-10 22:59:45 +02:00
0a31a35098 [YoutubeDL] format spec: add additional checks for invalid syntax 2015-07-10 22:46:25 +02:00
86f2541695 Remove unused 're' imports 2015-07-10 22:22:33 +02:00
181c4ccaaa [qqmusic] Add more localized names 2015-07-11 01:21:36 +08:00
ed848087d5 [neteasemusic] Add more localized names 2015-07-11 01:21:18 +08:00
edd66be5be [kuwo] Add more localized names 2015-07-11 01:21:04 +08:00
246995dbc8 [youku] Add localized name 2015-07-11 00:58:13 +08:00
b931fbe5ab [yinyuetai] Add localized name 2015-07-11 00:57:59 +08:00
e014ff015d [yam] Add localized name 2015-07-11 00:53:08 +08:00
4fa5f40232 [xuite] Add localized name 2015-07-11 00:52:56 +08:00
9b15be97aa [udn] Add localized name 2015-07-11 00:52:19 +08:00
a7ada46bd9 [qqmusic] Add localized name 2015-07-11 00:52:07 +08:00
9d16788ad9 [nextmedia] Add localized name 2015-07-11 00:51:55 +08:00
6ce89aecc3 [neteasemusic] Add localized name 2015-07-11 00:51:35 +08:00
963d0ce7e3 [letv] Add localized name 2015-07-11 00:51:26 +08:00
0f08d7f851 [kuwo] Add localized name 2015-07-11 00:51:14 +08:00
44c514eb9c [iqiyi] Add localized name 2015-07-11 00:51:03 +08:00
513cbdda93 [douyutv] Add localized name 2015-07-11 00:50:45 +08:00
e1ba152352 [ctsnews] Add localized name 2015-07-11 00:50:31 +08:00
446e764500 [baidu] Add localized name 2015-07-11 00:49:59 +08:00
901d00caa6 Merge branch 'ping-kuwo' 2015-07-11 00:11:41 +08:00
094790d2c9 [kuwo:song] Give warnings for unavailable optional fields 2015-07-11 00:03:49 +08:00
1c0163a5cc [gorillavid] Use _form_hidden_inputs 2015-07-10 21:58:49 +06:00
8fa7e5817a [hostingbulk] Use _form_hidden_inputs 2015-07-10 21:58:24 +06:00
01b89d5682 [played] Use _form_hidden_inputs 2015-07-10 21:57:29 +06:00
9f01c1a803 [kuwo] Use \d instead of [0-9] 2015-07-10 23:56:51 +08:00
46f0f50016 [primesharetv] Use _form_hidden_inputs 2015-07-10 21:56:41 +06:00
b8070dbbd7 [promptfile] Use _form_hidden_inputs 2015-07-10 21:56:14 +06:00
3b16d803c9 [shared] Use _form_hidden_inputs 2015-07-10 21:55:22 +06:00
de195c23a6 [vimeo] Use _form_hidden_inputs 2015-07-10 21:54:39 +06:00
d3b8908886 [kuwo] Simpler calls to url_result() 2015-07-10 23:53:48 +08:00
2688176c77 [vodlocker] Use _form_hidden_inputs 2015-07-10 21:53:38 +06:00
a5839317aa [vk] Use _form_hidden_inputs when logging in 2015-07-10 21:52:03 +06:00
a0aab26a41 [twitch] Use _form_hidden_inputs when logging in 2015-07-10 21:49:39 +06:00
27713812a0 [extractor/common] Add method for extracting form hidden input fields as dict 2015-07-10 21:49:09 +06:00
cf2c5fda4f [kuwo] Use single quotes 2015-07-10 23:48:48 +08:00
a9684c0dbf [kuwo] Add KuwoBaseIE 2015-07-10 23:46:44 +08:00
c0bf5e1c4d [twitch] Fix non-ASCII logins/passwords on python 2 2015-07-10 21:40:21 +06:00
a31e3e7dcb [kuwo] Regular expression improvements
1. Prevent .+ and .*
2. Use [^>]+ instead of spaces for HTML tags
3. Remove unnecessary trailing parts
2015-07-10 23:38:54 +08:00
17b41a3337 [twitch] Show reset password request 2015-07-10 21:16:42 +06:00
89a683ae74 [twitch] Fix error message regex 2015-07-10 21:15:09 +06:00
008661069b Merge branch 'master' of github.com:rg3/youtube-dl 2015-07-10 20:56:08 +06:00
9296e92e1c [twitch] Fix login (Closes #6186) 2015-07-10 20:55:53 +06:00
a34af8d066 [kuwo] PEP8 2015-07-10 19:13:52 +08:00
8726e04629 Merge branch 'kuwo' of https://github.com/ping/youtube-dl into ping-kuwo 2015-07-10 19:11:58 +08:00
2a01c940ec Merge branch 'ping-neteasemusic' 2015-07-10 18:59:58 +08:00
4eab60cbd2 [netease:djradio] Use compat_itertools_count 2015-07-10 18:59:12 +08:00
a0e060ac1e [compat] Add compat_itertools_count
'step' parameter is added in Python 2.7
2015-07-10 18:58:12 +08:00
397a8ea96e [neteasemusic] Encoding fixes for Python 2.6 and 3.x 2015-07-10 18:43:38 +08:00
15830339ef [neteasemusic] PEP8 2015-07-10 18:30:23 +08:00
b29280285e Merge branch 'neteasemusic' of https://github.com/ping/youtube-dl into ping-neteasemusic 2015-07-10 18:25:12 +08:00
1633491bff [kuwo] Merge KuwoSingerMusicIE into KuwoSingerIE (missed kuwo.py) 2015-07-10 15:19:07 +08:00
2b0fa1f7dd [kuwo] Merge KuwoSingerMusicIE into KuwoSingerIE 2015-07-10 15:09:12 +08:00
02b386f80a [neteasemusic] Changes after review 2015-07-10 13:29:57 +08:00
bf20b9c540 [extractor/generic] Add test for myvi embed 2015-07-10 01:15:55 +06:00
06a12933f3 [pbs] Add support for subtitles (Closes #6184) 2015-07-10 00:58:01 +06:00
6dd94d3a79 [myvi:embed] Rename to myvi 2015-07-10 00:27:44 +06:00
f2f89c762a [myvi:embed] Improve _VALID_URL 2015-07-10 00:27:02 +06:00
e6c2d9ad29 [extractor/generic:myvi] Add support for myvi embeds 2015-07-10 00:25:36 +06:00
83423254cc [myvi:embed] Extend _VALID_URL 2015-07-10 00:07:26 +06:00
1c20ddc966 [myvi:embed] Add extractor (Closes #6167) 2015-07-09 23:53:50 +06:00
675e9f22ea [vimple] Extract spruto player based extractor class 2015-07-09 23:52:03 +06:00
77c6fb5b24 [youtube] Make further DASH manifests not fatal after succeeded one 2015-07-09 20:48:38 +06:00
082a0140ef [yinyuetai] Do not capture unused group 2015-07-08 23:40:19 +06:00
9e535ce055 Merge branch 'ping-yinyuetai' 2015-07-09 01:11:26 +08:00
d76dea001b [yinyuetai] Miscellaneous improvements
1. Include all fields in _TEST
2. Use .get() for optional fields
3. Clarify the intention of 'ext' in formats
2015-07-09 01:07:45 +08:00
af0f9b0e95 [yinyuetai] Style 2015-07-09 00:54:37 +08:00
e2082ea942 [yinyuetai] Add test for h5/ part in _VALID_URL 2015-07-09 00:50:32 +08:00
68923e52a3 Merge branch 'yinyuetai' of https://github.com/ping/youtube-dl into ping-yinyuetai 2015-07-09 00:48:23 +08:00
9281f6d253 [vk] Add test for youtube embed 2015-07-08 20:41:08 +06:00
4647845679 [vk] Fix youtube extraction 2015-07-08 20:34:50 +06:00
cf9cf7dd04 [vk] Extend _VALID_URL to handle biqle.ru (Closes #6179) 2015-07-08 20:27:06 +06:00
1316b54956 [clipsyndicate] Use _match_id 2015-07-08 13:43:23 +08:00
cbc1fadd6f [clipsyndicate] Support chic subdomain (fixes #6176) 2015-07-08 13:40:21 +08:00
4dd09c9add release 2015.07.07 2015-07-07 10:36:07 +02:00
267dc07e6b [gfycat] Catch errors 2015-07-07 14:22:13 +08:00
d7b4d5dd50 [gfycat] Extract id correctly (fixes #6165) 2015-07-07 14:16:56 +08:00
7f220b2fac [vk] Catch ownership confirmation request 2015-07-07 00:04:19 +06:00
275c0423aa [vk] Fix extraction (Closes #6153) 2015-07-07 00:02:34 +06:00
d3ee4bbc5a Merge branch 'ping-qqmusic-format-fix' 2015-07-06 17:55:45 +08:00
85a064861f [qqmusic] Use regex for thumbnails in test cases 2015-07-06 17:54:41 +08:00
d0b436bff2 Merge branch 'qqmusic-format-fix' of https://github.com/ping/youtube-dl into ping-qqmusic-format-fix 2015-07-06 17:24:44 +08:00
92b2f18072 Merge branch 'ping-qqmusic-album-fix' 2015-07-06 17:09:56 +08:00
dfc4eca21f [qqmusic:album] Playlist names are optional 2015-07-06 17:09:17 +08:00
fc7ae675e2 [qqmusic:album] Strip description 2015-07-06 17:08:32 +08:00
804ad79985 Merge branch 'qqmusic-album-fix' of https://github.com/ping/youtube-dl into ping-qqmusic-album-fix 2015-07-06 17:01:59 +08:00
da839880e9 Merge branch 'ping-qqmusic-playlist' 2015-07-06 16:20:46 +08:00
e9d33454b5 [qqmusic:playlist] Playlist names are optional 2015-07-06 16:19:49 +08:00
d80891efc4 Merge branch 'qqmusic-playlist' of https://github.com/ping/youtube-dl into ping-qqmusic-playlist 2015-07-06 16:08:30 +08:00
37c1e4025c [yinyuetai] New extractor for yinyuetai.com 2015-07-06 15:26:49 +08:00
59a83d3e5b [spiegeltv] Skip invalid m3u8 manifests (closes #6157) 2015-07-06 08:41:14 +08:00
13af92fdc4 [common] Add 'fatal' to _extract_m3u8_formats 2015-07-06 08:39:38 +08:00
0c20ee7d4b [rtlnl] Clarify current adaptive -> flash workaround rationale 2015-07-06 04:16:56 +06:00
89d42c2c75 [rtlnl] Clarify test 2015-07-06 02:58:02 +06:00
04611765a4 Merge branch 'corone17-patch-1' 2015-07-05 19:07:51 +06:00
9dfc4fa1a1 [rtlnl] Add test with encrypted m3u8 streams for reference 2015-07-05 19:07:07 +06:00
43232d5c14 [rtlnl] Improve 2015-07-05 19:01:07 +06:00
f7c272d4fa Merge branch 'patch-1' of https://github.com/corone17/youtube-dl into corone17-patch-1 2015-07-05 18:07:39 +06:00
ede21449c8 [crunchyroll] Fix extraction (Closes #5855, closes #5881) 2015-07-05 06:29:36 +06:00
bb8e553662 [YoutubeDL] format spec: Do not fail when a filter gives an empty result
For example with 'best[height<40]' we ended getting a 'IndexError: list index out of range'.
2015-07-04 21:41:09 +02:00
f5f4a27a96 [YoutubeDL] format spec: fix handling of '/' with ','
When using 'bestvideo/best,bestaudio', 'bestvideo/best' must be set as the current_selector (instead of appending it to the selectors), otherwise when it gets the ',' it would append 'None' to the selectors.
2015-07-04 21:30:26 +02:00
d7c9a3e976 Credit @remitamine for snagfilms (#6096) 2015-07-04 17:22:11 +06:00
35eb649e9d release 2015.07.04 2015-07-04 09:24:00 +02:00
e56a4c9e9b [thisamericanlife] Improve and simplify 2015-07-04 05:42:53 +06:00
95506e37af [thisamericanlife] Remove unnecessary comment 2015-07-04 05:12:28 +06:00
e41840c522 [thisamericanlife] get info from <meta> tags 2015-07-04 05:12:20 +06:00
2a46a27e6c [thisamericanlife] Add a new extractor 2015-07-04 05:12:10 +06:00
0bcdc27653 [dailymotion:cloud] Extend _VALID_URL (Closes #6145) 2015-07-03 22:47:52 +06:00
ddf0f74de7 [howcast] Fix extraction and modernize 2015-07-03 22:32:56 +06:00
91b21b2334 [infoq] Fix extraction (closes #6141) 2015-07-03 11:54:36 +08:00
66e568de3b [extractor/generic] Improve kaltura embeds support (Closes #6137) 2015-07-02 21:39:46 +06:00
f5ca97e393 [npo] Clarify token decryption algorithm source 2015-07-02 20:20:09 +06:00
8d06a62485 [npo] Decrypting token (closes #6136) 2015-07-02 16:47:55 +08:00
93f9420993 [pbs] Add coding declaration
Python 2.x does not work without it.
2015-07-02 13:13:27 +08:00
5b61070c70 [pbs] skip_download for m3u8 test cases 2015-07-02 13:08:48 +08:00
dbe1a93526 [pbs] Fix player URL (closes #6139) 2015-07-02 13:05:43 +08:00
aa5d9a79d6 Simplify postprocessor_args transmission to PP base class
* Remove `extra_cmd_args` transmission from sub to super class.
* Simplify params transmission through `downloader.params`.
2015-07-01 20:12:26 -03:00
86511ea417 [drtuber] Fix extraction 2015-07-01 21:47:56 +06:00
1866432db7 Rename --pp-params to --postprocessor-args and access value as super class attribute 2015-06-30 16:22:09 -03:00
cf2ac6df68 [YoutubeDL] format spec: Fix handling of '+' with '/'
'bestvideo+bestaudio/best' was incorrectly interpreted as 'bestvideo+(bestaudio/best)', so it would fail if 'bestaudio' doesn't exist instead of falling back to 'best'.
2015-06-30 19:50:17 +02:00
33f1f81b8b Merge pull request #6132 from alarig/master
Add support of HTTPS for ina.fr
2015-06-30 20:53:49 +06:00
9d0b581fea [youtube] Prefer meta for upload date and modernize 2015-06-30 20:52:26 +06:00
c05724cb18 Add support of HTTPS for ina.fr 2015-06-30 16:47:14 +02:00
f0714c9f86 [youtube] Speed up upload date regex (#6125) 2015-06-30 01:02:48 +06:00
cf386750c9 [hentaistigma] Modernize 2015-06-29 22:21:09 +06:00
54f428f645 Merge pull request #6120 from nawl/master
[hentaistigma] Fix video extractor
2015-06-29 21:14:49 +05:00
dc2bd20e55 Merge pull request #6098 from dstftw/use-codecs-from-dash-manifest
[youtube] Pick up codecs info from DASH manifest when not set explicitly
2015-06-29 20:58:52 +05:00
c608ee491f Merge pull request #6097 from dstftw/union-itags-from-multiple-dashmpd
[youtube] Extract formats from multiple DASH manifests (Closes #6093)
2015-06-29 20:58:34 +05:00
0130afb76e [YoutubeDL] format spec: allow grouping specifiers with parentheses 2015-06-29 12:46:02 +02:00
738b926322 [hentaistigma] Fix video extractor 2015-06-28 17:24:00 -06:00
bea41c7f3f Update rtlnl.py
Better to extract 'http://manifest.us.rtl.nl' from the json, I'd say. And I think it's better to use the default json-url to make it more futureproof.
Succesfully tested with tarball.
2015-06-29 00:59:18 +02:00
1bbe660dfa Merge pull request #6117 from Kagee/patch-1
NRK now supports / requires HTTPS
2015-06-29 03:15:53 +05:00
c4bd188da4 NRK now supports / requires HTTPS
Add s? to regexp to support new urls. Update testcases to use HTTPS.
2015-06-29 00:11:31 +02:00
5acfa126c8 [YoutubeDL] format spec: treat 'all' like a normal specifier
So you can use filters with it, for example 'all[width>=400][width<=600]'.
2015-06-28 22:48:02 +02:00
67134eaba1 [YoutubeDL] rework how the format spec is processed
The spec string is processed using 'tokenize.tokenize' to split it in words and operators, the filters are still processed using regular expressions.
This should make easier to allow grouping operators with parens.
2015-06-28 22:31:35 +02:00
5414623791 [extractor/common] Remove superfluous line 2015-06-29 00:49:19 +06:00
c93d53f5e3 [youtube] Fix likes/dislike extraction 2015-06-29 00:48:06 +06:00
507683780e Credit @gebn for moviefap 2015-06-28 23:08:05 +06:00
e8b9ee5e08 Merge branch 'gebn-moviefap' 2015-06-28 23:05:49 +06:00
d16154d163 [tnaflix] Generalize tnaflix extractors 2015-06-28 23:05:09 +06:00
c342041fba [extractor/common] Use NO_DEFAULT from utils 2015-06-28 22:56:45 +06:00
bf42a9906d [utils] Add default value for xpath_text 2015-06-28 22:56:07 +06:00
9603e8a7d9 [YoutubeDL] Handle None width and height similarly to formats 2015-06-28 22:55:28 +06:00
c7c040b825 Merge branch 'moviefap' of https://github.com/gebn/youtube-dl into gebn-moviefap 2015-06-28 18:00:49 +06:00
ac0474f89d [twitch:vod] Update _TEST
The original test case is gone
2015-06-28 13:33:09 +08:00
bb512e57dc [twitch:vod] Fix 'Source' format in m3u8 (closes #6115) 2015-06-28 13:33:09 +08:00
db652ea186 [moviefap] Fix flake8 warnings introduced in 1a5fd4e 2015-06-27 23:04:55 +01:00
5a9cc19972 [moviefap] Move flv videos to formats in the metadata 2015-06-27 23:03:06 +01:00
1a5fd4eebc [moviefap] Wrap long lines 2015-06-27 22:32:56 +01:00
8a1b49ff19 [moviefap] Explicitly sort formats to handle possible site changes 2015-06-27 22:28:17 +01:00
b971abe897 [moviefap] Replace call to str() with compat.compat_str() 2015-06-27 21:04:53 +01:00
43b925ce74 [moviefap] Replace calls to find() with util.xpath_text(). 2015-06-27 20:52:12 +01:00
62b742ece3 [moviefap] Remove redundant comments 2015-06-27 20:51:11 +01:00
d16ef949ca [moviefap] Allow non-critical fields to change without breaking extraction 2015-06-27 20:36:46 +01:00
23e7cba87f [twitter:card] Add extractor (#5239) 2015-06-28 01:22:25 +06:00
a8e6f30d8e [moviefap] Swap and justify tests 2015-06-27 20:16:53 +01:00
9c49410898 [moviefap] Add categories to tests 2015-06-27 20:16:53 +01:00
802d74aa6b [moviefap] Swap test for an alternative non-copyrighted video 2015-06-27 20:16:53 +01:00
71f9e49e67 [moviefap] Fix dictionary comprehension syntax incompatible with Python 2.6 2015-06-27 20:16:53 +01:00
82ea1051b5 [moviefap] Add new extractor 2015-06-27 20:16:53 +01:00
6c4d20cd6f [downloader/external] Fix externals downloaders specified with extension on Windows 2015-06-28 00:08:52 +06:00
04c27802c0 [smotri] Add tests for password protected videos 2015-06-27 23:31:27 +06:00
c3b7202f4f [smotri] Remove non relevant test 2015-06-27 23:03:26 +06:00
81103ef35d [smotri] Fix password protected video extraction 2015-06-27 23:00:27 +06:00
0eb5c1c62a Merge pull request #6081 from yan12125/skip_problematic_sites
[planetaplay/quickvid/vube] Skip inaccessible sites
2015-06-27 18:49:29 +05:00
a9de951744 [snagfilms] More tests 2015-06-27 18:57:01 +06:00
a42a1bb09d [snagfilms] Capture not available error 2015-06-27 18:54:08 +06:00
9fbfc9bd4d [snagfilms:embed] Capture geolocation restriction error 2015-06-27 18:50:26 +06:00
242a998bdc [snagfilms] Add support for shows 2015-06-27 18:40:01 +06:00
9d1bf70234 Merge branch 'remitamine-snagfilms' 2015-06-27 18:29:16 +06:00
b8c1cc1a51 [extractor/generic] Add test for snagfilms embeds 2015-06-27 18:28:10 +06:00
eedd20ef96 [extractor/generic] Add support for snagfilms embeds 2015-06-27 18:26:14 +06:00
7c197ad96d [snagfilms] Add routine for generic embeds extractions 2015-06-27 18:25:50 +06:00
654fd03c73 [snagfilms] Improve and simplify 2015-06-27 18:20:42 +06:00
cee16e0fa3 [newstube] style: fix alignment 2015-06-27 14:20:33 +02:00
73c471e9ef [newstube] Fix GUID extraction (fixes #6109) 2015-06-27 14:18:01 +02:00
533b99fbf9 Merge branch 'snagfilms' of https://github.com/remitamine/youtube-dl into remitamine-snagfilms 2015-06-27 16:52:51 +06:00
f39eb98bab download all pages before start extracting info 2015-06-27 10:55:25 +01:00
da77d856a1 [youtube] Add test for #6093 2015-06-27 14:55:46 +06:00
b2575b38e7 [options] Clarify --youtube-skip-dash-manifest 2015-06-27 14:38:41 +06:00
0a3cf9ad3d [youtube] Skip get_video_info requests when --youtube-skip-dash-manifest is specified 2015-06-27 14:31:18 +06:00
00334d0de0 [options] Add missing whitespace and split lines 2015-06-27 14:26:51 +06:00
226b886ca8 [vk] Fix authentication (Closes #6105) 2015-06-27 14:04:55 +06:00
bc93bdb5bb [youtube] Fix reference before assignment for video_info 2015-06-27 13:19:46 +06:00
af214c3a79 [youtube] More useful messages for georestricted videos (#5716) 2015-06-27 13:15:57 +08:00
4eb10f6621 [utils] Add ISO3166Utils 2015-06-27 13:13:57 +08:00
7d7d469025 add support for embed links 2015-06-27 00:13:14 +01:00
fd40bdc0be remove unnecessary symbolic name for group 2015-06-26 21:56:15 +01:00
7e0480ae0e convert tabs to 4 spaces identation 2015-06-26 21:50:27 +01:00
d80265ccd6 [youtube] Simplify non-DASH formats exclusion 2015-06-27 02:48:50 +06:00
1b5a1ae257 [youtube] Pick up codecs info from DASH manifest when not set explicitly 2015-06-27 00:41:26 +06:00
d8d24a922a [youtube] Extract formats from multiple DASH manifests (Closes #6093)
DASH manifest pointed by dashmpd from the video webpage and one pointed by get_video_info may
be different (namely different itag set) - some itags are missing from DASH manifest pointed by
webpage's dashmpd, some - from DASH manifest pointed by get_video_info's dashmpd).
The general idea is to take a union of itags of both DASH manifests (for example video with such
'manifest behavior' see https://github.com/rg3/youtube-dl/issues/6093).
2015-06-27 00:36:23 +06:00
03339b7b5b [snagfilms] Add new extractor 2015-06-26 18:25:43 +01:00
2028c6e03d Added a Playlist Info Extractor for WebOfStories 2015-06-26 21:27:43 +05:30
2988835af5 [lynda] Fix non-ASCII logins/passwords on python 2 2015-06-26 19:48:23 +06:00
62cca96b72 [lynda] Fix confirm login request (#6088) 2015-06-26 19:46:42 +06:00
b4dea075a3 [lynda] Fix login request (Closes #6088) 2015-06-26 19:36:04 +06:00
533f67d3fa [infoq] Relax _VALID_URL (Closes #6071) 2015-06-25 19:54:44 +06:00
906e2f0eac [downloader/external] Add downloader for httpie (closes #6079) 2015-06-25 15:48:04 +02:00
b8091db6b9 [planetaplay/quickvid/vube] Skip inaccessible sites 2015-06-25 16:40:29 +08:00
381c067755 [thesixtyone] Modernize 2015-06-25 16:19:04 +08:00
2182ab5187 [thesixtyone] Fix audio_server
Some of the songs are moved to Amazon AWS
2015-06-25 16:15:13 +08:00
a1593a4a0e release 2015.06.25 2015-06-25 07:43:49 +02:00
aa5740fb61 Merge remote-tracking branch 'origin/master' into pr-bbcnews 2015-06-25 00:34:46 -05:00
da92eeae42 Fix tests, description formatting 2015-06-25 00:34:26 -05:00
12e9e8445d [README.md] Fix typo 2015-06-25 01:10:42 +06:00
8084be78c5 [extractor/generic] Add test for OnionStudios embeds 2015-06-24 23:23:16 +06:00
1ac1c4c26e [extractor/generic] Add support for OnionStudios embeds (Closes #5841) 2015-06-24 23:19:50 +06:00
d4f58034f7 [onionstudios] Add generic embed extraction routine 2015-06-24 23:16:33 +06:00
f843300fe5 [onionstudios] Add extractor 2015-06-24 23:12:13 +06:00
03b9c94437 [soundcloud:user] Add test 2015-06-24 20:49:22 +06:00
a219d175c6 [soundcloud] Improve _VALID_URL
Do not takeover soundcloud:user URLs
2015-06-24 20:48:57 +06:00
3c3b4176bd Merge pull request #5961 from dstftw/force-generic-extractor
Add --force-generic-extractor
2015-06-24 19:10:45 +05:00
022383139b Merge pull request #6067 from mitsukarenai/master
[noco.tv] Fix issue #6066: title interpreted as integer
2015-06-24 19:10:01 +05:00
1a1251e877 [noco.tv] Fix issue #6066: title interpreted as integer 2015-06-24 10:40:01 +02:00
18b5e1e534 [drbonanza] Fix extraction of videos 2015-06-24 16:02:10 +08:00
2fece970b8 [extractor/generic] Clarify generic extraction warning 2015-06-24 03:08:24 +06:00
e20d0c1e69 [brightcove] Use compat_xml_parse_error (Closes #6060) 2015-06-23 21:34:29 +06:00
a9dcf4a860 Prefer externalId over non-mediaserver-specific hashkey for video id. 2015-06-23 01:08:07 -05:00
255f5694aa [faz] Extend _VALID_URL (Closes #6050) 2015-06-22 20:11:15 +06:00
25701d5a2c [xhamster] pep8: remove trailing ';' 2015-06-22 11:18:52 +02:00
a5158f38a3 [generic/adobetv] Support AdobeTVVideo embeds (#6039) 2015-06-22 15:07:32 +08:00
c76799c555 [extractor/generic] Add test for xhamster embed 2015-06-21 23:18:28 +06:00
2bb5b6d0a1 [generic] Add support for xhamster embeds 2015-06-21 23:11:25 +06:00
0bbba43ed0 [xhamster:embed] Add extractor (Closes #6032) 2015-06-21 23:10:38 +06:00
98ca102441 [sohu] Fix extraction again 2015-06-22 00:59:55 +08:00
3f3308cd75 Revert "[sohu] Update extractor"
This reverts commit 32060c6d6b.
2015-06-21 23:29:40 +08:00
6f96e308d0 [francetvinfo.fr] Support dmcloud embeds (fixes #6034) 2015-06-21 21:31:33 +08:00
756f574e4e [dailymotion/generic] Add DailymotionCloudIE 2015-06-21 21:30:34 +08:00
78294e6a9c [bbccouk] Remove TTML to srt conversion codes
It's broken. See #6038
2015-06-21 19:24:45 +08:00
4e33577173 [utils] Support ttaf1 namespace in TTML
It's found in bbc.co.uk. See #6038
2015-06-21 19:24:39 +08:00
607841af64 [adobetv] Support embeddable videos (closes #6039) 2015-06-21 18:55:26 +08:00
396726244a [utils/ffmpeg] Move ISO 639 related codes to utils 2015-06-21 18:53:17 +08:00
c5895d5dbd [tumblr] Support Vimeo embeds (fixes #5969) 2015-06-21 18:30:38 +08:00
b407e173e4 [vimeo/generic] Move detection logic from GenericIE to VimeoIE 2015-06-21 18:23:58 +08:00
6a745c2c0f [pinkbike] PEP8 2015-06-21 18:23:08 +08:00
2da0cad6ae [neteasemusic] Do proper rounding conversion of millisecond timestamps/durations 2015-06-21 11:44:50 +08:00
af1fa6234e [neteasemusic] Add new extractor for music.163.com 2015-06-21 11:12:31 +08:00
c9ac7fa909 [imdb] Fix extraction 2015-06-21 04:17:54 +06:00
964afd0689 [xvideos] Support lower-quality formats found on Android
Closes #5968
2015-06-21 03:12:17 +08:00
2a282a3b5f Unbreak breakage that was broken to test breakage 2015-06-20 11:11:41 -05:00
7bb23aeca4 rename bbccouk.py -> bbc.py 2015-06-20 11:08:13 -05:00
de939d89eb Support BBC news in other languages, non-mediaselector videos 2015-06-20 11:04:46 -05:00
77c975f536 typofix 2015-06-20 08:28:14 -05:00
75ab0ebcf5 no .get('..',None) 2015-06-20 08:24:02 -05:00
10273d6e08 toss new stuff into old file 2015-06-20 08:22:13 -05:00
16d6973f8a [viki] Pass session token around (#6005) 2015-06-20 00:49:28 +06:00
edcd2d665b Merge branch 'misterhat-pinkbike' 2015-06-20 00:10:27 +06:00
385c3e5e91 [pinkbike] Improve and simplify 2015-06-20 00:10:08 +06:00
c8e337450b Merge branch 'pinkbike' of https://github.com/misterhat/youtube-dl into misterhat-pinkbike 2015-06-19 23:00:00 +06:00
10464af5d1 [dramafever:series] Fix extraction while authenticated 2015-06-19 22:02:07 +06:00
cbcd1a5474 [dramafever] Add support for authentication (Closes #6017) 2015-06-19 21:57:31 +06:00
c9bebed294 [youtube] Add itag 59 and 78 (Closes #5979) 2015-06-19 20:52:44 +06:00
d5552a3477 bbcnews: Switch to parse_duration, revert change to docs/supportedsites.md 2015-06-19 06:25:50 -05:00
a8b081a052 BBCNewsIE: eliminate redundant function.
BBCCoUkIE._download_media_selector: use class variable instead of
hardcoded string for mediaselector_url template.
2015-06-19 01:52:25 -05:00
9e96dc8b35 Support BBC News (bbc.com/news) 2015-06-19 01:39:30 -05:00
360075e28a [pornhub] Extend _VALID_URL (Closes #6019) 2015-06-18 22:26:17 +06:00
accf79b107 [viki] Add support for authentication (Closes #6005) 2015-06-18 21:17:26 +06:00
4d58b24c15 [qqmusic] Use _check_formats instead 2015-06-18 23:09:04 +08:00
c33a8639a7 [postprocessor/embedthumbnail] Skipping if thumbnail file missing
Fixes #5996
2015-06-18 22:05:02 +08:00
25fa8d66e6 [bbccouk] Fix description (closes #6006) 2015-06-18 22:00:13 +08:00
974a6146fe [bbccouk] Fix error handling 2015-06-18 21:40:45 +08:00
0392ac98d2 [qqmusic] Fix code formatting 2015-06-18 21:13:03 +08:00
5e3915cbe3 [qqmusic] Fix song extraction when certain formats are unavailable 2015-06-18 21:06:25 +08:00
29b809de68 [qqmusic] Fix album extraction 2015-06-18 15:52:04 +08:00
8f73e89ca0 [kuwo] New extractor for kuwo.cn 2015-06-18 14:15:54 +08:00
0d0d5d3717 [qqmusic] Add support for playlists 2015-06-18 13:59:37 +08:00
a69e8bfdd9 [lifenews] Fix tests 2015-06-17 20:29:15 +06:00
062a3fdf36 [lifenews] Modernize 2015-06-17 20:28:47 +06:00
028a33d7f2 [lifenews] Fix extraction 2015-06-17 20:27:38 +06:00
14835de9fb Use shlex.split for --pp-params and update related docs. 2015-06-16 18:10:31 -03:00
447053668f [spankwire] Fix extraction 2015-06-16 21:19:18 +06:00
f3aecb27a4 [youku] Simplify a bit the 'entries' construction
Mainly avoid having to use an index.
2015-06-16 14:41:52 +02:00
7f0172b3e5 Credit @jackyzy823 for iqiyi 2015-06-15 22:29:41 +06:00
79fe954d79 Merge branch 'PeterDing-youku' 2015-06-16 00:20:52 +08:00
0501bfa159 [YoutubeDL] Youku extractor now uses the standard format selection 2015-06-16 00:15:30 +08:00
a155b7e76c [youku] Coding style 2015-06-16 00:15:09 +08:00
5228b756af [youku] Add cn_verification_proxy support and add a georestricted test case 2015-06-16 00:06:23 +08:00
04e7596680 [youku] Better error handling 2015-06-15 23:54:55 +08:00
f1e66cb2eb [youku] Change video_id and add a multipart test case 2015-06-15 23:46:07 +08:00
4fd35ee072 [safari] Add test for #5985 2015-06-15 21:36:30 +06:00
ee69799262 [youku] Add a v.swf test case 2015-06-15 23:36:28 +08:00
636a9637f4 Merge pull request #5985 from zx8/master
[safari] make url regex more lenient
2015-06-15 20:31:47 +05:00
9383e66f94 [youku] Use _match_id 2015-06-15 23:31:30 +08:00
99e6833c85 [francetv] Update f4m manifest token URL (Closes #5981, Closes #5989) 2015-06-15 21:30:27 +06:00
c203be3fb4 [youku] Better handling for Python 2/3 compatibility 2015-06-15 23:28:59 +08:00
02175a7986 [youtube:search] Fix search query (Closes #5988) 2015-06-15 21:01:26 +06:00
8117df4cd9 [vk] Extract view count 2015-06-15 20:55:25 +06:00
7c7dd9dc7f [vk] Fix upload date extraction 2015-06-15 20:47:01 +06:00
054932f403 [vk] Fix extraction (Closes #5987) 2015-06-15 20:46:10 +06:00
aed473ccf9 [youku] PEP8 2015-06-15 22:41:24 +08:00
8268e94cd4 Merge branch 'youku' of https://github.com/PeterDing/youtube-dl into PeterDing-youku 2015-06-15 22:36:44 +08:00
4af98ecdfb [vbox7] Fix extraction (fixes #5967) 2015-06-15 18:49:27 +08:00
4b9f9010b0 release 2015.06.15 2015-06-15 01:35:50 +02:00
zx8
2a0fcf6113 [safari] make url regex more lenient 2015-06-15 00:27:43 +01:00
67d95f177c [niconico] Simplify format info 2015-06-15 03:43:33 +06:00
44773ad125 Merge pull request #5975 from chaoskagami/niconico_qualitynote
Quality note for niconico
2015-06-15 02:38:33 +05:00
5774ef35c4 [options] Add missing whitespace for --fixup description 2015-06-15 02:57:07 +06:00
b95cfa9170 [liveleak] Clarify test 2015-06-15 02:54:49 +06:00
afa1ded425 [liveleak] Clarify rationale for restoring raw video 2015-06-15 02:54:05 +06:00
00ac23e6e0 [liveleak] Improve regex for restoring original video URL 2015-06-15 02:51:21 +06:00
7d0c934a3e Merge pull request #5983 from jomo/master
LiveLeak: support more original videos
2015-06-15 01:49:41 +05:00
8f75761f24 LiveLak: add test for URLs with 'h264_270p' 2015-06-14 22:41:44 +02:00
9fd24e3a22 LiveLeak: support more original videos
some (old?) videos use ...mp4.h264_270p.mp4... instead of ...mp4.h264_base.mp4...
This is an addition to #4768
2015-06-14 21:50:03 +02:00
755a9d3d1a [tvplay] Add support for NovaTv 2015-06-14 20:59:22 +03:00
ac499cb61c Merge pull request #5976 from SpEcHiDe/patch-1
spelling mistake corrected
2015-06-14 18:26:53 +05:00
180940e02d spelling mistake corrected
acces changed to accessing
2015-06-14 11:19:42 +05:30
976b03c56b Quality note for niconico - at least notify whether you'll get low or src 2015-06-14 00:18:40 -04:00
450d89ddc1 [dramafever] Improve _VALID_URL 2015-06-14 09:58:26 +06:00
463b2e5542 [dramafever:series] Rollback _PAGE_SIZE to max possible 2015-06-14 09:51:07 +06:00
70a2002399 [dramafever:series] Fix _VALID_URL (Closes #5973) 2015-06-14 09:50:23 +06:00
a617b10075 Merge branch 'ping-dramafever' 2015-06-14 07:43:50 +06:00
0029071adb [dramefever] Improve and simplify 2015-06-14 07:43:14 +06:00
ad49fe7c8f Merge branch 'dramafever' of https://github.com/ping/youtube-dl into ping-dramafever 2015-06-14 04:56:54 +06:00
49bc802f81 Merge branch 'atomicdryad-brightcove_custombc_extractor' 2015-06-13 19:54:02 +06:00
af9cdee9cb [brightcove] Improve and generalize brightcove URL extraction from JS 2015-06-13 19:53:32 +06:00
b4e1576aee Brightcove extractor: support customBC.createVideo(...); method
found in http://www.americanbar.org/groups/family_law.html and
http://america.aljazeera.com/watch/shows/america-tonight/2015/6/exclusive-hunting-isil-with-the-pkk.html
2015-06-13 06:20:30 -05:00
78e2b74bb9 [tumblr] Add support for pornhub embeds (Closes #5963) 2015-06-13 03:39:14 +06:00
65d161c480 [extractor/generic] Add support for pornhub embeds 2015-06-13 03:36:16 +06:00
9fcbd5db2a [pornhub] Add support for embeds 2015-06-13 03:24:36 +06:00
4f3bf679f5 [vk] Fix authentication for non-ASCII login/password 2015-06-13 03:09:35 +06:00
0072afca8e [YoutubeDL] Remove force_generic_extractor arg from process_ie_result 2015-06-13 02:21:29 +06:00
61aa5ba36e [YoutubeDL] Remove global state for force_generic_extractor flag in favor of passing argument 2015-06-13 02:05:21 +06:00
9f4323252a [YoutubeDL] Fix for multiple URLs 2015-06-12 21:56:50 +06:00
8b6c896c4b [prosiebensat1] Add title regex 2015-06-12 21:18:13 +06:00
185dbc4974 [prosiebensat1] Fix rtmp extraction (Closes #5962) 2015-06-12 21:13:14 +06:00
3d535e0471 [tvc] Fix embed regex 2015-06-12 19:31:52 +06:00
d22dec74ff Add --force-generic-extractor
For some extractors that are hard to workout a good _VALID_URL we use very vague and unrestrictive ones,
e.g. just allowing anything after hostname and capturing part of URL as id.
If some of these extractors happen to have an video embed of some different hoster or platform
and this scenario was not handled in extractor itself we end up with inability to download this embed
until extractor is fixed to support embed of this kind.
Forcing downloader to use the generic extractor can be a neat temporary solution for this problem.
Example: FiveTV extractor with Tvigle embed - http://www.5-tv.ru/rabota/broadcasts/48/
2015-06-12 19:20:12 +06:00
9872d3110c [extractor/generic] Add support for tvigle embeds 2015-06-12 18:37:09 +06:00
b859971873 [extractor/generic] Rename tvc embed url variable 2015-06-12 18:15:30 +06:00
e5095f1198 Merge branch 'hlintala-5tv' 2015-06-12 17:49:07 +06:00
499a077761 [5tv] Improve 2015-06-12 17:48:42 +06:00
5da7177729 Merge branch '5tv' of https://github.com/hlintala/youtube-dl into hlintala-5tv 2015-06-12 16:34:28 +06:00
3507766bd0 Merge branch 'hlintala-tvc' 2015-06-12 16:29:10 +06:00
f37bdbe537 [extractor/generic] Add test for tvc embed 2015-06-12 16:28:45 +06:00
2da09ff8b0 [extractor/generic] Fix tvc ie_key 2015-06-12 16:26:31 +06:00
5ccddb7ecf [tvc] Fix ie_key 2015-06-12 16:25:26 +06:00
954c1d0529 [tvc] Refactor extractor names 2015-06-12 16:24:13 +06:00
494f20cbdc [extractor/generic] Add support for tvc embeds 2015-06-12 16:22:46 +06:00
29902c8ec0 [tvc:embed] Add embed extraction routine 2015-06-12 16:22:23 +06:00
9f15bdabc8 [tvc] Separate embed extractor 2015-06-12 16:13:36 +06:00
fff3455f58 Merge branch 'tvc' of https://github.com/hlintala/youtube-dl into hlintala-tvc 2015-06-12 15:12:54 +06:00
87446dc618 [tvc] Add extractor (Closes #5795) 2015-06-12 01:34:10 +03:00
99ac0390f5 [fivetv] Add extractor (Closes #5794) 2015-06-12 01:03:14 +03:00
ff0f0b9172 [tube8] Fix extraction (Closes #5952) 2015-06-11 22:18:08 +06:00
97b570a94c [generic] Improve rtl.nl embeds detection (Closes #5950) 2015-06-11 19:04:12 +06:00
a9d56c6843 [rtlnl] Improve _VALID_URL (#5950) 2015-06-11 19:03:22 +06:00
f98470df69 [bilibili] Fix FutureWarning 2015-06-10 23:01:12 +06:00
eb8be1fe76 [rtbf] Extract all formats (closes #5947) 2015-06-10 14:12:43 +02:00
8a1a26ce4c [youtube] Add a test for the DASH segment downloader 2015-06-10 14:47:02 +08:00
5bf3276e8d [downloader/dash] Add testing facility 2015-06-10 14:45:54 +08:00
7ebd5376fe [nfl] Relax _VALID_URL (fixes #5940) 2015-06-10 14:17:03 +08:00
93dfcb9357 [downloader/dash] Do not pollute ``self`` 2015-06-10 13:44:54 +08:00
0c8662d2b6 [youtube] Fix a TypeError caused by 4da31bd566 2015-06-10 13:40:41 +08:00
d84f1d14b5 Adds support for XviD output with extra parametrization
As the "LG Time Machine" (a (not so) smart TV) has a limitation for video dimensions (as for codecs), I take to implement an extra parameter `--pp-params` where we can send extra parameterization for the video converter (post-processor).

Example:
```
$ youtube-dl --recode-video=xvid --pp-params='-s 720x480' -c https://www.youtube.com/watch?v=BE7Qoe2ZiXE
```
That works fine on a 4yo LG Time Machine.

Closes #5733
2015-06-09 22:08:16 -03:00
70219b0f43 [youtube:playlist] Use an iterator for the entries (closes #5935)
So that '--playlist-end' downloads only the required pages.
2015-06-09 23:49:11 +02:00
bd5bc0cd5a [theplatform] Check for /select/media URLs first (#5746) 2015-06-09 23:12:13 +06:00
6e054aacca [theplatform] Take care of /select/media URLs (Closes #5746) 2015-06-09 23:07:22 +06:00
9d581f3d52 [cbs] Extract display_id 2015-06-09 21:39:45 +06:00
9bf99891d0 [cbs] Add support for colbertlateshow (Closes #5888) 2015-06-09 21:23:53 +06:00
d9cf48e81e [spiegeltv] Extract all formats and prefer hls (Closes #5843) 2015-06-09 20:36:08 +06:00
e1b9322b09 [youtube] Restricter DASH signature pattern
A problematic DASH url is:
https://manifest.googlevideo.com/api/manifest/dash/mm/35/key/yt5/ip/140.112.247.145/ms/pm/mv/s/mt/1433794435/id/o-AD2Od_dsOlAUYPu03ZsVWKSbGEbCJJrMp9vnXGhnyRhd/mn/sn-aigllm7r/sparams/as%2Chfr%2Cid%2Cip%2Cipbits%2Citag%2Cmm%2Cmn%2Cms%2Cmv%2Cnh%2Cpl%2Cplayback_host%2Crequiressl%2Csource%2Cexpire/fexp/9406009%2C9406821%2C9407575%2C9408142%2C9408420%2C9408710%2C9409121%2C9409208%2C9412514%2C9412780%2C9413208%2C9413426%2C9413476%2C9413503%2C9415304%2C9415753/upn/viDQrs8SnmE/as/fmp4_audio_clear%2Cwebm_audio_clear%2Cfmp4_sd_hd_clear%2Cwebm_sd_hd_clear%2Cwebm2_sd_hd_clear/playback_host/r4---sn-aigllm7r.googlevideo.com/ipbits/0/requiressl/yes/pl/20/itag/0/source/youtube/expire/1433824806/nh/EAQ/signature/81ABE6391E351BA495F5B041B00FF1257A353318.1A6E48ABB74E8F4AE73CA2CB1F963FC34E33DEE7/sver/3/hfr/1
2015-06-09 14:48:18 +08:00
627b964825 [kickstarted] Extract thumbnails in embedded videos (#5929) 2015-06-09 11:54:13 +08:00
a55e36f48d [YoutubeDL] Handle out-of-range timestamps (#5826) 2015-06-08 21:05:17 +06:00
01e21b89ee [noco] Skip invalid timestamps (closes #5826) 2015-06-08 17:39:55 +08:00
788be3313d [cnet] Fix theplatform vid extraction (fixes #5924) 2015-06-08 13:34:23 +08:00
e1ec93304d [instagram:user] Truncate title to 80 characters (#5919)
This is a workaround. Currently YoutubeDL.process_info() truncates
info_dict['title'] to 200 characters, but the implementation can't
handle wide characters.
2015-06-08 01:46:33 +08:00
edb99d4c18 [instagram] Handling null values (fixes #5919)
I didn't add the test case here because it takes too much time. (7
minutes on my machine)
2015-06-08 01:17:21 +08:00
68477c3dab [tlc] Fix test failure due to DiscoveryIE changes 2015-06-07 16:38:39 +08:00
65ba8b23f4 [discovery] Rewrite DiscoveryIE (fixes #5898)
Discovery.com now uses a completely different approach for serving
videos. At least in both test cases brightcove are involved. However,
AMF support is necessary for these brightcove videos. As a result, I
try to extract videos from the info page ('?flat=1'). The downloaded
file can be different from the one in browsers.
2015-06-07 16:34:19 +08:00
621ed9f5f4 [common] Add note and errnote field for _extract_m3u8_formats 2015-06-07 16:33:22 +08:00
b26733ba7f [brightcove] Allow single quotes in Brightcove URLs (fixes #5901) 2015-06-07 15:29:42 +08:00
9836cfb8d6 [options] Clarify --list-extractors (Closes #5916) 2015-06-07 08:12:21 +06:00
665b6c1236 Merge branch 'hlintala-ruutu' 2015-06-07 05:38:29 +06:00
9414338a48 [ruutu] Improve, make more robust and fix python 2.6 support 2015-06-07 05:37:29 +06:00
de390ea077 update: Use https for getting the version info (fixes #5909) 2015-06-07 00:21:30 +02:00
717b0239fd Merge branch 'ruutu' of https://github.com/hlintala/youtube-dl into hlintala-ruutu 2015-06-07 04:01:28 +06:00
d00735a0c5 [ruutu] Don't use fallback for DASH and other non-HTTP urls 2015-06-06 23:01:23 +03:00
c23d5ce926 Merge branch 'PeterDing-iqiyi' 2015-06-07 02:59:27 +08:00
b5a3c7f109 [iqiyi] Cache encryption keys 2015-06-07 02:47:36 +08:00
9c5f685ef1 [iqiyi] Improve regex pattern again 2015-06-07 02:39:03 +08:00
08bb8ef201 [iqiyi] Unify get_format() and get_bid() 2015-06-07 02:25:00 +08:00
865ab62f43 [iqiyi] Make _VALID_URL more accurate
v_* urls are individual videos, while a_* urls are playlists, which are
not supported yet.
2015-06-07 02:13:22 +08:00
9948113590 [iqiyi] Add a multipart test case 2015-06-07 02:09:33 +08:00
c4ee87022b [iqiyi] Change id for multipart videos 2015-06-07 01:57:05 +08:00
ffba4edb06 [iqiyi] Improve some variable names and add download notes 2015-06-07 01:52:51 +08:00
958d0b659b [iqiyi] Reorder imports 2015-06-07 01:35:09 +08:00
aacda28b28 [iqiyi] Give error message for assertion failures 2015-06-07 01:32:03 +08:00
29e7e0781b [iqiyi] Simplify and improve regex patterns
See the comments in #5849
2015-06-07 00:56:08 +08:00
7012620e2b [iqiyi] Remove format selection codes 2015-06-07 00:44:54 +08:00
f1da861018 [iqiyi] PEP8 2015-06-07 00:37:29 +08:00
4da31bd566 [youtube] Fix a FutureWarning from xml.etree.ElementTree 2015-06-06 22:22:26 +08:00
05aa9c82d9 [sunporno] Fix view_count extraction 2015-06-06 13:58:52 +03:00
a9e58ecd3f [turbo] Improve description extraction
`og:description` is empty for some videos.
2015-06-06 13:58:51 +03:00
223544552f [Ruutu] Add new extractor 2015-06-06 04:29:03 +03:00
3d8e9573a4 [youtube:channel] Improve channel id extraction (#5904) 2015-06-06 06:25:37 +06:00
54eb81a087 [pornovoisines] Improve average_rating extraction and update test case 2015-06-06 03:11:43 +03:00
c33c547d66 [izlesene] Avoid timestamp differences in tests due to DST 2015-06-06 02:57:21 +03:00
dfe7dd9bdb [izlesene] Unquote video URLs and simplify 2015-06-06 02:57:21 +03:00
63ccf6474d Merge branch 'ping-qqmusic-more-formats' 2015-06-05 23:19:54 +08:00
e8ac61e840 [qqmusic] Use meaningful variable names 2015-06-05 23:19:25 +08:00
f00a650705 [qqmusic] Rearrange codes 2015-06-05 23:16:34 +08:00
4bde5ce992 Merge branch 'qqmusic-more-formats' of https://github.com/ping/youtube-dl into ping-qqmusic-more-formats 2015-06-05 23:14:44 +08:00
d31573fa37 [teamcoco] Handle incomplete m3u8 URLs (fixes #5798)
There are 2 TODOs. I don't know how to handle these cases correctly.
2015-06-05 22:59:04 +08:00
8b8cde2140 [qqmusic] Set abr for mp3 formats 2015-06-05 06:04:26 +08:00
0e805e782b release 2015.06.04.1 2015-06-04 21:54:33 +02:00
f5c78d118b release 2015.06.04 2015-06-04 21:49:02 +02:00
9d4f213f90 [qqmusic:toplist] List name and description are optional 2015-06-05 00:52:18 +08:00
168db222c6 Merge pull request #5891 from ping/qqmusic-toplist-fix
[qqmusic] Fix toplist extraction
2015-06-05 00:50:59 +08:00
3d6388e34e [tnaflix] Fix relative URLs (empflix) 2015-06-04 20:42:37 +06:00
3ce9bc712a [empflix] Fix typo 2015-06-04 20:39:03 +06:00
e52c0bd0eb [tnaflix] Modernize 2015-06-04 20:37:05 +06:00
56c837ccb7 [tnaflix] Fix typo 2015-06-04 20:34:48 +06:00
423d2be5f8 [downloader/dash] Rename the protocol
'http_dash_segments' looks more like a protocol name than
'dash_segments'
2015-06-04 22:27:29 +08:00
453a1617aa [downloader/dash] Reorder imports 2015-06-04 22:12:05 +08:00
b9258c6178 [YoutubeDL] Change how DashSegmentsFD is selected 2015-06-04 22:05:33 +08:00
55e5841f14 [qqmusic] Extract additional formats (mp3-128, mp3-320) 2015-06-04 17:41:29 +08:00
ed15e9ba02 [qqmusic] Remove unused import 2015-06-04 17:32:06 +08:00
eedda32e6b [qqmusic] Fix toplist 2015-06-04 11:27:18 +08:00
4c8fea92f3 [test/aes] Fix on python 3.3 and higher
Since 878563c847 the aes functions only accepts the base64 data as a unicode string.
2015-06-03 23:50:38 +02:00
d073055dcd Merge pull request #5876 from slava-sh/nova
[nova] Update
2015-06-03 23:18:01 +05:00
e4ac7bb1e5 [nova] Revert "Fix extension extraction bug"
This reverts commit 9464a194db.
2015-06-03 19:25:30 +03:00
9bac8c57e3 Merge branch 'iqiyi' of https://github.com/PeterDing/youtube-dl into PeterDing-iqiyi 2015-06-03 23:59:52 +08:00
6800d3372f [YoutubeDL] Support DASH manifest downloading 2015-06-03 23:10:18 +08:00
3153a2c98d [tvigle] Skip tests 2015-06-03 20:53:54 +06:00
15b74b94be [tvigle] Capture error message 2015-06-03 20:52:47 +06:00
687cb3ad35 [24video] Fix uploader extraction 2015-06-03 20:47:11 +06:00
8f94784124 [tumblr] Detect vid.me embeds (fixes #5883) 2015-06-03 10:26:39 +08:00
23dd1fc74c [vidme] Always use the non-embedded page
For example, https://vid.me/Wmur contains more information than
https://vid.me/e/Wmur
2015-06-03 10:24:02 +08:00
fa971259e6 [nova] Add a comment about html in description 2015-06-02 19:09:47 +03:00
b0cda32f72 [nova] Fix Python 2.6 compatability issue 2015-06-02 18:30:25 +03:00
08b7968e28 [nova] Fix display_id extraction bug 2015-06-02 18:24:19 +03:00
4b5fe1349f [nova] Comply with review 2015-06-02 18:23:42 +03:00
d23da75b32 [iprima] Fix description extraction
`og:description` does not contain actual description anymore.
2015-06-02 21:10:18 +06:00
06e027992d Merge pull request #5877 from slava-sh/iprima
[iprima] Update
2015-06-02 20:04:04 +05:00
b5597738d4 [iprima] Comply with review 2015-06-02 17:42:53 +03:00
bc03e58565 [iprima] Update 2015-06-02 13:19:02 +03:00
a00234f1c5 [nova] Minor style improvement 2015-06-02 12:57:03 +03:00
34c0f95db2 [nova] Remove html tags from description 2015-06-02 12:56:36 +03:00
fcb04bcaca [nova] Extract upload_date in some cases 2015-06-02 12:55:41 +03:00
9464a194db [nova] Fix extension extraction bug
Replace the hardcoded flv with determine_ext. Let rtmpdump parse the url.
2015-06-02 12:54:20 +03:00
9f4b9118cc [nova] Fix display_id extraction bug
Make id group non-greedy so that .html is not included in it.
2015-06-02 12:49:01 +03:00
60158217ef [nova] Add tv test 2015-06-02 00:57:08 +06:00
923e79e2e4 [nova] Add extractor 2015-06-02 00:53:04 +06:00
866b296d0f [aftonbladet] Fix extraction and update _VALID_URL (Fixes #5863) 2015-06-01 16:12:11 +03:00
4053ee9104 Credit @PeterDing for 91porn extractor (#5830) 2015-06-01 14:44:10 +08:00
47fd8c2f76 [patreon] Fix embeds extraction (Closes #5862) 2015-06-01 00:04:36 +06:00
96b9690985 [imgur] Improve extraction 2015-05-31 04:05:26 +06:00
df15ef8dab [YoutubeDL] Tweak select_format for video only media 2015-05-31 04:05:09 +06:00
002c0fb511 Merge pull request #5852 from ivan/make-playlist-url
[youtube] Construct a playlist URL in case the page is missing one
2015-05-31 02:19:00 +05:00
7584e38ce4 [tvigle] Modernize 2015-05-31 03:01:41 +06:00
eb47569f8a [tvigle] Add support for m3u8 2015-05-31 03:00:13 +06:00
d2a9de78df [youtube] Construct a playlist URL in case the page is missing one
This fixes jumping from user/channel -> playlist for some users like
https://www.youtube.com/user/BitcoinFoundation

This also removes the superfluous log message
"add --no-playlist to just download video VIDEOID"
when downloading a user/channel.
2015-05-30 20:54:03 +00:00
c5138a7ce4 [extractor/generic] Clarify test comment 2015-05-31 02:36:20 +06:00
c5fa81fe81 [extractor/generic] Put all direct link tests near to each other for better navigation 2015-05-31 02:22:29 +06:00
a074e92296 [extractor/generic] Add test for large compressed media 2015-05-31 02:13:24 +06:00
1ddb9456c4 [extractor/generic] Use compat_urllib_parse_unquote for unquoting video_id and title from URL 2015-05-31 01:23:58 +06:00
58bde34a23 [extractor/generic] Force Accept-Encoding to any for extraction pass 2015-05-31 00:44:54 +06:00
339516072b [extractor/generic] Unescape video_id and title extracted from URL 2015-05-30 23:16:14 +06:00
931bc3c3a7 [YoutubeDL] Do not loose request method information 2015-05-30 22:52:02 +06:00
db1e9ee771 Merge branch 'PeterDing-porn91' 2015-05-31 00:33:30 +08:00
a2d971309b [porn91] Use single quotes 2015-05-31 00:31:18 +08:00
d05a1dbe70 [porn91] Catch daily limit error 2015-05-31 00:26:12 +08:00
a80601f8d9 [porn91] Extract more info 2015-05-31 00:20:37 +08:00
1c22238756 [porn91] Simplify 2015-05-31 00:03:19 +08:00
9ff811c5cd [porn91] PEP8 2015-05-30 23:35:55 +08:00
1ebc05df91 Merge branch 'porn91' of https://github.com/PeterDing/youtube-dl into PeterDing-porn91 2015-05-30 23:33:10 +08:00
386bdfa698 [youtube:user] Workaround 35 pages limitation (Closes #5778) 2015-05-30 18:29:16 +06:00
1ae7ff771b [tubitv] Add error message for videos that require login (#5524) 2015-05-30 14:33:27 +03:00
5196b98897 [tubitv] Add new extractor (Closes #5524) 2015-05-30 14:16:18 +03:00
e6e63e91a7 [tf1] Extend _VALID_URL (Closes #5848) 2015-05-30 16:18:11 +06:00
b4dd98358f [vgtv] Properly handle lives 2015-05-30 16:12:07 +06:00
181c7053e3 [YoutubeDL] Make sure all formats have unique format_id 2015-05-30 16:04:44 +06:00
4d454c5e4b [vgtv] Check for inactive videos 2015-05-30 15:15:42 +06:00
5c2191a605 [vgtv] Skip wasLive hds (Closes #5835) 2015-05-30 15:14:10 +06:00
bba5bfc890 Merge branch 'ping-soompi' 2015-05-30 14:37:18 +06:00
1a5b77dc21 [crunchyroll] Fix python 3.2 2015-05-30 14:36:45 +06:00
b2cf6543b2 [soompi] Improve and simplify 2015-05-30 14:30:04 +06:00
0385d64223 [crunchyroll] Extract subtitles extraction routine 2015-05-30 14:12:58 +06:00
6ebdfe43e4 [tube8] fix extractor (fixes #5846) 2015-05-30 09:30:14 +02:00
fafec39d41 [spiegeltv] Changed RTMP server (fixes #5788 and fixes #5843)
Thanks to @brickleroux for finding out the problem
2015-05-30 13:23:09 +08:00
670861bd20 [iqiyi] Do not request for unneeded formats 2015-05-30 10:37:54 +08:00
08f7db20c1 [youku] change format_id 2015-05-30 10:03:32 +08:00
605ec701b7 [iqiyi] Add new extractor for iqiyi.com 2015-05-29 23:32:04 +08:00
d6aa68ce75 [postprocessor/embedthumbnail] embed mp4 too (fixes #5840) 2015-05-29 12:47:20 +02:00
eb6cb9fbe9 release 2015.05.29 2015-05-29 07:52:17 +02:00
84e1e036c2 [senate] Extend _VALID_URL (fixes #5836) 2015-05-29 12:44:31 +08:00
1498940b10 [youku] compare bytes and str for compatible; use compat_urllib_parse for making video_url 2015-05-29 10:13:09 +08:00
806598b94d [porn91] the one that _search_regex returns not needs to be checked 2015-05-29 08:21:24 +08:00
e26be70bca Merge branch 'soompi' of https://github.com/ping/youtube-dl into ping-soompi 2015-05-28 22:22:29 +06:00
ca45246627 [youku] compatible for python > 3.3 or > 2.7 2015-05-28 21:04:58 +08:00
f9355dc989 [youku] update youku 2015-05-28 17:00:09 +08:00
9e0b579128 [nowtv] Add test for rtlnitro 2015-05-28 01:26:14 +06:00
ff4a1279f2 [nowtv] Do not request unnecessary metadata 2015-05-28 01:15:04 +06:00
9b254aa177 [nowtv] Add non-free video check 2015-05-27 23:41:43 +06:00
703d78bbf5 [porn91] change re to _search_regex 2015-05-28 01:37:24 +08:00
d9446c7319 Merge branch 'akirk-nowtv' 2015-05-27 23:22:19 +06:00
b25b645d51 [nowtv] Improve and simplify 2015-05-27 23:20:32 +06:00
d90b3854ca [porn91] Add new extractor for 91porn.com 2015-05-28 00:37:00 +08:00
bf24c3d017 [facebook] Improve title regex (Closes #5816) 2015-05-27 21:25:07 +06:00
f0bfaa2d7d [nrk] Update subtitles test
Subtitle conversion routine is removed, so the subtitles are TTML now. See
1c7e2e64f6
2015-05-27 15:23:34 +08:00
f9f3e3df9a [teamcoco] Use determine_ext to determine the video type
Some videos does not contain a 'type' field (#5798)
2015-05-27 14:51:18 +08:00
f8d5e1cfb5 [naver] Fix video url (fixes #5809)
RTMP urls in test:naver does not work. Need more investigation.
2015-05-27 14:44:08 +08:00
c23848b3c5 [naver] Enhanced error detection 2015-05-27 14:20:29 +08:00
6d00a2dcd1 [bilibili] Catch API call failures
JSON are returned in a failed API call
2015-05-27 04:23:21 +08:00
b535170b21 [bilibili] Skip assertion if HQ videos not available 2015-05-27 04:14:24 +08:00
1434184c57 [spankwire] Do not modify aes key string 2015-05-27 01:42:53 +06:00
7a372b64df [pornhub] Do not modify aes key string (Closes #5824) 2015-05-27 01:41:00 +06:00
5406af92bc [dailymotion:user] Fix _VALID_URL 2015-05-26 22:16:47 +06:00
7d65242dc3 [dailymotion:user] Process user home as user (Closes #5823) 2015-05-26 22:12:26 +06:00
544a8693b7 Remove Firedrive and Sockshare imports
Oops
2015-05-26 13:53:14 +03:00
35a4f24a37 [firedrive] Remove extractor (Closes #3870)
Haywire since last October.
2015-05-26 13:44:46 +03:00
ff305edd64 [sockshare] Remove extractor
Haywire since last October.
2015-05-26 13:43:00 +03:00
efec4358b9 [cinemassacre] Support an alternative form of screenwavemedia URL
fixes #5821
2015-05-26 13:54:41 +08:00
db3ca36403 [facebook] Move the title extraction warning below (fixes #5820) 2015-05-26 13:41:38 +08:00
42833b44b5 [tf1] Extend _VALID_URL (fixes #5819) 2015-05-26 13:32:43 +08:00
5d0a33eebc rtlnow is now hosted at nowtv.de 2015-05-25 20:36:25 +02:00
ba2df04b41 [odnoklassniki] Make URL explicit 2015-05-25 21:27:43 +06:00
c6bbdadd79 [odnoklassniki] Support extraction from metadata URL (Closes #5813) 2015-05-25 21:22:13 +06:00
b885bae634 Credit @misterhat for karrierevideos (#5729) 2015-05-25 04:53:53 +06:00
680f9744c4 [pinkbike] used proper conversion methods 2015-05-24 16:45:10 -05:00
2c935c0c72 [pinkbike] converted duration to int 2015-05-24 16:30:03 -05:00
7198063d96 [pinkbike] new extractor 2015-05-24 15:26:59 -05:00
d41ebe146b [tenplay] Fix formats and modernize (Closes #5806) 2015-05-24 23:58:09 +06:00
4b4e1af059 [arte] Remove unused import 2015-05-24 18:46:29 +02:00
80240b347e Merge pull request #5780 from jaimeMF/remove-nondash
[youtube] Remove the nondash formats (fixes #5774)
2015-05-24 21:42:15 +05:00
04b3b3df05 [youtube] Remove the nondash formats (fixes #5774)
Since we use fixed values for some fields like width and height they can be wrong, and would get picked by some formats filters.
For example for https://www.youtube.com/watch?v=EQCrhbBxsjA the biggest height is 720 and for nondash formats it's set to 1440, so -f 'bestvideo[height>=1200]+bestaudio' would incorrectly pick the nondash format, instead it should report that the requested format is not available.
2015-05-24 18:26:20 +02:00
2ad5708c43 [arte:future] Switch to search_regex for now (Closes #5801) 2015-05-24 21:25:00 +06:00
63f3cab4ae [rtbf] Fix extraction (Closes #5803) 2015-05-24 21:09:08 +06:00
8cdf03a7a2 Merge branch 'misterhat-karrierevideos' 2015-05-24 20:14:54 +06:00
d78c834ead [karrierevideos] Improve and simplify 2015-05-24 20:04:13 +06:00
05a976cd99 Merge branch 'karrierevideos' of https://github.com/misterhat/youtube-dl into misterhat-karrierevideos 2015-05-24 19:19:48 +06:00
34fb7e46ad [empflix] Relax _VALID_URL 2015-05-24 19:11:40 +06:00
abac15f3c6 [tnaflix] Do not capture cat_id 2015-05-24 19:11:31 +06:00
b700055ba4 Merge pull request #5772 from frenchy1983/fix_tnaflix_regex
[TNAFlix] Allow dot (and more) in cat_id and display_id
2015-05-24 17:54:25 +05:00
23905927e1 [README.md] Keep more idiomatic rwx order 2015-05-24 18:32:04 +06:00
56be5f1567 Merge pull request #5800 from WassimAttar/patch-1
[README.md] chmod error
2015-05-24 17:29:26 +05:00
1807ae22dd chmod error
After installing youtube-dl with this method
    sudo wget https://yt-dl.org/downloads/latest/youtube-dl -O /usr/local/bin/youtube-dl
    sudo chmod a+xr /usr/local/bin/youtube-dl
When i try to use it, i get this error
    python: can't open file '/usr/local/bin/youtube-dl': [Errno 13] Permission denied

The correct chmod is a+xr
2015-05-24 10:37:05 +02:00
71646e4653 [YoutubeDL] Initialize files_to_delete (Closes #5797) 2015-05-24 04:14:01 +06:00
1335c3aca8 [drtv] Improve extraction (Closes #5792) 2015-05-24 01:22:11 +06:00
30455ce255 [nextmedia] Extend and reorder _VALID_URL 2015-05-24 02:42:01 +08:00
9bf87ae3aa [nextmedia] Merge AppleDailyRealtimeNewsIE and AppleDailyAnimationNewsIE 2015-05-24 02:36:47 +08:00
abca34cbc0 [cnn] Relax _VALID_URL again (fixes #5737)
The problem is the same as test:CNN_1, so I didn't add the test case
2015-05-24 02:04:02 +08:00
d386878af9 [prosiebensat1] Add support for .at domain names (Closes #5786) 2015-05-23 21:25:53 +06:00
685c74d315 [rutv] Extend embed URL (Closes #5782) 2015-05-23 01:01:47 +06:00
69e0f1b445 Credit @ping for viki:channel, qqmusic:toplist 2015-05-23 00:08:10 +06:00
79979c6897 Clarify that --dump-pages encodes the pages using base64 (#5781) 2015-05-22 16:15:50 +02:00
ba64547616 [sportbox] Remove unused import 2015-05-22 11:35:09 +02:00
ed5a637d62 [TNAFlix] Restore test
See dstftw's comment in #5772
2015-05-22 09:29:35 +02:00
8a278a1d7e [nba] Fix duration extraction (fixes #5777) 2015-05-22 13:30:39 +08:00
77d9cb2f04 [sportbox] Fix extraction 2015-05-22 00:45:33 +06:00
0459432d96 [shared] Fix for python 3.2 2015-05-22 00:10:53 +06:00
43150d7ac3 [shared] Fix for python 3.2 2015-05-22 00:10:05 +06:00
afe8b594be [rtve.es:alacarta] Fix for python 3.2 2015-05-22 00:09:15 +06:00
878563c847 [aes] Fix for python 3.2 2015-05-22 00:06:10 +06:00
06947add03 [chilloutzone] Fix for python 3.2 2015-05-22 00:03:47 +06:00
5cd47a5e4f [videott] Fix for python 3.2 2015-05-21 23:58:46 +06:00
53de95da5e [viki] Extend _VALID_URLs 2015-05-21 22:27:22 +06:00
663004ac2b [options] Clarify --metadata-from-title additional templates 2015-05-21 22:06:25 +06:00
6ad9cb224a [mitele] It now uses m3u8 (#5764)
It should also be possible to use Adobe HDS, but it would require more work.
2015-05-21 12:02:53 +02:00
e7752cd578 [TNAFlix] Allow dot (and more) in cat_id and display_id
URLs with dots were raising a "UnsupportedError: Unsupported URL" error.
2015-05-21 11:47:16 +02:00
4d2f42361e [viki] remove unused import 2015-05-21 11:42:20 +02:00
4d8ee01389 [viki] Fix typo 2015-05-21 02:38:43 +06:00
d01924f488 [viki:channel] Extend matching URLs and extract movies 2015-05-21 02:30:04 +06:00
bc56355ec6 [viki:channel] Switch to API 2015-05-21 02:08:13 +06:00
ac20d95f97 [viki] Add support for youtube externals 2015-05-21 01:56:02 +06:00
1a83c731bd [viki] Switch extraction to API 2015-05-21 01:44:05 +06:00
ca57a59883 Merge branch 'ping-viki-shows' 2015-05-20 22:10:06 +06:00
b0d619fde2 [viki:channel] Extract title from JSON 2015-05-20 21:28:04 +06:00
cc7051efd7 Merge branch 'viki-shows' of https://github.com/ping/youtube-dl into ping-viki-shows 2015-05-20 20:17:47 +06:00
5137adb94d [soompi] Switch to non-geoblocked test video 2015-05-20 16:16:10 +08:00
0b9f7cd074 release 2015.05.20 2015-05-20 10:01:48 +02:00
2632941f32 [soompi] Add new extractor for tv.soompi.com 2015-05-20 15:53:45 +08:00
137597b0ea [dramafever] Streamline code 2015-05-20 15:15:28 +08:00
051df9ad99 [letv/sohu] Skip tests relying on external proxies
The proxy is currently broken. See #5655 and zhuzhuor/Unblock-Youku#427
2015-05-20 14:08:23 +08:00
f670ef1c8e [dramafever] Add new extractor for dramafever.com 2015-05-20 13:51:43 +08:00
d9d747a06a [ultimedia] Fix extraction 2015-05-19 21:28:41 +06:00
b813d8caf1 [qqmusic] Unescape '\\n' in description (#5705) 2015-05-19 01:01:42 +08:00
ecee572411 [yahoo] Add support for closed captions (closes #5714) 2015-05-19 00:50:24 +08:00
1b0427e6c4 [utils] Support TTML without default namespace
In a strict sense such TTML is invalid, but Yahoo uses it.
2015-05-19 00:45:01 +08:00
2aa64b89b3 tox: Pass HOME environment variable
Since version 2.0 it only passes a limited set of variables and we need HOME for the tests
2015-05-18 17:58:53 +02:00
484c9d2d5b [vier] Fix extraction 2015-05-18 21:43:54 +06:00
5d8dcb5342 [vuclip] Fix extraction 2015-05-18 21:39:15 +06:00
2328f2fe68 [vulture] Fix extraction 2015-05-18 21:34:20 +06:00
4f514c7e88 [wimp] Fix youtube extraction (Closes #5690) 2015-05-18 21:29:41 +06:00
5bdc520cf1 [xminus] Fix extraction 2015-05-18 21:23:05 +06:00
fc6e75dd57 [instagram] Only recognize https urls (fixes #5739)
http urls redirect to them.
2015-05-18 11:21:09 +02:00
4a5a898a8f [YoutubeDL] Clarify incompatible formats merge message
When `-f` is not specified it's misleading to see `You have requested ...` as user did not actually request any formats.
2015-05-17 20:56:03 +06:00
ba9d16291b manually specify namespace 2015-05-17 03:35:08 -05:00
725652e924 [karrierevideos] add support for www.karrierevideos.at (closes #5354) 2015-05-16 19:50:58 -05:00
8da0e0e946 [viki] Change IE name to channel, better message output 2015-05-17 06:19:38 +08:00
588b82bbf8 [tv2:article] Add extractor (Closes #5724) 2015-05-17 03:32:53 +06:00
bc0f937b55 [tv2] Add extractor (#5724) 2015-05-17 03:01:52 +06:00
baa43cbaf0 [extractor/common] Relax valid url check verbosity 2015-05-17 02:59:35 +06:00
adb6b1b316 Merge branch 'viki-shows' of https://github.com/ping/youtube-dl into ping-viki-shows 2015-05-17 00:38:58 +06:00
1c18de0019 [viki] Add proper paging and include clips 2015-05-17 01:38:50 +08:00
4d52f2eb7f [sbs] Remove unused import 2015-05-16 18:38:28 +02:00
363cf58645 Merge branch 'viki-shows' of https://github.com/ping/youtube-dl into ping-viki-shows 2015-05-16 21:28:36 +06:00
7e760fc188 [espn] Add extractor (#4396)
Unfinished
2015-05-16 21:14:19 +06:00
ef2dcbe4ad [sbs] Fix extraction (Closes #5725) 2015-05-16 21:07:29 +06:00
9354a5fad4 [ooyala] Fix unresolved reference 2015-05-16 20:15:31 +06:00
1c97b0a777 [ooyala:external] Add extractor 2015-05-16 20:00:40 +06:00
2f3bdab2b9 [viki] Fix code format 2015-05-16 15:56:37 +08:00
0d7f036429 [viki] Add support for shows 2015-05-16 15:43:13 +08:00
2cda13213d Merge pull request #5717 from blissland/master
[CBSNewsIE] Relax thumbnail regex so test passes
2015-05-15 22:36:07 +05:00
70d0d43b5e [rts] Check formats (Closes #5711) 2015-05-15 23:32:25 +06:00
25c3a7348f [generic] Fix typo 2015-05-15 23:23:51 +06:00
9123d64592 Merge branch 'maddoger-sportbox-fix' 2015-05-15 23:19:21 +06:00
b827a6015c [generic] Add test for sportbox embeds 2015-05-15 23:18:21 +06:00
d40a3b5b55 [generic] Add support for sportbox embeds 2015-05-15 23:09:34 +06:00
ef28a6cb26 [sportbox:embed] Relax thumbnail 2015-05-15 23:09:10 +06:00
1436a6835e [sportbox:embed] Add _extract_urls 2015-05-15 23:08:44 +06:00
e8cfacae37 [CBSNewsIE] Relax thumbnail regex so test passes 2015-05-15 17:57:32 +01:00
3a7382950b [sportbox:embed] Add extractor 2015-05-15 22:50:44 +06:00
eeb23eb7ea [gamespot] The protocol is not optional 2015-05-15 18:44:08 +02:00
34fe5a94ba [gamespot] Add support for videos that don't use 'f4m_stream' (fixes #5707) 2015-05-15 18:42:59 +02:00
6181864290 Merge branch 'sportbox-fix' of https://github.com/maddoger/youtube-dl into maddoger-sportbox-fix 2015-05-15 22:09:18 +06:00
e9ca615a98 New test 2015-05-15 19:57:54 +04:00
62c95fd5fc [youtube:feed] Check each 'load more' portion for unique video ids 2015-05-15 21:42:34 +06:00
25f14e9f93 [youtube] Separate feed extractor 2015-05-15 21:06:59 +06:00
ae670a6ed8 Sportbox source fix. HD videos support. 2015-05-15 17:53:05 +04:00
a7b8467ac0 Sportbox extractor fix. 2015-05-15 16:52:11 +04:00
15da7ce7fb Fix file format extraction regex and update test file checksum 2015-05-15 14:12:52 +02:00
e9eaf3fbcf [test/YoutubeDL] Add tests for 'playliststart', 'playlistend' and 'playlist_items' 2015-05-15 14:08:26 +02:00
3884dcf313 YoutubeDL: ignore indexes from 'playlist_items' that are not in the list (fixes #5706)
We ignore them instead of failing to match the behaviour of the 'playliststart' parameter.
2015-05-15 14:08:26 +02:00
c4fc559f45 release 2015.05.15 2015-05-15 10:13:43 +02:00
2bc4330303 [youtube:history] Fix extraction (fixes #5702)
It uses the same method as YoutubeSubscriptionsIE, if other feed starts using it we should consider using base class.
2015-05-14 23:41:27 +02:00
12675275a1 [teamcoco] Detect expired videos (#5626) 2015-05-15 02:28:41 +08:00
3a105f7b20 [teamcoco] Rewrite preload data extraction
Idea: "puncture" some consecutive fragments and check whether the
b64decode result of a punctured string is a valid JSON or not.

It's a O(N^3) algorithm, but should be fast for a small N (less than 30
fragments in all test cases)
2015-05-15 02:28:40 +08:00
1ae72fb23d [soundcloud:user] Defer download link resolve (Closes #5248)
Looks like final download links can expire before downloading process reach them. So, resolving download links right before actual downloading.
2015-05-14 22:28:42 +06:00
7ec676bb3d [qqmusic] Add IE_NAME for all extractors 2015-05-14 23:32:36 +08:00
29ea57283e [qqmusic] Refactoring QQMusicToplistIE 2015-05-14 23:28:42 +08:00
5488973961 [qqmusic] flake8 2015-05-14 23:25:43 +08:00
96d45a5489 Merge pull request #5680 from ping/qqmusic-toplist-ie
[qqmusic] Add support for charts / top lists
2015-05-14 23:23:32 +08:00
7a012d5a16 [screenwavemedia] Add support for player2 URLs (Closes #5696) 2015-05-14 16:39:35 +06:00
fa6a16996e [worldstarhiphop] Support Android URLs (fixes #5629) 2015-05-14 18:00:57 +08:00
82245a6de7 [YoutubeDL] Restore filename for thumbnails 2015-05-14 15:21:27 +06:00
ff28ede2d1 Merge branch 'dstftw-best-fallback-on-outdated-avconv' 2015-05-14 15:19:14 +06:00
98b8ec8616 Merge branch 'best-fallback-on-outdated-avconv' of https://github.com/dstftw/youtube-dl into dstftw-best-fallback-on-outdated-avconv
Conflicts:
	youtube_dl/YoutubeDL.py
2015-05-14 15:18:58 +06:00
88f9d8748c Merge remote-tracking branch 'upstream/master' 2015-05-14 17:07:02 +08:00
7d57d2e18b [canalplus] Restore checksums in tests 2015-05-14 14:59:27 +06:00
38caa00d18 Merge pull request #5695 from blissland/master
[CanalplusIE] Update tests that were no longer working
2015-05-14 13:57:56 +05:00
c827d4cfdb [xattr] Enhanced error messages on Windows 2015-05-14 16:53:10 +08:00
509c630db8 [CanalplusIE] Update tests that were no longer working 2015-05-14 08:09:56 +01:00
fbff30d2db [xattr] Catch 'Argument list too long' 2015-05-14 14:51:00 +08:00
86c7fdb17c [xattr] Enhance error handling to catch ENOSPC
Fixes #5589
2015-05-14 14:28:41 +08:00
62bd6589c7 Merge pull request #5692 from yan12125/fix-embedthumbnailpp
Use thumbnails downloaded by YoutubeDL in EmbedThumbnailPP
2015-05-14 12:35:58 +08:00
2cc6d13547 [postprocessor/embedthumbnail] Encode arguments in calling AtomicParsley 2015-05-14 04:41:30 +08:00
bb8ca1d112 [postprocessor/embedthumbnail] Use run_ffmpeg_multiple_files 2015-05-14 02:35:28 +08:00
8e59539752 [postprocessor/embedthumbnail] Use thumbnails downloaded by YoutubeDL 2015-05-14 02:32:00 +08:00
372744c544 [odnoklassniki] Fix extraction (Closes #5671) 2015-05-13 22:26:30 +06:00
83880949a1 Merge pull request #5682 from blissland/master
[BYUtvIE] Relax thumbnail regex so test does not fail
2015-05-13 19:36:22 +05:00
3749e36e9f [YoutubeDL] Fix PEP8 W503 2015-05-13 21:16:45 +08:00
0b4253fa37 [BYUtvIE] Change thumbnail regex so test does not fail 2015-05-12 18:57:06 +01:00
86ec1e487c [qqmusic] Code fixes 2015-05-13 01:37:56 +08:00
fd4eefed39 [qqmusic] Fix extraction for global list 2015-05-13 01:14:02 +08:00
b480e7874b [qqmusic] Fix code formatting 2015-05-12 22:41:37 +08:00
41333b97b9 [qqmusic] Add support for charts / top lists 2015-05-12 22:35:16 +08:00
c1c924abfe [utils,common] Merge format_srt_time and _subtitles_timecode
format_srt_time uses a comma as the delimiter between seconds and
milliseconds while _subtitles_timecode uses a dot. All .srt examples I
found on the Internet uses a comma, so I use a comma in the merged
version. See http://matroska.org/technical/specs/subtitles/srt.html and
http://devel.aegisub.org/wiki/SubtitleFormats/SRT
2015-05-12 13:04:54 +08:00
1c7e2e64f6 [nrk] Remove TTML to srt conversion codes
A common routine is implemented in utils.py and can be used via
--convert-subtitles.
2015-05-12 12:55:14 +08:00
7dff03636a [utils] Support 'dur' field in TTML 2015-05-12 12:47:37 +08:00
5332fd91bf [nytimes] Correct _VALID_URL of NYTimesArticleIE 2015-05-12 12:42:13 +08:00
d4b963d0a6 [vine] Relax alt_title (Closes #5677) 2015-05-12 01:54:56 +06:00
6d3f5935e5 [southpark] Fix IE_NAME 2015-05-11 23:47:50 +06:00
968ee17677 [southparkdk] Add extractor 2015-05-11 23:45:38 +06:00
81ed3bb9c0 [southpark] Sort alphabetically 2015-05-11 23:45:29 +06:00
5115652828 [zingmp3] Capture error message 2015-05-11 21:31:36 +06:00
1f92865494 [dumpert] Add cpc cookie (Closes #5672) 2015-05-11 21:05:39 +06:00
e41f450f28 [tmz] Add support for articles (fixes #5477) 2015-05-11 20:06:10 +08:00
97fcf1bbd0 [YoutubeDL] Check if merger can actually merge 2015-05-11 02:01:16 +06:00
13763ce599 [postprocessor/ffmpeg] Add can_merge method 2015-05-11 02:00:31 +06:00
7fcb605b82 [YoutubeDL] Fallback to -f best when merger is outdated 2015-05-11 00:27:29 +06:00
70484b9f8a [postprocessor/ffmpeg] Extract check_outdated method 2015-05-11 00:26:39 +06:00
69b46b3d95 ExecAfterDownloadPP: fix __init__ method 2015-05-10 17:47:49 +02:00
95c5534f8e ExecAfterDownloadPP, YoutubeDL: remove unused parameters 2015-05-10 17:41:11 +02:00
370b39e8ec [voicerepublic] Fix fallback branch formats extraction 2015-05-10 18:37:52 +06:00
3da8038918 Merge branch 'duncankl-voicerepublic' 2015-05-10 18:29:36 +06:00
a6762c4a22 [voicerepublic] Make more robust and extract more metadata 2015-05-10 18:29:15 +06:00
98c2c0febc Merge branch 'voicerepublic' of https://github.com/duncankl/youtube-dl into duncankl-voicerepublic 2015-05-10 17:31:55 +06:00
63cbd19f50 [ndr] Replace the 404 test case 2015-05-10 18:30:26 +08:00
1934f3a0ea [ndr] Extended to support n-joy.de as well (closes #4527)
According to http://en.wikipedia.org/wiki/N-Joy, n-joy.de is a service
hosted by NDR, so I put them together.
2015-05-10 18:22:07 +08:00
a909e6ad43 [dailymotion] Patch upload_date detection.
(closes #5665)
2015-05-10 11:13:14 +02:00
1dcb52188d [voicerepublic] Remove hardcoded paths to media files 2015-05-10 17:06:34 +12:00
28ebef0b1b [voicerepublic] Detect list of available formats from the web page 2015-05-10 16:03:09 +12:00
f03a8a3c4e [voicerepublic] Raise ExtractorError if audio is still being processed 2015-05-10 15:50:06 +12:00
03f760b1c0 [voicerepublic] Remove creator field 2015-05-10 15:41:27 +12:00
f900dc3fb9 [voicerepublic] Extract author using _html_search_meta 2015-05-10 15:01:58 +12:00
95eb1adda8 [life:embed] Sort formats 2015-05-10 08:54:50 +06:00
c6ddbdb66c [voicerepublic] Add new extractor 2015-05-10 12:39:24 +12:00
3800b908b1 [mlb] Fix #5663 2015-05-10 06:14:34 +06:00
69fe3a5f09 release 2015.05.10 2015-05-10 01:05:24 +02:00
754270313a [life:embed] Move to separated extractor and extract m3u8 formats 2015-05-10 01:03:26 +06:00
057ebeaca3 [lifenews] Add test for #5660 2015-05-10 00:27:49 +06:00
480065172d [lifenews] Add support for video URLs (Closes #5660) 2015-05-10 00:26:42 +06:00
f2e0056579 [vgtv] Avoid duplicate format_id 2015-05-09 21:23:09 +06:00
32fffff2cc [eroprofile] Fix video URL extraction (Closes #5657) 2015-05-09 21:19:09 +06:00
3c47824d6b Merge pull request #5658 from blissland/master
[BRIE] Updated two test cases
2015-05-09 20:07:21 +05:00
0892090a56 Added audio test for BRIE 2015-05-09 16:02:07 +01:00
d592b42f5c Updated two tests for BRIE 2015-05-09 15:26:00 +01:00
3b5f65a64c [mlb] Fix extraction of articles
And move test from generic, since it's directly handled by MLBIE
2015-05-09 12:41:56 +02:00
5c0b2c16a8 [vgtv] Escape '#' in _VALID_URL and remove empty newlines at the end
In verbose mode, '#' is interpreted as the start of a comment.
2015-05-09 12:34:45 +02:00
d39e0f05db [utils] Remove sanitize_url_path_consecutive_slashes()
This function is used only in SohuIE, which is updated to use a new
extraction logic.
2015-05-09 17:37:39 +08:00
6d14d08e06 [yam] Fix title and uploader id 2015-05-09 17:36:07 +08:00
32060c6d6b [sohu] Update extractor
The original extraction logic always fails for all test videos
2015-05-09 14:02:11 +08:00
3dbec410a0 [sohu] Enhance error handling 2015-05-09 14:02:11 +08:00
de765f6c31 [foxsports] Support some more URLs (#5611) 2015-05-09 02:15:51 +06:00
dc455a5f88 [extractor/generic] Add test for svt embed 2015-05-09 00:27:37 +06:00
bab19a8e91 [extractor/generic] Add support for svt embeds (Closes #5622) 2015-05-09 00:23:35 +06:00
322915014f [svtplay] Rename to svt 2015-05-09 00:13:40 +06:00
79998cd5af [svtplay] Generalize svt extractors and add svt.se extractor 2015-05-09 00:12:42 +06:00
50b9013064 [README.md] Fix typo 2015-05-08 23:21:23 +06:00
bb03fdae0d [README.md] Clarify format selection when streaming to stdout 2015-05-08 23:19:57 +06:00
4384cf9e7d [extractor/__init__] Fix alphabetic order 2015-05-08 23:04:27 +06:00
d47e980d0d Merge pull request #5641 from dstftw/preserve-best-for-stdout-outtmpl
[YoutubeDL] Do not force bestvideo+bestaudio when outtmpl is stdout
2015-05-08 22:01:50 +05:00
fe373287eb [vgtv] Add support for bt vestlendingen (Closes #5620) 2015-05-08 22:59:50 +06:00
cbe443362f [aftenposten] Implement in terms of xtream extractor 2015-05-08 22:52:20 +06:00
2c0c9dc46c [xstream] Move xstream to separate extractor 2015-05-08 22:50:01 +06:00
0ceab84749 [vgtv] Add support for bt.no articles (#5620) 2015-05-08 22:18:43 +06:00
34e7dc81a9 [vgtv] Add support for generic bt.no URLs (#5620) 2015-05-08 22:03:03 +06:00
4e6e9d21bd [mlb] Improve _VALID_URL 2015-05-08 21:48:47 +06:00
d1feb30811 [mlb] Fallback to extracting video id from webpage for all URLs that does not contain it explicitly (Closes #5630) 2015-05-08 20:07:53 +06:00
43837189c1 Fix URL template extraction for netzkino. Fixes #5614 2015-05-08 12:20:34 +02:00
249962ffa2 [bet] Use unique part of xml url as the video id and fix tests (closes #5642)
The guid changes often.
2015-05-08 11:31:05 +02:00
541168039d [utils] get_exe_version: encode executable name (fixes #5647)
It failed in python 2.x when $PATH contains a directory with non-ascii characters.
2015-05-08 11:01:24 +02:00
a650110ba7 remove print 2015-05-08 04:32:08 +02:00
54b31d149e Ir90Tv Add new extractor 2015-05-08 02:55:01 +02:00
a745475808 Ir90Tv Add new extractor 2015-05-08 02:50:46 +02:00
7ef00afe9d [nhl] Support RTMP videos (fixes #4481) 2015-05-08 03:11:25 +08:00
156fc83a55 [downloader/rtmp] Fix a typo 2015-05-08 03:11:24 +08:00
46be82b811 [vessel] Use main_video_asset when searching for video_asset (Fixes #5623) 2015-05-07 22:00:07 +03:00
09b412dafa [nhl] Partial support for hlg id (fixes #4285) 2015-05-08 02:14:28 +08:00
5268a05e47 [ooyala] Style fix 2015-05-07 17:04:15 +02:00
406224be52 [extractor/generic] Fix following incomplete redirects (#5640) 2015-05-07 21:02:59 +06:00
3799834dcf [YoutubeDL] Do not force bestvideo+bestaudio when outtmpl is stdout (#5627) 2015-05-07 20:46:11 +06:00
553e412bda Merge branch 'master' of github.com:rg3/youtube-dl 2015-05-07 22:24:49 +08:00
f22834a372 [bild] Relax thumbnail test check 2015-05-07 20:20:43 +06:00
bd349a8704 Merge pull request #5638 from blissland/master
[BildIE] Fix ampersands in xml attributes & update test thumbnails
2015-05-07 19:18:35 +05:00
bc08873cff Fix indents 2015-05-07 15:09:27 +01:00
aafe273990 [ooyala] Use SAS API to extract info (fixes #4336) 2015-05-07 22:07:32 +08:00
c09593c04e [BildIE] Escape ampersands in xml and update test thumbnail 2015-05-07 15:07:11 +01:00
84bf31aaf8 [ooyala] Extract m3u8 information (#2292) 2015-05-07 18:12:01 +08:00
05d5392cda [common] Ignore subtitles in m3u8 2015-05-07 18:06:22 +08:00
d9a743d917 [vice] Remove a redundant print 2015-05-07 18:05:37 +08:00
ac6c358c2a [teamcoco] Fix extracting preload data again 2015-05-07 12:58:00 +08:00
ad0c0ad3b4 [historicfilms] Fix tape id extraction 2015-05-06 21:52:26 +06:00
1ed34f3dd6 [gorillavid] Switch 404 test to only matching 2015-05-06 21:43:36 +06:00
6a8f9cd22e [giga] Fix view count extraction 2015-05-06 21:39:53 +06:00
e8b9ab8957 [pbs] Add format_id for direct links 2015-05-06 21:31:25 +06:00
74f728249f [extractor/common] Fallback to empty string for (yet) missing format_id in _sort_formats (Closes #5624) 2015-05-06 21:24:24 +06:00
d6a1738892 [archive.org] Fix incorrect url condition (closes #5628)
The condition for assigning to json_url is the wrong way round:

currently for url: aaa.com/xxx

we get:

aaa.com/xxx&output=json

instead of the correct value:

aaa.com/xxx?output=json
2015-05-06 15:06:10 +02:00
b326b07adc [lifenews] Use _proto_relative_url 2015-05-05 21:49:36 +06:00
07d2921c6d [lifenews] Correctly determine iframe links (fixes #5618) 2015-05-05 23:39:54 +08:00
22e462c97a Merge pull request #5612 from rrooij/southparknl
Southparknl
2015-05-05 19:32:27 +05:00
dcf8077906 [southparknl] Fix test to match playlist tests 2015-05-05 09:17:21 +02:00
3408f6e64a [southparkde] Fix naming inconsistency
The class was first called 'SouthparkDe'. It is now changed to
'SouthParkDe' to match the name of the other extractors.
2015-05-05 09:01:07 +02:00
e10dc0e1f0 [southparknl] Add extractor for southpark.nl 2015-05-05 08:59:09 +02:00
ce5c1ae517 [noco] Remove unused import 2015-05-05 02:52:21 +06:00
bbe718c97f Merge branch 'Tassatux-noco' 2015-05-05 02:50:58 +06:00
01e4b1ee14 [noco] Update tests 2015-05-05 02:50:39 +06:00
815ac0293e [noco] Modernize 2015-05-05 02:38:13 +06:00
6568382d6f [noco] Extract all variations of audio/subtitles media 2015-05-05 02:27:24 +06:00
f943b7ddce Merge branch 'noco' of https://github.com/Tassatux/youtube-dl into Tassatux-noco 2015-05-05 00:39:24 +06:00
ff9d68e7be [noco] Add test for multi languages video 2015-05-04 19:55:29 +02:00
7212560f4d [noco] Retrieve video language according to user options 2015-05-04 18:06:12 +02:00
1aa43d77c0 [rutv] Remove superfluous check 2015-05-04 21:29:56 +06:00
e038d5c4e3 [rutv] Fix preference 2015-05-04 21:29:32 +06:00
dfad3aac98 [rutv] Fix live stream test URL 2015-05-04 21:23:26 +06:00
df8418ffcf [nytimes] Extend _VALID_URL (#2754) 2015-05-04 23:03:47 +08:00
50aa43b3ae [nytimes] Implement extracting videos from articles (closes #5436) 2015-05-04 23:03:47 +08:00
a90552663e [livestream:original] Update url format (fixes #5598) 2015-05-04 16:54:01 +02:00
883340c107 [livestream:original] Fix extraction (fixes #4702) 2015-05-04 16:52:17 +02:00
0fe2ff78e6 [NBC] Enhance embedURL extraction (closes #2549) 2015-05-04 21:55:04 +08:00
dc1eed93be release 2015.05.04 2015-05-04 15:12:48 +02:00
b2f82360d7 [escapist] Add uploader to tests 2015-05-04 19:06:07 +06:00
782e0568ef [escapist] Modernize 2015-05-04 19:04:49 +06:00
90b4b0eabe [escapist] Improve _VALID_URL 2015-05-04 19:01:08 +06:00
cec04ef3a6 [escapist] Update tests' checksums 2015-05-04 19:00:34 +06:00
71fa56b887 [escapist] Fix formats extraction 2015-05-04 18:59:22 +06:00
b9b3ab45ea [NBC] Enhance extraction of ThePlatform URL (fixes #5470) 2015-05-04 19:09:18 +08:00
957b794c26 release 2015.05.03 2015-05-03 22:31:39 +02:00
8001607e90 [generic] Detect more MLB videos (fixes #5443) 2015-05-04 02:20:07 +08:00
3e7202c1bc [MLB] Extend _VALID_URL (#5443) 2015-05-04 01:59:26 +08:00
848edeab89 [lifenews] Detect <iframe> (fixes #5346) 2015-05-04 01:24:19 +08:00
1748d67aea [lifenews] Fix view count and comment count 2015-05-04 01:11:23 +08:00
5477ca8239 [dailymotion] Use https urls
The video url still redirects to an http url, but it doesn't explicitly contain the video id.
2015-05-03 16:59:14 +02:00
d0fd305023 [rutv] Add test for #5584 2015-05-03 10:00:34 +06:00
8dab1e9072 [rutv] Recognize live streams (#5584) 2015-05-03 09:56:03 +06:00
963aea5279 [baiduvideo] Improve _VALID_URL 2015-05-03 07:45:15 +06:00
0a64aa7355 [vgtv] Fix _VALID_URL (Closes #5578) 2015-05-03 00:58:42 +06:00
0669c89c55 [options] Clarify --write-annotations help 2015-05-02 23:38:30 +06:00
2699da8041 [YoutubeDL] Improve description file naming 2015-05-02 23:36:55 +06:00
98727e123f [YoutubeDL] Improve annotations file naming 2015-05-02 23:35:18 +06:00
b29e0000e6 [YoutubeDL] Improve JSON info file naming 2015-05-02 23:23:44 +06:00
b3ed15b760 [utils] Add replace_extension 2015-05-02 23:23:06 +06:00
666a9a2b95 [YoutubeDL] Improve audio/video-only file naming 2015-05-02 23:11:34 +06:00
a4bcaad773 [test_utils] Add tests for prepend_extension 2015-05-02 23:10:48 +06:00
e65e4c8874 [utils] Improve prepend_extension
Now `ext` is appended to filename if real extension != expected extension.
2015-05-02 23:06:01 +06:00
21f6330274 [baiduvideo] Add new extractor (closes #4563) 2015-05-03 00:53:24 +08:00
38c6902b90 [YoutubeDL] Ensure correct extension is always present for a merged file (Closes #5535) 2015-05-02 22:52:21 +06:00
2ddcd88129 Remove code that was only used by the Grooveshark extractor 2015-05-02 17:29:56 +02:00
dd8920653c [Grooveshark] Remove the extractor
grooveshark.com was shut down on 2015/04/30
2015-05-02 21:46:33 +08:00
c938c35f95 [iconosquare] Fix extraction 2015-05-02 07:18:22 +06:00
2eb0192155 [viki] Remove clean_html call 2015-05-02 01:35:46 +08:00
d948e09b61 [viki] Extract m3u8 videos (#4855) 2015-05-02 01:20:16 +08:00
89966a5aea [viki] Enhance error message handling (#3774) 2015-05-02 01:20:15 +08:00
8e3df9dfee [viki] Fix extractor and add a global availble test case 2015-05-02 01:20:15 +08:00
5890eef6b0 [pbs] Add support for HD (Closes #3564, closes #5390) 2015-05-01 17:43:06 +06:00
083c1bb960 Add ability to embed subtitles in mkv files (closes #5434) 2015-05-01 11:54:40 +02:00
861e65eb05 [yahoo] Extend _VALID_URL 2015-05-01 12:32:24 +08:00
650cfd0cb0 [bbccouk] Mute thumbnail 2015-05-01 04:07:30 +06:00
e68ae99a41 [bbccouk] Add test for #5530 2015-05-01 04:02:56 +06:00
8683b4d8d9 [bbccouk] Improve extraction (Closes #5530) 2015-05-01 03:59:13 +06:00
1dbd717eb4 [theplaform] Fix FutureWarning 2015-05-01 02:51:55 +06:00
6a8422b942 [foxsports] Add extractor (Closes #5517) 2015-05-01 02:49:06 +06:00
cb202fd286 [YoutubeDL] Filter requested info fields on --load-info as well
In order to properly handle JSON info files generated by youtube-dl versions prior to 4070b458ec
2015-05-01 00:44:34 +06:00
67fc8ecd53 [dreisat] Extend _VALID_URL (Closes #5548) 2015-04-30 21:28:08 +03:00
df8301fef5 [YoutubeDL] pep8: use 'k not in' instead of 'not k in' 2015-04-30 20:18:42 +02:00
4070b458ec [YoutubeDL] Do not write requested info in info JSON file (Closes #5562, closes #5564) 2015-04-30 23:55:05 +06:00
ffbc3901d2 Merge remote-tracking branch 'upstream/master' 2015-04-30 23:33:49 +08:00
7a03280df4 [vporn] More metadata extraction fixes and tests update (#5560) 2015-04-30 21:31:38 +06:00
482a1258de [VeeHD] Replace the third test case due to copyright issues 2015-04-30 23:27:07 +08:00
cd298882cd [vporn] Fix metadata extraction (#5560) 2015-04-30 21:25:17 +06:00
e01c56f9e1 [YoutubeDL] Generalize best/worst format match behavior 2015-04-30 21:06:51 +06:00
4d72df4031 Merge pull request #5556 from jaimeMF/best-format-nodash
Make 'best' format only match non-DASH formats (closes #5554)
2015-04-30 19:57:02 +05:00
f7f1df1d82 [VeeHD] Enhance extraction and fix tests (fixes #4965) 2015-04-30 22:37:41 +08:00
c4a21bc9db [bilibili] Extract multipart videos (closes #3250) 2015-04-30 18:26:08 +08:00
621ffe7bf4 [niconico] Fix so* video extraction (fixes #4874) (#2087) 2015-04-30 17:05:02 +08:00
8dd5418803 Make 'best' format only match non-DASH formats (closes #5554)
Otherwise it's impossible to only download non-DASH formats, for example `best[height=?480]/best` would download a DASH video if it's the only one with height=480, instead for falling back to the second format specifier.
For audio only urls (soundcloud, bandcamp ...), the best audio will be downloaded as before.
2015-04-29 22:53:18 +02:00
965cb8d530 [escapist] pep8 fixes 2015-04-29 22:46:19 +02:00
b2e8e7dab5 [niconico] Try to extract all optional fields from various sources 2015-04-30 02:24:05 +08:00
59d814f793 [niconico] Remove credentials from tests and enhance title extraction
All test videos can be downloaded without username and password now.
2015-04-30 00:50:48 +08:00
bb865f3a5e [niconico] Fix extraction and update tests (closes #5511) 2015-04-30 00:50:48 +08:00
9ee53a49f0 [YouPorn] Fix extractor 2015-04-30 00:50:48 +08:00
79adb09baa Merge pull request #5553 from zouhair/master
Typo: twice "the the" to "the"
2015-04-29 20:05:48 +05:00
cf0649f8b7 Typo: twice "the the" to "the" 2015-04-29 11:03:10 -04:00
f8690631e2 Merge pull request #5552 from zouhair/master
Typo "incompatible" instead of "uncompatible"
2015-04-29 19:09:47 +05:00
5456d78f0c Typo "incompatible" instead of "uncompatible" 2015-04-29 10:07:49 -04:00
cbbece96a2 [yourupload] Simplify 2015-04-29 04:05:14 +08:00
9d8ba307ef [yourupload] Fix extraction 2015-04-29 04:03:07 +08:00
ec7c1e85e0 [testtube] Fix test case 1
Seems the site now provides webm with higher bitrates
2015-04-29 00:24:58 +08:00
e70c7568c0 [testtube] Detect Youtube iframes (fixes #4867) 2015-04-29 00:22:17 +08:00
39b62db116 [youtube] Catch more alert messages (closes #5074) 2015-04-28 23:07:56 +08:00
2edce52584 [vimeo] Fix password protected videos again (#5082)
Since they have changed again to the previous format, I've modified the regex to match both formats.
2015-04-28 15:06:08 +02:00
10831b5ec9 [vimeo] Fix redirection 2015-04-28 14:56:48 +02:00
3a0f0c263a release 2015.04.28 2015-04-28 09:11:18 +02:00
2419a376b9 [moniker] Check not found error (#5541) 2015-04-27 23:46:16 +06:00
e206740fd7 [moniker] Capture and output error message (#5541) 2015-04-27 23:44:05 +06:00
290a5a8d85 [escapist] Fix imsVideo regex (#5090) 2015-04-27 22:17:51 +06:00
e2dc351d25 [escapist] Fix extractor (fixes #5090) 2015-04-27 17:44:13 +02:00
c86b61428b [utils] Fix another old python 2.6 kwargs issue (Closes #5539) 2015-04-27 20:00:18 +06:00
40b96352c9 Merge pull request #5523 from jaimeMF/remove-format-limit
Remove the --max-quality option
2015-04-27 16:44:58 +05:00
189ba90996 [README] Use youtube-dl test video URL 2015-04-27 16:05:01 +06:00
c8183e661d [README] Document special characters escaping (#5538) 2015-04-27 16:01:30 +06:00
053c94f1b3 [README] Clarify youtube-dl version when format selection changed to bestvideo+bestaudio/best 2015-04-27 15:21:51 +06:00
b9d76a9571 Merge branch 'fstirlitz-philharmoniedeparis' 2015-04-27 03:36:46 +06:00
a01cfc2951 [philharmoniedeparis] Fix extraction and tests, improve, simplify 2015-04-27 03:36:32 +06:00
4eb5c65bee release 2015.04.26 2015-04-26 22:45:20 +02:00
06d07c4000 New extractor: live.philharmoniedeparis.fr 2015-04-26 14:15:29 +02:00
74f8654a53 [downloader/external] Use encodeArgument 2015-04-26 04:33:43 +06:00
9e105a858c [downloader/rtmp] Fix arguments encoding and simplify retry logic (Closes #5528) 2015-04-26 04:32:54 +06:00
cd8a07a764 [downloader/common] Use decodeArgument 2015-04-26 04:30:45 +06:00
aa49acd15a [utils] Add get_subprocess_encoding and filename/argument decode counterparts 2015-04-26 04:29:41 +06:00
642f23bd81 [southpark] Use 'ñ' in the spanish extractor name
IE_NAME can contain unicode characters, so it shouldn't be a problem.
2015-04-25 22:36:11 +02:00
2e24e6bd17 Merge branch 'mp3' 2015-04-25 20:41:59 +02:00
2a09c1b8ab [postprocessor/embedthumbnail] Fix mp3 embedding with avconv (fixes #5526) 2015-04-25 20:41:15 +02:00
a5ebf77d87 [mplayer] Rename to RTSP 2015-04-26 00:25:51 +06:00
b874495b1f [mplayer] Simplify 2015-04-26 00:23:16 +06:00
b860f5dfd4 [mplayer] Clarify error message 2015-04-26 00:22:13 +06:00
b19fc36c81 Merge pull request #5521 from mrkrossxdx/mpv
Added support for mpv if mplayer is not available (new version)
2015-04-25 23:19:59 +05:00
d2d8248f68 [instagram] Modernize 2015-04-25 22:42:15 +06:00
f54bab4d67 [instagram] Improve _VALID_URL 2015-04-25 22:39:50 +06:00
bf6427d2fb [ffmpeg] Add dfxp (TTML) subtitles support (#3432, #5146) 2015-04-25 23:18:27 +08:00
672f1bd849 [cspan] Extract subtitles 2015-04-25 23:18:27 +08:00
529d26c3e1 [orf:iptv] Update test 2015-04-25 21:06:27 +06:00
857f00ed94 [southpark] Improve some _VALID_URL's 2015-04-25 20:24:15 +06:00
e4a5e772f2 [southpark:espanol] Add extractor (Closes #5525) 2015-04-25 20:23:42 +06:00
a542e372ab [mtv] Stuff lang into info URL when available 2015-04-25 20:22:20 +06:00
0d1bd5d62f README: remove --max-quality 2015-04-25 15:14:16 +02:00
9f3fa89f7c Remove the --max-quality option
It doesn't work well with 'bestvideo' and 'bestaudio' because they are usually before the max quality.
Format filters should be used instead, they are more flexible and don't require the requested quality to exist for each video.
2015-04-25 11:59:54 +02:00
92995e6265 [postprocessor/embedthumbnail] Style fix 2015-04-24 22:08:00 +02:00
a4196c3ea5 [ellentv] Remove unused import 2015-04-24 22:06:22 +02:00
db37e0c273 Added support for mpv if mplayer is not available 2015-04-24 20:50:34 +02:00
d0aefec99a [ellentv:clips] Fix test 2015-04-24 22:10:27 +06:00
66be4b89d7 [ellentv:clips] Fix extraction 2015-04-24 22:09:54 +06:00
870744ce8f [ellentv] Fix tests 2015-04-24 22:07:15 +06:00
2ad978532b [ellentv] Fix extraction 2015-04-24 22:03:14 +06:00
5090d93f2c [dotsub] Fix extraction 2015-04-24 21:47:13 +06:00
c8ff645766 [gdcvault] Add display_id 2015-04-24 22:43:33 +08:00
25f7d1beba [gdcvault] Extend _VALID_URL (fixes #5236) 2015-04-24 22:33:35 +08:00
09aa111918 Merge branch 'embedthumb' 2015-04-24 09:25:44 +02:00
10fb7710e8 Forgot to clean the remains of class 2015-04-24 09:17:46 +02:00
c0ea8ebb9b [ffmpeg] Remove unneeded class 2015-04-24 09:11:39 +02:00
31fd9c7601 [embedthumbnail] use FFmpegPostProcessor for mp3 2015-04-24 09:08:57 +02:00
ddbed36455 [embedthumbnail] Add support for mp3 cover embedding 2015-04-24 08:48:49 +02:00
a9b0d4e1f4 [Crunchyroll] Fix extraction on Python 2.6
XPath with recursive children selection not supported
2015-04-24 14:09:35 +08:00
4d6a3ff411 [README] Finally fix configuration file link 2015-04-24 01:41:36 +06:00
7fb993e1f4 [README] Fix configuration file link and typo 2015-04-24 01:38:02 +06:00
02f502f435 [README] Document on how to enable old format selection behavior (#5510, #5511) 2015-04-24 01:34:57 +06:00
4515cb43ca [xattrpp] Fix typo 2015-04-23 22:11:09 +06:00
d740333224 [cracked] Modernize 2015-04-23 21:59:18 +06:00
c610f38ba9 [cracked] Update tests 2015-04-23 21:58:50 +06:00
6447353f52 [cracked] Add support for youtube embeds 2015-04-23 21:49:54 +06:00
b46ed49996 [cracked] Fix extraction 2015-04-23 21:44:51 +06:00
cd9fdccde0 [ustream] Try to extract uploader from JSON data (#5128) 2015-04-23 18:33:25 +08:00
2a8137272d [ustream] Add an alternative approach to extract title (fixes #5128) 2015-04-23 18:24:44 +08:00
762155cc90 [ustream] Checking errors 2015-04-23 18:10:18 +08:00
f8610ba1ca [ustream] Fix extraction (closes #3998) 2015-04-23 18:10:18 +08:00
c99f4098c4 Merge branch 'master' of github.com:rg3/youtube-dl 2015-04-23 11:43:37 +02:00
3eec9fef30 [realvid] Add extractor for realvid.net (closes #5504) 2015-04-23 11:41:21 +02:00
8c8826176d [xattr] Add version detection for python-pyxattr
For more information, see #5498 and changes to convertObj() in
iustin/pyxattr@cc84e466f6
2015-04-23 13:50:44 +08:00
14a2d6789f [vimeo] one token overlooked 2015-04-22 23:55:19 +02:00
7513f298b0 [vimeo] Fix login token (fixes #5082) 2015-04-22 23:50:11 +02:00
c04c3e334c [flickr] Don't use regex for extracting the info from the xml files 2015-04-22 19:58:39 +02:00
f8e51f60b3 [flickr] Fix extraction (fixes #5501) 2015-04-22 19:24:14 +02:00
33b066bda0 [hitbox] Clarify download messages 2015-04-22 21:09:21 +06:00
14f41bc2fb [hitbox:live] Extract formats before metadata 2015-04-22 21:05:08 +06:00
008bee0f50 [hitbox] Extract formats before metadata 2015-04-22 21:03:56 +06:00
29492f3332 [hitbox] Sort formats 2015-04-22 21:01:52 +06:00
bc94bd510b [hitbox] Extract all formats (Closes #5494) 2015-04-22 21:01:25 +06:00
9dd8e46a2d [youtube:search] Cancel out _TESTS 2015-04-22 20:28:33 +06:00
8be2bdfabd [YoutubeDL] Remove the redundant assignment to old_filename
Caused by commmit 592e97e855
2015-04-22 15:05:35 +08:00
b4c0806963 [youtube:ytsearch] Use the same system as the search webpage (fixes #5483)
The gdata api V2 was deprecated and according to http://youtube-eng.blogspot.com.es/2014/03/committing-to-youtube-data-api-v3_4.html remains available until April 20, 2015.
2015-04-21 19:30:31 +02:00
cc38fa6cfb [youtube] Remove unused import 2015-04-21 22:55:59 +06:00
6de5dbafee [youtube:channel] Make extract_videos_from_page static 2015-04-21 22:42:21 +06:00
60bf45c80d [youtube:channel] Specify first page download message 2015-04-21 22:37:45 +06:00
eb0f3e7ec0 [youtube:user] Extract in terms of load_more_widget_html 2015-04-21 22:36:41 +06:00
ed553379df [youtube:ytsearch] Temporary workaround (#5483) 2015-04-21 20:55:05 +06:00
5c1e6f69c4 [senate] Simplify
There isn't any problem if the 'formats' field only has one element
2015-04-21 15:04:55 +02:00
757cda0a96 [Cinemassacre] Support Youtube embedded videos (fixes #5131) 2015-04-21 15:21:04 +08:00
e94443de80 [Cinemassacre] Move to a standalone module 2015-04-21 15:10:27 +08:00
0954cd8aa4 [Cinemassacre] Add detection for videos from blip.tv 2015-04-21 13:48:02 +08:00
da55dac047 [CSpan] Removed the md5 sum of CSpan_3 2015-04-21 05:22:23 +08:00
13a11b195f [SenateISVP] Fix tests
Remove md5 sums. They differs from my PC and the travis worker.
2015-04-21 05:13:25 +08:00
92dcba1e1c [CSpan] Fix test cases CSpan_1 and CSpan_2 2015-04-21 03:30:54 +08:00
2fe1b5bd2a [CSpan] Add detection for Senate ISVP. Closes #5302 2015-04-21 03:18:38 +08:00
f91e1a8739 [Senate] Try to capture thumbnails 2015-04-21 02:57:32 +08:00
24e21613b6 [bilibili] Capture the video-not-exist message 2015-04-21 02:32:10 +08:00
c6391cd587 [Senate] Add new extractor (#5302) 2015-04-21 02:29:56 +08:00
006ce15a0c [bambuser] Add support for authentication (#5478) 2015-04-20 23:00:37 +06:00
edf4216119 [bambuser] Modernize and extract more metadata 2015-04-20 22:46:01 +06:00
ae8953409e [bambuser] Capture and output error message (#5478) 2015-04-20 22:35:53 +06:00
bda44f31a1 [bambuser] Modernize 2015-04-20 22:33:35 +06:00
6621ca39a3 [ted] Skip hls quality selection format 2015-04-20 22:04:42 +06:00
14f7abfa71 [ted] Lower preference for direct audio since it's mono 2015-04-20 22:04:17 +06:00
0f0b5736da [ted] Fix hls audio/video-only formats 2015-04-20 22:01:02 +06:00
6728187ac0 [YoutubeDL] mp3 is compatible with mp4 2015-04-20 21:58:46 +06:00
17c8675853 [YoutubeDL] Allow bestvideo+bestaudio/best strategy for ted extractor 2015-04-20 21:58:29 +06:00
cfbee8a431 [ted] Clarify IE_NAME 2015-04-20 21:42:42 +06:00
736785ab63 [ted] Clarify audio/video-only formats 2015-04-20 21:42:20 +06:00
3ded7bac16 [extractor/common] Add ability to specify custom field preference for _sort_formats 2015-04-20 21:13:31 +06:00
b524a001d6 [bandcamp] fix video_id parsing (fixes #4861) 2015-04-20 15:45:57 +02:00
7b071e317b README: document bestvideo+bestaudio/best (#5447) 2015-04-19 18:54:05 +02:00
a380509259 Move the documentation for the --format option to the manpage
It's too big for beeing embedded in the help message and it's easier to edit in the markdown file.
2015-04-19 18:53:28 +02:00
c0dea0a782 [YoutubeDL] Respect explicit --merge-format-output for uncompatible formats as well 2015-04-19 22:33:52 +06:00
70947ea7b1 [parameters.json] Set default format parameter to best 2015-04-19 17:56:06 +02:00
81cd954a51 [YoutubeDL] Merge incompatible formats into mkv (#5456) 2015-04-19 17:55:42 +02:00
feccf29c87 [YoutubeDL] Make bestvideo+bestaudio/best default format when merger is available 2015-04-19 17:51:56 +02:00
5b5fbc0867 Detect already merged videos
Without the '--keep-video' option the two files would be downloaded again and even using the option, ffmpeg would be run again, which for some videos can take a long time.
We use a temporary file with ffmpeg so that the final file only exists if it success
2015-04-19 17:51:41 +02:00
f158799bbe [Sohu] Fix title extraction 2015-04-19 19:19:44 +08:00
8b0e8990c2 [miomio] Replace the slow test case
MioMio_1 takes about 25~35 seconds on information retrieval
2015-04-19 19:12:23 +08:00
880ee801cf [tests] Allow multi_video to be tested as playlists 2015-04-19 19:08:37 +08:00
163965d861 [megavideoz] Improve non-existing videos check 2015-04-19 04:14:58 +06:00
6e218b3f9a [megavideoz] Check non-existing videos 2015-04-19 04:09:01 +06:00
cc9b9df0b6 [megavideozeu] Rename extractor 2015-04-19 04:08:29 +06:00
31f224008e [megavideozeu] Simplify (Closes #5454) 2015-04-19 04:07:45 +06:00
f32cb5cb14 [megavideoez] Add working test 2015-04-19 04:06:45 +06:00
fec2d97ca2 Add megavideoz.eu support. 2015-04-19 04:06:27 +06:00
f2eeafb061 Merge pull request #5462 from hedii/hedii-patch-1
Update wat.py misspelling 'downloding'
2015-04-18 18:43:03 +05:00
8f4e8bf280 Update wat.py
line 116, modify 'Downloding' to 'Downloading'.
It looks like nothing, but it is very annoying when youtube-dl command's output is parsed to find progress on a php (or other language) website for example.
2015-04-18 15:40:40 +02:00
cc36e2295a [ign] Fix extraction of some videos in articles
Give higher preference to the hero-poster regex because some articles may contain other videos
2015-04-18 13:27:35 +02:00
d47aeb2252 FFmpegMergerPP: use the new system for specifying which files can be delete 2015-04-18 11:52:36 +02:00
14523ed969 FFmpegEmbedSubtitlePP: remove the subtitle files if '--keep-video' is not given (closes #5435) 2015-04-18 11:44:42 +02:00
592e97e855 Postprocessors: use a list for the files that can be deleted
We could only know if we had to delete the original file, but this system allows to specify us more files (like subtitles).
2015-04-18 11:36:42 +02:00
53faa3ca5f [facebook] Extend _VALID_URL take 2 (#5120) 2015-04-18 16:08:24 +08:00
c62566971f [facebook] Extend _VALID_URL 2015-04-18 16:00:33 +08:00
902be27cf9 Merge branch 'julianrichen-gfycat' 2015-04-18 03:51:38 +06:00
bf12cbe07c Credit @julianrichen for gfycat (#5440) 2015-04-18 03:51:21 +06:00
f52e66505a [gfycat] Simplify (Closes #5439, Closes #5394) 2015-04-18 03:50:22 +06:00
ca75235d3d Merge branch 'gfycat' of https://github.com/julianrichen/youtube-dl into julianrichen-gfycat 2015-04-18 03:49:32 +06:00
ecc6bd1341 YoutubeDL.post_process: simplify keep_video handling
Since keep_video started as None we always set it to keep_video_wish unless it was None, so in the end keep_video == keep_video_wish. This should have been changed in f3ff1a3696, but I didn't notice it.
2015-04-17 22:38:14 +02:00
ce81b1411d FFmpegExtractAudioPP: Simplify handling of already existing files 2015-04-17 22:37:27 +02:00
7691a7a3bd [comedycentral] Fix feed uri request (Closes #5449, closes #5455) 2015-04-17 23:41:07 +06:00
214e74bf6f [soundcloud] Raise an error instead of calling 'report_error' 2015-04-17 19:24:30 +02:00
c5826a491b [mixcloud] Simplify url extraction
On the tracks I tested the server number in the url from the webpage is valid
for the mp3 or the m4a file and any other number is invalid, it's a
waste of time to check them.
2015-04-17 19:02:49 +02:00
d8e7ef04dc [vimple] Fix extraction (Closes #5448) 2015-04-17 22:56:26 +06:00
08f2a92c9c InfoExtractor._search_regex: Suggest updating when the regex is not found (suggested in #5442)
Reuse the same message from ExtractorError
2015-04-17 14:55:24 +02:00
3220c50f9a release 2015.04.17 2015-04-17 11:14:25 +02:00
024ebb2706 [soundcloud] Handle 'secret_token' for 'w.soundcloud.com/player/?url=*' urls (fixes #5453) 2015-04-17 10:46:25 +02:00
f11554092b [Lecture2Go] Add new extractor 2015-04-17 09:21:54 +02:00
954352c4c0 [gfycat] Fixed preferences. 2015-04-16 18:11:30 -04:00
4aec95f3c9 [gfycat] Updated tests. 2015-04-16 18:10:53 -04:00
be531ef1ec [utils] Fix splitunc deprecation warning 2015-04-16 22:12:38 +06:00
65c1a750f5 [srf] Show display_id when present 2015-04-16 21:48:22 +06:00
5141249c59 [srf] Extend _VALID_URL 2015-04-16 21:47:42 +06:00
6225984681 [generic] Update pladform embed test 2015-04-16 21:37:15 +06:00
5cb91ceaa5 [pladform] Update test 2015-04-16 21:33:01 +06:00
89c09e2a08 [srf] Update test 2015-04-16 21:30:13 +06:00
fbbb219409 [srf] Fix direct links ext 2015-04-16 21:28:21 +06:00
820b064804 [srf] Extract subtitles 2015-04-16 20:48:17 +06:00
355c524bfa [srf] Extract all formats and prefer direct links over hls and hds 2015-04-16 20:31:02 +06:00
c052ce6cde [Srf] Add new extractor (fixes #981) 2015-04-16 22:00:45 +08:00
c9a779695d [extractor/common] Add the encoding parameter
The QQMusic info extractor need forced encoding for correct working.
2015-04-16 17:34:54 +08:00
a685ae511a [QQMusic] Song extractor: Add lyrics as description
Note: Test fails on python 3 due to encoding issues
2015-04-16 17:34:54 +08:00
5edea45fab [QQMusic] Add album info extractor 2015-04-16 17:34:54 +08:00
8afff9f849 [QQMusic] Add singer info extractor 2015-04-16 17:34:54 +08:00
a2043572aa [QQMusic] Implement the guid algorithm 2015-04-16 17:34:54 +08:00
5d98908b26 [QQMusic] Add new extractor 2015-04-16 17:34:54 +08:00
d6fd958c5f [generic] Extract videos from SMIL manifests (closes #5145 and fixes #5135) 2015-04-16 17:16:11 +08:00
d0eb724e22 [UDNEmbed] Enhance error checking and extend _VALID_URL 2015-04-16 17:04:53 +08:00
afe4a8c769 [gfycat] Add new extractor 2015-04-15 22:17:45 -04:00
9fc03aa87c [brightcove] Always return lists from _extract_brightcove_urls
In Python 3, filter() returns an iterable object, which is equivalently
to True even for an empty result set. It causes false positive playlists
in generic extraction logic.
2015-04-16 00:27:39 +08:00
c798f15b98 [generic] Add test for playwire embed (#5430) 2015-04-15 22:14:29 +06:00
2dcc114f84 [generic] Add support for playwire embeds (Closes #5430) 2015-04-15 22:10:08 +06:00
0dfe9bc9d2 [mtv] Capture and output error message (#5420) 2015-04-15 21:02:34 +06:00
4d1cdb5bfe [spike] Extend _VALID_URL (Closes #5420) 2015-04-15 20:58:48 +06:00
9c5335a027 [teamcoco] Fix "preload" data extraction (fixes #5179) 2015-04-15 19:56:21 +08:00
ae849ca170 [tumblr] Dismiss warnings for optional fields (fixes #5202) 2015-04-15 17:45:28 +08:00
94c1255782 [brightcove] Handle non well-formed XMLs (#5421) 2015-04-14 17:50:53 +06:00
476e1095fa [brightcove] Improve brightcove experience regex (Closes #5421) 2015-04-14 17:48:41 +06:00
8da1bb0418 [miomio] Enhance error checking and replace dead test case 2015-04-14 15:27:56 +08:00
01c58f8473 [generic] Fix test generic_51
The website replaced the original video with a new one
2015-04-14 13:10:10 +08:00
edfcf7abe2 [generic] Support another type of Ooyala embedded video 2015-04-14 12:45:43 +08:00
37b44fe7c1 [postprocessor/atomicparsley] Don't try to remove the temporary and original files if the format is unsupported (fixes #5419) 2015-04-13 22:50:40 +02:00
8f02ad4f12 [youtube] Simplify 2015-04-13 20:28:16 +06:00
51f1244600 [vine] flake8 2015-04-13 19:26:15 +08:00
7bd930368c [youtube] Remove unused variable 2015-04-13 00:08:39 +06:00
fb69240ca0 [youtube] Extract video titles for channel playlist if possible (Closes #4971) 2015-04-12 23:19:00 +06:00
830d53bfae [utils] Add video_title for url_result 2015-04-12 23:11:47 +06:00
c36a959549 [YoutubeDL] Try to download worst audio+video served by a single file first (Closes #5408) 2015-04-12 17:36:29 +06:00
e91b2d14e3 Credit @snipem for gamersyde (#5352) 2015-04-12 17:17:31 +06:00
ac58e68bc3 [footyroom] Remove superfluous whitespace 2015-04-12 17:11:11 +06:00
504c1cedfe [footyroom] Improve 2015-04-12 17:09:52 +06:00
9a4d8fae82 [FootyTube] Fixed wrong md5 checksum 2015-04-12 17:01:12 +06:00
7d2ba6394c [FootyRoom] Fixed missing http prefix
For some reason FootyTube is missing the „http:“ prefix on some
Playwire links for some videos
2015-04-12 17:01:03 +06:00
b04b94da5f [options] Fix file based configurations for python 2 (Closes #5401) 2015-04-12 03:57:56 +06:00
9933857f67 Merge branch 'fstirlitz-crooksandliars' 2015-04-11 20:27:53 +06:00
ed5641e249 [crooksandliars] Quotes consistency 2015-04-11 20:27:39 +06:00
a4257017ef [generic] Add tests for Crooks and Liars embeds 2015-04-11 20:26:42 +06:00
18153f1b32 [generic] Add support for Crooks and Liars embeds 2015-04-11 20:20:20 +06:00
7a91d1fc43 [crooksandliars] Improve embed extractor and remove article extractor 2015-04-11 20:03:12 +06:00
af14ded75e Merge branch 'crooksandliars' of https://github.com/fstirlitz/youtube-dl into fstirlitz-crooksandliars 2015-04-11 19:34:06 +06:00
65939effb5 [hitbox:live] Fix hls extration (Closes #5315) 2015-04-11 18:52:41 +06:00
66ee7b3234 [ted] Extract all formats (Closes #5397) 2015-04-10 23:36:28 +06:00
cd47a628fc [rai] Add test for #5396 2015-04-10 22:44:41 +06:00
d7c78decb0 [rai] Improve extraction 2015-04-10 22:44:33 +06:00
8749477ed0 [rai] Fix extraction (Closes #5396) 2015-04-10 22:44:24 +06:00
7088f5b5fa [teamcoco] Extract duration 2015-04-10 02:03:38 +03:00
5bb6328cb9 [teamcoco] Extract m3u8 URLs 2015-04-09 23:57:51 +03:00
ce9f47de99 [teamcoco] Fix extraction 2015-04-09 23:54:53 +03:00
4c4780c25e [vine] Modernize 2015-04-09 22:41:41 +06:00
64f1aba8f1 [vine] Extend _VALID_URL 2015-04-09 22:40:18 +06:00
3359fb661f [vine] Add tests for #5389 2015-04-09 22:37:54 +06:00
58a9f1b864 [vine] Fix post data regex (Closes #5389) 2015-04-09 22:32:48 +06:00
6ac41a4ef5 [vine] Zero rate videos is perfectly valid (#5389) 2015-04-09 22:32:22 +06:00
aa2af7ba74 [dumpert] Add nsfw cookie (Closes #5382) 2015-04-09 19:53:00 +06:00
ce73839fe4 [rtve] Detect videos that are no longer available 2015-04-09 14:01:33 +02:00
1dc2726f8d release 2015.04.09 2015-04-09 00:21:19 +02:00
af76e8174d [dailymotion:user] Improve _VALID_URL (Closes #5380) 2015-04-09 02:25:31 +06:00
402a3efc92 [theplatform] Modernize 2015-04-08 22:29:10 +06:00
372f08c990 [theplatform] Fix for python 2.6
At least single depth level extraction...
2015-04-08 22:27:25 +06:00
dd29eb7f81 [postprocessor/common:postprocessor/ffmpeg] Generalize utime 2015-04-08 21:40:31 +06:00
bca788ab1d Merge pull request #5376 from PeteHemery/ffmpeg-postproc-utime-bug
[ffmpeg] adding exception catching for call to os.utime in run_ffmpeg_multiple_files
2015-04-08 20:27:17 +05:00
aef8fdba11 [theplatform] Allow <par> without <swtich> at all
Bare `wget` on http://link.theplatform.com/s/kYEXFC/22d_qsQ6MIRTl results in an XML without <switch> at all
but with <par> and <video> inside it. Let's handle this possible outcome as well.
2015-04-08 21:03:11 +06:00
0a1603634b [utils] Remove url_infer_protocol 2015-04-08 21:39:34 +08:00
a662163fd5 [theplatform] Rework on <switch> inside <par> 2015-04-08 20:21:34 +08:00
bd7a6478a2 [theplatform] Fix video url extraction (fixes #5340)
In SMIL 2.1, <switch> nodes may be enclosed in <par>. See
http://www.w3.org/TR/SMIL2/smil-timing.html#edef-par
2015-04-08 19:20:34 +08:00
4a20c9f628 [livestream] Extend _VALID_URL (fixes #5375) 2015-04-08 17:42:26 +08:00
418c5cc3fc [udn] Add new extractor 2015-04-08 17:26:51 +08:00
cc55d08832 [ffmpeg] adding exception catching for call to os.utime in run_ffmpeg_multiple_files 2015-04-07 22:33:18 +01:00
de5c545648 [youtube] Skip WebVTT in DASH manifest (#5297) 2015-04-08 03:47:27 +08:00
a35099bd33 [addanime] Add test for #5372 2015-04-07 21:01:35 +06:00
5f4b5cf044 [addanime] Extend _VALID_URL (Closes #5372) 2015-04-07 21:00:52 +06:00
beb10f843f [addanime] Add format quality (Closes #5371) 2015-04-07 21:00:22 +06:00
29713e4268 [cnn] Match more affilliates 2015-04-07 14:59:13 +02:00
8e4b83b96b Remove check for ssl certs
When it uses a capath instead of a cafile, 'get_ca_certs' or 'cert_store_stats' only returns certificates already used in a connection.
(see #5364)
2015-04-06 22:18:08 +02:00
ae603b500e Merge branch 'newtonelectron-spankbang.com' 2015-04-06 21:24:45 +06:00
d97aae7572 [spankbang] Improve and simplify 2015-04-06 21:24:17 +06:00
a55e2f04a0 Merge branch 'spankbang.com' of https://github.com/newtonelectron/youtube-dl into newtonelectron-spankbang.com 2015-04-06 20:46:40 +06:00
6e53c91608 [crooksandliars] resolve protocol-relative URLs 2015-04-06 10:12:43 +02:00
d2272fcf6e crooksandliars.com extractor 2015-04-06 09:54:19 +02:00
c7ac5dce8c [SpankBang] Remove regexp type prefix from _TEST url. 2015-04-05 14:02:05 -07:00
5c1d459ae9 [SpankBang] Add test 2015-04-05 13:57:59 -07:00
2e7daef502 [SpankBang] Use python2.6 compatible string formatting spec 2015-04-05 13:43:21 -07:00
6410229681 [SpankBang] Add new extractor 2015-04-05 12:50:21 -07:00
e40bd5f06b [youtube] Simplify url_encoded_fmt_stream_map check 2015-04-06 00:45:57 +06:00
06b491eb7b [youtube] Add test for #5361 2015-04-06 00:35:55 +06:00
3a9fadd6df [youtube] Enhance url_encoded_fmt_stream_map checking (fix #5361) 2015-04-05 22:29:06 +08:00
0de9312a7e [ellentv] Replace test 2015-04-05 00:01:55 +06:00
27fe5e3473 [ellentv] Make video url extraction fatal 2015-04-05 00:00:04 +06:00
f67dcc09f5 [eagleplatform] Skip georestricted test 2015-04-04 23:36:45 +06:00
fefc9d121d [dump] Fix title extraction 2015-04-04 23:33:07 +06:00
a319c33d8b [dreisat] Update test 2015-04-04 23:30:38 +06:00
218d6bcc05 [dreisat] Capture status errors 2015-04-04 23:28:47 +06:00
7d25463972 [drtv] Update test 2015-04-04 23:19:28 +06:00
aff84bec07 [drtv] Check for unavailable videos 2015-04-04 23:17:09 +06:00
ac651e974e [culturebox] Fix test 2015-04-04 23:06:16 +06:00
e21a55abcc [extractor/common] Remove f4m section
It's now provided by `f4m_id`
2015-04-04 23:05:25 +06:00
bc03228ab5 [francetv] Improve formats extraction 2015-04-04 23:02:04 +06:00
f05d0e73c6 [francetv] Fix duration 2015-04-04 22:52:25 +06:00
aed2d4b31e [culturebox] Replace test 2015-04-04 22:50:13 +06:00
184a197441 [culturebox] Check for unavailable videos 2015-04-04 22:43:34 +06:00
ed676e8c0a [bliptv] Check format URLs
Some formats are now 404
2015-04-04 22:27:25 +06:00
8e1f937473 [aftonbladet] Modernize 2015-04-04 22:19:34 +06:00
1a68d39211 [aftonbladet] Fix extraction 2015-04-04 22:15:59 +06:00
4ba7d5b14c Merge branch 'tuexss-patch-1' 2015-04-04 20:09:36 +06:00
1a48181a9f [options] Fix load info help string 2015-04-04 20:09:11 +06:00
6b70a4eb7d [options] Number is a verb here 2015-04-04 20:02:29 +06:00
f01855813b [options] extractor is lowercase 2015-04-04 20:01:24 +06:00
4a3cdf81af [options] Restore some strings 2015-04-04 20:00:23 +06:00
f777397aca Merge branch 'patch-1' of https://github.com/tuexss/youtube-dl into tuexss-patch-1 2015-04-04 19:50:47 +06:00
8fb2e5a4f5 [radiojavan] Sort formats 2015-04-04 19:25:08 +06:00
4e8cc1e973 [radiojavan] Fix height 2015-04-04 19:24:37 +06:00
ff02a228e3 [test_execution] Fix test under python 2 @ windows 2015-04-04 19:21:50 +06:00
424266abb1 Credit @Roman2K for pornovoisines (#5264) 2015-04-04 19:16:18 +06:00
3fde134791 Merge branch 'Roman2K-pornovoisines' 2015-04-04 19:14:01 +06:00
7c39a65543 [pornovoisines] Simplify 2015-04-04 19:13:37 +06:00
8cf70de428 [test_utils] Add test for unified_strdate 2015-04-04 19:11:01 +06:00
15ac8413c7 [utils] Avoid treating *-%Y date template as UTC offset 2015-04-04 19:08:48 +06:00
79c21abba7 [utils] Add one more template to unified_strdate 2015-04-04 18:45:46 +06:00
d5c418f29f Merge branch 'pornovoisines' of https://github.com/Roman2K/youtube-dl into Roman2K-pornovoisines 2015-04-04 18:08:20 +06:00
536b94e56f Merge branch 'snipem-gamersyde' 2015-04-04 17:54:02 +06:00
5c29dbd0c7 [gamersyde] Simplify 2015-04-04 17:53:22 +06:00
ba9e68f402 [utils] Drop trailing comma before closing brace 2015-04-04 17:48:55 +06:00
e9f65f8749 [rtve] Extract a better quality video 2015-04-04 13:11:55 +02:00
ae0dd4b298 Merge branch 'gamersyde' of https://github.com/snipem/youtube-dl into snipem-gamersyde 2015-04-04 16:59:39 +06:00
f1ce35af1a Merge branch 'mtp1376-radiojavan' 2015-04-04 16:47:24 +06:00
6e617ed0b6 Credit @mtp1376 for varzesh3 and radiojavan 2015-04-04 16:47:09 +06:00
7cf97daf77 [radiojavan] Simplify and extract upload date 2015-04-04 16:45:41 +06:00
3d24d997ae Fixed intendation of test cases
Leaded to error on Linux machine
2015-04-04 12:42:14 +02:00
115c281672 [Gamersyde] Improved robustness, added duration and tests
Fix for Json syntax is now less error prone for Json syntax inside of
values. Extractor is now also using native Json handling. Added tests
for several videos that were producing errors in the first place.
2015-04-04 12:31:48 +02:00
cce23e43a9 Merge branch 'radiojavan' of https://github.com/mtp1376/youtube-dl into mtp1376-radiojavan 2015-04-04 16:10:17 +06:00
ff556f5c09 Do not encode outtmpl twice (Closes #5288) 2015-04-04 00:30:37 +06:00
16fa01291b [prosiebensat1] Fix test 2015-04-03 23:44:13 +06:00
01534bf54f [prosiebensat1] Fix bitrate (Closes #5350 closes #5351) 2015-04-03 23:42:53 +06:00
cd341b6e06 [mixcloud] Fix extraction of like count (reported in #5231) 2015-04-03 19:37:35 +02:00
185a7e25e7 [RadioJavan] Add new extractor 2015-04-03 20:55:39 +04:30
e81a474603 [Gamersyde] Add new extractor 2015-04-03 15:34:49 +02:00
ff2be6e180 [bloomberg] Adapt to website changes (fixes #5347) 2015-04-03 15:01:17 +02:00
3da4b31359 [postprocessor/ffmpeg] Fix crash when ffprobe/avprobe are not installed (closes #5349)
'self.probe_basename' was None, so 'probe_executable' raised a KeyError exception
2015-04-03 14:09:50 +02:00
4bbeb19fc7 [miomio] pep8: remove whitespaces in empty line 2015-04-03 14:09:07 +02:00
a9cbab1735 release 2015.04.03 2015-04-03 10:22:25 +02:00
6b7556a554 Credit @tiktok7 for miomio.tv (#5265) 2015-04-03 01:47:18 +06:00
a3c7019e06 [YoutubeDL] Check for get_ca_certs availability
`get_ca_certs` is not available in python <3.4
2015-04-02 22:50:10 +06:00
416b9c29f7 Merge branch 'tiktok7-MiomioTv' 2015-04-02 22:34:53 +06:00
2ec8e04cac [miomio] Fix alphabetic order 2015-04-02 22:34:08 +06:00
e03bfb30ce [miomio] Rename extractor 2015-04-02 22:33:30 +06:00
f5b669113f [miomio] Simplify and fix python 2.6 issue 2015-04-02 22:32:16 +06:00
d08225edf4 Merge branch 'MiomioTv' of https://github.com/tiktok7/youtube-dl into tiktok7-MiomioTv 2015-04-02 21:12:47 +06:00
8075d4f99d [playfm] Adapt to v2api (Closes #5344) 2015-04-02 20:26:05 +06:00
1a944d8a2a Print a warning if no ssl certificates are loaded 2015-04-02 14:09:55 +02:00
7cf02b6619 Merge branch 'mtp1376-varzesh3' 2015-04-01 22:03:35 +06:00
55cde6ef3c [varzesh3] Simplify 2015-04-01 22:02:55 +06:00
69c3af567d Merge branch 'varzesh3' of https://github.com/mtp1376/youtube-dl into mtp1376-varzesh3 2015-04-01 20:25:46 +06:00
60e1fe0079 Merge branch 'master' of github.com:rg3/youtube-dl 2015-04-01 20:25:11 +06:00
4669393070 Merge pull request #5311 from yan12125/fix_douyu
[douyutv] Fix extractor and improve error handling
2015-04-01 20:22:11 +06:00
ce3bfe5d57 Merge branch 'fix_douyu' of https://github.com/yan12125/youtube-dl 2015-04-01 19:54:00 +06:00
2a0c2ca2b8 [dailymotion] Fix ff cookie and use it for embed page (Closes #5330) 2015-03-31 20:55:21 +06:00
c89fbfb385 [nbc] Remove redundant note
This is already supposed by `only_matching`
2015-03-31 20:14:37 +06:00
facecb84a1 [generic] Add working NBC Sports vplayer test 2015-03-31 20:11:14 +06:00
ed06e9949b Merge pull request #5328 from yan12125/fix_5226
[Yahoo/NBCSports] Fix 5226 and add support for NBC sports
2015-03-31 20:00:47 +06:00
e15307a612 [NBCSports/Yahoo] Comment out some MD5 checksums
They seems to change constantly
2015-03-31 13:13:29 +08:00
5cbb2699ee [NBCSports] Add a test case for extended _VALID_URL 2015-03-31 03:38:45 +08:00
a2edf2e7ff [NBC/ThePlatform/Generic] Add a generic detector for NBCSportsVPlayer and enhance error detection in ThePlatformIE 2015-03-31 03:36:09 +08:00
1d31e7a2fc [NBCSports] Move imports alphabetically 2015-03-31 02:51:11 +08:00
a2a4d5fa31 [Yahoo/NBCSports] Generalize NBC sports info extractor 2015-03-31 02:47:18 +08:00
a28ccbabc6 [Yahoo/NBCSports] Fix #5226 2015-03-31 02:21:27 +08:00
edd7344820 [phoenix] Extend _VALID_URL (#5322) 2015-03-30 18:16:51 +03:00
c808ef81bb [soundcloud:set:user] Support mobile URLs (Closes #5323) 2015-03-30 21:03:38 +06:00
fd203fe357 Credit @jorams or dumpert.nl (#5319) 2015-03-30 20:12:55 +06:00
5bb7ab9928 Merge branch 'jorams-dumpert' 2015-03-30 20:12:09 +06:00
87270c8416 [dumpert] Simplify and fix python 3.2 2015-03-30 20:11:51 +06:00
ebc2f7a2db Merge branch 'dumpert' of https://github.com/jorams/youtube-dl into jorams-dumpert 2015-03-30 19:47:11 +06:00
7700207ec7 [pornhub] Fix comment count extraction (Closes #5320) 2015-03-30 19:41:04 +06:00
4d5d14f5cf [Dumpert] Add new extractor
Add support for the Dutch video site Dumpert. http://www.dumpert.nl/
2015-03-29 23:41:06 +02:00
72b249bf1f Merge pull request #5313 from yan12125/fix_xuite_python32
[Xuite] Fix extraction on python 3.2
2015-03-30 01:28:30 +06:00
9b4774b21b [Xuite] Fix extraction on python 3.2
base64.b64decode() accept only binary types in Python 3.2
2015-03-29 20:51:33 +08:00
2ddf083588 [douyutv] Simplify usage of isinstance 2015-03-29 18:17:48 +08:00
8343a03357 [douyutv] Fix extractor and improve error handling 2015-03-29 14:26:28 +08:00
ad320e9b83 [generic] Add support for 5min embeds (#5310) 2015-03-29 04:57:37 +03:00
ecb750a446 [cnn] Match more URLs 2015-03-28 23:39:41 +01:00
5f88e02818 [ultimedia] PEP8 2015-03-28 23:35:55 +01:00
616af2f4b9 Unduplicate @ossi96 2015-03-29 00:03:59 +06:00
5a3b315b5f [dhm] Improve _VALID_URL and add test 2015-03-28 23:55:15 +06:00
b7a2268e7b Credit @ossi96 for dhm (#5305) 2015-03-28 23:43:15 +06:00
20d729228c Merge branch 'ossi96-dhm' 2015-03-28 22:30:27 +06:00
af8c93086c [dhm] Simplify 2015-03-28 22:30:13 +06:00
79fd11ab8e Merge branch 'dhm' of https://github.com/ossi96/youtube-dl into ossi96-dhm 2015-03-28 22:09:05 +06:00
cb88671e37 [nbc] Recognize https urls (fixes #5300) 2015-03-28 14:18:11 +01:00
ff79552f13 [DHM] Add extractor description 2015-03-28 10:42:35 +01:00
643fe72717 [DHM] Add new extractor 2015-03-28 10:38:52 +01:00
4747e2183a release 2015.03.28 2015-03-28 08:12:05 +01:00
c59e701e35 Default to continuedl=True
We already do this in the CLI interface, so it should be just fine.
2015-03-28 08:11:39 +01:00
8e678af4ba Makefile: fix 'find' command
It worked with the GNU version, but not with the BSD version.
2015-03-27 14:21:53 +01:00
70a1165b32 Don't use bare 'except:'
They catch any exception, including KeyboardInterrupt, we don't want to catch it.
2015-03-27 13:02:20 +01:00
af14000215 [eroprofile] Add login support (#5269) 2015-03-26 23:24:28 +02:00
998e6cdba0 [vimeo] Capture and output error message (#5294) 2015-03-27 03:05:08 +06:00
2315fb5e5f unicde :( 2015-03-26 23:53:57 +04:30
157e9e5aa5 [youtube:watchlater] Remove unused properties and fix tests 2015-03-26 20:03:31 +01:00
c496ec0848 [vessel] Fix pep8 issue 2015-03-26 19:51:40 +01:00
15b67a268a Merge branch 'zx8-master' 2015-03-26 23:57:56 +06:00
31c4809827 [safari] Improve and simplify 2015-03-26 23:57:46 +06:00
ac0df2350a Merge branch 'master' of https://github.com/zx8/youtube-dl into zx8-master 2015-03-26 23:57:13 +06:00
223b27f46c [vessel] Add new extractor (Closes #5275) 2015-03-26 19:48:22 +02:00
425142be60 [slideshare] Fix extraction (#5279) 2015-03-26 17:47:25 +02:00
7e17ec8c71 [youtube] Clarify some IE_NAMEs 2015-03-26 21:42:28 +06:00
448830ce7b [youtube:watchlater] Extract watchlater as playlist (Closes #5280) 2015-03-26 21:41:09 +06:00
8896b614a9 removing unicode literal because it is imported :)) 2015-03-26 20:06:50 +04:30
a7fce980ad removed one of tests that made problem with testing server 2015-03-26 19:47:34 +04:30
91757b0f37 [utils] Escape all HTML entities written in hexadecimal form 2015-03-26 17:15:27 +02:00
fbfcc2972b [teamcoco] Fix extraction 2015-03-26 16:13:53 +02:00
db40364b87 [Varzesh3] Add new extractor 2015-03-26 18:17:21 +04:30
094ce39c45 Credit @amishb for 22tracks (#5276) 2015-03-25 22:27:20 +06:00
ae67d082fe [22tracks] Improve and simplify 2015-03-25 22:26:02 +06:00
8f76df7f37 Updated init to add 22tracks 2015-03-25 21:11:31 +06:00
5c19d18cbf [22Tracks] Add new extractor
Conflicts:
	youtube_dl/extractor/__init__.py
2015-03-25 21:10:54 +06:00
838b93405b [redtube] Fix test 2015-03-25 20:09:01 +06:00
2676caf344 [redtube] Capture and output removed video message (#5281) 2015-03-25 20:08:35 +06:00
17941321ab Clean up of --help output
For consistency and readability
2015-03-25 11:02:55 +01:00
48c971e073 release 2015.03.24 2015-03-24 16:39:53 +01:00
f5e2efbbf0 [options] Handle special characters in argv (Fixes #5157) 2015-03-24 16:39:46 +01:00
5d1f0e607b [MiomioTv] updated based on feedback to merge request:
1) added comment to explain extra xml link download
    2) changed {} entries to {0}, {1} etc
    3) removed redundant language header (the others are required)
    4) checked out the old version of the supported sites md (the change was
    not required)
2015-03-23 23:16:50 +01:00
b0872c19ea [npo] Skip broken URL links (Closes #5266) 2015-03-23 22:15:01 +06:00
9f790b9901 [mlb] Improve _VALID_URL (Closes #5260) 2015-03-23 21:23:57 +06:00
c41a2ec4af [MiomioTv] Add new extractor 2015-03-23 01:42:17 +01:00
575dad3c98 [pornovoisines] Add extractor 2015-03-22 20:27:45 +01:00
zx8
32d687f55e [safari] Add safaribooksonline extractor 2015-03-22 18:04:50 +00:00
93f787070f [twitch] Only match digits for the video id
Urls can also contain contain a query (for example a timestamp '?t=foo')
2015-03-22 15:39:35 +01:00
f9544f6e8f [test/aes] Test aes_decrypt_text with 256 bit 2015-03-22 12:09:58 +01:00
336d19044c [lybsyn] pep8: add space around operator 2015-03-22 11:03:52 +01:00
7866c9e173 Merge branch 'fstirlitz-the-daily-show-podcast' 2015-03-22 08:24:26 +06:00
1a4123de04 [comedycentral] Remove unused import 2015-03-22 08:23:38 +06:00
cf2e2eb1c0 [comedycentral] Drop thedailyshow podcast extractor
Generic extractor is just fine for Libsyn embeds
2015-03-22 08:23:20 +06:00
2051acdeb2 [extractor/generic] Add test for Libsyn embed 2015-03-22 08:20:27 +06:00
cefdf970cc [extractor/generic] Support Libsyn embeds 2015-03-22 08:18:13 +06:00
a1d0aa7b88 [libsyn] Fix extractor alphabetic order 2015-03-22 08:11:47 +06:00
49aeedb8cb [libsyn] Improve and simplify 2015-03-22 08:11:10 +06:00
ef249a2cd7 Merge branch 'the-daily-show-podcast' of https://github.com/fstirlitz/youtube-dl into fstirlitz-the-daily-show-podcast 2015-03-22 07:44:28 +06:00
a09141548a [nrk:playlist] Relax video id regex and improve _VALID_URL 2015-03-21 20:42:48 +06:00
5379a2d40d [test/utils] Test xpath_text 2015-03-21 14:12:43 +01:00
c9450c7ab1 [nrk:playlist] Restrict _VALID_URL
It would also match /videos/PS... urls
2015-03-21 14:00:37 +01:00
faa1b5c292 [nrk:playlist] Add extractor (Closes #5245) 2015-03-21 18:22:08 +06:00
393d9fc6d2 [nrk] Extract duration 2015-03-21 18:21:19 +06:00
4e6a228689 [nrk] Adapt to new URL format 2015-03-21 18:20:49 +06:00
179d6678b1 Remove the 'stitle' field
A warning has been printed for more than 2 years (since 97cd3afc75)
2015-03-21 12:34:44 +01:00
85698c5086 [crunchyroll] Remove unused class 2015-03-21 12:18:33 +01:00
a7d9ded45d [test] Add tests for aes 2015-03-21 12:07:23 +01:00
531980d89c [test/YoutubeDL] test match_filter 2015-03-20 17:05:28 +01:00
1887ecd4d6 [twitch] Fix login 2015-03-20 21:45:09 +06:00
cd32c2caba Merge branch 'ndac-todoroki-niconico_nm' 2015-03-20 20:53:27 +06:00
1c9a1457fc [niconico] Add nm video test 2015-03-20 20:53:14 +06:00
038b0eb1da Merge branch 'niconico_nm' of https://github.com/ndac-todoroki/youtube-dl into ndac-todoroki-niconico_nm 2015-03-20 20:52:56 +06:00
f20bf146e2 [test/YoutubeDL] split in two classes
The name was misleading
2015-03-20 15:14:25 +01:00
01218f919b [test/http] Add test for proxy support 2015-03-20 14:59:38 +01:00
2684871bc1 [vine] Fix formats extraction (Closes #5239) 2015-03-20 01:50:36 +02:00
ccf3960eec [nytimes] Improve _VALID_URL (Fixes #5238) 2015-03-19 20:55:05 +02:00
eecc0685c9 [videomega] Fix extraction and update test (Fixes #5235) 2015-03-19 19:38:03 +02:00
2ed849eccf Merge branch 'master' of github.com:rg3/youtube-dl 2015-03-19 21:27:38 +06:00
3378d67a18 [generic] Add support for nytimes embeds (Closes #5234) 2015-03-19 21:26:57 +06:00
f3c0c667a6 [nytimes] Modernize 2015-03-19 21:23:52 +06:00
0ae8bbac2d [nytimes] Support embed URL 2015-03-19 21:17:04 +06:00
cbc3cfcab4 release 2015.03.18 2015-03-18 22:02:39 +01:00
b30ef07c6c [ultimedia] Handle youtube embeds 2015-03-19 01:06:39 +06:00
73900846b1 [ultimedia] Capture and output unavailable video message 2015-03-19 00:53:26 +06:00
d1dc7e3991 [ultimedia] Fix alphabetic order 2015-03-18 23:11:48 +06:00
3073a6d5e9 [ultimedia] Add extractor
Sponsored by thankyoumotion.com
2015-03-18 23:08:18 +06:00
aae53774f2 [mixcloud] Try preview server first, then further numbers 2015-03-18 17:08:22 +01:00
7a757b7194 [mixcloud] Fix extraction of some metadata
The second test had some wrong info.
I couldn't find the timestamp, so I have removed it.
2015-03-18 17:08:19 +01:00
fa8ce26904 [mixcloud] Fix extraction like-count 2015-03-18 16:30:29 +01:00
2c2c06e359 [krasview] Fix extraction (Closes #5228) 2015-03-18 20:28:00 +06:00
ee580538fa fix nm video DL issue when logged in 2015-03-18 22:24:17 +09:00
c3c5c31517 fix nm video DL issue when logged in 2015-03-18 22:19:55 +09:00
ed9a25dd61 [generic] Generalize redirect regex 2015-03-18 00:05:40 +06:00
9ef4f12b53 testcases for libsyn and The Daily Show Podcast extractors 2015-03-17 18:54:36 +01:00
84f8101606 [generic] Follow redirects specified by Refresh HTTP header 2015-03-17 23:51:40 +06:00
b1337948eb [grooveshark] Fix extraction 2015-03-17 23:13:43 +06:00
98f02fdde2 Credit @jbuchbinder for primesharetv (#5123) 2015-03-17 22:33:05 +06:00
048fdc2292 Merge branch 'bonfy-douyutv' 2015-03-17 22:27:46 +06:00
2ca1c5aa9f [douyutv] Improve and extract all formats 2015-03-17 22:27:33 +06:00
674fb0fcc5 Merge branch 'douyutv' of https://github.com/bonfy/youtube-dl into bonfy-douyutv 2015-03-17 21:41:25 +06:00
00bfe40e4d Merge branch 'yan12125-sohu_fix' 2015-03-17 21:39:45 +06:00
cd459b1d49 [sohu] Fix test's note info 2015-03-17 21:39:31 +06:00
92a4793b3c [utils] Place sanitize url function near other sanitizing functions 2015-03-17 21:34:22 +06:00
dc03a42537 Merge branch 'sohu_fix' of https://github.com/yan12125/youtube-dl into yan12125-sohu_fix 2015-03-17 21:18:36 +06:00
219da6bb68 [megavideoeu] Remove extractor 2015-03-17 21:13:42 +06:00
0499cd866e [primesharetv] Clean up 2015-03-17 21:06:38 +06:00
13047f4135 [Primesharetv] Handle file not existing properly. 2015-03-17 20:33:32 +06:00
af69cab21d [Primesharetv] Add public domain example video 2015-03-17 20:33:24 +06:00
d41a3fa1b4 [Primesharetv] Add primeshare.tv extractor, still need test data 2015-03-17 20:33:16 +06:00
733be371af Add megavideoz.eu support. 2015-03-17 20:33:03 +06:00
576904bce6 [letv] Clarify download message 2015-03-17 20:01:31 +06:00
cf47794f09 Merge pull request #5116 from yan12125/letv_fix
[Letv] Fix test_Letv and test_Letv_1 failures in python 3
2015-03-17 19:58:34 +06:00
c06a9f8730 [arte+7] Check formats (Closes #5224) 2015-03-17 19:42:50 +06:00
2e90dff2c2 The Daily Show Podcast support 2015-03-16 20:05:02 +01:00
90183a46d8 Credit @eferro for the rtve.es:infantil extractor (#5214) 2015-03-15 22:49:03 +01:00
b68eedba23 [rtve.es:infantil] Minor fixes (closes #5214) 2015-03-15 22:18:41 +01:00
d5b559393b [rtve] Add new extractor for rtve infantil 2015-03-15 22:14:36 +01:00
1de4ac1385 release 2015.03.15 2015-03-15 19:38:50 +01:00
39aa42ffbb [ard] Capture and output time restricted videos (Closes #5213) 2015-03-16 00:21:38 +06:00
ec1b9577ba [cloudy] Fix key extraction (Closes #5211) 2015-03-15 22:42:13 +06:00
3b4444f99a Merge pull request #5208 from admire93/master
Fix mistyped docstring indent
2015-03-15 17:20:50 +06:00
613b2d9dc6 Fix mistyped docstring indent 2015-03-15 20:18:23 +09:00
8f4cc22455 [aftenposten] Adapt to new URL format 2015-03-15 10:08:14 +06:00
7c42327e0e tox.ini: Add python 3.4 2015-03-14 21:41:56 +01:00
873383e9bd tox.ini: Run the same command as 'make offlinetest' by default 2015-03-14 21:41:15 +01:00
8508557e77 [test/YoutubeDL] Use valid urls
It failed on python 3.4 when building the http_headers field
2015-03-14 20:51:42 +01:00
4d1652484f [test/unicode_literals] Don't look into the .git and .tox directories
The .tox directory contains python code that we can't control
2015-03-14 20:25:37 +01:00
88cf6fb368 [metadatafromtitle] Some improvements and cleanup
* Remove the 'songtitle' field, 'title' can be used instead.
* Remove newlines in the help text, for consistency with other options.
* Add 'from __future__ import unicode_literals'.
* Call '__init__' from the parent class.
* Add test for the format_to_regex method
2015-03-14 20:06:33 +01:00
e7db87f700 Add metadata from title parser
(Closes #5125)
2015-03-14 19:46:22 +01:00
2cb434e53e [Sohu] Fix title extraction 2015-03-15 01:05:01 +08:00
cd65491c30 [Sohu] Add a multiplart video test case 2015-03-15 00:59:49 +08:00
082b1155a3 [livestream] Extract all videos in events (fixes #5198)
The webpage only contains the most recent ones, but if you scroll down more will appear.
2015-03-14 12:06:01 +01:00
9202b1b787 [eighttracks] Remove unused import 2015-03-14 12:04:49 +01:00
a7e01c438d [8tracks] Modernize 2015-03-14 15:55:21 +06:00
05be67e77d [8tracks] Improve extraction 2015-03-14 15:54:23 +06:00
85741b9986 [8tracks] Use predefined avg duration when duration is negative (Closes #5200) 2015-03-14 15:52:06 +06:00
f247a199fe Merge pull request #5199 from MamayAlexander/yandexmusic
[yandexmusic] Site mirrors
2015-03-14 15:20:48 +06:00
29171bc2d2 [yandexmusic] Site mirrors 2015-03-14 13:56:04 +06:00
7be5a62ed7 [viewster] Improve extraction 2015-03-14 03:18:04 +06:00
3647136f24 [viewster] Add extractor 2015-03-14 02:12:11 +06:00
13598940e3 [kanalplay] Fix test 2015-03-14 01:27:21 +06:00
0eb365868e Merge branch 'djpohly-beatport-pro' 2015-03-13 22:15:00 +06:00
28c6411e49 Credit @djpohly for BeatportPro (#5189) 2015-03-13 22:14:51 +06:00
bba3fc7960 [beatenpro] Fix tests 2015-03-13 22:13:50 +06:00
fcd877013e [beatenpro] Simplify 2015-03-13 22:11:56 +06:00
ba1d4c0488 [beatenpro] Improve display_id 2015-03-13 22:03:58 +06:00
517bcca299 [beatenpro] Simplify and improve 2015-03-13 22:01:15 +06:00
1b53778175 [beatenpro] Use generic format sort 2015-03-13 21:51:49 +06:00
b7a0304d92 Merge branch 'beatport-pro' of https://github.com/djpohly/youtube-dl into djpohly-beatport-pro 2015-03-13 21:47:01 +06:00
545315a985 [nrk] Use generic subtitles timecode formatter 2015-03-13 21:40:34 +06:00
3f4327520c [kanalplay] Extract subtitles 2015-03-13 21:39:29 +06:00
4a34f69ea6 [extractor/common] Add subtitles timecode formatter 2015-03-13 21:38:28 +06:00
fb7e68833c [kanalplay] Add extractor (Closes #5188) 2015-03-13 20:51:44 +06:00
486dd09e0b [YoutubeDL] Check for bytes instead of unicode output templates (#5192)
Also adapt the embedding examples for those poor souls still using 2.x.
2015-03-13 08:40:20 +01:00
054b99a330 [jeuxvideo] Fix extraction (fixes #5190) 2015-03-12 22:33:59 +01:00
65c5e044c7 fix python2 2015-03-12 16:42:55 -04:00
11984c7467 [BeatportPro] Add new extractor
This extractor is for Beatport's 2-minute, low-quality track previews
only.  To obtain an entire track, you obviously have to purchase and
download it normally through the Beatport store!

Possible future improvements:
- Playlists for albums or other track-list pages
- User login to play from My Beatport, Hold Bin, or Cart
2015-03-12 16:03:37 -04:00
3946864c8a [vimeo] Use https for all vimeo.com urls
Unfortunately vimeopro.com doesn't support it yet.
2015-03-12 19:08:16 +01:00
b84037013e [vimeo] Fix login (#3886) 2015-03-12 18:45:00 +01:00
1dbfc62d75 Merge pull request #5186 from leleobhz/master
* Change globo.py flash ver to 17.0.0.132 - Chrome 42.0.2311.22
2015-03-12 23:37:03 +06:00
d7d79106c7 * Change globo.py flash ver to 17.0.0.132 - Chrome 42.0.2311.22 2015-03-12 14:23:42 -03:00
1138491631 [yam] Skip test 2015-03-12 21:59:46 +06:00
71705fa70d [footyroom] Add extractor (Closes #5000) 2015-03-12 21:56:56 +06:00
602814adab Merge pull request #5150 from yan12125/yam_fix
[Yam] Add an error detection and update test cases
2015-03-12 21:01:49 +06:00
3a77719c5a Don't accept '-1' as format, 'all' is clearer 2015-03-11 17:38:35 +01:00
7e195d0e92 [funnyordie] Add subtitles test 2015-03-11 22:00:37 +06:00
e04793401d Merge branch 'pishposhmcgee-master' 2015-03-11 21:56:40 +06:00
a3fbd18824 [funnyordie] Simplify subtitles 2015-03-11 21:56:22 +06:00
c6052b8c14 Merge branch 'master' of https://github.com/pishposhmcgee/youtube-dl into pishposhmcgee-master 2015-03-11 21:45:43 +06:00
c792b5011f [ssa] Add extractor (Closes #5169) 2015-03-11 21:15:36 +06:00
32aaeca775 [npo] Improve smooth stream skipping and set low preference for streams other than hds ans hls (Closes #5175) 2015-03-11 20:34:32 +06:00
1593194c63 Update funnyordie.py 2015-03-10 15:35:35 -05:00
614a7e1e23 Added subtitles for FunnyOrDie 2015-03-10 15:22:46 -05:00
2ebfeacabc [utils] Keep dot and dotdot unmodified (Closes #5171) 2015-03-10 00:50:11 +06:00
f5d8f58a17 [yandexmusic:album] Improve _VALID_URL to avoid matching tracks urls 2015-03-09 18:17:22 +01:00
937daef4a7 [niconico] Use '_match_id' 2015-03-09 18:12:41 +01:00
dd77f14c64 [yandexmusic] PEP8: remove blank line at the end of file 2015-03-09 18:07:31 +01:00
c36cbe5a8a Merge branch 'MamayAlexander-YandexMusic' 2015-03-09 21:46:44 +06:00
41b2194f86 Credit @MamayAlexander for yandexmusic (#5168) 2015-03-09 21:46:31 +06:00
d1e2e8f583 [yamusic] Rename to yandexmusic 2015-03-09 21:44:59 +06:00
47fe42e1ab [yamusic] Improve, simplify, fix python3 issues and add tests 2015-03-09 21:43:46 +06:00
4c60393854 [YandexMusic] Add new extractor 2015-03-09 19:06:49 +06:00
f848215dfc release 2015.03.09 2015-03-09 03:02:03 +01:00
dcca581967 Merge remote-tracking branch 'origin/master'
Conflicts:
	youtube_dl/YoutubeDL.py
2015-03-09 03:01:28 +01:00
d475b3384c [README] Better bug reporting instructions
Also address private emails which I get more and more these days.
2015-03-09 03:00:03 +01:00
dd7831fe94 [breakcom] Process only play purpose media formats (Closes #5164) 2015-03-09 04:55:35 +06:00
cc08b11d16 [adultswim] Improve video_info extraction (Fixes #5152)
Look for video_info inside `slugged_video`, if slug is not found among collections.
Also, simplify a bit.
2015-03-08 21:35:04 +02:00
8bba753cca [options] Rename --dump-intermediate-pages to --dump-pages for consistence with --write-pages 2015-03-08 18:37:43 +01:00
43d6280d0a [downloader/f4m] Fix use of base64 in python 3.2 (fixes #5132)
b64decode needs a byte string, but on 3.4 it also accepts strings.
2015-03-08 18:25:11 +01:00
e5a11a2293 [YoutubeDL] Sanitize path before creating non-existent paths (Closes #4324) 2015-03-08 22:09:42 +06:00
f18ef2d144 [utils] Disallow trailing dot in sanitize_path for a path part 2015-03-08 22:08:48 +06:00
1bb5c511a5 [YoutubeDL] Sanitize outtmpl as path 2015-03-08 20:57:30 +06:00
d55de57b67 [utils] Fix sanitize_open 2015-03-08 20:56:28 +06:00
a2aaf4dbc6 [utils] Add sanitize_path 2015-03-08 20:55:22 +06:00
bdf6eee0ae [gazeta] Extend _VALID_URL 2015-03-08 19:17:54 +06:00
8b910bda0c [teamcoco] Fix extraction 2015-03-08 14:28:53 +02:00
24993e3b39 [vidme] Fix view_count extraction and remove comment_count extraction (Fixes #5133)
Comment counts seem to no longer be listed on vid.me
2015-03-08 14:12:10 +02:00
11101076a1 [pladform] Fix format quality sorting 2015-03-08 18:09:47 +06:00
f838875726 [pladform] Add support for embeds 2015-03-08 18:07:10 +06:00
28778d6bae [pladform] Add extractor 2015-03-08 18:03:12 +06:00
1132eae56d [gazeta] Add new extractor (Closes #4222) 2015-03-08 13:54:01 +02:00
d34e79492d [twitch] Fix live streams (Closes #5158) 2015-03-08 16:54:11 +06:00
ab205b9dc8 Revert "[YoutubeDL] Sanitize outtmpl as it may contain forbidden characters"
This reverts commit 7dcad95d4f.

The output template is most definitly allowed to contain forbidden characters; otherwise -o /foo/bar/vid.mp4 wouldn't work.
2015-03-07 22:18:22 +01:00
7dcad95d4f [YoutubeDL] Sanitize outtmpl as it may contain forbidden characters 2015-03-08 01:13:23 +06:00
8a48223a7b [eagleplatform] Remove debug output 2015-03-07 22:35:36 +06:00
d47ae7f620 [eagleplatform] Add support for ClipYou embeds 2015-03-07 22:34:44 +06:00
135c9c42bf [eagleplatform] Add support for embeds 2015-03-07 22:22:57 +06:00
0bf79ac455 [eagleplatform] Add extractor 2015-03-07 22:16:23 +06:00
98998cded6 [youtube:search_url] Fix extraction (Closes #5155) 2015-03-07 18:59:06 +06:00
14137b5781 [orf:iptv] Add extractor (Closes #5140) 2015-03-07 17:31:03 +06:00
a172d96292 [douyutv] Add new extractor 2015-03-07 14:05:56 +08:00
23ba76bc0e [dailymotion] Replace test
It has been removed.
2015-03-06 22:45:05 +01:00
61e00a9775 [vimeo] Use https for player.vimeo.com urls (closes #5147) 2015-03-06 22:39:05 +01:00
d1508cd68d [vimeo:album] Fix password protected videos
Since it only uses https now, don't recognize http urls.
2015-03-06 22:16:26 +01:00
9c85b5376d [vimeo] Fix and use '_verify_video_password' (#5001)
It only supports verifying the password over https now.

Use it instead of manually setting the 'password' cookie because it allows to check if the password is correct.
2015-03-06 19:08:27 +01:00
3c6f245083 [vimeo] Fix upload date extraction 2015-03-06 18:16:56 +01:00
f207019ce5 [extractor/common] Remove 'm3u8' from quality selection URL 2015-03-06 22:53:53 +06:00
bd05aa4e24 [Yam] Add an error detection and update test cases 2015-03-07 00:53:52 +08:00
8dc9d361c2 [extractor/common] Fix format_id when last_media is None and always include m3u8_id if present
The rationale behind `m3u8_id` was to resolve duplicates when processing several m3u8 playlists within the same media that give equal resulting `format_id`'s,
e.g. `youtube-dl http://www.rts.ch/play/tv/passe-moi-les-jumelles/video/la-fee-des-bois-mustang-les-chemins-du-vent?id=3854925 -F`
2015-03-06 22:52:50 +06:00
d0e958c71c [twitch:vod] Prefer source stream (Fixes #5143) 2015-03-06 10:53:49 +01:00
a0bb7c5593 [extractor/common] Improve m3u format IDs (#5143) 2015-03-06 10:49:42 +01:00
7feddd9fc7 [travis] Declare 3.2 (Fixes #5144) 2015-03-06 10:44:24 +01:00
55969016e9 [utils] Add a function to sanitize consecutive slashes in URLs 2015-03-06 12:43:49 +08:00
9609f02e3c [vidme] Modernize 2015-03-05 22:34:56 +01:00
5c7495a194 [sohu] Correct wrong imports 2015-03-06 02:48:27 +08:00
5ee6fc974e [sohu] Fix info extractor and add tests 2015-03-06 02:43:39 +08:00
c2ebea6580 [extremetube] Fix extraction (Closes #5127) 2015-03-05 14:45:38 +02:00
12a129ec6d [playwire] Add extractor 2015-03-05 02:36:53 +06:00
f28fe66970 [downloader/http] Add missing fields for _hook_progress call
It would fail if you run 'youtube-dl --no-part URL' a second time when the file has already been downloaded.

(Reported in Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=1195779)
2015-03-04 12:14:38 +01:00
123397317c [downloader/http] Remove wrong '_hook_progress' call (fixes #5117) 2015-03-03 18:45:56 +01:00
dc570c4951 [lrt] Pass --realtime to rtmpdump 2015-03-03 18:41:34 +02:00
22d3628319 [tvplay] Adapt _VALID_URL and test case to domain name change 2015-03-03 18:39:28 +02:00
50c9949d7a [youporn] Imrove JSON regex and preserve the old one 2015-03-03 21:39:04 +06:00
376817c6d4 Merge pull request #5115 from chaos33/youporn-json
fix youporn extractor's json search regex
2015-03-03 21:32:13 +06:00
63fc800057 [Letv] Fix test_Letv and test_Letv_1 failures in python 3 2015-03-03 23:20:55 +08:00
e0d0572b73 fix youporn extractor's json search regex 2015-03-03 22:53:05 +08:00
7fde87c77d release 2015.03.03.1 2015-03-03 13:59:38 +01:00
938c3f65b6 Merge branch 'cn-verification-proxy' 2015-03-03 13:57:29 +01:00
2461f79d2a [utils] Correct per-request proxy handling 2015-03-03 13:56:06 +01:00
499bfcbfd0 Make sure netrc works for all extractors with login support
Fixes #5112
2015-03-03 12:59:17 +01:00
07490f8017 release 2015.03.03 2015-03-03 00:05:05 +01:00
91410c9bfa [letv] Add --cn-verification-proxy (Closes #5077) 2015-03-03 00:03:06 +01:00
a7440261c5 [utils] Streap leading dots
Fixes #2865, closes #5087
2015-03-02 19:07:19 +01:00
76c73715fb [generic] Parse RSS enclosure URLs (Fixes #5091) 2015-03-02 18:21:31 +01:00
c75f0b361a [downloader/external] Add support for custom options (Fixes #4885, closes #5098) 2015-03-02 18:21:31 +01:00
295df4edb9 [soundcloud] Fix glitches (#5101) 2015-03-02 22:47:07 +06:00
562ceab13d [soundcloud] Check direct links validity (Closes #5101) 2015-03-02 22:39:32 +06:00
2f0f6578c3 [extractor/common] Assume non HTTP(S) URLs valid 2015-03-02 22:38:44 +06:00
30cbd4e0d6 [lynda] Completely skip videos we don't have access to, extract base class and modernize (Closes #5093) 2015-03-02 22:12:10 +06:00
549e58069c Merge pull request #5105 from Ftornik/Lynda-subtitle-hotfix-2
[lynda] Check for the empty subtitles
2015-03-02 21:15:26 +06:00
7594be85ff [lynda] Check for the empty subtitle 2015-03-02 11:49:39 +02:00
3630034609 [vk] Fix test (Closes #5100) 2015-03-02 03:30:18 +06:00
4e01501bbf [vk] Fix extraction (Closes #4967, closes #4686) 2015-03-01 21:56:30 +06:00
1aa5172f56 [vk] Catch temporarily unavailable video error message 2015-03-01 21:55:43 +06:00
f7e2ee8fa6 Merge branch 'master' of github.com:rg3/youtube-dl 2015-03-01 12:05:13 +01:00
66dc9a3701 [README] Document HTTP 429 (Closes #5092) 2015-03-01 12:04:39 +01:00
31bd39256b --load-info: Use the fileinput module
It automatically handles the '-' filename as stdin
2015-03-01 11:54:48 +01:00
003c69a84b Use shutil.get_terminal_size for getting the terminal width if it's available (python >= 3.3) 2015-02-28 21:44:57 +01:00
0134901108 release 2015.02.28 2015-02-28 21:24:25 +01:00
eee6293d57 [thechive] remove in favor of Kaltura (#5072) 2015-02-28 20:55:49 +01:00
8237bec4f0 [escapist] Extract duration 2015-02-28 20:52:52 +01:00
29cad7ad13 Merge remote-tracking branch 'origin/master' 2015-02-28 20:51:54 +01:00
0d103de3b0 [twitch] Pass api_token along with every request (Closes #3986) 2015-02-28 22:59:55 +06:00
a0090691d0 Merge branch 'HanYOLO-puls4' 2015-02-28 22:26:35 +06:00
6c87c2eea8 [puls4] Improve and extract more metadata 2015-02-28 22:25:57 +06:00
58c2ec6ab3 Merge branch 'puls4' of https://github.com/HanYOLO/youtube-dl 2015-02-28 21:39:10 +06:00
df5ae3eb16 [oppetarkiv] Merge with svtplay 2015-02-28 21:25:04 +06:00
efda2d7854 Merge branch 'thc202-oppetarkiv' 2015-02-28 21:12:23 +06:00
e143f5dae9 [oppetarkiv] Extract f4m formats and age limit 2015-02-28 21:12:06 +06:00
48218cdb97 Merge branch 'oppetarkiv' of https://github.com/thc202/youtube-dl into thc202-oppetarkiv 2015-02-28 20:41:56 +06:00
e9fade72f3 Add postprocessor for converting subtitles (closes #4954) 2015-02-28 14:43:24 +01:00
0f2c0d335b [YoutubeDL] Use the InfoExtractor._download_webpage method for getting the subtitles
It handles encodings better, for example for 'http://www.npo.nl/nos-journaal/14-02-2015/POW_00942207'
2015-02-28 14:03:27 +01:00
40b077bc7e [oppetarkiv] Add new extractor
Some, if not all, of the videos appear to be geo-blocked (Sweden).
Test might fail (403 Forbidden) if not run through a Swedish connection.
2015-02-27 22:27:30 +00:00
a931092cb3 Merge branch 'puls4' of https://github.com/HanYOLO/youtube-dl into HanYOLO-puls4 2015-02-28 00:22:48 +06:00
bd3749ed69 [kaltura] Extend _VALID_URL (Closes #5081) 2015-02-28 00:19:31 +06:00
4ffbf77886 [odnoklassniki] Add extractor (Closes #5075) 2015-02-28 00:15:03 +06:00
781a7ef60a [lynda] Use 'lstrip' for the subtitles
The newlines at the end are important, they separate each piece of text.
2015-02-27 16:18:18 +01:00
5b2949ee0b Merge pull request #5076 from Ftornik/Lynda-subtitles-hotfix
[lynda] Fixed subtitles broken file
2015-02-27 20:56:54 +06:00
a0d646135a [lynda] Extend _VALID_URL 2015-02-27 20:56:06 +06:00
7862ad88b7 puls4 Add new extractor 2015-02-27 15:41:58 +01:00
f3bff94cf9 [rtve] Extract duration 2015-02-27 12:24:51 +01:00
0eba1e1782 [lynda] Fixed subtitles broken file 2015-02-27 00:51:22 +02:00
e3216b82bf [generic] Support dynamic Kaltura embeds (#5016) (#5073) 2015-02-27 00:34:19 +02:00
da419e2332 [musicvault] Use the Kaltura extractor 2015-02-26 23:47:45 +02:00
0d97ef43be [kaltura] Add new extractor 2015-02-26 23:45:54 +02:00
1a2313a6f2 [TheChiveIE] added support for TheChive.com (Closes #5016) 2015-02-27 02:36:45 +10:30
250a9bdfe2 [mpora] Improve _VALID_URL 2015-02-26 21:16:35 +06:00
6317a3e9da [mpora] Fix extraction 2015-02-26 21:10:49 +06:00
7ab7c9e932 [gamestar] Fix title extraction 2015-02-26 16:22:05 +02:00
e129c5bc0d [laola1tv] Allow live stream downloads 2015-02-26 14:35:48 +02:00
2e241242a3 Adding subtitles 2015-02-26 03:59:35 -06:00
9724e5d336 release 2015.02.26.2 2015-02-26 09:45:11 +01:00
63a562f95e [escapist] Detect IP blocking and use another UA (Fixes #5069) 2015-02-26 09:19:26 +01:00
5c340b0387 release 2015.02.26.1 2015-02-26 01:47:16 +01:00
1c6510f57a [Makefile] clean pyc files in clean target 2015-02-26 01:47:12 +01:00
2a15a98a6a [rmtp] Encode filename before invoking subprocess
This fixes #5066.
Reproducible with
LC_ALL=C youtube-dl "http://www.prosieben.de/tv/germanys-next-topmodel/video/playlist/ganze-folge-episode-2-das-casting-in-muenchen"
2015-02-26 01:44:20 +01:00
72a406e7aa [extractor/common] Pass in video_id (#5057) 2015-02-26 01:35:43 +01:00
feccc3ff37 Merge remote-tracking branch 'aajanki/wdr_live' 2015-02-26 01:34:01 +01:00
265bfa2c79 [letv] Simplify 2015-02-26 01:30:18 +01:00
8faf9b9b41 Merge remote-tracking branch 'yan12125/IE_Letv' 2015-02-26 01:26:55 +01:00
84be7c230c Cred @duncankl for airmozilla 2015-02-26 01:25:54 +01:00
3e675fabe0 [airmozilla] Be more tolerant when nonessential items are missing (#5030) 2015-02-26 01:25:00 +01:00
cd5b4b0bc2 Merge remote-tracking branch 'duncankl/airmozilla' 2015-02-26 01:15:08 +01:00
7ef822021b Merge remote-tracking branch 'mmue/fix-rtlnow' 2015-02-26 01:13:03 +01:00
9a48926a57 [escapist] Add support for advertisements 2015-02-26 00:59:53 +01:00
13cd97f3df release 2015.02.26 2015-02-26 00:42:02 +01:00
183139340b [utils] Bump our user agent 2015-02-26 00:40:12 +01:00
1c69bca258 [escapist] Fix config URL matching 2015-02-26 00:24:54 +01:00
c10ea454dc [telecinco] Recognize more urls (closes #5065) 2015-02-25 23:52:54 +01:00
9504fc21b5 Fix the RTL extractor for new episodes by using a different hostname 2015-02-25 23:27:19 +01:00
13d8fbef30 [generic] Don't set the 'title' if it's not defined in the entry (closes #5061)
Some of them may be an 'url' result, which in general don't have the 'title' field.
2015-02-25 17:56:51 +01:00
b8988b63a6 [wdr] Download a live stream 2015-02-24 21:23:59 +02:00
5eaaeb7c31 [f4m] Tolerate missed fragments on live streams 2015-02-24 21:22:59 +02:00
c4f8c453ae [f4m] Refresh fragment list periodically on live streams 2015-02-24 21:22:59 +02:00
6f4ba54079 [extractor/common] Extract HTTP (possibly f4m) URLs from a .smil file 2015-02-24 21:22:59 +02:00
637570326b [extractor/common] Extract the first of a seq of videos in a .smil file 2015-02-24 21:22:59 +02:00
37f885650c [eporner] Simplify and hardcode age limit 2015-02-25 01:08:54 +06:00
c8c34ccb20 Merge pull request #5056 from logon84/master
Eporner Fix (Closes #5050)
2015-02-25 01:05:35 +06:00
e765ed3a9c [eporner] Fix redirect_code error 2015-02-24 19:41:46 +01:00
677063594e [Letv] Update testcases 2015-02-25 02:10:55 +08:00
59c7cbd482 Update eporner.py
Updated to work. Old version shows an error about being unable to extract "redirect_code"
2015-02-24 18:58:32 +01:00
570311610e [Letv] Add playlist support 2015-02-25 01:26:44 +08:00
41b264e77c [nrktv] Workaround subtitles conversion issues on python 2.6 (Closes #5036) 2015-02-24 23:06:44 +06:00
df4bd0d53f [options] Add --yes-playlist as inverse of --no-playlist (Fixes #5051) 2015-02-24 17:25:02 +01:00
7f09a662a0 [Letv] Add new extractor. Single video only 2015-02-24 23:58:21 +08:00
4f3b21e1c7 release 2015.02.24.2 2015-02-24 16:34:42 +01:00
54233c9080 [escapist] Support JavaScript player (Fixes #5034) 2015-02-24 16:33:07 +01:00
db8e13ef71 release 2015.02.24.1 2015-02-24 11:38:21 +01:00
5a42414b9c [utils] Prevent hyphen at beginning of filename (Fixes #5035) 2015-02-24 11:38:01 +01:00
9c665ab72e [rtve] PEP8 2015-02-24 11:37:27 +01:00
b665ba6aa6 release 2015.02.24 2015-02-24 11:24:26 +01:00
ec5913b5cd [bloomberg] Modernize 2015-02-24 11:08:00 +01:00
25ac63ed71 [rtve] Extract subtitles 2015-02-23 23:04:07 +01:00
99209c2916 [youtube] Extract UL playlists as mixes (Closes #5040) 2015-02-24 01:35:15 +06:00
1fbaa0a521 [laola1tv] Use raw strings for regular expressions
Oops
2015-02-23 20:51:30 +02:00
3037b91e05 [laola1tv] Improve extraction and update test case (#3742) 2015-02-23 20:45:52 +02:00
ffdf972b91 [facebook] Extract all the formats (closes #5037) 2015-02-23 18:54:15 +01:00
459e5fbd5f release 2015.02.23.1 2015-02-23 18:17:39 +01:00
bfc993cc91 Merge branch 'subtitles-rework'
(Closes PR #4964)
2015-02-23 17:13:03 +01:00
4432db35d9 [gdcvault] Restore akamai host for rtmp videos 2015-02-23 21:59:11 +06:00
591ab1dff9 [soundgasm] PEP8 2015-02-23 16:51:21 +01:00
5bca2424bc [gdcvault] Remove dead code 2015-02-23 16:51:09 +01:00
bd61a9e770 release 2015.02.23 2015-02-23 16:47:19 +01:00
3438e7acd2 [soundgasm] Remove unused import 2015-02-23 21:40:50 +06:00
09c200acf2 Credit @skypher for chirbit and soundgasm:profile (#5032) 2015-02-23 21:31:57 +06:00
716889cab1 Merge branch 'skypher-chirbit' 2015-02-23 21:30:46 +06:00
409693984f [soundgasm:profile] Fix _VALID_URL 2015-02-23 21:30:30 +06:00
04e8c11080 [chirbit] Clarify extractors' IE_NAMEs 2015-02-23 21:28:14 +06:00
80af2b73ab [soundgasm] Clarify extractors' IE_NAMEs 2015-02-23 21:27:56 +06:00
3cc57f9645 [soundgasm:profile] Simplify 2015-02-23 21:27:24 +06:00
a65d4e7f14 [chirbit] Simplify and extract profile from RSS (#5032) 2015-02-23 21:15:16 +06:00
b531cfc019 [YoutubeDL] remove compatiblity with the old subtitles system 2015-02-23 16:12:35 +01:00
543ec2136b Merge branch 'chirbit' of https://github.com/skypher/youtube-dl into skypher-chirbit 2015-02-23 19:21:25 +06:00
93b5071f73 [soundgasm] add profile IE. 2015-02-23 12:11:19 +01:00
ddc369f073 [chirbit] fix profile downloader regex. 2015-02-23 12:00:43 +01:00
1b40dc92eb [airmozilla] Add new extractor 2015-02-23 16:10:08 +13:00
fcc3e6138b [r7] Add extractor (Closes #4405, closes #5004) 2015-02-23 03:32:53 +06:00
9fe6ef7ab2 [extractor/common] Fix preference for m3u8 quality selection URL 2015-02-23 03:30:10 +06:00
c010af6f19 [escapist] Make regexes more robust (Closes #5028) 2015-02-22 23:11:33 +06:00
35b7982303 [appletrailers] Add test (#5027) 2015-02-22 19:58:39 +06:00
f311cfa231 [appletrailers] Extend _VALID_URL (Closes #5027) 2015-02-22 19:53:32 +06:00
80970e531b [test/subtitles] Update checksum for Viki 2015-02-22 11:52:22 +01:00
b7bb76df05 [test/subtitles] Remove some tests
Test only with 'allsubtitles', the language selection is already tested in test_YoutubeDL.py
2015-02-22 11:51:57 +01:00
98c70d6fc7 [YoutubeDL] only add normal subtitles to the 'requested_subtitles' field if 'writesubtitles' is True 2015-02-22 11:37:27 +01:00
ab84349b16 [test/YoutubeDL] Add test for subtitles
Updated the offlinetest make target to not skip it
2015-02-22 11:29:56 +01:00
03091e372f [ted] Always extract the subtitles
The required info is already in the webpage
2015-02-22 00:27:59 +01:00
4d17184817 [YoutubeDL] don't set the 'requested_subtitles' without writesubtitles or writeautomaticsub 2015-02-22 00:27:49 +01:00
e086e0eb6c release 2015.02.21 2015-02-21 21:25:29 +01:00
314368c822 [teamcoco] Fix extraction
Also, use a single style of quotes
2015-02-21 22:19:39 +02:00
c5181ab410 [gdcvault] Fix rtmp streams (Closes #5024) 2015-02-22 02:10:26 +06:00
ea5152cae1 [zapiks] Extend _VALID_URL (#5014) 2015-02-22 01:42:47 +06:00
255fca5eea [generic] Add support for Zapiks embeds (#5014) 2015-02-22 01:39:26 +06:00
4aeccadf4e [zapiks] Add extractor (#5014) 2015-02-22 01:38:57 +06:00
93540ee10e [rtve] Fix the video url
Changing mvod to mvod1 fixes the url, we don't need to add the query.
2015-02-21 19:31:39 +01:00
8fb3ac3649 PEP8: W503 2015-02-21 14:55:13 +01:00
77b2986b5b [extractor/common] Recognize Indian censorship (#5021) 2015-02-21 14:51:07 +01:00
62b013df0d [vimeo] Encode password before hash calculation 2015-02-21 18:31:10 +06:00
fad6768bd1 [vimeo] Fix password protected videos (Closes #5001) 2015-02-21 18:00:25 +06:00
a78125f925 Merge pull request #5019 from cyberjacob/master
Change example URLs in readme (fixes #5018)
2015-02-20 23:56:56 +01:00
a00a8bcc8a Change example URLs in readme (fixes #5018y) 2015-02-20 22:43:51 +00:00
1e9a9e167d release 2015.02.20 2015-02-20 23:23:12 +01:00
3da0db62e6 [escapist] Fix extraction (fixes #5017) 2015-02-20 23:22:47 +01:00
e14ced7918 Merge branch 'master' of github.com:rg3/youtube-dl 2015-02-20 23:20:14 +01:00
ab9d02f53b Merge branch 'minusf-TED_code' 2015-02-21 00:14:51 +06:00
a461a11989 [ted] Improve external video handling and add test 2015-02-21 00:14:38 +06:00
1bd838608f prefer 'code' to 'uri' if present 2015-02-20 18:24:20 +01:00
365577f567 [chirbit] add profile extractor. 2015-02-20 14:48:12 +01:00
50efb383f0 [tv4] Add new extractor (Closes #4839) (Closes #2103) 2015-02-20 14:13:41 +02:00
5da6bd0083 [chirbit] Add new extractor. 2015-02-20 10:49:45 +01:00
5e9a033e6e [imgur] Allow alternative values
Every now and then, imgur.com goes crazy and gives us a generic title and description (otherwise it looks all fine though).
Simply update the test case to allow for that craziness.
2015-02-20 02:52:03 +01:00
fb7cb6823e Remove the SubtitlesInfoExtractor class
No longer needed
2015-02-19 23:24:24 +01:00
dd0a58f5f0 [blinkx] Fix extraction 2015-02-20 01:19:38 +06:00
a21420389e release 2015.02.19.3 2015-02-19 19:28:17 +01:00
6140baf4e1 [nationalgeographic] Add extractor (closes #4960) 2015-02-19 18:17:31 +01:00
8fc642eb5b [pornhub] Fix uploader regex 2015-02-19 22:15:49 +06:00
e66e1a0046 [pornhub] Add support for playlists (Closes #4995) 2015-02-19 22:15:19 +06:00
d5c69f1da4 [5min] Cover joystiq.com URLs (Closes #4962) 2015-02-19 21:47:11 +06:00
f13b1e7d7f [bbccouk] Convert to new subtitles system
I haven't found any video available outside the UK, so I haven't added tests.

I have updated how the srt file is build, because (at least for www.bbc.co.uk/programmes/p02j9b69) the subtitles is inside 'span' elements.
2015-02-19 16:46:41 +01:00
5c8a3f862a [nbc] Use a test video that works outside the US 2015-02-19 15:00:39 +01:00
8807f1277f [theplatform] Convert to new subtitles system 2015-02-19 14:54:50 +01:00
a3b9157f49 [cbssports] Add extractor (closes #4996) 2015-02-19 13:06:53 +01:00
b88ba05356 [imgur] Simplify 2015-02-19 05:53:09 +01:00
b74d505577 Merge remote-tracking branch 'jbboehr/imgur-gifv-improvements' 2015-02-19 05:16:11 +01:00
9e2d7dca87 [imgur] improve error check for non-video URLs 2015-02-18 19:47:54 -08:00
d236b37ac9 [imgur] improve regex #4998 2015-02-18 19:28:19 -08:00
e880c66bd8 [theonion] Modernize 2015-02-19 04:12:40 +01:00
383456aa29 [Makefile] Also delete *.avi files in clean 2015-02-19 04:09:52 +01:00
1a13940c8d [imgur] support regular URL 2015-02-18 18:12:48 -08:00
3d54788495 [webofstories] Fix extraction 2015-02-19 02:12:08 +01:00
71d53ace2f [sockshare] Do not require thumbnail anymore
Thumbnail is not present on the website anymore.
2015-02-19 02:04:30 +01:00
f37e3f99f0 [generic] Correct test case
Video has been reuploaded / edited
2015-02-19 02:00:52 +01:00
bd03ffc16e [netzkino] Skip download in test case
Works fine from Germany, but fails from everywhere else
2015-02-19 01:58:54 +01:00
1ac1af9b47 release 2015.02.19.2 2015-02-19 01:43:28 +01:00
3bf5705316 [imgur] Add new extractor 2015-02-19 01:43:20 +01:00
1c2528c8a3 [cbs] Modernize 2015-02-19 01:22:50 +01:00
7bd15b1a03 release 2015.02.19.1 2015-02-19 01:04:24 +01:00
6b961a85fd [patreon] Add support for embedlies (fixes #4969) 2015-02-19 01:04:19 +01:00
7707004043 [patreon] Modernize 2015-02-19 00:38:05 +01:00
a025d3c5a5 release 2015.02.19 2015-02-19 00:31:23 +01:00
c460bdd56b [sandia] Add new extractor (#4974) 2015-02-19 00:31:01 +01:00
b81a359eb6 [YoutubeDL] Use render_table for format listing 2015-02-19 00:28:58 +01:00
d61aefb24c Merge remote-tracking branch 'origin/master' 2015-02-19 00:01:14 +01:00
d305dd73a3 [utils] Fix js_to_json
Previously, the runtime could be atrocious for longer inputs.
2015-02-18 23:59:51 +01:00
93a16ba238 [vimeo] Raise the ExtractorError with expected=True when no video password is given 2015-02-18 22:00:12 +01:00
4f7cea6c53 [viki] Convert to new subtitles system 2015-02-18 20:37:16 +01:00
afbdd3acc3 [rai] Convert to new subtitles system 2015-02-18 20:14:42 +01:00
85d5866177 [yahoo] Remove md5sum from test case
The md5 sum has changed repeatedly, and we check whether it looks like a video anyways nowadays.
2015-02-18 20:03:04 +01:00
9789d7535d [xtube] Fix test case 2015-02-18 19:58:41 +01:00
d8443cd3f7 [wsj] Correct test case 2015-02-18 19:56:24 +01:00
d47c26e168 [brightcove] Correct keys in playlists 2015-02-18 19:56:10 +01:00
01561da142 [nrk] Convert to new subtitles system 2015-02-18 18:57:01 +01:00
0af25f784b [mtv] Convert to new subtitles system 2015-02-18 18:27:45 +01:00
b9b42f2ea0 [npo] Convert to new subtitles system 2015-02-18 17:57:10 +01:00
311c393838 [lynda] Convert to new subtitles system 2015-02-18 17:46:33 +01:00
18c1c42405 [drtv] Convert to new subtitles system 2015-02-18 17:20:22 +01:00
37dd5d4629 [mit] Don't set the subtitles field
YouTube already provides them in more formats
2015-02-18 17:19:56 +01:00
81975f4693 release 2015.02.18.1 2015-02-18 10:54:56 +01:00
b8b928d5cb [README] Add an FAQ entry for the player change in anticipation of many more bug reports 2015-02-18 10:54:45 +01:00
3eff81fbf7 [jsinterp] Disable comment support
We need a proper lexer to be able to understand YouTube's code, which contains /* inside of strings.
For now it's sufficient to just disable comment support altogether.

Fixes #4976, fixes #4979, fixes #4980, fixes #4981, fixes #4982.
Closes #4977.
2015-02-18 10:47:42 +01:00
785521bf4f [youtube] Remove useless if 2015-02-18 10:42:23 +01:00
6d1a55a521 [youtube] Show entire player URL when -v is given 2015-02-18 10:39:14 +01:00
9cad27008b release 2015.02.18 2015-02-18 00:49:34 +01:00
11e611a7fa Extend various playlist tests 2015-02-18 00:49:10 +01:00
72c1f8de06 [bandcamp:album] Fix extractor results and associated test 2015-02-18 00:48:52 +01:00
6e99868e4c [buzzfeed] Fix playlist test case 2015-02-18 00:41:45 +01:00
4d278fde64 [ign] Amend playlist test 2015-02-18 00:38:55 +01:00
f21e915fb9 [test/helper] Render info_dict with a final comma 2015-02-18 00:38:42 +01:00
6f53c63df6 [test/helper] Only output a newline for forgotten keys if keys are really missing 2015-02-18 00:37:54 +01:00
1def5f359e [livestream] Correct playlist ID and add a test for it 2015-02-18 00:34:45 +01:00
15ec669374 [vk] Amend playlist test 2015-02-18 00:33:41 +01:00
a3fa5da496 [vimeo] Amend playlist tests 2015-02-18 00:33:31 +01:00
30965ac66a [vimeo] Prevent infinite loops if video password verification fails
We're seeing this in the tests¹ right now, which do not terminate.

¹  https://travis-ci.org/jaimeMF/youtube-dl/jobs/51135858
2015-02-18 00:27:58 +01:00
09ab40b7d1 Merge branch 'progress-as-hook2' 2015-02-17 23:41:48 +01:00
edab9dbf4d [YoutubeDL] use the 'render_table' function for listing the subtitles 2015-02-17 22:59:19 +01:00
9868ea4936 [extractor/common] Simplify subtitles handling methods
Initially I was going to use a single method for handling both subtitles and automatic captions, that's why I used the 'list_subtitles' and the 'subtitles' variables.
2015-02-17 22:16:29 +01:00
85920dd01d [bliptv] Convert to new subtitles system 2015-02-17 21:56:25 +01:00
fa15607773 PEP8 fixes 2015-02-17 21:46:20 +01:00
a91a2c1a83 [downloader] Remove various unneeded assignments and imports 2015-02-17 21:44:41 +01:00
16e7711e22 [downloader/http] Remove gruesome import 2015-02-17 21:42:31 +01:00
5cda4eda72 [YoutubeDL] Use a progress hook for progress reporting
Instead of every downloader calling two helper functions, let our progress report be an ordinary progress hook like everyone else's.
Closes #4875.
2015-02-17 21:40:35 +01:00
98f000409f [radio.de] Fix extraction 2015-02-17 21:40:09 +01:00
bd7fe0cf66 [walla] Convert to new subtitles system 2015-02-17 21:23:09 +01:00
48246541da [ceskatelevize] Convert to new subtitles system 2015-02-17 21:17:47 +01:00
4a8d4a53b1 [videolecturesnet] Fix rtmp stream glitches (Closes #4968) 2015-02-18 01:16:49 +06:00
4cd95bcbc3 [twitch:stream] Prefer the 'source' format (fixes #4972) 2015-02-17 18:57:01 +01:00
be24c8697f release 2015.02.17.2 2015-02-17 17:38:31 +01:00
0d93378887 [videolecturesnet] Check http format URLs (Closes #4968) 2015-02-17 22:35:27 +06:00
4069766c52 [extractor/common] Test URLs with GET 2015-02-17 22:35:27 +06:00
7010577720 release 2015.02.17.1 2015-02-17 17:35:08 +01:00
8ac27a68e6 [hls] Switch to available as a property 2015-02-17 17:35:03 +01:00
46312e0b46 release 2015.02.17 2015-02-17 17:29:32 +01:00
f9216ed6ad Merge remote-tracking branch 'origin/master' 2015-02-17 17:28:51 +01:00
65bf37ef83 [ffmpeg] Remove trivial helper method 2015-02-17 17:27:29 +01:00
f740fae2a4 [ffmpeg] Make available a property 2015-02-17 17:26:41 +01:00
fbc503d696 [downloader/hls] Fix detection of ffmpeg/avconv (reported in #4966) 2015-02-17 16:40:42 +01:00
662435f728 [YoutubeDL] Use a Request object for getting the cookies (fixes #4970)
So that we don't have to implement all the methods used by the cookiejar.
2015-02-17 16:29:24 +01:00
163d966707 [downloader/external] curl: Add the '--location' flag
curl doesn't follow redirections by default
2015-02-17 16:21:02 +01:00
85729c51af [downloader] Add --hls-prefer-native to use the native HLS downloader (#4966) 2015-02-17 12:09:12 +01:00
360e1ca5cc [youtube] Convert to new subtitles system
The automatic captions are stored in the 'automactic_captions' field, which is used if no normal subtitles are found for an specific language.
2015-02-16 22:47:39 +01:00
a1f2a06b34 [dailymotion] Convert to new subtitles system 2015-02-16 21:51:08 +01:00
c84dd8a90d [YoutubeDL] store the subtitles to download in the 'requested_subtitles' field
We need to keep the orginal subtitles information, so that the '--load-info' option can be used to list or select the subtitles again.
We'll also be able to have a separate field for storing the automatic captions info.
2015-02-16 21:51:08 +01:00
65469a7f8b [vimeo] Convert to new subtitles system
Removed some tests, the behaviour should be checked in a test for the YoutubeDL class
2015-02-16 21:51:07 +01:00
6b597516c1 [atresplayer] Convert to new subtitles system 2015-02-16 21:51:07 +01:00
b5857f62e2 [crunchyroll] Convert to new subtitles system 2015-02-16 21:51:07 +01:00
a504ced097 Improve subtitles support
For each language the extractor builds a list with the available formats sorted (like for video formats), then YoutubeDL selects one of them using the '--sub-format' option which now allows giving the format preferences (for example 'ass/srt/best').
For each format the 'url' field can be set so that we only download the contents if needed, or if the contents needs to be processed (like in crunchyroll) the 'data' field can be used.

The reasons for this change are:
* We weren't checking that the format given with '--sub-format' was available, checking it in each extractor would be repetitive.
* It allows to easily support giving a format preference.
* The subtitles were automatically downloaded in the extractor, but I think that if you use for example the '--dump-json' option you want to finish as fast as possible.

Currently only the ted extractor has been updated, but the old system still works.
2015-02-16 21:51:03 +01:00
1db5fbcfe3 release 2015.02.16.1 2015-02-16 15:47:13 +01:00
59b8ab5834 [rtlnl|generic] Add support for rtl.nl embeds (Fixes #4959) 2015-02-16 15:45:45 +01:00
a568180441 release 2015.02.16 2015-02-16 04:51:20 +01:00
85e80f71cd [yam] Allow faults in optional fields (#4943) 2015-02-16 04:50:57 +01:00
bfa6bdcd8b Merge remote-tracking branch 'yan12125/IE_Yam' 2015-02-16 04:44:28 +01:00
03cd72b007 [extractor/common] Move up filesize
filesize and tbr should correlate, so it doesn't make sense to treat them differently.
2015-02-16 04:39:22 +01:00
5bfd430f81 Merge remote-tracking branch 'origin/master' 2015-02-16 04:09:10 +01:00
73fac4e911 [ffmpeg] Add --ffmpeg-location 2015-02-16 04:05:53 +01:00
8fb474fb17 [test/subtitles] Fix some tests
The checksym for the CeskaTelevize subtitles has changed again, so we just test that it has a reasonable length.
2015-02-15 15:01:07 +01:00
f813928e4b [bbccouk] Fix fallback to legacy playlist 2015-02-15 16:32:38 +06:00
b9c7a97318 [history] Add extractor (Closes #4934) 2015-02-15 04:57:52 +06:00
9fb2f1cd6d [theplatform] Add URL sign capability 2015-02-15 04:56:12 +06:00
6ca7732d5e [extractor/common] Fix link to external documentation 2015-02-14 22:20:24 +01:00
b0ab0fac49 Remove unused imports 2015-02-14 22:19:58 +01:00
a294bce82f [streamcz] Fix extraction (Closes #4940) 2015-02-14 17:48:04 +02:00
76d1466b08 [drtuber] Add one more title regex 2015-02-14 18:50:13 +06:00
1888d3f7b3 Merge pull request #4951 from peugeot/beeg
[beeg] fix test
2015-02-14 18:46:49 +06:00
c2787701cc Merge pull request #4950 from peugeot/drtuber
[drtuber] fix extraction
2015-02-14 18:46:43 +06:00
52e1d0ccc4 [beeg] fix test 2015-02-14 13:42:42 +01:00
10e3c4c221 [drtuber] fix extraction 2015-02-14 13:40:35 +01:00
68f2d273bf [sunporno] Keep old video regex just in case 2015-02-14 18:33:52 +06:00
7c86c21662 Merge pull request #4949 from peugeot/sunporno
[sunporno] fix extraction
2015-02-14 18:32:18 +06:00
ae1580d790 [sunporno] fix extraction 2015-02-14 13:29:44 +01:00
3215c50f25 Credit @ryandesign for nbcnews nightly news (#4948) 2015-02-14 17:44:24 +06:00
36f73e8044 Merge branch 'ryandesign-nbc-nightly-news' 2015-02-14 17:42:32 +06:00
a4f3d779db [nbcnews] Simplify 2015-02-14 17:42:12 +06:00
d9aa2b784d Support NBC Nightly News broadcasts 2015-02-14 04:10:23 -06:00
cffcbc02de [postprocessor/ffmpeg] Don't let ffmpeg read from stdin (fixes #4945)
If you run 'while read aurl ; do youtube-dl --extract-audio "${aurl}"; done < path_to_batch_file'  (batch_file contains one url per line) each call to youtube-dl consumed some characters and 'read' would assing to 'aurl' a non valid url, something like 'tube.com/watch?v=<id>'.
2015-02-13 22:25:34 +01:00
9347fddbfc [1tv] Cover arbitraty URLs 2015-02-14 02:04:28 +06:00
037e9437e4 [camdemy] Fix _VALID_URL 2015-02-13 20:10:42 +06:00
36e7a4ca2e [test/subtitles] Update checksums 2015-02-13 14:43:50 +01:00
ae6423d704 [bambuser] Fix 'uploader_id' extraction (fixes #4944) 2015-02-13 11:36:33 +01:00
7105440cec [Yam] Add new extractor 2015-02-13 15:14:23 +08:00
c80b9cd280 Merge branch 'robin007bond-nporadio' 2015-02-13 01:37:27 +06:00
171ca612af [npo:radio] Move to extractor to common npo place and add extractor for fragments 2015-02-13 01:36:54 +06:00
c3d64fc1b3 [nporadio] Edit to confirm to flake8 standards 2015-02-12 19:28:58 +01:00
7c24ce225d [NPORadio] Added extractor for live radio 2015-02-12 19:19:55 +01:00
08b38d5401 [camdemy] Simplify and make more robust (#4938)
Do not throw errors if view count or upload date extraction fails.
Dispose of re.MULTILINE, which had absolutely no effect without any ^ or $ in sight.
Follow PEP8 naming conventions.
2015-02-12 08:55:06 +01:00
024c53694d Merge remote-tracking branch 'yan12125/IE_camdemy' 2015-02-12 08:44:39 +01:00
7e6011101f [camdemy] Python2 compatibility 2015-02-12 14:23:25 +08:00
c40feaba77 [camdemy] Add support for folders 2015-02-12 14:13:19 +08:00
5277f09dfc release 2015.02.11 2015-02-11 19:02:39 +01:00
2d30521ab9 [youtube] Extract average rating (closes #2362) 2015-02-11 18:39:31 +01:00
050fa43561 flake8: Ignore some error added in pep8 1.6
* E402: we exectute code between imports, like modifying 'sys.path' in the tests
* E731: we assign to lambdas in a lot of places, we may want to consider defining functions in a single line instead (what pep8 recommends)
2015-02-11 18:15:15 +01:00
f36f92f4da [aes] style: Put __all__ variable at the end of the file 2015-02-11 18:15:15 +01:00
124f3bc67d [dotsub] Fix extraction and modernize 2015-02-11 22:33:03 +06:00
d304209a85 [test/parameters.json] Set 'fixup' to 'never'
The fixed audio files for Youtube have a size lower that the minimum required.
2015-02-11 17:25:04 +01:00
8367d3f3cb [camdemy] Detection of external sources 2015-02-12 00:11:33 +08:00
c56d7d899d [dctptv] Skip rtmp download 2015-02-11 22:10:33 +06:00
ea5db8469e [canalplus] Add support for itele.fr URLs (Closes #4931) 2015-02-11 16:21:52 +02:00
3811c567e7 [teamcoco] Fix video id extraction 2015-02-11 15:47:19 +02:00
8708d76425 [camdemy] Add new extractor
Single file download done, while folder extaction in plan
2015-02-11 16:39:15 +08:00
054fe3cc40 [ntvru] Adapt to new direct delivery and modernize (Closes #4918) 2015-02-10 21:35:34 +06:00
af0d11f244 release 2015.02.10.5 2015-02-10 15:56:04 +01:00
9650885be9 [escapist] Filter video differently (Fixes #4919) 2015-02-10 15:55:51 +01:00
596ac6e31f [escapist] Modernize 2015-02-10 15:45:36 +01:00
612ee37365 release 2015.02.10.4 2015-02-10 11:28:34 +01:00
442c37b7a9 [YoutubeDL] Do not perform filter matching on partial results (Fixes #4921) 2015-02-10 11:28:28 +01:00
04bbe41330 release 2015.02.10.3 2015-02-10 05:42:47 +01:00
8f84f57183 [ccc] Add new extractor (Fixes #4890) 2015-02-10 05:42:41 +01:00
6a78740211 [test/test_youtube_signature] Use fake YDL 2015-02-10 05:28:59 +01:00
c0e1a415fd [firstpost] Modernize 2015-02-10 05:28:48 +01:00
bf8f082a90 [vimeo:album] Add support for album passwords (Fixes #4917) 2015-02-10 04:53:21 +01:00
2f543a2142 [options] Add alias --dump-header for --print-traffic 2015-02-10 04:52:33 +01:00
7e5db8c930 [options] Add --no-color 2015-02-10 04:22:10 +01:00
f7a211dcc8 [pornhd] Fix extraction (fixes #4915) 2015-02-10 03:41:31 +01:00
845734773d release 2015.02.10.2 2015-02-10 03:32:55 +01:00
347de4931c [YoutubeDL] Add generic video filtering (Fixes #4916)
This functionality is intended to eventually encompass the current format filtering.
2015-02-10 03:32:24 +01:00
8829650513 release 2015.02.10.1 2015-02-10 01:46:09 +01:00
c73fae1e2e [commonmistakes] Detect BOMs at the beginning of URLs
Reported at https://bugzilla.redhat.com/show_bug.cgi?id=1093517 .
2015-02-10 01:40:55 +01:00
834bf069d2 [bandcamp] Correct variable name 2015-02-10 01:37:14 +01:00
c06a9fa34f Use snake_case instead of camelCase 2015-02-10 01:36:38 +01:00
753fad4adc [commonmistakes] Correct logic error 2015-02-10 01:34:01 +01:00
34814eb66e release 2015.02.10 2015-02-10 01:19:52 +01:00
3a5bcd0326 [extractor/common] Wrap extractor errors (Fixes #1194)
For now, we just wrap some common errors. More may follow. We do not want to catch actual programming errors in the extractors, such as 1 // 0.
2015-02-10 01:17:23 +01:00
99c2398bc6 [bandcamp] Use our API to get more stable error messages (#1194) 2015-02-09 19:08:51 +01:00
28f1272870 [svtplay] Correct test case 2015-02-09 16:05:01 +01:00
f18e3a2fc0 release 2015.02.09.3 2015-02-09 15:59:19 +01:00
c4c5dc27cb Merge branch 'master' of github.com:rg3/youtube-dl 2015-02-09 15:59:14 +01:00
2caf182f37 [trilulilu] Add support for videos without category in the URL (Closes #4067)
Also, update the testcase, detect private/country restricted videos and modernize a bit.
2015-02-09 17:00:05 +02:00
43f244b6d5 [YoutubeDL] Do not show worst in --list-formats output
Nobody wants to know what the worst possible format is. And if they do, they can still provide -f worst.
2015-02-09 15:57:42 +01:00
1309b396d0 [svtplay] Add new extractor (Fixes #4914) 2015-02-09 15:56:59 +01:00
ba61796458 [youtube] Don't override format info from the dash manifest (fixes #4911) 2015-02-09 15:04:22 +01:00
3255fe7141 release 2015.02.09.2 2015-02-09 14:46:30 +01:00
e98b8e79ea [generic] Improve SBS detection (Fixes #4899) 2015-02-09 14:46:10 +01:00
196121c51b release 2015.02.09.1 2015-02-09 10:49:10 +01:00
5269028951 [rtlnow] Add test for @mmue's extension (#4908) 2015-02-09 10:47:19 +01:00
f7bc056b5a Merge remote-tracking branch 'mmue/fix-rtlnow' 2015-02-09 10:44:55 +01:00
a0f7198544 [generic] Add support for jwPlayer YouTube videos
This makes nationalarchives.gov.uk work (Fixes #4907, fixes #4876)
2015-02-09 10:43:01 +01:00
dd8930684e release 2015.02.09 2015-02-09 10:28:16 +01:00
bdb186f3b0 fix rtlnow for newer series like "Der Bachelor" season 5 2015-02-08 21:55:39 +01:00
64f9baa084 [options] Mention asr as possible filter 2015-02-09 01:35:16 +06:00
b29231c040 release 2015.02.08 2015-02-08 20:28:38 +01:00
6128bf07a9 [options] Update help on string comparisons 2015-02-09 01:27:27 +06:00
2ec19e9558 [YoutubeDL] Allow filtering by audio sampling rate 2015-02-09 01:09:45 +06:00
9ddb6925bf [YoutubeDL] Allow filtering by string properties (#4906) 2015-02-09 01:07:43 +06:00
12931e1c6e Credit @robin007bond for tweakers (#4881) and gamekings fixes (#4901) 2015-02-08 23:33:29 +06:00
41c23b0da5 [gamekings] Support videos from news pages 2015-02-08 23:12:59 +06:00
2578ab19e4 Merge branch 'robin007bond-gamekings' 2015-02-08 23:03:31 +06:00
d87ec897e9 [gamekings] Improve extraction 2015-02-08 23:03:12 +06:00
3bd4bffb1c Merge branch 'gamekings' of https://github.com/robin007bond/youtube-dl into robin007bond-gamekings 2015-02-08 22:46:43 +06:00
c36b09a502 [Gamekings] Use thumbnail in return statement 2015-02-08 16:46:13 +01:00
641eb10d34 Use _family_friendly_search for determining age_limit 2015-02-08 17:45:38 +02:00
955c5505e7 [Gamekings] Use xpath
XPath is used for extracting the video url and the thumbnail
2015-02-08 16:44:25 +01:00
69319969de [extractor/common] Add new helper method _family_friendly_search 2015-02-08 17:39:00 +02:00
a14292e848 [soulanime] Remove extractor (#4554)
Was supposed to be deleted by 67c2bcd
2015-02-08 16:57:07 +02:00
5d678df64a [Gamekings] Download playlist
Todo: URL and Thumbnail should be extracted with XPath
2015-02-08 15:34:37 +01:00
8ca8cbe2bd [Gamekings] Check string for vimeo, fix test
The test now doesn't fail anymore. It just checks the string for having
"vimeo" in it, instead of using the method for URL-checking, since it's
returns an error.

The tests don't fail, and the extractor works fine now.
2015-02-08 14:41:14 +01:00
ba322d8209 [Gamekings] Added test and replaced video_url
Quick and dirty fix for the Gamekings extractor. It gives an error about
the video_url, but it downloads it now instead of giving a 404 error on
newer Gamekings videos
2015-02-08 14:23:37 +01:00
2f38289b79 [Gamekings] Fix order of replacement string
Oops.
2015-02-08 13:49:32 +01:00
f23a3ca699 [Gamekings] Fixed typo in URL replacement 2015-02-08 13:47:27 +01:00
77d2b106cc [Gamekings] Fix 404 when large isn't available
When trying to download some GameKings videos, not all worked. This was
because not all videos had a "/large"-URL available. The extractor
checks now if the /large URL is available, if it isn't, it tries to get
the normal URL.
2015-02-08 13:42:41 +01:00
c0e46412e9 [aparat] Fix extraction (Closes #4897) 2015-02-08 17:30:29 +06:00
0161353d7d [test/test_YoutubeDL] Remove debug print call 2015-02-06 23:58:01 +01:00
2b4ecde2c8 [test/YoutubeDL] Add a simple test for postprocesors
Just checks that the 'keepvideo' option works as intended.
2015-02-06 23:54:25 +01:00
b3a286d69d [YoutubeDL] _calc_cookies: add get_header method to _PseudoRequest (#4861) 2015-02-06 22:23:06 +01:00
467d3c9a0c [ffmpeg] --extrac-audio: Use the same options for avconv and ffmpeg
They have been available in ffmpeg since version 0.9, and we require 1.0 or higher.
2015-02-06 22:05:11 +01:00
ad5747bad1 [rtp] Construct regular HTTP download URLs (#4882) 2015-02-06 23:00:54 +02:00
d6eb66ed3c [aftenposten] Add extractor (Closes #4863) 2015-02-07 01:46:54 +06:00
7f2a9f1b49 [tvigle] Add support for cloud URLs (Closes #4887) 2015-02-06 21:15:01 +06:00
1e1896f2de [extractor/common] Correct sort order.
We should look at height and width before ext_preference.
2015-02-06 15:16:45 +01:00
c831973366 release 2015.02.06 2015-02-06 14:38:30 +01:00
1a2548d9e9 [rtp] Pass --realtime to rtmpdump (Fixes #4882)
A workaround for video jumping back in time.
2015-02-06 13:44:46 +02:00
3900eec27c [extractor/common] Fix 2.0 manifest extraction (Closes #4830) 2015-02-06 04:29:29 +06:00
a02d212638 Merge branch 'robin007bond-tweakers' 2015-02-06 03:23:56 +06:00
9c91a8fa70 [tweakers] Switch extraction to xspf playlist, extract all formats and meta (#4881) 2015-02-06 03:23:42 +06:00
41469f335e Merge branch 'tweakers' of https://github.com/robin007bond/youtube-dl into robin007bond-tweakers 2015-02-06 02:59:33 +06:00
67ce4f8820 Use match_id method instead of splitted URL 2015-02-05 21:49:13 +01:00
bc63d56cca Remove unnecessary TODO-comments 2015-02-05 21:40:18 +01:00
c893d70805 Remove player-url in tweakers.py
Player-url only needed for rmftp, not for regular URLs
2015-02-05 21:38:35 +01:00
3ee6e02564 Edit Tweakers extractor
Fixed code conventions (mainly adding two or more spaces before making
an inline comment)
2015-02-05 19:59:36 +01:00
e3aaace400 [tweakers] Add new extractor 2015-02-05 19:55:41 +01:00
300753a069 [YoutubeDL] Fix video+audio format field (Closes #4880) 2015-02-06 00:51:16 +06:00
f13b88c616 [rts] Fix f4m and m3u8 extraction (Closes #4873) 2015-02-05 22:17:50 +06:00
60ca389c64 [extractor/common] Prefix f4m/m3u8 entries with identifier 2015-02-05 22:16:27 +06:00
1b0f3919c1 Merge branch 'Frenzie-npo' 2015-02-05 20:15:13 +06:00
6a348cf7d5 Credit @Frenzie for npo subtitles (#4878) 2015-02-05 20:14:56 +06:00
9e91449c8d [npo] Fix subtitles (Closes #3638) 2015-02-05 20:13:28 +06:00
25e5ebf382 Add NPO.nl subtitles
Implements #3638
2015-02-05 12:51:33 +01:00
7dfc356625 release 2015.02.04 2015-02-04 16:09:35 +01:00
58ba6c0160 [mixcloud] Fix extraction (Closes #4862) 2015-02-04 19:47:55 +06:00
f076b63821 [generic/ooyala] Add support for Ooyala embeds on SBN network websites (Fixes #4859) 2015-02-04 15:33:37 +02:00
12f0454cd6 [README] Add an FAQ entry about anime sites 2015-02-03 14:18:15 +01:00
cd7342755f release 2015.02.03.1 2015-02-03 10:59:27 +01:00
9bb8e0a3f9 [wsj] Add new extractor (Fixes #4854) 2015-02-03 10:58:28 +01:00
1a6373ef39 [sort_formats] Prefer bitrate over video size
720p @ 1000KB/s looks way better than 1080p @ 500KB/s
2015-02-03 10:53:07 +01:00
f6c24009be [YoutubeDL] Calculate thumbnail IDs automatically 2015-02-03 10:52:22 +01:00
d862042301 [aftonbladet] Modernize 2015-02-03 10:18:32 +01:00
23d9ded655 [franceculture] Rewrite for new HTML scheme (Fixes #4853) 2015-02-03 10:17:13 +01:00
4c1a017e69 release 2015.02.03 2015-02-03 00:22:52 +01:00
ee623d9247 [descripts/release] Regenerate auxiliary documentation on build as well 2015-02-03 00:22:17 +01:00
330537d08a [README] typo 2015-02-03 00:20:57 +01:00
2cf0ecac7b [ffmpeg] --add-metadata: Set comment and purl fields (Fixes #4847) 2015-02-03 00:16:45 +01:00
d200b11c7e [Makefile] Simplify clean/cleanall 2015-02-03 00:14:42 +01:00
d0eca21021 release 2015.02.02.5 2015-02-02 23:47:19 +01:00
c1147c05e1 [brightcove] Fix up more generically invalid XML (Fixes #4849) 2015-02-02 23:47:14 +01:00
55898ad2cf release 2015.02.02.4 2015-02-02 23:39:03 +01:00
a465808592 Merge branch 'master' of github.com:rg3/youtube-dl 2015-02-02 23:38:54 +01:00
5c4862bad4 [normalboots] Remove unused import 2015-02-02 23:38:45 +01:00
995029a142 [nerdist] Add new extractor (Fixes #4851) 2015-02-02 23:38:35 +01:00
a57b562cff [nfl] Add support for articles pages (fixes #4848) 2015-02-02 23:17:00 +01:00
531572578e [normalboots] Modernize 2015-02-02 23:04:39 +01:00
3a4cca687f release 2015.02.02.3 2015-02-02 22:56:15 +01:00
7d3d06a16c [vevo] Restore SMIL support (#3656) 2015-02-02 22:48:12 +01:00
c21b1fbeeb release 2015.02.02.2 2015-02-02 21:58:58 +01:00
f920ce295e [ntvru] Remove unused import 2015-02-02 21:58:17 +01:00
7a7bd19c45 [n-tv.de] Use native m3u8 as best format 2015-02-02 21:57:48 +01:00
8f4b58d70e [ntvde] Add new extractor (Fixes #4850) 2015-02-02 21:48:54 +01:00
3fd45e03bf [ntvru] Rename from NTV to clarify the difference between n-tv.de and ntv.ru 2015-02-02 20:43:02 +01:00
390 changed files with 23302 additions and 6574 deletions

View File

@ -2,6 +2,7 @@ language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
before_install:

29
AUTHORS
View File

@ -108,3 +108,32 @@ Enam Mijbah Noor
David Luhmer
Shaya Goldberg
Paul Hartmann
Frans de Jonge
Robin de Rooij
Ryan Schmidt
Leslie P. Polzer
Duncan Keall
Alexander Mamay
Devin J. Pohly
Eduardo Ferro Aldama
Jeff Buchbinder
Amish Bhadeshia
Joram Schrijver
Will W.
Mohammad Teimori Pabandi
Roman Le Négrate
Matthias Küch
Julian Richen
Ping O.
Mister Hat
Peter Ding
jackyzy823
George Brighton
Remita Amine
Aurélio A. Heckert
Bernhard Minks
sceext
Zach Bruggeman
Tjark Saul
slangangular
Behrouz Abbasi

View File

@ -1,4 +1,6 @@
Please include the full output of the command when run with `--verbose`. The output (including the first lines) contain important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
**Please include the full output of youtube-dl when run with `-v`**.
The output (including the first lines) contain important debugging information. Issues without the full output are often not reproducible and therefore do not get solved in short order, if ever.
Please re-read your issue once again to avoid a couple of common mistakes (you can and should use this as a checklist):
@ -16,7 +18,9 @@ If your report is shorter than two lines, it is almost certainly missing some of
For bug reports, this means that your report should contain the *complete* output of youtube-dl when called with the -v flag. The error message you get for (most) bugs even says so, but you would not believe how many of our bug reports do not contain this information.
Site support requests **must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
If your server has multiple IPs or you suspect censorship, adding --call-home may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
### Are you using the latest version?
@ -122,7 +126,7 @@ If you want to add support for a new site, you can follow this quick list (assum
5. Add an import in [`youtube_dl/extractor/__init__.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/__init__.py).
6. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test, then rename ``_TEST`` to ``_TESTS`` and make it into a list of dictionaries. The tests will be then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc.
7. Have a look at [`youtube_dl/common/extractor/common.py`](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should return](https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/common.py#L38). Add tests and code for as many as you want.
8. If you can, check the code with [pyflakes](https://pypi.python.org/pypi/pyflakes) (a good idea) and [pep8](https://pypi.python.org/pypi/pep8) (optional, ignore E501).
8. If you can, check the code with [flake8](https://pypi.python.org/pypi/flake8).
9. When the tests pass, [add](http://git-scm.com/docs/git-add) the new files and [commit](http://git-scm.com/docs/git-commit) them and [push](http://git-scm.com/docs/git-push) the result, like this:
$ git add youtube_dl/extractor/__init__.py

View File

@ -1,10 +1,8 @@
all: youtube-dl README.md CONTRIBUTING.md README.txt youtube-dl.1 youtube-dl.bash-completion youtube-dl.zsh youtube-dl.fish supportedsites
clean:
rm -rf youtube-dl.1.temp.md youtube-dl.1 youtube-dl.bash-completion README.txt MANIFEST build/ dist/ .coverage cover/ youtube-dl.tar.gz youtube-dl.zsh youtube-dl.fish *.dump *.part *.info.json CONTRIBUTING.md.tmp
cleanall: clean
rm -f youtube-dl youtube-dl.exe
rm -rf youtube-dl.1.temp.md youtube-dl.1 youtube-dl.bash-completion README.txt MANIFEST build/ dist/ .coverage cover/ youtube-dl.tar.gz youtube-dl.zsh youtube-dl.fish *.dump *.part *.info.json *.mp4 *.flv *.mp3 *.avi CONTRIBUTING.md.tmp youtube-dl youtube-dl.exe
find . -name "*.pyc" -delete
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
@ -46,7 +44,7 @@ test:
ot: offlinetest
offlinetest: codetest
nosetests --verbose test --exclude test_download --exclude test_age_restriction --exclude test_subtitles --exclude test_write_annotations --exclude test_youtube_lists
nosetests --verbose test --exclude test_download.py --exclude test_age_restriction.py --exclude test_subtitles.py --exclude test_write_annotations.py --exclude test_youtube_lists.py
tar: youtube-dl.tar.gz

567
README.md
View File

@ -5,6 +5,7 @@ youtube-dl - download videos from youtube.com or other video platforms
- [OPTIONS](#options)
- [CONFIGURATION](#configuration)
- [OUTPUT TEMPLATE](#output-template)
- [FORMAT SELECTION](#format-selection)
- [VIDEO SELECTION](#video-selection)
- [FAQ](#faq)
- [DEVELOPER INSTRUCTIONS](#developer-instructions)
@ -16,12 +17,12 @@ youtube-dl - download videos from youtube.com or other video platforms
To install it right away for all UNIX users (Linux, OS X, etc.), type:
sudo curl https://yt-dl.org/latest/youtube-dl -o /usr/local/bin/youtube-dl
sudo chmod a+x /usr/local/bin/youtube-dl
sudo chmod a+rx /usr/local/bin/youtube-dl
If you do not have curl, you can alternatively use a recent wget:
sudo wget https://yt-dl.org/downloads/latest/youtube-dl -O /usr/local/bin/youtube-dl
sudo chmod a+x /usr/local/bin/youtube-dl
sudo chmod a+rx /usr/local/bin/youtube-dl
Windows users can [download a .exe file](https://yt-dl.org/latest/youtube-dl.exe) and place it in their home directory or any other location on their [PATH](http://en.wikipedia.org/wiki/PATH_%28variable%29).
@ -45,347 +46,218 @@ which means you can modify it, redistribute it or use it however you like.
youtube-dl [OPTIONS] URL [URL...]
# OPTIONS
-h, --help print this help text and exit
--version print program version and exit
-U, --update update this program to latest version. Make
sure that you have sufficient permissions
(run with sudo if needed)
-i, --ignore-errors continue on download errors, for example to
skip unavailable videos in a playlist
--abort-on-error Abort downloading of further videos (in the
playlist or the command line) if an error
occurs
--dump-user-agent display the current browser identification
--list-extractors List all supported extractors and the URLs
they would handle
--extractor-descriptions Output descriptions of all supported
extractors
--default-search PREFIX Use this prefix for unqualified URLs. For
example "gvsearch2:" downloads two videos
from google videos for youtube-dl "large
apple". Use the value "auto" to let
youtube-dl guess ("auto_warning" to emit a
warning when guessing). "error" just throws
an error. The default value "fixup_error"
repairs broken URLs, but emits an error if
this is not possible instead of searching.
--ignore-config Do not read configuration files. When given
in the global configuration file /etc
/youtube-dl.conf: Do not read the user
configuration in ~/.config/youtube-
dl/config (%APPDATA%/youtube-dl/config.txt
on Windows)
--flat-playlist Do not extract the videos of a playlist,
only list them.
-h, --help Print this help text and exit
--version Print program version and exit
-U, --update Update this program to latest version. Make sure that you have sufficient permissions (run with sudo if needed)
-i, --ignore-errors Continue on download errors, for example to skip unavailable videos in a playlist
--abort-on-error Abort downloading of further videos (in the playlist or the command line) if an error occurs
--dump-user-agent Display the current browser identification
--list-extractors List all supported extractors
--extractor-descriptions Output descriptions of all supported extractors
--force-generic-extractor Force extraction to use the generic extractor
--default-search PREFIX Use this prefix for unqualified URLs. For example "gvsearch2:" downloads two videos from google videos for youtube-dl "large apple".
Use the value "auto" to let youtube-dl guess ("auto_warning" to emit a warning when guessing). "error" just throws an error. The
default value "fixup_error" repairs broken URLs, but emits an error if this is not possible instead of searching.
--ignore-config Do not read configuration files. When given in the global configuration file /etc/youtube-dl.conf: Do not read the user configuration
in ~/.config/youtube-dl/config (%APPDATA%/youtube-dl/config.txt on Windows)
--flat-playlist Do not extract the videos of a playlist, only list them.
--no-color Do not emit color codes in output
## Network Options:
--proxy URL Use the specified HTTP/HTTPS proxy. Pass in
an empty string (--proxy "") for direct
connection
--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)
--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)
--cn-verification-proxy URL Use this proxy to verify the IP address for some Chinese sites. The default proxy specified by --proxy (or none, if the options is
not present) is used for the actual downloading. (experimental)
## Video Selection:
--playlist-start NUMBER playlist video to start at (default is 1)
--playlist-end NUMBER playlist video to end at (default is last)
--playlist-items ITEM_SPEC playlist video items to download. Specify
indices of the videos in the playlist
seperated by commas like: "--playlist-items
1,2,5,8" if you want to download videos
indexed 1, 2, 5, 8 in the playlist. You can
specify range: "--playlist-items
1-3,7,10-13", it will download the videos
at index 1, 2, 3, 7, 10, 11, 12 and 13.
--match-title REGEX download only matching titles (regex or
caseless sub-string)
--reject-title REGEX skip download for matching titles (regex or
caseless sub-string)
--playlist-start NUMBER Playlist video to start at (default is 1)
--playlist-end NUMBER Playlist video to end at (default is last)
--playlist-items ITEM_SPEC Playlist video items to download. Specify indices of the videos in the playlist separated by commas like: "--playlist-items 1,2,5,8"
if you want to download videos indexed 1, 2, 5, 8 in the playlist. You can specify range: "--playlist-items 1-3,7,10-13", it will
download the videos at index 1, 2, 3, 7, 10, 11, 12 and 13.
--match-title REGEX Download only matching titles (regex or caseless sub-string)
--reject-title REGEX Skip download for matching titles (regex or caseless sub-string)
--max-downloads NUMBER Abort after downloading NUMBER files
--min-filesize SIZE Do not download any videos smaller than
SIZE (e.g. 50k or 44.6m)
--max-filesize SIZE Do not download any videos larger than SIZE
(e.g. 50k or 44.6m)
--date DATE download only videos uploaded in this date
--datebefore DATE download only videos uploaded on or before
this date (i.e. inclusive)
--dateafter DATE download only videos uploaded on or after
this date (i.e. inclusive)
--min-views COUNT Do not download any videos with less than
COUNT views
--max-views COUNT Do not download any videos with more than
COUNT views
--no-playlist If the URL refers to a video and a
playlist, download only the video.
--age-limit YEARS download only videos suitable for the given
age
--download-archive FILE Download only videos not listed in the
archive file. Record the IDs of all
downloaded videos in it.
--include-ads Download advertisements as well
(experimental)
--min-filesize SIZE Do not download any videos smaller than SIZE (e.g. 50k or 44.6m)
--max-filesize SIZE Do not download any videos larger than SIZE (e.g. 50k or 44.6m)
--date DATE Download only videos uploaded in this date
--datebefore DATE Download only videos uploaded on or before this date (i.e. inclusive)
--dateafter DATE Download only videos uploaded on or after this date (i.e. inclusive)
--min-views COUNT Do not download any videos with less than COUNT views
--max-views COUNT Do not download any videos with more than COUNT views
--match-filter FILTER Generic video filter (experimental). Specify any key (see help for -o for a list of available keys) to match if the key is present,
!key to check if the key is not present,key > NUMBER (like "comment_count > 12", also works with >=, <, <=, !=, =) to compare against
a number, and & to require multiple matches. Values which are not known are excluded unless you put a question mark (?) after the
operator.For example, to only match videos that have been liked more than 100 times and disliked less than 50 times (or the dislike
functionality is not available at the given service), but who also have a description, use --match-filter "like_count > 100 &
dislike_count <? 50 & description" .
--no-playlist Download only the video, if the URL refers to a video and a playlist.
--yes-playlist Download the playlist, if the URL refers to a video and a playlist.
--age-limit YEARS Download only videos suitable for the given age
--download-archive FILE Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.
--include-ads Download advertisements as well (experimental)
## Download Options:
-r, --rate-limit LIMIT maximum download rate in bytes per second
(e.g. 50K or 4.2M)
-R, --retries RETRIES number of retries (default is 10), or
"infinite".
--buffer-size SIZE size of download buffer (e.g. 1024 or 16K)
(default is 1024)
--no-resize-buffer do not automatically adjust the buffer
size. By default, the buffer size is
automatically resized from an initial value
of SIZE.
-r, --rate-limit LIMIT Maximum download rate in bytes per second (e.g. 50K or 4.2M)
-R, --retries RETRIES Number of retries (default is 10), or "infinite".
--buffer-size SIZE Size of download buffer (e.g. 1024 or 16K) (default is 1024)
--no-resize-buffer Do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.
--playlist-reverse Download playlist videos in reverse order
--xattr-set-filesize (experimental) set file xattribute
ytdl.filesize with expected filesize
--external-downloader COMMAND (experimental) Use the specified external
downloader. Currently supports
aria2c,curl,wget
--xattr-set-filesize Set file xattribute ytdl.filesize with expected filesize (experimental)
--hls-prefer-native Use the native HLS downloader instead of ffmpeg (experimental)
--external-downloader COMMAND Use the specified external downloader. Currently supports aria2c,curl,httpie,wget
--external-downloader-args ARGS Give these arguments to the external downloader
## Filesystem Options:
-a, --batch-file FILE file containing URLs to download ('-' for
stdin)
--id use only video ID in file name
-o, --output TEMPLATE output filename template. Use %(title)s to
get the title, %(uploader)s for the
uploader name, %(uploader_id)s for the
uploader nickname if different,
%(autonumber)s to get an automatically
incremented number, %(ext)s for the
filename extension, %(format)s for the
format description (like "22 - 1280x720" or
"HD"), %(format_id)s for the unique id of
the format (like Youtube's itags: "137"),
%(upload_date)s for the upload date
(YYYYMMDD), %(extractor)s for the provider
(youtube, metacafe, etc), %(id)s for the
video id, %(playlist_title)s,
%(playlist_id)s, or %(playlist)s (=title if
present, ID otherwise) for the playlist the
video is in, %(playlist_index)s for the
position in the playlist. %(height)s and
%(width)s for the width and height of the
video format. %(resolution)s for a textual
description of the resolution of the video
format. %% for a literal percent. Use - to
output to stdout. Can also be used to
download to a different directory, for
example with -o '/my/downloads/%(uploader)s
/%(title)s-%(id)s.%(ext)s' .
--autonumber-size NUMBER Specifies the number of digits in
%(autonumber)s when it is present in output
filename template or --auto-number option
is given
--restrict-filenames Restrict filenames to only ASCII
characters, and avoid "&" and spaces in
filenames
-A, --auto-number [deprecated; use -o
"%(autonumber)s-%(title)s.%(ext)s" ] number
downloaded files starting from 00000
-t, --title [deprecated] use title in file name
(default)
-l, --literal [deprecated] alias of --title
-w, --no-overwrites do not overwrite files
-c, --continue force resume of partially downloaded files.
By default, youtube-dl will resume
downloads if possible.
--no-continue do not resume partially downloaded files
(restart from beginning)
--no-part do not use .part files - write directly
into output file
--no-mtime do not use the Last-modified header to set
the file modification time
--write-description write video description to a .description
file
--write-info-json write video metadata to a .info.json file
--write-annotations write video annotations to a .annotation
file
--load-info FILE json file containing the video information
(created with the "--write-json" option)
--cookies FILE file to read cookies from and dump cookie
jar in
--cache-dir DIR Location in the filesystem where youtube-dl
can store some downloaded information
permanently. By default $XDG_CACHE_HOME
/youtube-dl or ~/.cache/youtube-dl . At the
moment, only YouTube player files (for
videos with obfuscated signatures) are
cached, but that may change.
-a, --batch-file FILE File containing URLs to download ('-' for stdin)
--id Use only video ID in file name
-o, --output TEMPLATE Output filename template. Use %(title)s to get the title, %(uploader)s for the uploader name, %(uploader_id)s for the uploader
nickname if different, %(autonumber)s to get an automatically incremented number, %(ext)s for the filename extension, %(format)s for
the format description (like "22 - 1280x720" or "HD"), %(format_id)s for the unique id of the format (like YouTube's itags: "137"),
%(upload_date)s for the upload date (YYYYMMDD), %(extractor)s for the provider (youtube, metacafe, etc), %(id)s for the video id,
%(playlist_title)s, %(playlist_id)s, or %(playlist)s (=title if present, ID otherwise) for the playlist the video is in,
%(playlist_index)s for the position in the playlist. %(height)s and %(width)s for the width and height of the video format.
%(resolution)s for a textual description of the resolution of the video format. %% for a literal percent. Use - to output to stdout.
Can also be used to download to a different directory, for example with -o '/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s' .
--autonumber-size NUMBER Specify the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given
--restrict-filenames Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames
-A, --auto-number [deprecated; use -o "%(autonumber)s-%(title)s.%(ext)s" ] Number downloaded files starting from 00000
-t, --title [deprecated] Use title in file name (default)
-l, --literal [deprecated] Alias of --title
-w, --no-overwrites Do not overwrite files
-c, --continue Force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.
--no-continue Do not resume partially downloaded files (restart from beginning)
--no-part Do not use .part files - write directly into output file
--no-mtime Do not use the Last-modified header to set the file modification time
--write-description Write video description to a .description file
--write-info-json Write video metadata to a .info.json file
--write-annotations Write video annotations to a .annotations.xml file
--load-info FILE JSON file containing the video information (created with the "--write-info-json" option)
--cookies FILE File to read cookies from and dump cookie jar in
--cache-dir DIR Location in the filesystem where youtube-dl can store some downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl
or ~/.cache/youtube-dl . At the moment, only YouTube player files (for videos with obfuscated signatures) are cached, but that may
change.
--no-cache-dir Disable filesystem caching
--rm-cache-dir Delete all filesystem cache files
## Thumbnail images:
--write-thumbnail write thumbnail image to disk
--write-all-thumbnails write all thumbnail image formats to disk
--list-thumbnails Simulate and list all available thumbnail
formats
--write-thumbnail Write thumbnail image to disk
--write-all-thumbnails Write all thumbnail image formats to disk
--list-thumbnails Simulate and list all available thumbnail formats
## Verbosity / Simulation Options:
-q, --quiet activates quiet mode
-q, --quiet Activate quiet mode
--no-warnings Ignore warnings
-s, --simulate do not download the video and do not write
anything to disk
--skip-download do not download the video
-g, --get-url simulate, quiet but print URL
-e, --get-title simulate, quiet but print title
--get-id simulate, quiet but print id
--get-thumbnail simulate, quiet but print thumbnail URL
--get-description simulate, quiet but print video description
--get-duration simulate, quiet but print video length
--get-filename simulate, quiet but print output filename
--get-format simulate, quiet but print output format
-j, --dump-json simulate, quiet but print JSON information.
See --output for a description of available
keys.
-J, --dump-single-json simulate, quiet but print JSON information
for each command-line argument. If the URL
refers to a playlist, dump the whole
playlist information in a single line.
--print-json Be quiet and print the video information as
JSON (video is still being downloaded).
--newline output progress bar as new lines
--no-progress do not print progress bar
--console-title display progress in console titlebar
-v, --verbose print various debugging information
--dump-intermediate-pages print downloaded pages to debug problems
(very verbose)
--write-pages Write downloaded intermediary pages to
files in the current directory to debug
problems
-s, --simulate Do not download the video and do not write anything to disk
--skip-download Do not download the video
-g, --get-url Simulate, quiet but print URL
-e, --get-title Simulate, quiet but print title
--get-id Simulate, quiet but print id
--get-thumbnail Simulate, quiet but print thumbnail URL
--get-description Simulate, quiet but print video description
--get-duration Simulate, quiet but print video length
--get-filename Simulate, quiet but print output filename
--get-format Simulate, quiet but print output format
-j, --dump-json Simulate, quiet but print JSON information. See --output for a description of available keys.
-J, --dump-single-json Simulate, quiet but print JSON information for each command-line argument. If the URL refers to a playlist, dump the whole playlist
information in a single line.
--print-json Be quiet and print the video information as JSON (video is still being downloaded).
--newline Output progress bar as new lines
--no-progress Do not print progress bar
--console-title Display progress in console titlebar
-v, --verbose Print various debugging information
--dump-pages Print downloaded pages encoded using base64 to debug problems (very verbose)
--write-pages Write downloaded intermediary pages to files in the current directory to debug problems
--print-traffic Display sent and read HTTP traffic
-C, --call-home Contact the youtube-dl server for
debugging.
--no-call-home Do NOT contact the youtube-dl server for
debugging.
-C, --call-home Contact the youtube-dl server for debugging
--no-call-home Do NOT contact the youtube-dl server for debugging
## Workarounds:
--encoding ENCODING Force the specified encoding (experimental)
--no-check-certificate Suppress HTTPS certificate validation.
--prefer-insecure Use an unencrypted connection to retrieve
information about the video. (Currently
supported only for YouTube)
--user-agent UA specify a custom user agent
--referer URL specify a custom referer, use if the video
access is restricted to one domain
--add-header FIELD:VALUE specify a custom HTTP header and its value,
separated by a colon ':'. You can use this
option multiple times
--bidi-workaround Work around terminals that lack
bidirectional text support. Requires bidiv
or fribidi executable in PATH
--sleep-interval SECONDS Number of seconds to sleep before each
download.
--no-check-certificate Suppress HTTPS certificate validation
--prefer-insecure Use an unencrypted connection to retrieve information about the video. (Currently supported only for YouTube)
--user-agent UA Specify a custom user agent
--referer URL Specify a custom referer, use if the video access is restricted to one domain
--add-header FIELD:VALUE Specify a custom HTTP header and its value, separated by a colon ':'. You can use this option multiple times
--bidi-workaround Work around terminals that lack bidirectional text support. Requires bidiv or fribidi executable in PATH
--sleep-interval SECONDS Number of seconds to sleep before each download.
## Video Format Options:
-f, --format FORMAT video format code, specify the order of
preference using slashes, as in -f 22/17/18
. Instead of format codes, you can select
by extension for the extensions aac, m4a,
mp3, mp4, ogg, wav, webm. You can also use
the special names "best", "bestvideo",
"bestaudio", "worst". You can filter the
video results by putting a condition in
brackets, as in -f "best[height=720]" (or
-f "[filesize>10M]"). This works for
filesize, height, width, tbr, abr, vbr, and
fps and the comparisons <, <=, >, >=, =, !=
. Formats for which the value is not known
are excluded unless you put a question mark
(?) after the operator. You can combine
format filters, so -f "[height <=?
720][tbr>500]" selects up to 720p videos
(or videos where the height is not known)
with a bitrate of at least 500 KBit/s. By
default, youtube-dl will pick the best
quality. Use commas to download multiple
audio formats, such as -f
136/137/mp4/bestvideo,140/m4a/bestaudio.
You can merge the video and audio of two
formats into a single file using -f <video-
format>+<audio-format> (requires ffmpeg or
avconv), for example -f
bestvideo+bestaudio.
--all-formats download all available video formats
--prefer-free-formats prefer free video formats unless a specific
one is requested
--max-quality FORMAT highest quality format to download
-F, --list-formats list all available formats
--youtube-skip-dash-manifest Do not download the DASH manifest on
YouTube videos
--merge-output-format FORMAT If a merge is required (e.g.
bestvideo+bestaudio), output to given
container format. One of mkv, mp4, ogg,
webm, flv.Ignored if no merge is required
-f, --format FORMAT Video format code, see the "FORMAT SELECTION" for all the info
--all-formats Download all available video formats
--prefer-free-formats Prefer free video formats unless a specific one is requested
-F, --list-formats List all available formats
--youtube-skip-dash-manifest Do not download the DASH manifests and related data on YouTube videos
--merge-output-format FORMAT If a merge is required (e.g. bestvideo+bestaudio), output to given container format. One of mkv, mp4, ogg, webm, flv. Ignored if no
merge is required
## Subtitle Options:
--write-sub write subtitle file
--write-auto-sub write automatic subtitle file (youtube
only)
--all-subs downloads all the available subtitles of
the video
--list-subs lists all available subtitles for the video
--sub-format FORMAT subtitle format (default=srt) ([sbv/vtt]
youtube only)
--sub-lang LANGS languages of the subtitles to download
(optional) separated by commas, use IETF
language tags like 'en,pt'
--write-sub Write subtitle file
--write-auto-sub Write automatic subtitle file (YouTube only)
--all-subs Download all the available subtitles of the video
--list-subs List all available subtitles for the video
--sub-format FORMAT Subtitle format, accepts formats preference, for example: "srt" or "ass/srt/best"
--sub-lang LANGS Languages of the subtitles to download (optional) separated by commas, use IETF language tags like 'en,pt'
## Authentication Options:
-u, --username USERNAME login with this account ID
-p, --password PASSWORD account password. If this option is left
out, youtube-dl will ask interactively.
-2, --twofactor TWOFACTOR two-factor auth code
-n, --netrc use .netrc authentication data
--video-password PASSWORD video password (vimeo, smotri)
-u, --username USERNAME Login with this account ID
-p, --password PASSWORD Account password. If this option is left out, youtube-dl will ask interactively.
-2, --twofactor TWOFACTOR Two-factor auth code
-n, --netrc Use .netrc authentication data
--video-password PASSWORD Video password (vimeo, smotri)
## Post-processing Options:
-x, --extract-audio convert video files to audio-only files
(requires ffmpeg or avconv and ffprobe or
avprobe)
--audio-format FORMAT "best", "aac", "vorbis", "mp3", "m4a",
"opus", or "wav"; "best" by default
--audio-quality QUALITY ffmpeg/avconv audio quality specification,
insert a value between 0 (better) and 9
(worse) for VBR or a specific bitrate like
128K (default 5)
--recode-video FORMAT Encode the video to another format if
necessary (currently supported:
mp4|flv|ogg|webm|mkv)
-k, --keep-video keeps the video file on disk after the
post-processing; the video is erased by
default
--no-post-overwrites do not overwrite post-processed files; the
post-processed files are overwritten by
default
--embed-subs embed subtitles in the video (only for mp4
videos)
--embed-thumbnail embed thumbnail in the audio as cover art
--add-metadata write metadata to the video file
--xattrs write metadata to the video file's xattrs
(using dublin core and xdg standards)
--fixup POLICY Automatically correct known faults of the
file. One of never (do nothing), warn (only
emit a warning), detect_or_warn(the
default; fix file if we can, warn
otherwise)
--prefer-avconv Prefer avconv over ffmpeg for running the
postprocessors (default)
--prefer-ffmpeg Prefer ffmpeg over avconv for running the
postprocessors
--exec CMD Execute a command on the file after
downloading, similar to find's -exec
syntax. Example: --exec 'adb push {}
/sdcard/Music/ && rm {}'
-x, --extract-audio Convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)
--audio-format FORMAT Specify audio format: "best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; "best" by default
--audio-quality QUALITY Specify ffmpeg/avconv audio quality, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default
5)
--recode-video FORMAT Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm|mkv|avi)
--postprocessor-args ARGS Give these arguments to the postprocessor
-k, --keep-video Keep the video file on disk after the post-processing; the video is erased by default
--no-post-overwrites Do not overwrite post-processed files; the post-processed files are overwritten by default
--embed-subs Embed subtitles in the video (only for mkv and mp4 videos)
--embed-thumbnail Embed thumbnail in the audio as cover art
--add-metadata Write metadata to the video file
--metadata-from-title FORMAT Parse additional metadata like song title / artist from the video title. The format syntax is the same as --output, the parsed
parameters replace existing values. Additional templates: %(album)s, %(artist)s. Example: --metadata-from-title "%(artist)s -
%(title)s" matches a title like "Coldplay - Paradise"
--xattrs Write metadata to the video file's xattrs (using dublin core and xdg standards)
--fixup POLICY Automatically correct known faults of the file. One of never (do nothing), warn (only emit a warning), detect_or_warn (the default;
fix file if we can, warn otherwise)
--prefer-avconv Prefer avconv over ffmpeg for running the postprocessors (default)
--prefer-ffmpeg Prefer ffmpeg over avconv for running the postprocessors
--ffmpeg-location PATH Location of the ffmpeg/avconv binary; either the path to the binary or its containing directory.
--exec CMD Execute a command on the file after downloading, similar to find's -exec syntax. Example: --exec 'adb push {} /sdcard/Music/ && rm
{}'
--convert-subtitles FORMAT Convert the subtitles to other format (currently supported: srt|ass|vtt)
# CONFIGURATION
You can configure youtube-dl by placing default arguments (such as `--extract-audio --no-mtime` to always extract the audio and not copy the mtime) into `/etc/youtube-dl.conf` and/or `~/.config/youtube-dl/config`. On Windows, the configuration file locations are `%APPDATA%\youtube-dl\config.txt` and `C:\Users\<user name>\youtube-dl.conf`.
### Authentication with `.netrc` file ###
You may also want to configure automatic credentials storage for extractors that support authentication (by providing login and password with `--username` and `--password`) in order not to pass credentials as command line arguments on every youtube-dl execution and prevent tracking plain text passwords in shell command history. You can achieve this using [`.netrc` file](http://stackoverflow.com/tags/.netrc/info) on per extractor basis. For that you will need to create `.netrc` file in your `$HOME` and restrict permissions to read/write by you only:
```
touch $HOME/.netrc
chmod a-rwx,u+rw $HOME/.netrc
```
After that you can add credentials for extractor in the following format, where *extractor* is the name of extractor in lowercase:
```
machine <extractor> login <login> password <password>
```
For example:
```
machine youtube login myaccount@gmail.com password my_youtube_password
machine twitch login my_twitch_account_name password my_twitch_password
```
To activate authentication with `.netrc` file you should pass `--netrc` to youtube-dl or to place it in [configuration file](#configuration).
On Windows you may also need to setup `%HOME%` environment variable manually.
# OUTPUT TEMPLATE
The `-o` option allows users to indicate a template for the output file names. The basic usage is not to set any template arguments when downloading a single file, like in `youtube-dl -o funny_video.flv "http://some/video"`. However, it may contain special sequences that will be replaced when downloading each video. The special sequences have the format `%(NAME)s`. To clarify, that is a percent symbol followed by a name in parenthesis, followed by a lowercase S. Allowed names are:
@ -412,6 +284,17 @@ $ youtube-dl --get-filename -o "%(title)s.%(ext)s" BaW_jenozKc --restrict-filena
youtube-dl_test_video_.mp4 # A simple file name
```
# FORMAT SELECTION
By default youtube-dl tries to download the best quality, but sometimes you may want to download other format.
The simplest case is requesting a specific format, for example `-f 22`. You can get the list of available formats using `--list-formats`, you can also use a file extension (currently it supports aac, m4a, mp3, mp4, ogg, wav, webm) or the special names `best`, `bestvideo`, `bestaudio` and `worst`.
If you want to download multiple videos and they don't have the same formats available, you can specify the order of preference using slashes, as in `-f 22/17/18`. You can also filter the video results by putting a condition in brackets, as in `-f "best[height=720]"` (or `-f "[filesize>10M]"`). This works for filesize, height, width, tbr, abr, vbr, asr, and fps and the comparisons <, <=, >, >=, =, != and for ext, acodec, vcodec, container, and protocol and the comparisons =, != . Formats for which the value is not known are excluded unless you put a question mark (?) after the operator. You can combine format filters, so `-f "[height <=? 720][tbr>500]"` selects up to 720p videos (or videos where the height is not known) with a bitrate of at least 500 KBit/s. Use commas to download multiple formats, such as `-f 136/137/mp4/bestvideo,140/m4a/bestaudio`. You can merge the video and audio of two formats into a single file using `-f <video-format>+<audio-format>` (requires ffmpeg or avconv), for example `-f bestvideo+bestaudio`. Format selectors can also be grouped using parentheses, for example if you want to download the best mp4 and webm formats with a height lower than 480 you can use `-f '(mp4,webm)[height<480]'`.
Since the end of April 2015 and version 2015.04.26 youtube-dl uses `-f bestvideo+bestaudio/best` as default format selection (see #5447, #5456). If ffmpeg or avconv are installed this results in downloading `bestvideo` and `bestaudio` separately and muxing them together into a single file giving the best overall quality available. Otherwise it falls back to `best` and results in downloading best available quality served as a single file. `best` is also needed for videos that don't come from YouTube because they don't provide the audio and video in two different files. If you want to only download some dash formats (for example if you are not interested in getting videos with a resolution higher than 1080p), you can add `-f bestvideo[height<=?1080]+bestaudio/best` to your configuration file. Note that if you use youtube-dl to stream to `stdout` (and most likely to pipe it to your media player then), i.e. you explicitly specify output template as `-o -`, youtube-dl still uses `-f best` format selection in order to start content delivery immediately to your player and not to wait until `bestvideo` and `bestaudio` are downloaded and muxed.
If you want to preserve the old format selection behavior (prior to youtube-dl 2015.04.26), i.e. you want to download best available quality media served as a single file, you should explicitly specify your choice with `-f best`. You may want to add it to the [configuration file](#configuration) in order not to type it every time you run youtube-dl.
# VIDEO SELECTION
Videos can be filtered by their upload date using the options `--date`, `--datebefore` or `--dateafter`, they accept dates in two formats:
@ -462,9 +345,9 @@ YouTube changed their playlist format in March 2014 and later on, so you'll need
If you have installed youtube-dl with a package manager, pip, setup.py or a tarball, please use that to update. Note that Ubuntu packages do not seem to get updated anymore. Since we are not affiliated with Ubuntu, there is little we can do. Feel free to [report bugs](https://bugs.launchpad.net/ubuntu/+source/youtube-dl/+filebug) to the [Ubuntu packaging guys](mailto:ubuntu-motu@lists.ubuntu.com?subject=outdated%20version%20of%20youtube-dl) - all they have to do is update the package to a somewhat recent version. See above for a way to update.
### Do I always have to pass in `--max-quality FORMAT`, or `-citw`?
### Do I always have to pass `-citw`?
By default, youtube-dl intends to have the best options (incidentally, if you have a convincing case that these should be different, [please file an issue where you explain that](https://yt-dl.org/bug)). Therefore, it is unnecessary and sometimes harmful to copy long option strings from webpages. In particular, `--max-quality` *limits* the video quality (so if you want the best quality, do NOT pass it in), and the only option out of `-citw` that is regularly useful is `-i`.
By default, youtube-dl intends to have the best options (incidentally, if you have a convincing case that these should be different, [please file an issue where you explain that](https://yt-dl.org/bug)). Therefore, it is unnecessary and sometimes harmful to copy long option strings from webpages. In particular, the only option out of `-citw` that is regularly useful is `-i`.
### Can you please put the -b option back?
@ -490,11 +373,35 @@ If you want to play the video on a machine that is not running youtube-dl, you c
### ERROR: no fmt_url_map or conn information found in video info
youtube has switched to a new video info format in July 2011 which is not supported by old versions of youtube-dl. You can update youtube-dl with `sudo youtube-dl --update`.
YouTube has switched to a new video info format in July 2011 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
### ERROR: unable to download video ###
youtube requires an additional signature since September 2012 which is not supported by old versions of youtube-dl. You can update youtube-dl with `sudo youtube-dl --update`.
YouTube requires an additional signature since September 2012 which is not supported by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
### Video URL contains an ampersand and I'm getting some strange output `[1] 2839` or `'v' is not recognized as an internal or external command` ###
That's actually the output from your shell. Since ampersand is one of the special shell characters it's interpreted by shell preventing you from passing the whole URL to youtube-dl. To disable your shell from interpreting the ampersands (or any other special characters) you have to either put the whole URL in quotes or escape them with a backslash (which approach will work depends on your shell).
For example if your URL is https://www.youtube.com/watch?t=4&v=BaW_jenozKc you should end up with following command:
```youtube-dl 'https://www.youtube.com/watch?t=4&v=BaW_jenozKc'```
or
```youtube-dl https://www.youtube.com/watch?t=4\&v=BaW_jenozKc```
For Windows you have to use the double quotes:
```youtube-dl "https://www.youtube.com/watch?t=4&v=BaW_jenozKc"```
### ExtractorError: Could not find JS function u'OF'
In February 2015, the new YouTube player contained a character sequence in a string that was misinterpreted by old versions of youtube-dl. See [above](#how-do-i-update-youtube-dl) for how to update youtube-dl.
### HTTP Error 429: Too Many Requests or 402: Payment Required
These two error codes indicate that the service is blocking your IP address because of overuse. Contact the service and ask them to unblock your IP address, or - if you have acquired a whitelisted IP address already - use the [`--proxy` or `--source-address` options](#network-options) to select another IP address.
### SyntaxError: Non-ASCII character ###
@ -532,9 +439,35 @@ Either prepend `http://www.youtube.com/watch?v=` or separate the ID from the opt
youtube-dl -- -wNyEUrxzFU
youtube-dl "http://www.youtube.com/watch?v=-wNyEUrxzFU"
### How do I pass cookies to youtube-dl?
Use the `--cookies` option, for example `--cookies /path/to/cookies/file.txt`. Note that cookies file must be in Mozilla/Netscape format and the first line of cookies file must be either `# HTTP Cookie File` or `# Netscape HTTP Cookie File`. Make sure you have correct [newline format](https://en.wikipedia.org/wiki/Newline) in cookies file and convert newlines if necessary to correspond your OS, namely `CRLF` (`\r\n`) for Windows, `LF` (`\n`) for Linux and `CR` (`\r`) for Mac OS. `HTTP Error 400: Bad Request` when using `--cookies` is a good sign of invalid newline format.
Passing cookies to youtube-dl is a good way to workaround login when particular extractor does not implement it explicitly.
### Can you add support for this anime video site, or site which shows current movies for free?
As a matter of policy (as well as legality), youtube-dl does not include support for services that specialize in infringing copyright. As a rule of thumb, if you cannot easily find a video that the service is quite obviously allowed to distribute (i.e. that has been uploaded by the creator, the creator's distributor, or is published under a free license), the service is probably unfit for inclusion to youtube-dl.
A note on the service that they don't host the infringing content, but just link to those who do, is evidence that the service should **not** be included into youtube-dl. The same goes for any DMCA note when the whole front page of the service is filled with videos they are not allowed to distribute. A "fair use" note is equally unconvincing if the service shows copyright-protected videos in full without authorization.
Support requests for services that **do** purchase the rights to distribute their content are perfectly fine though. If in doubt, you can simply include a source that mentions the legitimate purchase of content.
### How can I speed up work on my issue?
(Also known as: Help, my important issue not being solved!) The youtube-dl core developer team is quite small. While we do our best to solve as many issues as possible, sometimes that can take quite a while. To speed up your issue, here's what you can do:
First of all, please do report the issue [at our issue tracker](https://yt-dl.org/bugs). That allows us to coordinate all efforts by users and developers, and serves as a unified point. Unfortunately, the youtube-dl project has grown too large to use personal email as an effective communication channel.
Please read the [bug reporting instructions](#bugs) below. A lot of bugs lack all the necessary information. If you can, offer proxy, VPN, or shell access to the youtube-dl developers. If you are able to, test the issue from multiple computers in multiple countries to exclude local censorship or misconfiguration issues.
If nobody is interested in solving your issue, you are welcome to take matters into your own hands and submit a pull request (or coerce/pay somebody else to do so).
Feel free to bump the issue from time to time by writing a small comment ("Issue is still present in youtube-dl version ...from France, but fixed from Belgium"), but please not more than once a month. Please do not declare your issue as `important` or `urgent`.
### How can I detect whether a given URL is supported by youtube-dl?
For one, have a look at the [list of supported sites](docs/supportedsites.md). Note that it can sometimes happen that the site changes its URL scheme (say, from http://example.com/v/1234567 to http://example.com/v/1234567 ) and youtube-dl reports an URL of a service in that list as unsupported. In that case, simply report a bug.
For one, have a look at the [list of supported sites](docs/supportedsites.md). Note that it can sometimes happen that the site changes its URL scheme (say, from http://example.com/video/1234567 to http://example.com/v/1234567 ) and youtube-dl reports an URL of a service in that list as unsupported. In that case, simply report a bug.
It is *not* possible to detect whether a URL is supported or not. That's because youtube-dl contains a generic extractor which matches **all** URLs. You may be tempted to disable, exclude, or remove the generic extractor, but the generic extractor not only allows users to extract videos from lots of websites that embed a video from another service, but may also be used to extract video from a service that it's hosting itself. Therefore, we neither recommend nor support disabling, excluding, or removing the generic extractor.
@ -631,6 +564,7 @@ youtube-dl makes the best effort to be a good command-line program, and thus sho
From a Python program, you can embed youtube-dl in a more powerful fashion, like this:
```python
from __future__ import unicode_literals
import youtube_dl
ydl_opts = {}
@ -643,6 +577,7 @@ Most likely, you'll want to use various options. For a list of what can be done,
Here's a more complete example of a program that outputs only errors (and a short message after the download is finished), and downloads/converts the video to an mp3 file:
```python
from __future__ import unicode_literals
import youtube_dl
@ -700,7 +635,9 @@ If your report is shorter than two lines, it is almost certainly missing some of
For bug reports, this means that your report should contain the *complete* output of youtube-dl when called with the -v flag. The error message you get for (most) bugs even says so, but you would not believe how many of our bug reports do not contain this information.
Site support requests **must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
If your server has multiple IPs or you suspect censorship, adding --call-home may be a good idea to get more diagnostics. If the error is `ERROR: Unable to extract ...` and you cannot reproduce it from multiple countries, add `--dump-pages` (warning: this will yield a rather large output, redirect it to the file `log.txt` by adding `>log.txt 2>&1` to your command-line) or upload the `.dump` files you get when you add `--write-pages` [somewhere](https://gist.github.com/).
**Site support requests must contain an example URL**. An example URL is a URL you might want to download, like http://www.youtube.com/watch?v=BaW_jenozKc . There should be an obvious video present. Except under very special circumstances, the main page of a video service (e.g. http://www.youtube.com/ ) is *not* an example URL.
### Are you using the latest version?
@ -728,7 +665,7 @@ In particular, every site support request issue should only pertain to services
### Is anyone going to need the feature?
Only post features that you (or an incapicated friend you can personally talk to) require. Do not post features because they seem like a good idea. If they are really useful, they will be requested by someone who requires them.
Only post features that you (or an incapacitated friend you can personally talk to) require. Do not post features because they seem like a good idea. If they are really useful, they will be requested by someone who requires them.
### Is your question about youtube-dl?

View File

@ -28,7 +28,7 @@ for test in get_testcases():
if METHOD == 'EURISTIC':
try:
webpage = compat_urllib_request.urlopen(test['url'], timeout=10).read()
except:
except Exception:
print('\nFail: {0}'.format(test['name']))
continue
@ -45,12 +45,12 @@ for test in get_testcases():
RESULT = ('.' + domain + '\n' in LIST or '\n' + domain + '\n' in LIST)
if RESULT and ('info_dict' not in test or 'age_limit' not in test['info_dict']
or test['info_dict']['age_limit'] != 18):
if RESULT and ('info_dict' not in test or 'age_limit' not in test['info_dict'] or
test['info_dict']['age_limit'] != 18):
print('\nPotential missing age_limit check: {0}'.format(test['name']))
elif not RESULT and ('info_dict' in test and 'age_limit' in test['info_dict']
and test['info_dict']['age_limit'] == 18):
elif not RESULT and ('info_dict' in test and 'age_limit' in test['info_dict'] and
test['info_dict']['age_limit'] == 18):
print('\nPotential false negative: {0}'.format(test['name']))
else:

View File

@ -0,0 +1,42 @@
from __future__ import unicode_literals
import codecs
import subprocess
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl.utils import intlist_to_bytes
from youtube_dl.aes import aes_encrypt, key_expansion
secret_msg = b'Secret message goes here'
def hex_str(int_list):
return codecs.encode(intlist_to_bytes(int_list), 'hex')
def openssl_encode(algo, key, iv):
cmd = ['openssl', 'enc', '-e', '-' + algo, '-K', hex_str(key), '-iv', hex_str(iv)]
prog = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, _ = prog.communicate(secret_msg)
return out
iv = key = [0x20, 0x15] + 14 * [0]
r = openssl_encode('aes-128-cbc', key, iv)
print('aes_cbc_decrypt')
print(repr(r))
password = key
new_key = aes_encrypt(password, key_expansion(password))
r = openssl_encode('aes-128-ctr', new_key, iv)
print('aes_decrypt_text 16')
print(repr(r))
password = key + 16 * [0]
new_key = aes_encrypt(password, key_expansion(password)) * (32 // 16)
r = openssl_encode('aes-256-ctr', new_key, iv)
print('aes_decrypt_text 32')
print(repr(r))

View File

@ -35,7 +35,7 @@ if [ ! -z "$useless_files" ]; then echo "ERROR: Non-.py files in youtube_dl: $us
if [ ! -f "updates_key.pem" ]; then echo 'ERROR: updates_key.pem missing'; exit 1; fi
/bin/echo -e "\n### First of all, testing..."
make cleanall
make clean
if $skip_tests ; then
echo 'SKIPPING TESTS'
else
@ -45,9 +45,9 @@ fi
/bin/echo -e "\n### Changing version in version.py..."
sed -i "s/__version__ = '.*'/__version__ = '$version'/" youtube_dl/version.py
/bin/echo -e "\n### Committing README.md and youtube_dl/version.py..."
make README.md
git add README.md youtube_dl/version.py
/bin/echo -e "\n### Committing documentation and youtube_dl/version.py..."
make README.md CONTRIBUTING.md supportedsites
git add README.md CONTRIBUTING.md docs/supportedsites.md youtube_dl/version.py
git commit -m "release $version"
/bin/echo -e "\n### Now tagging, signing and pushing..."

View File

@ -1,24 +1,35 @@
# Supported sites
- **1tv**: Первый канал
- **1up.com**
- **220.ro**
- **22tracks:genre**
- **22tracks:track**
- **24video**
- **3sat**
- **4tube**
- **56.com**
- **5min**
- **8tracks**
- **91porn**
- **9gag**
- **abc.net.au**
- **Abc7News**
- **AcademicEarth:Course**
- **AddAnime**
- **AdobeTV**
- **AdobeTVVideo**
- **AdultSwim**
- **Aftenposten**
- **Aftonbladet**
- **AirMozilla**
- **AlJazeera**
- **Allocine**
- **AlphaPorno**
- **anitube.se**
- **AnySex**
- **Aparat**
- **AppleConnect**
- **AppleDaily**: 臺灣蘋果日報
- **AppleTrailers**
- **archive.org**: archive.org videos
- **ARD**
@ -30,14 +41,19 @@
- **arte.tv:ddc**
- **arte.tv:embed**
- **arte.tv:future**
- **AtresPlayer**
- **ATTTechChannel**
- **audiomack**
- **AUEngine**
- **audiomack:album**
- **Azubu**
- **BaiduVideo**: 百度视频
- **bambuser**
- **bambuser:channel**
- **Bandcamp**
- **Bandcamp:album**
- **bbc**: BBC
- **bbc.co.uk**: BBC iPlayer
- **BeatportPro**
- **Beeg**
- **BehindKink**
- **Bet**
@ -51,16 +67,23 @@
- **BR**: Bayerischer Rundfunk Mediathek
- **Break**
- **Brightcove**
- **bt:article**: Bergens Tidende Articles
- **bt:vestlendingen**: Bergens Tidende - Vestlendingen
- **BuzzFeed**
- **BYUtv**
- **Camdemy**
- **CamdemyFolder**
- **Canal13cl**
- **canalc2.tv**
- **Canalplus**: canalplus.fr, piwiplus.fr and d8.tv
- **CBS**
- **CBSNews**: CBS News
- **CBSSports**
- **CeskaTelevize**
- **channel9**: Channel 9
- **Chilloutzone**
- **chirbit**
- **chirbit:profile**
- **Cinchcast**
- **Cinemassacre**
- **clipfish**
@ -71,44 +94,61 @@
- **cmt.com**
- **CNET**
- **CNN**
- **CNNArticle**
- **CNNBlogs**
- **CollegeHumor**
- **CollegeRama**
- **ComCarCoff**
- **ComedyCentral**
- **ComedyCentralShows**: The Daily Show / The Colbert Report
- **CondeNast**: Condé Nast media group: Condé Nast, GQ, Glamour, Vanity Fair, Vogue, W Magazine, WIRED
- **Cracked**
- **Criterion**
- **CrooksAndLiars**
- **Crunchyroll**
- **crunchyroll:playlist**
- **CSpan**: C-SPAN
- **CtsNews**: 華視新聞
- **culturebox.francetvinfo.fr**
- **dailymotion**
- **dailymotion:playlist**
- **dailymotion:user**
- **DailymotionCloud**
- **daum.net**
- **DBTV**
- **DctpTv**
- **DeezerPlaylist**
- **defense.gouv.fr**
- **DHM**: Filmarchiv - Deutsches Historisches Museum
- **Discovery**
- **divxstage**: DivxStage
- **Dotsub**
- **DouyuTV**: 斗鱼
- **dramafever**
- **dramafever:series**
- **DRBonanza**
- **Dropbox**
- **DrTuber**
- **DRTV**
- **Dump**
- **Dumpert**
- **dvtv**: http://video.aktualne.cz/
- **EaglePlatform**
- **EbaumsWorld**
- **EchoMsk**
- **eHow**
- **Einthusan**
- **eitb.tv**
- **EllenTV**
- **EllenTV:clips**
- **ElPais**: El País
- **Embedly**
- **EMPFlix**
- **Engadget**
- **Eporner**
- **EroProfile**
- **Escapist**
- **ESPN** (Currently broken)
- **EveryonesMixtape**
- **exfm**: ex.fm
- **ExpoTV**
@ -118,13 +158,14 @@
- **fc2**
- **fernsehkritik.tv**
- **fernsehkritik.tv:postecke**
- **Firedrive**
- **Firstpost**
- **firsttv**: Видеоархив - Первый канал
- **FiveTV**
- **Flickr**
- **Folketinget**: Folketinget (ft.dk; Danish parliament)
- **FootyRoom**
- **Foxgay**
- **FoxNews**
- **FoxSports**
- **france2.fr:generation-quoi**
- **FranceCulture**
- **FranceInter**
@ -137,25 +178,34 @@
- **Gamekings**
- **GameOne**
- **gameone:playlist**
- **Gamersyde**
- **GameSpot**
- **GameStar**
- **Gametrailers**
- **Gazeta**
- **GDCVault**
- **generic**: Generic downloader that works on some sites
- **Gfycat**
- **GiantBomb**
- **Giga**
- **Glide**: Glide mobile video messages (glide.me)
- **Globo**
- **GodTube**
- **GoldenMoustache**
- **Golem**
- **GorillaVid**: GorillaVid.in, daclips.in, movpod.in and fastvideo.in
- **GorillaVid**: GorillaVid.in, daclips.in, movpod.in, fastvideo.in and realvid.net
- **Goshgay**
- **Grooveshark**
- **Groupon**
- **Hark**
- **HearThisAt**
- **Heise**
- **HellPorno**
- **Helsinki**: helsinki.fi
- **HentaiStigma**
- **HistoricFilms**
- **History**
- **hitbox**
- **hitbox:live**
- **HornBunny**
- **HostingBulk**
- **HotNewHipHop**
@ -167,12 +217,15 @@
- **ign.com**
- **imdb**: Internet Movie Database trailers
- **imdb:list**: Internet Movie Database lists
- **Imgur**
- **Ina**
- **InfoQ**
- **Instagram**
- **instagram:user**: Instagram user profile
- **InternetVideoArchive**
- **IPrima**
- **iqiyi**: 爱奇艺
- **Ir90Tv**
- **ivi**: ivi.ru
- **ivi:compilation**: ivi.ru compilations
- **Izlesene**
@ -181,7 +234,11 @@
- **Jove**
- **jpopsuki.tv**
- **Jukebox**
- **Kaltura**
- **KanalPlay**: Kanal 5/9/11 Play
- **Kankan**
- **Karaoketv**
- **KarriereVideos**
- **keek**
- **KeezMovies**
- **KhanAcademy**
@ -189,12 +246,25 @@
- **kontrtube**: KontrTube.ru - Труба зовёт
- **KrasView**: Красвью
- **Ku6**
- **kuwo:album**: 酷我音乐 - 专辑
- **kuwo:category**: 酷我音乐 - 分类
- **kuwo:chart**: 酷我音乐 - 排行榜
- **kuwo:mv**: 酷我音乐 - MV
- **kuwo:singer**: 酷我音乐 - 歌手
- **kuwo:song**: 酷我音乐
- **la7.tv**
- **Laola1Tv**
- **Lecture2Go**
- **Letv**: 乐视网
- **LetvPlaylist**
- **LetvTv**
- **Libsyn**
- **life:embed**
- **lifenews**: LIFE | NEWS
- **LiveLeak**
- **livestream**
- **livestream:original**
- **LnkGo**
- **lrt.lt**
- **lynda**: lynda.com videos
- **lynda:course**: lynda.com online courses
@ -203,11 +273,14 @@
- **mailru**: Видео@Mail.Ru
- **Malemotion**
- **MDR**
- **media.ccc.de**
- **MegaVideoz**
- **metacafe**
- **Metacritic**
- **Mgoon**
- **Minhateca**
- **MinistryGrid**
- **miomio.tv**
- **mitele.es**
- **mixcloud**
- **MLB**
@ -220,6 +293,7 @@
- **Motherless**
- **Motorsport**: motorsport.com
- **MovieClips**
- **MovieFap**
- **Moviezine**
- **movshare**: MovShare
- **MPORA**
@ -233,66 +307,114 @@
- **MySpace**
- **MySpace:album**
- **MySpass**
- **Myvi**
- **myvideo**
- **MyVidster**
- **N-JOY**
- **n-tv.de**
- **NationalGeographic**
- **Naver**
- **NBA**
- **NBC**
- **NBCNews**
- **NBCSports**
- **NBCSportsVPlayer**
- **ndr**: NDR.de - Mediathek
- **NDTV**
- **NerdCubedFeed**
- **Nerdist**
- **netease:album**: 网易云音乐 - 专辑
- **netease:djradio**: 网易云音乐 - 电台
- **netease:mv**: 网易云音乐 - MV
- **netease:playlist**: 网易云音乐 - 歌单
- **netease:program**: 网易云音乐 - 电台节目
- **netease:singer**: 网易云音乐 - 歌手
- **netease:song**: 网易云音乐
- **Netzkino**
- **Newgrounds**
- **Newstube**
- **NextMedia**: 蘋果日報
- **NextMediaActionNews**: 蘋果日報 - 動新聞
- **nfb**: National Film Board of Canada
- **nfl.com**
- **nhl.com**
- **nhl.com:news**: NHL news
- **nhl.com:videocenter**: NHL videocenter category
- **niconico**: ニコニコ動画
- **NiconicoPlaylist**
- **Noco**
- **Normalboots**
- **NosVideo**
- **Nova**: TN.cz, Prásk.tv, Nova.cz, Novaplus.cz, FANDA.tv, Krásná.cz and Doma.cz
- **novamov**: NovaMov
- **Nowness**
- **NowTV**
- **nowvideo**: NowVideo
- **npo.nl**
- **npo**: npo.nl and ntr.nl
- **npo**: npo.nl and ntr.nl
- **npo.nl:live**
- **npo.nl:radio**
- **npo.nl:radio:fragment**
- **NRK**
- **NRKTV**
- **NTV**
- **NRKPlaylist**
- **NRKTV**: NRK TV and NRK Radio
- **ntv.ru**
- **Nuvid**
- **NYTimes**
- **NYTimesArticle**
- **ocw.mit.edu**
- **Odnoklassniki**
- **OktoberfestTV**
- **on.aol.com**
- **OnionStudios**
- **Ooyala**
- **OoyalaExternal**
- **OpenFilm**
- **orf:fm4**: radio FM4
- **orf:iptv**: iptv.ORF.at
- **orf:oe1**: Radio Österreich 1
- **orf:tvthek**: ORF TVthek
- **ORFFM4**: radio FM4
- **parliamentlive.tv**: UK parliament videos
- **Patreon**
- **PBS**
- **PhilharmonieDeParis**: Philharmonie de Paris
- **Phoenix**
- **Photobucket**
- **Pinkbike**
- **Pladform**
- **PlanetaPlay**
- **play.fm**
- **played.to**
- **Playvid**
- **Playwire**
- **plus.google**: Google Plus
- **pluzz.francetv.fr**
- **podomatic**
- **PornHd**
- **PornHub**
- **PornHubPlaylist**
- **Pornotube**
- **PornoVoisines**
- **PornoXO**
- **PrimeShareTV**
- **PromptFile**
- **prosiebensat1**: ProSiebenSat.1 Digital
- **Puls4**
- **Pyvideo**
- **qqmusic**: QQ音乐
- **qqmusic:album**: QQ音乐 - 专辑
- **qqmusic:playlist**: QQ音乐 - 歌单
- **qqmusic:singer**: QQ音乐 - 歌手
- **qqmusic:toplist**: QQ音乐 - 排行榜
- **QuickVid**
- **R7**
- **radio.de**
- **radiobremen**
- **radiofrance**
- **RadioJavan**
- **Rai**
- **RBMARadio**
- **RDS**: RDS.ca
- **RedTube**
- **Restudy**
- **ReverbNation**
@ -300,18 +422,25 @@
- **RottenTomatoes**
- **Roxwel**
- **RTBF**
- **RTLnow**
- **rtlxl.nl**
- **Rte**
- **rtl.nl**: rtl.nl and rtlxl.nl
- **RTL2**
- **RTP**
- **RTS**: RTS.ch
- **rtve.es:alacarta**: RTVE a la carta
- **rtve.es:infantil**: RTVE infantil
- **rtve.es:live**: RTVE.es live streams
- **RUHD**
- **rutube**: Rutube videos
- **rutube:channel**: Rutube channels
- **rutube:embed**: Rutube embedded videos
- **rutube:movie**: Rutube movies
- **rutube:person**: Rutube person videos
- **RUTV**: RUTV.RU
- **Ruutu**
- **safari**: safaribooksonline.com online video
- **safari:course**: safaribooksonline.com online courses
- **Sandia**: Sandia National Laboratories
- **Sapo**: SAPO Vídeos
- **savefrom.net**
- **SBS**: sbs.com.au
@ -320,6 +449,7 @@
- **Screencast**
- **ScreencastOMatic**
- **ScreenwaveMedia**
- **SenateISVP**
- **ServingSys**
- **Sexu**
- **SexyKarma**: Sexy Karma and Watch Indian Porn
@ -332,17 +462,25 @@
- **smotri:broadcast**: Smotri.com broadcasts
- **smotri:community**: Smotri.com community videos
- **smotri:user**: Smotri.com user videos
- **SnagFilms**
- **SnagFilmsEmbed**
- **Snotr**
- **Sockshare**
- **Sohu**
- **soompi**
- **soompi:show**
- **soundcloud**
- **soundcloud:playlist**
- **soundcloud:set**
- **soundcloud:user**
- **Soundgasm**
- **soundgasm**
- **soundgasm:profile**
- **southpark.cc.com**
- **southpark.cc.com:español**
- **southpark.de**
- **southpark.nl**
- **southparkstudios.dk**
- **Space**
- **SpankBang**
- **Spankwire**
- **Spiegel**
- **Spiegel:Article**: Articles on spiegel.de
@ -350,13 +488,20 @@
- **Spike**
- **Sport5**
- **SportBox**
- **SportBoxEmbed**
- **SportDeutschland**
- **SRMediathek**: Süddeutscher Rundfunk
- **Sportschau**
- **Srf**
- **SRMediathek**: Saarländischer Rundfunk
- **SSA**
- **stanfordoc**: Stanford Open ClassRoom
- **Steam**
- **streamcloud.eu**
- **StreamCZ**
- **StreetVoice**
- **SunPorno**
- **SVT**
- **SVTPlay**: SVT Play and Öppet arkiv
- **SWRMediathek**
- **Syfy**
- **SztvHu**
@ -370,16 +515,18 @@
- **TeamFour**
- **TechTalks**
- **techtv.mit.edu**
- **TED**
- **tegenlicht.vpro.nl**
- **ted**
- **TeleBruxelles**
- **telecinco.es**
- **TeleMB**
- **TeleTask**
- **TenPlay**
- **TestTube**
- **TF1**
- **TheOnion**
- **ThePlatform**
- **TheSixtyOne**
- **ThisAmericanLife**
- **ThisAV**
- **THVideo**
- **THVideoPlaylist**
@ -387,6 +534,7 @@
- **tlc.com**
- **tlc.de**
- **TMZ**
- **TMZArticle**
- **TNAFlix**
- **tou.tv**
- **Toypics**: Toypics user profile
@ -395,29 +543,48 @@
- **Trilulilu**
- **TruTube**
- **Tube8**
- **TubiTv**
- **Tudou**
- **Tumblr**
- **TuneIn**
- **Turbo**
- **Tutv**
- **tv.dfb.de**
- **TV2**
- **TV2Article**
- **TV4**: tv4.se and tv4play.se
- **TVC**
- **TVCArticle**
- **tvigle**: Интернет-телевидение Tvigle.ru
- **tvp.pl**
- **tvp.pl:Series**
- **TVPlay**: TV3Play and related services
- **Twitch**
- **Tweakers**
- **twitch:bookmarks**
- **twitch:chapter**
- **twitch:past_broadcasts**
- **twitch:profile**
- **twitch:stream**
- **twitch:video**
- **twitch:vod**
- **TwitterCard**
- **Ubu**
- **udemy**
- **udemy:course**
- **UDNEmbed**: 聯合影音
- **Ultimedia**
- **Unistra**
- **Urort**: NRK P3 Urørt
- **ustream**
- **ustream:channel**
- **Varzesh3**
- **Vbox7**
- **VeeHD**
- **Veoh**
- **Vessel**
- **Vesti**: Вести.Ru
- **Vevo**
- **VGTV**
- **VGTV**: VGTV and BTTV
- **vh1.com**
- **Vice**
- **Viddler**
@ -433,7 +600,11 @@
- **videoweed**: VideoWeed
- **Vidme**
- **Vidzi**
- **vier**
- **vier:videos**
- **Viewster**
- **viki**
- **viki:channel**
- **vimeo**
- **vimeo:album**
- **vimeo:channel**
@ -442,12 +613,13 @@
- **vimeo:review**: Review pages on vimeo
- **vimeo:user**
- **vimeo:watchlater**: Vimeo watch later list, "vimeowatchlater" keyword (requires authentication)
- **Vimple**: Vimple.ru
- **Vimple**: Vimple - one-click video hosting
- **Vine**
- **vine:user**
- **vk.com**
- **vk.com:user-videos**: vk.com:All of a user's videos
- **vk**: VK
- **vk:uservideos**: VK - User's Videos
- **Vodlocker**
- **VoiceRepublic**
- **Vporn**
- **VRT**
- **vube**: Vube.com
@ -460,24 +632,37 @@
- **WDR**
- **wdr:mobile**
- **WDRMaus**: Sendung mit der Maus
- **WebOfStories**
- **WebOfStoriesPlaylist**
- **Weibo**
- **Wimp**
- **Wistia**
- **WNL**
- **WorldStarHipHop**
- **wrzuta.pl**
- **WSJ**: Wall Street Journal
- **XBef**
- **XboxClips**
- **XHamster**
- **XHamsterEmbed**
- **XMinus**
- **XNXX**
- **Xstream**
- **XTube**
- **XTubeUser**: XTube user profile
- **Xuite**: 隨意窩Xuite影音
- **XVideos**
- **XXXYMovies**
- **Yahoo**: Yahoo screen and movies
- **Yam**: 蕃薯藤yam天空部落
- **yandexmusic:album**: Яндекс.Музыка - Альбом
- **yandexmusic:playlist**: Яндекс.Музыка - Плейлист
- **yandexmusic:track**: Яндекс.Музыка - Трек
- **YesJapan**
- **yinyuetai:video**: 音悦Tai
- **Ynet**
- **YouJizz**
- **Youku**
- **youku**: 优酷
- **YouPorn**
- **YourUpload**
- **youtube**: YouTube.com
@ -491,9 +676,9 @@
- **youtube:search_url**: YouTube.com search URLs
- **youtube:show**: YouTube.com (multi-season) shows
- **youtube:subscriptions**: YouTube.com subscriptions feed, "ytsubs" keyword (requires authentication)
- **youtube:toplist**: YouTube.com top lists, "yttoplist:{channel}:{list title}" (Example: "yttoplist:music:Top Tracks")
- **youtube:user**: YouTube.com user videos (URL or "ytuser" keyword)
- **youtube:watch_later**: Youtube watch later list, ":ytwatchlater" for short (requires authentication)
- **youtube:watchlater**: Youtube watch later list, ":ytwatchlater" for short (requires authentication)
- **Zapiks**
- **ZDF**
- **ZDFChannel**
- **zingmp3:album**: mp3.zing.vn albums

View File

@ -3,4 +3,4 @@ universal = True
[flake8]
exclude = youtube_dl/extractor/__init__.py,devscripts/buildserver.py,setup.py,build,.git
ignore = E501
ignore = E402,E501,E731

View File

@ -103,6 +103,26 @@ def expect_info_dict(self, got_dict, expected_dict):
self.assertTrue(
match_rex.match(got),
'field %s (value: %r) should match %r' % (info_field, got, match_str))
elif isinstance(expected, compat_str) and expected.startswith('startswith:'):
got = got_dict.get(info_field)
start_str = expected[len('startswith:'):]
self.assertTrue(
isinstance(got, compat_str),
'Expected a %s object, but got %s for field %s' % (
compat_str.__name__, type(got).__name__, info_field))
self.assertTrue(
got.startswith(start_str),
'field %s (value: %r) should start with %r' % (info_field, got, start_str))
elif isinstance(expected, compat_str) and expected.startswith('contains:'):
got = got_dict.get(info_field)
contains_str = expected[len('contains:'):]
self.assertTrue(
isinstance(got, compat_str),
'Expected a %s object, but got %s for field %s' % (
compat_str.__name__, type(got).__name__, info_field))
self.assertTrue(
contains_str in got,
'field %s (value: %r) should contain %r' % (info_field, got, contains_str))
elif isinstance(expected, type):
got = got_dict.get(info_field)
self.assertTrue(isinstance(got, expected),
@ -130,7 +150,7 @@ def expect_info_dict(self, got_dict, expected_dict):
'invalid value for field %s, expected %r, got %r' % (info_field, expected, got))
# Check for the presence of mandatory fields
if got_dict.get('_type') != 'playlist':
if got_dict.get('_type') not in ('playlist', 'multi_video'):
for key in ('id', 'url', 'title', 'ext'):
self.assertTrue(got_dict.get(key), 'Missing mandatory field %s' % key)
# Check for mandatory fields that are automatically set by YoutubeDL
@ -153,12 +173,14 @@ def expect_info_dict(self, got_dict, expected_dict):
info_dict_str += ''.join(
' %s: %s,\n' % (_repr(k), _repr(v))
for k, v in test_info_dict.items() if k not in missing_keys)
info_dict_str += '\n'
if info_dict_str:
info_dict_str += '\n'
info_dict_str += ''.join(
' %s: %s,\n' % (_repr(k), _repr(test_info_dict[k]))
for k in missing_keys)
write_string(
'\n\'info_dict\': {\n' + info_dict_str + '}\n', out=sys.stderr)
'\n\'info_dict\': {\n' + info_dict_str + '},\n', out=sys.stderr)
self.assertFalse(
missing_keys,
'Missing keys in test definition: %s' % (

View File

@ -7,8 +7,7 @@
"forcethumbnail": false,
"forcetitle": false,
"forceurl": false,
"format": null,
"format_limit": null,
"format": "best",
"ignoreerrors": false,
"listformats": null,
"logtostderr": false,
@ -28,7 +27,7 @@
"retries": 10,
"simulate": false,
"subtitleslang": null,
"subtitlesformat": "srt",
"subtitlesformat": "best",
"test": true,
"updatetime": true,
"usenetrc": false,
@ -39,5 +38,6 @@
"writesubtitles": false,
"allsubtitles": false,
"listssubtitles": false,
"socket_timeout": 20
"socket_timeout": 20,
"fixup": "never"
}

View File

@ -12,7 +12,12 @@ import copy
from test.helper import FakeYDL, assertRegexpMatches
from youtube_dl import YoutubeDL
from youtube_dl.compat import compat_str
from youtube_dl.extractor import YoutubeIE
from youtube_dl.postprocessor.common import PostProcessor
from youtube_dl.utils import ExtractorError, match_filter_func
TEST_URL = 'http://localhost/sample.mp4'
class YDL(FakeYDL):
@ -45,8 +50,8 @@ class TestFormatSelection(unittest.TestCase):
ydl = YDL()
ydl.params['prefer_free_formats'] = True
formats = [
{'ext': 'webm', 'height': 460, 'url': 'x'},
{'ext': 'mp4', 'height': 460, 'url': 'y'},
{'ext': 'webm', 'height': 460, 'url': TEST_URL},
{'ext': 'mp4', 'height': 460, 'url': TEST_URL},
]
info_dict = _make_result(formats)
yie = YoutubeIE(ydl)
@ -59,8 +64,8 @@ class TestFormatSelection(unittest.TestCase):
ydl = YDL()
ydl.params['prefer_free_formats'] = True
formats = [
{'ext': 'webm', 'height': 720, 'url': 'a'},
{'ext': 'mp4', 'height': 1080, 'url': 'b'},
{'ext': 'webm', 'height': 720, 'url': TEST_URL},
{'ext': 'mp4', 'height': 1080, 'url': TEST_URL},
]
info_dict['formats'] = formats
yie = YoutubeIE(ydl)
@ -73,9 +78,9 @@ class TestFormatSelection(unittest.TestCase):
ydl = YDL()
ydl.params['prefer_free_formats'] = False
formats = [
{'ext': 'webm', 'height': 720, 'url': '_'},
{'ext': 'mp4', 'height': 720, 'url': '_'},
{'ext': 'flv', 'height': 720, 'url': '_'},
{'ext': 'webm', 'height': 720, 'url': TEST_URL},
{'ext': 'mp4', 'height': 720, 'url': TEST_URL},
{'ext': 'flv', 'height': 720, 'url': TEST_URL},
]
info_dict['formats'] = formats
yie = YoutubeIE(ydl)
@ -87,8 +92,8 @@ class TestFormatSelection(unittest.TestCase):
ydl = YDL()
ydl.params['prefer_free_formats'] = False
formats = [
{'ext': 'flv', 'height': 720, 'url': '_'},
{'ext': 'webm', 'height': 720, 'url': '_'},
{'ext': 'flv', 'height': 720, 'url': TEST_URL},
{'ext': 'webm', 'height': 720, 'url': TEST_URL},
]
info_dict['formats'] = formats
yie = YoutubeIE(ydl)
@ -97,45 +102,13 @@ class TestFormatSelection(unittest.TestCase):
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['ext'], 'flv')
def test_format_limit(self):
formats = [
{'format_id': 'meh', 'url': 'http://example.com/meh', 'preference': 1},
{'format_id': 'good', 'url': 'http://example.com/good', 'preference': 2},
{'format_id': 'great', 'url': 'http://example.com/great', 'preference': 3},
{'format_id': 'excellent', 'url': 'http://example.com/exc', 'preference': 4},
]
info_dict = _make_result(formats)
ydl = YDL()
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'excellent')
ydl = YDL({'format_limit': 'good'})
assert ydl.params['format_limit'] == 'good'
ydl.process_ie_result(info_dict.copy())
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'good')
ydl = YDL({'format_limit': 'great', 'format': 'all'})
ydl.process_ie_result(info_dict.copy())
self.assertEqual(ydl.downloaded_info_dicts[0]['format_id'], 'meh')
self.assertEqual(ydl.downloaded_info_dicts[1]['format_id'], 'good')
self.assertEqual(ydl.downloaded_info_dicts[2]['format_id'], 'great')
self.assertTrue('3' in ydl.msgs[0])
ydl = YDL()
ydl.params['format_limit'] = 'excellent'
ydl.process_ie_result(info_dict.copy())
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'excellent')
def test_format_selection(self):
formats = [
{'format_id': '35', 'ext': 'mp4', 'preference': 1, 'url': '_'},
{'format_id': '45', 'ext': 'webm', 'preference': 2, 'url': '_'},
{'format_id': '47', 'ext': 'webm', 'preference': 3, 'url': '_'},
{'format_id': '2', 'ext': 'flv', 'preference': 4, 'url': '_'},
{'format_id': '35', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
{'format_id': 'example-with-dashes', 'ext': 'webm', 'preference': 1, 'url': TEST_URL},
{'format_id': '45', 'ext': 'webm', 'preference': 2, 'url': TEST_URL},
{'format_id': '47', 'ext': 'webm', 'preference': 3, 'url': TEST_URL},
{'format_id': '2', 'ext': 'flv', 'preference': 4, 'url': TEST_URL},
]
info_dict = _make_result(formats)
@ -164,12 +137,17 @@ class TestFormatSelection(unittest.TestCase):
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], '35')
ydl = YDL({'format': 'example-with-dashes'})
ydl.process_ie_result(info_dict.copy())
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'example-with-dashes')
def test_format_selection_audio(self):
formats = [
{'format_id': 'audio-low', 'ext': 'webm', 'preference': 1, 'vcodec': 'none', 'url': '_'},
{'format_id': 'audio-mid', 'ext': 'webm', 'preference': 2, 'vcodec': 'none', 'url': '_'},
{'format_id': 'audio-high', 'ext': 'flv', 'preference': 3, 'vcodec': 'none', 'url': '_'},
{'format_id': 'vid', 'ext': 'mp4', 'preference': 4, 'url': '_'},
{'format_id': 'audio-low', 'ext': 'webm', 'preference': 1, 'vcodec': 'none', 'url': TEST_URL},
{'format_id': 'audio-mid', 'ext': 'webm', 'preference': 2, 'vcodec': 'none', 'url': TEST_URL},
{'format_id': 'audio-high', 'ext': 'flv', 'preference': 3, 'vcodec': 'none', 'url': TEST_URL},
{'format_id': 'vid', 'ext': 'mp4', 'preference': 4, 'url': TEST_URL},
]
info_dict = _make_result(formats)
@ -184,8 +162,8 @@ class TestFormatSelection(unittest.TestCase):
self.assertEqual(downloaded['format_id'], 'audio-low')
formats = [
{'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': '_'},
{'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': '_'},
{'format_id': 'vid-low', 'ext': 'mp4', 'preference': 1, 'url': TEST_URL},
{'format_id': 'vid-high', 'ext': 'mp4', 'preference': 2, 'url': TEST_URL},
]
info_dict = _make_result(formats)
@ -227,9 +205,9 @@ class TestFormatSelection(unittest.TestCase):
def test_format_selection_video(self):
formats = [
{'format_id': 'dash-video-low', 'ext': 'mp4', 'preference': 1, 'acodec': 'none', 'url': '_'},
{'format_id': 'dash-video-high', 'ext': 'mp4', 'preference': 2, 'acodec': 'none', 'url': '_'},
{'format_id': 'vid', 'ext': 'mp4', 'preference': 3, 'url': '_'},
{'format_id': 'dash-video-low', 'ext': 'mp4', 'preference': 1, 'acodec': 'none', 'url': TEST_URL},
{'format_id': 'dash-video-high', 'ext': 'mp4', 'preference': 2, 'acodec': 'none', 'url': TEST_URL},
{'format_id': 'vid', 'ext': 'mp4', 'preference': 3, 'url': TEST_URL},
]
info_dict = _make_result(formats)
@ -257,29 +235,89 @@ class TestFormatSelection(unittest.TestCase):
'141', '172', '140', '171', '139',
]
for f1id, f2id in zip(order, order[1:]):
f1 = YoutubeIE._formats[f1id].copy()
f1['format_id'] = f1id
f1['url'] = 'url:' + f1id
f2 = YoutubeIE._formats[f2id].copy()
f2['format_id'] = f2id
f2['url'] = 'url:' + f2id
def format_info(f_id):
info = YoutubeIE._formats[f_id].copy()
info['format_id'] = f_id
info['url'] = 'url:' + f_id
return info
formats_order = [format_info(f_id) for f_id in order]
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': 'bestvideo+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], '137+141')
self.assertEqual(downloaded['ext'], 'mp4')
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': 'bestvideo[height>=999999]+bestaudio/best'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], '38')
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': 'bestvideo/best,bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['137', '141'])
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['137+141', '248+141'])
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': '(bestvideo[ext=mp4],bestvideo[ext=webm])[height<=720]+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['136+141', '247+141'])
info_dict = _make_result(list(formats_order), extractor='youtube')
ydl = YDL({'format': '(bestvideo[ext=none]/bestvideo[ext=webm])+bestaudio'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['248+141'])
for f1, f2 in zip(formats_order, formats_order[1:]):
info_dict = _make_result([f1, f2], extractor='youtube')
ydl = YDL()
ydl = YDL({'format': 'best/bestvideo'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], f1id)
self.assertEqual(downloaded['format_id'], f1['format_id'])
info_dict = _make_result([f2, f1], extractor='youtube')
ydl = YDL()
ydl = YDL({'format': 'best/bestvideo'})
yie = YoutubeIE(ydl)
yie._sort_formats(info_dict['formats'])
ydl.process_ie_result(info_dict)
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], f1id)
self.assertEqual(downloaded['format_id'], f1['format_id'])
def test_invalid_format_specs(self):
def assert_syntax_error(format_spec):
ydl = YDL({'format': format_spec})
info_dict = _make_result([{'format_id': 'foo', 'url': TEST_URL}])
self.assertRaises(SyntaxError, ydl.process_ie_result, info_dict)
assert_syntax_error('bestvideo,,best')
assert_syntax_error('+bestaudio')
assert_syntax_error('bestvideo+')
assert_syntax_error('/')
def test_format_filtering(self):
formats = [
@ -336,6 +374,79 @@ class TestFormatSelection(unittest.TestCase):
downloaded = ydl.downloaded_info_dicts[0]
self.assertEqual(downloaded['format_id'], 'G')
ydl = YDL({'format': 'all[width>=400][width<=600]'})
ydl.process_ie_result(info_dict)
downloaded_ids = [info['format_id'] for info in ydl.downloaded_info_dicts]
self.assertEqual(downloaded_ids, ['B', 'C', 'D'])
ydl = YDL({'format': 'best[height<40]'})
try:
ydl.process_ie_result(info_dict)
except ExtractorError:
pass
self.assertEqual(ydl.downloaded_info_dicts, [])
class TestYoutubeDL(unittest.TestCase):
def test_subtitles(self):
def s_formats(lang, autocaption=False):
return [{
'ext': ext,
'url': 'http://localhost/video.%s.%s' % (lang, ext),
'_auto': autocaption,
} for ext in ['vtt', 'srt', 'ass']]
subtitles = dict((l, s_formats(l)) for l in ['en', 'fr', 'es'])
auto_captions = dict((l, s_formats(l, True)) for l in ['it', 'pt', 'es'])
info_dict = {
'id': 'test',
'title': 'Test',
'url': 'http://localhost/video.mp4',
'subtitles': subtitles,
'automatic_captions': auto_captions,
'extractor': 'TEST',
}
def get_info(params={}):
params.setdefault('simulate', True)
ydl = YDL(params)
ydl.report_warning = lambda *args, **kargs: None
return ydl.process_video_result(info_dict, download=False)
result = get_info()
self.assertFalse(result.get('requested_subtitles'))
self.assertEqual(result['subtitles'], subtitles)
self.assertEqual(result['automatic_captions'], auto_captions)
result = get_info({'writesubtitles': True})
subs = result['requested_subtitles']
self.assertTrue(subs)
self.assertEqual(set(subs.keys()), set(['en']))
self.assertTrue(subs['en'].get('data') is None)
self.assertEqual(subs['en']['ext'], 'ass')
result = get_info({'writesubtitles': True, 'subtitlesformat': 'foo/srt'})
subs = result['requested_subtitles']
self.assertEqual(subs['en']['ext'], 'srt')
result = get_info({'writesubtitles': True, 'subtitleslangs': ['es', 'fr', 'it']})
subs = result['requested_subtitles']
self.assertTrue(subs)
self.assertEqual(set(subs.keys()), set(['es', 'fr']))
result = get_info({'writesubtitles': True, 'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
subs = result['requested_subtitles']
self.assertTrue(subs)
self.assertEqual(set(subs.keys()), set(['es', 'pt']))
self.assertFalse(subs['es']['_auto'])
self.assertTrue(subs['pt']['_auto'])
result = get_info({'writeautomaticsub': True, 'subtitleslangs': ['es', 'pt']})
subs = result['requested_subtitles']
self.assertTrue(subs)
self.assertEqual(set(subs.keys()), set(['es', 'pt']))
self.assertTrue(subs['es']['_auto'])
self.assertTrue(subs['pt']['_auto'])
def test_add_extra_info(self):
test_dict = {
'extractor': 'Foo',
@ -370,5 +481,156 @@ class TestFormatSelection(unittest.TestCase):
'vbr': 10,
}), '^\s*10k$')
def test_postprocessors(self):
filename = 'post-processor-testfile.mp4'
audiofile = filename + '.mp3'
class SimplePP(PostProcessor):
def run(self, info):
with open(audiofile, 'wt') as f:
f.write('EXAMPLE')
return [info['filepath']], info
def run_pp(params, PP):
with open(filename, 'wt') as f:
f.write('EXAMPLE')
ydl = YoutubeDL(params)
ydl.add_post_processor(PP())
ydl.post_process(filename, {'filepath': filename})
run_pp({'keepvideo': True}, SimplePP)
self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
os.unlink(filename)
os.unlink(audiofile)
run_pp({'keepvideo': False}, SimplePP)
self.assertFalse(os.path.exists(filename), '%s exists' % filename)
self.assertTrue(os.path.exists(audiofile), '%s doesn\'t exist' % audiofile)
os.unlink(audiofile)
class ModifierPP(PostProcessor):
def run(self, info):
with open(info['filepath'], 'wt') as f:
f.write('MODIFIED')
return [], info
run_pp({'keepvideo': False}, ModifierPP)
self.assertTrue(os.path.exists(filename), '%s doesn\'t exist' % filename)
os.unlink(filename)
def test_match_filter(self):
class FilterYDL(YDL):
def __init__(self, *args, **kwargs):
super(FilterYDL, self).__init__(*args, **kwargs)
self.params['simulate'] = True
def process_info(self, info_dict):
super(YDL, self).process_info(info_dict)
def _match_entry(self, info_dict, incomplete):
res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
if res is None:
self.downloaded_info_dicts.append(info_dict)
return res
first = {
'id': '1',
'url': TEST_URL,
'title': 'one',
'extractor': 'TEST',
'duration': 30,
'filesize': 10 * 1024,
}
second = {
'id': '2',
'url': TEST_URL,
'title': 'two',
'extractor': 'TEST',
'duration': 10,
'description': 'foo',
'filesize': 5 * 1024,
}
videos = [first, second]
def get_videos(filter_=None):
ydl = FilterYDL({'match_filter': filter_})
for v in videos:
ydl.process_ie_result(v, download=True)
return [v['id'] for v in ydl.downloaded_info_dicts]
res = get_videos()
self.assertEqual(res, ['1', '2'])
def f(v):
if v['id'] == '1':
return None
else:
return 'Video id is not 1'
res = get_videos(f)
self.assertEqual(res, ['1'])
f = match_filter_func('duration < 30')
res = get_videos(f)
self.assertEqual(res, ['2'])
f = match_filter_func('description = foo')
res = get_videos(f)
self.assertEqual(res, ['2'])
f = match_filter_func('description =? foo')
res = get_videos(f)
self.assertEqual(res, ['1', '2'])
f = match_filter_func('filesize > 5KiB')
res = get_videos(f)
self.assertEqual(res, ['1'])
def test_playlist_items_selection(self):
entries = [{
'id': compat_str(i),
'title': compat_str(i),
'url': TEST_URL,
} for i in range(1, 5)]
playlist = {
'_type': 'playlist',
'id': 'test',
'entries': entries,
'extractor': 'test:playlist',
'extractor_key': 'test:playlist',
'webpage_url': 'http://example.com',
}
def get_ids(params):
ydl = YDL(params)
# make a copy because the dictionary can be modified
ydl.process_ie_result(playlist.copy())
return [int(v['id']) for v in ydl.downloaded_info_dicts]
result = get_ids({})
self.assertEqual(result, [1, 2, 3, 4])
result = get_ids({'playlistend': 10})
self.assertEqual(result, [1, 2, 3, 4])
result = get_ids({'playlistend': 2})
self.assertEqual(result, [1, 2])
result = get_ids({'playliststart': 10})
self.assertEqual(result, [])
result = get_ids({'playliststart': 2})
self.assertEqual(result, [2, 3, 4])
result = get_ids({'playlist_items': '2-4'})
self.assertEqual(result, [2, 3, 4])
result = get_ids({'playlist_items': '2,4'})
self.assertEqual(result, [2, 4])
result = get_ids({'playlist_items': '10'})
self.assertEqual(result, [])
if __name__ == '__main__':
unittest.main()

55
test/test_aes.py Normal file
View File

@ -0,0 +1,55 @@
#!/usr/bin/env python
from __future__ import unicode_literals
# Allow direct execution
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl.aes import aes_decrypt, aes_encrypt, aes_cbc_decrypt, aes_decrypt_text
from youtube_dl.utils import bytes_to_intlist, intlist_to_bytes
import base64
# the encrypted data can be generate with 'devscripts/generate_aes_testdata.py'
class TestAES(unittest.TestCase):
def setUp(self):
self.key = self.iv = [0x20, 0x15] + 14 * [0]
self.secret_msg = b'Secret message goes here'
def test_encrypt(self):
msg = b'message'
key = list(range(16))
encrypted = aes_encrypt(bytes_to_intlist(msg), key)
decrypted = intlist_to_bytes(aes_decrypt(encrypted, key))
self.assertEqual(decrypted, msg)
def test_cbc_decrypt(self):
data = bytes_to_intlist(
b"\x97\x92+\xe5\x0b\xc3\x18\x91ky9m&\xb3\xb5@\xe6'\xc2\x96.\xc8u\x88\xab9-[\x9e|\xf1\xcd"
)
decrypted = intlist_to_bytes(aes_cbc_decrypt(data, self.key, self.iv))
self.assertEqual(decrypted.rstrip(b'\x08'), self.secret_msg)
def test_decrypt_text(self):
password = intlist_to_bytes(self.key).decode('utf-8')
encrypted = base64.b64encode(
intlist_to_bytes(self.iv[:8]) +
b'\x17\x15\x93\xab\x8d\x80V\xcdV\xe0\t\xcdo\xc2\xa5\xd8ksM\r\xe27N\xae'
).decode('utf-8')
decrypted = (aes_decrypt_text(encrypted, password, 16))
self.assertEqual(decrypted, self.secret_msg)
password = intlist_to_bytes(self.key).decode('utf-8')
encrypted = base64.b64encode(
intlist_to_bytes(self.iv[:8]) +
b'\x0b\xe6\xa4\xd9z\x0e\xb8\xb9\xd0\xd4i_\x85\x1d\x99\x98_\xe5\x80\xe7.\xbf\xa5\x83'
).decode('utf-8')
decrypted = (aes_decrypt_text(encrypted, password, 32))
self.assertEqual(decrypted, self.secret_msg)
if __name__ == '__main__':
unittest.main()

View File

@ -59,7 +59,7 @@ class TestAllURLsMatching(unittest.TestCase):
self.assertMatch('www.youtube.com/NASAgovVideo/videos', ['youtube:user'])
def test_youtube_feeds(self):
self.assertMatch('https://www.youtube.com/feed/watch_later', ['youtube:watch_later'])
self.assertMatch('https://www.youtube.com/feed/watch_later', ['youtube:watchlater'])
self.assertMatch('https://www.youtube.com/feed/subscriptions', ['youtube:subscriptions'])
self.assertMatch('https://www.youtube.com/feed/recommended', ['youtube:recommended'])
self.assertMatch('https://www.youtube.com/my_favorites', ['youtube:favorites'])
@ -104,11 +104,11 @@ class TestAllURLsMatching(unittest.TestCase):
self.assertMatch(':tds', ['ComedyCentralShows'])
def test_vimeo_matching(self):
self.assertMatch('http://vimeo.com/channels/tributes', ['vimeo:channel'])
self.assertMatch('http://vimeo.com/channels/31259', ['vimeo:channel'])
self.assertMatch('http://vimeo.com/channels/31259/53576664', ['vimeo'])
self.assertMatch('http://vimeo.com/user7108434', ['vimeo:user'])
self.assertMatch('http://vimeo.com/user7108434/videos', ['vimeo:user'])
self.assertMatch('https://vimeo.com/channels/tributes', ['vimeo:channel'])
self.assertMatch('https://vimeo.com/channels/31259', ['vimeo:channel'])
self.assertMatch('https://vimeo.com/channels/31259/53576664', ['vimeo'])
self.assertMatch('https://vimeo.com/user7108434', ['vimeo:user'])
self.assertMatch('https://vimeo.com/user7108434/videos', ['vimeo:user'])
self.assertMatch('https://vimeo.com/user21297594/review/75524534/3c257a1b5d', ['vimeo:review'])
# https://github.com/rg3/youtube-dl/issues/1930

View File

@ -14,6 +14,8 @@ from youtube_dl.utils import get_filesystem_encoding
from youtube_dl.compat import (
compat_getenv,
compat_expanduser,
compat_urllib_parse_unquote,
compat_urllib_parse_unquote_plus,
)
@ -42,5 +44,28 @@ class TestCompat(unittest.TestCase):
dir(youtube_dl.compat))) - set(['unicode_literals'])
self.assertEqual(all_names, sorted(present_names))
def test_compat_urllib_parse_unquote(self):
self.assertEqual(compat_urllib_parse_unquote('abc%20def'), 'abc def')
self.assertEqual(compat_urllib_parse_unquote('%7e/abc+def'), '~/abc+def')
self.assertEqual(compat_urllib_parse_unquote(''), '')
self.assertEqual(compat_urllib_parse_unquote('%'), '%')
self.assertEqual(compat_urllib_parse_unquote('%%'), '%%')
self.assertEqual(compat_urllib_parse_unquote('%%%'), '%%%')
self.assertEqual(compat_urllib_parse_unquote('%2F'), '/')
self.assertEqual(compat_urllib_parse_unquote('%2f'), '/')
self.assertEqual(compat_urllib_parse_unquote('%E6%B4%A5%E6%B3%A2'), '津波')
self.assertEqual(
compat_urllib_parse_unquote('''<meta property="og:description" content="%E2%96%81%E2%96%82%E2%96%83%E2%96%84%25%E2%96%85%E2%96%86%E2%96%87%E2%96%88" />
%<a href="https://ar.wikipedia.org/wiki/%D8%AA%D8%B3%D9%88%D9%86%D8%A7%D9%85%D9%8A">%a'''),
'''<meta property="og:description" content="▁▂▃▄%▅▆▇█" />
%<a href="https://ar.wikipedia.org/wiki/تسونامي">%a''')
self.assertEqual(
compat_urllib_parse_unquote('''%28%5E%E2%97%A3_%E2%97%A2%5E%29%E3%81%A3%EF%B8%BB%E3%83%87%E2%95%90%E4%B8%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%87%80 %E2%86%B6%I%Break%25Things%'''),
'''(^◣_◢^)っ︻デ═一 ⇀ ⇀ ⇀ ⇀ ⇀ ↶%I%Break%Things%''')
def test_compat_urllib_parse_unquote_plus(self):
self.assertEqual(compat_urllib_parse_unquote_plus('abc%20def'), 'abc def')
self.assertEqual(compat_urllib_parse_unquote_plus('%7e/abc+def'), '~/abc def')
if __name__ == '__main__':
unittest.main()

View File

@ -153,7 +153,7 @@ def generator(test_case):
break
if is_playlist:
self.assertEqual(res_dict['_type'], 'playlist')
self.assertTrue(res_dict['_type'] in ['playlist', 'multi_video'])
self.assertTrue('entries' in res_dict)
expect_info_dict(self, res_dict, test_case.get('info_dict', {}))

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python
# coding: utf-8
from __future__ import unicode_literals
import unittest
@ -6,6 +8,9 @@ import unittest
import sys
import os
import subprocess
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl.utils import encodeArgument
rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -27,5 +32,12 @@ class TestExecution(unittest.TestCase):
def test_main_exec(self):
subprocess.check_call([sys.executable, 'youtube_dl/__main__.py', '--version'], cwd=rootDir, stdout=_DEV_NULL)
def test_cmdline_umlauts(self):
p = subprocess.Popen(
[sys.executable, 'youtube_dl/__main__.py', encodeArgument('ä'), '--version'],
cwd=rootDir, stdout=_DEV_NULL, stderr=subprocess.PIPE)
_, stderr = p.communicate()
self.assertFalse(stderr)
if __name__ == '__main__':
unittest.main()

View File

@ -8,7 +8,7 @@ import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl import YoutubeDL
from youtube_dl.compat import compat_http_server
from youtube_dl.compat import compat_http_server, compat_urllib_request
import ssl
import threading
@ -68,5 +68,52 @@ class TestHTTP(unittest.TestCase):
r = ydl.extract_info('https://localhost:%d/video.html' % self.port)
self.assertEqual(r['url'], 'https://localhost:%d/vid.mp4' % self.port)
def _build_proxy_handler(name):
class HTTPTestRequestHandler(compat_http_server.BaseHTTPRequestHandler):
proxy_name = name
def log_message(self, format, *args):
pass
def do_GET(self):
self.send_response(200)
self.send_header('Content-Type', 'text/plain; charset=utf-8')
self.end_headers()
self.wfile.write('{self.proxy_name}: {self.path}'.format(self=self).encode('utf-8'))
return HTTPTestRequestHandler
class TestProxy(unittest.TestCase):
def setUp(self):
self.proxy = compat_http_server.HTTPServer(
('localhost', 0), _build_proxy_handler('normal'))
self.port = self.proxy.socket.getsockname()[1]
self.proxy_thread = threading.Thread(target=self.proxy.serve_forever)
self.proxy_thread.daemon = True
self.proxy_thread.start()
self.cn_proxy = compat_http_server.HTTPServer(
('localhost', 0), _build_proxy_handler('cn'))
self.cn_port = self.cn_proxy.socket.getsockname()[1]
self.cn_proxy_thread = threading.Thread(target=self.cn_proxy.serve_forever)
self.cn_proxy_thread.daemon = True
self.cn_proxy_thread.start()
def test_proxy(self):
cn_proxy = 'localhost:{0}'.format(self.cn_port)
ydl = YoutubeDL({
'proxy': 'localhost:{0}'.format(self.port),
'cn_verification_proxy': cn_proxy,
})
url = 'http://foo.com/bar'
response = ydl.urlopen(url).read().decode('utf-8')
self.assertEqual(response, 'normal: {0}'.format(url))
req = compat_urllib_request.Request(url)
req.add_header('Ytdl-request-proxy', cn_proxy)
response = ydl.urlopen(req).read().decode('utf-8')
self.assertEqual(response, 'cn: {0}'.format(url))
if __name__ == '__main__':
unittest.main()

View File

@ -70,6 +70,8 @@ class TestJSInterpreter(unittest.TestCase):
self.assertEqual(jsi.call_function('f'), -11)
def test_comments(self):
'Skipping: Not yet fully implemented'
return
jsi = JSInterpreter('''
function x() {
var x = /* 1 + */ 2;
@ -80,6 +82,15 @@ class TestJSInterpreter(unittest.TestCase):
''')
self.assertEqual(jsi.call_function('x'), 52)
jsi = JSInterpreter('''
function f() {
var x = "/*";
var y = 1 /* comment */ + 2;
return y;
}
''')
self.assertEqual(jsi.call_function('f'), 3)
def test_precedence(self):
jsi = JSInterpreter('''
function x() {

26
test/test_netrc.py Normal file
View File

@ -0,0 +1,26 @@
# coding: utf-8
from __future__ import unicode_literals
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl.extractor import (
gen_extractors,
)
class TestNetRc(unittest.TestCase):
def test_netrc_present(self):
for ie in gen_extractors():
if not hasattr(ie, '_login'):
continue
self.assertTrue(
hasattr(ie, '_NETRC_MACHINE'),
'Extractor %s supports login, but is missing a _NETRC_MACHINE property' % ie.IE_NAME)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,17 @@
#!/usr/bin/env python
from __future__ import unicode_literals
# Allow direct execution
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl.postprocessor import MetadataFromTitlePP
class TestMetadataFromTitle(unittest.TestCase):
def test_format_to_regex(self):
pp = MetadataFromTitlePP(None, '%(title)s - %(artist)s')
self.assertEqual(pp._titleregex, '(?P<title>.+)\ \-\ (?P<artist>.+)')

View File

@ -18,6 +18,15 @@ from youtube_dl.extractor import (
VimeoIE,
WallaIE,
CeskaTelevizeIE,
LyndaIE,
NPOIE,
ComedyCentralIE,
NRKTVIE,
RaiIE,
VikiIE,
ThePlatformIE,
RTVEALaCartaIE,
FunnyOrDieIE,
)
@ -27,42 +36,38 @@ class BaseTestSubtitles(unittest.TestCase):
def setUp(self):
self.DL = FakeYDL()
self.ie = self.IE(self.DL)
self.ie = self.IE()
self.DL.add_info_extractor(self.ie)
def getInfoDict(self):
info_dict = self.ie.extract(self.url)
info_dict = self.DL.extract_info(self.url, download=False)
return info_dict
def getSubtitles(self):
info_dict = self.getInfoDict()
return info_dict['subtitles']
subtitles = info_dict['requested_subtitles']
if not subtitles:
return subtitles
for sub_info in subtitles.values():
if sub_info.get('data') is None:
uf = self.DL.urlopen(sub_info['url'])
sub_info['data'] = uf.read().decode('utf-8')
return dict((l, sub_info['data']) for l, sub_info in subtitles.items())
class TestYoutubeSubtitles(BaseTestSubtitles):
url = 'QRS8MkLhQmM'
IE = YoutubeIE
def test_youtube_no_writesubtitles(self):
self.DL.params['writesubtitles'] = False
subtitles = self.getSubtitles()
self.assertEqual(subtitles, None)
def test_youtube_subtitles(self):
self.DL.params['writesubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['en']), '4cd9278a35ba2305f47354ee13472260')
def test_youtube_subtitles_lang(self):
self.DL.params['writesubtitles'] = True
self.DL.params['subtitleslangs'] = ['it']
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['it']), '164a51f16f260476a05b50fe4c2f161d')
def test_youtube_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(len(subtitles.keys()), 13)
self.assertEqual(md5(subtitles['en']), '4cd9278a35ba2305f47354ee13472260')
self.assertEqual(md5(subtitles['it']), '164a51f16f260476a05b50fe4c2f161d')
for lang in ['it', 'fr', 'de']:
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
def test_youtube_subtitles_sbv_format(self):
self.DL.params['writesubtitles'] = True
@ -76,12 +81,6 @@ class TestYoutubeSubtitles(BaseTestSubtitles):
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['en']), '3cb210999d3e021bd6c7f0ea751eab06')
def test_youtube_list_subtitles(self):
self.DL.expect_warning('Video doesn\'t have automatic captions')
self.DL.params['listsubtitles'] = True
info_dict = self.getInfoDict()
self.assertEqual(info_dict, None)
def test_youtube_automatic_captions(self):
self.url = '8YoUxe5ncPo'
self.DL.params['writeautomaticsub'] = True
@ -103,55 +102,22 @@ class TestYoutubeSubtitles(BaseTestSubtitles):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(len(subtitles), 0)
def test_youtube_multiple_langs(self):
self.url = 'QRS8MkLhQmM'
self.DL.params['writesubtitles'] = True
langs = ['it', 'fr', 'de']
self.DL.params['subtitleslangs'] = langs
subtitles = self.getSubtitles()
for lang in langs:
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
self.assertFalse(subtitles)
class TestDailymotionSubtitles(BaseTestSubtitles):
url = 'http://www.dailymotion.com/video/xczg00'
IE = DailymotionIE
def test_no_writesubtitles(self):
subtitles = self.getSubtitles()
self.assertEqual(subtitles, None)
def test_subtitles(self):
self.DL.params['writesubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['en']), '976553874490cba125086bbfea3ff76f')
def test_subtitles_lang(self):
self.DL.params['writesubtitles'] = True
self.DL.params['subtitleslangs'] = ['fr']
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['fr']), '594564ec7d588942e384e920e5341792')
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(len(subtitles.keys()), 5)
def test_list_subtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['listsubtitles'] = True
info_dict = self.getInfoDict()
self.assertEqual(info_dict, None)
def test_automatic_captions(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['writeautomaticsub'] = True
self.DL.params['subtitleslang'] = ['en']
subtitles = self.getSubtitles()
self.assertTrue(len(subtitles.keys()) == 0)
self.assertTrue(len(subtitles.keys()) >= 6)
self.assertEqual(md5(subtitles['en']), '976553874490cba125086bbfea3ff76f')
self.assertEqual(md5(subtitles['fr']), '594564ec7d588942e384e920e5341792')
for lang in ['es', 'fr', 'de']:
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
def test_nosubtitles(self):
self.DL.expect_warning('video doesn\'t have subtitles')
@ -159,61 +125,21 @@ class TestDailymotionSubtitles(BaseTestSubtitles):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(len(subtitles), 0)
def test_multiple_langs(self):
self.DL.params['writesubtitles'] = True
langs = ['es', 'fr', 'de']
self.DL.params['subtitleslangs'] = langs
subtitles = self.getSubtitles()
for lang in langs:
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
self.assertFalse(subtitles)
class TestTedSubtitles(BaseTestSubtitles):
url = 'http://www.ted.com/talks/dan_dennett_on_our_consciousness.html'
IE = TEDIE
def test_no_writesubtitles(self):
subtitles = self.getSubtitles()
self.assertEqual(subtitles, None)
def test_subtitles(self):
self.DL.params['writesubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['en']), '4262c1665ff928a2dada178f62cb8d14')
def test_subtitles_lang(self):
self.DL.params['writesubtitles'] = True
self.DL.params['subtitleslangs'] = ['fr']
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['fr']), '66a63f7f42c97a50f8c0e90bc7797bb5')
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertTrue(len(subtitles.keys()) >= 28)
def test_list_subtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['listsubtitles'] = True
info_dict = self.getInfoDict()
self.assertEqual(info_dict, None)
def test_automatic_captions(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['writeautomaticsub'] = True
self.DL.params['subtitleslang'] = ['en']
subtitles = self.getSubtitles()
self.assertTrue(len(subtitles.keys()) == 0)
def test_multiple_langs(self):
self.DL.params['writesubtitles'] = True
langs = ['es', 'fr', 'de']
self.DL.params['subtitleslangs'] = langs
subtitles = self.getSubtitles()
for lang in langs:
self.assertEqual(md5(subtitles['en']), '4262c1665ff928a2dada178f62cb8d14')
self.assertEqual(md5(subtitles['fr']), '66a63f7f42c97a50f8c0e90bc7797bb5')
for lang in ['es', 'fr', 'de']:
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
@ -221,14 +147,7 @@ class TestBlipTVSubtitles(BaseTestSubtitles):
url = 'http://blip.tv/a/a-6603250'
IE = BlipTVIE
def test_list_subtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['listsubtitles'] = True
info_dict = self.getInfoDict()
self.assertEqual(info_dict, None)
def test_allsubtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
@ -240,39 +159,13 @@ class TestVimeoSubtitles(BaseTestSubtitles):
url = 'http://vimeo.com/76979871'
IE = VimeoIE
def test_no_writesubtitles(self):
subtitles = self.getSubtitles()
self.assertEqual(subtitles, None)
def test_subtitles(self):
self.DL.params['writesubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['en']), '26399116d23ae3cf2c087cea94bc43b4')
def test_subtitles_lang(self):
self.DL.params['writesubtitles'] = True
self.DL.params['subtitleslangs'] = ['fr']
subtitles = self.getSubtitles()
self.assertEqual(md5(subtitles['fr']), 'b6191146a6c5d3a452244d853fde6dc8')
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['de', 'en', 'es', 'fr']))
def test_list_subtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['listsubtitles'] = True
info_dict = self.getInfoDict()
self.assertEqual(info_dict, None)
def test_automatic_captions(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['writeautomaticsub'] = True
self.DL.params['subtitleslang'] = ['en']
subtitles = self.getSubtitles()
self.assertTrue(len(subtitles.keys()) == 0)
self.assertEqual(md5(subtitles['en']), '8062383cf4dec168fc40a088aa6d5888')
self.assertEqual(md5(subtitles['fr']), 'b6191146a6c5d3a452244d853fde6dc8')
def test_nosubtitles(self):
self.DL.expect_warning('video doesn\'t have subtitles')
@ -280,27 +173,13 @@ class TestVimeoSubtitles(BaseTestSubtitles):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(len(subtitles), 0)
def test_multiple_langs(self):
self.DL.params['writesubtitles'] = True
langs = ['es', 'fr', 'de']
self.DL.params['subtitleslangs'] = langs
subtitles = self.getSubtitles()
for lang in langs:
self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)
self.assertFalse(subtitles)
class TestWallaSubtitles(BaseTestSubtitles):
url = 'http://vod.walla.co.il/movie/2705958/the-yes-men'
IE = WallaIE
def test_list_subtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['listsubtitles'] = True
info_dict = self.getInfoDict()
self.assertEqual(info_dict, None)
def test_allsubtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['writesubtitles'] = True
@ -315,26 +194,20 @@ class TestWallaSubtitles(BaseTestSubtitles):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(len(subtitles), 0)
self.assertFalse(subtitles)
class TestCeskaTelevizeSubtitles(BaseTestSubtitles):
url = 'http://www.ceskatelevize.cz/ivysilani/10600540290-u6-uzasny-svet-techniky'
IE = CeskaTelevizeIE
def test_list_subtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['listsubtitles'] = True
info_dict = self.getInfoDict()
self.assertEqual(info_dict, None)
def test_allsubtitles(self):
self.DL.expect_warning('Automatic Captions not supported by this server')
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['cs']))
self.assertEqual(md5(subtitles['cs']), '9bf52d9549533c32c427e264bf0847d4')
self.assertTrue(len(subtitles['cs']) > 20000)
def test_nosubtitles(self):
self.DL.expect_warning('video doesn\'t have subtitles')
@ -342,7 +215,122 @@ class TestCeskaTelevizeSubtitles(BaseTestSubtitles):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(len(subtitles), 0)
self.assertFalse(subtitles)
class TestLyndaSubtitles(BaseTestSubtitles):
url = 'http://www.lynda.com/Bootstrap-tutorials/Using-exercise-files/110885/114408-4.html'
IE = LyndaIE
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['en']))
self.assertEqual(md5(subtitles['en']), '09bbe67222259bed60deaa26997d73a7')
class TestNPOSubtitles(BaseTestSubtitles):
url = 'http://www.npo.nl/nos-journaal/28-08-2014/POW_00722860'
IE = NPOIE
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['nl']))
self.assertEqual(md5(subtitles['nl']), 'fc6435027572b63fb4ab143abd5ad3f4')
class TestMTVSubtitles(BaseTestSubtitles):
url = 'http://www.cc.com/video-clips/kllhuv/stand-up-greg-fitzsimmons--uncensored---too-good-of-a-mother'
IE = ComedyCentralIE
def getInfoDict(self):
return super(TestMTVSubtitles, self).getInfoDict()['entries'][0]
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['en']))
self.assertEqual(md5(subtitles['en']), 'b9f6ca22a6acf597ec76f61749765e65')
class TestNRKSubtitles(BaseTestSubtitles):
url = 'http://tv.nrk.no/serie/ikke-gjoer-dette-hjemme/DMPV73000411/sesong-2/episode-1'
IE = NRKTVIE
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['no']))
self.assertEqual(md5(subtitles['no']), '544fa917d3197fcbee64634559221cc2')
class TestRaiSubtitles(BaseTestSubtitles):
url = 'http://www.rai.tv/dl/RaiTV/programmi/media/ContentItem-cb27157f-9dd0-4aee-b788-b1f67643a391.html'
IE = RaiIE
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['it']))
self.assertEqual(md5(subtitles['it']), 'b1d90a98755126b61e667567a1f6680a')
class TestVikiSubtitles(BaseTestSubtitles):
url = 'http://www.viki.com/videos/1060846v-punch-episode-18'
IE = VikiIE
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['en']))
self.assertEqual(md5(subtitles['en']), '53cb083a5914b2d84ef1ab67b880d18a')
class TestThePlatformSubtitles(BaseTestSubtitles):
# from http://www.3playmedia.com/services-features/tools/integrations/theplatform/
# (see http://theplatform.com/about/partners/type/subtitles-closed-captioning/)
url = 'theplatform:JFUjUE1_ehvq'
IE = ThePlatformIE
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['en']))
self.assertEqual(md5(subtitles['en']), '97e7670cbae3c4d26ae8bcc7fdd78d4b')
class TestRtveSubtitles(BaseTestSubtitles):
url = 'http://www.rtve.es/alacarta/videos/los-misterios-de-laura/misterios-laura-capitulo-32-misterio-del-numero-17-2-parte/2428621/'
IE = RTVEALaCartaIE
def test_allsubtitles(self):
print('Skipping, only available from Spain')
return
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['es']))
self.assertEqual(md5(subtitles['es']), '69e70cae2d40574fb7316f31d6eb7fca')
class TestFunnyOrDieSubtitles(BaseTestSubtitles):
url = 'http://www.funnyordie.com/videos/224829ff6d/judd-apatow-will-direct-your-vine'
IE = FunnyOrDieIE
def test_allsubtitles(self):
self.DL.params['writesubtitles'] = True
self.DL.params['allsubtitles'] = True
subtitles = self.getSubtitles()
self.assertEqual(set(subtitles.keys()), set(['en']))
self.assertEqual(md5(subtitles['en']), 'c5593c193eacd353596c11c2d4f9ecc4')
if __name__ == '__main__':

View File

@ -34,8 +34,8 @@ def _make_testfunc(testfile):
def test_func(self):
as_file = os.path.join(TEST_DIR, testfile)
swf_file = os.path.join(TEST_DIR, test_id + '.swf')
if ((not os.path.exists(swf_file))
or os.path.getmtime(swf_file) < os.path.getmtime(as_file)):
if ((not os.path.exists(swf_file)) or
os.path.getmtime(swf_file) < os.path.getmtime(as_file)):
# Recompile
try:
subprocess.check_call([

View File

@ -17,13 +17,22 @@ IGNORED_FILES = [
'buildserver.py',
]
IGNORED_DIRS = [
'.git',
'.tox',
]
from test.helper import assertRegexpMatches
class TestUnicodeLiterals(unittest.TestCase):
def test_all_files(self):
for dirpath, _, filenames in os.walk(rootDir):
for dirpath, dirnames, filenames in os.walk(rootDir):
for ignore_dir in IGNORED_DIRS:
if ignore_dir in dirnames:
# If we remove the directory from dirnames os.walk won't
# recurse into it
dirnames.remove(ignore_dir)
for basename in filenames:
if not basename.endswith('.py'):
continue

View File

@ -24,6 +24,7 @@ from youtube_dl.utils import (
encodeFilename,
escape_rfc3986,
escape_url,
ExtractorError,
find_xpath_attr,
fix_xml_ampersands,
InAdvancePagedList,
@ -38,6 +39,9 @@ from youtube_dl.utils import (
parse_iso8601,
read_batch_urls,
sanitize_filename,
sanitize_path,
prepend_extension,
replace_extension,
shell_quote,
smuggle_url,
str_to_int,
@ -48,11 +52,16 @@ from youtube_dl.utils import (
unified_strdate,
unsmuggle_url,
uppercase_escape,
lowercase_escape,
url_basename,
urlencode_postdata,
version_tuple,
xpath_with_ns,
xpath_text,
render_table,
match_str,
parse_dfxp_time_expr,
dfxp2srt,
)
@ -85,6 +94,11 @@ class TestUtil(unittest.TestCase):
sanitize_filename('New World record at 0:12:34'),
'New World record at 0_12_34')
self.assertEqual(sanitize_filename('--gasdgf'), '_-gasdgf')
self.assertEqual(sanitize_filename('--gasdgf', is_id=True), '--gasdgf')
self.assertEqual(sanitize_filename('.gasdgf'), 'gasdgf')
self.assertEqual(sanitize_filename('.gasdgf', is_id=True), '.gasdgf')
forbidden = '"\0\\/'
for fc in forbidden:
for fbc in forbidden:
@ -125,6 +139,58 @@ class TestUtil(unittest.TestCase):
self.assertEqual(sanitize_filename('_BD_eEpuzXw', is_id=True), '_BD_eEpuzXw')
self.assertEqual(sanitize_filename('N0Y__7-UOdI', is_id=True), 'N0Y__7-UOdI')
def test_sanitize_path(self):
if sys.platform != 'win32':
return
self.assertEqual(sanitize_path('abc'), 'abc')
self.assertEqual(sanitize_path('abc/def'), 'abc\\def')
self.assertEqual(sanitize_path('abc\\def'), 'abc\\def')
self.assertEqual(sanitize_path('abc|def'), 'abc#def')
self.assertEqual(sanitize_path('<>:"|?*'), '#######')
self.assertEqual(sanitize_path('C:/abc/def'), 'C:\\abc\\def')
self.assertEqual(sanitize_path('C?:/abc/def'), 'C##\\abc\\def')
self.assertEqual(sanitize_path('\\\\?\\UNC\\ComputerName\\abc'), '\\\\?\\UNC\\ComputerName\\abc')
self.assertEqual(sanitize_path('\\\\?\\UNC/ComputerName/abc'), '\\\\?\\UNC\\ComputerName\\abc')
self.assertEqual(sanitize_path('\\\\?\\C:\\abc'), '\\\\?\\C:\\abc')
self.assertEqual(sanitize_path('\\\\?\\C:/abc'), '\\\\?\\C:\\abc')
self.assertEqual(sanitize_path('\\\\?\\C:\\ab?c\\de:f'), '\\\\?\\C:\\ab#c\\de#f')
self.assertEqual(sanitize_path('\\\\?\\C:\\abc'), '\\\\?\\C:\\abc')
self.assertEqual(
sanitize_path('youtube/%(uploader)s/%(autonumber)s-%(title)s-%(upload_date)s.%(ext)s'),
'youtube\\%(uploader)s\\%(autonumber)s-%(title)s-%(upload_date)s.%(ext)s')
self.assertEqual(
sanitize_path('youtube/TheWreckingYard ./00001-Not bad, Especially for Free! (1987 Yamaha 700)-20141116.mp4.part'),
'youtube\\TheWreckingYard #\\00001-Not bad, Especially for Free! (1987 Yamaha 700)-20141116.mp4.part')
self.assertEqual(sanitize_path('abc/def...'), 'abc\\def..#')
self.assertEqual(sanitize_path('abc.../def'), 'abc..#\\def')
self.assertEqual(sanitize_path('abc.../def...'), 'abc..#\\def..#')
self.assertEqual(sanitize_path('../abc'), '..\\abc')
self.assertEqual(sanitize_path('../../abc'), '..\\..\\abc')
self.assertEqual(sanitize_path('./abc'), 'abc')
self.assertEqual(sanitize_path('./../abc'), '..\\abc')
def test_prepend_extension(self):
self.assertEqual(prepend_extension('abc.ext', 'temp'), 'abc.temp.ext')
self.assertEqual(prepend_extension('abc.ext', 'temp', 'ext'), 'abc.temp.ext')
self.assertEqual(prepend_extension('abc.unexpected_ext', 'temp', 'ext'), 'abc.unexpected_ext.temp')
self.assertEqual(prepend_extension('abc', 'temp'), 'abc.temp')
self.assertEqual(prepend_extension('.abc', 'temp'), '.abc.temp')
self.assertEqual(prepend_extension('.abc.ext', 'temp'), '.abc.temp.ext')
def test_replace_extension(self):
self.assertEqual(replace_extension('abc.ext', 'temp'), 'abc.temp')
self.assertEqual(replace_extension('abc.ext', 'temp', 'ext'), 'abc.temp')
self.assertEqual(replace_extension('abc.unexpected_ext', 'temp', 'ext'), 'abc.unexpected_ext.temp')
self.assertEqual(replace_extension('abc', 'temp'), 'abc.temp')
self.assertEqual(replace_extension('.abc', 'temp'), '.abc.temp')
self.assertEqual(replace_extension('.abc.ext', 'temp'), '.abc.temp')
def test_ordered_set(self):
self.assertEqual(orderedSet([1, 1, 2, 3, 4, 4, 5, 6, 7, 3, 5]), [1, 2, 3, 4, 5, 6, 7])
self.assertEqual(orderedSet([]), [])
@ -134,6 +200,8 @@ class TestUtil(unittest.TestCase):
def test_unescape_html(self):
self.assertEqual(unescapeHTML('%20;'), '%20;')
self.assertEqual(unescapeHTML('&#x2F;'), '/')
self.assertEqual(unescapeHTML('&#47;'), '/')
self.assertEqual(
unescapeHTML('&eacute;'), 'é')
@ -156,6 +224,10 @@ class TestUtil(unittest.TestCase):
self.assertEqual(
unified_strdate('11/26/2014 11:30:00 AM PST', day_first=False),
'20141126')
self.assertEqual(
unified_strdate('2/2/2015 6:47:40 PM', day_first=False),
'20150202')
self.assertEqual(unified_strdate('25-09-2014'), '20140925')
def test_find_xpath_attr(self):
testxml = '''<root>
@ -163,12 +235,21 @@ class TestUtil(unittest.TestCase):
<node x="a"/>
<node x="a" y="c" />
<node x="b" y="d" />
<node x="" />
</root>'''
doc = xml.etree.ElementTree.fromstring(testxml)
self.assertEqual(find_xpath_attr(doc, './/fourohfour', 'n'), None)
self.assertEqual(find_xpath_attr(doc, './/fourohfour', 'n', 'v'), None)
self.assertEqual(find_xpath_attr(doc, './/node', 'n'), None)
self.assertEqual(find_xpath_attr(doc, './/node', 'n', 'v'), None)
self.assertEqual(find_xpath_attr(doc, './/node', 'x'), doc[1])
self.assertEqual(find_xpath_attr(doc, './/node', 'x', 'a'), doc[1])
self.assertEqual(find_xpath_attr(doc, './/node', 'x', 'b'), doc[3])
self.assertEqual(find_xpath_attr(doc, './/node', 'y'), doc[2])
self.assertEqual(find_xpath_attr(doc, './/node', 'y', 'c'), doc[2])
self.assertEqual(find_xpath_attr(doc, './/node', 'y', 'd'), doc[3])
self.assertEqual(find_xpath_attr(doc, './/node', 'x', ''), doc[4])
def test_xpath_with_ns(self):
testxml = '''<root xmlns:media="http://example.com/">
@ -183,6 +264,17 @@ class TestUtil(unittest.TestCase):
self.assertEqual(find('media:song/media:author').text, 'The Author')
self.assertEqual(find('media:song/url').text, 'http://server.com/download.mp3')
def test_xpath_text(self):
testxml = '''<root>
<div>
<p>Foo</p>
</div>
</root>'''
doc = xml.etree.ElementTree.fromstring(testxml)
self.assertEqual(xpath_text(doc, 'div/p'), 'Foo')
self.assertTrue(xpath_text(doc, 'div/bar') is None)
self.assertRaises(ExtractorError, xpath_text, doc, 'div/bar', fatal=True)
def test_smuggle_url(self):
data = {"ö": "ö", "abc": [3]}
url = 'https://foo.bar/baz?x=y#a'
@ -238,6 +330,10 @@ class TestUtil(unittest.TestCase):
self.assertEqual(parse_duration('5 s'), 5)
self.assertEqual(parse_duration('3 min'), 180)
self.assertEqual(parse_duration('2.5 hours'), 9000)
self.assertEqual(parse_duration('02:03:04'), 7384)
self.assertEqual(parse_duration('01:02:03:04'), 93784)
self.assertEqual(parse_duration('1 hour 3 minutes'), 3780)
self.assertEqual(parse_duration('87 Min.'), 5220)
def test_fix_xml_ampersands(self):
self.assertEqual(
@ -312,6 +408,10 @@ class TestUtil(unittest.TestCase):
self.assertEqual(uppercase_escape(''), '')
self.assertEqual(uppercase_escape('\\U0001d550'), '𝕐')
def test_lowercase_escape(self):
self.assertEqual(lowercase_escape(''), '')
self.assertEqual(lowercase_escape('\\u0026'), '&')
def test_limit_length(self):
self.assertEqual(limit_length(None, 12), None)
self.assertEqual(limit_length('foo', 12), 'foo')
@ -364,6 +464,10 @@ class TestUtil(unittest.TestCase):
"playlist":[{"controls":{"all":null}}]
}''')
inp = '"SAND Number: SAND 2013-7800P\\nPresenter: Tom Russo\\nHabanero Software Training - Xyce Software\\nXyce, Sandia\\u0027s"'
json_code = js_to_json(inp)
self.assertEqual(json.loads(json_code), json.loads(inp))
def test_js_to_json_edgecases(self):
on = js_to_json("{abc_def:'1\\'\\\\2\\\\\\'3\"4'}")
self.assertEqual(json.loads(on), {"abc_def": "1'\\2\\'3\"4"})
@ -371,6 +475,22 @@ class TestUtil(unittest.TestCase):
on = js_to_json('{"abc": true}')
self.assertEqual(json.loads(on), {'abc': True})
# Ignore JavaScript code as well
on = js_to_json('''{
"x": 1,
y: "a",
z: some.code
}''')
d = json.loads(on)
self.assertEqual(d['x'], 1)
self.assertEqual(d['y'], 'a')
on = js_to_json('["abc", "def",]')
self.assertEqual(json.loads(on), ['abc', 'def'])
on = js_to_json('{"abc": "def",}')
self.assertEqual(json.loads(on), {'abc': 'def'})
def test_clean_html(self):
self.assertEqual(clean_html('a:\nb'), 'a: b')
self.assertEqual(clean_html('a:\n "b"'), 'a: "b"')
@ -444,6 +564,88 @@ ffmpeg version 2.4.4 Copyright (c) 2000-2014 the FFmpeg ...'''), '2.4.4')
'123 4\n'
'9999 51')
def test_match_str(self):
self.assertRaises(ValueError, match_str, 'xy>foobar', {})
self.assertFalse(match_str('xy', {'x': 1200}))
self.assertTrue(match_str('!xy', {'x': 1200}))
self.assertTrue(match_str('x', {'x': 1200}))
self.assertFalse(match_str('!x', {'x': 1200}))
self.assertTrue(match_str('x', {'x': 0}))
self.assertFalse(match_str('x>0', {'x': 0}))
self.assertFalse(match_str('x>0', {}))
self.assertTrue(match_str('x>?0', {}))
self.assertTrue(match_str('x>1K', {'x': 1200}))
self.assertFalse(match_str('x>2K', {'x': 1200}))
self.assertTrue(match_str('x>=1200 & x < 1300', {'x': 1200}))
self.assertFalse(match_str('x>=1100 & x < 1200', {'x': 1200}))
self.assertFalse(match_str('y=a212', {'y': 'foobar42'}))
self.assertTrue(match_str('y=foobar42', {'y': 'foobar42'}))
self.assertFalse(match_str('y!=foobar42', {'y': 'foobar42'}))
self.assertTrue(match_str('y!=foobar2', {'y': 'foobar42'}))
self.assertFalse(match_str(
'like_count > 100 & dislike_count <? 50 & description',
{'like_count': 90, 'description': 'foo'}))
self.assertTrue(match_str(
'like_count > 100 & dislike_count <? 50 & description',
{'like_count': 190, 'description': 'foo'}))
self.assertFalse(match_str(
'like_count > 100 & dislike_count <? 50 & description',
{'like_count': 190, 'dislike_count': 60, 'description': 'foo'}))
self.assertFalse(match_str(
'like_count > 100 & dislike_count <? 50 & description',
{'like_count': 190, 'dislike_count': 10}))
def test_parse_dfxp_time_expr(self):
self.assertEqual(parse_dfxp_time_expr(None), 0.0)
self.assertEqual(parse_dfxp_time_expr(''), 0.0)
self.assertEqual(parse_dfxp_time_expr('0.1'), 0.1)
self.assertEqual(parse_dfxp_time_expr('0.1s'), 0.1)
self.assertEqual(parse_dfxp_time_expr('00:00:01'), 1.0)
self.assertEqual(parse_dfxp_time_expr('00:00:01.100'), 1.1)
def test_dfxp2srt(self):
dfxp_data = '''<?xml version="1.0" encoding="UTF-8"?>
<tt xmlns="http://www.w3.org/ns/ttml" xml:lang="en" xmlns:tts="http://www.w3.org/ns/ttml#parameter">
<body>
<div xml:lang="en">
<p begin="0" end="1">The following line contains Chinese characters and special symbols</p>
<p begin="1" end="2">第二行<br/>♪♪</p>
<p begin="2" dur="1"><span>Third<br/>Line</span></p>
</div>
</body>
</tt>'''
srt_data = '''1
00:00:00,000 --> 00:00:01,000
The following line contains Chinese characters and special symbols
2
00:00:01,000 --> 00:00:02,000
第二行
♪♪
3
00:00:02,000 --> 00:00:03,000
Third
Line
'''
self.assertEqual(dfxp2srt(dfxp_data), srt_data)
dfxp_data_no_default_namespace = '''<?xml version="1.0" encoding="UTF-8"?>
<tt xml:lang="en" xmlns:tts="http://www.w3.org/ns/ttml#parameter">
<body>
<div xml:lang="en">
<p begin="0" end="1">The first line</p>
</div>
</body>
</tt>'''
srt_data = '''1
00:00:00,000 --> 00:00:01,000
The first line
'''
self.assertEqual(dfxp2srt(dfxp_data_no_default_namespace), srt_data)
if __name__ == '__main__':
unittest.main()

View File

@ -8,11 +8,11 @@ import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import io
import re
import string
from test.helper import FakeYDL
from youtube_dl.extractor import YoutubeIE
from youtube_dl.compat import compat_str, compat_urlretrieve
@ -64,6 +64,12 @@ _TESTS = [
'js',
'4646B5181C6C3020DF1D9C7FCFEA.AD80ABF70C39BD369CCCAE780AFBB98FA6B6CB42766249D9488C288',
'82C8849D94266724DC6B6AF89BBFA087EACCD963.B93C07FBA084ACAEFCF7C9D1FD0203C6C1815B6B'
),
(
'https://s.ytimg.com/yts/jsbin/html5player-en_US-vflKjOTVq/html5player.js',
'js',
'312AA52209E3623129A412D56A40F11CB0AF14AE.3EE09501CB14E3BCDC3B2AE808BF3F1D14E7FBF12',
'112AA5220913623229A412D56A40F11CB0AF14AE.3EE0950FCB14EEBCDC3B2AE808BF331D14E7FBF3',
)
]
@ -88,7 +94,8 @@ def make_tfunc(url, stype, sig_input, expected_sig):
if not os.path.exists(fn):
compat_urlretrieve(url, fn)
ie = YoutubeIE()
ydl = FakeYDL()
ie = YoutubeIE(ydl)
if stype == 'js':
with io.open(fn, encoding='utf-8') as testf:
jscode = testf.read()

View File

@ -1,8 +1,13 @@
[tox]
envlist = py26,py27,py33
envlist = py26,py27,py33,py34
[testenv]
deps =
nose
coverage
commands = nosetests --verbose {posargs:test} # --with-coverage --cover-package=youtube_dl --cover-html
# We need a valid $HOME for test_compat_expanduser
passenv = HOME
defaultargs = test --exclude test_download.py --exclude test_age_restriction.py
--exclude test_subtitles.py --exclude test_write_annotations.py
--exclude test_youtube_lists.py
commands = nosetests --verbose {posargs:{[testenv]defaultargs}} # --with-coverage --cover-package=youtube_dl --cover-html
# test.test_download:TestDownload.test_NowVideo

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ import codecs
import io
import os
import random
import shlex
import sys
@ -23,9 +24,10 @@ from .compat import (
)
from .utils import (
DateRange,
DEFAULT_OUTTMPL,
decodeOption,
DEFAULT_OUTTMPL,
DownloadError,
match_filter_func,
MaxDownloadsReached,
preferredencoding,
read_batch_urls,
@ -167,8 +169,11 @@ def _real_main(argv=None):
if not opts.audioquality.isdigit():
parser.error('invalid audio quality specified')
if opts.recodevideo is not None:
if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg', 'mkv']:
if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg', 'mkv', 'avi']:
parser.error('invalid video recode format specified')
if opts.convertsubtitles is not None:
if opts.convertsubtitles not in ['srt', 'vtt', 'ass']:
parser.error('invalid subtitle format specified')
if opts.date is not None:
date = DateRange.day(opts.date)
@ -184,18 +189,14 @@ def _real_main(argv=None):
if opts.allsubtitles and not opts.writeautomaticsub:
opts.writesubtitles = True
if sys.version_info < (3,):
# In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
if opts.outtmpl is not None:
opts.outtmpl = opts.outtmpl.decode(preferredencoding())
outtmpl = ((opts.outtmpl is not None and opts.outtmpl)
or (opts.format == '-1' and opts.usetitle and '%(title)s-%(id)s-%(format)s.%(ext)s')
or (opts.format == '-1' and '%(id)s-%(format)s.%(ext)s')
or (opts.usetitle and opts.autonumber and '%(autonumber)s-%(title)s-%(id)s.%(ext)s')
or (opts.usetitle and '%(title)s-%(id)s.%(ext)s')
or (opts.useid and '%(id)s.%(ext)s')
or (opts.autonumber and '%(autonumber)s-%(id)s.%(ext)s')
or DEFAULT_OUTTMPL)
outtmpl = ((opts.outtmpl is not None and opts.outtmpl) or
(opts.format == '-1' and opts.usetitle and '%(title)s-%(id)s-%(format)s.%(ext)s') or
(opts.format == '-1' and '%(id)s-%(format)s.%(ext)s') or
(opts.usetitle and opts.autonumber and '%(autonumber)s-%(title)s-%(id)s.%(ext)s') or
(opts.usetitle and '%(title)s-%(id)s.%(ext)s') or
(opts.useid and '%(id)s.%(ext)s') or
(opts.autonumber and '%(autonumber)s-%(id)s.%(ext)s') or
DEFAULT_OUTTMPL)
if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
parser.error('Cannot download a video and extract audio into the same'
' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
@ -208,6 +209,11 @@ def _real_main(argv=None):
# PostProcessors
postprocessors = []
# Add the metadata pp first, the other pps will copy it
if opts.metafromtitle:
postprocessors.append({
'key': 'MetadataFromTitle',
'titleformat': opts.metafromtitle
})
if opts.addmetadata:
postprocessors.append({'key': 'FFmpegMetadata'})
if opts.extractaudio:
@ -222,23 +228,30 @@ def _real_main(argv=None):
'key': 'FFmpegVideoConvertor',
'preferedformat': opts.recodevideo,
})
if opts.convertsubtitles:
postprocessors.append({
'key': 'FFmpegSubtitlesConvertor',
'format': opts.convertsubtitles,
})
if opts.embedsubtitles:
postprocessors.append({
'key': 'FFmpegEmbedSubtitle',
'subtitlesformat': opts.subtitlesformat,
})
if opts.xattrs:
postprocessors.append({'key': 'XAttrMetadata'})
if opts.embedthumbnail:
if not opts.addmetadata:
postprocessors.append({'key': 'FFmpegAudioFix'})
postprocessors.append({'key': 'AtomicParsley'})
already_have_thumbnail = opts.writethumbnail or opts.write_all_thumbnails
postprocessors.append({
'key': 'EmbedThumbnail',
'already_have_thumbnail': already_have_thumbnail
})
if not already_have_thumbnail:
opts.writethumbnail = True
# Please keep ExecAfterDownload towards the bottom as it allows the user to modify the final file in any way.
# So if the user is able to remove the file before your postprocessor runs it might cause a few problems.
if opts.exec_cmd:
postprocessors.append({
'key': 'ExecAfterDownload',
'verboseOutput': opts.verbose,
'exec_cmd': opts.exec_cmd,
})
if opts.xattr_set_filesize:
@ -247,6 +260,15 @@ def _real_main(argv=None):
xattr # Confuse flake8
except ImportError:
parser.error('setting filesize xattr requested but python-xattr is not available')
external_downloader_args = None
if opts.external_downloader_args:
external_downloader_args = shlex.split(opts.external_downloader_args)
postprocessor_args = None
if opts.postprocessor_args:
postprocessor_args = shlex.split(opts.postprocessor_args)
match_filter = (
None if opts.match_filter is None
else match_filter_func(opts.match_filter))
ydl_opts = {
'usenetrc': opts.usenetrc,
@ -269,12 +291,12 @@ def _real_main(argv=None):
'simulate': opts.simulate or any_getting,
'skip_download': opts.skip_download,
'format': opts.format,
'format_limit': opts.format_limit,
'listformats': opts.listformats,
'outtmpl': outtmpl,
'autonumber_size': opts.autonumber_size,
'restrictfilenames': opts.restrictfilenames,
'ignoreerrors': opts.ignoreerrors,
'force_generic_extractor': opts.force_generic_extractor,
'ratelimit': opts.ratelimit,
'nooverwrites': opts.nooverwrites,
'retries': opts_retries,
@ -332,7 +354,6 @@ def _real_main(argv=None):
'default_search': opts.default_search,
'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
'encoding': opts.encoding,
'exec_cmd': opts.exec_cmd,
'extract_flat': opts.extract_flat,
'merge_output_format': opts.merge_output_format,
'postprocessors': postprocessors,
@ -344,6 +365,13 @@ def _real_main(argv=None):
'list_thumbnails': opts.list_thumbnails,
'playlist_items': opts.playlist_items,
'xattr_set_filesize': opts.xattr_set_filesize,
'match_filter': match_filter,
'no_color': opts.no_color,
'ffmpeg_location': opts.ffmpeg_location,
'hls_prefer_native': opts.hls_prefer_native,
'external_downloader_args': external_downloader_args,
'postprocessor_args': postprocessor_args,
'cn_verification_proxy': opts.cn_verification_proxy,
}
with YoutubeDL(ydl_opts) as ydl:

View File

@ -1,7 +1,5 @@
from __future__ import unicode_literals
__all__ = ['aes_encrypt', 'key_expansion', 'aes_ctr_decrypt', 'aes_cbc_decrypt', 'aes_decrypt_text']
import base64
from math import ceil
@ -154,7 +152,7 @@ def aes_decrypt_text(data, password, key_size_bytes):
"""
NONCE_LENGTH_BYTES = 8
data = bytes_to_intlist(base64.b64decode(data))
data = bytes_to_intlist(base64.b64decode(data.encode('utf-8')))
password = bytes_to_intlist(password.encode('utf-8'))
key = password[:key_size_bytes] + [0] * (key_size_bytes - len(password))
@ -329,3 +327,5 @@ def inc(data):
data[i] = data[i] + 1
break
return data
__all__ = ['aes_encrypt', 'key_expansion', 'aes_ctr_decrypt', 'aes_cbc_decrypt', 'aes_decrypt_text']

View File

@ -1,12 +1,15 @@
from __future__ import unicode_literals
import collections
import getpass
import optparse
import os
import re
import shutil
import socket
import subprocess
import sys
import itertools
try:
@ -39,16 +42,16 @@ try:
except ImportError: # Python 2
import cookielib as compat_cookiejar
try:
import http.cookies as compat_cookies
except ImportError: # Python 2
import Cookie as compat_cookies
try:
import html.entities as compat_html_entities
except ImportError: # Python 2
import htmlentitydefs as compat_html_entities
try:
import html.parser as compat_html_parser
except ImportError: # Python 2
import HTMLParser as compat_html_parser
try:
import http.client as compat_http_client
except ImportError: # Python 2
@ -77,42 +80,74 @@ except ImportError:
import BaseHTTPServer as compat_http_server
try:
from urllib.parse import unquote_to_bytes as compat_urllib_parse_unquote_to_bytes
from urllib.parse import unquote as compat_urllib_parse_unquote
except ImportError:
def compat_urllib_parse_unquote(string, encoding='utf-8', errors='replace'):
if string == '':
from urllib.parse import unquote_plus as compat_urllib_parse_unquote_plus
except ImportError: # Python 2
_asciire = (compat_urllib_parse._asciire if hasattr(compat_urllib_parse, '_asciire')
else re.compile('([\x00-\x7f]+)'))
# HACK: The following are the correct unquote_to_bytes, unquote and unquote_plus
# implementations from cpython 3.4.3's stdlib. Python 2's version
# is apparently broken (see https://github.com/rg3/youtube-dl/pull/6244)
def compat_urllib_parse_unquote_to_bytes(string):
"""unquote_to_bytes('abc%20def') -> b'abc def'."""
# Note: strings are encoded as UTF-8. This is only an issue if it contains
# unescaped non-ASCII characters, which URIs should not.
if not string:
# Is it a string-like object?
string.split
return b''
if isinstance(string, unicode):
string = string.encode('utf-8')
bits = string.split(b'%')
if len(bits) == 1:
return string
res = string.split('%')
if len(res) == 1:
res = [bits[0]]
append = res.append
for item in bits[1:]:
try:
append(compat_urllib_parse._hextochr[item[:2]])
append(item[2:])
except KeyError:
append(b'%')
append(item)
return b''.join(res)
def compat_urllib_parse_unquote(string, encoding='utf-8', errors='replace'):
"""Replace %xx escapes by their single-character equivalent. The optional
encoding and errors parameters specify how to decode percent-encoded
sequences into Unicode characters, as accepted by the bytes.decode()
method.
By default, percent-encoded sequences are decoded with UTF-8, and invalid
sequences are replaced by a placeholder character.
unquote('abc%20def') -> 'abc def'.
"""
if '%' not in string:
string.split
return string
if encoding is None:
encoding = 'utf-8'
if errors is None:
errors = 'replace'
# pct_sequence: contiguous sequence of percent-encoded bytes, decoded
pct_sequence = b''
string = res[0]
for item in res[1:]:
try:
if not item:
raise ValueError
pct_sequence += item[:2].decode('hex')
rest = item[2:]
if not rest:
# This segment was just a single percent-encoded character.
# May be part of a sequence of code units, so delay decoding.
# (Stored in pct_sequence).
continue
except ValueError:
rest = '%' + item
# Encountered non-percent-encoded characters. Flush the current
# pct_sequence.
string += pct_sequence.decode(encoding, errors) + rest
pct_sequence = b''
if pct_sequence:
# Flush the final pct_sequence
string += pct_sequence.decode(encoding, errors)
return string
bits = _asciire.split(string)
res = [bits[0]]
append = res.append
for i in range(1, len(bits), 2):
append(compat_urllib_parse_unquote_to_bytes(bits[i]).decode(encoding, errors))
append(bits[i + 1])
return ''.join(res)
def compat_urllib_parse_unquote_plus(string, encoding='utf-8', errors='replace'):
"""Like unquote(), but also replace plus signs by spaces, as required for
unquoting HTML form values.
unquote_plus('%7e/abc+def') -> '~/abc def'
"""
string = string.replace('+', ' ')
return compat_urllib_parse_unquote(string, encoding, errors)
try:
compat_str = unicode # Python 2
@ -364,19 +399,62 @@ def workaround_optparse_bug9161():
return real_add_option(self, *bargs, **bkwargs)
optparse.OptionGroup.add_option = _compat_add_option
if hasattr(shutil, 'get_terminal_size'): # Python >= 3.3
compat_get_terminal_size = shutil.get_terminal_size
else:
_terminal_size = collections.namedtuple('terminal_size', ['columns', 'lines'])
def compat_get_terminal_size():
columns = compat_getenv('COLUMNS', None)
if columns:
columns = int(columns)
else:
columns = None
lines = compat_getenv('LINES', None)
if lines:
lines = int(lines)
else:
lines = None
try:
sp = subprocess.Popen(
['stty', 'size'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = sp.communicate()
lines, columns = map(int, out.split())
except Exception:
pass
return _terminal_size(columns, lines)
try:
itertools.count(start=0, step=1)
compat_itertools_count = itertools.count
except TypeError: # Python 2.6
def compat_itertools_count(start=0, step=1):
n = start
while True:
yield n
n += step
if sys.version_info >= (3, 0):
from tokenize import tokenize as compat_tokenize_tokenize
else:
from tokenize import generate_tokens as compat_tokenize_tokenize
__all__ = [
'compat_HTTPError',
'compat_basestring',
'compat_chr',
'compat_cookiejar',
'compat_cookies',
'compat_expanduser',
'compat_get_terminal_size',
'compat_getenv',
'compat_getpass',
'compat_html_entities',
'compat_html_parser',
'compat_http_client',
'compat_http_server',
'compat_itertools_count',
'compat_kwargs',
'compat_ord',
'compat_parse_qs',
@ -384,9 +462,12 @@ __all__ = [
'compat_socket_create_connection',
'compat_str',
'compat_subprocess_get_DEVNULL',
'compat_tokenize_tokenize',
'compat_urllib_error',
'compat_urllib_parse',
'compat_urllib_parse_unquote',
'compat_urllib_parse_unquote_plus',
'compat_urllib_parse_unquote_to_bytes',
'compat_urllib_parse_urlparse',
'compat_urllib_request',
'compat_urlparse',

View File

@ -6,8 +6,9 @@ from .f4m import F4mFD
from .hls import HlsFD
from .hls import NativeHlsFD
from .http import HttpFD
from .mplayer import MplayerFD
from .rtsp import RtspFD
from .rtmp import RtmpFD
from .dash import DashSegmentsFD
from ..utils import (
determine_protocol,
@ -17,9 +18,10 @@ PROTOCOL_MAP = {
'rtmp': RtmpFD,
'm3u8_native': NativeHlsFD,
'm3u8': HlsFD,
'mms': MplayerFD,
'rtsp': MplayerFD,
'mms': RtspFD,
'rtsp': RtspFD,
'f4m': F4mFD,
'http_dash_segments': DashSegmentsFD,
}
@ -34,6 +36,9 @@ def get_suitable_downloader(info_dict, params={}):
if ed.supports(info_dict):
return ed
if protocol == 'm3u8' and params.get('hls_prefer_native'):
return NativeHlsFD
return PROTOCOL_MAP.get(protocol, HttpFD)

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals
from __future__ import division, unicode_literals
import os
import re
@ -8,6 +8,7 @@ import time
from ..compat import compat_str
from ..utils import (
encodeFilename,
decodeArgument,
format_bytes,
timeconvert,
)
@ -42,6 +43,8 @@ class FileDownloader(object):
max_filesize: Skip files larger than this size
xattr_set_filesize: Set ytdl.filesize user xattribute with expected size.
(experimenatal)
external_downloader_args: A list of additional command-line arguments for the
external downloader.
Subclasses of this one must re-define the real_download method.
"""
@ -54,6 +57,7 @@ class FileDownloader(object):
self.ydl = ydl
self._progress_hooks = []
self.params = params
self.add_progress_hook(self.report_progress)
@staticmethod
def format_seconds(seconds):
@ -201,7 +205,7 @@ class FileDownloader(object):
return
try:
os.utime(filename, (time.time(), filetime))
except:
except Exception:
pass
return filetime
@ -226,42 +230,64 @@ class FileDownloader(object):
self.to_screen(clear_line + fullmsg, skip_eol=not is_last_line)
self.to_console_title('youtube-dl ' + msg)
def report_progress(self, percent, data_len_str, speed, eta):
"""Report download progress."""
if self.params.get('noprogress', False):
def report_progress(self, s):
if s['status'] == 'finished':
if self.params.get('noprogress', False):
self.to_screen('[download] Download completed')
else:
s['_total_bytes_str'] = format_bytes(s['total_bytes'])
if s.get('elapsed') is not None:
s['_elapsed_str'] = self.format_seconds(s['elapsed'])
msg_template = '100%% of %(_total_bytes_str)s in %(_elapsed_str)s'
else:
msg_template = '100%% of %(_total_bytes_str)s'
self._report_progress_status(
msg_template % s, is_last_line=True)
if self.params.get('noprogress'):
return
if eta is not None:
eta_str = self.format_eta(eta)
else:
eta_str = 'Unknown ETA'
if percent is not None:
percent_str = self.format_percent(percent)
else:
percent_str = 'Unknown %'
speed_str = self.format_speed(speed)
msg = ('%s of %s at %s ETA %s' %
(percent_str, data_len_str, speed_str, eta_str))
self._report_progress_status(msg)
def report_progress_live_stream(self, downloaded_data_len, speed, elapsed):
if self.params.get('noprogress', False):
if s['status'] != 'downloading':
return
downloaded_str = format_bytes(downloaded_data_len)
speed_str = self.format_speed(speed)
elapsed_str = FileDownloader.format_seconds(elapsed)
msg = '%s at %s (%s)' % (downloaded_str, speed_str, elapsed_str)
self._report_progress_status(msg)
def report_finish(self, data_len_str, tot_time):
"""Report download finished."""
if self.params.get('noprogress', False):
self.to_screen('[download] Download completed')
if s.get('eta') is not None:
s['_eta_str'] = self.format_eta(s['eta'])
else:
self._report_progress_status(
('100%% of %s in %s' %
(data_len_str, self.format_seconds(tot_time))),
is_last_line=True)
s['_eta_str'] = 'Unknown ETA'
if s.get('total_bytes') and s.get('downloaded_bytes') is not None:
s['_percent_str'] = self.format_percent(100 * s['downloaded_bytes'] / s['total_bytes'])
elif s.get('total_bytes_estimate') and s.get('downloaded_bytes') is not None:
s['_percent_str'] = self.format_percent(100 * s['downloaded_bytes'] / s['total_bytes_estimate'])
else:
if s.get('downloaded_bytes') == 0:
s['_percent_str'] = self.format_percent(0)
else:
s['_percent_str'] = 'Unknown %'
if s.get('speed') is not None:
s['_speed_str'] = self.format_speed(s['speed'])
else:
s['_speed_str'] = 'Unknown speed'
if s.get('total_bytes') is not None:
s['_total_bytes_str'] = format_bytes(s['total_bytes'])
msg_template = '%(_percent_str)s of %(_total_bytes_str)s at %(_speed_str)s ETA %(_eta_str)s'
elif s.get('total_bytes_estimate') is not None:
s['_total_bytes_estimate_str'] = format_bytes(s['total_bytes_estimate'])
msg_template = '%(_percent_str)s of ~%(_total_bytes_estimate_str)s at %(_speed_str)s ETA %(_eta_str)s'
else:
if s.get('downloaded_bytes') is not None:
s['_downloaded_bytes_str'] = format_bytes(s['downloaded_bytes'])
if s.get('elapsed'):
s['_elapsed_str'] = self.format_seconds(s['elapsed'])
msg_template = '%(_downloaded_bytes_str)s at %(_speed_str)s (%(_elapsed_str)s)'
else:
msg_template = '%(_downloaded_bytes_str)s at %(_speed_str)s'
else:
msg_template = '%(_percent_str)s % at %(_speed_str)s ETA %(_eta_str)s'
self._report_progress_status(msg_template % s)
def report_resuming_byte(self, resume_len):
"""Report attempt to resume at given byte."""
@ -288,14 +314,14 @@ class FileDownloader(object):
"""
nooverwrites_and_exists = (
self.params.get('nooverwrites', False)
and os.path.exists(encodeFilename(filename))
self.params.get('nooverwrites', False) and
os.path.exists(encodeFilename(filename))
)
continuedl_and_exists = (
self.params.get('continuedl', False)
and os.path.isfile(encodeFilename(filename))
and not self.params.get('nopart', False)
self.params.get('continuedl', True) and
os.path.isfile(encodeFilename(filename)) and
not self.params.get('nopart', False)
)
# Check file already present
@ -328,19 +354,15 @@ class FileDownloader(object):
# this interface
self._progress_hooks.append(ph)
def _debug_cmd(self, args, subprocess_encoding, exe=None):
def _debug_cmd(self, args, exe=None):
if not self.params.get('verbose', False):
return
if exe is None:
exe = os.path.basename(args[0])
str_args = [decodeArgument(a) for a in args]
if exe is None:
exe = os.path.basename(str_args[0])
if subprocess_encoding:
str_args = [
a.decode(subprocess_encoding) if isinstance(a, bytes) else a
for a in args]
else:
str_args = args
try:
import pipes
shell_quote = lambda args: ' '.join(map(pipes.quote, str_args))

View File

@ -0,0 +1,66 @@
from __future__ import unicode_literals
import re
from .common import FileDownloader
from ..compat import compat_urllib_request
class DashSegmentsFD(FileDownloader):
"""
Download segments in a DASH manifest
"""
def real_download(self, filename, info_dict):
self.report_destination(filename)
tmpfilename = self.temp_name(filename)
base_url = info_dict['url']
segment_urls = info_dict['segment_urls']
is_test = self.params.get('test', False)
remaining_bytes = self._TEST_FILE_SIZE if is_test else None
byte_counter = 0
def append_url_to_file(outf, target_url, target_name, remaining_bytes=None):
self.to_screen('[DashSegments] %s: Downloading %s' % (info_dict['id'], target_name))
req = compat_urllib_request.Request(target_url)
if remaining_bytes is not None:
req.add_header('Range', 'bytes=0-%d' % (remaining_bytes - 1))
data = self.ydl.urlopen(req).read()
if remaining_bytes is not None:
data = data[:remaining_bytes]
outf.write(data)
return len(data)
def combine_url(base_url, target_url):
if re.match(r'^https?://', target_url):
return target_url
return '%s%s%s' % (base_url, '' if base_url.endswith('/') else '/', target_url)
with open(tmpfilename, 'wb') as outf:
append_url_to_file(
outf, combine_url(base_url, info_dict['initialization_url']),
'initialization segment')
for i, segment_url in enumerate(segment_urls):
segment_len = append_url_to_file(
outf, combine_url(base_url, segment_url),
'segment %d / %d' % (i + 1, len(segment_urls)),
remaining_bytes)
byte_counter += segment_len
if remaining_bytes is not None:
remaining_bytes -= segment_len
if remaining_bytes <= 0:
break
self.try_rename(tmpfilename, filename)
self._hook_progress({
'downloaded_bytes': byte_counter,
'total_bytes': byte_counter,
'filename': filename,
'status': 'finished',
})
return True

View File

@ -2,11 +2,11 @@ from __future__ import unicode_literals
import os.path
import subprocess
import sys
from .common import FileDownloader
from ..utils import (
encodeFilename,
encodeArgument,
)
@ -51,19 +51,18 @@ class ExternalFD(FileDownloader):
return []
return [command_option, source_address]
def _configuration_args(self, default=[]):
ex_args = self.params.get('external_downloader_args')
if ex_args is None:
return default
assert isinstance(ex_args, list)
return ex_args
def _call_downloader(self, tmpfilename, info_dict):
""" Either overwrite this or implement _make_cmd """
cmd = self._make_cmd(tmpfilename, info_dict)
cmd = [encodeArgument(a) for a in self._make_cmd(tmpfilename, info_dict)]
if sys.platform == 'win32' and sys.version_info < (3, 0):
# Windows subprocess module does not actually support Unicode
# on Python 2.x
# See http://stackoverflow.com/a/9951851/35070
subprocess_encoding = sys.getfilesystemencoding()
cmd = [a.encode(subprocess_encoding, 'ignore') for a in cmd]
else:
subprocess_encoding = None
self._debug_cmd(cmd, subprocess_encoding)
self._debug_cmd(cmd)
p = subprocess.Popen(
cmd, stderr=subprocess.PIPE)
@ -75,10 +74,11 @@ class ExternalFD(FileDownloader):
class CurlFD(ExternalFD):
def _make_cmd(self, tmpfilename, info_dict):
cmd = [self.exe, '-o', tmpfilename]
cmd = [self.exe, '--location', '-o', tmpfilename]
for key, val in info_dict['http_headers'].items():
cmd += ['--header', '%s: %s' % (key, val)]
cmd += self._source_address('--interface')
cmd += self._configuration_args()
cmd += ['--', info_dict['url']]
return cmd
@ -89,15 +89,16 @@ class WgetFD(ExternalFD):
for key, val in info_dict['http_headers'].items():
cmd += ['--header', '%s: %s' % (key, val)]
cmd += self._source_address('--bind-address')
cmd += self._configuration_args()
cmd += ['--', info_dict['url']]
return cmd
class Aria2cFD(ExternalFD):
def _make_cmd(self, tmpfilename, info_dict):
cmd = [
self.exe, '-c',
'--min-split-size', '1M', '--max-connection-per-server', '4']
cmd = [self.exe, '-c']
cmd += self._configuration_args([
'--min-split-size', '1M', '--max-connection-per-server', '4'])
dn = os.path.dirname(tmpfilename)
if dn:
cmd += ['--dir', dn]
@ -108,6 +109,14 @@ class Aria2cFD(ExternalFD):
cmd += ['--', info_dict['url']]
return cmd
class HttpieFD(ExternalFD):
def _make_cmd(self, tmpfilename, info_dict):
cmd = ['http', '--download', '--output', tmpfilename, info_dict['url']]
for key, val in info_dict['http_headers'].items():
cmd += ['%s:%s' % (key, val)]
return cmd
_BY_NAME = dict(
(klass.get_basename(), klass)
for name, klass in globals().items()
@ -122,5 +131,6 @@ def list_external_downloaders():
def get_external_downloader(external_downloader):
""" Given the name of the executable, see whether we support the given
downloader . """
bn = os.path.basename(external_downloader)
# Drop .exe extension on Windows
bn = os.path.splitext(os.path.basename(external_downloader))[0]
return _BY_NAME[bn]

View File

@ -1,4 +1,4 @@
from __future__ import unicode_literals
from __future__ import division, unicode_literals
import base64
import io
@ -7,17 +7,14 @@ import os
import time
import xml.etree.ElementTree as etree
from .common import FileDownloader
from .http import HttpFD
from .fragment import FragmentFD
from ..compat import (
compat_urlparse,
compat_urllib_error,
)
from ..utils import (
struct_pack,
struct_unpack,
format_bytes,
encodeFilename,
sanitize_open,
xpath_text,
)
@ -122,7 +119,8 @@ class FlvReader(io.BytesIO):
self.read_unsigned_int() # BootstrapinfoVersion
# Profile,Live,Update,Reserved
self.read(1)
flags = self.read_unsigned_char()
live = flags & 0x20 != 0
# time scale
self.read_unsigned_int()
# CurrentMediaTime
@ -161,6 +159,7 @@ class FlvReader(io.BytesIO):
return {
'segments': segments,
'fragments': fragments,
'live': live,
}
def read_bootstrap_info(self):
@ -183,6 +182,10 @@ def build_fragments_list(boot_info):
for segment, fragments_count in segment_run_table['segment_run']:
for _ in range(fragments_count):
res.append((segment, next(fragments_counter)))
if boot_info['live']:
res = res[-2:]
return res
@ -220,16 +223,13 @@ def _add_ns(prop):
return '{http://ns.adobe.com/f4m/1.0}%s' % prop
class HttpQuietDownloader(HttpFD):
def to_screen(self, *args, **kargs):
pass
class F4mFD(FileDownloader):
class F4mFD(FragmentFD):
"""
A downloader for f4m manifests or AdobeHDS.
"""
FD_NAME = 'f4m'
def _get_unencrypted_media(self, doc):
media = doc.findall(_add_ns('media'))
if not media:
@ -247,22 +247,43 @@ class F4mFD(FileDownloader):
self.report_error('Unsupported DRM')
return media
def _get_bootstrap_from_url(self, bootstrap_url):
bootstrap = self.ydl.urlopen(bootstrap_url).read()
return read_bootstrap_info(bootstrap)
def _update_live_fragments(self, bootstrap_url, latest_fragment):
fragments_list = []
retries = 30
while (not fragments_list) and (retries > 0):
boot_info = self._get_bootstrap_from_url(bootstrap_url)
fragments_list = build_fragments_list(boot_info)
fragments_list = [f for f in fragments_list if f[1] > latest_fragment]
if not fragments_list:
# Retry after a while
time.sleep(5.0)
retries -= 1
if not fragments_list:
self.report_error('Failed to update fragments')
return fragments_list
def _parse_bootstrap_node(self, node, base_url):
if node.text is None:
bootstrap_url = compat_urlparse.urljoin(
base_url, node.attrib['url'])
boot_info = self._get_bootstrap_from_url(bootstrap_url)
else:
bootstrap_url = None
bootstrap = base64.b64decode(node.text.encode('ascii'))
boot_info = read_bootstrap_info(bootstrap)
return (boot_info, bootstrap_url)
def real_download(self, filename, info_dict):
man_url = info_dict['url']
requested_bitrate = info_dict.get('tbr')
self.to_screen('[download] Downloading f4m manifest')
self.to_screen('[%s] Downloading f4m manifest' % self.FD_NAME)
manifest = self.ydl.urlopen(man_url).read()
self.report_destination(filename)
http_dl = HttpQuietDownloader(
self.ydl,
{
'continuedl': True,
'quiet': True,
'noprogress': True,
'ratelimit': self.params.get('ratelimit', None),
'test': self.params.get('test', False),
}
)
doc = etree.fromstring(manifest)
formats = [(int(f.attrib.get('bitrate', -1)), f)
@ -277,18 +298,13 @@ class F4mFD(FileDownloader):
base_url = compat_urlparse.urljoin(man_url, media.attrib['url'])
bootstrap_node = doc.find(_add_ns('bootstrapInfo'))
if bootstrap_node.text is None:
bootstrap_url = compat_urlparse.urljoin(
base_url, bootstrap_node.attrib['url'])
bootstrap = self.ydl.urlopen(bootstrap_url).read()
else:
bootstrap = base64.b64decode(bootstrap_node.text)
boot_info, bootstrap_url = self._parse_bootstrap_node(bootstrap_node, base_url)
live = boot_info['live']
metadata_node = media.find(_add_ns('metadata'))
if metadata_node is not None:
metadata = base64.b64decode(metadata_node.text)
metadata = base64.b64decode(metadata_node.text.encode('ascii'))
else:
metadata = None
boot_info = read_bootstrap_info(bootstrap)
fragments_list = build_fragments_list(boot_info)
if self.params.get('test', False):
@ -298,74 +314,67 @@ class F4mFD(FileDownloader):
# For some akamai manifests we'll need to add a query to the fragment url
akamai_pv = xpath_text(doc, _add_ns('pv-2.0'))
tmpfilename = self.temp_name(filename)
(dest_stream, tmpfilename) = sanitize_open(tmpfilename, 'wb')
write_flv_header(dest_stream)
write_metadata_tag(dest_stream, metadata)
# This dict stores the download progress, it's updated by the progress
# hook
state = {
'downloaded_bytes': 0,
'frag_counter': 0,
ctx = {
'filename': filename,
'total_frags': total_frags,
}
start = time.time()
def frag_progress_hook(status):
frag_total_bytes = status.get('total_bytes', 0)
estimated_size = (state['downloaded_bytes'] +
(total_frags - state['frag_counter']) * frag_total_bytes)
if status['status'] == 'finished':
state['downloaded_bytes'] += frag_total_bytes
state['frag_counter'] += 1
progress = self.calc_percent(state['frag_counter'], total_frags)
byte_counter = state['downloaded_bytes']
else:
frag_downloaded_bytes = status['downloaded_bytes']
byte_counter = state['downloaded_bytes'] + frag_downloaded_bytes
frag_progress = self.calc_percent(frag_downloaded_bytes,
frag_total_bytes)
progress = self.calc_percent(state['frag_counter'], total_frags)
progress += frag_progress / float(total_frags)
self._prepare_frag_download(ctx)
eta = self.calc_eta(start, time.time(), estimated_size, byte_counter)
self.report_progress(progress, format_bytes(estimated_size),
status.get('speed'), eta)
http_dl.add_progress_hook(frag_progress_hook)
dest_stream = ctx['dest_stream']
write_flv_header(dest_stream)
if not live:
write_metadata_tag(dest_stream, metadata)
self._start_frag_download(ctx)
frags_filenames = []
for (seg_i, frag_i) in fragments_list:
while fragments_list:
seg_i, frag_i = fragments_list.pop(0)
name = 'Seg%d-Frag%d' % (seg_i, frag_i)
url = base_url + name
if akamai_pv:
url += '?' + akamai_pv.strip(';')
frag_filename = '%s-%s' % (tmpfilename, name)
success = http_dl.download(frag_filename, {'url': url})
if not success:
return False
with open(frag_filename, 'rb') as down:
down_data = down.read()
reader = FlvReader(down_data)
while True:
_, box_type, box_data = reader.read_box_info()
if box_type == b'mdat':
dest_stream.write(box_data)
break
frags_filenames.append(frag_filename)
if info_dict.get('extra_param_to_segment_url'):
url += info_dict.get('extra_param_to_segment_url')
frag_filename = '%s-%s' % (ctx['tmpfilename'], name)
try:
success = ctx['dl'].download(frag_filename, {'url': url})
if not success:
return False
with open(frag_filename, 'rb') as down:
down_data = down.read()
reader = FlvReader(down_data)
while True:
_, box_type, box_data = reader.read_box_info()
if box_type == b'mdat':
dest_stream.write(box_data)
break
if live:
os.remove(frag_filename)
else:
frags_filenames.append(frag_filename)
except (compat_urllib_error.HTTPError, ) as err:
if live and (err.code == 404 or err.code == 410):
# We didn't keep up with the live window. Continue
# with the next available fragment.
msg = 'Fragment %d unavailable' % frag_i
self.report_warning(msg)
fragments_list = []
else:
raise
dest_stream.close()
self.report_finish(format_bytes(state['downloaded_bytes']), time.time() - start)
if not fragments_list and live and bootstrap_url:
fragments_list = self._update_live_fragments(bootstrap_url, frag_i)
total_frags += len(fragments_list)
if fragments_list and (fragments_list[0][1] > frag_i + 1):
msg = 'Missed %d fragments' % (fragments_list[0][1] - (frag_i + 1))
self.report_warning(msg)
self._finish_frag_download(ctx)
self.try_rename(tmpfilename, filename)
for frag_file in frags_filenames:
os.remove(frag_file)
fsize = os.path.getsize(encodeFilename(filename))
self._hook_progress({
'downloaded_bytes': fsize,
'total_bytes': fsize,
'filename': filename,
'status': 'finished',
})
return True

View File

@ -0,0 +1,110 @@
from __future__ import division, unicode_literals
import os
import time
from .common import FileDownloader
from .http import HttpFD
from ..utils import (
encodeFilename,
sanitize_open,
)
class HttpQuietDownloader(HttpFD):
def to_screen(self, *args, **kargs):
pass
class FragmentFD(FileDownloader):
"""
A base file downloader class for fragmented media (e.g. f4m/m3u8 manifests).
"""
def _prepare_and_start_frag_download(self, ctx):
self._prepare_frag_download(ctx)
self._start_frag_download(ctx)
def _prepare_frag_download(self, ctx):
self.to_screen('[%s] Total fragments: %d' % (self.FD_NAME, ctx['total_frags']))
self.report_destination(ctx['filename'])
dl = HttpQuietDownloader(
self.ydl,
{
'continuedl': True,
'quiet': True,
'noprogress': True,
'ratelimit': self.params.get('ratelimit', None),
'test': self.params.get('test', False),
}
)
tmpfilename = self.temp_name(ctx['filename'])
dest_stream, tmpfilename = sanitize_open(tmpfilename, 'wb')
ctx.update({
'dl': dl,
'dest_stream': dest_stream,
'tmpfilename': tmpfilename,
})
def _start_frag_download(self, ctx):
total_frags = ctx['total_frags']
# This dict stores the download progress, it's updated by the progress
# hook
state = {
'status': 'downloading',
'downloaded_bytes': 0,
'frag_index': 0,
'frag_count': total_frags,
'filename': ctx['filename'],
'tmpfilename': ctx['tmpfilename'],
}
start = time.time()
ctx['started'] = start
def frag_progress_hook(s):
if s['status'] not in ('downloading', 'finished'):
return
frag_total_bytes = s.get('total_bytes', 0)
if s['status'] == 'finished':
state['downloaded_bytes'] += frag_total_bytes
state['frag_index'] += 1
estimated_size = (
(state['downloaded_bytes'] + frag_total_bytes) /
(state['frag_index'] + 1) * total_frags)
time_now = time.time()
state['total_bytes_estimate'] = estimated_size
state['elapsed'] = time_now - start
if s['status'] == 'finished':
progress = self.calc_percent(state['frag_index'], total_frags)
else:
frag_downloaded_bytes = s['downloaded_bytes']
frag_progress = self.calc_percent(frag_downloaded_bytes,
frag_total_bytes)
progress = self.calc_percent(state['frag_index'], total_frags)
progress += frag_progress / float(total_frags)
state['eta'] = self.calc_eta(
start, time_now, estimated_size, state['downloaded_bytes'] + frag_downloaded_bytes)
state['speed'] = s.get('speed')
self._hook_progress(state)
ctx['dl'].add_progress_hook(frag_progress_hook)
return start
def _finish_frag_download(self, ctx):
ctx['dest_stream'].close()
elapsed = time.time() - ctx['started']
self.try_rename(ctx['tmpfilename'], ctx['filename'])
fsize = os.path.getsize(encodeFilename(ctx['filename']))
self._hook_progress({
'downloaded_bytes': fsize,
'total_bytes': fsize,
'filename': ctx['filename'],
'status': 'finished',
'elapsed': elapsed,
})

View File

@ -4,12 +4,11 @@ import os
import re
import subprocess
from ..postprocessor.ffmpeg import FFmpegPostProcessor
from .common import FileDownloader
from ..compat import (
compat_urlparse,
compat_urllib_request,
)
from .fragment import FragmentFD
from ..compat import compat_urlparse
from ..postprocessor.ffmpeg import FFmpegPostProcessor
from ..utils import (
encodeArgument,
encodeFilename,
@ -23,15 +22,14 @@ class HlsFD(FileDownloader):
tmpfilename = self.temp_name(filename)
ffpp = FFmpegPostProcessor(downloader=self)
program = ffpp._executable
if program is None:
if not ffpp.available:
self.report_error('m3u8 download detected but ffmpeg or avconv could not be found. Please install one.')
return False
ffpp.check_version()
args = [
encodeArgument(opt)
for opt in (program, '-y', '-i', url, '-f', 'mp4', '-c', 'copy', '-bsf:a', 'aac_adtstoasc')]
for opt in (ffpp.executable, '-y', '-i', url, '-f', 'mp4', '-c', 'copy', '-bsf:a', 'aac_adtstoasc')]
args.append(encodeFilename(tmpfilename, True))
retval = subprocess.call(args)
@ -48,58 +46,54 @@ class HlsFD(FileDownloader):
return True
else:
self.to_stderr('\n')
self.report_error('%s exited with code %d' % (program, retval))
self.report_error('%s exited with code %d' % (ffpp.basename, retval))
return False
class NativeHlsFD(FileDownloader):
class NativeHlsFD(FragmentFD):
""" A more limited implementation that does not require ffmpeg """
def real_download(self, filename, info_dict):
url = info_dict['url']
self.report_destination(filename)
tmpfilename = self.temp_name(filename)
FD_NAME = 'hlsnative'
self.to_screen(
'[hlsnative] %s: Downloading m3u8 manifest' % info_dict['id'])
data = self.ydl.urlopen(url).read()
s = data.decode('utf-8', 'ignore')
segment_urls = []
def real_download(self, filename, info_dict):
man_url = info_dict['url']
self.to_screen('[%s] Downloading m3u8 manifest' % self.FD_NAME)
manifest = self.ydl.urlopen(man_url).read()
s = manifest.decode('utf-8', 'ignore')
fragment_urls = []
for line in s.splitlines():
line = line.strip()
if line and not line.startswith('#'):
segment_url = (
line
if re.match(r'^https?://', line)
else compat_urlparse.urljoin(url, line))
segment_urls.append(segment_url)
is_test = self.params.get('test', False)
remaining_bytes = self._TEST_FILE_SIZE if is_test else None
byte_counter = 0
with open(tmpfilename, 'wb') as outf:
for i, segurl in enumerate(segment_urls):
self.to_screen(
'[hlsnative] %s: Downloading segment %d / %d' %
(info_dict['id'], i + 1, len(segment_urls)))
seg_req = compat_urllib_request.Request(segurl)
if remaining_bytes is not None:
seg_req.add_header('Range', 'bytes=0-%d' % (remaining_bytes - 1))
segment = self.ydl.urlopen(seg_req).read()
if remaining_bytes is not None:
segment = segment[:remaining_bytes]
remaining_bytes -= len(segment)
outf.write(segment)
byte_counter += len(segment)
if remaining_bytes is not None and remaining_bytes <= 0:
else compat_urlparse.urljoin(man_url, line))
fragment_urls.append(segment_url)
# We only download the first fragment during the test
if self.params.get('test', False):
break
self._hook_progress({
'downloaded_bytes': byte_counter,
'total_bytes': byte_counter,
ctx = {
'filename': filename,
'status': 'finished',
})
self.try_rename(tmpfilename, filename)
'total_frags': len(fragment_urls),
}
self._prepare_and_start_frag_download(ctx)
frags_filenames = []
for i, frag_url in enumerate(fragment_urls):
frag_filename = '%s-Frag%d' % (ctx['tmpfilename'], i)
success = ctx['dl'].download(frag_filename, {'url': frag_url})
if not success:
return False
with open(frag_filename, 'rb') as down:
ctx['dest_stream'].write(down.read())
frags_filenames.append(frag_filename)
self._finish_frag_download(ctx)
for frag_file in frags_filenames:
os.remove(frag_file)
return True

View File

@ -1,10 +1,10 @@
from __future__ import unicode_literals
import os
import time
from socket import error as SocketError
import errno
import os
import socket
import time
import re
from .common import FileDownloader
from ..compat import (
@ -15,7 +15,6 @@ from ..utils import (
ContentTooShortError,
encodeFilename,
sanitize_open,
format_bytes,
)
@ -30,13 +29,8 @@ class HttpFD(FileDownloader):
add_headers = info_dict.get('http_headers')
if add_headers:
headers.update(add_headers)
data = info_dict.get('http_post_data')
http_method = info_dict.get('http_method')
basic_request = compat_urllib_request.Request(url, data, headers)
request = compat_urllib_request.Request(url, data, headers)
if http_method is not None:
basic_request.get_method = lambda: http_method
request.get_method = lambda: http_method
basic_request = compat_urllib_request.Request(url, None, headers)
request = compat_urllib_request.Request(url, None, headers)
is_test = self.params.get('test', False)
@ -51,7 +45,7 @@ class HttpFD(FileDownloader):
open_mode = 'wb'
if resume_len != 0:
if self.params.get('continuedl', False):
if self.params.get('continuedl', True):
self.report_resuming_byte(resume_len)
request.add_header('Range', 'bytes=%d-' % resume_len)
open_mode = 'ab'
@ -64,6 +58,24 @@ class HttpFD(FileDownloader):
# Establish connection
try:
data = self.ydl.urlopen(request)
# When trying to resume, Content-Range HTTP header of response has to be checked
# to match the value of requested Range HTTP header. This is due to a webservers
# that don't support resuming and serve a whole file with no Content-Range
# set in response despite of requested Range (see
# https://github.com/rg3/youtube-dl/issues/6057#issuecomment-126129799)
if resume_len > 0:
content_range = data.headers.get('Content-Range')
if content_range:
content_range_m = re.search(r'bytes (\d+)-', content_range)
# Content-Range is present and matches requested Range, resume is possible
if content_range_m and resume_len == int(content_range_m.group(1)):
break
# Content-Range is either not present or invalid. Assuming remote webserver is
# trying to send the whole file, resume is not possible, so wiping the local file
# and performing entire redownload
self.report_unable_to_resume()
resume_len = 0
open_mode = 'wb'
break
except (compat_urllib_error.HTTPError, ) as err:
if (err.code < 500 or err.code >= 600) and err.code != 416:
@ -94,6 +106,8 @@ class HttpFD(FileDownloader):
self._hook_progress({
'filename': filename,
'status': 'finished',
'downloaded_bytes': resume_len,
'total_bytes': resume_len,
})
return True
else:
@ -102,7 +116,7 @@ class HttpFD(FileDownloader):
resume_len = 0
open_mode = 'wb'
break
except SocketError as e:
except socket.error as e:
if e.errno != errno.ECONNRESET:
# Connection reset is no problem, just retry
raise
@ -137,7 +151,6 @@ class HttpFD(FileDownloader):
self.to_screen('\r[download] File is larger than max-filesize (%s bytes > %s bytes). Aborting.' % (data_len, max_data_len))
return False
data_len_str = format_bytes(data_len)
byte_counter = 0 + resume_len
block_size = self.params.get('buffersize', 1024)
start = time.time()
@ -196,20 +209,19 @@ class HttpFD(FileDownloader):
# Progress message
speed = self.calc_speed(start, now, byte_counter - resume_len)
if data_len is None:
eta = percent = None
eta = None
else:
percent = self.calc_percent(byte_counter, data_len)
eta = self.calc_eta(start, time.time(), data_len - resume_len, byte_counter - resume_len)
self.report_progress(percent, data_len_str, speed, eta)
self._hook_progress({
'status': 'downloading',
'downloaded_bytes': byte_counter,
'total_bytes': data_len,
'tmpfilename': tmpfilename,
'filename': filename,
'status': 'downloading',
'eta': eta,
'speed': speed,
'elapsed': now - start,
})
if is_test and byte_counter == data_len:
@ -221,7 +233,7 @@ class HttpFD(FileDownloader):
return False
if tmpfilename != '-':
stream.close()
self.report_finish(data_len_str, (time.time() - start))
if data_len is not None and byte_counter != data_len:
raise ContentTooShortError(byte_counter, int(data_len))
self.try_rename(tmpfilename, filename)
@ -235,6 +247,7 @@ class HttpFD(FileDownloader):
'total_bytes': byte_counter,
'filename': filename,
'status': 'finished',
'elapsed': time.time() - start,
})
return True

View File

@ -3,7 +3,6 @@ from __future__ import unicode_literals
import os
import re
import subprocess
import sys
import time
from .common import FileDownloader
@ -11,7 +10,7 @@ from ..compat import compat_str
from ..utils import (
check_executable,
encodeFilename,
format_bytes,
encodeArgument,
get_exe_version,
)
@ -51,23 +50,23 @@ class RtmpFD(FileDownloader):
if not resume_percent:
resume_percent = percent
resume_downloaded_data_len = downloaded_data_len
eta = self.calc_eta(start, time.time(), 100 - resume_percent, percent - resume_percent)
speed = self.calc_speed(start, time.time(), downloaded_data_len - resume_downloaded_data_len)
time_now = time.time()
eta = self.calc_eta(start, time_now, 100 - resume_percent, percent - resume_percent)
speed = self.calc_speed(start, time_now, downloaded_data_len - resume_downloaded_data_len)
data_len = None
if percent > 0:
data_len = int(downloaded_data_len * 100 / percent)
data_len_str = '~' + format_bytes(data_len)
self.report_progress(percent, data_len_str, speed, eta)
cursor_in_new_line = False
self._hook_progress({
'status': 'downloading',
'downloaded_bytes': downloaded_data_len,
'total_bytes': data_len,
'total_bytes_estimate': data_len,
'tmpfilename': tmpfilename,
'filename': filename,
'status': 'downloading',
'eta': eta,
'elapsed': time_now - start,
'speed': speed,
})
cursor_in_new_line = False
else:
# no percent for live streams
mobj = re.search(r'([0-9]+\.[0-9]{3}) kB / [0-9]+\.[0-9]{2} sec', line)
@ -75,15 +74,15 @@ class RtmpFD(FileDownloader):
downloaded_data_len = int(float(mobj.group(1)) * 1024)
time_now = time.time()
speed = self.calc_speed(start, time_now, downloaded_data_len)
self.report_progress_live_stream(downloaded_data_len, speed, time_now - start)
cursor_in_new_line = False
self._hook_progress({
'downloaded_bytes': downloaded_data_len,
'tmpfilename': tmpfilename,
'filename': filename,
'status': 'downloading',
'elapsed': time_now - start,
'speed': speed,
})
cursor_in_new_line = False
elif self.params.get('verbose', False):
if not cursor_in_new_line:
self.to_screen('')
@ -106,7 +105,7 @@ class RtmpFD(FileDownloader):
protocol = info_dict.get('rtmp_protocol', None)
real_time = info_dict.get('rtmp_real_time', False)
no_resume = info_dict.get('no_resume', False)
continue_dl = info_dict.get('continuedl', False)
continue_dl = info_dict.get('continuedl', True)
self.report_destination(filename)
tmpfilename = self.temp_name(filename)
@ -120,7 +119,9 @@ class RtmpFD(FileDownloader):
# Download using rtmpdump. rtmpdump returns exit code 2 when
# the connection was interrumpted and resuming appears to be
# possible. This is part of rtmpdump's normal usage, AFAIK.
basic_args = ['rtmpdump', '--verbose', '-r', url, '-o', tmpfilename]
basic_args = [
'rtmpdump', '--verbose', '-r', url,
'-o', tmpfilename]
if player_url is not None:
basic_args += ['--swfVfy', player_url]
if page_url is not None:
@ -130,7 +131,7 @@ class RtmpFD(FileDownloader):
if play_path is not None:
basic_args += ['--playpath', play_path]
if tc_url is not None:
basic_args += ['--tcUrl', url]
basic_args += ['--tcUrl', tc_url]
if test:
basic_args += ['--stop', '1']
if flash_version is not None:
@ -153,16 +154,9 @@ class RtmpFD(FileDownloader):
if not live and continue_dl:
args += ['--skip', '1']
if sys.platform == 'win32' and sys.version_info < (3, 0):
# Windows subprocess module does not actually support Unicode
# on Python 2.x
# See http://stackoverflow.com/a/9951851/35070
subprocess_encoding = sys.getfilesystemencoding()
args = [a.encode(subprocess_encoding, 'ignore') for a in args]
else:
subprocess_encoding = None
args = [encodeArgument(a) for a in args]
self._debug_cmd(args, subprocess_encoding, exe='rtmpdump')
self._debug_cmd(args, exe='rtmpdump')
RD_SUCCESS = 0
RD_FAILED = 1
@ -179,7 +173,11 @@ class RtmpFD(FileDownloader):
prevsize = os.path.getsize(encodeFilename(tmpfilename))
self.to_screen('[rtmpdump] %s bytes' % prevsize)
time.sleep(5.0) # This seems to be needed
retval = run_rtmpdump(basic_args + ['-e'] + [[], ['-k', '1']][retval == RD_FAILED])
args = basic_args + ['--resume']
if retval == RD_FAILED:
args += ['--skip', '1']
args = [encodeArgument(a) for a in args]
retval = run_rtmpdump(args)
cursize = os.path.getsize(encodeFilename(tmpfilename))
if prevsize == cursize and retval == RD_FAILED:
break

View File

@ -10,21 +10,23 @@ from ..utils import (
)
class MplayerFD(FileDownloader):
class RtspFD(FileDownloader):
def real_download(self, filename, info_dict):
url = info_dict['url']
self.report_destination(filename)
tmpfilename = self.temp_name(filename)
args = [
'mplayer', '-really-quiet', '-vo', 'null', '-vc', 'dummy',
'-dumpstream', '-dumpfile', tmpfilename, url]
# Check for mplayer first
if not check_executable('mplayer', ['-h']):
self.report_error('MMS or RTSP download detected but "%s" could not be run' % args[0])
if check_executable('mplayer', ['-h']):
args = [
'mplayer', '-really-quiet', '-vo', 'null', '-vc', 'dummy',
'-dumpstream', '-dumpfile', tmpfilename, url]
elif check_executable('mpv', ['-h']):
args = [
'mpv', '-really-quiet', '--vo=null', '--stream-dump=' + tmpfilename, url]
else:
self.report_error('MMS or RTSP download detected but neither "mplayer" nor "mpv" could be run. Please install any.')
return False
# Download using mplayer.
retval = subprocess.call(args)
if retval == 0:
fsize = os.path.getsize(encodeFilename(tmpfilename))
@ -39,5 +41,5 @@ class MplayerFD(FileDownloader):
return True
else:
self.to_stderr('\n')
self.report_error('mplayer exited with code %d' % retval)
self.report_error('%s exited with code %d' % (args[0], retval))
return False

View File

@ -4,9 +4,14 @@ from .abc import ABCIE
from .abc7news import Abc7NewsIE
from .academicearth import AcademicEarthCourseIE
from .addanime import AddAnimeIE
from .adobetv import AdobeTVIE
from .adobetv import (
AdobeTVIE,
AdobeTVVideoIE,
)
from .adultswim import AdultSwimIE
from .aftenposten import AftenpostenIE
from .aftonbladet import AftonbladetIE
from .airmozilla import AirMozillaIE
from .aljazeera import AlJazeeraIE
from .alphaporno import AlphaPornoIE
from .anitube import AnitubeIE
@ -14,9 +19,14 @@ from .anysex import AnySexIE
from .aol import AolIE
from .allocine import AllocineIE
from .aparat import AparatIE
from .appleconnect import AppleConnectIE
from .appletrailers import AppleTrailersIE
from .archiveorg import ArchiveOrgIE
from .ard import ARDIE, ARDMediathekIE
from .ard import (
ARDIE,
ARDMediathekIE,
SportschauIE,
)
from .arte import (
ArteTvIE,
ArteTVPlus7IE,
@ -30,11 +40,16 @@ from .atresplayer import AtresPlayerIE
from .atttechchannel import ATTTechChannelIE
from .audiomack import AudiomackIE, AudiomackAlbumIE
from .azubu import AzubuIE
from .baidu import BaiduVideoIE
from .bambuser import BambuserIE, BambuserChannelIE
from .bandcamp import BandcampIE, BandcampAlbumIE
from .bbccouk import BBCCoUkIE
from .bbc import (
BBCCoUkIE,
BBCIE,
)
from .beeg import BeegIE
from .behindkink import BehindKinkIE
from .beatportpro import BeatportProIE
from .bet import BetIE
from .bild import BildIE
from .bilibili import BiliBiliIE
@ -48,15 +63,26 @@ from .brightcove import BrightcoveIE
from .buzzfeed import BuzzFeedIE
from .byutv import BYUtvIE
from .c56 import C56IE
from .camdemy import (
CamdemyIE,
CamdemyFolderIE
)
from .canal13cl import Canal13clIE
from .canalplus import CanalplusIE
from .canalc2 import Canalc2IE
from .cbs import CBSIE
from .cbsnews import CBSNewsIE
from .cbssports import CBSSportsIE
from .ccc import CCCIE
from .ceskatelevize import CeskaTelevizeIE
from .channel9 import Channel9IE
from .chilloutzone import ChilloutzoneIE
from .chirbit import (
ChirbitIE,
ChirbitProfileIE,
)
from .cinchcast import CinchcastIE
from .cinemassacre import CinemassacreIE
from .clipfish import ClipfishIE
from .cliphunter import CliphunterIE
from .clipsyndicate import ClipsyndicateIE
@ -73,10 +99,11 @@ from .collegehumor import CollegeHumorIE
from .collegerama import CollegeRamaIE
from .comedycentral import ComedyCentralIE, ComedyCentralShowsIE
from .comcarcoff import ComCarCoffIE
from .commonmistakes import CommonMistakesIE
from .commonmistakes import CommonMistakesIE, UnicodeBOMIE
from .condenast import CondeNastIE
from .cracked import CrackedIE
from .criterion import CriterionIE
from .crooksandliars import CrooksAndLiarsIE
from .crunchyroll import (
CrunchyrollIE,
CrunchyrollShowPlaylistIE
@ -87,23 +114,32 @@ from .dailymotion import (
DailymotionIE,
DailymotionPlaylistIE,
DailymotionUserIE,
DailymotionCloudIE,
)
from .daum import DaumIE
from .dbtv import DBTVIE
from .dctp import DctpTvIE
from .deezer import DeezerPlaylistIE
from .dfb import DFBIE
from .dhm import DHMIE
from .dotsub import DotsubIE
from .douyutv import DouyuTVIE
from .dramafever import (
DramaFeverIE,
DramaFeverSeriesIE,
)
from .dreisat import DreiSatIE
from .drbonanza import DRBonanzaIE
from .drtuber import DrTuberIE
from .drtv import DRTVIE
from .dvtv import DVTVIE
from .dump import DumpIE
from .dumpert import DumpertIE
from .defense import DefenseGouvFrIE
from .discovery import DiscoveryIE
from .divxstage import DivxStageIE
from .dropbox import DropboxIE
from .eagleplatform import EaglePlatformIE
from .ebaumsworld import EbaumsWorldIE
from .echomsk import EchoMskIE
from .ehow import EHowIE
@ -115,11 +151,12 @@ from .ellentv import (
EllenTVClipsIE,
)
from .elpais import ElPaisIE
from .empflix import EMPFlixIE
from .embedly import EmbedlyIE
from .engadget import EngadgetIE
from .eporner import EpornerIE
from .eroprofile import EroProfileIE
from .escapist import EscapistIE
from .espn import ESPNIE
from .everyonesmixtape import EveryonesMixtapeIE
from .exfm import ExfmIE
from .expotv import ExpoTVIE
@ -127,19 +164,21 @@ from .extremetube import ExtremeTubeIE
from .facebook import FacebookIE
from .faz import FazIE
from .fc2 import FC2IE
from .firedrive import FiredriveIE
from .firstpost import FirstpostIE
from .firsttv import FirstTVIE
from .fivemin import FiveMinIE
from .fivetv import FiveTVIE
from .fktv import (
FKTVIE,
FKTVPosteckeIE,
)
from .flickr import FlickrIE
from .folketinget import FolketingetIE
from .footyroom import FootyRoomIE
from .fourtube import FourTubeIE
from .foxgay import FoxgayIE
from .foxnews import FoxNewsIE
from .foxsports import FoxSportsIE
from .franceculture import FranceCultureIE
from .franceinter import FranceInterIE
from .francetv import (
@ -158,11 +197,14 @@ from .gameone import (
GameOneIE,
GameOnePlaylistIE,
)
from .gamersyde import GamersydeIE
from .gamespot import GameSpotIE
from .gamestar import GameStarIE
from .gametrailers import GametrailersIE
from .gazeta import GazetaIE
from .gdcvault import GDCVaultIE
from .generic import GenericIE
from .gfycat import GfycatIE
from .giantbomb import GiantBombIE
from .giga import GigaIE
from .glide import GlideIE
@ -174,7 +216,6 @@ from .googleplus import GooglePlusIE
from .googlesearch import GoogleSearchIE
from .gorillavid import GorillaVidIE
from .goshgay import GoshgayIE
from .grooveshark import GroovesharkIE
from .groupon import GrouponIE
from .hark import HarkIE
from .hearthisat import HearThisAtIE
@ -183,6 +224,7 @@ from .hellporno import HellPornoIE
from .helsinki import HelsinkiIE
from .hentaistigma import HentaiStigmaIE
from .historicfilms import HistoricFilmsIE
from .history import HistoryIE
from .hitbox import HitboxIE, HitboxLiveIE
from .hornbunny import HornBunnyIE
from .hostingbulk import HostingBulkIE
@ -197,11 +239,14 @@ from .imdb import (
ImdbIE,
ImdbListIE
)
from .imgur import ImgurIE
from .ina import InaIE
from .infoq import InfoQIE
from .instagram import InstagramIE, InstagramUserIE
from .internetvideoarchive import InternetVideoArchiveIE
from .iprima import IPrimaIE
from .iqiyi import IqiyiIE
from .ir90tv import Ir90TvIE
from .ivi import (
IviIE,
IviCompilationIE
@ -212,8 +257,11 @@ from .jeuxvideo import JeuxVideoIE
from .jove import JoveIE
from .jukebox import JukeboxIE
from .jpopsukitv import JpopsukiIE
from .kaltura import KalturaIE
from .kanalplay import KanalPlayIE
from .kankan import KankanIE
from .karaoketv import KaraoketvIE
from .karrierevideos import KarriereVideosIE
from .keezmovies import KeezMoviesIE
from .khanacademy import KhanAcademyIE
from .kickstarter import KickStarterIE
@ -221,9 +269,27 @@ from .keek import KeekIE
from .kontrtube import KontrTubeIE
from .krasview import KrasViewIE
from .ku6 import Ku6IE
from .kuwo import (
KuwoIE,
KuwoAlbumIE,
KuwoChartIE,
KuwoSingerIE,
KuwoCategoryIE,
KuwoMvIE,
)
from .la7 import LA7IE
from .laola1tv import Laola1TvIE
from .lifenews import LifeNewsIE
from .lecture2go import Lecture2GoIE
from .letv import (
LetvIE,
LetvTvIE,
LetvPlaylistIE
)
from .libsyn import LibsynIE
from .lifenews import (
LifeNewsIE,
LifeEmbedIE,
)
from .liveleak import LiveLeakIE
from .livestream import (
LivestreamIE,
@ -241,11 +307,13 @@ from .macgamestore import MacGameStoreIE
from .mailru import MailRuIE
from .malemotion import MalemotionIE
from .mdr import MDRIE
from .megavideoz import MegaVideozIE
from .metacafe import MetacafeIE
from .metacritic import MetacriticIE
from .mgoon import MgoonIE
from .minhateca import MinhatecaIE
from .ministrygrid import MinistryGridIE
from .miomio import MioMioIE
from .mit import TechTVMITIE, MITIE, OCWMITIE
from .mitele import MiTeleIE
from .mixcloud import MixcloudIE
@ -273,25 +341,41 @@ from .musicvault import MusicVaultIE
from .muzu import MuzuTVIE
from .myspace import MySpaceIE, MySpaceAlbumIE
from .myspass import MySpassIE
from .myvi import MyviIE
from .myvideo import MyVideoIE
from .myvidster import MyVidsterIE
from .nationalgeographic import NationalGeographicIE
from .naver import NaverIE
from .nba import NBAIE
from .nbc import (
NBCIE,
NBCNewsIE,
NBCSportsIE,
NBCSportsVPlayerIE,
)
from .ndr import (
NDRIE,
NJoyIE,
)
from .ndr import NDRIE
from .ndtv import NDTVIE
from .netzkino import NetzkinoIE
from .nerdcubed import NerdCubedFeedIE
from .nerdist import NerdistIE
from .neteasemusic import (
NetEaseMusicIE,
NetEaseMusicAlbumIE,
NetEaseMusicSingerIE,
NetEaseMusicListIE,
NetEaseMusicMvIE,
NetEaseMusicProgramIE,
NetEaseMusicDjRadioIE,
)
from .newgrounds import NewgroundsIE
from .newstube import NewstubeIE
from .nextmedia import (
NextMediaIE,
NextMediaActionNewsIE,
AppleDailyRealtimeNewsIE,
AppleDailyAnimationNewsIE
AppleDailyIE,
)
from .nfb import NFBIE
from .nfl import NFLIE
@ -305,52 +389,89 @@ from .ninegag import NineGagIE
from .noco import NocoIE
from .normalboots import NormalbootsIE
from .nosvideo import NosVideoIE
from .nova import NovaIE
from .novamov import NovaMovIE
from .nowness import NownessIE
from .nowtv import NowTVIE
from .nowvideo import NowVideoIE
from .npo import (
NPOIE,
NPOLiveIE,
TegenlichtVproIE,
NPORadioIE,
NPORadioFragmentIE,
VPROIE,
WNLIE
)
from .nrk import (
NRKIE,
NRKPlaylistIE,
NRKTVIE,
)
from .ntv import NTVIE
from .nytimes import NYTimesIE
from .ntvde import NTVDeIE
from .ntvru import NTVRuIE
from .nytimes import (
NYTimesIE,
NYTimesArticleIE,
)
from .nuvid import NuvidIE
from .odnoklassniki import OdnoklassnikiIE
from .oktoberfesttv import OktoberfestTVIE
from .ooyala import OoyalaIE
from .onionstudios import OnionStudiosIE
from .ooyala import (
OoyalaIE,
OoyalaExternalIE,
)
from .openfilm import OpenFilmIE
from .orf import (
ORFTVthekIE,
ORFOE1IE,
ORFFM4IE,
ORFIPTVIE,
)
from .parliamentliveuk import ParliamentLiveUKIE
from .patreon import PatreonIE
from .pbs import PBSIE
from .philharmoniedeparis import PhilharmonieDeParisIE
from .phoenix import PhoenixIE
from .photobucket import PhotobucketIE
from .pinkbike import PinkbikeIE
from .planetaplay import PlanetaPlayIE
from .pladform import PladformIE
from .played import PlayedIE
from .playfm import PlayFMIE
from .playvid import PlayvidIE
from .playwire import PlaywireIE
from .podomatic import PodomaticIE
from .porn91 import Porn91IE
from .pornhd import PornHdIE
from .pornhub import PornHubIE
from .pornhub import (
PornHubIE,
PornHubPlaylistIE,
)
from .pornotube import PornotubeIE
from .pornovoisines import PornoVoisinesIE
from .pornoxo import PornoXOIE
from .primesharetv import PrimeShareTVIE
from .promptfile import PromptFileIE
from .prosiebensat1 import ProSiebenSat1IE
from .puls4 import Puls4IE
from .pyvideo import PyvideoIE
from .qqmusic import (
QQMusicIE,
QQMusicSingerIE,
QQMusicAlbumIE,
QQMusicToplistIE,
QQMusicPlaylistIE,
)
from .quickvid import QuickVidIE
from .r7 import R7IE
from .radiode import RadioDeIE
from .radiojavan import RadioJavanIE
from .radiobremen import RadioBremenIE
from .radiofrance import RadioFranceIE
from .rai import RaiIE
from .rbmaradio import RBMARadioIE
from .rds import RDSIE
from .redtube import RedTubeIE
from .restudy import RestudyIE
from .reverbnation import ReverbNationIE
@ -360,12 +481,11 @@ from .rottentomatoes import RottenTomatoesIE
from .roxwel import RoxwelIE
from .rtbf import RTBFIE
from .rte import RteIE
from .rtlnl import RtlXlIE
from .rtlnow import RTLnowIE
from .rtlnl import RtlNlIE
from .rtl2 import RTL2IE
from .rtp import RTPIE
from .rts import RTSIE
from .rtve import RTVEALaCartaIE, RTVELiveIE
from .rtve import RTVEALaCartaIE, RTVELiveIE, RTVEInfantilIE
from .ruhd import RUHDIE
from .rutube import (
RutubeIE,
@ -375,13 +495,20 @@ from .rutube import (
RutubePersonIE,
)
from .rutv import RUTVIE
from .ruutu import RuutuIE
from .sandia import SandiaIE
from .safari import (
SafariIE,
SafariCourseIE,
)
from .sapo import SapoIE
from .savefrom import SaveFromIE
from .sbs import SBSIE
from .scivee import SciVeeIE
from .screencast import ScreencastIE
from .screencastomatic import ScreencastOMaticIE
from .screenwavemedia import CinemassacreIE, ScreenwaveMediaIE, TeamFourIE
from .screenwavemedia import ScreenwaveMediaIE, TeamFourIE
from .senateisvp import SenateISVPIE
from .servingsys import ServingSysIE
from .sexu import SexuIE
from .sexykarma import SexyKarmaIE
@ -396,35 +523,58 @@ from .smotri import (
SmotriUserIE,
SmotriBroadcastIE,
)
from .snagfilms import (
SnagFilmsIE,
SnagFilmsEmbedIE,
)
from .snotr import SnotrIE
from .sockshare import SockshareIE
from .sohu import SohuIE
from .soompi import (
SoompiIE,
SoompiShowIE,
)
from .soundcloud import (
SoundcloudIE,
SoundcloudSetIE,
SoundcloudUserIE,
SoundcloudPlaylistIE
)
from .soundgasm import SoundgasmIE
from .soundgasm import (
SoundgasmIE,
SoundgasmProfileIE
)
from .southpark import (
SouthParkIE,
SouthparkDeIE,
SouthParkDeIE,
SouthParkDkIE,
SouthParkEsIE,
SouthParkNlIE
)
from .space import SpaceIE
from .spankbang import SpankBangIE
from .spankwire import SpankwireIE
from .spiegel import SpiegelIE, SpiegelArticleIE
from .spiegeltv import SpiegeltvIE
from .spike import SpikeIE
from .sport5 import Sport5IE
from .sportbox import SportBoxIE
from .sportbox import (
SportBoxIE,
SportBoxEmbedIE,
)
from .sportdeutschland import SportDeutschlandIE
from .srf import SrfIE
from .srmediathek import SRMediathekIE
from .ssa import SSAIE
from .stanfordoc import StanfordOpenClassroomIE
from .steam import SteamIE
from .streamcloud import StreamcloudIE
from .streamcz import StreamCZIE
from .streetvoice import StreetVoiceIE
from .sunporno import SunPornoIE
from .svt import (
SVTIE,
SVTPlayIE,
)
from .swrmediathek import SWRMediathekIE
from .syfy import SyfyIE
from .sztvhu import SztvHuIE
@ -450,11 +600,19 @@ from .tf1 import TF1IE
from .theonion import TheOnionIE
from .theplatform import ThePlatformIE
from .thesixtyone import TheSixtyOneIE
from .thisamericanlife import ThisAmericanLifeIE
from .thisav import ThisAVIE
from .tinypic import TinyPicIE
from .tlc import TlcIE, TlcDeIE
from .tmz import TMZIE
from .tnaflix import TNAFlixIE
from .tmz import (
TMZIE,
TMZArticleIE,
)
from .tnaflix import (
TNAFlixIE,
EMPFlixIE,
MovieFapIE,
)
from .thvideo import (
THVideoIE,
THVideoPlaylistIE
@ -465,15 +623,30 @@ from .traileraddict import TrailerAddictIE
from .trilulilu import TriluliluIE
from .trutube import TruTubeIE
from .tube8 import Tube8IE
from .tubitv import TubiTvIE
from .tudou import TudouIE
from .tumblr import TumblrIE
from .tunein import TuneInIE
from .turbo import TurboIE
from .tutv import TutvIE
from .tv2 import (
TV2IE,
TV2ArticleIE,
)
from .tv4 import TV4IE
from .tvc import (
TVCIE,
TVCArticleIE,
)
from .tvigle import TvigleIE
from .tvp import TvpIE, TvpSeriesIE
from .tvplay import TVPlayIE
from .tweakers import TweakersIE
from .twentyfourvideo import TwentyFourVideoIE
from .twentytwotracks import (
TwentyTwoTracksIE,
TwentyTwoTracksGenreIE
)
from .twitch import (
TwitchVideoIE,
TwitchChapterIE,
@ -483,20 +656,29 @@ from .twitch import (
TwitchBookmarksIE,
TwitchStreamIE,
)
from .twitter import TwitterCardIE
from .ubu import UbuIE
from .udemy import (
UdemyIE,
UdemyCourseIE
)
from .udn import UDNEmbedIE
from .ultimedia import UltimediaIE
from .unistra import UnistraIE
from .urort import UrortIE
from .ustream import UstreamIE, UstreamChannelIE
from .varzesh3 import Varzesh3IE
from .vbox7 import Vbox7IE
from .veehd import VeeHDIE
from .veoh import VeohIE
from .vessel import VesselIE
from .vesti import VestiIE
from .vevo import VevoIE
from .vgtv import VGTVIE
from .vgtv import (
BTArticleIE,
BTVestlendingenIE,
VGTVIE,
)
from .vh1 import VH1IE
from .vice import ViceIE
from .viddler import ViddlerIE
@ -511,6 +693,7 @@ from .videoweed import VideoWeedIE
from .vidme import VidmeIE
from .vidzi import VidziIE
from .vier import VierIE, VierVideosIE
from .viewster import ViewsterIE
from .vimeo import (
VimeoIE,
VimeoAlbumIE,
@ -526,12 +709,16 @@ from .vine import (
VineIE,
VineUserIE,
)
from .viki import VikiIE
from .viki import (
VikiIE,
VikiChannelIE,
)
from .vk import (
VKIE,
VKUserVideosIE,
)
from .vodlocker import VodlockerIE
from .voicerepublic import VoiceRepublicIE
from .vporn import VpornIE
from .vrt import VRTIE
from .vube import VubeIE
@ -546,26 +733,41 @@ from .wdr import (
WDRMobileIE,
WDRMausIE,
)
from .webofstories import WebOfStoriesIE
from .webofstories import (
WebOfStoriesIE,
WebOfStoriesPlaylistIE,
)
from .weibo import WeiboIE
from .wimp import WimpIE
from .wistia import WistiaIE
from .worldstarhiphop import WorldStarHipHopIE
from .wrzuta import WrzutaIE
from .wsj import WSJIE
from .xbef import XBefIE
from .xboxclips import XboxClipsIE
from .xhamster import XHamsterIE
from .xhamster import (
XHamsterIE,
XHamsterEmbedIE,
)
from .xminus import XMinusIE
from .xnxx import XNXXIE
from .xvideos import XVideosIE
from .xstream import XstreamIE
from .xtube import XTubeUserIE, XTubeIE
from .xuite import XuiteIE
from .xvideos import XVideosIE
from .xxxymovies import XXXYMoviesIE
from .yahoo import (
YahooIE,
YahooSearchIE,
)
from .yam import YamIE
from .yandexmusic import (
YandexMusicTrackIE,
YandexMusicAlbumIE,
YandexMusicPlaylistIE,
)
from .yesjapan import YesJapanIE
from .yinyuetai import YinYueTaiIE
from .ynet import YnetIE
from .youjizz import YouJizzIE
from .youku import YoukuIE
@ -588,6 +790,7 @@ from .youtube import (
YoutubeUserIE,
YoutubeWatchLaterIE,
)
from .zapiks import ZapiksIE
from .zdf import ZDFIE, ZDFChannelIE
from .zingmp3 import (
ZingMp3SongIE,

View File

@ -11,12 +11,13 @@ from ..compat import (
)
from ..utils import (
ExtractorError,
qualities,
)
class AddAnimeIE(InfoExtractor):
_VALID_URL = r'^http://(?:\w+\.)?add-anime\.net/watch_video\.php\?(?:.*?)v=(?P<id>[\w_]+)(?:.*)'
_TEST = {
_VALID_URL = r'http://(?:\w+\.)?add-anime\.net/(?:watch_video\.php\?(?:.*?)v=|video/)(?P<id>[\w_]+)'
_TESTS = [{
'url': 'http://www.add-anime.net/watch_video.php?v=24MR3YO5SAS9',
'md5': '72954ea10bc979ab5e2eb288b21425a0',
'info_dict': {
@ -25,7 +26,10 @@ class AddAnimeIE(InfoExtractor):
'description': 'One Piece 606',
'title': 'One Piece 606',
}
}
}, {
'url': 'http://add-anime.net/video/MDUGWYKNGBD8/One-Piece-687',
'only_matching': True,
}]
def _real_extract(self, url):
video_id = self._match_id(url)
@ -63,8 +67,10 @@ class AddAnimeIE(InfoExtractor):
note='Confirming after redirect')
webpage = self._download_webpage(url, video_id)
FORMATS = ('normal', 'hq')
quality = qualities(FORMATS)
formats = []
for format_id in ('normal', 'hq'):
for format_id in FORMATS:
rex = r"var %s_video_file = '(.*?)';" % re.escape(format_id)
video_url = self._search_regex(rex, webpage, 'video file URLx',
fatal=False)
@ -73,6 +79,7 @@ class AddAnimeIE(InfoExtractor):
formats.append({
'format_id': format_id,
'url': video_url,
'quality': quality(format_id),
})
self._sort_formats(formats)
video_title = self._og_search_title(webpage)

View File

@ -5,6 +5,8 @@ from ..utils import (
parse_duration,
unified_strdate,
str_to_int,
float_or_none,
ISO639Utils,
)
@ -28,7 +30,6 @@ class AdobeTVIE(InfoExtractor):
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
player = self._parse_json(
@ -44,8 +45,10 @@ class AdobeTVIE(InfoExtractor):
self._html_search_meta('datepublished', webpage, 'upload date'))
duration = parse_duration(
self._html_search_meta('duration', webpage, 'duration')
or self._search_regex(r'Runtime:\s*(\d{2}:\d{2}:\d{2})', webpage, 'duration'))
self._html_search_meta('duration', webpage, 'duration') or
self._search_regex(
r'Runtime:\s*(\d{2}:\d{2}:\d{2})',
webpage, 'duration', fatal=False))
view_count = str_to_int(self._search_regex(
r'<div class="views">\s*Views?:\s*([\d,.]+)\s*</div>',
@ -68,3 +71,61 @@ class AdobeTVIE(InfoExtractor):
'view_count': view_count,
'formats': formats,
}
class AdobeTVVideoIE(InfoExtractor):
_VALID_URL = r'https?://video\.tv\.adobe\.com/v/(?P<id>\d+)'
_TEST = {
# From https://helpx.adobe.com/acrobat/how-to/new-experience-acrobat-dc.html?set=acrobat--get-started--essential-beginners
'url': 'https://video.tv.adobe.com/v/2456/',
'md5': '43662b577c018ad707a63766462b1e87',
'info_dict': {
'id': '2456',
'ext': 'mp4',
'title': 'New experience with Acrobat DC',
'description': 'New experience with Acrobat DC',
'duration': 248.667,
},
}
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
player_params = self._parse_json(self._search_regex(
r'var\s+bridge\s*=\s*([^;]+);', webpage, 'player parameters'),
video_id)
formats = [{
'url': source['src'],
'width': source.get('width'),
'height': source.get('height'),
'tbr': source.get('bitrate'),
} for source in player_params['sources']]
# For both metadata and downloaded files the duration varies among
# formats. I just pick the max one
duration = max(filter(None, [
float_or_none(source.get('duration'), scale=1000)
for source in player_params['sources']]))
subtitles = {}
for translation in player_params.get('translations', []):
lang_id = translation.get('language_w3c') or ISO639Utils.long2short(translation['language_medium'])
if lang_id not in subtitles:
subtitles[lang_id] = []
subtitles[lang_id].append({
'url': translation['vttPath'],
'ext': 'vtt',
})
return {
'id': video_id,
'formats': formats,
'title': player_params['title'],
'description': self._og_search_description(webpage),
'duration': duration,
'subtitles': subtitles,
}

View File

@ -2,13 +2,12 @@
from __future__ import unicode_literals
import re
import json
from .common import InfoExtractor
from ..utils import (
ExtractorError,
xpath_text,
float_or_none,
xpath_text,
)
@ -38,6 +37,7 @@ class AdultSwimIE(InfoExtractor):
},
],
'info_dict': {
'id': 'rQxZvXQ4ROaSOqq-or2Mow',
'title': 'Rick and Morty - Pilot',
'description': "Rick moves in with his daughter's family and establishes himself as a bad influence on his grandson, Morty. "
}
@ -55,9 +55,28 @@ class AdultSwimIE(InfoExtractor):
}
],
'info_dict': {
'id': '-t8CamQlQ2aYZ49ItZCFog',
'title': 'American Dad - Putting Francine Out of Business',
'description': 'Stan hatches a plan to get Francine out of the real estate business.Watch more American Dad on [adult swim].'
},
}, {
'url': 'http://www.adultswim.com/videos/tim-and-eric-awesome-show-great-job/dr-steve-brule-for-your-wine/',
'playlist': [
{
'md5': '3e346a2ab0087d687a05e1e7f3b3e529',
'info_dict': {
'id': 'sY3cMUR_TbuE4YmdjzbIcQ-0',
'ext': 'flv',
'title': 'Tim and Eric Awesome Show Great Job! - Dr. Steve Brule, For Your Wine',
'description': 'Dr. Brule reports live from Wine Country with a special report on wines. \r\nWatch Tim and Eric Awesome Show Great Job! episode #20, "Embarrassed" on Adult Swim.\r\n\r\n',
},
}
],
'info_dict': {
'id': 'sY3cMUR_TbuE4YmdjzbIcQ',
'title': 'Tim and Eric Awesome Show Great Job! - Dr. Steve Brule, For Your Wine',
'description': 'Dr. Brule reports live from Wine Country with a special report on wines. \r\nWatch Tim and Eric Awesome Show Great Job! episode #20, "Embarrassed" on Adult Swim.\r\n\r\n',
},
}]
@staticmethod
@ -78,6 +97,7 @@ class AdultSwimIE(InfoExtractor):
for video in collection.get('videos'):
if video.get('slug') == slug:
return collection, video
return None, None
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
@ -88,28 +108,30 @@ class AdultSwimIE(InfoExtractor):
webpage = self._download_webpage(url, episode_path)
# Extract the value of `bootstrappedData` from the Javascript in the page.
bootstrappedDataJS = self._search_regex(r'var bootstrappedData = ({.*});', webpage, episode_path)
try:
bootstrappedData = json.loads(bootstrappedDataJS)
except ValueError as ve:
errmsg = '%s: Failed to parse JSON ' % episode_path
raise ExtractorError(errmsg, cause=ve)
bootstrapped_data = self._parse_json(self._search_regex(
r'var bootstrappedData = ({.*});', webpage, 'bootstraped data'), episode_path)
# Downloading videos from a /videos/playlist/ URL needs to be handled differently.
# NOTE: We are only downloading one video (the current one) not the playlist
if is_playlist:
collections = bootstrappedData['playlists']['collections']
collections = bootstrapped_data['playlists']['collections']
collection = self.find_collection_by_linkURL(collections, show_path)
video_info = self.find_video_info(collection, episode_path)
show_title = video_info['showTitle']
segment_ids = [video_info['videoPlaybackID']]
else:
collections = bootstrappedData['show']['collections']
collections = bootstrapped_data['show']['collections']
collection, video_info = self.find_collection_containing_video(collections, episode_path)
show = bootstrappedData['show']
# Video wasn't found in the collections, let's try `slugged_video`.
if video_info is None:
if bootstrapped_data.get('slugged_video', {}).get('slug') == episode_path:
video_info = bootstrapped_data['slugged_video']
else:
raise ExtractorError('Unable to find video info')
show = bootstrapped_data['show']
show_title = show['title']
segment_ids = [clip['videoPlaybackID'] for clip in video_info['clips']]

View File

@ -0,0 +1,23 @@
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
class AftenpostenIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?aftenposten\.no/webtv/(?:#!/)?video/(?P<id>\d+)'
_TEST = {
'url': 'http://www.aftenposten.no/webtv/#!/video/21039/trailer-sweatshop-i-can-t-take-any-more',
'md5': 'fd828cd29774a729bf4d4425fe192972',
'info_dict': {
'id': '21039',
'ext': 'mov',
'title': 'TRAILER: "Sweatshop" - I can´t take any more',
'description': 'md5:21891f2b0dd7ec2f78d84a50e54f8238',
'timestamp': 1416927969,
'upload_date': '20141125',
}
}
def _real_extract(self, url):
return self.url_result('xstream:ap:%s' % self._match_id(url), 'Xstream')

View File

@ -1,17 +1,16 @@
# encoding: utf-8
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..utils import int_or_none
class AftonbladetIE(InfoExtractor):
_VALID_URL = r'^http://tv\.aftonbladet\.se/webbtv.+?(?P<video_id>article[0-9]+)\.ab(?:$|[?#])'
_VALID_URL = r'http://tv\.aftonbladet\.se/abtv/articles/(?P<id>[0-9]+)'
_TEST = {
'url': 'http://tv.aftonbladet.se/webbtv/nyheter/vetenskap/rymden/article36015.ab',
'url': 'http://tv.aftonbladet.se/abtv/articles/36015',
'info_dict': {
'id': 'article36015',
'id': '36015',
'ext': 'mp4',
'title': 'Vulkanutbrott i rymden - nu släpper NASA bilderna',
'description': 'Jupiters måne mest aktiv av alla himlakroppar',
@ -21,15 +20,14 @@ class AftonbladetIE(InfoExtractor):
}
def _real_extract(self, url):
mobj = re.search(self._VALID_URL, url)
video_id = mobj.group('video_id')
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
# find internal video meta data
meta_url = 'http://aftonbladet-play.drlib.aptoma.no/video/%s.json'
internal_meta_id = self._html_search_regex(
r'data-aptomaId="([\w\d]+)"', webpage, 'internal_meta_id')
player_config = self._parse_json(self._html_search_regex(
r'data-player-config="([^"]+)"', webpage, 'player config'), video_id)
internal_meta_id = player_config['videoId']
internal_meta_url = meta_url % internal_meta_id
internal_meta_json = self._download_json(
internal_meta_url, video_id, 'Downloading video meta data')
@ -47,9 +45,9 @@ class AftonbladetIE(InfoExtractor):
formats.append({
'url': 'http://%s:%d/%s/%s' % (p['address'], p['port'], p['path'], p['filename']),
'ext': 'mp4',
'width': fmt['width'],
'height': fmt['height'],
'tbr': fmt['bitrate'],
'width': int_or_none(fmt.get('width')),
'height': int_or_none(fmt.get('height')),
'tbr': int_or_none(fmt.get('bitrate')),
'protocol': 'http',
})
self._sort_formats(formats)
@ -58,9 +56,9 @@ class AftonbladetIE(InfoExtractor):
'id': video_id,
'title': internal_meta_json['title'],
'formats': formats,
'thumbnail': internal_meta_json['imageUrl'],
'description': internal_meta_json['shortPreamble'],
'timestamp': internal_meta_json['timePublished'],
'duration': internal_meta_json['duration'],
'view_count': internal_meta_json['views'],
'thumbnail': internal_meta_json.get('imageUrl'),
'description': internal_meta_json.get('shortPreamble'),
'timestamp': int_or_none(internal_meta_json.get('timePublished')),
'duration': int_or_none(internal_meta_json.get('duration')),
'view_count': int_or_none(internal_meta_json.get('views')),
}

View File

@ -0,0 +1,74 @@
# coding: utf-8
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..utils import (
int_or_none,
parse_duration,
parse_iso8601,
)
class AirMozillaIE(InfoExtractor):
_VALID_URL = r'https?://air\.mozilla\.org/(?P<id>[0-9a-z-]+)/?'
_TEST = {
'url': 'https://air.mozilla.org/privacy-lab-a-meetup-for-privacy-minded-people-in-san-francisco/',
'md5': '2e3e7486ba5d180e829d453875b9b8bf',
'info_dict': {
'id': '6x4q2w',
'ext': 'mp4',
'title': 'Privacy Lab - a meetup for privacy minded people in San Francisco',
'thumbnail': 're:https://\w+\.cloudfront\.net/6x4q2w/poster\.jpg\?t=\d+',
'description': 'Brings together privacy professionals and others interested in privacy at for-profits, non-profits, and NGOs in an effort to contribute to the state of the ecosystem...',
'timestamp': 1422487800,
'upload_date': '20150128',
'location': 'SFO Commons',
'duration': 3780,
'view_count': int,
'categories': ['Main'],
}
}
def _real_extract(self, url):
display_id = self._match_id(url)
webpage = self._download_webpage(url, display_id)
video_id = self._html_search_regex(r'//vid.ly/(.*?)/embed', webpage, 'id')
embed_script = self._download_webpage('https://vid.ly/{0}/embed'.format(video_id), video_id)
jwconfig = self._search_regex(r'\svar jwconfig = (\{.*?\});\s', embed_script, 'metadata')
metadata = self._parse_json(jwconfig, video_id)
formats = [{
'url': source['file'],
'ext': source['type'],
'format_id': self._search_regex(r'&format=(.*)$', source['file'], 'video format'),
'format': source['label'],
'height': int(source['label'].rstrip('p')),
} for source in metadata['playlist'][0]['sources']]
self._sort_formats(formats)
view_count = int_or_none(self._html_search_regex(
r'Views since archived: ([0-9]+)',
webpage, 'view count', fatal=False))
timestamp = parse_iso8601(self._html_search_regex(
r'<time datetime="(.*?)"', webpage, 'timestamp', fatal=False))
duration = parse_duration(self._search_regex(
r'Duration:\s*(\d+\s*hours?\s*\d+\s*minutes?)',
webpage, 'duration', fatal=False))
return {
'id': video_id,
'title': self._og_search_title(webpage),
'formats': formats,
'url': self._og_search_url(webpage),
'display_id': display_id,
'thumbnail': metadata['playlist'][0].get('image'),
'description': self._og_search_description(webpage),
'timestamp': timestamp,
'location': self._html_search_regex(r'Location: (.*)', webpage, 'location', default=None),
'duration': duration,
'view_count': view_count,
'categories': re.findall(r'<a href=".*?" class="channel">(.*?)</a>', webpage),
}

View File

@ -20,6 +20,7 @@ class AparatIE(InfoExtractor):
'id': 'wP8On',
'ext': 'mp4',
'title': 'تیم گلکسی 11 - زومیت',
'age_limit': 0,
},
# 'skip': 'Extremely unreliable',
}
@ -34,7 +35,8 @@ class AparatIE(InfoExtractor):
video_id + '/vt/frame')
webpage = self._download_webpage(embed_url, video_id)
video_urls = re.findall(r'fileList\[[0-9]+\]\s*=\s*"([^"]+)"', webpage)
video_urls = [video_url.replace('\\/', '/') for video_url in re.findall(
r'(?:fileList\[[0-9]+\]\s*=|"file"\s*:)\s*"([^"]+)"', webpage)]
for i, video_url in enumerate(video_urls):
req = HEADRequest(video_url)
res = self._request_webpage(
@ -46,7 +48,7 @@ class AparatIE(InfoExtractor):
title = self._search_regex(r'\s+title:\s*"([^"]+)"', webpage, 'title')
thumbnail = self._search_regex(
r'\s+image:\s*"([^"]+)"', webpage, 'thumbnail', fatal=False)
r'image:\s*"([^"]+)"', webpage, 'thumbnail', fatal=False)
return {
'id': video_id,
@ -54,4 +56,5 @@ class AparatIE(InfoExtractor):
'url': video_url,
'ext': 'mp4',
'thumbnail': thumbnail,
'age_limit': self._family_friendly_search(webpage),
}

View File

@ -0,0 +1,50 @@
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import (
str_to_int,
ExtractorError
)
class AppleConnectIE(InfoExtractor):
_VALID_URL = r'https?://itunes\.apple\.com/\w{0,2}/?post/idsa\.(?P<id>[\w-]+)'
_TEST = {
'url': 'https://itunes.apple.com/us/post/idsa.4ab17a39-2720-11e5-96c5-a5b38f6c42d3',
'md5': '10d0f2799111df4cb1c924520ca78f98',
'info_dict': {
'id': '4ab17a39-2720-11e5-96c5-a5b38f6c42d3',
'ext': 'm4v',
'title': 'Energy',
'uploader': 'Drake',
'thumbnail': 'http://is5.mzstatic.com/image/thumb/Video5/v4/78/61/c5/7861c5fa-ad6d-294b-1464-cf7605b911d6/source/1920x1080sr.jpg',
'upload_date': '20150710',
'timestamp': 1436545535,
},
}
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
try:
video_json = self._html_search_regex(
r'class="auc-video-data">(\{.*?\})', webpage, 'json')
except ExtractorError:
raise ExtractorError('This post doesn\'t contain a video', expected=True)
video_data = self._parse_json(video_json, video_id)
timestamp = str_to_int(self._html_search_regex(r'data-timestamp="(\d+)"', webpage, 'timestamp'))
like_count = str_to_int(self._html_search_regex(r'(\d+) Loves', webpage, 'like count'))
return {
'id': video_id,
'url': video_data['sslSrc'],
'title': video_data['title'],
'description': video_data['description'],
'uploader': video_data['artistName'],
'thumbnail': video_data['artworkUrl'],
'timestamp': timestamp,
'like_count': like_count,
}

View File

@ -11,9 +11,12 @@ from ..utils import (
class AppleTrailersIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?trailers\.apple\.com/trailers/(?P<company>[^/]+)/(?P<movie>[^/]+)'
_TEST = {
_VALID_URL = r'https?://(?:www\.)?trailers\.apple\.com/(?:trailers|ca)/(?P<company>[^/]+)/(?P<movie>[^/]+)'
_TESTS = [{
"url": "http://trailers.apple.com/trailers/wb/manofsteel/",
'info_dict': {
'id': 'manofsteel',
},
"playlist": [
{
"md5": "d97a8e575432dbcb81b7c3acb741f8a8",
@ -60,7 +63,10 @@ class AppleTrailersIE(InfoExtractor):
},
},
]
}
}, {
'url': 'http://trailers.apple.com/ca/metropole/autrui/',
'only_matching': True,
}]
_JSON_RE = r'iTunes.playURL\((.*?)\);'

View File

@ -33,7 +33,7 @@ class ArchiveOrgIE(InfoExtractor):
def _real_extract(self, url):
video_id = self._match_id(url)
json_url = url + ('?' if '?' in url else '&') + 'output=json'
json_url = url + ('&' if '?' in url else '?') + 'output=json'
data = self._download_json(json_url, video_id)
def get_optional(data_dict, field):

View File

@ -8,6 +8,7 @@ from .generic import GenericIE
from ..utils import (
determine_ext,
ExtractorError,
get_element_by_attribute,
qualities,
int_or_none,
parse_duration,
@ -22,19 +23,125 @@ class ARDMediathekIE(InfoExtractor):
_VALID_URL = r'^https?://(?:(?:www\.)?ardmediathek\.de|mediathek\.daserste\.de)/(?:.*/)(?P<video_id>[0-9]+|[^0-9][^/\?]+)[^/\?]*(?:\?.*)?'
_TESTS = [{
'url': 'http://www.ardmediathek.de/tv/Dokumentation-und-Reportage/Ich-liebe-das-Leben-trotzdem/rbb-Fernsehen/Video?documentId=29582122&bcastId=3822114',
'info_dict': {
'id': '29582122',
'ext': 'mp4',
'title': 'Ich liebe das Leben trotzdem',
'description': 'md5:45e4c225c72b27993314b31a84a5261c',
'duration': 4557,
},
'params': {
# m3u8 download
'skip_download': True,
},
}, {
'url': 'http://www.ardmediathek.de/tv/Tatort/Tatort-Scheinwelten-H%C3%B6rfassung-Video/Das-Erste/Video?documentId=29522730&bcastId=602916',
'md5': 'f4d98b10759ac06c0072bbcd1f0b9e3e',
'info_dict': {
'id': '29522730',
'ext': 'mp4',
'title': 'Tatort: Scheinwelten - Hörfassung (Video tgl. ab 20 Uhr)',
'description': 'md5:196392e79876d0ac94c94e8cdb2875f1',
'duration': 5252,
},
}, {
# audio
'url': 'http://www.ardmediathek.de/tv/WDR-H%C3%B6rspiel-Speicher/Tod-eines-Fu%C3%9Fballers/WDR-3/Audio-Podcast?documentId=28488308&bcastId=23074086',
'md5': '219d94d8980b4f538c7fcb0865eb7f2c',
'info_dict': {
'id': '28488308',
'ext': 'mp3',
'title': 'Tod eines Fußballers',
'description': 'md5:f6e39f3461f0e1f54bfa48c8875c86ef',
'duration': 3240,
},
}, {
'url': 'http://mediathek.daserste.de/sendungen_a-z/328454_anne-will/22429276_vertrauen-ist-gut-spionieren-ist-besser-geht',
'only_matching': True,
}, {
'url': 'http://www.ardmediathek.de/tv/Tatort/Das-Wunder-von-Wolbeck-Video-tgl-ab-20/Das-Erste/Video?documentId=22490580&bcastId=602916',
'info_dict': {
'id': '22490580',
'ext': 'mp4',
'title': 'Das Wunder von Wolbeck (Video tgl. ab 20 Uhr)',
'description': 'Auf einem restaurierten Hof bei Wolbeck wird der Heilpraktiker Raffael Lembeck eines morgens von seiner Frau Stella tot aufgefunden. Das Opfer war offensichtlich in seiner Praxis zu Fall gekommen und ist dann verblutet, erklärt Prof. Boerne am Tatort.',
},
'skip': 'Blocked outside of Germany',
}]
def _extract_media_info(self, media_info_url, webpage, video_id):
media_info = self._download_json(
media_info_url, video_id, 'Downloading media JSON')
formats = self._extract_formats(media_info, video_id)
if not formats:
if '"fsk"' in webpage:
raise ExtractorError(
'This video is only available after 20:00', expected=True)
elif media_info.get('_geoblocked'):
raise ExtractorError('This video is not available due to geo restriction', expected=True)
self._sort_formats(formats)
duration = int_or_none(media_info.get('_duration'))
thumbnail = media_info.get('_previewImage')
subtitles = {}
subtitle_url = media_info.get('_subtitleUrl')
if subtitle_url:
subtitles['de'] = [{
'ext': 'srt',
'url': subtitle_url,
}]
return {
'id': video_id,
'duration': duration,
'thumbnail': thumbnail,
'formats': formats,
'subtitles': subtitles,
}
def _extract_formats(self, media_info, video_id):
type_ = media_info.get('_type')
media_array = media_info.get('_mediaArray', [])
formats = []
for num, media in enumerate(media_array):
for stream in media.get('_mediaStreamArray', []):
stream_urls = stream.get('_stream')
if not stream_urls:
continue
if not isinstance(stream_urls, list):
stream_urls = [stream_urls]
quality = stream.get('_quality')
server = stream.get('_server')
for stream_url in stream_urls:
ext = determine_ext(stream_url)
if ext == 'f4m':
formats.extend(self._extract_f4m_formats(
stream_url + '?hdcore=3.1.1&plugin=aasp-3.1.1.69.124',
video_id, preference=-1, f4m_id='hds'))
elif ext == 'm3u8':
formats.extend(self._extract_m3u8_formats(
stream_url, video_id, 'mp4', preference=1, m3u8_id='hls'))
else:
if server and server.startswith('rtmp'):
f = {
'url': server,
'play_path': stream_url,
'format_id': 'a%s-rtmp-%s' % (num, quality),
}
elif stream_url.startswith('http'):
f = {
'url': stream_url,
'format_id': 'a%s-%s-%s' % (num, ext, quality)
}
else:
continue
m = re.search(r'_(?P<width>\d+)x(?P<height>\d+)\.mp4$', stream_url)
if m:
f.update({
'width': int(m.group('width')),
'height': int(m.group('height')),
})
if type_ == 'audio':
f['vcodec'] = 'none'
formats.append(f)
return formats
def _real_extract(self, url):
# determine video id from url
m = re.match(self._VALID_URL, url)
@ -50,6 +157,9 @@ class ARDMediathekIE(InfoExtractor):
if '>Der gewünschte Beitrag ist nicht mehr verfügbar.<' in webpage:
raise ExtractorError('Video %s is no longer available' % video_id, expected=True)
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:
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 re.search(r'[\?&]rss($|[=&])', url):
doc = parse_xml(webpage)
if doc.tag == 'rss':
@ -89,46 +199,22 @@ class ARDMediathekIE(InfoExtractor):
'format_id': fid,
'url': furl,
})
self._sort_formats(formats)
info = {
'formats': formats,
}
else: # request JSON file
media_info = self._download_json(
'http://www.ardmediathek.de/play/media/%s' % video_id, video_id)
# The second element of the _mediaArray contains the standard http urls
streams = media_info['_mediaArray'][1]['_mediaStreamArray']
if not streams:
if '"fsk"' in webpage:
raise ExtractorError('This video is only available after 20:00')
info = self._extract_media_info(
'http://www.ardmediathek.de/play/media/%s' % video_id, webpage, video_id)
formats = []
for s in streams:
if type(s['_stream']) == list:
for index, url in enumerate(s['_stream'][::-1]):
quality = s['_quality'] + index
formats.append({
'quality': quality,
'url': url,
'format_id': '%s-%s' % (determine_ext(url), quality)
})
continue
format = {
'quality': s['_quality'],
'url': s['_stream'],
}
format['format_id'] = '%s-%s' % (
determine_ext(format['url']), format['quality'])
formats.append(format)
self._sort_formats(formats)
return {
info.update({
'id': video_id,
'title': title,
'description': description,
'formats': formats,
'thumbnail': thumbnail,
}
})
return info
class ARDIE(InfoExtractor):
@ -186,3 +272,41 @@ class ARDIE(InfoExtractor):
'upload_date': upload_date,
'thumbnail': thumbnail,
}
class SportschauIE(ARDMediathekIE):
IE_NAME = 'Sportschau'
_VALID_URL = r'(?P<baseurl>https?://(?:www\.)?sportschau\.de/(?:[^/]+/)+video(?P<id>[^/#?]+))\.html'
_TESTS = [{
'url': 'http://www.sportschau.de/tourdefrance/videoseppeltkokainhatnichtsmitklassischemdopingzutun100.html',
'info_dict': {
'id': 'seppeltkokainhatnichtsmitklassischemdopingzutun100',
'ext': 'mp4',
'title': 'Seppelt: "Kokain hat nichts mit klassischem Doping zu tun"',
'thumbnail': 're:^https?://.*\.jpg$',
'description': 'Der ARD-Doping Experte Hajo Seppelt gibt seine Einschätzung zum ersten Dopingfall der diesjährigen Tour de France um den Italiener Luca Paolini ab.',
},
'params': {
# m3u8 download
'skip_download': True,
},
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id')
base_url = mobj.group('baseurl')
webpage = self._download_webpage(url, video_id)
title = get_element_by_attribute('class', 'headline', webpage)
description = self._html_search_meta('description', webpage, 'description')
info = self._extract_media_info(
base_url + '-mc_defaultQuality-h.json', webpage, video_id)
info.update({
'title': title,
'description': description,
})
return info

View File

@ -7,7 +7,6 @@ from .common import InfoExtractor
from ..utils import (
find_xpath_attr,
unified_strdate,
get_element_by_id,
get_element_by_attribute,
int_or_none,
qualities,
@ -146,6 +145,7 @@ class ArteTVPlus7IE(InfoExtractor):
formats.append(format)
self._check_formats(formats, video_id)
self._sort_formats(formats)
info_dict['formats'] = formats
@ -194,7 +194,9 @@ class ArteTVFutureIE(ArteTVPlus7IE):
def _real_extract(self, url):
anchor_id, lang = self._extract_url_info(url)
webpage = self._download_webpage(url, anchor_id)
row = get_element_by_id(anchor_id, webpage)
row = self._search_regex(
r'(?s)id="%s"[^>]*>.+?(<div[^>]*arte_vp_url[^>]*>)' % anchor_id,
webpage, 'row')
return self._extract_from_webpage(row, anchor_id, lang)

View File

@ -3,7 +3,7 @@ from __future__ import unicode_literals
import time
import hmac
from .subtitles import SubtitlesInfoExtractor
from .common import InfoExtractor
from ..compat import (
compat_str,
compat_urllib_parse,
@ -17,8 +17,9 @@ from ..utils import (
)
class AtresPlayerIE(SubtitlesInfoExtractor):
class AtresPlayerIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?atresplayer\.com/television/[^/]+/[^/]+/[^/]+/(?P<id>.+?)_\d+\.html'
_NETRC_MACHINE = 'atresplayer'
_TESTS = [
{
'url': 'http://www.atresplayer.com/television/programas/el-club-de-la-comedia/temporada-4/capitulo-10-especial-solidario-nochebuena_2014122100174.html',
@ -144,13 +145,12 @@ class AtresPlayerIE(SubtitlesInfoExtractor):
thumbnail = xpath_text(episode, './media/asset/files/background', 'thumbnail')
subtitles = {}
subtitle = xpath_text(episode, './media/asset/files/subtitle', 'subtitle')
if subtitle:
subtitles['es'] = subtitle
if self._downloader.params.get('listsubtitles', False):
self._list_available_subtitles(video_id, subtitles)
return
subtitle_url = xpath_text(episode, './media/asset/files/subtitle', 'subtitle')
if subtitle_url:
subtitles['es'] = [{
'ext': 'srt',
'url': subtitle_url,
}]
return {
'id': video_id,
@ -159,5 +159,5 @@ class AtresPlayerIE(SubtitlesInfoExtractor):
'thumbnail': thumbnail,
'duration': duration,
'formats': formats,
'subtitles': self.extract_subtitles(video_id, subtitles),
'subtitles': subtitles,
}

View File

@ -0,0 +1,69 @@
# coding: utf-8
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..compat import compat_urlparse
class BaiduVideoIE(InfoExtractor):
IE_DESC = '百度视频'
_VALID_URL = r'http://v\.baidu\.com/(?P<type>[a-z]+)/(?P<id>\d+)\.htm'
_TESTS = [{
'url': 'http://v.baidu.com/comic/1069.htm?frp=bdbrand&q=%E4%B8%AD%E5%8D%8E%E5%B0%8F%E5%BD%93%E5%AE%B6',
'info_dict': {
'id': '1069',
'title': '中华小当家 TV版 (全52集)',
'description': 'md5:395a419e41215e531c857bb037bbaf80',
},
'playlist_count': 52,
}, {
'url': 'http://v.baidu.com/show/11595.htm?frp=bdbrand',
'info_dict': {
'id': '11595',
'title': 're:^奔跑吧兄弟',
'description': 'md5:1bf88bad6d850930f542d51547c089b8',
},
'playlist_mincount': 3,
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
playlist_id = mobj.group('id')
category = category2 = mobj.group('type')
if category == 'show':
category2 = 'tvshow'
webpage = self._download_webpage(url, playlist_id)
playlist_title = self._html_search_regex(
r'title\s*:\s*(["\'])(?P<title>[^\']+)\1', webpage,
'playlist title', group='title')
playlist_description = self._html_search_regex(
r'<input[^>]+class="j-data-intro"[^>]+value="([^"]+)"/>', webpage,
playlist_id, 'playlist description')
site = self._html_search_regex(
r'filterSite\s*:\s*["\']([^"]*)["\']', webpage,
'primary provider site')
api_result = self._download_json(
'http://v.baidu.com/%s_intro/?dtype=%sPlayUrl&id=%s&site=%s' % (
category, category2, playlist_id, site),
playlist_id, 'Get playlist links')
entries = []
for episode in api_result[0]['episodes']:
episode_id = '%s_%s' % (playlist_id, episode['episode'])
redirect_page = self._download_webpage(
compat_urlparse.urljoin(url, episode['url']), episode_id,
note='Download Baidu redirect page')
real_url = self._html_search_regex(
r'location\.replace\("([^"]+)"\)', redirect_page, 'real URL')
entries.append(self.url_result(
real_url, video_title=episode['single_title']))
return self.playlist_result(
entries, playlist_id, playlist_title, playlist_description)

View File

@ -1,12 +1,18 @@
from __future__ import unicode_literals
import re
import json
import itertools
from .common import InfoExtractor
from ..compat import (
compat_urllib_parse,
compat_urllib_request,
compat_str,
)
from ..utils import (
ExtractorError,
int_or_none,
float_or_none,
)
@ -14,6 +20,8 @@ class BambuserIE(InfoExtractor):
IE_NAME = 'bambuser'
_VALID_URL = r'https?://bambuser\.com/v/(?P<id>\d+)'
_API_KEY = '005f64509e19a868399060af746a00aa'
_LOGIN_URL = 'https://bambuser.com/user'
_NETRC_MACHINE = 'bambuser'
_TEST = {
'url': 'http://bambuser.com/v/4050584',
@ -26,6 +34,9 @@ class BambuserIE(InfoExtractor):
'duration': 3741,
'uploader': 'pixelversity',
'uploader_id': '344706',
'timestamp': 1382976692,
'upload_date': '20131028',
'view_count': int,
},
'params': {
# It doesn't respect the 'Range' header, it would download the whole video
@ -34,23 +45,60 @@ class BambuserIE(InfoExtractor):
},
}
def _login(self):
(username, password) = self._get_login_info()
if username is None:
return
login_form = {
'form_id': 'user_login',
'op': 'Log in',
'name': username,
'pass': password,
}
request = compat_urllib_request.Request(
self._LOGIN_URL, compat_urllib_parse.urlencode(login_form).encode('utf-8'))
request.add_header('Referer', self._LOGIN_URL)
response = self._download_webpage(
request, None, 'Logging in as %s' % username)
login_error = self._html_search_regex(
r'(?s)<div class="messages error">(.+?)</div>',
response, 'login error', default=None)
if login_error:
raise ExtractorError(
'Unable to login: %s' % login_error, expected=True)
def _real_initialize(self):
self._login()
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id')
info_url = ('http://player-c.api.bambuser.com/getVideo.json?'
'&api_key=%s&vid=%s' % (self._API_KEY, video_id))
info_json = self._download_webpage(info_url, video_id)
info = json.loads(info_json)['result']
video_id = self._match_id(url)
info = self._download_json(
'http://player-c.api.bambuser.com/getVideo.json?api_key=%s&vid=%s'
% (self._API_KEY, video_id), video_id)
error = info.get('error')
if error:
raise ExtractorError(
'%s returned error: %s' % (self.IE_NAME, error), expected=True)
result = info['result']
return {
'id': video_id,
'title': info['title'],
'url': info['url'],
'thumbnail': info.get('preview'),
'duration': int(info['length']),
'view_count': int(info['views_total']),
'uploader': info['username'],
'uploader_id': info['uid'],
'title': result['title'],
'url': result['url'],
'thumbnail': result.get('preview'),
'duration': int_or_none(result.get('length')),
'uploader': result.get('username'),
'uploader_id': compat_str(result.get('owner', {}).get('uid')),
'timestamp': int_or_none(result.get('created')),
'fps': float_or_none(result.get('framerate')),
'view_count': int_or_none(result.get('views_total')),
'comment_count': int_or_none(result.get('comment_count')),
}

View File

@ -72,26 +72,29 @@ class BandcampIE(InfoExtractor):
download_link = m_download.group(1)
video_id = self._search_regex(
r'var TralbumData = {.*?id: (?P<id>\d+),?$',
webpage, 'video id', flags=re.MULTILINE | re.DOTALL)
r'(?ms)var TralbumData = .*?[{,]\s*id: (?P<id>\d+),?$',
webpage, 'video id')
download_webpage = self._download_webpage(download_link, video_id, 'Downloading free downloads page')
# We get the dictionary of the track from some javascript code
info = re.search(r'items: (.*?),$', download_webpage, re.MULTILINE).group(1)
info = json.loads(info)[0]
all_info = self._parse_json(self._search_regex(
r'(?sm)items: (.*?),$', download_webpage, 'items'), video_id)
info = all_info[0]
# We pick mp3-320 for now, until format selection can be easily implemented.
mp3_info = info['downloads']['mp3-320']
# If we try to use this url it says the link has expired
initial_url = mp3_info['url']
re_url = r'(?P<server>http://(.*?)\.bandcamp\.com)/download/track\?enc=mp3-320&fsig=(?P<fsig>.*?)&id=(?P<id>.*?)&ts=(?P<ts>.*)$'
m_url = re.match(re_url, initial_url)
m_url = re.match(
r'(?P<server>http://(.*?)\.bandcamp\.com)/download/track\?enc=mp3-320&fsig=(?P<fsig>.*?)&id=(?P<id>.*?)&ts=(?P<ts>.*)$',
initial_url)
# We build the url we will use to get the final track url
# This url is build in Bandcamp in the script download_bunde_*.js
request_url = '%s/statdownload/track?enc=mp3-320&fsig=%s&id=%s&ts=%s&.rand=665028774616&.vrs=1' % (m_url.group('server'), m_url.group('fsig'), video_id, m_url.group('ts'))
final_url_webpage = self._download_webpage(request_url, video_id, 'Requesting download url')
# If we could correctly generate the .rand field the url would be
# in the "download_url" key
final_url = re.search(r'"retry_url":"(.*?)"', final_url_webpage).group(1)
final_url = self._search_regex(
r'"retry_url":"(.*?)"', final_url_webpage, 'final video URL')
return {
'id': video_id,
@ -106,7 +109,7 @@ class BandcampIE(InfoExtractor):
class BandcampAlbumIE(InfoExtractor):
IE_NAME = 'Bandcamp:album'
_VALID_URL = r'https?://(?:(?P<subdomain>[^.]+)\.)?bandcamp\.com(?:/album/(?P<title>[^?#]+)|/?(?:$|[?#]))'
_VALID_URL = r'https?://(?:(?P<subdomain>[^.]+)\.)?bandcamp\.com(?:/album/(?P<album_id>[^?#]+)|/?(?:$|[?#]))'
_TESTS = [{
'url': 'http://blazo.bandcamp.com/album/jazz-format-mixtape-vol-1',
@ -130,31 +133,37 @@ class BandcampAlbumIE(InfoExtractor):
],
'info_dict': {
'title': 'Jazz Format Mixtape vol.1',
'id': 'jazz-format-mixtape-vol-1',
'uploader_id': 'blazo',
},
'params': {
'playlistend': 2
},
'skip': 'Bandcamp imposes download limits. See test_playlists:test_bandcamp_album for the playlist test'
'skip': 'Bandcamp imposes download limits.'
}, {
'url': 'http://nightbringer.bandcamp.com/album/hierophany-of-the-open-grave',
'info_dict': {
'title': 'Hierophany of the Open Grave',
'uploader_id': 'nightbringer',
'id': 'hierophany-of-the-open-grave',
},
'playlist_mincount': 9,
}, {
'url': 'http://dotscale.bandcamp.com',
'info_dict': {
'title': 'Loom',
'id': 'dotscale',
'uploader_id': 'dotscale',
},
'playlist_mincount': 7,
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
playlist_id = mobj.group('subdomain')
title = mobj.group('title')
display_id = title or playlist_id
webpage = self._download_webpage(url, display_id)
uploader_id = mobj.group('subdomain')
album_id = mobj.group('album_id')
playlist_id = album_id or uploader_id
webpage = self._download_webpage(url, playlist_id)
tracks_paths = re.findall(r'<a href="(.*?)" itemprop="url">', webpage)
if not tracks_paths:
raise ExtractorError('The page doesn\'t contain any tracks')
@ -165,8 +174,8 @@ class BandcampAlbumIE(InfoExtractor):
r'album_title\s*:\s*"(.*?)"', webpage, 'title', fatal=False)
return {
'_type': 'playlist',
'uploader_id': uploader_id,
'id': playlist_id,
'display_id': display_id,
'title': title,
'entries': entries,
}

780
youtube_dl/extractor/bbc.py Normal file
View File

@ -0,0 +1,780 @@
# coding: utf-8
from __future__ import unicode_literals
import re
import xml.etree.ElementTree
from .common import InfoExtractor
from ..utils import (
ExtractorError,
float_or_none,
int_or_none,
parse_duration,
parse_iso8601,
)
from ..compat import compat_HTTPError
class BBCCoUkIE(InfoExtractor):
IE_NAME = 'bbc.co.uk'
IE_DESC = 'BBC iPlayer'
_VALID_URL = r'https?://(?:www\.)?bbc\.co\.uk/(?:(?:(?:programmes|iplayer(?:/[^/]+)?/(?:episode|playlist))/)|music/clips[/#])(?P<id>[\da-z]{8})'
_MEDIASELECTOR_URLS = [
'http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/mediaset/pc/vpid/%s',
]
_TESTS = [
{
'url': 'http://www.bbc.co.uk/programmes/b039g8p7',
'info_dict': {
'id': 'b039d07m',
'ext': 'flv',
'title': 'Kaleidoscope, Leonard Cohen',
'description': 'The Canadian poet and songwriter reflects on his musical career.',
'duration': 1740,
},
'params': {
# rtmp download
'skip_download': True,
}
},
{
'url': 'http://www.bbc.co.uk/iplayer/episode/b00yng5w/The_Man_in_Black_Series_3_The_Printed_Name/',
'info_dict': {
'id': 'b00yng1d',
'ext': 'flv',
'title': 'The Man in Black: Series 3: The Printed Name',
'description': "Mark Gatiss introduces Nicholas Pierpan's chilling tale of a writer's devilish pact with a mysterious man. Stars Ewan Bailey.",
'duration': 1800,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'Episode is no longer available on BBC iPlayer Radio',
},
{
'url': 'http://www.bbc.co.uk/iplayer/episode/b03vhd1f/The_Voice_UK_Series_3_Blind_Auditions_5/',
'info_dict': {
'id': 'b00yng1d',
'ext': 'flv',
'title': 'The Voice UK: Series 3: Blind Auditions 5',
'description': "Emma Willis and Marvin Humes present the fifth set of blind auditions in the singing competition, as the coaches continue to build their teams based on voice alone.",
'duration': 5100,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'Currently BBC iPlayer TV programmes are available to play in the UK only',
},
{
'url': 'http://www.bbc.co.uk/iplayer/episode/p026c7jt/tomorrows-worlds-the-unearthly-history-of-science-fiction-2-invasion',
'info_dict': {
'id': 'b03k3pb7',
'ext': 'flv',
'title': "Tomorrow's Worlds: The Unearthly History of Science Fiction",
'description': '2. Invasion',
'duration': 3600,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'Currently BBC iPlayer TV programmes are available to play in the UK only',
}, {
'url': 'http://www.bbc.co.uk/programmes/b04v20dw',
'info_dict': {
'id': 'b04v209v',
'ext': 'flv',
'title': 'Pete Tong, The Essential New Tune Special',
'description': "Pete has a very special mix - all of 2014's Essential New Tunes!",
'duration': 10800,
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
'url': 'http://www.bbc.co.uk/music/clips/p02frcc3',
'note': 'Audio',
'info_dict': {
'id': 'p02frcch',
'ext': 'flv',
'title': 'Pete Tong, Past, Present and Future Special, Madeon - After Hours mix',
'description': 'French house superstar Madeon takes us out of the club and onto the after party.',
'duration': 3507,
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
'url': 'http://www.bbc.co.uk/music/clips/p025c0zz',
'note': 'Video',
'info_dict': {
'id': 'p025c103',
'ext': 'flv',
'title': 'Reading and Leeds Festival, 2014, Rae Morris - Closer (Live on BBC Three)',
'description': 'Rae Morris performs Closer for BBC Three at Reading 2014',
'duration': 226,
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
'url': 'http://www.bbc.co.uk/iplayer/episode/b054fn09/ad/natural-world-20152016-2-super-powered-owls',
'info_dict': {
'id': 'p02n76xf',
'ext': 'flv',
'title': 'Natural World, 2015-2016: 2. Super Powered Owls',
'description': 'md5:e4db5c937d0e95a7c6b5e654d429183d',
'duration': 3540,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'geolocation',
}, {
'url': 'http://www.bbc.co.uk/iplayer/episode/b05zmgwn/royal-academy-summer-exhibition',
'info_dict': {
'id': 'b05zmgw1',
'ext': 'flv',
'description': 'Kirsty Wark and Morgan Quaintance visit the Royal Academy as it prepares for its annual artistic extravaganza, meeting people who have come together to make the show unique.',
'title': 'Royal Academy Summer Exhibition',
'duration': 3540,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'geolocation',
}, {
'url': 'http://www.bbc.co.uk/iplayer/playlist/p01dvks4',
'only_matching': True,
}, {
'url': 'http://www.bbc.co.uk/music/clips#p02frcc3',
'only_matching': True,
}, {
'url': 'http://www.bbc.co.uk/iplayer/cbeebies/episode/b0480276/bing-14-atchoo',
'only_matching': True,
}
]
class MediaSelectionError(Exception):
def __init__(self, id):
self.id = id
def _extract_asx_playlist(self, connection, programme_id):
asx = self._download_xml(connection.get('href'), programme_id, 'Downloading ASX playlist')
return [ref.get('href') for ref in asx.findall('./Entry/ref')]
def _extract_connection(self, connection, programme_id):
formats = []
protocol = connection.get('protocol')
supplier = connection.get('supplier')
if protocol == 'http':
href = connection.get('href')
transfer_format = connection.get('transferFormat')
# ASX playlist
if supplier == 'asx':
for i, ref in enumerate(self._extract_asx_playlist(connection, programme_id)):
formats.append({
'url': ref,
'format_id': 'ref%s_%s' % (i, supplier),
})
# Skip DASH until supported
elif transfer_format == 'dash':
pass
# Direct link
else:
formats.append({
'url': href,
'format_id': supplier,
})
elif protocol == 'rtmp':
application = connection.get('application', 'ondemand')
auth_string = connection.get('authString')
identifier = connection.get('identifier')
server = connection.get('server')
formats.append({
'url': '%s://%s/%s?%s' % (protocol, server, application, auth_string),
'play_path': identifier,
'app': '%s?%s' % (application, auth_string),
'page_url': 'http://www.bbc.co.uk',
'player_url': 'http://www.bbc.co.uk/emp/releases/iplayer/revisions/617463_618125_4/617463_618125_4_emp.swf',
'rtmp_live': False,
'ext': 'flv',
'format_id': supplier,
})
return formats
def _extract_items(self, playlist):
return playlist.findall('./{http://bbc.co.uk/2008/emp/playlist}item')
def _extract_medias(self, media_selection):
error = media_selection.find('./{http://bbc.co.uk/2008/mp/mediaselection}error')
if error is not None:
raise BBCCoUkIE.MediaSelectionError(error.get('id'))
return media_selection.findall('./{http://bbc.co.uk/2008/mp/mediaselection}media')
def _extract_connections(self, media):
return media.findall('./{http://bbc.co.uk/2008/mp/mediaselection}connection')
def _extract_video(self, media, programme_id):
formats = []
vbr = int_or_none(media.get('bitrate'))
vcodec = media.get('encoding')
service = media.get('service')
width = int_or_none(media.get('width'))
height = int_or_none(media.get('height'))
file_size = int_or_none(media.get('media_file_size'))
for connection in self._extract_connections(media):
conn_formats = self._extract_connection(connection, programme_id)
for format in conn_formats:
format.update({
'format_id': '%s_%s' % (service, format['format_id']),
'width': width,
'height': height,
'vbr': vbr,
'vcodec': vcodec,
'filesize': file_size,
})
formats.extend(conn_formats)
return formats
def _extract_audio(self, media, programme_id):
formats = []
abr = int_or_none(media.get('bitrate'))
acodec = media.get('encoding')
service = media.get('service')
for connection in self._extract_connections(media):
conn_formats = self._extract_connection(connection, programme_id)
for format in conn_formats:
format.update({
'format_id': '%s_%s' % (service, format['format_id']),
'abr': abr,
'acodec': acodec,
})
formats.extend(conn_formats)
return formats
def _get_subtitles(self, media, programme_id):
subtitles = {}
for connection in self._extract_connections(media):
captions = self._download_xml(connection.get('href'), programme_id, 'Downloading captions')
lang = captions.get('{http://www.w3.org/XML/1998/namespace}lang', 'en')
subtitles[lang] = [
{
'url': connection.get('href'),
'ext': 'ttml',
},
]
return subtitles
def _raise_extractor_error(self, media_selection_error):
raise ExtractorError(
'%s returned error: %s' % (self.IE_NAME, media_selection_error.id),
expected=True)
def _download_media_selector(self, programme_id):
last_exception = None
for mediaselector_url in self._MEDIASELECTOR_URLS:
try:
return self._download_media_selector_url(
mediaselector_url % programme_id, programme_id)
except BBCCoUkIE.MediaSelectionError as e:
if e.id == 'notukerror':
last_exception = e
continue
self._raise_extractor_error(e)
self._raise_extractor_error(last_exception)
def _download_media_selector_url(self, url, programme_id=None):
try:
media_selection = self._download_xml(
url, programme_id, 'Downloading media selection XML')
except ExtractorError as ee:
if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 403:
media_selection = xml.etree.ElementTree.fromstring(ee.cause.read().decode('utf-8'))
else:
raise
return self._process_media_selector(media_selection, programme_id)
def _process_media_selector(self, media_selection, programme_id):
formats = []
subtitles = None
for media in self._extract_medias(media_selection):
kind = media.get('kind')
if kind == 'audio':
formats.extend(self._extract_audio(media, programme_id))
elif kind == 'video':
formats.extend(self._extract_video(media, programme_id))
elif kind == 'captions':
subtitles = self.extract_subtitles(media, programme_id)
return formats, subtitles
def _download_playlist(self, playlist_id):
try:
playlist = self._download_json(
'http://www.bbc.co.uk/programmes/%s/playlist.json' % playlist_id,
playlist_id, 'Downloading playlist JSON')
version = playlist.get('defaultAvailableVersion')
if version:
smp_config = version['smpConfig']
title = smp_config['title']
description = smp_config['summary']
for item in smp_config['items']:
kind = item['kind']
if kind != 'programme' and kind != 'radioProgramme':
continue
programme_id = item.get('vpid')
duration = int_or_none(item.get('duration'))
formats, subtitles = self._download_media_selector(programme_id)
return programme_id, title, description, duration, formats, subtitles
except ExtractorError as ee:
if not (isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 404):
raise
# fallback to legacy playlist
return self._process_legacy_playlist(playlist_id)
def _process_legacy_playlist_url(self, url, display_id):
playlist = self._download_legacy_playlist_url(url, display_id)
return self._extract_from_legacy_playlist(playlist, display_id)
def _process_legacy_playlist(self, playlist_id):
return self._process_legacy_playlist_url(
'http://www.bbc.co.uk/iplayer/playlist/%s' % playlist_id, playlist_id)
def _download_legacy_playlist_url(self, url, playlist_id=None):
return self._download_xml(
url, playlist_id, 'Downloading legacy playlist XML')
def _extract_from_legacy_playlist(self, playlist, playlist_id):
no_items = playlist.find('./{http://bbc.co.uk/2008/emp/playlist}noItems')
if no_items is not None:
reason = no_items.get('reason')
if reason == 'preAvailability':
msg = 'Episode %s is not yet available' % playlist_id
elif reason == 'postAvailability':
msg = 'Episode %s is no longer available' % playlist_id
elif reason == 'noMedia':
msg = 'Episode %s is not currently available' % playlist_id
else:
msg = 'Episode %s is not available: %s' % (playlist_id, reason)
raise ExtractorError(msg, expected=True)
for item in self._extract_items(playlist):
kind = item.get('kind')
if kind != 'programme' and kind != 'radioProgramme':
continue
title = playlist.find('./{http://bbc.co.uk/2008/emp/playlist}title').text
description = playlist.find('./{http://bbc.co.uk/2008/emp/playlist}summary').text
def get_programme_id(item):
def get_from_attributes(item):
for p in('identifier', 'group'):
value = item.get(p)
if value and re.match(r'^[pb][\da-z]{7}$', value):
return value
get_from_attributes(item)
mediator = item.find('./{http://bbc.co.uk/2008/emp/playlist}mediator')
if mediator is not None:
return get_from_attributes(mediator)
programme_id = get_programme_id(item)
duration = int_or_none(item.get('duration'))
# TODO: programme_id can be None and media items can be incorporated right inside
# playlist's item (e.g. http://www.bbc.com/turkce/haberler/2015/06/150615_telabyad_kentin_cogu)
# as f4m and m3u8
formats, subtitles = self._download_media_selector(programme_id)
return programme_id, title, description, duration, formats, subtitles
def _real_extract(self, url):
group_id = self._match_id(url)
webpage = self._download_webpage(url, group_id, 'Downloading video page')
programme_id = None
tviplayer = self._search_regex(
r'mediator\.bind\(({.+?})\s*,\s*document\.getElementById',
webpage, 'player', default=None)
if tviplayer:
player = self._parse_json(tviplayer, group_id).get('player', {})
duration = int_or_none(player.get('duration'))
programme_id = player.get('vpid')
if not programme_id:
programme_id = self._search_regex(
r'"vpid"\s*:\s*"([\da-z]{8})"', webpage, 'vpid', fatal=False, default=None)
if programme_id:
formats, subtitles = self._download_media_selector(programme_id)
title = self._og_search_title(webpage)
description = self._search_regex(
r'<p class="[^"]*medium-description[^"]*">([^<]+)</p>',
webpage, 'description', fatal=False)
else:
programme_id, title, description, duration, formats, subtitles = self._download_playlist(group_id)
self._sort_formats(formats)
return {
'id': programme_id,
'title': title,
'description': description,
'thumbnail': self._og_search_thumbnail(webpage, default=None),
'duration': duration,
'formats': formats,
'subtitles': subtitles,
}
class BBCIE(BBCCoUkIE):
IE_NAME = 'bbc'
IE_DESC = 'BBC'
_VALID_URL = r'https?://(?:www\.)?bbc\.(?:com|co\.uk)/(?:[^/]+/)+(?P<id>[^/#?]+)'
_MEDIASELECTOR_URLS = [
# Provides more formats, namely direct mp4 links, but fails on some videos with
# notukerror for non UK (?) users (e.g.
# http://www.bbc.com/travel/story/20150625-sri-lankas-spicy-secret)
'http://open.live.bbc.co.uk/mediaselector/4/mtis/stream/%s',
# Provides fewer formats, but works everywhere for everybody (hopefully)
'http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/mediaset/journalism-pc/vpid/%s',
]
_TESTS = [{
# article with multiple videos embedded with data-media-meta containing
# playlist.sxml, externalId and no direct video links
'url': 'http://www.bbc.com/news/world-europe-32668511',
'info_dict': {
'id': 'world-europe-32668511',
'title': 'Russia stages massive WW2 parade despite Western boycott',
'description': 'md5:00ff61976f6081841f759a08bf78cc9c',
},
'playlist_count': 2,
}, {
# article with multiple videos embedded with data-media-meta (more videos)
'url': 'http://www.bbc.com/news/business-28299555',
'info_dict': {
'id': 'business-28299555',
'title': 'Farnborough Airshow: Video highlights',
'description': 'BBC reports and video highlights at the Farnborough Airshow.',
},
'playlist_count': 9,
'skip': 'Save time',
}, {
# article with multiple videos embedded with `new SMP()`
'url': 'http://www.bbc.co.uk/blogs/adamcurtis/entries/3662a707-0af9-3149-963f-47bea720b460',
'info_dict': {
'id': '3662a707-0af9-3149-963f-47bea720b460',
'title': 'BBC Blogs - Adam Curtis - BUGGER',
},
'playlist_count': 18,
}, {
# single video embedded with mediaAssetPage.init()
'url': 'http://www.bbc.com/news/world-europe-32041533',
'info_dict': {
'id': 'p02mprgb',
'ext': 'mp4',
'title': 'Aerial footage showed the site of the crash in the Alps - courtesy BFM TV',
'duration': 47,
'timestamp': 1427219242,
'upload_date': '20150324',
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
# article with single video embedded with data-media-meta containing
# direct video links (for now these are extracted) and playlist.xml (with
# media items as f4m and m3u8 - currently unsupported)
'url': 'http://www.bbc.com/turkce/haberler/2015/06/150615_telabyad_kentin_cogu',
'info_dict': {
'id': '150615_telabyad_kentin_cogu',
'ext': 'mp4',
'title': "YPG: Tel Abyad'ın tamamı kontrolümüzde",
'duration': 47,
'timestamp': 1434397334,
'upload_date': '20150615',
},
'params': {
'skip_download': True,
}
}, {
# single video embedded with mediaAssetPage.init() (regional section)
'url': 'http://www.bbc.com/mundo/video_fotos/2015/06/150619_video_honduras_militares_hospitales_corrupcion_aw',
'info_dict': {
'id': '150619_video_honduras_militares_hospitales_corrupcion_aw',
'ext': 'mp4',
'title': 'Honduras militariza sus hospitales por nuevo escándalo de corrupción',
'duration': 87,
'timestamp': 1434713142,
'upload_date': '20150619',
},
'params': {
'skip_download': True,
}
}, {
# single video from video playlist embedded with vxp-playlist-data JSON
'url': 'http://www.bbc.com/news/video_and_audio/must_see/33376376',
'info_dict': {
'id': 'p02w6qjc',
'ext': 'mp4',
'title': '''Judge Mindy Glazer: "I'm sorry to see you here... I always wondered what happened to you"''',
'duration': 56,
},
'params': {
'skip_download': True,
}
}, {
# single video story with digitalData
'url': 'http://www.bbc.com/travel/story/20150625-sri-lankas-spicy-secret',
'info_dict': {
'id': 'p02q6gc4',
'ext': 'flv',
'title': 'Sri Lankas spicy secret',
'description': 'As a new train line to Jaffna opens up the countrys north, travellers can experience a truly distinct slice of Tamil culture.',
'timestamp': 1437674293,
'upload_date': '20150723',
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
# single video story without digitalData
'url': 'http://www.bbc.com/autos/story/20130513-hyundais-rock-star',
'info_dict': {
'id': 'p018zqqg',
'ext': 'mp4',
'title': 'Hyundai Santa Fe Sport: Rock star',
'description': 'md5:b042a26142c4154a6e472933cf20793d',
'timestamp': 1368473503,
'upload_date': '20130513',
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
# single video with playlist.sxml URL
'url': 'http://www.bbc.com/sport/0/football/33653409',
'info_dict': {
'id': 'p02xycnp',
'ext': 'mp4',
'title': 'Transfers: Cristiano Ronaldo to Man Utd, Arsenal to spend?',
'description': 'md5:398fca0e2e701c609d726e034fa1fc89',
'duration': 140,
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
# single video with playlist URL from weather section
'url': 'http://www.bbc.com/weather/features/33601775',
'only_matching': True,
}, {
# custom redirection to www.bbc.com
'url': 'http://www.bbc.co.uk/news/science-environment-33661876',
'only_matching': True,
}]
@classmethod
def suitable(cls, url):
return False if BBCCoUkIE.suitable(url) else super(BBCIE, cls).suitable(url)
def _extract_from_media_meta(self, media_meta, video_id):
# Direct links to media in media metadata (e.g.
# http://www.bbc.com/turkce/haberler/2015/06/150615_telabyad_kentin_cogu)
# TODO: there are also f4m and m3u8 streams incorporated in playlist.sxml
source_files = media_meta.get('sourceFiles')
if source_files:
return [{
'url': f['url'],
'format_id': format_id,
'ext': f.get('encoding'),
'tbr': float_or_none(f.get('bitrate'), 1000),
'filesize': int_or_none(f.get('filesize')),
} for format_id, f in source_files.items() if f.get('url')], []
programme_id = media_meta.get('externalId')
if programme_id:
return self._download_media_selector(programme_id)
# Process playlist.sxml as legacy playlist
href = media_meta.get('href')
if href:
playlist = self._download_legacy_playlist_url(href)
_, _, _, _, formats, subtitles = self._extract_from_legacy_playlist(playlist, video_id)
return formats, subtitles
return [], []
def _real_extract(self, url):
playlist_id = self._match_id(url)
webpage = self._download_webpage(url, playlist_id)
timestamp = parse_iso8601(self._search_regex(
[r'"datePublished":\s*"([^"]+)',
r'<meta[^>]+property="article:published_time"[^>]+content="([^"]+)"',
r'itemprop="datePublished"[^>]+datetime="([^"]+)"'],
webpage, 'date', default=None))
# single video with playlist.sxml URL (e.g. http://www.bbc.com/sport/0/football/3365340ng)
playlist = self._search_regex(
r'<param[^>]+name="playlist"[^>]+value="([^"]+)"',
webpage, 'playlist', default=None)
if playlist:
programme_id, title, description, duration, formats, subtitles = \
self._process_legacy_playlist_url(playlist, playlist_id)
self._sort_formats(formats)
return {
'id': programme_id,
'title': title,
'description': description,
'duration': duration,
'timestamp': timestamp,
'formats': formats,
'subtitles': subtitles,
}
# single video story (e.g. http://www.bbc.com/travel/story/20150625-sri-lankas-spicy-secret)
programme_id = self._search_regex(
[r'data-video-player-vpid="([\da-z]{8})"',
r'<param[^>]+name="externalIdentifier"[^>]+value="([\da-z]{8})"'],
webpage, 'vpid', default=None)
if programme_id:
formats, subtitles = self._download_media_selector(programme_id)
self._sort_formats(formats)
# digitalData may be missing (e.g. http://www.bbc.com/autos/story/20130513-hyundais-rock-star)
digital_data = self._parse_json(
self._search_regex(
r'var\s+digitalData\s*=\s*({.+?});?\n', webpage, 'digital data', default='{}'),
programme_id, fatal=False)
page_info = digital_data.get('page', {}).get('pageInfo', {})
title = page_info.get('pageName') or self._og_search_title(webpage)
description = page_info.get('description') or self._og_search_description(webpage)
timestamp = parse_iso8601(page_info.get('publicationDate')) or timestamp
return {
'id': programme_id,
'title': title,
'description': description,
'timestamp': timestamp,
'formats': formats,
'subtitles': subtitles,
}
playlist_title = self._html_search_regex(
r'<title>(.*?)(?:\s*-\s*BBC [^ ]+)?</title>', webpage, 'playlist title')
playlist_description = self._og_search_description(webpage, default=None)
def extract_all(pattern):
return list(filter(None, map(
lambda s: self._parse_json(s, playlist_id, fatal=False),
re.findall(pattern, webpage))))
# Multiple video article (e.g.
# http://www.bbc.co.uk/blogs/adamcurtis/entries/3662a707-0af9-3149-963f-47bea720b460)
EMBED_URL = r'https?://(?:www\.)?bbc\.co\.uk/(?:[^/]+/)+[\da-z]{8}(?:\b[^"]+)?'
entries = []
for match in extract_all(r'new\s+SMP\(({.+?})\)'):
embed_url = match.get('playerSettings', {}).get('externalEmbedUrl')
if embed_url and re.match(EMBED_URL, embed_url):
entries.append(embed_url)
entries.extend(re.findall(
r'setPlaylist\("(%s)"\)' % EMBED_URL, webpage))
if entries:
return self.playlist_result(
[self.url_result(entry, 'BBCCoUk') for entry in entries],
playlist_id, playlist_title, playlist_description)
# Multiple video article (e.g. http://www.bbc.com/news/world-europe-32668511)
medias = extract_all(r"data-media-meta='({[^']+})'")
if not medias:
# Single video article (e.g. http://www.bbc.com/news/video_and_audio/international)
media_asset = self._search_regex(
r'mediaAssetPage\.init\(\s*({.+?}), "/',
webpage, 'media asset', default=None)
if media_asset:
media_asset_page = self._parse_json(media_asset, playlist_id, fatal=False)
medias = []
for video in media_asset_page.get('videos', {}).values():
medias.extend(video.values())
if not medias:
# Multiple video playlist with single `now playing` entry (e.g.
# http://www.bbc.com/news/video_and_audio/must_see/33767813)
vxp_playlist = self._parse_json(
self._search_regex(
r'<script[^>]+class="vxp-playlist-data"[^>]+type="application/json"[^>]*>([^<]+)</script>',
webpage, 'playlist data'),
playlist_id)
playlist_medias = []
for item in vxp_playlist:
media = item.get('media')
if not media:
continue
playlist_medias.append(media)
# Download single video if found media with asset id matching the video id from URL
if item.get('advert', {}).get('assetId') == playlist_id:
medias = [media]
break
# Fallback to the whole playlist
if not medias:
medias = playlist_medias
entries = []
for num, media_meta in enumerate(medias, start=1):
formats, subtitles = self._extract_from_media_meta(media_meta, playlist_id)
if not formats:
continue
self._sort_formats(formats)
video_id = media_meta.get('externalId')
if not video_id:
video_id = playlist_id if len(medias) == 1 else '%s-%s' % (playlist_id, num)
title = media_meta.get('caption')
if not title:
title = playlist_title if len(medias) == 1 else '%s - Video %s' % (playlist_title, num)
duration = int_or_none(media_meta.get('durationInSeconds')) or parse_duration(media_meta.get('duration'))
images = []
for image in media_meta.get('images', {}).values():
images.extend(image.values())
if 'image' in media_meta:
images.append(media_meta['image'])
thumbnails = [{
'url': image.get('href'),
'width': int_or_none(image.get('width')),
'height': int_or_none(image.get('height')),
} for image in images]
entries.append({
'id': video_id,
'title': title,
'thumbnails': thumbnails,
'duration': duration,
'timestamp': timestamp,
'formats': formats,
'subtitles': subtitles,
})
return self.playlist_result(entries, playlist_id, playlist_title, playlist_description)

View File

@ -1,340 +0,0 @@
from __future__ import unicode_literals
import xml.etree.ElementTree
from .subtitles import SubtitlesInfoExtractor
from ..utils import ExtractorError
from ..compat import compat_HTTPError
class BBCCoUkIE(SubtitlesInfoExtractor):
IE_NAME = 'bbc.co.uk'
IE_DESC = 'BBC iPlayer'
_VALID_URL = r'https?://(?:www\.)?bbc\.co\.uk/(?:(?:(?:programmes|iplayer(?:/[^/]+)?/(?:episode|playlist))/)|music/clips[/#])(?P<id>[\da-z]{8})'
_TESTS = [
{
'url': 'http://www.bbc.co.uk/programmes/b039g8p7',
'info_dict': {
'id': 'b039d07m',
'ext': 'flv',
'title': 'Kaleidoscope, Leonard Cohen',
'description': 'The Canadian poet and songwriter reflects on his musical career.',
'duration': 1740,
},
'params': {
# rtmp download
'skip_download': True,
}
},
{
'url': 'http://www.bbc.co.uk/iplayer/episode/b00yng5w/The_Man_in_Black_Series_3_The_Printed_Name/',
'info_dict': {
'id': 'b00yng1d',
'ext': 'flv',
'title': 'The Man in Black: Series 3: The Printed Name',
'description': "Mark Gatiss introduces Nicholas Pierpan's chilling tale of a writer's devilish pact with a mysterious man. Stars Ewan Bailey.",
'duration': 1800,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'Episode is no longer available on BBC iPlayer Radio',
},
{
'url': 'http://www.bbc.co.uk/iplayer/episode/b03vhd1f/The_Voice_UK_Series_3_Blind_Auditions_5/',
'info_dict': {
'id': 'b00yng1d',
'ext': 'flv',
'title': 'The Voice UK: Series 3: Blind Auditions 5',
'description': "Emma Willis and Marvin Humes present the fifth set of blind auditions in the singing competition, as the coaches continue to build their teams based on voice alone.",
'duration': 5100,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'Currently BBC iPlayer TV programmes are available to play in the UK only',
},
{
'url': 'http://www.bbc.co.uk/iplayer/episode/p026c7jt/tomorrows-worlds-the-unearthly-history-of-science-fiction-2-invasion',
'info_dict': {
'id': 'b03k3pb7',
'ext': 'flv',
'title': "Tomorrow's Worlds: The Unearthly History of Science Fiction",
'description': '2. Invasion',
'duration': 3600,
},
'params': {
# rtmp download
'skip_download': True,
},
'skip': 'Currently BBC iPlayer TV programmes are available to play in the UK only',
}, {
'url': 'http://www.bbc.co.uk/programmes/b04v20dw',
'info_dict': {
'id': 'b04v209v',
'ext': 'flv',
'title': 'Pete Tong, The Essential New Tune Special',
'description': "Pete has a very special mix - all of 2014's Essential New Tunes!",
'duration': 10800,
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
'url': 'http://www.bbc.co.uk/music/clips/p02frcc3',
'note': 'Audio',
'info_dict': {
'id': 'p02frcch',
'ext': 'flv',
'title': 'Pete Tong, Past, Present and Future Special, Madeon - After Hours mix',
'description': 'French house superstar Madeon takes us out of the club and onto the after party.',
'duration': 3507,
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
'url': 'http://www.bbc.co.uk/music/clips/p025c0zz',
'note': 'Video',
'info_dict': {
'id': 'p025c103',
'ext': 'flv',
'title': 'Reading and Leeds Festival, 2014, Rae Morris - Closer (Live on BBC Three)',
'description': 'Rae Morris performs Closer for BBC Three at Reading 2014',
'duration': 226,
},
'params': {
# rtmp download
'skip_download': True,
}
}, {
'url': 'http://www.bbc.co.uk/iplayer/playlist/p01dvks4',
'only_matching': True,
}, {
'url': 'http://www.bbc.co.uk/music/clips#p02frcc3',
'only_matching': True,
}, {
'url': 'http://www.bbc.co.uk/iplayer/cbeebies/episode/b0480276/bing-14-atchoo',
'only_matching': True,
}
]
def _extract_asx_playlist(self, connection, programme_id):
asx = self._download_xml(connection.get('href'), programme_id, 'Downloading ASX playlist')
return [ref.get('href') for ref in asx.findall('./Entry/ref')]
def _extract_connection(self, connection, programme_id):
formats = []
protocol = connection.get('protocol')
supplier = connection.get('supplier')
if protocol == 'http':
href = connection.get('href')
# ASX playlist
if supplier == 'asx':
for i, ref in enumerate(self._extract_asx_playlist(connection, programme_id)):
formats.append({
'url': ref,
'format_id': 'ref%s_%s' % (i, supplier),
})
# Direct link
else:
formats.append({
'url': href,
'format_id': supplier,
})
elif protocol == 'rtmp':
application = connection.get('application', 'ondemand')
auth_string = connection.get('authString')
identifier = connection.get('identifier')
server = connection.get('server')
formats.append({
'url': '%s://%s/%s?%s' % (protocol, server, application, auth_string),
'play_path': identifier,
'app': '%s?%s' % (application, auth_string),
'page_url': 'http://www.bbc.co.uk',
'player_url': 'http://www.bbc.co.uk/emp/releases/iplayer/revisions/617463_618125_4/617463_618125_4_emp.swf',
'rtmp_live': False,
'ext': 'flv',
'format_id': supplier,
})
return formats
def _extract_items(self, playlist):
return playlist.findall('./{http://bbc.co.uk/2008/emp/playlist}item')
def _extract_medias(self, media_selection):
error = media_selection.find('./{http://bbc.co.uk/2008/mp/mediaselection}error')
if error is not None:
raise ExtractorError(
'%s returned error: %s' % (self.IE_NAME, error.get('id')), expected=True)
return media_selection.findall('./{http://bbc.co.uk/2008/mp/mediaselection}media')
def _extract_connections(self, media):
return media.findall('./{http://bbc.co.uk/2008/mp/mediaselection}connection')
def _extract_video(self, media, programme_id):
formats = []
vbr = int(media.get('bitrate'))
vcodec = media.get('encoding')
service = media.get('service')
width = int(media.get('width'))
height = int(media.get('height'))
file_size = int(media.get('media_file_size'))
for connection in self._extract_connections(media):
conn_formats = self._extract_connection(connection, programme_id)
for format in conn_formats:
format.update({
'format_id': '%s_%s' % (service, format['format_id']),
'width': width,
'height': height,
'vbr': vbr,
'vcodec': vcodec,
'filesize': file_size,
})
formats.extend(conn_formats)
return formats
def _extract_audio(self, media, programme_id):
formats = []
abr = int(media.get('bitrate'))
acodec = media.get('encoding')
service = media.get('service')
for connection in self._extract_connections(media):
conn_formats = self._extract_connection(connection, programme_id)
for format in conn_formats:
format.update({
'format_id': '%s_%s' % (service, format['format_id']),
'abr': abr,
'acodec': acodec,
})
formats.extend(conn_formats)
return formats
def _extract_captions(self, media, programme_id):
subtitles = {}
for connection in self._extract_connections(media):
captions = self._download_xml(connection.get('href'), programme_id, 'Downloading captions')
lang = captions.get('{http://www.w3.org/XML/1998/namespace}lang', 'en')
ps = captions.findall('./{0}body/{0}div/{0}p'.format('{http://www.w3.org/2006/10/ttaf1}'))
srt = ''
for pos, p in enumerate(ps):
srt += '%s\r\n%s --> %s\r\n%s\r\n\r\n' % (str(pos), p.get('begin'), p.get('end'),
p.text.strip() if p.text is not None else '')
subtitles[lang] = srt
return subtitles
def _download_media_selector(self, programme_id):
try:
media_selection = self._download_xml(
'http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/mediaset/pc/vpid/%s' % programme_id,
programme_id, 'Downloading media selection XML')
except ExtractorError as ee:
if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 403:
media_selection = xml.etree.ElementTree.fromstring(ee.cause.read().encode('utf-8'))
else:
raise
formats = []
subtitles = None
for media in self._extract_medias(media_selection):
kind = media.get('kind')
if kind == 'audio':
formats.extend(self._extract_audio(media, programme_id))
elif kind == 'video':
formats.extend(self._extract_video(media, programme_id))
elif kind == 'captions':
subtitles = self._extract_captions(media, programme_id)
return formats, subtitles
def _download_playlist(self, playlist_id):
try:
playlist = self._download_json(
'http://www.bbc.co.uk/programmes/%s/playlist.json' % playlist_id,
playlist_id, 'Downloading playlist JSON')
version = playlist.get('defaultAvailableVersion')
if version:
smp_config = version['smpConfig']
title = smp_config['title']
description = smp_config['summary']
for item in smp_config['items']:
kind = item['kind']
if kind != 'programme' and kind != 'radioProgramme':
continue
programme_id = item.get('vpid')
duration = int(item.get('duration'))
formats, subtitles = self._download_media_selector(programme_id)
return programme_id, title, description, duration, formats, subtitles
except ExtractorError as ee:
if not isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 404:
raise
# fallback to legacy playlist
playlist = self._download_xml(
'http://www.bbc.co.uk/iplayer/playlist/%s' % playlist_id,
playlist_id, 'Downloading legacy playlist XML')
no_items = playlist.find('./{http://bbc.co.uk/2008/emp/playlist}noItems')
if no_items is not None:
reason = no_items.get('reason')
if reason == 'preAvailability':
msg = 'Episode %s is not yet available' % playlist_id
elif reason == 'postAvailability':
msg = 'Episode %s is no longer available' % playlist_id
elif reason == 'noMedia':
msg = 'Episode %s is not currently available' % playlist_id
else:
msg = 'Episode %s is not available: %s' % (playlist_id, reason)
raise ExtractorError(msg, expected=True)
for item in self._extract_items(playlist):
kind = item.get('kind')
if kind != 'programme' and kind != 'radioProgramme':
continue
title = playlist.find('./{http://bbc.co.uk/2008/emp/playlist}title').text
description = playlist.find('./{http://bbc.co.uk/2008/emp/playlist}summary').text
programme_id = item.get('identifier')
duration = int(item.get('duration'))
formats, subtitles = self._download_media_selector(programme_id)
return programme_id, title, description, duration, formats, subtitles
def _real_extract(self, url):
group_id = self._match_id(url)
webpage = self._download_webpage(url, group_id, 'Downloading video page')
programme_id = self._search_regex(
r'"vpid"\s*:\s*"([\da-z]{8})"', webpage, 'vpid', fatal=False, default=None)
if programme_id:
player = self._download_json(
'http://www.bbc.co.uk/iplayer/episode/%s.json' % group_id,
group_id)['jsConf']['player']
title = player['title']
description = player['subtitle']
duration = player['duration']
formats, subtitles = self._download_media_selector(programme_id)
else:
programme_id, title, description, duration, formats, subtitles = self._download_playlist(group_id)
if self._downloader.params.get('listsubtitles', False):
self._list_available_subtitles(programme_id, subtitles)
return
self._sort_formats(formats)
return {
'id': programme_id,
'title': title,
'description': description,
'duration': duration,
'formats': formats,
'subtitles': subtitles,
}

View File

@ -0,0 +1,103 @@
# coding: utf-8
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..compat import compat_str
from ..utils import int_or_none
class BeatportProIE(InfoExtractor):
_VALID_URL = r'https?://pro\.beatport\.com/track/(?P<display_id>[^/]+)/(?P<id>[0-9]+)'
_TESTS = [{
'url': 'https://pro.beatport.com/track/synesthesia-original-mix/5379371',
'md5': 'b3c34d8639a2f6a7f734382358478887',
'info_dict': {
'id': '5379371',
'display_id': 'synesthesia-original-mix',
'ext': 'mp4',
'title': 'Froxic - Synesthesia (Original Mix)',
},
}, {
'url': 'https://pro.beatport.com/track/love-and-war-original-mix/3756896',
'md5': 'e44c3025dfa38c6577fbaeb43da43514',
'info_dict': {
'id': '3756896',
'display_id': 'love-and-war-original-mix',
'ext': 'mp3',
'title': 'Wolfgang Gartner - Love & War (Original Mix)',
},
}, {
'url': 'https://pro.beatport.com/track/birds-original-mix/4991738',
'md5': 'a1fd8e8046de3950fd039304c186c05f',
'info_dict': {
'id': '4991738',
'display_id': 'birds-original-mix',
'ext': 'mp4',
'title': "Tos, Middle Milk, Mumblin' Johnsson - Birds (Original Mix)",
}
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
track_id = mobj.group('id')
display_id = mobj.group('display_id')
webpage = self._download_webpage(url, display_id)
playables = self._parse_json(
self._search_regex(
r'window\.Playables\s*=\s*({.+?});', webpage,
'playables info', flags=re.DOTALL),
track_id)
track = next(t for t in playables['tracks'] if t['id'] == int(track_id))
title = ', '.join((a['name'] for a in track['artists'])) + ' - ' + track['name']
if track['mix']:
title += ' (' + track['mix'] + ')'
formats = []
for ext, info in track['preview'].items():
if not info['url']:
continue
fmt = {
'url': info['url'],
'ext': ext,
'format_id': ext,
'vcodec': 'none',
}
if ext == 'mp3':
fmt['preference'] = 0
fmt['acodec'] = 'mp3'
fmt['abr'] = 96
fmt['asr'] = 44100
elif ext == 'mp4':
fmt['preference'] = 1
fmt['acodec'] = 'aac'
fmt['abr'] = 96
fmt['asr'] = 44100
formats.append(fmt)
self._sort_formats(formats)
images = []
for name, info in track['images'].items():
image_url = info.get('url')
if name == 'dynamic' or not image_url:
continue
image = {
'id': name,
'url': image_url,
'height': int_or_none(info.get('height')),
'width': int_or_none(info.get('width')),
}
images.append(image)
return {
'id': compat_str(track.get('id')) or track_id,
'display_id': track.get('slug') or display_id,
'title': title,
'formats': formats,
'thumbnails': images,
}

View File

@ -9,7 +9,7 @@ class BeegIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?beeg\.com/(?P<id>\d+)'
_TEST = {
'url': 'http://beeg.com/5416503',
'md5': '634526ae978711f6b748fe0dd6c11f57',
'md5': '1bff67111adb785c51d1b42959ec10e5',
'info_dict': {
'id': '5416503',
'ext': 'mp4',

View File

@ -1,7 +1,7 @@
from __future__ import unicode_literals
from .common import InfoExtractor
from ..compat import compat_urllib_parse
from ..compat import compat_urllib_parse_unquote
from ..utils import (
xpath_text,
xpath_with_ns,
@ -16,11 +16,11 @@ class BetIE(InfoExtractor):
{
'url': 'http://www.bet.com/news/politics/2014/12/08/in-bet-exclusive-obama-talks-race-and-racism.html',
'info_dict': {
'id': '740ab250-bb94-4a8a-8787-fe0de7c74471',
'id': 'news/national/2014/a-conversation-with-president-obama',
'display_id': 'in-bet-exclusive-obama-talks-race-and-racism',
'ext': 'flv',
'title': 'BET News Presents: A Conversation With President Obama',
'description': 'md5:5a88d8ae912c1b33e090290af7ec33c6',
'title': 'A Conversation With President Obama',
'description': 'md5:699d0652a350cf3e491cd15cc745b5da',
'duration': 1534,
'timestamp': 1418075340,
'upload_date': '20141208',
@ -35,7 +35,7 @@ class BetIE(InfoExtractor):
{
'url': 'http://www.bet.com/video/news/national/2014/justice-for-ferguson-a-community-reacts.html',
'info_dict': {
'id': 'bcd1b1df-673a-42cf-8d01-b282db608f2d',
'id': 'news/national/2014/justice-for-ferguson-a-community-reacts',
'display_id': 'justice-for-ferguson-a-community-reacts',
'ext': 'flv',
'title': 'Justice for Ferguson: A Community Reacts',
@ -57,10 +57,13 @@ class BetIE(InfoExtractor):
display_id = self._match_id(url)
webpage = self._download_webpage(url, display_id)
media_url = compat_urllib_parse.unquote(self._search_regex(
media_url = compat_urllib_parse_unquote(self._search_regex(
[r'mediaURL\s*:\s*"([^"]+)"', r"var\s+mrssMediaUrl\s*=\s*'([^']+)'"],
webpage, 'media URL'))
video_id = self._search_regex(
r'/video/(.*)/_jcr_content/', media_url, 'video id')
mrss = self._download_xml(media_url, display_id)
item = mrss.find('./channel/item')
@ -75,8 +78,6 @@ class BetIE(InfoExtractor):
description = xpath_text(
item, './description', 'description', fatal=False)
video_id = xpath_text(item, './guid', 'video id', fatal=False)
timestamp = parse_iso8601(xpath_text(
item, xpath_with_ns('./dc:date', NS_MAP),
'upload date', fatal=False))

View File

@ -2,7 +2,10 @@
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import int_or_none
from ..utils import (
int_or_none,
fix_xml_ampersands,
)
class BildIE(InfoExtractor):
@ -15,7 +18,7 @@ class BildIE(InfoExtractor):
'id': '38184146',
'ext': 'mp4',
'title': 'BILD hat sie getestet',
'thumbnail': 'http://bilder.bild.de/fotos/stand-das-koennen-die-neuen-ipads-38184138/Bild/1.bild.jpg',
'thumbnail': 're:^https?://.*\.jpg$',
'duration': 196,
'description': 'Mit dem iPad Air 2 und dem iPad Mini 3 hat Apple zwei neue Tablet-Modelle präsentiert. BILD-Reporter Sven Stein durfte die Geräte bereits testen. ',
}
@ -25,7 +28,7 @@ class BildIE(InfoExtractor):
video_id = self._match_id(url)
xml_url = url.split(".bild.html")[0] + ",view=xml.bild.xml"
doc = self._download_xml(xml_url, video_id)
doc = self._download_xml(xml_url, video_id, transform_source=fix_xml_ampersands)
duration = int_or_none(doc.attrib.get('duration'), scale=1000)

View File

@ -2,34 +2,54 @@
from __future__ import unicode_literals
import re
import itertools
import json
import xml.etree.ElementTree as ET
from .common import InfoExtractor
from ..utils import (
int_or_none,
unified_strdate,
ExtractorError,
)
class BiliBiliIE(InfoExtractor):
_VALID_URL = r'http://www\.bilibili\.(?:tv|com)/video/av(?P<id>[0-9]+)/'
_TEST = {
_TESTS = [{
'url': 'http://www.bilibili.tv/video/av1074402/',
'md5': '2c301e4dab317596e837c3e7633e7d86',
'info_dict': {
'id': '1074402',
'id': '1074402_part1',
'ext': 'flv',
'title': '【金坷垃】金泡沫',
'duration': 308,
'upload_date': '20140420',
'thumbnail': 're:^https?://.+\.jpg',
},
}
}, {
'url': 'http://www.bilibili.com/video/av1041170/',
'info_dict': {
'id': '1041170',
'title': '【BD1080P】刀语【诸神&异域】',
},
'playlist_count': 9,
}]
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
if '(此视频不存在或被删除)' in webpage:
raise ExtractorError(
'The video does not exist or was deleted', expected=True)
if '>你没有权限浏览! 由于版权相关问题 我们不对您所在的地区提供服务<' in webpage:
raise ExtractorError(
'The video is not available in your region due to copyright reasons',
expected=True)
video_code = self._search_regex(
r'(?s)<div itemprop="video".*?>(.*?)</div>', webpage, 'video code')
@ -54,19 +74,22 @@ class BiliBiliIE(InfoExtractor):
cid = self._search_regex(r'cid=(\d+)', webpage, 'cid')
lq_doc = self._download_xml(
entries = []
lq_page = self._download_webpage(
'http://interface.bilibili.com/v_cdn_play?appkey=1&cid=%s' % cid,
video_id,
note='Downloading LQ video info'
)
lq_durl = lq_doc.find('./durl')
formats = [{
'format_id': 'lq',
'quality': 1,
'url': lq_durl.find('./url').text,
'filesize': int_or_none(
lq_durl.find('./size'), get_attr='text'),
}]
try:
err_info = json.loads(lq_page)
raise ExtractorError(
'BiliBili said: ' + err_info['error_text'], expected=True)
except ValueError:
pass
lq_doc = ET.fromstring(lq_page)
lq_durls = lq_doc.findall('./durl')
hq_doc = self._download_xml(
'http://interface.bilibili.com/playurl?appkey=1&cid=%s' % cid,
@ -75,22 +98,45 @@ class BiliBiliIE(InfoExtractor):
fatal=False,
)
if hq_doc is not False:
hq_durl = hq_doc.find('./durl')
formats.append({
'format_id': 'hq',
'quality': 2,
'ext': 'flv',
'url': hq_durl.find('./url').text,
hq_durls = hq_doc.findall('./durl')
assert len(lq_durls) == len(hq_durls)
else:
hq_durls = itertools.repeat(None)
i = 1
for lq_durl, hq_durl in zip(lq_durls, hq_durls):
formats = [{
'format_id': 'lq',
'quality': 1,
'url': lq_durl.find('./url').text,
'filesize': int_or_none(
hq_durl.find('./size'), get_attr='text'),
lq_durl.find('./size'), get_attr='text'),
}]
if hq_durl is not None:
formats.append({
'format_id': 'hq',
'quality': 2,
'ext': 'flv',
'url': hq_durl.find('./url').text,
'filesize': int_or_none(
hq_durl.find('./size'), get_attr='text'),
})
self._sort_formats(formats)
entries.append({
'id': '%s_part%d' % (video_id, i),
'title': title,
'formats': formats,
'duration': duration,
'upload_date': upload_date,
'thumbnail': thumbnail,
})
self._sort_formats(formats)
i += 1
return {
'_type': 'multi_video',
'entries': entries,
'id': video_id,
'title': title,
'formats': formats,
'duration': duration,
'upload_date': upload_date,
'thumbnail': thumbnail,
'title': title
}

View File

@ -1,40 +1,35 @@
from __future__ import unicode_literals
import json
import re
from .common import InfoExtractor
from ..utils import remove_start
from ..utils import (
remove_start,
int_or_none,
)
class BlinkxIE(InfoExtractor):
_VALID_URL = r'^(?:https?://(?:www\.)blinkx\.com/#?ce/|blinkx:)(?P<id>[^?]+)'
_VALID_URL = r'(?:https?://(?:www\.)blinkx\.com/#?ce/|blinkx:)(?P<id>[^?]+)'
IE_NAME = 'blinkx'
_TEST = {
'url': 'http://www.blinkx.com/ce/8aQUy7GVFYgFzpKhT0oqsilwOGFRVXk3R1ZGWWdGenBLaFQwb3FzaWx3OGFRVXk3R1ZGWWdGenB',
'md5': '2e9a07364af40163a908edbf10bb2492',
'url': 'http://www.blinkx.com/ce/Da0Gw3xc5ucpNduzLuDDlv4WC9PuI4fDi1-t6Y3LyfdY2SZS5Urbvn-UPJvrvbo8LTKTc67Wu2rPKSQDJyZeeORCR8bYkhs8lI7eqddznH2ofh5WEEdjYXnoRtj7ByQwt7atMErmXIeYKPsSDuMAAqJDlQZ-3Ff4HJVeH_s3Gh8oQ',
'md5': '337cf7a344663ec79bf93a526a2e06c7',
'info_dict': {
'id': '8aQUy7GV',
'id': 'Da0Gw3xc',
'ext': 'mp4',
'title': 'Police Car Rolls Away',
'uploader': 'stupidvideos.com',
'upload_date': '20131215',
'timestamp': 1387068000,
'description': 'A police car gently rolls away from a fight. Maybe it felt weird being around a confrontation and just had to get out of there!',
'duration': 14.886,
'thumbnails': [{
'width': 100,
'height': 76,
'resolution': '100x76',
'url': 'http://cdn.blinkx.com/stream/b/41/StupidVideos/20131215/1873969261/1873969261_tn_0.jpg',
}],
'title': 'No Daily Show for John Oliver; HBO Show Renewed - IGN News',
'uploader': 'IGN News',
'upload_date': '20150217',
'timestamp': 1424215740,
'description': 'HBO has renewed Last Week Tonight With John Oliver for two more seasons.',
'duration': 47.743333,
},
}
def _real_extract(self, rl):
m = re.match(self._VALID_URL, rl)
video_id = m.group('id')
def _real_extract(self, url):
video_id = self._match_id(url)
display_id = video_id[:8]
api_url = ('https://apib4.blinkx.com/api.php?action=play_video&' +
@ -60,18 +55,20 @@ class BlinkxIE(InfoExtractor):
elif m['type'] in ('flv', 'mp4'):
vcodec = remove_start(m['vcodec'], 'ff')
acodec = remove_start(m['acodec'], 'ff')
tbr = (int(m['vbr']) + int(m['abr'])) // 1000
vbr = int_or_none(m.get('vbr') or m.get('vbitrate'), 1000)
abr = int_or_none(m.get('abr') or m.get('abitrate'), 1000)
tbr = vbr + abr if vbr and abr else None
format_id = '%s-%sk-%s' % (vcodec, tbr, m['w'])
formats.append({
'format_id': format_id,
'url': m['link'],
'vcodec': vcodec,
'acodec': acodec,
'abr': int(m['abr']) // 1000,
'vbr': int(m['vbr']) // 1000,
'abr': abr,
'vbr': vbr,
'tbr': tbr,
'width': int(m['w']),
'height': int(m['h']),
'width': int_or_none(m.get('w')),
'height': int_or_none(m.get('h')),
})
self._sort_formats(formats)

View File

@ -3,10 +3,8 @@ from __future__ import unicode_literals
import re
from .common import InfoExtractor
from .subtitles import SubtitlesInfoExtractor
from ..compat import (
compat_str,
compat_urllib_request,
compat_urlparse,
)
@ -15,19 +13,21 @@ from ..utils import (
int_or_none,
parse_iso8601,
unescapeHTML,
xpath_text,
xpath_with_ns,
)
class BlipTVIE(SubtitlesInfoExtractor):
class BlipTVIE(InfoExtractor):
_VALID_URL = r'https?://(?:\w+\.)?blip\.tv/(?:(?:.+-|rss/flash/)(?P<id>\d+)|((?:play/|api\.swf#)(?P<lookup_id>[\da-zA-Z+_]+)))'
_TESTS = [
{
'url': 'http://blip.tv/cbr/cbr-exclusive-gotham-city-imposters-bats-vs-jokerz-short-3-5796352',
'md5': 'c6934ad0b6acf2bd920720ec888eb812',
'md5': '80baf1ec5c3d2019037c1c707d676b9f',
'info_dict': {
'id': '5779306',
'ext': 'mov',
'ext': 'm4v',
'title': 'CBR EXCLUSIVE: "Gotham City Imposters" Bats VS Jokerz Short 3',
'description': 'md5:9bc31f227219cde65e47eeec8d2dc596',
'timestamp': 1323138843,
@ -101,8 +101,31 @@ class BlipTVIE(SubtitlesInfoExtractor):
'vcodec': 'none',
}
},
{
# missing duration
'url': 'http://blip.tv/rss/flash/6700880',
'info_dict': {
'id': '6684191',
'ext': 'm4v',
'title': 'Cowboy Bebop: Gateway Shuffle Review',
'description': 'md5:3acc480c0f9ae157f5fe88547ecaf3f8',
'timestamp': 1386639757,
'upload_date': '20131210',
'uploader': 'sfdebris',
'uploader_id': '706520',
}
}
]
@staticmethod
def _extract_url(webpage):
mobj = re.search(r'<meta\s[^>]*https?://api\.blip\.tv/\w+/redirect/\w+/(\d+)', webpage)
if mobj:
return 'http://blip.tv/a/a-' + mobj.group(1)
mobj = re.search(r'<(?:iframe|embed|object)\s[^>]*(https?://(?:\w+\.)?blip\.tv/(?:play/|api\.swf#)[a-zA-Z0-9_]+)', webpage)
if mobj:
return mobj.group(1)
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
lookup_id = mobj.group('lookup_id')
@ -120,35 +143,34 @@ class BlipTVIE(SubtitlesInfoExtractor):
rss = self._download_xml('http://blip.tv/rss/flash/%s' % video_id, video_id, 'Downloading video RSS')
def blip(s):
return '{http://blip.tv/dtd/blip/1.0}%s' % s
def media(s):
return '{http://search.yahoo.com/mrss/}%s' % s
def itunes(s):
return '{http://www.itunes.com/dtds/podcast-1.0.dtd}%s' % s
def _x(p):
return xpath_with_ns(p, {
'blip': 'http://blip.tv/dtd/blip/1.0',
'media': 'http://search.yahoo.com/mrss/',
'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd',
})
item = rss.find('channel/item')
video_id = item.find(blip('item_id')).text
title = item.find('./title').text
description = clean_html(compat_str(item.find(blip('puredescription')).text))
timestamp = parse_iso8601(item.find(blip('datestamp')).text)
uploader = item.find(blip('user')).text
uploader_id = item.find(blip('userid')).text
duration = int(item.find(blip('runtime')).text)
media_thumbnail = item.find(media('thumbnail'))
thumbnail = media_thumbnail.get('url') if media_thumbnail is not None else item.find(itunes('image')).text
categories = [category.text for category in item.findall('category')]
video_id = xpath_text(item, _x('blip:item_id'), 'video id') or lookup_id
title = xpath_text(item, 'title', 'title', fatal=True)
description = clean_html(xpath_text(item, _x('blip:puredescription'), 'description'))
timestamp = parse_iso8601(xpath_text(item, _x('blip:datestamp'), 'timestamp'))
uploader = xpath_text(item, _x('blip:user'), 'uploader')
uploader_id = xpath_text(item, _x('blip:userid'), 'uploader id')
duration = int_or_none(xpath_text(item, _x('blip:runtime'), 'duration'))
media_thumbnail = item.find(_x('media:thumbnail'))
thumbnail = (media_thumbnail.get('url') if media_thumbnail is not None
else xpath_text(item, 'image', 'thumbnail'))
categories = [category.text for category in item.findall('category') if category is not None]
formats = []
subtitles = {}
subtitles_urls = {}
media_group = item.find(media('group'))
for media_content in media_group.findall(media('content')):
media_group = item.find(_x('media:group'))
for media_content in media_group.findall(_x('media:content')):
url = media_content.get('url')
role = media_content.get(blip('role'))
role = media_content.get(_x('blip:role'))
msg = self._download_webpage(
url + '?showplayer=20140425131715&referrer=http://blip.tv&mask=7&skin=flashvars&view=url',
video_id, 'Resolving URL for %s' % role)
@ -161,25 +183,22 @@ class BlipTVIE(SubtitlesInfoExtractor):
}
lang = role.rpartition('-')[-1].strip().lower()
langcode = LANGS.get(lang, lang)
subtitles[langcode] = url
subtitles_urls[langcode] = url
elif media_type.startswith('video/'):
formats.append({
'url': real_url,
'format_id': role,
'format_note': media_type,
'vcodec': media_content.get(blip('vcodec')) or 'none',
'acodec': media_content.get(blip('acodec')),
'vcodec': media_content.get(_x('blip:vcodec')) or 'none',
'acodec': media_content.get(_x('blip:acodec')),
'filesize': media_content.get('filesize'),
'width': int_or_none(media_content.get('width')),
'height': int_or_none(media_content.get('height')),
})
self._check_formats(formats, video_id)
self._sort_formats(formats)
# subtitles
video_subtitles = self.extract_subtitles(video_id, subtitles)
if self._downloader.params.get('listsubtitles', False):
self._list_available_subtitles(video_id, subtitles)
return
subtitles = self.extract_subtitles(video_id, subtitles_urls)
return {
'id': video_id,
@ -192,15 +211,22 @@ class BlipTVIE(SubtitlesInfoExtractor):
'thumbnail': thumbnail,
'categories': categories,
'formats': formats,
'subtitles': video_subtitles,
'subtitles': subtitles,
}
def _download_subtitle_url(self, sub_lang, url):
# For some weird reason, blip.tv serves a video instead of subtitles
# when we request with a common UA
req = compat_urllib_request.Request(url)
req.add_header('User-Agent', 'youtube-dl')
return self._download_webpage(req, None, note=False)
def _get_subtitles(self, video_id, subtitles_urls):
subtitles = {}
for lang, url in subtitles_urls.items():
# For some weird reason, blip.tv serves a video instead of subtitles
# when we request with a common UA
req = compat_urllib_request.Request(url)
req.add_header('User-Agent', 'youtube-dl')
subtitles[lang] = [{
# The extension is 'srt' but it's actually an 'ass' file
'ext': 'ass',
'data': self._download_webpage(req, None, note=False),
}]
return subtitles
class BlipTVUserIE(InfoExtractor):

View File

@ -6,32 +6,39 @@ from .common import InfoExtractor
class BloombergIE(InfoExtractor):
_VALID_URL = r'https?://www\.bloomberg\.com/video/(?P<name>.+?)\.html'
_VALID_URL = r'https?://www\.bloomberg\.com/news/videos/[^/]+/(?P<id>[^/?#]+)'
_TEST = {
'url': 'http://www.bloomberg.com/video/shah-s-presentation-on-foreign-exchange-strategies-qurhIVlJSB6hzkVi229d8g.html',
'url': 'http://www.bloomberg.com/news/videos/b/aaeae121-5949-481e-a1ce-4562db6f5df2',
# The md5 checksum changes
'info_dict': {
'id': 'qurhIVlJSB6hzkVi229d8g',
'ext': 'flv',
'title': 'Shah\'s Presentation on Foreign-Exchange Strategies',
'description': 'md5:0681e0d30dcdfc6abf34594961d8ea88',
'description': 'md5:a8ba0302912d03d246979735c17d2761',
},
}
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
name = mobj.group('name')
name = self._match_id(url)
webpage = self._download_webpage(url, name)
f4m_url = self._search_regex(
r'<source src="(https?://[^"]+\.f4m.*?)"', webpage,
'f4m url')
video_id = self._search_regex(r'"bmmrId":"(.+?)"', webpage, 'id')
title = re.sub(': Video$', '', self._og_search_title(webpage))
embed_info = self._download_json(
'http://www.bloomberg.com/api/embed?id=%s' % video_id, video_id)
formats = []
for stream in embed_info['streams']:
if stream["muxing_format"] == "TS":
formats.extend(self._extract_m3u8_formats(stream['url'], video_id))
else:
formats.extend(self._extract_f4m_formats(stream['url'], video_id))
self._sort_formats(formats)
return {
'id': name.split('-')[-1],
'id': video_id,
'title': title,
'formats': self._extract_f4m_formats(f4m_url, name),
'formats': formats,
'description': self._og_search_description(webpage),
'thumbnail': self._og_search_thumbnail(webpage),
}

View File

@ -16,27 +16,38 @@ class BRIE(InfoExtractor):
_TESTS = [
{
'url': 'http://www.br.de/mediathek/video/sendungen/heimatsound/heimatsound-festival-2014-trailer-100.html',
'md5': '93556dd2bcb2948d9259f8670c516d59',
'url': 'http://www.br.de/mediathek/video/sendungen/abendschau/betriebliche-altersvorsorge-104.html',
'md5': '83a0477cf0b8451027eb566d88b51106',
'info_dict': {
'id': '25e279aa-1ffd-40fd-9955-5325bd48a53a',
'id': '48f656ef-287e-486f-be86-459122db22cc',
'ext': 'mp4',
'title': 'Wenn das Traditions-Theater wackelt',
'description': 'Heimatsound-Festival 2014: Wenn das Traditions-Theater wackelt',
'duration': 34,
'uploader': 'BR',
'upload_date': '20140802',
'title': 'Die böse Überraschung',
'description': 'Betriebliche Altersvorsorge: Die böse Überraschung',
'duration': 180,
'uploader': 'Reinhard Weber',
'upload_date': '20150422',
}
},
{
'url': 'http://www.br.de/nachrichten/schaeuble-haushaltsentwurf-bundestag-100.html',
'md5': '3db0df1a9a9cd9fa0c70e6ea8aa8e820',
'url': 'http://www.br.de/nachrichten/oberbayern/inhalt/muenchner-polizeipraesident-schreiber-gestorben-100.html',
'md5': 'a44396d73ab6a68a69a568fae10705bb',
'info_dict': {
'id': 'c6aae3de-2cf9-43f2-957f-f17fef9afaab',
'id': 'a4b83e34-123d-4b81-9f4e-c0d3121a4e05',
'ext': 'mp4',
'title': 'Manfred Schreiber ist tot',
'description': 'Abendschau kompakt: Manfred Schreiber ist tot',
'duration': 26,
}
},
{
'url': 'http://www.br.de/radio/br-klassik/sendungen/allegro/premiere-urauffuehrung-the-land-2015-dance-festival-muenchen-100.html',
'md5': '8b5b27c0b090f3b35eac4ab3f7a73d3d',
'info_dict': {
'id': '74c603c9-26d3-48bb-b85b-079aeed66e0b',
'ext': 'aac',
'title': '"Keine neuen Schulden im nächsten Jahr"',
'description': 'Haushaltsentwurf: "Keine neuen Schulden im nächsten Jahr"',
'duration': 64,
'title': 'Kurzweilig und sehr bewegend',
'description': '"The Land" von Peeping Tom: Kurzweilig und sehr bewegend',
'duration': 296,
}
},
{

View File

@ -41,7 +41,7 @@ class BreakIE(InfoExtractor):
'tbr': media['bitRate'],
'width': media['width'],
'height': media['height'],
} for media in info['media']]
} for media in info['media'] if media.get('mediaPurpose') == 'play']
if not formats:
formats.append({

View File

@ -13,6 +13,7 @@ from ..compat import (
compat_urllib_parse_urlparse,
compat_urllib_request,
compat_urlparse,
compat_xml_parse_error,
)
from ..utils import (
determine_ext,
@ -95,6 +96,7 @@ class BrightcoveIE(InfoExtractor):
'url': 'http://c.brightcove.com/services/viewer/htmlFederated?playerID=3550052898001&playerKey=AQ%7E%7E%2CAAABmA9XpXk%7E%2C-Kp7jNgisre1fG5OdqpAFUTcs0lP_ZoL',
'info_dict': {
'title': 'Sealife',
'id': '3550319591001',
},
'playlist_mincount': 7,
},
@ -108,7 +110,7 @@ class BrightcoveIE(InfoExtractor):
"""
# Fix up some stupid HTML, see https://github.com/rg3/youtube-dl/issues/1553
object_str = re.sub(r'(<param name="[^"]+" value="[^"]+")>',
object_str = re.sub(r'(<param(?:\s+[a-zA-Z0-9_]+="[^"]*")*)>',
lambda m: m.group(1) + '/>', object_str)
# Fix up some stupid XML, see https://github.com/rg3/youtube-dl/issues/1608
object_str = object_str.replace('<--', '<!--')
@ -116,7 +118,10 @@ class BrightcoveIE(InfoExtractor):
object_str = re.sub(r'(<object[^>]*)(xmlns=".*?")', r'\1', object_str)
object_str = fix_xml_ampersands(object_str)
object_doc = xml.etree.ElementTree.fromstring(object_str.encode('utf-8'))
try:
object_doc = xml.etree.ElementTree.fromstring(object_str.encode('utf-8'))
except compat_xml_parse_error:
return
fv_el = find_xpath_attr(object_doc, './param', 'name', 'flashVars')
if fv_el is not None:
@ -152,6 +157,28 @@ class BrightcoveIE(InfoExtractor):
linkBase = find_param('linkBaseURL')
if linkBase is not None:
params['linkBaseURL'] = linkBase
return cls._make_brightcove_url(params)
@classmethod
def _build_brighcove_url_from_js(cls, object_js):
# The layout of JS is as follows:
# customBC.createVideo = function (width, height, playerID, playerKey, videoPlayer, VideoRandomID) {
# // build Brightcove <object /> XML
# }
m = re.search(
r'''(?x)customBC.\createVideo\(
.*? # skipping width and height
["\'](?P<playerID>\d+)["\']\s*,\s* # playerID
["\'](?P<playerKey>AQ[^"\']{48})[^"\']*["\']\s*,\s* # playerKey begins with AQ and is 50 characters
# in length, however it's appended to itself
# in places, so truncate
["\'](?P<videoID>\d+)["\'] # @videoPlayer
''', object_js)
if m:
return cls._make_brightcove_url(m.groupdict())
@classmethod
def _make_brightcove_url(cls, params):
data = compat_urllib_parse.urlencode(params)
return cls._FEDERATED_URL_TEMPLATE % data
@ -168,7 +195,7 @@ class BrightcoveIE(InfoExtractor):
"""Return a list of all Brightcove URLs from the webpage """
url_m = re.search(
r'<meta\s+property="og:video"\s+content="(https?://(?:secure|c)\.brightcove.com/[^"]+)"',
r'<meta\s+property=[\'"]og:video[\'"]\s+content=[\'"](https?://(?:secure|c)\.brightcove.com/[^\'"]+)[\'"]',
webpage)
if url_m:
url = unescapeHTML(url_m.group(1))
@ -182,9 +209,14 @@ class BrightcoveIE(InfoExtractor):
(?:
[^>]+?class=[\'"][^>]*?BrightcoveExperience.*?[\'"] |
[^>]*?>\s*<param\s+name="movie"\s+value="https?://[^/]*brightcove\.com/
).+?</object>''',
).+?>\s*</object>''',
webpage)
return [cls._build_brighcove_url(m) for m in matches]
if matches:
return list(filter(None, [cls._build_brighcove_url(m) for m in matches]))
return list(filter(None, [
cls._build_brighcove_url_from_js(custom_bc)
for custom_bc in re.findall(r'(customBC\.createVideo\(.+?\);)', webpage)]))
def _real_extract(self, url):
url, smuggled_data = unsmuggle_url(url, {})
@ -247,7 +279,7 @@ class BrightcoveIE(InfoExtractor):
playlist_info = json_data['videoList']
videos = [self._extract_video_info(video_info) for video_info in playlist_info['mediaCollectionDTO']['videoDTOs']]
return self.playlist_result(videos, playlist_id=playlist_info['id'],
return self.playlist_result(videos, playlist_id='%s' % playlist_info['id'],
playlist_title=playlist_info['mediaCollectionDTO']['displayName'])
def _extract_video_info(self, video_info):

View File

@ -33,6 +33,7 @@ class BuzzFeedIE(InfoExtractor):
'skip_download': True, # Got enough YouTube download tests
},
'info_dict': {
'id': 'look-at-this-cute-dog-omg',
'description': 're:Munchkin the Teddy Bear is back ?!',
'title': 'You Need To Stop What You\'re Doing And Watching This Dog Walk On A Treadmill',
},
@ -42,8 +43,8 @@ class BuzzFeedIE(InfoExtractor):
'ext': 'mp4',
'upload_date': '20141124',
'uploader_id': 'CindysMunchkin',
'description': 're:© 2014 Munchkin the Shih Tzu',
'uploader': 'Munchkin the Shih Tzu',
'description': 're:© 2014 Munchkin the',
'uploader': 're:^Munchkin the',
'title': 're:Munchkin the Teddy Bear gets her exercise',
},
}]

View File

@ -16,7 +16,7 @@ class BYUtvIE(InfoExtractor):
'ext': 'mp4',
'description': 'md5:5438d33774b6bdc662f9485a340401cc',
'title': 'Season 5 Episode 5',
'thumbnail': 're:^https?://.*promo.*'
'thumbnail': 're:^https?://.*\.jpg$'
},
'params': {
'skip_download': True,

View File

@ -0,0 +1,153 @@
# coding: utf-8
from __future__ import unicode_literals
import datetime
import re
from .common import InfoExtractor
from ..compat import (
compat_urllib_parse,
compat_urlparse,
)
from ..utils import (
parse_iso8601,
str_to_int,
)
class CamdemyIE(InfoExtractor):
_VALID_URL = r'http://(?:www\.)?camdemy\.com/media/(?P<id>\d+)'
_TESTS = [{
# single file
'url': 'http://www.camdemy.com/media/5181/',
'md5': '5a5562b6a98b37873119102e052e311b',
'info_dict': {
'id': '5181',
'ext': 'mp4',
'title': 'Ch1-1 Introduction, Signals (02-23-2012)',
'thumbnail': 're:^https?://.*\.jpg$',
'description': '',
'creator': 'ss11spring',
'upload_date': '20130114',
'timestamp': 1358154556,
'view_count': int,
}
}, {
# With non-empty description
'url': 'http://www.camdemy.com/media/13885',
'md5': '4576a3bb2581f86c61044822adbd1249',
'info_dict': {
'id': '13885',
'ext': 'mp4',
'title': 'EverCam + Camdemy QuickStart',
'thumbnail': 're:^https?://.*\.jpg$',
'description': 'md5:050b62f71ed62928f8a35f1a41e186c9',
'creator': 'evercam',
'upload_date': '20140620',
'timestamp': 1403271569,
}
}, {
# External source
'url': 'http://www.camdemy.com/media/14842',
'md5': '50e1c3c3aa233d3d7b7daa2fa10b1cf7',
'info_dict': {
'id': '2vsYQzNIsJo',
'ext': 'mp4',
'upload_date': '20130211',
'uploader': 'Hun Kim',
'description': 'Excel 2013 Tutorial for Beginners - How to add Password Protection',
'uploader_id': 'hunkimtutorials',
'title': 'Excel 2013 Tutorial - How to add Password Protection',
}
}]
def _real_extract(self, url):
video_id = self._match_id(url)
page = self._download_webpage(url, video_id)
src_from = self._html_search_regex(
r"<div class='srcFrom'>Source: <a title='([^']+)'", page,
'external source', default=None)
if src_from:
return self.url_result(src_from)
oembed_obj = self._download_json(
'http://www.camdemy.com/oembed/?format=json&url=' + url, video_id)
thumb_url = oembed_obj['thumbnail_url']
video_folder = compat_urlparse.urljoin(thumb_url, 'video/')
file_list_doc = self._download_xml(
compat_urlparse.urljoin(video_folder, 'fileList.xml'),
video_id, 'Filelist XML')
file_name = file_list_doc.find('./video/item/fileName').text
video_url = compat_urlparse.urljoin(video_folder, file_name)
timestamp = parse_iso8601(self._html_search_regex(
r"<div class='title'>Posted\s*:</div>\s*<div class='value'>([^<>]+)<",
page, 'creation time', fatal=False),
delimiter=' ', timezone=datetime.timedelta(hours=8))
view_count = str_to_int(self._html_search_regex(
r"<div class='title'>Views\s*:</div>\s*<div class='value'>([^<>]+)<",
page, 'view count', fatal=False))
return {
'id': video_id,
'url': video_url,
'title': oembed_obj['title'],
'thumbnail': thumb_url,
'description': self._html_search_meta('description', page),
'creator': oembed_obj['author_name'],
'duration': oembed_obj['duration'],
'timestamp': timestamp,
'view_count': view_count,
}
class CamdemyFolderIE(InfoExtractor):
_VALID_URL = r'http://www.camdemy.com/folder/(?P<id>\d+)'
_TESTS = [{
# links with trailing slash
'url': 'http://www.camdemy.com/folder/450',
'info_dict': {
'id': '450',
'title': '信號與系統 2012 & 2011 (Signals and Systems)',
},
'playlist_mincount': 145
}, {
# links without trailing slash
# and multi-page
'url': 'http://www.camdemy.com/folder/853',
'info_dict': {
'id': '853',
'title': '科學計算 - 使用 Matlab'
},
'playlist_mincount': 20
}, {
# with displayMode parameter. For testing the codes to add parameters
'url': 'http://www.camdemy.com/folder/853/?displayMode=defaultOrderByOrg',
'info_dict': {
'id': '853',
'title': '科學計算 - 使用 Matlab'
},
'playlist_mincount': 20
}]
def _real_extract(self, url):
folder_id = self._match_id(url)
# Add displayMode=list so that all links are displayed in a single page
parsed_url = list(compat_urlparse.urlparse(url))
query = dict(compat_urlparse.parse_qsl(parsed_url[4]))
query.update({'displayMode': 'list'})
parsed_url[4] = compat_urllib_parse.urlencode(query)
final_url = compat_urlparse.urlunparse(parsed_url)
page = self._download_webpage(final_url, folder_id)
matches = re.findall(r"href='(/media/\d+/?)'", page)
entries = [self.url_result('http://www.camdemy.com' + media_path)
for media_path in matches]
folder_title = self._html_search_meta('keywords', page)
return self.playlist_result(entries, folder_id, folder_title)

View File

@ -15,23 +15,24 @@ from ..utils import (
class CanalplusIE(InfoExtractor):
IE_DESC = 'canalplus.fr, piwiplus.fr and d8.tv'
_VALID_URL = r'https?://(?:www\.(?P<site>canalplus\.fr|piwiplus\.fr|d8\.tv)/.*?/(?P<path>.*)|player\.canalplus\.fr/#/(?P<id>[0-9]+))'
_VALID_URL = r'https?://(?:www\.(?P<site>canalplus\.fr|piwiplus\.fr|d8\.tv|itele\.fr)/.*?/(?P<path>.*)|player\.canalplus\.fr/#/(?P<id>[0-9]+))'
_VIDEO_INFO_TEMPLATE = 'http://service.canal-plus.com/video/rest/getVideosLiees/%s/%s'
_SITE_ID_MAP = {
'canalplus.fr': 'cplus',
'piwiplus.fr': 'teletoon',
'd8.tv': 'd8',
'itele.fr': 'itele',
}
_TESTS = [{
'url': 'http://www.canalplus.fr/c-infos-documentaires/pid1830-c-zapping.html?vid=922470',
'md5': '3db39fb48b9685438ecf33a1078023e4',
'url': 'http://www.canalplus.fr/c-emissions/pid1830-c-zapping.html?vid=1263092',
'md5': 'b3481d7ca972f61e37420798d0a9d934',
'info_dict': {
'id': '922470',
'id': '1263092',
'ext': 'flv',
'title': 'Zapping - 26/08/13',
'description': 'Le meilleur de toutes les chaînes, tous les jours.\nEmission du 26 août 2013',
'upload_date': '20130826',
'title': 'Le Zapping - 13/05/15',
'description': 'md5:09738c0d06be4b5d06a0940edb0da73f',
'upload_date': '20150513',
},
}, {
'url': 'http://www.piwiplus.fr/videos-piwi/pid1405-le-labyrinthe-boing-super-ranger.html?vid=1108190',
@ -53,6 +54,16 @@ class CanalplusIE(InfoExtractor):
'upload_date': '20131108',
},
'skip': 'videos get deleted after a while',
}, {
'url': 'http://www.itele.fr/france/video/aubervilliers-un-lycee-en-colere-111559',
'md5': 'f3a46edcdf28006598ffaf5b30e6a2d4',
'info_dict': {
'id': '1213714',
'ext': 'flv',
'title': 'Aubervilliers : un lycée en colère - Le 11/02/2015 à 06h45',
'description': 'md5:8216206ec53426ea6321321f3b3c16db',
'upload_date': '20150211',
},
}]
def _real_extract(self, url):
@ -95,15 +106,11 @@ class CanalplusIE(InfoExtractor):
continue
format_id = fmt.tag
if format_id == 'HLS':
hls_formats = self._extract_m3u8_formats(format_url, video_id, 'flv')
for fmt in hls_formats:
fmt['preference'] = preference(format_id)
formats.extend(hls_formats)
formats.extend(self._extract_m3u8_formats(
format_url, video_id, 'mp4', preference=preference(format_id)))
elif format_id == 'HDS':
hds_formats = self._extract_f4m_formats(format_url + '?hdcore=2.11.3', video_id)
for fmt in hds_formats:
fmt['preference'] = preference(format_id)
formats.extend(hds_formats)
formats.extend(self._extract_f4m_formats(
format_url + '?hdcore=2.11.3', video_id, preference=preference(format_id)))
else:
formats.append({
'url': format_url,

View File

@ -1,17 +1,16 @@
from __future__ import unicode_literals
import re
from .common import InfoExtractor
class CBSIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?cbs\.com/shows/[^/]+/(?:video|artist)/(?P<id>[^/]+)/.*'
_VALID_URL = r'https?://(?:www\.)?(?:cbs\.com/shows/[^/]+/(?:video|artist)|colbertlateshow\.com/(?:video|podcasts))/[^/]+/(?P<id>[^/]+)'
_TESTS = [{
'url': 'http://www.cbs.com/shows/garth-brooks/video/_u7W953k6la293J7EPTd9oHkSPs6Xn6_/connect-chat-feat-garth-brooks/',
'info_dict': {
'id': '4JUVEwq3wUT7',
'display_id': 'connect-chat-feat-garth-brooks',
'ext': 'flv',
'title': 'Connect Chat feat. Garth Brooks',
'description': 'Connect with country music singer Garth Brooks, as he chats with fans on Wednesday November 27, 2013. Be sure to tune in to Garth Brooks: Live from Las Vegas, Friday November 29, at 9/8c on CBS!',
@ -26,6 +25,7 @@ class CBSIE(InfoExtractor):
'url': 'http://www.cbs.com/shows/liveonletterman/artist/221752/st-vincent/',
'info_dict': {
'id': 'WWF_5KqY3PK1',
'display_id': 'st-vincent',
'ext': 'flv',
'title': 'Live on Letterman - St. Vincent',
'description': 'Live On Letterman: St. Vincent in concert from New York\'s Ed Sullivan Theater on Tuesday, July 16, 2014.',
@ -36,13 +36,23 @@ class CBSIE(InfoExtractor):
'skip_download': True,
},
'_skip': 'Blocked outside the US',
}, {
'url': 'http://colbertlateshow.com/video/8GmB0oY0McANFvp2aEffk9jZZZ2YyXxy/the-colbeard/',
'only_matching': True,
}, {
'url': 'http://www.colbertlateshow.com/podcasts/dYSwjqPs_X1tvbV_P2FcPWRa_qT6akTC/in-the-bad-room-with-stephen/',
'only_matching': True,
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id')
webpage = self._download_webpage(url, video_id)
display_id = self._match_id(url)
webpage = self._download_webpage(url, display_id)
real_id = self._search_regex(
r"video\.settings\.pid\s*=\s*'([^']+)';",
[r"video\.settings\.pid\s*=\s*'([^']+)';", r"cbsplayer\.pid\s*=\s*'([^']+)';"],
webpage, 'real video ID')
return self.url_result('theplatform:%s' % real_id)
return {
'_type': 'url_transparent',
'ie_key': 'ThePlatform',
'url': 'theplatform:%s' % real_id,
'display_id': display_id,
}

View File

@ -32,7 +32,7 @@ class CBSNewsIE(InfoExtractor):
'id': 'fort-hood-shooting-army-downplays-mental-illness-as-cause-of-attack',
'ext': 'flv',
'title': 'Fort Hood shooting: Army downplays mental illness as cause of attack',
'thumbnail': 'http://cbsnews2.cbsistatic.com/hub/i/r/2014/04/04/0c9fbc66-576b-41ca-8069-02d122060dd2/thumbnail/140x90/6dad7a502f88875ceac38202984b6d58/en-0404-werner-replace-640x360.jpg',
'thumbnail': 're:^https?://.*\.jpg$',
'duration': 205,
},
'params': {

View File

@ -0,0 +1,30 @@
from __future__ import unicode_literals
import re
from .common import InfoExtractor
class CBSSportsIE(InfoExtractor):
_VALID_URL = r'http://www\.cbssports\.com/video/player/(?P<section>[^/]+)/(?P<id>[^/]+)'
_TEST = {
'url': 'http://www.cbssports.com/video/player/tennis/318462531970/0/us-open-flashbacks-1990s',
'info_dict': {
'id': '_d5_GbO8p1sT',
'ext': 'flv',
'title': 'US Open flashbacks: 1990s',
'description': 'Bill Macatee relives the best moments in US Open history from the 1990s.',
},
}
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
section = mobj.group('section')
video_id = mobj.group('id')
all_videos = self._download_json(
'http://www.cbssports.com/data/video/player/getVideos/%s?as=json' % section,
video_id)
# The json file contains the info of all the videos in the section
video_info = next(v for v in all_videos if v['pcid'] == video_id)
return self.url_result('theplatform:%s' % video_info['pid'], 'ThePlatform')

View File

@ -0,0 +1,99 @@
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..utils import (
int_or_none,
qualities,
unified_strdate,
)
class CCCIE(InfoExtractor):
IE_NAME = 'media.ccc.de'
_VALID_URL = r'https?://(?:www\.)?media\.ccc\.de/[^?#]+/[^?#/]*?_(?P<id>[0-9]{8,})._[^?#/]*\.html'
_TEST = {
'url': 'http://media.ccc.de/browse/congress/2013/30C3_-_5443_-_en_-_saal_g_-_201312281830_-_introduction_to_processor_design_-_byterazor.html#video',
'md5': '3a1eda8f3a29515d27f5adb967d7e740',
'info_dict': {
'id': '20131228183',
'ext': 'mp4',
'title': 'Introduction to Processor Design',
'description': 'md5:5ddbf8c734800267f2cee4eab187bc1b',
'thumbnail': 're:^https?://.*\.jpg$',
'view_count': int,
'upload_date': '20131229',
}
}
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
if self._downloader.params.get('prefer_free_formats'):
preference = qualities(['mp3', 'opus', 'mp4-lq', 'webm-lq', 'h264-sd', 'mp4-sd', 'webm-sd', 'mp4', 'webm', 'mp4-hd', 'h264-hd', 'webm-hd'])
else:
preference = qualities(['opus', 'mp3', 'webm-lq', 'mp4-lq', 'webm-sd', 'h264-sd', 'mp4-sd', 'webm', 'mp4', 'webm-hd', 'mp4-hd', 'h264-hd'])
title = self._html_search_regex(
r'(?s)<h1>(.*?)</h1>', webpage, 'title')
description = self._html_search_regex(
r"(?s)<p class='description'>(.*?)</p>",
webpage, 'description', fatal=False)
upload_date = unified_strdate(self._html_search_regex(
r"(?s)<span class='[^']*fa-calendar-o'></span>(.*?)</li>",
webpage, 'upload date', fatal=False))
view_count = int_or_none(self._html_search_regex(
r"(?s)<span class='[^']*fa-eye'></span>(.*?)</li>",
webpage, 'view count', fatal=False))
matches = re.finditer(r'''(?xs)
<(?:span|div)\s+class='label\s+filetype'>(?P<format>.*?)</(?:span|div)>\s*
<a\s+download\s+href='(?P<http_url>[^']+)'>\s*
(?:
.*?
<a\s+href='(?P<torrent_url>[^']+\.torrent)'
)?''', webpage)
formats = []
for m in matches:
format = m.group('format')
format_id = self._search_regex(
r'.*/([a-z0-9_-]+)/[^/]*$',
m.group('http_url'), 'format id', default=None)
vcodec = 'h264' if 'h264' in format_id else (
'none' if format_id in ('mp3', 'opus') else None
)
formats.append({
'format_id': format_id,
'format': format,
'url': m.group('http_url'),
'vcodec': vcodec,
'preference': preference(format_id),
})
if m.group('torrent_url'):
formats.append({
'format_id': 'torrent-%s' % (format if format_id is None else format_id),
'format': '%s (torrent)' % format,
'proto': 'torrent',
'format_note': '(unsupported; will just download the .torrent file)',
'vcodec': vcodec,
'preference': -100 + preference(format_id),
'url': m.group('torrent_url'),
})
self._sort_formats(formats)
thumbnail = self._html_search_regex(
r"<video.*?poster='([^']+)'", webpage, 'thumbnail', fatal=False)
return {
'id': video_id,
'title': title,
'description': description,
'thumbnail': thumbnail,
'view_count': view_count,
'upload_date': upload_date,
'formats': formats,
}

View File

@ -3,10 +3,11 @@ from __future__ import unicode_literals
import re
from .subtitles import SubtitlesInfoExtractor
from .common import InfoExtractor
from ..compat import (
compat_urllib_request,
compat_urllib_parse,
compat_urllib_parse_unquote,
compat_urllib_parse_urlparse,
)
from ..utils import (
@ -15,7 +16,7 @@ from ..utils import (
)
class CeskaTelevizeIE(SubtitlesInfoExtractor):
class CeskaTelevizeIE(InfoExtractor):
_VALID_URL = r'https?://www\.ceskatelevize\.cz/(porady|ivysilani)/(.+/)?(?P<id>[^?#]+)'
_TESTS = [
@ -88,7 +89,7 @@ class CeskaTelevizeIE(SubtitlesInfoExtractor):
if playlist_url == 'error_region':
raise ExtractorError(NOT_AVAILABLE_STRING, expected=True)
req = compat_urllib_request.Request(compat_urllib_parse.unquote(playlist_url))
req = compat_urllib_request.Request(compat_urllib_parse_unquote(playlist_url))
req.add_header('Referer', url)
playlist = self._download_json(req, video_id)
@ -107,13 +108,7 @@ class CeskaTelevizeIE(SubtitlesInfoExtractor):
subtitles = {}
subs = item.get('subtitles')
if subs:
subtitles['cs'] = subs[0]['url']
if self._downloader.params.get('listsubtitles', False):
self._list_available_subtitles(video_id, subtitles)
return
subtitles = self._fix_subtitles(self.extract_subtitles(video_id, subtitles))
subtitles = self.extract_subtitles(episode_id, subs)
return {
'id': episode_id,
@ -125,11 +120,20 @@ class CeskaTelevizeIE(SubtitlesInfoExtractor):
'subtitles': subtitles,
}
def _get_subtitles(self, episode_id, subs):
original_subtitles = self._download_webpage(
subs[0]['url'], episode_id, 'Downloading subtitles')
srt_subs = self._fix_subtitles(original_subtitles)
return {
'cs': [{
'ext': 'srt',
'data': srt_subs,
}]
}
@staticmethod
def _fix_subtitles(subtitles):
""" Convert millisecond-based subtitles to SRT """
if subtitles is None:
return subtitles # subtitles not requested
def _msectotimecode(msec):
""" Helper utility to convert milliseconds to timecode """
@ -149,7 +153,4 @@ class CeskaTelevizeIE(SubtitlesInfoExtractor):
else:
yield line
fixed_subtitles = {}
for k, v in subtitles.items():
fixed_subtitles[k] = "\r\n".join(_fix_subtitle(v))
return fixed_subtitles
return "\r\n".join(_fix_subtitle(subtitles))

View File

@ -57,7 +57,7 @@ class ChilloutzoneIE(InfoExtractor):
base64_video_info = self._html_search_regex(
r'var cozVidData = "(.+?)";', webpage, 'video data')
decoded_video_info = base64.b64decode(base64_video_info).decode("utf-8")
decoded_video_info = base64.b64decode(base64_video_info.encode('utf-8')).decode('utf-8')
video_info_dict = json.loads(decoded_video_info)
# get video information from dict

View File

@ -0,0 +1,84 @@
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import (
parse_duration,
int_or_none,
)
class ChirbitIE(InfoExtractor):
IE_NAME = 'chirbit'
_VALID_URL = r'https?://(?:www\.)?chirb\.it/(?:(?:wp|pl)/|fb_chirbit_player\.swf\?key=)?(?P<id>[\da-zA-Z]+)'
_TESTS = [{
'url': 'http://chirb.it/PrIPv5',
'md5': '9847b0dad6ac3e074568bf2cfb197de8',
'info_dict': {
'id': 'PrIPv5',
'ext': 'mp3',
'title': 'Фасадстрой',
'duration': 52,
'view_count': int,
'comment_count': int,
}
}, {
'url': 'https://chirb.it/fb_chirbit_player.swf?key=PrIPv5',
'only_matching': True,
}]
def _real_extract(self, url):
audio_id = self._match_id(url)
webpage = self._download_webpage(
'http://chirb.it/%s' % audio_id, audio_id)
audio_url = self._search_regex(
r'"setFile"\s*,\s*"([^"]+)"', webpage, 'audio url')
title = self._search_regex(
r'itemprop="name">([^<]+)', webpage, 'title')
duration = parse_duration(self._html_search_meta(
'duration', webpage, 'duration', fatal=False))
view_count = int_or_none(self._search_regex(
r'itemprop="playCount"\s*>(\d+)', webpage,
'listen count', fatal=False))
comment_count = int_or_none(self._search_regex(
r'>(\d+) Comments?:', webpage,
'comment count', fatal=False))
return {
'id': audio_id,
'url': audio_url,
'title': title,
'duration': duration,
'view_count': view_count,
'comment_count': comment_count,
}
class ChirbitProfileIE(InfoExtractor):
IE_NAME = 'chirbit:profile'
_VALID_URL = r'https?://(?:www\.)?chirbit.com/(?:rss/)?(?P<id>[^/]+)'
_TEST = {
'url': 'http://chirbit.com/ScarletBeauty',
'info_dict': {
'id': 'ScarletBeauty',
'title': 'Chirbits by ScarletBeauty',
},
'playlist_mincount': 3,
}
def _real_extract(self, url):
profile_id = self._match_id(url)
rss = self._download_xml(
'http://chirbit.com/rss/%s' % profile_id, profile_id)
entries = [
self.url_result(audio_url.text, 'Chirbit')
for audio_url in rss.findall('./channel/item/link')]
title = rss.find('./channel/title').text
return self.playlist_result(entries, profile_id, title)

View File

@ -0,0 +1,110 @@
# encoding: utf-8
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..utils import ExtractorError
from .bliptv import BlipTVIE
class CinemassacreIE(InfoExtractor):
_VALID_URL = 'https?://(?:www\.)?cinemassacre\.com/(?P<date_y>[0-9]{4})/(?P<date_m>[0-9]{2})/(?P<date_d>[0-9]{2})/(?P<display_id>[^?#/]+)'
_TESTS = [
{
'url': 'http://cinemassacre.com/2012/11/10/avgn-the-movie-trailer/',
'md5': 'fde81fbafaee331785f58cd6c0d46190',
'info_dict': {
'id': 'Cinemassacre-19911',
'ext': 'mp4',
'upload_date': '20121110',
'title': '“Angry Video Game Nerd: The Movie” Trailer',
'description': 'md5:fb87405fcb42a331742a0dce2708560b',
},
},
{
'url': 'http://cinemassacre.com/2013/10/02/the-mummys-hand-1940',
'md5': 'd72f10cd39eac4215048f62ab477a511',
'info_dict': {
'id': 'Cinemassacre-521be8ef82b16',
'ext': 'mp4',
'upload_date': '20131002',
'title': 'The Mummys Hand (1940)',
},
},
{
# blip.tv embedded video
'url': 'http://cinemassacre.com/2006/12/07/chronologically-confused-about-bad-movie-and-video-game-sequel-titles/',
'md5': 'ca9b3c8dd5a66f9375daeb5135f5a3de',
'info_dict': {
'id': '4065369',
'ext': 'flv',
'title': 'AVGN: Chronologically Confused about Bad Movie and Video Game Sequel Titles',
'upload_date': '20061207',
'uploader': 'cinemassacre',
'uploader_id': '250778',
'timestamp': 1283233867,
'description': 'md5:0a108c78d130676b207d0f6d029ecffd',
}
},
{
# Youtube embedded video
'url': 'http://cinemassacre.com/2006/09/01/mckids/',
'md5': '6eb30961fa795fedc750eac4881ad2e1',
'info_dict': {
'id': 'FnxsNhuikpo',
'ext': 'mp4',
'upload_date': '20060901',
'uploader': 'Cinemassacre Extras',
'description': 'md5:de9b751efa9e45fbaafd9c8a1123ed53',
'uploader_id': 'Cinemassacre',
'title': 'AVGN: McKids',
}
},
{
'url': 'http://cinemassacre.com/2015/05/25/mario-kart-64-nintendo-64-james-mike-mondays/',
'md5': '1376908e49572389e7b06251a53cdd08',
'info_dict': {
'id': 'Cinemassacre-555779690c440',
'ext': 'mp4',
'description': 'Lets Play Mario Kart 64 !! Mario Kart 64 is a classic go-kart racing game released for the Nintendo 64 (N64). Today James & Mike do 4 player Battle Mode with Kyle and Bootsy!',
'title': 'Mario Kart 64 (Nintendo 64) James & Mike Mondays',
'upload_date': '20150525',
}
}
]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
display_id = mobj.group('display_id')
video_date = mobj.group('date_y') + mobj.group('date_m') + mobj.group('date_d')
webpage = self._download_webpage(url, display_id)
playerdata_url = self._search_regex(
[
r'src="(http://(?:player2\.screenwavemedia\.com|player\.screenwavemedia\.com/play)/[a-zA-Z]+\.php\?[^"]*\bid=.+?)"',
r'<iframe[^>]+src="((?:https?:)?//(?:[^.]+\.)?youtube\.com/.+?)"',
],
webpage, 'player data URL', default=None)
if not playerdata_url:
playerdata_url = BlipTVIE._extract_url(webpage)
if not playerdata_url:
raise ExtractorError('Unable to find player data')
video_title = self._html_search_regex(
r'<title>(?P<title>.+?)\|', webpage, 'title')
video_description = self._html_search_regex(
r'<div class="entry-content">(?P<description>.+?)</div>',
webpage, 'description', flags=re.DOTALL, fatal=False)
video_thumbnail = self._og_search_thumbnail(webpage)
return {
'_type': 'url_transparent',
'display_id': display_id,
'title': video_title,
'description': video_description,
'upload_date': video_date,
'thumbnail': video_thumbnail,
'url': playerdata_url,
}

View File

@ -1,7 +1,5 @@
from __future__ import unicode_literals
import re
from .common import InfoExtractor
from ..utils import (
find_xpath_attr,
@ -10,9 +8,9 @@ from ..utils import (
class ClipsyndicateIE(InfoExtractor):
_VALID_URL = r'http://www\.clipsyndicate\.com/video/play(list/\d+)?/(?P<id>\d+)'
_VALID_URL = r'http://(?:chic|www)\.clipsyndicate\.com/video/play(list/\d+)?/(?P<id>\d+)'
_TEST = {
_TESTS = [{
'url': 'http://www.clipsyndicate.com/video/play/4629301/brick_briscoe',
'md5': '4d7d549451bad625e0ff3d7bd56d776c',
'info_dict': {
@ -22,11 +20,13 @@ class ClipsyndicateIE(InfoExtractor):
'duration': 612,
'thumbnail': 're:^https?://.+\.jpg',
},
}
}, {
'url': 'http://chic.clipsyndicate.com/video/play/5844117/shark_attack',
'only_matching': True,
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id')
video_id = self._match_id(url)
js_player = self._download_webpage(
'http://eplayer.clipsyndicate.com/embed/player.js?va_id=%s' % video_id,
video_id, 'Downlaoding player')

View File

@ -105,6 +105,7 @@ class CloudyIE(InfoExtractor):
webpage = self._download_webpage(url, video_id)
file_key = self._search_regex(
r'filekey\s*=\s*"([^"]+)"', webpage, 'file_key')
[r'key\s*:\s*"([^"]+)"', r'filekey\s*=\s*"([^"]+)"'],
webpage, 'file_key')
return self._extract_video(video_host, video_id, file_key)

View File

@ -11,7 +11,7 @@ from ..utils import (
class CNETIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?cnet\.com/videos/(?P<id>[^/]+)/'
_TEST = {
_TESTS = [{
'url': 'http://www.cnet.com/videos/hands-on-with-microsofts-windows-8-1-update/',
'info_dict': {
'id': '56f4ea68-bd21-4852-b08c-4de5b8354c60',
@ -25,7 +25,20 @@ class CNETIE(InfoExtractor):
'params': {
'skip_download': 'requires rtmpdump',
}
}
}, {
'url': 'http://www.cnet.com/videos/whiny-pothole-tweets-at-local-government-when-hit-by-cars-tomorrow-daily-187/',
'info_dict': {
'id': '56527b93-d25d-44e3-b738-f989ce2e49ba',
'ext': 'flv',
'description': 'Khail and Ashley wonder what other civic woes can be solved by self-tweeting objects, investigate a new kind of VR camera and watch an origami robot self-assemble, walk, climb, dig and dissolve. #TDPothole',
'uploader_id': 'b163284d-6b73-44fc-b3e6-3da66c392d40',
'uploader': 'Ashley Esqueda',
'title': 'Whiny potholes tweet at local government when hit by cars (Tomorrow Daily 187)',
},
'params': {
'skip_download': True, # requires rtmpdump
},
}]
def _real_extract(self, url):
display_id = self._match_id(url)
@ -42,7 +55,7 @@ class CNETIE(InfoExtractor):
raise ExtractorError('Cannot find video data')
mpx_account = data['config']['players']['default']['mpx_account']
vid = vdata['files']['rtmp']
vid = vdata['files'].get('rtmp', vdata['files']['hds'])
tp_link = 'http://link.theplatform.com/s/%s/%s' % (mpx_account, vid)
video_id = vdata['id']

View File

@ -12,7 +12,7 @@ from ..utils import (
class CNNIE(InfoExtractor):
_VALID_URL = r'''(?x)https?://(?:(?:edition|www)\.)?cnn\.com/video/(?:data/.+?|\?)/
(?P<path>.+?/(?P<title>[^/]+?)(?:\.(?:cnn|hln)(?:-ap)?|(?=&)))'''
(?P<path>.+?/(?P<title>[^/]+?)(?:\.(?:[a-z\-]+)|(?=&)))'''
_TESTS = [{
'url': 'http://edition.cnn.com/video/?/video/sports/2013/06/09/nadal-1-on-1.cnn',
@ -45,6 +45,12 @@ class CNNIE(InfoExtractor):
'description': 'md5:e7223a503315c9f150acac52e76de086',
'upload_date': '20141222',
}
}, {
'url': 'http://cnn.com/video/?/video/politics/2015/03/27/pkg-arizona-senator-church-attendance-mandatory.ktvk',
'only_matching': True,
}, {
'url': 'http://cnn.com/video/?/video/us/2015/04/06/dnt-baker-refuses-anti-gay-order.wkmg',
'only_matching': True,
}]
def _real_extract(self, url):

View File

@ -36,7 +36,7 @@ class ComCarCoffIE(InfoExtractor):
webpage, 'full data json'))
video_id = full_data['activeVideo']['video']
video_data = full_data['videos'][video_id]
video_data = full_data.get('videos', {}).get(video_id) or full_data['singleshots'][video_id]
thumbnails = [{
'url': video_data['images']['thumb'],
}, {

View File

@ -201,7 +201,7 @@ class ComedyCentralShowsIE(MTVServicesInfoExtractor):
uri = mMovieParams[0][1]
# Correct cc.com in uri
uri = re.sub(r'(episode:[^.]+)(\.cc)?\.com', r'\1.cc.com', uri)
uri = re.sub(r'(episode:[^.]+)(\.cc)?\.com', r'\1.com', uri)
index_url = 'http://%s.cc.com/feeds/mrss?%s' % (show_name, compat_urllib_parse.urlencode({'uri': uri}))
idoc = self._download_xml(
@ -250,6 +250,8 @@ class ComedyCentralShowsIE(MTVServicesInfoExtractor):
})
self._sort_formats(formats)
subtitles = self._extract_subtitles(cdoc, guid)
virtual_id = show_name + ' ' + epTitle + ' part ' + compat_str(part_num + 1)
entries.append({
'id': guid,
@ -260,6 +262,7 @@ class ComedyCentralShowsIE(MTVServicesInfoExtractor):
'duration': duration,
'thumbnail': thumbnail,
'description': description,
'subtitles': subtitles,
})
return {

View File

@ -14,26 +14,30 @@ import xml.etree.ElementTree
from ..compat import (
compat_cookiejar,
compat_cookies,
compat_HTTPError,
compat_http_client,
compat_urllib_error,
compat_urllib_parse_urlparse,
compat_urllib_request,
compat_urlparse,
compat_str,
)
from ..utils import (
NO_DEFAULT,
age_restricted,
bug_reports_message,
clean_html,
compiled_regex_type,
determine_ext,
ExtractorError,
fix_xml_ampersands,
float_or_none,
HEADRequest,
int_or_none,
RegexNotFoundError,
sanitize_filename,
unescapeHTML,
)
_NO_DEFAULT = object()
class InfoExtractor(object):
@ -47,7 +51,7 @@ class InfoExtractor(object):
information possibly downloading the video to the file system, among
other possible outcomes.
The type field determines the the type of the result.
The type field determines the type of the result.
By far the most common value (and the default if _type is missing) is
"video", which indicates a single video.
@ -63,7 +67,7 @@ class InfoExtractor(object):
Potential fields:
* url Mandatory. The URL of the video file
* ext Will be calculated from url if missing
* ext Will be calculated from URL if missing
* format A human-readable description of the format
("mp4 container with h264/opus").
Calculated from the format_id, width, height.
@ -111,11 +115,8 @@ class InfoExtractor(object):
(quality takes higher priority)
-1 for default (order by other properties),
-2 or smaller for less than default.
* http_method HTTP method to use for the download.
* http_headers A dictionary of additional HTTP headers
to add to the request.
* http_post_data Additional data to send with a POST
request.
* stretched_ratio If given and not 1, indicates that the
video's pixels are not square.
width : height ratio as float.
@ -145,17 +146,25 @@ class InfoExtractor(object):
thumbnail: Full URL to a video thumbnail image.
description: Full video description.
uploader: Full name of the video uploader.
creator: The main artist who created the video.
timestamp: UNIX timestamp of the moment the video became available.
upload_date: Video upload date (YYYYMMDD).
If not explicitly set, calculated from timestamp.
uploader_id: Nickname or id of the video uploader.
location: Physical location where the video was filmed.
subtitles: The subtitle file contents as a dictionary in the format
{language: subtitles}.
subtitles: The available subtitles as a dictionary in the format
{language: subformats}. "subformats" is a list sorted from
lower to higher preference, each element is a dictionary
with the "ext" entry and one of:
* "data": The subtitles file contents
* "url": A URL pointing to the subtitles file
automatic_captions: Like 'subtitles', used by the YoutubeIE for
automatically generated captions
duration: Length of the video in seconds, as an integer.
view_count: How many users have watched the video on the platform.
like_count: Number of positive ratings of the video
dislike_count: Number of negative ratings of the video
average_rating: Average rating give by users, the scale used depends on the webpage
comment_count: Number of comments on the video
comments: A list of comments, each with one or more of the following
properties (all but one of text or html optional):
@ -169,13 +178,18 @@ class InfoExtractor(object):
Set to "root" to indicate that this is a
comment to the original video.
age_limit: Age restriction for the video, as an integer (years)
webpage_url: The url to the video webpage, if given to youtube-dl it
webpage_url: The URL to the video webpage, if given to youtube-dl it
should allow to get the same result again. (It will be set
by YoutubeDL if it's missing)
categories: A list of categories that the video falls in, for example
["Sports", "Berlin"]
tags: A list of tags assigned to the video, e.g. ["sweden", "pop music"]
is_live: True, False, or None (=unknown). Whether this video is a
live stream that goes on instead of a fixed-length video.
start_time: Time in seconds where the reproduction should start, as
specified in the URL.
end_time: Time in seconds where the reproduction should end, as
specified in the URL.
Unless mentioned otherwise, the fields should be Unicode strings.
@ -263,8 +277,15 @@ class InfoExtractor(object):
def extract(self, url):
"""Extracts URL information and returns it in list of dicts."""
self.initialize()
return self._real_extract(url)
try:
self.initialize()
return self._real_extract(url)
except ExtractorError:
raise
except compat_http_client.IncompleteRead as e:
raise ExtractorError('A network error has occured.', cause=e, expected=True)
except (KeyError, StopIteration) as e:
raise ExtractorError('An extractor error has occured.', cause=e)
def set_downloader(self, downloader):
"""Sets the downloader for this IE."""
@ -310,7 +331,7 @@ class InfoExtractor(object):
self._downloader.report_warning(errmsg)
return False
def _download_webpage_handle(self, url_or_request, video_id, note=None, errnote=None, fatal=True):
def _download_webpage_handle(self, url_or_request, video_id, note=None, errnote=None, fatal=True, encoding=None):
""" Returns a tuple (page content as string, URL handle) """
# Strip hashes from the URL (#1038)
if isinstance(url_or_request, (compat_str, str)):
@ -320,14 +341,11 @@ class InfoExtractor(object):
if urlh is False:
assert not fatal
return False
content = self._webpage_read_content(urlh, url_or_request, video_id, note, errnote, fatal)
content = self._webpage_read_content(urlh, url_or_request, video_id, note, errnote, fatal, encoding=encoding)
return (content, urlh)
def _webpage_read_content(self, urlh, url_or_request, video_id, note=None, errnote=None, fatal=True, prefix=None):
content_type = urlh.headers.get('Content-Type', '')
webpage_bytes = urlh.read()
if prefix is not None:
webpage_bytes = prefix + webpage_bytes
@staticmethod
def _guess_encoding_from_content(content_type, webpage_bytes):
m = re.match(r'[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+\s*;\s*charset=(.+)', content_type)
if m:
encoding = m.group(1)
@ -340,6 +358,16 @@ class InfoExtractor(object):
encoding = 'utf-16'
else:
encoding = 'utf-8'
return encoding
def _webpage_read_content(self, urlh, url_or_request, video_id, note=None, errnote=None, fatal=True, prefix=None, encoding=None):
content_type = urlh.headers.get('Content-Type', '')
webpage_bytes = urlh.read()
if prefix is not None:
webpage_bytes = prefix + webpage_bytes
if not encoding:
encoding = self._guess_encoding_from_content(content_type, webpage_bytes)
if self._downloader.params.get('dump_intermediate_pages', False):
try:
url = url_or_request.get_full_url()
@ -383,16 +411,26 @@ class InfoExtractor(object):
if blocked_iframe:
msg += ' Visit %s for more details' % blocked_iframe
raise ExtractorError(msg, expected=True)
if '<title>The URL you requested has been blocked</title>' in content[:512]:
msg = (
'Access to this webpage has been blocked by Indian censorship. '
'Use a VPN or proxy server (with --proxy) to route around it.')
block_msg = self._html_search_regex(
r'</h1><p>(.*?)</p>',
content, 'block message', default=None)
if block_msg:
msg += ' (Message: "%s")' % block_msg.replace('\n', ' ')
raise ExtractorError(msg, expected=True)
return content
def _download_webpage(self, url_or_request, video_id, note=None, errnote=None, fatal=True, tries=1, timeout=5):
def _download_webpage(self, url_or_request, video_id, note=None, errnote=None, fatal=True, tries=1, timeout=5, encoding=None):
""" Returns the data of the page as a string """
success = False
try_count = 0
while success is False:
try:
res = self._download_webpage_handle(url_or_request, video_id, note, errnote, fatal)
res = self._download_webpage_handle(url_or_request, video_id, note, errnote, fatal, encoding=encoding)
success = True
except compat_http_client.IncompleteRead as e:
try_count += 1
@ -407,10 +445,10 @@ class InfoExtractor(object):
def _download_xml(self, url_or_request, video_id,
note='Downloading XML', errnote='Unable to download XML',
transform_source=None, fatal=True):
transform_source=None, fatal=True, encoding=None):
"""Return the xml as an xml.etree.ElementTree.Element"""
xml_string = self._download_webpage(
url_or_request, video_id, note, errnote, fatal=fatal)
url_or_request, video_id, note, errnote, fatal=fatal, encoding=encoding)
if xml_string is False:
return xml_string
if transform_source:
@ -421,9 +459,10 @@ class InfoExtractor(object):
note='Downloading JSON metadata',
errnote='Unable to download JSON metadata',
transform_source=None,
fatal=True):
fatal=True, encoding=None):
json_string = self._download_webpage(
url_or_request, video_id, note, errnote, fatal=fatal)
url_or_request, video_id, note, errnote, fatal=fatal,
encoding=encoding)
if (not fatal) and json_string is False:
return None
return self._parse_json(
@ -468,14 +507,16 @@ class InfoExtractor(object):
# Methods for following #608
@staticmethod
def url_result(url, ie=None, video_id=None):
"""Returns a url that points to a page that should be processed"""
def url_result(url, ie=None, video_id=None, video_title=None):
"""Returns a URL that points to a page that should be processed"""
# TODO: ie should be the class used for getting the info
video_info = {'_type': 'url',
'url': url,
'ie_key': ie}
if video_id is not None:
video_info['id'] = video_id
if video_title is not None:
video_info['title'] = video_title
return video_info
@staticmethod
@ -491,7 +532,7 @@ class InfoExtractor(object):
video_info['description'] = playlist_description
return video_info
def _search_regex(self, pattern, string, name, default=_NO_DEFAULT, fatal=True, flags=0, group=None):
def _search_regex(self, pattern, string, name, default=NO_DEFAULT, fatal=True, flags=0, group=None):
"""
Perform a regex search on the given string, using a single or a list of
patterns returning the first matching group.
@ -506,7 +547,7 @@ class InfoExtractor(object):
if mobj:
break
if os.name != 'nt' and sys.stderr.isatty():
if not self._downloader.params.get('no_color') and os.name != 'nt' and sys.stderr.isatty():
_name = '\033[0;34m%s\033[0m' % name
else:
_name = name
@ -517,16 +558,15 @@ class InfoExtractor(object):
return next(g for g in mobj.groups() if g is not None)
else:
return mobj.group(group)
elif default is not _NO_DEFAULT:
elif default is not NO_DEFAULT:
return default
elif fatal:
raise RegexNotFoundError('Unable to extract %s' % _name)
else:
self._downloader.report_warning('unable to extract %s; '
'please report this issue on http://yt-dl.org/bug' % _name)
self._downloader.report_warning('unable to extract %s' % _name + bug_reports_message())
return None
def _html_search_regex(self, pattern, string, name, default=_NO_DEFAULT, fatal=True, flags=0, group=None):
def _html_search_regex(self, pattern, string, name, default=NO_DEFAULT, fatal=True, flags=0, group=None):
"""
Like _search_regex, but strips HTML tags and unescapes entities.
"""
@ -538,7 +578,7 @@ class InfoExtractor(object):
def _get_login_info(self):
"""
Get the the login info as (username, password)
Get the login info as (username, password)
It will look in the netrc file using the _NETRC_MACHINE value
If there's no info available, return (None, None)
"""
@ -593,6 +633,12 @@ class InfoExtractor(object):
template % (content_re, property_re),
]
@staticmethod
def _meta_regex(prop):
return r'''(?isx)<meta
(?=[^>]+(?:itemprop|name|property)=(["\']?)%s\1)
[^>]+?content=(["\'])(?P<content>.*?)\2''' % re.escape(prop)
def _og_search_property(self, prop, html, name=None, **kargs):
if name is None:
name = 'OpenGraph %s' % prop
@ -602,7 +648,7 @@ class InfoExtractor(object):
return unescapeHTML(escaped)
def _og_search_thumbnail(self, html, **kargs):
return self._og_search_property('image', html, 'thumbnail url', fatal=False, **kargs)
return self._og_search_property('image', html, 'thumbnail URL', fatal=False, **kargs)
def _og_search_description(self, html, **kargs):
return self._og_search_property('description', html, fatal=False, **kargs)
@ -623,9 +669,7 @@ class InfoExtractor(object):
if display_name is None:
display_name = name
return self._html_search_regex(
r'''(?isx)<meta
(?=[^>]+(?:itemprop|name|property)=(["\']?)%s\1)
[^>]+?content=(["\'])(?P<content>.*?)\2''' % re.escape(name),
self._meta_regex(name),
html, display_name, fatal=fatal, group='content', **kwargs)
def _dc_search_uploader(self, html):
@ -655,11 +699,45 @@ class InfoExtractor(object):
}
return RATING_TABLE.get(rating.lower(), None)
def _family_friendly_search(self, html):
# See http://schema.org/VideoObject
family_friendly = self._html_search_meta('isFamilyFriendly', html)
if not family_friendly:
return None
RATING_TABLE = {
'1': 0,
'true': 0,
'0': 18,
'false': 18,
}
return RATING_TABLE.get(family_friendly.lower(), None)
def _twitter_search_player(self, html):
return self._html_search_meta('twitter:player', html,
'twitter card player')
def _sort_formats(self, formats):
@staticmethod
def _hidden_inputs(html):
return dict([
(input.group('name'), input.group('value')) for input in re.finditer(
r'''(?x)
<input\s+
type=(?P<q_hidden>["\'])hidden(?P=q_hidden)\s+
name=(?P<q_name>["\'])(?P<name>.+?)(?P=q_name)\s+
(?:id=(?P<q_id>["\']).+?(?P=q_id)\s+)?
value=(?P<q_value>["\'])(?P<value>.*?)(?P=q_value)
''', html)
])
def _form_hidden_inputs(self, form_id, html):
form = self._search_regex(
r'(?s)<form[^>]+?id=(["\'])%s\1[^>]*>(?P<form>.+?)</form>' % form_id,
html, '%s form' % form_id, group='form')
return self._hidden_inputs(form)
def _sort_formats(self, formats, field_preference=None):
if not formats:
raise ExtractorError('No video formats found')
@ -669,6 +747,9 @@ class InfoExtractor(object):
if not f.get('ext') and 'url' in f:
f['ext'] = determine_ext(f['url'])
if isinstance(field_preference, (list, tuple)):
return tuple(f.get(field) if f.get(field) is not None else -1 for field in field_preference)
preference = f.get('preference')
if preference is None:
proto = f.get('protocol')
@ -704,18 +785,18 @@ class InfoExtractor(object):
preference,
f.get('language_preference') if f.get('language_preference') is not None else -1,
f.get('quality') if f.get('quality') is not None else -1,
f.get('tbr') if f.get('tbr') is not None else -1,
f.get('filesize') if f.get('filesize') is not None else -1,
f.get('vbr') if f.get('vbr') is not None else -1,
f.get('height') if f.get('height') is not None else -1,
f.get('width') if f.get('width') is not None else -1,
ext_preference,
f.get('tbr') if f.get('tbr') is not None else -1,
f.get('vbr') if f.get('vbr') is not None else -1,
f.get('abr') if f.get('abr') is not None else -1,
audio_ext_preference,
f.get('fps') if f.get('fps') is not None else -1,
f.get('filesize') if f.get('filesize') is not None else -1,
f.get('filesize_approx') if f.get('filesize_approx') is not None else -1,
f.get('source_preference') if f.get('source_preference') is not None else -1,
f.get('format_id'),
f.get('format_id') if f.get('format_id') is not None else '',
)
formats.sort(key=_formats_key)
@ -728,15 +809,17 @@ class InfoExtractor(object):
formats)
def _is_valid_url(self, url, video_id, item='video'):
url = self._proto_relative_url(url, scheme='http:')
# For now assume non HTTP(S) URLs always valid
if not (url.startswith('http://') or url.startswith('https://')):
return True
try:
self._request_webpage(
HEADRequest(url), video_id,
'Checking %s URL' % item)
self._request_webpage(url, video_id, 'Checking %s URL' % item)
return True
except ExtractorError as e:
if isinstance(e.cause, compat_HTTPError):
self.report_warning(
'%s URL is invalid, skipping' % item, video_id)
self.to_screen(
'%s: %s URL is invalid, skipping' % (video_id, item))
return False
raise
@ -764,10 +847,14 @@ class InfoExtractor(object):
self.to_screen(msg)
time.sleep(timeout)
def _extract_f4m_formats(self, manifest_url, video_id):
def _extract_f4m_formats(self, manifest_url, video_id, preference=None, f4m_id=None,
transform_source=lambda s: fix_xml_ampersands(s).strip()):
manifest = self._download_xml(
manifest_url, video_id, 'Downloading f4m manifest',
'Unable to download f4m manifest')
'Unable to download f4m manifest',
# Some manifests may be malformed, e.g. prosiebensat1 generated manifests
# (see https://github.com/rg3/youtube-dl/issues/6215#issuecomment-121704244)
transform_source=transform_source)
formats = []
manifest_version = '1.0'
@ -777,30 +864,44 @@ class InfoExtractor(object):
media_nodes = manifest.findall('{http://ns.adobe.com/f4m/2.0}media')
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')
media_url = media_el.attrib.get('href') or media_el.attrib.get('url')
if not media_url:
continue
manifest_url = (
media_url if media_url.startswith('http://') or media_url.startswith('https://')
else ('/'.join(manifest_url.split('/')[:-1]) + '/' + media_url))
# If media_url is itself a f4m manifest do the recursive extraction
# since bitrates in parent manifest (this one) and media_url manifest
# may differ leading to inability to resolve the format by requested
# bitrate in f4m downloader
if determine_ext(manifest_url) == 'f4m':
formats.extend(self._extract_f4m_formats(manifest_url, video_id, preference, f4m_id))
continue
tbr = int_or_none(media_el.attrib.get('bitrate'))
format_id = 'f4m-%d' % (i if tbr is None else tbr)
formats.append({
'format_id': format_id,
'format_id': '-'.join(filter(None, [f4m_id, compat_str(i if tbr is None else tbr)])),
'url': manifest_url,
'ext': 'flv',
'tbr': tbr,
'width': int_or_none(media_el.attrib.get('width')),
'height': int_or_none(media_el.attrib.get('height')),
'preference': preference,
})
self._sort_formats(formats)
return formats
def _extract_m3u8_formats(self, m3u8_url, video_id, ext=None,
entry_protocol='m3u8', preference=None):
entry_protocol='m3u8', preference=None,
m3u8_id=None, note=None, errnote=None,
fatal=True):
formats = [{
'format_id': 'm3u8-meta',
'format_id': '-'.join(filter(None, [m3u8_id, 'meta'])),
'url': m3u8_url,
'ext': ext,
'protocol': 'm3u8',
'preference': -1,
'preference': preference - 1 if preference else -1,
'resolution': 'multiple',
'format_note': 'Quality selection URL',
}]
@ -812,9 +913,13 @@ class InfoExtractor(object):
m3u8_doc = self._download_webpage(
m3u8_url, video_id,
note='Downloading m3u8 information',
errnote='Failed to download m3u8 information')
note=note or 'Downloading m3u8 information',
errnote=errnote or 'Failed to download m3u8 information',
fatal=fatal)
if m3u8_doc is False:
return m3u8_doc
last_info = None
last_media = None
kv_rex = re.compile(
r'(?P<key>[a-zA-Z_-]+)=(?P<val>"[^"]+"|[^",]+)(?:,|$)')
for line in m3u8_doc.splitlines():
@ -825,6 +930,13 @@ class InfoExtractor(object):
if v.startswith('"'):
v = v[1:-1]
last_info[m.group('key')] = v
elif line.startswith('#EXT-X-MEDIA:'):
last_media = {}
for m in kv_rex.finditer(line):
v = m.group('val')
if v.startswith('"'):
v = v[1:-1]
last_media[m.group('key')] = v
elif line.startswith('#') or not line.strip():
continue
else:
@ -832,9 +944,13 @@ class InfoExtractor(object):
formats.append({'url': format_url(line)})
continue
tbr = int_or_none(last_info.get('BANDWIDTH'), scale=1000)
format_id = []
if m3u8_id:
format_id.append(m3u8_id)
last_media_name = last_media.get('NAME') if last_media and last_media.get('TYPE') != 'SUBTITLES' else None
format_id.append(last_media_name if last_media_name else '%d' % (tbr if tbr else len(formats)))
f = {
'format_id': 'm3u8-%d' % (tbr if tbr else len(formats)),
'format_id': '-'.join(format_id),
'url': format_url(line.strip()),
'tbr': tbr,
'ext': ext,
@ -854,54 +970,78 @@ class InfoExtractor(object):
width_str, height_str = resolution.split('x')
f['width'] = int(width_str)
f['height'] = int(height_str)
if last_media is not None:
f['m3u8_media'] = last_media
last_media = None
formats.append(f)
last_info = {}
self._sort_formats(formats)
return formats
# TODO: improve extraction
def _extract_smil_formats(self, smil_url, video_id):
def _extract_smil_formats(self, smil_url, video_id, fatal=True):
smil = self._download_xml(
smil_url, video_id, 'Downloading SMIL file',
'Unable to download SMIL file')
'Unable to download SMIL file', fatal=fatal)
if smil is False:
assert not fatal
return []
base = smil.find('./head/meta').get('base')
formats = []
rtmp_count = 0
for video in smil.findall('./body/switch/video'):
src = video.get('src')
if not src:
continue
bitrate = int_or_none(video.get('system-bitrate') or video.get('systemBitrate'), 1000)
width = int_or_none(video.get('width'))
height = int_or_none(video.get('height'))
proto = video.get('proto')
if not proto:
if base:
if base.startswith('rtmp'):
proto = 'rtmp'
elif base.startswith('http'):
proto = 'http'
ext = video.get('ext')
if proto == 'm3u8':
formats.extend(self._extract_m3u8_formats(src, video_id, ext))
elif proto == 'rtmp':
rtmp_count += 1
streamer = video.get('streamer') or base
formats.append({
'url': streamer,
'play_path': src,
'ext': 'flv',
'format_id': 'rtmp-%d' % (rtmp_count if bitrate is None else bitrate),
'tbr': bitrate,
'width': width,
'height': height,
})
if smil.findall('./body/seq/video'):
video = smil.findall('./body/seq/video')[0]
fmts, rtmp_count = self._parse_smil_video(video, video_id, base, rtmp_count)
formats.extend(fmts)
else:
for video in smil.findall('./body/switch/video'):
fmts, rtmp_count = self._parse_smil_video(video, video_id, base, rtmp_count)
formats.extend(fmts)
self._sort_formats(formats)
return formats
def _parse_smil_video(self, video, video_id, base, rtmp_count):
src = video.get('src')
if not src:
return [], rtmp_count
bitrate = int_or_none(video.get('system-bitrate') or video.get('systemBitrate'), 1000)
width = int_or_none(video.get('width'))
height = int_or_none(video.get('height'))
proto = video.get('proto')
if not proto:
if base:
if base.startswith('rtmp'):
proto = 'rtmp'
elif base.startswith('http'):
proto = 'http'
ext = video.get('ext')
if proto == 'm3u8':
return self._extract_m3u8_formats(src, video_id, ext), rtmp_count
elif proto == 'rtmp':
rtmp_count += 1
streamer = video.get('streamer') or base
return ([{
'url': streamer,
'play_path': src,
'ext': 'flv',
'format_id': 'rtmp-%d' % (rtmp_count if bitrate is None else bitrate),
'tbr': bitrate,
'width': width,
'height': height,
}], rtmp_count)
elif proto.startswith('http'):
return ([{
'url': base + src,
'ext': ext or 'flv',
'tbr': bitrate,
'width': width,
'height': height,
}], rtmp_count)
def _live_title(self, name):
""" Generate the title for a live video """
now = datetime.datetime.now()
@ -936,6 +1076,12 @@ class InfoExtractor(object):
None, '/', True, False, expire_time, '', None, None, None)
self._downloader.cookiejar.set_cookie(cookie)
def _get_cookies(self, url):
""" Return a compat_cookies.SimpleCookie with the cookies for the url """
req = compat_urllib_request.Request(url)
self._downloader.cookiejar.add_cookie_header(req)
return compat_cookies.SimpleCookie(req.get_header('Cookie'))
def get_testcases(self, include_onlymatching=False):
t = getattr(self, '_TEST', None)
if t:
@ -965,11 +1111,29 @@ class InfoExtractor(object):
any_restricted = any_restricted or is_restricted
return not any_restricted
def extract_subtitles(self, *args, **kwargs):
if (self._downloader.params.get('writesubtitles', False) or
self._downloader.params.get('listsubtitles')):
return self._get_subtitles(*args, **kwargs)
return {}
def _get_subtitles(self, *args, **kwargs):
raise NotImplementedError("This method must be implemented by subclasses")
def extract_automatic_captions(self, *args, **kwargs):
if (self._downloader.params.get('writeautomaticsub', False) or
self._downloader.params.get('listsubtitles')):
return self._get_automatic_captions(*args, **kwargs)
return {}
def _get_automatic_captions(self, *args, **kwargs):
raise NotImplementedError("This method must be implemented by subclasses")
class SearchInfoExtractor(InfoExtractor):
"""
Base class for paged search queries extractors.
They accept urls in the format _SEARCH_KEY(|all|[0-9]):{query}
They accept URLs in the format _SEARCH_KEY(|all|[0-9]):{query}
Instances should define _SEARCH_KEY and _MAX_RESULTS.
"""

View File

@ -24,6 +24,23 @@ class CommonMistakesIE(InfoExtractor):
'That doesn\'t make any sense. '
'Simply remove the parameter in your command or configuration.'
) % url
if self._downloader.params.get('verbose'):
if not self._downloader.params.get('verbose'):
msg += ' Add -v to the command line to see what arguments and configuration youtube-dl got.'
raise ExtractorError(msg, expected=True)
class UnicodeBOMIE(InfoExtractor):
IE_DESC = False
_VALID_URL = r'(?P<bom>\ufeff)(?P<id>.*)$'
_TESTS = [{
'url': '\ufeffhttp://www.youtube.com/watch?v=BaW_jenozKc',
'only_matching': True,
}]
def _real_extract(self, url):
real_url = self._match_id(url)
self.report_warning(
'Your URL starts with a Byte Order Mark (BOM). '
'Removing the BOM and looking for "%s" ...' % real_url)
return self.url_result(real_url)

View File

@ -11,39 +11,65 @@ from ..utils import (
class CrackedIE(InfoExtractor):
_VALID_URL = r'https?://(?:www\.)?cracked\.com/video_(?P<id>\d+)_[\da-z-]+\.html'
_TEST = {
'url': 'http://www.cracked.com/video_19006_4-plot-holes-you-didnt-notice-in-your-favorite-movies.html',
'md5': '4b29a5eeec292cd5eca6388c7558db9e',
_TESTS = [{
'url': 'http://www.cracked.com/video_19070_if-animal-actors-got-e21-true-hollywood-stories.html',
'md5': '89b90b9824e3806ca95072c4d78f13f7',
'info_dict': {
'id': '19006',
'id': '19070',
'ext': 'mp4',
'title': '4 Plot Holes You Didn\'t Notice in Your Favorite Movies',
'description': 'md5:3b909e752661db86007d10e5ec2df769',
'timestamp': 1405659600,
'upload_date': '20140718',
'title': 'If Animal Actors Got E! True Hollywood Stories',
'timestamp': 1404954000,
'upload_date': '20140710',
}
}
}, {
# youtube embed
'url': 'http://www.cracked.com/video_19006_4-plot-holes-you-didnt-notice-in-your-favorite-movies.html',
'md5': 'ccd52866b50bde63a6ef3b35016ba8c7',
'info_dict': {
'id': 'EjI00A3rZD0',
'ext': 'mp4',
'title': "4 Plot Holes You Didn't Notice in Your Favorite Movies - The Spit Take",
'description': 'md5:c603708c718b796fe6079e2b3351ffc7',
'upload_date': '20140725',
'uploader_id': 'Cracked',
'uploader': 'Cracked',
}
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('id')
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
youtube_url = self._search_regex(
r'<iframe[^>]+src="((?:https?:)?//www\.youtube\.com/embed/[^"]+)"',
webpage, 'youtube url', default=None)
if youtube_url:
return self.url_result(youtube_url, 'Youtube')
video_url = self._html_search_regex(
[r'var\s+CK_vidSrc\s*=\s*"([^"]+)"', r'<video\s+src="([^"]+)"'], webpage, 'video URL')
[r'var\s+CK_vidSrc\s*=\s*"([^"]+)"', r'<video\s+src="([^"]+)"'],
webpage, 'video URL')
title = self._og_search_title(webpage)
description = self._og_search_description(webpage)
title = self._search_regex(
[r'property="?og:title"?\s+content="([^"]+)"', r'class="?title"?>([^<]+)'],
webpage, 'title')
timestamp = self._html_search_regex(r'<time datetime="([^"]+)"', webpage, 'upload date', fatal=False)
description = self._search_regex(
r'name="?(?:og:)?description"?\s+content="([^"]+)"',
webpage, 'description', default=None)
timestamp = self._html_search_regex(
r'"date"\s*:\s*"([^"]+)"', webpage, 'upload date', fatal=False)
if timestamp:
timestamp = parse_iso8601(timestamp[:-6])
view_count = str_to_int(self._html_search_regex(
r'<span class="views" id="viewCounts">([\d,\.]+) Views</span>', webpage, 'view count', fatal=False))
r'<span\s+class="?views"? id="?viewCounts"?>([\d,\.]+) Views</span>',
webpage, 'view count', fatal=False))
comment_count = str_to_int(self._html_search_regex(
r'<span id="commentCounts">([\d,\.]+)</span>', webpage, 'comment count', fatal=False))
r'<span\s+id="?commentCounts"?>([\d,\.]+)</span>',
webpage, 'comment count', fatal=False))
m = re.search(r'_(?P<width>\d+)X(?P<height>\d+)\.mp4$', video_url)
if m:

View File

@ -0,0 +1,60 @@
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import (
int_or_none,
qualities,
)
class CrooksAndLiarsIE(InfoExtractor):
_VALID_URL = r'https?://embed\.crooksandliars\.com/(?:embed|v)/(?P<id>[A-Za-z0-9]+)'
_TESTS = [{
'url': 'https://embed.crooksandliars.com/embed/8RUoRhRi',
'info_dict': {
'id': '8RUoRhRi',
'ext': 'mp4',
'title': 'Fox & Friends Says Protecting Atheists From Discrimination Is Anti-Christian!',
'description': 'md5:e1a46ad1650e3a5ec7196d432799127f',
'thumbnail': 're:^https?://.*\.jpg',
'timestamp': 1428207000,
'upload_date': '20150405',
'uploader': 'Heather',
'duration': 236,
}
}, {
'url': 'http://embed.crooksandliars.com/v/MTE3MjUtMzQ2MzA',
'only_matching': True,
}]
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(
'http://embed.crooksandliars.com/embed/%s' % video_id, video_id)
manifest = self._parse_json(
self._search_regex(
r'var\s+manifest\s*=\s*({.+?})\n', webpage, 'manifest JSON'),
video_id)
quality = qualities(('webm_low', 'mp4_low', 'webm_high', 'mp4_high'))
formats = [{
'url': item['url'],
'format_id': item['type'],
'quality': quality(item['type']),
} for item in manifest['flavors'] if item['mime'].startswith('video/')]
self._sort_formats(formats)
return {
'url': url,
'id': video_id,
'title': manifest['title'],
'description': manifest.get('description'),
'thumbnail': self._proto_relative_url(manifest.get('poster')),
'timestamp': int_or_none(manifest.get('created')),
'uploader': manifest.get('author'),
'duration': int_or_none(manifest.get('duration')),
'formats': formats,
}

View File

@ -9,9 +9,10 @@ import xml.etree.ElementTree
from hashlib import sha1
from math import pow, sqrt, floor
from .subtitles import SubtitlesInfoExtractor
from .common import InfoExtractor
from ..compat import (
compat_urllib_parse,
compat_urllib_parse_unquote,
compat_urllib_request,
)
from ..utils import (
@ -23,13 +24,12 @@ from ..utils import (
)
from ..aes import (
aes_cbc_decrypt,
inc,
)
from .common import InfoExtractor
class CrunchyrollIE(SubtitlesInfoExtractor):
_VALID_URL = r'https?://(?:(?P<prefix>www|m)\.)?(?P<url>crunchyroll\.(?:com|fr)/(?:[^/]*/[^/?&]*?|media/\?id=)(?P<video_id>[0-9]+))(?:[/?&]|$)'
class CrunchyrollIE(InfoExtractor):
_VALID_URL = r'https?://(?:(?P<prefix>www|m)\.)?(?P<url>crunchyroll\.(?:com|fr)/(?:media(?:-|/\?id=)|[^/]*/[^/?&]*?)(?P<video_id>[0-9]+))(?:[/?&]|$)'
_NETRC_MACHINE = 'crunchyroll'
_TESTS = [{
'url': 'http://www.crunchyroll.com/wanna-be-the-strongest-in-the-world/episode-1-an-idol-wrestler-is-born-645513',
'info_dict': {
@ -46,6 +46,22 @@ class CrunchyrollIE(SubtitlesInfoExtractor):
# rtmp
'skip_download': True,
},
}, {
'url': 'http://www.crunchyroll.com/media-589804/culture-japan-1',
'info_dict': {
'id': '589804',
'ext': 'flv',
'title': 'Culture Japan Episode 1 Rebuilding Japan after the 3.11',
'description': 'md5:fe2743efedb49d279552926d0bd0cd9e',
'thumbnail': 're:^https?://.*\.jpg$',
'uploader': 'Danny Choo Network',
'upload_date': '20120213',
},
'params': {
# rtmp
'skip_download': True,
},
}, {
'url': 'http://www.crunchyroll.fr/girl-friend-beta/episode-11-goodbye-la-mode-661697',
'only_matching': True,
@ -77,8 +93,8 @@ class CrunchyrollIE(SubtitlesInfoExtractor):
self._login()
def _decrypt_subtitles(self, data, iv, id):
data = bytes_to_intlist(data)
iv = bytes_to_intlist(iv)
data = bytes_to_intlist(base64.b64decode(data.encode('utf-8')))
iv = bytes_to_intlist(base64.b64decode(iv.encode('utf-8')))
id = int(id)
def obfuscate_key_aux(count, modulo, start):
@ -102,13 +118,6 @@ class CrunchyrollIE(SubtitlesInfoExtractor):
key = obfuscate_key(id)
class Counter:
__value = iv
def next_value(self):
temp = self.__value
self.__value = inc(self.__value)
return temp
decrypted_data = intlist_to_bytes(aes_cbc_decrypt(data, key, iv))
return zlib.decompress(decrypted_data)
@ -187,6 +196,34 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
return output
def _extract_subtitles(self, subtitle):
sub_root = xml.etree.ElementTree.fromstring(subtitle)
return [{
'ext': 'srt',
'data': self._convert_subtitles_to_srt(sub_root),
}, {
'ext': 'ass',
'data': self._convert_subtitles_to_ass(sub_root),
}]
def _get_subtitles(self, video_id, webpage):
subtitles = {}
for sub_id, sub_name in re.findall(r'\?ssid=([0-9]+)" title="([^"]+)', webpage):
sub_page = self._download_webpage(
'http://www.crunchyroll.com/xml/?req=RpcApiSubtitle_GetXml&subtitle_script_id=' + sub_id,
video_id, note='Downloading subtitles for ' + sub_name)
id = self._search_regex(r'id=\'([0-9]+)', sub_page, 'subtitle_id', fatal=False)
iv = self._search_regex(r'<iv>([^<]+)', sub_page, 'subtitle_iv', fatal=False)
data = self._search_regex(r'<data>([^<]+)', sub_page, 'subtitle_data', fatal=False)
if not id or not iv or not data:
continue
subtitle = self._decrypt_subtitles(data, iv, id).decode('utf-8')
lang_code = self._search_regex(r'lang_code=["\']([^"\']+)', subtitle, 'subtitle_lang_code', fatal=False)
if not lang_code:
continue
subtitles[lang_code] = self._extract_subtitles(subtitle)
return subtitles
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
video_id = mobj.group('video_id')
@ -218,7 +255,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
video_upload_date = unified_strdate(video_upload_date)
video_uploader = self._html_search_regex(r'<div>\s*Publisher:(.+?)</div>', webpage, 'video_uploader', fatal=False, flags=re.DOTALL)
playerdata_url = compat_urllib_parse.unquote(self._html_search_regex(r'"config_url":"([^"]+)', webpage, 'playerdata_url'))
playerdata_url = compat_urllib_parse_unquote(self._html_search_regex(r'"config_url":"([^"]+)', webpage, 'playerdata_url'))
playerdata_req = compat_urllib_request.Request(playerdata_url)
playerdata_req.data = compat_urllib_parse.urlencode({'current_page': webpage_url})
playerdata_req.add_header('Content-Type', 'application/x-www-form-urlencoded')
@ -231,16 +268,17 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
for fmt in re.findall(r'showmedia\.([0-9]{3,4})p', webpage):
stream_quality, stream_format = self._FORMAT_IDS[fmt]
video_format = fmt + 'p'
streamdata_req = compat_urllib_request.Request('http://www.crunchyroll.com/xml/')
# urlencode doesn't work!
streamdata_req.data = 'req=RpcApiVideoEncode%5FGetStreamInfo&video%5Fencode%5Fquality=' + stream_quality + '&media%5Fid=' + stream_id + '&video%5Fformat=' + stream_format
streamdata_req = compat_urllib_request.Request(
'http://www.crunchyroll.com/xml/?req=RpcApiVideoPlayer_GetStandardConfig&media_id=%s&video_format=%s&video_quality=%s'
% (stream_id, stream_format, stream_quality),
compat_urllib_parse.urlencode({'current_page': url}).encode('utf-8'))
streamdata_req.add_header('Content-Type', 'application/x-www-form-urlencoded')
streamdata_req.add_header('Content-Length', str(len(streamdata_req.data)))
streamdata = self._download_xml(
streamdata_req, video_id,
note='Downloading media info for %s' % video_format)
video_url = streamdata.find('.//host').text
video_play_path = streamdata.find('.//file').text
stream_info = streamdata.find('./{default}preload/stream_info')
video_url = stream_info.find('./host').text
video_play_path = stream_info.find('./file').text
formats.append({
'url': video_url,
'play_path': video_play_path,
@ -249,34 +287,7 @@ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
'format_id': video_format,
})
subtitles = {}
sub_format = self._downloader.params.get('subtitlesformat', 'srt')
for sub_id, sub_name in re.findall(r'\?ssid=([0-9]+)" title="([^"]+)', webpage):
sub_page = self._download_webpage(
'http://www.crunchyroll.com/xml/?req=RpcApiSubtitle_GetXml&subtitle_script_id=' + sub_id,
video_id, note='Downloading subtitles for ' + sub_name)
id = self._search_regex(r'id=\'([0-9]+)', sub_page, 'subtitle_id', fatal=False)
iv = self._search_regex(r'<iv>([^<]+)', sub_page, 'subtitle_iv', fatal=False)
data = self._search_regex(r'<data>([^<]+)', sub_page, 'subtitle_data', fatal=False)
if not id or not iv or not data:
continue
id = int(id)
iv = base64.b64decode(iv)
data = base64.b64decode(data)
subtitle = self._decrypt_subtitles(data, iv, id).decode('utf-8')
lang_code = self._search_regex(r'lang_code=["\']([^"\']+)', subtitle, 'subtitle_lang_code', fatal=False)
if not lang_code:
continue
sub_root = xml.etree.ElementTree.fromstring(subtitle)
if sub_format == 'ass':
subtitles[lang_code] = self._convert_subtitles_to_ass(sub_root)
else:
subtitles[lang_code] = self._convert_subtitles_to_srt(sub_root)
if self._downloader.params.get('listsubtitles', False):
self._list_available_subtitles(video_id, subtitles)
return
subtitles = self.extract_subtitles(video_id, webpage)
return {
'id': video_id,

View File

@ -7,7 +7,10 @@ from ..utils import (
int_or_none,
unescapeHTML,
find_xpath_attr,
smuggle_url,
determine_ext,
)
from .senateisvp import SenateISVPIE
class CSpanIE(InfoExtractor):
@ -35,11 +38,22 @@ class CSpanIE(InfoExtractor):
}
}, {
'url': 'http://www.c-span.org/video/?318608-1/gm-ignition-switch-recall',
'md5': '446562a736c6bf97118e389433ed88d4',
'info_dict': {
'id': '342759',
'ext': 'mp4',
'title': 'General Motors Ignition Switch Recall',
'duration': 14848,
'description': 'md5:70c7c3b8fa63fa60d42772440596034c'
},
'playlist_duration_sum': 14855,
}, {
# Video from senate.gov
'url': 'http://www.c-span.org/video/?104517-1/immigration-reforms-needed-protect-skilled-american-workers',
'info_dict': {
'id': 'judiciary031715',
'ext': 'flv',
'title': 'Immigration Reforms Needed to Protect Skilled American Workers',
}
}]
def _real_extract(self, url):
@ -56,7 +70,7 @@ class CSpanIE(InfoExtractor):
# present, otherwise this is a stripped version
r'<p class=\'initial\'>(.*?)</p>'
],
webpage, 'description', flags=re.DOTALL)
webpage, 'description', flags=re.DOTALL, default=None)
info_url = 'http://c-spanvideo.org/videoLibrary/assets/player/ajax-player.php?os=android&html5=program&id=' + video_id
data = self._download_json(info_url, video_id)
@ -68,7 +82,16 @@ class CSpanIE(InfoExtractor):
title = find_xpath_attr(doc, './/string', 'name', 'title').text
thumbnail = find_xpath_attr(doc, './/string', 'name', 'poster').text
senate_isvp_url = SenateISVPIE._search_iframe_url(webpage)
if senate_isvp_url:
surl = smuggle_url(senate_isvp_url, {'force_title': title})
return self.url_result(surl, 'SenateISVP', video_id, title)
files = data['video']['files']
try:
capfile = data['video']['capfile']['#text']
except KeyError:
capfile = None
entries = [{
'id': '%s_%d' % (video_id, partnum + 1),
@ -79,11 +102,22 @@ class CSpanIE(InfoExtractor):
'description': description,
'thumbnail': thumbnail,
'duration': int_or_none(f.get('length', {}).get('#text')),
'subtitles': {
'en': [{
'url': capfile,
'ext': determine_ext(capfile, 'dfxp')
}],
} if capfile else None,
} for partnum, f in enumerate(files)]
return {
'_type': 'playlist',
'entries': entries,
'title': title,
'id': video_id,
}
if len(entries) == 1:
entry = dict(entries[0])
entry['id'] = video_id
return entry
else:
return {
'_type': 'playlist',
'entries': entries,
'title': title,
'id': video_id,
}

View File

@ -6,6 +6,7 @@ from ..utils import parse_iso8601, ExtractorError
class CtsNewsIE(InfoExtractor):
IE_DESC = '華視新聞'
# https connection failed (Connection reset)
_VALID_URL = r'http://news\.cts\.com\.tw/[a-z]+/[a-z]+/\d+/(?P<id>\d+)\.html'
_TESTS = [{

View File

@ -6,7 +6,6 @@ import json
import itertools
from .common import InfoExtractor
from .subtitles import SubtitlesInfoExtractor
from ..compat import (
compat_str,
@ -14,8 +13,9 @@ from ..compat import (
)
from ..utils import (
ExtractorError,
determine_ext,
int_or_none,
orderedSet,
parse_iso8601,
str_to_int,
unescapeHTML,
)
@ -26,14 +26,19 @@ class DailymotionBaseInfoExtractor(InfoExtractor):
def _build_request(url):
"""Build a request with the family filter disabled"""
request = compat_urllib_request.Request(url)
request.add_header('Cookie', 'family_filter=off')
request.add_header('Cookie', 'ff=off')
request.add_header('Cookie', 'family_filter=off; ff=off')
return request
def _download_webpage_handle_no_ff(self, url, *args, **kwargs):
request = self._build_request(url)
return self._download_webpage_handle(request, *args, **kwargs)
class DailymotionIE(DailymotionBaseInfoExtractor, SubtitlesInfoExtractor):
"""Information Extractor for Dailymotion"""
def _download_webpage_no_ff(self, url, *args, **kwargs):
request = self._build_request(url)
return self._download_webpage(request, *args, **kwargs)
class DailymotionIE(DailymotionBaseInfoExtractor):
_VALID_URL = r'(?i)(?:https?://)?(?:(www|touch)\.)?dailymotion\.[a-z]{2,3}/(?:(embed|#)/)?video/(?P<id>[^/?_]+)'
IE_NAME = 'dailymotion'
@ -47,13 +52,22 @@ class DailymotionIE(DailymotionBaseInfoExtractor, SubtitlesInfoExtractor):
_TESTS = [
{
'url': 'http://www.dailymotion.com/video/x33vw9_tutoriel-de-youtubeur-dl-des-video_tech',
'md5': '392c4b85a60a90dc4792da41ce3144eb',
'url': 'https://www.dailymotion.com/video/x2iuewm_steam-machine-models-pricing-listed-on-steam-store-ign-news_videogames',
'md5': '2137c41a8e78554bb09225b8eb322406',
'info_dict': {
'id': 'x33vw9',
'id': 'x2iuewm',
'ext': 'mp4',
'uploader': 'Amphora Alex and Van .',
'title': 'Tutoriel de Youtubeur"DL DES VIDEO DE YOUTUBE"',
'title': 'Steam Machine Models, Pricing Listed on Steam Store - IGN News',
'description': 'Several come bundled with the Steam Controller.',
'thumbnail': 're:^https?:.*\.(?:jpg|png)$',
'duration': 74,
'timestamp': 1425657362,
'upload_date': '20150306',
'uploader': 'IGN',
'uploader_id': 'xijv66',
'age_limit': 0,
'view_count': int,
'comment_count': int,
}
},
# Vevo video
@ -87,37 +101,106 @@ class DailymotionIE(DailymotionBaseInfoExtractor, SubtitlesInfoExtractor):
def _real_extract(self, url):
video_id = self._match_id(url)
url = 'http://www.dailymotion.com/video/%s' % video_id
# Retrieve video webpage to extract further information
request = self._build_request(url)
webpage = self._download_webpage(request, video_id)
# Extract URL, uploader and title from webpage
self.report_extraction(video_id)
# It may just embed a vevo video:
m_vevo = re.search(
r'<link rel="video_src" href="[^"]*?vevo.com[^"]*?video=(?P<id>[\w]*)',
webpage)
if m_vevo is not None:
vevo_id = m_vevo.group('id')
self.to_screen('Vevo video detected: %s' % vevo_id)
return self.url_result('vevo:%s' % vevo_id, ie='Vevo')
webpage = self._download_webpage_no_ff(
'https://www.dailymotion.com/video/%s' % video_id, video_id)
age_limit = self._rta_search(webpage)
video_upload_date = None
mobj = re.search(r'<div class="[^"]*uploaded_cont[^"]*" title="[^"]*">([0-9]{2})-([0-9]{2})-([0-9]{4})</div>', webpage)
if mobj is not None:
video_upload_date = mobj.group(3) + mobj.group(2) + mobj.group(1)
description = self._og_search_description(webpage) or self._html_search_meta(
'description', webpage, 'description')
view_count = str_to_int(self._search_regex(
[r'<meta[^>]+itemprop="interactionCount"[^>]+content="UserPlays:(\d+)"',
r'video_views_count[^>]+>\s+([\d\.,]+)'],
webpage, 'view count', fatal=False))
comment_count = int_or_none(self._search_regex(
r'<meta[^>]+itemprop="interactionCount"[^>]+content="UserComments:(\d+)"',
webpage, 'comment count', fatal=False))
player_v5 = self._search_regex(
r'playerV5\s*=\s*dmp\.create\([^,]+?,\s*({.+?})\);',
webpage, 'player v5', default=None)
if player_v5:
player = self._parse_json(player_v5, video_id)
metadata = player['metadata']
formats = []
for quality, media_list in metadata['qualities'].items():
for media in media_list:
media_url = media.get('url')
if not media_url:
continue
type_ = media.get('type')
if type_ == 'application/vnd.lumberjack.manifest':
continue
if type_ == 'application/x-mpegURL' or determine_ext(media_url) == 'm3u8':
formats.extend(self._extract_m3u8_formats(
media_url, video_id, 'mp4', m3u8_id='hls'))
else:
f = {
'url': media_url,
'format_id': quality,
}
m = re.search(r'H264-(?P<width>\d+)x(?P<height>\d+)', media_url)
if m:
f.update({
'width': int(m.group('width')),
'height': int(m.group('height')),
})
formats.append(f)
self._sort_formats(formats)
title = metadata['title']
duration = int_or_none(metadata.get('duration'))
timestamp = int_or_none(metadata.get('created_time'))
thumbnail = metadata.get('poster_url')
uploader = metadata.get('owner', {}).get('screenname')
uploader_id = metadata.get('owner', {}).get('id')
subtitles = {}
for subtitle_lang, subtitle in metadata.get('subtitles', {}).get('data', {}).items():
subtitles[subtitle_lang] = [{
'ext': determine_ext(subtitle_url),
'url': subtitle_url,
} for subtitle_url in subtitle.get('urls', [])]
return {
'id': video_id,
'title': title,
'description': description,
'thumbnail': thumbnail,
'duration': duration,
'timestamp': timestamp,
'uploader': uploader,
'uploader_id': uploader_id,
'age_limit': age_limit,
'view_count': view_count,
'comment_count': comment_count,
'formats': formats,
'subtitles': subtitles,
}
# vevo embed
vevo_id = self._search_regex(
r'<link rel="video_src" href="[^"]*?vevo.com[^"]*?video=(?P<id>[\w]*)',
webpage, 'vevo embed', default=None)
if vevo_id:
return self.url_result('vevo:%s' % vevo_id, 'Vevo')
# fallback old player
embed_page = self._download_webpage_no_ff(
'https://www.dailymotion.com/embed/video/%s' % video_id,
video_id, 'Downloading embed page')
timestamp = parse_iso8601(self._html_search_meta(
'video:release_date', webpage, 'upload date'))
info = self._parse_json(
self._search_regex(
r'var info = ({.*?}),$', embed_page,
'video info', flags=re.MULTILINE),
video_id)
embed_url = 'http://www.dailymotion.com/embed/video/%s' % video_id
embed_page = self._download_webpage(embed_url, video_id,
'Downloading embed page')
info = self._search_regex(r'var info = ({.*?}),$', embed_page,
'video info', flags=re.MULTILINE)
info = json.loads(info)
if info.get('error') is not None:
msg = 'Couldn\'t get video, Dailymotion says: %s' % info['error']['title']
raise ExtractorError(msg, expected=True)
@ -138,18 +221,10 @@ class DailymotionIE(DailymotionBaseInfoExtractor, SubtitlesInfoExtractor):
'width': width,
'height': height,
})
if not formats:
raise ExtractorError('Unable to extract video URL')
self._sort_formats(formats)
# subtitles
video_subtitles = self.extract_subtitles(video_id, webpage)
if self._downloader.params.get('listsubtitles', False):
self._list_available_subtitles(video_id, webpage)
return
view_count = str_to_int(self._search_regex(
r'video_views_count[^>]+>\s+([\d\.,]+)',
webpage, 'view count', fatal=False))
title = self._og_search_title(webpage, default=None)
if title is None:
@ -161,15 +236,17 @@ class DailymotionIE(DailymotionBaseInfoExtractor, SubtitlesInfoExtractor):
'id': video_id,
'formats': formats,
'uploader': info['owner.screenname'],
'upload_date': video_upload_date,
'timestamp': timestamp,
'title': title,
'description': description,
'subtitles': video_subtitles,
'thumbnail': info['thumbnail_url'],
'age_limit': age_limit,
'view_count': view_count,
'duration': info['duration']
}
def _get_available_subtitles(self, video_id, webpage):
def _get_subtitles(self, video_id, webpage):
try:
sub_list = self._download_webpage(
'https://api.dailymotion.com/video/%s/subtitles?fields=id,language,url' % video_id,
@ -179,7 +256,7 @@ class DailymotionIE(DailymotionBaseInfoExtractor, SubtitlesInfoExtractor):
return {}
info = json.loads(sub_list)
if (info['total'] > 0):
sub_lang_list = dict((l['language'], l['url']) for l in info['list'])
sub_lang_list = dict((l['language'], [{'url': l['url'], 'ext': 'srt'}]) for l in info['list'])
return sub_lang_list
self._downloader.report_warning('video doesn\'t have subtitles')
return {}
@ -194,23 +271,32 @@ class DailymotionPlaylistIE(DailymotionBaseInfoExtractor):
'url': 'http://www.dailymotion.com/playlist/xv4bw_nqtv_sport/1#video=xl8v3q',
'info_dict': {
'title': 'SPORT',
'id': 'xv4bw_nqtv_sport',
},
'playlist_mincount': 20,
}]
def _extract_entries(self, id):
video_ids = []
video_ids = set()
processed_urls = set()
for pagenum in itertools.count(1):
request = self._build_request(self._PAGE_TEMPLATE % (id, pagenum))
webpage = self._download_webpage(request,
id, 'Downloading page %s' % pagenum)
page_url = self._PAGE_TEMPLATE % (id, pagenum)
webpage, urlh = self._download_webpage_handle_no_ff(
page_url, id, 'Downloading page %s' % pagenum)
if urlh.geturl() in processed_urls:
self.report_warning('Stopped at duplicated page %s, which is the same as %s' % (
page_url, urlh.geturl()), id)
break
video_ids.extend(re.findall(r'data-xid="(.+?)"', webpage))
processed_urls.add(urlh.geturl())
for video_id in re.findall(r'data-xid="(.+?)"', webpage):
if video_id not in video_ids:
yield self.url_result('http://www.dailymotion.com/video/%s' % video_id, 'Dailymotion')
video_ids.add(video_id)
if re.search(self._MORE_PAGES_INDICATOR, webpage) is None:
break
return [self.url_result('http://www.dailymotion.com/video/%s' % video_id, 'Dailymotion')
for video_id in orderedSet(video_ids)]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
@ -227,7 +313,7 @@ class DailymotionPlaylistIE(DailymotionBaseInfoExtractor):
class DailymotionUserIE(DailymotionPlaylistIE):
IE_NAME = 'dailymotion:user'
_VALID_URL = r'https?://(?:www\.)?dailymotion\.[a-z]{2,3}/user/(?P<user>[^/]+)'
_VALID_URL = r'https?://(?:www\.)?dailymotion\.[a-z]{2,3}/(?!(?:embed|#|video|playlist)/)(?:(?:old/)?user/)?(?P<user>[^/]+)'
_PAGE_TEMPLATE = 'http://www.dailymotion.com/user/%s/%s'
_TESTS = [{
'url': 'https://www.dailymotion.com/user/nqtv',
@ -236,12 +322,24 @@ class DailymotionUserIE(DailymotionPlaylistIE):
'title': 'Rémi Gaillard',
},
'playlist_mincount': 100,
}, {
'url': 'http://www.dailymotion.com/user/UnderProject',
'info_dict': {
'id': 'UnderProject',
'title': 'UnderProject',
},
'playlist_mincount': 1800,
'expected_warnings': [
'Stopped at duplicated page',
],
'skip': 'Takes too long time',
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
user = mobj.group('user')
webpage = self._download_webpage(url, user)
webpage = self._download_webpage(
'https://www.dailymotion.com/user/%s' % user, user)
full_user = unescapeHTML(self._html_search_regex(
r'<a class="nav-image" title="([^"]+)" href="/%s">' % re.escape(user),
webpage, 'user'))
@ -252,3 +350,52 @@ class DailymotionUserIE(DailymotionPlaylistIE):
'title': full_user,
'entries': self._extract_entries(user),
}
class DailymotionCloudIE(DailymotionBaseInfoExtractor):
_VALID_URL_PREFIX = r'http://api\.dmcloud\.net/(?:player/)?embed/'
_VALID_URL = r'%s[^/]+/(?P<id>[^/?]+)' % _VALID_URL_PREFIX
_VALID_EMBED_URL = r'%s[^/]+/[^\'"]+' % _VALID_URL_PREFIX
_TESTS = [{
# From http://www.francetvinfo.fr/economie/entreprises/les-entreprises-familiales-le-secret-de-la-reussite_933271.html
# Tested at FranceTvInfo_2
'url': 'http://api.dmcloud.net/embed/4e7343f894a6f677b10006b4/556e03339473995ee145930c?auth=1464865870-0-jyhsm84b-ead4c701fb750cf9367bf4447167a3db&autoplay=1',
'only_matching': True,
}, {
# http://www.francetvinfo.fr/societe/larguez-les-amarres-le-cobaturage-se-developpe_980101.html
'url': 'http://api.dmcloud.net/player/embed/4e7343f894a6f677b10006b4/559545469473996d31429f06?auth=1467430263-0-90tglw2l-a3a4b64ed41efe48d7fccad85b8b8fda&autoplay=1',
'only_matching': True,
}]
@classmethod
def _extract_dmcloud_url(self, webpage):
mobj = re.search(r'<iframe[^>]+src=[\'"](%s)[\'"]' % self._VALID_EMBED_URL, webpage)
if mobj:
return mobj.group(1)
mobj = re.search(
r'<input[^>]+id=[\'"]dmcloudUrlEmissionSelect[\'"][^>]+value=[\'"](%s)[\'"]' % self._VALID_EMBED_URL,
webpage)
if mobj:
return mobj.group(1)
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage_no_ff(url, video_id)
title = self._html_search_regex(r'<title>([^>]+)</title>', webpage, 'title')
video_info = self._parse_json(self._search_regex(
r'var\s+info\s*=\s*([^;]+);', webpage, 'video info'), video_id)
# TODO: parse ios_url, which is in fact a manifest
video_url = video_info['mp4_url']
return {
'id': video_id,
'url': video_url,
'title': title,
'thumbnail': video_info.get('thumbnail_url'),
}

View File

@ -14,6 +14,10 @@ class DctpTvIE(InfoExtractor):
'display_id': 'videoinstallation-fuer-eine-kaufhausfassade',
'ext': 'flv',
'title': 'Videoinstallation für eine Kaufhausfassade'
},
'params': {
# rtmp download
'skip_download': True,
}
}

View File

@ -25,8 +25,9 @@ class DefenseGouvFrIE(InfoExtractor):
r"flashvars.pvg_id=\"(\d+)\";",
webpage, 'ID')
json_url = ('http://static.videos.gouv.fr/brightcovehub/export/json/'
+ video_id)
json_url = (
'http://static.videos.gouv.fr/brightcovehub/export/json/%s' %
video_id)
info = self._download_json(json_url, title, 'Downloading JSON config')
video_url = info['renditions'][0]['url']

Some files were not shown because too many files have changed in this diff Show More