Scoring sorted

This commit is contained in:
2025-12-28 17:44:24 +01:00
parent aab50864c3
commit d60c7e2e2f
11 changed files with 214 additions and 412 deletions

View File

@@ -1,15 +1,15 @@
# 📝 Tagger - Centrální Poznámky Projektu
# 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
**Poslední aktualizace:** 2025-12-28
**Verze:** 1.0.3
**Status:** Stable, v aktivním vývoji
---
## 🎯 O projektu
## O projektu
**Tagger** je desktopová aplikace pro správu a organizaci souborů pomocí hierarchických tagů (štítků).
@@ -19,22 +19,21 @@
- 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)
- 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
## Struktura projektu
```
Tagger/
├── Tagger.py # Entry point - klasické GUI
├── Tagger_modern.py # Entry point - moderní GUI
├── 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í
├── pytest.ini # Pytest konfigurace
├── .editorconfig # Editor konfigurace
├── .gitignore # Git ignore pravidla
├── src/
@@ -43,54 +42,50 @@ Tagger/
│ │ ├── 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)
│ │ ├── 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 # Původní Tkinter GUI
│ ├── gui_modern.py # Moderní qBittorrent-style GUI ✨ NOVÉ
│ └── gui_old.py # Backup původního GUI
── gui.py # Moderní qBittorrent-style GUI
├── tests/ # 116 testů, 100% core coverage
├── tests/ # 189 testů, 100% core coverage
│ ├── __init__.py
│ ├── conftest.py # Pytest fixtures
│ ├── test_tag.py # 13 testů
│ ├── test_tag_manager.py # 19 testů
│ ├── test_tag_manager.py # 31 testů
│ ├── test_file.py # 22 testů
│ ├── test_file_manager.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_config.py # 18 testů
│ ├── test_media_utils.py # 3 testy
│ └── README.md # Dokumentace testů
── test_media_utils.py # 3 testy
├── src/resources/
│ └── images/32/ # Ikony (16x16 PNG)
│ └── images/32/ # Ikony (32x32 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
└── data/samples/ # Testovací data
```
---
## 🎨 Architektura
## Architektura
### Vrstvová struktura
```
┌─────────────────────────────────┐
│ Presentation (UI) │ ← gui.py, gui_modern.py
│ Presentation (UI) │ ← gui.py
│ - Tkinter GUI │ - NESMÍ obsahovat business logiku
│ - Jen zobrazení + interakce │ - NESMÍ importovat přímo z core
├─────────────────────────────────┤
│ Business Logic │ ← FileManager, TagManager
│ Business Logic │ ← FileManager, TagManager, HardlinkManager
│ - Správa souborů/tagů │ - Callable z UI
│ - Filtrování, validace │ - Callback pattern pro notifikace
├─────────────────────────────────┤
@@ -104,9 +99,27 @@ Tagger/
└─────────────────────────────────┘
```
### Tříúrovňový konfigurační systém
1. **Globální config** (`.Tagger.!gtag` vedle Tagger.py)
- Geometrie okna, maximalizace
- Poslední otevřená složka
- Recent folders
2. **Složkový config** (`.Tagger.!ftag` v projekt složce)
- Ignore patterns
- Custom tagy pro složku
- Hardlink nastavení (output_dir, categories)
- Rekurzivní skenování
3. **Souborové tagy** (`.filename.!tag`)
- Tagy souboru
- Datum
- Stav (nové, ignorované)
### Klíčová pravidla
#### CO DĚLAT:
#### CO DĚLAT:
1. **UI NESMÍ obsahovat business logiku**
```python
@@ -148,46 +161,16 @@ Tagger/
pass
```
#### CO NEDĚLAT:
#### 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"
```
1. **Globální stav** - NIKDY
2. **Magic numbers** - použít konstanty
3. **Ignorovat exceptions** - vždy logovat nebo ošetřit
4. **Hardcoded paths** - použít Path
---
## 🔑 Klíčové komponenty
## Klíčové komponenty
### 1. Tag (immutable value object)
@@ -200,19 +183,8 @@ class Tag:
@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
@@ -223,7 +195,6 @@ class File:
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):**
@@ -236,28 +207,18 @@ class File:
}
```
**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
# Automaticky načte výchozí tagy (Hodnocení, Barva)
```
**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)
**Výchozí tagy:**
- Hodnocení: 1-5 hvězd (exkluzivní výběr)
- Barva: Červená, Modrá, Zelená, Žlutá, Oranžová
### 4. FileManager (správa souborů)
@@ -267,55 +228,41 @@ class FileManager:
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
self.global_config = load_global_config()
self.folder_config = {}
```
**Callback pattern:**
### 5. HardlinkManager (hardlink struktura)
```python
# V GUI:
filemanager.on_files_changed = self.update_ui
class HardlinkManager:
def __init__(self, output_dir: Path):
self.output_dir = output_dir
# V FileManager:
if self.on_files_changed:
self.on_files_changed(self.filelist)
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)
```
**Proč callback?**
- Core nezávisí na UI
- Jednoduché na testování
- Flexibilní (můžeš změnit UI bez změny core)
**Příklad struktury:**
```
output/
├── žánr/
│ ├── Komedie/
│ │ └── film.mkv (hardlink)
│ └── Akční/
│ └── film.mkv (hardlink)
└── rok/
└── 1988/
└── film.mkv (hardlink)
```
---
## 🎨 GUI Verze
## GUI
### 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É
### Moderní GUI (gui.py)
```
┌─────────────────────────────────────────────────────┐
@@ -333,14 +280,15 @@ if self.on_files_changed:
└─────────────────────────────────────────────────────┘
```
**Použít:** `poetry run python Tagger_modern.py`
**Použít:** `poetry run python Tagger.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
**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žku
@@ -353,7 +301,7 @@ if self.on_files_changed:
---
## 🔧 Vývoj
## Vývoj
### Setup prostředí
@@ -363,52 +311,30 @@ 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ů)
# 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_file.py -v
poetry run pytest tests/test_hardlink_manager.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
```
**Test coverage:** 100% core modulů
---
## 📝 Coding Standards
## Coding Standards
### Python Style
@@ -419,26 +345,6 @@ poetry run pytest tests/ -q
- **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
@@ -456,21 +362,9 @@ 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
## Git Workflow
### Branches
@@ -492,7 +386,7 @@ feature/* ← Feature branches ← VYVÍJÍME TADY
[optional body]
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
```
**Types:**
@@ -504,89 +398,9 @@ Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- `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 <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
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
## Plánované features
- [ ] Progress bar pro dlouhé operace
- [ ] Undo/Redo mechanismus
@@ -607,12 +421,11 @@ Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
---
## 📊 Metriky projektu
## Metriky projektu
**Řádky kódu:** ~1060 Python LOC
**Testy:** 116 (všechny ✅)
**Testy:** 189 (všechny ✅)
**Test coverage:** 100% core modulů
**Python verze:** 3.12
**Python verze:** 3.12+
**Dependencies:** Pillow (PIL)
**Vývojové prostředí:** Poetry
@@ -623,20 +436,20 @@ Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
---
## 🔍 Debugování
## Debugování
### Časté problémy
**1. "Cannot import ImageTk"**
```bash
# Řešení: Použij poetry environment
poetry run python Tagger_modern.py
poetry run python Tagger.py
```
**2. "Config file not found"**
```bash
# Normální při prvním spuštění
# Vytvoří se automaticky config.json
# Vytvoří se automaticky .Tagger.!gtag
```
**3. "Metadata corrupted"**
@@ -645,132 +458,58 @@ poetry run python Tagger_modern.py
# 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
## Dokumentace
**AKTUÁLNÍ:**
- **PROJECT_NOTES.md** - TENTO SOUBOR (single source of truth)
**AKTUÁLNÍ:**
- **PROJECT_NOTES.md** - TENTO SOUBOR (single source of truth)
- **CHANGELOG.md** - Historie verzí
- 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)
## 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
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ý
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
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
---
## 📞 Kontakt & Help
## Kontakt & Help
**Autor:** honza
**Repository:** /home/honza/Dokumenty/Tagger
**Python:** 3.12
**OS:** Linux 6.14.0-37-generic
**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
- 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!**
**Last updated:** 2025-12-28
**Maintainer:** Claude Opus 4.5 + honza