mirror of
https://github.com/zoriya/Kyoo.git
synced 2026-04-25 02:20:02 -04:00
Delete chormaprint
This commit is contained in:
parent
43a5f9a098
commit
0e70374d2c
@ -8,12 +8,6 @@ create table gocoder.fingerprints(
|
||||
end_data text not null
|
||||
);
|
||||
|
||||
create table gocoder.chapterprints(
|
||||
id serial primary key,
|
||||
data text not null
|
||||
);
|
||||
|
||||
alter table gocoder.chapters add column fingerprint_id integer references gocoder.chapterprints(id) on delete set null;
|
||||
alter table gocoder.chapters add column match_accuracy integer;
|
||||
|
||||
commit;
|
||||
|
||||
@ -45,10 +45,6 @@ func (s *MetadataService) IdentifyChapters(ctx context.Context, info *MediaInfo,
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.DeleteFingerprint(ctx, info.Id); err != nil {
|
||||
slog.WarnContext(ctx, "failed to delete fingerprint", "path", info.Path, "err", err)
|
||||
}
|
||||
|
||||
_, err = s.Database.Exec(ctx,
|
||||
`update gocoder.info set ver_fingerprint = $2 where id = $1`,
|
||||
info.Id, FingerprintVersion,
|
||||
@ -73,79 +69,6 @@ func (s *MetadataService) compareWithOther(
|
||||
return nil, fmt.Errorf("failed to get metadata for %s: %w", otherPath, err)
|
||||
}
|
||||
|
||||
hasChapterprints := false
|
||||
for _, c := range otherInfo.Chapters {
|
||||
if c.FingerprintId != nil {
|
||||
hasChapterprints = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasChapterprints {
|
||||
return s.matchByChapterprints(ctx, info, fingerprint, otherInfo)
|
||||
}
|
||||
|
||||
return s.matchByOverlap(ctx, info, fingerprint, otherInfo)
|
||||
}
|
||||
|
||||
func (s *MetadataService) matchByChapterprints(
|
||||
ctx context.Context,
|
||||
info *MediaInfo,
|
||||
fingerprint *Fingerprint,
|
||||
otherInfo *MediaInfo,
|
||||
) ([]Chapter, error) {
|
||||
var candidates []Chapter
|
||||
|
||||
for _, ch := range otherInfo.Chapters {
|
||||
if ch.FingerprintId == nil {
|
||||
continue
|
||||
}
|
||||
if ch.Type == Content {
|
||||
continue
|
||||
}
|
||||
|
||||
needle, err := s.GetChapterprint(ctx, *ch.FingerprintId)
|
||||
if err != nil {
|
||||
slog.WarnContext(ctx, "failed to get chapterprint", "chapterprintId", *ch.FingerprintId, "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fp := fingerprint.Start
|
||||
startOffset := 0.0
|
||||
if ch.Type == Credits {
|
||||
fp = fingerprint.End
|
||||
startOffset = max(info.Duration-FpEndDuration, 0)
|
||||
}
|
||||
|
||||
match, err := FpFindContain(ctx, fp, needle)
|
||||
if err != nil {
|
||||
slog.WarnContext(ctx, "failed to find chapterprint in fingerprint", "err", err)
|
||||
continue
|
||||
}
|
||||
if match == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
candidates = append(candidates, Chapter{
|
||||
Id: info.Id,
|
||||
StartTime: float32(startOffset + match.Start),
|
||||
EndTime: float32(startOffset + match.Start + match.Duration),
|
||||
Name: "",
|
||||
Type: ch.Type,
|
||||
FingerprintId: ch.FingerprintId,
|
||||
MatchAccuracy: new(int32(match.Accuracy)),
|
||||
})
|
||||
}
|
||||
|
||||
return candidates, nil
|
||||
}
|
||||
|
||||
func (s *MetadataService) matchByOverlap(
|
||||
ctx context.Context,
|
||||
info *MediaInfo,
|
||||
fingerprint *Fingerprint,
|
||||
otherInfo *MediaInfo,
|
||||
) ([]Chapter, error) {
|
||||
otherPrint, err := s.ComputeFingerprint(ctx, otherInfo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compute fingerprint for %s: %w", otherInfo.Path, err)
|
||||
@ -173,7 +96,6 @@ func (s *MetadataService) matchByOverlap(
|
||||
EndTime: float32(intro.StartFirst + intro.Duration),
|
||||
Name: "",
|
||||
Type: Intro,
|
||||
Fingerprint: fingerprint.Start,
|
||||
MatchAccuracy: new(int32(intro.Accuracy)),
|
||||
})
|
||||
}
|
||||
@ -182,14 +104,12 @@ func (s *MetadataService) matchByOverlap(
|
||||
endOffset := info.Duration - samplesToSec(len(fingerprint.End))
|
||||
slog.InfoContext(ctx, "Identified credits", "start", endOffset+cred.StartFirst, "duration", cred.Duration, "end_offset", endOffset)
|
||||
candidates = append(candidates, Chapter{
|
||||
Id: info.Id,
|
||||
StartTime: float32(endOffset + cred.StartFirst),
|
||||
EndTime: float32(endOffset + cred.StartFirst + cred.Duration),
|
||||
Name: "",
|
||||
Type: Credits,
|
||||
Fingerprint: fingerprint.End,
|
||||
FingerprintOffset: endOffset,
|
||||
MatchAccuracy: new(int32(cred.Accuracy)),
|
||||
Id: info.Id,
|
||||
StartTime: float32(endOffset + cred.StartFirst),
|
||||
EndTime: float32(endOffset + cred.StartFirst + cred.Duration),
|
||||
Name: "",
|
||||
Type: Credits,
|
||||
MatchAccuracy: new(int32(cred.Accuracy)),
|
||||
})
|
||||
}
|
||||
|
||||
@ -216,9 +136,6 @@ func mergeChapters(info *MediaInfo, candidates []Chapter) []Chapter {
|
||||
if chapters[i].Type == Content {
|
||||
chapters[i].Type = cand.Type
|
||||
}
|
||||
chapters[i].Fingerprint = cand.Fingerprint
|
||||
chapters[i].FingerprintOffset = cand.FingerprintOffset
|
||||
chapters[i].FingerprintId = cand.FingerprintId
|
||||
chapters[i].MatchAccuracy = cand.MatchAccuracy
|
||||
merged = true
|
||||
break
|
||||
@ -238,9 +155,6 @@ func mergeChapters(info *MediaInfo, candidates []Chapter) []Chapter {
|
||||
EndTime: cand.EndTime,
|
||||
Name: "",
|
||||
Type: cand.Type,
|
||||
Fingerprint: cand.Fingerprint,
|
||||
FingerprintOffset: cand.FingerprintOffset,
|
||||
FingerprintId: cand.FingerprintId,
|
||||
MatchAccuracy: cand.MatchAccuracy,
|
||||
}, info.Duration)
|
||||
}
|
||||
@ -326,34 +240,10 @@ func (s *MetadataService) saveChapters(ctx context.Context, infoId int32, chapte
|
||||
}
|
||||
|
||||
for _, c := range chapters {
|
||||
if c.FingerprintId == nil && c.Fingerprint != nil {
|
||||
fp, err := ExtractSegment(
|
||||
c.Fingerprint,
|
||||
float64(c.StartTime)-c.FingerprintOffset,
|
||||
float64(c.EndTime)-c.FingerprintOffset,
|
||||
)
|
||||
slog.InfoContext(
|
||||
ctx,
|
||||
"extracting chapterprint",
|
||||
"start", float64(c.StartTime)-c.FingerprintOffset,
|
||||
"end", float64(c.EndTime)-c.FingerprintOffset,
|
||||
)
|
||||
if err != nil {
|
||||
slog.WarnContext(ctx, "failed to extract chapter segment", "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
fpId, err := s.StoreChapterprint(ctx, fp)
|
||||
if err != nil {
|
||||
slog.WarnContext(ctx, "failed to store intro chapterprint", "err", err)
|
||||
} else {
|
||||
c.FingerprintId = new(fpId)
|
||||
}
|
||||
}
|
||||
_, err = tx.Exec(ctx,
|
||||
`insert into gocoder.chapters(id, start_time, end_time, name, type, fingerprint_id, match_accuracy)
|
||||
values ($1, $2, $3, $4, $5, $6, $7)`,
|
||||
infoId, c.StartTime, c.EndTime, c.Name, c.Type, c.FingerprintId, c.MatchAccuracy,
|
||||
`insert into gocoder.chapters(id, start_time, end_time, name, type, match_accuracy)
|
||||
values ($1, $2, $3, $4, $5, $6)`,
|
||||
infoId, c.StartTime, c.EndTime, c.Name, c.Type, c.MatchAccuracy,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert chapter: %w", err)
|
||||
|
||||
@ -154,37 +154,3 @@ func (s *MetadataService) DeleteFingerprint(ctx context.Context, infoID int32) e
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *MetadataService) GetChapterprint(ctx context.Context, id int32) ([]uint32, error) {
|
||||
var data string
|
||||
err := s.Database.QueryRow(ctx,
|
||||
`select data from gocoder.chapterprints where id = $1`,
|
||||
id,
|
||||
).Scan(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get chapterprint %d: %w", id, err)
|
||||
}
|
||||
|
||||
fingerprint, err := DecompressFingerprint(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decompress chapterprint %d: %w", id, err)
|
||||
}
|
||||
return fingerprint, nil
|
||||
}
|
||||
|
||||
func (s *MetadataService) StoreChapterprint(ctx context.Context, fp []uint32) (int32, error) {
|
||||
data, err := CompressFingerprint(fp)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to compress chapterprint: %w", err)
|
||||
}
|
||||
|
||||
var id int32
|
||||
err = s.Database.QueryRow(ctx,
|
||||
`insert into gocoder.chapterprints(data) values ($1) returning id`,
|
||||
data,
|
||||
).Scan(&id)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to store chapterprint: %w", err)
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
@ -242,22 +242,3 @@ func FpFindOverlap(ctx context.Context, fp1 []uint32, fp2 []uint32) ([]Overlap,
|
||||
runs := findMatchingRuns(a1, a2, s1, s2)
|
||||
return runs, nil
|
||||
}
|
||||
|
||||
func FpFindContain(ctx context.Context, haystack []uint32, needle []uint32) (*Match, error) {
|
||||
offset := findBestOffset(ctx, haystack, needle)
|
||||
if offset == nil || *offset < 0 || *offset+len(needle) < len(haystack) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
corr := segmentCorrelation(haystack[*offset:*offset+len(needle)], needle)
|
||||
if corr < MatchThreshold {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
accuracy := min(int(corr*100), 100)
|
||||
return &Match{
|
||||
Start: samplesToSec(*offset),
|
||||
Duration: samplesToSec(len(needle)),
|
||||
Accuracy: accuracy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -75,22 +75,3 @@ func DecompressFingerprint(compressed string) ([]uint32, error) {
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func ExtractSegment(fp []uint32, startSec, endSec float64) ([]uint32, error) {
|
||||
startIdx := secToSamples(startSec)
|
||||
endIdx := secToSamples(endSec)
|
||||
|
||||
if startIdx < 0 {
|
||||
startIdx = 0
|
||||
}
|
||||
if endIdx > len(fp) {
|
||||
endIdx = len(fp)
|
||||
}
|
||||
if startIdx >= endIdx {
|
||||
return nil, fmt.Errorf("invalid segment range: %f-%f", startSec, endSec)
|
||||
}
|
||||
|
||||
segment := make([]uint32, endIdx-startIdx)
|
||||
copy(segment, fp[startIdx:endIdx])
|
||||
return segment, nil
|
||||
}
|
||||
|
||||
@ -155,12 +155,6 @@ type Chapter struct {
|
||||
Name string `json:"name" db:"name"`
|
||||
/// The type value is used to mark special chapters (opening/credits...)
|
||||
Type ChapterType `json:"type" db:"type"`
|
||||
/// Reference to the chapterprint used for fingerprint matching.
|
||||
FingerprintId *int32 `json:"-" db:"fingerprint_id"`
|
||||
/// Only used internally, never fetched from db.
|
||||
Fingerprint []uint32 `json:"-" db:"-"`
|
||||
/// Only used internally, never fetched from db
|
||||
FingerprintOffset float64 `json:"-" db:"-"`
|
||||
/// Accuracy of the fingerprint match (0-100).
|
||||
MatchAccuracy *int32 `json:"matchAccuracy,omitempty" db:"match_accuracy"`
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user