#!/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: