This commit is contained in:
@@ -5,7 +5,7 @@ import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from .config import CHANNELS_FILE, DATA_ROOT
|
||||
from .config import CHANNELS_FILE, DATA_ROOT, MOVIES_ROOT, SERIES_ROOT
|
||||
|
||||
CACHE_DIR = DATA_ROOT / "cache"
|
||||
|
||||
@@ -145,6 +145,10 @@ class CacheManager:
|
||||
safe_id = "".join(c if c.isalnum() or c in "-_" else "_" for c in channel_id)
|
||||
return self._cache_dir / f"playlist_{safe_id}.json"
|
||||
|
||||
def _schedule_cache_path(self, channel_id: str) -> Path:
|
||||
safe_id = "".join(c if c.isalnum() or c in "-_" else "_" for c in channel_id)
|
||||
return self._cache_dir / f"schedule_{safe_id}.json"
|
||||
|
||||
def get_playlist(self, channel_id: str) -> list[tuple[str, str]] | None:
|
||||
"""
|
||||
Return cached playlist data as [(display_name, path_str), ...] if valid.
|
||||
@@ -178,3 +182,81 @@ class CacheManager:
|
||||
self._ensure_hash_stored(current)
|
||||
except OSError as e:
|
||||
logger.warning("Could not write playlist cache for %s: %s", channel_id, e)
|
||||
|
||||
def get_schedule(self, channel_id: str) -> tuple[list[Path], list[float], list[dict]] | None:
|
||||
"""
|
||||
Return cached schedule (paths, durations, path_configs) if valid.
|
||||
"""
|
||||
self.invalidate_if_needed()
|
||||
current = get_channels_hash(self._channels_file)
|
||||
if current is None:
|
||||
return None
|
||||
path = self._schedule_cache_path(channel_id)
|
||||
if not path.exists():
|
||||
return None
|
||||
stored = self._get_stored_hash()
|
||||
if stored != current:
|
||||
return None
|
||||
try:
|
||||
data = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError, TypeError) as e:
|
||||
logger.warning("Could not read schedule cache for %s: %s", channel_id, e)
|
||||
return None
|
||||
path_strs = data.get("path_strs")
|
||||
durations = data.get("durations")
|
||||
path_configs = data.get("path_configs")
|
||||
if not path_strs or not durations or len(path_strs) != len(durations):
|
||||
return None
|
||||
paths = []
|
||||
for ps in path_strs:
|
||||
if not isinstance(ps, str) or ".." in ps:
|
||||
return None
|
||||
if ps.startswith("movies/"):
|
||||
p = MOVIES_ROOT / ps[7:]
|
||||
elif ps.startswith("series/"):
|
||||
p = SERIES_ROOT / ps[7:]
|
||||
else:
|
||||
return None
|
||||
if not p.exists():
|
||||
return None
|
||||
paths.append(p)
|
||||
if not path_configs or len(path_configs) != len(paths):
|
||||
return None
|
||||
return (paths, [float(d) for d in durations], path_configs)
|
||||
|
||||
def set_schedule(
|
||||
self,
|
||||
channel_id: str,
|
||||
paths: list[Path],
|
||||
durations: list[float],
|
||||
path_configs: list[dict],
|
||||
) -> None:
|
||||
"""Save schedule to cache."""
|
||||
current = get_channels_hash(self._channels_file)
|
||||
if current is None or not self._ensure_cache_dir():
|
||||
return
|
||||
path_strs = []
|
||||
for p in paths:
|
||||
try:
|
||||
if MOVIES_ROOT in p.parents:
|
||||
path_strs.append("movies/" + str(p.relative_to(MOVIES_ROOT)).replace("\\", "/"))
|
||||
else:
|
||||
path_strs.append("series/" + str(p.relative_to(SERIES_ROOT)).replace("\\", "/"))
|
||||
except ValueError:
|
||||
path_strs.append("movies/" + p.name)
|
||||
path = self._schedule_cache_path(channel_id)
|
||||
try:
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"path_strs": path_strs,
|
||||
"durations": durations,
|
||||
"path_configs": path_configs,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
self._ensure_hash_stored(current)
|
||||
except OSError as e:
|
||||
logger.warning("Could not write schedule cache for %s: %s", channel_id, e)
|
||||
|
||||
Reference in New Issue
Block a user