#!/usr/bin/env python3 # -*- coding: utf-8 -*- import sqlite3 import json import os import urllib.request import sys # Dodajanje poti do korenskega imenika, da lahko uvozimo db_schema sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from db_schema import create_tables DB_PATH = 'songs.db' SETTINGS_PATH = 'settings.json' EXPORT_PATH = 'pesmi_export.txt' # --------------------------------------------------------------------------- # PREDHODNE NASTAVITVE IN POVEZAVA NA BAZO # --------------------------------------------------------------------------- if not os.path.exists(SETTINGS_PATH): print("Nastavitve manjkajo! Zaženi program za prjekcijo, da jih pripravi.") exit() with open(SETTINGS_PATH, "r", encoding="utf-8") as f: settings = json.load(f) conn = sqlite3.connect(DB_PATH) create_tables(conn) cursor = conn.cursor() # --------------------------------------------------------------------------- # POMOŽNE FUNKCIJE # --------------------------------------------------------------------------- def send_ntfy_notification(song_id, title, lyrics): """ Pošlje obvestilo o spremembi besedila preko ntfy.sh. """ topic = settings.get("ntfy_topic", "").strip() if not topic: return label = settings.get("installation_label", "Projekcija") message = f"{song_id}\n{title}\n{lyrics}" try: url = f"https://ntfy.sh/{topic}" req = urllib.request.Request( url, data=message.encode('utf-8'), method='POST' ) with urllib.request.urlopen(req, timeout=5) as response: pass except Exception as e: print(f"Napaka pri pošiljanju ntfy obvestila: {e}") def get_next_free_id(start: int = 792) -> int: """Vrne prvo prosto številko pesmi, ki je ≥ start (privzeto 792).""" next_id = start while True: cursor.execute("SELECT 1 FROM songs WHERE id = ?", (next_id,)) if cursor.fetchone() is None: return next_id next_id += 1 def slovenski_kljuc(naslov: str) -> str: nadom = {'č': 'cz', 'Č': 'Cz', 'š': 'sz', 'Š': 'Sz', 'ž': 'zz', 'Ž': 'Zz'} return ''.join(nadom.get(z, z) for z in naslov).lower() def prikazi_meni(): print("\nIzberi možnost:") print("1. Dodaj pesem") print("2. Uredi pesem") print("3. Prestavi pesem") print("4. Izbriši pesem") print("5. Izvozi bazo v TXT") print("6. Uvozi bazo iz TXT") print("7. Izpiši kazalo") print("9. Zapri program") def uredi_vnos(lines): processed, prazne = [], 0 for line in lines: if line.strip() == "": prazne += 1 continue if prazne: processed.extend([""] * prazne) prazne = 0 if line.strip().startswith("- "): line = line.replace("- ", "• ", 1) processed.append(line) if prazne: processed.extend([""] * prazne) return "\n".join(processed) # --------------------------------------------------------------------------- # FUNKCIJE POSAMEZNIH MENIJSKIH OPCIJ # --------------------------------------------------------------------------- def dodaj_pesem(): # -- izbira št. pesmi ---------------------------------------------------- while True: try: song_id = int(input("Vnesi številko pesmi: ")) break except ValueError: print("Vnesi veljavno celo število!") cursor.execute("SELECT title FROM songs WHERE id = ?", (song_id,)) row = cursor.fetchone() if row: print(f"Želiš prepisati obstoječo pesem {song_id} – {row[0]}?") predlagana = get_next_free_id() print(f"Prva prosta številka nad 791 je {predlagana}.") izbira = input("D = prepiši, N ali Enter = uporabi predlagano, " "ali vnesi drugo številko: ").strip() if izbira.lower() == "d": pass elif izbira.lower() == "n" or izbira == "": song_id = predlagana else: try: song_id = int(izbira) except ValueError: print("Neveljaven vnos – uporabljam predlagano številko.") song_id = predlagana # -- vnos besedila ------------------------------------------------------- title = input("Vnesi naslov pesmi: ") print("Vnesi besedilo (prazna vrstica = presledek, dve prazni = nova kitica).\n" "Ko končaš, vpiši 'konec'.") lines = [] while True: line = input() if line.strip().lower() == "konec": break if line.strip().startswith("- "): line = line.replace("- ", "• ", 1) lines.append(line) full_lyrics = uredi_vnos(lines) cursor.execute("INSERT OR REPLACE INTO songs (id, title, lyrics) VALUES (?,?,?)", (song_id, title, full_lyrics)) conn.commit() send_ntfy_notification(song_id, title, full_lyrics) print("Pesem uspešno shranjena!") def uredi_pesem(): try: song_id = int(input("Vnesi številko pesmi za urejanje: ")) except ValueError: print("Uporabi celo število!") return cursor.execute("SELECT title, lyrics FROM songs WHERE id = ?", (song_id,)) result = cursor.fetchone() if not result: print("Pesem s to številko ne obstaja.") return print(f"Trenutni naslov: {result[0]}") print(f"Trenutno besedilo:\n{result[1]}") new_title = input("Nov naslov (pusti prazno za obdržanje): ") print("Novo besedilo (vpiši 'konec' za zaključek, pusti prazno za obdržanje):") lines = [] while True: line = input() if line.strip().lower() == "konec": break if line.strip().startswith("- "): line = line.replace("- ", "• ", 1) lines.append(line) if new_title.strip() == "": new_title = result[0] new_lyrics = result[1] if len(lines) == 0 else uredi_vnos(lines) cursor.execute("UPDATE songs SET title = ?, lyrics = ? WHERE id = ?", (new_title, new_lyrics, song_id)) conn.commit() send_ntfy_notification(song_id, new_title, new_lyrics) print("Pesem uspešno posodobljena!") def prestavi_pesem(): try: old_id = int(input("Vnesi številko pesmi, ki jo želiš prestaviti: ")) new_id = int(input("Vnesi novo številko pesmi: ")) except ValueError: print("Uporabi cela števila!") return cursor.execute("SELECT title, lyrics FROM songs WHERE id = ?", (old_id,)) vir = cursor.fetchone() if vir is None: print("Pesem s to številko ne obstaja.") return cursor.execute("SELECT title FROM songs WHERE id = ?", (new_id,)) cilj = cursor.fetchone() if cilj: print(f"Želiš prepisati obstoječo pesem {new_id} – {cilj[0]}?") predlagana = get_next_free_id() print(f"Prva prosta številka nad 791 je {predlagana}.") izbira = input("D = prepiši, N ali Enter = predlagana, ali vnesi drugo številko: ").strip() if izbira.lower() == "d": pass elif izbira.lower() == "n" or izbira == "": new_id = predlagana else: try: new_id = int(izbira) except ValueError: print("Neveljaven vnos – uporabljam predlagano številko.") new_id = predlagana cursor.execute("INSERT OR REPLACE INTO songs (id, title, lyrics) VALUES (?,?,?)", (new_id, vir[0], vir[1])) cursor.execute("DELETE FROM songs WHERE id = ?", (old_id,)) conn.commit() send_ntfy_notification(new_id, vir[0], vir[1]) print("Pesem uspešno prestavljena!") def izbrisi_pesem(): try: song_id = int(input("Vnesi številko pesmi za izbris: ")) except ValueError: print("Uporabi celo število!") return cursor.execute("SELECT title FROM songs WHERE id = ?", (song_id,)) row = cursor.fetchone() if row is None: print("Pesem s to številko ne obstaja.") return potrdi = input(f"Želiš res izbrisati pesem {song_id} – {row[0]}? (D/N): ").strip().lower() if potrdi == "d": cursor.execute("DELETE FROM songs WHERE id = ?", (song_id,)) conn.commit() print("Pesem uspešno izbrisana!") else: print("Brisanje preklicano.") def izvozi_bazo(): cursor.execute("SELECT id, title, lyrics FROM songs ORDER BY id") pesmi = cursor.fetchall() with open(EXPORT_PATH, "w", encoding="utf-8") as f: for pesem in pesmi: f.write("===\n") f.write(f"{pesem[0]}\n{pesem[1]}\n{pesem[2]}\n") print(f"Baza je bila izvožena v '{EXPORT_PATH}'.") # --------------------------------------------------------------------------- # 6. UVOZ BAZE Z NAPREDNO KONTROLO PODVOJENIH PESMI # --------------------------------------------------------------------------- def uvozi_bazo(): if not os.path.exists(EXPORT_PATH): print(f"Datoteka '{EXPORT_PATH}' ne obstaja.") return with open(EXPORT_PATH, "r", encoding="utf-8") as f: vsebina = f.read().replace('\r\n', '\n').replace('\r', '\n') pesmi_raw = [p for p in vsebina.strip().split("===\n") if p.strip()] duplicate_mode = None # 'd', 'n', 'p' ==> vedno prepiši / preskoči / nova ID for pesem_raw in pesmi_raw: vrstice = pesem_raw.strip().split("\n") if len(vrstice) < 3: print("Preskočena nepopolna pesem.") continue try: song_id = int(vrstice[0]) except ValueError: print("Neveljaven ID – preskočeno.") continue title = vrstice[1] raw_lyrics_lines = vrstice[2:] # -- predobdelava besedila ------------------------------------------ processed_lines, prazne = [], 0 for line in raw_lyrics_lines: if line.strip().startswith("- "): line = line.replace("- ", "• ", 1) if line.strip() == "": prazne += 1 continue if prazne: processed_lines.extend([""] * prazne) prazne = 0 processed_lines.append(line) if prazne: processed_lines.extend([""] * prazne) lyrics = "\n".join(processed_lines) # -- obravnava podvojene številke ----------------------------------- cursor.execute("SELECT title FROM songs WHERE id = ?", (song_id,)) exists = cursor.fetchone() if exists: # Če imamo globalni način, ga upoštevamo if duplicate_mode is not None: choice = duplicate_mode else: print(f"\nPozor: pesem št. {song_id} – \"{exists[0]}\" že obstaja.") print("Izberi dejanje:") print(" d … prepiši") print(" n … preskoči") print(" p … shrani pod prvo prosto številko ≥ 792") print(" da … prepiši to in vse naslednje podvojene pesmi") print(" na … preskoči to in vse naslednje podvojene pesmi") print(" pa … shrani to in vse naslednje podvojene pesmi pod novo ID") izbira = input("Tvoja izbira: ").strip().lower() if izbira in {"da", "na", "pa"}: duplicate_mode = izbira[0] # 'd', 'n', 'p' choice = duplicate_mode elif izbira in {"d", "n", "p"}: choice = izbira else: print("Neznana izbira – pesem preskočena.") continue # izvajanje po izbrani logiki if choice == "n": print("Pesem preskočena.") continue elif choice == "p": song_id = get_next_free_id() print(f"Shranjujem pod novo številko {song_id}.") # choice == 'd' -> prepis # -- shranjevanje pesmi --------------------------------------------- cursor.execute("INSERT OR REPLACE INTO songs (id, title, lyrics) VALUES (?,?,?)", (song_id, title, lyrics)) send_ntfy_notification(song_id, title, lyrics) conn.commit() print("\nUvoz pesmi uspešen!") # --------------------------------------------------------------------------- # DODATNE FUNKCIJE (kazalo, projekcija) – nespremenjene # --------------------------------------------------------------------------- def izpisi_kazalo(): poglavja = [ (13, " -- SLAVIMO GOSPODA -- "), (13, "ADVENTNE"), (27, "BOŽIČNA DEVETDNEVNICA"), (39, "BOŽIČNE"), (65, "POSTNE"), (119, "VELIKONOČNE"), (142, "ČAS MED LETOM"), (160, "MARIJINE"), (240, "SVETNIŠKE"), (263, "ZAKRAMENTI"), (383, "MAŠNE"), (406, "DAROVANJSKE"), (419, "OBHAJILNE"), (470, "BLAGOSLOVNE"), (497, "ZAKRAMENT SPRAVE"), (505, "MAŠNIŠKO POSVEČENJE"), (539, "POGREB"), (696, "LITANIJE"), (773, "KRIŽEV POT"), (777, "ROŽNI VENEC"), (786, "MISIJONSKE"), (788, "ZAHVALNE"), (790, "JUBILATE DEO in ON ŽIVI"), (1273,"DRUGE PESMI"), ] cursor.execute("SELECT id, title FROM songs ORDER BY id") zaporedno = cursor.fetchall() cursor.execute("SELECT id, title FROM songs") abecedno = cursor.fetchall() abecedno.sort(key=lambda x: slovenski_kljuc(x[1])) with open("kazalo.txt", "w", encoding="utf-8") as f: f.write("ZAPOREDNO KAZALO\n") trenutno_poglavje, indeks = None, 0 for pesem in zaporedno: while indeks < len(poglavja) and pesem[0] >= poglavja[indeks][0]: trenutno_poglavje = poglavja[indeks][1] f.write(f"\n--- {trenutno_poglavje} ---\n") indeks += 1 f.write(f"{pesem[0]}\t{pesem[1]}\n") f.write("\n\nABECEDNO KAZALO\n") for pesem in abecedno: f.write(f"{pesem[0]}\t{pesem[1]}\n") print("Kazalo izpisano v 'kazalo.txt'.") # --------------------------------------------------------------------------- # G L A V N I Z A G O N # --------------------------------------------------------------------------- def main(): while True: prikazi_meni() izbira = input("Vnesi številko možnosti: ").strip() os.system('cls' if os.name == 'nt' else 'clear') if izbira == "1": dodaj_pesem() elif izbira == "2": uredi_pesem() elif izbira == "3": prestavi_pesem() elif izbira == "4": izbrisi_pesem() elif izbira == "5": izvozi_bazo() elif izbira == "6": uvozi_bazo() elif izbira == "7": izpisi_kazalo() elif izbira == "9": print("Program se zapira …") break else: print("Napačna izbira, poskusi znova.") conn.close() if __name__ == "__main__": main()