Skip to content

Releases: nitrobass24/seedsync

v1.0.0

10 Jun 20:11
38d6ef2

Choose a tag to compare

What's Changed

SeedSync 1.0.0 — first stable release. This milestone bundles the optional FTPS transfer protocol, a large backend reliability and persistence hardening pass, frontend performance work, the Angular 22 upgrade, and a security-focused test and runtime baseline. Existing SFTP installs are unaffected.

Added

  • Optional FTPS transfer protocol — A new protocol setting (sftp by default, or ftps) runs transfers over FTPS (FTP over TLS) instead of SFTP for substantially higher throughput on high-latency links. Hybrid design: file discovery always stays on SSH (new remote_ftp_port, default 21, used only for FTPS transfers). FTPS uses the same persisted Connections settings as SFTP. The data channel is always TLS-encrypted; certificate verification (ftp_ssl_verify_certificate) defaults off with a per-connection WARNING log to accommodate self-signed seedbox certificates. FTPS options live in a dedicated Transfer Protocol settings section. (#485)
  • Notify on download start — New notify_on_download_start option (off by default) emits a download_start event when a file enters DOWNLOADING, via webhook/Discord/Telegram. (#486)
  • Automatic extract/validate worker recovery — A crashed extract or validate worker is detected and recreated via a shared WorkerSupervisor, so processing resumes after a transient fault without a container restart. (#535)
  • Failed-move surfacing + in-session retry — A failed staging→final move now shows as a distinct MOVE_FAILED state (with a "Move failed" badge) instead of silently appearing done, and is retried within the session. (#536)

Changed

  • Angular 21 → 22 upgrade — Lockstep major bump of all @angular/* packages, @angular/cli, @angular/build, @angular/cdk, and angular-eslint to 22.0.0; TypeScript to 6.0; migrated to provideAppInitializer() and explicit provideZonelessChangeDetection(). (#556)
  • Performance — backend model build — Replaced the O(n²) per-cycle build with O(1) BFS frontiers and a skipped child-list copy. (#520)
  • Performance — frontend file list — Coalesced SSE-driven rebuilds, memoized the filter, single-pass bulk-remove. (#521)
  • Performance — logs page — Capped live-log buffer (ring buffer + stable trackBy), CDK virtual scroll, batched change detection. (#522, #539)
  • Refactor — lftp parser — Decomposed the 412-line, complexity-48 __parse_jobs into focused, strictly-typed helpers. (#523)
  • Refactor — ViewFileService — Split into capabilities module, selection service, and command service with a single source of truth for the status→capability state machine. (#524, #541)
  • Refactor — backend coupling & service conventions — Decoupled Controller/CommandPipeline/persist-sync, typo-safe config option types, tap-based mutating-service contract for ConfigService.set / AutoQueueService. (#525, #542)
  • Repo & CI hygiene.gitignore cleanup, SHA-pinned third-party GitHub Actions, per-job timeouts, dead-script removal, re-enabled mock-based lftp/ssh/scanner unit tests in CI. (#527, #529)
  • Dependency updates — Angular, React 19.2.x, typescript-eslint, eslint, vitest, hono, qs, postcss, webpack-dev-server, webob, shell-quote, and astral-sh/setup-uv, among others. (#488#506, #545#554, #560, #565)

Fixed

  • Remote scan timed out at 30s under password auth — The SSH password-prompt wait now uses the full command timeout instead of pexpect's silent 30s default. (#562)
  • Config handler persistence atomicity/server/config/set captures the pre-mutation value, attempts the write, and rolls back in-memory state + returns a structured HTTP 500 on failure; the LFTP hot-reload callback only fires after a successful write. (#469)
  • Config values containing % crashed persistenceConfig.from_str/to_str now use ConfigParser(interpolation=None); the handler rolls back on any persist failure. (#530, #507)
  • Integration delete persistence ordering — DELETE writes path_pairs.json before integrations.json, downgrading a crash to a harmless orphaned instance. (#496)
  • Handlers wrap persistence in try/except — auto-queue, path-pairs, and integrations endpoints return a controlled HTTP 500 instead of leaking a stack trace; auto-queue rolls back on failure. (#497, #518, #530)
  • Controller.exit() leaked worker subprocesses and queue FDs — teardown is now best-effort with bounded joins. (#508)
  • Auto-queue thread-safety — cross-thread set/list races are lock-guarded. (#509)
  • Move pipeline silent data loss — failed staging→final moves now propagate via a result queue. (#510)
  • Cross-device move raced lftp's temp-file rename — the copy fallback now defers while *.lftp temp files remain, instead of crashing MoveProcess with ENOENT. (#567)
  • Worker crash isolation & ERROR surfacing — a Validate/Extract subprocess crash is isolated from the controller loop; a permanently-dead worker and failed periodic persist() are surfaced at ERROR. (#511, #512)
  • lftp job-status parser robustness — three edge-case parsing bugs, plus a pget header with no data line that consumed the next job's header. (#517, #555)
  • Directory validation broke on tilde/relative remote paths — fixed tilde expansion in the remote find/hash commands. (#519)
  • Web command handlers could block the request thread indefinitely — now bounded with a 504 timeout. (#526)
  • Frontend resilience — single-file action errors surface and stuck rows recover (#513); SSE 401 init deadlock fixed by bootstrapping config off the stream (#514); two-click confirm for bulk Delete Local/Remote (#515); guarded JSON.parse in SSE/logs/auto-queue handlers (#516); version-check banner bounded with a 10s timeout (#527).

Security

  • Documented hardened Docker runtime baselinedocker-compose.dev.yml and the install docs recommend no-new-privileges and cap_drop: ALL (adding back only CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER). (#528)
  • Web API key no longer persisted client-side — kept out of browser storage. (#514)
  • Security-critical path test coverage — extraction zip-slip, SSH command quoting, persist races, config special characters, scanner symlinks, webhook URL-scheme validation. (#530)

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:1.0.0

Full Changelog: v0.18.1...v1.0.0

v0.18.1

16 May 21:37

Choose a tag to compare

What's Changed

  • chore(deps): bump ip-address and express-rate-limit in /src/angular by @dependabot[bot] in #473
  • chore(deps): bump hono from 4.12.14 to 4.12.18 in /src/angular by @dependabot[bot] in #474
  • chore(deps): bump fast-uri from 3.1.0 to 3.1.2 in /website by @dependabot[bot] in #475
  • chore(deps): bump fast-uri from 3.1.0 to 3.1.2 in /src/angular by @dependabot[bot] in #476
  • chore(deps): bump @babel/plugin-transform-modules-systemjs from 7.29.0 to 7.29.4 in /website by @dependabot[bot] in #477
  • chore(deps): bump react from 19.2.5 to 19.2.6 in /website by @dependabot[bot] in #478
  • chore(deps): bump the angular group in /src/angular with 10 updates by @dependabot[bot] in #480
  • chore(deps-dev): bump typescript-eslint from 8.59.1 to 8.59.2 in /src/angular by @dependabot[bot] in #481
  • chore(deps): bump react-dom from 19.2.5 to 19.2.6 in /website by @dependabot[bot] in #479
  • Fix Discord webhook 403 by setting explicit User-Agent by @nitrobass24 in #484

Full Changelog: v0.18.0...v0.18.1

v0.18.0

06 May 18:17
686d6f2

Choose a tag to compare

What's Changed

Changed

  • Image size reduced from 50 MB to 39 MBRUN --mount=from=ghcr.io/astral-sh/uv keeps uv out of the runtime image; build artifacts no longer persist (#437)
  • Dockerfile collapsed to 2 stages on Python 3.13-alpine — Removes an intermediate stage and the legacy Buster build path (#436)
  • Test image rewritten as Alpine with Python 3.13 (#435)
  • Removed stale Docker test infrastructure — Old Compose files and fixture data carried over from the Protractor era (#434)
  • Playwright E2E migrated to the official mcr.microsoft.com/playwright container — Eliminates host-side browser install and apt install of system deps; image tag auto-pinned to the @playwright/test version from package-lock.json (#456)
  • Build and Test (amd64) runs on develop pushes — Populates the GHA cache so PRs against develop hit a warm cache instead of paying the install cost on every run (#456)
  • Playwright browser cache + npm cache wired through actions/cache (#452, #453)
  • Python 3.12 → 3.13 in CI and Dockerfile (#451)
  • README refreshed to cover features through v0.17.0 — Notifications, Sonarr/Radarr, integrity verification, staging, API key (#454)
  • Test count badges added to the README (#451)
  • Dependency updates — Angular group (10 packages), typescript-eslint, jsdom, eslint, Docusaurus 3.10.0 → 3.10.1 across 5 packages (#458, #459, #460, #461, #463, #464, #465, #466)

Added

  • LFTP hot-reload — Connection-related settings (parallel connections, max total connections, socket buffer size, bandwidth limit) apply without a container restart. Settings UI distinguishes between options that take effect immediately and those that require restart (#433)
  • Atomic config writesConfig.to_file() now flushes to disk via temp file + os.rename so a process kill mid-write can't truncate the config (#433)
  • Expanded unit and E2E test coverage:
    • 47 security middleware unit tests (#439)
    • 36 controller core unit tests (#444)
    • 28 FileOptions / Integrations / Option component tests (#448)
    • 25 AutoQueueService and PathPairsService tests (#445)
    • 20 HeaderComponent and VersionCheckService tests (#443)
    • 18 ViewFileFilterService tests (#440)
    • E2E for integrations CRUD (#441)
    • E2E for File Actions & Error States (#438)
    • E2E Settings coverage expansion (#442)
    • Web App Job & Context Python tests (#446)
    • Handler integration test expansion (#447)
    • Python integration tests added to CI (#449)

Fixed

  • Hash Algorithm select test flake — Test waited on the wrong config field; the algorithm select's disable gate is validate.enabled, not validate.xfer_verify. Test now sets the correct field and waits for the SSE-delivered model value before asserting (#455)
  • StreamHandler leaks in test setUp methods — Tests added a handler to the shared root logger but never removed it. Loggers are singletons, so by test N the logger had N handlers and each log line printed N times. Fixed via `self.addCleanup(logger.removeHandler, handler)` across 8 test files / 10 setUp methods (#450, #457)
  • Multiprocessing resource leak in test_active_scanner.pyscanner.close() now registered with addCleanup so resources release even if assertions raise

Security

  • `apk` and its package database are stripped from the runtime image/sbin/apk, /etc/apk, /var/cache/apk, /lib/apk, and the libapk shared libraries are removed in the runtime stage to keep the image under 64 MB (#437). This means in-image vulnerability scanners (Trivy, Grype) can't enumerate Alpine packages directly from a running container; consumers should scan the published `ghcr.io/nitrobass24/seedsync` image via SBOM or image-history tooling. Affected runtime packages: `lftp`, `openssh-client`, `ca-certificates`, `setpriv`, `libstdc++`. Derived images that need `apk add` should base on Alpine and reinstall what they need rather than extending this image.

Docker Pull

```bash
docker pull ghcr.io/nitrobass24/seedsync:0.18.0
```

Full Changelog: v0.17.0...v0.18.0

v0.17.0

30 Apr 21:28

Choose a tag to compare

What's Changed

Added

  • Multi-instance Sonarr/Radarr integration — Replace single Sonarr/Radarr config with named instances stored in integrations.json; each path pair can be mapped to specific *arr instances via arr_target_ids; full CRUD REST API and chip-picker UI (#425, #426)
  • Discord notification preset — Configure a Discord webhook URL in Settings to receive rich embed notifications with color-coded event types; includes Test button (#329, #428)
  • Telegram notification preset — Configure a Telegram bot token and chat ID in Settings to receive Markdown-formatted notifications; includes Test button (#329, #428)
  • Cross-validation for arr_target_ids — Path pair create/update rejects unknown integration instance IDs (#426)

Changed

  • Notification architecture — Refactored WebhookNotifier with extracted _resolve_event_type and generic _fire_raw dispatch; Discord and Telegram formatters are pure functions (#428)
  • Controller decomposition — Decomposed step(), _update_pair_model_state(), and update() into focused methods for C901 compliance (#419, #420)
  • Settings UI consistency — Matching headers, dark mode fixes, semantic <h3> headings (#429, #430, #431)
  • Dependency updates — Angular group (10 updates), vitest, typescript-eslint, postcss (#421-#424)

Fixed

  • Corrupt integrations.json recovery — Returns empty config instead of re-migrating with new UUIDs (#426)
  • Refresh preserves instances on error — No longer replaces list with empty on HTTP error (#426)
  • Toggle enabled error handling — Shows error and refreshes on failure (#426)
  • Arr-picker dark mode — Fixed white dropdown background (#430)
  • Telegram Markdown safety — Backticks in filenames escaped (#428)
  • Thread leak on start failure — Cleans up _active_threads if thread.start() raises (#428)

Security

  • Credential redaction — Discord webhook URLs, Telegram bot tokens, and webhook URLs redacted in API responses (#428)
  • URL scheme validation — Notification test endpoints reject non-http(s) URLs (#428)

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:0.17.0

Full Changelog: v0.16.0...v0.17.0

v0.16.0

22 Apr 17:17
75c4562

Choose a tag to compare

What's Changed

Added

  • Sonarr/Radarr integration — Test connection buttons in Settings to verify Sonarr and Radarr API connectivity (#328, #362)
  • Angular ESLint enforced in CI — All 17 lint rules at error with --max-warnings 0; covers OnPush, a11y, type safety, and code style (#376-#382, #389-#392)

Fixed

  • Mobile file list scrolling — Fixed items skipping during scroll on Android/iOS by correcting virtual scroll itemSize (50→82) and switching to dynamic viewport height measurement via ResizeObserver (#370, #371, #396)
  • Log streaming memory — Stream log files line-by-line instead of readlines() to avoid loading entire log into memory (#385)
  • Controller deadlock on exception — Use with statement on model lock to prevent deadlock when exception occurs during model update (#373, #384)
  • Integrations error leaking details — Strip internal exception details from Sonarr/Radarr error responses (#386)

Changed

  • Accessibility — 55 template a11y violations fixed: <div>/<a> click targets converted to <button>, keyboard navigation added, decorative images marked with alt="" aria-hidden="true" (#391)
  • OnPush change detection — All components now use ChangeDetectionStrategy.OnPush with Angular signals (#392)
  • Type safety — Replaced 50 no-explicit-any violations with proper types; added ModelFileJson, ConfigValue, OptionValue interfaces (#390)
  • Dependency updates — Angular group (8 packages), follow-redirects, hono, vitest, ruff, pytest, pexpect, tblib, Docusaurus (#347-#368, #388)

Security

  • npm audit fixes — Resolved high-severity vulnerabilities in Angular dependencies (#388)

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:0.16.0

Full Changelog: v0.15.0...v0.16.0

v0.15.0

08 Apr 15:08
8af5868

Choose a tag to compare

What's Changed

Added

  • Virtual scrolling for large file lists — Improves performance when browsing directories with many files (#335)
  • Size sorting in file list — New sort option to order files by size (#334)
  • Log level dropdown — Replaced debug toggle with a full log level selector (DEBUG/INFO/WARNING/ERROR/CRITICAL) (#332)

Fixed

  • Bulk delete crash — Fixed unbounded process spawning that caused crashes during bulk delete; scoped concurrency cap to delete operations and added move retry on failure (#338, #341)
  • Infinite busy-loop in command process throttling — Fixed CPU spin in the controller process throttle logic
  • Mobile viewport height — File list viewport no longer wastes 40px on small screens where the header row is hidden
  • Bulk action error resilience — A single failed action no longer aborts the entire bulk operation pipeline

Changed

  • Dependency updates — Angular group bump (9 packages), hono 4.12.7→4.12.12, @hono/node-server bump, jsdom 29.0.1→29.0.2, vitest 4.1.2→4.1.3, lodash 4.17.23→4.18.1, all deps to latest compatible versions (#326, #333, #336, #337, #343, #344, #345)
  • Documentation — Moved recommended hard-link workflow from FAQ to a dedicated Usage section; fixed UI label consistency for "Delete from remote after download" (#340)

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:0.15.0

Full Changelog: v0.14.4...v0.15.0

v0.14.4

30 Mar 23:27

Choose a tag to compare

What's Changed

Changed

  • Pyright strict mode — Upgraded Pyright type checking from basic to strict mode across the entire Python codebase; added type stubs for bottle, pexpect, and tblib (#291, #316)

Fixed

  • Extraction-move validation race — Extraction completion no longer spawns a staging move while validation is still running; the move is deferred to the validation completion path (#316)
  • Directory size preservation in exclude filter_filter_children now preserves scanner-reported directory sizes instead of recomputing from filtered children, preventing remote_size divergence (#316)

Security

  • Website dependency bumps — Fixed 4 vulnerabilities in website transitive dependencies: brace-expansion, path-to-regexp, picomatch, minimatch (#324)
  • Pygments 2.20.0 — Bumped pygments to fix ReDoS vulnerability GHSA-5239-wwwm-4pmq (#325)

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:0.14.4

Full Changelog: v0.14.3...v0.14.4

v0.14.3

25 Mar 16:08

Choose a tag to compare

What's Changed

Added

  • Configurable remote Python path — New "Remote Python Path" setting lets users specify a custom Python binary on the remote server (e.g. ~/python3/bin/python3), solving issues on seedboxes where python3 is not on the default PATH (#314, #315)
  • Startup config validation — SeedSync now validates required LFTP config fields on startup and shows clear error messages when remote_address, remote_username, remote_path, or local_path are missing (#310, #313)

Fixed

  • scan_fs.py Python 3.5 compatibility — Remote scanner script now works on servers with Python 3.5+ by using typing.List/Optional instead of modern type syntax (#314, #315)
  • Sshcp.copy() user@host format — Fixed scp command construction to use the shared _remote_address() helper (#312)
  • Pre-existing code quality bugs — Fixed extraction retry counter, NotImplementedError base class, and process cleanup issues (#289, #312)

Changed

  • uv for Python dependencies — Replaced pip + requirements.txt with uv and PEP 621 dependency groups; pinned uv versions in CI and Docker (#286, #311)

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:0.14.3

Full Changelog: v0.14.2...v0.14.3

v0.14.2

24 Mar 01:14
1fa5dee

Choose a tag to compare

What's Changed

Added

  • Playwright E2E test suite — Replaced legacy Protractor tests with Playwright; 55 tests covering all pages, navigation, themes, and settings (#250)
  • Pyright type checking enforced in CI — Completed Pyright phases 3 & 4, fixing 166 type errors to reach 0 errors in basic mode; Pyright check is now required in CI (#249)

Fixed

  • ModelFile nullable size fieldslocal_size and remote_size are now correctly typed as number | null to match the Python backend JSON contract

Security

  • Reject control characters in filenames — Decoded filenames containing control characters are now rejected to prevent corrupted file entries and queue command injection (#300)
  • Redact sensitive credentials from API — SSH password and key passphrase are no longer exposed in API responses; set handler rejects the redacted sentinel value (#257)

Changed

  • Angular dependency updates — Bumped Angular group to latest, jsdom to 29.0.1 (#307, #308)
  • CI: actions/setup-python v6 — Bumped setup-python action from v5 to v6 (#306)

Removed

  • Legacy Docker E2E infrastructure — Cleaned up Protractor Docker Compose files, test images, and fixture data

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:0.14.2

Full Changelog: v0.14.1...v0.14.2

v0.14.1

18 Mar 20:42
f96e41d

Choose a tag to compare

What's Changed

Fixed

  • Parser crash on long filenames — Chunk progress lines that wrap across PTY boundaries no longer crash the controller; unrecognized lines inside a job context are skipped with a warning (#290, #293)
  • False download completion on parser error — Parser failures no longer trigger false "download completed" signals that left files stuck in staging at partial progress (#296)
  • Progress tracking with .lftp temp naming — ActiveScanner now recognizes .lftp-suffixed temp files in staging, fixing 0% progress display for single-file downloads when temp naming is enabled (#298)
  • Remote scanner compatibility — Fixed Python 3.8+ compatibility for scan_fs.py which runs on remote seedbox servers

Changed

  • PEP 621 pyproject.toml — Consolidated Python dependencies from Poetry format to PEP 621 with proper dependency groups (runtime, test, dev); removed dead dependencies (#287)
  • Ruff linting and formatting — Added Ruff as Python linter/formatter with CI enforcement; applied auto-fixes across 99 files (#288)
  • Pyright type checking — Added Pyright in basic mode with CI reporting; fixed 91 type errors across 26 modules (#292, #295)
  • Python unit tests in CI — Python tests now run in CI alongside Angular tests (#287)
  • Angular dependency updates — Bumped Angular group to 21.2.4, vitest to 4.1.0, jsdom to 29.0.0 (#282, #283, #284)

Docker Pull

docker pull ghcr.io/nitrobass24/seedsync:0.14.1

Full Changelog: v0.14.0...v0.14.1