1
0
mirror of https://github.com/yt-dlp/yt-dlp.git synced 2026-01-20 22:01:21 +00:00

Compare commits

...

16 Commits

Author SHA1 Message Date
pukkandan
0e7f2c7b4d Release 2021.01.07-2 2021-01-08 02:05:52 +05:30
pukkandan
1b77b347d4 Allow passing different arguments to different postprocessors
* Also deprecated --sponskrub-args

Closes: https://github.com/ytdl-org/youtube-dl/issues/27593
Eg: `--postprocessor-args "VideoConvertor:-c:v h264_nvenc -preset slow"`
Eg: `--postprocessor-args "SponsKrub:-include-selfpromo"`

For backward compatibility, `--postprocessor-args args` is equivalent to:
`--post-processor-args "sponskrub:" --post-processor-args "default:args"`
2021-01-08 01:41:08 +05:30
pukkandan
6c40e33c9e ffmpeg: ignore extra data streams #9 by jbruchon
closes #2, blackjack4494#291

Authored by jbruchon
2021-01-08 01:08:21 +05:30
Jody Bruchon
e0da59fe54 ffmpeg: ignore extra data streams with -dn (fixes #2)
Sometimes, video files will arrive with a timecode data stream
that causes `-map 0` to error out due to the stream not being
supported in the output container. These data streams generally do
not matter, so tell ffmpeg to ignore them rather than choking on
them.
2021-01-07 12:26:50 -05:00
pukkandan
c82fc65d03 Akamai fix #6 (blackjack4494#274) by nixxo
Authored by nixxo
2021-01-07 21:22:31 +05:30
nixxo
1c3a61baae Merge branch 'master' into akamai-fix 2021-01-07 16:49:07 +01:00
pukkandan
9d88274ca2 Tiktok fix #8 (blackjack4494#20)
Authored by GreyAlien502
2021-01-07 20:53:03 +05:30
pukkandan
7dbce2c532 [vlive] add support for playlists #7 (blackjack4494#223)
Authored by kyuyeunk
2021-01-07 20:53:03 +05:30
pukkandan
2c35345868 Make sure playerOffsetMs is positive in youtube_live_chat by siikamiika #5 (blackjack4494#262)
Authored by siikamiika
2021-01-07 20:53:03 +05:30
pukkandan
3ad6c46175 Release 2021.01.07 2021-01-07 20:10:10 +05:30
Kyu Yeun Kim
3d54ebd427 [vlive] add support for playlists 2020-12-04 23:24:23 +09:00
Remita Amine
727006d951 [extractor/commons] improve Akamai HTTP formats extraction 2020-12-03 13:11:21 +01:00
Remita Amine
0827033479 [extractor/common] improve Akamai HTTP format extraction
- Allow m3u8 manifest without an additional audio format
- Fix extraction for qualities starting with a number
Solution provided by @nixxo based on: https://stackoverflow.com/a/5984688
2020-12-03 13:10:24 +01:00
siikamiika
ae6e4e25aa make sure playerOffsetMs is positive 2020-11-28 02:19:38 +02:00
GreyAlien502
61e76c1e5f simplify second page fetch
Co-authored-by: Merval <merval@users.noreply.github.com>
2020-10-27 02:20:18 +00:00
GreyAlien502
7bbc0bbce0 fix tiktok download 2020-10-26 12:38:25 +00:00
22 changed files with 183 additions and 100 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 youtube-dlc: Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.05-2. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED. - First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07. If it's not, see https://github.com/pukkandan/yt-dlc 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 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/pukkandan/yt-dlc. - Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/pukkandan/yt-dlc.
- Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates. - Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. 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'm reporting a broken site support
- [ ] I've verified that I'm running youtube-dlc version **2021.01.05-2** - [ ] I've verified that I'm running youtube-dlc version **2021.01.07**
- [ ] I've checked that all provided URLs are alive and playable in a browser - [ ] 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 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 - [ ] 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 youtube-dlc with (`youtube-dlc -v
[debug] User config: [] [debug] User config: []
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj'] [debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251 [debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
[debug] youtube-dlc version 2021.01.05-2 [debug] youtube-dlc version 2021.01.07
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2 [debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4 [debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
[debug] Proxy map: {} [debug] Proxy map: {}

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 youtube-dlc: Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.05-2. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED. - First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07. If it's not, see https://github.com/pukkandan/yt-dlc 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 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/pukkandan/yt-dlc. youtube-dlc does not support such sites. In order for site support request to be accepted all provided example URLs should not violate any copyrights. - Make sure that site you are requesting is not dedicated to copyright infringement, see https://github.com/pukkandan/yt-dlc. youtube-dlc 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/pukkandan/yt-dlc. DO NOT post duplicates. - Search the bugtracker for similar site support requests: https://github.com/pukkandan/yt-dlc. 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'm reporting a new site support request
- [ ] I've verified that I'm running youtube-dlc version **2021.01.05-2** - [ ] I've verified that I'm running youtube-dlc version **2021.01.07**
- [ ] I've checked that all provided URLs are alive and playable in a browser - [ ] 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 checked that none of provided URLs violate any copyrights
- [ ] I've searched the bugtracker for similar site support requests including closed ones - [ ] 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 youtube-dlc: Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.05-2. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED. - First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED.
- Search the bugtracker for similar site feature requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates. - Search the bugtracker for similar site feature requests: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates.
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space) - 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'm reporting a site feature request
- [ ] I've verified that I'm running youtube-dlc version **2021.01.05-2** - [ ] I've verified that I'm running youtube-dlc version **2021.01.07**
- [ ] I've searched the bugtracker for similar site feature requests including closed ones - [ ] 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 youtube-dlc: Carefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dlc:
- First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.05-2. If it's not, see https://github.com/pukkandan/yt-dlc on how to update. Issues with outdated version will be REJECTED. - First of, make sure you are using the latest version of youtube-dlc. Run `youtube-dlc --version` and ensure your version is 2021.01.07. If it's not, see https://github.com/pukkandan/yt-dlc 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 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/pukkandan/yt-dlc. - Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/pukkandan/yt-dlc.
- Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. DO NOT post duplicates. - Search the bugtracker for similar issues: https://github.com/pukkandan/yt-dlc. 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'm reporting a broken site support issue
- [ ] I've verified that I'm running youtube-dlc version **2021.01.05-2** - [ ] I've verified that I'm running youtube-dlc version **2021.01.07**
- [ ] I've checked that all provided URLs are alive and playable in a browser - [ ] 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 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 - [ ] 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 youtube-dlc with (`youtube-dlc -v
[debug] User config: [] [debug] User config: []
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj'] [debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251 [debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
[debug] youtube-dlc version 2021.01.05-2 [debug] youtube-dlc version 2021.01.07
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2 [debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4 [debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
[debug] Proxy map: {} [debug] Proxy map: {}

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

View File

@@ -1,3 +1,8 @@
pukkandan pukkandan
h-h-h-h h-h-h-h
pauldubois98 pauldubois98
nixxo
GreyAlien502
kyuyeunk
siikamiika
jbruchon

View File

@@ -1,5 +1,5 @@
all: youtube-dlc README.md CONTRIBUTING.md README.txt issuetemplates youtube-dlc.1 youtube-dlc.bash-completion youtube-dlc.zsh youtube-dlc.fish supportedsites all: youtube-dlc README.md CONTRIBUTING.md README.txt issuetemplates youtube-dlc.1 youtube-dlc.bash-completion youtube-dlc.zsh youtube-dlc.fish supportedsites
doc: README.md CONTRIBUTING.md issuetemplates supportedsites clean doc: README.md CONTRIBUTING.md issuetemplates supportedsites
clean: clean:
rm -rf youtube-dlc.1.temp.md youtube-dlc.1 youtube-dlc.bash-completion README.txt MANIFEST build/ dist/ .coverage cover/ youtube-dlc.tar.gz youtube-dlc.zsh youtube-dlc.fish youtube_dlc/extractor/lazy_extractors.py *.dump *.part* *.ytdl *.info.json *.mp4 *.m4a *.flv *.mp3 *.avi *.mkv *.webm *.3gp *.wav *.ape *.swf *.jpg *.png CONTRIBUTING.md.tmp youtube-dlc youtube-dlc.exe rm -rf youtube-dlc.1.temp.md youtube-dlc.1 youtube-dlc.bash-completion README.txt MANIFEST build/ dist/ .coverage cover/ youtube-dlc.tar.gz youtube-dlc.zsh youtube-dlc.fish youtube_dlc/extractor/lazy_extractors.py *.dump *.part* *.ytdl *.info.json *.mp4 *.m4a *.flv *.mp3 *.avi *.mkv *.webm *.3gp *.wav *.ape *.swf *.jpg *.png CONTRIBUTING.md.tmp youtube-dlc youtube-dlc.exe

View File

@@ -1,5 +1,5 @@
[![Build Status](https://github.com/pukkandan/yt-dlc/workflows/CI/badge.svg)](https://github.com/pukkandan/yt-dlc/actions?query=workflow%3ACI) [![Build Status](https://github.com/pukkandan/yt-dlc/workflows/CI/badge.svg?branch=master)](https://github.com/pukkandan/yt-dlc/actions?query=workflow%3ACI)
[![Release Version](https://img.shields.io/badge/Release-2021.01.07-brightgreen)](https://github.com/pukkandan/yt-dlc/releases/latest) [![Release Version](https://img.shields.io/badge/Release-2021.01.07-2-brightgreen)](https://github.com/pukkandan/yt-dlc/releases/latest)
[![License: Unlicense](https://img.shields.io/badge/License-Unlicense-blue.svg)](https://github.com/pukkandan/yt-dlc/blob/master/LICENSE) [![License: Unlicense](https://img.shields.io/badge/License-Unlicense-blue.svg)](https://github.com/pukkandan/yt-dlc/blob/master/LICENSE)
youtube-dlc - download videos from youtube.com and many other [video platforms](docs/supportedsites.md) youtube-dlc - download videos from youtube.com and many other [video platforms](docs/supportedsites.md)
@@ -58,7 +58,7 @@ See [commits](https://github.com/pukkandan/yt-dlc/commits) for more details
* Added `--list-formats-as-table`, `--list-formats-old` * Added `--list-formats-as-table`, `--list-formats-old`
* **Negative Options:** Makes it possible to negate boolean options by adding a `no-` to the switch * **Negative Options:** Makes it possible to negate boolean options by adding a `no-` to the switch
* Added `--no-ignore-dynamic-mpd`, `--no-allow-dynamic-mpd`, `--allow-dynamic-mpd`, `--youtube-include-hls-manifest`, `--no-youtube-include-hls-manifest`, `--no-youtube-skip-hls-manifest`, `--no-download`, `--no-download-archive`, `--resize-buffer`, `--part`, `--mtime`, `--no-keep-fragments`, `--no-cookies`, `--no-write-annotations`, `--no-write-info-json`, `--no-write-description`, `--no-write-thumbnail`, `--youtube-include-dash-manifest`, `--post-overwrites`, `--no-keep-video`, `--no-embed-subs`, `--no-embed-thumbnail`, `--no-add-metadata`, `--no-include-ads`, `--no-write-sub`, `--no-write-auto-sub`, `--no-playlist-reverse`, `--no-restrict-filenames`, `--youtube-include-dash-manifest`, `--no-format-sort-force`, `--flat-videos`, `--no-list-formats-as-table`, `--no-sponskrub`, `--no-sponskrub-cut`, `--no-sponskrub-force` * Added `--no-ignore-dynamic-mpd`, `--no-allow-dynamic-mpd`, `--allow-dynamic-mpd`, `--youtube-include-hls-manifest`, `--no-youtube-include-hls-manifest`, `--no-youtube-skip-hls-manifest`, `--no-download`, `--no-download-archive`, `--resize-buffer`, `--part`, `--mtime`, `--no-keep-fragments`, `--no-cookies`, `--no-write-annotations`, `--no-write-info-json`, `--no-write-description`, `--no-write-thumbnail`, `--youtube-include-dash-manifest`, `--post-overwrites`, `--no-keep-video`, `--no-embed-subs`, `--no-embed-thumbnail`, `--no-add-metadata`, `--no-include-ads`, `--no-write-sub`, `--no-write-auto-sub`, `--no-playlist-reverse`, `--no-restrict-filenames`, `--youtube-include-dash-manifest`, `--no-format-sort-force`, `--flat-videos`, `--no-list-formats-as-table`, `--no-sponskrub`, `--no-sponskrub-cut`, `--no-sponskrub-force`
* Renamed: `--write-subs`, --no-write-subs`, `--no-write-auto-subs, `--write-auto-subs`. Note that these can still be used without the ending "s" * Renamed: `--write-subs`, `--no-write-subs`, `--no-write-auto-subs`, `--write-auto-subs`. Note that these can still be used without the ending "s"
* Relaxed validation for format filters so that any arbitrary field can be used * Relaxed validation for format filters so that any arbitrary field can be used
* Fix for embedding thumbnail in mp3 by @pauldubois98 * Fix for embedding thumbnail in mp3 by @pauldubois98
* Make Twitch Video ID output from Playlist and VOD extractor same. This is only a temporary fix * Make Twitch Video ID output from Playlist and VOD extractor same. This is only a temporary fix
@@ -80,6 +80,16 @@ See [commits](https://github.com/pukkandan/yt-dlc/commits) for more details
* Added `duration_string` to be used in `--output` * Added `duration_string` to be used in `--output`
* Created First Release * Created First Release
### 2021.01.07-2
* [Akamai] fix by @nixxo
* [Tiktok] fix extractor by @GreyAlien502
* [vlive] add support for playlists by @kyuyeunk
* [youtube_live_chat] make sure playerOffsetMs is positive by @siikamiika
* Ignore extra data streams in ffmpeg by @jbruchon
* Allow passing different arguments to different postprocessors using `--postprocessor-args`
* Deprecated `--sponskrub-args`. The same can now be done using `--postprocessor-args "sponskrub:<args>"`
# INSTALLATION # INSTALLATION
To use the latest version, simply download and run the [latest release](https://github.com/pukkandan/yt-dlc/releases/latest). To use the latest version, simply download and run the [latest release](https://github.com/pukkandan/yt-dlc/releases/latest).
@@ -550,7 +560,18 @@ Then simply type this
--recode-video FORMAT Re-encode the video into another format if --recode-video FORMAT Re-encode the video into another format if
re-encoding is necessary (currently re-encoding is necessary (currently
supported: mp4|flv|ogg|webm|mkv|avi) supported: mp4|flv|ogg|webm|mkv|avi)
--postprocessor-args ARGS Give these arguments to the postprocessor --postprocessor-args NAME:ARGS Give these arguments to the postprocessors.
Specify the postprocessor name and the
arguments separated by a colon ':' to give
the argument to only the specified
postprocessor. Supported names are
ExtractAudio, VideoRemuxer, VideoConvertor,
EmbedSubtitle, Metadata, Merger,
FixupStretched, FixupM4a, FixupM3u8,
SubtitlesConvertor, SponSkrub and Default.
You can use this option multiple times to
give different arguments to different
postprocessors
-k, --keep-video Keep the intermediate video file on disk -k, --keep-video Keep the intermediate video file on disk
after post-processing after post-processing
--no-keep-video Delete the intermediate video file after --no-keep-video Delete the intermediate video file after

View File

@@ -333,8 +333,9 @@ class YoutubeDL(object):
otherwise prefer ffmpeg. otherwise prefer ffmpeg.
ffmpeg_location: Location of the ffmpeg/avconv binary; either the path ffmpeg_location: Location of the ffmpeg/avconv binary; either the path
to the binary or its containing directory. to the binary or its containing directory.
postprocessor_args: A list of additional command-line arguments for the postprocessor_args: A dictionary of postprocessor names (in lower case) and a list
postprocessor. of additional command-line arguments for the postprocessor.
Use 'default' as the name for arguments to passed to all PP.
The following options are used by the Youtube extractor: The following options are used by the Youtube extractor:
youtube_include_dash_manifest: If True (default), DASH manifests and related youtube_include_dash_manifest: If True (default), DASH manifests and related

View File

@@ -331,9 +331,23 @@ def _real_main(argv=None):
external_downloader_args = None external_downloader_args = None
if opts.external_downloader_args: if opts.external_downloader_args:
external_downloader_args = compat_shlex_split(opts.external_downloader_args) external_downloader_args = compat_shlex_split(opts.external_downloader_args)
postprocessor_args = None
if opts.postprocessor_args: postprocessor_args = {}
postprocessor_args = compat_shlex_split(opts.postprocessor_args) if opts.postprocessor_args is not None:
for string in opts.postprocessor_args:
mobj = re.match(r'(?P<pp>\w+):(?P<args>.*)$', string)
if mobj is None:
if 'sponskrub' not in postprocessor_args: # for backward compatibility
postprocessor_args['sponskrub'] = []
if opts.verbose:
write_string('[debug] Adding postprocessor args from command line option sponskrub:\n')
pp_name, pp_args = 'default', string
else:
pp_name, pp_args = mobj.group('pp').lower(), mobj.group('args')
if opts.verbose:
write_string('[debug] Adding postprocessor args from command line option %s:%s\n' % (pp_name, pp_args))
postprocessor_args[pp_name] = compat_shlex_split(pp_args)
match_filter = ( match_filter = (
None if opts.match_filter is None None if opts.match_filter is None
else match_filter_func(opts.match_filter)) else match_filter_func(opts.match_filter))

View File

@@ -61,7 +61,7 @@ class YoutubeLiveChatReplayFD(FragmentFD):
else: else:
url = ('https://www.youtube.com/live_chat_replay/get_live_chat_replay' url = ('https://www.youtube.com/live_chat_replay/get_live_chat_replay'
+ '?continuation={}'.format(continuation_id) + '?continuation={}'.format(continuation_id)
+ '&playerOffsetMs={}'.format(offset - 5000) + '&playerOffsetMs={}'.format(max(offset - 5000, 0))
+ '&hidden=false' + '&hidden=false'
+ '&pbj=1') + '&pbj=1')
success, raw_fragment = dl_fragment(url) success, raw_fragment = dl_fragment(url)

View File

@@ -133,6 +133,8 @@ class TikTokIE(TikTokBaseIE):
def _real_extract(self, url): def _real_extract(self, url):
video_id = self._match_id(url) video_id = self._match_id(url)
# If we only call once, we get a 403 when downlaoding the video.
self._download_webpage(url, video_id)
webpage = self._download_webpage(url, video_id, note='Downloading video webpage') webpage = self._download_webpage(url, video_id, note='Downloading video webpage')
json_string = self._search_regex( json_string = self._search_regex(
r'id=\"__NEXT_DATA__\"\s+type=\"application\/json\"\s*[^>]+>\s*(?P<json_string_ld>[^<]+)', r'id=\"__NEXT_DATA__\"\s+type=\"application\/json\"\s*[^>]+>\s*(?P<json_string_ld>[^<]+)',

View File

@@ -72,6 +72,13 @@ class VLiveIE(VLiveBaseIE):
# works only with gcc=KR # works only with gcc=KR
'url': 'https://www.vlive.tv/video/225019', 'url': 'https://www.vlive.tv/video/225019',
'only_matching': True, 'only_matching': True,
}, {
'url': 'https://www.vlive.tv/video/223906',
'info_dict': {
'id': '58',
'title': 'RUN BTS!'
},
'playlist_mincount': 120
}] }]
def _real_initialize(self): def _real_initialize(self):
@@ -105,10 +112,12 @@ class VLiveIE(VLiveBaseIE):
if not is_logged_in(): if not is_logged_in():
raise ExtractorError('Unable to log in', expected=True) raise ExtractorError('Unable to log in', expected=True)
def _call_api(self, path_template, video_id, fields=None): def _call_api(self, path_template, video_id, fields=None, limit=None):
query = {'appId': self._APP_ID, 'gcc': 'KR'} query = {'appId': self._APP_ID, 'gcc': 'KR'}
if fields: if fields:
query['fields'] = fields query['fields'] = fields
if limit:
query['limit'] = limit
try: try:
return self._download_json( return self._download_json(
'https://www.vlive.tv/globalv-web/vam-web/' + path_template % video_id, video_id, 'https://www.vlive.tv/globalv-web/vam-web/' + path_template % video_id, video_id,
@@ -124,10 +133,34 @@ class VLiveIE(VLiveBaseIE):
post = self._call_api( post = self._call_api(
'post/v1.0/officialVideoPost-%s', video_id, 'post/v1.0/officialVideoPost-%s', video_id,
'author{nickname},channel{channelCode,channelName},officialVideo{commentCount,exposeStatus,likeCount,playCount,playTime,status,title,type,vodId}') 'author{nickname},channel{channelCode,channelName},officialVideo{commentCount,exposeStatus,likeCount,playCount,playTime,status,title,type,vodId},playlist{playlistSeq,totalCount,name}')
video = post['officialVideo'] playlist = post.get('playlist')
if not playlist or self._downloader.params.get('noplaylist'):
if playlist:
self.to_screen(
'Downloading just video %s because of --no-playlist'
% video_id)
video = post['officialVideo']
return self._get_vlive_info(post, video, video_id)
else:
playlist_name = playlist.get('name')
playlist_id = str_or_none(playlist.get('playlistSeq'))
playlist_count = str_or_none(playlist.get('totalCount'))
playlist = self._call_api(
'playlist/v1.0/playlist-%s/posts', playlist_id, 'data', limit=playlist_count)
entries = []
for video_data in playlist['data']:
video = video_data.get('officialVideo')
video_id = str_or_none(video.get('videoSeq'))
entries.append(self._get_vlive_info(video_data, video, video_id))
return self.playlist_result(entries, playlist_id, playlist_name)
def _get_vlive_info(self, post, video, video_id):
def get_common_fields(): def get_common_fields():
channel = post.get('channel') or {} channel = post.get('channel') or {}
return { return {
@@ -323,22 +356,17 @@ class VLiveChannelIE(VLiveBaseIE):
video_id = compat_str(video_id) video_id = compat_str(video_id)
if video_type in ('PLAYLIST'): if video_type in ('PLAYLIST'):
playlist_videos = try_get( first_video_id = try_get(
video, video,
lambda x: x['videoPlaylist']['videoList'], list) lambda x: x['videoPlaylist']['videoList'][0]['videoSeq'], int)
if not playlist_videos:
if not first_video_id:
continue continue
for playlist_video in playlist_videos: entries.append(
playlist_video_id = playlist_video.get('videoSeq') self.url_result(
if not playlist_video_id: 'http://www.vlive.tv/video/%s' % first_video_id,
continue ie=VLiveIE.ie_key(), video_id=first_video_id))
playlist_video_id = compat_str(playlist_video_id)
entries.append(
self.url_result(
'http://www.vlive.tv/video/%s' % playlist_video_id,
ie=VLiveIE.ie_key(), video_id=playlist_video_id))
else: else:
entries.append( entries.append(
self.url_result( self.url_result(

View File

@@ -970,9 +970,14 @@ def parseOpts(overrideArguments=None):
metavar='FORMAT', dest='recodevideo', default=None, metavar='FORMAT', dest='recodevideo', default=None,
help='Re-encode the video into another format if re-encoding is necessary (currently supported: mp4|flv|ogg|webm|mkv|avi)') help='Re-encode the video into another format if re-encoding is necessary (currently supported: mp4|flv|ogg|webm|mkv|avi)')
postproc.add_option( postproc.add_option(
'--postprocessor-args', '--postprocessor-args', metavar='NAME:ARGS',
dest='postprocessor_args', metavar='ARGS', dest='postprocessor_args', action='append',
help='Give these arguments to the postprocessor') help=(
'Give these arguments to the postprocessors. '
"Specify the postprocessor name and the arguments separated by a colon ':' "
'to give the argument to only the specified postprocessor. Supported names are '
'ExtractAudio, VideoRemuxer, VideoConvertor, EmbedSubtitle, Metadata, Merger, FixupStretched, FixupM4a, FixupM3u8, SubtitlesConvertor, SponSkrub and Default'
'. You can use this option multiple times to give different arguments to different postprocessors'))
postproc.add_option( postproc.add_option(
'-k', '--keep-video', '-k', '--keep-video',
action='store_true', dest='keepvideo', default=False, action='store_true', dest='keepvideo', default=False,
@@ -1089,7 +1094,7 @@ def parseOpts(overrideArguments=None):
help='Location of the sponskrub binary; either the path to the binary or its containing directory.') help='Location of the sponskrub binary; either the path to the binary or its containing directory.')
sponskrub.add_option( sponskrub.add_option(
'--sponskrub-args', dest='sponskrub_args', metavar='ARGS', '--sponskrub-args', dest='sponskrub_args', metavar='ARGS',
help='Give these arguments to sponskrub') help=optparse.SUPPRESS_HELP)
extractor = optparse.OptionGroup(parser, 'Extractor Options') extractor = optparse.OptionGroup(parser, 'Extractor Options')
extractor.add_option( extractor.add_option(

View File

@@ -33,6 +33,11 @@ class PostProcessor(object):
def __init__(self, downloader=None): def __init__(self, downloader=None):
self._downloader = downloader self._downloader = downloader
if not hasattr(self, 'PP_NAME'):
self.PP_NAME = self.__class__.__name__[:-2]
def to_screen(self, text, *args, **kwargs):
return self._downloader.to_screen('[%s] %s' % (self.PP_NAME, text), *args, **kwargs)
def set_downloader(self, downloader): def set_downloader(self, downloader):
"""Sets the downloader for this PP.""" """Sets the downloader for this PP."""
@@ -62,7 +67,10 @@ class PostProcessor(object):
self._downloader.report_warning(errnote) self._downloader.report_warning(errnote)
def _configuration_args(self, default=[]): def _configuration_args(self, default=[]):
return cli_configuration_args(self._downloader.params, 'postprocessor_args', default) args = self._downloader.params.get('postprocessor_args', {})
if isinstance(args, list): # for backward compatibility
args = {'default': args, 'sponskrub': []}
return cli_configuration_args(args, self.PP_NAME.lower(), args.get('default', []))
class AudioConversionError(PostProcessingError): class AudioConversionError(PostProcessingError):

View File

@@ -23,6 +23,8 @@ class EmbedThumbnailPPError(PostProcessingError):
class EmbedThumbnailPP(FFmpegPostProcessor): class EmbedThumbnailPP(FFmpegPostProcessor):
PP_NAME = 'EmbedThumbnail'
def __init__(self, downloader=None, already_have_thumbnail=False): def __init__(self, downloader=None, already_have_thumbnail=False):
super(EmbedThumbnailPP, self).__init__(downloader) super(EmbedThumbnailPP, self).__init__(downloader)
self._already_have_thumbnail = already_have_thumbnail self._already_have_thumbnail = already_have_thumbnail
@@ -32,7 +34,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
if not info.get('thumbnails'): if not info.get('thumbnails'):
self._downloader.to_screen('[embedthumbnail] There aren\'t any thumbnails to embed') self.to_screen('There aren\'t any thumbnails to embed')
return [], info return [], info
thumbnail_filename = info['thumbnails'][-1]['filename'] thumbnail_filename = info['thumbnails'][-1]['filename']
@@ -52,8 +54,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
if thumbnail_ext: if thumbnail_ext:
thumbnail_ext = thumbnail_ext[1:].lower() thumbnail_ext = thumbnail_ext[1:].lower()
if thumbnail_ext != 'webp' and is_webp(thumbnail_filename): if thumbnail_ext != 'webp' and is_webp(thumbnail_filename):
self._downloader.to_screen( self.to_screen('Correcting extension to webp and escaping path for thumbnail "%s"' % thumbnail_filename)
'[ffmpeg] Correcting extension to webp and escaping path for thumbnail "%s"' % thumbnail_filename)
thumbnail_webp_filename = replace_extension(thumbnail_filename, 'webp') thumbnail_webp_filename = replace_extension(thumbnail_filename, 'webp')
os.rename(encodeFilename(thumbnail_filename), encodeFilename(thumbnail_webp_filename)) os.rename(encodeFilename(thumbnail_filename), encodeFilename(thumbnail_webp_filename))
thumbnail_filename = thumbnail_webp_filename thumbnail_filename = thumbnail_webp_filename
@@ -66,7 +67,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
escaped_thumbnail_filename = thumbnail_filename.replace('%', '#') escaped_thumbnail_filename = thumbnail_filename.replace('%', '#')
os.rename(encodeFilename(thumbnail_filename), encodeFilename(escaped_thumbnail_filename)) os.rename(encodeFilename(thumbnail_filename), encodeFilename(escaped_thumbnail_filename))
escaped_thumbnail_jpg_filename = replace_extension(escaped_thumbnail_filename, 'jpg') escaped_thumbnail_jpg_filename = replace_extension(escaped_thumbnail_filename, 'jpg')
self._downloader.to_screen('[ffmpeg] Converting thumbnail "%s" to JPEG' % escaped_thumbnail_filename) self.to_screen('Converting thumbnail "%s" to JPEG' % escaped_thumbnail_filename)
self.run_ffmpeg(escaped_thumbnail_filename, escaped_thumbnail_jpg_filename, ['-bsf:v', 'mjpeg2jpeg']) self.run_ffmpeg(escaped_thumbnail_filename, escaped_thumbnail_jpg_filename, ['-bsf:v', 'mjpeg2jpeg'])
os.remove(encodeFilename(escaped_thumbnail_filename)) os.remove(encodeFilename(escaped_thumbnail_filename))
thumbnail_jpg_filename = replace_extension(thumbnail_filename, 'jpg') thumbnail_jpg_filename = replace_extension(thumbnail_filename, 'jpg')
@@ -79,7 +80,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
'-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version', '3', '-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version', '3',
'-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"'] '-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"']
self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename) self.to_screen('Adding thumbnail to "%s"' % filename)
self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options) self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options)
@@ -96,10 +97,10 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
os.rename(encodeFilename(old_thumbnail_filename), encodeFilename(thumbnail_filename)) os.rename(encodeFilename(old_thumbnail_filename), encodeFilename(thumbnail_filename))
options = [ options = [
'-c', 'copy', '-map', '0', '-c', 'copy', '-map', '0', '-dn',
'-attach', thumbnail_filename, '-metadata:s:t', 'mimetype=image/jpeg'] '-attach', thumbnail_filename, '-metadata:s:t', 'mimetype=image/jpeg']
self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename) self.to_screen('Adding thumbnail to "%s"' % filename)
self.run_ffmpeg_multiple_files([filename], temp_filename, options) self.run_ffmpeg_multiple_files([filename], temp_filename, options)
@@ -121,7 +122,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
encodeArgument('-o'), encodeArgument('-o'),
encodeFilename(temp_filename, True)] encodeFilename(temp_filename, True)]
self._downloader.to_screen('[atomicparsley] Adding thumbnail to "%s"' % filename) self.to_screen('Adding thumbnail to "%s"' % filename)
if self._downloader.params.get('verbose', False): if self._downloader.params.get('verbose', False):
self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd)) self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd))

View File

@@ -11,6 +11,8 @@ from ..utils import (
class ExecAfterDownloadPP(PostProcessor): class ExecAfterDownloadPP(PostProcessor):
PP_NAME = 'Exec'
def __init__(self, downloader, exec_cmd): def __init__(self, downloader, exec_cmd):
super(ExecAfterDownloadPP, self).__init__(downloader) super(ExecAfterDownloadPP, self).__init__(downloader)
self.exec_cmd = exec_cmd self.exec_cmd = exec_cmd
@@ -22,7 +24,7 @@ class ExecAfterDownloadPP(PostProcessor):
cmd = cmd.replace('{}', compat_shlex_quote(information['filepath'])) cmd = cmd.replace('{}', compat_shlex_quote(information['filepath']))
self._downloader.to_screen('[exec] Executing command: %s' % cmd) self.to_screen('Executing command: %s' % cmd)
retCode = subprocess.call(encodeArgument(cmd), shell=True) retCode = subprocess.call(encodeArgument(cmd), shell=True)
if retCode != 0: if retCode != 0:
raise PostProcessingError( raise PostProcessingError(

View File

@@ -53,6 +53,8 @@ class FFmpegPostProcessorError(PostProcessingError):
class FFmpegPostProcessor(PostProcessor): class FFmpegPostProcessor(PostProcessor):
def __init__(self, downloader=None): def __init__(self, downloader=None):
if not hasattr(self, 'PP_NAME'):
self.PP_NAME = self.__class__.__name__[6:-2] # Remove ffmpeg from the front
PostProcessor.__init__(self, downloader) PostProcessor.__init__(self, downloader)
self._determine_executables() self._determine_executables()
@@ -328,11 +330,11 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor):
# If we download foo.mp3 and convert it to... foo.mp3, then don't delete foo.mp3, silly. # If we download foo.mp3 and convert it to... foo.mp3, then don't delete foo.mp3, silly.
if (new_path == path if (new_path == path
or (self._nopostoverwrites and os.path.exists(encodeFilename(new_path)))): or (self._nopostoverwrites and os.path.exists(encodeFilename(new_path)))):
self._downloader.to_screen('[ffmpeg] Post-process file %s exists, skipping' % new_path) self.to_screen('Post-process file %s exists, skipping' % new_path)
return [], information return [], information
try: try:
self._downloader.to_screen('[ffmpeg] Destination: ' + new_path) self.to_screen('Destination: ' + new_path)
self.run_ffmpeg(path, new_path, acodec, more_opts) self.run_ffmpeg(path, new_path, acodec, more_opts)
except AudioConversionError as e: except AudioConversionError as e:
raise PostProcessingError( raise PostProcessingError(
@@ -357,12 +359,12 @@ class FFmpegVideoRemuxerPP(FFmpegPostProcessor):
def run(self, information): def run(self, information):
path = information['filepath'] path = information['filepath']
if information['ext'] == self._preferedformat: if information['ext'] == self._preferedformat:
self._downloader.to_screen('[ffmpeg] Not remuxing video file %s - already is in target format %s' % (path, self._preferedformat)) self.to_screen('Not remuxing video file %s - already is in target format %s' % (path, self._preferedformat))
return [], information return [], information
options = ['-c', 'copy', '-map', '0'] options = ['-c', 'copy', '-map', '0', '-dn']
prefix, sep, ext = path.rpartition('.') prefix, sep, ext = path.rpartition('.')
outpath = prefix + sep + self._preferedformat outpath = prefix + sep + self._preferedformat
self._downloader.to_screen('[' + 'ffmpeg' + '] Remuxing video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath) self.to_screen('Remuxing video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath)
self.run_ffmpeg(path, outpath, options) self.run_ffmpeg(path, outpath, options)
information['filepath'] = outpath information['filepath'] = outpath
information['format'] = self._preferedformat information['format'] = self._preferedformat
@@ -378,14 +380,14 @@ class FFmpegVideoConvertorPP(FFmpegPostProcessor):
def run(self, information): def run(self, information):
path = information['filepath'] path = information['filepath']
if information['ext'] == self._preferedformat: if information['ext'] == self._preferedformat:
self._downloader.to_screen('[ffmpeg] Not converting video file %s - already is in target format %s' % (path, self._preferedformat)) self.to_screen('Not converting video file %s - already is in target format %s' % (path, self._preferedformat))
return [], information return [], information
options = [] options = []
if self._preferedformat == 'avi': if self._preferedformat == 'avi':
options.extend(['-c:v', 'libxvid', '-vtag', 'XVID']) options.extend(['-c:v', 'libxvid', '-vtag', 'XVID'])
prefix, sep, ext = path.rpartition('.') prefix, sep, ext = path.rpartition('.')
outpath = prefix + sep + self._preferedformat outpath = prefix + sep + self._preferedformat
self._downloader.to_screen('[' + 'ffmpeg' + '] Converting video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath) self.to_screen('Converting video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath)
self.run_ffmpeg(path, outpath, options) self.run_ffmpeg(path, outpath, options)
information['filepath'] = outpath information['filepath'] = outpath
information['format'] = self._preferedformat information['format'] = self._preferedformat
@@ -396,11 +398,11 @@ class FFmpegVideoConvertorPP(FFmpegPostProcessor):
class FFmpegEmbedSubtitlePP(FFmpegPostProcessor): class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
def run(self, information): def run(self, information):
if information['ext'] not in ('mp4', 'webm', 'mkv'): if information['ext'] not in ('mp4', 'webm', 'mkv'):
self._downloader.to_screen('[ffmpeg] Subtitles can only be embedded in mp4, webm or mkv files') self.to_screen('Subtitles can only be embedded in mp4, webm or mkv files')
return [], information return [], information
subtitles = information.get('requested_subtitles') subtitles = information.get('requested_subtitles')
if not subtitles: if not subtitles:
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to embed') self.to_screen('There aren\'t any subtitles to embed')
return [], information return [], information
filename = information['filepath'] filename = information['filepath']
@@ -413,14 +415,14 @@ class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
for lang, sub_info in subtitles.items(): for lang, sub_info in subtitles.items():
sub_ext = sub_info['ext'] sub_ext = sub_info['ext']
if sub_ext == 'json': if sub_ext == 'json':
self._downloader.to_screen('[ffmpeg] JSON subtitles cannot be embedded') self.to_screen('JSON subtitles cannot be embedded')
elif ext != 'webm' or ext == 'webm' and sub_ext == 'vtt': elif ext != 'webm' or ext == 'webm' and sub_ext == 'vtt':
sub_langs.append(lang) sub_langs.append(lang)
sub_filenames.append(subtitles_filename(filename, lang, sub_ext, ext)) sub_filenames.append(subtitles_filename(filename, lang, sub_ext, ext))
else: else:
if not webm_vtt_warn and ext == 'webm' and sub_ext != 'vtt': if not webm_vtt_warn and ext == 'webm' and sub_ext != 'vtt':
webm_vtt_warn = True webm_vtt_warn = True
self._downloader.to_screen('[ffmpeg] Only WebVTT subtitles can be embedded in webm files') self.to_screen('Only WebVTT subtitles can be embedded in webm files')
if not sub_langs: if not sub_langs:
return [], information return [], information
@@ -428,7 +430,7 @@ class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
input_files = [filename] + sub_filenames input_files = [filename] + sub_filenames
opts = [ opts = [
'-c', 'copy', '-map', '0', '-c', 'copy', '-map', '0', '-dn',
# Don't copy the existing subtitles, we may be running the # Don't copy the existing subtitles, we may be running the
# postprocessor a second time # postprocessor a second time
'-map', '-0:s', '-map', '-0:s',
@@ -444,7 +446,7 @@ class FFmpegEmbedSubtitlePP(FFmpegPostProcessor):
opts.extend(['-metadata:s:s:%d' % i, 'language=%s' % lang_code]) opts.extend(['-metadata:s:s:%d' % i, 'language=%s' % lang_code])
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
self._downloader.to_screen('[ffmpeg] Embedding subtitles in \'%s\'' % filename) self.to_screen('Embedding subtitles in \'%s\'' % filename)
self.run_ffmpeg_multiple_files(input_files, temp_filename, opts) self.run_ffmpeg_multiple_files(input_files, temp_filename, opts)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
os.rename(encodeFilename(temp_filename), encodeFilename(filename)) os.rename(encodeFilename(temp_filename), encodeFilename(filename))
@@ -492,13 +494,13 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
add('episode_sort', 'episode_number') add('episode_sort', 'episode_number')
if not metadata: if not metadata:
self._downloader.to_screen('[ffmpeg] There isn\'t any metadata to add') self.to_screen('There isn\'t any metadata to add')
return [], info return [], info
filename = info['filepath'] filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
in_filenames = [filename] in_filenames = [filename]
options = ['-map', '0'] options = ['-map', '0', '-dn']
if info['ext'] == 'm4a': if info['ext'] == 'm4a':
options.extend(['-vn', '-acodec', 'copy']) options.extend(['-vn', '-acodec', 'copy'])
@@ -527,7 +529,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
in_filenames.append(metadata_filename) in_filenames.append(metadata_filename)
options.extend(['-map_metadata', '1']) options.extend(['-map_metadata', '1'])
self._downloader.to_screen('[ffmpeg] Adding metadata to \'%s\'' % filename) self.to_screen('Adding metadata to \'%s\'' % filename)
self.run_ffmpeg_multiple_files(in_filenames, temp_filename, options) self.run_ffmpeg_multiple_files(in_filenames, temp_filename, options)
if chapters: if chapters:
os.remove(metadata_filename) os.remove(metadata_filename)
@@ -546,7 +548,7 @@ class FFmpegMergerPP(FFmpegPostProcessor):
args.extend(['-map', '%u:a:0' % (i)]) args.extend(['-map', '%u:a:0' % (i)])
if fmt.get('vcodec') != 'none': if fmt.get('vcodec') != 'none':
args.extend(['-map', '%u:v:0' % (i)]) args.extend(['-map', '%u:v:0' % (i)])
self._downloader.to_screen('[ffmpeg] Merging formats into "%s"' % filename) self.to_screen('Merging formats into "%s"' % filename)
self.run_ffmpeg_multiple_files(info['__files_to_merge'], temp_filename, args) self.run_ffmpeg_multiple_files(info['__files_to_merge'], temp_filename, args)
os.rename(encodeFilename(temp_filename), encodeFilename(filename)) os.rename(encodeFilename(temp_filename), encodeFilename(filename))
return info['__files_to_merge'], info return info['__files_to_merge'], info
@@ -578,8 +580,8 @@ class FFmpegFixupStretchedPP(FFmpegPostProcessor):
filename = info['filepath'] filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
options = ['-c', 'copy', '-map', '0', '-aspect', '%f' % stretched_ratio] options = ['-c', 'copy', '-map', '0', '-dn', '-aspect', '%f' % stretched_ratio]
self._downloader.to_screen('[ffmpeg] Fixing aspect ratio in "%s"' % filename) self.to_screen('Fixing aspect ratio in "%s"' % filename)
self.run_ffmpeg(filename, temp_filename, options) self.run_ffmpeg(filename, temp_filename, options)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
@@ -596,8 +598,8 @@ class FFmpegFixupM4aPP(FFmpegPostProcessor):
filename = info['filepath'] filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
options = ['-c', 'copy', '-map', '0', '-f', 'mp4'] options = ['-c', 'copy', '-map', '0', '-dn', '-f', 'mp4']
self._downloader.to_screen('[ffmpeg] Correcting container in "%s"' % filename) self.to_screen('Correcting container in "%s"' % filename)
self.run_ffmpeg(filename, temp_filename, options) self.run_ffmpeg(filename, temp_filename, options)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
@@ -612,8 +614,8 @@ class FFmpegFixupM3u8PP(FFmpegPostProcessor):
if self.get_audio_codec(filename) == 'aac': if self.get_audio_codec(filename) == 'aac':
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
options = ['-c', 'copy', '-map', '0', '-f', 'mp4', '-bsf:a', 'aac_adtstoasc'] options = ['-c', 'copy', '-map', '0', '-dn', '-f', 'mp4', '-bsf:a', 'aac_adtstoasc']
self._downloader.to_screen('[ffmpeg] Fixing malformed AAC bitstream in "%s"' % filename) self.to_screen('Fixing malformed AAC bitstream in "%s"' % filename)
self.run_ffmpeg(filename, temp_filename, options) self.run_ffmpeg(filename, temp_filename, options)
os.remove(encodeFilename(filename)) os.remove(encodeFilename(filename))
@@ -634,19 +636,18 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
if new_format == 'vtt': if new_format == 'vtt':
new_format = 'webvtt' new_format = 'webvtt'
if subs is None: if subs is None:
self._downloader.to_screen('[ffmpeg] There aren\'t any subtitles to convert') self.to_screen('There aren\'t any subtitles to convert')
return [], info return [], info
self._downloader.to_screen('[ffmpeg] Converting subtitles') self.to_screen('Converting subtitles')
sub_filenames = [] sub_filenames = []
for lang, sub in subs.items(): for lang, sub in subs.items():
ext = sub['ext'] ext = sub['ext']
if ext == new_ext: if ext == new_ext:
self._downloader.to_screen( self.to_screen('Subtitle file for %s is already in the requested format' % new_ext)
'[ffmpeg] Subtitle file for %s is already in the requested format' % new_ext)
continue continue
elif ext == 'json': elif ext == 'json':
self._downloader.to_screen( self.to_screen(
'[ffmpeg] You have requested to convert json subtitles into another format, ' 'You have requested to convert json subtitles into another format, '
'which is currently not possible') 'which is currently not possible')
continue continue
old_file = subtitles_filename(filename, lang, ext, info.get('ext')) old_file = subtitles_filename(filename, lang, ext, info.get('ext'))
@@ -655,7 +656,7 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
if ext in ('dfxp', 'ttml', 'tt'): if ext in ('dfxp', 'ttml', 'tt'):
self._downloader.report_warning( self._downloader.report_warning(
'[ffmpeg] You have requested to convert dfxp (TTML) subtitles into another format, ' 'You have requested to convert dfxp (TTML) subtitles into another format, '
'which results in style information loss') 'which results in style information loss')
dfxp_file = old_file dfxp_file = old_file

View File

@@ -35,14 +35,10 @@ class MetadataFromTitlePP(PostProcessor):
title = info['title'] title = info['title']
match = re.match(self._titleregex, title) match = re.match(self._titleregex, title)
if match is None: if match is None:
self._downloader.to_screen( self.to_screen('Could not interpret title of video as "%s"' % self._titleformat)
'[fromtitle] Could not interpret title of video as "%s"'
% self._titleformat)
return [], info return [], info
for attribute, value in match.groupdict().items(): for attribute, value in match.groupdict().items():
info[attribute] = value info[attribute] = value
self._downloader.to_screen( self.to_screen('parsed %s: %s' % (attribute, value if value is not None else 'NA'))
'[fromtitle] parsed %s: %s'
% (attribute, value if value is not None else 'NA'))
return [], info return [], info

View File

@@ -22,7 +22,7 @@ class SponSkrubPP(PostProcessor):
self.force = force self.force = force
self.cutout = cut self.cutout = cut
self.args = ['-chapter'] if not cut else [] self.args = ['-chapter'] if not cut else []
self.args += self._def_args if args is None else compat_shlex_split(args) self.args += self._configuration_args(self._def_args) if args is None else compat_shlex_split(args)
self.path = self.get_exe(path) self.path = self.get_exe(path)
if not ignoreerror and self.path is None: if not ignoreerror and self.path is None:
@@ -43,7 +43,7 @@ class SponSkrubPP(PostProcessor):
return [], information return [], information
if information['extractor_key'].lower() != 'youtube': if information['extractor_key'].lower() != 'youtube':
self._downloader.to_screen('[sponskrub] Skipping sponskrub since it is not a YouTube video') self.to_screen('Skipping sponskrub since it is not a YouTube video')
return [], information return [], information
if self.cutout and not self.force and not information.get('__real_download', False): if self.cutout and not self.force and not information.get('__real_download', False):
self._downloader.to_screen( self._downloader.to_screen(
@@ -51,7 +51,7 @@ class SponSkrubPP(PostProcessor):
'Use --sponskrub-force to run sponskrub anyway') 'Use --sponskrub-force to run sponskrub anyway')
return [], information return [], information
self._downloader.to_screen('[sponskrub] Trying to %s sponsor sections' % ('remove' if self.cutout else 'mark')) self.to_screen('Trying to %s sponsor sections' % ('remove' if self.cutout else 'mark'))
if self.cutout: if self.cutout:
self._downloader.to_screen('WARNING: Cutting out sponsor segments will cause the subtitles to go out of sync.') self._downloader.to_screen('WARNING: Cutting out sponsor segments will cause the subtitles to go out of sync.')
if not information.get('__real_download', False): if not information.get('__real_download', False):
@@ -76,11 +76,11 @@ class SponSkrubPP(PostProcessor):
if p.returncode == 0: if p.returncode == 0:
os.remove(filename) os.remove(filename)
os.rename(temp_filename, filename) os.rename(temp_filename, filename)
self._downloader.to_screen('[sponskrub] Sponsor sections have been %s' % ('removed' if self.cutout else 'marked')) self.to_screen('Sponsor sections have been %s' % ('removed' if self.cutout else 'marked'))
elif p.returncode != 3: # error code 3 means there was no info about the video elif p.returncode == 3:
self.to_screen('No segments in the SponsorBlock database')
else:
stderr = stderr.decode('utf-8', 'replace') stderr = stderr.decode('utf-8', 'replace')
msg = stderr.strip().split('\n')[-1] msg = stderr.strip().split('\n')[-1]
raise PostProcessingError(msg if msg else 'sponskrub failed with error code %s!' % p.returncode) raise PostProcessingError(msg if msg else 'sponskrub failed with error code %s!' % p.returncode)
else:
self._downloader.to_screen('[sponskrub] No segments in the SponsorBlock database')
return [], information return [], information

View File

@@ -11,7 +11,6 @@ from ..utils import (
class XAttrMetadataPP(PostProcessor): class XAttrMetadataPP(PostProcessor):
# #
# More info about extended attributes for media: # More info about extended attributes for media:
# http://freedesktop.org/wiki/CommonExtendedAttributes/ # http://freedesktop.org/wiki/CommonExtendedAttributes/
@@ -27,7 +26,7 @@ class XAttrMetadataPP(PostProcessor):
""" Set extended attributes on downloaded file (if xattr support is found). """ """ Set extended attributes on downloaded file (if xattr support is found). """
# Write the metadata to the file's xattrs # Write the metadata to the file's xattrs
self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs') self.to_screen('Writing metadata to file\'s xattrs')
filename = info['filepath'] filename = info['filepath']

View File

@@ -1,3 +1,3 @@
from __future__ import unicode_literals from __future__ import unicode_literals
__version__ = '2021.01.05-2' __version__ = '2021.01.07'