Small fixes & error handling

This commit is contained in:
Zoe Roux 2025-05-12 13:03:36 +02:00
parent f8331c083a
commit decb09ecca
No known key found for this signature in database
3 changed files with 50 additions and 43 deletions

View File

@ -18,7 +18,7 @@ class KyooClient:
print("Missing environment variable 'KYOO_APIKEY'.") print("Missing environment variable 'KYOO_APIKEY'.")
exit(2) exit(2)
self._client = ClientSession( self._client = ClientSession(
base_url=os.environ.get("KYOO_URL", "http://api:3567/api"), base_url=os.environ.get("KYOO_URL", "http://api:3567/api") + "/",
headers={ headers={
"User-Agent": "kyoo scanner v5", "User-Agent": "kyoo scanner v5",
"X-API-KEY": api_key, "X-API-KEY": api_key,
@ -37,7 +37,7 @@ class KyooClient:
await self._client.close() await self._client.close()
async def get_videos_info(self) -> VideoInfo: async def get_videos_info(self) -> VideoInfo:
async with self._client.get("/videos") as r: async with self._client.get("videos") as r:
r.raise_for_status() r.raise_for_status()
return VideoInfo(**await r.json()) return VideoInfo(**await r.json())

View File

@ -39,56 +39,63 @@ class Scanner:
logger.info("Starting scan at %s. This may take some time...", path) logger.info("Starting scan at %s. This may take some time...", path)
if self._ignore_pattern: if self._ignore_pattern:
logger.info(f"Applying ignore pattern: {self._ignore_pattern}") logger.info(f"Applying ignore pattern: {self._ignore_pattern}")
videos = self.walk_fs(path) try:
videos = self.walk_fs(path)
self._info = await self._client.get_videos_info() self._info = await self._client.get_videos_info()
# TODO: handle unmatched # TODO: handle unmatched
to_register = videos - self._info.paths to_register = videos - self._info.paths
to_delete = self._info.paths - videos if remove_deleted else set() to_delete = self._info.paths - videos if remove_deleted else set()
if ( if (
not any(to_register) not any(to_register)
and any(to_delete) and any(to_delete)
and len(to_delete) == len(self._info.paths) and len(to_delete) == len(self._info.paths)
): ):
logger.warning("All video files are unavailable. Check your disks.") logger.warning("All video files are unavailable. Check your disks.")
return return
# delete stale files before creating new ones to prevent potential conflicts # delete stale files before creating new ones to prevent potential conflicts
if to_delete: if to_delete:
logger.info("Removing %d stale files.", len(to_delete)) logger.info("Removing %d stale files.", len(to_delete))
await self._client.delete_videos(to_delete) await self._client.delete_videos(to_delete)
if to_register: if to_register:
logger.info("Found %d new files to register.", len(to_register)) logger.info("Found %d new files to register.", len(to_register))
await self._register(to_register) await self._register(to_register)
logger.info("Scan finished for %s.", path) logger.info("Scan finished for %s.", path)
except Exception as e:
logger.error("Unexpected error while running scan.", exc_info=e)
async def monitor(self): async def monitor(self):
logger.info(f"Watching for new files in {self._root_path}")
async for changes in awatch(self._root_path, ignore_permission_denied=True): async for changes in awatch(self._root_path, ignore_permission_denied=True):
for event, file in changes: try:
if not isdir(file) and not is_video(file): for event, file in changes:
continue if not isdir(file) and not is_video(file):
if ( continue
self._ignore_pattern and self._ignore_pattern.match(file) if (
) or is_ignored_path(file): self._ignore_pattern and self._ignore_pattern.match(file)
logger.info("Ignoring event %s for file %s", event, file) ) or is_ignored_path(file):
continue logger.info("Ignoring event %s for file %s", event, file)
continue
match event: match event:
case Change.added if isdir(file): case Change.added if isdir(file):
logger.info("New dir found: %s", file) logger.info("New dir found: %s", file)
await self.scan(file) await self.scan(file)
case Change.added: case Change.added:
logger.info("New video found: %s", file) logger.info("New video found: %s", file)
await self._register([file]) await self._register([file])
case Change.deleted: case Change.deleted:
logger.info("Delete video at: %s", file) logger.info("Delete video at: %s", file)
await self._client.delete_videos([file]) await self._client.delete_videos([file])
case Change.modified: case Change.modified:
pass pass
except Exception as e:
logger.error("Unexpected error while monitoring files.", exc_info=e)
async def _register(self, videos: list[str] | set[str]): async def _register(self, videos: list[str] | set[str]):
# TODO: we should probably chunk those # TODO: we should probably chunk those

View File

@ -31,7 +31,7 @@ class TheMovieDatabase(Provider):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self._client = ClientSession( self._client = ClientSession(
base_url="https://api.themoviedb.org/3", base_url="https://api.themoviedb.org/3/",
headers={ headers={
"User-Agent": "kyoo scanner v5", "User-Agent": "kyoo scanner v5",
"X-API-KEY": ( "X-API-KEY": (