Difference between revisions of "How to use Vifm as your music player"

From Vifm Wiki
Jump to navigation Jump to search
m (Fix removal of a song from the playlist)
(Add Playlist Editor Script)
Line 1: Line 1:
 
If you have [https://github.com/MusicPlayerDaemon/mpc mpc] then with some scripting you can use Vifm as your music player!
 
If you have [https://github.com/MusicPlayerDaemon/mpc mpc] then with some scripting you can use Vifm as your music player!
  
{{NOTE|text=You need [https://github.com/junegunn/fzf fzf] for this.}}
+
== Requirements and Reccomendations ==
{{NOTE|text=You should also have the most recent version of mpc compiled from github.}}
+
 
 +
* The most recent version of [https://github.com/MusicPlayerDaemon/mpc mpc], preferably compiled from github.
 +
* [https://github.com/junegunn/fzf fzf]: Fuzzy search finder that makes life easier.
 +
* Python 3 with the [https://pypi.org/project/python-mpd2/ python-mpd2] package installed. ('''OPTIONAL''')
  
 
You '''can''' use older versions of mpc and still get 99% of the functionality, but certain mappings will have to be adjusted for displaying the current status.
 
You '''can''' use older versions of mpc and still get 99% of the functionality, but certain mappings will have to be adjusted for displaying the current status.
 +
The python dependency is only for if you want to sort or edit your playlist with a terminal-based text editor ''on-the-fly''. What's nice about it is that if the new, edited playlist contains the same song you were just listening to, then it will immediately jump to were you left off and continue playing.
 
Make sure that you set the shell variables at the beginning here to their appropriate locations on the harddrive.
 
Make sure that you set the shell variables at the beginning here to their appropriate locations on the harddrive.
 +
 +
== Vifm mappings and Commands ==
  
 
Simply copy and paste this into your vifmrc:
 
Simply copy and paste this into your vifmrc:
Line 33: Line 39:
 
nnoremap rmc :!mpc crop %i<cr>:echo 'Playlist cropped'<cr>
 
nnoremap rmc :!mpc crop %i<cr>:echo 'Playlist cropped'<cr>
 
nnoremap rme :!mpc clear %i<cr>:echo 'Playlist cleared'<cr>
 
nnoremap rme :!mpc clear %i<cr>:echo 'Playlist cleared'<cr>
 +
nnoremap rmE :mpcEdit<cr>
 
nnoremap rmn :let $IGNORE = system('mpc next')<cr>:ShowSong<cr>
 
nnoremap rmn :let $IGNORE = system('mpc next')<cr>:ShowSong<cr>
 
nnoremap rmv :let $IGNORE = system('mpc prev')<cr>:ShowSong<cr>
 
nnoremap rmv :let $IGNORE = system('mpc prev')<cr>:ShowSong<cr>
Line 56: Line 63:
 
command mpcStat :echo system('mpc | sed -ne '.%a.'p --')
 
command mpcStat :echo system('mpc | sed -ne '.%a.'p --')
 
command mpcls mpc playlist | sed -e "s%%$(mpc | sed -ne '1p')%%& *%%" -- %M
 
command mpcls mpc playlist | sed -e "s%%$(mpc | sed -ne '1p')%%& *%%" -- %M
" Unfortunitly vifm doesn't have the capability to give a user command the functionality of
+
command mpcEdit mpc_edit.py %s
" something like :rename
 
" command mpcEdit !mpc playlist | $EDITOR - /tmp/tmp.m3u
 
 
command mpcplay :if system('mpc | sed -ne 2p -- | cut -d " " -f 1') == '' | execute '!mpc toggle &' | else | execute '!mpc next &' | endif
 
command mpcplay :if system('mpc | sed -ne 2p -- | cut -d " " -f 1') == '' | execute '!mpc toggle &' | else | execute '!mpc next &' | endif
 
" }}}2
 
" }}}2
Line 64: Line 69:
 
</source>
 
</source>
  
A video showcasing almost all the features is [https://youtu.be/6JNZKT7VgIg here].
+
== Playlist Editor Script ==
 +
 
 +
Copy and paste the following into your <code>$VIFM/scripts</code> folder or somewhere in your <code>$PATH</code> as <code>mpc_edit.py</code>:
 +
 
 +
<source lang="python">
 +
#!/usr/bin/env python3
 +
 
 +
import os
 +
import tempfile
 +
from mpd import MPDClient
 +
 
 +
# Options
 +
editor = os.environ['EDITOR']
 +
# Amount (in seconds) to rewind when reloading the playlist
 +
setback = 4
 +
 
 +
# Startup
 +
client = MPDClient()
 +
client.connect("localhost", 6600)
 +
 
 +
with tempfile.NamedTemporaryFile('w+') as tmpf:
 +
    tmpf.writelines((song['file']+'\n' for song in client.playlistid()))
 +
    tmpf.seek(0)
 +
    old_playlist = [song.strip() for song in tmpf.readlines()]
 +
    # Ensure that the file has been written to disk
 +
    tmpf.flush()
 +
    os.system("{} {}".format(editor, tmpf.name))
 +
    tmpf.seek(0)
 +
    new_playlist = [song.strip() for song in tmpf.readlines()]
 +
 
 +
if new_playlist != old_playlist:
 +
    # Save the status right before we change things:
 +
    current_song = client.currentsong()['file']
 +
    elapsed = float(client.status()['elapsed'])
 +
 
 +
    client.clear()
 +
    for song in new_playlist:
 +
        client.add(song)
 +
 
 +
    # Check if the song we were listing to is in the new playlist
 +
    try:
 +
        new_pos = [song['file'] for song in
 +
                client.playlistid()].index(current_song)
 +
    except ValueError:
 +
        pass
 +
    else:
 +
        client.seek(new_pos, elapsed-setback if elapsed>setback else 0)
 +
</source>
 +
 
 +
This allows you to edit the current playlist by tying <code>rmE</code> if you have the optional dependencies installed.
 +
 
 +
A video showcasing most of the features is [https://youtu.be/6JNZKT7VgIg here].

Revision as of 19:46, 31 May 2021

If you have mpc then with some scripting you can use Vifm as your music player!

Requirements and Reccomendations

  • The most recent version of mpc, preferably compiled from github.
  • fzf: Fuzzy search finder that makes life easier.
  • Python 3 with the python-mpd2 package installed. (OPTIONAL)

You can use older versions of mpc and still get 99% of the functionality, but certain mappings will have to be adjusted for displaying the current status. The python dependency is only for if you want to sort or edit your playlist with a terminal-based text editor on-the-fly. What's nice about it is that if the new, edited playlist contains the same song you were just listening to, then it will immediately jump to were you left off and continue playing. Make sure that you set the shell variables at the beginning here to their appropriate locations on the harddrive.

Vifm mappings and Commands

Simply copy and paste this into your vifmrc:

" {{{1 MUSIC PLAYER
let $SONG_FORMAT="[[%artist% - ]%title%]|[%file%]"
let $MUSIC_DIR=expand("$HOME/music")
let $PLAY_LIST=expand("$HOME/music/play_list")
" {{{2 MAPPINGS
nnoremap L :!mpc seek +5%% %i<cr>:mpcStat 2<cr>
nnoremap B :!mpc seek -5%% %i<cr>:mpcStat 2<cr>
nnoremap l :!mpc seek +5 %i<cr>:mpcStat 2<cr>
nnoremap b :!mpc seek -5 %i<cr>:mpcStat 2<cr>
nnoremap rmp :!mpc toggle %i<cr>:mpcStat 2<cr>
nnoremap rmw :ShowSong<cr>
nnoremap rmg :GotoSong<cr>
nnoremap rmt :mpcStat 2<cr>
nnoremap rm3 :echo system('mpc status "vol:%volume% rep %repeat% rand %random% single %single%"')<cr>
nnoremap rm0 :let $IGNORE = system('mpd_restart')<cr>:echo 'Music player daemon has been restarted'<cr>
nnoremap rmi :mpcinsert<cr>:!echo Song %f:t inserted. %S<cr>
nnoremap rma :mpcadd<cr>:!echo Song %f:t added. %S<cr>
nnoremap rmm :!echo "%f" | sed -e 's/\([^\]\) /\1\n/g' -e 's/\\//g' | xargs -d '\n' -L 1 realpath --relative-to=$MUSIC_DIR %M | sort -nr | xargs -d '\n' -L 1 mpc insert<cr>:mpcplay<cr>:ShowSong<cr>
nnoremap rmd :Delfind<cr>
nnoremap rmf :goto $MUSIC_DIR<cr>i:FZFfind<cr>
nnoremap rms :Playfind<cr>
nnoremap rmc :!mpc crop %i<cr>:echo 'Playlist cropped'<cr>
nnoremap rme :!mpc clear %i<cr>:echo 'Playlist cleared'<cr>
nnoremap rmE :mpcEdit<cr>
nnoremap rmn :let $IGNORE = system('mpc next')<cr>:ShowSong<cr>
nnoremap rmv :let $IGNORE = system('mpc prev')<cr>:ShowSong<cr>
nnoremap rmr :let $IGNORE = system('mpc seek 0%')<cr>:let $IGNORE = system('mpc play')<cr>:mpcStat 1<cr>
nnoremap rmR :let $IGNORE = system('mpc stop')<cr>:!mpc play 1 %i<cr>
nnoremap rmx :let $IGNORE = system('mpc random')<cr>:echo system('mpc status "Random is %random%"')<cr>
nnoremap rml :let $IGNORE = system('mpc repeat')<cr>:echo system('mpc status "Repeat is %repeat%"')<cr>
nnoremap rmS :let $IGNORE = system('mpc single')<cr>:echo system('mpc status "Single is %single%"')<cr>
nnoremap rmh :!mpc shuffle %i<cr>:echo 'Playlist shuffled'<cr>
nnoremap rmL :PlayListfind<cr>:!sleep 0.2 %i<cr>:Playfind<cr>
nnoremap + :!mpc volume +5 %i<cr>:echo system('mpc status "Volume is:%volume%"')<cr>
nnoremap - :!mpc volume -5 %i<cr>:echo system('mpc status "Volume is:%volume%"')<cr>
" }}}2
" {{{2 COMMANDS
command! Playfind :exe '!mpc play "'.system('mpc playlist | nl | grep -Fv "$(mpc | sed -ne "1p" --)" | fzf --height 40 --with-nth 2.. 2>/dev/tty | cut -f 1 | tr -d " "').'" &>/dev/null %IU' | redraw
command! PlayListfind :exe '!mpc load "'.system('mpc lsplaylist | fzf --height 40 2>/dev/tty').'"' | redraw
command Delfind :exe '!mpc del "'.system('mpc playlist | nl | fzf --height 40 --with-nth 2.. 2>/dev/tty | cut -f 1 | tr -d " "').'" &' | redraw
command ShowSong mpc -f "$SONG_FORMAT" current %S
command GotoSong :exe 'goto "$MUSIC_DIR/'.system('mpc -f "%%file%%" | sed -ne "1p" --').'"'
command mpcadd :let $IGNORE = system(expand('mpc search filename "$(realpath --relative-to=$MUSIC_DIR %%f)" | mpc add'))
command pls mpc save %a | echo "Playlist saved." %i
command pll mpc load %a %i
command mpcStat :echo system('mpc | sed -ne '.%a.'p --')
command mpcls mpc playlist | sed -e "s%%$(mpc | sed -ne '1p')%%& *%%" -- %M
command mpcEdit mpc_edit.py %s
command mpcplay :if system('mpc | sed -ne 2p -- | cut -d " " -f 1') == '' | execute '!mpc toggle &' | else | execute '!mpc next &' | endif
" }}}2
" }}}1

Playlist Editor Script

Copy and paste the following into your $VIFM/scripts folder or somewhere in your $PATH as mpc_edit.py:

#!/usr/bin/env python3

import os
import tempfile
from mpd import MPDClient

# Options
editor = os.environ['EDITOR']
# Amount (in seconds) to rewind when reloading the playlist
setback = 4

# Startup
client = MPDClient()
client.connect("localhost", 6600)

with tempfile.NamedTemporaryFile('w+') as tmpf:
    tmpf.writelines((song['file']+'\n' for song in client.playlistid()))
    tmpf.seek(0)
    old_playlist = [song.strip() for song in tmpf.readlines()]
    # Ensure that the file has been written to disk
    tmpf.flush()
    os.system("{} {}".format(editor, tmpf.name))
    tmpf.seek(0)
    new_playlist = [song.strip() for song in tmpf.readlines()]

if new_playlist != old_playlist:
    # Save the status right before we change things:
    current_song = client.currentsong()['file']
    elapsed = float(client.status()['elapsed'])

    client.clear()
    for song in new_playlist:
        client.add(song)

    # Check if the song we were listing to is in the new playlist
    try:
        new_pos = [song['file'] for song in
                client.playlistid()].index(current_song)
    except ValueError:
        pass
    else:
        client.seek(new_pos, elapsed-setback if elapsed>setback else 0)

This allows you to edit the current playlist by tying rmE if you have the optional dependencies installed.

A video showcasing most of the features is here.