From fed86c9e858f55809550ce6c3e421e4c0f4bf5fc Mon Sep 17 00:00:00 2001 From: Connor Johnstone Date: Fri, 20 Mar 2026 13:38:49 -0400 Subject: [PATCH] Updated the ytmusic cookies situation --- frontend/src/api.rs | 22 +++ frontend/src/pages/settings.rs | 218 +++++++++++++++++++-- frontend/src/types.rs | 31 +++ frontend/style.css | 1 + src/cookie_refresh.rs | 107 +++++++++++ src/lib.rs | 1 + src/main.rs | 4 + src/routes/mod.rs | 4 +- src/routes/ytauth.rs | 341 +++++++++++++++++++++++++++++++++ src/state.rs | 8 +- 10 files changed, 722 insertions(+), 15 deletions(-) create mode 100644 src/cookie_refresh.rs create mode 100644 src/routes/ytauth.rs diff --git a/frontend/src/api.rs b/frontend/src/api.rs index fcc92e0..7f49d76 100644 --- a/frontend/src/api.rs +++ b/frontend/src/api.rs @@ -242,3 +242,25 @@ pub async fn save_config(config: &AppConfig) -> Result { } resp.json().await.map_err(|e| ApiError(e.to_string())) } + +// --- YouTube Auth --- + +pub async fn get_ytauth_status() -> Result { + get_json(&format!("{BASE}/ytauth/status")).await +} + +pub async fn ytauth_login_start() -> Result { + post_empty(&format!("{BASE}/ytauth/login-start")).await +} + +pub async fn ytauth_login_stop() -> Result { + post_empty(&format!("{BASE}/ytauth/login-stop")).await +} + +pub async fn ytauth_refresh() -> Result { + post_empty(&format!("{BASE}/ytauth/refresh")).await +} + +pub async fn ytauth_clear_cookies() -> Result<(), ApiError> { + delete(&format!("{BASE}/ytauth/cookies")).await +} diff --git a/frontend/src/pages/settings.rs b/frontend/src/pages/settings.rs index 57834d9..2fd4714 100644 --- a/frontend/src/pages/settings.rs +++ b/frontend/src/pages/settings.rs @@ -3,17 +3,20 @@ use web_sys::HtmlSelectElement; use yew::prelude::*; use crate::api; -use crate::types::AppConfig; +use crate::types::{AppConfig, YtAuthStatus}; #[function_component(SettingsPage)] pub fn settings_page() -> Html { let config = use_state(|| None::); let error = use_state(|| None::); let message = use_state(|| None::); + let ytauth = use_state(|| None::); + let ytauth_loading = use_state(|| false); { let config = config.clone(); let error = error.clone(); + let ytauth = ytauth.clone(); use_effect_with((), move |_| { wasm_bindgen_futures::spawn_local(async move { match api::get_config().await { @@ -21,6 +24,11 @@ pub fn settings_page() -> Html { Err(e) => error.set(Some(e.0)), } }); + wasm_bindgen_futures::spawn_local(async move { + if let Ok(status) = api::get_ytauth_status().await { + ytauth.set(Some(status)); + } + }); }); } @@ -68,6 +76,195 @@ pub fn settings_page() -> Html { return html! {

{ "Loading configuration..." }

}; }; + // Build YouTube auth card HTML outside the main html! macro + let ytauth_html = { + let ytauth = ytauth.clone(); + let ytauth_loading = ytauth_loading.clone(); + let message = message.clone(); + let error = error.clone(); + if let Some(ref status) = *ytauth { + if status.login_session_active { + let vnc_url = status.vnc_url.clone().unwrap_or_default(); + let on_done = { + let ytauth = ytauth.clone(); + let ytauth_loading = ytauth_loading.clone(); + let message = message.clone(); + let error = error.clone(); + Callback::from(move |_: MouseEvent| { + let ytauth = ytauth.clone(); + let ytauth_loading = ytauth_loading.clone(); + let message = message.clone(); + let error = error.clone(); + ytauth_loading.set(true); + wasm_bindgen_futures::spawn_local(async move { + match api::ytauth_login_stop().await { + Ok(_) => { + message.set(Some("YouTube login complete! Cookies exported.".into())); + if let Ok(s) = api::get_ytauth_status().await { + ytauth.set(Some(s)); + } + } + Err(e) => error.set(Some(e.0)), + } + ytauth_loading.set(false); + }); + }) + }; + html! { + <> +

{ "Log into YouTube in the browser below, then click Done." }

+ if !vnc_url.is_empty() { +

{ "Open login window" }

+