This commit is contained in:
afkarxyz
2026-04-14 07:36:41 +07:00
parent 59a057b14a
commit 7346730be9
336 changed files with 13800 additions and 1142 deletions
+37 -31
View File
@@ -5,8 +5,9 @@ import { Spinner } from "@/components/ui/spinner";
import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip";
import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination";
import type { TrackMetadata, TrackAvailability } from "@/types/api";
import { TidalAvailabilityIcon, QobuzAvailabilityIcon, AmazonAvailabilityIcon } from "./PlatformIcons";
import { usePreview } from "@/hooks/usePreview";
import { AvailabilityLinks, hasAvailabilityLinks } from "./AvailabilityLinks";
import { buildClickableArtists } from "@/lib/artist-links";
interface TrackListProps {
tracks: TrackMetadata[];
searchQuery: string;
@@ -172,6 +173,22 @@ export function TrackList({ tracks, searchQuery, sortBy, selectedTracks, downloa
return plays;
return num.toLocaleString();
};
const getAvailabilityButtonIcon = (spotifyId?: string) => {
if (!spotifyId) {
return <Globe className="h-4 w-4"/>;
}
if (checkingAvailabilityTrack === spotifyId) {
return <Spinner />;
}
const availability = availabilityMap?.get(spotifyId);
if (!availability) {
return <Globe className="h-4 w-4"/>;
}
if (hasAvailabilityLinks(availability)) {
return <CheckCircle className="h-4 w-4 text-green-500"/>;
}
return <XCircle className="h-4 w-4 text-red-500"/>;
};
return (<div className="space-y-4">
<div className="rounded-md border">
<div className="overflow-x-auto">
@@ -233,29 +250,22 @@ export function TrackList({ tracks, searchQuery, sortBy, selectedTracks, downloa
{track.spotify_id && skippedTracks.has(track.spotify_id) ? (<FileCheck className="h-4 w-4 text-yellow-500 shrink-0"/>) : track.spotify_id && downloadedTracks.has(track.spotify_id) ? (<CheckCircle className="h-4 w-4 text-green-500 shrink-0"/>) : track.spotify_id && failedTracks.has(track.spotify_id) ? (<XCircle className="h-4 w-4 text-red-500 shrink-0"/>) : null}
</div>
<span className="text-sm text-muted-foreground">
{track.artists_data && track.artists_data.length > 0 ? ((() => {
const artistNames = track.artists.split(", ").map(name => name.trim());
return artistNames.map((name, i) => {
const artistData = track.artists_data![i];
const hasArtistData = artistData && artistData.id && artistData.external_urls;
return (<span key={artistData?.id || i}>
{onArtistClick && hasArtistData ? (<span className="cursor-pointer hover:underline" onClick={() => onArtistClick({
id: artistData.id,
name: name,
external_urls: artistData.external_urls,
})}>
{name}
</span>) : (name)}
{i < artistNames.length - 1 && ", "}
</span>);
});
})()) : onArtistClick && track.artist_id && track.artist_url ? (<span className="cursor-pointer hover:underline" onClick={() => onArtistClick({
id: track.artist_id!,
name: track.artists,
external_urls: track.artist_url!,
})}>
{track.artists}
</span>) : (track.artists)}
{(() => {
const clickableArtists = buildClickableArtists(track.artists, track.artists_data, track.artist_id, track.artist_url);
if (clickableArtists.length === 0) {
return track.artists;
}
return clickableArtists.map((artist, i) => (<span key={`${artist.id || artist.name}-${i}`}>
{onArtistClick ? (<span className="cursor-pointer hover:underline" onClick={() => onArtistClick({
id: artist.id,
name: artist.name,
external_urls: artist.external_urls,
})}>
{artist.name}
</span>) : (artist.name)}
{i < clickableArtists.length - 1 && ", "}
</span>));
})()}
</span>
</div>
</div>
@@ -323,15 +333,11 @@ export function TrackList({ tracks, searchQuery, sortBy, selectedTracks, downloa
{track.spotify_id && onCheckAvailability && (<Tooltip>
<TooltipTrigger asChild>
<Button onClick={() => onCheckAvailability(track.spotify_id!)} size="icon" variant="outline" disabled={checkingAvailabilityTrack === track.spotify_id}>
{checkingAvailabilityTrack === track.spotify_id ? (<Spinner />) : availabilityMap?.has(track.spotify_id) ? (<CheckCircle className="h-4 w-4 text-green-500"/>) : (<Globe className="h-4 w-4"/>)}
{getAvailabilityButtonIcon(track.spotify_id)}
</Button>
</TooltipTrigger>
<TooltipContent>
{availabilityMap?.has(track.spotify_id) ? (<div className="flex items-center gap-2">
<TidalAvailabilityIcon className={`w-4 h-4 ${availabilityMap.get(track.spotify_id)?.tidal ? "text-green-500" : "text-red-500"}`}/>
<QobuzAvailabilityIcon className={`w-4 h-4 ${availabilityMap.get(track.spotify_id)?.qobuz ? "text-green-500" : "text-red-500"}`}/>
<AmazonAvailabilityIcon className={`w-4 h-4 ${availabilityMap.get(track.spotify_id)?.amazon ? "text-green-500" : "text-red-500"}`}/>
</div>) : (<p>Check Availability</p>)}
<TooltipContent className="pointer-events-auto">
<AvailabilityLinks availability={track.spotify_id ? availabilityMap?.get(track.spotify_id) : undefined}/>
</TooltipContent>
</Tooltip>)}
</div>