0.2.64 update
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
package credits
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Identifying a media *version*, not an item.
|
||||
//
|
||||
// An Emby item id survives a file being replaced, which is exactly the case this subsystem
|
||||
// must not get wrong: Sonarr swapping a 720p rip for a 1080p one leaves the id alone, and a
|
||||
// marker measured against the old file would put Skip Credits somewhere arbitrary in the new
|
||||
// one. Keying the marker on item *and* fingerprint means a replaced file simply stops
|
||||
// matching — the episode becomes a candidate again, and nothing had to notice the swap or
|
||||
// run an invalidation pass to make that happen.
|
||||
|
||||
// MediaVersion is what a fingerprint is computed from. Every field is optional except the
|
||||
// item id: a source that can only offer runtime still produces a usable fingerprint, it is
|
||||
// just a coarser one.
|
||||
type MediaVersion struct {
|
||||
ItemID string
|
||||
RuntimeMs int64
|
||||
SizeBytes int64
|
||||
ModifiedAt time.Time
|
||||
// ETag is Emby's own version token where it offers one. It is the strongest field here
|
||||
// because it changes for reasons the other three can miss — a remux to the same length
|
||||
// and near-enough the same size.
|
||||
ETag string
|
||||
}
|
||||
|
||||
// Fingerprint is a short, stable digest of a media version.
|
||||
//
|
||||
// Truncated to sixteen bytes because it is an equality key rather than a security claim: it
|
||||
// is only ever compared against another fingerprint of the same item, and a full digest
|
||||
// would double the width of the busiest index in the schema for no gain.
|
||||
func Fingerprint(version MediaVersion) string {
|
||||
parts := []string{
|
||||
strings.TrimSpace(version.ItemID),
|
||||
strconv.FormatInt(version.RuntimeMs, 10),
|
||||
strconv.FormatInt(version.SizeBytes, 10),
|
||||
strings.TrimSpace(version.ETag),
|
||||
}
|
||||
if !version.ModifiedAt.IsZero() {
|
||||
// Second resolution. Filesystems and Emby disagree about sub-second timestamps often
|
||||
// enough that finer granularity would invalidate markers on files nothing had
|
||||
// touched, which is the expensive direction to be wrong in.
|
||||
parts = append(parts, strconv.FormatInt(version.ModifiedAt.UTC().Unix(), 10))
|
||||
}
|
||||
sum := sha256.Sum256([]byte(strings.Join(parts, "|")))
|
||||
return hex.EncodeToString(sum[:16])
|
||||
}
|
||||
|
||||
// Weak reports a fingerprint built from too little to detect a file swap.
|
||||
//
|
||||
// Runtime alone does not distinguish a re-encode of the same episode, so a marker stored
|
||||
// against a weak fingerprint is one that could survive a replacement it should not have. The
|
||||
// service refuses to store those rather than storing a marker it cannot invalidate — the
|
||||
// alternative is a wrong Skip Credits position that nothing will ever correct.
|
||||
func (v MediaVersion) Weak() bool {
|
||||
return v.SizeBytes <= 0 && strings.TrimSpace(v.ETag) == "" && v.ModifiedAt.IsZero()
|
||||
}
|
||||
Reference in New Issue
Block a user