ytdl_hook: parse youtube playlist urls to set start index

Still needs `--ytdl-raw-option=yes-playlist=` because this only
works for youtube.

This was requested in a few issues:
https://github.com/mpv-player/mpv/issues/1400
https://github.com/mpv-player/mpv/issues/2592
https://github.com/mpv-player/mpv/issues/3024

For #1400 to be completely implemented would need ytdl_hook to
re-request the same playlist with the last video's ID for the mix to
continue indefinitely which would probably too hackish to work reliably.
This commit is contained in:
Ricardo Constantino 2018-01-15 21:16:36 +00:00 committed by Kevin Mitchell
parent 976daf1942
commit 664e8fe66a
No known key found for this signature in database
GPG Key ID: 559A34B46A917232
1 changed files with 53 additions and 5 deletions

View File

@ -142,6 +142,45 @@ local function is_blacklisted(url)
return false
end
local function parse_yt_playlist(url, json)
-- return 0-based index to use with --playlist-start
if not json.extractor or json.extractor ~= "youtube:playlist" then
return nil
end
local query = url:match("%?.+")
if not query then return nil end
local args = {}
for arg, param in query:gmatch("(%a+)=([^&?]+)") do
if arg and param then
args[arg] = param
end
end
local maybe_idx = tonumber(args["index"])
-- if index matches v param it's probably the requested item
if maybe_idx and #json.entries >= maybe_idx and
json.entries[maybe_idx].id == args["v"] then
msg.debug("index matches requested video")
return maybe_idx - 1
end
-- if there's no index or it doesn't match, look for video
for i = 1, #json.entries do
if json.entries[i] == args["v"] then
msg.debug("found requested video in index " .. (i - 1))
return i - 1
end
end
msg.debug("requested video not found in playlist")
-- if item isn't on the playlist, give up
return nil
end
local function make_absolute_url(base_url, url)
if url:find("https?://") == 1 then return url end
@ -417,10 +456,11 @@ mp.add_hook(o.try_ytdl_first and "on_load" or "on_load_fail", 10, function ()
local raw_options = mp.get_property_native("options/ytdl-raw-options")
local allsubs = true
local proxy = nil
local use_playlist = false
local command = {
ytdl.path, "--no-warnings", "-J", "--flat-playlist",
"--sub-format", "ass/srt/best", "--no-playlist"
"--sub-format", "ass/srt/best"
}
-- Checks if video option is "no", change format accordingly,
@ -445,15 +485,19 @@ mp.add_hook(o.try_ytdl_first and "on_load" or "on_load_fail", 10, function ()
end
if (param == "sub-lang") and (arg ~= "") then
allsubs = false
end
if (param == "proxy") and (arg ~= "") then
elseif (param == "proxy") and (arg ~= "") then
proxy = arg
elseif (param == "yes-playlist") then
use_playlist = true
end
end
if (allsubs == true) then
table.insert(command, "--all-subs")
end
if not use_playlist then
table.insert(command, "--no-playlist")
end
table.insert(command, "--")
table.insert(command, url)
msg.debug("Running: " .. table.concat(command,' '))
@ -559,6 +603,7 @@ mp.add_hook(o.try_ytdl_first and "on_load" or "on_load_fail", 10, function ()
msg.verbose("Playlist with single entry detected.")
add_single_video(json.entries[1])
else
local playlist_index = parse_yt_playlist(url, json)
local playlist = {"#EXTM3U"}
for i, entry in pairs(json.entries) do
local site = entry.url
@ -589,9 +634,12 @@ mp.add_hook(o.try_ytdl_first and "on_load" or "on_load_fail", 10, function ()
end
if #playlist > 0 then
mp.set_property("stream-open-filename", "memory://" .. table.concat(playlist, "\n"))
if use_playlist and
not option_was_set("playlist-start") and playlist_index then
mp.set_property_number("playlist-start", playlist_index)
end
mp.set_property("stream-open-filename", "memory://" .. table.concat(playlist, "\n"))
end
else -- probably a video