This commit is contained in:
afkarxyz
2026-04-14 07:28:39 +07:00
parent ce1e6cc65a
commit a9c52e7b6d
10 changed files with 35 additions and 58 deletions
+5 -26
View File
@@ -2,19 +2,16 @@ import type { ReactNode } from "react";
import type { TrackAvailability } from "@/types/api";
import { openExternal } from "@/lib/utils";
import { AmazonAvailabilityIcon, QobuzAvailabilityIcon, TidalAvailabilityIcon } from "./PlatformIcons";
interface AvailabilityLinkEntry {
id: string;
found: boolean;
url?: string;
icon: ReactNode;
}
function getAvailabilityLinkEntries(availability: TrackAvailability): AvailabilityLinkEntry[] {
const tidalUrl = availability.tidal_url?.trim() || "";
const qobuzUrl = availability.qobuz_url?.trim() || "";
const amazonUrl = availability.amazon_url?.trim() || "";
return [
{
id: "tidal",
@@ -36,48 +33,30 @@ function getAvailabilityLinkEntries(availability: TrackAvailability): Availabili
},
];
}
export function hasAvailabilityLinks(availability?: TrackAvailability): boolean {
if (!availability) {
return false;
}
return getAvailabilityLinkEntries(availability).some((entry) => entry.found);
}
export function AvailabilityLinks({ availability }: {
availability?: TrackAvailability;
}) {
if (!availability) {
return <p>Check Availability</p>;
}
const entries = getAvailabilityLinkEntries(availability);
return (
<div className="flex flex-col gap-1.5 w-[260px] max-w-[260px] pointer-events-auto">
{entries.map((entry) => entry.found ? (
<button
key={entry.id}
type="button"
onClick={() => entry.url && openExternal(entry.url)}
className="flex items-center gap-2 text-left text-xs hover:underline min-w-0 cursor-pointer"
title={entry.url}
>
return (<div className="flex flex-col gap-1.5 w-[260px] max-w-[260px] pointer-events-auto">
{entries.map((entry) => entry.found ? (<button key={entry.id} type="button" onClick={() => entry.url && openExternal(entry.url)} className="flex items-center gap-2 text-left text-xs hover:underline min-w-0 cursor-pointer" title={entry.url}>
{entry.icon}
<span className="truncate whitespace-nowrap leading-5 min-w-0">
{entry.url}
</span>
</button>
) : (
<div
key={entry.id}
className="flex items-center gap-2 text-left text-xs min-w-0"
>
</button>) : (<div key={entry.id} className="flex items-center gap-2 text-left text-xs min-w-0">
{entry.icon}
<span className="truncate whitespace-nowrap leading-5 min-w-0 text-red-500">
Not Found
</span>
</div>
))}
</div>
);
</div>))}
</div>);
}
-2
View File
@@ -5,7 +5,6 @@ import { fetchCurrentIPInfo } from "@/lib/api";
import type { CurrentIPInfo } from "@/types/api";
import { openExternal } from "@/lib/utils";
import { useEffect, useRef, useState } from "react";
const IP_INFO_REFRESH_INTERVAL_MS = 30000;
const SPOTIFY_BLOCKED_COUNTRY_CODES = new Set([
"AF",
@@ -25,7 +24,6 @@ const SPOTIFY_BLOCKED_COUNTRY_CODES = new Set([
"TM",
"YE",
]);
export function TitleBar() {
const [currentIPInfo, setCurrentIPInfo] = useState<CurrentIPInfo | null>(null);
const [isLoadingCurrentIPInfo, setIsLoadingCurrentIPInfo] = useState(false);
+4 -2
View File
@@ -33,8 +33,10 @@ const CheckFilesExistence = (outputDir: string, rootDir: string, tracks: CheckFi
const SkipDownloadItem = (itemID: string, filePath: string): Promise<void> => (window as any)["go"]["main"]["App"]["SkipDownloadItem"](itemID, filePath);
const CreateM3U8File = (playlistName: string, outputDir: string, filePaths: string[]): Promise<void> => (window as any)["go"]["main"]["App"]["CreateM3U8File"](playlistName, outputDir, filePaths);
const GetTrackISRC = (spotifyId: string): Promise<string> => (window as any)["go"]["main"]["App"]["GetTrackISRC"](spotifyId);
async function resolveTemplateISRC(settings: { folderTemplate?: string; filenameTemplate?: string }, spotifyId?: string): Promise<string> {
async function resolveTemplateISRC(settings: {
folderTemplate?: string;
filenameTemplate?: string;
}, spotifyId?: string): Promise<string> {
if (!spotifyId) {
return "";
}
+4 -2
View File
@@ -6,8 +6,10 @@ import { joinPath, sanitizePath, getFirstArtist } from "@/lib/utils";
import { logger } from "@/lib/logger";
import type { TrackMetadata } from "@/types/api";
const GetTrackISRC = (spotifyId: string): Promise<string> => (window as any)["go"]["main"]["App"]["GetTrackISRC"](spotifyId);
async function resolveTemplateISRC(settings: { folderTemplate?: string; filenameTemplate?: string }, spotifyId?: string): Promise<string> {
async function resolveTemplateISRC(settings: {
folderTemplate?: string;
filenameTemplate?: string;
}, spotifyId?: string): Promise<string> {
if (!spotifyId) {
return "";
}
-1
View File
@@ -32,7 +32,6 @@ let apiStatusState: ApiStatusState = {
};
let activeCheckAll: Promise<void> | null = null;
const listeners = new Set<() => void>();
type SpotiFLACUnifiedStatusResponse = {
tidal?: string;
qobuz_a?: string;
-3
View File
@@ -1,11 +1,9 @@
import type { ArtistSimple } from "@/types/api";
export interface ClickableArtist {
id: string;
name: string;
external_urls: string;
}
export function splitArtistNames(value: string): string[] {
const trimmed = value.trim();
if (!trimmed) {
@@ -14,7 +12,6 @@ export function splitArtistNames(value: string): string[] {
const parts = trimmed.split(/\s*[;,]\s*/).map((part) => part.trim()).filter(Boolean);
return parts.length > 0 ? parts : [trimmed];
}
export function buildClickableArtists(artists: string, artistsData?: ArtistSimple[], fallbackArtistId?: string, fallbackArtistUrl?: string): ClickableArtist[] {
const names = splitArtistNames(artists);
if (names.length === 0) {