diff --git a/backend/http_headers.go b/backend/http_headers.go
index 94f95f3..4d6a042 100644
--- a/backend/http_headers.go
+++ b/backend/http_headers.go
@@ -18,4 +18,3 @@ func NewRequestWithDefaultHeaders(method string, rawURL string, body io.Reader)
return req, nil
}
-
diff --git a/frontend/src/components/ApiStatusTab.tsx b/frontend/src/components/ApiStatusTab.tsx
index 730a55e..3314b28 100644
--- a/frontend/src/components/ApiStatusTab.tsx
+++ b/frontend/src/components/ApiStatusTab.tsx
@@ -3,7 +3,6 @@ import { SearchCheck, CheckCircle2, XCircle, Loader2 } from "lucide-react";
import { TidalIcon, QobuzIcon, AmazonIcon, MusicBrainzIcon, AppleMusicIcon, DeezerIcon } from "./PlatformIcons";
import { useApiStatus } from "@/hooks/useApiStatus";
import { SPOTIFLAC_NEXT_SOURCES } from "@/lib/api-status";
-
function renderStatusIcon(status: "checking" | "online" | "offline" | "idle") {
if (status === "online") {
return ;
@@ -13,7 +12,6 @@ function renderStatusIcon(status: "checking" | "online" | "offline" | "idle") {
}
return null;
}
-
function renderPlatformIcon(type: string) {
if (type === "tidal") {
return ;
@@ -32,7 +30,6 @@ function renderPlatformIcon(type: string) {
}
return ;
}
-
export function ApiStatusTab() {
const { sources, statuses, nextStatuses, checkingSources, checkOne } = useApiStatus();
return (
diff --git a/frontend/src/lib/api-status.ts b/frontend/src/lib/api-status.ts
index c89b4a4..ad6b915 100644
--- a/frontend/src/lib/api-status.ts
+++ b/frontend/src/lib/api-status.ts
@@ -1,20 +1,16 @@
import { CheckAPIStatus } from "../../wailsjs/go/main/App";
import { CHECK_TIMEOUT_MS, withTimeout } from "@/lib/async-timeout";
-
export type ApiCheckStatus = "checking" | "online" | "offline" | "idle";
-
export interface ApiSource {
id: string;
type: string;
name: string;
url: string;
}
-
interface SpotiFLACNextSource {
id: string;
name: string;
}
-
type SpotiFLACNextStatusResponse = {
tidal?: string;
qobuz_a?: string;
@@ -27,14 +23,12 @@ type SpotiFLACNextStatusResponse = {
amazon_c?: string;
apple?: string;
};
-
export const API_SOURCES: ApiSource[] = [
{ id: "tidal", type: "tidal", name: "Tidal", url: "" },
{ id: "qobuz", type: "qobuz", name: "Qobuz", url: "" },
{ id: "amazon", type: "amazon", name: "Amazon Music", url: "" },
{ id: "musicbrainz", type: "musicbrainz", name: "MusicBrainz", url: "https://musicbrainz.org" },
];
-
export const SPOTIFLAC_NEXT_SOURCES: SpotiFLACNextSource[] = [
{ id: "tidal", name: "Tidal" },
{ id: "qobuz", name: "Qobuz" },
@@ -42,38 +36,31 @@ export const SPOTIFLAC_NEXT_SOURCES: SpotiFLACNextSource[] = [
{ id: "deezer", name: "Deezer" },
{ id: "apple", name: "Apple Music" },
];
-
const SPOTIFLAC_NEXT_STATUS_URL = "https://status.spotbye.qzz.io/status";
const SPOTIFLAC_NEXT_MAX_ATTEMPTS = 3;
const SPOTIFLAC_NEXT_RETRY_DELAY_MS = 1200;
-
type ApiStatusState = {
checkingSources: Record
;
statuses: Record;
nextStatuses: Record;
};
-
let apiStatusState: ApiStatusState = {
checkingSources: {},
statuses: {},
nextStatuses: {},
};
-
let activeCheckNextOnly: Promise | null = null;
const activeSourceChecks = new Map>();
const listeners = new Set<() => void>();
-
function emitApiStatusChange() {
for (const listener of listeners) {
listener();
}
}
-
function setApiStatusState(updater: (current: ApiStatusState) => ApiStatusState) {
apiStatusState = updater(apiStatusState);
emitApiStatusChange();
}
-
async function checkSourceStatus(source: ApiSource): Promise {
try {
const isOnline = await withTimeout(CheckAPIStatus(source.type, source.url), CHECK_TIMEOUT_MS, `API status check timed out after 10 seconds for ${source.name}`);
@@ -83,19 +70,15 @@ async function checkSourceStatus(source: ApiSource): Promise {
return "offline";
}
}
-
function statusFromNextValue(value: string | undefined): ApiCheckStatus {
return value === "up" ? "online" : "offline";
}
-
function anyNextVariantUp(values: Array): ApiCheckStatus {
return values.some((value) => value === "up") ? "online" : "offline";
}
-
function delay(ms: number): Promise {
return new Promise((resolve) => window.setTimeout(resolve, ms));
}
-
function getSafeNextStatusesFallback(currentStatuses: Record): Record {
return SPOTIFLAC_NEXT_SOURCES.reduce>((acc, source) => {
const current = currentStatuses[source.id];
@@ -103,7 +86,6 @@ function getSafeNextStatusesFallback(currentStatuses: Record> {
const response = await withTimeout(fetch(SPOTIFLAC_NEXT_STATUS_URL, {
method: "GET",
@@ -112,11 +94,9 @@ async function fetchSpotiFLACNextStatusesOnce(): Promise> {
let lastError: unknown = null;
-
for (let attempt = 1; attempt <= SPOTIFLAC_NEXT_MAX_ATTEMPTS; attempt++) {
try {
return await fetchSpotiFLACNextStatusesOnce();
@@ -141,33 +119,27 @@ async function checkSpotiFLACNextStatuses(): Promise void): () => void {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
}
-
function hasSpotiFLACNextResults(): boolean {
return SPOTIFLAC_NEXT_SOURCES.some((source) => {
const status = apiStatusState.nextStatuses[source.id];
return status === "online" || status === "offline";
});
}
-
export async function checkSpotiFLACNextStatusesOnly(): Promise {
if (activeCheckNextOnly) {
return activeCheckNextOnly;
}
-
activeCheckNextOnly = (async () => {
const checkingNextStatuses = Object.fromEntries(SPOTIFLAC_NEXT_SOURCES.map((source) => [source.id, "checking" as ApiCheckStatus]));
setApiStatusState((current) => ({
@@ -177,15 +149,12 @@ export async function checkSpotiFLACNextStatusesOnly(): Promise {
...checkingNextStatuses,
},
}));
-
try {
setApiStatusState((current) => ({
...current,
nextStatuses: { ...current.nextStatuses },
}));
-
const nextStatuses = await checkSpotiFLACNextStatuses();
-
setApiStatusState((current) => ({
...current,
nextStatuses: {
@@ -204,27 +173,22 @@ export async function checkSpotiFLACNextStatusesOnly(): Promise {
activeCheckNextOnly = null;
}
})();
-
return activeCheckNextOnly;
}
-
export function ensureSpotiFLACNextStatusCheckStarted(): void {
if (!activeCheckNextOnly && !hasSpotiFLACNextResults()) {
void checkSpotiFLACNextStatusesOnly();
}
}
-
export async function checkApiStatus(sourceId: string): Promise {
const source = API_SOURCES.find((item) => item.id === sourceId);
if (!source) {
return;
}
-
const activeCheck = activeSourceChecks.get(sourceId);
if (activeCheck) {
return activeCheck;
}
-
const task = (async () => {
setApiStatusState((current) => ({
...current,
@@ -237,10 +201,8 @@ export async function checkApiStatus(sourceId: string): Promise {
[sourceId]: "checking",
},
}));
-
try {
const status = await checkSourceStatus(source);
-
setApiStatusState((current) => ({
...current,
statuses: {
@@ -260,7 +222,6 @@ export async function checkApiStatus(sourceId: string): Promise {
activeSourceChecks.delete(sourceId);
}
})();
-
activeSourceChecks.set(sourceId, task);
return task;
}