diff --git a/apps/master-api/src/stremio/routes.ts b/apps/master-api/src/stremio/routes.ts index 34931b0..56c0108 100644 --- a/apps/master-api/src/stremio/routes.ts +++ b/apps/master-api/src/stremio/routes.ts @@ -45,7 +45,7 @@ async function buildShelfCatalogs() { orderBy: [{ sortOrder: "asc" }, { name: "asc" }], }); // Skip default Films/Series — already in BASE_CATALOGS as movies/series - return shelves + const catalogs = shelves .filter((s) => s.slug !== "films" && s.slug !== "series") .map((s) => ({ type: s.kind === "SERIES" ? "series" : "movie", @@ -53,18 +53,31 @@ async function buildShelfCatalogs() { name: s.name, extra: SEARCH_SKIP_EXTRAS, })); + // Fingerprint so Stremio refreshes when shelves are added/renamed (version cache). + const stamp = shelves + .filter((s) => s.slug !== "films" && s.slug !== "series") + .map((s) => `${s.slug}:${s.kind}:${s.updatedAt.getTime()}`) + .join("|"); + return { catalogs, stamp }; } catch { - return []; + return { catalogs: [] as Array<{ type: string; id: string; name: string; extra: typeof SEARCH_SKIP_EXTRAS }>, stamp: "" }; } } async function buildManifest(tokenId: string | null, config: Config) { const iptv = tokenId ? await buildIptvCatalogs(tokenId, config) : { catalogs: [], types: [] }; - const shelfCatalogs = await buildShelfCatalogs(); + const { catalogs: shelfCatalogs, stamp } = await buildShelfCatalogs(); const types = new Set(["movie", "series", ...iptv.types]); + // Patch version when shelves change so clients drop cached catalogs. + const shelfPatch = + stamp.length === 0 + ? "0" + : String( + [...stamp].reduce((h, c) => ((h << 5) - h + c.charCodeAt(0)) | 0, 0) >>> 0 + ).slice(-4); return { id: "com.mediacluster.library", - version: "1.6.1", + version: `1.7.${shelfPatch}`, name: "Media Cluster", description: "Privé bibliotheek + Live TV / IPTV (Xtream) met EPG", catalogs: [...BASE_CATALOGS, ...shelfCatalogs, ...iptv.catalogs], diff --git a/deploy/docker/Dockerfile.master-api b/deploy/docker/Dockerfile.master-api index 65c3e52..b908901 100644 --- a/deploy/docker/Dockerfile.master-api +++ b/deploy/docker/Dockerfile.master-api @@ -7,8 +7,8 @@ WORKDIR /src RUN apk add --no-cache git ca-certificates COPY node/media-node/ ./ RUN go mod tidy \ - && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.version=1.2.1" -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.1" -o /media-node-linux-arm64 ./cmd/media-node + && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.version=1.2.2" -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.2" -o /media-node-linux-arm64 ./cmd/media-node FROM base AS builder COPY package.json pnpm-workspace.yaml ./ diff --git a/node/media-node/cmd/media-node/main.go b/node/media-node/cmd/media-node/main.go index 76b88ae..3d7b9ad 100644 --- a/node/media-node/cmd/media-node/main.go +++ b/node/media-node/cmd/media-node/main.go @@ -24,7 +24,7 @@ import ( "github.com/sthmedia/media-node/internal/streaming" ) -var version = "1.2.1" +var version = "1.2.2" func main() { if len(os.Args) < 2 { diff --git a/node/media-node/internal/scanner/scanner.go b/node/media-node/internal/scanner/scanner.go index a0c54b9..9fab0f3 100644 --- a/node/media-node/internal/scanner/scanner.go +++ b/node/media-node/internal/scanner/scanner.go @@ -406,21 +406,37 @@ func (s *Scanner) runWatchSession() { func (s *Scanner) detectRootMeta(path string, rootType, rootShelf map[string]string) (kind, shelfID string) { clean := filepath.Clean(path) + bestRoot := "" + bestKind := "" for root, k := range rootType { if clean == root || strings.HasPrefix(clean, root+string(filepath.Separator)) { - return k, rootShelf[root] + if len(root) >= len(bestRoot) { + bestRoot = root + bestKind = k + } } } + if bestRoot != "" { + return bestKind, rootShelf[bestRoot] + } return detectMediaType(path), "" } func (s *Scanner) detectRootType(path string, rootType map[string]string) string { clean := filepath.Clean(path) + bestRoot := "" + bestKind := "" for root, kind := range rootType { if clean == root || strings.HasPrefix(clean, root+string(filepath.Separator)) { - return kind + if len(root) >= len(bestRoot) { + bestRoot = root + bestKind = kind + } } } + if bestRoot != "" { + return bestKind + } return detectMediaType(path) } @@ -503,13 +519,18 @@ func (s *Scanner) AllMediaFiles() []MediaFileInfo { func shelfForPath(path string, roots []config.MediaRoot) string { clean := filepath.Clean(path) + best := "" + bestLen := -1 for _, r := range roots { root := filepath.Clean(r.Path) if clean == root || strings.HasPrefix(clean, root+string(filepath.Separator)) { - return r.ShelfID + if len(root) > bestLen { + bestLen = len(root) + best = r.ShelfID + } } } - return "" + return best } func isVideo(path string) bool {