feat: feed UI, in-app player, offline mode, settings

Adds an end-to-end integration test that runs the real pipeline against
live YouTube Atom feeds, verifying the merged feed is newest-first
across channels.
This commit is contained in:
vincent
2026-08-29 02:34:14 +02:00
parent a30423e4b5
commit e75d896933
16 changed files with 1059 additions and 2 deletions
+77
View File
@@ -0,0 +1,77 @@
// Mirrors of the Rust structs in src-tauri/src/models.rs. Field names match
// serde's output exactly so no mapping layer is needed.
export type DownloadState =
| "queued"
| "running"
| "done"
| "failed"
| "cancelled";
export interface ChannelWithCount {
id: string;
title: string;
url: string;
video_count: number;
downloaded_count: number;
}
export interface FeedItem {
id: string;
channel_id: string;
channel_title: string;
title: string;
description: string;
/** Unix seconds. */
published: number;
thumb_url: string;
thumb_path: string | null;
views: number;
is_short: boolean;
state: DownloadState | null;
path: string | null;
pct: number | null;
error: string | null;
}
export interface FeedFilter {
channel_id?: string | null;
search?: string | null;
downloaded_only: boolean;
hide_shorts: boolean;
limit?: number | null;
}
export interface Prereqs {
yt_dlp: string | null;
ffmpeg: string | null;
library_path: string;
}
export interface RefreshSummary {
channels: number;
new_videos: number;
failures: string[];
}
export interface RefreshProgress {
done: number;
total: number;
channel: string;
}
export interface DownloadProgressEvent {
video_id: string;
pct: number | null;
bytes_done: number;
bytes_total: number | null;
speed: number | null;
eta: number | null;
}
export interface DownloadStateEvent {
video_id: string;
state: DownloadState;
error: string | null;
path: string | null;
}