Refactor path handling

- Use pathlib for path joining sugar using slashes
- Rename BASE_DIR to MEDIA_DIR, which is more meaningful
- Introduce INSTALL_DIR for the installation base dir
- Replace glob.glob usage with no wildcard to file existance check
This commit is contained in:
Martin Weinelt 2024-02-01 13:29:44 +01:00
parent 3df8b5829c
commit 6596207fb4
No known key found for this signature in database
GPG Key ID: 87C1E9888F856759
10 changed files with 48 additions and 38 deletions

View File

@ -109,7 +109,7 @@ class FrigateApp:
root_configurer(self.log_queue)
def init_config(self) -> None:
config_file = os.environ.get("CONFIG_FILE", "/config/config.yml")
config_file = os.environ.get("CONFIG_FILE", str(CONFIG_DIR / "config.yml"))
# Check if we can use .yaml instead of .yml
config_file_yaml = config_file.replace(".yml", ".yaml")

View File

@ -910,7 +910,7 @@ class CameraConfig(FrigateBaseModel):
class DatabaseConfig(FrigateBaseModel):
path: str = Field(default=DEFAULT_DB_PATH, title="Database path.")
path: str = Field(default=str(DEFAULT_DB_PATH), title="Database path.")
class LogLevelEnum(str, Enum):

View File

@ -1,14 +1,23 @@
CONFIG_DIR = "/config"
DEFAULT_DB_PATH = f"{CONFIG_DIR}/frigate.db"
MODEL_CACHE_DIR = f"{CONFIG_DIR}/model_cache"
BASE_DIR = "/media/frigate"
CLIPS_DIR = f"{BASE_DIR}/clips"
RECORD_DIR = f"{BASE_DIR}/recordings"
EXPORT_DIR = f"{BASE_DIR}/exports"
BIRDSEYE_PIPE = "/tmp/cache/birdseye"
CACHE_DIR = "/tmp/cache"
from pathlib import Path
CACHE_DIR = Path("/tmp/cache")
BIRDSEYE_PIPE = CACHE_DIR / "birdseye"
CONFIG_DIR = Path("/config")
DEFAULT_DB_PATH = CONFIG_DIR / "frigate.db"
MODEL_CACHE_DIR = CONFIG_DIR / "model_cache"
INSTALL_DIR = Path("/opt/frigate")
MEDIA_DIR = Path("/media/frigate")
CLIPS_DIR = MEDIA_DIR / "clips"
RECORD_DIR = MEDIA_DIR / "recordings"
EXPORT_DIR = MEDIA_DIR / "exports"
YAML_EXT = (".yaml", ".yml")
FRIGATE_LOCALHOST = "http://127.0.0.1:5000"
PLUS_ENV_VAR = "PLUS_API_KEY"
PLUS_API_HOST = "https://api.frigate.video"

View File

@ -10,6 +10,7 @@ import requests
from pydantic import BaseModel, Extra, Field
from pydantic.fields import PrivateAttr
from frigate.const import MODEL_CACHE_DIR
from frigate.plus import PlusApi
from frigate.util.builtin import load_labels
@ -83,7 +84,7 @@ class ModelConfig(BaseModel):
return
model_id = self.path[7:]
self.path = f"/config/model_cache/{model_id}"
self.path = str(MODEL_CACHE_DIR / model_id)
model_info_path = f"{self.path}.json"
# download the model if it doesn't exist

View File

@ -15,6 +15,7 @@ except: # noqa: E722
from pydantic import Field
from frigate.const import MODEL_CACHE_DIR
from frigate.detectors.detection_api import DetectionApi
from frigate.detectors.detector_config import BaseDetectorConfig
@ -86,12 +87,10 @@ class Rknn(DetectionApi):
else:
model_suffix = yolov8_suffix[self.model_path]
self.model_path = (
"/config/model_cache/rknn/yolov8{suffix}-320x320-{soc}.rknn".format(
suffix=model_suffix, soc=soc
)
MODEL_CACHE_DIR / f"rknn/yolov8{model_suffix}-320x320-{soc}.rknn"
)
os.makedirs("/config/model_cache/rknn", exist_ok=True)
os.makedirs(MODEL_CACHE_DIR / "rknn", exist_ok=True)
if not os.path.isfile(self.model_path):
logger.info(
"Downloading yolov8{suffix} model.".format(suffix=model_suffix)

View File

@ -1,6 +1,5 @@
import base64
import copy
import glob
import json
import logging
import os
@ -41,7 +40,9 @@ from frigate.const import (
CLIPS_DIR,
CONFIG_DIR,
EXPORT_DIR,
INSTALL_DIR,
MAX_SEGMENT_DURATION,
MEDIA_DIR,
RECORD_DIR,
)
from frigate.events.external import ExternalEventProcessor
@ -1384,7 +1385,7 @@ def config():
@bp.route("/config/raw")
def config_raw():
config_file = os.environ.get("CONFIG_FILE", "/config/config.yml")
config_file = os.environ.get("CONFIG_FILE", CONFIG_DIR / "config.yml")
# Check if we can use .yaml instead of .yml
config_file_yaml = config_file.replace(".yml", ".yaml")
@ -1434,7 +1435,7 @@ def config_save():
# Save the config to file
try:
config_file = os.environ.get("CONFIG_FILE", "/config/config.yml")
config_file = os.environ.get("CONFIG_FILE", CONFIG_DIR / "config.yml")
# Check if we can use .yaml instead of .yml
config_file_yaml = config_file.replace(".yml", ".yaml")
@ -1647,11 +1648,11 @@ def latest_frame(camera_name):
+ retry_interval
):
if current_app.camera_error_image is None:
error_image = glob.glob("/opt/frigate/frigate/images/camera-error.jpg")
error_image = INSTALL_DIR / "frigate/images/camera-error.jpg"
if len(error_image) > 0:
if error_image.is_file():
current_app.camera_error_image = cv2.imread(
error_image[0], cv2.IMREAD_UNCHANGED
str(error_image), cv2.IMREAD_UNCHANGED
)
frame = current_app.camera_error_image
@ -2097,7 +2098,7 @@ def preview_ts(camera_name, start_ts, end_ts):
clips.append(
{
"camera": preview["camera"],
"src": preview["path"].replace("/media/frigate", ""),
"src": preview["path"].replace(MEDIA_DIR, ""),
"type": "video/mp4",
"start": preview["start_time"],
"end": preview["end_time"],

View File

@ -1,7 +1,6 @@
"""Handle outputting birdseye frames via jsmpeg and go2rtc."""
import datetime
import glob
import logging
import math
import multiprocessing as mp
@ -15,7 +14,7 @@ import cv2
import numpy as np
from frigate.config import BirdseyeModeEnum, FrigateConfig
from frigate.const import BASE_DIR, BIRDSEYE_PIPE
from frigate.const import BIRDSEYE_PIPE, INSTALL_DIR, MEDIA_DIR
from frigate.types import CameraMetricsTypes
from frigate.util.image import (
SharedMemoryFrameManager,
@ -280,16 +279,16 @@ class BirdsEyeFrameManager:
# find and copy the logo on the blank frame
birdseye_logo = None
custom_logo_files = glob.glob(f"{BASE_DIR}/custom.png")
custom_logo_file = MEDIA_DIR / "custom.png"
if len(custom_logo_files) > 0:
birdseye_logo = cv2.imread(custom_logo_files[0], cv2.IMREAD_UNCHANGED)
if custom_logo_file.is_file():
birdseye_logo = cv2.imread(str(custom_logo_file), cv2.IMREAD_UNCHANGED)
if birdseye_logo is None:
logo_files = glob.glob("/opt/frigate/frigate/images/birdseye.png")
logo_file = INSTALL_DIR / "frigate/images/birdseye.png"
if len(logo_files) > 0:
birdseye_logo = cv2.imread(logo_files[0], cv2.IMREAD_UNCHANGED)
if logo_file.is_file():
birdseye_logo = cv2.imread(str(logo_file), cv2.IMREAD_UNCHANGED)
if birdseye_logo is not None:
transparent_layer = birdseye_logo[:, :, 3]

View File

@ -300,7 +300,7 @@ def stats_snapshot(
for path in [RECORD_DIR, CLIPS_DIR, CACHE_DIR, "/dev/shm"]:
try:
storage_stats = shutil.disk_usage(path)
storage_stats = shutil.disk_usage(str(path))
except FileNotFoundError:
stats["service"]["storage"][path] = {}
continue
@ -309,7 +309,7 @@ def stats_snapshot(
"total": round(storage_stats.total / pow(2, 20), 1),
"used": round(storage_stats.used / pow(2, 20), 1),
"free": round(storage_stats.free / pow(2, 20), 1),
"mount_type": get_fs_type(path),
"mount_type": get_fs_type(str(path)),
}
stats["processes"] = {}

View File

@ -847,9 +847,9 @@ class TestConfig(unittest.TestCase):
assert runtime_config.model.merged_labelmap[0] == "person"
def test_plus_labelmap(self):
with open("/config/model_cache/test", "w") as f:
with open(MODEL_CACHE_DIR / "test", "w") as f:
json.dump(self.plus_model_info, f)
with open("/config/model_cache/test.json", "w") as f:
with open(MODEL_CACHE_DIR / "test.json", "w") as f:
json.dump(self.plus_model_info, f)
config = {

View File

@ -11,6 +11,7 @@ from playhouse.sqlite_ext import SqliteExtDatabase
from playhouse.sqliteq import SqliteQueueDatabase
from frigate.config import FrigateConfig
from frigate.const import CACHE_DIR, CLIPS_DIR, RECORD_DIR
from frigate.http import create_app
from frigate.models import Event, Recordings
from frigate.plus import PlusApi
@ -76,19 +77,19 @@ class TestHttp(unittest.TestCase):
"total": 67.1,
"used": 16.6,
},
"/media/frigate/clips": {
str(CLIPS_DIR): {
"free": 42429.9,
"mount_type": "ext4",
"total": 244529.7,
"used": 189607.0,
},
"/media/frigate/recordings": {
str(RECORD_DIR): {
"free": 0.2,
"mount_type": "ext4",
"total": 8.0,
"used": 7.8,
},
"/tmp/cache": {
str(CACHE_DIR): {
"free": 976.8,
"mount_type": "tmpfs",
"total": 1000.0,