Commit Graph

52 Commits

Author SHA1 Message Date
NimBold 2d427b96d3 feat(torrents): add global open-file limit 2026-08-02 10:50:30 +03:30
NimBold 48b4d984a2 feat(torrents): add tracker timing controls 2026-08-02 10:24:59 +03:30
NimBold 1d27b5b0bf feat(torrents): add encryption policy 2026-08-02 10:05:39 +03:30
NimBold b4da68655a feat(torrents): safely remove unselected files 2026-08-02 09:49:57 +03:30
NimBold 67023d3f0d feat(torrents): support piece priority 2026-08-02 09:22:15 +03:30
NimBold a46a64994d feat(torrents): support tracker exclusion 2026-08-02 01:19:18 +03:30
NimBold ab9f0507d0 feat(torrents): add peer diagnostics 2026-08-02 01:04:04 +03:30
NimBold 2474d2c1cb feat(torrents): add stall timeout control 2026-08-02 00:48:19 +03:30
NimBold 0f1f4e8003 feat(torrents): add tracker controls 2026-08-01 23:53:07 +03:30
NimBold e31a3fcc90 feat(torrents): add integrity verification policy 2026-08-01 22:53:37 +03:30
NimBold ab6c3c372e feat(torrents): add live peer controls 2026-08-01 22:27:32 +03:30
NimBold 52082c1e1d feat(torrents): add peer discovery controls 2026-08-01 21:58:09 +03:30
NimBold dea6ad1974 feat(torrents): add seeding lifecycle and upload controls 2026-08-01 21:27:49 +03:30
NimBold 292447d417 feat(torrents): harden Aria2 torrent downloads 2026-07-30 22:51:46 +03:30
NimBold 546be23c91 fix(queue): harden resume failure and legacy controls 2026-07-29 16:14:44 +03:30
NimBold 5633896d14 chore(deps): refresh package locks and Rust warnings 2026-07-28 18:29:14 +03:30
NimBold cf09bfa2e4 fix(downloads): harden power management and aria2 recovery 2026-07-26 03:04:50 +03:30
NimBold b579c35e42 feat(settings): add curated multilingual fonts
Bundle Vazirmatn, Noto Sans Hebrew, Noto Sans SC, and Roboto with locale-aware fallbacks while keeping custom font import out of scope.

Refs #31
2026-07-23 17:29:29 +03:30
NimBold 1f1ec828f9 feat(settings): add locale-aware font preferences
Bundle optional Inter and Outfit families, preserve the platform system default, and provide script-aware fallbacks for every supported locale.

Refs #31
2026-07-23 17:13:00 +03:30
NimBold 4e3ceb21a5 feat(ui): add cross-platform window control styles
Persist automatic and explicit macOS, Windows, GNOME, and minimal control presets with localized settings and platform-aware fallback.

Refs #31
2026-07-23 16:25:39 +03:30
NimBold 3587fb0c0d fix(downloads): harden queue admission and live speed controls 2026-07-23 04:13:07 +03:30
NimBold 5463d27ed3 feat(settings): add opt-in calendar localization 2026-07-23 03:08:52 +03:30
NimBold ceab8a5fdf feat(downloads): add media quality and queue reordering 2026-07-23 02:55:33 +03:30
NimBold 60f13f756c fix(ui): harden RTL sidebar and desktop window controls
Keep custom Windows/Linux controls available during platform detection, preserve RTL table order while aligning filenames left, and persist sidebar placement overrides.

Refs #17
2026-07-19 02:34:32 +03:30
NimBold 93ddf427b4 feat(i18n): add localized desktop UI
Refs #17
2026-07-18 13:44:29 +03:30
NimBold 160e6af945 feat(locations): remember last Add-window directory
Remember manually selected Add-window folders during the current session, with a persisted Locations toggle and cross-platform path handling.\n\nRefs #23
2026-07-18 11:52:24 +03:30
NimBold 1d197432b2 feat(downloads): add live limits clipboard capture and byte progress 2026-07-15 20:35:05 +03:30
NimBold c34c489aef fix(settings): preserve speed limiter units
Persist the selected display unit for disabled limits, preserve in-progress fractional input, and keep exact KiB-backed preset values visible.\n\nNo linked issue.
2026-07-15 09:19:19 +03:30
NimBold 1da0fa7223 fix(security): harden credential and path boundaries
Preserve pending pairing tokens until credential-store migration succeeds, defer keychain access until frontend hydration, reject symlink and malformed ownership paths, and restrict metadata credentials to exact origins.

Refs #15

Refs #16
2026-07-15 08:23:43 +03:30
NimBold 9805c9288a fix(downloads): harden aria2 recovery and resume lifecycle 2026-07-13 00:35:09 +03:30
NimBold a0f44b79ad feat(portable): add secure Windows portable release (#15)
Implement marker-based portable storage, portable WebView and log paths, secure queue and migration sanitization, and Windows portable ZIP validation while preserving the NSIS installer path.

Refs #15
2026-07-12 23:08:56 +03:30
NimBold 8c035167c8 chore(deps): refresh package versions 2026-07-09 18:05:36 +03:30
NimBold 85ad9d18e8 fix(settings): add category subfolders toggle
Add a Settings > Locations toggle that disables automatic category subfolders while keeping the selected base download folder as the automatic destination.

Persist the setting across frontend and backend startup paths and disable the category subfolder controls when the feature is off.

Fixes #6
2026-07-06 23:37:03 +03:30
NimBold 757e313f71 fix(download): require aria2 for file transfers
Update yt-dlp to 2026.07.04 and refresh the bundled macOS runtime plus engine locks.

Route every non-media download through aria2 by removing the native HTTP fallback path, native GID handling, and the old direct-download harness.

Retry transient aria2 startup/RPC failures before failing, then show the real last error in the download row and Properties modal so Windows failures are diagnosable instead of silent.

Refresh docs and tests around the aria2-only file-download contract, and advance the Firefox extension submodule to its published wording cleanup.
2026-07-05 20:00:53 +03:30
NimBold 84a4ff4bfc feat(tools): harden scheduler speed limiter logs
Modernize the Tools release surfaces for the cross-platform re-release checklist.

- make Speed Limiter presets unit-aware and persist custom removable quick presets

- keep diagnostic logging opt-in on clean installs and honor the saved log state on startup

- stage Scheduler enablement edits without discarding unsaved draft changes

- extend persisted settings and bindings for log opt-in and speed preset state

Verification:

- npm run build

- npm test -- --run src/store/useDownloadStore.test.ts

- cargo test --lib

- cargo test settings --lib
2026-07-03 22:21:16 +03:30
NimBold 63abf23622 fix(engine): broaden media cookie source support 2026-07-02 23:11:47 +03:30
NimBold 6b7eaa1f66 fix(media): preserve yt-dlp output names 2026-07-01 14:45:55 +03:30
NimBold 77b940df60 feat: add resumability detection and pause warnings
- Update 'fetch_metadata' to detect 'Accept-Ranges' HTTP header
- Persist 'resumable' flag in DownloadItem across backend and frontend
- Add confirmation dialog when pausing non-resumable downloads (single and bulk actions)
- Improve UI for start/pause/options buttons by adopting the application accent color on hover
2026-06-28 00:03:12 +03:30
NimBold 8eb1a55e72 fix: eliminate OS keychain prompt on startup by persisting pairing token in DB
The root cause was hydrate_extension_pairing_token accessing the
keychain when keychainAccessGranted was true in the DB.  Any keychain
access on macOS triggers the system prompt when the binary signature
changes after an update.

Architecture change: two-store model.
- The SQLite settings DB is now the primary store for the token.
  hydrate_extension_pairing_token reads from it exclusively -- it
  never touches the OS keychain.  No system prompt on startup.
- The OS keychain remains defence-in-depth: grant_keychain_access
  still writes the token there, but it is only reached from the
  explicit Grant Access button, so any system prompt is user-initiated.

DB helpers: load_pairing_token_from_settings / save_pairing_token_to_settings
hydrate_extension_pairing_token: reads from DB, skips keychain entirely
grant_keychain_access: syncs token to DB after keychain access
Frontend: extensionPairingToken included in partialize for auto-persist
2026-06-25 03:09:50 +03:30
NimBold 6f426c1a18 fix(keychain): persist access state, update granted UI, and resolve build errors 2026-06-24 15:45:21 +03:30
NimBold f603b74a99 feat(release): add cross-platform packaging
Add target-aware engine provisioning, platform package configs, and CI/release verification for macOS arm64, Windows x64, and Linux AppImage.
2026-06-23 21:26:51 +03:30
NimBold 7c835b022f fix: harden scheduler, permissions, and download safety
- Implement scheduler hydration barrier to prevent premature triggers
- Track scheduler exact runs using keys to avoid false stops
- Use 'System Events' for accurate macOS automation permissions
- Prevent system-sleep via proper idle assertions
- Ensure download pauses use channel acknowledgements (PauseWithAck)
- Require Firelink ownership before replacing files in add/conflict UI
- Retain partial download assets when removing entries without deletion
- Clear progress state in store when downloads complete or pause to reduce churn
- Handle empty/invalid queue selections gracefully
2026-06-22 18:05:04 +03:30
NimBold 06b14df307 fix(core): harden download lifecycle and scheduling 2026-06-22 11:19:18 +03:30
NimBold 038f31b988 feat(settings): modernize download location settings
- Replace split 'Default Download Path' and 'All Categories Base' with a canonical baseDownloadFolder and categorySubfolders model
- Retain absolute category overrides only where required
- Update Add window to accurately reflect intended destination:
  - Single URL: specific category path
  - Multiple URLs: base folder with explanatory text
  - Manual Browse override: selected folder
- Centralize path resolution logic shared by Rust backend and UI
2026-06-20 19:22:20 +03:30
NimBold 487e1fea43 fix(downloads): correct add window actions 2026-06-20 18:51:38 +03:30
NimBold 894c238bb7 feat(queue): implement concurrent deduplication and safe backend detachment
- Add backendRegisteredIds and backendDispatchPromises for single dispatch enforcement

- Add detach_download_for_reconfigure to safely modify properties of active downloads

- Add applyProperties logic handling completed, failed, paused, and active queues

- Add extractValidDownloadUrls and fix multi-url paste handling

- Setup vitest and add useDownloadStore unit tests for backend registration lifecycle
2026-06-20 11:41:55 +03:30
NimBold 3a76c6f5d7 fix(security): redact secrets from plaintext persistence
- Strip password, cookies, and headers from download_queue before writing
  to store.bin; secrets remain in-memory for the active session only.
- Move extension pairing token from PersistedSettings to the OS keychain,
  rotating it on upgrade from versions that persisted it as plaintext.
- Add ignores_legacy_extension_pairing_token_field test to confirm serde
  silently drops the old field so existing installs migrate cleanly.
- Document intentional retention of URLs (signed params are the download
  source and cannot be redacted without breaking resume/retry).
2026-06-18 08:20:22 +03:30
NimBold cb39113117 feat(observability): add centralized diagnostics logging engine and native log viewer panel
- Configure tauri-plugin-log with 10MB rotation and 3-file retention
- Add high-frequency format filter to strip [download]% progress ticks
- Hook yt-dlp, aria2c, and native reqwest runners with lifecycle log macros
- Add export_logs Tauri command for async log file export via save dialog
- Create DiagnosticsView React component with streaming monospace console
- Apply severity highlighting: ERROR=red, WARN=yellow, INFO=grey, DEBUG=dim
- Wire Diagnostics tab into sidebar navigation and ActiveView routing
- Log native download failures to log::error! in download.rs
2026-06-17 10:57:32 +03:30
NimBold 58f4a8a14d fix(security): harden sidecar and media processing lifecycles 2026-06-17 09:45:31 +03:30
NimBold f6851682dd feat(retry): add connection-aware exponential backoff across all download backends
Transient network drops and Wi-Fi timeouts no longer promote a download
straight to a hard Failed state. A shared retry engine classifies the
error, emits a transient `Retrying` state, and runs a 3-strike
exponential backoff (2s / 5s / 10s) while preserving the active download
allocation (semaphore permit / worker slot). Resumability primitives are
reused on every retry so no downloaded bytes are discarded.

Engine core (src-tauri/src/retry.rs, new):
- BACKOFF_SCHEDULE = [2s, 5s, 10s], MAX_RETRIES = 3
- backoff_for(strike): schedule index with graceful clamp beyond range
- is_transient_network_error(msg): string classifier covering reqwest,
  yt-dlp, and aria2c phrasing; permanent conditions (HTTP 401/403/404/
  410/451, not-found, permission denied, out-of-disk) checked first so
  they always fail fast
- backoff_and_emit / backoff_and_emit_cancel: cancel-safe sleep helpers
  driving a Retrying state emit before each delay
- 9 unit tests covering schedule math, clamping, transient vs permanent
  classification, and permanent-wins-over-transient precedence

State model (src-tauri/src/ipc.rs):
- DownloadStatus::Retrying variant (serialized "retrying")
- DownloadStateEvent::retrying(id, reason) constructor
- Regenerated TypeScript binding: src/bindings/DownloadStatus.ts

Native reqwest backend (src-tauri/src/download.rs):
- DownloadEvent::Retrying variant (headless mirror)
- CoordinatorEventSink::emit_retrying() drives the production
  download-state channel with status "retrying"
- download_file retry core rewritten: transient -> emit_retrying ->
  backoff_for sleep inside a control_rx select (pause/cancel honored
  mid-backoff) -> re-issue Range header; permanent errors or strike
  exhaustion advance to the next URL then hard Failed

yt-dlp media backend (src-tauri/src/lib.rs):
- child spawn+stream loop wrapped in a 3-strike re-spawn loop; stderr
  tail classified and, if transient, the process is re-spawned after
  backoff (--continue resumes); --retry-wait=2 added to aria2c downloader

aria2c backend (src-tauri/src/queue.rs):
- retry-wait=2 option so aria2's internal retries are not rapid-fire
- handle_aria2_download_error: intercepts transient onDownloadError,
  backs off, re-issues addUri, and rotates the stale gid -> id mapping
  via rotate_aria2_gid (fresh addUri mints a new gid; not rotating would
  detach subsequent WS events and leak the semaphore permit permanently)
- aria2_payloads / aria2_retry_strikes tracking with cleanup on terminal
  outcomes

Verification: cargo build clean; cargo test --lib 37 passed / 0 failed.
2026-06-17 09:16:17 +03:30