Media Organizer — Full Product & Engineering
Specification
0. Vision
Build a desktop application called Media Organizer whose only job is to detect movies, TV
series, and their subtitles, and organize the files and folders automatically — with maximum
accuracy and minimum risk.
This must never grow into a media player or a cluttered media manager. All of its power lives
in the detection/organization engine, and that power stays hidden behind a very simple UI.
Design principle: Simple UI — Powerful Engine — Safe Operations
User-facing flow (always these 5 steps, nothing more):
1. Select folder
2. Scan
3. Preview
4. Confirm
5. Organize
Final priority order (highest to lowest) — this order governs every trade-off in this
spec:
1. Data Safety
2. Detection Accuracy
3. Correct Subtitle Matching
4. Existing Structure Preservation
5. Complete Undo
6. Crash Recovery
7. Performance / Low RAM usage
8. Simple UI\n\nBuild order: Architecture & folder/module layout → Detection Engine (Parser, Detectors,
ConfidenceEngine) → Organization Planner & Transaction System (including cross-drive
safety) → simple UI on top. At no stage may Safety, Confidence, Preview, Journal, Undo,
Crash Recovery, or Logging be cut to simplify implementation.
1. Core Responsibilities
The app scans one or more folders and must be able to:
Detect movies.
Detect TV series, including season and episode.
Detect subtitles and match them to the correct movie/episode.
Group related files into a single logical Media Group.
Place files into the correct structure, creating folders as needed.
Leave already-correctly-organized files and folders untouched.
Never guess dangerously on ambiguous files — defer to the user instead.
Log every change it makes or considers making.
Fully undo any completed operation.
No internet access of any kind is used for detection (no TVDB, TMDb, or any online
metadata lookup, ever). Every decision comes from: filename, parent folder name,
grandparent folder name, file/subtitle extensions, and (optionally) local video file metadata.
No single signal ever decides anything alone.
2. Golden Rules (Non-Destructive Principles)
These rules override every other part of this spec whenever there is a conflict:
1. Never delete a file automatically — not even duplicates.
2. Never overwrite an existing file automatically.
3. Never move a Low-confidence file automatically.
4. Never modify a file that is already correctly organized.
5. Every modification must be logged before and after it happens.\n\n6. Every modification must be reversible whenever technically possible.
7. When uncertain, ask the user — never guess to force an output.
Only three kinds of filesystem operations are ever permitted: Move, Rename, Create
Folder.
3. “Already Organized” Rule
If the engine determines a file is already in a valid location with a valid name, the decision is
Action = NONE, even if the engine could technically suggest a different (also valid) naming
convention. Example — both of these, if internally consistent, are left untouched:
Movies/Inception (2010)/Inception.2010.1080p.mkv
Series/Breaking Bad/Season 01/
├── S01E01.mkv
├── S01E02.mkv
└── S01E03.mkv
The goal is “organize only what needs organizing,” not “rebuild the whole library every
time.” This also keeps repeat scans fast and non-destructive.
4. Filename Parser
Must reliably parse messy release names such as:
Breaking.Bad.S02E05.1080p.WEB-DL.x265-GROUP.mkv
into:
Title:          Breaking Bad
Season:         2
Episode:        5
Resolution:     1080p
Source:         WEB-DL
Codec:          x265
Release Group:  GROUP
All non-title tokens (resolution, source, codec, release group, year, edition tags) must be\n\nstripped cleanly out of the parsed Title.
5. Series Detection
Support at minimum these patterns and other common variants:
S01E01   S01 E01   s01e01   1x01   01x01
Breaking.Bad.S01E01.mkv → Show = Breaking Bad, Season = 1, Episode = 1.
6. Movie Detection (Year Optional)
Inception.2010.1080p.mkv → Title = Inception, Year = 2010.
A bare number in a filename is never sufficient on its own to conclude “movie.”
Year is optional. If a year is present in the filename or folder, extract it and use it in the
destination naming/path. The engine never guesses a year and never performs an online
lookup to find one.
If no year is present: organize using Title (+ Folder Context) only, with no year in the
destination folder name (e.g. Movies/Inception/). If this creates ambiguity against
another already-known title with the same name but a different year, Confidence drops
to Medium/Low and the user is asked: “Is this the same movie as the existing one, or a
different film with the same title?”
Progressive enrichment (year discovered later): If a movie was previously organized
without a year (Movies/Inception/) and a later scan finds a new file for the same title that
does carry a year, the engine must not silently rename the existing folder (that would violate
the “don’t touch correctly organized files” rule). Instead, this is raised as its own Medium-
confidence review item: “A year (2010) was found for the existing title ‘Inception’. Rename
folder to ‘Inception (2010)’ and merge?” with explicit options [Rename & Merge] / [Keep
Separate] / [Skip]. Nothing is renamed without this explicit confirmation.
7. Multi-Par t Movies vs. Multi-Version Movies
These two cases must be told apart by an explicit rule, never by guesswork:
7.1 — Multi-Par t movie (parts of one single work): explicit sequential markers in the\n\nfilename, such as .Part.1 / .Part.2, 1CD / 2CD, 1Disk / 2Disk, 1pt / 2pt. These files
are marked as parts of one work (not independent movies) and are kept together in a single
folder without being split apart by resolution or any other qualifier in the folder name.
7.2 — Multi-Version movie (different releases of the same film): same Title and Year, but
differing in Resolution (1080p vs 2160p), Source (WEB-DL vs BluRay), or Edition (Extended,
Director’s Cut, Theatrical, Unrated). These files must never be merged or deleted — all
versions are kept in the same movie folder, and filenames must retain the distinguishing
detail so they stay identifiable side by side (e.g. Avatar.2009.1080p.mkv and
Avatar.2009.2160p.mkv living together).
Decision procedure:
Sequential/part marker found → 7.1.
No sequential marker, but a version-differentiating signal (resolution/source/edition)
found → 7.2.
Neither is clear, or both signals appear at once → Confidence drops to Low, and the
user is asked. Never auto-delete, never auto-merge under ambiguity.
Files are never deleted just because they share a Title — all such files are preserved by
default.
8. Subtitle Detection
Recognized extensions: .srt .ass .ssa .sub .vtt.
Language detection from common codes in the filename:
fa, farsi, per → Persian
en, eng → English
(and other common ISO/common-name variants)
Subtitle filenames are not guaranteed to exactly match their video’s filename, so matching
must be multi-stage (see below).
9. Subtitle Matching & Media Group
Matching proceeds through multiple stages (exact name match → normalized/fuzzy name
match → season/episode number match → parent-folder correlation). If a match is not\n\ncertain, the subtitle is not auto-moved — the user is asked.
Related files are never processed independently of each other. They are unified into one
logical Media Group:
MediaGroup:
  Breaking Bad — Season 2 — Episode 5
    video:    Breaking.Bad.S01E05.mkv
    subtitle: Breaking.Bad.S01E05.fa.srt
    subtitle: Breaking.Bad.S01E05.en.srt
When a group moves, every member of the group moves together. This atomicity also
applies to blocking: if the video member of a group is marked CORRUPTED (see §15.1) and is
therefore held back from automatic organization, its matched subtitle(s) are held back with
it as one unit, rather than being organized separately while the video waits in review.
10. Non-Primary File Detection
Detect (as best-effort) non-primary content: sample, trailer, preview, teaser,
featurette. Movie.sample.mkv must never be treated as the main release. Ambiguous
cases go to the user.
11. Confidence Scoring System
Every decision produces a single confidence score between 0 and 100, from a weighted
sum of independent signals:
Confidence =
    (FilenamePatternMatch     × 0.40) +
    (ParentFolderMatch        × 0.20) +
    (GrandparentFolderMatch   × 0.10) +
    (VideoMetadataMatch       × 0.25) +
    (ExtensionConsistency     × 0.05)
Each component is itself a 0–100 score. Weights and thresholds live in one external config
file — never hardcoded — so they can be tuned later.
If video metadata is disabled (see §14), its weight is not simply dropped to zero; the
remaining four weights are proportionally renormalized so they always sum to 1.0 (e.g.
each remaining weight becomes original_weight / 0.75). This keeps the 0–100 scale\n\nmeaningful regardless of whether metadata extraction is on.
If a matching User Rule exists (see §12), the weighted formula above is bypassed entirely
and Confidence is set directly to 100 — a confirmed user rule is always treated as certain,
never blended with the other signals.
Thresholds:
Range Level Behavior
95–100 High Enters Preview with no question asked.
70–94 Medium Enters Preview; if a Conflict flag is present, the user is asked.
< 70 Low Never auto-moved. Always listed under “Needs Review.”
Golden rule: when uncertain, ask. The app never guesses just to always produce an
output.
12. Rule Engine (Learned User Decisions)
When a user corrects a file or a pattern, the app can save that decision as a local rule (e.g.
“pattern X → Series,” “pattern Y → Persian subtitle”) and reuse it on future scans.
Each rule has:
Scope: Global (whole library) or Folder-specific (only the root folder it was created
in).
Specificity: an exact filename match outranks a wildcard/regex pattern match.
Final priority order, highest to lowest:
1. Folder-specific + exact filename match
2. Global + exact filename match
3. Folder-specific + pattern match
4. Global + pattern match
5. Default engine logic (no rule matched)
If two rules sit at the exact same level (same scope, same specificity) and contradict each
other, the most recently created rule wins; the older one is kept but marked inactive (never\n\nsilently deleted).
Rules must be visible, editable, and deletable in the UI. Deleting a rule never retroactively
reverts files that were already organized under it — it only affects future decisions.
13. Folder Context & Structure Preservation
Existing folder structure is an important information source. Even a bare filename like
01.mkv sitting inside Series/Breaking Bad/Season 01/ should let the engine reasonably
infer it belongs to Breaking Bad S01E01.
The engine does not assume there is only one “correct” structure. If the current structure
(e.g. per-season subfolders) is already coherent and detectable, it is preserved as-is.
“Organize only what needs organizing,” not “rebuild the entire library every time.”
14. Video Metadata Engine (Core Signal)
MediaInfo/ffprobe runs on every video file as a core part of the engine — on by default
— and its result (VideoMetadataMatch) is one of the weighted Confidence signals (§11).
Performance safeguards:
Only the file’s header/container metadata is read (format/streams probe) — never a
full frame decode. This typically takes milliseconds, up to ~1–2 seconds worst case.
Probes run asynchronously, in a dedicated worker pool, off the UI thread, and never
block scanning.
Results are cached in SQLite keyed by the file’s CacheKey (§24); unchanged files are
never re-probed.
Settings toggle: a full on/off switch remains available (for very weak hardware or slow
network shares), default on.
Cascading effect when disabled (this is deliberate, not an oversight): turning video
metadata off does all of the following automatically, and the Settings/Advanced Details UI
states this explicitly next to the toggle:
VideoMetadataMatch is removed from the Confidence formula and the remaining four
weights are renormalized to sum to 1.0 (§11).
All five supplementary features in §15 (Corrupted detection, Mismatch detection,\n\nDuplicate detection, Language cross-check, Health Report) are disabled together, since
they all depend on probed metadata. The Library Health Report section shows “Video
metadata is disabled — these checks were skipped” instead of silently showing zero
issues.
VideoMetadataMatch semantics:
Full agreement between filename claim and actual metadata (e.g. filename says 1080p,
real resolution is 1920×1080) → score 90–100.
Real mismatch (e.g. filename says 1080p, real resolution is 720p) → score below 30,
and a Conflict is logged and shown in Advanced Details as “Filename does not match
actual content.”
Unreadable/corrupted file → score is not computed at all; the file is routed straight to
the corrupted-files review list (§15.1), bypassing the normal confidence flow entirely.
Duration is also used as a sanity check — e.g. a file named like a single episode
(S01E01) but with a ~150-minute duration (movie-length) generates a duration-
mismatch flag that lowers VideoMetadataMatch.
15. Supplementary Integrity & Insight Features
All five of the following ride on top of the same metadata extraction pass, are purely
informational/routing aids, and never trigger an automatic destructive action.
15.1 Corrupted File Detection
If ffprobe cannot open a file or finds no valid audio/video streams, the file is marked
CORRUPTED. It is placed in the Organization Plan under its own “Corrupted files” sub-section
inside “Needs Review” (kept separate from ordinary ambiguous cases). No automatic
Rename/Move ever happens to a corrupted file; the user must explicitly confirm an action
(e.g. “move anyway” or “ignore”).
15.2 Name/Content Mismatch Detection
Checked at Confidence-computation time (§14): claimed vs. actual resolution, and claimed
content type (episode vs. movie) vs. actual duration. Exact values are shown in Advanced
Details, e.g. “Filename claims 1080p; actual content is 720p.”
15.3 Duplicate Detection (Library-Wide)
After probing, files are compared across the entire scanned library (not just within a\n\nsingle folder) so that the same title copied into two unrelated folders is still caught. Two or
more differently-named files are flagged as a Possible Duplicate Group when, within
tolerance, they share:
Size (±2%)
Duration (±1 second)
Resolution (exact match)
This is informational only, shown in Advanced Details as “Possible Duplicate Group.” No file
is ever auto-deleted or auto-merged. The user may use Review to manually delete one
copy through the OS, outside the Organizer — the app itself never performs this deletion.
15.4 Audio/Subtitle Language Cross-Check
Compares an external subtitle’s claimed language (from its filename, §8) against the
embedded audio/subtitle track languages reported by ffprobe. A mismatch (e.g. an en
subtitle file next to a video that already has an embedded English subtitle) raises an
informational conflict so the user can double check before moving. This never blocks or
changes the plan by itself.
15.5 Library Health Report
After each scan, a rollup is generated and shown in a collapsible section, closed by
default, separate from the main scan summary:
Library Health Report
12 corrupted files found
5 mismatches (filename vs actual content)
8 possible duplicate groups
3 language mismatches
16. Empty Folders
After files are moved out, folders that become empty are never deleted. They are relocated
— with their name and nesting preserved exactly, with no renaming — under a top-level
Empty Folders/ directory inside the scanned root:
Before:                          After:
Downloads/                       Downloads/
└── Old Folder/                  └── Empty Folders/
    └── Movie.mkv                    └── Old Folder/\n\nNested example:
Old/Movies/Temporary/    →    Empty Folders/Old/Movies/Temporary/
Quarantine rule (to prevent loops/duplication on later scans): Empty Folders/ at the
root of a scanned library is treated as a quarantine zone, excluded from active
detection/classification logic on every scan. It is listed for the user to browse/delete
manually if desired, but the engine never recurses into it to reclassify its contents, and a
folder that is already inside Empty Folders/ is never re-wrapped into a nested Empty
Folders/Empty Folders/... structure even if it becomes empty again.
17. Delete / Overwrite Policy
The app never deletes files automatically — not even duplicates.
If a destination already has a file with the same name, the existing file is never
overwritten. The app stops and offers: Keep Both / Choose / Skip / Review.
18. Dry Run / Preview & Pre-Apply Re-Verification
Before any real change, the engine builds an Organization Plan:
428 files scanned
86 files need organization
42 subtitles matched
23 folders will be created
293 files already correctly organized
7 files need user decision
Nothing on disk changes until the user presses [Apply Changes].
Re-verification: time can pass between Scan (plan built) and the moment the user clicks
Apply, during which files may have changed on disk (edited, moved, deleted by the user or
another program). Immediately before real execution, each plan item gets a quick check —
Size + Modified-Time only, not a full re-scan. If a source file no longer exists, or its
Size/mtime no longer matches what the plan was built from, that item is pulled from the plan
and flagged: “This file changed since the scan — please re-scan.” The rest of the plan
proceeds without being blocked by this one item.\n\n19. Transactional Operations & Cross-Drive Safety
Every change is journaled before it happens:
BEFORE: D:\Downloads\Movie.mkv
AFTER:  D:\Movies\Movie (2020)\Movie.mkv
Same drive/partition: use the OS’s atomic Rename — fast, no copy/verify needed.
Cross drive/partition (a plain OS rename is not atomic here — it’s really a Copy then
Delete, and an interruption mid-way, e.g. power loss, can destroy or desync the file):
1. Check the destination has at least enough free space for the file.
2. Copy the file to a temporary name at the destination (e.g. filename.mkv.mo-tmp).
3. Verify: compare file Size between source and destination, plus (if enabled in Settings) a
fast hash — a block-sampled or CRC32-style hash rather than a full hash for very large
files, to avoid excessive delay.
4. Only on a full match: rename the temp file to its final name at the destination, then
delete the source file.
5. If any step fails: delete the temp destination file, leave the source file untouched, and log
the failure to the Journal. The user is then offered [Retry] / [Skip] / [Abort Remaining]
for that item — the same treatment given to locked files (§23) — rather than silently
rolling back with no recourse.
Every operation’s Journal entry records BEFORE/AFTER paths.
20. Batch Apply Execution Model
Each file operation (Move/Rename/Create Folder) is its own atomic, independent
transaction. If one item in a running batch fails recoverably — a locked file, a permission
error, a cross-drive verification failure — that single item is skipped, logged, and surfaced in
an “Issues during Apply” list with [Retry] / [Skip], while the rest of the batch continues
uninterrupted. A recoverable per-file error never halts the whole Apply run.
A crash (the process or the OS terminating mid-operation) is a different, more severe case
and is handled by Crash Recovery (§21) — it is the only scenario that requires a full
resume/rollback/review decision on next launch.\n\n21. Undo, Operation History, Crash Recovery
Undo: the user can fully revert an entire completed Organization run:
Organization #18
1,842 files moved
327 folders created
94 empty folders relocated
612 files renamed
[Undo]
Undo restores the filesystem to its prior state as exactly as technically possible.
Operation History: every past run is kept, with timestamp, file/folder/rename/move counts,
status, and whether it can still be undone.
Crash Recovery: if the app or the system is terminated mid-run (e.g. 400 / 1000 files
completed), the next launch detects the incomplete operation from the Journal and offers
[Resume] / [Rollback] / [Review].
22. Verification
After every Move, the app confirms:
The destination file exists.
Its size matches what the plan/Journal expected.
The move/rename genuinely succeeded.
For cross-drive moves specifically, the §19 verification result (size/hash match) is what gets
recorded in the Journal, and the source file must no longer exist once the operation is
marked complete (since it was a Copy+Delete, not a true Move).
23. Conflicts, Permissions, Locked Files, Paths, Special
Characters
All conflicts are detected before execution begins:
Destination already exists
Duplicate filename\n\nAmbiguous subtitle match
Ambiguous movie/series classification
Permission denied
File locked
Invalid path
Insufficient permissions
No dangerous conflict is ever executed without a user decision. A locked file (in use) is
never force-deleted or force-overwritten; the app shows “File is currently unavailable” with
[Retry] / [Skip].
Long Windows paths are supported as far as technically possible; if a path cannot be
handled, the user is warned before the Move is attempted.
Unicode text — Persian, Kurdish, Arabic, spaces, parentheses, brackets — must be handled
without corruption anywhere in the pipeline (parsing, DB storage, filesystem operations,
logs).
24. Performance, Caching & Streaming
Cache Key — a file is only considered “already processed, skip heavy analysis” when all
three of the following match a previous database record:
CacheKey = (FullPath, FileSize, ModifiedTime, PartialHash)
PartialHash = a fast hash (e.g. CRC32-style) of the first 64KB + last 64KB of the file —
never the whole file. This sharply cuts false negatives from files with a changed mtime but
identical content (or the reverse) without paying the cost of reading entire large media files.
If all three match → skip re-parsing/re-matching/re-probing; reuse the cached result
from SQLite.
If mtime changed but the content hash is identical → still treated as changed and fully
re-parsed (mtime is not trusted blindly).
If the content hash changed but mtime is identical for any reason → also fully re-parsed
(hash is not trusted blindly either).
In short: any of the three differing means no cache hit.\n\nStreaming/batched scanning (to avoid loading huge libraries into RAM): the Scanner never
holds the entire file list in memory at once. It processes folder-by-folder or in small batches
(e.g. 500 files per batch), writing results directly and incrementally into SQLite. The
Organization Plan is built from SQLite via a paginated cursor, not from an in-memory list.
25. Local Database (SQLite)
A lightweight local SQLite database stores organizational metadata only — never the media
files themselves:
File records (path, size, mtime, PartialHash, CacheKey)
Media Groups
Previous scan results
User rules (scope, specificity, pattern, decision, active/inactive, created-at)
Operation history & Undo journal
Confidence results & flags (Conflict, Mismatch, Corrupted, Possible Duplicate)
Known folder structures
Probed video metadata (per §14 cache)
26. User Interface
Main screen — deliberately minimal, no dashboards, no unnecessary animation:
Media Organizer
[ Select Folder ]
Selected: D:\Downloads
[ Scan ]
After Scan:
Scan Complete
1,284 files analyzed\n\n842 organized
391 subtitles matched
23 folders created
7 need review
▸ Library Health Report (12 issues found)     ← collapsible, closed by default
[ Review ]
[ Preview Changes ]
[ Apply Changes ]
Only one root folder is selectable at a time. If the user wants to process several root folders,
each is scanned and applied as its own separate, sequential run — never merged into one
simultaneous multi-folder batch. This is a deliberate simplicity/RAM trade-off.
Advanced Details (tucked away, never shown on the main screen) exposes, per item:
parsed title/season/episode, detected subtitle language, match confidence, reason for the
decision, any conflict, and the suggested destination.
The engine’s internal complexity — however many rules or signals it evaluates — must never
surface on the main screen. The app should feel like a small, fast tool: grab a folder →
understand it → show the changes → apply with permission.
27. Settings
Organization
☑ Create movie folders
☑ Create season folders
☑ Keep subtitles beside videos
☑ Preserve existing structure
Detection
☑ Use video metadata (ffprobe) for accurate detection
   Disabling this also turns off Corrupted/Mismatch/Duplicate/
   Language-mismatch detection and the Health Report.
   Recommended to disable only on very weak hardware or slow network shares.
Safety
☑ Never delete files
☑ Never overwrite files
☑ Require preview before changes
☑ Don't move low-confidence files
☑ Verify file integrity on cross-drive moves\n\nHistory
☑ Keep operation history
☑ Enable Undo
Diagnostics
☑ Enable detailed logging
[ Export Diagnostic Bundle ]
28. Non-Destructive Principle (Summary)
This is the most important principle in the whole application:
1. Never delete automatically.
2. Never overwrite automatically.
3. Never move a low-confidence file automatically.
4. Never modify a correctly organized file.
5. Every modification is logged.
6. Every modification is reversible whenever technically possible.
7. When uncertain, ask the user.
29. Worked Example
Input, Downloads/:
Breaking.Bad.S01E01.1080p.mkv
Breaking.Bad.S01E01.fa.srt
Breaking.Bad.S01E02.1080p.mkv
Breaking.Bad.S01E02.fa.srt
Inception.2010.1080p.mkv
Inception.2010.fa.srt
unknown_video.mkv
Old Folder/
trailer.mkv
Proposed plan:\n\n30. Logging & Diagnostics System
Logging is a first-class subsystem, not an afterthought — it must independently reconstruct
“what did the app try to do, and why, and what happened” for every single decision and
every filesystem operation, entirely in English, regardless of the UI display language.
30.1 Log Levels
30.2 Structured Format
Every log line is a single structured JSON record (JSON Lines format, one object per line),
so logs are both human-readable and machine-parseable:
Movies/
└── Inception (2010)/
    ├── Inception.2010.1080p.mkv
    └── Inception.2010.fa.srt
Series/
└── Breaking Bad/
    └── Season 01/
        ├── Breaking.Bad.S01E01.1080p.mkv
        ├── Breaking.Bad.S01E01.fa.srt
        ├── Breaking.Bad.S01E02.1080p.mkv
        └── Breaking.Bad.S01E02.fa.srt
Needs Review:
    trailer.mkv          (looks like non-primary content)
Unknown:
    unknown_video.mkv    (no usable signal at all)
Empty Folders:
    Old Folder/          (was emptied by this run, if it contained only moved files)
TRACE     — per-signal scoring detail (very verbose, off by default)
DEBUG     — parser/detector intermediate results
INFO      — scan started/completed, plan built, operation applied
WARN      — recoverable issues (locked file, verification retry, ambiguous match)
ERROR     — an operation failed and could not complete
CRITICAL  — data-safety-relevant failure (e.g. Journal write failed, DB corruption)\n\n{
  "timestamp": "2026-09-05T14:32:07.114Z",
  "level": "INFO",
  "module": "OrganizationExecutor",
  "operation_id": "op-2026-09-05-000018",
  "item_id": "grp-004821",
  "event": "move.completed",
  "message": "Cross-drive move verified and completed",
  "context": {
    "source": "D:\\Downloads\\Movie.mkv",
    "destination": "E:\\Movies\\Movie (2020)\\Movie.mkv",
    "verification": "size+hash",
    "duration_ms": 842
  }
}
30.3 Log Categories (one logical channel per module)
Scanner, FilenameParser, MovieDetector, SeriesDetector, SubtitleMatcher,
MediaGrouper, MetadataExtractor, ConfidenceEngine, RuleEngine, ConflictDetector,
OrganizationPlanner, OrganizationExecutor, OperationJournal, UndoManager,
CrashRecovery, LibraryDatabase, VerificationService, UserInteractionService, UI.
30.4 Correlation IDs
Every Scan run and every Apply run is assigned a unique operation_id (matching the
numbered entry in Operation History, e.g. “Organization #18”). Every log line produced
during that run carries this ID, so the full trail of a single run can be filtered and replayed
independently of any other run happening before or after it.
30.5 Mandatory Logging Points
Every exception/error is caught and logged with level ERROR or CRITICAL, full stack
trace, and surrounding context (file path, operation id, module) — errors are never
silently swallowed.
Every Move/Rename/Create-Folder operation logs its BEFORE state, intended AFTER
state, actual result (success/failure/skipped), and duration — mirroring the Journal (§19)
but for diagnostic purposes.
Every Confidence computation above TRACE level logs the final score and level
(High/Medium/Low) and, at DEBUG, the per-signal breakdown that produced it.
Every Rule Engine match/conflict/tie-break logs which rule fired and why it outranked\n\ncompeting rules.
Every cache hit/miss logs which of the three CacheKey components (§24) changed,
when it’s a miss.
Crash Recovery reads the log stream and the Journal together on startup to reconstruct
the exact point an interrupted operation stopped at.
30.6 Delivery, Rotation & Performance
Logging is asynchronous (a dedicated queue + writer thread) so it never blocks the
Scanner, the Executor, or the UI thread.
Logs are written to rotating local files (e.g. capped at 20MB per file, keeping the last 10
files by default — both values configurable), independent of the Operation Journal/Undo
data, which is never subject to rotation or deletion.
An Export Diagnostic Bundle action (Settings → Diagnostics) zips the recent logs plus
relevant Journal/Operation History entries for bug reports, with an option to keep full file
paths or redact them.
Log file contents include file paths and metadata, but never file contents.
31. Module Architecture
FileScanner              — streaming, batched directory traversal
FileClassifier
FilenameParser
FolderContextAnalyzer
MovieDetector
SeriesDetector
SeasonEpisodeParser
SubtitleDetector
SubtitleMatcher
MediaGrouper
MetadataExtractor        — core async service (§14), feeds ConfidenceEngine
                            and only §14/§15 consumers; never runs synchronously
IntegrityChecker          — corrupted / mismatch detection (§15.1, §15.2)
DuplicateDetector          — library-wide near-duplicate grouping (§15.3), never deletes
LanguageCrossChecker      — embedded vs. external subtitle language check (§15.4)
HealthReportGenerator      — builds the post-scan rollup (§15.5)
ConfidenceEngine
ConflictDetector
RuleEngine                — scope/specificity/priority (§12), persisted in LibraryDatabase\n\nDetection/organization logic is fully decoupled from the UI. The UI never moves a file
directly — it only ever talks to OrganizationPlanner/OrganizationExecutor.
32. Required Test Coverage
At minimum, cover:
Parsing & Detection
Simple movie name; movie with year; with resolution; with codec; with release group
Series S01E01; series 1x01; multiple seasons; multiple episodes; out-of-order episodes
Movie with no year + no prior conflict (organized without year)
Movie with no year + a prior same-title-different-year conflict (must ask)
Year discovered later for an already-organized no-year movie (must ask, never silent-
rename)
Multi-part detection (.Part1/.Part2, 1CD/2CD)
Multi-version detection (same title/year, different resolution/source/edition)
Both multi-part and multi-version signals present simultaneously (must ask, never
guess)
Subtitles
Persian subtitle; English subtitle; multiple subtitles per video; subtitle with a differing
filename; folder-context-only subtitle matching
A CORRUPTED video with matched subtitles — subtitles must be held with it, not
organized separately
OrganizationPlanner
OrganizationExecutor      — implements same-drive atomic rename and cross-drive
                            copy→verify→rename→delete (§19) as clearly separate paths
OperationJournal
UndoManager
CrashRecovery
LibraryDatabase           — CacheKey (§24), Rules, history, confidence results
VerificationService
UserInteractionService
LoggingService            — structured, async, correlated logging (§30)\n\nStructure & Safety
Already-correctly-organized files (must be left untouched, Action = NONE)
Duplicate destination names; existing destination file (no overwrite)
Locked files; permission errors (skip + retry, batch continues)
Empty folders (single-level and nested) moved into Empty Folders/
A folder already inside Empty Folders/ becoming empty again (must not nest further)
Files inside Empty Folders/ are never reclassified by later scans
Cache & Performance
mtime changed, content hash unchanged → full re-parse still occurs
content hash changed, mtime unchanged → full re-parse still occurs
both unchanged → cache hit, no re-parse
a folder with tens of thousands of files → memory stays flat as file count grows
(streaming/batched scan)
Video Metadata & Supplementary Features
Filename/resolution mismatch → lowers VideoMetadataMatch, logged as Conflict
Duration contradicts claimed content type (episode-named file with movie-length
duration)
Unreadable/corrupted file routed to its own review list, never auto-moved
Two differently-named, near-identical files (size/duration/resolution within tolerance) →
flagged as Possible Duplicate, never auto-deleted, found even when the two files sit in
different folders
External subtitle language vs. embedded track language mismatch → informational
warning only
Video metadata disabled in Settings → Confidence weights renormalize correctly, and all
5 supplementary features and the Health Report visibly reflect being skipped
Parallel ffprobe runs on thousands of files never freeze the UI (worker pool / async)
Rules
Folder-specific exact match outranks global exact match; exact match outranks pattern
match\n\nTwo same-level conflicting rules → newest wins, older kept inactive (not deleted)
Deleting a rule never retroactively reverts previously organized files
Transactions, Undo, Crash Recovery
Cross-drive move: happy path (copy → verify → rename → delete)
Cross-drive move: verification failure → temp file cleaned up, source untouched,
Retry/Skip/Abort offered
Same-drive move uses atomic rename, no copy/verify overhead
A file changing on disk between Scan and Apply → pulled from plan, user notified, rest
of plan proceeds
A locked/failed file mid-batch-Apply → skipped and logged, batch continues (not
treated as a crash)
A genuine crash mid-Apply → detected on next launch, Resume/Rollback/Review offered
Full Undo of a completed run restores prior filesystem state
Unicode/Persian/Kurdish/Arabic filenames and folder names survive the full pipeline
without corruption
Long path handling and pre-move warnings when a path can’t be supported
Logging
Every operation type (Move/Rename/Create Folder/Skip/Error) produces a structured log
line with a correct operation_id
No exception path exists that fails to produce at least one ERROR/CRITICAL log line
Crash Recovery can reconstruct the exact stopping point purely from logs + Journal
Log rotation caps file count/size without ever touching Journal/Undo data
33. Implementation Order (Restated)
1. Project architecture and module/folder layout.
2. Detection engine: Parser → Detectors → ConfidenceEngine → RuleEngine.
3. Organization Planner and Transaction System, including cross-drive safety and the
Logging subsystem wired in from the start (not bolted on later).\n\n4. Simple UI on top of the finished engine.
At no stage may Safety, Confidence, Preview, Journal, Undo, Crash Recovery, or Logging be
removed or simplified away to make implementation easier.