Sync: automated syncs honor the configured playlist sync mode instead of hardcoding 'replace' (#823)

carlosjfcasero: "append" sync mode still recreated the playlist (wiping image +
description) on both the sync-page auto-sync and the Playlist Pipeline. Root
cause: _run_sync_task defaulted sync_mode='replace', and every AUTOMATED caller
omits the mode — auto_sync_playlist (mirrored auto-sync + pipeline), the
iTunes-link sync, and Wing It. So those paths always replaced, ignoring the
user's chosen mode entirely. (Manual sync + the per-source discovery path already
passed a mode, which is why it only bit automated runs.)

Fix: when no mode is passed, _run_sync_task resolves the user's configured global
"Playlist sync mode" (normalize_sync_mode(None, playlist_sync.mode)) — the same
thing _submit_sync_task already does — instead of hardcoding 'replace'. The
global default is still 'replace', so users who never changed it are unaffected;
only those who set Append/Reconcile get the corrected behavior.

Tests: normalize_sync_mode(None,'append')→'append' (and 'replace' unchanged);
auto_sync_playlist must not force a mode (no sync_mode kwarg / no 7th positional)
so the resolution can happen. 896 sync/automation/discovery/playlist tests pass.
pull/848/head
BoulderBadgeDad 1 week ago
parent a79816ad69
commit 6fa956d63a

@ -738,6 +738,12 @@ class TestSyncPlaylist:
import time
time.sleep(0.01)
assert len(sync_calls) == 1
# #823 — the handler must NOT force a sync mode; it leaves it unset so
# _run_sync_task resolves the user's configured global mode (else the
# automated sync always 'replace'd and wiped the playlist image/desc).
args, kwargs = sync_calls[0]
assert kwargs.get('sync_mode') is None # not forced via kwarg
assert len(args) == 6 # no 7th positional sync_mode either
def test_organize_by_playlist_passes_skip_wishlist_add(self):
discovered_track = {

@ -138,6 +138,15 @@ def test_normalize_keeps_reconcile_from_config():
assert normalize_sync_mode('', 'reconcile') == 'reconcile'
def test_normalize_keeps_append_from_config():
# #823 — an AUTOMATED sync (mirrored auto-sync / Playlist Pipeline) passes no
# per-request mode, so it must resolve to the user's configured global mode
# instead of hardcoding 'replace' (which recreated the playlist + wiped its
# image/description). Default 'replace' users are unaffected.
assert normalize_sync_mode(None, 'append') == 'append'
assert normalize_sync_mode(None, 'replace') == 'replace'
def test_normalize_request_overrides_config():
assert normalize_sync_mode('append', 'reconcile') == 'append'
assert normalize_sync_mode('reconcile', 'replace') == 'reconcile'

@ -24136,9 +24136,20 @@ def _run_sync_task(
automation_id=None,
profile_id=1,
playlist_image_url='',
sync_mode='replace',
sync_mode=None,
skip_wishlist_add=False,
):
# When a caller doesn't specify a mode — the mirrored auto-sync + Playlist
# Pipeline (auto_sync_playlist), iTunes-link sync, Wing It — honor the user's
# configured global "Playlist sync mode" instead of hardcoding 'replace'.
# Hardcoding replace meant every AUTOMATED sync recreated the server
# playlist, wiping its custom image + description even when the user chose
# Append/Reconcile (#823 carlosjfcasero). The global default is still
# 'replace', so default users are unaffected; only users who set
# Append/Reconcile get the change. (Mirrors _submit_sync_task.)
if sync_mode is None:
from core.sync.playlist_edit import normalize_sync_mode
sync_mode = normalize_sync_mode(None, config_manager.get('playlist_sync.mode', 'replace'))
return _discovery_sync.run_sync_task(
playlist_id, playlist_name, tracks_json, automation_id, profile_id, playlist_image_url,
_build_sync_deps(),

Loading…
Cancel
Save