132 lines
3.4 KiB
TypeScript
132 lines
3.4 KiB
TypeScript
import { useCallback } from 'react';
|
|
import { api } from '@/lib/api';
|
|
import { useAudio } from '@/lib/audio-context';
|
|
import { Artist, Album, Track } from '../types';
|
|
|
|
export function useArtistActions() {
|
|
const { playTrack: playTrackFromContext, playTracks } = useAudio();
|
|
|
|
// Helper to load all tracks from owned albums
|
|
const loadAllOwnedTracks = async (artist: Artist, albums: Album[]) => {
|
|
// Get owned albums sorted by year (newest first)
|
|
const ownedAlbums = albums
|
|
.filter((album) => album.owned)
|
|
.sort((a, b) => (b.year || 0) - (a.year || 0));
|
|
|
|
if (ownedAlbums.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
// Load tracks from all owned albums in parallel
|
|
const albumDataPromises = ownedAlbums.map((album) =>
|
|
api.getAlbum(album.id).catch(() => null)
|
|
);
|
|
|
|
const albumsData = await Promise.all(albumDataPromises);
|
|
|
|
// Combine all tracks, maintaining album order (newest first)
|
|
const allTracks: any[] = [];
|
|
|
|
albumsData.forEach((albumData, index) => {
|
|
if (!albumData || !albumData.tracks) return;
|
|
|
|
const album = ownedAlbums[index];
|
|
const formattedTracks = albumData.tracks.map((track: any) => ({
|
|
id: track.id,
|
|
title: track.title,
|
|
trackNumber: track.trackNumber || 0,
|
|
artist: { name: artist.name, id: artist.id },
|
|
album: {
|
|
title: album.title,
|
|
coverArt: album.coverArt,
|
|
id: album.id,
|
|
year: album.year,
|
|
},
|
|
duration: track.duration,
|
|
}));
|
|
|
|
// Sort tracks within album by track number
|
|
formattedTracks.sort((a: any, b: any) => a.trackNumber - b.trackNumber);
|
|
allTracks.push(...formattedTracks);
|
|
});
|
|
|
|
return allTracks;
|
|
};
|
|
|
|
const playAll = useCallback(
|
|
async (artist: Artist | null, albums: Album[]) => {
|
|
if (!artist) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const allTracks = await loadAllOwnedTracks(artist, albums);
|
|
|
|
if (allTracks.length === 0) {
|
|
return;
|
|
}
|
|
|
|
// Play tracks in order (newest album first, track 1 to end, then next album)
|
|
playTracks(allTracks);
|
|
} catch (error) {
|
|
console.error('Failed to play artist:', error);
|
|
}
|
|
},
|
|
[playTracks]
|
|
);
|
|
|
|
const shufflePlay = useCallback(
|
|
async (artist: Artist | null, albums: Album[]) => {
|
|
if (!artist) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const allTracks = await loadAllOwnedTracks(artist, albums);
|
|
|
|
if (allTracks.length === 0) {
|
|
return;
|
|
}
|
|
|
|
// Shuffle all tracks randomly
|
|
const shuffledTracks = [...allTracks].sort(() => Math.random() - 0.5);
|
|
|
|
playTracks(shuffledTracks);
|
|
} catch (error) {
|
|
console.error('Failed to shuffle play artist:', error);
|
|
}
|
|
},
|
|
[playTracks]
|
|
);
|
|
|
|
const playTrack = useCallback(
|
|
(track: Track, artist: Artist) => {
|
|
try {
|
|
// Format track for audio context
|
|
const formattedTrack = {
|
|
id: track.id,
|
|
title: track.title,
|
|
artist: { name: artist.name, id: artist.id },
|
|
album: {
|
|
title: track.album?.title || 'Unknown Album',
|
|
coverArt: track.album?.coverArt,
|
|
id: track.album?.id,
|
|
},
|
|
duration: track.duration,
|
|
};
|
|
|
|
playTrackFromContext(formattedTrack);
|
|
} catch (error) {
|
|
console.error('Failed to play track:', error);
|
|
}
|
|
},
|
|
[playTrackFromContext]
|
|
);
|
|
|
|
return {
|
|
playAll,
|
|
shufflePlay,
|
|
playTrack,
|
|
};
|
|
}
|