feat: first tested version

This commit is contained in:
2026-06-17 21:35:32 +02:00
parent 8c6a25cdb0
commit a82f503e79
4 changed files with 280 additions and 291 deletions

View File

@@ -1,9 +1,7 @@
#!/usr/bin/env python3
"""
Exporte tous les cue points de Mixxx vers des fichiers .mixxx (JSON)
placés à côté de chaque fichier audio.
Usage : python3 mixxx_export.py [chemin_db]
mixxx_export.py - Exporte TOUTES les métadonnées de préparation Mixxx
(cues, BPM, grille de beat, clé) vers des fichiers .mixxx JSON.
"""
import sqlite3
@@ -18,55 +16,109 @@ def export_cues(db_path: Path, output_dir: Path = None):
con = sqlite3.connect(db_path)
con.row_factory = sqlite3.Row
# Récupérer cues + métadonnées de library en une seule requête par piste
rows = con.execute("""
SELECT
tl.location AS audio_path,
tl.filename AS filename,
c.type AS type,
c.position AS position,
c.length AS length,
c.hotcue AS hotcue,
c.label AS label,
c.color AS color
tl.location AS audio_path,
tl.filename AS filename,
lib.artist AS artist,
lib.title AS title,
lib.album AS album,
lib.genre AS genre,
lib.year AS year,
lib.comment AS comment,
lib.bpm AS bpm,
lib.bpm_lock AS bpm_lock,
lib.key AS key,
lib.key_id AS key_id,
lib.cuepoint AS cuepoint,
lib.beats AS beats,
lib.beats_version AS beats_version,
lib.beats_sub_version AS beats_sub_version,
c.type AS type,
c.position AS position,
c.length AS length,
c.hotcue AS hotcue,
c.label AS label,
c.color AS color
FROM cues c
JOIN library l ON l.id = c.track_id
JOIN track_locations tl ON tl.id = l.location
JOIN library lib ON lib.id = c.track_id
JOIN track_locations tl ON tl.id = lib.location
WHERE tl.fs_deleted = 0
ORDER BY tl.location, c.hotcue, c.type
""").fetchall()
by_file = {}
# Grouper par fichier audio
tracks: dict[str, dict] = {}
for r in rows:
path = r["audio_path"]
by_file.setdefault(path, []).append({
"type": r["type"],
if path not in tracks:
tracks[path] = {
"filename": r["filename"],
"artist": r["artist"] or "",
"title": r["title"] or "",
"album": r["album"] or "",
"genre": r["genre"] or "",
"year": r["year"] or "",
"comment": r["comment"] or "",
"bpm": r["bpm"] or 0.0,
"bpm_lock": bool(r["bpm_lock"]),
"key": r["key"] or "",
"key_id": r["key_id"] or 0,
"cuepoint": r["cuepoint"] or 0,
"beats_version": r["beats_version"] or "",
"beats_sub_version": r["beats_sub_version"] or "",
"beats": None, # sera rempli une seule fois
"cues": []
}
# Encoder le BLOB beats en base64 s'il existe
if r["beats"] is not None:
import base64
tracks[path]["beats"] = base64.b64encode(r["beats"]).decode("ascii")
tracks[path]["cues"].append({
"type": r["type"],
"position": r["position"],
"length": r["length"],
"hotcue": r["hotcue"],
"label": r["label"] or "",
"color": r["color"],
"length": r["length"],
"hotcue": r["hotcue"],
"label": r["label"] or "",
"color": r["color"],
})
con.close()
exported = 0
for audio_path, cues in by_file.items():
for audio_path, data in tracks.items():
audio_file = Path(audio_path)
if not audio_file.exists():
print(f"[SKIP] fichier introuvable : {audio_path}")
continue
# Déterminer où écrire le .mixxx
if output_dir:
out = output_dir / (audio_file.stem + audio_file.suffix + ".mixxx")
else:
out = audio_file.with_suffix(audio_file.suffix + ".mixxx")
payload = {
"version": 1,
"filename": audio_file.name,
"cues": cues,
"version": 2, # version incrémentée car nouveau format
"filename": data["filename"],
"artist": data["artist"],
"title": data["title"],
"album": data["album"],
"genre": data["genre"],
"year": data["year"],
"comment": data["comment"],
"bpm": data["bpm"],
"bpm_lock": data["bpm_lock"],
"key": data["key"],
"key_id": data["key_id"],
"cuepoint": data["cuepoint"],
"beats": data["beats"],
"beats_version": data["beats_version"],
"beats_sub_version": data["beats_sub_version"],
"cues": data["cues"],
}
try:
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps(payload, indent=2, ensure_ascii=False))
@@ -79,7 +131,7 @@ def export_cues(db_path: Path, output_dir: Path = None):
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(description="Export complet Mixxx (cues + BPM + grille + clé)")
parser.add_argument("db_path", nargs="?", default=str(DEFAULT_DB), help="Chemin vers mixxxdb.sqlite")
parser.add_argument("--output-dir", help="Dossier de sortie pour les .mixxx (par défaut : à côté de l'audio)")
args = parser.parse_args()