Skip to content

Instantly share code, notes, and snippets.

@stith
Created September 28, 2023 10:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stith/d62fe526608aee928e0c74d7dfdb9227 to your computer and use it in GitHub Desktop.
Save stith/d62fe526608aee928e0c74d7dfdb9227 to your computer and use it in GitHub Desktop.
Rekordbox .flac to .aiff conversion

quick script that, given a rekordbox library.xml file, converts all .flac files to .aiff, preserving file metadata like cue points, play count, and album art. also maintains the file's bit rate.

probably will fail in some weird cases that i didn't have to care about with my tiny baby library

import xml.etree.ElementTree as ET
import urllib.parse
from pathlib import Path
import os
import subprocess
import json
import argparse
def convert_files(input_xml_path, output_xml_path):
tree = ET.parse(input_xml_path)
logfile = open('flac-conversion-log2.txt', 'a')
tracks = tree.getroot().findall('./COLLECTION/TRACK')
for track in tracks:
track_name = f"{track.attrib['Artist']} - {track.attrib['Name']}"
if track.attrib['Kind'].lower() == 'flac file':
# Fenagle rekordbox path to something usable
filename: str = track.attrib['Location'].replace('file://localhost', '')
filename = urllib.parse.unquote(filename)
flac_path = Path(filename)
aiff_path = flac_path.with_suffix('.aiff')
# Convert flac -> wav
if not aiff_path.exists():
if not flac_path.exists():
raise RuntimeError(f"Path doesn't exist: {flac_path}")
print("Probing", track_name)
probed_data = subprocess.run(['ffprobe', '-v', 'quiet', '-print_format', 'json', '-show_streams', flac_path], capture_output=True, text=True).stdout
parsed_probe = json.loads(probed_data)
bit_depth = parsed_probe["streams"][0]["bits_per_raw_sample"]
print(f"Converting with bit depth {bit_depth}:", track_name)
convert_result = subprocess.run(['ffmpeg', '-i', flac_path, '-write_id3v2', '1', '-c:a', f"pcm_s{bit_depth}be", '-c:v', 'copy', aiff_path], capture_output=True)
if convert_result.returncode != 0:
print("Failed", convert_result.returncode, "on", flac_path)
print("STDOUT:", convert_result.stdout)
print("STDERR:", convert_result.stderr)
break
logfile.write(str(flac_path))
logfile.write("\n")
# Defenagle sensible path into rekordbox's thing
aiff_uri = aiff_path.as_uri().replace('file:///', 'file://localhost/')
track.attrib['Kind'] = 'AIFF File'
track.attrib['Location'] = aiff_uri
track.attrib['Comments'] = f"{track.attrib['Comments']} flac-converted"
track.attrib['Size'] = str(os.path.getsize(aiff_path))
print("Done with", track_name)
tree.write(output_xml_path)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input", help="library.xml location", required=True)
parser.add_argument("-o", "--output", help="updated library.xml location", required=True)
args = parser.parse_args()
convert_files(args.input, args.output)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment