Dateigröße pro Aufnahme entkoppelt - feste Größe nach Abschluss
Die Dateigröße wird jetzt pro Aufnahme korrekt berechnet statt das gesamte Verzeichnis zu summieren. Bei abgeschlossenen Aufnahmen wird die Größe einmalig gespeichert und nicht mehr durch laufende Aufnahmen verändert. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
1ad87c7186
commit
851ff086ac
+121
-38
@@ -1,5 +1,6 @@
|
||||
import datetime
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from sqlalchemy import or_
|
||||
from models import Job, Recording, get_session
|
||||
|
||||
DAY_MAP = {
|
||||
@@ -75,6 +76,111 @@ class StreamScheduler:
|
||||
today = job.schedule_date or today
|
||||
return f"{job.id}|{job.schedule_once}|{today}|{job.schedule_start}"
|
||||
|
||||
def _schedule_state(self, job: dict, now: datetime.datetime | None = None) -> dict:
|
||||
now = now or datetime.datetime.now()
|
||||
today_num = now.isoweekday()
|
||||
today_date = now.strftime("%Y-%m-%d")
|
||||
now_time = now.strftime("%H:%M")
|
||||
|
||||
occ_key = (
|
||||
f"{job['id']}|{job['schedule_once']}|"
|
||||
f"{today_date if not job['schedule_once'] else job['schedule_date']}|"
|
||||
f"{job['schedule_start']}"
|
||||
)
|
||||
|
||||
is_today = False
|
||||
multi_day = bool(job.get("schedule_end_date") and job["schedule_once"])
|
||||
|
||||
if job["schedule_once"]:
|
||||
if job["schedule_date"] == today_date:
|
||||
is_today = True
|
||||
else:
|
||||
if _matches_day(today_num, job["schedule_days"] or "*"):
|
||||
is_today = True
|
||||
|
||||
in_window = False
|
||||
is_cross_midnight = False
|
||||
if is_today:
|
||||
if multi_day:
|
||||
now_min = _time_to_minutes(now_time)
|
||||
start_min = _time_to_minutes(job["schedule_start"])
|
||||
in_window = now_min >= start_min
|
||||
elif job["schedule_stop"]:
|
||||
start_min = _time_to_minutes(job["schedule_start"])
|
||||
stop_min = _time_to_minutes(job["schedule_stop"])
|
||||
if stop_min <= start_min:
|
||||
is_cross_midnight = True
|
||||
now_min = _time_to_minutes(now_time)
|
||||
in_window = now_min >= start_min
|
||||
else:
|
||||
in_window = _in_time_window(now_time, job["schedule_start"], job["schedule_stop"])
|
||||
else:
|
||||
now_min = _time_to_minutes(now_time)
|
||||
start_min = _time_to_minutes(job["schedule_start"])
|
||||
in_window = now_min >= start_min
|
||||
|
||||
return {
|
||||
"occ_key": occ_key,
|
||||
"in_window": in_window,
|
||||
"multi_day": multi_day,
|
||||
"is_cross_midnight": is_cross_midnight,
|
||||
}
|
||||
|
||||
def suppress_current_occurrence(self, job_id: int) -> bool:
|
||||
session = get_session()
|
||||
try:
|
||||
j = session.query(Job).filter_by(id=job_id).first()
|
||||
if not j or not j.schedule_enabled or not j.schedule_start:
|
||||
return False
|
||||
job = {
|
||||
"id": j.id,
|
||||
"schedule_once": j.schedule_once,
|
||||
"schedule_date": j.schedule_date,
|
||||
"schedule_days": j.schedule_days,
|
||||
"schedule_start": j.schedule_start,
|
||||
"schedule_stop": j.schedule_stop,
|
||||
"schedule_end_date": j.schedule_end_date,
|
||||
}
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
state = self._schedule_state(job)
|
||||
if not state["in_window"]:
|
||||
return False
|
||||
|
||||
self._started_keys.add(state["occ_key"])
|
||||
return True
|
||||
|
||||
def _occurrence_start_utc(self, job: dict, now: datetime.datetime) -> datetime.datetime | None:
|
||||
date_text = job["schedule_date"] if job["schedule_once"] else now.strftime("%Y-%m-%d")
|
||||
try:
|
||||
local_start = datetime.datetime.strptime(
|
||||
f"{date_text} {job['schedule_start']}",
|
||||
"%Y-%m-%d %H:%M",
|
||||
)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
local_utc_offset = datetime.datetime.now() - datetime.datetime.utcnow()
|
||||
return local_start - local_utc_offset
|
||||
|
||||
def _has_recording_for_occurrence(self, job: dict, now: datetime.datetime) -> bool:
|
||||
occurrence_start = self._occurrence_start_utc(job, now)
|
||||
if occurrence_start is None:
|
||||
return False
|
||||
|
||||
session = get_session()
|
||||
try:
|
||||
return session.query(Recording).filter(
|
||||
Recording.job_id == job["id"],
|
||||
or_(
|
||||
Recording.started_at >= occurrence_start,
|
||||
Recording.stopped_at >= occurrence_start,
|
||||
),
|
||||
).first() is not None
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
def _is_job_recording(self, job_id: int) -> bool:
|
||||
session = get_session()
|
||||
try:
|
||||
@@ -99,9 +205,6 @@ class StreamScheduler:
|
||||
|
||||
def _tick(self):
|
||||
now = datetime.datetime.now()
|
||||
today_num = now.isoweekday()
|
||||
today_date = now.strftime("%Y-%m-%d")
|
||||
now_time = now.strftime("%H:%M")
|
||||
|
||||
session = get_session()
|
||||
try:
|
||||
@@ -132,44 +235,19 @@ class StreamScheduler:
|
||||
if not job["schedule_start"]:
|
||||
continue
|
||||
|
||||
is_today = False
|
||||
multi_day = bool(job.get("schedule_end_date") and job["schedule_once"])
|
||||
|
||||
if job["schedule_once"]:
|
||||
if job["schedule_date"] == today_date:
|
||||
is_today = True
|
||||
else:
|
||||
if _matches_day(today_num, job["schedule_days"] or "*"):
|
||||
is_today = True
|
||||
|
||||
in_window = False
|
||||
is_cross_midnight = False
|
||||
if is_today:
|
||||
if multi_day:
|
||||
now_min = _time_to_minutes(now_time)
|
||||
start_min = _time_to_minutes(job["schedule_start"])
|
||||
in_window = now_min >= start_min
|
||||
elif job["schedule_stop"]:
|
||||
start_min = _time_to_minutes(job["schedule_start"])
|
||||
stop_min = _time_to_minutes(job["schedule_stop"])
|
||||
if stop_min <= start_min:
|
||||
is_cross_midnight = True
|
||||
now_min = _time_to_minutes(now_time)
|
||||
in_window = now_min >= start_min
|
||||
else:
|
||||
in_window = _in_time_window(now_time, job["schedule_start"], job["schedule_stop"])
|
||||
else:
|
||||
now_min = _time_to_minutes(now_time)
|
||||
start_min = _time_to_minutes(job["schedule_start"])
|
||||
in_window = now_min >= start_min
|
||||
|
||||
occ_key = f"{job['id']}|{job['schedule_once']}|{today_date if not job['schedule_once'] else job['schedule_date']}|{job['schedule_start']}"
|
||||
state = self._schedule_state(job, now)
|
||||
in_window = state["in_window"]
|
||||
occ_key = state["occ_key"]
|
||||
|
||||
if in_window:
|
||||
if occ_key not in self._started_keys and not self._is_job_recording(job["id"]):
|
||||
if (
|
||||
occ_key not in self._started_keys
|
||||
and not self._is_job_recording(job["id"])
|
||||
and not self._has_recording_for_occurrence(job, now)
|
||||
):
|
||||
duration = job["max_duration"]
|
||||
if not duration and job["schedule_stop"]:
|
||||
if multi_day:
|
||||
if state["multi_day"]:
|
||||
start_dt = datetime.datetime.strptime(
|
||||
f"{job['schedule_date']} {job['schedule_start']}", "%Y-%m-%d %H:%M")
|
||||
end_dt = datetime.datetime.strptime(
|
||||
@@ -204,7 +282,12 @@ class StreamScheduler:
|
||||
)
|
||||
self._started_keys.add(occ_key)
|
||||
else:
|
||||
if not multi_day and not is_cross_midnight and job["schedule_stop"] and self._is_job_recording(job["id"]):
|
||||
if (
|
||||
not state["multi_day"]
|
||||
and not state["is_cross_midnight"]
|
||||
and job["schedule_stop"]
|
||||
and self._is_job_recording(job["id"])
|
||||
):
|
||||
rec_id = self._get_active_scheduled_recording_for_job(job["id"])
|
||||
if rec_id:
|
||||
self.recorder.stop_recording(rec_id)
|
||||
|
||||
Reference in New Issue
Block a user