fix(autotag): the orphan cleanup keeps a system tag a saved view filters on

Feed views store tag ids. A system tag no channel carried for a while was deleted and, once a
channel earned it again, recreated under a new id — the view's filter then pointed at nothing, the
feed dropped the unknown id, and the view showed the whole feed under its old name. The cleanup now
skips tags a saved feed view references (test seen red without it).
This commit is contained in:
2026-10-03 19:37:24 +02:00
parent 328d415cfe
commit 4fc307c426
2 changed files with 48 additions and 2 deletions
+12 -2
View File
@@ -12,7 +12,7 @@ from sqlalchemy import and_, exists, func, select
from sqlalchemy.orm import Session
from app import logs, progress, sysconfig
from app.models import Channel, ChannelTag, Tag, Video
from app.models import Channel, ChannelTag, SavedView, Tag, Video
log = logs.get_logger(__name__)
@@ -289,12 +289,22 @@ def run_autotag_all(db: Session, only_missing: bool = False) -> dict:
def _cleanup_orphan_system_tags(db: Session) -> int:
"""Delete system tags that no longer link to any channel (e.g. after a mapping change)."""
"""Delete system tags that no longer link to any channel (e.g. after a mapping change) — but not
one a saved feed view filters on. Views hold tag IDS, and a deleted tag comes back under a new id
when a channel earns it again, so the view's filter would point at nothing; the feed drops an
unknown id, and the view showed the whole feed under its old name (E32 S2)."""
in_views = {
t
for (filters,) in db.execute(select(SavedView.filters).where(SavedView.source == "feed"))
for t in ((filters or {}).get("tags") or [])
if isinstance(t, int)
}
orphans = (
db.execute(
select(Tag).where(
Tag.user_id.is_(None),
~exists().where(ChannelTag.tag_id == Tag.id),
Tag.id.notin_(in_views),
)
)
.scalars()