WiP: more changes to classes to support Path

This commit is contained in:
arabcoders 2025-06-09 00:47:11 +03:00
parent 6a9beea89e
commit b1bc399a0c
6 changed files with 46 additions and 46 deletions

View file

@ -47,6 +47,7 @@ from .Utils import (
get_file_sidecar, get_file_sidecar,
get_files, get_files,
get_mime_type, get_mime_type,
init_class,
read_logfile, read_logfile,
validate_url, validate_url,
validate_uuid, validate_uuid,
@ -914,7 +915,7 @@ class HttpAPI(Common):
status=web.HTTPBadRequest.status_code, status=web.HTTPBadRequest.status_code,
) )
items.append(Condition(**item)) items.append(init_class(Condition, item))
try: try:
items = cls.save(items=items).load().get_all() items = cls.save(items=items).load().get_all()
except Exception as e: except Exception as e:

View file

@ -6,6 +6,7 @@ import os
import shlex import shlex
import time import time
from datetime import UTC, datetime from datetime import UTC, datetime
from pathlib import Path
import anyio import anyio
import socketio import socketio
@ -289,13 +290,17 @@ class HttpSocket(Common):
manual_archive = self.config.manual_archive manual_archive = self.config.manual_archive
if manual_archive: if manual_archive:
manual_archive = Path(manual_archive)
if not manual_archive.exists():
manual_archive.touch(exist_ok=True)
previouslyArchived = False previouslyArchived = False
if os.path.exists(manual_archive): async with await anyio.open_file(manual_archive) as f:
async with await anyio.open_file(manual_archive) as f: async for line in f:
async for line in f: if idDict["archive_id"] in line:
if idDict["archive_id"] in line: previouslyArchived = True
previouslyArchived = True break
break
if not previouslyArchived: if not previouslyArchived:
async with await anyio.open_file(manual_archive, "a") as f: async with await anyio.open_file(manual_archive, "a") as f:
@ -313,9 +318,7 @@ class HttpSocket(Common):
"paused": self.queue.is_paused(), "paused": self.queue.is_paused(),
} }
# get download folder listing. data["folders"] = [folder.name for folder in Path(self.config.download_path).iterdir() if folder.is_dir()]
downloadPath: str = self.config.download_path
data["folders"] = [name for name in os.listdir(downloadPath) if os.path.isdir(os.path.join(downloadPath, name))]
await self._notify.emit(Events.INITIAL_DATA, data=data, to=sid) await self._notify.emit(Events.INITIAL_DATA, data=data, to=sid)
@ -355,10 +358,11 @@ class HttpSocket(Common):
await self.subscribe_emit(event=event, data=data) await self.subscribe_emit(event=event, data=data)
if "log_lines" == event and self.log_task is None: if "log_lines" == event and self.log_task is None:
LOG.debug("Starting log tailing task.") log_file = Path(self.config.config_path) / "logs" / "app.log"
LOG.debug(f"Starting tailing '{log_file!s}'.")
self.log_task = asyncio.create_task( self.log_task = asyncio.create_task(
tail_log( tail_log(
file=os.path.join(self.config.config_path, "logs", "app.log"), file=log_file,
emitter=emit_logs, emitter=emit_logs,
), ),
name="tail_log", name="tail_log",

View file

@ -1,10 +1,10 @@
import asyncio import asyncio
import json import json
import logging import logging
import os
from collections.abc import Awaitable from collections.abc import Awaitable
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
from pathlib import Path
from typing import Any from typing import Any
import httpx import httpx
@ -134,15 +134,15 @@ class Notification(metaclass=Singleton):
config: Config = config or Config.get_instance() config: Config = config or Config.get_instance()
self._debug = config.debug self._debug = config.debug
self._file: str = file or os.path.join(config.config_path, "notifications.json") self._file: Path = Path(file) if file else (Path(config.config_path) / "notifications.json")
self._client: httpx.AsyncClient = client or httpx.AsyncClient() self._client: httpx.AsyncClient = client or httpx.AsyncClient()
self._encoder: Encoder = encoder or Encoder() self._encoder: Encoder = encoder or Encoder()
self._version = config.version self._version = config.version
if os.path.exists(self._file): if self._file.exists():
try: try:
if "600" != oct(os.stat(self._file).st_mode)[-3:]: if "600" != self._file.stat().st_mode:
os.chmod(self._file, 0o600) self._file.chmod(0o600)
except Exception: except Exception:
pass pass
@ -184,34 +184,30 @@ class Notification(metaclass=Singleton):
Notification: The Notification instance. Notification: The Notification instance.
""" """
LOG.info(f"Saving notification targets to '{self._file}'.")
try: try:
with open(self._file, "w") as f: self._file.write_text(json.dumps([t.serialize() for t in targets], indent=4))
json.dump([t.serialize() for t in targets], fp=f, indent=4) LOG.info(f"Updated '{self._file}'.")
except Exception as e: except Exception as e:
LOG.exception(e) LOG.exception(e)
LOG.error(f"Error saving notification targets to '{self._file}'. '{e!s}'") LOG.error(f"Error saving '{self._file}'. '{e!s}'")
return self return self
def load(self) -> "Notification": def load(self) -> "Notification":
"""Load or reload notification targets from the file.""" """Load or reload notification targets from the file."""
if len(self._targets) > 0: if len(self._targets) > 0:
LOG.info("Clearing existing notification targets.")
self.clear() self.clear()
if not os.path.exists(self._file) or os.path.getsize(self._file) < 10: if not self._file.exists() or self._file.stat().st_size < 1:
return self return self
targets = [] targets = []
LOG.info(f"Loading notification targets from '{self._file}'.")
try: try:
with open(self._file) as f: LOG.info(f"Loading '{self._file}'.")
targets = json.load(f) targets = json.loads(self._file.read_text())
except Exception as e: except Exception as e:
LOG.error(f"Error loading notification targets from '{self._file}'. '{e!s}'") LOG.error(f"Error loading '{self._file}'. '{e!s}'")
for target in targets: for target in targets:
try: try:
@ -227,7 +223,7 @@ class Notification(metaclass=Singleton):
self._targets.append(target) self._targets.append(target)
LOG.info( LOG.info(
f"Will send {target.request.type} request on '{', '.join(target.on) if len(target.on) > 0 else 'all events'}' to '{target.name}'." f"Send '{target.request.type}' request on '{', '.join(target.on) if len(target.on) > 0 else 'all events'}' to '{target.name}'."
) )
except Exception as e: except Exception as e:
LOG.error(f"Error loading notification target '{target}'. '{e!s}'") LOG.error(f"Error loading notification target '{target}'. '{e!s}'")

View file

@ -951,7 +951,7 @@ async def read_logfile(file: str, offset: int = 0, limit: int = 50) -> dict:
return {"logs": [], "next_offset": None, "end_is_reached": True} return {"logs": [], "next_offset": None, "end_is_reached": True}
async def tail_log(file: str, emitter: callable, sleep_time: float = 0.5): async def tail_log(file: pathlib.Path, emitter: callable, sleep_time: float = 0.5):
""" """
Continuously read a log file and emit new lines. Continuously read a log file and emit new lines.
@ -966,7 +966,7 @@ async def tail_log(file: str, emitter: callable, sleep_time: float = 0.5):
from anyio import open_file from anyio import open_file
if not pathlib.Path(file).exists(): if not file.exists():
return return
try: try:

View file

@ -11,7 +11,7 @@ from .config import Config
from .encoder import Encoder from .encoder import Encoder
from .Events import EventBus, Events from .Events import EventBus, Events
from .Singleton import Singleton from .Singleton import Singleton
from .Utils import arg_converter from .Utils import arg_converter, init_class
LOG = logging.getLogger("conditions") LOG = logging.getLogger("conditions")
@ -117,12 +117,12 @@ class Conditions(metaclass=Singleton):
if not self._file.exists() or self._file.stat().st_size < 1: if not self._file.exists() or self._file.stat().st_size < 1:
return self return self
LOG.info(f"Loading '{self._file}'.")
try: try:
with open(self._file) as f: LOG.info(f"Loading '{self._file}'.")
items = json.load(f) items = json.loads(self._file.read_text())
except Exception as e: except Exception as e:
LOG.error(f"Failed to parse '{self._file}'. '{e}'.") LOG.exception(e)
LOG.error(f"Error loading '{self._file}'. '{e}'.")
return self return self
if not items or len(items) < 1: if not items or len(items) < 1:
@ -137,15 +137,15 @@ class Conditions(metaclass=Singleton):
item["id"] = str(uuid.uuid4()) item["id"] = str(uuid.uuid4())
need_save = True need_save = True
item = Condition(**item) item: Condition = init_class(Condition, item)
self._items.append(item) self._items.append(item)
except Exception as e: except Exception as e:
LOG.error(f"Failed to parse failure condition at list position '{i}'. '{e!s}'.") LOG.error(f"Failed to parse condition at list position '{i}'. '{e!s}'.")
continue continue
if need_save: if need_save:
LOG.info("Saving failure conditions due to format, or id change.") LOG.info("Saving conditions due to format, or id change.")
self.save(self._items) self.save(self._items)
return self return self
@ -229,7 +229,7 @@ class Conditions(metaclass=Singleton):
for i, item in enumerate(items): for i, item in enumerate(items):
try: try:
if not isinstance(item, Condition): if not isinstance(item, Condition):
item = Condition(**item) item: Condition = init_class(Condition, item)
items[i] = item items[i] = item
except Exception as e: except Exception as e:
LOG.error(f"Failed to save '{i}' due to parsing error. '{e!s}'.") LOG.error(f"Failed to save '{i}' due to parsing error. '{e!s}'.")
@ -242,12 +242,10 @@ class Conditions(metaclass=Singleton):
continue continue
try: try:
with open(self._file, "w") as f: self._file.write_text(json.dumps(obj=[item.serialize() for item in items], indent=4))
json.dump(obj=[item.serialize() for item in items], fp=f, indent=4)
LOG.info(f"Updated '{self._file}'.") LOG.info(f"Updated '{self._file}'.")
except Exception as e: except Exception as e:
LOG.error(f"Failed to save '{self._file}'. '{e!s}'.") LOG.error(f"Error saving '{self._file}'. '{e!s}'.")
return self return self

View file

@ -7,6 +7,7 @@ import functools
import json import json
import operator import operator
import os import os
from pathlib import Path
import anyio import anyio
@ -271,7 +272,7 @@ async def ffprobe(file: str) -> FFProbeResult:
msg = "ffprobe not found." msg = "ffprobe not found."
raise OSError(msg) from e raise OSError(msg) from e
if not os.path.isfile(file): if not Path(file).exists():
msg = f"No such media file '{file}'." msg = f"No such media file '{file}'."
raise OSError(msg) raise OSError(msg)
@ -290,7 +291,7 @@ async def ffprobe(file: str) -> FFProbeResult:
if 0 == exitCode: if 0 == exitCode:
parsed: dict = json.loads(data.decode("utf-8")) parsed: dict = json.loads(data.decode("utf-8"))
else: else:
msg = f"FFProbe return with non-0 exit code. '{err.decode('utf-8')}'" msg = f"ffprobe returned with non-0 exit code. '{err.decode('utf-8')}'"
raise FFProbeError(msg) raise FFProbeError(msg)
result = FFProbeResult() result = FFProbeResult()