From 3ec02b57cb3861d19f31810b582c507604d12fe6 Mon Sep 17 00:00:00 2001 From: Stephen Johnson Date: Sun, 27 Sep 2020 00:23:27 +0900 Subject: [PATCH] Guarantee previous track return where seek supported --- README.md | 5 +++ dbus/get_property | 4 +- plugin/vimedia.vim | 108 +++++++++++++++++++++++++-------------------- 3 files changed, 67 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index b0a9d97..086b6a4 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,11 @@ for now I've just tried to cover those places that throw errors when unavailable Rhythmbox is an example of a fully-implemented player, while a player like chromium is still very limited in terms of supported functionality. +For players that support the `Seek` command, `Prev` will return to the previous +track regardless of the position of the current track. If `Seek` is not +supported, `Prev` will only return to the previous track if the command is +called within the first few seconds of playback (default MPRIS behavior). + ## Config To configure a default media player, add a line like the following to your vimrc dotfile: diff --git a/dbus/get_property b/dbus/get_property index 6a83b21..b698d3e 100755 --- a/dbus/get_property +++ b/dbus/get_property @@ -4,7 +4,7 @@ case $2 in "Volume") sed_pattern="/double/{s/[[:alpha:]-]//g;s/^\s*//g;p}" ;; -"Shuffle") +"Shuffle"|"CanSeek") sed_pattern="/boolean/{s/variant//g;s/boolean//g;s/^\s*//g;p}" ;; "Position") @@ -22,4 +22,4 @@ dbus-send \ /org/mpris/MediaPlayer2 \ org.freedesktop.DBus.Properties.Get \ string:'org.mpris.MediaPlayer2.Player' \ -string:$2 | sed -ne "$sed_pattern" \ No newline at end of file +string:$2 | sed -ne "$sed_pattern" diff --git a/plugin/vimedia.vim b/plugin/vimedia.vim index 1e87bbd..b1c3a68 100644 --- a/plugin/vimedia.vim +++ b/plugin/vimedia.vim @@ -52,7 +52,7 @@ fu! s:QuitCmd(player) endfu " *************************************************************************** " -" ********************** D-Bus Command Callbacks ************************ " +" ************************* Command Callbacks *************************** " " *************************************************************************** " fu! s:SetPlayerCallback(channel, msg) @@ -96,6 +96,18 @@ fu! s:PauseAllCallback(channel, msg) call s:PauseAllPlayers(a:msg) endfu +fu! s:PreviousCallback(channel, msg) + if a:msg == "true" + call job_start(s:SeekCmd(s:selected_player, -1 * s:ticker_microseconds), {"callback": function("s:SeekStartCallback")}) + else + call job_start(s:ControlPlaybackCmd(s:selected_player, "Previous")) + endif +endfu + +fu! s:SeekStartCallback(channel, msg) + call job_start(s:ControlPlaybackCmd(s:selected_player, "Previous")) +endfu + fu! s:MuteCallback(channel, msg) call s:SetVolumeAll(a:msg, 0.0) endfu @@ -138,7 +150,7 @@ fu! s:QuitCallback(channel, msg) endfu " *************************************************************************** " -" ************************** Timer Functions **************************** " +" ************************* Base Functionality ************************** " " *************************************************************************** " fu! s:init_now_playing_config() @@ -149,51 +161,6 @@ endfu call s:init_now_playing_config() -fu! s:Refresh(timer) - if s:selected_player == "N/A" - return - endif - - call job_start(s:GetPropertyCmd(s:selected_player, "Position"), {"out_cb": function("s:GetPositionCallback")}) - call job_start(s:GetMetadataCmd(s:selected_player, "Title"), {"out_cb": function("s:GetTitleCallback")}) - call job_start(s:GetMetadataCmd(s:selected_player, "Artist"), {"out_cb": function("s:GetArtistCallback")}) -endfu - -fu! NowPlayingText() - return s:current_track_name . " - " . s:current_artist_name -endfu - -fu! PlaybackTicker() - let l:pos_seconds = s:ticker_microseconds / 1000000 - let l:min = l:pos_seconds / 60 - let l:sec = l:pos_seconds - (l:min * 60) - return l:min . ":" . (l:sec > 9 ? l:sec : ("0" . l:sec)) -endfu - -fu! s:UpdateStatusline(timer) - if g:vimedia_statusline_enabled == 0 - return - endif - - if s:selected_player == "N/A" || s:current_artist_name == "N/A" || s:current_track_name == "N/A" - return - endif - - set statusline= - set statusline+=\%{NowPlayingText()} - set statusline+=%= - set statusline+=\%{PlaybackTicker()} -endfu - -"" Refresh track/artist name and playback ticker every half-second -let timer = timer_start(500, function('s:Refresh'), {'repeat':-1}) -"" Update the status line each second with the latest playback info -let timer = timer_start(1000, function('s:UpdateStatusline'), {'repeat':-1}) - -" *************************************************************************** " -" ************************* Base Functionality ************************** " -" *************************************************************************** " - fu! s:init_player_config() let s:selected_player_abbrev = "" @@ -240,7 +207,7 @@ fu! s:Skip() abort endfu fu! s:Previous() abort - call job_start(s:ControlPlaybackCmd(s:selected_player, "Previous")) + call job_start(s:GetPropertyCmd(s:selected_player, "CanSeek"), {"out_cb": function("s:PreviousCallback")}) endfu fu! s:Seek(duration_seconds) abort @@ -347,6 +314,51 @@ fu! s:CheckPlayer(fn, ...) abort endif endfu +" *************************************************************************** " +" ************************** Timer Functions **************************** " +" *************************************************************************** " + +fu! s:Refresh(timer) + if s:selected_player == "N/A" + return + endif + + call job_start(s:GetPropertyCmd(s:selected_player, "Position"), {"out_cb": function("s:GetPositionCallback")}) + call job_start(s:GetMetadataCmd(s:selected_player, "Title"), {"out_cb": function("s:GetTitleCallback")}) + call job_start(s:GetMetadataCmd(s:selected_player, "Artist"), {"out_cb": function("s:GetArtistCallback")}) +endfu + +fu! NowPlayingText() + return s:current_track_name . " - " . s:current_artist_name +endfu + +fu! PlaybackTicker() + let l:pos_seconds = s:ticker_microseconds / 1000000 + let l:min = l:pos_seconds / 60 + let l:sec = l:pos_seconds - (l:min * 60) + return l:min . ":" . (l:sec > 9 ? l:sec : ("0" . l:sec)) +endfu + +fu! s:UpdateStatusline(timer) + if g:vimedia_statusline_enabled == 0 + return + endif + + if s:selected_player == "N/A" || s:current_artist_name == "N/A" || s:current_track_name == "N/A" + return + endif + + set statusline= + set statusline+=\%{NowPlayingText()} + set statusline+=%= + set statusline+=\%{PlaybackTicker()} +endfu + +"" Refresh track/artist name and playback ticker every half-second +let timer = timer_start(500, function('s:Refresh'), {'repeat':-1}) +"" Update the status line each second with the latest playback info +let timer = timer_start(1000, function('s:UpdateStatusline'), {'repeat':-1}) + " *************************************************************************** " " *************************** Command Bindngs *************************** " " *************************************************************************** "