fix(cover): embed fanart.tv project key so from-source builds work (#1139)

The project key was injected only at our build time (CI secret / option_env!),
so AUR, Nix and any from-source build had no key baked in and the External
Artwork toggle was inert there. Commit it as a source literal (like the Last.fm
key, and as fanart.tv terms expect: the app ships a project key, users add
their own on top via BYOK). Drops the now-redundant CI wiring.
This commit is contained in:
Psychotoxical
2026-06-20 23:03:12 +02:00
committed by GitHub
parent b950d4704b
commit a5313d5cb1
4 changed files with 16 additions and 10 deletions
@@ -306,7 +306,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }} VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }}
VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }} VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }}
PSYSONIC_FANART_KEY: ${{ secrets.PSYSONIC_FANART_KEY }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
@@ -400,7 +399,6 @@ jobs:
env: env:
VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }} VITE_LASTFM_API_KEY: ${{ secrets.VITE_LASTFM_API_KEY }}
VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }} VITE_LASTFM_API_SECRET: ${{ secrets.VITE_LASTFM_API_SECRET }}
PSYSONIC_FANART_KEY: ${{ secrets.PSYSONIC_FANART_KEY }}
APPIMAGE_EXTRACT_AND_RUN: 1 APPIMAGE_EXTRACT_AND_RUN: 1
run: npm run tauri:build -- --bundles deb,rpm,appimage run: npm run tauri:build -- --bundles deb,rpm,appimage
- name: upload Linux artifacts - name: upload Linux artifacts
+7
View File
@@ -15,6 +15,13 @@ use super::fetch::build_subsonic_url;
const FANART_API_BASE: &str = "https://webservice.fanart.tv/v3/music"; const FANART_API_BASE: &str = "https://webservice.fanart.tv/v3/music";
const MUSICBRAINZ_BASE: &str = "https://musicbrainz.org/ws/2"; 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). /// MusicBrainz requires a meaningful, contactable User-Agent (their ToS).
const MUSICBRAINZ_USER_AGENT: &str = concat!( const MUSICBRAINZ_USER_AGENT: &str = concat!(
"Psysonic/", "Psysonic/",
+6 -5
View File
@@ -188,13 +188,14 @@ pub(super) async fn try_external_fanart(
requested: u32, requested: u32,
surface: &str, surface: &str,
) -> Option<PathBuf> { ) -> Option<PathBuf> {
// Behind the project key: a runtime env var (dev convenience) wins, else the // Project key: a runtime env var (dev convenience) wins, else the embedded
// key baked in at build time via `option_env!` (release builds). No secret // `FANART_PROJECT_KEY` committed in the source — so the feature works in every
// lands in the repo. The BYOK personal key is optional (§22). // 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") let api_key = std::env::var("PSYSONIC_FANART_KEY")
.ok() .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. // BYOK personal key (§22): the settings field wins, else the dev env var.
let byok = args let byok = args
.external_artwork_byok .external_artwork_byok
+3 -3
View File
@@ -135,9 +135,9 @@ pub struct CoverCacheEnsureArgs {
/// with the album/artist name. On-demand UI ensures leave it `None`. /// with the album/artist name. On-demand UI ensures leave it `None`.
#[serde(default)] #[serde(default)]
pub library_server_id: Option<String>, pub library_server_id: Option<String>,
/// Image-scraper spike (§16 P0): when true, an artist `fanart` ensure may /// External artwork (§16): when true, an artist `fanart`/`banner` ensure may
/// fetch a fanart.tv background into `{tier}-fanart.webp`. Inert unless the /// fetch from fanart.tv into `{tier}-{provider}.webp`. Gated by the master
/// fanart project key is present (`PSYSONIC_FANART_KEY`). Off by default. /// toggle (off by default); the project key is embedded (`FANART_PROJECT_KEY`).
#[serde(default)] #[serde(default)]
pub external_artwork_enabled: bool, pub external_artwork_enabled: bool,
/// Surface intent for external artwork — `fanart` for the 16:9 artist /// Surface intent for external artwork — `fanart` for the 16:9 artist