update yt-dlp and fix some bugs with TPE2. Fixes #3
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -247,7 +247,8 @@ Python versions 3.10+ (CPython) and 3.11+ (PyPy) are supported. Other
|
|||||||
versions and implementations may or may not work correctly.
|
versions and implementations may or may not work correctly.
|
||||||
|
|
||||||
While all the other dependencies are optional, ffmpeg, ffprobe,
|
While all the other dependencies are optional, ffmpeg, ffprobe,
|
||||||
yt-dlp-ejs and a JavaScript runtime are highly recommended
|
yt-dlp-ejs and a supported JavaScript runtime/engine are highly
|
||||||
|
recommended
|
||||||
|
|
||||||
Strongly recommended
|
Strongly recommended
|
||||||
|
|
||||||
@@ -264,11 +265,11 @@ Strongly recommended
|
|||||||
Important: What you need is ffmpeg binary, NOT the Python package of
|
Important: What you need is ffmpeg binary, NOT the Python package of
|
||||||
the same name
|
the same name
|
||||||
|
|
||||||
- yt-dlp-ejs - Required for deciphering YouTube n/sig values. Licensed
|
- yt-dlp-ejs - Required for full YouTube support. Licensed under
|
||||||
under Unlicense, bundles MIT and ISC components.
|
Unlicense, bundles MIT and ISC components.
|
||||||
|
|
||||||
A JavaScript runtime like deno (recommended), node.js, bun, or
|
A JavaScript runtime/engine like deno (recommended), node.js, bun,
|
||||||
QuickJS is also required to run yt-dlp-ejs. See the wiki.
|
or QuickJS is also required to run yt-dlp-ejs. See the wiki.
|
||||||
|
|
||||||
Networking
|
Networking
|
||||||
|
|
||||||
@@ -289,7 +290,7 @@ may be required for some sites that employ TLS fingerprinting.
|
|||||||
- curl_cffi (recommended) - Python binding for curl-impersonate.
|
- curl_cffi (recommended) - Python binding for curl-impersonate.
|
||||||
Provides impersonation targets for Chrome, Edge and Safari. Licensed
|
Provides impersonation targets for Chrome, Edge and Safari. Licensed
|
||||||
under MIT
|
under MIT
|
||||||
- Can be installed with the curl-cffi group, e.g.
|
- Can be installed with the curl-cffi extra, e.g.
|
||||||
pip install "yt-dlp[default,curl-cffi]"
|
pip install "yt-dlp[default,curl-cffi]"
|
||||||
- Currently included in most builds except yt-dlp (Unix zipimport
|
- Currently included in most builds except yt-dlp (Unix zipimport
|
||||||
binary), yt-dlp_x86 (Windows 32-bit) and
|
binary), yt-dlp_x86 (Windows 32-bit) and
|
||||||
@@ -343,7 +344,7 @@ will be built for the same CPU architecture as the Python used.
|
|||||||
|
|
||||||
You can run the following commands:
|
You can run the following commands:
|
||||||
|
|
||||||
python devscripts/install_deps.py --include-group pyinstaller
|
python devscripts/install_deps.py --include-extra pyinstaller
|
||||||
python devscripts/make_lazy_extractors.py
|
python devscripts/make_lazy_extractors.py
|
||||||
python -m bundle.pyinstaller
|
python -m bundle.pyinstaller
|
||||||
|
|
||||||
@@ -580,7 +581,7 @@ Geo-restriction:
|
|||||||
|
|
||||||
Video Selection:
|
Video Selection:
|
||||||
|
|
||||||
-I, --playlist-items ITEM_SPEC Comma separated playlist_index of the items
|
-I, --playlist-items ITEM_SPEC Comma-separated playlist_index of the items
|
||||||
to download. You can specify a range using
|
to download. You can specify a range using
|
||||||
"[START]:[STOP][:STEP]". For backward
|
"[START]:[STOP][:STEP]". For backward
|
||||||
compatibility, START-STOP is also supported.
|
compatibility, START-STOP is also supported.
|
||||||
@@ -962,6 +963,8 @@ Video Format Options:
|
|||||||
for more details
|
for more details
|
||||||
-S, --format-sort SORTORDER Sort the formats by the fields given, see
|
-S, --format-sort SORTORDER Sort the formats by the fields given, see
|
||||||
"Sorting Formats" for more details
|
"Sorting Formats" for more details
|
||||||
|
--format-sort-reset Disregard previous user specified sort order
|
||||||
|
and reset to the default
|
||||||
--format-sort-force Force user specified sort order to have
|
--format-sort-force Force user specified sort order to have
|
||||||
precedence over all fields, see "Sorting
|
precedence over all fields, see "Sorting
|
||||||
Formats" for more details (Alias: --S-force)
|
Formats" for more details (Alias: --S-force)
|
||||||
@@ -1481,7 +1484,7 @@ have some special formatting:
|
|||||||
7. More Conversions: In addition to the normal format types
|
7. More Conversions: In addition to the normal format types
|
||||||
diouxXeEfFgGcrs, yt-dlp additionally supports converting to B =
|
diouxXeEfFgGcrs, yt-dlp additionally supports converting to B =
|
||||||
Bytes, j = json (flag # for pretty-printing, + for Unicode), h =
|
Bytes, j = json (flag # for pretty-printing, + for Unicode), h =
|
||||||
HTML escaping, l = a comma separated list (flag # for \n
|
HTML escaping, l = a comma-separated list (flag # for \n
|
||||||
newline-separated), q = a string quoted for the terminal (flag # to
|
newline-separated), q = a string quoted for the terminal (flag # to
|
||||||
split a list into different arguments), D = add Decimal suffixes
|
split a list into different arguments), D = add Decimal suffixes
|
||||||
(e.g. 10M) (flag # to use 1024 as factor), and S = Sanitize as
|
(e.g. 10M) (flag # to use 1024 as factor), and S = Sanitize as
|
||||||
@@ -1562,6 +1565,8 @@ The available fields are:
|
|||||||
- comment_count (numeric): Number of comments on the video (For some
|
- comment_count (numeric): Number of comments on the video (For some
|
||||||
extractors, comments are only downloaded at the end, and so this
|
extractors, comments are only downloaded at the end, and so this
|
||||||
field cannot be used)
|
field cannot be used)
|
||||||
|
- save_count (numeric): Number of times the video has been saved or
|
||||||
|
bookmarked
|
||||||
- age_limit (numeric): Age restriction for the video (years)
|
- age_limit (numeric): Age restriction for the video (years)
|
||||||
- live_status (string): One of "not_live", "is_live", "is_upcoming",
|
- live_status (string): One of "not_live", "is_live", "is_upcoming",
|
||||||
"was_live", "post_live" (was live, but VOD is not yet processed)
|
"was_live", "post_live" (was live, but VOD is not yet processed)
|
||||||
@@ -2035,6 +2040,15 @@ respects. Most of the time, what you actually want is the video with the
|
|||||||
smallest filesize instead. So it is generally better to use
|
smallest filesize instead. So it is generally better to use
|
||||||
-f best -S +size,+br,+res,+fps.
|
-f best -S +size,+br,+res,+fps.
|
||||||
|
|
||||||
|
If you use the -S/--format-sort option multiple times, each subsequent
|
||||||
|
sorting argument will be prepended to the previous one, and only the
|
||||||
|
highest priority entry of any duplicated field will be preserved. E.g.
|
||||||
|
-S proto -S res is equivalent to -S res,proto, and
|
||||||
|
-S res:720,fps -S vcodec,res:1080 is equivalent to
|
||||||
|
-S vcodec,res:1080,fps. You can use --format-sort-reset to disregard any
|
||||||
|
previously passed -S/--format-sort arguments and reset to the default
|
||||||
|
order.
|
||||||
|
|
||||||
Tip: You can use the -v -F to see how the formats have been sorted
|
Tip: You can use the -v -F to see how the formats have been sorted
|
||||||
(worst to best).
|
(worst to best).
|
||||||
|
|
||||||
@@ -2223,9 +2237,9 @@ metadata:
|
|||||||
|
|
||||||
composer composer or composers
|
composer composer or composers
|
||||||
|
|
||||||
genre genre or genres
|
genre genre, genres, categories or tags
|
||||||
|
|
||||||
album album
|
album album or series
|
||||||
|
|
||||||
album_artist album_artist or album_artists
|
album_artist album_artist or album_artists
|
||||||
|
|
||||||
@@ -2252,6 +2266,9 @@ Modifying metadata examples
|
|||||||
# Regex example
|
# Regex example
|
||||||
$ yt-dlp --parse-metadata "description:Artist - (?P<artist>.+)"
|
$ yt-dlp --parse-metadata "description:Artist - (?P<artist>.+)"
|
||||||
|
|
||||||
|
# Copy the episode field to the title field (with FROM and TO as single fields)
|
||||||
|
$ yt-dlp --parse-metadata "episode:title"
|
||||||
|
|
||||||
# Set title as "Series name S01E05"
|
# Set title as "Series name S01E05"
|
||||||
$ yt-dlp --parse-metadata "%(series)s S%(season_number)02dE%(episode_number)02d:%(title)s"
|
$ yt-dlp --parse-metadata "%(series)s S%(season_number)02dE%(episode_number)02d:%(title)s"
|
||||||
|
|
||||||
@@ -2295,20 +2312,20 @@ youtube
|
|||||||
respectively
|
respectively
|
||||||
- player_client: Clients to extract video data from. The currently
|
- player_client: Clients to extract video data from. The currently
|
||||||
available clients are web, web_safari, web_embedded, web_music,
|
available clients are web, web_safari, web_embedded, web_music,
|
||||||
web_creator, mweb, ios, android, android_sdkless, android_vr, tv,
|
web_creator, mweb, ios, ios_downgraded, android, android_vr, tv,
|
||||||
tv_simply, tv_downgraded, and tv_embedded. By default,
|
tv_simply, tv_downgraded, and tv_embedded. By default,
|
||||||
tv,android_sdkless,web is used. If no JavaScript runtime is
|
android_vr,ios_downgraded,web,web_safari is used. If no JavaScript
|
||||||
available, then android_sdkless,web_safari,web is used. If logged-in
|
runtime/engine is available, then android_vr,ios_downgraded is used.
|
||||||
cookies are passed to yt-dlp, then tv_downgraded,web_safari,web is
|
If logged-in cookies are passed to yt-dlp, then
|
||||||
used for free accounts and tv_downgraded,web_creator,web is used for
|
tv_downgraded,web,web_safari is used for free accounts and
|
||||||
premium accounts. The web_music client is added for
|
tv_downgraded,web_creator,web is used for premium accounts. The
|
||||||
music.youtube.com URLs when logged-in cookies are used. The
|
web_music client is added for music.youtube.com URLs when logged-in
|
||||||
web_embedded client is added for age-restricted videos but only
|
cookies are used. The web_embedded client is added for
|
||||||
works if the video is embeddable. The tv_embedded and web_creator
|
age-restricted videos but only works if the video is embeddable. The
|
||||||
clients are added for age-restricted videos if account
|
tv_embedded and web_creator clients are added for age-restricted
|
||||||
age-verification is required. Some clients, such as web and
|
videos if account age-verification is required. Some clients, such
|
||||||
web_music, require a po_token for their formats to be downloadable.
|
as web and web_music, require a po_token for their formats to be
|
||||||
Some clients, such as web_creator, will only work with
|
downloadable. Some clients, such as web_creator, will only work with
|
||||||
authentication. Not all clients support authentication via cookies.
|
authentication. Not all clients support authentication via cookies.
|
||||||
You can use default for the default clients, or you can use all for
|
You can use default for the default clients, or you can use all for
|
||||||
all clients (not recommended). You can prefix a client with - to
|
all clients (not recommended). You can prefix a client with - to
|
||||||
@@ -2338,11 +2355,15 @@ youtube
|
|||||||
YouTube's side)
|
YouTube's side)
|
||||||
- max_comments: Limit the amount of comments to gather.
|
- max_comments: Limit the amount of comments to gather.
|
||||||
Comma-separated list of integers representing
|
Comma-separated list of integers representing
|
||||||
max-comments,max-parents,max-replies,max-replies-per-thread. Default
|
max-comments,max-parents,max-replies,max-replies-per-thread,max-depth.
|
||||||
is all,all,all,all
|
Default is all,all,all,all,all
|
||||||
- E.g. all,all,1000,10 will get a maximum of 1000 replies total,
|
- A max-depth value of 1 will discard all replies, regardless of
|
||||||
with up to 10 replies per thread. 1000,all,100 will get a
|
the max-replies or max-replies-per-thread values given
|
||||||
maximum of 1000 comments, with a maximum of 100 replies total
|
- E.g. all,all,1000,10,2 will get a maximum of 1000 replies total,
|
||||||
|
with up to 10 replies per thread, and only 2 levels of depth
|
||||||
|
(i.e. top-level comments plus their immediate replies).
|
||||||
|
1000,all,100 will get a maximum of 1000 comments, with a maximum
|
||||||
|
of 100 replies total
|
||||||
- formats: Change the types of formats to return. dashy (convert HTTP
|
- formats: Change the types of formats to return. dashy (convert HTTP
|
||||||
to DASH), duplicate (identical content but different URLs or
|
to DASH), duplicate (identical content but different URLs or
|
||||||
protocol; includes dashy), incomplete (cannot be downloaded
|
protocol; includes dashy), incomplete (cannot be downloaded
|
||||||
@@ -2363,7 +2384,7 @@ youtube
|
|||||||
without cookies. Note: this may have adverse effects if used
|
without cookies. Note: this may have adverse effects if used
|
||||||
improperly. If a session from a browser is wanted, you should pass
|
improperly. If a session from a browser is wanted, you should pass
|
||||||
cookies instead (which contain the Visitor ID)
|
cookies instead (which contain the Visitor ID)
|
||||||
- po_token: Proof of Origin (PO) Token(s) to use. Comma seperated list
|
- po_token: Proof of Origin (PO) Token(s) to use. Comma-separated list
|
||||||
of PO Tokens in the format CLIENT.CONTEXT+PO_TOKEN, e.g.
|
of PO Tokens in the format CLIENT.CONTEXT+PO_TOKEN, e.g.
|
||||||
youtube:po_token=web.gvs+XXX,web.player=XXX,web_safari.gvs+YYY.
|
youtube:po_token=web.gvs+XXX,web.player=XXX,web_safari.gvs+YYY.
|
||||||
Context can be any of gvs (Google Video Server URLs), player
|
Context can be any of gvs (Google Video Server URLs), player
|
||||||
@@ -2375,18 +2396,20 @@ youtube
|
|||||||
requires one for the given context), never (never fetch a PO Token),
|
requires one for the given context), never (never fetch a PO Token),
|
||||||
or auto (default; only fetch a PO Token if the client requires one
|
or auto (default; only fetch a PO Token if the client requires one
|
||||||
for the given context)
|
for the given context)
|
||||||
- playback_wait: Duration (in seconds) to wait inbetween the
|
|
||||||
extraction and download stages in order to ensure the formats are
|
|
||||||
available. The default is 6 seconds
|
|
||||||
- jsc_trace: Enable debug logging for JS Challenge fetching. Either
|
- jsc_trace: Enable debug logging for JS Challenge fetching. Either
|
||||||
true or false (default)
|
true or false (default)
|
||||||
|
- use_ad_playback_context: Skip preroll ads to eliminate the mandatory
|
||||||
|
wait period before download. Do NOT use this when passing premium
|
||||||
|
account cookies to yt-dlp, as it will result in a loss of premium
|
||||||
|
formats. Only effective with the web, web_safari, web_music and mweb
|
||||||
|
player clients. Either true or false (default)
|
||||||
|
|
||||||
youtube-ejs
|
youtube-ejs
|
||||||
|
|
||||||
- jitless: Run suported Javascript engines in JIT-less mode. Supported
|
- jitless: Run supported Javascript engines in JIT-less mode.
|
||||||
runtimes are deno, node and bun. Provides better security at the
|
Supported runtimes are deno, node and bun. Provides better security
|
||||||
cost of performance/speed. Do note that node and bun are still
|
at the cost of performance/speed. Do note that node and bun are
|
||||||
considered unsecure. Either true or false (default)
|
still considered insecure. Either true or false (default)
|
||||||
|
|
||||||
youtubepot-webpo
|
youtubepot-webpo
|
||||||
|
|
||||||
@@ -2568,10 +2591,11 @@ tver
|
|||||||
vimeo
|
vimeo
|
||||||
|
|
||||||
- client: Client to extract video data from. The currently available
|
- client: Client to extract video data from. The currently available
|
||||||
clients are android, ios, and web. Only one client can be used. The
|
clients are android, ios, macos and web. Only one client can be
|
||||||
web client is used by default. The web client only works with
|
used. The macos client is used by default, but the web client is
|
||||||
account cookies or login credentials. The android and ios clients
|
used when logged-in. The web client only works with account cookies
|
||||||
only work with previously cached OAuth tokens
|
or login credentials. The android and ios clients only work with
|
||||||
|
previously cached OAuth tokens
|
||||||
- original_format_policy: Policy for when to try extracting original
|
- original_format_policy: Policy for when to try extracting original
|
||||||
formats. One of always, never, or auto. The default auto policy
|
formats. One of always, never, or auto. The default auto policy
|
||||||
tries to avoid exceeding the web client's API rate-limit by only
|
tries to avoid exceeding the web client's API rate-limit by only
|
||||||
@@ -3085,7 +3109,7 @@ and youtube-dlc:
|
|||||||
files by default. Use --mtime or --compat-options mtime-by-default
|
files by default. Use --mtime or --compat-options mtime-by-default
|
||||||
to revert this.
|
to revert this.
|
||||||
|
|
||||||
For ease of use, a few more compat options are available:
|
For convenience, there are some compat option aliases available to use:
|
||||||
|
|
||||||
- --compat-options all: Use all compat options (Do NOT use this!)
|
- --compat-options all: Use all compat options (Do NOT use this!)
|
||||||
- --compat-options youtube-dl: Same as
|
- --compat-options youtube-dl: Same as
|
||||||
@@ -3097,8 +3121,13 @@ For ease of use, a few more compat options are available:
|
|||||||
- --compat-options 2022: Same as
|
- --compat-options 2022: Same as
|
||||||
--compat-options 2023,playlist-match-filter,no-external-downloader-progress,prefer-legacy-http-handler,manifest-filesize-approx
|
--compat-options 2023,playlist-match-filter,no-external-downloader-progress,prefer-legacy-http-handler,manifest-filesize-approx
|
||||||
- --compat-options 2023: Same as --compat-options 2024,prefer-vp9-sort
|
- --compat-options 2023: Same as --compat-options 2024,prefer-vp9-sort
|
||||||
- --compat-options 2024: Same as --compat-options mtime-by-default.
|
- --compat-options 2024: Same as
|
||||||
Use this to enable all future compat options
|
--compat-options 2025,mtime-by-default
|
||||||
|
- --compat-options 2025: Currently does nothing. Use this to enable
|
||||||
|
all future compat options
|
||||||
|
|
||||||
|
Using one of the yearly compat option aliases will pin yt-dlp's default
|
||||||
|
behavior to what it was at the end of that calendar year.
|
||||||
|
|
||||||
The following compat options restore vulnerable behavior from before
|
The following compat options restore vulnerable behavior from before
|
||||||
security patches:
|
security patches:
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ complete --command yt-dlp --long-option geo-bypass-country
|
|||||||
complete --command yt-dlp --long-option geo-bypass-ip-block
|
complete --command yt-dlp --long-option geo-bypass-ip-block
|
||||||
complete --command yt-dlp --long-option playlist-start
|
complete --command yt-dlp --long-option playlist-start
|
||||||
complete --command yt-dlp --long-option playlist-end
|
complete --command yt-dlp --long-option playlist-end
|
||||||
complete --command yt-dlp --long-option playlist-items --short-option I --description 'Comma separated playlist_index of the items to download. You can specify a range using "[START]:[STOP][:STEP]". For backward compatibility, START-STOP is also supported. Use negative indices to count from the right and negative STEP to download in reverse order. E.g. "-I 1:3,7,-5::2" used on a playlist of size 15 will download the items at index 1,2,3,7,11,13,15'
|
complete --command yt-dlp --long-option playlist-items --short-option I --description 'Comma-separated playlist_index of the items to download. You can specify a range using "[START]:[STOP][:STEP]". For backward compatibility, START-STOP is also supported. Use negative indices to count from the right and negative STEP to download in reverse order. E.g. "-I 1:3,7,-5::2" used on a playlist of size 15 will download the items at index 1,2,3,7,11,13,15'
|
||||||
complete --command yt-dlp --long-option match-title
|
complete --command yt-dlp --long-option match-title
|
||||||
complete --command yt-dlp --long-option reject-title
|
complete --command yt-dlp --long-option reject-title
|
||||||
complete --command yt-dlp --long-option min-filesize --description 'Abort download if filesize is smaller than SIZE, e.g. 50k or 44.6M'
|
complete --command yt-dlp --long-option min-filesize --description 'Abort download if filesize is smaller than SIZE, e.g. 50k or 44.6M'
|
||||||
@@ -199,6 +199,7 @@ complete --command yt-dlp --long-option max-sleep-interval --description 'Maximu
|
|||||||
complete --command yt-dlp --long-option sleep-subtitles --description 'Number of seconds to sleep before each subtitle download'
|
complete --command yt-dlp --long-option sleep-subtitles --description 'Number of seconds to sleep before each subtitle download'
|
||||||
complete --command yt-dlp --long-option format --short-option f --description 'Video format code, see "FORMAT SELECTION" for more details'
|
complete --command yt-dlp --long-option format --short-option f --description 'Video format code, see "FORMAT SELECTION" for more details'
|
||||||
complete --command yt-dlp --long-option format-sort --short-option S --description 'Sort the formats by the fields given, see "Sorting Formats" for more details'
|
complete --command yt-dlp --long-option format-sort --short-option S --description 'Sort the formats by the fields given, see "Sorting Formats" for more details'
|
||||||
|
complete --command yt-dlp --long-option format-sort-reset --description 'Disregard previous user specified sort order and reset to the default'
|
||||||
complete --command yt-dlp --long-option format-sort-force --description 'Force user specified sort order to have precedence over all fields, see "Sorting Formats" for more details (Alias: --S-force)'
|
complete --command yt-dlp --long-option format-sort-force --description 'Force user specified sort order to have precedence over all fields, see "Sorting Formats" for more details (Alias: --S-force)'
|
||||||
complete --command yt-dlp --long-option no-format-sort-force --description 'Some fields have precedence over the user specified sort order (default)'
|
complete --command yt-dlp --long-option no-format-sort-force --description 'Some fields have precedence over the user specified sort order (default)'
|
||||||
complete --command yt-dlp --long-option video-multistreams --description 'Allow multiple video streams to be merged into a single file'
|
complete --command yt-dlp --long-option video-multistreams --description 'Allow multiple video streams to be merged into a single file'
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ One of \[dq]default\[dq] (only when known to be useful),
|
|||||||
.SS Video Selection:
|
.SS Video Selection:
|
||||||
.TP
|
.TP
|
||||||
-I, --playlist-items \f[I]ITEM_SPEC\f[R]
|
-I, --playlist-items \f[I]ITEM_SPEC\f[R]
|
||||||
Comma separated playlist_index of the items to download.
|
Comma-separated playlist_index of the items to download.
|
||||||
You can specify a range using \[dq][START]:[STOP][:STEP]\[dq].
|
You can specify a range using \[dq][START]:[STOP][:STEP]\[dq].
|
||||||
For backward compatibility, START-STOP is also supported.
|
For backward compatibility, START-STOP is also supported.
|
||||||
Use negative indices to count from the right and negative STEP to
|
Use negative indices to count from the right and negative STEP to
|
||||||
@@ -811,6 +811,9 @@ Video format code, see \[dq]FORMAT SELECTION\[dq] for more details
|
|||||||
Sort the formats by the fields given, see \[dq]Sorting Formats\[dq] for
|
Sort the formats by the fields given, see \[dq]Sorting Formats\[dq] for
|
||||||
more details
|
more details
|
||||||
.TP
|
.TP
|
||||||
|
--format-sort-reset
|
||||||
|
Disregard previous user specified sort order and reset to the default
|
||||||
|
.TP
|
||||||
--format-sort-force
|
--format-sort-force
|
||||||
Force user specified sort order to have precedence over all fields, see
|
Force user specified sort order to have precedence over all fields, see
|
||||||
\[dq]Sorting Formats\[dq] for more details (Alias: --S-force)
|
\[dq]Sorting Formats\[dq] for more details (Alias: --S-force)
|
||||||
@@ -1513,7 +1516,7 @@ E.g.
|
|||||||
\f[V]diouxXeEfFgGcrs\f[R], yt-dlp additionally supports converting to
|
\f[V]diouxXeEfFgGcrs\f[R], yt-dlp additionally supports converting to
|
||||||
\f[V]B\f[R] = \f[B]B\f[R]ytes, \f[V]j\f[R] = \f[B]j\f[R]son (flag
|
\f[V]B\f[R] = \f[B]B\f[R]ytes, \f[V]j\f[R] = \f[B]j\f[R]son (flag
|
||||||
\f[V]#\f[R] for pretty-printing, \f[V]+\f[R] for Unicode), \f[V]h\f[R] =
|
\f[V]#\f[R] for pretty-printing, \f[V]+\f[R] for Unicode), \f[V]h\f[R] =
|
||||||
HTML escaping, \f[V]l\f[R] = a comma separated \f[B]l\f[R]ist (flag
|
HTML escaping, \f[V]l\f[R] = a comma-separated \f[B]l\f[R]ist (flag
|
||||||
\f[V]#\f[R] for \f[V]\[rs]n\f[R] newline-separated), \f[V]q\f[R] = a
|
\f[V]#\f[R] for \f[V]\[rs]n\f[R] newline-separated), \f[V]q\f[R] = a
|
||||||
string \f[B]q\f[R]uoted for the terminal (flag \f[V]#\f[R] to split a
|
string \f[B]q\f[R]uoted for the terminal (flag \f[V]#\f[R] to split a
|
||||||
list into different arguments), \f[V]D\f[R] = add \f[B]D\f[R]ecimal
|
list into different arguments), \f[V]D\f[R] = add \f[B]D\f[R]ecimal
|
||||||
@@ -1650,6 +1653,9 @@ scale used depends on the webpage
|
|||||||
some extractors, comments are only downloaded at the end, and so this
|
some extractors, comments are only downloaded at the end, and so this
|
||||||
field cannot be used)
|
field cannot be used)
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
|
\f[V]save_count\f[R] (numeric): Number of times the video has been saved
|
||||||
|
or bookmarked
|
||||||
|
.IP \[bu] 2
|
||||||
\f[V]age_limit\f[R] (numeric): Age restriction for the video (years)
|
\f[V]age_limit\f[R] (numeric): Age restriction for the video (years)
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]live_status\f[R] (string): One of \[dq]not_live\[dq],
|
\f[V]live_status\f[R] (string): One of \[dq]not_live\[dq],
|
||||||
@@ -2349,6 +2355,18 @@ filesize instead.
|
|||||||
So it is generally better to use
|
So it is generally better to use
|
||||||
\f[V]-f best -S +size,+br,+res,+fps\f[R].
|
\f[V]-f best -S +size,+br,+res,+fps\f[R].
|
||||||
.PP
|
.PP
|
||||||
|
If you use the \f[V]-S\f[R]/\f[V]--format-sort\f[R] option multiple
|
||||||
|
times, each subsequent sorting argument will be prepended to the
|
||||||
|
previous one, and only the highest priority entry of any duplicated
|
||||||
|
field will be preserved.
|
||||||
|
E.g.
|
||||||
|
\f[V]-S proto -S res\f[R] is equivalent to \f[V]-S res,proto\f[R], and
|
||||||
|
\f[V]-S res:720,fps -S vcodec,res:1080\f[R] is equivalent to
|
||||||
|
\f[V]-S vcodec,res:1080,fps\f[R].
|
||||||
|
You can use \f[V]--format-sort-reset\f[R] to disregard any previously
|
||||||
|
passed \f[V]-S\f[R]/\f[V]--format-sort\f[R] arguments and reset to the
|
||||||
|
default order.
|
||||||
|
.PP
|
||||||
\f[B]Tip\f[R]: You can use the \f[V]-v -F\f[R] to see how the formats
|
\f[B]Tip\f[R]: You can use the \f[V]-v -F\f[R] to see how the formats
|
||||||
have been sorted (worst to best).
|
have been sorted (worst to best).
|
||||||
.SS Format Selection examples
|
.SS Format Selection examples
|
||||||
@@ -2582,12 +2600,13 @@ T}
|
|||||||
T{
|
T{
|
||||||
\f[V]genre\f[R]
|
\f[V]genre\f[R]
|
||||||
T}@T{
|
T}@T{
|
||||||
\f[V]genre\f[R] or \f[V]genres\f[R]
|
\f[V]genre\f[R], \f[V]genres\f[R], \f[V]categories\f[R] or
|
||||||
|
\f[V]tags\f[R]
|
||||||
T}
|
T}
|
||||||
T{
|
T{
|
||||||
\f[V]album\f[R]
|
\f[V]album\f[R]
|
||||||
T}@T{
|
T}@T{
|
||||||
\f[V]album\f[R]
|
\f[V]album\f[R] or \f[V]series\f[R]
|
||||||
T}
|
T}
|
||||||
T{
|
T{
|
||||||
\f[V]album_artist\f[R]
|
\f[V]album_artist\f[R]
|
||||||
@@ -2637,6 +2656,9 @@ $ yt-dlp --parse-metadata \[dq]title:%(artist)s - %(title)s\[dq]
|
|||||||
# Regex example
|
# Regex example
|
||||||
$ yt-dlp --parse-metadata \[dq]description:Artist - (?P<artist>.+)\[dq]
|
$ yt-dlp --parse-metadata \[dq]description:Artist - (?P<artist>.+)\[dq]
|
||||||
|
|
||||||
|
# Copy the episode field to the title field (with FROM and TO as single fields)
|
||||||
|
$ yt-dlp --parse-metadata \[dq]episode:title\[dq]
|
||||||
|
|
||||||
# Set title as \[dq]Series name S01E05\[dq]
|
# Set title as \[dq]Series name S01E05\[dq]
|
||||||
$ yt-dlp --parse-metadata \[dq]%(series)s S%(season_number)02dE%(episode_number)02d:%(title)s\[dq]
|
$ yt-dlp --parse-metadata \[dq]%(series)s S%(season_number)02dE%(episode_number)02d:%(title)s\[dq]
|
||||||
|
|
||||||
@@ -2691,14 +2713,14 @@ respectively
|
|||||||
\f[V]player_client\f[R]: Clients to extract video data from.
|
\f[V]player_client\f[R]: Clients to extract video data from.
|
||||||
The currently available clients are \f[V]web\f[R], \f[V]web_safari\f[R],
|
The currently available clients are \f[V]web\f[R], \f[V]web_safari\f[R],
|
||||||
\f[V]web_embedded\f[R], \f[V]web_music\f[R], \f[V]web_creator\f[R],
|
\f[V]web_embedded\f[R], \f[V]web_music\f[R], \f[V]web_creator\f[R],
|
||||||
\f[V]mweb\f[R], \f[V]ios\f[R], \f[V]android\f[R],
|
\f[V]mweb\f[R], \f[V]ios\f[R], \f[V]ios_downgraded\f[R],
|
||||||
\f[V]android_sdkless\f[R], \f[V]android_vr\f[R], \f[V]tv\f[R],
|
\f[V]android\f[R], \f[V]android_vr\f[R], \f[V]tv\f[R],
|
||||||
\f[V]tv_simply\f[R], \f[V]tv_downgraded\f[R], and \f[V]tv_embedded\f[R].
|
\f[V]tv_simply\f[R], \f[V]tv_downgraded\f[R], and \f[V]tv_embedded\f[R].
|
||||||
By default, \f[V]tv,android_sdkless,web\f[R] is used.
|
By default, \f[V]android_vr,ios_downgraded,web,web_safari\f[R] is used.
|
||||||
If no JavaScript runtime is available, then
|
If no JavaScript runtime/engine is available, then
|
||||||
\f[V]android_sdkless,web_safari,web\f[R] is used.
|
\f[V]android_vr,ios_downgraded\f[R] is used.
|
||||||
If logged-in cookies are passed to yt-dlp, then
|
If logged-in cookies are passed to yt-dlp, then
|
||||||
\f[V]tv_downgraded,web_safari,web\f[R] is used for free accounts and
|
\f[V]tv_downgraded,web,web_safari\f[R] is used for free accounts and
|
||||||
\f[V]tv_downgraded,web_creator,web\f[R] is used for premium accounts.
|
\f[V]tv_downgraded,web_creator,web\f[R] is used for premium accounts.
|
||||||
The \f[V]web_music\f[R] client is added for \f[V]music.youtube.com\f[R]
|
The \f[V]web_music\f[R] client is added for \f[V]music.youtube.com\f[R]
|
||||||
URLs when logged-in cookies are used.
|
URLs when logged-in cookies are used.
|
||||||
@@ -2757,13 +2779,18 @@ choose comment sorting mode (on YouTube\[aq]s side)
|
|||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]max_comments\f[R]: Limit the amount of comments to gather.
|
\f[V]max_comments\f[R]: Limit the amount of comments to gather.
|
||||||
Comma-separated list of integers representing
|
Comma-separated list of integers representing
|
||||||
\f[V]max-comments,max-parents,max-replies,max-replies-per-thread\f[R].
|
\f[V]max-comments,max-parents,max-replies,max-replies-per-thread,max-depth\f[R].
|
||||||
Default is \f[V]all,all,all,all\f[R]
|
Default is \f[V]all,all,all,all,all\f[R]
|
||||||
.RS 2
|
.RS 2
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
|
A \f[V]max-depth\f[R] value of \f[V]1\f[R] will discard all replies,
|
||||||
|
regardless of the \f[V]max-replies\f[R] or
|
||||||
|
\f[V]max-replies-per-thread\f[R] values given
|
||||||
|
.IP \[bu] 2
|
||||||
E.g.
|
E.g.
|
||||||
\f[V]all,all,1000,10\f[R] will get a maximum of 1000 replies total, with
|
\f[V]all,all,1000,10,2\f[R] will get a maximum of 1000 replies total,
|
||||||
up to 10 replies per thread.
|
with up to 10 replies per thread, and only 2 levels of depth (i.e.
|
||||||
|
top-level comments plus their immediate replies).
|
||||||
\f[V]1000,all,100\f[R] will get a maximum of 1000 comments, with a
|
\f[V]1000,all,100\f[R] will get a maximum of 1000 comments, with a
|
||||||
maximum of 100 replies total
|
maximum of 100 replies total
|
||||||
.RE
|
.RE
|
||||||
@@ -2801,7 +2828,7 @@ If a session from a browser is wanted, you should pass cookies instead
|
|||||||
(which contain the Visitor ID)
|
(which contain the Visitor ID)
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]po_token\f[R]: Proof of Origin (PO) Token(s) to use.
|
\f[V]po_token\f[R]: Proof of Origin (PO) Token(s) to use.
|
||||||
Comma seperated list of PO Tokens in the format
|
Comma-separated list of PO Tokens in the format
|
||||||
\f[V]CLIENT.CONTEXT+PO_TOKEN\f[R], e.g.
|
\f[V]CLIENT.CONTEXT+PO_TOKEN\f[R], e.g.
|
||||||
\f[V]youtube:po_token=web.gvs+XXX,web.player=XXX,web_safari.gvs+YYY\f[R].
|
\f[V]youtube:po_token=web.gvs+XXX,web.player=XXX,web_safari.gvs+YYY\f[R].
|
||||||
Context can be any of \f[V]gvs\f[R] (Google Video Server URLs),
|
Context can be any of \f[V]gvs\f[R] (Google Video Server URLs),
|
||||||
@@ -2818,20 +2845,23 @@ client requires one for the given context), \f[V]never\f[R] (never fetch
|
|||||||
a PO Token), or \f[V]auto\f[R] (default; only fetch a PO Token if the
|
a PO Token), or \f[V]auto\f[R] (default; only fetch a PO Token if the
|
||||||
client requires one for the given context)
|
client requires one for the given context)
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]playback_wait\f[R]: Duration (in seconds) to wait inbetween the
|
|
||||||
extraction and download stages in order to ensure the formats are
|
|
||||||
available.
|
|
||||||
The default is \f[V]6\f[R] seconds
|
|
||||||
.IP \[bu] 2
|
|
||||||
\f[V]jsc_trace\f[R]: Enable debug logging for JS Challenge fetching.
|
\f[V]jsc_trace\f[R]: Enable debug logging for JS Challenge fetching.
|
||||||
Either \f[V]true\f[R] or \f[V]false\f[R] (default)
|
Either \f[V]true\f[R] or \f[V]false\f[R] (default)
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[V]use_ad_playback_context\f[R]: Skip preroll ads to eliminate the
|
||||||
|
mandatory wait period before download.
|
||||||
|
Do NOT use this when passing premium account cookies to yt-dlp, as it
|
||||||
|
will result in a loss of premium formats.
|
||||||
|
Only effective with the \f[V]web\f[R], \f[V]web_safari\f[R],
|
||||||
|
\f[V]web_music\f[R] and \f[V]mweb\f[R] player clients.
|
||||||
|
Either \f[V]true\f[R] or \f[V]false\f[R] (default)
|
||||||
.SS youtube-ejs
|
.SS youtube-ejs
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]jitless\f[R]: Run suported Javascript engines in JIT-less mode.
|
\f[V]jitless\f[R]: Run supported Javascript engines in JIT-less mode.
|
||||||
Supported runtimes are \f[V]deno\f[R], \f[V]node\f[R] and \f[V]bun\f[R].
|
Supported runtimes are \f[V]deno\f[R], \f[V]node\f[R] and \f[V]bun\f[R].
|
||||||
Provides better security at the cost of performance/speed.
|
Provides better security at the cost of performance/speed.
|
||||||
Do note that \f[V]node\f[R] and \f[V]bun\f[R] are still considered
|
Do note that \f[V]node\f[R] and \f[V]bun\f[R] are still considered
|
||||||
unsecure.
|
insecure.
|
||||||
Either \f[V]true\f[R] or \f[V]false\f[R] (default)
|
Either \f[V]true\f[R] or \f[V]false\f[R] (default)
|
||||||
.SS youtubepot-webpo
|
.SS youtubepot-webpo
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
@@ -3045,9 +3075,10 @@ Default is \f[V]asc\f[R]
|
|||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]client\f[R]: Client to extract video data from.
|
\f[V]client\f[R]: Client to extract video data from.
|
||||||
The currently available clients are \f[V]android\f[R], \f[V]ios\f[R],
|
The currently available clients are \f[V]android\f[R], \f[V]ios\f[R],
|
||||||
and \f[V]web\f[R].
|
\f[V]macos\f[R] and \f[V]web\f[R].
|
||||||
Only one client can be used.
|
Only one client can be used.
|
||||||
The \f[V]web\f[R] client is used by default.
|
The \f[V]macos\f[R] client is used by default, but the \f[V]web\f[R]
|
||||||
|
client is used when logged-in.
|
||||||
The \f[V]web\f[R] client only works with account cookies or login
|
The \f[V]web\f[R] client only works with account cookies or login
|
||||||
credentials.
|
credentials.
|
||||||
The \f[V]android\f[R] and \f[V]ios\f[R] clients only work with
|
The \f[V]android\f[R] and \f[V]ios\f[R] clients only work with
|
||||||
@@ -3161,8 +3192,8 @@ Python versions 3.10+ (CPython) and 3.11+ (PyPy) are supported.
|
|||||||
Other versions and implementations may or may not work correctly.
|
Other versions and implementations may or may not work correctly.
|
||||||
.PP
|
.PP
|
||||||
While all the other dependencies are optional, \f[V]ffmpeg\f[R],
|
While all the other dependencies are optional, \f[V]ffmpeg\f[R],
|
||||||
\f[V]ffprobe\f[R], \f[V]yt-dlp-ejs\f[R] and a JavaScript runtime are
|
\f[V]ffprobe\f[R], \f[V]yt-dlp-ejs\f[R] and a supported JavaScript
|
||||||
highly recommended
|
runtime/engine are highly recommended
|
||||||
.SS Strongly recommended
|
.SS Strongly recommended
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[B]ffmpeg\f[R] and \f[B]ffprobe\f[R] (https://www.ffmpeg.org) -
|
\f[B]ffmpeg\f[R] and \f[B]ffprobe\f[R] (https://www.ffmpeg.org) -
|
||||||
@@ -3185,8 +3216,8 @@ for details on the specific issues solved by these builds
|
|||||||
name (https://pypi.org/project/ffmpeg)
|
name (https://pypi.org/project/ffmpeg)
|
||||||
.RE
|
.RE
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[B]yt-dlp-ejs\f[R] (https://github.com/yt-dlp/ejs) - Required for
|
\f[B]yt-dlp-ejs\f[R] (https://github.com/yt-dlp/ejs) - Required for full
|
||||||
deciphering YouTube n/sig values.
|
YouTube support.
|
||||||
Licensed under
|
Licensed under
|
||||||
Unlicense (https://github.com/yt-dlp/ejs/blob/main/LICENSE), bundles
|
Unlicense (https://github.com/yt-dlp/ejs/blob/main/LICENSE), bundles
|
||||||
MIT (https://github.com/davidbonnet/astring/blob/main/LICENSE) and
|
MIT (https://github.com/davidbonnet/astring/blob/main/LICENSE) and
|
||||||
@@ -3194,7 +3225,7 @@ ISC (https://github.com/meriyah/meriyah/blob/main/LICENSE.md)
|
|||||||
components.
|
components.
|
||||||
.RS 2
|
.RS 2
|
||||||
.PP
|
.PP
|
||||||
A JavaScript runtime like \f[B]deno\f[R] (https://deno.land)
|
A JavaScript runtime/engine like \f[B]deno\f[R] (https://deno.land)
|
||||||
(recommended), \f[B]node.js\f[R] (https://nodejs.org),
|
(recommended), \f[B]node.js\f[R] (https://nodejs.org),
|
||||||
\f[B]bun\f[R] (https://bun.sh), or
|
\f[B]bun\f[R] (https://bun.sh), or
|
||||||
\f[B]QuickJS\f[R] (https://bellard.org/quickjs/) is also required to run
|
\f[B]QuickJS\f[R] (https://bellard.org/quickjs/) is also required to run
|
||||||
@@ -3237,7 +3268,7 @@ Licensed under
|
|||||||
MIT (https://github.com/lexiforest/curl_cffi/blob/main/LICENSE)
|
MIT (https://github.com/lexiforest/curl_cffi/blob/main/LICENSE)
|
||||||
.RS 2
|
.RS 2
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
Can be installed with the \f[V]curl-cffi\f[R] group, e.g.
|
Can be installed with the \f[V]curl-cffi\f[R] extra, e.g.
|
||||||
\f[V]pip install \[dq]yt-dlp[default,curl-cffi]\[dq]\f[R]
|
\f[V]pip install \[dq]yt-dlp[default,curl-cffi]\[dq]\f[R]
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
Currently included in most builds \f[I]except\f[R] \f[V]yt-dlp\f[R]
|
Currently included in most builds \f[I]except\f[R] \f[V]yt-dlp\f[R]
|
||||||
@@ -3326,7 +3357,7 @@ You can run the following commands:
|
|||||||
.IP
|
.IP
|
||||||
.nf
|
.nf
|
||||||
\f[C]
|
\f[C]
|
||||||
python devscripts/install_deps.py --include-group pyinstaller
|
python devscripts/install_deps.py --include-extra pyinstaller
|
||||||
python devscripts/make_lazy_extractors.py
|
python devscripts/make_lazy_extractors.py
|
||||||
python -m bundle.pyinstaller
|
python -m bundle.pyinstaller
|
||||||
\f[R]
|
\f[R]
|
||||||
@@ -4056,7 +4087,7 @@ default.
|
|||||||
Use \f[V]--mtime\f[R] or \f[V]--compat-options mtime-by-default\f[R] to
|
Use \f[V]--mtime\f[R] or \f[V]--compat-options mtime-by-default\f[R] to
|
||||||
revert this.
|
revert this.
|
||||||
.PP
|
.PP
|
||||||
For ease of use, a few more compat options are available:
|
For convenience, there are some compat option aliases available to use:
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]--compat-options all\f[R]: Use all compat options (\f[B]Do NOT use
|
\f[V]--compat-options all\f[R]: Use all compat options (\f[B]Do NOT use
|
||||||
this!\f[R])
|
this!\f[R])
|
||||||
@@ -4077,9 +4108,15 @@ this!\f[R])
|
|||||||
\f[V]--compat-options 2024,prefer-vp9-sort\f[R]
|
\f[V]--compat-options 2024,prefer-vp9-sort\f[R]
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[V]--compat-options 2024\f[R]: Same as
|
\f[V]--compat-options 2024\f[R]: Same as
|
||||||
\f[V]--compat-options mtime-by-default\f[R].
|
\f[V]--compat-options 2025,mtime-by-default\f[R]
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[V]--compat-options 2025\f[R]: Currently does nothing.
|
||||||
Use this to enable all future compat options
|
Use this to enable all future compat options
|
||||||
.PP
|
.PP
|
||||||
|
Using one of the yearly compat option aliases will pin yt-dlp\[aq]s
|
||||||
|
default behavior to what it was at the \f[I]end\f[R] of that calendar
|
||||||
|
year.
|
||||||
|
.PP
|
||||||
The following compat options restore vulnerable behavior from before
|
The following compat options restore vulnerable behavior from before
|
||||||
security patches:
|
security patches:
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -91,7 +91,9 @@ def search_google_images_and_save(x: str, audio):
|
|||||||
if x.endswith(".flac"):
|
if x.endswith(".flac"):
|
||||||
songpath = join(".",str(audio["artist"]),str(audio["album"]))
|
songpath = join(".",str(audio["artist"]),str(audio["album"]))
|
||||||
else:
|
else:
|
||||||
songpath = join(".",str(audio["TPE2"]),str(audio["TALB"]))
|
# Use TPE2 if available, otherwise fallback to TPE1
|
||||||
|
artist_folder = str(audio.get("TPE2", audio.get("TPE1", "Unknown Artist")))
|
||||||
|
songpath = join(".", artist_folder, str(audio["TALB"]))
|
||||||
if "\x00" in songpath:
|
if "\x00" in songpath:
|
||||||
# having null bytes in os.replace will throw an error
|
# having null bytes in os.replace will throw an error
|
||||||
songpath = songpath.replace("\x00",", ")
|
songpath = songpath.replace("\x00",", ")
|
||||||
@@ -189,7 +191,7 @@ def create_ID3_tag(audio, tagname: str, textvalue: str):
|
|||||||
def check_tag(audio, filename: str, ID3_tag: str, normal_tag) -> bool:
|
def check_tag(audio, filename: str, ID3_tag: str, normal_tag) -> bool:
|
||||||
res = False
|
res = False
|
||||||
|
|
||||||
# check if the ID3 artist tag exists
|
# check if the ID3 tag exists
|
||||||
if (ID3_tag in audio.keys() and len(str(audio[ID3_tag])) != 0):
|
if (ID3_tag in audio.keys() and len(str(audio[ID3_tag])) != 0):
|
||||||
logging.info(ID3_tag + " ID3 tag found! " + str(audio[ID3_tag]))
|
logging.info(ID3_tag + " ID3 tag found! " + str(audio[ID3_tag]))
|
||||||
|
|
||||||
@@ -201,7 +203,7 @@ def check_tag(audio, filename: str, ID3_tag: str, normal_tag) -> bool:
|
|||||||
logging.info("Set " + normal_tag + " to " + str(audio[normal_tag]))
|
logging.info("Set " + normal_tag + " to " + str(audio[normal_tag]))
|
||||||
res = True
|
res = True
|
||||||
|
|
||||||
# check if general album tag exists
|
# check if general tag exists
|
||||||
elif (normal_tag in audio.keys() and len(str(audio[normal_tag])) != 0):
|
elif (normal_tag in audio.keys() and len(str(audio[normal_tag])) != 0):
|
||||||
logging.info(normal_tag + " normal tag found! " + str(audio[normal_tag]))
|
logging.info(normal_tag + " normal tag found! " + str(audio[normal_tag]))
|
||||||
if audio[normal_tag] is not str:
|
if audio[normal_tag] is not str:
|
||||||
@@ -228,6 +230,11 @@ def check_title_songname(x: str, audio):
|
|||||||
|
|
||||||
if (" - " in x):
|
if (" - " in x):
|
||||||
items = x.split(" - ")
|
items = x.split(" - ")
|
||||||
|
# If the format is 'artist - Topic - title', remove 'Topic'
|
||||||
|
if len(items) > 2 and items[1].strip().lower() == "topic":
|
||||||
|
logging.info("Detected ' - Topic - ' in name, removing 'Topic'.")
|
||||||
|
# Rebuild items without 'Topic'
|
||||||
|
items = [items[0]] + items[2:]
|
||||||
if (len(items) > 2):
|
if (len(items) > 2):
|
||||||
logging.info("song title has more than 1 part after the -: " + str(items))
|
logging.info("song title has more than 1 part after the -: " + str(items))
|
||||||
if (items[1].count(".mp3") >= 1):
|
if (items[1].count(".mp3") >= 1):
|
||||||
@@ -266,7 +273,7 @@ def check_for_multiple_artists(audio, filename: str, name: str):
|
|||||||
artists = name.split(",")
|
artists = name.split(",")
|
||||||
elif ("/" in name):
|
elif ("/" in name):
|
||||||
artists = name.split("/")
|
artists = name.split("/")
|
||||||
elif ("\x00" in name):
|
elif ("\x00" in name):
|
||||||
artists = name.split("\x00")
|
artists = name.split("\x00")
|
||||||
|
|
||||||
if (len(artists) > 0):
|
if (len(artists) > 0):
|
||||||
@@ -276,7 +283,11 @@ def check_for_multiple_artists(audio, filename: str, name: str):
|
|||||||
else:
|
else:
|
||||||
audio["TPE1"] = TPE2(encoding=3,text=["\0".join(artists)])
|
audio["TPE1"] = TPE2(encoding=3,text=["\0".join(artists)])
|
||||||
else:
|
else:
|
||||||
logging.info("no multiple artists found in name " + name)
|
logging.info("no multiple artists found in name " + name + ", setting artist to " + name)
|
||||||
|
if filename.endswith(".flac"):
|
||||||
|
audio["artist"] = TPE2(encoding=3,text=name)
|
||||||
|
else:
|
||||||
|
audio["TPE1"] = TPE2(encoding=3,text=name)
|
||||||
|
|
||||||
|
|
||||||
# checks for any artist from the song name. If it exists it sets the properties of the file
|
# checks for any artist from the song name. If it exists it sets the properties of the file
|
||||||
@@ -297,6 +308,9 @@ def check_artist(audio, filename: str) -> bool:
|
|||||||
res = False
|
res = False
|
||||||
|
|
||||||
# check if the ID3 artist tag exists
|
# check if the ID3 artist tag exists
|
||||||
|
check_tag(audio, filename, "TPE1","artist")
|
||||||
|
check_tag(audio, filename, "TPE2","artist")
|
||||||
|
|
||||||
if ("TPE1" in audio.keys()):
|
if ("TPE1" in audio.keys()):
|
||||||
if (len(str(audio["TPE1"])) != 0):
|
if (len(str(audio["TPE1"])) != 0):
|
||||||
logging.info("TPE1 tag was found! " + str(audio["TPE1"]))
|
logging.info("TPE1 tag was found! " + str(audio["TPE1"]))
|
||||||
@@ -445,9 +459,9 @@ def check_spotify_album_and_save(spotify, audio,x: str) -> bool:
|
|||||||
comment ="Spotify ID: {0}. Release date precision: {1}, total tracks in album: {2}. This album has {3} version(s)".format(album["id"],album["release_date_precision"], album["total_tracks"],len(results["albums"]["items"]))
|
comment ="Spotify ID: {0}. Release date precision: {1}, total tracks in album: {2}. This album has {3} version(s)".format(album["id"],album["release_date_precision"], album["total_tracks"],len(results["albums"]["items"]))
|
||||||
logging.info("Comment: " + comment)
|
logging.info("Comment: " + comment)
|
||||||
if x.endswith(".flac"):
|
if x.endswith(".flac"):
|
||||||
audio["comment"] = comment
|
audio["comment"] = audio["comment"] + comment
|
||||||
else:
|
else:
|
||||||
audio["COMM"] = COMM(encoding=3,text=comment)
|
audio["COMM"] = COMM(encoding=3,text=comment + audio["COMM"])
|
||||||
|
|
||||||
if x.endswith(".flac"):
|
if x.endswith(".flac"):
|
||||||
remove_flac_ID3_tags(audio,x)
|
remove_flac_ID3_tags(audio,x)
|
||||||
@@ -748,10 +762,12 @@ def main():
|
|||||||
logging.info("valid artist found. making folder for artist " + str(audio["artist"][0]))
|
logging.info("valid artist found. making folder for artist " + str(audio["artist"][0]))
|
||||||
make_folder(join(".",str(audio["artist"][0])))
|
make_folder(join(".",str(audio["artist"][0])))
|
||||||
else:
|
else:
|
||||||
logging.info("valid artist found. making folder for artist " + str(audio["TPE1"]))
|
# Use TPE2 if available, otherwise fallback to TPE1
|
||||||
if "/" in audio["TPE2"]:
|
artist_folder = str(audio.get("TPE2", audio.get("TPE1", "Unknown Artist")))
|
||||||
audio["TPE2"] = audio["TPE2"].replace("/","")
|
logging.info("valid artist found. making folder for artist " + artist_folder)
|
||||||
make_folder(join(".",str(audio["TPE2"])))
|
if "/" in artist_folder:
|
||||||
|
artist_folder = artist_folder.replace("/","")
|
||||||
|
make_folder(join(".", artist_folder))
|
||||||
|
|
||||||
if (has_valid_album):
|
if (has_valid_album):
|
||||||
if (x.endswith(".flac")):
|
if (x.endswith(".flac")):
|
||||||
|
|||||||
Reference in New Issue
Block a user