diff --git a/.github/workflows/reusable-channel-publish.yml b/.github/workflows/reusable-channel-publish.yml index 31c19b54..21c340f6 100644 --- a/.github/workflows/reusable-channel-publish.yml +++ b/.github/workflows/reusable-channel-publish.yml @@ -306,7 +306,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }} VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }} - PSYSONIC_FANART_KEY: ${{ secrets.PSYSONIC_FANART_KEY }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} @@ -400,7 +399,6 @@ jobs: env: VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }} VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }} - PSYSONIC_FANART_KEY: ${{ secrets.PSYSONIC_FANART_KEY }} APPIMAGE_EXTRACT_AND_RUN: 1 run: npm run tauri:build -- --bundles deb,rpm,appimage - name: upload Linux artifacts diff --git a/src-tauri/src/cover_cache/external.rs b/src-tauri/src/cover_cache/external.rs index 2f8202b3..849d3d2a 100644 --- a/src-tauri/src/cover_cache/external.rs +++ b/src-tauri/src/cover_cache/external.rs @@ -15,6 +15,13 @@ use super::fetch::build_subsonic_url; const FANART_API_BASE: &str = "https://webservice.fanart.tv/v3/music"; const MUSICBRAINZ_BASE: &str = "https://musicbrainz.org/ws/2"; +/// fanart.tv project `api_key`, embedded in the binary like Last.fm's key and as +/// fanart.tv's own terms expect ("sent in addition to your project key" — the app +/// ships a project key, users add a personal one on top). Committed as a literal +/// (not a build secret) so every build — CI, local, AUR, Nix, from-source — has +/// it; desktop-app keys are extractable from any binary anyway. Users can still +/// add their own personal key (BYOK, §22), sent in addition to this one. +pub(super) const FANART_PROJECT_KEY: &str = "a32e00543d18deadb797bc0cc9826760"; /// MusicBrainz requires a meaningful, contactable User-Agent (their ToS). const MUSICBRAINZ_USER_AGENT: &str = concat!( "Psysonic/", diff --git a/src-tauri/src/cover_cache/external_ensure.rs b/src-tauri/src/cover_cache/external_ensure.rs index e7bbcb7f..05501973 100644 --- a/src-tauri/src/cover_cache/external_ensure.rs +++ b/src-tauri/src/cover_cache/external_ensure.rs @@ -188,13 +188,14 @@ pub(super) async fn try_external_fanart( requested: u32, surface: &str, ) -> Option { - // Behind the project key: a runtime env var (dev convenience) wins, else the - // key baked in at build time via `option_env!` (release builds). No secret - // lands in the repo. The BYOK personal key is optional (§22). + // Project key: a runtime env var (dev convenience) wins, else the embedded + // `FANART_PROJECT_KEY` committed in the source — so the feature works in every + // build (CI, local, AUR, Nix, from-source), not just ones built with a secret. + // The BYOK personal key is optional and sent in addition (§22). let api_key = std::env::var("PSYSONIC_FANART_KEY") .ok() - .or_else(|| option_env!("PSYSONIC_FANART_KEY").map(str::to_string)) - .filter(|k| !k.is_empty())?; + .filter(|k| !k.is_empty()) + .unwrap_or_else(|| external::FANART_PROJECT_KEY.to_string()); // BYOK personal key (§22): the settings field wins, else the dev env var. let byok = args .external_artwork_byok diff --git a/src-tauri/src/cover_cache/mod.rs b/src-tauri/src/cover_cache/mod.rs index eb159a7c..9b081ddb 100644 --- a/src-tauri/src/cover_cache/mod.rs +++ b/src-tauri/src/cover_cache/mod.rs @@ -135,9 +135,9 @@ pub struct CoverCacheEnsureArgs { /// with the album/artist name. On-demand UI ensures leave it `None`. #[serde(default)] pub library_server_id: Option, - /// Image-scraper spike (§16 P0): when true, an artist `fanart` ensure may - /// fetch a fanart.tv background into `{tier}-fanart.webp`. Inert unless the - /// fanart project key is present (`PSYSONIC_FANART_KEY`). Off by default. + /// External artwork (§16): when true, an artist `fanart`/`banner` ensure may + /// fetch from fanart.tv into `{tier}-{provider}.webp`. Gated by the master + /// toggle (off by default); the project key is embedded (`FANART_PROJECT_KEY`). #[serde(default)] pub external_artwork_enabled: bool, /// Surface intent for external artwork — `fanart` for the 16:9 artist