Smooth video playing with mpv and ranger

The Wary Fox

linuxrangermpv

1358 Words - Reading Time: 11 Minutes

2025/08/27 18:52


Marriages aren’t easy

Ranger and mpv are among my favourite open-souce software projects. They are both such a delight to use. I have always had - however - the impression that the defaults for these two to dance together nicely are not exactly great.

Once you open a new video from ranger, it will run it with mpv via rifle. After the video is finished, the mpv process is terminated, and the window is gone. I would rather have the mpv window stay where it already is, so I don’t have to move it again with my window manager.

The list goes on. For instance, new videos added to an mpv playlist won’t play automatically after they’ve been added if something is already playing. Did the video finish before you added the new video? Great, now you also have to press play!

You can see this by tracing the system calls mpv does:

lstrace -e trace=exit mpv your_video_file.mp4
● Video  --vid=1               (av1 3840x2160 23.976 fps) [default]
● Audio  --aid=1  --alang=eng  (aac 2ch 44100 Hz 128 kbps) [default]
AO: [pipewire] 44100Hz stereo 2ch floatp
VO: [gpu] 3840x2160 yuv420p
AV: 01:04:11 / 01:04:11 (100%) A-V:  0.000
Exiting... (End of file)
exit_group(0) = ?
+++ exited with 0 +++

Here’s what happens when the video reaches 100%: It exits.

But don’t despair lads, mpv has more options than days are there in a year, so lets get to it:

MPV

Configuring mpv

There’s a couple of options I need to change in order for mpv to behave the way I want it to. I will be adding the following to the mpv config file, which is at ~/.config/mpv/mpv.conf.

keep-open=yes
keep-open-pause=no
input-ipc-server=/var/run/user/1000/mpv.sock

Now lets see what they mean:

  • keep-open prevents the mpv process/window terminating after a video is finished.
  • keep-open-pause If set to no, instead of pausing when keep-open is active, just stop at end of file and continue playing forward when you seek backwards until end where it stops again. (In other words, with this option set to yes you don’t have to play the video manually if you add the new video in the playlist AFTER the previous video has stopped).
  • input-ipc-server allows us to send JSON IPC messages to an mpv instance (we will need this to send the new videos to mpv later).

The socket can be whatever you have in $XDG_RUNTIME_DIR.

I have seen people saving the socket file in /tmp, but I think its a bit safer to have it on $XDG_RUNTIME_DIR. You get this created automatically (I think by… systemd?) and the right permissions 0700/drwx------.

You have all these options and more in the mpv manual [1].

Since we will be using the sock path in the ranger/rifle configuration we can export a variable in our .zshrc or .bashrc:

export MPV_SOCKET=$XDG_RUNTIME_DIR/mpv.sock

Messaging mpv

You can send messages to mpv using the JSON IPC with the socket we configured above.

Here’s the message pattern:

{"command": ["command_name", "param1", "param2"]}

Now you can send commands to the mpv instance that is playing your video. You can for example request video properties. They are listed in the mpv manual in the section “Property list”.

Let’s ask mpv to let us know the video duration using socat.

The socket should be already there if you reconfigured mpv like above and started mpv:

stat /var/run/user/1000/mpv.sock
  File: /var/run/user/1000/mpv.sock
  Size: 0         	Blocks: 0          IO Block: 4096   socket
Device: 0,44	Inode: 4034        Links: 1
Access: (0600/srw-------)  Uid: ( 1000/   twfox)   Gid: ( 1000/   twfox)
Access: 2025-08-09 23:18:12.269760532 +0200
Modify: 2025-08-09 23:18:12.269760532 +0200
Change: 2025-08-09 23:18:12.269760532 +0200
Birth: 2025-08-09 23:18:12.269760532 +0200
echo '{"command": ["get_property", "file-size"]}' | socat - /var/run/user/1000/mpv.sock

Or, if you created the environmental variable MPV_SOCKET you can also use:

echo '{"command": ["get_property", "file-size"]}' | socat - $MPV_SOCKET
{"data":5632598817,"request_id":0,"error":"success"}

The command we used is get-property. The whole list of input commands are available in the mpv manual on the “Input Commands” section.

For playing the videos from ranger and sending them to mpv we will be using the loadfile, append-play and playlist-next commands:

  • loadfile Load the given file or URL and play it.
  • playlist-next Go to the next entry on the playlist.
  • append-play Append the file, and if nothing is currently playing, start playback.

And now that we know how to talk with mpv let’s mess around with ranger/rifle.

Rifle

Rifle is ranger’s file executor. It has a lot of defaults for common applications, but you change the actions if you want for each file type. The config file is at ~/.config/ranger/rifle.conf

mime ^video,  has mpv,  X, flag f = if pgrep -x mpv; then echo "{ \"command\": [ \"loadfile\", \"$1\", \"append-play\" ] }" | socat - $MPV_SOCKET && echo "{ \"command\": [ \"playlist-next\", \"force\" ] }" | socat - $MPV_SOCKET; else mpv "$1"; fi

Pretty complex for a one liner, isn’t it? Let’s go by parts, said Jack:

mime ^video,  has mpv,  X, flag f

Rifle matches the different files (such as images, videos etc.) with mime types [2]. Then it checks mpv is installed and in our PATH, and finally checks if we are running inside X11. We can use different flags, but we use the most common f:

  • f fork program to background.
  • r run program as root, using sudo.
  • t run program in a separate terminal, as specified by $TERMCM.

Now, for the program we are running, you may have already notice an if statement based wether mpv is already running or not.

if pgrep -x mpv; then echo "{ \"command\": [ \"loadfile\", \"$1\", \"append-play\" ] }" | socat - $MPV_SOCKET && echo "{ \"command\": [ \"playlist-next\", \"force\" ] }" | socat - $MPV_SOCKET; else mpv "$1"; fi

$1 is the filename of the file we open with ranger.

The pgrep command is what I use to check if mpv is running.

The status code and the if statement value will be:

  • If TRUE, mpv is running, the status code is 0:
$ pgrep -x mpv
387911
$ echo $?
0
  • If FALSE, mpv is not running the status code is 1:
$ pgrep -x mpv
$ echo $?
1
  • So, when its TRUE, we already have an mpv instance, so we can issue the loadfile command to load the new video, and append-play to add it to the playlist. If you don’t want a playlist you can just use loadfile instead. What I do then is also optional and depending on your preference you may want to:

    • Append the video to the playlist, but don’t start playing it interrupting the current video. append-play is enough.
    • That you want to start the new video as soon as its added, in which case we also need to use playlist-next so the playlist moves on to the video we just added.
echo "{ \"command\": [ \"loadfile\", \"$1\", \"append-play\" ] }" | socat - $MPV_SOCKET && echo "{ \"command\": [ \"playlist-next\", \"force\" ] }" | socat - $MPV_SOCKET
  • When its FALSE, mpv is not running, we can’t just messages to it, there’s nothing listening. We start mpv instead.
mpv "$1"

Wrapper

If the one-liner is too much for you, you can always create a wrapper and replace that monstruosity we created earlier:

#!/bin/bash
if pgrep -x mpv > /dev/null; then
  # mpv is running, send via IPC
  echo '{"command": ["loadfile", "'$1'","append-play"]}' | socat - "$MPV_SOCKET"
  echo '{"command": ["playlist-next","force"]}' | socat - "$MPV_SOCKET"
else
  # mpv not running, start it
  mpv "$1"
fi

Make sure you create this somewhere inside your PATH and give it execute permission:

chmod +x ~/local/bin/mpv-ranger

Now reconfigure rifle:

mime ^video,  has mpv,  X, flag f = mpv-ranger "$1"

Troubleshooting

If something’s not working as expected you can always try to configure mpv logging level to debug.

Logging to a file in case you have to troubleshoot something that work when running in the terminal but not through ranger/rifle is also a good idea you can explore.

msg-level=all=debug
log-file=/tmp/mpv.log

I do recommend that you try all the commands manually before you start moving them to rifle.conf so you know wether they work or not.

Have fun & good luck!