Skip to content

Add Webhook notifications and option to prune orphan strm files. - #7

Open
mcortt wants to merge 8 commits into
R3XCHRIS:mainfrom
mcortt:main
Open

Add Webhook notifications and option to prune orphan strm files.#7
mcortt wants to merge 8 commits into
R3XCHRIS:mainfrom
mcortt:main

Conversation

@mcortt

@mcortt mcortt commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@mcortt

mcortt commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Also added an option to prune orphan strm files

@mcortt mcortt changed the title Add Webhook notifications for Slack, Discord, and other generic JSON forms. Add Webhook notifications and option to prune orphan strm files. Jul 5, 2026
@R3XCHRIS

Copy link
Copy Markdown
Owner

Sorry for the long silence on this @mcortt — I was away and this deserved a proper read rather than a quick skim. I've now gone through it carefully.

The quality here is genuinely high. Some specific things I want to call out, because they're the things people usually get wrong:

  • _collect_expected_movie_files deliberately ignoring batch_size — with the reasoning in the docstring. That's exactly right, and getting it wrong would have deleted most of a library on anyone running the default batch of 250.
  • The (keep, ok, count) return with ok=False meaning "MUST NOT prune" — failing closed on a DB/import error is the correct instinct.
  • The "0 active but files on disk → refuse" guardrail. A provider outage wiping the library is the obvious catastrophic scenario and you closed it.
  • Keeping the .nfo in the keep set regardless of the current NFO toggle, so toggling NFO off doesn't orphan good files.
  • realpath for keep-set identity, protected subtrees, and startswith(pref + os.sep) — you even anticipated the /Movies vs /Movies2 prefix bug, which has a test.
  • ~40 tests including test_user_files_preserved, test_protected_subtree_untouched, test_root_never_removed_even_when_emptied.

The webhook half I have no concerns about: opt-in, 10s timeout, failures logged not raised, and — importantly — no URLs or credentials in the payloads, only counts.


One blocker, and it's not your fault

This PR is from 2 July; main has since had v1.16.1 and v1.17.0, and one of those changes breaks a core assumption here.

v1.16.1 added a tmdb_tag_format setting (issue #9 — Jellyfin/Emby want [tmdbid-123], Plex wants {tmdb-123}). _movie_target_paths / _series_target_folder now take a tmdb_tag_format argument that defaults to "plex".

Your collectors call them without it:

movie_folder, strm_filename, _name, _year = self._movie_target_paths(
    movie, root_folder, cat_name, nest_by_cat, append_tmdb_id,
)   # <-- tmdb_tag_format defaults to "plex"

So for a user with Append TMDB ID ON and format jellyfin:

  • Generate writes Cool Hand Luke (1967) [tmdbid-378]/…
  • The keep set computes Cool Hand Luke (1967) {tmdb-378}/…
  • Nothing on disk matches the keep set → every file is an "orphan" → the whole library is deleted.

The 0-active guardrail doesn't catch it, because count is non-zero — the catalogue resolves fine, it's the paths that are wrong.

That's not a corner case: most users of this plugin are on Jellyfin/Emby (Plex can't play .strm at all), and v1.16.1's release notes actively tell them to switch to the jellyfin format.

Fix is one argument in each collector — pass tmdb_tag_format through, read the same way _generate_movies does:

tmdb_tag_format = (settings.get("tmdb_tag_format") or "plex").strip().lower()

Two smaller items

  1. category_exclude (new in v1.17.0) isn't applied in the collectors. This one fails safe — the keep set becomes a superset, so prune under-deletes rather than over-deletes — but it should be applied for correctness, right after _apply_category_filter.
  2. Worth a rebase regardless — 4 commits have touched plugin.py since your base, so this will need conflict resolution anyway. (Also: plugin.py is CRLF — worth checking your editor preserves that, or the diff balloons to the whole file.)

How do you want to play it?

Happy either way:

One last thought, no strong feelings: webhooks and prune are two unrelated features in one PR. If you'd rather land them separately I'd take the webhook half immediately — it has no blockers at all. But I'm equally happy to take both together once the tag-format bug is closed.

Really nice work — the guardrails in the prune path are better than most of what I'd have written first time.

@mcortt

mcortt commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

You are absolutely right. It should've been two separate PRs. My bad. I am fine with whatever you want to do. If you want to rebase/fix and push it go for it. That way you can go ahead and implement the webhook portion, and then once the follow-up commit is processed the prune can be added at your convenience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants