# 📝 Tagger - Centrální Poznámky Projektu > **DŮLEŽITÉ:** Tento soubor obsahuje VŠE co potřebuji vědět o projektu. > Pokud pracuji na Tagger, VŽDY nejdříve přečtu tento soubor! **Poslední aktualizace:** 2025-12-23 **Verze:** 1.0.2 **Status:** ✅ Stable, v aktivním vývoji --- ## 🎯 O projektu **Tagger** je desktopová aplikace pro správu a organizaci souborů pomocí hierarchických tagů (štítků). **Hlavní funkce:** - Rekurzivní procházení složek - Hierarchické tagy (kategorie/název) - Filtrování podle tagů - Metadata uložená v JSON souborech - Automatická detekce rozlišení videí (ffprobe) - Dvě verze GUI: klasické a moderní (qBittorrent-style) - TODO: Budu mit filmotéku ve složce sloužící jako zdroj (zadne složky uvnitr jen hromada souborů a tagy) a chctel bych na pokyn (menu funkce) aby povytvářel složky dle kategorii tagů a uložil hardlinky na prislušná místa (orig složka: film s tagy "žánr/Komedie" "žánr/Akční" "rok/1988" a soubor v originalni složce zanechá a jen vytvoří na danem míste všechny složky zala tyto zmínene tagy a vytvoří linky) --- ## 📁 Struktura projektu ``` Tagger/ ├── Tagger.py # Entry point - klasické GUI ├── Tagger_modern.py # Entry point - moderní GUI ├── PROJECT_NOTES.md # ← TENTO SOUBOR - HLAVNÍ ZDROJ PRAVDY ├── pyproject.toml # Poetry konfigurace ├── poetry.lock # Zamčené verze závislostí ├── pytest.ini # Pytest konfigurace ├── .editorconfig # Editor konfigurace ├── .gitignore # Git ignore pravidla │ ├── src/ │ ├── core/ # Jádro aplikace (ŽÁDNÉ UI!) │ │ ├── tag.py # Tag value object (immutable) │ │ ├── tag_manager.py # Správa tagů a kategorií │ │ ├── file.py # File s metadaty │ │ ├── file_manager.py # Správa souborů, filtrování │ │ ├── config.py # Konfigurace (JSON) │ │ ├── utils.py # list_files() - rekurzivní procházení │ │ ├── media_utils.py # load_icon(), ffprobe │ │ ├── constants.py # APP_NAME, VERSION, APP_VIEWPORT │ │ └── list_manager.py # Třídění (málo používaný) │ │ │ └── ui/ │ ├── gui.py # Původní Tkinter GUI │ ├── gui_modern.py # Moderní qBittorrent-style GUI ✨ NOVÉ │ └── gui_old.py # Backup původního GUI │ ├── tests/ # 116 testů, 100% core coverage │ ├── __init__.py │ ├── conftest.py # Pytest fixtures │ ├── test_tag.py # 13 testů │ ├── test_tag_manager.py # 19 testů │ ├── test_file.py # 22 testů │ ├── test_file_manager.py # 22 testů │ ├── test_utils.py # 17 testů │ ├── test_config.py # 18 testů │ ├── test_media_utils.py # 3 testy │ └── README.md # Dokumentace testů │ ├── src/resources/ │ └── images/32/ # Ikony (16x16 PNG) │ ├── 32_unchecked.png │ ├── 32_checked.png │ └── 32_tag.png │ └── docs/ # Dokumentace (ZASTARALÁ - použij tento soubor!) ├── ARCHITECTURE.md # ⚠️ DEPRECATED - info je zde ├── CONTRIBUTING.md # ⚠️ DEPRECATED - info je zde └── GUI_MODERN_README.md # ⚠️ DEPRECATED - info je zde ``` --- ## 🎨 Architektura ### Vrstvová struktura ``` ┌─────────────────────────────────┐ │ Presentation (UI) │ ← gui.py, gui_modern.py │ - Tkinter GUI │ - NESMÍ obsahovat business logiku │ - Jen zobrazení + interakce │ - NESMÍ importovat přímo z core ├─────────────────────────────────┤ │ Business Logic │ ← FileManager, TagManager │ - Správa souborů/tagů │ - Callable z UI │ - Filtrování, validace │ - Callback pattern pro notifikace ├─────────────────────────────────┤ │ Data Layer │ ← File, Tag (models) │ - File, Tag třídy │ - Immutable kde je možné │ - Validation logic │ - __eq__ a __hash__ správně ├─────────────────────────────────┤ │ Persistence │ ← config.py, .!tag soubory │ - JSON soubory │ - UTF-8 encoding VŽDY │ - Config management │ - ensure_ascii=False └─────────────────────────────────┘ ``` ### Klíčová pravidla #### ✅ CO DĚLAT: 1. **UI NESMÍ obsahovat business logiku** ```python # ❌ ŠPATNĚ class GUI: def save_file(self): with open(file, 'w') as f: json.dump(data, f) # ✅ SPRÁVNĚ class GUI: def save_file(self): self.filemanager.save_file(file) ``` 2. **Core moduly NESMÍ importovat UI** ```python # V src/core/*.py NIKDY: import tkinter from src.ui import anything ``` 3. **Dependency Injection - předávat dependencies přes konstruktor** ```python class FileManager: def __init__(self, tagmanager: TagManager): self.tagmanager = tagmanager ``` 4. **UTF-8 encoding VŠUDE** ```python with open(file, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) ``` 5. **Type hints VŽDY** ```python def filter_files(files: List[File], tags: List[Tag]) -> List[File]: pass ``` #### ❌ CO NEDĚLAT: 1. **Globální stav** ```python # ❌ NIKDY current_file = None # global ``` 2. **Magic numbers** ```python # ❌ ŠPATNĚ if len(files) > 100: # ✅ SPRÁVNĚ MAX_FILES = 100 if len(files) > MAX_FILES: ``` 3. **Ignorovat exceptions** ```python # ❌ NIKDY try: operation() except: pass ``` 4. **Hardcoded paths** ```python # ❌ ŠPATNĚ icon = "/home/user/icon.png" # ✅ SPRÁVNĚ ICON_DIR = Path(__file__).parent / "resources" icon = ICON_DIR / "icon.png" ``` --- ## 🔑 Klíčové komponenty ### 1. Tag (immutable value object) ```python class Tag: def __init__(self, category: str, name: str): self.category = category # Nemění se po vytvoření! self.name = name @property def full_path(self) -> str: return f"{self.category}/{self.name}" def __eq__(self, other): return (self.category, self.name) == (other.category, other.name) def __hash__(self): return hash((self.category, self.name)) ``` **Proč immutable?** - Lze použít jako klíč v dict/set - Thread-safe - Jasná sémantika rovnosti ### 2. File (reprezentace souboru s metadaty) ```python class File: def __init__(self, file_path: Path, tagmanager=None): self.file_path = file_path self.filename = file_path.name self.metadata_filename = parent / f".{filename}.!tag" self.tags: list[Tag] = [] self.date: str | None = None self.get_metadata() # Auto-load při vytvoření ``` **Metadata format (.filename.!tag):** ```json { "new": false, "ignored": false, "tags": ["Stav/Nové", "Video/HD"], "date": "2025-12-23" } ``` **DŮLEŽITÉ:** - Každá změna (add_tag, set_date) automaticky volá `save_metadata()` - UTF-8 encoding! - ensure_ascii=False pro češtinu ### 3. TagManager (správa tagů) ```python class TagManager: def __init__(self): self.tags_by_category = {} # {category: set(Tag)} def add_tag(self, category: str, name: str) -> Tag: # Vytvoří kategorii pokud neexistuje # Používá set - duplicity automaticky ignorovány # Vrací Tag objekt ``` **Speciální chování:** - Když odstraníš poslední tag z kategorie → kategorie se smaže - Set zajišťuje uniqueness - Vždy vrací Tag objekt (ne string) ### 4. FileManager (správa souborů) ```python class FileManager: def __init__(self, tagmanager: TagManager): self.filelist: list[File] = [] self.tagmanager = tagmanager self.on_files_changed = None # CALLBACK pro UI! self.config = load_config() def append(self, folder: Path): # Rekurzivně načte soubory # Ignoruje podle patterns # Vytvoří File objekty # Zavolá on_files_changed callback ``` **Callback pattern:** ```python # V GUI: filemanager.on_files_changed = self.update_ui # V FileManager: if self.on_files_changed: self.on_files_changed(self.filelist) ``` **Proč callback?** - Core nezávisí na UI - Jednoduché na testování - Flexibilní (můžeš změnit UI bez změny core) --- ## 🎨 GUI Verze ### Klasické GUI (gui.py) ``` ┌─────────────────────────────────────────┐ │ Soubor │ Pohled │ Funkce Menu ├──────────┬──────────────────────────────┤ │ │ [Filter____] [Name][Name][ASC] │ Tree │ ┌──────────────────────────┐ │ │ (tagy) │ │ Listbox (soubory) │ │ │ 📂 Štítky│ │ - file1.txt — 2025-01-01│ │ │ ☑ Nové │ │ - file2.mp4 │ │ │ ☐ HD │ │ - file3.jpg │ │ │ │ └──────────────────────────┘ │ ├──────────┴──────────────────────────────┤ │ Status: Připraven │ └─────────────────────────────────────────┘ ``` **Použít:** `poetry run python Tagger.py` ### Moderní GUI (gui_modern.py) ✨ NOVÉ ``` ┌─────────────────────────────────────────────────────┐ │ 📁 Otevřít │ 🔄 │ 🏷️ │ 📅 🔍 [____] Toolbar ├────────────┬────────────────────────────────────────┤ │ 📂 Štítky │ ☐ Plná │ Třídění: [Název] [▲] │ │ ├─📁 Stav │ ┌──────────────────────────────────┐ │ │ │ ☑ Nové │ │ Název│Datum│Štítky│Velikost │ │ │ │ ☐ OK │ │file1 │2025 │HD │1.2 MB │ │ │ ├─📁 Video│ │file2 │ │4K │15 MB │ │ │ │ ☐ HD │ └──────────────────────────────────┘ │ │ │ ☐ 4K │ │ ├────────────┴───────────────────────────────────────┤ │ Připraven 3 vybráno │ 125 souborů │ └─────────────────────────────────────────────────────┘ ``` **Použít:** `poetry run python Tagger_modern.py` **Nové funkce:** - 📋 Tabulka s 4 sloupci (Název, Datum, Štítky, Velikost) - 🔧 Toolbar s tlačítky - ⌨️ Keyboard shortcuts (Ctrl+O, Ctrl+T, F5, Del...) - 📊 Status bar se 3 sekcemi - 🎨 qBittorrent-inspired design **Keyboard shortcuts:** - `Ctrl+O` - Otevřít složku - `Ctrl+Q` - Ukončit - `Ctrl+T` - Přiřadit tagy - `Ctrl+D` - Nastavit datum - `Ctrl+F` - Focus search - `F5` - Refresh - `Del` - Smazat z indexu --- ## 🔧 Vývoj ### Setup prostředí ```bash # Poetry environment (VŽDY použij poetry!) poetry install poetry shell # Nebo přímo: poetry run python Tagger_modern.py ``` **Poetry environment path:** ``` /home/honza/.cache/pypoetry/virtualenvs/tagger-qKyHMOtL-py3.12 ``` ### Spuštění aplikace ```bash # Moderní GUI (doporučeno) poetry run python Tagger_modern.py # Klasické GUI poetry run python Tagger.py ``` ### Testy ```bash # Všechny testy (116 testů) poetry run pytest tests/ -v # S coverage poetry run pytest tests/ --cov=src/core --cov-report=html # Konkrétní modul poetry run pytest tests/test_file.py -v # Quick check poetry run pytest tests/ -q ``` **Test coverage:** 100% core modulů ✅ ### Linting & Formatting ```bash # TODO: Přidat black, flake8 do pyproject.toml # Zatím manuální kontrola podle PEP 8 ``` --- ## 📝 Coding Standards ### Python Style - **PEP 8** s výjimkami: - Max line length: **120** (ne 79) - Indentation: **4 mezery** (ne taby) - **UTF-8** encoding všude - **Type hints** povinné - **Docstrings** pro public API ### Naming Conventions ```python # Classes class FileManager: pass # Functions/methods def load_config(): pass # Constants APP_NAME = "Tagger" MAX_FILES = 1000 # Private def _internal_method(): pass ``` ### Imports Order ```python # 1. Standard library import os import sys from pathlib import Path # 2. Third-party import tkinter as tk from PIL import Image # 3. Local from src.core.file import File from src.core.tag import Tag ``` ### String Formatting ```python # ✅ F-strings name = "John" msg = f"Hello, {name}!" # ❌ NE msg = "Hello, " + name msg = "Hello, {}".format(name) ``` --- ## 🔀 Git Workflow ### Branches ``` main/master ← Production (NE commity přímo!) ↑ release ← Release candidate ↑ devel ← Development integration ↑ feature/* ← Feature branches ← VYVÍJÍME TADY ``` ### Commit Messages ``` : [optional body] 🤖 Generated with Claude Code Co-Authored-By: Claude Sonnet 4.5 ``` **Types:** - `feat:` - Nová funkce - `fix:` - Bug fix - `refactor:` - Refactoring - `test:` - Testy - `docs:` - Dokumentace - `style:` - Formátování - `chore:` - Build, dependencies **Příklad:** ```bash git commit -m "feat: Add modern qBittorrent-style GUI Implemented new GUI with toolbar, table view, and keyboard shortcuts. 🤖 Generated with Claude Code Co-Authored-By: Claude Sonnet 4.5 " ``` --- ## 🎯 Design Decisions (ADR) ### ADR-001: JSON soubory místo databáze **Rozhodnutí:** Metadata v `.filename.!tag` JSON souborech **Proč:** - ✅ Jednoduchý backup (copy složky) - ✅ Git-friendly - ✅ Portable - ✅ Metadata zůstanou při přesunu souboru **Kdy přehodnotit:** - Pokud >10k souborů (zvážit SQLite) ### ADR-002: Callback pattern pro UI updates **Rozhodnutí:** `on_files_changed` callback **Proč:** - ✅ Core nezávisí na UI - ✅ Jednoduché testování - ✅ Flexibilní **Alternativy zamítnuté:** - Observer pattern (overkill) - Event system (složitější) ### ADR-003: Tkinter pro GUI **Rozhodnutí:** Tkinter (standard library) **Proč:** - ✅ Žádné extra dependencies - ✅ Cross-platform - ✅ Dobře dokumentované **Alternativy:** - Qt - lepší UI, ale větší závislost - Web - overkill pro desktop app ### ADR-004: Poetry pro dependencies **Rozhodnutí:** Poetry místo pip **Proč:** - ✅ Deterministické buildy (poetry.lock) - ✅ Dev dependencies oddělené - ✅ Moderní tool --- ## 🐛 Známé problémy & TODO ### Aktuální problémy 1. **Git merge konflikty** - `poetry.lock` a `pyproject.toml` - konflikty při merge devel→feature - `tests/test_image.py` - deleted in devel, modified in feature - **Stav:** Nezresolváno ⚠️ 2. **ListManager málo použitý** - Třídící logika duplicitní v GUI - **TODO:** Refactor nebo odstranit 3. **Dlouhé operace blokují UI** - ffprobe detection běží v main threadu - **TODO:** Threading pro dlouhé operace ### Plánované features - [ ] Progress bar pro dlouhé operace - [ ] Undo/Redo mechanismus - [ ] Export do CSV/Excel - [ ] Dark mode theme - [ ] Drag & drop souborů - [ ] Image preview v sidebar - [ ] SQLite fallback pro >10k souborů - [ ] Full-text search ### Nice to have - [ ] Plugin systém - [ ] Web interface (Flask) - [ ] Cloud sync (Dropbox, GDrive) - [ ] Batch rename podle tagů - [ ] Smart folder suggestions --- ## 📊 Metriky projektu **Řádky kódu:** ~1060 Python LOC **Testy:** 116 (všechny ✅) **Test coverage:** 100% core modulů **Python verze:** 3.12 **Dependencies:** Pillow (PIL) **Vývojové prostředí:** Poetry **Performance:** - ✅ Dobré: <1000 souborů - ⚠️ Přijatelné: 1000-5000 souborů - ❌ Pomalé: >5000 souborů --- ## 🔍 Debugování ### Časté problémy **1. "Cannot import ImageTk"** ```bash # Řešení: Použij poetry environment poetry run python Tagger_modern.py ``` **2. "Config file not found"** ```bash # Normální při prvním spuštění # Vytvoří se automaticky config.json ``` **3. "Metadata corrupted"** ```python # V config.py je graceful degradation # Vrátí default config při chybě ``` ### Logování ```python # Zatím jen print() statements # TODO: Přidat logging module import logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) ``` --- ## 📚 Dokumentace **✅ AKTUÁLNÍ:** - **PROJECT_NOTES.md** - TENTO SOUBOR (single source of truth) ⭐ - Docstrings v kódu **📝 Poznámka:** - Všechny ostatní .md soubory byly smazány a skonsolidovány SEM - .gitignore ignoruje všechny .md kromě PROJECT_NOTES.md - Pokud vytvoříš nový .md, MUSÍŠ ho přidat do .gitignore whitelist --- ## 💡 Pro AI asistenty (jako Claude) ### Když začínám práci na projektu: 1. ✅ **PŘEČTI TENTO SOUBOR CELÝ!** 2. ✅ Zkontroluj `git status` 3. ✅ Aktivuj poetry environment 4. ✅ Spusť testy (`poetry run pytest tests/`) 5. ✅ Dodržuj pravidla výše ### Při commitování: 1. ✅ Testy prošly (`pytest tests/`) 2. ✅ Type hints přidány 3. ✅ UTF-8 encoding 4. ✅ Žádné TODO/FIXME 5. ✅ Commit message formát správný ### Při přidání nové funkce: 1. ✅ Testy napsány PŘED implementací (TDD) 2. ✅ Dokumentace aktualizována (TENTO SOUBOR!) 3. ✅ Architecture decision zdokumentováno (pokud významné) 4. ✅ Type hints všude 5. ✅ Error handling přidán ### Při refactoringu: 1. ✅ Testy před (měly by projít) 2. ✅ Refactor 3. ✅ Testy po (měly by stále projít) 4. ✅ Update dokumentace --- ## 📞 Kontakt & Help **Autor:** honza **Repository:** /home/honza/Dokumenty/Tagger **Python:** 3.12 **OS:** Linux 6.14.0-37-generic **Pro pomoc:** - Přečti TENTO soubor - Podívej se do testů (`tests/`) - Zkontroluj docstrings v kódu - V nouzi spusť: `poetry run python -i` a explorej objekty --- ## 📅 Changelog ### [Unreleased] - Merge konflikty s devel branch (poetry.lock, test_image.py) ### [1.0.2] - 2025-12-23 - ✨ Přidáno moderní GUI (gui_modern.py) - ✨ Keyboard shortcuts - ✨ Tabulkové zobrazení s 4 sloupci - ✨ Toolbar s tlačítky - ✨ 116 testů (100% core coverage) - 📝 Vytvoření PROJECT_NOTES.md (tento soubor) - 🔧 Poetry setup ### [1.0.1] - 2025-10-05 - 🐛 Bug fixy - ✨ Video resolution detection ### [1.0.0] - 2025-10-05 - 🎉 Initial release - ✨ Základní funkcionalita - ✨ Tkinter GUI - ✨ JSON metadata --- ## 🎉 Poznámky na závěr **Tento soubor je SINGLE SOURCE OF TRUTH pro projekt Tagger.** Když přidávám funkci, fixuju bug, nebo dělám změnu: 1. Nejdřív PŘEČTU tento soubor 2. Pak UPRAVÍM kód 3. Pak AKTUALIZUJU tento soubor **Living document** - průběžně aktualizován! --- **Last updated:** 2025-12-23 18:30 **Next review:** Při každé větší změně **Maintainer:** Claude Sonnet 4.5 + honza --- ## 📋 Changelog dokumentace ### 2025-12-23 11:24 - Konsolidace dokumentace - ✅ Smazány: CONTRIBUTING.md, GUI_MODERN_README.md, docs/ARCHITECTURE.md - ✅ Vše skonsolidováno do PROJECT_NOTES.md - ✅ Vytvořen README.md pro GitHub (základní intro) - ✅ Aktualizován .gitignore (ignoruje všechny .md kromě PROJECT_NOTES.md a README.md) - ⭐ **PROJECT_NOTES.md je nyní jediný zdroj pravdy pro dokumentaci!**