summaryrefslogtreecommitdiffstats
path: root/player/lua/ytdl_hook.lua
diff options
context:
space:
mode:
authorUmar Getagazov <umar@handlerug.me>2023-10-20 00:18:25 +0300
committerDudemanguy <random342@airmail.cc>2023-10-21 22:30:22 +0000
commitb388c735408af1a78e8f6165fa3af31bc623ef8f (patch)
treea15dfc12cf3e8193ef5dc76289ae9afdcc82ada8 /player/lua/ytdl_hook.lua
parentce03b42424c2e40a85ec7160ca9d3939cbde82d3 (diff)
downloadmpv-b388c735408af1a78e8f6165fa3af31bc623ef8f.tar.bz2
mpv-b388c735408af1a78e8f6165fa3af31bc623ef8f.tar.xz
ytdl_hook: parse the separate cookies field
https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-v8mc-9377-rwjj https://github.com/yt-dlp/yt-dlp/commit/1ceb657bdd25
Diffstat (limited to 'player/lua/ytdl_hook.lua')
-rw-r--r--player/lua/ytdl_hook.lua105
1 files changed, 104 insertions, 1 deletions
diff --git a/player/lua/ytdl_hook.lua b/player/lua/ytdl_hook.lua
index 19a0467f76..8e7d910144 100644
--- a/player/lua/ytdl_hook.lua
+++ b/player/lua/ytdl_hook.lua
@@ -24,6 +24,7 @@ options.read_options(o, nil, function()
end)
local chapter_list = {}
+local playlist_cookies = {}
function Set (t)
local set = {}
@@ -138,6 +139,78 @@ local function set_http_headers(http_headers)
end
end
+local special_cookie_field_names = Set {
+ "expires", "max-age", "domain", "path"
+}
+
+-- parse single-line Set-Cookie syntax
+local function parse_cookies(cookies_line)
+ if not cookies_line then
+ return {}
+ end
+ local cookies = {}
+ local cookie = {}
+ for stem in cookies_line:gmatch('[^;]+') do
+ stem = stem:gsub("^%s*(.-)%s*$", "%1")
+ local name, value = stem:match('^(.-)=(.+)$')
+ if name and name ~= "" and value then
+ local cmp_name = name:lower()
+ if special_cookie_field_names[cmp_name] then
+ cookie[cmp_name] = value
+ else
+ if cookie.name and cookie.value then
+ table.insert(cookies, cookie)
+ end
+ cookie = {
+ name = name,
+ value = value,
+ }
+ end
+ end
+ end
+ if cookie.name and cookie.value then
+ local cookie_key = cookie.domain .. ":" .. cookie.name
+ cookies[cookie_key] = cookie
+ end
+ return cookies
+end
+
+-- serialize cookies for avformat
+local function serialize_cookies_for_avformat(cookies)
+ local result = ''
+ for _, cookie in pairs(cookies) do
+ local cookie_str = ('%s=%s; '):format(cookie.name, cookie.value)
+ for k, v in pairs(cookie) do
+ if k ~= "name" and k ~= "value" then
+ cookie_str = cookie_str .. ('%s=%s; '):format(k, v)
+ end
+ end
+ result = result .. cookie_str .. '\r\n'
+ end
+ return result
+end
+
+-- set file-local cookies, preserving existing ones
+local function set_cookies(cookies)
+ if not cookies or cookies == "" then
+ return
+ end
+
+ local option_key = "file-local-options/stream-lavf-o"
+ local stream_opts = mp.get_property_native(option_key, {})
+ local existing_cookies = parse_cookies(stream_opts["cookies"])
+
+ local new_cookies = parse_cookies(cookies)
+ for cookie_key, cookie in pairs(new_cookies) do
+ if not existing_cookies[cookie_key] then
+ existing_cookies[cookie_key] = cookie
+ end
+ end
+
+ stream_opts["cookies"] = serialize_cookies_for_avformat(existing_cookies)
+ mp.set_property_native(option_key, stream_opts)
+end
+
local function append_libav_opt(props, name, value)
if not props then
props = {}
@@ -553,6 +626,9 @@ local function add_single_video(json)
local http_headers = has_requested_formats
and requested_formats[1].http_headers
or json.http_headers
+ local cookies = has_requested_formats
+ and requested_formats[1].cookies
+ or json.cookies
if o.use_manifests and valid_manifest(json) then
-- prefer manifest_url if present
@@ -740,6 +816,15 @@ local function add_single_video(json)
"http_proxy", json.proxy)
end
+ if cookies and cookies ~= "" then
+ local existing_cookies = parse_cookies(stream_opts["cookies"])
+ local new_cookies = parse_cookies(cookies)
+ for cookie_key, cookie in pairs(new_cookies) do
+ existing_cookies[cookie_key] = cookie
+ end
+ stream_opts["cookies"] = serialize_cookies_for_avformat(existing_cookies)
+ end
+
mp.set_property_native("file-local-options/stream-lavf-o", stream_opts)
end
@@ -938,6 +1023,7 @@ function run_ytdl_hook(url)
-- can't change the http headers for each entry, so use the 1st
set_http_headers(json.entries[1].http_headers)
+ set_cookies(json.entries[1].cookies or json.cookies)
mp.set_property("stream-open-filename", playlist)
if json.title and mp.get_property("force-media-title", "") == "" then
@@ -999,15 +1085,24 @@ function run_ytdl_hook(url)
site = entry["webpage_url"]
end
+ local playlist_url = nil
+
-- links without protocol as returned by --flat-playlist
if not site:find("://") then
-- youtube extractor provides only IDs,
-- others come prefixed with the extractor name and ":"
local prefix = site:find(":") and "ytdl://" or
"https://youtu.be/"
+ playlist_url = prefix .. site
table.insert(playlist, prefix .. site)
elseif url_is_safe(site) then
- table.insert(playlist, site)
+ playlist_url = site
+ end
+
+ if playlist_url then
+ table.insert(playlist, playlist_url)
+ -- save the cookies in a table for the playlist hook
+ playlist_cookies[playlist_url] = entry.cookies or json.cookies
end
end
@@ -1038,6 +1133,14 @@ if (not o.try_ytdl_first) then
end)
end
+mp.add_hook("on_load", 20, function ()
+ msg.verbose('playlist hook')
+ local url = mp.get_property("stream-open-filename", "")
+ if playlist_cookies[url] then
+ set_cookies(playlist_cookies[url])
+ end
+end)
+
mp.add_hook(o.try_ytdl_first and "on_load" or "on_load_fail", 10, function()
msg.verbose('full hook')
local url = mp.get_property("stream-open-filename", "")