Commit graph

68 commits

Author SHA1 Message Date
jlightner
05045828d8 feat: Wire keyword filter into scheduler scan flow — exclude/include pa…
- "src/services/scheduler.ts"
- "src/__tests__/scheduler.test.ts"
- "src/db/repositories/channel-repository.ts"

GSD-Task: S03/T03
2026-04-04 05:41:55 +00:00
jlightner
cc031a78a9 test: Implement matchesKeywordFilter engine with pipe-separated pattern…
- "src/services/keyword-filter.ts"
- "src/__tests__/keyword-filter.test.ts"

GSD-Task: S03/T02
2026-04-04 05:38:37 +00:00
jlightner
8d133024a5 feat: Add includeKeywords and excludeKeywords nullable text columns to…
- "src/db/schema/channels.ts"
- "src/types/index.ts"
- "src/db/repositories/channel-repository.ts"
- "drizzle/0015_perfect_lethal_legion.sql"
- "src/__tests__/sources.test.ts"

GSD-Task: S03/T01
2026-04-04 05:35:13 +00:00
jlightner
3bfdb7b634 feat: Add File Organization settings section with output template input…
- "src/frontend/src/pages/Settings.tsx"
- "src/frontend/src/components/FormatProfileForm.tsx"
- "src/frontend/src/api/hooks/useFormatProfiles.ts"
- "src/types/api.ts"
- "src/server/routes/system.ts"

GSD-Task: S02/T04
2026-04-04 05:30:34 +00:00
jlightner
fb731377bd feat: Wire FormatProfile.outputTemplate into DownloadService with conte…
- "src/services/download.ts"
- "src/services/file-organizer.ts"

GSD-Task: S02/T03
2026-04-04 05:25:41 +00:00
jlightner
71175198bd test: Add resolveTemplate and validateTemplate methods to FileOrganizer…
- "src/services/file-organizer.ts"
- "src/__tests__/file-organizer.test.ts"

GSD-Task: S02/T02
2026-04-04 05:23:22 +00:00
jlightner
e6371ba196 chore: Add outputTemplate column to format_profiles schema and app.outp…
- "src/db/schema/content.ts"
- "src/types/index.ts"
- "src/db/repositories/system-config-repository.ts"
- "src/db/repositories/format-profile-repository.ts"
- "drizzle/0014_adorable_miek.sql"

GSD-Task: S02/T01
2026-04-04 05:20:18 +00:00
jlightner
61105a74b0 feat: Created AddUrlModal with two-step preview/confirm flow, useAdhocD…
- "src/frontend/src/components/AddUrlModal.tsx"
- "src/frontend/src/api/hooks/useAdhocDownload.ts"
- "src/frontend/src/components/Sidebar.tsx"

GSD-Task: S01/T04
2026-04-04 05:15:28 +00:00
jlightner
22077e0eb1 feat: Add POST /api/v1/download/url/confirm endpoint for ad-hoc downloa…
- "src/server/routes/adhoc-download.ts"
- "src/services/download.ts"
- "src/services/queue.ts"
- "src/__tests__/adhoc-download-api.test.ts"

GSD-Task: S01/T03
2026-04-04 05:12:11 +00:00
jlightner
373a2ee649 test: Created POST /api/v1/download/url/preview endpoint that resolves…
- "src/server/routes/adhoc-download.ts"
- "src/__tests__/adhoc-download-api.test.ts"
- "src/server/index.ts"
- "drizzle/0013_flat_lady_deathstrike.sql"

GSD-Task: S01/T02
2026-04-04 05:07:24 +00:00
jlightner
8150b1f6cf chore: Made content_items.channelId nullable via SQLite table recreatio…
- "src/db/schema/content.ts"
- "src/types/index.ts"
- "src/db/repositories/content-repository.ts"
- "src/services/queue.ts"
- "drizzle/0012_adhoc_nullable_channel.sql"
- "drizzle/meta/_journal.json"

GSD-Task: S01/T01
2026-04-04 05:03:40 +00:00
jlightner
9e5033026e revise issue templates: add location, reproducibility, scope; drop low-signal fields
Some checks failed
CI / test (push) Failing after 17s
2026-04-04 04:02:48 +00:00
jlightner
287f0aa068 add issue templates for bug reports and feature requests
Some checks failed
CI / test (push) Failing after 19s
2026-04-04 04:00:25 +00:00
jlightner
4fe4986f01 docs: naming templates + metadata embedding design spec
Some checks failed
CI / test (push) Failing after 17s
Four-slice feature: template engine with {token} syntax, Plex-compatible
metadata embedding via ffmpeg, batch rename tool, live preview UI.
Per-platform and per-channel naming profile support.

Design only — implementation in next milestone.
2026-04-04 03:27:12 +00:00
jlightner
7de71f1062 fix: strip # from filenames — breaks Plex scanner
Some checks failed
CI / test (push) Failing after 17s
Plex interprets # as a URL fragment delimiter, causing files with # in
the name to be silently skipped during library scans.

- Added # to FORBIDDEN_CHARS in file-organizer.ts sanitizer
- Bulk-renamed 100 existing files on disk
- Updated 100 filePath records in DB to match
2026-04-04 03:15:11 +00:00
jlightner
21a458f500 feat: FormatProfile settings UI + extract ChannelDetail hooks
Some checks failed
CI / test (push) Failing after 19s
- FormatProfile editor now includes embedChapters, embedThumbnail,
  sponsorBlockRemove fields with proper labels and help text
- Extract usePersistedState hook (replaces 7 localStorage try/catch blocks)
- Extract useBulkSelection hook (replaces inline selection state management)
- ChannelDetail.tsx: 1721 → 1672 lines
2026-04-04 02:53:50 +00:00
jlightner
aa09bc089c feat: Generic platform + YouTube enhancements (chapters, SponsorBlock, thumbnails)
Generic Platform:
- New 'generic' platform type — catch-all for any URL yt-dlp supports
- GenericSource resolves channel metadata from any URL via yt-dlp extractors
- Content type auto-detection (video/audio/livestream) from yt-dlp metadata
- Works with Vimeo, Twitch, Bandcamp, Dailymotion, and 1000+ other sites
- Registered in both scheduler registry and channel route registry
- Frontend: indigo badge, URL detection fallback, AddChannelModal support

YouTube Enhancements:
- embedChapters: --embed-chapters flag on FormatProfile
- embedThumbnail: --embed-thumbnail flag on FormatProfile
- sponsorBlockRemove: --sponsorblock-remove with configurable categories
  (sponsor, selfpromo, interaction, intro, outro, preview, music_offtopic, filler)
- Migration 0011: adds columns to format_profiles table
- All three configurable per format profile via API and (future) Settings UI
2026-04-04 02:45:02 +00:00
jlightner
b1e90ea8d6 refactor: consolidate format utils, extract route helpers, remove dead code
- Consolidate 5 duplicate format functions (formatDuration, formatRelativeTime,
  formatFileSize, formatSubscriberCount) into shared utils/format.ts
- Extract parseIdParam() route helper, replacing 22 copy-paste blocks across 9 route files
- Remove dead exports: useScanStatus, useChannelContent (non-paginated),
  getContentItemsByStatus, deleteQueueItem, deletePlaylistsByChannelId
- Fix as-any type assertion in system.ts (queueService already typed on FastifyInstance)
- Net: -411 lines, 23 files touched
2026-04-03 22:55:43 +00:00
jlightner
1078b6dcd7 fix: default monitoring mode to 'none' for new channels
Prevents accidental system bloat from auto-downloading all content
on channel add. Users must explicitly opt in to monitoring.
2026-04-03 22:12:21 +00:00
jlightner
f494d31e60 fix: raise default scan limit from 100 to 500, use 999 for initial scans
- Default scanLimit increased to 500 (was 100, missing most channel content)
- First scan (lastCheckedAt === null) uses max(scanLimit, 999) for full catalog
- Discovery timeout scales with limit: 60s base + 30s per 500 items
- Updated platform-settings-repository defaults to match
2026-04-03 22:07:24 +00:00
jlightner
4546ddb4ea feat: real-time scan streaming with fire-and-forget API and cancel support
- Scan endpoint returns 202 immediately, runs in background
- Items appear in real-time via WebSocket scan:item-discovered events
- Phase 1 (fast flat-playlist) runs first with discoveryOnly flag
- Phase 2 (slow enrichment) runs as background post-scan pass
- Added POST /api/v1/channel/:id/scan-cancel endpoint
- AbortController support in scheduler for scan cancellation
- Frontend: Scan button toggles to Stop button during scan
- Frontend: Live item count shown during scanning
- Frontend: useCancelScan hook for cancel functionality
- Moved tubearr config to local Docker volume (SQLite on CIFS fix)
2026-04-03 21:43:23 +00:00
jlightner
24dbf79ac0 Merge: fold yt-dlp controls into Health card 2026-04-03 07:30:33 +00:00
jlightner
f26db65121 refactor: fold yt-dlp update controls into existing Health card, remove standalone section 2026-04-03 07:30:25 +00:00
jlightner
c016916706 Merge github/master — resolve Queue.tsx import conflict (keep both Skeleton + DownloadProgressBar) 2026-04-03 07:25:36 +00:00
jlightner
d4c595958f Merge milestone/M008: Frontend polish & real-time features (M002) 2026-04-03 07:23:47 +00:00
jlightner
9f35d06e88 feat: Added useYtDlpStatus/useUpdateYtDlp hooks and yt-dlp card to Syst…
- "src/frontend/src/api/hooks/useSystem.ts"
- "src/frontend/src/pages/System.tsx"

GSD-Task: S06/T02
2026-04-03 07:23:39 +00:00
jlightner
c5820fe957 feat: Added YtDlpStatusResponse/YtDlpUpdateResponse types, YTDLP_LAST_U…
- "src/types/api.ts"
- "src/db/repositories/system-config-repository.ts"
- "src/server/routes/system.ts"

GSD-Task: S06/T01
2026-04-03 07:23:39 +00:00
jlightner
cc50ed25e9 perf: Expanded DownloadProgressContext with ScanStore to handle scan We…
- "src/frontend/src/contexts/DownloadProgressContext.tsx"
- "src/frontend/src/pages/ChannelDetail.tsx"

GSD-Task: S05/T02
2026-04-03 07:23:39 +00:00
jlightner
cdd1128632 feat: Added typed scan event pipeline — EventBus emits scan:started/ite…
- "src/services/event-bus.ts"
- "src/services/scheduler.ts"
- "src/index.ts"
- "src/server/routes/websocket.ts"

GSD-Task: S05/T01
2026-04-03 07:23:39 +00:00
jlightner
1711389d9c feat: Added groupedContent useMemo and renderGroupedContent to unify pl…
- "src/frontend/src/pages/ChannelDetail.tsx"

GSD-Task: S04/T02
2026-04-03 07:23:39 +00:00
jlightner
79b2a3a566 feat: Add SortGroupBar with Date/Title/Duration/Size/Status sort button…
- "src/frontend/src/components/SortGroupBar.tsx"
- "src/frontend/src/pages/ChannelDetail.tsx"

GSD-Task: S04/T01
2026-04-03 07:23:39 +00:00
jlightner
9fc15a3ed0 feat: Wired ContentListItem into ChannelDetail with three-button segmen…
- "src/frontend/src/pages/ChannelDetail.tsx"

GSD-Task: S03/T02
2026-04-03 07:23:39 +00:00
jlightner
592c8b1317 feat: Created ContentListItem component with horizontal flexbox layout:…
- "src/frontend/src/components/ContentListItem.tsx"

GSD-Task: S03/T01
2026-04-03 07:23:39 +00:00
jlightner
ab7ab3634b feat: Reordered Add Channel modal fields to URL → Monitoring Mode → For…
- "src/frontend/src/components/AddChannelModal.tsx"
- "src/frontend/src/api/hooks/useChannels.ts"

GSD-Task: S02/T01
2026-04-03 07:23:39 +00:00
jlightner
6a5402ce8d feat: Added banner_url, description, subscriber_count columns with Driz…
- "src/db/schema/channels.ts"
- "drizzle/0010_special_ghost_rider.sql"
- "src/types/index.ts"
- "src/sources/youtube.ts"
- "src/sources/soundcloud.ts"
- "src/db/repositories/channel-repository.ts"
- "src/server/routes/channel.ts"
- "src/__tests__/sources.test.ts"

GSD-Task: S01/T01
2026-04-03 07:23:39 +00:00
jlightner
1dd1e992c6 ci: use host-accessible instance URL
All checks were successful
CI / test (push) Successful in 17s
2026-04-03 06:23:24 +00:00
jlightner
b4c1efc4a6 ci: test Docker DNS resolution
Some checks failed
CI / test (push) Failing after 35s
2026-04-03 06:21:55 +00:00
jlightner
d54924d2ef ci: retry CI run
Some checks failed
CI / test (push) Failing after 37s
2026-04-03 06:19:10 +00:00
jlightner
8a7e5bce8c ci: add Forgejo Actions workflow for test automation
Some checks failed
CI / test (push) Failing after 9m19s
Runs TypeScript type checking and vitest on push/PR to master.
2026-04-03 06:06:32 +00:00
jlightner
0bf63fed9c ci: add Forgejo Actions workflow for test automation
Runs TypeScript type checking and vitest on push/PR to master.
2026-04-03 06:06:20 +00:00
jlightner
ecbfd5afa7 feat: Applied glassmorphism styling (backdrop-filter blur, semi-transpa…
- "src/frontend/src/pages/ChannelDetail.tsx"

GSD-Task: S03/T03
2026-04-03 04:42:22 +00:00
jlightner
cca396a7e8 feat: Refactored channel header into grouped control sections (Monitori…
- "src/frontend/src/pages/ChannelDetail.tsx"

GSD-Task: S03/T02
2026-04-03 04:40:36 +00:00
jlightner
49ac76c379 feat: Created Toast notification system and migrated Channels.tsx + Cha…
- "src/frontend/src/components/Toast.tsx"
- "src/frontend/src/App.tsx"
- "src/frontend/src/pages/Channels.tsx"
- "src/frontend/src/pages/ChannelDetail.tsx"
- "src/frontend/src/styles/global.css"

GSD-Task: S02/T04
2026-04-03 04:27:36 +00:00
jlightner
538f9ec69b feat: Replaced all 28 JS hover handlers in Settings.tsx with CSS utilit…
- "src/frontend/src/pages/Settings.tsx"
- "src/frontend/src/styles/global.css"
- "src/frontend/src/components/Skeleton.tsx"

GSD-Task: S02/T03
2026-04-03 04:21:08 +00:00
jlightner
3355326526 feat: Added CSS button utilities (.btn, .btn-icon, .btn-ghost, .btn-dan…
- "src/frontend/src/styles/global.css"
- "src/frontend/src/components/Skeleton.tsx"
- "src/frontend/src/components/Modal.tsx"
- "src/frontend/src/components/Sidebar.tsx"
- "src/frontend/src/pages/Queue.tsx"
- "src/frontend/src/pages/Library.tsx"
- "src/frontend/src/pages/Activity.tsx"
- "src/frontend/src/pages/System.tsx"

GSD-Task: S02/T02
2026-04-03 04:15:46 +00:00
jlightner
a0906f3cdb feat(S03/T01): content card view with grid layout and view toggle
- Created ContentCard component: 16:9 thumbnail with duration badge,
  title, status badge, relative time, monitor/download/external actions,
  overlay checkbox for selection (visible on hover + when selected)
- Added card/table view toggle button in Content header (Grid3X3/List icons)
- View preference persisted to localStorage (tubearr-content-view)
- Card grid uses CSS grid with auto-fill minmax(240px, 1fr)
- Card hover shows border-light highlight, selected shows accent border
- Download progress overlay on card thumbnail for active downloads
- Added .card-checkbox CSS rule for hover-reveal behavior
- Both views share pagination, search, filter, bulk selection
2026-04-03 03:08:56 +00:00
jlightner
91b0b74dcb chore: add media/ to .gitignore and remove from tracking 2026-04-03 02:39:19 +00:00
jlightner
76e6b9727e fix: update download test expectations for format fallback chains
Tests expected old single-format strings, updated to match the new
fallback chain format: preferred → next best → any.
2026-04-03 02:35:37 +00:00
jlightner
ac8905ca38 feat(S02): modern UI design system — theme overhaul, skeletons, animations
- Redesigned theme.css: deeper darks (#0f1117), glassmorphism tokens,
  accent glow, softer borders (rgba), spring/slow transitions, new radii
- Added Inter + JetBrains Mono web fonts for premium typography
- Enhanced global.css: focus rings with box-shadow, skeleton shimmer animation,
  glass-card class, fade-in page transitions, slide-up animations, badge-glow pulse
- Created Skeleton component library: Skeleton, SkeletonRow, SkeletonTable,
  SkeletonChannelHeader, SkeletonChannelsList
- Replaced spinner-text loading states with skeleton placeholders
  (Channels page, ChannelDetail header and content table)
- Updated all card border-radius from radius-lg to radius-xl across all pages
- Added responsive breakpoint stub for mobile (768px)
2026-04-03 02:33:49 +00:00
jlightner
c057b6a286 feat(S01+S04): server-side pagination, search/filter, download engine hardening
S01 — Server-Side Pagination:
- Added getChannelContentPaginated() to content repository with search, filter, sort
- Channel content API now supports ?page, ?pageSize, ?search, ?status, ?contentType, ?sortBy, ?sortDirection
- Backwards-compatible: no params returns all items (legacy mode)
- Frontend useChannelContentPaginated hook with keepPreviousData
- ChannelDetail page: search bar, status/type filter dropdowns, pagination controls
- Sorting delegated to server (removed client-side sortedContent)
- Item count shown in Content header (e.g. '121 items')

S04 — Download Engine Hardening:
- yt-dlp auto-update on production startup (native -U with pip fallback)
- Error classification: rate_limit, format_unavailable, geo_blocked, age_restricted, private, network
- Format fallback chains: preferred res → best under res → single best → any
- Improved parseFinalPath: explicit non-path prefix detection, extension validation
- Error category included in download:failed events
- classifyYtDlpError() exported from yt-dlp module for downstream use
2026-04-03 02:29:49 +00:00