WiP: more changes to classes to support Path
This commit is contained in:
parent
6a9beea89e
commit
b1bc399a0c
6 changed files with 46 additions and 46 deletions
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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}'")
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue