changes in db

This commit is contained in:
Mateusz Gruszczyński
2026-05-26 09:25:47 +02:00
parent 8268ad87cf
commit 70a9344cdd
10 changed files with 346 additions and 165 deletions

View File

@@ -135,9 +135,8 @@ def _int_setting(data: dict[str, Any], current: dict[str, Any], key: str, defaul
return max(minimum, int(default))
def _default_settings(user_id: int, profile_id: int) -> dict[str, Any]:
def _default_settings(profile_id: int) -> dict[str, Any]:
return {
'user_id': user_id,
'profile_id': profile_id,
'enabled': 0,
'max_active_downloads': 5,
@@ -162,18 +161,16 @@ def _default_settings(user_id: int, profile_id: int) -> dict[str, Any]:
def get_settings(profile_id: int, user_id: int | None = None) -> dict[str, Any]:
user_id = user_id or default_user_id()
with connect() as conn:
row = conn.execute(
'SELECT * FROM smart_queue_settings WHERE user_id=? AND profile_id=?',
(user_id, profile_id),
'SELECT * FROM smart_queue_settings WHERE profile_id=?',
(profile_id,),
).fetchone()
settings = dict(row or _default_settings(user_id, profile_id))
settings = dict(row or _default_settings(profile_id))
return settings
def save_settings(profile_id: int, data: dict[str, Any], user_id: int | None = None) -> dict[str, Any]:
user_id = user_id or default_user_id()
current = get_settings(profile_id, user_id)
settings = {
'enabled': 1 if data.get('enabled', current.get('enabled')) else 0,
@@ -214,9 +211,9 @@ def save_settings(profile_id: int, data: dict[str, Any], user_id: int | None = N
now = utcnow()
with connect() as conn:
conn.execute(
'''INSERT INTO smart_queue_settings(user_id,profile_id,enabled,max_active_downloads,stalled_seconds,min_speed_bytes,min_seeds,min_peers,ignore_seed_peer,ignore_speed,manage_stopped,cooldown_minutes,stop_batch_size,start_grace_seconds,protect_active_below_cap,auto_stop_idle,refill_enabled,refill_interval_minutes,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
ON CONFLICT(user_id, profile_id) DO UPDATE SET
'''INSERT INTO smart_queue_settings(profile_id,enabled,max_active_downloads,stalled_seconds,min_speed_bytes,min_seeds,min_peers,ignore_seed_peer,ignore_speed,manage_stopped,cooldown_minutes,stop_batch_size,start_grace_seconds,protect_active_below_cap,auto_stop_idle,refill_enabled,refill_interval_minutes,updated_at)
VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
ON CONFLICT(profile_id) DO UPDATE SET
enabled=excluded.enabled,
max_active_downloads=excluded.max_active_downloads,
stalled_seconds=excluded.stalled_seconds,
@@ -234,80 +231,74 @@ def save_settings(profile_id: int, data: dict[str, Any], user_id: int | None = N
refill_enabled=excluded.refill_enabled,
refill_interval_minutes=excluded.refill_interval_minutes,
updated_at=excluded.updated_at''',
(user_id, profile_id, settings['enabled'], settings['max_active_downloads'], settings['stalled_seconds'], settings['min_speed_bytes'], settings['min_seeds'], settings['min_peers'], settings['ignore_seed_peer'], settings['ignore_speed'], settings['manage_stopped'], settings['cooldown_minutes'], settings['stop_batch_size'], settings['start_grace_seconds'], settings['protect_active_below_cap'], settings['auto_stop_idle'], settings['refill_enabled'], settings['refill_interval_minutes'], now),
(profile_id, settings['enabled'], settings['max_active_downloads'], settings['stalled_seconds'], settings['min_speed_bytes'], settings['min_seeds'], settings['min_peers'], settings['ignore_seed_peer'], settings['ignore_speed'], settings['manage_stopped'], settings['cooldown_minutes'], settings['stop_batch_size'], settings['start_grace_seconds'], settings['protect_active_below_cap'], settings['auto_stop_idle'], settings['refill_enabled'], settings['refill_interval_minutes'], now),
)
return get_settings(profile_id, user_id)
def list_exclusions(profile_id: int, user_id: int | None = None) -> list[dict[str, Any]]:
user_id = user_id or default_user_id()
with connect() as conn:
return conn.execute(
'SELECT * FROM smart_queue_exclusions WHERE user_id=? AND profile_id=? ORDER BY created_at DESC',
(user_id, profile_id),
'SELECT * FROM smart_queue_exclusions WHERE profile_id=? ORDER BY created_at DESC',
(profile_id,),
).fetchall()
def set_exclusion(profile_id: int, torrent_hash: str, excluded: bool, reason: str = '', user_id: int | None = None) -> None:
user_id = user_id or default_user_id()
now = utcnow()
with connect() as conn:
if excluded:
conn.execute(
'INSERT OR REPLACE INTO smart_queue_exclusions(user_id,profile_id,torrent_hash,reason,created_at) VALUES(?,?,?,?,?)',
(user_id, profile_id, torrent_hash, reason, now),
'INSERT OR REPLACE INTO smart_queue_exclusions(profile_id,torrent_hash,reason,created_at) VALUES(?,?,?,?)',
(profile_id, torrent_hash, reason, now),
)
else:
conn.execute(
'DELETE FROM smart_queue_exclusions WHERE user_id=? AND profile_id=? AND torrent_hash=?',
(user_id, profile_id, torrent_hash),
'DELETE FROM smart_queue_exclusions WHERE profile_id=? AND torrent_hash=?',
(profile_id, torrent_hash),
)
def add_history(profile_id: int, event: str, paused: list[str] | None = None, resumed: list[str] | None = None, checked: int = 0, details: dict[str, Any] | None = None, user_id: int | None = None) -> None:
user_id = user_id or default_user_id()
paused = paused or []
resumed = resumed or []
details = details or {}
with connect() as conn:
conn.execute(
'INSERT INTO smart_queue_history(user_id,profile_id,event,paused_count,resumed_count,checked_count,details_json,created_at) VALUES(?,?,?,?,?,?,?,?)',
(user_id, profile_id, event, len(paused), len(resumed), int(checked or 0), json.dumps({**details, 'paused': paused, 'resumed': resumed}), utcnow()),
'INSERT INTO smart_queue_history(profile_id,event,paused_count,resumed_count,checked_count,details_json,created_at) VALUES(?,?,?,?,?,?,?)',
(profile_id, event, len(paused), len(resumed), int(checked or 0), json.dumps({**details, 'paused': paused, 'resumed': resumed}), utcnow()),
)
def list_history(profile_id: int, user_id: int | None = None, limit: int = 30) -> list[dict[str, Any]]:
user_id = user_id or default_user_id()
with connect() as conn:
return conn.execute(
'SELECT * FROM smart_queue_history WHERE user_id=? AND profile_id=? ORDER BY created_at DESC LIMIT ?',
(user_id, profile_id, max(1, min(int(limit or 30), 100))),
'SELECT * FROM smart_queue_history WHERE profile_id=? ORDER BY created_at DESC LIMIT ?',
(profile_id, max(1, min(int(limit or 30), 100))),
).fetchall()
def clear_history(profile_id: int, user_id: int | None = None) -> int:
"""Delete Smart Queue history rows for the current profile and return the removed count."""
# Note: Manual cleanup only removes audit history; settings, exclusions and pending queue state stay untouched.
user_id = user_id or default_user_id()
with connect() as conn:
row = conn.execute(
'SELECT COUNT(*) AS count FROM smart_queue_history WHERE user_id=? AND profile_id=?',
(user_id, profile_id),
'SELECT COUNT(*) AS count FROM smart_queue_history WHERE profile_id=?',
(profile_id,),
).fetchone()
count = int((row or {}).get('count') or 0)
conn.execute(
'DELETE FROM smart_queue_history WHERE user_id=? AND profile_id=?',
(user_id, profile_id),
'DELETE FROM smart_queue_history WHERE profile_id=?',
(profile_id,),
)
return count
def count_history(profile_id: int, user_id: int | None = None) -> int:
user_id = user_id or default_user_id()
with connect() as conn:
row = conn.execute(
'SELECT COUNT(*) AS count FROM smart_queue_history WHERE user_id=? AND profile_id=?',
(user_id, profile_id),
'SELECT COUNT(*) AS count FROM smart_queue_history WHERE profile_id=?',
(profile_id,),
).fetchone()
return int((row or {}).get('count') or 0)
@@ -315,11 +306,10 @@ def count_history(profile_id: int, user_id: int | None = None) -> int:
def _latest_history_event(profile_id: int, user_id: int | None = None) -> str:
"""Return the newest Smart Queue history event for duplicate suppression."""
# Note: Disabled Smart Queue should leave one waiting marker, not a poller-generated log stream.
user_id = user_id or default_user_id()
with connect() as conn:
row = conn.execute(
'SELECT event FROM smart_queue_history WHERE user_id=? AND profile_id=? ORDER BY created_at DESC LIMIT 1',
(user_id, profile_id),
'SELECT event FROM smart_queue_history WHERE profile_id=? ORDER BY created_at DESC LIMIT 1',
(profile_id,),
).fetchone()
return str((row or {}).get('event') or '')
@@ -338,8 +328,8 @@ def _record_disabled_waiting_once(profile_id: int, user_id: int, details: dict[s
return True
def _excluded_hashes(profile_id: int, user_id: int) -> set[str]:
return {r['torrent_hash'] for r in list_exclusions(profile_id, user_id)}
def _excluded_hashes(profile_id: int, user_id: int | None = None) -> set[str]:
return {r['torrent_hash'] for r in list_exclusions(profile_id)}
@@ -891,7 +881,7 @@ def _refill_mode(settings: dict[str, Any]) -> str:
def _mark_refill_run(profile_id: int, user_id: int) -> None:
# Note: Custom refill interval is measured from the last lightweight refill attempt.
with connect() as conn:
conn.execute('UPDATE smart_queue_settings SET last_refill_at=?, updated_at=? WHERE user_id=? AND profile_id=?', (utcnow(), utcnow(), user_id, profile_id))
conn.execute('UPDATE smart_queue_settings SET last_refill_at=?, updated_at=? WHERE profile_id=?', (utcnow(), utcnow(), profile_id))
def _refill_underfilled_queue(profile: dict, settings: dict[str, Any], profile_id: int, user_id: int) -> dict[str, Any]:
@@ -1090,13 +1080,13 @@ def _refill_underfilled_queue(profile: dict, settings: dict[str, Any], profile_i
def mark_run(profile_id: int, user_id: int | None = None) -> None:
user_id = user_id or default_user_id()
with connect() as conn:
conn.execute('UPDATE smart_queue_settings SET last_run_at=?, updated_at=? WHERE user_id=? AND profile_id=?', (utcnow(), utcnow(), user_id, profile_id))
conn.execute('UPDATE smart_queue_settings SET last_run_at=?, updated_at=? WHERE profile_id=?', (utcnow(), utcnow(), profile_id))
def _disable_when_idle(profile_id: int, user_id: int, torrents: list[dict[str, Any]], details: dict[str, Any]) -> dict[str, Any]:
# Note: Auto-stop is intentionally profile-scoped and only flips the Smart Queue enabled flag; saved thresholds remain intact.
now = utcnow()
with connect() as conn:
conn.execute('UPDATE smart_queue_settings SET enabled=0, last_run_at=?, updated_at=? WHERE user_id=? AND profile_id=?', (now, now, user_id, profile_id))
conn.execute('UPDATE smart_queue_settings SET enabled=0, last_run_at=?, updated_at=? WHERE profile_id=?', (now, now, profile_id))
add_history(profile_id, 'auto_stopped_idle', [], [], len(torrents), details, user_id)
settings = get_settings(profile_id, user_id)
return {'ok': True, 'enabled': False, 'auto_stopped_idle': True, 'paused': [], 'resumed': [], 'stopped': [], 'started': [], 'checked': len(torrents), 'settings': settings, 'message': 'Smart Queue stopped because there is no active or waiting work.'}