Add settings and live sidebar counts

This commit is contained in:
Abel Luck 2026-03-30 18:26:02 +02:00
parent 2a99edeec3
commit a809bde16c
16 changed files with 696 additions and 51 deletions

View file

@ -1,11 +1,13 @@
from __future__ import annotations
import json
import os
from datetime import UTC, datetime
from enum import IntEnum
from importlib import resources
from importlib.resources.abc import Traversable
from pathlib import Path
from typing import Any
from peewee import (
BooleanField,
@ -29,6 +31,8 @@ DATABASE_PRAGMAS = {
"temp_store": "memory",
}
SCHEMA_GLOB = "*.sql"
MAX_CONCURRENT_JOBS_SETTING_KEY = "max_concurrent_jobs"
DEFAULT_MAX_CONCURRENT_JOBS = 1
database = SqliteDatabase(None, pragmas=DATABASE_PRAGMAS)
@ -78,17 +82,85 @@ def initialize_database(db_path: str | Path | None = None) -> Path:
connection = database.connection()
for path in schema_paths():
connection.executescript(path.read_text(encoding="utf-8"))
_ensure_schema(connection)
finally:
database.close()
return resolved_path
def _ensure_schema(connection: Any) -> None:
connection.execute(
"""
CREATE TABLE IF NOT EXISTS app_setting (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
"""
)
job_columns = {
row[1] for row in connection.execute("PRAGMA table_info('job')").fetchall()
}
if "convert_images" not in job_columns:
connection.execute(
"""
ALTER TABLE job
ADD COLUMN convert_images INTEGER NOT NULL DEFAULT 1
CHECK (convert_images IN (0, 1))
"""
)
if "convert_video" not in job_columns:
connection.execute(
"""
ALTER TABLE job
ADD COLUMN convert_video INTEGER NOT NULL DEFAULT 1
CHECK (convert_video IN (0, 1))
"""
)
def source_slug_exists(slug: str) -> bool:
with database.connection_context():
return Source.select().where(Source.slug == slug).exists()
def save_setting(key: str, value: Any) -> None:
payload = json.dumps(value, sort_keys=True)
with database.connection_context():
with database.atomic():
setting = AppSetting.get_or_none(AppSetting.key == key)
if setting is None:
AppSetting.create(key=key, value=payload)
return
setting.value = payload
setting.save()
def load_setting(key: str, default: Any) -> Any:
with database.connection_context():
setting = AppSetting.get_or_none(AppSetting.key == key)
if setting is None:
return default
try:
return json.loads(setting.value)
except json.JSONDecodeError:
return default
def load_max_concurrent_jobs() -> int:
value = load_setting(MAX_CONCURRENT_JOBS_SETTING_KEY, DEFAULT_MAX_CONCURRENT_JOBS)
try:
parsed = int(value)
except (TypeError, ValueError):
return DEFAULT_MAX_CONCURRENT_JOBS
return parsed if parsed >= 1 else DEFAULT_MAX_CONCURRENT_JOBS
def load_settings_form() -> dict[str, object]:
return {"max_concurrent_jobs": load_max_concurrent_jobs()}
def load_source_form(slug: str) -> dict[str, object] | None:
with database.connection_context():
source = Source.get_or_none(Source.slug == slug)
@ -103,6 +175,8 @@ def load_source_form(slug: str) -> dict[str, object] | None:
"notes": source.notes,
"spider_arguments": job.spider_arguments,
"enabled": job.enabled,
"convert_images": job.convert_images,
"convert_video": job.convert_video,
"cron_minute": job.cron_minute,
"cron_hour": job.cron_hour,
"cron_day_of_month": job.cron_day_of_month,
@ -155,6 +229,8 @@ def create_source(
cron_day_of_month: str,
cron_day_of_week: str,
cron_month: str,
convert_images: bool = True,
convert_video: bool = True,
feed_url: str = "",
pangea_domain: str = "",
pangea_category: str = "",
@ -197,6 +273,8 @@ def create_source(
Job.create(
source=source,
enabled=enabled,
convert_images=convert_images,
convert_video=convert_video,
spider_arguments=spider_arguments,
cron_minute=cron_minute,
cron_hour=cron_hour,
@ -221,6 +299,8 @@ def update_source(
cron_day_of_month: str,
cron_day_of_week: str,
cron_month: str,
convert_images: bool = True,
convert_video: bool = True,
feed_url: str = "",
pangea_domain: str = "",
pangea_category: str = "",
@ -246,6 +326,8 @@ def update_source(
job = Job.get(Job.source == source)
job.enabled = enabled
job.convert_images = convert_images
job.convert_video = convert_video
job.spider_arguments = spider_arguments
job.cron_minute = cron_minute
job.cron_hour = cron_hour
@ -375,6 +457,14 @@ class BaseModel(Model):
database = database
class AppSetting(BaseModel):
key = TextField(primary_key=True)
value = TextField()
class Meta:
table_name = "app_setting"
class Source(BaseModel):
created_at = DateTimeField(default=utc_now)
updated_at = DateTimeField(default=utc_now)
@ -419,6 +509,8 @@ class Job(BaseModel):
created_at = DateTimeField(default=utc_now)
updated_at = DateTimeField(default=utc_now)
enabled = BooleanField()
convert_images = BooleanField(default=True)
convert_video = BooleanField(default=True)
spider_arguments = TextField(default="")
cron_minute = TextField()
cron_hour = TextField()