docs
This commit is contained in:
444
docs/filename-matching-requirements-prompt.md
Normal file
444
docs/filename-matching-requirements-prompt.md
Normal file
@ -0,0 +1,444 @@
|
||||
Jag vill implementera en första, skrivskyddad version av funktionaliteten som beskrivs i:
|
||||
|
||||
```text
|
||||
docs/filename-matching-requirements.md
|
||||
```
|
||||
|
||||
Läs hela kravspecifikationen innan du föreslår eller skriver kod.
|
||||
|
||||
## Projektets nuvarande struktur
|
||||
|
||||
Projektrot:
|
||||
|
||||
```text
|
||||
/storage/disk1/WCX
|
||||
```
|
||||
|
||||
SQLite-databas:
|
||||
|
||||
```text
|
||||
/storage/disk1/WCX/database/wcx.db
|
||||
```
|
||||
|
||||
Databasschema:
|
||||
|
||||
```text
|
||||
/storage/disk1/WCX/scripts/schema.sql
|
||||
```
|
||||
|
||||
Nya script ska placeras i:
|
||||
|
||||
```text
|
||||
/storage/disk1/WCX/scripts
|
||||
```
|
||||
|
||||
Databasen innehåller tabellen `movie` med bland annat:
|
||||
|
||||
```text
|
||||
id
|
||||
name
|
||||
duration_seconds
|
||||
```
|
||||
|
||||
Den innehåller även `movie_history` med historiska snapshots och bland annat:
|
||||
|
||||
```text
|
||||
movie_id
|
||||
name
|
||||
duration_seconds
|
||||
archived_at
|
||||
change_summary
|
||||
```
|
||||
|
||||
Fältet `movie.name` är filmens kanoniska namn från siten. Det består alltid av ett eller flera personnamn. Flera personer separeras med `+`.
|
||||
|
||||
Exempel:
|
||||
|
||||
```text
|
||||
Alyn Borav
|
||||
Ilona
|
||||
Angelique Lapiedra + Scarlett Lapiedra
|
||||
```
|
||||
|
||||
Lokala videofiler kan däremot ha kraftigt nedsmutsade filnamn, exempelvis:
|
||||
|
||||
```text
|
||||
Alyn_Borav_AlynBorav.mp4
|
||||
AngeliqueLapiedra_ScarlettLapiedra.mp4
|
||||
BrendaBoop_Interwiev_Fisting.mp4
|
||||
Busty_Slovakian_Ilona_On_Bed.mp4
|
||||
Eden_Ivy_EdenIvy_DP.mp4
|
||||
Version_AngelikaFyres_DP.mp4
|
||||
```
|
||||
|
||||
## Uppgift
|
||||
|
||||
Implementera den första versionen av:
|
||||
|
||||
```text
|
||||
scripts/match_filenames.py
|
||||
```
|
||||
|
||||
Scriptet ska analysera lokala videofiler och försöka matcha dem mot poster i `movie`.
|
||||
|
||||
Det ska vara konservativt. Korrekthet är viktigare än hur många filer som matchas automatiskt.
|
||||
|
||||
Resultatet ska klassificeras som:
|
||||
|
||||
```text
|
||||
matched
|
||||
ambiguous
|
||||
unmatched
|
||||
```
|
||||
|
||||
Osäkra filer ska lämnas för manuell inspektion.
|
||||
|
||||
## Omfattning för första versionen
|
||||
|
||||
Första versionen ska:
|
||||
|
||||
1. Läsa videofiler från en angiven katalog.
|
||||
2. Ha stöd för rekursiv sökning.
|
||||
3. Läsa `id`, `name` och `duration_seconds` från `movie`.
|
||||
4. Läsa historiska längder från `movie_history`.
|
||||
5. Normalisera filnamn och databasnamn.
|
||||
6. Dela flerpersonsnamn på `+`.
|
||||
7. Hitta exakta normaliserade namn i nedsmutsade filnamn.
|
||||
8. Hantera namn som skrivits utan separatorer.
|
||||
9. Hantera upprepade namn i filnamnet.
|
||||
10. Prioritera den mest specifika flerpersonsposten.
|
||||
11. Identifiera när filnamnet innehåller flera kända personer.
|
||||
12. Läsa videons faktiska längd med `ffprobe`.
|
||||
13. Använda längd som en sekundär signal.
|
||||
14. Jämföra längden mot både aktuell och historisk sitelängd.
|
||||
15. Rangordna kandidater med en förklarbar poängmodell.
|
||||
16. Kräva både en tillräckligt hög poäng och en tydlig marginal till kandidat nummer två för `matched`.
|
||||
17. Klassificera osäkra resultat som `ambiguous`.
|
||||
18. Skriva rapporter för `matched`, `ambiguous` och `unmatched`.
|
||||
19. Inte ändra databasen eller några videofiler.
|
||||
|
||||
## Viktiga säkerhetsregler
|
||||
|
||||
Scriptet får inte:
|
||||
|
||||
* ändra databasen
|
||||
* flytta filer
|
||||
* döpa om filer
|
||||
* radera filer
|
||||
* registrera alias
|
||||
* permanent koppla en fil till en databaspost
|
||||
* automatcha en fil enbart på grund av liknande längd
|
||||
* automatcha en fil enbart på grund av fuzzy matching
|
||||
|
||||
Fuzzy matching får gärna förberedas eller användas för kandidatförslag, men ett resultat som är beroende av fuzzy matching ska i första versionen klassificeras som `ambiguous`.
|
||||
|
||||
En felaktig automatisk match är värre än en omatchad fil.
|
||||
|
||||
## Namnnormalisering
|
||||
|
||||
Normaliseringen ska minst:
|
||||
|
||||
* ta bort filändelsen
|
||||
* göra texten gemen
|
||||
* normalisera diakritiska tecken
|
||||
* ta bort mellanslag
|
||||
* ta bort `_`
|
||||
* ta bort `-`
|
||||
* ta bort `+`
|
||||
* ta bort punkter och annan interpunktion
|
||||
* behålla bokstäver och siffror
|
||||
|
||||
Exempel:
|
||||
|
||||
```text
|
||||
Alyn_Borav_AlynBorav.mp4
|
||||
→ alynboravalynborav
|
||||
|
||||
Alyn Borav
|
||||
→ alynborav
|
||||
```
|
||||
|
||||
Exakta normaliserade delsträngsträffar ska väga tungt.
|
||||
|
||||
Extra ord i filnamnet behöver inte tas bort om databasnamnet ändå kan identifieras som en exakt normaliserad delsträng.
|
||||
|
||||
## Flerpersonsfilmer
|
||||
|
||||
För:
|
||||
|
||||
```text
|
||||
Angelique Lapiedra + Scarlett Lapiedra
|
||||
```
|
||||
|
||||
ska personerna behandlas separat:
|
||||
|
||||
```text
|
||||
Angelique Lapiedra
|
||||
Scarlett Lapiedra
|
||||
```
|
||||
|
||||
Båda dessa filnamn ska kunna matcha posten:
|
||||
|
||||
```text
|
||||
AngeliqueLapiedra_ScarlettLapiedra.mp4
|
||||
ScarlettLapiedra_AngeliqueLapiedra.mp4
|
||||
```
|
||||
|
||||
Ordningen ska alltså inte vara avgörande.
|
||||
|
||||
Om databasen innehåller både:
|
||||
|
||||
```text
|
||||
Scarlett Knight
|
||||
Scarlett Knight + Anya Shidlerova
|
||||
```
|
||||
|
||||
och filen heter:
|
||||
|
||||
```text
|
||||
ScarlettKnight_AnyaShidlerova.mp4
|
||||
```
|
||||
|
||||
ska flerpersonsposten rankas högre.
|
||||
|
||||
## Videolängd
|
||||
|
||||
Använd `ffprobe` för att läsa faktisk längd utan omkodning.
|
||||
|
||||
Längd ska endast användas för att stärka eller diskriminera mellan redan rimliga namnkandidater.
|
||||
|
||||
Beräkna både:
|
||||
|
||||
```text
|
||||
absolut skillnad i sekunder
|
||||
procentuell skillnad
|
||||
```
|
||||
|
||||
En första längdmodell kan ungefär vara:
|
||||
|
||||
```text
|
||||
≤ 15 sekunder eller ≤ 1 % mycket stark signal
|
||||
≤ 60 sekunder eller ≤ 2 % stark signal
|
||||
≤ 3 minuter eller ≤ 5 % rimlig signal
|
||||
≤ 10 minuter eller ≤ 10 % svag signal
|
||||
> 10 minuter och > 10 % negativ signal
|
||||
```
|
||||
|
||||
Dessa värden ska definieras som tydliga konstanter så att de senare kan justeras.
|
||||
|
||||
En större längdskillnad ska inte automatiskt ge `unmatched`, eftersom filer kan vara klippta, förlängda eller motsvara en äldre version.
|
||||
|
||||
Historiska längder från `movie_history` ska kunna ge klassificeringen:
|
||||
|
||||
```text
|
||||
historical_version_match
|
||||
```
|
||||
|
||||
Andra möjliga versionsklassificeringar:
|
||||
|
||||
```text
|
||||
current_version_match
|
||||
historical_version_match
|
||||
possible_truncated_version
|
||||
possible_extended_version
|
||||
duration_mismatch
|
||||
unknown_version
|
||||
```
|
||||
|
||||
## Automatisk matchning
|
||||
|
||||
`matched` ska kräva:
|
||||
|
||||
1. en tillräckligt stark namnmatchning
|
||||
2. en totalpoäng över ett tydligt tröskelvärde
|
||||
3. en tydlig marginal till kandidat nummer två
|
||||
4. inga starka motstridiga namnsignaler
|
||||
5. att fuzzy matching inte är den enda avgörande signalen
|
||||
|
||||
Alla tröskelvärden ska ligga som namngivna konstanter nära början av scriptet.
|
||||
|
||||
Poängen ska vara förklarbar. Varje kandidat ska innehålla en lista över skäl, exempelvis:
|
||||
|
||||
```text
|
||||
exact normalized full-name match
|
||||
all participants matched
|
||||
exact participant set
|
||||
current duration differs by 5 seconds
|
||||
historical duration differs by 8 seconds
|
||||
extra known participant found
|
||||
fuzzy match required
|
||||
```
|
||||
|
||||
## Kommandoradsgränssnitt
|
||||
|
||||
Scriptet ska minst stödja:
|
||||
|
||||
```bash
|
||||
scripts/match_filenames.py /path/to/videos
|
||||
```
|
||||
|
||||
Följande argument ska finnas:
|
||||
|
||||
```text
|
||||
--database
|
||||
--recursive
|
||||
--limit
|
||||
--output-directory
|
||||
--debug
|
||||
--no-ffprobe
|
||||
```
|
||||
|
||||
Standardsökväg för databasen:
|
||||
|
||||
```text
|
||||
/storage/disk1/WCX/database/wcx.db
|
||||
```
|
||||
|
||||
`--no-ffprobe` ska göra det möjligt att testa enbart namnmatchningen.
|
||||
|
||||
## Rapportering
|
||||
|
||||
Skapa följande CSV-filer i output-katalogen:
|
||||
|
||||
```text
|
||||
matched.csv
|
||||
ambiguous.csv
|
||||
unmatched.csv
|
||||
```
|
||||
|
||||
Rapporterna ska vara UTF-8-kodade och ha rubrikrad.
|
||||
|
||||
`matched.csv` ska minst innehålla:
|
||||
|
||||
```text
|
||||
path
|
||||
filename
|
||||
file_duration_seconds
|
||||
movie_id
|
||||
movie_name
|
||||
site_duration_seconds
|
||||
matched_duration_seconds
|
||||
version_classification
|
||||
score
|
||||
score_margin
|
||||
match_reason
|
||||
```
|
||||
|
||||
`ambiguous.csv` ska minst innehålla:
|
||||
|
||||
```text
|
||||
path
|
||||
filename
|
||||
file_duration_seconds
|
||||
candidate_1_id
|
||||
candidate_1_name
|
||||
candidate_1_score
|
||||
candidate_2_id
|
||||
candidate_2_name
|
||||
candidate_2_score
|
||||
reason
|
||||
```
|
||||
|
||||
`unmatched.csv` ska minst innehålla:
|
||||
|
||||
```text
|
||||
path
|
||||
filename
|
||||
file_duration_seconds
|
||||
best_candidate_id
|
||||
best_candidate_name
|
||||
best_score
|
||||
reason
|
||||
```
|
||||
|
||||
Skriv även en sammanfattning till konsolen:
|
||||
|
||||
```text
|
||||
Files analyzed
|
||||
Matched
|
||||
Ambiguous
|
||||
Unmatched
|
||||
ffprobe failures
|
||||
```
|
||||
|
||||
I `--debug` ska de bästa kandidaterna och deras poängkomponenter visas per fil.
|
||||
|
||||
## Tekniska krav
|
||||
|
||||
Använd Python 3.12 och endast standardbiblioteket i första versionen.
|
||||
|
||||
`ffprobe` får anropas via `subprocess`.
|
||||
|
||||
Använd:
|
||||
|
||||
* `argparse`
|
||||
* `csv`
|
||||
* `dataclasses`
|
||||
* `pathlib`
|
||||
* `sqlite3`
|
||||
* `subprocess`
|
||||
* `unicodedata`
|
||||
* tydliga type hints
|
||||
|
||||
Använd inte externa Python-paket utan att först motivera varför de behövs.
|
||||
|
||||
Fel i en enskild videofil eller ett `ffprobe`-anrop får inte avbryta hela körningen.
|
||||
|
||||
Scriptet ska ge tydliga felmeddelanden och avsluta med felkod endast vid övergripande fel, exempelvis:
|
||||
|
||||
* databasen saknas
|
||||
* databasschemat är inkompatibelt
|
||||
* inputkatalogen saknas
|
||||
* output-katalogen kan inte skapas
|
||||
|
||||
## Tester
|
||||
|
||||
Skapa även:
|
||||
|
||||
```text
|
||||
tests/test_match_filenames.py
|
||||
```
|
||||
|
||||
Använd `unittest` från standardbiblioteket.
|
||||
|
||||
Tester ska minst täcka:
|
||||
|
||||
1. enkel normalisering
|
||||
2. namn med understreck
|
||||
3. sammanfogade namn
|
||||
4. upprepade namn
|
||||
5. extra skräpord
|
||||
6. flerpersonsnamn
|
||||
7. personer i omvänd ordning
|
||||
8. prioritering av flerpersonspost
|
||||
9. korta namn
|
||||
10. längdpoäng
|
||||
11. historisk längdmatchning
|
||||
12. otillräcklig marginal mellan kandidater
|
||||
13. fuzzy-beroende resultat blir inte `matched`
|
||||
14. fil utan kandidat blir `unmatched`
|
||||
|
||||
Använd temporär SQLite-databas och temporära kataloger i testerna. Testerna får inte använda produktionsdatabasen eller verkliga videofiler.
|
||||
|
||||
## Arbetssätt
|
||||
|
||||
Arbeta stegvis.
|
||||
|
||||
Börja med att:
|
||||
|
||||
1. läsa den befintliga kravspecifikationen
|
||||
2. inspektera relevant databasschema
|
||||
3. föreslå en kort implementationstruktur
|
||||
4. implementera normalisering och kandidatmodell
|
||||
5. implementera namnmatchning
|
||||
6. implementera längdmatchning
|
||||
7. implementera klassificering
|
||||
8. implementera CSV-rapportering
|
||||
9. lägga till tester
|
||||
10. uppdatera README med användning och begränsningar
|
||||
|
||||
Gör inga förändringar utanför den här funktionaliteten.
|
||||
|
||||
När du levererar kod ska du ge hela innehållet för nya eller ändrade filer, inte små kodfragment som kräver besvärlig manuell infogning.
|
||||
|
||||
När något är osäkert ska du välja den konservativa matchningen och tydligt dokumentera antagandet.
|
||||
Reference in New Issue
Block a user