Commit Graph

15 Commits

Author SHA1 Message Date
xRangerDE
3f04b42b02 feat: auto-resume queue toggle + already-downloaded VOD indicator
Two real UX wins.

1. Auto-resume queue on startup. New checkbox in Settings -> Download
   ("Queue beim Start automatisch fortsetzen"). When enabled and the
   persisted queue has pending items, processQueue() fires ~5 seconds
   after did-finish-load — long enough for the user to see the queue
   and pause if they did not actually want this. Default off so the
   existing behaviour (explicit Start click) is preserved on upgrade.
   The Settings auto-save fingerprint includes the new flag and
   syncSettingsFormFromConfig restores it. Tooltip explains the
   timing on hover.

2. Already-downloaded indicator on VOD cards. Config gains
   downloaded_vod_ids: string[] (bounded to 4096 latest entries).
   Every successful queue-item download appends its parsed VOD ID
   (or every component ID for merge groups). On the VOD grid each
   card whose vod.id is in the set gets a small green checkmark
   badge in the top-right plus a slightly dimmed thumbnail, with a
   localized "Already downloaded" / "Bereits heruntergeladen"
   tooltip. The lookup builds a Set once per render so it stays
   O(1) per card. The renderer refreshes its local config copy on
   every "newly completed" queue update so the badge appears live
   without waiting for a settings save.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:16:21 +02:00
xRangerDE
3e1d4e188c feat: cutter/merge i18n + per-item retry + status-bar queue summary
Three Phase-6 wins.

1. Cutter & Merge tab labels were the same i18n gap as the trim-VOD
   dialog before 4.5.20: Dauer / Aufloesung / FPS / Auswahl / Start: /
   Ende: / Schneiden / Zusammenfuegen were hardcoded German in
   index.html. Each got an id + setText wiring + DE/EN locale strings
   (cutter.infoDuration / .infoResolution / .infoFps / .infoSelection
   / .startLabel / .endLabel; cutter.cut + merge.merge already existed
   for dynamic state, now also used as initial text on btnCut /
   btnMerge).

2. Per-item retry button on failed queue entries. The existing
   "retry failed" queue-action retried ALL failed items at once;
   when only one specific item should be retried (e.g. transient
   network blip on one URL), the user had to remove every other
   failed item first. New ipcMain.handle("retry-queue-item", id)
   resets that single item to status: pending and triggers
   processQueue if idle. A small ↻ icon now sits next to the
   remove (x) button on items in the error state.

3. Status bar queue summary. The footer previously showed only the
   connection status + version. With longer queues the user had to
   scroll the queue panel to see how many downloads were active
   versus pending. New span between the status indicator and the
   version reads "{downloading} dl, {pending} queued" (locale-aware,
   hidden when queue is empty). Updated on onQueueUpdated and
   onDownloadProgress so it stays live.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 14:02:42 +02:00
xRangerDE
16d2456770 feat: trim-VOD dialog i18n + Twitch API help link + log file shortcut
Three small UX wins.

1. Trim-VOD dialog: every inner label was hardcoded German in
   index.html (Start:, Ende:, Startzeit (HH:MM:SS):, Dauer:, Start
   Part-Nummer..., Leer lassen = Teil 1, Dateinamen-Format:, Zur
   Queue hinzufuegen). EN-mode users had a German dialog. Each
   element now has an id + setText wiring + DE/EN locale strings.

2. Settings -> Twitch API card now opens with a help line + link
   to dev.twitch.tv/console/apps. Uses window.api.openExternal so
   the link opens in the user's default browser instead of the
   Electron renderer (which has nodeIntegration off / no native
   navigation). Fixes the "no idea how to set this up" first-run
   friction.

3. Settings -> Live Debug Log gets an "Open log file" button next
   to Refresh. Uses a new ipcMain handle (open-debug-log-file ->
   shell.showItemInFolder on DEBUG_LOG_FILE) so users no longer
   have to navigate manually to ProgramData. As a small defensive
   bundle:
   - get-debug-log: lines parameter capped at [1, 5000] so a
     misbehaving renderer (or future feature) cannot ask main to
     slice millions of lines.
   - export-runtime-metrics: now uses writeFileAtomicSync (the
     fsync+rename helper from cycle 1) instead of plain
     writeFileSync so a power loss mid-export cannot leave a
     half-written metrics file at the user-chosen path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 13:33:10 +02:00
xRangerDE
44c9173f10 feat: backend i18n for user-visible errors + light-theme color vars
Two related Phase-4 changes.

1. main.ts: tBackend(key, params) helper with DE/EN tables for every
   user-visible error / status string produced server-side. Previously
   every backend message was hardcoded German, so EN-mode users saw
   German errors in the queue (last_error), in download progress
   status, in clip-download responses, and in the preflight panel.
   ~30 keys covered: invalidVodUrl, streamlinkMissing, fileTooSmall,
   integrity*, downloadCancelled / downloadPaused, attemptFailed,
   retryingIn, statusBytesDownloaded, mergeGroupFileMissing,
   notAllPartsDownloaded / notAllClipPartsDownloaded, ffmpegMerge/
   SplitFailed, diskSpaceShortFor, all preflight* messages, etc.
   classifyDownloadError extended to recognize EN equivalents
   (streamlink not found, no video stream, folder) so the retry
   classification still works correctly when the language is EN.
   The hand-rolled translation table in renderer.ts:downloadClip is
   gone — backend strings are already locale-correct.

2. styles.css: --border-soft CSS var added to :root and the
   theme-light override. Inline styles in index.html for the VOD
   filter input / sort select / bulk bar were referencing
   --bg-secondary / --text-primary / --border-color (which don't
   exist) and falling through to dark hex fallbacks (#222 / #fff /
   #444), producing a dark patch in light theme. Now uses
   var(--bg-card) / var(--text) / var(--border-soft) which both
   themes define.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 12:33:18 +02:00
xRangerDE
013e8be1f0 feat(clip): add Parts-format preset to Trim-Clip dialog
The Trim-Clip filename-format radio group only offered three presets
(simple, timestamp, custom template). Users who organise their archive
with the global filename_template_parts pattern (e.g.
08.05.2026_Part07.mp4) had to switch to "custom template" and retype
{date}_Part{part_padded}.mp4 every time.

New "parts" preset:
- index.html: 4th radio option, span#formatParts for the live preview
- types.ts + renderer-globals.d.ts: filenameFormat union extended
- main.ts: makeClipFilename branch produces ${dateStr}_Part${padded}.mp4;
  sanitizeCustomClip whitelists "parts" so persisted queue items with
  the new format survive a restart
- renderer.ts: getSelectedFilenameFormat returns "parts"; live preview
  via partNum.padStart(2, "0")
- DE/EN locales: clips.formatParts label

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 11:46:20 +02:00
xRangerDE
832b606701 ui: VOD sort dropdown with persisted key + locale labels
Adds a sort selector next to the existing filter input. Five modes:
newest first (default), oldest first, most viewed, longest first,
shortest first. Concrete user pain — long archives previously had no
way to find the longest stream, the most-watched, or to scroll back
to the start chronologically.

- vodSortKey state persisted to localStorage as
  twitch-vod-manager:vod-sort and validated against an enum on load,
  so an unknown stored value falls back to date_desc
- renderVodGridFromCurrentState now applies sortVods before
  filterVodsByQuery so the filter sees the sort and the match counter
  is consistent
- sortVods uses created_at timestamps for date sorts, view_count for
  views, and a tiny vodDurationToSeconds parser (XhYmZs) for duration
- DE + EN labels for both the "Sort:" prefix and the five option
  texts; refreshVodSortSelectLabels re-runs on language switch
- syncVodSortSelect on init preselects the persisted value before
  any VOD load so the dropdown reflects state immediately

Browser-default keyboard nav (arrows, type-ahead) covers keyboard
access for the select.

docs/IMPROVEMENT_LOG.md: Cycle 4 dated section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 15:54:53 +02:00
xRangerDE
23d0dd5829 ui: VOD list filter with persistence + Ctrl+F focus + Esc clear
Filter row above the VOD grid lets the user search the loaded archive
by title. Concrete user pain: streamers commonly have hundreds of VODs
and the current UI only supported scrolling.

- vodFilterInput / vodFilterClearBtn / vodFilterCount in index.html
- localized placeholder + clear-button title (DE + EN)
- vodFilterQuery state persisted to localStorage as
  twitch-vod-manager:vod-filter so the search bar survives reloads
- renderVODs split: it now caches lastLoadedVods + lastLoadedStreamer
  and delegates to renderVodGridFromCurrentState which applies
  filterVodsByQuery on every input event (no re-fetch)
- empty-state DOM is now built with createElement + textContent (via
  setVodGridEmptyState) instead of an innerHTML template, even for
  locale-only strings — defence in depth
- keyboard: Ctrl/Cmd+F focuses the filter when the VODs tab is active
  (Electron has no native find bar, so the default is suppressed). Esc
  clears the filter when the input has focus and content. Esc still
  closes modals first if any are open.

docs/IMPROVEMENT_LOG.md: Cycle 3 dated section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 15:43:16 +02:00
xRangerDE
feebfc86a1 ui: data-id queue lookup + persisted active tab + Esc/Ctrl+N shortcuts
Renderer-side polish bundle.

- updateQueueItemProgress now looks up items by [data-id] selector instead
  of array index. Resilient against queue/DOM divergence between renders.
  Determinate vs indeterminate progress logic tightened.

- Active tab persisted to localStorage on every showTab; restored on init
  via loadPersistedActiveTab (whitelisted to known tab IDs so a future
  rename cannot strand the user on a missing tab). Page title now only
  shows the streamer name on the VODs tab — it no longer leaks into
  Settings / Cutter / Merge.

- Escape closes the topmost open modal regardless of focus (clip dialog,
  template guide, update modal — in that priority order).

- Ctrl+1..5 (Cmd+1..5 on macOS) jumps directly to a tab. The existing Del
  (delete selected) and S (start/pause) shortcuts still work and remain
  blocked while typing in inputs.

Adds docs/IMPROVEMENT_LOG.md (new, single dated section for this cycle).

Build: tsc clean. Full smoke suite green (failures: [], runtimeIssues: []).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 15:10:28 +02:00
xRangerDE
5f2e85e455 fix: clip time validation, cutter 0-byte check, pagination guard, atomic config write
H1: Add NaN/negative/zero-duration validation to clip dialog before IPC call
H2: Reject cut video output <= 256 bytes as effectively empty
H3: Add paginated VOD fetching with MAX_VOD_PAGES=50 safety guard
H4: Atomic write (tmp+rename) for config and queue persistence

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 15:33:31 +01:00
xRangerDE
6c47c63fa8 fix: clamp ETA bounds, store stats interval, add activeDownloads finally-cleanup, prevent progress backward jump
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 15:04:59 +01:00
xRangerDE
fbcf3935d0 feat: add drag & drop queue reordering and expandable queue item details
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 09:42:35 +01:00
xRangerDE
2481230983 feat: add keyboard shortcuts (Del/S) and download statistics bar
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 09:40:39 +01:00
xRangerDE
76ecbc652d perf: parallel init with Promise.all, targeted DOM updates for download progress
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 09:26:19 +01:00
xRangerDE
1005b583bd release: 4.2.2 add full settings autosave 2026-03-06 02:05:23 +01:00
xRangerDE
2631924ef5 chore: migrate repository to Codeberg, bump version to 4.2.0, update update logic 2026-03-01 20:23:21 +01:00