reelsort 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,480 @@
1
+ # ReelSort
2
+
3
+ A CLI to organize and manage your media library. Renames messy download filenames into clean, consistent formats, moves files into the right destination folders, tracks everything in a local SQLite database, and keeps your library inspectable with a single command.
4
+
5
+ Works on macOS, Windows, and Linux.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g reelsort
11
+ ```
12
+
13
+ ### Prerequisites
14
+
15
+ - **Node.js** >= 18
16
+ - **ffmpeg** — optional, required only for `reelsort probe`
17
+
18
+ ## Quick Start
19
+
20
+ ```bash
21
+ # Tell ReelSort where your downloads land and where your library lives
22
+ reelsort config add source ~/Downloads
23
+ reelsort config set dest movie /Volumes/Media/Movies
24
+ reelsort config set dest tv /Volumes/Media/TV
25
+
26
+ # Preview what would be imported without touching anything
27
+ reelsort scan --dry-run
28
+
29
+ # Import
30
+ reelsort scan
31
+ ```
32
+
33
+ ---
34
+
35
+ ## Commands
36
+
37
+ ### `reelsort config`
38
+
39
+ Manage configuration stored at `~/.config/reelsort/config.json`.
40
+
41
+ ```bash
42
+ reelsort config add source <dir> # add a source directory
43
+ reelsort config remove source <dir> # remove a source directory
44
+ reelsort config set dest movie <dir> # set movie destination
45
+ reelsort config set dest tv <dir> # set TV destination
46
+ reelsort config set dest ps3 <dir> # set PS3 destination
47
+ reelsort config set language <code> # subtitle language (default: eng)
48
+ reelsort config set tmdb-key <key> # TMDb API key
49
+ reelsort config set format movie <fmt> # movie naming format
50
+ reelsort config set format episode <fmt> # episode naming format
51
+ reelsort config set format season <fmt> # season folder format
52
+ reelsort config show # print current config
53
+ ```
54
+
55
+ Multiple sources are supported — useful if your torrent client and browser downloads land in different folders:
56
+
57
+ ```bash
58
+ reelsort config add source ~/Downloads
59
+ reelsort config add source /Volumes/External/uTorrent/Completed
60
+ ```
61
+
62
+ ---
63
+
64
+ ### `reelsort add <name>`
65
+
66
+ Register a TV show for scanning. Searches TMDb by name, shows an interactive picker when multiple results are found (with a clickable link to each candidate's TMDb page), and creates the show folder in your TV destination.
67
+
68
+ ```bash
69
+ reelsort add Severance
70
+ reelsort add "The Bear"
71
+ ```
72
+
73
+ TV episodes are only imported during `reelsort scan` if the show is registered. Use `reelsort link` to register shows that already exist on disk.
74
+
75
+ ---
76
+
77
+ ### `reelsort scan`
78
+
79
+ Import media from all configured sources into their destinations. Parses raw download filenames, renames files, creates folder structure, and records every import in the database.
80
+
81
+ ```bash
82
+ reelsort scan # move files to destinations
83
+ reelsort scan --hardlink # hardlink instead of moving (great for seeders)
84
+ reelsort scan --dry-run # preview without touching anything
85
+ reelsort scan --type movie # only process movies
86
+ reelsort scan --verbose # show skipped items
87
+ reelsort scan --auto # auto-register unrecognised TV shows instead of skipping
88
+ ```
89
+
90
+ TV episodes are skipped unless the show has been registered via `reelsort add` or `reelsort link`. `--auto` restores the old behaviour: unregistered shows are created on the fly without prompting.
91
+
92
+ TV output creates the full folder structure:
93
+
94
+ ```
95
+ TV/
96
+ Severance (2022)/
97
+ Season 2/
98
+ 2x01.mkv
99
+ ```
100
+
101
+ Season folders are matched by number if they already exist under any naming convention. New season folders are created using your configured format.
102
+
103
+ ---
104
+
105
+ ### `reelsort watch`
106
+
107
+ Watch all configured sources continuously and auto-import new files as they arrive. Same logic as `scan`, triggered per item with a debounce to handle large downloads that arrive in chunks.
108
+
109
+ ```bash
110
+ reelsort watch
111
+ reelsort watch --hardlink
112
+ ```
113
+
114
+ Press `Ctrl+C` to stop.
115
+
116
+ ---
117
+
118
+ ### `reelsort clean`
119
+
120
+ Remove source files that were already imported via hardlink or copy. Safe to run while seeding — if a file is locked by your torrent client, it is skipped and left for the next run.
121
+
122
+ ```bash
123
+ reelsort clean # remove imported source files
124
+ reelsort clean --dry-run # preview what would be removed
125
+ reelsort clean --older-than 14d # only clean imports older than 14 days
126
+ ```
127
+
128
+ `--older-than` accepts `d` (days), `h` (hours), or `m` (minutes).
129
+
130
+ ---
131
+
132
+ ### `reelsort rename`
133
+
134
+ Rename media files in-place inside a directory. Useful for cleaning up an existing library that wasn't imported through `scan`.
135
+
136
+ ```bash
137
+ reelsort rename <dir>
138
+ reelsort rename <dir> --type movie
139
+ reelsort rename <dir> --type tv
140
+ reelsort rename <dir> --type ps3
141
+ reelsort rename <dir> --verbose
142
+ ```
143
+
144
+ Renames folders and their primary video file to match your configured movie format. Keeps one subtitle file (matching your configured language) and removes everything else.
145
+
146
+ ---
147
+
148
+ ### `reelsort reset`
149
+
150
+ Rename episode files inside a season folder to match your configured episode format. Useful for seasons that were copied in without going through `scan`.
151
+
152
+ ```bash
153
+ reelsort reset <dir> # e.g. "TV/Severance/Season 2"
154
+ reelsort reset <dir> --double # episodes are double-length (1x01-1x02)
155
+ ```
156
+
157
+ The season number is detected automatically from the folder name. The show title is read from the parent folder.
158
+
159
+ ---
160
+
161
+ ### `reelsort probe`
162
+
163
+ Index your library using `ffprobe` to get accurate codec and resolution for every video file. Results are stored in SQLite and used by `reelsort list`. Run this once to populate your existing library, then re-run whenever you add files outside of `scan`.
164
+
165
+ ```bash
166
+ reelsort probe # index all destinations
167
+ reelsort probe --type movie # index only movies
168
+ reelsort probe --force # re-probe files already indexed
169
+ reelsort probe --verbose # show each file as it is probed
170
+ ```
171
+
172
+ Requires ffmpeg to be installed. If ffprobe is not found, the command tells you rather than silently doing nothing.
173
+
174
+ ---
175
+
176
+ ### `reelsort list`
177
+
178
+ Display your library in a table, sorted by year. Codec and resolution come from the probe index (populated by `reelsort probe`) if available, otherwise fall back to parsing the original download filename from import history.
179
+
180
+ ```bash
181
+ reelsort list # list all configured destinations
182
+ reelsort list --type movie # list only movies
183
+ reelsort list --missing-subs # only show items without subtitles
184
+ reelsort list --codec x265 # filter by codec
185
+ reelsort list --resolution 1080p # filter by resolution
186
+ reelsort list --sort title # sort alphabetically (default: year)
187
+ ```
188
+
189
+ Example output:
190
+
191
+ ```
192
+ MOVIE /Volumes/Media/Movies
193
+ ──────────────────────────────────────────────────────────────────────
194
+ Title Year Res Codec Size Sub
195
+ ──────────────────────────────────────────────────────────────────────
196
+ Dune Part Two 2024 2160p x265 58.2 GB ✓
197
+ Oppenheimer 2023 1080p x264 22.1 GB ✗
198
+ The Dark Knight 2008 — — 14.8 GB ✓
199
+ ──────────────────────────────────────────────────────────────────────
200
+ 3 of 3 items
201
+ ```
202
+
203
+ ---
204
+
205
+ ### `reelsort link`
206
+
207
+ Register TV shows that already exist on disk — useful when migrating an existing library or after manually organising files. Walks your TV destination, looks up each unregistered folder in TMDb, and prompts when multiple matches are found (with a clickable link to each candidate's TMDb page).
208
+
209
+ ```bash
210
+ reelsort link # register all unlinked shows
211
+ reelsort link --force # re-link shows that are already registered
212
+ ```
213
+
214
+ Shows with a single TMDb match are linked automatically. Shows not found in TMDb are skipped with a warning. Once registered, shows work with `reelsort scan` and `reelsort missing`.
215
+
216
+ ---
217
+
218
+ ### `reelsort ended`
219
+
220
+ Mark a show as ended so it is excluded from `reelsort missing`. Run it again with `--remove` to restore a show to active.
221
+
222
+ ```bash
223
+ reelsort ended # pick a show to mark as ended
224
+ reelsort ended --remove # pick an ended show to restore
225
+ ```
226
+
227
+ An interactive picker lists your tracked shows. Ended shows are skipped in `reelsort missing` and a count is shown at the bottom of that output.
228
+
229
+ ---
230
+
231
+ ### `reelsort shows`
232
+
233
+ List all registered TV shows with their TMDb link, size on disk, and ended status.
234
+
235
+ ```bash
236
+ reelsort shows
237
+ ```
238
+
239
+ Example output:
240
+
241
+ ```
242
+ SHOWS /Volumes/Media/TV (3 registered)
243
+ ────────────────────────────────────────────────────────
244
+ Title Size Linked Status
245
+ ────────────────────────────────────────────────────────
246
+ Severance (2022) 28.4 GB ✓ tmdb active
247
+ The Bear (2022) 14.1 GB ✓ tmdb active
248
+ White Lotus (2021) 9.7 GB ✗ ended
249
+ ────────────────────────────────────────────────────────
250
+ 3 shows · 2 linked · 1 ended
251
+ ```
252
+
253
+ ---
254
+
255
+ ### `reelsort stats`
256
+
257
+ Show library statistics — total counts and size per destination.
258
+
259
+ ```bash
260
+ reelsort stats
261
+ ```
262
+
263
+ ---
264
+
265
+ ### `reelsort missing`
266
+
267
+ Check your TV library against TMDb and report any episodes that have aired but aren't on disk. Requires a TMDb API key. Shows must be linked (via `reelsort scan` or `reelsort link`) to appear.
268
+
269
+ ```bash
270
+ reelsort missing # check all shows
271
+ reelsort missing --show Severance # check a specific show
272
+ ```
273
+
274
+ Example output:
275
+
276
+ ```
277
+ Severance (2022)
278
+ S01E04 — The You You Are
279
+ S01E07 — Defiant Jazz
280
+
281
+ 2 missing episodes total
282
+ 2 ended shows skipped
283
+ ```
284
+
285
+ Only episodes with a past air date are reported — future episodes are ignored. Ended shows are excluded entirely.
286
+
287
+ ---
288
+
289
+ ### `reelsort history`
290
+
291
+ Show rename or import history grouped by session.
292
+
293
+ ```bash
294
+ reelsort history # rename history
295
+ reelsort history --imports # import history (what scan/watch moved)
296
+ reelsort history --limit 5 # show last 5 sessions (default: 10)
297
+ reelsort history --imports --limit 3
298
+ ```
299
+
300
+ ---
301
+
302
+ ### `reelsort undo`
303
+
304
+ Reverse all renames from the last `reelsort rename` session.
305
+
306
+ ```bash
307
+ reelsort undo
308
+ ```
309
+
310
+ ---
311
+
312
+ ### `reelsort diff`
313
+
314
+ Compare two directories and show what's in one but not the other.
315
+
316
+ ```bash
317
+ reelsort diff <dir1> <dir2>
318
+ reelsort diff <dir1> <dir2> --only mkv
319
+ reelsort diff <dir1> <dir2> --ignore nfo jpg
320
+ ```
321
+
322
+ ---
323
+
324
+ ## Configuration Reference
325
+
326
+ ### Naming Formats
327
+
328
+ All formats use token substitution. Unrecognized tokens are left as literals.
329
+
330
+ #### Movie format
331
+
332
+ | Token | Description |
333
+ |---|---|
334
+ | `{title}` | Movie title (required) |
335
+ | `{year}` | Release year |
336
+ | `{edition}` | Plex edition tag, e.g. `{edition-Director's Cut}` |
337
+
338
+ ```bash
339
+ reelsort config set format movie "{title} ({year})" # default
340
+ reelsort config set format movie "{title} ({year}){edition}" # Plex editions
341
+ ```
342
+
343
+ Detected editions: Director's Cut, Final Cut, Extended, Theatrical, Unrated, Anniversary Edition, Collector's Edition, Special Edition.
344
+
345
+ #### Episode format
346
+
347
+ | Token | Description |
348
+ |---|---|
349
+ | `{s}` | Season number, no padding |
350
+ | `{ss}` | Season number, 2-digit padded |
351
+ | `{sss}` | Season number, 3-digit padded |
352
+ | `{e}` `{ee}` `{eee}` | Episode number, same padding options |
353
+ | `{title}` | Show title |
354
+ | `{name}` | Episode title (from TMDb, requires API key) |
355
+
356
+ ```bash
357
+ reelsort config set format episode "{s}x{ee}" # 1x01 (default)
358
+ reelsort config set format episode "S{ss}E{ee}" # S01E01
359
+ reelsort config set format episode "S{ss}E{ee} - {title}" # S01E01 - Severance
360
+ ```
361
+
362
+ #### Season folder format
363
+
364
+ Uses the same `{s}` / `{ss}` / `{sss}` tokens.
365
+
366
+ ```bash
367
+ reelsort config set format season "Season {s}" # Season 1 (default)
368
+ reelsort config set format season "Season {ss}" # Season 01
369
+ reelsort config set format season "S{ss}" # S01
370
+ ```
371
+
372
+ ### Subtitle Language
373
+
374
+ Set the preferred subtitle language code. When multiple subtitle files are present, the one matching this language is kept. Falls back to the first subtitle found.
375
+
376
+ ```bash
377
+ reelsort config set language eng # default
378
+ reelsort config set language fre
379
+ reelsort config set language spa
380
+ ```
381
+
382
+ ### TMDb Integration
383
+
384
+ When a TMDb API key is configured, `reelsort scan` looks up each title before naming it. This corrects capitalization, fills in missing years, and resolves ambiguous names — the canonical TMDb title and year are used instead of whatever was in the download filename.
385
+
386
+ ```bash
387
+ reelsort config set tmdb-key <your-key>
388
+ ```
389
+
390
+ **Movie lookup** — automatically uses the top result.
391
+
392
+ **TV show lookup** — if only one show matches, it is used automatically. If multiple shows share the same name, an interactive picker is shown so you can choose the right one:
393
+
394
+ ```
395
+ ◆ Multiple shows found for "Severance":
396
+ > 1. Severance (2022) — In a corporation, a group of employees have... <
397
+ 2. Severance (2006) — Six office workers on a corporate retreat...
398
+ 0. Skip
399
+ ```
400
+
401
+ Arrow keys or number keys to select, Enter to confirm. Choosing `0` or Skip falls back to the parsed filename as-is. If TMDb is unreachable or returns no results, ReelSort falls back silently and continues.
402
+
403
+ **Episode names** — TMDb also supplies the episode title for each file. Use the `{name}` token in your episode format to include it:
404
+
405
+ ```bash
406
+ reelsort config set format episode "S{ss}E{ee} - {name}"
407
+ # produces: S01E01 - Good News About Hell.mkv
408
+ ```
409
+
410
+ The TMDb ID is stored alongside every import in the database, which powers the `reelsort missing` command.
411
+
412
+ **Getting a free API key:**
413
+ 1. Create a free account at [themoviedb.org](https://www.themoviedb.org)
414
+ 2. Go to **Settings → API**
415
+ 3. Request a developer key — no credit card or approval needed, it's instant
416
+
417
+ Keys are stored locally in `~/.config/reelsort/config.json` and never leave your machine.
418
+
419
+ ---
420
+
421
+ ## Workflows
422
+
423
+ ### Hardlink mode (recommended for seeders)
424
+
425
+ Hardlinks let your torrent client keep seeding the original file while your library gets the clean, organized copy — no extra disk space used. Only works within the same filesystem.
426
+
427
+ ```bash
428
+ reelsort scan --hardlink # or reelsort watch --hardlink
429
+ # ... seed until done ...
430
+ reelsort clean # remove source files once seeding is finished
431
+ ```
432
+
433
+ If source and destination are on different filesystems, `--hardlink` automatically falls back to copy with a warning. Copied files are also tracked and cleaned up by `reelsort clean`.
434
+
435
+ ### One-time library cleanup
436
+
437
+ If you already have a library that was organized manually:
438
+
439
+ ```bash
440
+ # Rename in-place to your preferred format
441
+ reelsort rename /Volumes/Media/Movies
442
+
443
+ # Index metadata
444
+ reelsort probe
445
+
446
+ # Inspect
447
+ reelsort list
448
+ ```
449
+
450
+ ### Fully automated
451
+
452
+ ```bash
453
+ reelsort config add source ~/Downloads
454
+ reelsort config set dest movie /Volumes/Media/Movies
455
+ reelsort config set dest tv /Volumes/Media/TV
456
+ reelsort watch --hardlink
457
+ ```
458
+
459
+ ---
460
+
461
+ ## Database
462
+
463
+ ReelSort stores its database at `~/.config/reelsort/reelsort.db`. It tracks:
464
+
465
+ - **renameHistory** — every rename performed by `reelsort rename`, used by `reelsort undo`
466
+ - **imports** — every file imported by `reelsort scan` or `reelsort watch`, used by `reelsort clean`
467
+ - **shows** — one row per TV show folder, storing the TMDb series ID and ended flag. Populated by `reelsort scan` and `reelsort link`, used by `reelsort missing` and `reelsort ended`
468
+ - **mediaInfo** — codec, resolution, and duration indexed by `reelsort probe`, used by `reelsort list`
469
+
470
+ ---
471
+
472
+ ## Platform Support
473
+
474
+ | Platform | Supported |
475
+ |---|---|
476
+ | macOS | ✓ |
477
+ | Windows | ✓ |
478
+ | Linux | ✓ |
479
+
480
+ File watching on macOS uses FSEvents, Windows uses ReadDirectoryChangesW, and Linux uses inotify — all via [chokidar](https://github.com/paulmillr/chokidar).