Skip to content

Instantly share code, notes, and snippets.

@c2nes
Created August 26, 2012 20:28
Show Gist options
  • Save c2nes/3483398 to your computer and use it in GitHub Desktop.
Save c2nes/3483398 to your computer and use it in GitHub Desktop.
For syncing music to a MP3 player from clementine
#!/usr/bin/env python
import hashlib
import os
import os.path
import shutil
import sys
import urllib
import sqlite3
import os.path
OUT_DIR = "/media/usb/MUSIC"
PLS = "Mix"
DB_PATH = "/home/christopher/.config/Clementine/clementine.db"
query = """
SELECT songs.filename FROM playlist_items
JOIN songs, playlists
ON songs.rowid = playlist_items.library_id AND playlists.rowid = playlist_items.playlist
WHERE playlists.name = ?
"""
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
if len(sys.argv) > 1:
PLS = sys.argv[1]
cursor.execute(query, (PLS,))
files = [urllib.unquote(str(fn)).replace("file://", "") for (fn,) in cursor]
conn.close()
if len(files) == 0:
sys.stderr.write("No such playlist or playlist empty\n")
sys.exit(1)
checksum_cache = "sync_cache_%s.txt" % (PLS,)
try:
f = open(checksum_cache)
cache = [l.strip().split(" ", 1) for l in f.readlines()]
cache = [(fn, csum) for csum, fn in cache]
cache = dict(cache)
f.close()
except IOError:
cache = dict()
def compute_digest(filename):
csum = hashlib.md5()
f = open(filename)
while True:
data = f.read(csum.block_size)
if not data:
break
csum.update(data)
return csum.hexdigest()
try:
checksums = []
for i, f in enumerate(files):
sys.stdout.write("\rCompute checksums... %4d/%d %d%%" % (i, len(files), int((float(i)/len(files)) * 100)))
sys.stdout.flush()
if f in cache:
checksums.append((f, cache[f]))
else:
digest = compute_digest(f) + ".mp3"
checksums.append((f, digest))
cache[f] = digest
print "\rCompute checksums... done. "
finally:
f = open(checksum_cache, "w")
f.write("\n".join(["%s %s" % (csum, fn) for fn, csum in cache.items()]) + "\n")
f.close()
if not os.path.exists(OUT_DIR):
sys.stderr.write("Out directory does not exist. Is the device mounted?\n")
sys.exit(1)
existing_files = set([f for f in os.listdir(OUT_DIR) if f.endswith(".mp3")])
to_add = [(f, csum) for (f, csum) in checksums if csum not in existing_files]
to_remove = existing_files - set([csum for f, csum in checksums])
prompt = ""
if to_add and to_remove:
prompt = "Adding %d files and removing %d files. Proceed? [yN] " % (len(to_add), len(to_remove))
elif to_add:
prompt = "Adding %d files. Proceed? [yN] " % (len(to_add),)
elif to_remove:
prompt = "Removing %d files. Proceed? [yN] " % (len(to_remove),)
if prompt and raw_input(prompt) != "y":
sys.stderr.write("Quiting.\n")
sys.exit(1)
if to_add:
i = 1
for f, csum in to_add:
sys.stdout.write("\rCopying... %4d/%d %d%%" % (i, len(to_add), int((float(i)/len(to_add))*100)))
sys.stdout.flush()
dst = os.path.join(OUT_DIR, csum)
try:
shutil.copy(f, dst)
except:
os.remove(dst)
raise
i += 1
print "\rCopying... done. "
if to_remove:
print "Removing %d files" % (len(to_remove),)
for f in to_remove:
os.remove(os.path.join(OUT_DIR, f))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment