Skip to content

Commit

Permalink
Merge branch 'yt-dlp'
Browse files Browse the repository at this point in the history
  • Loading branch information
jcorporation committed Aug 25, 2024
2 parents 48d9b1b + c35566f commit cd0047e
Showing 1 changed file with 208 additions and 0 deletions.
208 changes: 208 additions & 0 deletions yt-dlp/yt-dlp.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
-- {"order":1,"arguments":["uri"]}

-- yt-dlp helper functions
local yt_dlp_path = "yt-dlp"
local yt_dlp_cache = string.gsub((os.getenv("TMPDIR") or "/tmp"), "/+$", "").. "/yt-dlp"

local function yt_dlp_call(uri, parse_json, ...)
local args = {...}
local cmd = string.format(
"'%s' --cache-dir '%s' --paths 'temp:%s' %s '%s' 2>/dev/null",
yt_dlp_path, yt_dlp_cache, yt_dlp_cache, table.concat(args, " "), uri
)
mympd.log(6, "running command: " .. cmd)
local output = mympd.os_capture(cmd)

-- check result from yt-dlp for malformed format or bad data
if string.sub(output, 1, 2) == "NA" then
mympd.log(3, "bad format or no metadata: " ..output)
error("yt-dlp failed to parse --format string, or returned no usable metadata!")
end

if not parse_json then
-- return string if we don't have to parse json
return output
elseif not output or output == "" then
-- return an empty table if there isn't output
return {}
else
-- remove any trailing commas, pack into json array, and parse
return json.decode("[" ..string.gsub(output, ",+$", "").. "]")
end
end

local extensions = {
"webp",
"jpg",
"jpeg",
"png",
"avif",
"svg"
}

local function file_exists(name)
local f = io.open(name,"r")
if f ~= nil then
io.close(f)
return true
end
return false
end

local function check_image(base)
for _, ext in ipairs(extensions) do
local p = base .. "." .. ext
if file_exists(p) then
return p
end
end
return nil
end

-- uri argument is required
if mympd_arguments.uri == "" then
return "No URI provided"
end

if mympd_env.scriptevent == "http" then
-- calling from a stream play event: redirect to the real stream URI
local uri = yt_dlp_call(mympd_arguments.uri, false,
"--format bestaudio",
"--print '%(urls)s'")
if not uri or uri == "" then
error("yt-dlp did not return a URI for this track: " ..mympd_arguments.uri)
end
return mympd.http_redirect(uri)
else
-- calling from user invocation/API
mympd.notify_client(0, "Starting yt-dlp...")
mympd.init()

local misc_cache = mympd_env.cachedir_misc .. "/"

-- look up the uri
local results = yt_dlp_call(mympd_arguments.uri, true,
"--print '%(.{" ..
"id,webpage_url,availability,thumbnails_table," ..
"fulltitle,title,episode," ..
"artist,album_artist,composer,creator,channel,uploader," ..
"album,playlist_title,series,season," ..
"disc_number,season_number," ..
"track_number,playlist_index,episode_number,playlist_count," ..
"genre,release_date,description,extractor,extractor_key})j,'",
"--no-simulate",
"--skip-download",
"--write-thumbnail",
"--output 'thumbnail:" .. misc_cache .. "%(id)s.%(ext)s'",
"--flat-playlist")
if #results < 1 then
return "No streams found"
end

-- generate script URIs and process metadata to create the streams
local uri_format = string.format(
"%sscript/%s/%s?uri=%%s",
mympd_state.mympd_uri_plain,
mympd_env.partition,
mympd.urlencode(mympd_env.scriptname)
)
for i, x in ipairs(results) do
local uri = string.format(uri_format, mympd.urlencode(x.webpage_url))

-- special processing for some values
local title = x.fulltitle or x.title or x.episode or uri
if x.availability and x.availability ~= "public" then
-- notify if stream is not public, to signal it will probably not play
title = "[" ..x.availability.. "] " .. title
end

local album = x.album or x.playlist_title
if not album then
if x.series and x.season then
album = x.series.. " / " ..x.season
else
album = x.series or x.season or x.extractor_key
end
end

local track = x.track_number or x.playlist_index or x.episode_number
if track then
track = tostring(track)
end
if x.playlist_count then
track = track.. "/" ..tostring(x.playlist_count)
end

local disc = x.disc_number or x.season_number
if disc then
disc = tostring(disc)
end

local comment = "[" ..mympd_env.scriptname.. "] " .. x.extractor.. ": " .. x.webpage_url
if x.webpage_url ~= mympd_arguments.uri then
comment = comment.. " | from: " ..mympd_arguments.uri
end
if x.description then
-- replace illegal characters from the tag value with a space
comment = comment.. " | " .. string.gsub(x.description, "[\r\n\t]+", " ")
end
if #comment > 3000 then
comment = string.sub(comment, 1, 3000 - 3) .. "..."
end

-- build metadata table
local meta = {
title = title,
artist = x.artist or x.album_artist or x.composer or
x.creator or x.channel or x.uploader,
album = album,
disc = disc,
track = track,
genre = x.genre,
date = x.release_date,
comment = comment
}

local thumb = check_image(misc_cache .. x.id)
if thumb == nil then
-- yt-dlp didn't download the thumbnail or it doesn't have one, download it
-- Workaround for: https://github.com/yt-dlp/yt-dlp/issues/9983
local thumbs = {}
for id, w, h, th in string.gmatch(x.thumbnails_table.."\n", "(%w+)%s+(%w+)%s+(%w+)%s+(%g+)[\r\n]+") do
if id ~= "ID" then
w = tonumber(w) or 0
h = tonumber(h) or 0
table.insert(thumbs, {size = w + h, thumb = th})
end
end
if #thumbs > 0 then
table.sort(thumbs, function(a, b) return a.size > b.size end)
thumb = thumbs[1].thumb
if thumb and thumb ~= "" then
local tmp_file = mympd.tmp_file()
mympd.log(6, "Downloading " .. thumb .. " to " ..tmp_file)
local rc, code, headers = mympd.http_download(thumb, "", tmp_file)
if rc == 0 then
rc = mympd.cache_cover_write(tmp_file, uri)
if rc == 1 then
mympd.notify_client(2, "Failed to rename thumbnail!")
end
else
mympd.notify_client(2, "Failed to download thumbnail!")
end
end
end
else
-- if yt-dlp downloaded the thumbnail, rename it from id to hash
local rc = mympd.cache_cover_write(thumb, uri)
if rc == 1 then
mympd.notify_client(2, "Failed to rename thumbnail!")
end
end

-- append result to the queue and set tags
-- NOTE: change to MYMPD_API_QUEUE_INSERT_URI_TAGS
-- or MYMPD_API_QUEUE_REPLACE_URI_TAGS if you prefer
mympd.api("MYMPD_API_QUEUE_APPEND_URI_TAGS", {uri = uri, tags = meta, play = false})
end
end

0 comments on commit cd0047e

Please sign in to comment.