Added function for media resolution tagging

This commit is contained in:
2025-10-03 17:29:54 +02:00
parent 6936f376c3
commit 3f6fe0fb4d
11 changed files with 199 additions and 36 deletions

View File

@@ -6,13 +6,16 @@ from tkinter import ttk, simpledialog, messagebox, filedialog
from pathlib import Path
from typing import List
from src.core.image import load_icon
from src.core.media_utils import load_icon
from src.core.file_manager import FileManager
from src.core.tag_manager import TagManager
from src.core.file import File
from src.core.tag import Tag
from src.core.list_manager import ListManager
from src.core.constants import APP_NAME, VERSION, APP_VIEWPORT
from src.core.config import save_config # <-- doplněno
class TagSelectionDialog(tk.Toplevel):
@@ -40,7 +43,7 @@ class TagSelectionDialog(tk.Toplevel):
btn_frame = tk.Frame(self)
btn_frame.pack(pady=5)
tk.Button(btn_frame, text="OK", command=self.on_ok).pack(side="left", padx=5)
tk.Button(btn_frame, text="Cancel", command=self.destroy).pack(side="left", padx=5)
tk.Button(btn_frame, text="Zrušit", command=self.destroy).pack(side="left", padx=5)
self.transient(parent)
self.grab_set()
@@ -127,7 +130,7 @@ class MultiFileTagAssignDialog(tk.Toplevel):
class App:
def __init__(self, filehandler: FileManager, tagmanager: TagManager):
self.states = {} # tree states (checkboxy) item_id -> bool
self.states = {}
self.listbox_map: dict[int, list[File]] = {}
self.selected_tree_item_for_context = None
self.selected_list_index_for_context = None
@@ -135,15 +138,48 @@ class App:
self.tagmanager = tagmanager
self.list_manager = ListManager()
# nové proměnné
# tady jen připravíme proměnnou, ale nevytváříme BooleanVar!
self.hide_ignored_var = None
self.filter_text = ""
self.show_full_path = False
self.sort_mode = "name"
self.sort_order = "asc"
# callback z FileManageru
self.filehandler.on_files_changed = self.update_files_from_manager
def detect_video_resolution(self):
files = self.get_selected_files_objects()
if not files:
self.status_bar.config(text="Nebyly vybrány žádné soubory")
return
count = 0
for f in files:
try:
path = str(f.file_path)
result = subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=height", "-of", "csv=p=0", path],
capture_output=True,
text=True,
check=True
)
height_str = result.stdout.strip()
if not height_str.isdigit():
continue
height = int(height_str)
tag_name = f"{height}p"
tag_obj = self.tagmanager.add_tag("Rozlišení", tag_name)
f.add_tag(tag_obj)
count += 1
except Exception as e:
print(f"Chyba u {f.filename}: {e}")
self.update_files_from_manager(self.filehandler.filelist)
self.status_bar.config(text=f"Přiřazeno rozlišení tagů k {count} souborům")
# ==================================================
# MAIN GUI
# ==================================================
@@ -153,6 +189,16 @@ class App:
root.geometry(APP_VIEWPORT)
self.root = root
# teď už máme root, takže můžeme vytvořit BooleanVar
self.hide_ignored_var = tk.BooleanVar(value=False, master=root)
last = self.filehandler.config.get("last_folder")
if last:
try:
self.filehandler.append(Path(last))
except Exception:
pass
# ---- Ikony
unchecked = load_icon("src/resources/images/32/32_unchecked.png")
checked = load_icon("src/resources/images/32/32_checked.png")
@@ -165,12 +211,27 @@ class App:
# ---- Layout
menu_bar = tk.Menu(root)
root.config(menu=menu_bar)
file_menu = tk.Menu(menu_bar, tearoff=0)
file_menu.add_command(label="Open Folder...", command=self.open_folder_dialog)
file_menu.add_command(label="Set date for selected...", command=self.set_date_for_selected)
file_menu.add_command(label="Nastavit ignorované vzory", command=self.set_ignore_patterns)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=root.quit)
menu_bar.add_cascade(label="File", menu=file_menu)
view_menu = tk.Menu(menu_bar, tearoff=0)
view_menu.add_checkbutton(
label="Skrýt ignorované",
variable=self.hide_ignored_var,
command=self.toggle_hide_ignored
)
function_menu = tk.Menu(menu_bar, tearoff=0)
function_menu.add_command(label="Nastavit datum", command=self.set_date_for_selected)
function_menu.add_command(label="Detekovat rozlišení u videí", command=self.detect_video_resolution)
menu_bar.add_cascade(label="Soubor", menu=file_menu)
menu_bar.add_cascade(label="Pohled", menu=view_menu)
menu_bar.add_cascade(label="Funkce", menu=function_menu)
main_frame = tk.Frame(root)
main_frame.pack(fill="both", expand=True)
@@ -192,7 +253,7 @@ class App:
# Filter + buttons row
filter_frame = tk.Frame(right_frame)
filter_frame.grid(row=0, column=0, columnspan=2, sticky="ew", pady=(0,4))
filter_frame.grid(row=0, column=0, columnspan=2, sticky="ew", pady=(0, 4))
filter_frame.columnconfigure(0, weight=1)
self.filter_entry = tk.Entry(filter_frame)
@@ -224,14 +285,14 @@ class App:
# ---- Context menus
self.tree_menu = tk.Menu(root, tearoff=0)
self.tree_menu.add_command(label="Nový tag zde", command=self.tree_add_tag)
self.tree_menu.add_command(label="Smazat tag", command=self.tree_delete_tag)
self.tree_menu.add_command(label="Nový štítek", command=self.tree_add_tag)
self.tree_menu.add_command(label="Smazat štítek", command=self.tree_delete_tag)
self.list_menu = tk.Menu(root, tearoff=0)
self.list_menu.add_command(label="Otevřít soubor", command=self.list_open_file)
self.list_menu.add_command(label="Smazat z indexu", command=self.list_remove_file)
self.list_menu.add_command(label="Assign Tag", command=self.assign_tag_to_selected)
self.list_menu.add_command(label="Assign Tag (advanced)...", command=self.assign_tag_to_selected_bulk)
self.list_menu.add_command(label="Nastavit datum", command=self.set_date_for_selected)
self.list_menu.add_command(label="Přiřadit štítek", command=self.assign_tag_to_selected_bulk)
# ---- Root node
root_id = self.tree.insert("", "end", text="Štítky", image=self.icons["tag"])
@@ -244,9 +305,23 @@ class App:
root.mainloop()
# ==================================================
# FILTER + SORT TOGGLES
# ==================================================
def set_ignore_patterns(self):
current = ", ".join(self.filehandler.config.get("ignore_patterns", []))
s = simpledialog.askstring("Ignore patterns", "Zadej patterny oddělené čárkou (např. *.png, *.tmp):", initialvalue=current)
if s is None:
return
patterns = [p.strip() for p in s.split(",") if p.strip()]
self.filehandler.config["ignore_patterns"] = patterns
save_config(self.filehandler.config)
self.update_files_from_manager(self.filehandler.filelist)
def toggle_hide_ignored(self):
self.update_files_from_manager(self.filehandler.filelist)
def on_filter_changed(self):
self.filter_text = self.filter_entry.get().strip().lower()
self.update_files_from_manager(self.filehandler.filelist)
@@ -285,6 +360,14 @@ class App:
(self.show_full_path and self.filter_text in str(f.file_path).lower())
]
if self.hide_ignored_var and self.hide_ignored_var.get():
filtered_files = [
f for f in filtered_files
if "Stav/Ignorované" not in {t.full_path for t in f.tags}
]
# řazení
reverse = (self.sort_order == "desc")
if self.sort_mode == "name":