video automations: migrate the Download->Process rename in seeded DBs
bug: renaming the action_types only changed code — a db already seeded under the old names kept the stale rows (the seeder only CREATES missing ones, never removes or renames). so on restart you got BOTH 'Auto-Download Movie Wishlist' (orphaned, dead action) AND 'Auto-Process Movie Wishlist'. add _fix_wishlist_processor_rename (runs in ensure_system_automations like the other _fix_* migrations): deletes the orphaned video_download_movie/episode_wishlist system rows (clearing is_system first, since delete_automation guards system rows) and renames the youtube row in place (its action_type was unchanged). idempotent. tested.
This commit is contained in:
parent
7d7d242e5d
commit
10895a7c16
2 changed files with 62 additions and 0 deletions
|
|
@ -453,6 +453,7 @@ class AutomationEngine:
|
||||||
self._fix_video_scan_default()
|
self._fix_video_scan_default()
|
||||||
self._fix_airing_automation_schedule()
|
self._fix_airing_automation_schedule()
|
||||||
self._fix_deep_scan_schedules()
|
self._fix_deep_scan_schedules()
|
||||||
|
self._fix_wishlist_processor_rename()
|
||||||
|
|
||||||
def _fix_video_scan_default(self):
|
def _fix_video_scan_default(self):
|
||||||
"""Remove the obsolete standalone 'Scan Video Library' SYSTEM automation — it's
|
"""Remove the obsolete standalone 'Scan Video Library' SYSTEM automation — it's
|
||||||
|
|
@ -473,6 +474,31 @@ class AutomationEngine:
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("video scan cleanup failed")
|
logger.exception("video scan cleanup failed")
|
||||||
|
|
||||||
|
def _fix_wishlist_processor_rename(self):
|
||||||
|
"""Migrate the wishlist processors' 'Download' → 'Process' rename so a DB seeded
|
||||||
|
under the old names doesn't show stale duplicates.
|
||||||
|
|
||||||
|
The movie/episode ACTIONS were renamed (``video_download_*`` → ``video_process_*``),
|
||||||
|
so the old seeded rows are now orphaned (dead action_type) while the new ones reseed
|
||||||
|
alongside them — delete the orphans. ``delete_automation`` refuses system rows, so
|
||||||
|
clear ``is_system`` first. The YouTube action kept its type but its label changed, so
|
||||||
|
rename that row in place. Idempotent — no-ops once the DB is clean."""
|
||||||
|
try:
|
||||||
|
for dead in ('video_download_movie_wishlist', 'video_download_episode_wishlist'):
|
||||||
|
auto = self.db.get_system_automation_by_action(dead)
|
||||||
|
if auto:
|
||||||
|
self.db.update_automation(auto['id'], is_system=0) # lift the delete guard
|
||||||
|
self.db.delete_automation(auto['id'])
|
||||||
|
logger.info("Removed orphaned '%s' system automation (renamed to process, id=%s)",
|
||||||
|
auto.get('name'), auto.get('id'))
|
||||||
|
yt = self.db.get_system_automation_by_action('video_process_youtube_wishlist')
|
||||||
|
if yt and yt.get('name') == 'Auto-Download YouTube Wishlist':
|
||||||
|
self.db.update_automation(yt['id'], name='Auto-Process YouTube Wishlist')
|
||||||
|
logger.info("Renamed YouTube wishlist automation → 'Auto-Process YouTube Wishlist' (id=%s)",
|
||||||
|
yt.get('id'))
|
||||||
|
except Exception:
|
||||||
|
logger.exception("wishlist processor rename migration failed")
|
||||||
|
|
||||||
def _fix_airing_automation_schedule(self):
|
def _fix_airing_automation_schedule(self):
|
||||||
"""Migrate 'Auto-Wishlist Episodes Airing Today' from the old rolling 24h
|
"""Migrate 'Auto-Wishlist Episodes Airing Today' from the old rolling 24h
|
||||||
interval to a fixed daily 1am run.
|
interval to a fixed daily 1am run.
|
||||||
|
|
|
||||||
|
|
@ -528,3 +528,39 @@ def test_deep_scan_migration_is_idempotent_and_safe_when_absent():
|
||||||
db2.get_system_automation_by_action.return_value = None
|
db2.get_system_automation_by_action.return_value = None
|
||||||
AutomationEngine(db2)._fix_deep_scan_schedules()
|
AutomationEngine(db2)._fix_deep_scan_schedules()
|
||||||
db2.update_automation.assert_not_called()
|
db2.update_automation.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_wishlist_processor_rename_removes_orphans_and_renames_youtube():
|
||||||
|
"""The Download→Process rename: a DB seeded under the old names has orphaned
|
||||||
|
'Auto-Download Movie/Episode Wishlist' rows (dead action_type) — they're deleted (after
|
||||||
|
lifting the is_system delete-guard); the YouTube row (action_type unchanged) is renamed
|
||||||
|
in place, never deleted."""
|
||||||
|
rows = {
|
||||||
|
'video_download_movie_wishlist': {'id': 10, 'is_system': 1, 'name': 'Auto-Download Movie Wishlist'},
|
||||||
|
'video_download_episode_wishlist': {'id': 11, 'is_system': 1, 'name': 'Auto-Download Episode Wishlist'},
|
||||||
|
'video_process_youtube_wishlist': {'id': 12, 'is_system': 1, 'name': 'Auto-Download YouTube Wishlist'},
|
||||||
|
}
|
||||||
|
db = MagicMock()
|
||||||
|
db.get_system_automation_by_action.side_effect = lambda a: rows.get(a)
|
||||||
|
AutomationEngine(db)._fix_wishlist_processor_rename()
|
||||||
|
|
||||||
|
db.delete_automation.assert_any_call(10)
|
||||||
|
db.delete_automation.assert_any_call(11)
|
||||||
|
# is_system=0 lifted on each orphan before deleting
|
||||||
|
cleared = {c.args[0] for c in db.update_automation.call_args_list if c.kwargs.get('is_system') == 0}
|
||||||
|
assert cleared == {10, 11}
|
||||||
|
# youtube renamed (in place), NOT deleted
|
||||||
|
renamed = [c for c in db.update_automation.call_args_list if c.kwargs.get('name')]
|
||||||
|
assert renamed and renamed[0].args[0] == 12
|
||||||
|
assert renamed[0].kwargs['name'] == 'Auto-Process YouTube Wishlist'
|
||||||
|
assert all(c.args[0] != 12 for c in db.delete_automation.call_args_list)
|
||||||
|
|
||||||
|
|
||||||
|
def test_wishlist_processor_rename_is_idempotent_when_clean():
|
||||||
|
# orphans already gone + youtube already renamed → no deletes, no rename
|
||||||
|
rows = {'video_process_youtube_wishlist': {'id': 12, 'is_system': 1, 'name': 'Auto-Process YouTube Wishlist'}}
|
||||||
|
db = MagicMock()
|
||||||
|
db.get_system_automation_by_action.side_effect = lambda a: rows.get(a)
|
||||||
|
AutomationEngine(db)._fix_wishlist_processor_rename()
|
||||||
|
db.delete_automation.assert_not_called()
|
||||||
|
assert not any(c.kwargs.get('name') for c in db.update_automation.call_args_list)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue