Prefer longest scan root for shelf assignment and refresh Stremio shelf manifests.

This commit is contained in:
Jos Vooges | STH 2026-08-26 02:05:13 +02:00
parent 788cfa1255
commit 8200b908e1
4 changed files with 45 additions and 11 deletions

View file

@ -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],

View file

@ -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 ./

View file

@ -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 {

View file

@ -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 {