14 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-28 Verze: 1.0.4 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)
- Moderní GUI (qBittorrent-style)
- Hardlink struktura - vytváření adresářové struktury pomocí hardlinků podle tagů
- Tříúrovňový konfigurační systém (globální, složkový, souborový)
Struktura projektu
Tagger/
├── Tagger.py # Entry point
├── PROJECT_NOTES.md # ← TENTO SOUBOR - HLAVNÍ ZDROJ PRAVDY
├── CHANGELOG.md # Historie verzí
├── pyproject.toml # Poetry konfigurace
├── poetry.lock # Zamčené verze závislostí
├── .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 # Tříúrovňová konfigurace (global, folder, file)
│ │ ├── hardlink_manager.py # Správa hardlink struktury
│ │ ├── 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 # Moderní qBittorrent-style GUI
│
├── tests/ # 189 testů, 100% core coverage
│ ├── __init__.py
│ ├── conftest.py # Pytest fixtures
│ ├── test_tag.py # 13 testů
│ ├── test_tag_manager.py # 31 testů
│ ├── test_file.py # 22 testů
│ ├── test_file_manager.py # 40 testů
│ ├── test_config.py # 33 testů
│ ├── test_hardlink_manager.py # 28 testů
│ ├── test_utils.py # 17 testů
│ └── test_media_utils.py # 3 testy
│
├── src/resources/
│ └── images/32/ # Ikony (32x32 PNG)
│ ├── 32_unchecked.png
│ ├── 32_checked.png
│ └── 32_tag.png
│
└── data/samples/ # Testovací data
Architektura
Vrstvová struktura
┌─────────────────────────────────┐
│ Presentation (UI) │ ← gui.py
│ - Tkinter GUI │ - NESMÍ obsahovat business logiku
│ - Jen zobrazení + interakce │ - NESMÍ importovat přímo z core
├─────────────────────────────────┤
│ Business Logic │ ← FileManager, TagManager, HardlinkManager
│ - 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
└─────────────────────────────────┘
Tříúrovňový konfigurační systém
-
Globální config (
.Tagger.!gtagvedle Tagger.py)- Geometrie okna, maximalizace
- Poslední otevřená složka
- Recent folders
-
Složkový config (
.Tagger.!ftagv projekt složce)- Ignore patterns
- Custom tagy pro složku
- Hardlink nastavení (output_dir, categories)
- Rekurzivní skenování
-
Souborové tagy (
.filename.!tag)- Tagy souboru
- Datum
- Stav (nové, ignorované)
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
- Magic numbers - použít konstanty
- Ignorovat exceptions - vždy logovat nebo ošetřit
- Hardcoded paths - použít Path
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}"
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
Metadata format (.filename.!tag):
{
"new": false,
"ignored": false,
"tags": ["Stav/Nové", "Video/HD"],
"date": "2025-12-23"
}
3. TagManager (správa tagů)
class TagManager:
def __init__(self):
self.tags_by_category = {} # {category: set(Tag)}
# Automaticky načte výchozí tagy (Hodnocení, Barva)
Výchozí tagy:
- Hodnocení: 1-5 hvězd (exkluzivní výběr)
- Barva: Červená, Modrá, Zelená, Žlutá, Oranžová
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.global_config = load_global_config()
self.folder_config = {}
5. HardlinkManager (hardlink struktura)
class HardlinkManager:
def __init__(self, output_dir: Path):
self.output_dir = output_dir
def create_structure_for_files(files, categories=None) -> (success, fail)
def find_obsolete_links(files, categories=None) -> List[(link, source)]
def remove_obsolete_links(files, categories=None) -> (count, paths)
def sync_structure(files, categories=None) -> (created, c_fail, removed, r_fail)
Příklad struktury:
output/
├── žánr/
│ ├── Komedie/
│ │ └── film.mkv (hardlink)
│ └── Akční/
│ └── film.mkv (hardlink)
└── rok/
└── 1988/
└── film.mkv (hardlink)
GUI
Moderní GUI (gui.py)
┌─────────────────────────────────────────────────────┐
│ 📁 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.py
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
- Hromadné přiřazování tagů
- Hardlink menu (Nástroje → Hardlink)
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.py
Testy
# Všechny testy (189 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_hardlink_manager.py -v
# Quick check
poetry run pytest tests/ -q
Test coverage: 100% core modulů
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
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
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 Opus 4.5 <noreply@anthropic.com>
Types:
feat:- Nová funkcefix:- Bug fixrefactor:- Refactoringtest:- Testydocs:- Dokumentacestyle:- Formátováníchore:- Build, dependencies
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
Testy: 189 (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.py
2. "Config file not found"
# Normální při prvním spuštění
# Vytvoří se automaticky .Tagger.!gtag
3. "Metadata corrupted"
# V config.py je graceful degradation
# Vrátí default config při chybě
Dokumentace
AKTUÁLNÍ:
- PROJECT_NOTES.md - TENTO SOUBOR (single source of truth)
- CHANGELOG.md - Historie verzí
- Docstrings v kódu
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
Kontakt & Help
Autor: honza Repository: /home/honza/Documents/Tagger Python: 3.12+ OS: Linux
Pro pomoc:
- Přečti TENTO soubor
- Podívej se do testů (
tests/) - Zkontroluj docstrings v kódu
Last updated: 2025-12-28 Maintainer: Claude Opus 4.5 + honza