Skip to content

Instantly share code, notes, and snippets.

@blairdrummond
Created May 8, 2021 16:30
Show Gist options
  • Save blairdrummond/f022f7215fb92a20289c9752746c0888 to your computer and use it in GitHub Desktop.
Save blairdrummond/f022f7215fb92a20289c9752746c0888 to your computer and use it in GitHub Desktop.
Print mpd.db database file into jsonlines (for jq, or sqlite-utils --nl)
#!/bin/python3
# Convert an mpd.db file into jsonlines.
# Example usage:
#
# > parse-mpd.py /nfs/music | sqlite-utils insert --alter --nl music mpd.sqlite3 music -
#
# Based on: https://github.com/Delapouite/mpdump
#
# NOTE: If your Artist, Album, or Track names start/end with " ",
# then expect the script to fail. (This is fixable, but probably better to just
# clean up the file names)
import gzip
import json
from os.path import join, exists
import argparse
parser = argparse.ArgumentParser(description='Jsonify an mpd database.')
parser.add_argument('music_folder', type=str, help='Root Directory of music library')
parser.add_argument('database', type=str, help='MPD Database')
args = parser.parse_args()
# The database is just a gzipped text file with a specific format
with gzip.open(args.database, "rb") as f:
# bytes -> str
lines = (
x.decode('utf-8').strip()
for x in f.readlines()
)
def split(line):
""" Get key-value pair from line """
blocks = line.strip().split(': ')
assert len(blocks) > 1
return blocks[0], ': '.join(blocks[1:])
def consume(stream, acc={}):
""" Read until song_end tag """
head = next(stream)
if head == 'song_end':
return acc
else:
k, v = split(head)
acc[k] = v
return consume(stream, acc)
directory = []
try:
while True:
line = next(lines)
if line.startswith('directory:'):
_, d = split(line)
directory.append(d)
elif directory and line.startswith('end: ' + join(*directory)):
directory.pop()
elif line.startswith('song_begin:'):
_, track = split(line)
song = consume(lines, acc={'File': join(args.music_folder, *(directory+[track]))})
try:
assert exists(song['File'])
except:
print("~%s~" % song['File'])
raise FileNotFoundError()
print(json.dumps(song))
except StopIteration:
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment