Only matters when configuring ytdl_hook with `all_formats=yes`.
So far the tracks were ordered from worst to best quality.
Web players with quality selection always show the highest quality
option at the top. Since tracks are usually listed with the first
track at the top, that should also be the highest quality one.
yt-dlp/youtube-dl sorts it's formats from worst to best.
Iterate in reverse to get best track first.
Every format that was not detected as a video format was added to the
audio tracks. This resulted in e.g. YouTube storyboards from ending up
in the list of audio tracks.
Now formats that are already known to be neither video formats nor audio
formats, will also not end up in any track list.
Formats where it is unknown if they are video or audio get added to
tracks if `force_all_formats` is used, otherwise only
formats that are known to contain video or audio become video or audio
tracks respectively.
https://github.com/yt-dlp/yt-dlp/issues/4373#issuecomment-1186637357
One would expect that e.g.
`--script-opts=ytdl_hook-all_formats=no --ytdl-format=bestaudio` and
`--script-opts=ytdl_hook-all_formats=yes --ytdl-format=bestaudio`
to play the exact same tracks without manual intervention.
This already worked when two formats were requested.
For a single format with `all_formats=yes` it would also play a track
that was not requested when available. This was inconsistant with the
behavior of `all_formats=no` (default), which would not play a second
track when only a single one was requested.
This combined with #10395 now plays the exact same tracks with
`all_formats=yes` as without, even when only one format is requested.
Tracks are marked as default tracks based on what yt-dlp/youtube-dl
returns in the field `requested_formats`. The problem is that this field
only exists when there is more then one requested format.
So `ytdl-format=bestvideo+bestaudio` would have that field,
but `ytdl-format=bestaudio` would not,
leading to no tracks being marked as default tracks.
The requested formats can also be found under `requested_downloads`,
which exists regardless of the number of requested formats.
However when there is more then one requested format,
`requested_downloads` doesn't contain those formats directly and instead
has a field `requested_formats` that is identical to the other
`requested_formats`. Therefore use `requested_downloads` as a fallback
for when `requested_formats` doesn't exist.
The example given in #3024 would not play the correct video when
combined with `--ytdl-raw-options=yes-playlist=`.
Allowing `youtube:tab` as extractor and correcting the id check fixes
that.
Previously only status<0 was considered as error, but status>0 is
also an error (the process exit code). Change to status != 0.
This likely makes little to no difference in practice, because if
stdout is empty or can't be parsed as JSON then it's considered
an error anyway, but still, this is more correct.
Also, on error, add the complete subprocess result to the verbose log.
Some youtube_dl extractors retrieve URLs which contain other URLs
inside of them, for example Funimation, like this:
https://example.com/video?parameter=https://example.net/something
The url_is_safe function uses a pattern to match the protocol at the
start of the URL. Before this commit, this pattern was not compliant
with the URL spec (see the definition of "A URL-scheme string"):
https://url.spec.whatwg.org/#url-writing
Therefore it would match any characters, including "://", until the
last occurence of "://" in the string. Thus the above URL would match
https://example.com/video?parameter=https
which is not in safe_protos so the video will not play.
Now the protocol can only start with a letter and only contain
alphanumerics, "." "+" or "-" as the spec says, so it will only match
the first protocol in the URL ("https" in the above example.)
Previously the URL also had to contain "//" after the ":". Data URLs
do not contain "//": https://datatracker.ietf.org/doc/html/rfc2397
so now the pattern does not look for "//", only ":".
youtube-dl and yt-dlp both support --sub-langs and --srt-lang in
addition to --sub-lang for defining languages of subtitles. This hook
only checked for sub-lang in --ytdl-raw-options and inserted --all-subs
in its absence.
Because youtube-dl is inactive and the yt-dlp fork is becoming more
popular, make mpv use yt-dlp without any extra configuration.
yt-dlp is ordered before youtube-dl because it's more obscure, so users
who have yt-dlp installed are more likely to want to use it rather than
youtube-dl.
Fixes#9208.
This moves the JSON parsing above the main youtube-dl error-handling
block and integrates parsing errors into that block. Now, if a parsing
error occurs, youtube-dl's stderr will be logged as it is with other
errors. This also catches errors that cause youtube-dl to output
"null", which would previously be mishandled as a parsing error and
crash ytdl_hook when it attempted to concatenate the error string from
parse_json.
Shows uploader, channel, description fields. This works only if the
media media is constructed as EDL (for youtube it usually does this),
and if the all_formats option is not set to true (does anyone even use
it?). The former usually happens because youtube serves audio and video
separately, though it will not for live HLS/DASH. The latter uses
delayed media opening, which breaks the global_tags mechanism (see
previous commit).
Some tracks happen to lack bitrate information (ie. no tbr value).
In that case, just ignore the track while computing the max bitrate.
For an example, this is a stream in which all audio tracks
have no bitrate: https://www.raiplay.it/dirette/rai1
The subtitle list is returned in randomized order, because a table (i.e.
JSON object) is used. To make the order stable across repeated
invocations, sort it by language.
This was obviously nonsense. In Lua 5.1 this appeared to work correctly,
but it really turned "\." into "." (making the pattern accept any
character). The proper way is using "%" for escaping.
In all_formats mode, we've ignored what --ytdl-format did so far, since
we've converted the full format list, instead of just the formats
selected by youtube-dl.
But we can easily restore --ytdl-format behavior: just mark the selected
tracks as default tracks.
vbr and abr are the video and audio bitrates. Sometimes there is a weird
mix of any of them available, but in these cases, it's not good to fall
back to tbr if a specific track has no vbr/abr.
For example, the alphabetic site provides tbr only for the muxed
fallback stream, but using tbr would make the primitive mpv hls_bitrate
selection pick the compatibility stream for audio, because it appears to
have a higher bitrate than the other audio-only streams (because the
bitrate includes video). So we must not use tbr in this case.
On the other hand, formats coming from youtube-dl HLS master playlist
use will only have tbr set.
So as a heuristic, use the tbr only if it's the only bitrate available
in any track entry.
I don't think the skip_muxed option was overlay useful. While it was
nice to filter out the low quality muxed versions (as it happens on the
alphabetic site, I suspect it's compatibility stuff), it's not really
necessary, and just makes for another tricky and rarely used
configuration option. (This was different before muxed tracks were also
delay-loaded, and including the muxed versions slowed down loading.)
Add the force_all_formats option instead, which handles the HLS case.
Set it to true because they are also delay-loaded now, and don't slow
down startup as much.
If all streams were delay loaded, there was actually no duration present
at all in the EDL metadata. So the length was considered unknown by the
player frontend.
See manpage additions. We would have to extend delay_open to support
multiple sub-tracks (for audio and video), and we'd still don't know (?)
whether it might contain more than one stream each (thinking of HLS
master streams). And if it's a true interleaved file (such as a "normal"
mp4 file provided as fallback for more primitive players), we'd either
have to signal such "bundled" tracks, or waste bandwidth.
This restructures a lot. The if/else tree in add_single_video for format
selection was a bit annoying, so it's split into separate if blocks,
where it checks each time whether a URL was determined yet.
If a "format" has both audio and video codec set, it might contain both
audio and video. all_format assumes that each format is just a quality
variant containing a single track.
This seems to happen with sites that provide a HLS master URL.
youtube-dl tends to "butcher" it, and the result isn't very ideal. I
guess HLS "renditions" simply don't map well to youtube-dl's output
format and what mpv expects. Playing master HLS directly is also less
than ideal, because of libavformat's stupid probing.
Fix this by not using the delay-opening mechanism if it appears like we
detected such a case. Add a metadata override to set the track titles to
"muxed-N", to indicate that they form a single unit. (Mostly helpful for
testing.)
Pretty worthless I guess. I only tested one site (and 2 videos), it's
somewhat likely that it will break with other sites. Even if you leave
the option disabled (the default).
Slightly related to #3548. This will allows you to use the bitrate
stream selection mechanism, that was added for HLS, with normal videos.
Uses the infrastructure added in the previous commits. This is
admittedly a bit weird (constructing EDL URLs and such). But on the
other hand, adding this as "first class" mechanism directly to the
sub-add command or so would increase weirdness and unexpected behavior
in other places, or at least that's what I think.
To reduce confusion, this goes through the effort of mapping the webvtt
codec, so it's shown "properly" in the codec list. Without this it would
show "null", but still work. In particular, any non-webvtt codecs should
still work if libavcodec supports it.
Not sure if I should remove the --all-subs hack from the code. But I
guess it does no harm.
Some failures by youtube-dl prompt the user to submit a bug report.
If such a failure occurs, we can compare youtube-dl's version to the
current calendar date to see how old it is. We don't make this check
on every youtube-dl failure, as failing to extract an URL is quite
common, and waiting for a second blocking python interpreter startup
for every such case would be a bit unpleasant.
Here the assumption is made that any youtube-dl version older than
3 months is probably severely out of date. Users will be warned about
this.
We also output the trimmed stderr of youtube-dl with msg.error, as this
appeared to have been the behaviour of utils.subprocess without stderr
capturing. Since this uses mp.command_native now, we'll have to do this
ourselves where appropriate.
Remove the singly linked list hack, replace it with a slightly more
proper data structure. This probably gets rid of a few minor bugs along
the way, caused by the awkward nonsensical sharing/duplication of some
fields.
Another change (because I'm touching everything related to timeline
anyway) is that I'm removing the special semantics for parts[num_parts].
This is now strictly out of bounds, and instead of using the start time
of the next/beyond-last part, there is an end time field now.
Unfortunately, this also requires touching the code for cue and mkv
ordered chapters. From some superficial testing, they still seem to
mostly work.
One observable change is that the "no_chapters" header is per-stream
now, which is arguably more correct, and getting the old behavior would
require adding code to handle it as special-case, so just adjust
ytdl_hook.lua to the new behavior.
I noticed that some ytdl streams have a start time other than 0. There's
currently no mechanism inside of the EDL stuff that determines this
start time correctly, so it can happen that if the start time is high,
demux_timeline.c tries to clip off the entire video and audio, resulting
in failure of playback.
As a counter measure, use the no_clip header, which entirely disables
clipping against time ranges in demux_timeline.c. (It's basically a
hack.)
Init fragments are not a necessity for DASH, but this code assumed so.
Maybe the check was to prevent worse. But using normal EDL here leads to
very shitty behavior where it tries to open hundreds or thousands of
fragments, each with its own demuxer and HTTP connection. (This behavior
is fine for normal uses of EDLs, but completely unacceptable when
emulating fragmented streaming protocols. I'm not sure why the normal
EDL code is needed here, but I think someone claimed some obscure sites
just need it.)
This happens in the same situation as the one described in the previous
commit.
Otherwise we'd just use the base URL as media URL, which would fail with
a 404 error.
Not sure if there's a deeper reason why the audio path was explicitly
different from the video one. But this actually works now for a video
that returned fragmented DASH audio with the default format selection.
(This affects streams on that well known site of a big evil Silicon
Valley company. Typically happens after live stream gets converted to a
normal video, though after some time passes, this fragmented version is
deleted, and replaced by a non-fragmented one. I've observed this
several times and this seems to be the "normal" behavior.)