1
0
mirror of https://github.com/yt-dlp/yt-dlp.git synced 2026-01-11 17:31:31 +00:00

Compare commits

...

202 Commits

Author SHA1 Message Date
pukkandan
3b1fe47d84 Release 2021.06.08 2021-06-08 20:13:41 +05:30
pukkandan
ed64ce5905 [build] Release yt-dlp.tar.gz
Closes #386
2021-06-08 20:12:00 +05:30
pukkandan
76a264ac9e Make outtmpl more robust and catch errors early 2021-06-08 20:11:00 +05:30
pukkandan
324ad82006 [utils] Generalize traverse_dict to traverse_obj 2021-06-08 19:26:44 +05:30
Nil Admirari
beb982bead [build,update] Add GNU-style SHA512 and prepare updater for simlar SHA256 (#383)
Authored by: nihil-admirari <50202386+nihil-admirari@users.noreply.github.com>

Related: #385
2021-06-08 16:04:07 +05:30
pukkandan
e88396f123 [build] Fix SHA256 2021-06-08 01:29:35 +05:30
pukkandan
46358f647d Update to ytdl-commit-c2350ca
Update MSVC 2010 redist URL
c2350cac24
2021-06-08 00:28:32 +05:30
pukkandan
bd99f6e648 Add field original_url with the user-inputted URL
So that they can be processed by `--parse-metadata` for example

`webpage_url` is the same, but may be modified by the extractor
2021-06-08 00:20:06 +05:30
pukkandan
ecb5419149 Make more fields available for --print when used with --flat-playlist 2021-06-08 00:17:53 +05:30
pukkandan
cf59cd4dcd [docs] Improve documentation of dependencies
Related: #348
2021-06-08 00:16:44 +05:30
Nil Admirari
56ce9eb832 [pyinst] Show Python version in EXE metadata (#384)
Authored by: nihil-admirari
2021-06-07 23:02:39 +05:30
pukkandan
89ee4cf8ae [viki] Fix extraction
Closes #381
Code from: 59e583f7e8
2021-06-07 12:42:58 +05:30
pukkandan
87ea7dfc04 Fix filename sanitization
Bug from 752cda3880
2021-06-06 19:36:28 +05:30
pukkandan
eb0f9d6838 [zoom] Extract transcripts as subtitles 2021-06-06 17:09:09 +05:30
pukkandan
d3d8d8184a [extractor] Fix pre-checking archive for some extractors
The `id` regex group must be present for `_match_id` and pre-checking archive to work correctly
2021-06-06 15:05:07 +05:30
pukkandan
e85a39717a [twitcasting] Add TwitCastingUserIE, TwitCastingLiveIE
Closes #374

Code adapted from: f1fb9222bb/youtube_dl/extractor/twitcasting.py
Authored by: pukkandan, nao20010128nao
2021-06-06 03:26:33 +05:30
MinePlayersPE
f2cd7060fc [vidio] Add VidioPremierIE and VidioLiveIE (#371)
Authored-by: MinePlayersPE
2021-06-06 01:25:26 +05:30
pukkandan
752cda3880 Fix and refactor prepare_outtmpl
The following tests would have failed previously:
%(id)d %(id)r
%(ext)s-%(ext|def)d
%(width|)d
%(id)r %(height)r
%(formats.0)r
%s
2021-06-06 00:59:04 +05:30
pukkandan
9d83ad93d0 [cleanup] Mark unused files 2021-06-06 00:59:04 +05:30
felix
cc52de4356 [cleanup] Point all shebang to python3 (#372)
Authored by: fstirlitz
2021-06-06 00:59:04 +05:30
pukkandan
14b17a551f Remove support for obsolete python versions 2021-06-06 00:59:04 +05:30
felix
2ec1759f9d [downloader/ffmpeg] Hide FFmpeg banner unless in verbose mode (#372)
Authored by: fstirlitz
2021-06-06 00:59:04 +05:30
felix
e2efe599aa [common] Fix FourCC fallback when parsing ISM (#372)
In some DASH manifests, the FourCC attribute is actually present,
but empty.  We thus apply the same fallback to 'AACL' that we do
when the attribute is entirely absent.

Authored by: fstirlitz
2021-06-06 00:59:04 +05:30
pukkandan
5e1dba8ed6 Remove duplicate file trovolive.py 2021-06-06 00:59:04 +05:30
pukkandan
bea742222f [youtube] Support shorts URL
Closes #375
2021-06-06 00:59:04 +05:30
pukkandan
e06ca6ddac [hls] Decrypt fragment when reading from disk
Closes #373
2021-06-05 18:51:15 +05:30
pukkandan
eb03899192 [version] update
:ci skip all
2021-06-01 21:08:44 +05:30
pukkandan
3de7c2ce9a Release 2021.06.01 2021-06-01 20:29:03 +05:30
pukkandan
bc6b9bcd65 [utils] Escape URLs in sanitized_Request, not sanitize_url
d2558234cf added escaping of URLs while sanitizing. However, `sanitize_url` may not always receive an actual URL.
Eg: When using `yt-dlp "search query" --default-search ytsearch`, `search query` gets escaped to `search%20query` before being prefixed with `ytsearch:` which is not the intended behavior. So the escaping is moved to `sanitized_Request` instead.
2021-06-01 20:29:02 +05:30
Ashish
6e6390321c [Hotstar] Add HotStarSeriesIE (#366)
Authored by: Ashish0804
2021-06-01 20:14:03 +05:30
pukkandan
4040428efc [update] Block further update for unsupported systems 2021-06-01 03:32:09 +05:30
pukkandan
cc1dfc9373 [cleanup] setup.py 2021-06-01 02:48:20 +05:30
pukkandan
14eb1ee1cb Update to ytdl-commit-d495292
[ard] Relax _VALID_URL and fix video ids
d495292852

Closes #357
2021-06-01 02:48:20 +05:30
coletdjnz
879e7199bb [archiveorg] Add YoutubeWebArchiveIE (#356)
Co-authored by: colethedj, pukkandan, alex-gedeon
2021-05-31 01:12:38 +00:00
pukkandan
d89da64b1d [hls,dash] When using concurrent_fragment_downloads, do not keep the fragment content in memory
Partial fix for #359
This is a temporary solution until #364 can be implemented
2021-05-30 23:01:49 +05:30
pukkandan
5dcd8e1d88 [hls] Disable external downloader for webtt 2021-05-30 23:00:57 +05:30
MinePlayersPE
10bb7e51e8 [vidio] Add login support (#362)
Authored by: MinePlayersPE
2021-05-30 20:19:14 +05:30
pukkandan
b0089e8992 [fancode] Add extractor (#316,#354)
Closes #269, #363

Authored by: rmsmachine
2021-05-30 19:34:39 +05:30
Ashish
a3ed14cbaf [Voot] Add VootSeriesIE (#351)
Authored by: Ashish0804
2021-05-30 16:45:42 +05:30
LE
9dee4df559 [Saitosan] Add new extractor (#350)
Closes #224
Authored by: llacb47
2021-05-30 14:32:18 +05:30
pukkandan
adddc50cbf [extractor] Functions to parse socket.io response as json
Authored by: pukkandan, llacb47
2021-05-30 14:22:42 +05:30
MinePlayersPE
46c43ffc9d [vidio] Support premium videos (#358)
Authored by: MinePlayersPE
2021-05-29 20:24:19 +05:30
pukkandan
37a3bb66a7 [extractor] Allow note=False when extracting manifests 2021-05-29 14:22:44 +05:30
pukkandan
337e0c62f8 [embedthumbnail] Correctly escape filename
Closes #352
The approach in [1] is faulty as can be seen in the test cases
1. bff857a8af
2021-05-29 02:31:14 +05:30
pukkandan
885cc0b75c [embedthumbnail] Embed if any thumbnail was downloaded, not just the best 2021-05-29 02:31:14 +05:30
pukkandan
46953e7e6e [youtube:playlist] fix bug 2021-05-29 02:31:13 +05:30
pukkandan
ae8f99e648 Remove None values from info.json 2021-05-29 02:31:13 +05:30
pukkandan
077c476276 [zee5] Fix m3u8 formats extension 2021-05-29 02:31:12 +05:30
pukkandan
835a1478b4 Write messages to stderr when both quiet and verbose 2021-05-29 02:31:10 +05:30
pukkandan
120fe5134a Pre-check archive and filters during playlist extraction
This makes `--break-on-existing` much faster.
It also helps `--break-on-reject` if the playlist extractor can extract the relevant fields
2021-05-29 02:12:09 +05:30
pukkandan
56a8fb4f77 Refactor __process_playlist using LazyList 2021-05-29 02:12:09 +05:30
pukkandan
55575225b4 [utils] Add __getitem__ for PagedList 2021-05-29 02:12:08 +05:30
pukkandan
483336e79e [utils] Add LazyList 2021-05-29 02:12:08 +05:30
pukkandan
c77495e3a4 [cleanup] _match_entry 2021-05-29 02:12:07 +05:30
rhsmachine
65af1839c6 [patreon] Support vimeo embeds (#349)
Authored by: rhsmachine
2021-05-27 22:14:43 +05:30
pukkandan
177877c544 [extractor] Always prefer native hls downloader by default
When the manifest is not downloadable by native downloader, it already is able to detect it and switch to `ffmpeg`. So there doesn't seem to be a reason anymore to use ffmpeg as the preferred downloader
2021-05-26 01:27:39 +05:30
pukkandan
b25522ba52 [update] Replace self without launching a subprocess in windows
Closes: #335, https://github.com/ytdl-org/youtube-dl/issues/28488, https://github.com/ytdl-org/youtube-dl/issues/5810, https://github.com/ytdl-org/youtube-dl/issues/5994

In windows, a running executable cannot be replaced. So, the old updater worked by launching a batch script and then exiting, so that the batch script can replace the executable. However, this caused the above-mentioned issues.

The new method takes advantage of the fact that while the executable cannot be replaced or deleted, it can still be renamed. The current update process on windows is as follows:
1. Delete `yt-dlp.exe.old` if it exists
2. Download the new version as `yt-dlp.exe.new`
3. Rename the running exe to `yt-dlp.exe.old`
4. Rename `yt-dlp.exe.new` to `yt-dlp.exe`
5. Open a shell that deletes `yt-dlp.exe.old` and terminate

While we still use a subprocess, the actual update is already done before the app terminates and the batch script does not print anything to stdout/stderr. So this solves all the above issues
2021-05-26 01:13:34 +05:30
pukkandan
c19bc311cb [cleanup] Refactor updater
The updater now uses `.update.run_update` and not `.update.update_self`.
Although I don't expect anyone to be using the updater via API, a wrapper `update_self` is provided for compatibility just in case
2021-05-26 01:13:08 +05:30
Hubert Hirtz
5435dcf96e Handle Basic Auth user:pass in URLs
Fixes https://github.com/ytdl-org/youtube-dl/issues/20258, https://github.com/ytdl-org/youtube-dl/issues/26211
Authored by: hhirtz, pukkandan
2021-05-24 03:38:02 +05:30
Oliver Freyermuth
f17c702270 [ard] Allow URLs without - before id
https://github.com/ytdl-org/youtube-dl/pull/29091

Authored by: olifre
2021-05-23 23:03:08 +05:30
pukkandan
3907333c5d [extractor] Skip subtitles without URI in m3u8 manifests
Closes #339

Authored by: hheimbuerger
2021-05-23 22:32:47 +05:30
pukkandan
acdecdfaef [embedthumbnail] Embed in mp4/m4a using mutagen
Code from: https://github.com/ytdl-org/youtube-dl/pull/23525
Co-authored by: tripulse , pukkandan
2021-05-23 22:16:35 +05:30
Ashish
09d18ad07e [Sonyliv] Add subtitle support (#342)
Authored by: Ashish0804
2021-05-23 21:26:27 +05:30
pukkandan
bc516a3f3c Sanitize and sort playlist thumbnails
Closes #341
2021-05-23 17:28:15 +05:30
Ashish
9572eaaa11 [ShemarooMe] Add extractor (#332)
Closes #307
Co-authored-by: Ashish0804, pukkandan
2021-05-23 12:42:50 +05:30
pukkandan
18e674b4f6 [ffmpeg] Download and merge in a single step if possible 2021-05-23 03:53:18 +05:30
pukkandan
8d68ab98a7 [youtube] Fix bug where not all hls formats were extracted
Bug introduced in 9297939ec3
2021-05-23 03:53:17 +05:30
Ashish
135e6b93f4 [SonyLIV] Add SonyLIVSeriesIE (#331)
Authored by: Ashish0804
2021-05-22 17:53:06 +05:30
king-millez
13a49340ed [telemundo] add extractor (#327)
Closes #284
Authored by: king-millez
2021-05-22 17:17:49 +05:30
pukkandan
81a23040eb [cleanup] Refactor ffmpeg convertors 2021-05-22 15:20:42 +05:30
pukkandan
857f63136d [videoconvertor] Generalize with remuxer and allow conditional recoding 2021-05-22 15:20:42 +05:30
louie-github
a927acb1ec [ThumbnailsConvertor] Support conversion to png and make it the default (#333)
PNG, being a lossless format, should be a better default here compared to JPG since we won't be compressing to a lossy format and losing some of the original image data
PNG is also supported for embedding in all the formats similar to JPEG

Authored by: louie-github
2021-05-21 23:39:48 +05:30
pukkandan
09f1580e2d [youtube] /live URLs should raise error if channel is not live
Fixes: https://github.com/ytdl-org/youtube-dl/issues/29090
2021-05-21 20:05:54 +05:30
pukkandan
cd59e22191 [version] update
:ci skip all
2021-05-20 21:15:41 +05:30
shirt
7237fdc6ce [build] Fix pefile version for x86
Authored by: shirt-dev
2021-05-20 21:15:41 +05:30
pukkandan
0fdf490d33 Release 2021.05.20 2021-05-20 21:13:19 +05:30
pukkandan
b73612a254 Update to ytdl-commit-dfbbe29
[redbulltv] fix embed data extraction
dfbbe2902f
2021-05-20 21:13:18 +05:30
king-millez
5014558ab9 [parlview] Add extractor (#322)
Authored by: king-millez
2021-05-20 18:35:37 +05:30
pukkandan
28b0eb0f65 [cleanup] See desc
* Remove struct from `embedthumbnail`
* Use bullet lists in readme where numbered list don't make sense
* Fix error introduced in 9c2b75b561 when `ie_result` is `None`
2021-05-20 18:02:58 +05:30
pukkandan
95131b2176 [embedthumbnail] Add flac support and refactor mutagen code
https://github.com/ytdl-org/youtube-dl/pull/28894, https://github.com/ytdl-org/youtube-dl/pull/24310
Authored by: tripulse
2021-05-20 17:51:33 +05:30
pukkandan
2305e2e5c9 [options] Alias --write-comments, --no-write-comments
Closes: #264
2021-05-20 15:56:57 +05:30
coletdjnz
00ae27690d [youtube] Add html5=1 param to get_video_info page requests (#329)
Workaround for #319, https://github.com/ytdl-org/youtube-dl/issues/29086
Authored by: colethedj
2021-05-20 15:56:57 +05:30
pukkandan
9d5d4d64f8 [youtube] Better message when login required 2021-05-20 15:55:55 +05:30
king-millez
98784ef8d6 [audius:artist] Add extractor (#323)
Authored by: king-millez
2021-05-20 15:55:55 +05:30
pukkandan
d3fc8074a4 [youtube] Sort audio-only formats correctly
Closes #317
2021-05-19 18:29:20 +05:30
pukkandan
9c2b75b561 Field additional_urls to download additional videos from metadata 2021-05-19 18:11:15 +05:30
pukkandan
856bb8f99d [downloader] Fix write_debug 2021-05-19 17:34:17 +05:30
pukkandan
af32f40bf5 [test] Fix test_YoutubeDL.TestYoutubeDL
Test `test_ignoreerrors_for_playlist_with_url_transparent_iterable_entries` was broken due to `__original_infodict` being added to the dict
2021-05-19 17:00:40 +05:30
pukkandan
4ec82a72bb Ensure post_extract and pre_process only run once
Previously, they ran once for each format requested
2021-05-19 16:48:22 +05:30
pukkandan
07cce701de [cleanup] linter, code formatting and readme 2021-05-19 16:48:20 +05:30
king-millez
74e001af1d [tenplay] Fix extractor (#314)
Authored by: king-millez
2021-05-19 16:43:34 +05:30
pukkandan
ff2751ac9c [youtube] Always extract maxresdefault thumbnail
Fixes: https://github.com/ytdl-org/youtube-dl/issues/29049
2021-05-18 19:31:17 +05:30
pukkandan
abcdd12b26 [youtube:tab] Support youtube music MP pages 2021-05-18 19:31:08 +05:30
pukkandan
18db754858 [youtube:tab] Redirect UC channels that doesn't have a videos tab
Many topic URLs don't have a videos tab, but has an equivalent `UU` playlist.
If there is no playlist, fallback to using channel page
2021-05-18 19:31:07 +05:30
pukkandan
fe03a6cdc8 [youtube:tab] Support youtube music VL and browse pages 2021-05-18 19:31:06 +05:30
pukkandan
cd684175ad [youtube:tab] Support channel search
Fixes: https://github.com/ytdl-org/youtube-dl/issues/29071
2021-05-18 19:30:21 +05:30
pukkandan
da692b7920 [cleanup] youtube tests 2021-05-18 18:10:15 +05:30
pukkandan
95c01b6c16 [youtube:tab] Show alerts only from the final webpage 2021-05-18 18:09:04 +05:30
pukkandan
6911e11edd [test:download] Only extract enough videos for playlist_mincount 2021-05-18 18:08:55 +05:30
pukkandan
5112f26a60 Add pl_thumbnail outtmpl key for playlist thumbnails
This should have been implemented in 681de68e9d, but I forgot
2021-05-18 17:12:20 +05:30
pukkandan
a06916d98e [extractor] Add write_debug and get_param 2021-05-17 18:59:51 +05:30
pukkandan
681de68e9d Write thumbnail of playlist
Related: https://github.com/ytdl-org/youtube-dl/pull/28872, https://github.com/ytdl-org/youtube-dl/pull/28860
This is slightly different from the above PRs in that this downloads the playlist's thumbnail instead of the uploader's profile picture. But for youtube channel URLs these are the same
2021-05-17 18:24:17 +05:30
pukkandan
7aee40c13c Fix bug in listing subtitles
Bug introduced by: 2412044c90
2021-05-17 18:24:16 +05:30
coletdjnz
9297939ec3 [Youtube] Extract more formats for music.youtube URLs (#311)
Based on: https://github.com/ytdl-org/youtube-dl/pull/28778, https://github.com/ytdl-org/youtube-dl/pull/26160

Co-authored-by: craftingmod, colethedj, pukkandan
2021-05-15 20:08:47 +05:30
pukkandan
774d79cc4c [youtube] Add language names
Co-authored by: nixxo, tpikonen
Based on: https://github.com/ytdl-org/youtube-dl/pull/26112
Closes: #310
2021-05-15 19:27:53 +05:30
pukkandan
2412044c90 Add field name for subtitles
Co-authored by: pukkandan, tpikonen

Based on: #310, https://github.com/ytdl-org/youtube-dl/pull/26112
2021-05-15 19:27:52 +05:30
pukkandan
120916dac2 [youtube] multiple subtitles in same language
Fixes: https://github.com/ytdl-org/youtube-dl/issues/21164
Related: #310, https://github.com/ytdl-org/youtube-dl/pull/26112
2021-05-15 19:27:48 +05:30
pukkandan
fe346461ff Fix --check-formats when there is network error 2021-05-15 19:26:01 +05:30
pukkandan
d2a1fad968 [compat] Fix py2 2021-05-14 13:35:13 +05:30
pukkandan
0fb983f62d [youtube] Extract audio language 2021-05-14 13:15:48 +05:30
pukkandan
53c18592d3 Add option --print
Deprecates: `--get-description`, `--get-duration`, `--get-filename`, `--get-format`, `--get-id`, `--get-thumbnail`, `--get-title`, `--get-url`
Closes #295
2021-05-14 13:15:47 +05:30
pukkandan
e632bce2e4 [options] Refactor callbacks 2021-05-14 13:15:47 +05:30
pukkandan
0760b0a7e2 Standardize write_debug 2021-05-14 13:15:29 +05:30
pukkandan
d908aa636a [cleanup] Fix typos 2021-05-11 23:34:40 +05:30
pukkandan
3d89341b47 [common] bugfix for when compat_opts is not given 2021-05-11 23:29:26 +05:30
pukkandan
d8ec40b39f [rmcdecouverte] Generalize _VALID_URL
Closes #291
2021-05-11 18:57:55 +05:30
pukkandan
4171221823 Add compat-option no-attach-infojson 2021-05-11 14:25:31 +05:30
pukkandan
eaeca38fc4 [version] update :ci skip all 2021-05-11 13:42:58 +05:30
pukkandan
fac988053f Release 2021.05.11
* and some documentation improvements
2021-05-11 13:35:05 +05:30
pukkandan
61241abbb0 [generic] Respect the encoding in manifest 2021-05-11 13:32:03 +05:30
pukkandan
53ed7066ab Option --compat-options to revert some of yt-dlp's changes
* Deprecates `--list-formats-as-table`, `--list-formats-old`
2021-05-11 13:30:48 +05:30
pukkandan
a61f4b287b Deprecate support for python versions < 3.6
Closes #267
2021-05-09 04:32:23 +05:30
pukkandan
486fb17975 Remove -l, -t, -A completely and disable --auto-number, --title, --literal, --id 2021-05-09 04:22:29 +05:30
pukkandan
2f567473c6 [Plugins] Prioritize plugins over standard extractors
and prevent plugins from overwriting the standard extractor classes

Closes #304
2021-05-09 04:22:27 +05:30
pukkandan
000ee7ef34 [fragment] Make sure first segment is not skipped 2021-05-09 04:22:26 +05:30
pukkandan
41d1cca328 Update to ytdl-commit-a726009
[blinkx] Remove extractor
a726009987
2021-05-06 21:31:20 +05:30
pukkandan
717297545b Fix playlist_index and add playlist_autonumber (#302)
Now `playlist_index` is always the position of the video in the actual playlist and `playlist_autonumber` is the position of the item in the playlist queue
2021-05-06 20:56:19 +05:30
pukkandan
e8e738406a Add experimental option --check-formats to test the URLs before format selection 2021-05-06 20:50:44 +05:30
pukkandan
e625be0d10 Improve output template internal formatting
* Allow slicing lists/strings using `field.start:end:step`
* A field can also be used as offset like `field1+num+field2`
* A default value can be given using `field|default`
* Capture all format strings and set it to `None` if invalid. This prevents invalid fields from causing errors
2021-05-06 20:28:58 +05:30
pukkandan
12e73423f1 [plutotv] Fix format extraction for some urls
* And fallback to the first urls if ad-free urls can't be found
Closes #299
2021-05-06 20:28:57 +05:30
pukkandan
7700b37f39 [plutotv] Extract subtitles from manifests 2021-05-06 20:28:56 +05:30
Ashish
c28cfda81f [SonyLiv] Fix title and series extraction (#301)
Authored by: Ashish0804
2021-05-06 20:27:43 +05:30
pukkandan
848887eb7a [downloader] Fix quiet and to_stderr 2021-05-04 22:38:10 +05:30
pukkandan
3158150cb7 [utils] Add network_exceptions 2021-05-04 22:36:18 +05:30
pukkandan
6ef6bcbd6b [fragment] Ensure the file is closed on error 2021-05-04 22:27:44 +05:30
pukkandan
06425e9621 [blinkx] Minor fix
Fixes: https://github.com/ytdl-org/youtube-dl/issues/28941
2021-05-04 22:27:44 +05:30
pukkandan
4d224a3022 [embedthumbnail] Fix bug where jpeg thumbnails were converted again
Closes #297
2021-05-04 22:18:40 +05:30
pukkandan
f59ae58163 Fix number of digits in %(playlist_index)s
When used with `--playlist-(items|start|end)`, the number of digits should depend on the last index in the playlist, not number of items
2021-05-03 22:49:05 +05:30
pukkandan
0d1bb027aa Move option warnings to YoutubeDL
Previously, these warnings did not obey `--no-warnings` and did not output colors
2021-05-03 22:49:04 +05:30
pukkandan
4cd0a709aa Fix preload_download_archive writing verbose message to stdout
* And move it after all deprecated warnings
2021-05-03 22:49:03 +05:30
pukkandan
1815d1028b [zee5] Fix py2 compatibility 2021-05-03 22:49:03 +05:30
The Hatsune Daishi
0fa9a1e236 [whowatch] Add extractor #292
closes #223

Authored by: nao20010128nao 
Modified from: 9e4a0e061a/youtube_dl/extractor/whowatch.py
2021-05-02 19:43:37 +05:30
pukkandan
eb55bad5a0 [aria2c] Fix whitespace being stripped off
Closes #276
2021-05-02 14:03:13 +05:30
pukkandan
cc0ec3e161 Do not strip out whitespaces in -o and -P
Related: https://github.com/yt-dlp/yt-dlp/issues/276#issuecomment-827361652
2021-05-02 14:03:12 +05:30
pukkandan
80185155a1 [ukcolumn] Add Extractor
Closes #287
2021-05-02 13:57:50 +05:30
pukkandan
c755f1901f [CBS] Improve _VALID_URL to support movies
Closes #290
Tested by: BeeMuffins
2021-05-01 21:32:14 +05:30
pukkandan
68b91dc905 [youtube] Add oembed to reserved names 2021-05-01 21:24:31 +05:30
pukkandan
88f06afc0c [rmcdecouverte] Improve _VALID_URL
Closes #291
2021-05-01 21:24:31 +05:30
CXwudi
40078a55e2 [niconico] Fix bug in thumbnail extraction #289
Bug from: 6b1d8c1e30
Authored by: CXwudi
2021-05-01 19:35:47 +05:30
pukkandan
d2558234cf [utils] Escape URL while sanitizing
Closes #263

While this fixes the issue in question, it does not try to address the root-cause of the problem
Refer: 915f911e36, f5fa042c82
2021-04-29 05:20:50 +05:30
pukkandan
f5fa042c82 Revert "[utils] Encode URLs in YoutubeDLCookieProcessor"
This reverts commit 915f911e36.

When the request is copied, `unredirected_hdrs` are not copied, which causes issues elsewhere
Reopens #263
2021-04-29 05:20:18 +05:30
pukkandan
07e4a40a9a [crackle] Improve extraction (See desc)
Closes #282

* Refactor authorization as an extension to `_download_json`
* Better error messages and warnings
* Respect `--ignore-no-formats-error`
* Extract subtitles from manifests
* Try with crackle's geo-location service if all hard-coded countries fail
2021-04-29 05:20:16 +05:30
pukkandan
e28f1c0ae8 [cleanup] Fix linter and some typos
* Also remove inconsistent use of `"` in setup.py
2021-04-28 19:59:40 +05:30
pukkandan
ef39f8600a [curiositystream] Fix collections
Closes #277

* A bug with authentication was reported in <https://github.com/yt-dlp/yt-dlp/issues/277#issuecomment-828254721> but cannot be tested without an account
2021-04-28 19:29:33 +05:30
pukkandan
2291dbce2a [niconico] Fix HLS formats
Closes #171

* The structure of the API JSON was changed
* Smile Video seems to be no longer available. So remove the warning
* Move ping to downloader
* Change heartbeat interval to 40sec
* Remove unnecessary API headers

Authored-by: CXwudi, tsukumijima, nao20010128nao, pukkandan
Tested by: tsukumijima
2021-04-28 19:18:29 +05:30
pukkandan
58f197b76c Revert "[core] be able to hand over id and title using url_result"
This reverts commit 0704d2224b.

This is a commit from `youtube-dlc`. It is not clear what the original purpose of this was. It seems to be a way for extractors to pass `title` and `id` through when the entry is processed by another extractor

* But `title` can already be passed through using `url_transparent`
* `id` is never supposed to be passed through since it could cause issues with archiving
2021-04-28 19:18:06 +05:30
pukkandan
895b0931e5 [youtube:tab] Detect playlists inside community posts 2021-04-28 19:18:06 +05:30
pukkandan
1ad047d0f7 [nebula] Move to nebula.app
Closes #272
Tested by: Lamieur
2021-04-28 19:18:06 +05:30
pukkandan
be6202f12b Subtitle extraction from streaming media manifests #247
Authored by fstirlitz
Modified from: https://github.com/ytdl-org/youtube-dl/pull/6144

Closes: #73
Fixes:
https://github.com/ytdl-org/youtube-dl/issues/6106
https://github.com/ytdl-org/youtube-dl/issues/14977
https://github.com/ytdl-org/youtube-dl/issues/21438
https://github.com/ytdl-org/youtube-dl/issues/23609
https://github.com/ytdl-org/youtube-dl/issues/28132

Might also fix (untested):
https://github.com/ytdl-org/youtube-dl/issues/15424
https://github.com/ytdl-org/youtube-dl/issues/18267
https://github.com/ytdl-org/youtube-dl/issues/23899
https://github.com/ytdl-org/youtube-dl/issues/24375
https://github.com/ytdl-org/youtube-dl/issues/24595
https://github.com/ytdl-org/youtube-dl/issues/27899

Related:
https://github.com/ytdl-org/youtube-dl/issues/22379
https://github.com/ytdl-org/youtube-dl/pull/24517
https://github.com/ytdl-org/youtube-dl/pull/24886
https://github.com/ytdl-org/youtube-dl/pull/27215

Notes:
* The functions `extractor.common._extract_..._formats` are still kept for compatibility
* Only some extractors have currently been moved to using `_extract_..._formats_and_subtitles`
* Direct subtitle manifests (without a master) are not supported and are wrongly identified as containing video formats
* AES support is untested
* The fragmented TTML subtitles extracted from DASH/ISM are valid, but are unsupported by `ffmpeg` and most video players
    * Their XML fragments can be dumped using `ffmpeg -i in.mp4 -f data -map 0 -c copy out.ttml`.
        Once the unnecessary headers are stripped out of this, it becomes a valid self-contained ttml file
    * The ttml subs downloaded from DASH manifests can also be directly opened with <https://github.com/SubtitleEdit>
* Fragmented WebVTT files extracted from DASH/ISM are also unsupported by most tools
    * Unlike the ttml files, the XML fragments of these cannot be dumped using `ffmpeg`
    * The webtt subs extracted from DASH can be parsed by <https://github.com/gpac/gpac>
    * But validity of the those extracted from ISM are untested
2021-04-28 19:02:43 +05:30
Felix S
e8f834cd8d [threeqsdn] Extract subtitles from streaming manifests 2021-04-28 17:24:50 +05:30
Felix S
e0e624ca7f [canvas] Extract subtitles from streaming manifests 2021-04-28 17:24:19 +05:30
Felix S
ec4f374c05 [wat] Extract subtitles from streaming manifests 2021-04-28 17:24:08 +05:30
Felix S
c811e8d8bd [atresplayer] Extract subtitles from streaming manifests 2021-04-28 17:23:56 +05:30
Felix S
b2cd5da460 [francetv] Extract subtitles from the HLS manifest 2021-04-28 17:23:47 +05:30
Felix S
2de3b21e05 [uplynk] Extract subtitles from HLS manifests 2021-04-28 17:23:37 +05:30
Felix S
4bed436371 [twitter] Extract subtitles from HLS manifests 2021-04-28 17:23:27 +05:30
Felix S
efe9dba595 [srgssr] Extract subtitles from HLS manifests 2021-04-28 17:23:16 +05:30
Felix S
47f4203dd3 [nytimes] Extract subtitles from HLS manifests 2021-04-28 17:23:05 +05:30
Felix S
015c10aeec [roosterteeth] Use common code for subtitle extraction 2021-04-28 17:22:56 +05:30
Felix S
a00d781b73 [elonet] Use common code for subtitle extraction 2021-04-28 17:22:45 +05:30
Felix S
0c541b563f [tv4] Extract subtitles from streaming manifests 2021-04-28 17:22:36 +05:30
Felix S
64a5cf7929 [byutv] Extract subtitles from streaming manifests 2021-04-28 17:22:27 +05:30
Felix S
7a450a3b1c [generic] Extract subtitles from direct SSTR manifest links 2021-04-28 17:22:18 +05:30
Felix S
7de27caf16 [generic] Extract subtitles from direct DASH manifest links 2021-04-28 17:22:07 +05:30
Felix S
c26326c1be [generic] Extract subtitles from direct HLS manifest links 2021-04-28 17:21:55 +05:30
Felix S
66a1b8643a [downloader/ism] Support muxing TTML subtitles 2021-04-28 17:21:45 +05:30
Felix S
15828bcf25 [downloader/hls] Handle MPEG-2 PES timestamp overflow 2021-04-28 17:21:35 +05:30
Felix S
333217f43e [downloader/hls] Remove duplicate cues using a sliding window of candidates 2021-04-28 17:21:26 +05:30
Felix S
4a2f19abbd [downloader/hls] Assemble single-file WebVTT subtitles from HLS segments 2021-04-28 17:21:14 +05:30
Felix S
5fbcebed8c [test] Test SSTR manifest parsing 2021-04-28 17:21:01 +05:30
Felix S
becdc7f82c [test] Test subtitle extraction from DASH manifests 2021-04-28 17:20:49 +05:30
Felix S
73b9088a1c [test] Test subtitle extraction from HLS manifests 2021-04-28 17:20:39 +05:30
Felix S
f6a1d69a87 [extractor/common] Extend _extract_akamai_formats to also extract subtitle tracks 2021-04-28 17:20:29 +05:30
Felix S
fd76a14259 [extractor/common, downloader/ism] Extract SSTR subtitle tracks
_parse_ism_formats was extended into _parse_ism_formats_and_subtitles;
all direct users were updated, though _extract_ism_formats was left
as a compatibility wrapper.

The SSTR downloader was also modified in order to prepare for muxing
subtitle streams, although no support for any subtitle codecs was
added in this commit.
2021-04-28 17:20:20 +05:30
Felix S
171e59edd4 [extractor/common] Extract DASH subtitle tracks
_extract_mpd_formats and _parse_mpd_formats were extended into
_…_formats_and_subtitles; wrappers with old names are provided
for compatibility.
2021-04-28 17:20:11 +05:30
Felix S
a0c3b2d5cf [extractor/common] Extract HLS subtitle tracks
_extract_m3u8_formats is renamed to _extract_m3u8_formats_and_subtitles
and extended to handle subtitle tracks instead of skipping them;
a wrapper with the old name is provided for compatibility.

_parse_m3u8_formats is likewise renamed and extended, but without adding
the compatibility wrapper; the test suite is adjusted to test the enhanced
method instead.
2021-04-28 17:19:57 +05:30
Felix S
19bb39202d [extractor/common] Generalise _merge_subtitles
This allows modifying a subtitles dictionary in-place.
2021-04-28 17:19:46 +05:30
Felix S
d4553567d2 [downloader/ism] Prevent writing the header again when resuming an interrupted download 2021-04-28 17:19:37 +05:30
Felix S
4d49884c58 [downloader/fragment] Allow persisting extra state when a download is interrupted 2021-04-28 17:19:31 +05:30
Felix S
5873d4ccdd [utils] Improve bug_report_message
Add an optional argument specifying the text that should go before
the message.
2021-04-28 17:19:23 +05:30
Hadi0609
db9a564b6a [zee5] Fix extraction for some URLs (#279)
Closes: #278
2021-04-28 14:51:54 +05:30
Felix S
c72967d5de [mediasite] Generalize URL pattern (#275)
Authored by: fstirlitz
2021-04-26 17:23:20 +05:30
pukkandan
598d185db1 Fix case sensitivity of format selector
Bug introduced in f8d4ad9ab0
2021-04-26 10:56:56 +05:30
pukkandan
b982cbdd0e [limelight] Obey allow_unplayable_formats 2021-04-26 10:56:55 +05:30
pukkandan
6a04a74e8b [FormatSort] Fix for when some formats have quality and others don't 2021-04-26 10:56:54 +05:30
pukkandan
88728713c8 Py2 compatibility for FileNotFoundError 2021-04-26 10:56:53 +05:30
CXwudi
6b1d8c1e30 [niconico] Fix title and thumbnail extraction (#273)
Authored by: CXwudi
2021-04-26 08:23:57 +05:30
Ashish
87c3d06271 [Mxplayer] Add MxplayerShowIE (#270)
Authored by: Ashish0804
2021-04-26 08:12:51 +05:30
pukkandan
915f911e36 [utils] Encode URLs in YoutubeDLCookieProcessor
Closes #263
2021-04-24 19:20:07 +05:30
pukkandan
cf9d6cfb0c [tubi] Raise "no video formats" error when video url is empty
Related: #266
2021-04-24 17:52:33 +05:30
pukkandan
bbed5763f1 [francetvinfo] Improve video id extraction
Closes #261
2021-04-23 00:01:09 +05:30
pukkandan
ca0b91b39e [version] update :ci skip all 2021-04-22 17:30:36 +05:30
234 changed files with 7643 additions and 2417 deletions

View File

@@ -21,7 +21,7 @@ assignees: ''
<!--
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.11. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.06.01. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/yt-dlp/yt-dlp.
- Search the bugtracker for similar issues: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
@@ -29,7 +29,7 @@ Carefully read and work through this check list in order to prevent the most com
-->
- [ ] I'm reporting a broken site support
- [ ] I've verified that I'm running yt-dlp version **2021.04.11**
- [ ] I've verified that I'm running yt-dlp version **2021.06.01**
- [ ] I've checked that all provided URLs are alive and playable in a browser
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
- [ ] I've searched the bugtracker for similar issues including closed ones
@@ -44,7 +44,7 @@ Add the `-v` flag to your command line you run yt-dlp with (`yt-dlp -v <your com
[debug] User config: []
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
[debug] yt-dlp version 2021.04.11
[debug] yt-dlp version 2021.06.01
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
[debug] Proxy map: {}

View File

@@ -21,7 +21,7 @@ assignees: ''
<!--
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.11. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.06.01. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
- Make sure that site you are requesting is not dedicated to copyright infringement, see https://github.com/yt-dlp/yt-dlp. yt-dlp does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights.
- Search the bugtracker for similar site support requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
@@ -29,7 +29,7 @@ Carefully read and work through this check list in order to prevent the most com
-->
- [ ] I'm reporting a new site support request
- [ ] I've verified that I'm running yt-dlp version **2021.04.11**
- [ ] I've verified that I'm running yt-dlp version **2021.06.01**
- [ ] I've checked that all provided URLs are alive and playable in a browser
- [ ] I've checked that none of provided URLs violate any copyrights
- [ ] I've searched the bugtracker for similar site support requests including closed ones

View File

@@ -21,13 +21,13 @@ assignees: ''
<!--
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.11. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.06.01. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- Search the bugtracker for similar site feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
-->
- [ ] I'm reporting a site feature request
- [ ] I've verified that I'm running yt-dlp version **2021.04.11**
- [ ] I've verified that I'm running yt-dlp version **2021.06.01**
- [ ] I've searched the bugtracker for similar site feature requests including closed ones

View File

@@ -21,7 +21,7 @@ assignees: ''
<!--
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.11. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.06.01. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/yt-dlp/yt-dlp.
- Search the bugtracker for similar issues: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
@@ -30,7 +30,7 @@ Carefully read and work through this check list in order to prevent the most com
-->
- [ ] I'm reporting a broken site support issue
- [ ] I've verified that I'm running yt-dlp version **2021.04.11**
- [ ] I've verified that I'm running yt-dlp version **2021.06.01**
- [ ] I've checked that all provided URLs are alive and playable in a browser
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
- [ ] I've searched the bugtracker for similar bug reports including closed ones
@@ -46,7 +46,7 @@ Add the `-v` flag to your command line you run yt-dlp with (`yt-dlp -v <your com
[debug] User config: []
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
[debug] yt-dlp version 2021.04.11
[debug] yt-dlp version 2021.06.01
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
[debug] Proxy map: {}

View File

@@ -21,13 +21,13 @@ assignees: ''
<!--
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.04.11. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.06.01. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- Search the bugtracker for similar feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
-->
- [ ] I'm reporting a feature request
- [ ] I've verified that I'm running yt-dlp version **2021.04.11**
- [ ] I've verified that I'm running yt-dlp version **2021.06.01**
- [ ] I've searched the bugtracker for similar feature requests including closed ones

View File

@@ -7,13 +7,13 @@ on:
jobs:
build_unix:
runs-on: ubuntu-latest
outputs:
ytdlp_version: ${{ steps.bump_version.outputs.ytdlp_version }}
upload_url: ${{ steps.create_release.outputs.upload_url }}
sha2_unix: ${{ steps.sha2_file.outputs.sha2_unix }}
sha256_unix: ${{ steps.sha256_file.outputs.sha256_unix }}
sha512_unix: ${{ steps.sha512_file.outputs.sha512_unix }}
steps:
- uses: actions/checkout@v2
@@ -29,7 +29,7 @@ jobs:
- name: Print version
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
- name: Run Make
run: make
run: make all tar
- name: Create Release
id: create_release
uses: actions/create-release@v1
@@ -44,7 +44,7 @@ jobs:
draft: false
prerelease: false
- name: Upload yt-dlp Unix binary
id: upload-release-asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -53,9 +53,21 @@ jobs:
asset_path: ./yt-dlp
asset_name: yt-dlp
asset_content_type: application/octet-stream
- name: Upload Source tar
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./yt-dlp.tar.gz
asset_name: yt-dlp.tar.gz
asset_content_type: application/gzip
- name: Get SHA2-256SUMS for yt-dlp
id: sha2_file
run: echo "::set-output name=sha2_unix::$(sha256sum yt-dlp | awk '{print $1}')"
id: sha256_file
run: echo "::set-output name=sha256_unix::$(sha256sum yt-dlp | awk '{print $1}')"
- name: Get SHA2-512SUMS for yt-dlp
id: sha512_file
run: echo "::set-output name=sha512_unix::$(sha512sum yt-dlp | awk '{print $1}')"
- name: Install dependencies for pypi
env:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
@@ -74,13 +86,12 @@ jobs:
twine upload dist/*
build_windows:
runs-on: windows-latest
needs: build_unix
outputs:
sha2_windows: ${{ steps.sha2_file_win.outputs.sha2_windows }}
needs: build_unix
sha256_windows: ${{ steps.sha256_file_win.outputs.sha256_windows }}
sha512_windows: ${{ steps.sha512_file_win.outputs.sha512_windows }}
steps:
- uses: actions/checkout@v2
@@ -110,17 +121,19 @@ jobs:
asset_name: yt-dlp.exe
asset_content_type: application/vnd.microsoft.portable-executable
- name: Get SHA2-256SUMS for yt-dlp.exe
id: sha2_file_win
run: echo "::set-output name=sha2_windows::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA256).Hash.ToLower())"
id: sha256_file_win
run: echo "::set-output name=sha256_windows::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA256).Hash.ToLower())"
- name: Get SHA2-512SUMS for yt-dlp.exe
id: sha512_file_win
run: echo "::set-output name=sha512_windows::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA512).Hash.ToLower())"
build_windows32:
runs-on: windows-latest
needs: [build_unix, build_windows]
outputs:
sha2_windows32: ${{ steps.sha2_file_win32.outputs.sha2_windows32 }}
needs: [build_unix, build_windows]
sha256_windows32: ${{ steps.sha256_file_win32.outputs.sha256_windows32 }}
sha512_windows32: ${{ steps.sha512_file_win32.outputs.sha512_windows32 }}
steps:
- uses: actions/checkout@v2
@@ -132,7 +145,7 @@ jobs:
- name: Upgrade pip and enable wheel support
run: python -m pip install pip==19.1.1 setuptools==43.0.0 wheel==0.33.6
- name: Install Requirements for 32 Bit
run: pip install pyinstaller==3.5 mutagen==1.42.0 pycryptodome==3.9.4
run: pip install pyinstaller==3.5 mutagen==1.42.0 pycryptodome==3.9.4 pefile==2019.4.18
- name: Bump version
id: bump_version
run: python devscripts/update-version.py
@@ -151,20 +164,28 @@ jobs:
asset_name: yt-dlp_x86.exe
asset_content_type: application/vnd.microsoft.portable-executable
- name: Get SHA2-256SUMS for yt-dlp_x86.exe
id: sha2_file_win32
run: echo "::set-output name=sha2_windows32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA256).Hash.ToLower())"
id: sha256_file_win32
run: echo "::set-output name=sha256_windows32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA256).Hash.ToLower())"
- name: Get SHA2-512SUMS for yt-dlp_x86.exe
id: sha512_file_win32
run: echo "::set-output name=sha512_windows32::$((Get-FileHash dist\yt-dlp_x86.exe -Algorithm SHA512).Hash.ToLower())"
finish:
runs-on: ubuntu-latest
needs: [build_unix, build_windows, build_windows32]
steps:
- name: Make SHA2-256SUMS file
env:
SHA2_WINDOWS: ${{ needs.build_windows.outputs.sha2_windows }}
SHA2_WINDOWS32: ${{ steps.sha2_file_win32.outputs.sha2_windows32 }}
SHA2_UNIX: ${{ needs.build_unix.outputs.sha2_unix }}
SHA256_WINDOWS: ${{ needs.build_windows.outputs.sha256_windows }}
SHA256_WINDOWS32: ${{ needs.build_windows32.outputs.sha256_windows32 }}
SHA256_UNIX: ${{ needs.build_unix.outputs.sha256_unix }}
YTDLP_VERSION: ${{ needs.build_unix.outputs.ytdlp_version }}
run: |
echo "version:${env:YTDLP_VERSION}" >> SHA2-256SUMS
echo "yt-dlp.exe:${env:SHA2_WINDOWS}" >> SHA2-256SUMS
echo "yt-dlp_x86.exe:${env:SHA2_WINDOWS32}" >> SHA2-256SUMS
echo "yt-dlp:${env:SHA2_UNIX}" >> SHA2-256SUMS
echo "version:${{ env.YTDLP_VERSION }}" >> SHA2-256SUMS
echo "yt-dlp.exe:${{ env.SHA256_WINDOWS }}" >> SHA2-256SUMS
echo "yt-dlp_x86.exe:${{ env.SHA256_WINDOWS32 }}" >> SHA2-256SUMS
echo "yt-dlp:${{ env.SHA256_UNIX }}" >> SHA2-256SUMS
- name: Upload 256SUMS file
id: upload-sums
uses: actions/upload-release-asset@v1
@@ -175,3 +196,22 @@ jobs:
asset_path: ./SHA2-256SUMS
asset_name: SHA2-256SUMS
asset_content_type: text/plain
- name: Make SHA2-512SUMS file
env:
SHA512_WINDOWS: ${{ needs.build_windows.outputs.sha512_windows }}
SHA512_WINDOWS32: ${{ needs.build_windows32.outputs.sha512_windows32 }}
SHA512_UNIX: ${{ needs.build_unix.outputs.sha512_unix }}
run: |
echo "${{ env.SHA512_WINDOWS }} yt-dlp.exe" >> SHA2-512SUMS
echo "${{ env.SHA512_WINDOWS32 }} yt-dlp_x86.exe" >> SHA2-512SUMS
echo "${{ env.SHA512_UNIX }} yt-dlp" >> SHA2-512SUMS
- name: Upload 512SUMS file
id: upload-512sums
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.build_unix.outputs.upload_url }}
asset_path: ./SHA2-512SUMS
asset_name: SHA2-512SUMS
asset_content_type: text/plain

View File

@@ -9,46 +9,23 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-18.04]
# TODO: python 2.6
python-version: [2.7, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, pypy-2.7, pypy-3.6, pypy-3.7]
python-impl: [cpython]
ytdl-test-set: [core]
python-version: [3.6, 3.7, 3.8, 3.9, pypy-3.6, pypy-3.7]
run-tests-ext: [sh]
include:
# python 3.2 is only available on windows via setup-python
- os: windows-latest
python-version: 3.2
python-impl: cpython
ytdl-test-set: core
python-version: 3.4 # Windows x86 build is still in 3.4
run-tests-ext: bat
# jython
- os: ubuntu-latest
python-impl: jython
ytdl-test-set: core
run-tests-ext: sh
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
if: ${{ matrix.python-impl == 'cpython' }}
with:
python-version: ${{ matrix.python-version }}
- name: Set up Java 8
if: ${{ matrix.python-impl == 'jython' }}
uses: actions/setup-java@v1
with:
java-version: 8
- name: Install Jython
if: ${{ matrix.python-impl == 'jython' }}
run: |
wget http://search.maven.org/remotecontent?filepath=org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar -O jython-installer.jar
java -jar jython-installer.jar -s -d "$HOME/jython"
echo "$HOME/jython/bin" >> $GITHUB_PATH
- name: Install nose
run: pip install nose
- name: Run tests
continue-on-error: ${{ matrix.ytdl-test-set == 'download' || matrix.python-impl == 'jython' }}
continue-on-error: False
env:
YTDL_TEST_SET: ${{ matrix.ytdl-test-set }}
YTDL_TEST_SET: core
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }}
# Linter is in quick-test

View File

@@ -9,45 +9,22 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-18.04]
# TODO: python 2.6
python-version: [2.7, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, pypy-2.7, pypy-3.6, pypy-3.7]
python-impl: [cpython]
ytdl-test-set: [download]
python-version: [3.6, 3.7, 3.8, 3.9, pypy-3.6, pypy-3.7]
run-tests-ext: [sh]
include:
# python 3.2 is only available on windows via setup-python
- os: windows-latest
python-version: 3.2
python-impl: cpython
ytdl-test-set: download
python-version: 3.4 # Windows x86 build is still in 3.4
run-tests-ext: bat
# jython - disable for now since it takes too long to complete
# - os: ubuntu-latest
# python-impl: jython
# ytdl-test-set: download
# run-tests-ext: sh
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
if: ${{ matrix.python-impl == 'cpython' }}
with:
python-version: ${{ matrix.python-version }}
- name: Set up Java 8
if: ${{ matrix.python-impl == 'jython' }}
uses: actions/setup-java@v1
with:
java-version: 8
- name: Install Jython
if: ${{ matrix.python-impl == 'jython' }}
run: |
wget http://search.maven.org/remotecontent?filepath=org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar -O jython-installer.jar
java -jar jython-installer.jar -s -d "$HOME/jython"
echo "$HOME/jython/bin" >> $GITHUB_PATH
- name: Install nose
run: pip install nose
- name: Run tests
continue-on-error: ${{ matrix.ytdl-test-set == 'download' || matrix.python-impl == 'jython' }}
continue-on-error: true
env:
YTDL_TEST_SET: ${{ matrix.ytdl-test-set }}
YTDL_TEST_SET: download
run: ./devscripts/run_tests.${{ matrix.run-tests-ext }}

85
.gitignore vendored
View File

@@ -1,3 +1,46 @@
# Config
*.conf
*.spec
cookies
cookies.txt
# Downloaded
*.srt
*.ttml
*.sbv
*.vtt
*.flv
*.mp4
*.m4a
*.m4v
*.mp3
*.3gp
*.webm
*.wav
*.ape
*.mkv
*.swf
*.part
*.part-*
*.ytdl
*.dump
*.frag
*.frag.urls
*.aria2
*.swp
*.ogg
*.opus
*.info.json
*.live_chat.json
*.jpg
*.png
*.webp
*.annotations.xml
*.description
# Allow config/media files in testdata
!test/testdata/**
# Python
*.pyc
*.pyo
@@ -43,48 +86,6 @@ README.txt
yt-dlp.zip
*.exe
# Downloaded
*.srt
*.ttml
*.sbv
*.vtt
*.flv
*.mp4
*.m4a
*.m4v
*.mp3
*.3gp
*.webm
*.wav
*.ape
*.mkv
*.swf
*.part
*.part-*
*.ytdl
*.dump
*.frag
*.frag.urls
*.aria2
*.swp
*.ogg
*.opus
*.info.json
*.live_chat.json
*.jpg
*.png
*.webp
*.annotations.xml
*.description
# Config
*.conf
*.spec
cookies
cookies.txt
# Text Editor / IDE
.idea
*.iml

View File

@@ -1,6 +1,7 @@
pukkandan (owner)
shirt-dev (collaborator)
colethedj (collaborator)
Ashish0804 (collaborator)
h-h-h-h
pauldubois98
nixxo
@@ -20,11 +21,9 @@ FelixFrog
Zocker1999NET
nao20010128nao
kurumigi
tsukumi
bbepis
animelover1984
Pccode66
Ashish0804
RobinD42
hseg
DennyDai
@@ -40,3 +39,18 @@ hheimbuerger
B0pol
lkho
fstirlitz
Lamieur
tsukumijima
Hadi0609
b5eff52
craftingmod
tpikonen
tripulse
king-millez
alex-gedeon
hhirtz
louie-github
MinePlayersPE
olifre
rhsmachine
nihil-admirari

View File

@@ -10,7 +10,7 @@
* Commit to master as `Release <version>`
* Push to origin/release using `git push origin master:release`
build task will now run
* Update version.py using devscripts\update-version.py
* Update version.py using `devscripts\update-version.py`
* Run `make issuetemplates`
* Commit to master as `[version] update :ci skip all`
* Push to origin/master
@@ -19,6 +19,167 @@
-->
### 2021.06.08
* Remove support for obsolete Python versions: Only 3.6+ is now supported
* Merge youtube-dl: Upto [commit/c2350ca](https://github.com/ytdl-org/youtube-dl/commit/c2350cac243ba1ec1586fe85b0d62d1b700047a2)
* [hls] Fix decryption for multithreaded downloader
* [extractor] Fix pre-checking archive for some extractors
* [extractor] Fix FourCC fallback when parsing ISM [fstirlitz](https://github.com/fstirlitz)
* [twitcasting] Add TwitCastingUserIE, TwitCastingLiveIE [pukkandan](https://github.com/pukkandan), [nao20010128nao](https://github.com/nao20010128nao)
* [vidio] Add VidioPremierIE and VidioLiveIE [minEplaYerspe](Https://github.com/MinePlayersPE)
* [viki] Fix extraction from [ytdl-org/youtube-dl@59e583f](https://github.com/ytdl-org/youtube-dl/commit/59e583f7e8530ca92776c866897d895c072e2a82)
* [youtube] Support shorts URL
* [zoom] Extract transcripts as subtitles
* Add field `original_url` with the user-inputted URL
* Fix and refactor `prepare_outtmpl`
* Make more fields available for `--print` when used with `--flat-playlist`
* [utils] Generalize `traverse_dict` to `traverse_obj`
* [downloader/ffmpeg] Hide FFmpeg banner unless in verbose mode [fstirlitz](https://github.com/fstirlitz)
* [build] Release `yt-dlp.tar.gz`
* [build,update] Add GNU-style SHA512 and prepare updater for simlar SHA256 [nihil-admirari](https://github.com/nihil-admirari)
* [pyinst] Show Python version in exe metadata [nihil-admirari](https://github.com/nihil-admirari)
* [docs] Improve documentation of dependencies
* [cleanup] Mark unused files
* [cleanup] Point all shebang to `python3` [fstirlitz](https://github.com/fstirlitz)
* [cleanup] Remove duplicate file `trovolive.py`
### 2021.06.01
* Merge youtube-dl: Upto [commit/d495292](https://github.com/ytdl-org/youtube-dl/commit/d495292852b6c2f1bd58bc2141ff2b0265c952cf)
* Pre-check archive and filters during playlist extraction
* Handle Basic Auth `user:pass` in URLs by [hhirtz](https://github.com/hhirtz) and [pukkandan](https://github.com/pukkandan)
* [archiveorg] Add YoutubeWebArchiveIE by [colethedj](https://github.com/colethedj) and [alex-gedeon](https://github.com/alex-gedeon)
* [fancode] Add extractor by [rhsmachine](https://github.com/rhsmachine)
* [patreon] Support vimeo embeds by [rhsmachine](https://github.com/rhsmachine)
* [Saitosan] Add new extractor by [llacb47](https://github.com/llacb47)
* [ShemarooMe] Add extractor by [Ashish0804](https://github.com/Ashish0804) and [pukkandan](https://github.com/pukkandan)
* [telemundo] Add extractor by [king-millez](https://github.com/king-millez)
* [SonyLIV] Add SonyLIVSeriesIE and subtitle support by [Ashish0804](https://github.com/Ashish0804)
* [Hotstar] Add HotStarSeriesIE by [Ashish0804](https://github.com/Ashish0804)
* [Voot] Add VootSeriesIE by [Ashish0804](https://github.com/Ashish0804)
* [vidio] Support login and premium videos by [MinePlayersPE](https://github.com/MinePlayersPE)
* [fragment] When using `-N`, do not keep the fragment content in memory
* [ffmpeg] Download and merge in a single step if possible
* [ThumbnailsConvertor] Support conversion to `png` and make it the default by [louie-github](https://github.com/louie-github)
* [VideoConvertor] Generalize with remuxer and allow conditional recoding
* [EmbedThumbnail] Embed in `mp4`/`m4a` using mutagen by [tripulse](https://github.com/tripulse) and [pukkandan](https://github.com/pukkandan)
* [EmbedThumbnail] Embed if any thumbnail was downloaded, not just the best
* [EmbedThumbnail] Correctly escape filename
* [update] replace self without launching a subprocess in windows
* [update] Block further update for unsupported systems
* Refactor `__process_playlist` by creating `LazyList`
* Write messages to `stderr` when both `quiet` and `verbose`
* Sanitize and sort playlist thumbnails
* Remove `None` values from `info.json`
* [extractor] Always prefer native hls downloader by default
* [extractor] Skip subtitles without URI in m3u8 manifests by [hheimbuerger](https://github.com/hheimbuerger)
* [extractor] Functions to parse `socket.io` response as `json` by [pukkandan](https://github.com/pukkandan) and [llacb47](https://github.com/llacb47)
* [extractor] Allow `note=False` when extracting manifests
* [utils] Escape URLs in `sanitized_Request`, not `sanitize_url`
* [hls] Disable external downloader for `webtt`
* [youtube] `/live` URLs should raise error if channel is not live
* [youtube] Bug fixes
* [zee5] Fix m3u8 formats' extension
* [ard] Allow URLs without `-` before id by [olifre](https://github.com/olifre)
* [cleanup] `YoutubeDL._match_entry`
* [cleanup] Refactor updater
* [cleanup] Refactor ffmpeg convertors
* [cleanup] setup.py
### 2021.05.20
* **Youtube improvements**:
* Support youtube music `MP`, `VL` and `browse` pages
* Extract more formats for youtube music by [craftingmod](https://github.com/craftingmod), [colethedj](https://github.com/colethedj) and [pukkandan](https://github.com/pukkandan)
* Extract multiple subtitles in same language by [pukkandan](https://github.com/pukkandan) and [tpikonen](https://github.com/tpikonen)
* Redirect channels that doesn't have a `videos` tab to their `UU` playlists
* Support in-channel search
* Sort audio-only formats correctly
* Always extract `maxresdefault` thumbnail
* Extract audio language
* Add subtitle language names by [nixxo](https://github.com/nixxo) and [tpikonen](https://github.com/tpikonen)
* Show alerts only from the final webpage
* Add `html5=1` param to `get_video_info` page requests by [colethedj](https://github.com/colethedj)
* Better message when login required
* **Add option `--print`**: to print any field/template
* Deprecates: `--get-description`, `--get-duration`, `--get-filename`, `--get-format`, `--get-id`, `--get-thumbnail`, `--get-title`, `--get-url`
* Field `additional_urls` to download additional videos from metadata using [`--parse-metadata`](https://github.com/yt-dlp/yt-dlp#modifying-metadata)
* Merge youtube-dl: Upto [commit/dfbbe29](https://github.com/ytdl-org/youtube-dl/commit/dfbbe2902fc67f0f93ee47a8077c148055c67a9b)
* Write thumbnail of playlist and add `pl_thumbnail` outtmpl key
* [embedthumbnail] Add `flac` support and refactor `mutagen` code by [pukkandan](https://github.com/pukkandan) and [tripulse](https://github.com/tripulse)
* [audius:artist] Add extractor by [king-millez](https://github.com/king-millez)
* [parlview] Add extractor by [king-millez](https://github.com/king-millez)
* [tenplay] Fix extractor by [king-millez](https://github.com/king-millez)
* [rmcdecouverte] Generalize `_VALID_URL`
* Add compat-option `no-attach-infojson`
* Add field `name` for subtitles
* Ensure `post_extract` and `pre_process` only run once
* Fix `--check-formats` when there is network error
* Standardize `write_debug` and `get_param`
* [options] Alias `--write-comments`, `--no-write-comments`
* [options] Refactor callbacks
* [test:download] Only extract enough videos for `playlist_mincount`
* [extractor] bugfix for when `compat_opts` is not given
* [build] Fix x86 build by [shirt](https://github.com/shirt-dev)
* [cleanup] code formatting, youtube tests and readme
### 2021.05.11
* **Deprecate support for python versions < 3.6**
* **Subtitle extraction from manifests** by [fstirlitz](https://github.com/fstirlitz). See [be6202f](https://github.com/yt-dlp/yt-dlp/commit/be6202f12b97858b9d716e608394b51065d0419f) for details
* **Improve output template:**
* Allow slicing lists/strings using `field.start:end:step`
* A field can also be used as offset like `field1+num+field2`
* A default value can be given using `field|default`
* Prevent invalid fields from causing errors
* **Merge youtube-dl**: Upto [commit/a726009](https://github.com/ytdl-org/youtube-dl/commit/a7260099873acc6dc7d76cafad2f6b139087afd0)
* **Remove options** `-l`, `-t`, `-A` completely and disable `--auto-number`, `--title`, `--literal`, `--id`
* [Plugins] Prioritize plugins over standard extractors and prevent plugins from overwriting the standard extractor classes
* [downloader] Fix `quiet` and `to_stderr`
* [fragment] Ensure the file is closed on error
* [fragment] Make sure first segment is not skipped
* [aria2c] Fix whitespace being stripped off
* [embedthumbnail] Fix bug where jpeg thumbnails were converted again
* [FormatSort] Fix for when some formats have quality and others don't
* [utils] Add `network_exceptions`
* [utils] Escape URL while sanitizing
* [ukcolumn] Add Extractor
* [whowatch] Add extractor by [nao20010128nao](https://github.com/nao20010128nao)
* [CBS] Improve `_VALID_URL` to support movies
* [crackle] Improve extraction
* [curiositystream] Fix collections
* [francetvinfo] Improve video id extraction
* [generic] Respect the encoding in manifest
* [limelight] Obey `allow_unplayable_formats`
* [mediasite] Generalize URL pattern by [fstirlitz](https://github.com/fstirlitz)
* [mxplayer] Add MxplayerShowIE by [Ashish0804](https://github.com/Ashish0804)
* [nebula] Move to nebula.app by [Lamieur](https://github.com/Lamieur)
* [niconico] Fix HLS formats by [CXwudi](https://github.com/CXwudi), [tsukumijima](https://github.com/tsukumijima), [nao20010128nao](https://github.com/nao20010128nao) and [pukkandan](https://github.com/pukkandan)
* [niconico] Fix title and thumbnail extraction by [CXwudi](https://github.com/CXwudi)
* [plutotv] Extract subtitles from manifests
* [plutotv] Fix format extraction for some urls
* [rmcdecouverte] Improve `_VALID_URL`
* [sonyliv] Fix `title` and `series` extraction by [Ashish0804](https://github.com/Ashish0804)
* [tubi] Raise "no video formats" error when video url is empty
* [youtube:tab] Detect playlists inside community posts
* [youtube] Add `oembed` to reserved names
* [zee5] Fix extraction for some URLs by [Hadi0609](https://github.com/Hadi0609)
* [zee5] Fix py2 compatibility
* Fix `playlist_index` and add `playlist_autonumber`. See [#302](https://github.com/yt-dlp/yt-dlp/issues/302) for details
* Add experimental option `--check-formats` to test the URLs before format selection
* Option `--compat-options` to revert [some of yt-dlp's changes](https://github.com/yt-dlp/yt-dlp#differences-in-default-behavior)
* Deprecates `--list-formats-as-table`, `--list-formats-old`
* Fix number of digits in `%(playlist_index)s`
* Fix case sensitivity of format selector
* Revert "[core] be able to hand over id and title using url_result"
* Do not strip out whitespaces in `-o` and `-P`
* Fix `preload_download_archive` writing verbose message to `stdout`
* Move option warnings to `YoutubeDL`so that they obey `--no-warnings` and can output colors
* Py2 compatibility for `FileNotFoundError`
### 2021.04.22
* **Improve output template:**
* Objects can be traversed like `%(field.key1.key2)s`
@@ -33,11 +194,11 @@
* Add option `--skip-playlist-after-errors` to skip the rest of a playlist after a given number of errors are encountered
* Merge youtube-dl: Upto [commit/7e8b3f9](https://github.com/ytdl-org/youtube-dl/commit/7e8b3f9439ebefb3a3a4e5da9c0bd2b595976438)
* [downloader] Fix bug in downloader selection
* [BilibiliChannel] Fix pagination by [nao20010128nao](https://github.com/nao20010128nao) and[pukkandan](https://github.com/pukkandan)
* [BilibiliChannel] Fix pagination by [nao20010128nao](https://github.com/nao20010128nao) and [pukkandan](https://github.com/pukkandan)
* [rai] Add support for http formats by [nixxo](https://github.com/nixxo)
* [TubiTv] Add TubiTvShowIE by [Ashish0804](https://github.com/Ashish0804)
* [twitcasting] Fix extractor
* [viu:ott] Fix extractor and support series by [lkho](https://github.com/lkho) and[pukkandan](https://github.com/pukkandan)
* [viu:ott] Fix extractor and support series by [lkho](https://github.com/lkho) and [pukkandan](https://github.com/pukkandan)
* [youtube:tab] Show unavailable videos in playlists by [colethedj](https://github.com/colethedj)
* [youtube:tab] Reload with unavailable videos for all playlists
* [youtube] Ignore invalid stretch ratio
@@ -265,7 +426,7 @@
### 2021.02.15
* Merge youtube-dl: Upto [2021.02.10](https://github.com/ytdl-org/youtube-dl/releases/tag/2021.02.10) (except archive.org)
* [niconico] Improved extraction and support encrypted/SMILE movies by [kurumigi](https://github.com/kurumigi), [tsukumi](https://github.com/tsukumi), [bbepis](https://github.com/bbepis), [pukkandan](https://github.com/pukkandan)
* [niconico] Improved extraction and support encrypted/SMILE movies by [kurumigi](https://github.com/kurumigi), [tsukumijima](https://github.com/tsukumijima), [bbepis](https://github.com/bbepis), [pukkandan](https://github.com/pukkandan)
* Fix HLS AES-128 with multiple keys in external downloaders by [shirt](https://github.com/shirt-dev)
* [youtube_live_chat] Fix by using POST API by [siikamiika](https://github.com/siikamiika)
* [rumble] Add support for video page
@@ -519,4 +680,4 @@
* [generic] Extract embedded youtube and twitter videos by [diegorodriguezv](https://github.com/diegorodriguezv)
* [ffmpeg] Ensure all streams are copied by [pukkandan](https://github.com/pukkandan)
* [embedthumbnail] Fix for os.rename error by [pukkandan](https://github.com/pukkandan)
* make_win.bat: don't use UPX to pack vcruntime140.dll by [jbruchon](https://github.com/jbruchon)
* make_win.bat: don't use UPX to pack vcruntime140.dll by [jbruchon](https://github.com/jbruchon)

View File

@@ -25,6 +25,7 @@ completion-zsh: completions/zsh/_yt-dlp
lazy-extractors: yt_dlp/extractor/lazy_extractors.py
PREFIX ?= /usr/local
DESTDIR ?= .
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/man
SHAREDIR ?= $(PREFIX)/share

200
README.md
View File

@@ -20,9 +20,10 @@ A command-line program to download videos from YouTube and many other [video pla
yt-dlp is a [youtube-dl](https://github.com/ytdl-org/youtube-dl) fork based on the now inactive [youtube-dlc](https://github.com/blackjack4494/yt-dlc). The main focus of this project is adding new features and patches while also keeping up to date with the original project
* [NEW FEATURES](#new-features)
* [Differences in default behavior](#differences-in-default-behavior)
* [INSTALLATION](#installation)
* [Dependencies](#dependencies)
* [Update](#update)
* [Dependencies](#dependencies)
* [Compile](#compile)
* [USAGE AND OPTIONS](#usage-and-options)
* [General Options](#general-options)
@@ -65,15 +66,17 @@ The major new features from the latest release of [blackjack4494/yt-dlc](https:/
* **[Format Sorting](#sorting-formats)**: The default format sorting options have been changed so that higher resolution and better codecs will be now preferred instead of simply using larger bitrate. Furthermore, you can now specify the sort order using `-S`. This allows for much easier format selection that what is possible by simply using `--format` ([examples](#format-selection-examples))
* **Merged with youtube-dl v2021.04.17**: You get all the latest features and patches of [youtube-dl](https://github.com/ytdl-org/youtube-dl) in addition to all the features of [youtube-dlc](https://github.com/blackjack4494/yt-dlc)
* **Merged with youtube-dl [commit/c2350ca](https://github.com/ytdl-org/youtube-dl/commit/c2350cac243ba1ec1586fe85b0d62d1b700047a2)**: (v2021.06.06) You get all the latest features and patches of [youtube-dl](https://github.com/ytdl-org/youtube-dl) in addition to all the features of [youtube-dlc](https://github.com/blackjack4494/yt-dlc)
* **Merged with animelover1984/youtube-dl**: You get most of the features and improvements from [animelover1984/youtube-dl](https://github.com/animelover1984/youtube-dl) including `--get-comments`, `BiliBiliSearch`, `BilibiliChannel`, Embedding thumbnail in mp4/ogg/opus, Playlist infojson etc. Note that the NicoNico improvements are not available. See [#31](https://github.com/yt-dlp/yt-dlp/pull/31) for details.
* **Merged with animelover1984/youtube-dl**: You get most of the features and improvements from [animelover1984/youtube-dl](https://github.com/animelover1984/youtube-dl) including `--write-comments`, `BiliBiliSearch`, `BilibiliChannel`, Embedding thumbnail in mp4/ogg/opus, playlist infojson etc. Note that the NicoNico improvements are not available. See [#31](https://github.com/yt-dlp/yt-dlp/pull/31) for details.
* **Youtube improvements**:
* All Youtube Feeds (`:ytfav`, `:ytwatchlater`, `:ytsubs`, `:ythistory`, `:ytrec`) works and supports downloading multiple pages of content
* Youtube search (`ytsearch:`, `ytsearchdate:`) along with Search URLs work
* Youtube mixes supports downloading multiple pages of content
* All Feeds (`:ytfav`, `:ytwatchlater`, `:ytsubs`, `:ythistory`, `:ytrec`) supports downloading multiple pages of content
* Search (`ytsearch:`, `ytsearchdate:`), search URLs and in-channel search works
* Mixes supports downloading multiple pages of content
* Redirect channel's home URL automatically to `/video` to preserve the old behaviour
* `255kbps` audio is extracted from youtube music if premium cookies are given
* Youtube music Albums, channels etc can be downloaded
* **Split video by chapters**: Videos can be split into multiple files based on chapters using `--split-chapters`
@@ -81,17 +84,21 @@ The major new features from the latest release of [blackjack4494/yt-dlc](https:/
* **Aria2c with HLS/DASH**: You can use `aria2c` as the external downloader for DASH(mpd) and HLS(m3u8) formats
* **New extractors**: AnimeLab, Philo MSO, Rcs, Gedi, bitwave.tv, mildom, audius, zee5, mtv.it, wimtv, pluto.tv, niconico users, discoveryplus.in, mediathek, NFHSNetwork, nebula
* **New extractors**: AnimeLab, Philo MSO, Rcs, Gedi, bitwave.tv, mildom, audius, zee5, mtv.it, wimtv, pluto.tv, niconico users, discoveryplus.in, mediathek, NFHSNetwork, nebula, ukcolumn, whowatch, MxplayerShow, parlview (au), YoutubeWebArchive, fancode, Saitosan, ShemarooMe, telemundo, VootSeries, SonyLIVSeries, HotstarSeries, VidioPremier, VidioLive
* **Fixed extractors**: archive.org, roosterteeth.com, skyit, instagram, itv, SouthparkDe, spreaker, Vlive, akamai, ina, rumble, tennistv, amcnetworks, la7 podcasts, linuxacadamy, nitter, twitcasting, viu
* **Fixed extractors**: archive.org, roosterteeth.com, skyit, instagram, itv, SouthparkDe, spreaker, Vlive, akamai, ina, rumble, tennistv, amcnetworks, la7 podcasts, linuxacadamy, nitter, twitcasting, viu, crackle, curiositystream, mediasite, rmcdecouverte, sonyliv, tubi, tenplay, patreon
* **Subtitle extraction from manifests**: Subtitles can be extracted from streaming media manifests. See [commit/be6202f](https://github.com/yt-dlp/yt-dlp/commit/be6202f12b97858b9d716e608394b51065d0419f) for details
* **Multiple paths and output templates**: You can give different [output templates](#output-template) and download paths for different types of files. You can also set a temporary path where intermediary files are downloaded to using `--paths` (`-P`)
* **Portable Configuration**: Configuration files are automatically loaded from the home and root directories. See [configuration](#configuration) for details
* **Other new options**: `--parse-metadata`, `--list-formats-as-table`, `--write-link`, `--force-download-archive`, `--force-overwrites`, `--break-on-reject` etc
* **Output template improvements**: Output templates can now have date-time formatting, numeric offsets, object traversal etc. See [output template](#output-template) for details. Even more advanced operations can also be done with the help of `--parse-metadata`
* **Improvements**: Multiple `--postprocessor-args` and `--external-downloader-args`, Date/time formatting in `-o`, faster archive checking, more [format selection options](#format-selection) etc
* **Other new options**: `--sleep-requests`, `--convert-thumbnails`, `--write-link`, `--force-download-archive`, `--force-overwrites`, `--break-on-reject` etc
* **Improvements**: Multiple `--postprocessor-args` and `--downloader-args`, faster archive checking, more [format selection options](#format-selection) etc
* **Plugin extractors**: Extractors can be loaded from an external file. See [plugins](#plugins) for details
@@ -105,15 +112,42 @@ See [changelog](Changelog.md) or [commits](https://github.com/yt-dlp/yt-dlp/comm
If you are coming from [youtube-dl](https://github.com/ytdl-org/youtube-dl), the amount of changes are very large. Compare [options](#options) and [supported sites](supportedsites.md) with youtube-dl's to get an idea of the massive number of features/patches [youtube-dlc](https://github.com/blackjack4494/yt-dlc) has accumulated.
### Differences in default behavior
Some of yt-dlp's default options are different from that of youtube-dl and youtube-dlc.
* The options `--id`, `--auto-number` (`-A`), `--title` (`-t`) and `--literal` (`-l`), no longer work. See [removed options](#Removed) for details
* `avconv` is not supported as as an alternative to `ffmpeg`
* The default [output template](#output-template) is `%(title)s [%(id)s].%(ext)s`. There is no real reason for this change. This was changed before yt-dlp was ever made public and now there are no plans to change it back to `%(title)s.%(id)s.%(ext)s`. Instead, you may use `--compat-options filename`
* The default [format sorting](sorting-formats) is different from youtube-dl and prefers higher resolution and better codecs rather than higher bitrates. You can use the `--format-sort` option to change this to any order you prefer, or use `--compat-options format-sort` to use youtube-dl's sorting order
* The default format selector is `bv*+ba/b`. This means that if a combined video + audio format that is better than the best video-only format is found, the former will be prefered. Use `-f bv+ba/b` or `--compat-options format-spec` to revert this
* Unlike youtube-dlc, yt-dlp does not allow merging multiple audio/video streams into one file by default (since this conflicts with the use of `-f bv*+ba`). If needed, this feature must be enabled using `--audio-multistreams` and `--video-multistreams`. You can also use `--compat-options multistreams` to enable both
* `--ignore-errors` is enabled by default. Use `--abort-on-error` or `--compat-options abort-on-error` to abort on errors instead
* When writing metadata files such as thumbnails, description or infojson, the same information (if available) is also written for playlists. Use `--no-write-playlist-metafiles` or `--compat-options no-playlist-metafiles` to not write these files
* `--add-metadata` attaches the `infojson` to `mkv` files in addition to writing the metadata when used with `--write-infojson`. Use `--compat-options no-attach-info-json` to revert this
* `playlist_index` behaves differently when used with options like `--playlist-reverse` and `--playlist-items`. See [#302](https://github.com/yt-dlp/yt-dlp/issues/302) for details. You can use `--compat-options playlist-index` if you want to keep the earlier behavior
* The output of `-F` is listed in a new format. Use `--compat-options list-formats` to revert this
* Youtube live chat (if available) is considered as a subtitle. Use `--sub-langs all,-live_chat` to download all subtitles except live chat. You can also use `--compat-options no-live-chat` to prevent live chat from downloading
* Youtube channel URLs are automatically redirected to `/video`. Append a `/featured` to the URL to download only the videos in the home page. If the channel does not have a videos tab, we try to download the equivalent `UU` playlist instead. Also, `/live` URLs raise an error if there are no live videos instead of silently downloading the entire channel. You may use `--compat-options no-youtube-channel-redirect` to revert all these redirections
* Unavailable videos are also listed for youtube playlists. Use `--compat-options no-youtube-unavailable-videos` to remove this
* If `ffmpeg` is used as the downloader, the downloading and merging of formats happen in a single step when possible. Use `--compat-options no-direct-merge` to revert this
For ease of use, a few more compat options are available:
* `--compat-options all`: Use all compat options
* `--compat-options youtube-dl`: Same as `--compat-options all,-multistreams`
* `--compat-options youtube-dlc`: Same as `--compat-options all,-no-live-chat,-no-youtube-channel-redirect`
# INSTALLATION
yt-dlp is not platform specific. So it should work on your Unix box, on Windows or on macOS
You can install yt-dlp using one of the following methods:
* Download the binary from the [latest release](https://github.com/yt-dlp/yt-dlp/releases/latest) (recommended method)
* Use [PyPI package](https://pypi.org/project/yt-dlp): `python -m pip install --upgrade yt-dlp`
* Use pip+git: `python -m pip install --upgrade git+https://github.com/yt-dlp/yt-dlp.git@release`
* Install master branch: `python -m pip install --upgrade git+https://github.com/yt-dlp/yt-dlp`
* Use [PyPI package](https://pypi.org/project/yt-dlp): `python3 -m pip install --upgrade yt-dlp`
* Use pip+git: `python3 -m pip install --upgrade git+https://github.com/yt-dlp/yt-dlp.git@release`
* Install master branch: `python3 -m pip install --upgrade git+https://github.com/yt-dlp/yt-dlp`
Note that on some systems, you may need to use `py` or `python` instead of `python3`
UNIX users (Linux, macOS, BSD) can also install the [latest release](https://github.com/yt-dlp/yt-dlp/releases/latest) one of the following ways:
@@ -132,27 +166,45 @@ sudo aria2c https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o
sudo chmod a+rx /usr/local/bin/yt-dlp
```
### DEPENDENCIES
Python versions 2.6, 2.7, or 3.2+ are currently supported. However, 3.2+ is strongly recommended and python2 support will be deprecated in the future.
Although there are no required dependencies, `ffmpeg` and `ffprobe` are highly recommended. Other optional dependencies are `sponskrub`, `AtomicParsley`, `mutagen`, `pycryptodome` and any of the supported external downloaders. Note that the windows releases are already built with the python interpreter, mutagen and pycryptodome included.
### UPDATE
You can use `yt-dlp -U` to update if you are using the provided release.
If you are using `pip`, simply re-run the same command that was used to install the program.
### DEPENDENCIES
Python versions 3.6+ (CPython and PyPy) are supported. Other versions and implementations may or may not work correctly.
<!-- https://www.microsoft.com/en-us/download/details.aspx?id=26999 -->
On windows, [Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)](https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x86.exe) is also necessary to run yt-dlp. You probably already have this, but if the executable throws an error due to missing `MSVCR100.dll` you need to install it manually.
While all the other dependancies are optional, `ffmpeg` and `ffprobe` are highly recommended
* [**ffmpeg** and **ffprobe**](https://www.ffmpeg.org) - Required for [merging seperate video and audio files](#format-selection) as well as for various [post-processing](#post-processing-options) tasks. Licence [depends on the build](https://www.ffmpeg.org/legal.html)
* [**sponskrub**](https://github.com/faissaloo/SponSkrub) - For using the [sponskrub options](#sponskrub-sponsorblock-options). Licenced under [GPLv3+](https://github.com/faissaloo/SponSkrub/blob/master/LICENCE.md)
* [**mutagen**](https://github.com/quodlibet/mutagen) - For embedding thumbnail in certain formats. Licenced under [GPLv2+](https://github.com/quodlibet/mutagen/blob/master/COPYING)
* [**pycryptodome**](https://github.com/Legrandin/pycryptodome) - For decrypting various data. Licenced under [BSD2](https://github.com/Legrandin/pycryptodome/blob/master/LICENSE.rst)
* [**AtomicParsley**](https://github.com/wez/atomicparsley) - For embedding thumbnail in mp4/m4a if mutagen is not present. Licenced under [GPLv2+](https://github.com/wez/atomicparsley/blob/master/COPYING)
* [**rtmpdump**](http://rtmpdump.mplayerhq.hu) - For downloading `rtmp` streams. ffmpeg will be used as a fallback. Licenced under [GPLv2+](http://rtmpdump.mplayerhq.hu)
* [**mplayer**](http://mplayerhq.hu/design7/info.html) or [**mpv**](https://mpv.io) - For downloading `rstp` streams. ffmpeg will be used as a fallback. Licenced under [GPLv2+](https://github.com/mpv-player/mpv/blob/master/Copyright)
* [**phantomjs**](https://github.com/ariya/phantomjs) - Used in extractors where javascript needs to be run. Licenced under [BSD3](https://github.com/ariya/phantomjs/blob/master/LICENSE.BSD)
* Any external downloader that you want to use with `--downloader`
To use or redistribute the dependencies, you must agree to their respective licensing terms.
Note that the windows releases are already built with the python interpreter, mutagen and pycryptodome included.
### COMPILE
**For Windows**:
To build the Windows executable, you must have pyinstaller (and optionally mutagen and pycryptodome)
python -m pip install --upgrade pyinstaller mutagen pycryptodome
python3 -m pip install --upgrade pyinstaller mutagen pycryptodome
Once you have all the necessary dependencies installed, just run `py pyinst.py`. The executable will be built for the same architecture (32/64 bit) as the python used to build it. It is strongly recommended to use python3 although python2.6+ is supported.
Once you have all the necessary dependencies installed, just run `py pyinst.py`. The executable will be built for the same architecture (32/64 bit) as the python used to build it.
You can also build the executable without any version info or metadata by using:
pyinstaller.exe yt_dlp\__main__.py --onefile --name yt-dlp
Note that pyinstaller [does not support](https://github.com/pyinstaller/pyinstaller#requirements-and-tested-platforms) Python installed from the Windows store without using a virtual environment
**For Unix**:
You will need the required build tools: `python`, `make` (GNU), `pandoc`, `zip`, `nosetests`
@@ -210,6 +262,11 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
--mark-watched Mark videos watched (YouTube only)
--no-mark-watched Do not mark videos watched (default)
--no-colors Do not emit color codes in output
--compat-options OPTS Options that can help keep compatibility
with youtube-dl and youtube-dlc
configurations by reverting some of the
changes made in yt-dlp. See "Differences in
default behavior" for details
## Network Options:
--proxy URL Use the specified HTTP/HTTPS/SOCKS proxy.
@@ -443,10 +500,13 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
could still contain some personal
information (default)
--no-clean-infojson Write all fields to the infojson
--get-comments Retrieve video comments to be placed in the
.info.json file. The comments are fetched
even without this option if the extraction
is known to be quick
--write-comments Retrieve video comments to be placed in the
infojson. The comments are fetched even
without this option if the extraction is
known to be quick (Alias: --get-comments)
--no-write-comments Do not retrieve video comments unless the
extraction is known to be quick
(Alias: --no-get-comments)
--load-info-json FILE JSON file containing the video information
(created with the "--write-info-json"
option)
@@ -454,13 +514,10 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
jar in
--no-cookies Do not read/dump cookies (default)
--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
can store some downloaded information (such
as client ids and signatures) permanently.
By default $XDG_CACHE_HOME/youtube-dl or
~/.cache/youtube-dl
--no-cache-dir Disable filesystem caching
--rm-cache-dir Delete all filesystem cache files
@@ -494,14 +551,9 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
formats are found (default)
--skip-download Do not download the video but write all
related files (Alias: --no-download)
-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
-O, --print TEMPLATE Simulate, quiet but print the given fields.
Either a field name or similar formatting
as the output template can be used
-j, --dump-json Simulate, quiet but print JSON information.
See "OUTPUT TEMPLATE" for a description of
available keys
@@ -577,12 +629,10 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
containers irrespective of quality
--no-prefer-free-formats Don't give any special preference to free
containers (default)
--check-formats Check that the formats selected are
actually downloadable (Experimental)
-F, --list-formats List all available formats of requested
videos
--list-formats-as-table Present the output of -F in tabular form
(default)
--list-formats-old Present the output of -F in the old form
(Alias: --no-list-formats-as-table)
--merge-output-format FORMAT If a merge is required (e.g.
bestvideo+bestaudio), output to given
container format. One of mkv, mp4, ogg,
@@ -632,10 +682,10 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
## Post-Processing Options:
-x, --extract-audio Convert video files to audio-only files
(requires ffmpeg and ffprobe)
--audio-format FORMAT Specify audio format: "best", "aac",
"flac", "mp3", "m4a", "opus", "vorbis", or
"wav"; "best" by default; No effect without
-x
--audio-format FORMAT Specify audio format to convert the audio
to when -x is used. Currently supported
formats are: best (default) or one of
aac|flac|mp3|m4a|opus|vorbis|wav
--audio-quality QUALITY Specify ffmpeg audio quality, insert a
value between 0 (better) and 9 (worse) for
VBR or a specific bitrate like 128K
@@ -645,12 +695,12 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
|webm|mov|avi|mp3|mka|m4a|ogg|opus). If
target container does not support the
video/audio codec, remuxing will fail. You
can specify multiple rules; eg.
can specify multiple rules; Eg.
"aac>m4a/mov>mp4/mkv" will remux aac to
m4a, mov to mp4 and anything else to mkv.
--recode-video FORMAT Re-encode the video into another format if
re-encoding is necessary. The supported
formats are the same as --remux-video
re-encoding is necessary. The syntax and
supported formats are the same as --remux-video
--postprocessor-args NAME:ARGS Give these arguments to the postprocessors.
Specify the postprocessor/executable name
and the arguments separated by a colon ":"
@@ -711,10 +761,10 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
fields are passed, "%(filepath)s" is
appended to the end of the command
--convert-subs FORMAT Convert the subtitles to another format
(currently supported: srt|ass|vtt|lrc)
(currently supported: srt|vtt|ass|lrc)
(Alias: --convert-subtitles)
--convert-thumbnails FORMAT Convert the thumbnails to another format
(currently supported: jpg)
(currently supported: jpg|png)
--split-chapters Split video into multiple files based on
internal chapters. The "chapter:" prefix
can be used with "--paths" and "--output"
@@ -785,7 +835,7 @@ You can configure yt-dlp by placing any supported command line option to a confi
* `~/yt-dlp.conf.txt`
Note that `~` points to `C:\Users\<user name>` on windows. Also, `%XDG_CONFIG_HOME%` defaults to `~/.config` if undefined
1. **System Configuration**: `/etc/yt-dlp.conf` or `/etc/yt-dlp.conf`
1. **System Configuration**: `/etc/yt-dlp.conf`
For example, with the following configuration file yt-dlp will always extract the audio, not copy the mtime, use a proxy and save all videos under `YouTube` directory in your home directory:
```
@@ -842,16 +892,17 @@ The simplest usage of `-o` is not to set any template arguments when downloading
It may however also contain special sequences that will be replaced when downloading each video. The special sequences may be formatted according to [python string formatting operations](https://docs.python.org/2/library/stdtypes.html#string-formatting). For example, `%(NAME)s` or `%(NAME)05d`. To clarify, that is a percent symbol followed by a name in parentheses, followed by formatting operations.
The field names themselves (the part inside the parenthesis) can also have some special formatting:
1. **Date/time Formatting**: Date/time fields can be formatted according to [strftime formatting](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) by specifying it separated from the field name using a `>`. Eg: `%(duration>%H-%M-%S)s` or `%(upload_date>%Y-%m-%d)s`
2. **Offset numbers**: Numeric fields can have an initial offset specified by using a `+` separator. Eg: `%(playlist_index+10)03d`. This can also be used in conjunction with the date-time formatting. Eg: `%(epoch+-3600>%H-%M-%S)s`
3. **Object traversal**: The dictionaries and lists available in metadata can be traversed by using a `.` (dot) separator. Eg: `%(tags.0)s` or `%(subtitles.en.-1.ext)`. Note that the fields that become available using this method are not listed below. Use `-j` to see such fields
1. **Object traversal**: The dictionaries and lists available in metadata can be traversed by using a `.` (dot) separator. You can also do python slicing using `:`. Eg: `%(tags.0)s`, `%(subtitles.en.-1.ext)`, `%(id.3:7:-1)s`. Note that the fields that become available using this method are not listed below. Use `-j` to see such fields
1. **Addition**: Addition and subtraction of numeric fields can be done using `+` and `-` respectively. Eg: `%(playlist_index+10)03d`, `%(n_entries+1-playlist_index)d`
1. **Date/time Formatting**: Date/time fields can be formatted according to [strftime formatting](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) by specifying it separated from the field name using a `>`. Eg: `%(duration>%H-%M-%S)s`, `%(upload_date>%Y-%m-%d)s`, `%(epoch-3600>%H-%M-%S)s`
1. **Default**: A default value can be specified for when the field is empty using a `|` seperator. This overrides `--output-na-template`. Eg: `%(uploader|Unknown)s`
To summarize, the general syntax for a field is:
```
%(name[.keys][+offset][>strf])[flags][width][.precision][length]type
%(name[.keys][addition][>strf][|default])[flags][width][.precision][length]type
```
Additionally, you can set different output templates for the various metadata files separately from the general output template by specifying the type of file followed by the template separated by a colon `:`. The different file types supported are `subtitle`, `thumbnail`, `description`, `annotation`, `infojson`, `pl_description`, `pl_infojson`, `chapter`. For example, `-o '%(title)s.%(ext)s' -o 'thumbnail:%(title)s\%(title)s.%(ext)s'` will put the thumbnails in a folder with the same name as the video.
Additionally, you can set different output templates for the various metadata files separately from the general output template by specifying the type of file followed by the template separated by a colon `:`. The different file types supported are `subtitle`, `thumbnail`, `description`, `annotation`, `infojson`, `pl_thumbnail`, `pl_description`, `pl_infojson`, `chapter`. For example, `-o '%(title)s.%(ext)s' -o 'thumbnail:%(title)s\%(title)s.%(ext)s'` will put the thumbnails in a folder with the same name as the video.
The available fields are:
@@ -873,7 +924,7 @@ The available fields are:
- `channel_id` (string): Id of the channel
- `location` (string): Physical location where the video was filmed
- `duration` (numeric): Length of the video in seconds
- `duration_string` (string): Length of the video (HH-mm-ss)
- `duration_string` (string): Length of the video (HH:mm:ss)
- `view_count` (numeric): How many users have watched the video on the platform
- `like_count` (numeric): Number of positive ratings of the video
- `dislike_count` (numeric): Number of negative ratings of the video
@@ -914,6 +965,8 @@ The available fields are:
- `playlist_title` (string): Playlist title
- `playlist_uploader` (string): Full name of the playlist uploader
- `playlist_uploader_id` (string): Nickname or id of the playlist uploader
- `webpage_url` (string): A URL to the video webpage which if given to yt-dlp should allow to get the same result again
- `original_url` (string): The URL given by the user (or same as `webpage_url` for playlist entries)
Available for the video that belongs to some logical chapter or section:
@@ -951,6 +1004,11 @@ Available for `chapter:` prefix when using `--split-chapters` for videos with in
- `section_start` (numeric): Start time of the chapter in seconds
- `section_end` (numeric): End time of the chapter in seconds
Available only when used in `--print`:
- `urls` (string): The URLs of all requested formats, one in each line
- `filename` (string): Name of the video file. Note that the actual filename may be different due to post-processing. Use `--exec echo` to get the name after all postprocessing is complete
Each aforementioned sequence when referenced in an output template will be replaced by the actual value corresponding to the sequence name. Note that some of the sequences are not guaranteed to be present since they depend on the metadata obtained by a particular extractor. Such sequences will be replaced with placeholder value provided with `--output-na-placeholder` (`NA` by default).
For example for `-o %(title)s-%(id)s.%(ext)s` and an mp4 video with title `yt-dlp test video` and id `BaW_jenozKcj`, this will result in a `yt-dlp test video-BaW_jenozKcj.mp4` file created in the current directory.
@@ -1240,7 +1298,9 @@ The metadata obtained the the extractors can be modified by using `--parse-metad
Note that any field created by this can be used in the [output template](#output-template) and will also affect the media file's metadata added when using `--add-metadata`.
You can also use this to change only the metadata that is embedded in the media file. To do this, set the value of the corresponding field with a `meta_` prefix. For example, any value you set to `meta_description` field will be added to the `description` field in the file. You can use this to set a different "description" and "synopsis", for example.
This option also has a few special uses:
* You can use this to change the metadata that is embedded in the media file. To do this, set the value of the corresponding field with a `meta_` prefix. For example, any value you set to `meta_description` field will be added to the `description` field in the file. You can use this to set a different "description" and "synopsis", for example
* You can download an additional URL based on the metadata of the currently downloaded video. To do this, set the field `additional_urls` to the URL that you want to download. Eg: `--parse-metadata "description:(?P<additional_urls>https?://www\.vimeo\.com/\d+)` will download the first vimeo video found in the description
## Modifying metadata examples
@@ -1274,6 +1334,14 @@ These are all the deprecated options and the current alternative to achieve the
#### Not recommended
While these options still work, their use is not recommended since there are other alternatives to achieve the same
--get-description --print description
--get-duration --print duration_string
--get-filename --print filename
--get-format --print format
--get-id --print id
--get-thumbnail --print thumbnail
-e, --get-title --print title
-g, --get-url --print urls
--all-formats -f all
--all-subs --sub-langs all --write-subs
--autonumber-size NUMBER Use string formatting. Eg: %(autonumber)03d
@@ -1281,8 +1349,11 @@ While these options still work, their use is not recommended since there are oth
--metadata-from-title FORMAT --parse-metadata "%(title)s:FORMAT"
--hls-prefer-native --downloader "m3u8:native"
--hls-prefer-ffmpeg --downloader "m3u8:ffmpeg"
--list-formats-old --compat-options list-formats (Alias: --no-list-formats-as-table)
--list-formats-as-table --compat-options -list-formats [Default] (Alias: --no-list-formats-old)
--sponskrub-args ARGS --ppa "sponskrub:ARGS"
--test Used by developers for testing extractors. Not intended for the end user
--youtube-print-sig-code Used for testing youtube signatures
#### Old aliases
@@ -1313,16 +1384,15 @@ These options may no longer work as intended
--no-call-home Default
--include-ads No longer supported
--no-include-ads Default
--youtube-print-sig-code No longer supported
#### Removed
These options were deprecated since 2014 and have now been entirely removed
--id -o "%(id)s.%(ext)s"
-A, --auto-number -o "%(autonumber)s-%(id)s.%(ext)s"
-t, --title -o "%(title)s-%(id)s.%(ext)s"
-l, --literal -o accepts literal names
#### Removed
Currently, there are no options that have been completely removed. But there are plans to remove the old output options `-A`,`-t`, `-l`, `--id` (which have been deprecated since 2014) in the near future. If you are still using these, please move to using `--output` instead
# MORE
For FAQ, Developer Instructions etc., see the [original README](https://github.com/ytdl-org/youtube-dl#faq)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import os

View File

@@ -1,3 +1,5 @@
# UNUSED
#!/usr/bin/python3
import argparse

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
"""

View File

@@ -1,6 +1,6 @@
# Unused
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import io

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import optparse

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
from __future__ import unicode_literals
import codecs

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import with_statement, unicode_literals

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# import io

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import io

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
from __future__ import unicode_literals, print_function
from inspect import getsource

View File

@@ -1,3 +1,8 @@
#!/usr/bin/env python3
# yt-dlp --help | make_readme.py
# This must be run in a console of correct width
from __future__ import unicode_literals
import io

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import io

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python3
from __future__ import unicode_literals
import io

View File

@@ -1,4 +1,5 @@
# Unused
#!/bin/bash
# IMPORTANT: the following assumptions are made

View File

@@ -1,6 +1,6 @@
# Unused
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import itertools

View File

@@ -1,4 +1,6 @@
#!/usr/bin/env python3
from __future__ import unicode_literals
from datetime import datetime
# import urllib.request

View File

@@ -1,3 +1,5 @@
# UNUSED
#!/bin/bash
# Run with as parameter a setup.py that works in the current directory

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import os

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals
@@ -17,7 +17,7 @@ assert arch in ('32', '64')
print('Building %sbit version' % arch)
_x86 = '_x86' if arch == '32' else ''
FILE_DESCRIPTION = 'Media Downloader%s' % (' (32 Bit)' if _x86 else '')
FILE_DESCRIPTION = 'yt-dlp%s' % (' (32 Bit)' if _x86 else '')
# root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
# print('Changing working directory to %s' % root_dir)
@@ -58,7 +58,9 @@ VERSION_FILE = VSVersionInfo(
),
StringStruct('OriginalFilename', 'yt-dlp%s.exe' % _x86),
StringStruct('ProductName', 'yt-dlp%s' % _x86),
StringStruct('ProductVersion', '%s%s' % (VERSION, _x86)),
StringStruct(
'ProductVersion',
'%s%s on Python %s' % (VERSION, _x86, platform.python_version())),
])]),
VarFileInfo([VarStruct('Translation', [0, 1200])])
]

111
setup.py
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from setuptools import setup, Command, find_packages
@@ -9,45 +9,44 @@ from distutils.spawn import spawn
# Get the version from yt_dlp/version.py without importing the package
exec(compile(open('yt_dlp/version.py').read(),
'yt_dlp/version.py', 'exec'))
exec(compile(open('yt_dlp/version.py').read(), 'yt_dlp/version.py', 'exec'))
DESCRIPTION = 'Command-line program to download videos from YouTube.com and many other other video platforms.'
LONG_DESCRIPTION = '\n\n'.join((
'Official repository: <https://github.com/yt-dlp/yt-dlp>',
'**PS**: Many links in this document will not work since this is a copy of the README.md from Github',
open("README.md", "r", encoding="utf-8").read()))
'**PS**: Some links in this document will not work since this is a copy of the README.md from Github',
open('README.md', 'r', encoding='utf-8').read()))
REQUIREMENTS = ['mutagen', 'pycryptodome']
if sys.argv[1:2] == ['py2exe']:
raise NotImplementedError('py2exe is not currently supported; instead, use "pyinst.py" to build with pyinstaller')
if len(sys.argv) >= 2 and sys.argv[1] == 'py2exe':
print("inv")
else:
files_spec = [
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
('share/zsh/site-functions', ['completions/zsh/_yt-dlp']),
('share/fish/vendor_completions.d', ['completions/fish/yt-dlp.fish']),
('share/doc/yt_dlp', ['README.txt']),
('share/man/man1', ['yt-dlp.1'])
]
root = os.path.dirname(os.path.abspath(__file__))
data_files = []
for dirname, files in files_spec:
resfiles = []
for fn in files:
if not os.path.exists(fn):
warnings.warn('Skipping file %s since it is not present. Try running `make pypi-files` first.' % fn)
else:
resfiles.append(fn)
data_files.append((dirname, resfiles))
params = {
'data_files': data_files,
}
params['entry_points'] = {'console_scripts': ['yt-dlp = yt_dlp:main']}
files_spec = [
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
('share/zsh/site-functions', ['completions/zsh/_yt-dlp']),
('share/fish/vendor_completions.d', ['completions/fish/yt-dlp.fish']),
('share/doc/yt_dlp', ['README.txt']),
('share/man/man1', ['yt-dlp.1'])
]
root = os.path.dirname(os.path.abspath(__file__))
data_files = []
for dirname, files in files_spec:
resfiles = []
for fn in files:
if not os.path.exists(fn):
warnings.warn('Skipping file %s since it is not present. Try running `make pypi-files` first' % fn)
else:
resfiles.append(fn)
data_files.append((dirname, resfiles))
params = {
'data_files': data_files,
}
params['entry_points'] = {'console_scripts': ['yt-dlp = yt_dlp:main']}
class build_lazy_extractors(Command):
@@ -61,23 +60,21 @@ class build_lazy_extractors(Command):
pass
def run(self):
spawn(
[sys.executable, 'devscripts/make_lazy_extractors.py', 'yt_dlp/extractor/lazy_extractors.py'],
dry_run=self.dry_run,
)
spawn([sys.executable, 'devscripts/make_lazy_extractors.py', 'yt_dlp/extractor/lazy_extractors.py'],
dry_run=self.dry_run)
packages = find_packages(exclude=("youtube_dl", "test", "ytdlp_plugins"))
packages = find_packages(exclude=('youtube_dl', 'test', 'ytdlp_plugins'))
setup(
name="yt-dlp",
name='yt-dlp',
version=__version__,
maintainer="pukkandan",
maintainer_email="pukkandan.ytdlp@gmail.com",
maintainer='pukkandan',
maintainer_email='pukkandan.ytdlp@gmail.com',
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
long_description_content_type="text/markdown",
url="https://github.com/yt-dlp/yt-dlp",
long_description_content_type='text/markdown',
url='https://github.com/yt-dlp/yt-dlp',
packages=packages,
install_requires=REQUIREMENTS,
project_urls={
@@ -87,30 +84,20 @@ setup(
#'Funding': 'https://donate.pypi.org',
},
classifiers=[
"Topic :: Multimedia :: Video",
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.2",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: Implementation",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: IronPython",
"Programming Language :: Python :: Implementation :: Jython",
"Programming Language :: Python :: Implementation :: PyPy",
"License :: Public Domain",
"Operating System :: OS Independent",
'Topic :: Multimedia :: Video',
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Programming Language :: Python',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: Implementation',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'License :: Public Domain',
'Operating System :: OS Independent',
],
python_requires='>=2.6',
python_requires='>=3.6',
cmdclass={'build_lazy_extractors': build_lazy_extractors},
**params

View File

@@ -82,6 +82,7 @@
- **audiomack**
- **audiomack:album**
- **Audius**: Audius.co
- **audius:artist**: Audius.co profile/artist pages
- **audius:playlist**: Audius.co playlists
- **audius:track**: Audius track ID or API link. Prepend with "audius:"
- **AWAAN**
@@ -130,7 +131,6 @@
- **bitwave:stream**
- **BleacherReport**
- **BleacherReportCMS**
- **blinkx**
- **Bloomberg**
- **BokeCC**
- **BongaCams**
@@ -225,7 +225,8 @@
- **Culturebox**
- **CultureUnplugged**
- **curiositystream**
- **curiositystream:collection**
- **curiositystream:collections**
- **curiositystream:series**
- **CWTV**
- **DagelijkseKost**: dagelijksekost.een.be
- **DailyMail**
@@ -306,6 +307,7 @@
- **EyedoTV**
- **facebook**
- **FacebookPluginsVideo**
- **fancode:vod**
- **faz.net**
- **fc2**
- **fc2:embed**
@@ -391,6 +393,7 @@
- **HotNewHipHop**
- **hotstar**
- **hotstar:playlist**
- **hotstar:series**
- **Howcast**
- **HowStuffWorks**
- **hrfernsehen**
@@ -584,6 +587,7 @@
- **Mwave**
- **MwaveMeetGreet**
- **Mxplayer**
- **MxplayerShow**
- **MyChannels**
- **MySpace**
- **MySpace:album**
@@ -724,6 +728,7 @@
- **pandora.tv**: 판도라TV
- **ParamountNetwork**
- **parliamentlive.tv**: UK parliament videos
- **Parlview**
- **Patreon**
- **pbs**: Public Broadcasting Service (PBS) and member stations: PBS: Public Broadcasting Service, APT - Alabama Public Television (WBIQ), GPB/Georgia Public Broadcasting (WGTV), Mississippi Public Broadcasting (WMPN), Nashville Public Television (WNPT), WFSU-TV (WFSU), WSRE (WSRE), WTCI (WTCI), WPBA/Channel 30 (WPBA), Alaska Public Media (KAKM), Arizona PBS (KAET), KNME-TV/Channel 5 (KNME), Vegas PBS (KLVX), AETN/ARKANSAS ETV NETWORK (KETS), KET (WKLE), WKNO/Channel 10 (WKNO), LPB/LOUISIANA PUBLIC BROADCASTING (WLPB), OETA (KETA), Ozarks Public Television (KOZK), WSIU Public Broadcasting (WSIU), KEET TV (KEET), KIXE/Channel 9 (KIXE), KPBS San Diego (KPBS), KQED (KQED), KVIE Public Television (KVIE), PBS SoCal/KOCE (KOCE), ValleyPBS (KVPT), CONNECTICUT PUBLIC TELEVISION (WEDH), KNPB Channel 5 (KNPB), SOPTV (KSYS), Rocky Mountain PBS (KRMA), KENW-TV3 (KENW), KUED Channel 7 (KUED), Wyoming PBS (KCWC), Colorado Public Television / KBDI 12 (KBDI), KBYU-TV (KBYU), Thirteen/WNET New York (WNET), WGBH/Channel 2 (WGBH), WGBY (WGBY), NJTV Public Media NJ (WNJT), WLIW21 (WLIW), mpt/Maryland Public Television (WMPB), WETA Television and Radio (WETA), WHYY (WHYY), PBS 39 (WLVT), WVPT - Your Source for PBS and More! (WVPT), Howard University Television (WHUT), WEDU PBS (WEDU), WGCU Public Media (WGCU), WPBT2 (WPBT), WUCF TV (WUCF), WUFT/Channel 5 (WUFT), WXEL/Channel 42 (WXEL), WLRN/Channel 17 (WLRN), WUSF Public Broadcasting (WUSF), ETV (WRLK), UNC-TV (WUNC), PBS Hawaii - Oceanic Cable Channel 10 (KHET), Idaho Public Television (KAID), KSPS (KSPS), OPB (KOPB), KWSU/Channel 10 & KTNW/Channel 31 (KWSU), WILL-TV (WILL), Network Knowledge - WSEC/Springfield (WSEC), WTTW11 (WTTW), Iowa Public Television/IPTV (KDIN), Nine Network (KETC), PBS39 Fort Wayne (WFWA), WFYI Indianapolis (WFYI), Milwaukee Public Television (WMVS), WNIN (WNIN), WNIT Public Television (WNIT), WPT (WPNE), WVUT/Channel 22 (WVUT), WEIU/Channel 51 (WEIU), WQPT-TV (WQPT), WYCC PBS Chicago (WYCC), WIPB-TV (WIPB), WTIU (WTIU), CET (WCET), ThinkTVNetwork (WPTD), WBGU-TV (WBGU), WGVU TV (WGVU), NET1 (KUON), Pioneer Public Television (KWCM), SDPB Television (KUSD), TPT (KTCA), KSMQ (KSMQ), KPTS/Channel 8 (KPTS), KTWU/Channel 11 (KTWU), East Tennessee PBS (WSJK), WCTE-TV (WCTE), WLJT, Channel 11 (WLJT), WOSU TV (WOSU), WOUB/WOUC (WOUB), WVPB (WVPB), WKYU-PBS (WKYU), KERA 13 (KERA), MPBN (WCBB), Mountain Lake PBS (WCFE), NHPTV (WENH), Vermont PBS (WETK), witf (WITF), WQED Multimedia (WQED), WMHT Educational Telecommunications (WMHT), Q-TV (WDCQ), WTVS Detroit Public TV (WTVS), CMU Public Television (WCMU), WKAR-TV (WKAR), WNMU-TV Public TV 13 (WNMU), WDSE - WRPT (WDSE), WGTE TV (WGTE), Lakeland Public Television (KAWE), KMOS-TV - Channels 6.1, 6.2 and 6.3 (KMOS), MontanaPBS (KUSM), KRWG/Channel 22 (KRWG), KACV (KACV), KCOS/Channel 13 (KCOS), WCNY/Channel 24 (WCNY), WNED (WNED), WPBS (WPBS), WSKG Public TV (WSKG), WXXI (WXXI), WPSU (WPSU), WVIA Public Media Studios (WVIA), WTVI (WTVI), Western Reserve PBS (WNEO), WVIZ/PBS ideastream (WVIZ), KCTS 9 (KCTS), Basin PBS (KPBT), KUHT / Channel 8 (KUHT), KLRN (KLRN), KLRU (KLRU), WTJX Channel 12 (WTJX), WCVE PBS (WCVE), KBTC Public Television (KBTC)
- **PearVideo**
@@ -747,6 +752,7 @@
- **play.fm**
- **player.sky.it**
- **PlayPlusTV**
- **PlayStuff**
- **PlaysTV**
- **Playtvak**: Playtvak.cz, iDNES.cz and Lidovky.cz
- **Playvid**
@@ -855,6 +861,7 @@
- **safari**: safaribooksonline.com online video
- **safari:api**
- **safari:course**: safaribooksonline.com online courses
- **Saitosan**
- **SAKTV**
- **SaltTV**
- **SampleFocus**
@@ -879,6 +886,7 @@
- **Shahid**
- **ShahidShow**
- **Shared**: shared.sx
- **ShemarooMe**
- **ShowRoomLive**
- **simplecast**
- **simplecast:episode**
@@ -898,6 +906,7 @@
- **Snotr**
- **Sohu**
- **SonyLIV**
- **SonyLIVSeries**
- **soundcloud**
- **soundcloud:playlist**
- **soundcloud:search**: Soundcloud search
@@ -976,6 +985,7 @@
- **Telecinco**: telecinco.es, cuatro.com and mediaset.es
- **Telegraaf**
- **TeleMB**
- **Telemundo**
- **TeleQuebec**
- **TeleQuebecEmission**
- **TeleQuebecLive**
@@ -1059,6 +1069,8 @@
- **TVPlayHome**
- **Tweakers**
- **TwitCasting**
- **TwitCastingLive**
- **TwitCastingUser**
- **twitch:clips**
- **twitch:stream**
- **twitch:vod**
@@ -1076,6 +1088,7 @@
- **UDNEmbed**: 聯合影音
- **UFCArabia**
- **UFCTV**
- **ukcolumn**
- **UKTVPlay**
- **umg:de**: Universal Music Deutschland
- **Unistra**
@@ -1119,6 +1132,8 @@
- **videomore:video**
- **VideoPress**
- **Vidio**
- **VidioLive**
- **VidioPremier**
- **VidLii**
- **vidme**
- **vidme:user**
@@ -1158,6 +1173,7 @@
- **VODPlatform**
- **VoiceRepublic**
- **Voot**
- **VootSeries**
- **VoxMedia**
- **VoxMediaVolume**
- **vpro**: npo.nl, ntr.nl, omroepwnl.nl, zapp.nl and npo3.nl
@@ -1187,6 +1203,7 @@
- **wdr:mobile**
- **WDRElefant**
- **WDRPage**
- **web.archive:youtube**: web.archive.org saved youtube videos
- **Webcaster**
- **WebcasterFeed**
- **WebOfStories**
@@ -1194,6 +1211,7 @@
- **Weibo**
- **WeiboMobile**
- **WeiqiTV**: WQTV
- **whowatch**
- **WimTV**
- **Wistia**
- **WistiaPlaylist**
@@ -1204,7 +1222,7 @@
- **WWE**
- **XBef**
- **XboxClips**
- **XFileShare**: XFileShare based sites: Aparat, ClipWatching, GoUnlimited, GoVid, HolaVid, Streamty, TheVideoBee, Uqload, VidBom, vidlo, VidLocker, VidShare, VUp, XVideoSharing
- **XFileShare**: XFileShare based sites: Aparat, ClipWatching, GoUnlimited, GoVid, HolaVid, Streamty, TheVideoBee, Uqload, VidBom, vidlo, VidLocker, VidShare, VUp, WolfStream, XVideoSharing
- **XHamster**
- **XHamsterEmbed**
- **XHamsterUser**

View File

@@ -1,41 +1,40 @@
{
"consoletitle": false,
"continuedl": true,
"forcedescription": false,
"forcefilename": false,
"forceformat": false,
"forcethumbnail": false,
"forcetitle": false,
"forceurl": false,
"consoletitle": false,
"continuedl": true,
"forcedescription": false,
"forcefilename": false,
"forceformat": false,
"forcethumbnail": false,
"forcetitle": false,
"forceurl": false,
"force_write_download_archive": false,
"format": "best",
"ignoreerrors": false,
"listformats": null,
"logtostderr": false,
"matchtitle": null,
"max_downloads": null,
"overwrites": null,
"nopart": false,
"noprogress": false,
"outtmpl": "%(id)s.%(ext)s",
"password": null,
"playlistend": -1,
"playliststart": 1,
"prefer_free_formats": false,
"quiet": false,
"ratelimit": null,
"rejecttitle": null,
"retries": 10,
"simulate": false,
"subtitleslang": null,
"ignoreerrors": false,
"listformats": null,
"logtostderr": false,
"matchtitle": null,
"max_downloads": null,
"overwrites": null,
"nopart": false,
"noprogress": false,
"outtmpl": "%(id)s.%(ext)s",
"password": null,
"playliststart": 1,
"prefer_free_formats": false,
"quiet": false,
"ratelimit": null,
"rejecttitle": null,
"retries": 10,
"simulate": false,
"subtitleslang": null,
"subtitlesformat": "best",
"test": true,
"updatetime": true,
"usenetrc": false,
"username": null,
"verbose": true,
"writedescription": false,
"writeinfojson": true,
"test": true,
"updatetime": true,
"usenetrc": false,
"username": null,
"verbose": true,
"writedescription": false,
"writeinfojson": true,
"writeannotations": false,
"writelink": false,
"writeurllink": false,

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
@@ -450,7 +450,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'language': 'en',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'audio_ext': 'mp4',
}, {
'format_id': 'aud2-English',
@@ -458,7 +458,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'language': 'en',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'audio_ext': 'mp4',
}, {
'format_id': 'aud3-English',
@@ -466,14 +466,14 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'language': 'en',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'audio_ext': 'mp4',
}, {
'format_id': '530',
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 480,
'height': 270,
'vcodec': 'avc1.640015',
@@ -482,7 +482,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 480,
'height': 270,
'vcodec': 'avc1.640015',
@@ -491,7 +491,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v2/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 480,
'height': 270,
'vcodec': 'avc1.640015',
@@ -500,7 +500,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 640,
'height': 360,
'vcodec': 'avc1.64001e',
@@ -509,7 +509,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 640,
'height': 360,
'vcodec': 'avc1.64001e',
@@ -518,7 +518,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v3/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 640,
'height': 360,
'vcodec': 'avc1.64001e',
@@ -527,7 +527,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 768,
'height': 432,
'vcodec': 'avc1.64001e',
@@ -536,7 +536,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 768,
'height': 432,
'vcodec': 'avc1.64001e',
@@ -545,7 +545,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v4/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 768,
'height': 432,
'vcodec': 'avc1.64001e',
@@ -554,7 +554,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 960,
'height': 540,
'vcodec': 'avc1.640020',
@@ -563,7 +563,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 960,
'height': 540,
'vcodec': 'avc1.640020',
@@ -572,7 +572,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v5/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 960,
'height': 540,
'vcodec': 'avc1.640020',
@@ -581,7 +581,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1280,
'height': 720,
'vcodec': 'avc1.640020',
@@ -590,7 +590,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1280,
'height': 720,
'vcodec': 'avc1.640020',
@@ -599,7 +599,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v6/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1280,
'height': 720,
'vcodec': 'avc1.640020',
@@ -608,7 +608,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -617,7 +617,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -626,7 +626,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v7/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -635,7 +635,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -644,7 +644,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -653,7 +653,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v8/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -662,7 +662,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -671,7 +671,7 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
@@ -680,21 +680,190 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/v9/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8',
'ext': 'mp4',
'protocol': 'm3u8',
'protocol': 'm3u8_native',
'width': 1920,
'height': 1080,
'vcodec': 'avc1.64002a',
}]
}],
{}
),
(
'bipbop_16x9',
'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
[{
'format_id': 'bipbop_audio-BipBop Audio 2',
'format_index': None,
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/alternate_audio_aac/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
'language': 'eng',
'ext': 'mp4',
'protocol': 'm3u8_native',
'preference': None,
'quality': None,
'vcodec': 'none',
'audio_ext': 'mp4',
'video_ext': 'none',
}, {
'format_id': '41',
'format_index': None,
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear0/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
'tbr': 41.457,
'ext': 'mp4',
'fps': None,
'protocol': 'm3u8_native',
'preference': None,
'quality': None,
'vcodec': 'none',
'acodec': 'mp4a.40.2',
'audio_ext': 'mp4',
'video_ext': 'none',
'abr': 41.457,
}, {
'format_id': '263',
'format_index': None,
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear1/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
'tbr': 263.851,
'ext': 'mp4',
'fps': None,
'protocol': 'm3u8_native',
'preference': None,
'quality': None,
'width': 416,
'height': 234,
'vcodec': 'avc1.4d400d',
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 263.851,
'abr': 0,
}, {
'format_id': '577',
'format_index': None,
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear2/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
'tbr': 577.61,
'ext': 'mp4',
'fps': None,
'protocol': 'm3u8_native',
'preference': None,
'quality': None,
'width': 640,
'height': 360,
'vcodec': 'avc1.4d401e',
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 577.61,
'abr': 0,
}, {
'format_id': '915',
'format_index': None,
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear3/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
'tbr': 915.905,
'ext': 'mp4',
'fps': None,
'protocol': 'm3u8_native',
'preference': None,
'quality': None,
'width': 960,
'height': 540,
'vcodec': 'avc1.4d401f',
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 915.905,
'abr': 0,
}, {
'format_id': '1030',
'format_index': None,
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear4/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
'tbr': 1030.138,
'ext': 'mp4',
'fps': None,
'protocol': 'm3u8_native',
'preference': None,
'quality': None,
'width': 1280,
'height': 720,
'vcodec': 'avc1.4d401f',
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 1030.138,
'abr': 0,
}, {
'format_id': '1924',
'format_index': None,
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/gear5/prog_index.m3u8',
'manifest_url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8',
'tbr': 1924.009,
'ext': 'mp4',
'fps': None,
'protocol': 'm3u8_native',
'preference': None,
'quality': None,
'width': 1920,
'height': 1080,
'vcodec': 'avc1.4d401f',
'acodec': 'mp4a.40.2',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 1924.009,
'abr': 0,
}],
{
'en': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/eng/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/eng_forced/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}],
'fr': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/fra/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/fra_forced/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}],
'es': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/spa/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/spa_forced/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}],
'ja': [{
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/jpn/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}, {
'url': 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/subtitles/jpn_forced/prog_index.m3u8',
'ext': 'vtt',
'protocol': 'm3u8_native'
}],
}
),
]
for m3u8_file, m3u8_url, expected_formats in _TEST_CASES:
for m3u8_file, m3u8_url, expected_formats, expected_subs in _TEST_CASES:
with io.open('./test/testdata/m3u8/%s.m3u8' % m3u8_file,
mode='r', encoding='utf-8') as f:
formats = self.ie._parse_m3u8_formats(
formats, subs = self.ie._parse_m3u8_formats_and_subtitles(
f.read(), m3u8_url, ext='mp4')
self.ie._sort_formats(formats)
expect_value(self, formats, expected_formats, None)
expect_value(self, subs, expected_subs, None)
def test_parse_mpd_formats(self):
_TEST_CASES = [
@@ -780,7 +949,8 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'tbr': 5997.485,
'width': 1920,
'height': 1080,
}]
}],
{},
), (
# https://github.com/ytdl-org/youtube-dl/pull/14844
'urls_only',
@@ -863,7 +1033,8 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'tbr': 4400,
'width': 1920,
'height': 1080,
}]
}],
{},
), (
# https://github.com/ytdl-org/youtube-dl/issues/20346
# Media considered unfragmented even though it contains
@@ -909,18 +1080,328 @@ jwplayer("mediaplayer").setup({"abouttext":"Visit Indie DB","aboutlink":"http:\/
'width': 360,
'height': 360,
'fps': 30,
}]
}],
{},
), (
'subtitles',
'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/',
[{
'format_id': 'audio=128001',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'ext': 'm4a',
'tbr': 128.001,
'asr': 48000,
'format_note': 'DASH audio',
'container': 'm4a_dash',
'vcodec': 'none',
'acodec': 'mp4a.40.2',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
'audio_ext': 'm4a',
'video_ext': 'none',
'abr': 128.001,
}, {
'format_id': 'video=100000',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'ext': 'mp4',
'width': 336,
'height': 144,
'tbr': 100,
'format_note': 'DASH video',
'container': 'mp4_dash',
'vcodec': 'avc1.4D401F',
'acodec': 'none',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 100,
}, {
'format_id': 'video=326000',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'ext': 'mp4',
'width': 562,
'height': 240,
'tbr': 326,
'format_note': 'DASH video',
'container': 'mp4_dash',
'vcodec': 'avc1.4D401F',
'acodec': 'none',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 326,
}, {
'format_id': 'video=698000',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'ext': 'mp4',
'width': 844,
'height': 360,
'tbr': 698,
'format_note': 'DASH video',
'container': 'mp4_dash',
'vcodec': 'avc1.4D401F',
'acodec': 'none',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 698,
}, {
'format_id': 'video=1493000',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'ext': 'mp4',
'width': 1126,
'height': 480,
'tbr': 1493,
'format_note': 'DASH video',
'container': 'mp4_dash',
'vcodec': 'avc1.4D401F',
'acodec': 'none',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 1493,
}, {
'format_id': 'video=4482000',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'ext': 'mp4',
'width': 1688,
'height': 720,
'tbr': 4482,
'format_note': 'DASH video',
'container': 'mp4_dash',
'vcodec': 'avc1.4D401F',
'acodec': 'none',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
'video_ext': 'mp4',
'audio_ext': 'none',
'vbr': 4482,
}],
{
'en': [
{
'ext': 'mp4',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/manifest.mpd',
'fragment_base_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/dash/',
'protocol': 'http_dash_segments',
}
]
},
)
]
for mpd_file, mpd_url, mpd_base_url, expected_formats in _TEST_CASES:
for mpd_file, mpd_url, mpd_base_url, expected_formats, expected_subtitles in _TEST_CASES:
with io.open('./test/testdata/mpd/%s.mpd' % mpd_file,
mode='r', encoding='utf-8') as f:
formats = self.ie._parse_mpd_formats(
formats, subtitles = self.ie._parse_mpd_formats_and_subtitles(
compat_etree_fromstring(f.read().encode('utf-8')),
mpd_base_url=mpd_base_url, mpd_url=mpd_url)
self.ie._sort_formats(formats)
expect_value(self, formats, expected_formats, None)
expect_value(self, subtitles, expected_subtitles, None)
def test_parse_ism_formats(self):
_TEST_CASES = [
(
'sintel',
'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
[{
'format_id': 'audio-128',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'ext': 'isma',
'tbr': 128,
'asr': 48000,
'vcodec': 'none',
'acodec': 'AACL',
'protocol': 'ism',
'_download_params': {
'stream_type': 'audio',
'duration': 8880746666,
'timescale': 10000000,
'width': 0,
'height': 0,
'fourcc': 'AACL',
'codec_private_data': '1190',
'sampling_rate': 48000,
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
'audio_ext': 'isma',
'video_ext': 'none',
'abr': 128,
}, {
'format_id': 'video-100',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'ext': 'ismv',
'width': 336,
'height': 144,
'tbr': 100,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'_download_params': {
'stream_type': 'video',
'duration': 8880746666,
'timescale': 10000000,
'width': 336,
'height': 144,
'fourcc': 'AVC1',
'codec_private_data': '00000001674D401FDA0544EFFC2D002CBC40000003004000000C03C60CA80000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
'video_ext': 'ismv',
'audio_ext': 'none',
'vbr': 100,
}, {
'format_id': 'video-326',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'ext': 'ismv',
'width': 562,
'height': 240,
'tbr': 326,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'_download_params': {
'stream_type': 'video',
'duration': 8880746666,
'timescale': 10000000,
'width': 562,
'height': 240,
'fourcc': 'AVC1',
'codec_private_data': '00000001674D401FDA0241FE23FFC3BC83BA44000003000400000300C03C60CA800000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
'video_ext': 'ismv',
'audio_ext': 'none',
'vbr': 326,
}, {
'format_id': 'video-698',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'ext': 'ismv',
'width': 844,
'height': 360,
'tbr': 698,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'_download_params': {
'stream_type': 'video',
'duration': 8880746666,
'timescale': 10000000,
'width': 844,
'height': 360,
'fourcc': 'AVC1',
'codec_private_data': '00000001674D401FDA0350BFB97FF06AF06AD1000003000100000300300F1832A00000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
'video_ext': 'ismv',
'audio_ext': 'none',
'vbr': 698,
}, {
'format_id': 'video-1493',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'ext': 'ismv',
'width': 1126,
'height': 480,
'tbr': 1493,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'_download_params': {
'stream_type': 'video',
'duration': 8880746666,
'timescale': 10000000,
'width': 1126,
'height': 480,
'fourcc': 'AVC1',
'codec_private_data': '00000001674D401FDA011C3DE6FFF0D890D871000003000100000300300F1832A00000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
'video_ext': 'ismv',
'audio_ext': 'none',
'vbr': 1493,
}, {
'format_id': 'video-4482',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'ext': 'ismv',
'width': 1688,
'height': 720,
'tbr': 4482,
'vcodec': 'AVC1',
'acodec': 'none',
'protocol': 'ism',
'_download_params': {
'stream_type': 'video',
'duration': 8880746666,
'timescale': 10000000,
'width': 1688,
'height': 720,
'fourcc': 'AVC1',
'codec_private_data': '00000001674D401FDA01A816F97FFC1ABC1AB440000003004000000C03C60CA80000000168EF32C8',
'channels': 2,
'bits_per_sample': 16,
'nal_unit_length_field': 4
},
'video_ext': 'ismv',
'audio_ext': 'none',
'vbr': 4482,
}],
{
'eng': [
{
'ext': 'ismt',
'protocol': 'ism',
'url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'manifest_url': 'https://sdn-global-streaming-cache-3qsdn.akamaized.net/stream/3144/files/17/07/672975/3144-kZT4LWMQw6Rh7Kpd.ism/Manifest',
'_download_params': {
'stream_type': 'text',
'duration': 8880746666,
'timescale': 10000000,
'fourcc': 'TTML',
'codec_private_data': ''
}
}
]
},
),
]
for ism_file, ism_url, expected_formats, expected_subtitles in _TEST_CASES:
with io.open('./test/testdata/ism/%s.Manifest' % ism_file,
mode='r', encoding='utf-8') as f:
formats, subtitles = self.ie._parse_ism_formats_and_subtitles(
compat_etree_fromstring(f.read().encode('utf-8')), ism_url=ism_url)
self.ie._sort_formats(formats)
expect_value(self, formats, expected_formats, None)
expect_value(self, subtitles, expected_subtitles, None)
def test_parse_f4m_formats(self):
_TEST_CASES = [

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals
@@ -17,7 +17,7 @@ from yt_dlp.compat import compat_str, compat_urllib_error
from yt_dlp.extractor import YoutubeIE
from yt_dlp.extractor.common import InfoExtractor
from yt_dlp.postprocessor.common import PostProcessor
from yt_dlp.utils import ExtractorError, match_filter_func
from yt_dlp.utils import ExtractorError, float_or_none, match_filter_func
TEST_URL = 'http://localhost/sample.mp4'
@@ -29,6 +29,7 @@ class YDL(FakeYDL):
self.msgs = []
def process_info(self, info_dict):
info_dict.pop('__original_infodict', None)
self.downloaded_info_dicts.append(info_dict)
def to_screen(self, msg):
@@ -647,56 +648,108 @@ class TestYoutubeDL(unittest.TestCase):
self.assertEqual(test_dict['extractor'], 'Foo')
self.assertEqual(test_dict['playlist'], 'funny videos')
def test_prepare_filename(self):
info = {
'id': '1234',
'ext': 'mp4',
'width': None,
'height': 1080,
'title1': '$PATH',
'title2': '%PATH%',
'timestamp': 1618488000,
'formats': [{'id': 'id1'}, {'id': 'id2'}]
}
outtmpl_info = {
'id': '1234',
'ext': 'mp4',
'width': None,
'height': 1080,
'title1': '$PATH',
'title2': '%PATH%',
'title3': 'foo/bar\\test',
'timestamp': 1618488000,
'duration': 100000,
'playlist_index': 1,
'_last_playlist_index': 100,
'n_entries': 10,
'formats': [{'id': 'id1'}, {'id': 'id2'}, {'id': 'id3'}]
}
def fname(templ, na_placeholder='NA'):
params = {'outtmpl': templ}
if na_placeholder != 'NA':
params['outtmpl_na_placeholder'] = na_placeholder
def test_prepare_outtmpl(self):
def out(tmpl, **params):
params['outtmpl'] = tmpl
ydl = YoutubeDL(params)
return ydl.prepare_filename(info)
self.assertEqual(fname('%(id)s.%(ext)s'), '1234.mp4')
self.assertEqual(fname('%(id)s-%(width)s.%(ext)s'), '1234-NA.mp4')
NA_TEST_OUTTMPL = '%(uploader_date)s-%(width)d-%(id)s.%(ext)s'
# Replace missing fields with 'NA' by default
self.assertEqual(fname(NA_TEST_OUTTMPL), 'NA-NA-1234.mp4')
# Or by provided placeholder
self.assertEqual(fname(NA_TEST_OUTTMPL, na_placeholder='none'), 'none-none-1234.mp4')
self.assertEqual(fname(NA_TEST_OUTTMPL, na_placeholder=''), '--1234.mp4')
self.assertEqual(fname('%(height)s.%(ext)s'), '1080.mp4')
self.assertEqual(fname('%(height)d.%(ext)s'), '1080.mp4')
self.assertEqual(fname('%(height)6d.%(ext)s'), ' 1080.mp4')
self.assertEqual(fname('%(height)-6d.%(ext)s'), '1080 .mp4')
self.assertEqual(fname('%(height)06d.%(ext)s'), '001080.mp4')
self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
self.assertEqual(fname('%(height) 06d.%(ext)s'), ' 01080.mp4')
self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
self.assertEqual(fname('%(height)0 6d.%(ext)s'), ' 01080.mp4')
self.assertEqual(fname('%(height) 0 6d.%(ext)s'), ' 01080.mp4')
ydl._num_downloads = 1
err = ydl.validate_outtmpl(tmpl)
if err:
raise err
outtmpl, tmpl_dict = ydl.prepare_outtmpl(tmpl, self.outtmpl_info)
return outtmpl % tmpl_dict
self.assertEqual(out('%(id)s.%(ext)s'), '1234.mp4')
self.assertEqual(out('%(duration_string)s'), '27:46:40')
self.assertTrue(float_or_none(out('%(epoch)d')))
self.assertEqual(out('%(resolution)s'), '1080p')
self.assertEqual(out('%(playlist_index)s'), '001')
self.assertEqual(out('%(autonumber)s'), '00001')
self.assertEqual(out('%(autonumber+2)03d', autonumber_start=3), '005')
self.assertEqual(out('%(autonumber)s', autonumber_size=3), '001')
self.assertEqual(out('%%'), '%')
self.assertEqual(out('%%%%'), '%%')
self.assertEqual(out('%(invalid@tmpl|def)s', outtmpl_na_placeholder='none'), 'none')
self.assertEqual(out('%()s'), 'NA')
self.assertEqual(out('%s'), '%s')
self.assertEqual(out('%d'), '%d')
self.assertRaises(ValueError, out, '%')
self.assertRaises(ValueError, out, '%(title)')
NA_TEST_OUTTMPL = '%(uploader_date)s-%(width)d-%(x|def)s-%(id)s.%(ext)s'
self.assertEqual(out(NA_TEST_OUTTMPL), 'NA-NA-def-1234.mp4')
self.assertEqual(out(NA_TEST_OUTTMPL, outtmpl_na_placeholder='none'), 'none-none-def-1234.mp4')
self.assertEqual(out(NA_TEST_OUTTMPL, outtmpl_na_placeholder=''), '--def-1234.mp4')
FMT_TEST_OUTTMPL = '%%(height)%s.%%(ext)s'
self.assertEqual(out(FMT_TEST_OUTTMPL % 's'), '1080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % 'd'), '1080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % '6d'), ' 1080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % '-6d'), '1080 .mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % '06d'), '001080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % ' 06d'), ' 01080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % ' 06d'), ' 01080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % '0 6d'), ' 01080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % '0 6d'), ' 01080.mp4')
self.assertEqual(out(FMT_TEST_OUTTMPL % ' 0 6d'), ' 01080.mp4')
self.assertEqual(out('%(id)d'), '1234')
self.assertEqual(out('%(height)c'), '1')
self.assertEqual(out('%(ext)c'), 'm')
self.assertEqual(out('%(id)d %(id)r'), "1234 '1234'")
self.assertEqual(out('%(ext)s-%(ext|def)d'), 'mp4-def')
self.assertEqual(out('%(width|0)04d'), '0000')
self.assertEqual(out('%(width|)d', outtmpl_na_placeholder='none'), '')
FORMATS = self.outtmpl_info['formats']
self.assertEqual(out('%(timestamp+-1000>%H-%M-%S)s'), '11-43-20')
self.assertEqual(out('%(id+1-height+3)05d'), '00158')
self.assertEqual(out('%(width+100)05d'), 'NA')
self.assertEqual(out('%(formats.0)s'), str(FORMATS[0]))
self.assertEqual(out('%(height.0)03d'), '001')
self.assertEqual(out('%(formats.-1.id)s'), str(FORMATS[-1]['id']))
self.assertEqual(out('%(formats.3)s'), 'NA')
self.assertEqual(out('%(formats.:2:-1)r'), repr(FORMATS[:2:-1]))
self.assertEqual(out('%(formats.0.id.-1+id)f'), '1235.000000')
def test_prepare_filename(self):
def fname(templ):
params = {'outtmpl': templ}
ydl = YoutubeDL(params)
return ydl.prepare_filename(self.outtmpl_info)
self.assertEqual(fname('%%'), '%')
self.assertEqual(fname('%%%%'), '%%')
self.assertEqual(fname('%%(height)06d.%(ext)s'), '%(height)06d.mp4')
self.assertEqual(fname('%%(width)06d.%(ext)s'), '%(width)06d.mp4')
self.assertEqual(fname('%(width)06d.%(ext)s'), 'NA.mp4')
self.assertEqual(fname('%(width)06d.%%(ext)s'), 'NA.%(ext)s')
self.assertEqual(fname('%%(width)06d.%(ext)s'), '%(width)06d.mp4')
self.assertEqual(fname('Hello %(title1)s'), 'Hello $PATH')
self.assertEqual(fname('Hello %(title2)s'), 'Hello %PATH%')
self.assertEqual(fname('%(timestamp+-1000>%H-%M-%S)s'), '11-43-20')
self.assertEqual(fname('%(id+1)05d'), '01235')
self.assertEqual(fname('%(width+100)05d'), 'NA')
self.assertEqual(fname('%(formats.0)s').replace("u", ""), "{'id' - 'id1'}")
self.assertEqual(fname('%(formats.-1.id)s'), 'id2')
self.assertEqual(fname('%(formats.2)s'), 'NA')
self.assertEqual(fname('%(title3)s'), 'foo_bar_test')
self.assertEqual(fname('%(formats.0)s'), "{'id' - 'id1'}")
self.assertEqual(fname('%(id)r %(height)r'), "'1234' 1080")
self.assertEqual(fname('%(formats.0)r'), "{'id' - 'id1'}")
def test_format_note(self):
ydl = YoutubeDL()
@@ -755,7 +808,7 @@ class TestYoutubeDL(unittest.TestCase):
def process_info(self, info_dict):
super(YDL, self).process_info(info_dict)
def _match_entry(self, info_dict, incomplete):
def _match_entry(self, info_dict, incomplete=False):
res = super(FilterYDL, self)._match_entry(info_dict, incomplete)
if res is None:
self.downloaded_info_dicts.append(info_dict)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,5 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# Allow direct execution

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# Allow direct execution

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
@@ -121,6 +121,7 @@ def generator(test_case, tname):
params['outtmpl'] = tname + '_' + params['outtmpl']
if is_playlist and 'playlist' not in test_case:
params.setdefault('extract_flat', 'in_playlist')
params.setdefault('playlistend', test_case.get('playlist_mincount'))
params.setdefault('skip_download', True)
ydl = YoutubeDL(params, auto_init=False)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
import os

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
@@ -8,7 +8,14 @@ import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from yt_dlp.postprocessor import MetadataFromFieldPP, MetadataFromTitlePP
from yt_dlp import YoutubeDL
from yt_dlp.compat import compat_shlex_quote
from yt_dlp.postprocessor import (
ExecAfterDownloadPP,
FFmpegThumbnailsConvertorPP,
MetadataFromFieldPP,
MetadataFromTitlePP,
)
class TestMetadataFromField(unittest.TestCase):
@@ -30,3 +37,35 @@ class TestMetadataFromTitle(unittest.TestCase):
def test_format_to_regex(self):
pp = MetadataFromTitlePP(None, '%(title)s - %(artist)s')
self.assertEqual(pp._titleregex, r'(?P<title>.+)\ \-\ (?P<artist>.+)')
class TestConvertThumbnail(unittest.TestCase):
def test_escaping(self):
pp = FFmpegThumbnailsConvertorPP()
if not pp.available:
print('Skipping: ffmpeg not found')
return
file = 'test/testdata/thumbnails/foo %d bar/foo_%d.{}'
tests = (('webp', 'png'), ('png', 'jpg'))
for inp, out in tests:
out_file = file.format(out)
if os.path.exists(out_file):
os.remove(out_file)
pp.convert_thumbnail(file.format(inp), out)
assert os.path.exists(out_file)
for _, out in tests:
os.remove(file.format(out))
class TestExecAfterDownload(unittest.TestCase):
def test_parse_cmd(self):
pp = ExecAfterDownloadPP(YoutubeDL(), '')
info = {'filepath': 'file name'}
quoted_filepath = compat_shlex_quote(info['filepath'])
self.assertEqual(pp.parse_cmd('echo', info), 'echo %s' % quoted_filepath)
self.assertEqual(pp.parse_cmd('echo.{}', info), 'echo.%s' % quoted_filepath)
self.assertEqual(pp.parse_cmd('echo "%(filepath)s"', info), 'echo "%s"' % info['filepath'])

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# Allow direct execution

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# Allow direct execution

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals
@@ -66,6 +66,7 @@ from yt_dlp.utils import (
sanitize_filename,
sanitize_path,
sanitize_url,
sanitized_Request,
expand_path,
prepend_extension,
replace_extension,
@@ -238,6 +239,16 @@ class TestUtil(unittest.TestCase):
self.assertEqual(sanitize_url('httpss://foo.bar'), 'https://foo.bar')
self.assertEqual(sanitize_url('rmtps://foo.bar'), 'rtmps://foo.bar')
self.assertEqual(sanitize_url('https://foo.bar'), 'https://foo.bar')
self.assertEqual(sanitize_url('foo bar'), 'foo bar')
def test_extract_basic_auth(self):
auth_header = lambda url: sanitized_Request(url).get_header('Authorization')
self.assertFalse(auth_header('http://foo.bar'))
self.assertFalse(auth_header('http://:foo.bar'))
self.assertEqual(auth_header('http://@foo.bar'), 'Basic Og==')
self.assertEqual(auth_header('http://:pass@foo.bar'), 'Basic OnBhc3M=')
self.assertEqual(auth_header('http://user:@foo.bar'), 'Basic dXNlcjo=')
self.assertEqual(auth_header('http://user:pass@foo.bar'), 'Basic dXNlcjpwYXNz')
def test_expand_path(self):
def env(var):

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# Allow direct execution

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# Allow direct execution

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals

988
test/testdata/ism/sintel.Manifest vendored Normal file
View File

@@ -0,0 +1,988 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Unified Streaming Platform (version=1.10.18-20255) -->
<SmoothStreamingMedia
MajorVersion="2"
MinorVersion="0"
TimeScale="10000000"
Duration="8880746666">
<StreamIndex
Type="audio"
QualityLevels="1"
TimeScale="10000000"
Name="audio"
Chunks="445"
Url="QualityLevels({bitrate})/Fragments(audio={start time})">
<QualityLevel
Index="0"
Bitrate="128001"
CodecPrivateData="1190"
SamplingRate="48000"
Channels="2"
BitsPerSample="16"
PacketSize="4"
AudioTag="255"
FourCC="AACL" />
<c t="0" d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="20053333" />
<c d="20053333" />
<c d="20053334" />
<c d="19840000" />
<c d="746666" />
</StreamIndex>
<StreamIndex
Type="text"
QualityLevels="1"
TimeScale="10000000"
Language="eng"
Subtype="CAPT"
Name="textstream_eng"
Chunks="11"
Url="QualityLevels({bitrate})/Fragments(textstream_eng={start time})">
<QualityLevel
Index="0"
Bitrate="1000"
CodecPrivateData=""
FourCC="TTML" />
<c t="0" d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="600000000" />
<c d="240000000" />
</StreamIndex>
<StreamIndex
Type="video"
QualityLevels="5"
TimeScale="10000000"
Name="video"
Chunks="444"
Url="QualityLevels({bitrate})/Fragments(video={start time})"
MaxWidth="1688"
MaxHeight="720"
DisplayWidth="1689"
DisplayHeight="720">
<QualityLevel
Index="0"
Bitrate="100000"
CodecPrivateData="00000001674D401FDA0544EFFC2D002CBC40000003004000000C03C60CA80000000168EF32C8"
MaxWidth="336"
MaxHeight="144"
FourCC="AVC1" />
<QualityLevel
Index="1"
Bitrate="326000"
CodecPrivateData="00000001674D401FDA0241FE23FFC3BC83BA44000003000400000300C03C60CA800000000168EF32C8"
MaxWidth="562"
MaxHeight="240"
FourCC="AVC1" />
<QualityLevel
Index="2"
Bitrate="698000"
CodecPrivateData="00000001674D401FDA0350BFB97FF06AF06AD1000003000100000300300F1832A00000000168EF32C8"
MaxWidth="844"
MaxHeight="360"
FourCC="AVC1" />
<QualityLevel
Index="3"
Bitrate="1493000"
CodecPrivateData="00000001674D401FDA011C3DE6FFF0D890D871000003000100000300300F1832A00000000168EF32C8"
MaxWidth="1126"
MaxHeight="480"
FourCC="AVC1" />
<QualityLevel
Index="4"
Bitrate="4482000"
CodecPrivateData="00000001674D401FDA01A816F97FFC1ABC1AB440000003004000000C03C60CA80000000168EF32C8"
MaxWidth="1688"
MaxHeight="720"
FourCC="AVC1" />
<c t="0" d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
<c d="20000000" />
</StreamIndex>
</SmoothStreamingMedia>

38
test/testdata/m3u8/bipbop_16x9.m3u8 vendored Normal file
View File

@@ -0,0 +1,38 @@
#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="bipbop_audio",LANGUAGE="eng",NAME="BipBop Audio 1",AUTOSELECT=YES,DEFAULT=YES
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="bipbop_audio",LANGUAGE="eng",NAME="BipBop Audio 2",AUTOSELECT=NO,DEFAULT=NO,URI="alternate_audio_aac/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE="en",CHARACTERISTICS="public.accessibility.transcribes-spoken-dialog, public.accessibility.describes-music-and-sound",URI="subtitles/eng/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="English (Forced)",DEFAULT=NO,AUTOSELECT=NO,FORCED=YES,LANGUAGE="en",URI="subtitles/eng_forced/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Français",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,LANGUAGE="fr",CHARACTERISTICS="public.accessibility.transcribes-spoken-dialog, public.accessibility.describes-music-and-sound",URI="subtitles/fra/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Français (Forced)",DEFAULT=NO,AUTOSELECT=NO,FORCED=YES,LANGUAGE="fr",URI="subtitles/fra_forced/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Español",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,LANGUAGE="es",CHARACTERISTICS="public.accessibility.transcribes-spoken-dialog, public.accessibility.describes-music-and-sound",URI="subtitles/spa/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="Español (Forced)",DEFAULT=NO,AUTOSELECT=NO,FORCED=YES,LANGUAGE="es",URI="subtitles/spa_forced/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="日本語",DEFAULT=NO,AUTOSELECT=YES,FORCED=NO,LANGUAGE="ja",CHARACTERISTICS="public.accessibility.transcribes-spoken-dialog, public.accessibility.describes-music-and-sound",URI="subtitles/jpn/prog_index.m3u8"
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="日本語 (Forced)",DEFAULT=NO,AUTOSELECT=NO,FORCED=YES,LANGUAGE="ja",URI="subtitles/jpn_forced/prog_index.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=263851,CODECS="mp4a.40.2, avc1.4d400d",RESOLUTION=416x234,AUDIO="bipbop_audio",SUBTITLES="subs"
gear1/prog_index.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=28451,CODECS="avc1.4d400d",URI="gear1/iframe_index.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=577610,CODECS="mp4a.40.2, avc1.4d401e",RESOLUTION=640x360,AUDIO="bipbop_audio",SUBTITLES="subs"
gear2/prog_index.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=181534,CODECS="avc1.4d401e",URI="gear2/iframe_index.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=915905,CODECS="mp4a.40.2, avc1.4d401f",RESOLUTION=960x540,AUDIO="bipbop_audio",SUBTITLES="subs"
gear3/prog_index.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=297056,CODECS="avc1.4d401f",URI="gear3/iframe_index.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1030138,CODECS="mp4a.40.2, avc1.4d401f",RESOLUTION=1280x720,AUDIO="bipbop_audio",SUBTITLES="subs"
gear4/prog_index.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=339492,CODECS="avc1.4d401f",URI="gear4/iframe_index.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1924009,CODECS="mp4a.40.2, avc1.4d401f",RESOLUTION=1920x1080,AUDIO="bipbop_audio",SUBTITLES="subs"
gear5/prog_index.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=669554,CODECS="avc1.4d401f",URI="gear5/iframe_index.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=41457,CODECS="mp4a.40.2",AUDIO="bipbop_audio",SUBTITLES="subs"
gear0/prog_index.m3u8

351
test/testdata/mpd/subtitles.mpd vendored Normal file
View File

@@ -0,0 +1,351 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Unified Streaming Platform (version=1.10.18-20255) -->
<MPD
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:mpeg:dash:schema:mpd:2011"
xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
type="static"
mediaPresentationDuration="PT14M48S"
maxSegmentDuration="PT1M"
minBufferTime="PT10S"
profiles="urn:mpeg:dash:profile:isoff-live:2011">
<Period
id="1"
duration="PT14M48S">
<BaseURL>dash/</BaseURL>
<AdaptationSet
id="1"
group="1"
contentType="audio"
segmentAlignment="true"
audioSamplingRate="48000"
mimeType="audio/mp4"
codecs="mp4a.40.2"
startWithSAP="1">
<AudioChannelConfiguration
schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
value="2" />
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
<SegmentTemplate
timescale="48000"
initialization="3144-kZT4LWMQw6Rh7Kpd-$RepresentationID$.dash"
media="3144-kZT4LWMQw6Rh7Kpd-$RepresentationID$-$Time$.dash">
<SegmentTimeline>
<S t="0" d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="96256" r="2" />
<S d="95232" />
<S d="3584" />
</SegmentTimeline>
</SegmentTemplate>
<Representation
id="audio=128001"
bandwidth="128001">
</Representation>
</AdaptationSet>
<AdaptationSet
id="2"
group="3"
contentType="text"
lang="en"
mimeType="application/mp4"
codecs="stpp"
startWithSAP="1">
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="subtitle" />
<SegmentTemplate
timescale="1000"
initialization="3144-kZT4LWMQw6Rh7Kpd-$RepresentationID$.dash"
media="3144-kZT4LWMQw6Rh7Kpd-$RepresentationID$-$Time$.dash">
<SegmentTimeline>
<S t="0" d="60000" r="9" />
<S d="24000" />
</SegmentTimeline>
</SegmentTemplate>
<Representation
id="textstream_eng=1000"
bandwidth="1000">
</Representation>
</AdaptationSet>
<AdaptationSet
id="3"
group="2"
contentType="video"
par="960:409"
minBandwidth="100000"
maxBandwidth="4482000"
maxWidth="1689"
maxHeight="720"
segmentAlignment="true"
mimeType="video/mp4"
codecs="avc1.4D401F"
startWithSAP="1">
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main" />
<SegmentTemplate
timescale="12288"
initialization="3144-kZT4LWMQw6Rh7Kpd-$RepresentationID$.dash"
media="3144-kZT4LWMQw6Rh7Kpd-$RepresentationID$-$Time$.dash">
<SegmentTimeline>
<S t="0" d="24576" r="443" />
</SegmentTimeline>
</SegmentTemplate>
<Representation
id="video=100000"
bandwidth="100000"
width="336"
height="144"
sar="2880:2863"
scanType="progressive">
</Representation>
<Representation
id="video=326000"
bandwidth="326000"
width="562"
height="240"
sar="115200:114929"
scanType="progressive">
</Representation>
<Representation
id="video=698000"
bandwidth="698000"
width="844"
height="360"
sar="86400:86299"
scanType="progressive">
</Representation>
<Representation
id="video=1493000"
bandwidth="1493000"
width="1126"
height="480"
sar="230400:230267"
scanType="progressive">
</Representation>
<Representation
id="video=4482000"
bandwidth="4482000"
width="1688"
height="720"
sar="86400:86299"
scanType="progressive">
</Representation>
</AdaptationSet>
</Period>
</MPD>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# coding: utf-8
from __future__ import unicode_literals
@@ -24,6 +24,7 @@ from .utils import (
DateRange,
decodeOption,
DownloadError,
error_to_compat_str,
ExistingVideoReached,
expand_path,
match_filter_func,
@@ -31,20 +32,26 @@ from .utils import (
preferredencoding,
read_batch_urls,
RejectedVideoReached,
REMUX_EXTENSIONS,
render_table,
SameFileError,
setproctitle,
std_headers,
write_string,
)
from .update import update_self
from .update import run_update
from .downloader import (
FileDownloader,
)
from .extractor import gen_extractors, list_extractors
from .extractor.common import InfoExtractor
from .extractor.adobepass import MSO_INFO
from .postprocessor.ffmpeg import (
FFmpegExtractAudioPP,
FFmpegSubtitlesConvertorPP,
FFmpegThumbnailsConvertorPP,
FFmpegVideoConvertorPP,
FFmpegVideoRemuxerPP,
)
from .postprocessor.metadatafromfield import MetadataFromFieldPP
from .YoutubeDL import YoutubeDL
@@ -60,6 +67,7 @@ def _real_main(argv=None):
setproctitle('yt-dlp')
parser, opts, args = parseOpts(argv)
warnings = []
# Set user agent
if opts.user_agent is not None:
@@ -128,16 +136,12 @@ def _real_main(argv=None):
parser.error('account username missing\n')
if opts.ap_password is not None and opts.ap_username is None:
parser.error('TV Provider account username missing\n')
if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
parser.error('using output template conflicts with using title, video ID or auto number')
if opts.autonumber_size is not None:
if opts.autonumber_size <= 0:
parser.error('auto number size must be positive')
if opts.autonumber_start is not None:
if opts.autonumber_start < 0:
parser.error('auto number start must be positive or 0')
if opts.usetitle and opts.useid:
parser.error('using title conflicts with using video ID')
if opts.username is not None and opts.password is None:
opts.password = compat_getpass('Type account password and press [Return]: ')
if opts.ap_username is not None and opts.ap_password is None:
@@ -177,8 +181,7 @@ def _real_main(argv=None):
parser.error('requests sleep interval must be positive or 0')
if opts.ap_mso and opts.ap_mso not in MSO_INFO:
parser.error('Unsupported TV Provider, use --ap-list-mso to get a list of supported TV Providers')
if opts.overwrites:
# --yes-overwrites implies --no-continue
if opts.overwrites: # --yes-overwrites implies --no-continue
opts.continue_dl = False
if opts.concurrent_fragment_downloads <= 0:
raise ValueError('Concurrent fragments must be positive')
@@ -213,25 +216,25 @@ def _real_main(argv=None):
if opts.playlistend not in (-1, None) and opts.playlistend < opts.playliststart:
raise ValueError('Playlist end must be greater than playlist start')
if opts.extractaudio:
if opts.audioformat not in ['best', 'aac', 'flac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
if opts.audioformat not in ['best'] + list(FFmpegExtractAudioPP.SUPPORTED_EXTS):
parser.error('invalid audio format specified')
if opts.audioquality:
opts.audioquality = opts.audioquality.strip('k').strip('K')
if not opts.audioquality.isdigit():
parser.error('invalid audio quality specified')
if opts.recodevideo is not None:
if opts.recodevideo not in REMUX_EXTENSIONS:
parser.error('invalid video recode format specified')
opts.recodevideo = opts.recodevideo.replace(' ', '')
if not re.match(FFmpegVideoConvertorPP.FORMAT_RE, opts.recodevideo):
parser.error('invalid video remux format specified')
if opts.remuxvideo is not None:
opts.remuxvideo = opts.remuxvideo.replace(' ', '')
remux_regex = r'{0}(?:/{0})*$'.format(r'(?:\w+>)?(?:%s)' % '|'.join(REMUX_EXTENSIONS))
if not re.match(remux_regex, opts.remuxvideo):
if not re.match(FFmpegVideoRemuxerPP.FORMAT_RE, opts.remuxvideo):
parser.error('invalid video remux format specified')
if opts.convertsubtitles is not None:
if opts.convertsubtitles not in ('srt', 'vtt', 'ass', 'lrc'):
if opts.convertsubtitles not in FFmpegSubtitlesConvertorPP.SUPPORTED_EXTS:
parser.error('invalid subtitle format specified')
if opts.convertthumbnails is not None:
if opts.convertthumbnails not in ('jpg', ):
if opts.convertthumbnails not in FFmpegThumbnailsConvertorPP.SUPPORTED_EXTS:
parser.error('invalid thumbnail format specified')
if opts.date is not None:
@@ -239,21 +242,85 @@ def _real_main(argv=None):
else:
date = DateRange(opts.dateafter, opts.datebefore)
# Do not download videos when there are audio-only formats
def parse_compat_opts():
parsed_compat_opts, compat_opts = set(), opts.compat_opts[::-1]
while compat_opts:
actual_opt = opt = compat_opts.pop().lower()
if opt == 'youtube-dl':
compat_opts.extend(['-multistreams', 'all'])
elif opt == 'youtube-dlc':
compat_opts.extend(['-no-youtube-channel-redirect', '-no-live-chat', 'all'])
elif opt == 'all':
parsed_compat_opts.update(all_compat_opts)
elif opt == '-all':
parsed_compat_opts = set()
else:
if opt[0] == '-':
opt = opt[1:]
parsed_compat_opts.discard(opt)
else:
parsed_compat_opts.update([opt])
if opt not in all_compat_opts:
parser.error('Invalid compatibility option %s' % actual_opt)
return parsed_compat_opts
all_compat_opts = [
'filename', 'format-sort', 'abort-on-error', 'format-spec', 'no-playlist-metafiles',
'multistreams', 'no-live-chat', 'playlist-index', 'list-formats', 'no-direct-merge',
'no-youtube-channel-redirect', 'no-youtube-unavailable-videos', 'no-attach-info-json',
]
compat_opts = parse_compat_opts()
def _unused_compat_opt(name):
if name not in compat_opts:
return False
compat_opts.discard(name)
compat_opts.update(['*%s' % name])
return True
def set_default_compat(compat_name, opt_name, default=True, remove_compat=False):
attr = getattr(opts, opt_name)
if compat_name in compat_opts:
if attr is None:
setattr(opts, opt_name, not default)
return True
else:
if remove_compat:
_unused_compat_opt(compat_name)
return False
elif attr is None:
setattr(opts, opt_name, default)
return None
set_default_compat('abort-on-error', 'ignoreerrors')
set_default_compat('no-playlist-metafiles', 'allow_playlist_files')
if 'format-sort' in compat_opts:
opts.format_sort.extend(InfoExtractor.FormatSort.ytdl_default)
_video_multistreams_set = set_default_compat('multistreams', 'allow_multiple_video_streams', False, remove_compat=False)
_audio_multistreams_set = set_default_compat('multistreams', 'allow_multiple_audio_streams', False, remove_compat=False)
if _video_multistreams_set is False and _audio_multistreams_set is False:
_unused_compat_opt('multistreams')
outtmpl_default = opts.outtmpl.get('default')
if 'filename' in compat_opts:
if outtmpl_default is None:
outtmpl_default = '%(title)s.%(id)s.%(ext)s'
opts.outtmpl.update({'default': outtmpl_default})
else:
_unused_compat_opt('filename')
def validate_outtmpl(tmpl, msg):
err = YoutubeDL.validate_outtmpl(tmpl)
if err:
parser.error('invalid %s %r: %s' % (msg, tmpl, error_to_compat_str(err)))
for k, tmpl in opts.outtmpl.items():
validate_outtmpl(tmpl, '%s output template' % k)
for tmpl in opts.forceprint:
validate_outtmpl(tmpl, 'print template')
if opts.extractaudio and not opts.keepvideo and opts.format is None:
opts.format = 'bestaudio/best'
outtmpl = opts.outtmpl
if not outtmpl:
outtmpl = {'default': (
'%(title)s-%(id)s-%(format)s.%(ext)s' if opts.format == '-1' and opts.usetitle
else '%(id)s-%(format)s.%(ext)s' if opts.format == '-1'
else '%(autonumber)s-%(title)s-%(id)s.%(ext)s' if opts.usetitle and opts.autonumber
else '%(title)s-%(id)s.%(ext)s' if opts.usetitle
else '%(id)s.%(ext)s' if opts.useid
else '%(autonumber)s-%(id)s.%(ext)s' if opts.autonumber
else None)}
outtmpl_default = outtmpl.get('default')
if outtmpl_default is not None and not os.path.splitext(outtmpl_default)[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'
@@ -271,7 +338,7 @@ def _real_main(argv=None):
if re.match(MetadataFromFieldPP.regex, f) is None:
parser.error('invalid format string "%s" specified for --parse-metadata' % f)
any_getting = opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration or opts.dumpjson or opts.dump_single_json
any_getting = opts.forceprint or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration or opts.dumpjson or opts.dump_single_json
any_printing = opts.print_json
download_archive_fn = expand_path(opts.download_archive) if opts.download_archive is not None else opts.download_archive
@@ -281,7 +348,7 @@ def _real_main(argv=None):
opts.writeinfojson = True
def report_conflict(arg1, arg2):
write_string('WARNING: %s is ignored since %s was given\n' % (arg2, arg1), out=sys.stderr)
warnings.append('%s is ignored since %s was given' % (arg2, arg1))
if opts.remuxvideo and opts.recodevideo:
report_conflict('--recode-video', '--remux-video')
@@ -419,11 +486,10 @@ def _real_main(argv=None):
})
def report_args_compat(arg, name):
write_string(
'WARNING: %s given without specifying name. The arguments will be given to all %s\n' % (arg, name),
out=sys.stderr)
warnings.append('%s given without specifying name. The arguments will be given to all %s' % (arg, name))
if 'default' in opts.external_downloader_args:
report_args_compat('--external-downloader-args', 'external downloaders')
report_args_compat('--downloader-args', 'external downloaders')
if 'default-compat' in opts.postprocessor_args and 'default' not in opts.postprocessor_args:
report_args_compat('--post-processor-args', 'post-processors')
@@ -431,10 +497,10 @@ def _real_main(argv=None):
opts.postprocessor_args['default'] = opts.postprocessor_args['default-compat']
final_ext = (
opts.recodevideo
or (opts.remuxvideo in REMUX_EXTENSIONS) and opts.remuxvideo
or (opts.extractaudio and opts.audioformat != 'best') and opts.audioformat
or None)
opts.recodevideo if opts.recodevideo in FFmpegVideoConvertorPP.SUPPORTED_EXTS
else opts.remuxvideo if opts.remuxvideo in FFmpegVideoRemuxerPP.SUPPORTED_EXTS
else opts.audioformat if (opts.extractaudio and opts.audioformat != 'best')
else None)
match_filter = (
None if opts.match_filter is None
@@ -459,6 +525,7 @@ def _real_main(argv=None):
'forceduration': opts.getduration,
'forcefilename': opts.getfilename,
'forceformat': opts.getformat,
'forceprint': opts.forceprint,
'forcejson': opts.dumpjson or opts.print_json,
'dump_single_json': opts.dump_single_json,
'force_write_download_archive': opts.force_write_download_archive,
@@ -471,9 +538,10 @@ def _real_main(argv=None):
'format_sort_force': opts.format_sort_force,
'allow_multiple_video_streams': opts.allow_multiple_video_streams,
'allow_multiple_audio_streams': opts.allow_multiple_audio_streams,
'check_formats': opts.check_formats,
'listformats': opts.listformats,
'listformats_table': opts.listformats_table,
'outtmpl': outtmpl,
'outtmpl': opts.outtmpl,
'outtmpl_na_placeholder': opts.outtmpl_na_placeholder,
'paths': opts.paths,
'autonumber_size': opts.autonumber_size,
@@ -588,9 +656,12 @@ def _real_main(argv=None):
'geo_bypass': opts.geo_bypass,
'geo_bypass_country': opts.geo_bypass_country,
'geo_bypass_ip_block': opts.geo_bypass_ip_block,
'warnings': warnings,
'compat_opts': compat_opts,
# just for deprecation check
'autonumber': opts.autonumber if opts.autonumber is True else None,
'usetitle': opts.usetitle if opts.usetitle is True else None,
'autonumber': opts.autonumber or None,
'usetitle': opts.usetitle or None,
'useid': opts.useid or None,
}
with YoutubeDL(ydl_opts) as ydl:
@@ -603,7 +674,7 @@ def _real_main(argv=None):
# Update version
if opts.update_self:
# If updater returns True, exit. Required for windows
if update_self(ydl.to_screen, opts.verbose, ydl._opener):
if run_update(ydl):
if actual_use:
sys.exit('ERROR: The program must exit for the update to complete')
sys.exit()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import unicode_literals
# Execute with

View File

@@ -3018,10 +3018,24 @@ else:
return ctypes.WINFUNCTYPE(*args, **kwargs)
try:
compat_Pattern = re.Pattern
except AttributeError:
compat_Pattern = type(re.compile(''))
try:
compat_Match = re.Match
except AttributeError:
compat_Match = type(re.compile('').match(''))
__all__ = [
'compat_HTMLParseError',
'compat_HTMLParser',
'compat_HTTPError',
'compat_Match',
'compat_Pattern',
'compat_Struct',
'compat_b64decode',
'compat_basestring',

View File

@@ -31,6 +31,7 @@ from .external import (
PROTOCOL_MAP = {
'rtmp': RtmpFD,
'rtmp_ffmpeg': FFmpegFD,
'm3u8_native': HlsFD,
'm3u8': FFmpegFD,
'mms': RtspFD,
@@ -46,6 +47,7 @@ PROTOCOL_MAP = {
def shorten_protocol_name(proto, simplify=False):
short_protocol_names = {
'm3u8_native': 'm3u8_n',
'rtmp_ffmpeg': 'rtmp_f',
'http_dash_segments': 'dash',
'niconico_dmc': 'dmc',
}
@@ -54,6 +56,7 @@ def shorten_protocol_name(proto, simplify=False):
'https': 'http',
'ftps': 'ftp',
'm3u8_native': 'm3u8',
'rtmp_ffmpeg': 'rtmp',
'm3u8_frag_urls': 'm3u8',
'dash_frag_urls': 'dash',
})

View File

@@ -147,10 +147,10 @@ class FileDownloader(object):
return int(round(number * multiplier))
def to_screen(self, *args, **kargs):
self.ydl.to_screen(*args, **kargs)
self.ydl.to_stdout(*args, quiet=self.params.get('quiet'), **kargs)
def to_stderr(self, message):
self.ydl.to_screen(message)
self.ydl.to_stderr(message)
def to_console_title(self, message):
self.ydl.to_console_title(message)
@@ -164,6 +164,9 @@ class FileDownloader(object):
def report_error(self, *args, **kargs):
self.ydl.report_error(*args, **kargs)
def write_debug(self, *args, **kargs):
self.ydl.write_debug(*args, **kargs)
def slow_down(self, start_time, now, byte_counter):
"""Sleep if the download speed is over the rate limit."""
rate_limit = self.params.get('ratelimit')
@@ -402,5 +405,4 @@ class FileDownloader(object):
if exe is None:
exe = os.path.basename(str_args[0])
self.to_screen('[debug] %s command line: %s' % (
exe, shell_quote(str_args)))
self.write_debug('%s command line: %s' % (exe, shell_quote(str_args)))

View File

@@ -1,5 +1,6 @@
from __future__ import unicode_literals
import errno
try:
import concurrent.futures
can_threaded_download = True
@@ -112,12 +113,14 @@ class DashSegmentsFD(FragmentFD):
if count > fragment_retries:
if not fatal:
return False, frag_index
ctx['dest_stream'].close()
self.report_error('Giving up after %s fragment retries' % fragment_retries)
return False, frag_index
return frag_content, frag_index
def append_fragment(frag_content, frag_index):
fatal = frag_index == 1 or not skip_unavailable_fragments
if frag_content:
fragment_filename = '%s-Frag%d' % (ctx['tmpfilename'], frag_index)
try:
@@ -126,19 +129,24 @@ class DashSegmentsFD(FragmentFD):
file.close()
self._append_fragment(ctx, frag_content)
return True
except FileNotFoundError:
if skip_unavailable_fragments:
except EnvironmentError as ose:
if ose.errno != errno.ENOENT:
raise
# FileNotFoundError
if not fatal:
self.report_skip_fragment(frag_index)
return True
else:
ctx['dest_stream'].close()
self.report_error(
'fragment %s not found, unable to continue' % frag_index)
return False
else:
if skip_unavailable_fragments:
if not fatal:
self.report_skip_fragment(frag_index)
return True
else:
ctx['dest_stream'].close()
self.report_error(
'fragment %s not found, unable to continue' % frag_index)
return False
@@ -146,8 +154,9 @@ class DashSegmentsFD(FragmentFD):
max_workers = self.params.get('concurrent_fragment_downloads', 1)
if can_threaded_download and max_workers > 1:
self.report_warning('The download speed shown is only of one thread. This is a known issue')
_download_fragment = lambda f: (f, download_fragment(f)[1])
with concurrent.futures.ThreadPoolExecutor(max_workers) as pool:
futures = [pool.submit(download_fragment, fragment) for fragment in fragments_to_download]
futures = [pool.submit(_download_fragment, fragment) for fragment in fragments_to_download]
# timeout must be 0 to return instantly
done, not_done = concurrent.futures.wait(futures, timeout=0)
try:
@@ -161,9 +170,13 @@ class DashSegmentsFD(FragmentFD):
# timeout must be none to cancel
concurrent.futures.wait(not_done, timeout=None)
raise KeyboardInterrupt
results = [future.result() for future in futures]
for frag_content, frag_index in results:
for fragment, frag_index in map(lambda x: x.result(), futures):
fragment_filename = '%s-Frag%d' % (ctx['tmpfilename'], frag_index)
down, frag_sanitized = sanitize_open(fragment_filename, 'rb')
fragment['fragment_filename_sanitized'] = frag_sanitized
frag_content = down.read()
down.close()
result = append_fragment(frag_content, frag_index)
if not result:
return False

View File

@@ -290,11 +290,19 @@ class Aria2cFD(ExternalFD):
cmd += self._bool_option('--remote-time', 'updatetime', 'true', 'false', '=')
cmd += self._configuration_args()
# aria2c strips out spaces from the beginning/end of filenames and paths.
# We work around this issue by adding a "./" to the beginning of the
# filename and relative path, and adding a "/" at the end of the path.
# See: https://github.com/yt-dlp/yt-dlp/issues/276
# https://github.com/ytdl-org/youtube-dl/issues/20312
# https://github.com/aria2/aria2/issues/1373
dn = os.path.dirname(tmpfilename)
if dn:
cmd += ['--dir', dn]
if not os.path.isabs(dn):
dn = '.%s%s' % (os.path.sep, dn)
cmd += ['--dir', dn + os.path.sep]
if 'fragments' not in info_dict:
cmd += ['--out', os.path.basename(tmpfilename)]
cmd += ['--out', '.%s%s' % (os.path.sep, os.path.basename(tmpfilename))]
cmd += ['--auto-file-renaming=false']
if 'fragments' in info_dict:
@@ -330,7 +338,7 @@ class HttpieFD(ExternalFD):
class FFmpegFD(ExternalFD):
SUPPORTED_PROTOCOLS = ('http', 'https', 'ftp', 'ftps', 'm3u8', 'm3u8_native', 'rtsp', 'rtmp', 'mms')
SUPPORTED_PROTOCOLS = ('http', 'https', 'ftp', 'ftps', 'm3u8', 'm3u8_native', 'rtsp', 'rtmp', 'rtmp_ffmpeg', 'mms')
@classmethod
def available(cls, path=None):
@@ -338,7 +346,7 @@ class FFmpegFD(ExternalFD):
return FFmpegPostProcessor().available
def _call_downloader(self, tmpfilename, info_dict):
url = info_dict['url']
urls = [f['url'] for f in info_dict.get('requested_formats', [])] or [info_dict['url']]
ffpp = FFmpegPostProcessor(downloader=self)
if not ffpp.available:
self.report_error('m3u8 download detected but ffmpeg could not be found. Please install')
@@ -351,6 +359,8 @@ class FFmpegFD(ExternalFD):
if self.params.get(log_level, False):
args += ['-loglevel', log_level]
break
if not self.params.get('verbose'):
args += ['-hide_banner']
seekable = info_dict.get('_seekable')
if seekable is not None:
@@ -370,7 +380,7 @@ class FFmpegFD(ExternalFD):
# if end_time:
# args += ['-t', compat_str(end_time - start_time)]
if info_dict.get('http_headers') is not None and re.match(r'^https?://', url):
if info_dict.get('http_headers') is not None and re.match(r'^https?://', urls[0]):
# Trailing \r\n after each HTTP header is important to prevent warning from ffmpeg/avconv:
# [http @ 00000000003d2fa0] No trailing CRLF found in HTTP header.
headers = handle_youtubedl_headers(info_dict['http_headers'])
@@ -428,7 +438,15 @@ class FFmpegFD(ExternalFD):
elif isinstance(conn, compat_str):
args += ['-rtmp_conn', conn]
args += ['-i', url, '-c', 'copy']
for url in urls:
args += ['-i', url]
args += ['-c', 'copy']
if info_dict.get('requested_formats'):
for (i, fmt) in enumerate(info_dict['requested_formats']):
if fmt.get('acodec') != 'none':
args.extend(['-map', '%d:a:0' % i])
if fmt.get('vcodec') != 'none':
args.extend(['-map', '%d:v:0' % i])
if self.params.get('test', False):
args += ['-fs', compat_str(self._TEST_FILE_SIZE)]

View File

@@ -31,6 +31,7 @@ class FragmentFD(FileDownloader):
Skip unavailable fragments (DASH and hlsnative only)
keep_fragments: Keep downloaded fragments on disk after downloading is
finished
_no_ytdl_file: Don't use .ytdl file
For each incomplete fragment download yt-dlp keeps on disk a special
bookkeeping file with download state and metadata (in future such files will
@@ -69,15 +70,17 @@ class FragmentFD(FileDownloader):
self._prepare_frag_download(ctx)
self._start_frag_download(ctx)
@staticmethod
def __do_ytdl_file(ctx):
return not ctx['live'] and not ctx['tmpfilename'] == '-'
def __do_ytdl_file(self, ctx):
return not ctx['live'] and not ctx['tmpfilename'] == '-' and not self.params.get('_no_ytdl_file')
def _read_ytdl_file(self, ctx):
assert 'ytdl_corrupt' not in ctx
stream, _ = sanitize_open(self.ytdl_filename(ctx['filename']), 'r')
try:
ctx['fragment_index'] = json.loads(stream.read())['downloader']['current_fragment']['index']
ytdl_data = json.loads(stream.read())
ctx['fragment_index'] = ytdl_data['downloader']['current_fragment']['index']
if 'extra_state' in ytdl_data['downloader']:
ctx['extra_state'] = ytdl_data['downloader']['extra_state']
except Exception:
ctx['ytdl_corrupt'] = True
finally:
@@ -90,6 +93,8 @@ class FragmentFD(FileDownloader):
'index': ctx['fragment_index'],
},
}
if 'extra_state' in ctx:
downloader['extra_state'] = ctx['extra_state']
if ctx.get('fragment_count') is not None:
downloader['fragment_count'] = ctx['fragment_count']
frag_index_stream.write(json.dumps({'downloader': downloader}))

View File

@@ -1,6 +1,8 @@
from __future__ import unicode_literals
import errno
import re
import io
import binascii
try:
from Crypto.Cipher import AES
@@ -26,7 +28,9 @@ from ..utils import (
parse_m3u8_attributes,
sanitize_open,
update_url_query,
bug_reports_message,
)
from .. import webvtt
class HlsFD(FragmentFD):
@@ -95,7 +99,11 @@ class HlsFD(FragmentFD):
# fd.add_progress_hook(ph)
return fd.real_download(filename, info_dict)
real_downloader = _get_real_downloader(info_dict, 'm3u8_frag_urls', self.params, None)
is_webvtt = info_dict['ext'] == 'vtt'
if is_webvtt:
real_downloader = None # Packing the fragments is not currently supported for external downloader
else:
real_downloader = _get_real_downloader(info_dict, 'm3u8_frag_urls', self.params, None)
if real_downloader and not real_downloader.supports_manifest(s):
real_downloader = None
if real_downloader:
@@ -141,6 +149,8 @@ class HlsFD(FragmentFD):
else:
self._prepare_and_start_frag_download(ctx)
extra_state = ctx.setdefault('extra_state', {})
fragment_retries = self.params.get('fragment_retries', 0)
skip_unavailable_fragments = self.params.get('skip_unavailable_fragments', True)
test = self.params.get('test', False)
@@ -262,12 +272,24 @@ class HlsFD(FragmentFD):
if not success:
return False
else:
def decrypt_fragment(fragment, frag_content):
decrypt_info = fragment['decrypt_info']
if decrypt_info['METHOD'] != 'AES-128':
return frag_content
iv = decrypt_info.get('IV') or compat_struct_pack('>8xq', fragment['media_sequence'])
decrypt_info['KEY'] = decrypt_info.get('KEY') or self.ydl.urlopen(
self._prepare_url(info_dict, info_dict.get('_decryption_key_url') or decrypt_info['URI'])).read()
# Don't decrypt the content in tests since the data is explicitly truncated and it's not to a valid block
# size (see https://github.com/ytdl-org/youtube-dl/pull/27660). Tests only care that the correct data downloaded,
# not what it decrypts to.
if test:
return frag_content
return AES.new(decrypt_info['KEY'], AES.MODE_CBC, iv).decrypt(frag_content)
def download_fragment(fragment):
frag_index = fragment['frag_index']
frag_url = fragment['url']
decrypt_info = fragment['decrypt_info']
byte_range = fragment['byte_range']
media_sequence = fragment['media_sequence']
ctx['fragment_index'] = frag_index
@@ -291,44 +313,111 @@ class HlsFD(FragmentFD):
if count <= fragment_retries:
self.report_retry_fragment(err, frag_index, count, fragment_retries)
if count > fragment_retries:
ctx['dest_stream'].close()
self.report_error('Giving up after %s fragment retries' % fragment_retries)
return False, frag_index
if decrypt_info['METHOD'] == 'AES-128':
iv = decrypt_info.get('IV') or compat_struct_pack('>8xq', media_sequence)
decrypt_info['KEY'] = decrypt_info.get('KEY') or self.ydl.urlopen(
self._prepare_url(info_dict, info_dict.get('_decryption_key_url') or decrypt_info['URI'])).read()
# Don't decrypt the content in tests since the data is explicitly truncated and it's not to a valid block
# size (see https://github.com/ytdl-org/youtube-dl/pull/27660). Tests only care that the correct data downloaded,
# not what it decrypts to.
if not test:
frag_content = AES.new(
decrypt_info['KEY'], AES.MODE_CBC, iv).decrypt(frag_content)
return decrypt_fragment(fragment, frag_content), frag_index
return frag_content, frag_index
pack_fragment = lambda frag_content, _: frag_content
if is_webvtt:
def pack_fragment(frag_content, frag_index):
output = io.StringIO()
adjust = 0
for block in webvtt.parse_fragment(frag_content):
if isinstance(block, webvtt.CueBlock):
block.start += adjust
block.end += adjust
dedup_window = extra_state.setdefault('webvtt_dedup_window', [])
cue = block.as_json
# skip the cue if an identical one appears
# in the window of potential duplicates
# and prune the window of unviable candidates
i = 0
skip = True
while i < len(dedup_window):
window_cue = dedup_window[i]
if window_cue == cue:
break
if window_cue['end'] >= cue['start']:
i += 1
continue
del dedup_window[i]
else:
skip = False
if skip:
continue
# add the cue to the window
dedup_window.append(cue)
elif isinstance(block, webvtt.Magic):
# take care of MPEG PES timestamp overflow
if block.mpegts is None:
block.mpegts = 0
extra_state.setdefault('webvtt_mpegts_adjust', 0)
block.mpegts += extra_state['webvtt_mpegts_adjust'] << 33
if block.mpegts < extra_state.get('webvtt_mpegts_last', 0):
extra_state['webvtt_mpegts_adjust'] += 1
block.mpegts += 1 << 33
extra_state['webvtt_mpegts_last'] = block.mpegts
if frag_index == 1:
extra_state['webvtt_mpegts'] = block.mpegts or 0
extra_state['webvtt_local'] = block.local or 0
# XXX: block.local = block.mpegts = None ?
else:
if block.mpegts is not None and block.local is not None:
adjust = (
(block.mpegts - extra_state.get('webvtt_mpegts', 0))
- (block.local - extra_state.get('webvtt_local', 0))
)
continue
elif isinstance(block, webvtt.HeaderBlock):
if frag_index != 1:
# XXX: this should probably be silent as well
# or verify that all segments contain the same data
self.report_warning(bug_reports_message(
'Discarding a %s block found in the middle of the stream; '
'if the subtitles display incorrectly,'
% (type(block).__name__)))
continue
block.write_into(output)
return output.getvalue().encode('utf-8')
def append_fragment(frag_content, frag_index):
fatal = frag_index == 1 or not skip_unavailable_fragments
if frag_content:
fragment_filename = '%s-Frag%d' % (ctx['tmpfilename'], frag_index)
try:
file, frag_sanitized = sanitize_open(fragment_filename, 'rb')
ctx['fragment_filename_sanitized'] = frag_sanitized
file.close()
frag_content = pack_fragment(frag_content, frag_index)
self._append_fragment(ctx, frag_content)
return True
except FileNotFoundError:
if skip_unavailable_fragments:
except EnvironmentError as ose:
if ose.errno != errno.ENOENT:
raise
# FileNotFoundError
if not fatal:
self.report_skip_fragment(frag_index)
return True
else:
ctx['dest_stream'].close()
self.report_error(
'fragment %s not found, unable to continue' % frag_index)
return False
else:
if skip_unavailable_fragments:
if not fatal:
self.report_skip_fragment(frag_index)
return True
else:
ctx['dest_stream'].close()
self.report_error(
'fragment %s not found, unable to continue' % frag_index)
return False
@@ -336,8 +425,9 @@ class HlsFD(FragmentFD):
max_workers = self.params.get('concurrent_fragment_downloads', 1)
if can_threaded_download and max_workers > 1:
self.report_warning('The download speed shown is only of one thread. This is a known issue')
_download_fragment = lambda f: (f, download_fragment(f)[1])
with concurrent.futures.ThreadPoolExecutor(max_workers) as pool:
futures = [pool.submit(download_fragment, fragment) for fragment in fragments]
futures = [pool.submit(_download_fragment, fragment) for fragment in fragments]
# timeout must be 0 to return instantly
done, not_done = concurrent.futures.wait(futures, timeout=0)
try:
@@ -351,10 +441,14 @@ class HlsFD(FragmentFD):
# timeout must be none to cancel
concurrent.futures.wait(not_done, timeout=None)
raise KeyboardInterrupt
results = [future.result() for future in futures]
for frag_content, frag_index in results:
result = append_fragment(frag_content, frag_index)
for fragment, frag_index in map(lambda x: x.result(), futures):
fragment_filename = '%s-Frag%d' % (ctx['tmpfilename'], frag_index)
down, frag_sanitized = sanitize_open(fragment_filename, 'rb')
fragment['fragment_filename_sanitized'] = frag_sanitized
frag_content = down.read()
down.close()
result = append_fragment(decrypt_fragment(fragment, frag_content), frag_index)
if not result:
return False
else:

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