Update some scripts, add script for backing up TL2 savegames and using ncmpcpp to play back and manage a mpd-httpd stream

master
Taeyeon Mori 10 years ago
parent bb560c9e93
commit aa3326e000
  1. 3
      bin/aur.sh
  2. 23
      bin/backup-tl2saves
  3. 170
      bin/mpr
  4. 0
      bin/superseded/aconvert
  5. 37
      bin/superseded/mpr

@ -19,7 +19,7 @@ test -d "$build" || mkdir -p "$build" || exit 1
# Parse commandline: anything prefixed with - is a makepkg option
packages=()
flags=()
aur_get=aur_get_old # new one not working yet
aur_get=aur_get_aur4 # new one not working yet
DL_ONLY=false
for cx in "$@"; do
@ -42,6 +42,7 @@ for cx in "$@"; do
echo "Useful makepkg options:"
echo " -i Install package after building it"
echo " -s Install dependencies from official repos"
exit 0
;;
-*)
makepkg_flags=("${makepkg_flags[@]}" "$cx");;

@ -0,0 +1,23 @@
#!/bin/zsh
# Back-up Torchlight II savegames
# Path to steam library
STEAM_APPS=/media/Data/SteamLibrary/SteamApps
# Steam User ID to save, use * to backup all saves
STEAM_USER=*
# Path to create backups at
BACKUP_DIR=~/.backup/TL2
# TL2 paths
TL2_FOLDER="common/Torchlight II"
SAV_FOLDER="my games/runic games/torchlight 2"
source $DOTFILES/lib/libzsh-utils.zsh
cd "$STEAM_APPS/$TL2_FOLDER/$SAV_FOLDER"
filename="tl2saves_`date +%Y-%m-%d_%H-%M`.tar.xz"
msg "Backing up Torchlight II Saves as $filename (in $BACKUP_DIR)"
[ -e "$BACKUP_DIR" ] || mkdir -p "$BACKUP_DIR"
color 36 tar -cJvf "$BACKUP_DIR/$filename" {,mod}save/${^~STEAM_USER}
msg "Done!"

@ -0,0 +1,170 @@
#!/usr/bin/python
# Use ncmpcpp to play and control a mpd-httpd stream while still being able to control the local volume
# (c) 2015 Taeyeon Mori
# requires Python 3.4 or higher
import os
import sys
import pty
import tty
import stat
import array
import fcntl
import signal
import asyncio
import termios
import argparse
import contextlib
import subprocess
import concurrent.futures
URL_TEMPLATE = "http://{host}:{http_port}/"
# ASYNCIO HACKS ==================================================================================
# asyncio is following a great rationale, but at this point in time, there are still some things
# missing from it to make it truly useful. Here comes one of 'em:
@asyncio.coroutine
def async_stdio(loop=None):
# get streams for the standard I/O (stdin and stdout)
if not os.path.sameopenfile(0, 1):
raise RuntimeError("The async_stdio hack only works when both STDIN and STDOUT point to the same TTY/PTS")
if loop is None:
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader()
reader_protocol = asyncio.StreamReaderProtocol(reader)
writer_transport, writer_protocol = yield from loop.connect_write_pipe(asyncio.streams.FlowControlMixin, os.fdopen(0, 'wb'))
writer = asyncio.StreamWriter(writer_transport, writer_protocol, None, loop)
yield from loop.connect_read_pipe(lambda: reader_protocol, sys.stdin)
return reader, writer
@asyncio.coroutine
def async_pty(pty, loop=None):
# same as above, just with a pty descriptor instead of STD*
if loop is None:
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader()
reader_protocol = asyncio.StreamReaderProtocol(reader)
writer_transport, writer_protocol = yield from loop.connect_write_pipe(asyncio.streams.FlowControlMixin, os.fdopen(pty, 'wb'))
writer = asyncio.StreamWriter(writer_transport, writer_protocol, None, loop)
yield from loop.connect_read_pipe(lambda: reader_protocol, os.fdopen(pty))
return reader, writer
# END ASYNCIO HACKS ==============================================================================
def parse_args(argv):
parser = argparse.ArgumentParser(prog=argv[0], add_help=False)
parser.add_argument("--help", action="store_true")
parser.add_argument("-h", "--host", default=os.environ.get("MPD_HOST", "localhost"))
parser.add_argument("-p", "--port", default=os.environ.get("MPD_PORT", "6600"))
parser.add_argument("-P", "--http-port", default="8000")
parser.add_argument("-E", "--http-output", default="1")
args = parser.parse_args(argv[1:])
if args.help:
parser.print_help()
sys.exit(0)
return args
@asyncio.coroutine
def main_coro(args, loop):
# Enable stream
subprocess.check_call(["mpc", "-h", args.host, "-p", args.port, "enable", args.http_output])
# Manage stdio
std_reader, std_writer = yield from async_stdio()
# Manage vlc
vlc_proc = yield from asyncio.create_subprocess_exec("vlc", "--repeat", URL_TEMPLATE.format(**vars(args)), "-I", "rc", stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
vlc_writer = vlc_proc.stdin
# Manage pty
ptm, pts = pty.openpty()
loop.add_signal_handler(signal.SIGWINCH, propagate_winsize, ptm)
propagate_winsize(ptm)
# Manage ncmpc
ptm_reader, ptm_writer = yield from async_pty(ptm)
pty_proc = yield from asyncio.create_subprocess_exec("ncmpcpp", "-h", args.host, "-p", args.port, stdin=pts, stdout=pts, stderr=pts, start_new_session=True, preexec_fn=reopen_tty)
# Magic
input_task = asyncio.async(process_input(std_reader, ptm_writer, vlc_writer))
output_task = asyncio.async(process_output(ptm_reader, std_writer))
yield from asyncio.wait([input_task, output_task, pty_proc.wait()], return_when=concurrent.futures.FIRST_COMPLETED)
# Cleanup
if pty_proc.returncode is None:
pty_proc.terminate()
vlc_proc.terminate()
yield from asyncio.wait([input_task, output_task], timeout=1)
loop.remove_signal_handler(signal.SIGWINCH)
os.close(ptm)
def propagate_winsize(fd):
# Notify pty of window size
buf = array.array('h', [0, 0, 0, 0])
fcntl.ioctl(1, termios.TIOCGWINSZ, buf, True)
fcntl.ioctl(fd, termios.TIOCSWINSZ, buf)
def reopen_tty():
# reopen tty to make it the controlling tty (see stdlib pty)
open(os.ttyname(1), "wb").close()
@asyncio.coroutine
def process_input(reader, writer, vlc_writer):
reader_fd = reader._transport.get_extra_info("pipe").fileno()
if True: # placeholder for eventual context manager for termio reset
tty.setraw(reader_fd)
while True:
data = yield from reader.read(512)
if not data:
break
elif data == b'+':
vlc_writer.write(b"volup 2\n")
yield from vlc_writer.drain()
elif data == b'-':
vlc_writer.write(b"voldown 2\n")
yield from vlc_writer.drain()
#elif data == b'\x03': # CTRL-C, RAW mode
# raise KeyboardInterrupt()
else:
writer.write(data)
yield from writer.drain()
@asyncio.coroutine
def process_output(reader, writer):
while True:
data = yield from reader.read(256)
if data:
writer.write(data)
yield from writer.drain()
else:
break
if __name__ == "__main__":
args = parse_args(sys.argv)
loop = asyncio.get_event_loop()
mode = termios.tcgetattr(0)
try:
sys.exit(loop.run_until_complete(main_coro(args, loop)))
finally:
termios.tcsetattr(0, termios.TCSADRAIN, mode)

@ -0,0 +1,37 @@
#!/bin/sh
# connect to the mpd httpd and open ncmpcpp
# Requirements: vlc, mpc, ncmpcpp
# Use MPD_HOST, MPD_PORT, MPD_HTTP_SINK, MPD_HTTP_PORT environment variables instead of arguments
: ${MPD_HOST:=127.0.0.1} ${MPD_PORT:=6600}
: ${MPD_HTTP_SINK:=1} ${MPD_HTTP_PORT:=8080}
export MPD_HOST
export MPD_PORT
# Find programs
mpc=`which mpc 2>/dev/null`
vlc=`which vlc 2>/dev/null`
client=`which ncmpcpp 2>/dev/null || which ncmpc 2>/dev/null`
if [ -z "$mpc" ]; then
echo "ERROR: mpc (MusicPlayerClient) not found on the system"
elif [ -z "$vlc" ]; then
echo "ERROR: VLC is required for local stream playback"
elif [ -z "$client" ]; then
echo "ERROR: No MPD client installed (ncmpcpp or ncmpc)"
else
# Enable Stream
mpc enable $MPC_HTTP_SINK
# Play Stream (have vlc on fd:3)
vlc --repeat http://$MPD_HOST:$MPD_HTTP_PORT/mpd.ogg -I dummy 2>/dev/null &
vlc_pid=$!
# Launch client in pty
"$client" -h $MPD_HOST -p $MPD_PORT
# Stop stream playback
kill $vlc_pid
fi
Loading…
Cancel
Save