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.
- migratarr-0.1.0rc1/LICENSE +21 -0
- migratarr-0.1.0rc1/PKG-INFO +278 -0
- migratarr-0.1.0rc1/README.md +239 -0
- migratarr-0.1.0rc1/migratarr/__init__.py +1 -0
- migratarr-0.1.0rc1/migratarr/approval_store.py +165 -0
- migratarr-0.1.0rc1/migratarr/approve_execution.py +385 -0
- migratarr-0.1.0rc1/migratarr/arr_files.py +95 -0
- migratarr-0.1.0rc1/migratarr/audit_overrides.py +141 -0
- migratarr-0.1.0rc1/migratarr/batch_cross_movies.py +140 -0
- migratarr-0.1.0rc1/migratarr/batch_cross_tv.py +146 -0
- migratarr-0.1.0rc1/migratarr/build_execution_manifest.py +306 -0
- migratarr-0.1.0rc1/migratarr/build_move_plan.py +776 -0
- migratarr-0.1.0rc1/migratarr/cli.py +80 -0
- migratarr-0.1.0rc1/migratarr/demo.py +196 -0
- migratarr-0.1.0rc1/migratarr/demo_library.py +163 -0
- migratarr-0.1.0rc1/migratarr/doctor.py +82 -0
- migratarr-0.1.0rc1/migratarr/dry_run_movies.py +747 -0
- migratarr-0.1.0rc1/migratarr/dry_run_tv.py +939 -0
- migratarr-0.1.0rc1/migratarr/engine/__init__.py +1 -0
- migratarr-0.1.0rc1/migratarr/engine/nas_side.py +178 -0
- migratarr-0.1.0rc1/migratarr/engine/primitives.py +78 -0
- migratarr-0.1.0rc1/migratarr/engine/transport.py +77 -0
- migratarr-0.1.0rc1/migratarr/execute_cross_movie.py +365 -0
- migratarr-0.1.0rc1/migratarr/execute_cross_tv.py +404 -0
- migratarr-0.1.0rc1/migratarr/execute_movie.py +288 -0
- migratarr-0.1.0rc1/migratarr/execute_movie_nas.py +381 -0
- migratarr-0.1.0rc1/migratarr/execute_tv_nas.py +398 -0
- migratarr-0.1.0rc1/migratarr/executor_command.py +133 -0
- migratarr-0.1.0rc1/migratarr/executor_inventory.py +25 -0
- migratarr-0.1.0rc1/migratarr/executor_manifest.py +98 -0
- migratarr-0.1.0rc1/migratarr/executor_nfs.py +39 -0
- migratarr-0.1.0rc1/migratarr/health.py +372 -0
- migratarr-0.1.0rc1/migratarr/jobs.py +448 -0
- migratarr-0.1.0rc1/migratarr/media_layout.py +86 -0
- migratarr-0.1.0rc1/migratarr/movie_placement_v1.py +853 -0
- migratarr-0.1.0rc1/migratarr/paths.py +77 -0
- migratarr-0.1.0rc1/migratarr/pipeline_inputs.py +65 -0
- migratarr-0.1.0rc1/migratarr/plan.py +173 -0
- migratarr-0.1.0rc1/migratarr/planner_settings.py +366 -0
- migratarr-0.1.0rc1/migratarr/read_api.py +280 -0
- migratarr-0.1.0rc1/migratarr/reconcile.py +55 -0
- migratarr-0.1.0rc1/migratarr/reconcile_store.py +124 -0
- migratarr-0.1.0rc1/migratarr/recover_cross_0102.py +233 -0
- migratarr-0.1.0rc1/migratarr/recover_cross_0116.py +157 -0
- migratarr-0.1.0rc1/migratarr/recover_cross_published.py +290 -0
- migratarr-0.1.0rc1/migratarr/runtime_config.py +364 -0
- migratarr-0.1.0rc1/migratarr/service_keys.py +195 -0
- migratarr-0.1.0rc1/migratarr/services.py +105 -0
- migratarr-0.1.0rc1/migratarr/settings/__init__.py +20 -0
- migratarr-0.1.0rc1/migratarr/settings/keys.py +87 -0
- migratarr-0.1.0rc1/migratarr/settings/store.py +508 -0
- migratarr-0.1.0rc1/migratarr/settings/ui_backend.py +879 -0
- migratarr-0.1.0rc1/migratarr/settings_contract.py +138 -0
- migratarr-0.1.0rc1/migratarr/settings_ui.py +341 -0
- migratarr-0.1.0rc1/migratarr/setup_wizard.py +239 -0
- migratarr-0.1.0rc1/migratarr/snapshot_run.py +254 -0
- migratarr-0.1.0rc1/migratarr/status.py +94 -0
- migratarr-0.1.0rc1/migratarr/storage_targets.py +278 -0
- migratarr-0.1.0rc1/migratarr/tv_placement_v1.py +1017 -0
- migratarr-0.1.0rc1/migratarr/ui.py +1483 -0
- migratarr-0.1.0rc1/migratarr.egg-info/PKG-INFO +278 -0
- migratarr-0.1.0rc1/migratarr.egg-info/SOURCES.txt +114 -0
- migratarr-0.1.0rc1/migratarr.egg-info/dependency_links.txt +1 -0
- migratarr-0.1.0rc1/migratarr.egg-info/entry_points.txt +2 -0
- migratarr-0.1.0rc1/migratarr.egg-info/top_level.txt +1 -0
- migratarr-0.1.0rc1/pyproject.toml +40 -0
- migratarr-0.1.0rc1/setup.cfg +4 -0
- migratarr-0.1.0rc1/tests/test_approval_store.py +92 -0
- migratarr-0.1.0rc1/tests/test_arr_file_checks.py +211 -0
- migratarr-0.1.0rc1/tests/test_audit.py +35 -0
- migratarr-0.1.0rc1/tests/test_audit_overrides.py +97 -0
- migratarr-0.1.0rc1/tests/test_batch_approval.py +238 -0
- migratarr-0.1.0rc1/tests/test_capture.py +54 -0
- migratarr-0.1.0rc1/tests/test_cli.py +124 -0
- migratarr-0.1.0rc1/tests/test_config.py +103 -0
- migratarr-0.1.0rc1/tests/test_copy_tree_permissions.py +98 -0
- migratarr-0.1.0rc1/tests/test_demo.py +51 -0
- migratarr-0.1.0rc1/tests/test_dry_run_parity.py +106 -0
- migratarr-0.1.0rc1/tests/test_engine_layout.py +100 -0
- migratarr-0.1.0rc1/tests/test_executor_command.py +102 -0
- migratarr-0.1.0rc1/tests/test_executor_golden.py +370 -0
- migratarr-0.1.0rc1/tests/test_executor_idle_timeout.py +114 -0
- migratarr-0.1.0rc1/tests/test_executor_safety.py +701 -0
- migratarr-0.1.0rc1/tests/test_executor_safety_phase2.py +395 -0
- migratarr-0.1.0rc1/tests/test_health.py +326 -0
- migratarr-0.1.0rc1/tests/test_impact.py +139 -0
- migratarr-0.1.0rc1/tests/test_inventory_metadata.py +170 -0
- migratarr-0.1.0rc1/tests/test_local_transport.py +185 -0
- migratarr-0.1.0rc1/tests/test_manifest_parity.py +73 -0
- migratarr-0.1.0rc1/tests/test_media_layout.py +371 -0
- migratarr-0.1.0rc1/tests/test_nas_program_parity.py +78 -0
- migratarr-0.1.0rc1/tests/test_nfs_verifier.py +90 -0
- migratarr-0.1.0rc1/tests/test_override_tags.py +124 -0
- migratarr-0.1.0rc1/tests/test_paths.py +105 -0
- migratarr-0.1.0rc1/tests/test_pipeline_inputs.py +127 -0
- migratarr-0.1.0rc1/tests/test_plan_command.py +196 -0
- migratarr-0.1.0rc1/tests/test_planner_streaming.py +171 -0
- migratarr-0.1.0rc1/tests/test_planner_targets.py +132 -0
- migratarr-0.1.0rc1/tests/test_planner_unknown_category.py +270 -0
- migratarr-0.1.0rc1/tests/test_provider_families.py +124 -0
- migratarr-0.1.0rc1/tests/test_read_api.py +292 -0
- migratarr-0.1.0rc1/tests/test_reconcile.py +144 -0
- migratarr-0.1.0rc1/tests/test_recover_cross_published.py +280 -0
- migratarr-0.1.0rc1/tests/test_rules.py +150 -0
- migratarr-0.1.0rc1/tests/test_runtime_config.py +289 -0
- migratarr-0.1.0rc1/tests/test_scoring_settings.py +125 -0
- migratarr-0.1.0rc1/tests/test_service_keys.py +225 -0
- migratarr-0.1.0rc1/tests/test_service_urls.py +151 -0
- migratarr-0.1.0rc1/tests/test_settings.py +447 -0
- migratarr-0.1.0rc1/tests/test_settings_ui.py +312 -0
- migratarr-0.1.0rc1/tests/test_storage_targets.py +198 -0
- migratarr-0.1.0rc1/tests/test_ui.py +208 -0
- migratarr-0.1.0rc1/tests/test_ui_actions.py +253 -0
- migratarr-0.1.0rc1/tests/test_ui_backend.py +454 -0
- migratarr-0.1.0rc1/tests/test_ui_jobs.py +237 -0
- 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."""
|