utility-scripts/backup_mpd_playlist.py

150 lines
5.0 KiB
Python
Executable File

#!/usr/bin/env python
# Back up the state of MPD (current playlist and so on)
import ast
import datetime
import os
import re
import sys
import pprint
import mpd
from optparse import OptionParser
from subprocess import Popen, PIPE
parser = OptionParser()
parser.add_option("-s", "--server", dest="host",
help="set the MPD hostname (default: localhost)", metavar="HOST")
parser.add_option("-p", "--port", dest="port",
help="set the MPD port (default: 6600)", metavar="6600")
parser.add_option("-d", dest="dest",
help="save or load the backup to directory <DIR>", metavar="DIR")
parser.add_option("-l", dest="load", action="store_true",
help="load the last backup")
parser.add_option("-f", "--file", dest="load_file",
help="load the backup in file <FILE>", metavar="FILE")
(options, args) = parser.parse_args()
host = options.host or 'localhost'
port = options.port or '6600'
#backup_dir = options.dest or '/var/lib/mpd/backups'
backup_dir = options.dest or '/home/tim/.mpd/backups'
now = datetime.datetime.now().strftime("%Y%m%d@%H:%M")
ps = Popen(['ps', 'ax'], shell=False, stdout=PIPE).communicate()[0]
if not re.search("\d+\s+mpd\s+", ps):
sys.exit()
client = mpd.MPDClient()
client.timeout = 10
client.idletimeout = 10
client.connect(host, port)
# Get the contents of the most recent backup
all_backups = [os.path.join(backup_dir, f) for f in os.listdir(backup_dir) if f.startswith('mpd_state')]
last_backup = max(all_backups, key=os.path.getctime) if all_backups else []
backup_output = open(last_backup).read() if last_backup else ''
if options.load or options.load_file:
# Override the last backup if the user desires
if options.load_file:
if not os.path.exists(options.load_file):
sys.exit("No such file: " + options.load_file)
backup_output = open(options.load_file).read()
# load file into backup_output
backup = ast.literal_eval(backup_output)
# Check server and port
if backup['src'] != host+":"+port:
if not sys.stdin.isatty():
sys.exit("Error: Backup is from a different server or port.")
c = raw_input("Error: Backup is from a different server or port. Continue? (y/N) ").rstrip('\n')
if c != 'Y' and c != 'y':
sys.exit("Exiting.")
# Clear playlist
client.clear()
# Load songs
for song in backup['playlist']:
try:
client.add(song)
except mpd.CommandError as e:
print("File not found: %s" % e)
pass
# Parse and communicate extra info
if 'repeat' in backup:
client.repeat(backup['repeat'])
if 'random' in backup:
client.random(backup['random'])
if 'single' in backup:
client.single(backup['single'])
if 'consume' in backup:
client.consume(backup['consume'])
id = None
if 'current' in backup:
for song in client.playlistinfo():
if song['file'] == backup['current']:
id = song['id']
print song['file']
print id
next
if not id:
print "Error: Can't find currently-playing song on playlist."
if 'time' in backup and id:
client.seekid(id, backup['time'])
if 'state' in backup:
if backup['state'] == 'play':
client.play()
elif backup['state'] == 'pause':
client.pause(1)
elif backup['state'] == 'stop':
client.stop()
# setvol returns an error, for some reason
# mpd.CommandError: [52@0] {setvol} problems setting volume
#if 'volume' in backup:
# client.setvol(backup['volume'])
else:
# Get current state
get_status = client.status()
get_playlist = client.playlistinfo()
get_currentsong = client.currentsong()
state = {}
playlist = []
for song in get_playlist:
playlist.append(song.get('file', ''))
state = dict(
playlist = playlist,
src = host+":"+port,
consume = get_status.get('consume', ''),
current = get_currentsong.get('file', ''),
time = get_status.get('time', '').split(":")[0],
random = get_status.get('random', ''),
repeat = get_status.get('repeat', ''),
single = get_status.get('single', ''),
state = get_status.get('state', ''),
volume = get_status.get('volume', ''),
)
pp = pprint.PrettyPrinter(indent=4)
current_output = pp.pformat(state)
# We don't care if the volume or currently-playing song has changed, only
# the playlist
strip = re.compile(r'\s*?[\'\"](consume|current|random|repeat|single|state|time|volume)[\'\"]:\s*?[\'\"].*?[\'\"],?');
curr = strip.sub('', current_output)
prev = strip.sub('', backup_output)
# Only copy if the current playlist has changed
if curr != prev:
new_backup_file = os.path.join(backup_dir, 'mpd_state' + "-" + now)
# Write backup
new_backup = open(new_backup_file, 'w')
new_backup.write(current_output)
new_backup.close()
client.close()
client.disconnect()
# vim: set expandtab shiftwidth=4 softtabstop=4 textwidth=79: