Add web UI, AGPL3, notifications, continue watching, bulk watched, storage stats, scheduler

License:
- GPL3 → AGPL3

New features:
- Web interface (--web [port]): axum/tokio server with SSE progress, library browser,
  download trigger, watched toggle; embedded single-page HTML/JS UI
- Desktop notifications via notify-rust when downloads complete or fail
- Continue Watching sidebar entry showing videos with saved resume positions
- Bulk select mode: select multiple videos, mark all watched/unwatched at once
- Storage stats: channel disk usage shown in sidebar next to video count
- Scheduled channel checks: configurable interval (hours), auto re-downloads all
  tracked channels using channel_url from info.json; enabled in Settings

Theme fixes:
- Scene Queen: remove override_text_color so active button text uses fg_stroke
  (dark navy on neon green) instead of near-white — fixes unreadable contrast
- Trans: override_text_color → hot pink #cc0066 for pink-tinted text throughout

Settings additions:
- Auto-check channels toggle + interval_hours DragValue
- Web UI port setting

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Luna 2026-05-11 04:27:04 -07:00
parent 5b3b8fc901
commit 80cce00b99
8 changed files with 1526 additions and 211 deletions

View file

@ -8,6 +8,10 @@ pub struct Config {
pub player: PlayerSection,
#[serde(default)]
pub ui: UiSection,
#[serde(default)]
pub scheduler: SchedulerSection,
#[serde(default)]
pub web: WebSection,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@ -41,9 +45,37 @@ impl Default for UiSection {
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SchedulerSection {
#[serde(default)]
pub enabled: bool,
#[serde(default = "default_interval_hours")]
pub interval_hours: u32,
}
impl Default for SchedulerSection {
fn default() -> Self {
Self { enabled: false, interval_hours: default_interval_hours() }
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct WebSection {
#[serde(default = "default_web_port")]
pub port: u16,
}
impl Default for WebSection {
fn default() -> Self {
Self { port: default_web_port() }
}
}
fn default_player() -> String { "mpv".to_string() }
fn default_browser() -> String { "firefox".to_string() }
fn default_theme() -> String { "dark".to_string() }
fn default_interval_hours() -> u32 { 24 }
fn default_web_port() -> u16 { 8080 }
impl Config {
pub fn load(path: &Path) -> Result<Self, Box<dyn std::error::Error>> {
@ -62,6 +94,8 @@ impl Config {
backup: BackupSection { directory: dir },
player: PlayerSection::default(),
ui: UiSection::default(),
scheduler: SchedulerSection::default(),
web: WebSection::default(),
}
}
}