Episode: 4585
Title: mpv util scripts
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr4585/hpr4585.mp3
Transcribed: 2026-07-31 16:14:30 (official HPR transcript)

---

This is Hacker Public Radio Episode 4585, for 2026-02-27
Today's show is entitled, "mpv util scripts"
The host is candycanearter and the duration is 00:11:55
The flag is Clean, and the license is CC-BY-SA
The summary is "a collection of hand-written scripts for mpv and explaining how the mpv api works"
There are some programs that act as a cornerstone, a little next to meody, like Vim or Emacs,
deserve some publicity and high levels of extendability. One of these options is really better,
but today we're talking about a different program that I think deserves more attention for its
flexibility. That program isn't baby-y, simply described as a media player in its documentation.
Despite the name, it has tons of support for everything from DVDs to HLS streams to even YouTube
support and has been fantastic for my daily use cases. I wanted it to show off some scripts
I had written in order to display how I took advantage of the flexibility and to potentially
provide a starting point for others who MPV the poor scripts in three different languages,
being Lua, JavaScript, and C. Regardless of which language you're using,
the underlying framework is similar. The cornerstone of scripting an MPV is properties.
Nearly every feature of MPV is exposed through some property or another,
and it can be things that first termed a video, setting, or even state flags.
There's also a dedicated property and for you to find a global, that can be written to
by any script, and it's liberally not touched by the player. The generalization of many different
pieces of info to his property to them makes scripting much easier as all data can be forced through
to think where and point. Property is probably able to be affirmed. This is done through the
of variable property function, which calls the given function whenever the property is updated through
any source. This can be used for anything from when the player goes into a certain state
from when the mouse is moved thanks to the flexible property system. Register event runs the given
function on a global event. This is for state changes that like a fouling started or stopped
or thinking operations, and it's generally a more live away to detect such global state
tuned over using a property. Added hook is an experimental feature, but it is required for
certain cases. Unlike other hooks, it is blocking, which can be important for preventing
waste conditions. Register script message, expose that a user-thread function under
the given name and can be activated from the command line or through a key bind. Added time
out an ad periodic timer are the most basic hooks, calling the function once or repeatedly
for a given number of time. The other command that are important are get and set property
native, which read and write two properties. Command, which runs the command within the MPV
console syntax, LST method, which displays a message to the user on the top left.
These nine functions make up the majority of the interaction with the MPV core.
So we have the button blocks. Let's see what we can do with them.
A and a square profit that Lua doesn't do much on the phone, but it sets up properties for
other scripts to use. In particular, it watches for when the path and play time remaining,
property of or being written to, parses the data out of it, and then writes the data to
user data properties that can be used by other scripts. Getting into this script selects
to do stuff A and a square aspect ratio at Lua. MPV by default has the geometry property,
which may written to you to change the window size. However, did geometry either set to the
value, whenever any fellow said it, which can be annoying if you would previously resize the window.
Wet the script is doing its useful. First, it watches a geometry variable and make sure it
is of a specified aspect ratio. This allows you to do things that like specify the geometry as
the percent of the screen without having to be calculated by use manually. It also resets a geometry
value to the current window size, whenever new fellow voted, in order to prevent random recitals.
First, the target aspect ratio is stored in local variables. This technically should be described
off system, but for a personal script, I didn't want to go through the treble of implementing it.
The reset gem function is simply gets the current dimensions of the window, and writes it to
the geometry. The dimension hop function does a heavy lifting of calculating the aspect ratio
in writing a new geometry 5 if needed. Then the function are just registered to the corresponding
properties and events to make it work. Next, the audiovisual. By default, MPV only displays a black screen
when playing audio files of no associated video track, which is lame. Fortunately, MPV also supports
assigning an arbitrary FFM pedic photographs, so we can rectify that. Due to FFM pedic limitations
of every input having to be filled, this program actually requires a default cover file with
the name covered up PNG to be put either in your home directory or in the MPV config directory.
The one that I drill and made will be in the show notes. The script is split in the two different
functions. That being one that handled adding the missing cover is needed, and one that actually
assigns the filter graph. First, a look-up table of images to the main is put in the top of the
function. This is the useful for network streams that do not provide a cover image, such as this
podcast for some reason. Because the command to add the image stream returns a false value if the image
can't be found, we can use a suit check whether the given image exists and provide a fault
that option is not. You also try to add the FFM from the domain, but this will most likely fail.
Since there is no way to parse HTML, we simply try to access FFM.itio into domain root.
Finally, it just adds the cover image if all other methods have failed. Inject needed,
it's a function that actually does most of the work. First, it scans your all the tracks in the
track list, and if there is a video track, then it simply returns without doing anything.
If there is no image track present, then it calls resolve within cover with the domain paths
that we have assigned in a props.lua. Finally, it writes the filter graph.
Now, this isn't a filter tutorial, but in essence, what is this doing is scaling the image up
to 250 thick by 250 thick if it's smaller, using nearest neighbor, and then scaling it to a width of
720. This width is big enough that the element on the screen do not look too blurry.
We'll also be following us that doesn't overload the RAM. Then it calls it's a built-in audio
visual either, and overlay it with the image. This uses ad hook since the function needs to be run
after the tracks have been parsed, but before the videos are playing, then the F event will crash
if it's missing a source. A and F are playing with that lua, it's just um,
either function I defined it in order to help with playlists ordering. The full clear is simply
clear is a playlists and resets MPV to an idle site is, and playlists next to last simply moves
at the next element in the playlists to the end of it. A, R, C, Fill, dot lua,
or relative cash fill. This makes the winning for cash state a little bit more dynamic.
By default, when the network screen runs out of cash, MPV will simply wait for one second
of the cash to be filled before playing again. In most cases, this is fine, when playing a
flow stream, it's a constant starting and stopping and can be distracting. This script changes
how much cash the cash waits for before playing again, based on the current cash speed,
the bit rate, and the speed. The audio and video bit rate are thumbed and multiplied by the current
playback speed, and then multiplied by 3 in order to give some extra room for the cash. That's
then divided by the current download speed, and they clamped to 20 seconds maximum, and are
supervented from rating forever. Then, erase the cash cause of the weight property and deflate
an OSB message. Also note that it writes to a file local options instead of the default cash
cause weight. This means that it's reset after the file is loaded. Jump to E-Cash is another
either hub or function that sets a playback to 5 seconds before the cash is done. This is very useful
for things like live streams. Last and thirdly not least, is a ton of art at the wall,
which writes to the title bar. By default, MPV uses the title property in order to set what
the title bar displays, which uses property expansion. For update expansion, define special characters
that expand to whatever the property of fallen. By default, property expansion contains some
logical operations that like checking if a property is set to a third value, but with scripting,
we can go further and make it even more dynamic. When the function is first started on startup,
it writes the current value of the title property to a special user data variable. This is
thought that the user can still set a title bar for things like the idle state. Everything related
to updating the title dynamically is handled by a function title update. First, the media title property
is checked, and if it's not that, that no file is currently loaded. So, we set the title to the
previously saved default title and return. Next, the current playlist position is retrieved,
and if it's not negative one, the subtracted it from the current playlist count to get the number
of files remaining in the playlist. Negative one is a special case, meaning no playlist is loaded.
Next, the play time remaining at property if retrieved, and if it's not set,
we assume that we're currently loading the file. So, we just display the currently loading title,
and one left a number of files remaining in the playlist if it was set. And earlier return.
Everything produced by on is for contracting the title bar, for a file that's currently being played.
The progress number is the most dynamic part of the script. By default, it displays the current
position in the file from 0 to 100%. However, after it's less than 100 seconds left of playback,
then it instead displays the number of seconds until the file is over. It also uses the
prepping doubts that up in a underscore props. Apparently, it's also displayed the number of seconds
behind real time a livestream at being played, since those were by constantly updating the end
time of the file. Finally, if the player is popular cash, then it displays the percentage of cash
until it'll start playing again. If the the MOOC's are the network property is set, then it also
displays the cash speed or download speed of the file. Finally, if the domain path, which we set
in a underscore props, is set, we also display the host name of the file being played. Finally,
we set title to the concatenation of all of the different variables, and we're done.
Thankfully, Louis isn't as strict as, say, JavaScript, or a fee yet about 5-inch signatures. So,
we can assign a title update function to a myriad of different properties and events,
as well as a periodic timer, just in case. Title update only shows the template of the title,
not how fast the values in the title are being updated. Keep that in mind if you want to extend
this one. Hopefully, this episode aspires you to try out MPB and try your hand out the
wascripting. Even if you're not an expert in coding, Louis is one of the easiest languages to get into.
And crafting your own customized media player is a surprisingly easy goal to achieve for even
for a first timer. You just have to be patient. Happy MPB-Aing and have some good.
You have been listening to the Hacker Public Radio podcast, at hackerpublicradio.org.
Today's show was contributed by a HPR listener like yourself.
If you ever thought of recording a podcast, then visit the HPR site to find out how easy it really is.
Hosting for HPR has been kindly provided by anhonesthost.com, the Internet Archive, rsync.net, and the HPR Community Content Delivery Network.
Unless otherwise stated, today's show is released under a Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.
