feat(sxyprn purge): tryb --strip, sceny zostaja bez tagow i performerow spoza tytulu

This commit is contained in:
goon-foss 2026-09-04 11:27:21 +02:00
parent 01298c9699
commit ded80d3bc7

View file

@ -23,6 +23,10 @@ Co robi:
Uzycie (na VPS, z pliku, nie przez stdin):
docker compose run --rm worker python3 -u /srv/scripts/sxyprn_purge_uploaders.py
docker compose run --rm worker python3 -u /srv/scripts/sxyprn_purge_uploaders.py --apply
docker compose run --rm worker python3 -u /srv/scripts/sxyprn_purge_uploaders.py --apply --strip
Wariant --strip (wybrany 2026-09-04): sceny zostaja z playbackiem, ulubionymi i historia,
wylatuja tylko tagi i performerzy spoza tytulu.
"""
from __future__ import annotations
@ -100,6 +104,12 @@ def main() -> int:
ap.add_argument("--apply", action="store_true", help="bez tego tylko raport")
ap.add_argument("--skip-junk", action="store_true", help="pomin krok 3 (smieciowi performerzy)")
ap.add_argument("--only-junk", action="store_true", help="tylko krok 3, scen i zrodel nie ruszaj")
ap.add_argument(
"--strip",
action="store_true",
help="zamiast kasowac sceny: zdejmij im wszystkie tagi i performerow spoza tytulu "
"(decyzja 2026-09-04, zeby nie tracic ulubionych i historii userow)",
)
ap.add_argument("--authors", default=",".join(AUTORZY), help="id autorow po przecinku")
args = ap.parse_args()
autorzy = [a.strip().lower() for a in args.authors.split(",") if a.strip()]
@ -158,6 +168,43 @@ def main() -> int:
do_odciecia, do_usuniecia = [], []
print("tylko krok 3, sceny i zrodla zostaja")
if args.strip:
# Sceny wylacznie tych autorow: zostaja razem ze zrodlem, ale bez tagow
# (wszystkie sa z hashtagow spamera) i bez performerow, ktorych nie ma w tytule.
n_tag = n_perf = 0
for chunk in _chunks(do_usuniecia, _CHUNK):
n_tag += s.execute(
text("DELETE FROM scene_tags WHERE scene_id = ANY(:sceny)"), {"sceny": chunk}
).rowcount
n_perf += s.execute(
text(
"DELETE FROM scene_performers sp USING scenes sc, performers p "
"WHERE sc.id = sp.scene_id AND p.id = sp.performer_id AND sp.scene_id = ANY(:sceny) "
"AND position(lower(p.canonical_name) IN lower(sc.title)) = 0 "
"AND position(regexp_replace(lower(p.canonical_name), '[^a-z0-9]', '', 'g') "
"IN regexp_replace(lower(sc.title), '[^a-z0-9]', '', 'g')) = 0"
),
{"sceny": chunk},
).rowcount
s.commit()
# Sceny scalone z innymi tubami: tagow nie da sie przypisac do autora, wiec
# tylko podpis Shizuki.
n_siz = 0
for chunk in _chunks(do_odciecia, _CHUNK):
n_siz += s.execute(
text(
"DELETE FROM scene_tags st USING tags t "
"WHERE t.id = st.tag_id AND t.slug = 'sizuka' AND st.scene_id = ANY(:sceny)"
),
{"sceny": chunk},
).rowcount
s.commit()
print(
f"strip: scen {len(do_usuniecia)}, zdjete tagi {n_tag}, zdjeci performerzy {n_perf}; "
f"scalone {len(do_odciecia)}, zdjety tag sizuka {n_siz}"
)
do_odciecia, do_usuniecia = [], []
# 2. sceny scalone: zostaja, wylatuje tylko zrodlo autora + tag Sizuka
n_ps = 0
for chunk in _chunks(do_odciecia, _CHUNK):