malo prepucano po nasvetih kopilota, fix za shutdown na linux-u, nekaj dodatkov na temo robustnosti

This commit is contained in:
2026-03-04 22:35:03 +01:00
parent cd4ad32641
commit 9e32e58c4c
3 changed files with 65 additions and 39 deletions

View File

@@ -15,7 +15,7 @@ DEFAULT_SETTINGS = {
"screen_width_percent": 60, "screen_width_percent": 60,
"font_bold": True, "font_bold": True,
"show_song_info": True, "show_song_info": True,
"split_by_stanza": True "split_by_stanza": False
} }
SETTINGS_FILE = "settings.json" SETTINGS_FILE = "settings.json"

View File

@@ -7,16 +7,28 @@ import json
import os import os
import math import math
import subprocess import subprocess
import sys
import tkinter.messagebox as messagebox
DB_PATH = 'songs.db' DB_PATH = 'songs.db'
SETTINGS_PATH = 'settings.json' SETTINGS_PATH = 'settings.json'
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
class SongProjector: class SongProjector:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
self.conn = sqlite3.connect(DB_PATH) # ...
try:
# Odpri read-only; ne bo ustvaril prazne baze, če datoteka manjka
self.conn = sqlite3.connect(f"file:{DB_PATH}?mode=ro", uri=True)
self.cursor = self.conn.cursor() self.cursor = self.conn.cursor()
except sqlite3.OperationalError as e:
# Jasno sporočilo in varen izhod
messagebox.showerror("Napaka baze", f"Ne morem odpreti baze '{DB_PATH}':\n{e}")
root.destroy()
sys.exit(1)
self.current_song = None self.current_song = None
self.pages = [] self.pages = []
self.current_page_index = 0 self.current_page_index = 0
@@ -27,21 +39,28 @@ class SongProjector:
# -------------------------------------------------- # --------------------------------------------------
# Nastavitve # Nastavitve
# -------------------------------------------------- # --------------------------------------------------
if not os.path.exists(SETTINGS_PATH): DEFAULT_SETTINGS = {
self.settings = {
"font_name": "Times New Roman", "font_name": "Times New Roman",
"bg_color": "#000000", "bg_color": "#000000",
"fg_color": "#FFFFFF", "fg_color": "#FFFFFF",
"font_size": 32, "font_size": 32,
"screen_width_percent": 60, "screen_width_percent": 60,
"font_bold": True, "font_bold": True,
"show_song_info": True "show_song_info": True,
"split_by_stanza": False # TODO: mogoče nekoč (prelom po kitici namesto po višini)
} }
if not os.path.exists(SETTINGS_PATH):
self.settings = DEFAULT_SETTINGS.copy()
with open(SETTINGS_PATH, "w", encoding="utf-8") as f: with open(SETTINGS_PATH, "w", encoding="utf-8") as f:
json.dump(self.settings, f, indent=4) json.dump(self.settings, f, indent=4, ensure_ascii=False)
else: else:
try:
with open(SETTINGS_PATH, "r", encoding="utf-8") as f: with open(SETTINGS_PATH, "r", encoding="utf-8") as f:
self.settings = json.load(f) self.settings = json.load(f)
except (json.JSONDecodeError, OSError):
# Povratek na varne privzete
self.settings = DEFAULT_SETTINGS.copy()
self.line_height = int(int(self.settings["font_size"]) * 1.5) self.line_height = int(int(self.settings["font_size"]) * 1.5)
@@ -171,7 +190,7 @@ class SongProjector:
# Upravljanje tipkovnice # Upravljanje tipkovnice
# ------------------------------------------------------ # ------------------------------------------------------
def key_pressed(self, event): def key_pressed(self, event):
if event.keysym.isdigit(): if event.char and event.char.isdigit():
self.song_number += event.char self.song_number += event.char
elif event.keysym == "BackSpace": elif event.keysym == "BackSpace":
self.song_number = self.song_number[:-1] self.song_number = self.song_number[:-1]
@@ -205,17 +224,20 @@ class SongProjector:
# Posebni ukazi # Posebni ukazi
if self.song_number == "9999": if self.song_number == "9999":
subprocess.Popen(["shutdown", "/s", "/f", "/t", "0"]) if sys.platform.startswith("win"):
subprocess.Popen(["shutdown", "/s", "/t", "0"]) # brez /f manj agresivno
else:
subprocess.Popen(["shutdown", "-h", "now"])
return return
elif self.song_number == "7777": elif self.song_number == "7777":
subprocess.Popen(["python", "nastavitve.py"]) subprocess.Popen([sys.executable, os.path.join(BASE_DIR, "nastavitve.py")]) # fixme: novi proces ne dobi stdin-a; predelati na tkinter aplikacijo?
self.exit_program() self.exit_program()
return return
elif self.song_number == "8888": elif self.song_number == "8888":
self.exit_program() self.exit_program()
return return
elif self.song_number == "6666": elif self.song_number == "6666":
subprocess.Popen(["python", "add_song.py"]) subprocess.Popen([sys.executable, os.path.join(BASE_DIR, "add_song.py")]) # fixme: novi proces ne dobi stdin-a; predelati na tkinter aplikacijo?
self.exit_program() self.exit_program()
return return
@@ -392,25 +414,29 @@ class SongProjector:
self.search_entry.bind("<Return>", self.perform_search) self.search_entry.bind("<Return>", self.perform_search)
def perform_search(self, event=None): def perform_search(self, event=None):
query = self.search_entry.get().strip().lower() query = self.search_entry.get().strip()
self.search_label.destroy() self.search_label.destroy()
self.search_entry.destroy() self.search_entry.destroy()
self.label.pack(expand=True)
if query: if not query:
self.cursor.execute("SELECT id, title FROM songs") self.label.config(text="(Prazno iskanje)")
all_results = self.cursor.fetchall() return
matched = [] try:
for song_id, title in all_results: self.cursor.execute(
if query in title.lower(): "SELECT id, title FROM songs WHERE title LIKE ? COLLATE NOCASE",
matched.append((song_id, title)) (f"%{query}%",)
)
matched = self.cursor.fetchall()
except Exception as e:
self.label.config(text=f"Napaka pri iskanju: {e}")
return
if matched: if matched:
found = "\n".join(f"{id}: {title}" for id, title in matched) found = "\n".join(f"{sid}: {title}" for sid, title in matched)
self.label.pack(expand=True)
self.label.config(text=found) self.label.config(text=found)
else: else:
self.label.pack(expand=True)
self.label.config(text="Ni zadetkov.") self.label.config(text="Ni zadetkov.")
# ------------------------------------------------------ # ------------------------------------------------------

View File

@@ -2,9 +2,9 @@
"font_name": "Times New Roman", "font_name": "Times New Roman",
"bg_color": "#000000", "bg_color": "#000000",
"fg_color": "#FFFFFF", "fg_color": "#FFFFFF",
"font_size": 38, "font_size": 32,
"screen_width_percent": 60, "screen_width_percent": 60,
"font_bold": true, "font_bold": true,
"show_song_info": true, "show_song_info": true,
"split_by_stanza": true "split_by_stanza": false
} }