Last active
November 5, 2024 02:15
-
-
Save youthlin/a3b3fc033586bede6046086f3d889322 to your computer and use it in GitHub Desktop.
show lyrics in vlc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[-- | |
show lyrics on visualization 在可视化界面显示歌词 | |
url 项目地址: https://gist.github.com/youthlin/a3b3fc033586bede6046086f3d889322 | |
author 作者: youthlin | |
author url 作者博客: https://youthlin.com | |
How to install: | |
1. put this file on lua/intf/ | |
2. enable extra interface: luaintf (Settings[Show all] -> Interface -> Main Interfaces -> extract modules='luaintf'[make the 'Lua interpreter' checked]) | |
(important: extraintf=luaintf not lua) | |
3. set lua interface to this file name: All Settings -> Interface -> Main Interface -> Lua -> Lua interface = lyrics | |
4. Settings - subtitle/osd - make "enable osd" checked. | |
如何启用: | |
1、将本文件放在 lua/intf/ 文件夹下 | |
2、设置(显示所有)-界面-主界面-扩展界面,填入 luaintf,并勾选 Lua interpreter(勾选会自动填为 lua, 需要手动改成 luaintf) | |
3、设置(显示所有)-界面-主界面-Lua,在 Lua 界面 字段填入本文件名: lyrics | |
4、设置-字幕/OSD-确保 "启用 OSD" 勾选,下方可以设置字体 | |
INSTALLATION directory (\lua\intf\): 安装文件夹在哪里: | |
* Windows (all users): %ProgramFiles%\VideoLAN\VLC\lua\intf\ | |
* Windows (current user): %APPDATA%\VLC\lua\intf\ | |
* Linux (all users): /usr/lib/vlc/lua/intf/ | |
* Linux (current user): ~/.local/share/vlc/lua/intf/ | |
* Mac OS X (all users): /Applications/VLC.app/Contents/MacOS/share/lua/intf/ | |
* Mac OS X (current user): /Users/%your_name%/Library/Application Support/org.videolan.vlc/lua/intf/ | |
Create directory if it does not exist! | |
links: | |
lrcview extension: http://eadmaster.altervista.org/pub/prj/lrcview.lua | |
Times v3.2: https://addons.videolan.org/p/1154032/ | |
vlc lua document: https://github.com/videolan/vlc/tree/master/share/lua | |
document: https://github.com/verghost/vlc-lua-docs/blob/master/index.md | |
VLC forum / Scripting VLC in lua: https://forum.videolan.org/viewforum.php?f=29 | |
--]] -- | |
-- [[ entrance ]] -- | |
(function() -- 立即执行的函数: 入口 | |
local lrc_config = { -- 配置项 | |
supports = {"mp3", "wav", "flac", "ape", "aif", "m4a", "ogg"}, -- 后缀名 file extension | |
pre = { -- 上一行歌词 | |
show = false, | |
prefix = "", | |
suffix = " ♪\n" | |
}, | |
current = { -- 当前歌词 | |
show = true, | |
prefix = "", | |
suffix = " ♪\n" | |
}, | |
next = { -- 下一行歌词 | |
show = true, | |
prefix = "", | |
suffix = " ♪\n" | |
}, | |
lyrics_not_found = "未找到歌词", -- 未找到歌词时显示的文本 | |
position = "top-right" -- 显示位置 | |
} | |
if vlc == nil then | |
vlc = {} -- 消除警告 | |
end | |
local function info(lm) -- Info | |
vlc.msg.info("[lyrics] " .. lm) | |
end | |
local function logerr(lm) -- Error | |
vlc.msg.err("[lyrics] " .. lm) | |
end | |
local function debug(lm) -- debug | |
vlc.msg.dbg("[lyrics] " .. lm) | |
end | |
info("lyrics started! 歌词插件已启动") | |
local function sleep(st) -- 休眠的秒数 seconds | |
vlc.misc.mwait(vlc.misc.mdate() + st * 1000000) | |
end | |
local function dump(name, object, level) -- 显示变量 | |
if level == nil then | |
level = 0 | |
end | |
local prefix = string.rep(" ", level * 2) | |
if type(object) ~= "table" then -- 不是 table | |
info(prefix .. "> " .. name .. " type=" .. type(object) .. " tostring = " .. tostring(object)) | |
return false | |
end | |
info(prefix .. "> " .. name .. " tostring = " .. tostring(object)) | |
for k, v in pairs(object) do | |
k = name .. "." .. k | |
info(prefix .. "> " .. k .. " => " .. type(v) .. " = " .. tostring(v)) | |
if type(v) == "table" then | |
dump(k, v, level + 1) | |
end | |
end | |
return true | |
end | |
dump("vlc", vlc) | |
dump("lrc_config", lrc_config) | |
local function is_win() | |
return vlc.win ~= nil | |
end | |
info("is windows == " .. tostring(is_win())) | |
local curi = nil -- current uri | |
local is_audio = false | |
local seconds_to_lrc = nil -- seconds to lyrics | |
local VLC_tc = 1 -- time corrector | |
if tonumber(string.sub(vlc.misc.version(), 1, 1)) > 2 then | |
VLC_tc = 1000000 | |
end -- VLC3 | |
debug("VLC_tc=" .. tostring(VLC_tc)) | |
local function reset() -- 停止播放时重置变量 | |
info("reset") | |
curi = nil | |
is_audio = false | |
seconds_to_lrc = nil | |
end | |
local function get_lrc() -- 从 lrc 文件获取歌词 | |
if curi == nil or curi == "" then | |
return "" | |
end | |
local file = curi | |
if is_win() then | |
file = string.gsub(file, "file:///", "") -- file:///c:/xxx -> c:/xxx | |
else | |
file = string.gsub(file, "file://", "") -- file:///Users/xxx -> /Users/xxx | |
end | |
local dotIndex = -1 | |
local dot = string.byte(".") | |
for i = #file, 0, -1 do | |
local ch = string.sub(file, i, i) | |
local ch_byte = string.byte(ch) | |
if ch_byte < 128 then | |
if ch_byte == dot then | |
dotIndex = i | |
break | |
end | |
else | |
break | |
end | |
end | |
file = string.sub(file, 1, dotIndex) .. "lrc" | |
if string.match(file, "^http") then | |
info("从网络 lrc 文件读取歌词: " .. file .. " dotIndex=" .. dotIndex) | |
local fd = vlc.stream(file) | |
if not fd then | |
logerr("未获取到网络歌词") | |
return "" | |
end | |
dump("fd", fd) | |
local result = fd:read(65653) | |
fd = nil | |
info('网络读取歌词 ok') | |
return result | |
end | |
file = vlc.strings.decode_uri(file) | |
info("从本地 lrc 文件读取歌词: " .. file .. " dotIndex=" .. dotIndex) | |
-- 使用 vlc.io.open 而不是原生 io.open 可以兼容 Windows 下无法打开中文路径的问题 | |
-- https://github.com/verghost/vlc-lua-docs/blob/master/m/io/index.md | |
local f, err = vlc.io.open(file, "r") | |
if f == nil then | |
logerr("找不到 lrc 歌词文件: " .. file .. " err: " .. err) | |
return "" | |
end | |
local result = f:read("*all") | |
f:close() | |
info('本地 lrc 文件读取歌词 ok') | |
return result | |
end | |
local function get_lyrics() -- 获取当前歌曲的歌词 | |
debug("get_lyrics") | |
local item = vlc.input.item() | |
if item == nil then | |
return "" | |
end | |
local metas = item:metas() | |
dump("metas", metas) | |
if metas["LYRICS"] then | |
info("从歌曲 Tag 中获取歌词") | |
return metas["LYRICS"] | |
end | |
return get_lrc() | |
end | |
local function extract_time(line) -- 获取一行歌词的开始时间 seconds | |
if (line == nil) then | |
return (-1) | |
end | |
local min, sec, mil = line:match('%[(%d%d):(%d%d)%.(%d%d)%]') | |
if (min == nil or sec == nil or mil == nil) then | |
return (-1) | |
end | |
return (tonumber(min) * 60 + tonumber(sec) + tonumber(mil) / 100) | |
end | |
local function build_lrc_table() -- 构造歌词表 | |
debug("build_lrc_table") | |
local lrc = {} | |
local lyrics = get_lyrics() | |
local i = 1 | |
for line in lyrics:gmatch("[^\n]+") do | |
line = string.gsub(line, "\n", "") -- remove newlines | |
line = string.gsub(line, "\r", "") -- remove newlines | |
local time = extract_time(line) | |
if time >= 0 then | |
lrc[i] = { | |
time = time, | |
lrc = string.gsub(line, "^%[.-%]", "") -- 去掉 [xxx] 时间 | |
} | |
i = i + 1 | |
end | |
end | |
return lrc | |
end | |
local function uri_changed(uri) -- 读取当前歌曲的歌词 | |
info("uri_changed to " .. uri) | |
curi = uri | |
local support = false | |
for _, value in pairs(lrc_config.supports) do | |
if string.match(uri, value .. "$") then | |
support = true | |
break | |
end | |
end | |
is_audio = support | |
info("is_audio=" .. tostring(support)) | |
if not support then | |
return | |
end | |
seconds_to_lrc = build_lrc_table() | |
dump("seconds_to_lrc", seconds_to_lrc) | |
if #seconds_to_lrc == 0 then | |
info("没有歌词") | |
end | |
local input = vlc.object.input() | |
dump("input", input) | |
end | |
local function get_show_lyrics() -- 获取要显示的歌词 | |
local total = #seconds_to_lrc | |
-- 没有歌词 | |
if #seconds_to_lrc == 0 then | |
-- debug("没有歌词") | |
return lrc_config.lyrics_not_found | |
end | |
-- 有歌词 | |
local input = vlc.object.input() | |
local current_second = vlc.var.get(input, "time") / VLC_tc | |
local prefix, current, next = "", "", "" | |
debug("get_show_lyrics current_second = " .. current_second) | |
local index = 1 | |
for i = 1, total do | |
local item = seconds_to_lrc[i] | |
local second, value = item.time, item.lrc | |
if second <= current_second then | |
current = value | |
index = i | |
end | |
end | |
if index > 1 then | |
prefix = seconds_to_lrc[index - 1].lrc | |
end | |
if index < total then | |
next = seconds_to_lrc[index + 1].lrc | |
end | |
info("get_show_lyrics = " .. prefix .. " / " .. current .. " / " .. next) | |
local result = "" | |
if lrc_config.pre.show then | |
result = result .. lrc_config.pre.prefix .. prefix .. lrc_config.pre.suffix | |
end | |
if lrc_config.current.show then | |
result = result .. lrc_config.current.prefix .. current .. lrc_config.current.suffix | |
end | |
if lrc_config.next.show then | |
result = result .. lrc_config.next.prefix .. next .. lrc_config.next.suffix | |
end | |
return result | |
end | |
local function do_task() -- 播放时持续调用的函数(每0.1s) | |
--[[ | |
local vout = vlc.object.vout() | |
if vout == nil then | |
-- info("可视化未开启") | |
return | |
end | |
--]] | |
if not is_audio then | |
return | |
end | |
vlc.osd.message(get_show_lyrics(), nil, lrc_config.position) | |
end | |
-- 主循环 | |
while true do | |
if vlc.volume.get() == -256 then -- 当进程被杀时 | |
break | |
end -- inspired by syncplay.lua; kills vlc.exe process in Task Manager | |
if vlc.playlist.status() == "stopped" then -- no input or stopped input | |
if curi then -- input stopped | |
info("stopped") | |
reset() | |
end | |
sleep(1) | |
else -- playing, paused | |
local uri = nil | |
if vlc.input.item() then | |
uri = vlc.input.item():uri() | |
end | |
if not uri then --- WTF (VLC 2.1+): status playing with nil input? Stopping? O.K. in VLC 2.0.x | |
info("WTF??? " .. vlc.playlist.status()) | |
sleep(0.1) | |
elseif not curi or curi ~= uri then -- new input (first input or changed input) | |
uri_changed(uri) | |
else -- current input | |
do_task() | |
if vlc.playlist.status() == "playing" then | |
-- info("playing") | |
elseif vlc.playlist.status() == "paused" then | |
-- info("paused") | |
sleep(0.3) | |
else -- ? | |
info("unknown play status") | |
sleep(1) | |
end | |
sleep(0.1) -- 每 0.1 秒调用一次 task | |
end | |
end | |
end | |
end)() |
顺便补充一下,如果有朋友使用外挂lrc文件在windows上无法显示中文歌词,需要将lrc文件改为utf-8编码,并且要在设置-字幕/OSD-字体改为【Microsoft YaHei UI】,部分中文字体也会导致歌词失效
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
[Mac]网易云音乐网页版歌词显示到菜单栏