Skip to main content

mpv lyrics plugin

 

https://git.sr.ht/~guidocella/mpv-lrc
 
cd ~/.config/mpv/plugins
git clone  https://git.sr.ht/~guidocella/mpv-lrc
 
chmod +x lrc.sh
 
mv  scripts-opts ..
 
alt+m to download lyrics
needs metadata to download else fails
 
 
cat ~/.config/mpv/mpv.conf
sub-font-size=100  

fir big lyrics font 

The default shortcuts for adjusting subtitle font size:

shitft + g : to increase font size

shitft + f : to decrease font size

 

files:: @Mon Oct 10 01:03:11 PM +0545 2022



lrc.sh
#!/bin/sh

lrc_path=$(printf %s\\n '{ "command": ["get_property", "path"] }' | socat - /tmp/mpv-socket | jq -r .data)
[ "$lrc_path" ] || exit 1
lrc_path=${lrc_path%.*}.lrc
case $lrc_path in
    /*) ;;
    *) lrc_path=$(printf %s\\n '{ "command": ["get_property", "working-directory"] }' | socat - /tmp/mpv-socket | jq -r .data)/$lrc_path
esac

[ -e "$lrc_path" ] && exec $EDITOR "$lrc_path"

metadata=$(printf %s\\n '{ "command": ["get_property", "metadata"] }' \
    | socat - /tmp/mpv-socket | jq .data)
# The keys are lower case in ID3 tags and upper case in Vorbis comments.
artist=$(printf %s "$metadata" | jq -r 'if has("artist") then .artist else .ARTIST end')
title=$(printf %s "$metadata" | jq -r 'if has("title") then .title else .TITLE end')
album=$(printf %s "$metadata" | jq -r 'if has("album") then .album else .ALBUM end')
[ "$album" = null ] && album= || album="[album:$album]
"
duration=$(printf %s\\n '{ "command": ["get_property", "duration"] }' | socat - /tmp/mpv-socket | jq .data)
seconds=${duration%.*}
length=$(printf %02d $(( seconds / 60 ))):$(printf %02d $(( seconds % 60 )))

printf %s "[ar:$artist]
[ti:$title]
$album[length:$length]
[by:$1]

" > "$lrc_path"

query="$artist $title"

if printf %s "$query" | grep -Eiq '([ぁ-ヺ一-龢]|KOTOKO |Ceui )'; then
    # Exclude sites that serve lyrics as images and some non-lyrics sites
    # that Duckduckgo occasionally returns as the first result.
    # When sites try to block copying text, you can inspect the HTML element
    # with the lyrics and execute copy($0.innerText) in the console.
    query="$query 歌詞 -site:petitlyrics.com -site:youtube.com -site:www.amazon.co.jp -site:recochoku.jp"
else
    query="$query lyrics"
fi

${BROWSER:-chromium} "https://duckduckgo.com/?q=\\$query" 2>/dev/null &

if [ "$WAYLAND_DISPLAY" ] && command -v wl-copy >/dev/null; then
    wl-copy -- "$query"
elif command -v xclip >/dev/null; then
    printf %s "$query" | xclip -selection clipboard
fi

exec $EDITOR + "$lrc_path" 
 
lrc.lua
local options = {
    musixmatch_token = '220215b052d6aeaa3e9a410986f6c3ae7ea9f5238731cb918d05ea',
}
local utils = require 'mp.utils'

require 'mp.options'.read_options(options)

local function error_message(string)
    mp.msg.error(string)
    if mp.get_property_native('vo-configured') then
        mp.osd_message(string, 5)
    end
end

local function curl(args)
    local r = mp.command_native({name = 'subprocess', capture_stdout = true, args = args})

    if r.killed_by_us then
        -- don't print an error when curl fails because the playlist index was changed
        return false
    end

    if r.status < 0 then
        error_message('subprocess error: ' .. r.error_string)
        return false
    end

    if r.status > 0 then
        error_message('curl failed with code ' .. r.status)
        return false
    end

    local response, error = utils.parse_json(r.stdout)

    if error then
        error_message('Unable to parse the JSON response')
        return false
    end

    return response
end

local function save_lyrics(lyrics)
    if lyrics == '' then
        error_message('Lyrics not found')
        return
    end

    local current_sub_path = mp.get_property('current-tracks/sub/external-filename')

    if current_sub_path and lyrics:match('^%[') == nil then
        error_message("Only lyrics without timestamps are available, so the existing LRC file won't be overwritten")
        return
    end

    local success_message = 'LRC downloaded'
    if current_sub_path then
        -- os.rename only works across the same filesystem
        local _, current_sub_filename = utils.split_path(current_sub_path)
        local current_sub = io.open(current_sub_path)
        local backup = io.open('/tmp/' .. current_sub_filename, 'w')
        if current_sub and backup then
            backup:write(current_sub:read('*a'))
            success_message = success_message .. '. The old one has been backupped to /tmp.'
        end
        if current_sub then
            current_sub:close()
        end
        if backup then
            backup:close()
        end
    end

    local path = mp.get_property('path')
    local lrc_path = (path:match('(.*)%.[^/]*$') or path) .. '.lrc'
    local lrc = io.open(lrc_path, 'w')
    if lrc == nil then
        error_message('Failed writing to ' .. lrc_path)
        return
    end
    lrc:write(lyrics)
    lrc:close()

    if lyrics:match('^%[') then
        mp.command(current_sub_path and 'sub-reload 1' or 'rescan-external-files')
        mp.osd_message(success_message)
    else
        mp.osd_message('Lyrics without timestamps downloaded')
    end
end

mp.add_key_binding('Alt+m', 'musixmatch-download', function()
    local metadata = mp.get_property_native('metadata')
    local title = metadata.title or metadata.TITLE or metadata.Title
    local artist = metadata.artist or metadata.ARTIST or metadata.Artist

    if not title then
        error_message('This song has no title metadata')
        return
    end

    if not artist then
        error_message('This song has no artist metadata')
        return
    end

    mp.osd_message('Downloading lyrics')

    local response = curl({
        'curl',
        '--silent',
        '--get',
        '--cookie', 'x-mxm-token-guid=' .. options.musixmatch_token, -- avoids a redirect
        'https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get',
        '--data', 'app_id=web-desktop-app-v1.0',
        '--data', 'usertoken=' .. options.musixmatch_token,
        '--data-urlencode', 'q_track=' .. title,
        '--data-urlencode', 'q_artist=' .. artist,
    })

    if not response then
        return
    end

    if response.message.header.status_code == 401 and response.message.header.hint == 'renew' then
        error_message('The Musixmatch token has been rate limited. script-opts/lrc.conf explains how to generate a new one.')
        return
    end

    if response.message.header.status_code ~= 200 then
        error_message('Request failed with status code ' .. response.message.header.status_code .. '. Hint: ' .. response.message.header.hint)
        return
    end

    local body = response.message.body.macro_calls

    local lyrics = ''
    if body['matcher.track.get'].message.header.status_code == 200 then
        if body['matcher.track.get'].message.body.track.has_subtitles == 1 then
            lyrics = body['track.subtitles.get'].message.body.subtitle_list[1].subtitle.subtitle_body
        elseif body['matcher.track.get'].message.body.track.has_lyrics == 1 then -- lyrics without timestamps
            lyrics = body['track.lyrics.get'].message.body.lyrics.lyrics_body
        elseif body['matcher.track.get'].message.body.track.instrumental == 1 then
            error_message('This is an instrumental track')
            return
        end
    end

    save_lyrics(lyrics)
end)

mp.add_key_binding('Alt+n', 'netease-download', function()
    local metadata = mp.get_property_native('metadata')
    local title = metadata.title or metadata.TITLE or metadata.Title
    local artist = metadata.artist or metadata.ARTIST or metadata.Artist

    if not title then
        error_message('This song has no title metadata')
        return
    end

    if not artist then
        error_message('This song has no artist metadata')
        return
    end

    mp.osd_message('Downloading lyrics')

    local response = curl({
        'curl',
        '--silent',
        '--get',
        'https://music.xianqiao.wang/neteaseapiv2/search?limit=10',
        '--data-urlencode', 'keywords=' .. title .. ' ' .. artist,
    })

    if not response then
        return
    end

    local songs = response.result.songs

    if songs == nil or #songs == 0 then
        error_message('Lyrics not found')
        return
    end

    for _, song in ipairs(songs) do
        mp.msg.info(
            'Found lyrics for the song with id ' .. song.id ..
            ', name ' .. song.name ..
            ', artist ' .. song.artists[1].name ..
            ', album ' .. song.album.name ..
            ', url https://music.xianqiao.wang/neteaseapiv2/lyric?id=' .. song.id
        )
    end

    local song = songs[1]
    local album = metadata.album or metadata.ALBUM or metadata.Album
    if album then
        album = album:lower()

        for _, loop_song in ipairs(songs) do
            if loop_song.album.name:lower() == album then
                song = loop_song
                break
            end
        end
    end

    mp.msg.info(
        'Downloading lyrics for the song with id ' .. song.id ..
        ', name ' .. song.name ..
        ', artist ' .. song.artists[1].name ..
        ', album ' .. song.album.name
    )

    response = curl({
        'curl',
        '--silent',
        'https://music.xianqiao.wang/neteaseapiv2/lyric?id=' .. song.id,
    })

    if response then
        save_lyrics(response.lrc.lyric)
    end
end)

mp.add_key_binding('Ctrl+o', 'offset-sub', function()
    local sub_path = mp.get_property('current-tracks/sub/external-filename')

    if not sub_path then
        error_message('No external subtitle is loaded')
        return
    end

    local r = mp.command_native({
        name = 'subprocess',
        capture_stdout = true,
        args = {'ffmpeg', '-loglevel', 'quiet', '-itsoffset', mp.get_property('sub-delay'), '-i', sub_path, '-f', sub_path:match('[^%.]+$'), '-fflags', '+bitexact', '-'}
    })

    if r.status < 0 then
        error_message('subprocess error: ' .. r.error_string)
        return
    end

    if r.status > 0 then
        error_message('ffmpeg failed with code ' .. r.status)
        return
    end

    local sub_file = io.open(sub_path, 'w')
    if sub_file == nil then
        error_message('Failed writing to ' .. sub_path)
        return
    end
    local subs = r.stdout:gsub('^[\r\n]+', '')
    sub_file:write(subs)
    sub_file:close()

    mp.set_property('sub-delay', 0)
    mp.command('sub-reload')
    mp.osd_message('Subtitles updated')
end) 
 
scripts-opts/lrc.conf
# The token to authenticate with Musixmatch's API.
# If you get rate limited, you can obtain a new token with
# curl --location https://apic-desktop.musixmatch.com/ws/1.1/token.get?app_id=web-desktop-app-v1.0
musixmatch_token=220215b052d6aeaa3e9a410986f6c3ae7ea9f5238731cb918d05ea 
 

Comments

Popular posts from this blog

sxhkd volume andbrightness config for dwm on void

xbps-install  sxhkd ------------ mkdir .config/sxhkd cd .config/sxhkd nano/vim sxhkdrc -------------------------------- XF86AudioRaiseVolume         amixer -c 1 -- sset Master 2db+ XF86AudioLowerVolume         amixer -c 1 -- sset Master 2db- XF86AudioMute         amixer -c 1 -- sset Master toggle alt + shift + Escape         pkill -USR1 -x sxhkd XF86MonBrightnessUp          xbacklight -inc 20 XF86MonBrightnessDown          xbacklight -dec 20 ------------------------------------------------------------- amixer -c card_no -- sset Interface volume run alsamixer to find card no and interface names xbps-install -S git git clone https://git.suckless.org/dwm xbps-install -S base-devel libX11-devel libXft-devel libXinerama-devel  vim config.mk # FREETYPEINC = ${X11INC}/freetype2 #comment for non-bsd make clean install   cp config.def.h config.h vim config.h xbps-install -S font-symbola #for emoji on statusbar support     void audio config xbps-i

Hidden Wiki

Welcome to The Hidden Wiki New hidden wiki url 2015 http://zqktlwi4fecvo6ri.onion Add it to bookmarks and spread it!!! Editor's picks Bored? Pick a random page from the article index and replace one of these slots with it. The Matrix - Very nice to read. How to Exit the Matrix - Learn how to Protect yourself and your rights, online and off. Verifying PGP signatures - A short and simple how-to guide. In Praise Of Hawala - Anonymous informal value transfer system. Volunteer Here are five different things that you can help us out with. Plunder other hidden service lists for links and place them here! File the SnapBBSIndex links wherever they go. Set external links to HTTPS where available, good certificate, and same content. Care to start recording onionland's history? Check out Onionland's Museum Perform Dead Services Duties. Introduction Points Ahmia.fi - Clearnet search engine for Tor Hidden Services (allows you

fix idm integration on chrome

Chrome Browser Integration I do not see IDM extension in Chrome extensions list. How can I install it?  How to configure IDM extension for Chrome? Please note that all IDM extensions that can be found in Google Store are fake and should not be used. You need to install IDM extension manually from IDM installation folder. Read in step 2 how to do it . 1. Please update IDM to the latest version by using  "IDM Help->Check for updates..."  menu item 2.  I don't see  "IDM Integration module"  extension in the list of extensions in  Chrome . How can I install it? Press on  Chrome  menu ( arrow 1  on the image), select  "Settings"  menu item ( arrow 2  on the image) and then select  "Extensions"  tab ( arrow 3  on the image). After this open IDM installation folder ( "C:\Program Files (x86)\Internet Download Manager"  by default,  arrow 4  on the image) and drag and drop  "IDMGCExt.crx"  ( arrow 5  on the image) file int