migratarr 0.1.0rc1__tar.gz

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.
Files changed (116) hide show
  1. migratarr-0.1.0rc1/LICENSE +21 -0
  2. migratarr-0.1.0rc1/PKG-INFO +278 -0
  3. migratarr-0.1.0rc1/README.md +239 -0
  4. migratarr-0.1.0rc1/migratarr/__init__.py +1 -0
  5. migratarr-0.1.0rc1/migratarr/approval_store.py +165 -0
  6. migratarr-0.1.0rc1/migratarr/approve_execution.py +385 -0
  7. migratarr-0.1.0rc1/migratarr/arr_files.py +95 -0
  8. migratarr-0.1.0rc1/migratarr/audit_overrides.py +141 -0
  9. migratarr-0.1.0rc1/migratarr/batch_cross_movies.py +140 -0
  10. migratarr-0.1.0rc1/migratarr/batch_cross_tv.py +146 -0
  11. migratarr-0.1.0rc1/migratarr/build_execution_manifest.py +306 -0
  12. migratarr-0.1.0rc1/migratarr/build_move_plan.py +776 -0
  13. migratarr-0.1.0rc1/migratarr/cli.py +80 -0
  14. migratarr-0.1.0rc1/migratarr/demo.py +196 -0
  15. migratarr-0.1.0rc1/migratarr/demo_library.py +163 -0
  16. migratarr-0.1.0rc1/migratarr/doctor.py +82 -0
  17. migratarr-0.1.0rc1/migratarr/dry_run_movies.py +747 -0
  18. migratarr-0.1.0rc1/migratarr/dry_run_tv.py +939 -0
  19. migratarr-0.1.0rc1/migratarr/engine/__init__.py +1 -0
  20. migratarr-0.1.0rc1/migratarr/engine/nas_side.py +178 -0
  21. migratarr-0.1.0rc1/migratarr/engine/primitives.py +78 -0
  22. migratarr-0.1.0rc1/migratarr/engine/transport.py +77 -0
  23. migratarr-0.1.0rc1/migratarr/execute_cross_movie.py +365 -0
  24. migratarr-0.1.0rc1/migratarr/execute_cross_tv.py +404 -0
  25. migratarr-0.1.0rc1/migratarr/execute_movie.py +288 -0
  26. migratarr-0.1.0rc1/migratarr/execute_movie_nas.py +381 -0
  27. migratarr-0.1.0rc1/migratarr/execute_tv_nas.py +398 -0
  28. migratarr-0.1.0rc1/migratarr/executor_command.py +133 -0
  29. migratarr-0.1.0rc1/migratarr/executor_inventory.py +25 -0
  30. migratarr-0.1.0rc1/migratarr/executor_manifest.py +98 -0
  31. migratarr-0.1.0rc1/migratarr/executor_nfs.py +39 -0
  32. migratarr-0.1.0rc1/migratarr/health.py +372 -0
  33. migratarr-0.1.0rc1/migratarr/jobs.py +448 -0
  34. migratarr-0.1.0rc1/migratarr/media_layout.py +86 -0
  35. migratarr-0.1.0rc1/migratarr/movie_placement_v1.py +853 -0
  36. migratarr-0.1.0rc1/migratarr/paths.py +77 -0
  37. migratarr-0.1.0rc1/migratarr/pipeline_inputs.py +65 -0
  38. migratarr-0.1.0rc1/migratarr/plan.py +173 -0
  39. migratarr-0.1.0rc1/migratarr/planner_settings.py +366 -0
  40. migratarr-0.1.0rc1/migratarr/read_api.py +280 -0
  41. migratarr-0.1.0rc1/migratarr/reconcile.py +55 -0
  42. migratarr-0.1.0rc1/migratarr/reconcile_store.py +124 -0
  43. migratarr-0.1.0rc1/migratarr/recover_cross_0102.py +233 -0
  44. migratarr-0.1.0rc1/migratarr/recover_cross_0116.py +157 -0
  45. migratarr-0.1.0rc1/migratarr/recover_cross_published.py +290 -0
  46. migratarr-0.1.0rc1/migratarr/runtime_config.py +364 -0
  47. migratarr-0.1.0rc1/migratarr/service_keys.py +195 -0
  48. migratarr-0.1.0rc1/migratarr/services.py +105 -0
  49. migratarr-0.1.0rc1/migratarr/settings/__init__.py +20 -0
  50. migratarr-0.1.0rc1/migratarr/settings/keys.py +87 -0
  51. migratarr-0.1.0rc1/migratarr/settings/store.py +508 -0
  52. migratarr-0.1.0rc1/migratarr/settings/ui_backend.py +879 -0
  53. migratarr-0.1.0rc1/migratarr/settings_contract.py +138 -0
  54. migratarr-0.1.0rc1/migratarr/settings_ui.py +341 -0
  55. migratarr-0.1.0rc1/migratarr/setup_wizard.py +239 -0
  56. migratarr-0.1.0rc1/migratarr/snapshot_run.py +254 -0
  57. migratarr-0.1.0rc1/migratarr/status.py +94 -0
  58. migratarr-0.1.0rc1/migratarr/storage_targets.py +278 -0
  59. migratarr-0.1.0rc1/migratarr/tv_placement_v1.py +1017 -0
  60. migratarr-0.1.0rc1/migratarr/ui.py +1483 -0
  61. migratarr-0.1.0rc1/migratarr.egg-info/PKG-INFO +278 -0
  62. migratarr-0.1.0rc1/migratarr.egg-info/SOURCES.txt +114 -0
  63. migratarr-0.1.0rc1/migratarr.egg-info/dependency_links.txt +1 -0
  64. migratarr-0.1.0rc1/migratarr.egg-info/entry_points.txt +2 -0
  65. migratarr-0.1.0rc1/migratarr.egg-info/top_level.txt +1 -0
  66. migratarr-0.1.0rc1/pyproject.toml +40 -0
  67. migratarr-0.1.0rc1/setup.cfg +4 -0
  68. migratarr-0.1.0rc1/tests/test_approval_store.py +92 -0
  69. migratarr-0.1.0rc1/tests/test_arr_file_checks.py +211 -0
  70. migratarr-0.1.0rc1/tests/test_audit.py +35 -0
  71. migratarr-0.1.0rc1/tests/test_audit_overrides.py +97 -0
  72. migratarr-0.1.0rc1/tests/test_batch_approval.py +238 -0
  73. migratarr-0.1.0rc1/tests/test_capture.py +54 -0
  74. migratarr-0.1.0rc1/tests/test_cli.py +124 -0
  75. migratarr-0.1.0rc1/tests/test_config.py +103 -0
  76. migratarr-0.1.0rc1/tests/test_copy_tree_permissions.py +98 -0
  77. migratarr-0.1.0rc1/tests/test_demo.py +51 -0
  78. migratarr-0.1.0rc1/tests/test_dry_run_parity.py +106 -0
  79. migratarr-0.1.0rc1/tests/test_engine_layout.py +100 -0
  80. migratarr-0.1.0rc1/tests/test_executor_command.py +102 -0
  81. migratarr-0.1.0rc1/tests/test_executor_golden.py +370 -0
  82. migratarr-0.1.0rc1/tests/test_executor_idle_timeout.py +114 -0
  83. migratarr-0.1.0rc1/tests/test_executor_safety.py +701 -0
  84. migratarr-0.1.0rc1/tests/test_executor_safety_phase2.py +395 -0
  85. migratarr-0.1.0rc1/tests/test_health.py +326 -0
  86. migratarr-0.1.0rc1/tests/test_impact.py +139 -0
  87. migratarr-0.1.0rc1/tests/test_inventory_metadata.py +170 -0
  88. migratarr-0.1.0rc1/tests/test_local_transport.py +185 -0
  89. migratarr-0.1.0rc1/tests/test_manifest_parity.py +73 -0
  90. migratarr-0.1.0rc1/tests/test_media_layout.py +371 -0
  91. migratarr-0.1.0rc1/tests/test_nas_program_parity.py +78 -0
  92. migratarr-0.1.0rc1/tests/test_nfs_verifier.py +90 -0
  93. migratarr-0.1.0rc1/tests/test_override_tags.py +124 -0
  94. migratarr-0.1.0rc1/tests/test_paths.py +105 -0
  95. migratarr-0.1.0rc1/tests/test_pipeline_inputs.py +127 -0
  96. migratarr-0.1.0rc1/tests/test_plan_command.py +196 -0
  97. migratarr-0.1.0rc1/tests/test_planner_streaming.py +171 -0
  98. migratarr-0.1.0rc1/tests/test_planner_targets.py +132 -0
  99. migratarr-0.1.0rc1/tests/test_planner_unknown_category.py +270 -0
  100. migratarr-0.1.0rc1/tests/test_provider_families.py +124 -0
  101. migratarr-0.1.0rc1/tests/test_read_api.py +292 -0
  102. migratarr-0.1.0rc1/tests/test_reconcile.py +144 -0
  103. migratarr-0.1.0rc1/tests/test_recover_cross_published.py +280 -0
  104. migratarr-0.1.0rc1/tests/test_rules.py +150 -0
  105. migratarr-0.1.0rc1/tests/test_runtime_config.py +289 -0
  106. migratarr-0.1.0rc1/tests/test_scoring_settings.py +125 -0
  107. migratarr-0.1.0rc1/tests/test_service_keys.py +225 -0
  108. migratarr-0.1.0rc1/tests/test_service_urls.py +151 -0
  109. migratarr-0.1.0rc1/tests/test_settings.py +447 -0
  110. migratarr-0.1.0rc1/tests/test_settings_ui.py +312 -0
  111. migratarr-0.1.0rc1/tests/test_storage_targets.py +198 -0
  112. migratarr-0.1.0rc1/tests/test_ui.py +208 -0
  113. migratarr-0.1.0rc1/tests/test_ui_actions.py +253 -0
  114. migratarr-0.1.0rc1/tests/test_ui_backend.py +454 -0
  115. migratarr-0.1.0rc1/tests/test_ui_jobs.py +237 -0
  116. migratarr-0.1.0rc1/tests/test_validation_engine.py +287 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Josh Wilcox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,278 @@
1
+ Metadata-Version: 2.4
2
+ Name: migratarr
3
+ Version: 0.1.0rc1
4
+ Summary: Moves Radarr/Sonarr media between storage tiers by how hard it is to re-acquire, where it streams and how it is watched; every move is approved first.
5
+ License: MIT License
6
+
7
+ Copyright (c) 2026 Josh Wilcox
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
27
+ Project-URL: Source, https://github.com/jwilcox99/Migratarr
28
+ Project-URL: Issues, https://github.com/jwilcox99/Migratarr/issues
29
+ Classifier: Development Status :: 3 - Alpha
30
+ Classifier: Programming Language :: Python :: 3
31
+ Classifier: Programming Language :: Python :: 3 :: Only
32
+ Classifier: Operating System :: POSIX :: Linux
33
+ Classifier: Environment :: Web Environment
34
+ Classifier: Topic :: Multimedia :: Video
35
+ Requires-Python: >=3.10
36
+ Description-Content-Type: text/markdown
37
+ License-File: LICENSE
38
+ Dynamic: license-file
39
+
40
+ <p align="center">
41
+ <picture>
42
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jwilcox99/Migratarr/main/assets/migratarr-lockup-dark.svg">
43
+ <img alt="Migratarr" src="https://raw.githubusercontent.com/jwilcox99/Migratarr/main/assets/migratarr-lockup-light.svg" width="360">
44
+ </picture>
45
+ </p>
46
+
47
+ # Migratarr
48
+
49
+ Migratarr decides *where* your Radarr and Sonarr media should live, and moves
50
+ it there once you approve. It works alongside Radarr and Sonarr (which manage
51
+ what's in your library) and Jellyfin (which plays it), and sorts movies and TV
52
+ across your disks by how hard each title would be to get again, whether it's
53
+ on a streaming service you pay for, and how your household actually watches
54
+ it.
55
+
56
+ Every move is planned first. Nothing moves until you review the plan and
57
+ approve it.
58
+
59
+ > **Status: 0.1.0, the first public release.** Migratarr was built for one
60
+ > home media stack and has moved real libraries there over a NAS. Moving
61
+ > files between disks attached to the same machine is new in 0.1.0 and
62
+ > **experimental**. Linux only. Read [Safety model](#safety-model) before
63
+ > pointing it at a library you care about.
64
+
65
+ ## Who it's for
66
+
67
+ You run Radarr and Sonarr (and Jellyfin) at home, your media is spread over
68
+ several disks, and you'd like the titles you'd struggle to replace on the
69
+ disks you trust most, without moving thousands of folders by hand.
70
+
71
+ ## What it does
72
+
73
+ For each movie and series, Migratarr looks at:
74
+
75
+ - **Replacement difficulty:** how many releases Radarr or Sonarr can still
76
+ find. An estimate, not a guarantee.
77
+ - **Streaming:** whether it's on a service you subscribe to, free with ads,
78
+ rent/buy only, or not streaming in your region (from TMDB).
79
+ - **Usage:** Jellyfin plays, how recent, repeat plays and how many people in
80
+ the household watched it, with a grace period for new additions.
81
+ - **Collections (movies):** a small bonus when related films are already
82
+ protected.
83
+
84
+ From that it picks a placement category:
85
+
86
+ | Movies | TV |
87
+ | --- | --- |
88
+ | Common | Current |
89
+ | Library | Library |
90
+ | Rare | Rare |
91
+ | Archive | Archive |
92
+
93
+ You decide which disks hold each category and which folder each one uses. A
94
+ title that's hard to replace and isn't streaming anywhere stays in Rare even
95
+ if nobody has watched it lately; a widely available title nobody plays may
96
+ become an Archive candidate.
97
+
98
+ ## Requirements
99
+
100
+ - A Linux machine with Python 3.10 or newer that can see your media disks.
101
+ Migratarr uses only the standard library.
102
+ - Radarr and Sonarr (Sonarr v4 recommended), Jellyfin, and a
103
+ [TMDB API Read Access Token](https://www.themoviedb.org/settings/api).
104
+ - Radarr's and Sonarr's root folders already pointing at the disks and
105
+ category folders Migratarr will use.
106
+ - To move files, by default, permission to run `docker exec` in the Radarr and
107
+ Sonarr containers: before and after every move Migratarr checks the files
108
+ where Radarr and Sonarr see them. Non-Docker installs can check on the host
109
+ instead; see [Arr file checks](https://github.com/jwilcox99/Migratarr/blob/main/docs/runtime-configuration.md#arr-file-checks).
110
+ - For moves on a NAS: SSH access to the NAS with a key used only by Migratarr,
111
+ and Python 3 on the NAS.
112
+
113
+ ## Install
114
+
115
+ ```sh
116
+ pip install migratarr
117
+ ```
118
+
119
+ Install it into a virtual environment, or with `pipx install migratarr`, if
120
+ your system Python doesn't allow `pip install`. Check it worked with
121
+ `migratarr --version`.
122
+
123
+ ## Try it first
124
+
125
+ ```sh
126
+ migratarr demo
127
+ ```
128
+
129
+ Plans a made-up library with the real planning pipeline and opens the web UI
130
+ read-only at `http://localhost:8767`, so you can see what a plan looks like
131
+ before connecting anything. It needs no Radarr, Sonarr, Jellyfin or TMDB,
132
+ uses no network, and never reads or writes your own settings. Everything
133
+ goes in a new temporary folder (`--dir` to choose one; delete it when done).
134
+
135
+ ## First run
136
+
137
+ Run Migratarr as a user that can read and write your media folders, then:
138
+
139
+ ```sh
140
+ migratarr ui
141
+ ```
142
+
143
+ It prints the address, `http://localhost:8765`. The UI listens on this machine
144
+ only (127.0.0.1). If Migratarr runs on a server, open an SSH tunnel from your
145
+ own computer and browse to the same address:
146
+
147
+ ```sh
148
+ ssh -L 8765:localhost:8765 media-host.example
149
+ ```
150
+
151
+ With no settings yet, every page leads to the setup wizard:
152
+
153
+ 1. **Connect your services:** Radarr, Sonarr, Jellyfin and TMDB. Detect reads
154
+ Radarr's and Sonarr's keys from their own config; or paste a key.
155
+ 2. **Where your disks are:** on a NAS over SSH, or on this machine's own
156
+ disks (experimental). Also the data folder.
157
+ 3. **Disks and categories:** your disks, the folder for each category, and
158
+ which disks hold each category.
159
+ 4. **Streaming services:** your TMDB region and the services you pay for.
160
+ 5. **Review and save:** nothing is written until you save.
161
+
162
+ After saving, the wizard runs the health checks. Fix anything that failed in
163
+ **Settings & health**, then make your first plan. [SETUP.md](https://github.com/jwilcox99/Migratarr/blob/main/SETUP.md) walks
164
+ through each step.
165
+
166
+ ## Where moves run
167
+
168
+ | | How it works | Status |
169
+ | --- | --- | --- |
170
+ | **NAS over SSH** | Migratarr runs on a machine that mounts the NAS disks and sends each move to the NAS over SSH, so files are copied on the NAS rather than over the network | Used on a real library |
171
+ | **This machine's own disks** | Moves run directly on disks attached to the machine running Migratarr | **Experimental**: not yet run end to end against a real Radarr and Sonarr |
172
+
173
+ Both use the same plan, approval and safety checks.
174
+
175
+ ## Using it
176
+
177
+ The web UI covers the whole cycle:
178
+
179
+ 1. **Plan:** "Plan a new run". Planning is read-only: it scores your library,
180
+ proposes moves and freezes the result as a run. A large library can take a
181
+ while.
182
+ 2. **Review and approve:** pick moves (or "Review all"), check sizes, free
183
+ space afterwards and folder permissions, then approve them.
184
+ 3. **Run:** "Run N approved moves", check the order, then "Start moving".
185
+ Each move is checked again just before it runs. You can stop after the
186
+ current move.
187
+
188
+ Jobs keep running if you close the browser or restart the UI.
189
+ `migratarr ui --read-only` shows everything with every action switched off.
190
+
191
+ ## Safety model
192
+
193
+ - **Plan, review, approve, run.** Planning never touches media files. Only an
194
+ approved move can run, and you start it.
195
+ - **No plan while a health check fails.** `migratarr plan` and the UI refuse
196
+ to plan until every check passes (warnings are fine).
197
+ - **Plans are frozen.** Each run is a read-only, checksummed snapshot of the
198
+ plan and the code that made it.
199
+ - **Approvals are tied to the exact plan.** If the plan changes after you
200
+ approve, the move refuses to run.
201
+ - **Every move is checked again first:** the plan and approval, what Radarr or
202
+ Sonarr say about that item right now, and a SHA-256 hash of every file.
203
+ - **Moves don't overwrite.** A move on one disk is a rename that never
204
+ replaces an existing folder. A move between disks copies to a staging
205
+ folder, verifies, publishes, updates Radarr or Sonarr, and deletes the
206
+ source only after checking the copy.
207
+ - **Everything is journaled.** Each move writes a journal before and after
208
+ every change. A move that fails part way is never retried automatically:
209
+ you check it and record what you found with `migratarr reconcile`.
210
+ - **Settings changes are careful.** Saving makes a backup, and is refused
211
+ while a job or move is running.
212
+
213
+ There is no undo. Start with your smallest, least important titles.
214
+
215
+ ## Commands
216
+
217
+ | Command | What it does |
218
+ | --- | --- |
219
+ | `migratarr demo [--dir DIR] [--port N] [--no-ui]` | Try it on a made-up library: plans offline, UI read-only |
220
+ | `migratarr ui [--port N] [--read-only]` | The web UI: setup, settings, plan, approve, run |
221
+ | `migratarr plan [--check]` | Make a new plan; nothing moves. `--check` runs the checks only |
222
+ | `migratarr status [--run RUN \| --execution ID] [--json]` | Runs, moves and their journals (read-only) |
223
+ | `migratarr approve ...` | Approve moves from the terminal: `--list`, `--approve ID`, `--approve-batch --media TV --transfer CROSS_DISK_TRANSFER [--limit N] [--yes]`, `--revoke ID`, `--status` |
224
+ | `migratarr doctor [--offline] [--json] [--migrate]` | Check settings, services, disks and the NAS; shows the data folder |
225
+ | `migratarr reconcile ID --outcome ... --note ...` | Record that a move flagged for checking was checked by hand |
226
+
227
+ `migratarr <command> --help` lists each command's options. Moves are started
228
+ from the web UI.
229
+
230
+ ## Where settings and data live
231
+
232
+ Everything goes in one **data folder**: `$MIGRATARR_HOME` if set, otherwise
233
+ `~/.local/share/migratarr`. (Running from a git clone, the clone itself.)
234
+ `migratarr doctor` prints which folder is in use. It holds `config/` (the
235
+ three settings files and their backups), runs, approvals and move journals.
236
+
237
+ Pasted API keys are kept apart, in `~/.config/migratarr/secrets/`, readable by
238
+ your user only; see [SECURITY.md](https://github.com/jwilcox99/Migratarr/blob/main/SECURITY.md).
239
+
240
+ ## Limitations
241
+
242
+ - Linux only.
243
+ - Moves on this machine's own disks are experimental.
244
+ - One machine runs Migratarr, and it must see the disks. With a NAS, that's
245
+ one NAS reached over SSH.
246
+ - Radarr and Sonarr must see the media under the same folder layout: one root,
247
+ then a category folder, then the title.
248
+ - Radarr or Sonarr on a different machine, with no view of their media from
249
+ the machine running Migratarr, isn't supported.
250
+ - Moves run from the web UI; there's no command that runs them.
251
+ - Streaming groups are written for the US; elsewhere, add your region's
252
+ services ([Provider families](https://github.com/jwilcox99/Migratarr/blob/main/docs/planner-settings.md#provider-families)).
253
+ - 0.x: settings files and commands may still change between minor versions,
254
+ always with a migration or a note in the [changelog](https://github.com/jwilcox99/Migratarr/blob/main/CHANGELOG.md).
255
+
256
+ ## Documentation
257
+
258
+ - [SETUP.md](https://github.com/jwilcox99/Migratarr/blob/main/SETUP.md): the setup wizard step by step, and editing settings by hand
259
+ - [Settings](https://github.com/jwilcox99/Migratarr/blob/main/docs/settings.md): the settings files, version 2 and the health checks
260
+ - [Runtime configuration](https://github.com/jwilcox99/Migratarr/blob/main/docs/runtime-configuration.md): `runtime.json` reference
261
+ - [Storage targets](https://github.com/jwilcox99/Migratarr/blob/main/docs/storage-targets.md): disks, categories and placement
262
+ - [Planner settings](https://github.com/jwilcox99/Migratarr/blob/main/docs/planner-settings.md): streaming, override tags and scoring
263
+ - [Media layout](https://github.com/jwilcox99/Migratarr/blob/main/docs/media-layout.md): where Migratarr expects each title to be
264
+ - [UI actions](https://github.com/jwilcox99/Migratarr/blob/main/docs/ui-actions.md): what each button does and checks
265
+ - [Changelog](https://github.com/jwilcox99/Migratarr/blob/main/CHANGELOG.md)
266
+
267
+ ## Contributing
268
+
269
+ See [CONTRIBUTING.md](https://github.com/jwilcox99/Migratarr/blob/main/CONTRIBUTING.md).
270
+
271
+ ## Security
272
+
273
+ See [SECURITY.md](https://github.com/jwilcox99/Migratarr/blob/main/SECURITY.md). Report vulnerabilities privately through
274
+ GitHub, not in a public issue.
275
+
276
+ ## License
277
+
278
+ [MIT](https://github.com/jwilcox99/Migratarr/blob/main/LICENSE).
@@ -0,0 +1,239 @@
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/jwilcox99/Migratarr/main/assets/migratarr-lockup-dark.svg">
4
+ <img alt="Migratarr" src="https://raw.githubusercontent.com/jwilcox99/Migratarr/main/assets/migratarr-lockup-light.svg" width="360">
5
+ </picture>
6
+ </p>
7
+
8
+ # Migratarr
9
+
10
+ Migratarr decides *where* your Radarr and Sonarr media should live, and moves
11
+ it there once you approve. It works alongside Radarr and Sonarr (which manage
12
+ what's in your library) and Jellyfin (which plays it), and sorts movies and TV
13
+ across your disks by how hard each title would be to get again, whether it's
14
+ on a streaming service you pay for, and how your household actually watches
15
+ it.
16
+
17
+ Every move is planned first. Nothing moves until you review the plan and
18
+ approve it.
19
+
20
+ > **Status: 0.1.0, the first public release.** Migratarr was built for one
21
+ > home media stack and has moved real libraries there over a NAS. Moving
22
+ > files between disks attached to the same machine is new in 0.1.0 and
23
+ > **experimental**. Linux only. Read [Safety model](#safety-model) before
24
+ > pointing it at a library you care about.
25
+
26
+ ## Who it's for
27
+
28
+ You run Radarr and Sonarr (and Jellyfin) at home, your media is spread over
29
+ several disks, and you'd like the titles you'd struggle to replace on the
30
+ disks you trust most, without moving thousands of folders by hand.
31
+
32
+ ## What it does
33
+
34
+ For each movie and series, Migratarr looks at:
35
+
36
+ - **Replacement difficulty:** how many releases Radarr or Sonarr can still
37
+ find. An estimate, not a guarantee.
38
+ - **Streaming:** whether it's on a service you subscribe to, free with ads,
39
+ rent/buy only, or not streaming in your region (from TMDB).
40
+ - **Usage:** Jellyfin plays, how recent, repeat plays and how many people in
41
+ the household watched it, with a grace period for new additions.
42
+ - **Collections (movies):** a small bonus when related films are already
43
+ protected.
44
+
45
+ From that it picks a placement category:
46
+
47
+ | Movies | TV |
48
+ | --- | --- |
49
+ | Common | Current |
50
+ | Library | Library |
51
+ | Rare | Rare |
52
+ | Archive | Archive |
53
+
54
+ You decide which disks hold each category and which folder each one uses. A
55
+ title that's hard to replace and isn't streaming anywhere stays in Rare even
56
+ if nobody has watched it lately; a widely available title nobody plays may
57
+ become an Archive candidate.
58
+
59
+ ## Requirements
60
+
61
+ - A Linux machine with Python 3.10 or newer that can see your media disks.
62
+ Migratarr uses only the standard library.
63
+ - Radarr and Sonarr (Sonarr v4 recommended), Jellyfin, and a
64
+ [TMDB API Read Access Token](https://www.themoviedb.org/settings/api).
65
+ - Radarr's and Sonarr's root folders already pointing at the disks and
66
+ category folders Migratarr will use.
67
+ - To move files, by default, permission to run `docker exec` in the Radarr and
68
+ Sonarr containers: before and after every move Migratarr checks the files
69
+ where Radarr and Sonarr see them. Non-Docker installs can check on the host
70
+ instead; see [Arr file checks](https://github.com/jwilcox99/Migratarr/blob/main/docs/runtime-configuration.md#arr-file-checks).
71
+ - For moves on a NAS: SSH access to the NAS with a key used only by Migratarr,
72
+ and Python 3 on the NAS.
73
+
74
+ ## Install
75
+
76
+ ```sh
77
+ pip install migratarr
78
+ ```
79
+
80
+ Install it into a virtual environment, or with `pipx install migratarr`, if
81
+ your system Python doesn't allow `pip install`. Check it worked with
82
+ `migratarr --version`.
83
+
84
+ ## Try it first
85
+
86
+ ```sh
87
+ migratarr demo
88
+ ```
89
+
90
+ Plans a made-up library with the real planning pipeline and opens the web UI
91
+ read-only at `http://localhost:8767`, so you can see what a plan looks like
92
+ before connecting anything. It needs no Radarr, Sonarr, Jellyfin or TMDB,
93
+ uses no network, and never reads or writes your own settings. Everything
94
+ goes in a new temporary folder (`--dir` to choose one; delete it when done).
95
+
96
+ ## First run
97
+
98
+ Run Migratarr as a user that can read and write your media folders, then:
99
+
100
+ ```sh
101
+ migratarr ui
102
+ ```
103
+
104
+ It prints the address, `http://localhost:8765`. The UI listens on this machine
105
+ only (127.0.0.1). If Migratarr runs on a server, open an SSH tunnel from your
106
+ own computer and browse to the same address:
107
+
108
+ ```sh
109
+ ssh -L 8765:localhost:8765 media-host.example
110
+ ```
111
+
112
+ With no settings yet, every page leads to the setup wizard:
113
+
114
+ 1. **Connect your services:** Radarr, Sonarr, Jellyfin and TMDB. Detect reads
115
+ Radarr's and Sonarr's keys from their own config; or paste a key.
116
+ 2. **Where your disks are:** on a NAS over SSH, or on this machine's own
117
+ disks (experimental). Also the data folder.
118
+ 3. **Disks and categories:** your disks, the folder for each category, and
119
+ which disks hold each category.
120
+ 4. **Streaming services:** your TMDB region and the services you pay for.
121
+ 5. **Review and save:** nothing is written until you save.
122
+
123
+ After saving, the wizard runs the health checks. Fix anything that failed in
124
+ **Settings & health**, then make your first plan. [SETUP.md](https://github.com/jwilcox99/Migratarr/blob/main/SETUP.md) walks
125
+ through each step.
126
+
127
+ ## Where moves run
128
+
129
+ | | How it works | Status |
130
+ | --- | --- | --- |
131
+ | **NAS over SSH** | Migratarr runs on a machine that mounts the NAS disks and sends each move to the NAS over SSH, so files are copied on the NAS rather than over the network | Used on a real library |
132
+ | **This machine's own disks** | Moves run directly on disks attached to the machine running Migratarr | **Experimental**: not yet run end to end against a real Radarr and Sonarr |
133
+
134
+ Both use the same plan, approval and safety checks.
135
+
136
+ ## Using it
137
+
138
+ The web UI covers the whole cycle:
139
+
140
+ 1. **Plan:** "Plan a new run". Planning is read-only: it scores your library,
141
+ proposes moves and freezes the result as a run. A large library can take a
142
+ while.
143
+ 2. **Review and approve:** pick moves (or "Review all"), check sizes, free
144
+ space afterwards and folder permissions, then approve them.
145
+ 3. **Run:** "Run N approved moves", check the order, then "Start moving".
146
+ Each move is checked again just before it runs. You can stop after the
147
+ current move.
148
+
149
+ Jobs keep running if you close the browser or restart the UI.
150
+ `migratarr ui --read-only` shows everything with every action switched off.
151
+
152
+ ## Safety model
153
+
154
+ - **Plan, review, approve, run.** Planning never touches media files. Only an
155
+ approved move can run, and you start it.
156
+ - **No plan while a health check fails.** `migratarr plan` and the UI refuse
157
+ to plan until every check passes (warnings are fine).
158
+ - **Plans are frozen.** Each run is a read-only, checksummed snapshot of the
159
+ plan and the code that made it.
160
+ - **Approvals are tied to the exact plan.** If the plan changes after you
161
+ approve, the move refuses to run.
162
+ - **Every move is checked again first:** the plan and approval, what Radarr or
163
+ Sonarr say about that item right now, and a SHA-256 hash of every file.
164
+ - **Moves don't overwrite.** A move on one disk is a rename that never
165
+ replaces an existing folder. A move between disks copies to a staging
166
+ folder, verifies, publishes, updates Radarr or Sonarr, and deletes the
167
+ source only after checking the copy.
168
+ - **Everything is journaled.** Each move writes a journal before and after
169
+ every change. A move that fails part way is never retried automatically:
170
+ you check it and record what you found with `migratarr reconcile`.
171
+ - **Settings changes are careful.** Saving makes a backup, and is refused
172
+ while a job or move is running.
173
+
174
+ There is no undo. Start with your smallest, least important titles.
175
+
176
+ ## Commands
177
+
178
+ | Command | What it does |
179
+ | --- | --- |
180
+ | `migratarr demo [--dir DIR] [--port N] [--no-ui]` | Try it on a made-up library: plans offline, UI read-only |
181
+ | `migratarr ui [--port N] [--read-only]` | The web UI: setup, settings, plan, approve, run |
182
+ | `migratarr plan [--check]` | Make a new plan; nothing moves. `--check` runs the checks only |
183
+ | `migratarr status [--run RUN \| --execution ID] [--json]` | Runs, moves and their journals (read-only) |
184
+ | `migratarr approve ...` | Approve moves from the terminal: `--list`, `--approve ID`, `--approve-batch --media TV --transfer CROSS_DISK_TRANSFER [--limit N] [--yes]`, `--revoke ID`, `--status` |
185
+ | `migratarr doctor [--offline] [--json] [--migrate]` | Check settings, services, disks and the NAS; shows the data folder |
186
+ | `migratarr reconcile ID --outcome ... --note ...` | Record that a move flagged for checking was checked by hand |
187
+
188
+ `migratarr <command> --help` lists each command's options. Moves are started
189
+ from the web UI.
190
+
191
+ ## Where settings and data live
192
+
193
+ Everything goes in one **data folder**: `$MIGRATARR_HOME` if set, otherwise
194
+ `~/.local/share/migratarr`. (Running from a git clone, the clone itself.)
195
+ `migratarr doctor` prints which folder is in use. It holds `config/` (the
196
+ three settings files and their backups), runs, approvals and move journals.
197
+
198
+ Pasted API keys are kept apart, in `~/.config/migratarr/secrets/`, readable by
199
+ your user only; see [SECURITY.md](https://github.com/jwilcox99/Migratarr/blob/main/SECURITY.md).
200
+
201
+ ## Limitations
202
+
203
+ - Linux only.
204
+ - Moves on this machine's own disks are experimental.
205
+ - One machine runs Migratarr, and it must see the disks. With a NAS, that's
206
+ one NAS reached over SSH.
207
+ - Radarr and Sonarr must see the media under the same folder layout: one root,
208
+ then a category folder, then the title.
209
+ - Radarr or Sonarr on a different machine, with no view of their media from
210
+ the machine running Migratarr, isn't supported.
211
+ - Moves run from the web UI; there's no command that runs them.
212
+ - Streaming groups are written for the US; elsewhere, add your region's
213
+ services ([Provider families](https://github.com/jwilcox99/Migratarr/blob/main/docs/planner-settings.md#provider-families)).
214
+ - 0.x: settings files and commands may still change between minor versions,
215
+ always with a migration or a note in the [changelog](https://github.com/jwilcox99/Migratarr/blob/main/CHANGELOG.md).
216
+
217
+ ## Documentation
218
+
219
+ - [SETUP.md](https://github.com/jwilcox99/Migratarr/blob/main/SETUP.md): the setup wizard step by step, and editing settings by hand
220
+ - [Settings](https://github.com/jwilcox99/Migratarr/blob/main/docs/settings.md): the settings files, version 2 and the health checks
221
+ - [Runtime configuration](https://github.com/jwilcox99/Migratarr/blob/main/docs/runtime-configuration.md): `runtime.json` reference
222
+ - [Storage targets](https://github.com/jwilcox99/Migratarr/blob/main/docs/storage-targets.md): disks, categories and placement
223
+ - [Planner settings](https://github.com/jwilcox99/Migratarr/blob/main/docs/planner-settings.md): streaming, override tags and scoring
224
+ - [Media layout](https://github.com/jwilcox99/Migratarr/blob/main/docs/media-layout.md): where Migratarr expects each title to be
225
+ - [UI actions](https://github.com/jwilcox99/Migratarr/blob/main/docs/ui-actions.md): what each button does and checks
226
+ - [Changelog](https://github.com/jwilcox99/Migratarr/blob/main/CHANGELOG.md)
227
+
228
+ ## Contributing
229
+
230
+ See [CONTRIBUTING.md](https://github.com/jwilcox99/Migratarr/blob/main/CONTRIBUTING.md).
231
+
232
+ ## Security
233
+
234
+ See [SECURITY.md](https://github.com/jwilcox99/Migratarr/blob/main/SECURITY.md). Report vulnerabilities privately through
235
+ GitHub, not in a public issue.
236
+
237
+ ## License
238
+
239
+ [MIT](https://github.com/jwilcox99/Migratarr/blob/main/LICENSE).
@@ -0,0 +1 @@
1
+ """Migratarr package: the shared execution engine lives in migratarr.engine."""