import sqlite3
import os
DB_PATH = os.path.join(os.path.dirname(__file__), 'kiosk.db')
def get_conn():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def init_db():
with get_conn() as conn:
conn.executescript("""
CREATE TABLE IF NOT EXISTS jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
label TEXT NOT NULL,
duration REAL NOT NULL,
type TEXT NOT NULL,
source TEXT NOT NULL,
enabled INTEGER DEFAULT 1,
position INTEGER,
shuffle INTEGER DEFAULT 0,
show_chat INTEGER DEFAULT 0,
transition_type TEXT DEFAULT '',
transition_duration INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS state (
key TEXT PRIMARY KEY,
value TEXT
);
""")
# Migrering: time → duration
cols = {r[1]: r[2] for r in conn.execute("PRAGMA table_info(jobs)").fetchall()}
if 'time' in cols and 'duration' not in cols:
conn.executescript("""
ALTER TABLE jobs ADD COLUMN duration REAL NOT NULL DEFAULT 5;
UPDATE jobs SET duration = 5;
""")
# Migrering: add shuffle + show_chat columns if missing
if 'shuffle' not in cols:
conn.execute("ALTER TABLE jobs ADD COLUMN shuffle INTEGER DEFAULT 0")
if 'show_chat' not in cols:
conn.execute("ALTER TABLE jobs ADD COLUMN show_chat INTEGER DEFAULT 0")
if 'transition_type' not in cols:
conn.execute("ALTER TABLE jobs ADD COLUMN transition_type TEXT DEFAULT ''")
if 'transition_duration' not in cols:
conn.execute("ALTER TABLE jobs ADD COLUMN transition_duration INTEGER DEFAULT 0")
# Migrering: add position column if missing
if 'position' not in cols:
conn.executescript("""
ALTER TABLE jobs RENAME TO jobs_old;
CREATE TABLE jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
label TEXT NOT NULL,
duration REAL NOT NULL,
type TEXT NOT NULL,
source TEXT NOT NULL,
enabled INTEGER DEFAULT 1,
position INTEGER
);
INSERT INTO jobs (id, label, duration, type, source, enabled) SELECT id, label, duration, type, source, enabled FROM jobs_old;
DROP TABLE jobs_old;
""")
# initialize positions to id
conn.execute("UPDATE jobs SET position = id;")
# Migrering: INTEGER → REAL
elif cols.get('duration') == 'INTEGER':
conn.executescript("""
ALTER TABLE jobs RENAME TO jobs_old;
CREATE TABLE jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
label TEXT NOT NULL,
duration REAL NOT NULL,
type TEXT NOT NULL,
source TEXT NOT NULL,
enabled INTEGER DEFAULT 1
);
INSERT INTO jobs SELECT * FROM jobs_old;
DROP TABLE jobs_old;
""")
# --- Jobs ---
def get_all_jobs():
with get_conn() as conn:
return [dict(r) for r in conn.execute("SELECT * FROM jobs ORDER BY COALESCE(position, id), id").fetchall()]
def get_enabled_jobs():
with get_conn() as conn:
return [dict(r) for r in conn.execute(
"SELECT * FROM jobs WHERE enabled = 1 ORDER BY COALESCE(position, id), id"
).fetchall()]
def add_job(label, duration, type_, source, shuffle=False, show_chat=False,
transition_type='', transition_duration=0):
with get_conn() as conn:
curpos = conn.execute("SELECT MAX(position) AS m FROM jobs").fetchone()
nextpos = (curpos['m'] or 0) + 1
cur = conn.execute(
"INSERT INTO jobs (label, duration, type, source, position, shuffle, show_chat, "
"transition_type, transition_duration) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
(label, duration, type_, source, nextpos,
1 if shuffle else 0, 1 if show_chat else 0,
transition_type or '', int(transition_duration or 0))
)
return cur.lastrowid
def delete_job(job_id):
with get_conn() as conn:
conn.execute("DELETE FROM jobs WHERE id = ?", (job_id,))
def toggle_job(job_id):
with get_conn() as conn:
conn.execute(
"UPDATE jobs SET enabled = CASE WHEN enabled = 1 THEN 0 ELSE 1 END WHERE id = ?",
(job_id,)
)
row = conn.execute("SELECT enabled FROM jobs WHERE id = ?", (job_id,)).fetchone()
return dict(row) if row else None
def update_job(job_id, **fields):
if not fields:
return
keys = []
vals = []
for k, v in fields.items():
if k in ('label', 'duration', 'type', 'source', 'enabled', 'shuffle', 'show_chat',
'transition_type', 'transition_duration'):
keys.append(f"{k} = ?")
vals.append(v)
if not keys:
return
vals.append(job_id)
with get_conn() as conn:
conn.execute(f"UPDATE jobs SET {', '.join(keys)} WHERE id = ?", tuple(vals))
def reorder_jobs(id_list):
with get_conn() as conn:
for idx, jid in enumerate(id_list, start=1):
conn.execute("UPDATE jobs SET position = ? WHERE id = ?", (idx, jid))
# --- State ---
def set_state(key, value):
with get_conn() as conn:
conn.execute(
"INSERT OR REPLACE INTO state (key, value) VALUES (?, ?)", (key, value)
)
def set_current(type_, source):
with get_conn() as conn:
conn.execute(
"INSERT OR REPLACE INTO state (key, value) VALUES ('current_type', ?)", (type_,)
)
conn.execute(
"INSERT OR REPLACE INTO state (key, value) VALUES ('current_source', ?)", (source,)
)
def get_state():
with get_conn() as conn:
rows = conn.execute("SELECT key, value FROM state").fetchall()
return {r['key']: r['value'] for r in rows}
class AddonDB:
"""
Scoped DB-access för addons.
Alla nycklar prefixas automatiskt med addon-prefixet
så att addons inte kan råka skriva utanför sin namnrymd.
Exempel:
_db = AddonDB('ticker_')
_db.set('enabled', '1') # sparar 'ticker_enabled'
_db.get('enabled') # läser 'ticker_enabled'
"""
def __init__(self, prefix: str):
self._prefix = prefix
def get(self, key: str, default=None):
return get_state().get(self._prefix + key, default)
def set(self, key: str, value):
set_state(self._prefix + key, str(value))
def get_all(self) -> dict:
"""Returnerar alla värden för detta prefix, utan prefixet i nyckelnamnen."""
state = get_state()
pfx = self._prefix
return {k[len(pfx):]: v for k, v in state.items() if k.startswith(pfx)}