#!/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 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 ", 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 ", 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' now = datetime.datetime.now().strftime("%Y%m%d@%H:%M") 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["file"]) state = dict( playlist = playlist, src = host+":"+port, consume = get_status['consume'], current = get_currentsong['file'] if get_currentsong['file'] else '', random = get_status['random'], repeat = get_status['repeat'], single = get_status['single'], state = get_status['state'], time = get_status['time'].split(":")[0] if get_status['time'] else '', volume = get_status['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 current_output != backup_output: 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: