"""Path resolution utilities for Jellyfin → SSH path mapping.""" from __future__ import annotations import logging import posixpath logger = logging.getLogger(__name__) def apply_remote_path_prefix(path: str, prefix: str) -> str: """Apply an optional fallback prefix for Jellyfin->SSH path handoff.""" if not path: return path normalized_prefix = (prefix or "").strip() if not normalized_prefix: return path normalized_prefix = normalized_prefix.rstrip("/") if path == normalized_prefix or path.startswith(normalized_prefix + "/"): resolved = posixpath.normpath(path) logger.debug("Path prefix already applied path=%s prefix=%s resolved=%s", path, normalized_prefix, resolved) return resolved if path.startswith("/"): resolved = posixpath.normpath(normalized_prefix + path) logger.debug("Applied path prefix path=%s prefix=%s resolved=%s", path, normalized_prefix, resolved) return resolved resolved = posixpath.normpath(posixpath.join(normalized_prefix, path)) logger.debug("Joined path prefix path=%s prefix=%s resolved=%s", path, normalized_prefix, resolved) return resolved def map_path_to_media_root(path: str, media_root: str) -> str: """Map a Jellyfin path to the configured SSH media root when possible. If the final segment of media_root (e.g. 'media') appears in the Jellyfin path, the prefix up to that segment is replaced by media_root. """ if not path: return path normalized_root = (media_root or "").strip() if not normalized_root: return path normalized_root = posixpath.normpath(normalized_root) raw_parts = [part for part in str(path).split("/") if part] if not raw_parts: return path path_absolute = "/" + "/".join(raw_parts) if path_absolute == normalized_root or path_absolute.startswith(normalized_root + "/"): logger.debug("Path already under media root path=%s media_root=%s", path, normalized_root) return path_absolute root_anchor = posixpath.basename(normalized_root) if not root_anchor: return path if root_anchor in raw_parts: anchor_index = raw_parts.index(root_anchor) remainder_parts = raw_parts[anchor_index + 1:] resolved = posixpath.join(normalized_root, *remainder_parts) if remainder_parts else normalized_root logger.debug("Mapped path to media root path=%s media_root=%s resolved=%s", path, normalized_root, resolved) return resolved return path def resolve_remote_media_path(path: str, media_root: str, fallback_prefix: str) -> str: """Resolve Jellyfin paths to SSH-visible paths. Strategy: 1. Prefer mapping to media_root when it can anchor on the root basename. 2. If no mapping happened, apply optional fallback prefix. """ if not path: return path mapped = map_path_to_media_root(path, media_root) if mapped and mapped != path: logger.debug("Resolved media path via media root original=%s resolved=%s", path, mapped) return mapped resolved = apply_remote_path_prefix(mapped or path, fallback_prefix) logger.debug("Resolved media path via fallback original=%s resolved=%s", path, resolved) return resolved