Preserve server source during album fill

- derive the destination server_source from the target album context
- write it on copied rows and retarget moved rows too
- cover the copy branch with a regression test
pull/538/head
Antti Kettunen 4 days ago
parent e7e32652f5
commit 8603cd6680
No known key found for this signature in database
GPG Key ID: C6B2A3D250359BD7

@ -12,6 +12,7 @@ import os
import re
import shutil
import sys
import sqlite3
import threading
import time
import uuid
@ -2231,6 +2232,46 @@ class RepairWorker:
album_folder, filename_pattern, download_folder):
"""Move or copy a candidate track into the album folder and update DB."""
try:
def _fallback_server_source():
if getattr(candidate, 'server_source', None):
return candidate.server_source
if self._config_manager:
getter = getattr(self._config_manager, 'get_active_media_server', None)
if callable(getter):
return getter() or 'plex'
return self._config_manager.get('active_media_server', 'plex')
return 'plex'
def _resolve_target_context(cursor):
cursor.execute(
"""
SELECT artist_id, server_source
FROM tracks
WHERE album_id = ?
ORDER BY track_number, title
LIMIT 1
""",
(album_id,),
)
row = cursor.fetchone()
if row:
return row[0] or candidate.artist_id, row[1] or _fallback_server_source()
try:
cursor.execute(
"SELECT artist_id, server_source FROM albums WHERE id = ? LIMIT 1",
(album_id,),
)
except sqlite3.OperationalError:
row = None
else:
row = cursor.fetchone()
if row:
return row[0] or candidate.artist_id, row[1] or _fallback_server_source()
return candidate.artist_id, _fallback_server_source()
# Resolve source file
src_path = _resolve_file_path(candidate.file_path, self.transfer_folder, download_folder, config_manager=self._config_manager)
if not src_path or not os.path.exists(src_path):
@ -2264,18 +2305,15 @@ class RepairWorker:
# Update existing DB record to point to new album and path
conn = self.db._get_connection()
cursor = conn.cursor()
# Get the target album's artist_id for consistency
cursor.execute("SELECT artist_id FROM tracks WHERE album_id = ? LIMIT 1", (album_id,))
artist_row = cursor.fetchone()
target_artist_id = artist_row[0] if artist_row else candidate.artist_id
target_artist_id, target_server_source = _resolve_target_context(cursor)
cursor.execute("""
UPDATE tracks
SET album_id = ?, artist_id = ?, title = ?,
file_path = ?, track_number = ?,
file_path = ?, track_number = ?, server_source = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
""", (album_id, target_artist_id, track_name,
target_path, track_number, candidate.id))
target_path, track_number, target_server_source, candidate.id))
# Clean up the source single's album if it's now empty
cursor.execute("SELECT COUNT(*) FROM tracks WHERE album_id = ?", (candidate.album_id,))
@ -2300,17 +2338,14 @@ class RepairWorker:
conn = self.db._get_connection()
cursor = conn.cursor()
# Get artist_id from existing album tracks
cursor.execute("SELECT artist_id FROM tracks WHERE album_id = ? LIMIT 1", (album_id,))
artist_row = cursor.fetchone()
target_artist_id = artist_row[0] if artist_row else candidate.artist_id
target_artist_id, target_server_source = _resolve_target_context(cursor)
cursor.execute("""
INSERT INTO tracks (id, album_id, artist_id, title, track_number, duration,
file_path, bitrate, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
file_path, bitrate, server_source, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
""", (new_track_id, album_id, target_artist_id, track_name, track_number,
candidate.duration, target_path, candidate.bitrate))
candidate.duration, target_path, candidate.bitrate, target_server_source))
conn.commit()
finally:

@ -62,6 +62,7 @@ def test_perform_album_fill_copy_branch_generates_track_id(tmp_path, monkeypatch
duration INTEGER,
file_path TEXT,
bitrate INTEGER,
server_source TEXT,
created_at TEXT,
updated_at TEXT
)
@ -69,10 +70,10 @@ def test_perform_album_fill_copy_branch_generates_track_id(tmp_path, monkeypatch
)
conn.execute(
"""
INSERT INTO tracks (id, album_id, artist_id, title, track_number, duration, file_path, bitrate, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
INSERT INTO tracks (id, album_id, artist_id, title, track_number, duration, file_path, bitrate, server_source, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
""",
("target-track-1", "target-album", "target-artist", "Existing Track", 1, 180000, str(src_path), 320),
("target-track-1", "target-album", "target-artist", "Existing Track", 1, 180000, str(src_path), 320, "navidrome"),
)
conn.commit()
@ -89,6 +90,7 @@ def test_perform_album_fill_copy_branch_generates_track_id(tmp_path, monkeypatch
duration=180000,
file_path=str(src_path),
bitrate=320,
server_source="soulsync",
),
SimpleNamespace(
id="source-track-2",
@ -97,6 +99,7 @@ def test_perform_album_fill_copy_branch_generates_track_id(tmp_path, monkeypatch
duration=181000,
file_path=str(src_path),
bitrate=320,
server_source="soulsync",
),
]
@ -120,6 +123,7 @@ def test_perform_album_fill_copy_branch_generates_track_id(tmp_path, monkeypatch
duration=180000,
file_path=str(src_path),
bitrate=320,
server_source="soulsync",
),
album_id="target-album",
album_title="Target Album",
@ -137,7 +141,7 @@ def test_perform_album_fill_copy_branch_generates_track_id(tmp_path, monkeypatch
with sqlite3.connect(db_path) as verify_conn:
row = verify_conn.execute(
"SELECT id, title, file_path FROM tracks WHERE title = ?",
"SELECT id, title, file_path, server_source FROM tracks WHERE title = ?",
("New Track",),
).fetchone()
assert row is not None
@ -145,4 +149,5 @@ def test_perform_album_fill_copy_branch_generates_track_id(tmp_path, monkeypatch
assert row[0].startswith("album_fill_source-track-1_deadbeef")
assert row[1] == "New Track"
assert Path(row[2]).exists()
assert row[3] == "navidrome"
assert verify_conn.execute("SELECT COUNT(*) FROM tracks WHERE id IS NULL").fetchone()[0] == 0

Loading…
Cancel
Save