20 KiB
📝 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)
📁 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:
-
UI NESMÍ obsahovat business logiku
# ❌ Š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) -
Core moduly NESMÍ importovat UI
# V src/core/*.py NIKDY: import tkinter from src.ui import anything -
Dependency Injection - předávat dependencies přes konstruktor
class FileManager: def __init__(self, tagmanager: TagManager): self.tagmanager = tagmanager -
UTF-8 encoding VŠUDE
with open(file, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) -
Type hints VŽDY
def filter_files(files: List[File], tags: List[Tag]) -> List[File]: pass
❌ CO NEDĚLAT:
-
Globální stav
# ❌ NIKDY current_file = None # global -
Magic numbers
# ❌ ŠPATNĚ if len(files) > 100: # ✅ SPRÁVNĚ MAX_FILES = 100 if len(files) > MAX_FILES: -
Ignorovat exceptions
# ❌ NIKDY try: operation() except: pass -
Hardcoded paths
# ❌ Š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)
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)
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):
{
"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ů)
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ů)
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:
# 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žkuCtrl+Q- UkončitCtrl+T- Přiřadit tagyCtrl+D- Nastavit datumCtrl+F- Focus searchF5- RefreshDel- Smazat z indexu
🔧 Vývoj
Setup prostředí
# 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
# Moderní GUI (doporučeno)
poetry run python Tagger_modern.py
# Klasické GUI
poetry run python Tagger.py
Testy
# 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
# 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
# Classes
class FileManager:
pass
# Functions/methods
def load_config():
pass
# Constants
APP_NAME = "Tagger"
MAX_FILES = 1000
# Private
def _internal_method():
pass
Imports Order
# 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
# ✅ 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
<type>: <subject>
[optional body]
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Types:
feat:- Nová funkcefix:- Bug fixrefactor:- Refactoringtest:- Testydocs:- Dokumentacestyle:- Formátováníchore:- Build, dependencies
Příklad:
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 <noreply@anthropic.com>"
🎯 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
-
Git merge konflikty
poetry.lockapyproject.toml- konflikty při merge devel→featuretests/test_image.py- deleted in devel, modified in feature- Stav: Nezresolváno ⚠️
-
ListManager málo použitý
- Třídící logika duplicitní v GUI
- TODO: Refactor nebo odstranit
-
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"
# Řešení: Použij poetry environment
poetry run python Tagger_modern.py
2. "Config file not found"
# Normální při prvním spuštění
# Vytvoří se automaticky config.json
3. "Metadata corrupted"
# V config.py je graceful degradation
# Vrátí default config při chybě
Logování
# 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:
- ✅ PŘEČTI TENTO SOUBOR CELÝ!
- ✅ Zkontroluj
git status - ✅ Aktivuj poetry environment
- ✅ Spusť testy (
poetry run pytest tests/) - ✅ Dodržuj pravidla výše
Při commitování:
- ✅ Testy prošly (
pytest tests/) - ✅ Type hints přidány
- ✅ UTF-8 encoding
- ✅ Žádné TODO/FIXME
- ✅ Commit message formát správný
Při přidání nové funkce:
- ✅ Testy napsány PŘED implementací (TDD)
- ✅ Dokumentace aktualizována (TENTO SOUBOR!)
- ✅ Architecture decision zdokumentováno (pokud významné)
- ✅ Type hints všude
- ✅ Error handling přidán
Při refactoringu:
- ✅ Testy před (měly by projít)
- ✅ Refactor
- ✅ Testy po (měly by stále projít)
- ✅ 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 -ia 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:
- Nejdřív PŘEČTU tento soubor
- Pak UPRAVÍM kód
- 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!