Make full scans local-only then sync; log RESCAN and per-root progress.
This commit is contained in:
parent
49d2f8a186
commit
9168a159f7
4 changed files with 28 additions and 23 deletions
|
|
@ -7,8 +7,8 @@ WORKDIR /src
|
||||||
RUN apk add --no-cache git ca-certificates
|
RUN apk add --no-cache git ca-certificates
|
||||||
COPY node/media-node/ ./
|
COPY node/media-node/ ./
|
||||||
RUN go mod tidy \
|
RUN go mod tidy \
|
||||||
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.version=1.2.3" -o /media-node-linux-amd64 ./cmd/media-node \
|
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.version=1.2.4" -o /media-node-linux-amd64 ./cmd/media-node \
|
||||||
&& CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X main.version=1.2.3" -o /media-node-linux-arm64 ./cmd/media-node
|
&& CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-s -w -X main.version=1.2.4" -o /media-node-linux-arm64 ./cmd/media-node
|
||||||
|
|
||||||
FROM base AS builder
|
FROM base AS builder
|
||||||
COPY package.json pnpm-workspace.yaml ./
|
COPY package.json pnpm-workspace.yaml ./
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
"github.com/sthmedia/media-node/internal/streaming"
|
"github.com/sthmedia/media-node/internal/streaming"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "1.2.3"
|
var version = "1.2.4"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) < 2 {
|
if len(os.Args) < 2 {
|
||||||
|
|
|
||||||
|
|
@ -356,6 +356,7 @@ func (c *Client) handleMessage(msgType string, payload json.RawMessage) {
|
||||||
log.Printf("Playback session revoked: %s", p.SessionID)
|
log.Printf("Playback session revoked: %s", p.SessionID)
|
||||||
}
|
}
|
||||||
case "RESCAN":
|
case "RESCAN":
|
||||||
|
log.Println("RESCAN requested by master")
|
||||||
go c.scanner.FullScan()
|
go c.scanner.FullScan()
|
||||||
case "FULL_LIBRARY_SYNC":
|
case "FULL_LIBRARY_SYNC":
|
||||||
go c.sendFullSync()
|
go c.sendFullSync()
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,7 @@ func (s *Scanner) FullScan() {
|
||||||
if s.scanning {
|
if s.scanning {
|
||||||
s.rescanQueued = true
|
s.rescanQueued = true
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
log.Println("Full scan already running — queued re-run after current pass")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.scanning = true
|
s.scanning = true
|
||||||
|
|
@ -258,8 +259,9 @@ func (s *Scanner) FullScan() {
|
||||||
kind = "episode"
|
kind = "episode"
|
||||||
}
|
}
|
||||||
before := len(found)
|
before := len(found)
|
||||||
s.walkRoot(root.Path, kind, root.ShelfID, found)
|
log.Printf("Scanning root %s (%s) shelf=%s ...", root.Path, kind, root.ShelfID)
|
||||||
log.Printf("Scan root %s (%s) shelf=%s → +%d files", root.Path, kind, root.ShelfID, len(found)-before)
|
s.walkRoot(root.Path, kind, root.ShelfID, found, false)
|
||||||
|
log.Printf("Scan root done %s → +%d files (total %d)", root.Path, len(found)-before, len(found))
|
||||||
}
|
}
|
||||||
|
|
||||||
if aborted {
|
if aborted {
|
||||||
|
|
@ -271,31 +273,29 @@ func (s *Scanner) FullScan() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Local prune only — Master learns removals via the full library sync that follows.
|
||||||
existing, _ := s.store.AllFiles()
|
existing, _ := s.store.AllFiles()
|
||||||
|
removed := 0
|
||||||
for _, f := range existing {
|
for _, f := range existing {
|
||||||
if !found[f.Path] {
|
if !found[f.Path] {
|
||||||
rev, _ := s.store.NextRevision()
|
|
||||||
event := LibraryEvent{
|
|
||||||
Type: "FILE_REMOVED",
|
|
||||||
NodeRevision: rev,
|
|
||||||
File: fileToInfo(f),
|
|
||||||
}
|
|
||||||
_ = s.store.DeleteFile(f.LocalFileID)
|
_ = s.store.DeleteFile(f.LocalFileID)
|
||||||
s.onEvents([]LibraryEvent{event})
|
removed++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Printf("Full scan completed (%d files)", len(found))
|
log.Printf("Full scan completed (%d files, %d removed locally)", len(found), removed)
|
||||||
|
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
if s.rescanQueued {
|
||||||
s.scanning = false
|
s.scanning = false
|
||||||
s.status = "idle"
|
s.status = "idle"
|
||||||
again := s.rescanQueued
|
|
||||||
doneHook := s.onScanComplete
|
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
if again {
|
|
||||||
log.Println("Re-running full scan after path/config change...")
|
log.Println("Re-running full scan after path/config change...")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
s.scanning = false
|
||||||
|
s.status = "idle"
|
||||||
|
doneHook := s.onScanComplete
|
||||||
|
s.mu.Unlock()
|
||||||
if doneHook != nil {
|
if doneHook != nil {
|
||||||
go doneHook()
|
go doneHook()
|
||||||
}
|
}
|
||||||
|
|
@ -303,7 +303,7 @@ func (s *Scanner) FullScan() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) walkRoot(dir, mediaType, shelfID string, found map[string]bool) {
|
func (s *Scanner) walkRoot(dir, mediaType, shelfID string, found map[string]bool, emitEvents bool) {
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -315,7 +315,7 @@ func (s *Scanner) walkRoot(dir, mediaType, shelfID string, found map[string]bool
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
found[path] = true
|
found[path] = true
|
||||||
s.indexFile(path, info, "FILE_UPDATED", mediaType, shelfID)
|
s.indexFile(path, info, "FILE_UPDATED", mediaType, shelfID, emitEvents)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -425,7 +425,7 @@ func (s *Scanner) runWatchSession() {
|
||||||
info, err := os.Stat(path)
|
info, err := os.Stat(path)
|
||||||
if err == nil && !info.IsDir() && isVideo(path) {
|
if err == nil && !info.IsDir() && isVideo(path) {
|
||||||
kind, shelf := s.detectRootMeta(path, rootType, rootShelf)
|
kind, shelf := s.detectRootMeta(path, rootType, rootShelf)
|
||||||
s.indexFile(path, info, "FILE_ADDED", kind, shelf)
|
s.indexFile(path, info, "FILE_ADDED", kind, shelf, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pending = make(map[string]struct{})
|
pending = make(map[string]struct{})
|
||||||
|
|
@ -474,7 +474,7 @@ func (s *Scanner) detectRootType(path string, rootType map[string]string) string
|
||||||
return detectMediaType(path)
|
return detectMediaType(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scanner) indexFile(path string, info os.FileInfo, eventType, preferredType, shelfID string) {
|
func (s *Scanner) indexFile(path string, info os.FileInfo, eventType, preferredType, shelfID string, emitEvents bool) {
|
||||||
mediaType := preferredType
|
mediaType := preferredType
|
||||||
if mediaType == "" {
|
if mediaType == "" {
|
||||||
mediaType = detectMediaType(path)
|
mediaType = detectMediaType(path)
|
||||||
|
|
@ -504,6 +504,10 @@ func (s *Scanner) indexFile(path string, info os.FileInfo, eventType, preferredT
|
||||||
}
|
}
|
||||||
_ = s.store.UpsertFile(lf)
|
_ = s.store.UpsertFile(lf)
|
||||||
|
|
||||||
|
if !emitEvents {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
info2 := buildMediaInfo(lf)
|
info2 := buildMediaInfo(lf)
|
||||||
info2.ShelfID = shelfID
|
info2.ShelfID = shelfID
|
||||||
event := LibraryEvent{
|
event := LibraryEvent{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue