Renames Sources/PlumTV→TVAnarchy and PlumTVCore→TVAnarchyCore (the rename the auto-commit service couldn't stage — it git-add'd the old, now-gone paths and aborted every cycle), and commits the accumulated work: - Library: black-built index fast path (LibraryIndex + scanFromIndex) with NFS-walk fallback; incremental --add on download-complete; mtime staleness gate; loose-file series-collapse fix; determinate scan/index progress. - Cover art: keyless TVmaze cartoon-vs-live-action disambiguation (type/year). - Player: sleep timer (timed + end-of-episode); visibility-gated polling. - Home: Continue Watching cover art + live refresh; Recently Added; adult gate. - Logs: multi-line selection + copy; truncated giant tx-list errors. - Hover previews (opt-in) via black ffmpeg + scp. Also gitignores foreign project trees (governor/mcp/fleet/recommender) that sit in this directory but belong to their own repos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
45 lines
2.2 KiB
Swift
45 lines
2.2 KiB
Swift
import Foundation
|
|
|
|
/// Translates between plum-side mount paths and black-side absolute paths for the
|
|
/// same library. The library is reachable on plum under a few different mounts
|
|
/// (`~/media`, `~/_/bigdisk/_/media`) while black sees it at `/bigdisk/_/media`;
|
|
/// the scanner and the watchlog disagree on which prefix they record. When a
|
|
/// `.file` is launched on a remote (black) target it must be the black-side path,
|
|
/// not plum's mount path — that mismatch is why continue-watching silently failed.
|
|
public enum MediaPaths {
|
|
/// Black-side media root (env-overridable, matches the TS bridge default).
|
|
public static var remoteRoot: String {
|
|
ProcessInfo.processInfo.environment["BLACK_MEDIA_ROOT"] ?? "/bigdisk/_/media"
|
|
}
|
|
|
|
/// plum mount prefix → black-side absolute prefix. Longest first so
|
|
/// `~/_/bigdisk/_/media` wins over `~/_/bigdisk`.
|
|
private static var mappings: [(plum: String, remote: String)] {
|
|
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
|
return [
|
|
(home + "/_/bigdisk/_/media", remoteRoot),
|
|
(home + "/media", remoteRoot),
|
|
(home + "/_/bigdisk", "/bigdisk"),
|
|
]
|
|
}
|
|
|
|
/// plum mount path → black-side path. Unchanged if it's not under a known
|
|
/// mount (already a remote/absolute path, or something we don't manage).
|
|
public static func toRemote(_ path: String) -> String {
|
|
let p = path.hasPrefix("file://") ? String(path.dropFirst(7)) : path
|
|
for m in mappings where p.hasPrefix(m.plum) {
|
|
return m.remote + String(p.dropFirst(m.plum.count))
|
|
}
|
|
return p
|
|
}
|
|
|
|
/// black-side absolute path → plum mount path (inverse of `toRemote`). Used to
|
|
/// turn the black-built library index into local paths VLC/frame-grab can open.
|
|
/// Maps to the canonical `~/media` mount. Unchanged if not under a known root.
|
|
public static func toLocal(_ path: String) -> String {
|
|
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
|
if path.hasPrefix(remoteRoot) { return home + "/media" + String(path.dropFirst(remoteRoot.count)) }
|
|
if path.hasPrefix("/bigdisk") { return home + "/_/bigdisk" + String(path.dropFirst("/bigdisk".count)) }
|
|
return path
|
|
}
|
|
}
|