Something went wrong. Try again.
🎥 Command line media player
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798#!/usr/bin/env python"""This script emulates "unique application" functionality on Linux. When startingplayback with this script, it will try to reuse an already running instance ofmpv (but only if that was started with umpv). Other mpv instances (not startedby umpv) are ignored, and the script doesn't know about them.This only takes filenames as arguments. Custom options can't be used; the scriptinterprets them as filenames. If mpv is already running, the files passed toumpv are appended to mpv's internal playlist. If a file does not exist or isotherwise not playable, mpv will skip the playlist entry when attempting toplay it (from the GUI perspective, it's silently ignored).If mpv isn't running yet, this script will start mpv and let it control thecurrent terminal. It will not write output to stdout/stderr, because thiswill typically just fill ~/.xsession-errors with garbage.mpv will terminate if there are no more files to play, and running the umpvscript after that will start a new mpv instance.Note that you can control the mpv instance by writing to the command fifo: echo "cycle fullscreen" > ~/.umpv_fifoNote: you can supply custom mpv path and options with the MPV environment variable. The environment variable will be split on whitespace, and the first item is used as path to mpv binary and the rest is passed as options _if_ the script starts mpv. If mpv is not started by the script (i.e. mpv is already running), this will be ignored."""import sysimport osimport errnoimport subprocessimport fcntlimport statimport stringfiles = sys.argv[1:]# this is the same method mpv uses to decide thisdef is_url(filename): parts = filename.split("://", 1) if len(parts) < 2: return False # protocol prefix has no special characters => it's an URL allowed_symbols = string.ascii_letters + string.digits + '_' prefix = parts[0] return all(map(lambda c: c in allowed_symbols, prefix))# make them absolute; also makes them safe against interpretation as optionsdef make_abs(filename): if not is_url(filename): return os.path.abspath(filename) return filenamefiles = [make_abs(f) for f in files]FIFO = os.path.join(os.getenv("HOME"), ".umpv_fifo")fifo_fd = -1try: fifo_fd = os.open(FIFO, os.O_NONBLOCK | os.O_WRONLY)except OSError as e: if e.errno == errno.ENXIO: pass # pipe has no writer elif e.errno == errno.ENOENT: pass # doesn't exist else: raise eif fifo_fd >= 0: # Unhandled race condition: what if mpv is terminating right now? fcntl.fcntl(fifo_fd, fcntl.F_SETFL, 0) # set blocking mode fifo = os.fdopen(fifo_fd, "w") for f in files: # escape: \ \n " f = f.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n") f = "\"" + f + "\"" fifo.write("raw loadfile " + f + " append\n")else: # Recreate pipe if it doesn't already exist. # Also makes sure it's safe, and no other user can create a bogus pipe # that breaks security. try: os.unlink(FIFO) except OSError as e: pass os.mkfifo(FIFO, 0o600) opts = (os.getenv("MPV") or "mpv").split() opts.extend(["--no-terminal", "--force-window", "--input-file=" + FIFO, "--"]) opts.extend(files) subprocess.check_call(opts)