Move filename matching to collection project
This commit is contained in:
@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
This repository maintains a local SQLite index of WCX publications. Production code lives in `scripts/`: `wcx_sync.py` scrapes site metadata, `import_site.py` imports it into SQLite, and `update_wcx.sh` coordinates synchronization, import, and OCR. OCR is split across `process_pending_ocr.py`, `check_ocr.py`, `ocr.sh`, and `parse_ocr.py`.
|
This repository maintains a local SQLite index of WCX publications. Production code lives in `scripts/`: `wcx_sync.py` scrapes site metadata, `import_site.py` imports it into SQLite, and `update_wcx.sh` coordinates synchronization, import, and OCR. OCR is split across `process_pending_ocr.py`, `check_ocr.py`, `ocr.sh`, and `parse_ocr.py`.
|
||||||
|
|
||||||
`scripts/schema.sql` defines the database model. Generated databases belong in `database/`, while generated scraper output belongs in `import/`; both are ignored by Git. Historical source data is stored in `migration/`. Matching requirements and design notes live in `docs/`. The main executable test/diagnostic script is `scripts/test_duration_matching.py`.
|
`scripts/schema.sql` defines the database model. Generated databases belong in `database/`, while generated scraper output belongs in `import/`; both are ignored by Git. Historical source data is stored in `migration/`. Database design notes live in `docs/`. The main executable test/diagnostic script is `scripts/test_duration_matching.py`.
|
||||||
|
|
||||||
## Architectural boundaries
|
## Architectural boundaries
|
||||||
|
|
||||||
The repository is currently combined, but it is intended to be split into a reference-data project and a file-management project. The reference-data project owns the database schema, metadata, OCR, imports, history, and aliases, and it is the sole writer to the reference database. File-management code may open that database only in strict read-only mode using SQLite `mode=ro`.
|
This repository is the reference-data project. Filename matching and `scripts/match_filenames.py` have moved to the separate `/storage/disk1/WCX-collection` repository; this repository no longer contains or runs filename matching. The reference-data project owns the database schema, metadata, OCR, imports, history, and aliases, and it is the sole writer to the reference database.
|
||||||
|
|
||||||
Local file status, paths, matching decisions, and collection status must never be stored in the reference database. `scripts/match_filenames.py` belongs to the future file-management part and should later move to the separate project. Any future file-management registry or database must be owned separately and may refer to `movie.id` as the stable external ID. Do not introduce a shared Python library or API without a concrete need.
|
WCX-collection is an external read-only consumer of the reference database and may open it only in strict read-only mode using SQLite `mode=ro`. Local file status, paths, matching decisions, and collection status must never be stored in the reference database. Any future file-management registry or database must be owned separately and may refer to `movie.id` as the stable external ID. Do not introduce a shared Python library or API without a concrete need.
|
||||||
|
|
||||||
## Build, Test, and Development Commands
|
## Build, Test, and Development Commands
|
||||||
|
|
||||||
@ -21,7 +21,6 @@ There is no build step or third-party Python package installation; scripts use P
|
|||||||
- `scripts/migrate_csv.py --dry-run` validates legacy CSV data without modifying SQLite.
|
- `scripts/migrate_csv.py --dry-run` validates legacy CSV data without modifying SQLite.
|
||||||
- `scripts/test_duration_matching.py` exercises duration-matching behavior against the configured database and media paths.
|
- `scripts/test_duration_matching.py` exercises duration-matching behavior against the configured database and media paths.
|
||||||
- `python3 -m py_compile scripts/*.py` performs a quick syntax check.
|
- `python3 -m py_compile scripts/*.py` performs a quick syntax check.
|
||||||
- `scripts/match_filenames.py /path/to/videos --recursive --debug` diagnoses filename matches; it requires `ffprobe`.
|
|
||||||
|
|
||||||
Use a copied test database for commands that can write data. Never recreate or overwrite `database/wcx.db` casually because it contains manually maintained metadata.
|
Use a copied test database for commands that can write data. Never recreate or overwrite `database/wcx.db` casually because it contains manually maintained metadata.
|
||||||
|
|
||||||
|
|||||||
@ -1,892 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
Exempel:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scripts/match_filenames.py /path/to/video/files
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternativt stöd för en textfil med filnamn:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
scripts/match_filenames.py \
|
|
||||||
--file-list filenames.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
Möjliga framtida argument:
|
|
||||||
|
|
||||||
```text
|
|
||||||
--database
|
|
||||||
--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.
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user