diff --git a/docs/filename-matching-requirements.md b/docs/filename-matching-requirements.md new file mode 100644 index 0000000..0ed4f99 --- /dev/null +++ b/docs/filename-matching-requirements.md @@ -0,0 +1,896 @@ +# Kravspecifikation: Matchning av lokala videofiler mot WCX-databasen + +## 1. Syfte + +Funktionen ska identifiera vilken post i WCX-databasen en lokal videofil sannolikt motsvarar. + +Databasen innehåller filmens kanoniska namn enligt siten. Namnet består alltid av ett eller flera personnamn och inga andra beskrivande ord. + +Lokala filnamn är däremot ofta inkonsekventa och kan innehålla: + +* sammanfogade namn +* understreck eller andra separatorer +* upprepade namn +* felstavningar +* extra beskrivande ord +* tekniska eller innehållsrelaterade suffix +* flera personnamn +* inkonsekvent användning av stora och små bokstäver + +Exempel: + +```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 +``` + +Dessa ska kunna matchas mot databasnamn som: + +```text +Alyn Borav +Angelique Lapiedra + Scarlett Lapiedra +Brenda Boop +Ilona +Eden Ivy +Angelika Fyres +``` + +Funktionen ska prioritera korrekthet framför täckning. En fil som inte kan identifieras med tillräcklig säkerhet ska lämnas för manuell inspektion. + +--- + +## 2. Grundprinciper + +Matchningen ska vara konservativ. + +Funktionen ska inte försöka automatcha varje fil. Den ska klassificera resultatet i tre huvudkategorier: + +```text +matched +ambiguous +unmatched +``` + +Betydelse: + +* `matched`: en kandidat är tillräckligt stark och tydligt bättre än övriga kandidater +* `ambiguous`: en eller flera rimliga kandidater finns, men säkerheten är inte tillräcklig +* `unmatched`: ingen rimlig kandidat kunde identifieras + +En felaktig automatisk match är allvarligare än att en fil lämnas omatchad. + +--- + +## 3. Datakällor + +Funktionen ska använda följande datakällor. + +### 3.1 Aktuella filmposter + +Från tabellen `movie`: + +```text +id +name +duration_seconds +``` + +Övriga fält kan senare användas, men krävs inte för den första versionen. + +### 3.2 Historiska filmposter + +Från tabellen `movie_history`: + +```text +movie_id +name +duration_seconds +archived_at +change_summary +``` + +Historiska längder kan användas för att identifiera att en lokal fil motsvarar en äldre version av samma film. + +### 3.3 Lokala videofiler + +För varje fil ska minst följande information läsas: + +```text +path +filename +file extension +actual duration +``` + +Den faktiska längden hämtas med `ffprobe`. + +--- + +## 4. Namnmodell + +Databasfältet `movie.name` innehåller alltid ett eller flera personnamn. + +Exempel med en person: + +```text +Alyn Borav +Ilona +Eden Ivy +``` + +Exempel med flera personer: + +```text +Angelique Lapiedra + Scarlett Lapiedra +Susanna Melo + Cherry Sweet +``` + +Plustecknet ska betraktas som separator mellan personer. + +Varje databaspost ska därför kunna representeras som: + +```text +movie name +list of person names +normalized full name +normalized person names +``` + +Exempel: + +```text +Movie name: +Angelique Lapiedra + Scarlett Lapiedra + +Persons: +- Angelique Lapiedra +- Scarlett Lapiedra + +Normalized persons: +- angeliquelapiedra +- scarlettlapiedra + +Normalized full name: +angeliquelapiedrascarlettlapiedra +``` + +--- + +## 5. Normalisering av namn + +Filnamn och databasnamn ska normaliseras innan jämförelse. + +Normaliseringen ska minst: + +1. ta bort filändelsen +2. konvertera till gemener +3. ta bort mellanslag +4. ta bort understreck +5. ta bort bindestreck +6. ta bort plustecken +7. ta bort punkter och annan interpunktion +8. normalisera diakritiska tecken +9. behålla bokstäver och siffror + +Exempel: + +```text +Alyn_Borav_AlynBorav.mp4 +→ alynboravalynborav +``` + +```text +Angelique Lapiedra + Scarlett Lapiedra +→ angeliquelapiedrascarlettlapiedra +``` + +```text +CatherineBoss.mp4 +→ catherineboss +``` + +```text +Catherine Boss +→ catherineboss +``` + +--- + +## 6. Matchning av filnamn + +### 6.1 Exakt normaliserad delsträng + +Om ett normaliserat databasnamn förekommer exakt i det normaliserade filnamnet ska detta räknas som en stark signal. + +Exempel: + +```text +Fil: +Eden_Ivy_EdenIvy_DP.mp4 + +Normaliserad fil: +edenivyedenivydp + +Databasnamn: +Eden Ivy + +Normaliserat namn: +edenivy +``` + +`edenivy` förekommer två gånger och ska ge en stark matchning. + +### 6.2 Upprepade namn + +Upprepade personnamn i filnamnet ska inte tolkas som flera personer. + +Exempel: + +```text +Vanessa_Rodriguez_VanessaRodriguez.mp4 +``` + +ska fortfarande motsvara personen: + +```text +Vanessa Rodriguez +``` + +Upprepning kan däremot stärka matchningen. + +### 6.3 Extra ord i filnamnet + +Extra ord behöver inte tas bort för att exakt delsträngsmatchning ska fungera. + +Exempel: + +```text +BrendaBoop_Interwiev_Fisting.mp4 +``` + +kan matchas mot: + +```text +Brenda Boop +``` + +eftersom det normaliserade namnet förekommer intakt i filnamnet. + +Exempel på vanliga extra ord: + +```text +DP +Group +Interview +Fisting +OralSex +TruFun67 +Version +OnBed +PissingInMouth +``` + +Dessa ska initialt behandlas som okänd extrainformation och inte som del av databasnamnet. + +### 6.4 Korta namn + +Korta namn som exempelvis: + +```text +Ilona +Mia +Eva +Ana +``` + +kräver större försiktighet eftersom de kan förekomma som delar av andra ord. + +För korta namn ska tokenbaserad matchning väga tyngre än ren delsträngsmatchning. + +### 6.5 Flera personer + +Om en databaspost innehåller flera personer ska samtliga namn kunna sökas oberoende av ordning. + +Exempel: + +```text +Angelique Lapiedra + Scarlett Lapiedra +``` + +ska kunna matcha både: + +```text +AngeliqueLapiedra_ScarlettLapiedra.mp4 +``` + +och: + +```text +ScarlettLapiedra_AngeliqueLapiedra.mp4 +``` + +Matchningen ska därför inte kräva att personerna förekommer i samma ordning som i databasen. + +### 6.6 Längsta och mest specifika kandidat + +Om flera databasnamn matchar ska den mest specifika kandidaten prioriteras. + +Exempel: + +```text +Scarlett Knight +Scarlett Knight + Anya Shidlerova +``` + +Fil: + +```text +ScarlettKnight_AnyaShidlerova.mp4 +``` + +Posten med båda personerna ska rankas högre. + +### 6.7 Exakt personmängd + +När flera kända personer identifieras i filnamnet ska databaskandidater med exakt samma personmängd prioriteras. + +Exempel: + +```text +Filnamn: +Susanna_Melo_Cherry_Sweet.mp4 + +Identifierade personer: +- Susanna Melo +- Cherry Sweet +``` + +Följande kandidat ska rankas högre: + +```text +Susanna Melo + Cherry Sweet +``` + +än: + +```text +Susanna Melo +``` + +--- + +## 7. Stavfel och fuzzy matching + +Filnamn kan innehålla stavfel. + +Exempel: + +```text +SusannaMello +Susamma_Melo +``` + +kan sannolikt motsvara: + +```text +Susanna Melo +``` + +Fuzzy matching får användas för att skapa kandidater, men ska vara konservativt. + +I den första versionen gäller: + +* fuzzy matching får inte ensam leda till automatisk match +* fuzzy-resultat ska normalt klassificeras som `ambiguous` +* kandidat och orsak ska visas för manuell bedömning + +Exempel: + +```text +Filename: +SusannaMello.mp4 + +Candidate: +Susanna Melo + +Status: +ambiguous + +Reason: +fuzzy name match +``` + +Verifierade stavningsvarianter kan senare sparas som alias. + +Ett alias ska endast registreras efter manuell bekräftelse. + +--- + +## 8. Längd som sekundär signal + +Videons faktiska längd ska användas för att stärka eller försvaga redan rimliga namnkandidater. + +Längden ska inte ensam kunna identifiera en film. + +Exempel: + +```text +File: +Alyn_Borav_AlynBorav.mp4 + +File duration: +43:00 +``` + +Kandidater: + +```text +Alyn Borav +Site duration: 43:05 +Difference: 5 seconds +``` + +```text +Alyn Borav + Cherry Sweet +Site duration: 1:54:00 +Difference: 71 minutes +``` + +Den första kandidaten ska då få betydligt högre poäng. + +### 8.1 Absolut och relativ skillnad + +Både absolut skillnad och procentuell skillnad ska beräknas. + +```text +absolute difference = abs(file duration - site duration) +relative difference = absolute difference / site duration +``` + +### 8.2 Initial poängmodell för längd + +En första approximation kan 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 +``` + +Exakt poängsättning ska kunna justeras efter testning mot verkliga filer. + +### 8.3 Längd får inte rädda en dålig namnmatch + +Exempel: + +```text +unknown_video.mp4 +``` + +ska inte automatchas till en film bara för att längden råkar vara nästan identisk. + +Längd används endast för att diskriminera mellan kandidater som redan har en rimlig namnmatchning. + +### 8.4 Klippta och förlängda versioner + +En större längdskillnad ska inte automatiskt innebära att kandidaten är fel. + +Filen kan vara: + +```text +truncated +extended +edited +missing intro +missing ending +``` + +En stark namnmatchning kombinerad med tydlig längdavvikelse ska normalt ge: + +```text +ambiguous +``` + +eller en särskild versionsklassificering, inte automatiskt `unmatched`. + +--- + +## 9. Historiska längder + +Matchningen ska kunna jämföra filens längd mot både aktuell och historisk sitelängd. + +Exempel: + +```text +Current site duration: 63:05 +Historical duration: 43:05 +Local file duration: 43:00 +``` + +Möjlig slutsats: + +```text +Filmen matchar sannolikt rätt databaspost men motsvarar en äldre version. +``` + +Möjliga versionsklassificeringar: + +```text +current_version_match +historical_version_match +possible_truncated_version +possible_extended_version +duration_mismatch +unknown_version +``` + +Historisk längd ska vara en stödjande signal och inte ensam avgöra filmidentiteten. + +--- + +## 10. Kandidatpoäng + +Varje databaspost ska kunna få en sammanlagd poäng baserad på flera signaler. + +Exempel på positiva signaler: + +```text +exakt normaliserat fullständigt namn +samtliga personnamn hittade +exakt personmängd +namnet förekommer flera gånger +längden ligger mycket nära aktuell sitelängd +längden ligger mycket nära historisk sitelängd +stor marginal till kandidat nummer två +``` + +Exempel på negativa signaler: + +```text +bara en del av namnet hittades +fuzzy matching krävdes +filnamnet innehåller ytterligare kända personer +databasposten förväntar flera personer men endast en hittas +stor skillnad i längd +kort och osäker namnträff +flera kandidater har nästan samma poäng +``` + +Poängmodellen ska vara förklarbar. Resultatet ska visa vilka signaler som påverkade poängen. + +--- + +## 11. Säkerhetskrav för automatisk matchning + +En fil får klassificeras som `matched` endast om: + +1. bästa kandidaten uppnår ett fastställt minimikrav +2. kandidaten bygger på en tillräckligt stark namnmatchning +3. kandidaten ligger tydligt före näst bästa kandidat +4. inga motstridiga personsignaler finns +5. eventuell fuzzy matching inte är den enda avgörande signalen + +Exempel på säker match: + +```text +Candidate 1: 170 +Candidate 2: 45 +Margin: 125 +``` + +Exempel på osäker match: + +```text +Candidate 1: 92 +Candidate 2: 87 +Margin: 5 +``` + +Det senare ska klassificeras som: + +```text +ambiguous +``` + +även om förstaplatsen har relativt hög poäng. + +--- + +## 12. Manuell inspektion + +Filer som klassificeras som `ambiguous` eller `unmatched` ska kunna granskas manuellt. + +För `ambiguous` ska rapporten visa de bästa kandidaterna. + +Exempel: + +```text +Filename: +SusannaMello_Cherry.mp4 + +Status: +ambiguous + +Candidate 1: +Susanna Melo + Cherry Sweet +Score: 91 + +Candidate 2: +Susanna Melo +Score: 86 + +Reasons: +- fuzzy match for Susanna Melo +- partial match for Cherry Sweet +- candidates have similar scores +``` + +Manuell granskning ska kunna resultera i: + +```text +confirmed match +rejected candidates +verified alias +ignored file +``` + +Manuella beslut ska kunna sparas senare, men första versionen behöver endast rapportera kandidater. + +--- + +## 13. Första versionens omfattning + +Den första versionen ska vara helt skrivskyddad. + +Den får: + +* läsa filer från en katalog +* läsa poster från SQLite-databasen +* läsa historiska längder +* köra `ffprobe` +* normalisera filnamn +* rangordna kandidater +* skriva rapporter + +Den får inte: + +* byta namn på filer +* flytta filer +* radera filer +* ändra databasen +* automatiskt registrera alias +* permanent koppla filer till filmer + +--- + +## 14. Förväntat kommando + +Scriptet finns i WCX-collection som `scripts/match_filenames.py` och kräver +alltid ett explicit `--database`-argument. + +Exempel: + +```bash +scripts/match_filenames.py /path/to/video/files \ + --database /storage/disk1/WCX/database/wcx.db +``` + +Alternativt stöd för en textfil med filnamn: + +```bash +scripts/match_filenames.py \ + --database /storage/disk1/WCX/database/wcx.db \ + --file-list filenames.txt +``` + +Möjliga framtida argument: + +```text +--recursive +--limit +--output-directory +--min-score +--min-margin +--debug +--no-ffprobe +``` + +--- + +## 15. Rapportformat + +Resultatet bör delas upp i minst tre rapporter: + +```text +matched.csv +ambiguous.csv +unmatched.csv +``` + +### 15.1 matched.csv + +Föreslagna kolumner: + +```text +path +filename +file_duration_seconds +movie_id +movie_name +site_duration_seconds +matched_duration_seconds +version_classification +score +score_margin +match_reason +``` + +### 15.2 ambiguous.csv + +Föreslagna kolumner: + +```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 +``` + +### 15.3 unmatched.csv + +Föreslagna kolumner: + +```text +path +filename +file_duration_seconds +best_candidate +best_score +reason +``` + +--- + +## 16. Konsolutskrift + +En läsbar konsolrapport ska också kunna visas. + +Exempel: + +```text +Alyn_Borav_AlynBorav.mp4 +File duration: 43:00 + +1. Alyn Borav + Name score: 120 + Duration score: 50 + Total: 170 + Duration diff: 5 sec + +2. Alyn Borav + Cherry Sweet + Name score: 65 + Duration score: -30 + Total: 35 + Duration diff: 71 min + +Result: matched +Version: current_version_match +``` + +Exempel på osäker fil: + +```text +SusannaMello_Cherry.mp4 +File duration: 42:58 + +1. Susanna Melo + Cherry Sweet + Total: 91 + +2. Susanna Melo + Total: 86 + +Result: ambiguous +Reason: fuzzy match and insufficient score margin +``` + +--- + +## 17. Prestanda + +Filnamnsmatchningen ska kunna genomföras utan att läsa videofilernas innehåll. + +`ffprobe` ska endast läsa metadata och ska inte omkoda eller spela upp videon. + +Första versionen behöver inte använda: + +* fullständiga filhashar +* perceptuella videofingeravtryck +* bildextraktion +* maskininlärning +* OCR från videobilder + +Sådana funktioner kan utvärderas senare för svåra fall. + +--- + +## 18. Framtida utökningar + +Möjliga senare förbättringar: + +### 18.1 Alias + +Verifierade stavningsvarianter kan sparas: + +```text +susannamello → Susanna Melo +susammamelo → Susanna Melo +``` + +Alias ska endast skapas efter manuell bekräftelse. + +### 18.2 Filtabell + +Lokala filer kan senare lagras i en tabell, exempelvis: + +```text +media_file +``` + +En film ska kunna ha flera lokala filer eftersom olika omkodningar och versioner kan förekomma. + +### 18.3 Manuella beslut + +Manuellt bekräftade matchningar ska inte behöva lösas igen. + +### 18.4 Visuella fingeravtryck + +För svåra fall kan ett perceptuellt videofingeravtryck skapas genom att: + +* extrahera bilder med intervall +* skala ned bilderna +* beräkna perceptuella hashvärden +* jämföra sekvenser av hashvärden + +Detta ligger utanför den första versionen. + +--- + +## 19. Acceptanskriterier för första versionen + +Den första versionen är godkänd när den kan: + +1. läsa alla namn och längder från databasen +2. dela flerpersonsnamn på `+` +3. normalisera databasnamn och filnamn +4. hitta exakta normaliserade namn i smutsiga filnamn +5. hantera upprepade namn +6. hantera namn utan separatorer +7. prioritera den mest specifika flerpersonsposten +8. läsa faktisk videolängd med `ffprobe` +9. jämföra mot aktuell sitelängd +10. jämföra mot historiska sitelängder +11. rangordna kandidater +12. klassificera filer som `matched`, `ambiguous` eller `unmatched` +13. lämna osäkra filer för manuell inspektion +14. skriva separata rapporter +15. inte ändra filer eller databas + +Det viktigaste kvalitetsmåttet är: + +```text +precision bland automatiskt matchade filer +``` + +Målet är nära noll felaktiga automatiska matchningar, även om det innebär att en betydande andel filer lämnas för manuell granskning.