~rootmos/media

My Python wrappers around feh and mpv
955732e5 — Gustav Behm a month ago
Bind the mouse buttons in mpv
7b362dfa — Gustav Behm a month ago
Merge branch 'readme'
648129c8 — Gustav Behm a month ago
Link to the .build.yml instead

refs

master
browse  log 

clone

read-only
https://git.sr.ht/~rootmos/media
read/write
git@git.sr.ht:~rootmos/media

You can also use your local clone with git send-email.

#media

builds.sr.ht status

My Python wrappers and around feh and mpv.

The package builds its own instances of forks of feh and mpv (feh, mpv) parametrizing the relevant XDG directories in order to obtain isolation from any already present configurations.

Other small features I've found useful are:

  • in mpv: expose wall-clock with nanosecond resolution
  • in feh: add an alternative exit event (useful for breaking while loops: while feh ...; do ...; end)
  • in feh: make feh play nice with Xmonad when viewing smaller images (maybe useful for other tiling window managers, but at least this solves it for me)

These wrappers primarily evolved from my inability to remember the flags when switching from mplayer to mplayer2 to mpv. My scheme being: one purposeful wrapper around whatever tool implements the functionality at the time: play, view and edit. So when fashions change, the implementation changes not the facade (hey I remember this from the Gang of Four).

The Python wrappers evolved to being capable of triggering callbacks in the Python host program. The idea came from binding feh's action keys to use socat to sending back the trigger over a Unix socket.

#Examples

Following are two examples binding actions/keys in feh and mpv to Python callbacks. These are tested (results) using xdotool and Xvfb.

#Player

import asyncio
import sys

from media.play import Player

sources = sys.argv[1:]

result = None
def sample_action(path, instance):
    global result
    result = True
    instance.terminate()

actions = [
    Player.Action(key="F1", f=sample_action),
]

async def amain():
    async with Player(mute=True).run(sources, actions) as i:
        rc = await i.wait()

asyncio.run(amain())
sys.exit(0 if result else 1)

#Viewer

import asyncio
import sys

from media.view import Viewer

sources = sys.argv[1:]

result = None
def sample_action(path, instance):
    global result
    result = True
    instance.terminate()

actions = [
    Viewer.Action(number=1, f=sample_action),
]

async def amain():
    async with Viewer().run(sources, actions) as i:
        rc = await i.wait()

asyncio.run(amain())
sys.exit(0 if result else 1)