@@ -31,7 +32,7 @@ export function NowPlaying({ apiRoot, track }: { apiRoot: string; track: QueueIt
)
}
- const coverUrl = `${apiRoot}/tracks/${track.slug}/cover`
+ const coverUrl = `${API_ROOT}/tracks/${track.slug}/cover`
return (
diff --git a/furumi-node-player/client/src/components/QueueList.tsx b/furumi-node-player/client/src/components/QueueList.tsx
index f1529fe..c371f09 100644
--- a/furumi-node-player/client/src/components/QueueList.tsx
+++ b/furumi-node-player/client/src/components/QueueList.tsx
@@ -1,4 +1,5 @@
import { useEffect, useRef, useState } from 'react'
+import { API_ROOT } from '../furumiApi'
export type QueueItem = {
slug: string
@@ -9,7 +10,6 @@ export type QueueItem = {
}
type QueueListProps = {
- apiRoot: string
queue: QueueItem[]
order: number[]
playingOrigIdx: number
@@ -43,7 +43,6 @@ function Cover({ src }: { src: string }) {
}
export function QueueList({
- apiRoot,
queue,
order,
playingOrigIdx,
@@ -78,7 +77,7 @@ export function QueueList({
if (!t) return null
const isPlaying = origIdx === playingOrigIdx
- const coverSrc = t.album_slug ? `${apiRoot}/tracks/${t.slug}/cover` : ''
+ const coverSrc = t.album_slug ? `${API_ROOT}/tracks/${t.slug}/cover` : ''
const dur = t.duration ? fmt(t.duration) : ''
const isDragging = draggingPos === pos
const isDragOver = dragOverPos === pos
diff --git a/furumi-node-player/client/src/furumiApi.ts b/furumi-node-player/client/src/furumiApi.ts
index 412b656..8cc8c4e 100644
--- a/furumi-node-player/client/src/furumiApi.ts
+++ b/furumi-node-player/client/src/furumiApi.ts
@@ -1,12 +1,12 @@
-export type FurumiApiClient = (path: string) => Promise
+import axios from 'axios'
-export function createFurumiApiClient(apiRoot: string): FurumiApiClient {
- const API = apiRoot
+const API_BASE = import.meta.env.VITE_API_BASE_URL ?? ''
+export const API_ROOT = `${API_BASE}/api`
- return async function api(path: string) {
- const r = await fetch(API + path)
- if (!r.ok) return null
- return r.json()
- }
-}
+const apiKey = import.meta.env.VITE_API_KEY
+
+export const furumiApi = axios.create({
+ baseURL: API_ROOT,
+ headers: apiKey ? { 'x-api-key': apiKey } : {},
+})
diff --git a/furumi-web-player/Cargo.toml b/furumi-web-player/Cargo.toml
index 03088db..822300c 100644
--- a/furumi-web-player/Cargo.toml
+++ b/furumi-web-player/Cargo.toml
@@ -25,3 +25,4 @@ base64 = "0.22"
rand = "0.8"
urlencoding = "2.1.3"
rustls = { version = "0.23", features = ["ring"] }
+tower-http = { version = "0.6", features = ["cors"] }
diff --git a/furumi-web-player/src/web/mod.rs b/furumi-web-player/src/web/mod.rs
index 90d761c..355b4bb 100644
--- a/furumi-web-player/src/web/mod.rs
+++ b/furumi-web-player/src/web/mod.rs
@@ -3,9 +3,12 @@ pub mod auth;
use std::sync::Arc;
use std::path::PathBuf;
+use std::time::Duration;
use axum::{Router, routing::get, middleware};
+use axum::http::{header, Method};
use sqlx::PgPool;
+use tower_http::cors::{Any, CorsLayer};
#[derive(Clone)]
pub struct AppState {
@@ -42,12 +45,19 @@ pub fn build_router(state: Arc) -> Router {
authed
};
+ let cors = CorsLayer::new()
+ .allow_origin(Any)
+ .allow_methods([Method::GET, Method::OPTIONS, Method::HEAD])
+ .allow_headers([header::ACCEPT, header::CONTENT_TYPE, header::HeaderName::from_static("x-api-key")])
+ .max_age(Duration::from_secs(600));
+
Router::new()
.route("/login", get(auth::login_page))
.route("/logout", get(auth::logout))
.route("/auth/login", get(auth::oidc_login))
.route("/auth/callback", get(auth::oidc_callback))
.merge(app)
+ .layer(cors)
.with_state(state)
}