Skip to content

New Features and Code Optimizations#32

Open
ttlequals0 wants to merge 23 commits intonullable-eth:mainfrom
ttlequals0:main
Open

New Features and Code Optimizations#32
ttlequals0 wants to merge 23 commits intonullable-eth:mainfrom
ttlequals0:main

Conversation

@ttlequals0
Copy link
Copy Markdown

[1.3.0] - 2026-04-12

Added

  • POST /scan endpoint on the webhook server for manual scan triggers.
    • POST /scan runs a full scan across all non-excluded libraries.
    • POST /scan?library=<id|name> scans a single library; library
      accepts the numeric Plex section ID or a case-insensitive library
      title.
    • Returns 202 Accepted immediately; the scan runs in the
      background. Returns 409 Conflict if a scan is already in
      progress, 404 Not Found if the library param does not match, and
      405 Method Not Allowed for non-POST requests.
    • Works in WEBHOOK_ONLY=true mode — enables ad-hoc catchup scans
      without toggling environment variables.
  • MOVIE_LIBRARY_EXCLUDE / TV_LIBRARY_EXCLUDE: comma-separated library
    IDs to skip when *_PROCESS_ALL=true. Excluded libraries are filtered
    from both timer-driven processing and webhook routing.
  • WEBHOOK_ONLY=true: skips the startup full scan and the periodic timer
    entirely, leaving the webhook server as the only trigger. Requires
    WEBHOOK_ENABLED=true.

Plex Webhook Support #22

  • Webhook listener for real-time processing (WEBHOOK_ENABLED, WEBHOOK_PORT)
  • Handles library.new and library.on.deck events
  • Configurable debounce window (WEBHOOK_DEBOUNCE, default 30s)
  • Prevents concurrent processing of the same library
  • Health check endpoint at /health
  • Runs alongside the existing timer

Keyword Prefix #24

  • KEYWORD_PREFIX env var to prepend text to keywords (e.g. "- ")
  • Useful when UPDATE_FIELD=genre to separate TMDb keywords from real genres

Batch Processing #26

  • BATCH_SIZE (default 100) and BATCH_DELAY (default 10s) env vars
  • Prevents API flooding on large libraries (4000+ items)
  • ITEM_DELAY (default 500ms) controls per-item pacing

Version Tracking

  • Version constant in internal/version/version.go
  • Logs version on startup

Changed

  • Removed all emoji from log output; replaced with bracketed tags
  • Extracted Clients struct for processor initialization
  • Added keyword cache by TMDb ID to avoid redundant API calls
  • Eliminated redundant Plex API call after keyword sync for export*

ttlequals0 and others added 19 commits April 10, 2026 09:37
- Batch processing (BATCH_SIZE, BATCH_DELAY, ITEM_DELAY) to prevent
  API flooding on large libraries
- Keyword prefix (KEYWORD_PREFIX) to separate TMDb keywords from real
  genres in Plex dropdown
- Plex webhook server (WEBHOOK_ENABLED, WEBHOOK_PORT, WEBHOOK_DEBOUNCE)
  for real-time processing on media add events
- Remove all emoji from Go source, replace with bracketed tags
- Rewrite README with table of contents and accurate feature docs
- Clean up CHANGELOG to remove AI writing patterns
- Refactor: Clients struct, keyword cache, batch helpers,
  forEachLibrary, graceful shutdown, concurrency safety
Keep feature branch versions for all three conflicted files
(CHANGELOG.md, README.md, processor.go). The origin/main content
was the old pre-cleanup version that our branch replaces.
- Remove remaining emoji and unicode arrows from processor.go and
  tmdb/client.go
- Expand webhook payload struct to match Plex spec
- Use LibrarySectionType for correct media type resolution
- Note Plex Pass requirement for webhooks in README
- Cache GetAllMovies/GetAllSeries results per client instance to
  eliminate thousands of redundant API calls per processing cycle
- Add bidirectional title matching (either string contains the other)
- Add CleanTitle matching (strips all punctuation for fuzzy matching)
  Fixes movies like "(500) Days of Summer" where Plex strips parens
- Clear Radarr/Sonarr caches alongside keyword cache each cycle
- Apply same improvements to both Radarr and Sonarr clients
Replace globe and timer emojis in verbose Plex API logging with
bracketed tags [API] and [TIMING].
- Replace [ERROR] with [SKIP] for expected lookup misses (not found
  in Radarr/Sonarr, no TMDb ID in path). Keep [ERROR] only for real
  API/fetch failures.
- Collapse duplicate file path iteration: check both API path match
  and TMDb ID regex in a single pass instead of listing paths twice.
- Cap file path logging at 3 paths with "and N more" summary.
- Consolidate episode fetching in TV show extraction to a single call
  instead of fetching twice (once for Sonarr, again for regex).
- Shorter, more scannable log format for lookup results.
…ions

Add build/test/deploy commands (Docker + Portainer webhook), architecture
overview, coding conventions, key patterns, and gotchas.
- Create internal/version/version.go as single source of truth
- Log version at startup before config loading
- Tag Docker images with version (1.2.0 + latest)
- Update CHANGELOG with 1.2.0 release date
feat: batch processing, keyword prefix, Plex webhooks
- Add ProcessSingleItem method that tags only the newly added item
- Webhook accumulates rating keys during debounce window instead of
  keeping only the last one (fixes dropped items on rapid events)
- ProcessSingleItem acquires the per-library mutex to prevent races
  with timer-triggered ProcessAllItems
- ProcessSingleItem includes export logic for consistency
- Remove library.on.deck event handling (fires on playback, not new
  media -- was triggering unnecessary reprocessing)
- Falls back to full library scan when no rating key is in the payload
…ebhook-only mode

ProcessSingleItem previously returned nil when the per-library mutex was
held by a full scan, logging "queuing for next cycle" without any queue.
Items were silently dropped. Replace the check-and-bail with a poll loop
(5s interval, 2h deadline). ProcessAllItems keeps its skip-on-busy
behavior so timer-driven scans do not stack; the asymmetry is documented
inline.

Add MOVIE_LIBRARY_EXCLUDE and TV_LIBRARY_EXCLUDE (comma-separated IDs) to
skip specific libraries under *_PROCESS_ALL=true. Filter runs once at
startup so both timer and webhook routing see the same set.

Add WEBHOOK_ONLY=true to skip the startup full scan and periodic timer,
leaving the webhook server as the sole trigger. Validated in config
(requires WEBHOOK_ENABLED=true).

Bumps version to 1.2.1.
fix: webhook items wait for in-flight scan; add library exclude and webhook-only mode
Plex deliveries were being rejected with bare HTTP 400s and no log
output, making it impossible to tell which failure path fired
(multipart parse, missing payload field, or JSON unmarshal). Each 400
branch now logs the error plus diagnostics (Content-Type, form/file
part keys, payload snippet) so the root cause of real Plex failures
can be diagnosed from logs alone.
Plex sends Metadata.Guid as an array of objects for items with multiple
provider IDs (imdb, tmdb, tvdb). PlexWebhookPayload declared it as a
string, so json.Unmarshal failed on every such payload and the handler
returned 400, making labelarr ignore all real webhooks. The field was
never read anywhere in the codebase; removing it lets the JSON decoder
skip it regardless of shape.
fix(webhook): log reason for 400 responses
Adds a manual scan trigger so operators can force a catchup cycle
without toggling WEBHOOK_ONLY. POST /scan runs a full scan; POST
/scan?library=<id|name> targets a single library. Returns 202 on
accept, 409 on concurrent scan, 404 on unknown library. A Scanner
interface is introduced and implemented by a scanRunner in main;
the periodic timer now uses the same code path.
feat(webhook): add POST /scan endpoint for manual scan triggers
@dgomesbr
Copy link
Copy Markdown
Contributor

@nullable-eth is this still maintained?

ttlequals0 and others added 4 commits April 21, 2026 18:04
…kflow permissions)

- plex/client.go: gate InsecureSkipVerify on new PLEX_INSECURE_SKIP_VERIFY
  env var (default false). Startup logs a [WARN] when the opt-in is active.
  Resolves go/disabled-certificate-check.
- export/export.go: add safeJoin containment check and harden
  sanitizeFilename to reject '', '.', '..'. All filepath.Join calls onto
  the export root now verify the result stays inside EXPORT_LOCATION.
  Resolves go/path-injection.
- .github/workflows/release.yml: add least-privilege top-level
  'permissions: contents: read' so the check-changes job inherits a
  read-only token. Existing per-job elevated permissions unchanged.
  Resolves actions/missing-workflow-permissions.

Bump to v1.3.1.
Clears 1 CRITICAL + 8 HIGH CVEs surfaced by Trivy on the prior
golang:1.23-alpine / alpine:3.21 base (stdlib CVEs across crypto/tls,
crypto/x509, archive/tar, archive/zip, net/url).

- Dockerfile: golang:1.23-alpine -> 1.26-alpine, alpine:3.21 -> 3.22
- go.mod: go 1.21 -> 1.26
- release.yml: actions/setup-go pinned to 1.26
- .dockerignore: add .env*, *.pem, *.key, .claude, .github, CLAUDE.md,
  PR_DESCRIPTION.md, tmp/ to prevent accidental inclusion

Post-bump Trivy scan: 0 HIGH / 0 CRITICAL on ttlequals0/labelarr:1.3.1.
….3.2

Transport failures on the Plex HTTP client bubble up Go's *url.Error,
which embeds the full request URL including the token. With TLS verify
now defaulting on, a misconfigured cert produces repeating error lines
containing the Plex token, leaking it to stdout/Loki.

- Add urlSecretRedactor regexp and redactURLSecrets helper
- Add (*Client).safeDo wrapper that scrubs Do() errors before returning
- Route all 9 httpClient.Do(req) call sites through safeDo
- Redact url.Parse errors in UpdateMediaField/RemoveMediaFieldKeywords
fix(security): CodeQL alerts + Go/Alpine bump + Plex token redaction - v1.3.2
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