-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathplugin.json
More file actions
328 lines (328 loc) · 18.2 KB
/
Copy pathplugin.json
File metadata and controls
328 lines (328 loc) · 18.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
{
"name": "VOD to Media Library",
"version": "1.18.0",
"description": "VOD → media library bridge. Generates .strm + NFO files from Dispatcharr's VOD catalogue, with optional cron-driven auto-rescan that picks up newly-added episodes.",
"author": "R3XCHRIS",
"license": "MIT",
"min_dispatcharr_version": "v0.24.0",
"repo_url": "https://github.com/R3XCHRIS/VOD2MLIB",
"help_url": "https://github.com/R3XCHRIS/VOD2MLIB#readme",
"discord_thread": "https://discord.com/channels/1340492560220684331/1503076618078261374",
"fields": [
{
"id": "_about",
"label": "About",
"type": "info",
"description": "Workflow:\n 1. Configure paths below.\n 2. Actions → Scan → see catalogue totals.\n 3. Actions → Generate Movies / Generate Series (start with Batch Size 10).\n 4. (Optional) Turn ON Refresh Existing Series, set cron, click Apply Schedule for nightly auto-rescan.\n\nDocs: https://github.com/R3XCHRIS/VOD2MLIB"
},
{
"id": "_section_paths",
"label": "[PATHS & HOSTS]",
"type": "info",
"description": "Where to write .strm files and how media servers reach Dispatcharr."
},
{
"id": "root_folder",
"label": "Root Folder for Movies",
"type": "string",
"default": "/VODS/Movies",
"help_text": "Path inside the Dispatcharr container where movie folders will be created. Map a host folder to /VODS in your container."
},
{
"id": "series_root_folder",
"label": "Root Folder for Series",
"type": "string",
"default": "/VODS/Series",
"help_text": "Path inside the Dispatcharr container where series folders will be created."
},
{
"id": "dispatcharr_url",
"label": "Dispatcharr URL (REQUIRED)",
"type": "string",
"default": "",
"placeholder": "http://192.168.1.10:9191",
"help_text": "Required. The externally-reachable URL of your Dispatcharr instance — this gets baked into every .strm file, so it must resolve from wherever your media server runs. localhost works ONLY if the media server is on the same host with shared network namespace; otherwise use a routable LAN IP/hostname. Don't forget to click Save."
},
{
"id": "_section_movies",
"label": "[MOVIES]",
"type": "info",
"description": "Settings for the Generate Movies action."
},
{
"id": "batch_size",
"label": "Batch Size (Movies)",
"type": "select",
"default": "250",
"options": [
{"value": "10", "label": "10 movies"},
{"value": "100", "label": "100 movies"},
{"value": "200", "label": "200 movies"},
{"value": "250", "label": "250 movies"},
{"value": "500", "label": "500 movies"},
{"value": "1000", "label": "1000 movies"},
{"value": "all", "label": "All movies"}
],
"help_text": "Number of movies to process in this run. Start small (10) to verify, then scale up."
},
{
"id": "generate_nfo",
"label": "Generate Movie NFO Files",
"type": "boolean",
"default": true,
"help_text": "Create .nfo metadata files alongside each movie .strm."
},
{
"id": "nfo_omit_title",
"label": "Omit <title> from NFO files",
"type": "boolean",
"default": false,
"help_text": "Leave the `<title>` element OUT of generated movie and tvshow NFO files. Jellyfin (and Emby) treat a `<title>` in the NFO as authoritative and will NOT override it from TMDB — so if your provider prefixes titles with tags like `4K-A+`, `EN-TOP` or `AMZ`, that junk becomes the displayed name. With this ON the plugin still writes the NFO (IDs, plot, genres, rating, poster) but omits the title, letting your media server take the clean title from TMDB via the `<tmdbid>` we already emit. OFF by default (unchanged behaviour). Note v1.18.0 also cleans provider junk out of the title, so try that first — this is the belt-and-braces option. Episode NFOs always keep their title (media servers match episodes by season/episode number)."
},
{
"id": "nest_movies_by_category",
"label": "Nest Movies by Category",
"type": "boolean",
"default": false,
"help_text": "Wrap each movie's folder inside a subfolder named by its M3U category. Useful when your provider organises movies by genre. Movies without a category go into a folder named 'Unassigned'. Same content with different categories (e.g. 4K vs HD) gets separate folders intentionally — turn ON Dedupe Movies Across Categories below to suppress this for genre-overlap cases."
},
{
"id": "dedupe_movies_across_categories",
"label": "Dedupe Movies Across Categories",
"type": "boolean",
"default": false,
"help_text": "When `Nest Movies by Category` is ON and a movie is tagged with multiple categories upstream (e.g. 'Action' AND 'Sci-Fi'), write the `.strm` under the first category only (alphabetical by category name) instead of duplicating across all of them. No effect when `Nest Movies by Category` is OFF — multi-category movies already resolve to the same folder in that case. Use this when you want one folder per movie regardless of provider tagging. ⚠ MIGRATION: changing this on an already-generated library does NOT remove the old duplicate folders — it just stops creating new ones. To clean up existing duplicates, run `[⚠ DANGER] Clean up Movies` once, then re-generate."
},
{
"id": "append_tmdb_id_to_folder",
"label": "Append TMDB ID to folder names",
"type": "boolean",
"default": false,
"help_text": "Append a TMDB id tag to every Movies and Series folder name when a TMDB ID is known — e.g. `Cool Hand Luke (1967) {tmdb-378}/`. Media servers honour this as a forced exact match, which is the safest defence against name collisions and bad metadata scrapes. Pick the convention your server expects with `TMDB Folder Tag Format` below. ⚠ MIGRATION: the plugin does NOT rename existing folders in place — turning this on (or off) for an already-generated library writes the new folder names ALONGSIDE the old ones, creating duplicates. To switch cleanly, run `[⚠ DANGER] Clean up Movies` / `Series` first, then re-generate; or accept the duplicates until the old folders age out."
},
{
"id": "tmdb_tag_format",
"label": "TMDB Folder Tag Format",
"type": "select",
"default": "plex",
"options": [
{"value": "plex", "label": "Plex / ChannelsDVR — {tmdb-123}"},
{"value": "jellyfin", "label": "Jellyfin / Emby — [tmdbid-123]"}
],
"help_text": "Which convention to use for the TMDB folder tag — media servers disagree, and each ignores the other's format. `Plex / ChannelsDVR` writes `Cool Hand Luke (1967) {tmdb-378}`; `Jellyfin / Emby` writes `Cool Hand Luke (1967) [tmdbid-378]`. Only has an effect when `Append TMDB ID to folder names` is ON. Defaults to Plex for backwards compatibility with libraries generated before v1.16.1 — if you use Jellyfin or Emby, switch this to `jellyfin` or the tag is silently ignored by your server. ⚠ MIGRATION: changing the format renames every folder, and the plugin does NOT rename in place — the new names are written ALONGSIDE the old ones. Run `[⚠ DANGER] Clean up Movies` / `Series` first, then re-generate."
},
{
"id": "omit_stream_id",
"label": "Don't pin .strm files to a specific provider stream",
"type": "boolean",
"default": false,
"help_text": "When ON, .strm URLs omit ?stream_id=, so Dispatcharr's VOD proxy resolves and fails over across every account carrying the title instead of being locked to the one relation this plugin happened to pick. Requires a patched Dispatcharr with VOD failover support (PR #1398). When OFF (default), the .strm is pinned to this plugin's selected relation, matching original behavior."
},
{
"id": "category_filter",
"label": "Category Filter (include only)",
"type": "string",
"default": "",
"help_text": "Only generate content whose M3U CATEGORY name STARTS WITH one of these comma-separated prefixes — e.g. `[EN],[FR]` or `EN`. Case-insensitive. Leave empty to generate all (active) content. Ideal for large multi-language catalogues where you only want one or two languages: it filters at the database-query level, so unwanted folders are never created (no generate-then-clean-up waste). Applies to BOTH Movies and Series. When a filter is set, content with no category — or a category that doesn't match — is skipped. ⚠ This matches the CATEGORY name, NOT the movie/series title — many providers put a language tag in the title (`|EN| The Matrix`) while the category is something else entirely (`FOR ADULTS`). Run `[LIBRARY] Catalogue snapshot` to print your real category names and see exactly which ones your filter matches."
},
{
"id": "category_exclude",
"label": "Category Exclude (block list)",
"type": "string",
"default": "",
"help_text": "Skip content whose M3U CATEGORY name starts with any of these comma-separated prefixes — e.g. `FOR ADULTS,XXX`. Case-insensitive. Applied AFTER the include filter, so you can use both together. This is usually what you want for 'everything EXCEPT adult content': leave `Category Filter` empty and put the unwanted categories here, rather than trying to list every category you do want. Content with no category is never excluded. Run `[LIBRARY] Catalogue snapshot` to see your exact category names. ⚠ Already-generated folders are not removed when you add an exclude — run `[⚠ DANGER] Clean up` once, then re-generate."
},
{
"id": "_section_series",
"label": "[SERIES]",
"type": "info",
"description": "Settings for the Generate Series action."
},
{
"id": "series_batch_size",
"label": "Batch Size (Series)",
"type": "select",
"default": "10",
"options": [
{"value": "1", "label": "1 series (testing)"},
{"value": "5", "label": "5 series"},
{"value": "10", "label": "10 series"},
{"value": "25", "label": "25 series"},
{"value": "50", "label": "50 series"},
{"value": "100", "label": "100 series"},
{"value": "250", "label": "250 series"},
{"value": "all", "label": "All series (may time out — use the schedule)"}
],
"help_text": "Number of series to process per click (episodes are auto-fetched for each, so series are much slower than movies). ⚠ This button runs synchronously and your reverse proxy will usually cut it off after ~60s with a 504 — the run keeps going server-side, but you lose the result. For a big catalogue don't use 'All' here: set the cron to 'Full rescan' and click [SCHEDULE] Apply / Update. Scheduled runs execute on the Celery worker with no HTTP timeout."
},
{
"id": "generate_series_nfo",
"label": "Generate Series NFO Files",
"type": "boolean",
"default": true,
"help_text": "Create tvshow.nfo and per-episode .nfo metadata files."
},
{
"id": "refresh_existing",
"label": "Refresh Existing Series (rescan-friendly)",
"type": "boolean",
"default": false,
"help_text": "Re-evaluate series that already have folders, picking up new episodes added upstream AND rewriting existing episode .strm files so they pick up the current Dispatcharr URL. .nfo files (including tvshow.nfo) are only written when missing, so your edits are preserved. Off = fast manual iteration (skip done series); On = scan everything for new content and refresh existing URLs. Turn ON before clicking Apply Schedule for cron rescans of target 'generate_series'. Note: 'rescan_all' forces this ON regardless."
},
{
"id": "nest_series_by_category",
"label": "Nest Series by Category",
"type": "boolean",
"default": false,
"help_text": "Wrap each series' folder inside a subfolder named by its M3U category. Useful when your provider organises series by genre. Series without a category go into a folder named 'Unassigned'. Same content with different categories gets separate folders intentionally — turn ON Dedupe Series Across Categories below to suppress this for genre-overlap cases."
},
{
"id": "dedupe_series_across_categories",
"label": "Dedupe Series Across Categories",
"type": "boolean",
"default": false,
"help_text": "When `Nest Series by Category` is ON and a series is tagged with multiple categories upstream, write the series folder + episodes under the first category only (alphabetical by category name) instead of duplicating across all of them. No effect when `Nest Series by Category` is OFF. ⚠ MIGRATION: changing this on an already-generated library does NOT remove the old duplicate folders — run `[⚠ DANGER] Clean up Series` once, then re-generate, to clean them up."
},
{
"id": "_section_schedule",
"label": "[AUTO-RESCAN SCHEDULE]",
"type": "info",
"description": "Configure the cron job. Click Apply in the Actions tab to register or update."
},
{
"id": "schedule_cron",
"label": "Auto-Rescan Schedule (cron)",
"type": "string",
"default": "0 3 * * *",
"help_text": "Standard 5-field cron: 'minute hour day-of-month month day-of-week'. Default '0 3 * * *' = every day at 03:00. Used by Apply Schedule."
},
{
"id": "schedule_timezone",
"label": "Schedule Timezone",
"type": "string",
"default": "",
"placeholder": "Europe/London",
"help_text": "IANA timezone name the cron expression is interpreted in (e.g. 'Europe/London', 'America/New_York', 'Australia/Sydney'). Leave empty to use UTC. Affects when the cron fires — '0 3 * * *' in 'Europe/London' means 03:00 London time year-round (handling BST automatically), not 03:00 UTC."
},
{
"id": "schedule_target",
"label": "Scheduled Action",
"type": "select",
"default": "rescan_all",
"options": [
{"value": "scan_all_vods", "label": "Scan only (totals)"},
{"value": "generate_movies", "label": "Movies only"},
{"value": "generate_series", "label": "Series only"},
{"value": "rescan_all", "label": "Full rescan (movies + series)"}
],
"help_text": "Which action the scheduler should run on each tick. 'Full rescan' is recommended."
}
],
"actions": [
{
"id": "scan_all_vods",
"label": "[LIBRARY] Catalogue snapshot",
"description": "Count unique Movies and Series in the Dispatcharr database. Read-only.",
"button_label": "Scan",
"button_variant": "outline",
"button_color": "blue"
},
{
"id": "generate_movies",
"label": "[GENERATE] Movies",
"description": "Process movies per Batch Size. Existing .strm files are skipped.",
"button_label": "Generate",
"button_variant": "filled",
"button_color": "green"
},
{
"id": "generate_series",
"label": "[GENERATE] Series",
"description": "Create episode .strm files. See 'Refresh Existing Series' setting.",
"button_label": "Generate",
"button_variant": "filled",
"button_color": "green"
},
{
"id": "rescan_all",
"label": "[GENERATE] Full rescan",
"description": "Rescan then force regenerate Movies + Series.",
"button_label": "Rescan all",
"button_variant": "filled",
"button_color": "teal",
"confirm": {
"required": true,
"title": "Run full rescan now?",
"message": "Full rescan walks every Movie and every Series, re-fetching episode lists from the M3U source and writing any missing files. On large catalogues this can take many minutes. The cron schedule already runs this action nightly — only click here for an immediate refresh."
}
},
{
"id": "schedule_status",
"label": "[SCHEDULE] Show status",
"description": "Show registered cron, last run, and total runs.",
"button_label": "Status",
"button_variant": "outline",
"button_color": "blue"
},
{
"id": "schedule_test_fire",
"label": "[SCHEDULE] Test fire now",
"description": "Fire the scheduled task immediately. Verifies the cron pipeline.",
"button_label": "Test fire",
"button_variant": "outline",
"button_color": "blue",
"confirm": {
"required": true,
"title": "Fire scheduled task now?",
"message": "Runs the same action the cron will fire (with the snapshotted settings) right now. Useful to verify the pipeline works. May take many minutes depending on the action."
}
},
{
"id": "apply_schedule",
"label": "[SCHEDULE] Apply / Update",
"description": "Register or update the cron task. Re-click after changing any setting.",
"button_label": "Apply",
"button_variant": "outline",
"button_color": "blue"
},
{
"id": "remove_schedule",
"label": "[SCHEDULE] Unschedule",
"description": "Remove the periodic auto-rescan task.",
"button_label": "Remove",
"button_variant": "outline",
"button_color": "orange",
"confirm": {
"required": true,
"title": "Remove auto-rescan schedule?",
"message": "This unregisters the periodic task. You can re-create it any time with Apply."
}
},
{
"id": "cleanup_movies",
"label": "[⚠ DANGER] Clean up Movies",
"description": "Delete plugin .strm/.nfo from Movies root. User files preserved.",
"button_label": "Clean up",
"button_variant": "filled",
"button_color": "red",
"confirm": {
"required": true,
"title": "Delete generated movie files?",
"message": "This deletes every .strm and .nfo file this plugin created under your Movies root. User-added files (subtitles, posters, custom .nfo) in those folders are preserved. Continue?"
}
},
{
"id": "cleanup_series",
"label": "[⚠ DANGER] Clean up Series",
"description": "Delete plugin .strm/.nfo from Series root. User files preserved.",
"button_label": "Clean up",
"button_variant": "filled",
"button_color": "red",
"confirm": {
"required": true,
"title": "Delete generated series files?",
"message": "This deletes every .strm and .nfo file this plugin created under your Series root. User-added files in those folders are preserved. Continue?"
}
}
]
}