feat: enhance audio player and favorites functionality with improved type safety, update image handling in components
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
'use client';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useAudioPlayer } from '@/app/components/AudioPlayerContext';
|
||||
import { useAudioPlayer, Track } from '@/app/components/AudioPlayerContext';
|
||||
import { FullScreenPlayer } from '@/app/components/FullScreenPlayer';
|
||||
import { FaPlay, FaPause, FaVolumeHigh, FaForward, FaBackward, FaCompress, FaVolumeXmark, FaExpand, FaShuffle } from "react-icons/fa6";
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
@@ -44,30 +44,30 @@ export const AudioPlayer: React.FC = () => {
|
||||
} = useStandaloneLastFm();
|
||||
|
||||
// Combined Last.fm handlers
|
||||
const onTrackStart = (track: any) => {
|
||||
const onTrackStart = useCallback((track: Track) => {
|
||||
navidromeOnTrackStart(track);
|
||||
standaloneOnTrackStart(track);
|
||||
};
|
||||
}, [navidromeOnTrackStart, standaloneOnTrackStart]);
|
||||
|
||||
const onTrackPlay = (track: any) => {
|
||||
const onTrackPlay = useCallback((track: Track) => {
|
||||
navidromeOnTrackPlay(track);
|
||||
standaloneOnTrackPlay(track);
|
||||
};
|
||||
}, [navidromeOnTrackPlay, standaloneOnTrackPlay]);
|
||||
|
||||
const onTrackPause = (currentTime: number) => {
|
||||
const onTrackPause = useCallback((currentTime: number) => {
|
||||
navidromeOnTrackPause(currentTime);
|
||||
standaloneOnTrackPause(currentTime);
|
||||
};
|
||||
}, [navidromeOnTrackPause, standaloneOnTrackPause]);
|
||||
|
||||
const onTrackProgress = (track: any, currentTime: number, duration: number) => {
|
||||
const onTrackProgress = useCallback((track: Track, currentTime: number, duration: number) => {
|
||||
navidromeOnTrackProgress(track, currentTime, duration);
|
||||
standaloneOnTrackProgress(track, currentTime, duration);
|
||||
};
|
||||
}, [navidromeOnTrackProgress, standaloneOnTrackProgress]);
|
||||
|
||||
const onTrackEnd = (track: any, currentTime: number, duration: number) => {
|
||||
const onTrackEnd = useCallback((track: Track, currentTime: number, duration: number) => {
|
||||
navidromeOnTrackEnd(track, currentTime, duration);
|
||||
standaloneOnTrackEnd(track, currentTime, duration);
|
||||
};
|
||||
}, [navidromeOnTrackEnd, standaloneOnTrackEnd]);
|
||||
|
||||
const handleOpenQueue = () => {
|
||||
setIsFullScreen(false);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client';
|
||||
import Image from 'next/image';
|
||||
import { Song } from '@/lib/navidrome';
|
||||
import { useAudioPlayer } from '@/app/components/AudioPlayerContext';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -92,9 +93,11 @@ export function PopularSongs({ songs, artistName }: PopularSongsProps) {
|
||||
{/* Album Art */}
|
||||
<div className="relative w-12 h-12 bg-muted rounded-md overflow-hidden flex-shrink-0">
|
||||
{song.coverArt && api && (
|
||||
<img
|
||||
<Image
|
||||
src={api.getCoverArtUrl(song.coverArt, 96)}
|
||||
alt={song.album}
|
||||
width={48}
|
||||
height={48}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
import { useState, useEffect } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { lastFmAPI } from '@/lib/lastfm-api';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area';
|
||||
@@ -71,9 +72,11 @@ export function SimilarArtists({ artistName }: SimilarArtistsProps) {
|
||||
>
|
||||
<div className="w-32 space-y-2 group cursor-pointer">
|
||||
<div className="relative w-32 h-32 bg-muted rounded-full overflow-hidden">
|
||||
<img
|
||||
<Image
|
||||
src={getArtistImage(artist)}
|
||||
alt={artist.name}
|
||||
width={128}
|
||||
height={128}
|
||||
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
|
||||
import { useNavidrome } from "./NavidromeContext"
|
||||
import Link from "next/link";
|
||||
import { useAudioPlayer } from "@/app/components/AudioPlayerContext";
|
||||
import { useAudioPlayer, Track } from "@/app/components/AudioPlayerContext";
|
||||
import { getNavidromeAPI } from "@/lib/navidrome";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -82,7 +82,7 @@ export function AlbumArtwork({
|
||||
}));
|
||||
|
||||
playTrack(tracks[0]);
|
||||
tracks.slice(1).forEach((track: any) => addToQueue(track));
|
||||
tracks.slice(1).forEach((track: Track) => addToQueue(track));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to play album:', error);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
@@ -68,11 +68,7 @@ export function LoginForm({
|
||||
}, []);
|
||||
|
||||
// Check if Navidrome is already working on component mount
|
||||
useEffect(() => {
|
||||
checkNavidromeConnection();
|
||||
}, []);
|
||||
|
||||
const checkNavidromeConnection = async () => {
|
||||
const checkNavidromeConnection = useCallback(async () => {
|
||||
try {
|
||||
// First check if there's a working API instance
|
||||
const { getNavidromeAPI } = await import('@/lib/navidrome');
|
||||
@@ -122,7 +118,11 @@ export function LoginForm({
|
||||
} catch (error) {
|
||||
console.log('Navidrome connection check failed, will show config step');
|
||||
}
|
||||
};
|
||||
}, [config, setStep, setFormData, setCanSkipNavidrome, testConnection]);
|
||||
|
||||
useEffect(() => {
|
||||
checkNavidromeConnection();
|
||||
}, [checkNavidromeConnection]);
|
||||
|
||||
const handleInputChange = (field: string, value: string) => {
|
||||
setFormData(prev => ({ ...prev, [field]: value }));
|
||||
|
||||
@@ -9,7 +9,7 @@ import { AlbumArtwork } from "@/app/components/album-artwork";
|
||||
import { ArtistIcon } from "@/app/components/artist-icon";
|
||||
import { Album, Artist, Song } from "@/lib/navidrome";
|
||||
import { Heart, Music, Disc, Mic, Play } from "lucide-react";
|
||||
import { useAudioPlayer } from "@/app/components/AudioPlayerContext";
|
||||
import { useAudioPlayer, Track } from "@/app/components/AudioPlayerContext";
|
||||
import Image from "next/image";
|
||||
|
||||
const FavoritesPage = () => {
|
||||
@@ -82,7 +82,7 @@ const FavoritesPage = () => {
|
||||
}));
|
||||
|
||||
playTrack(tracks[0]);
|
||||
tracks.slice(1).forEach((track: any) => addToQueue(track));
|
||||
tracks.slice(1).forEach((track: Track) => addToQueue(track));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to play album:', error);
|
||||
|
||||
@@ -73,7 +73,7 @@ export class LastFmAPI {
|
||||
}
|
||||
}
|
||||
|
||||
private async makeRequest(method: string, params: Record<string, string>): Promise<any> {
|
||||
private async makeRequest(method: string, params: Record<string, string>): Promise<Record<string, unknown>> {
|
||||
const credentials = this.getCredentials();
|
||||
if (!credentials?.apiKey) {
|
||||
throw new Error('No Last.fm API key available');
|
||||
@@ -108,7 +108,7 @@ export class LastFmAPI {
|
||||
autocorrect: '1'
|
||||
});
|
||||
|
||||
return data.artist || null;
|
||||
return (data.artist as LastFmArtistInfo) || null;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch artist info from Last.fm:', error);
|
||||
return null;
|
||||
@@ -123,7 +123,7 @@ export class LastFmAPI {
|
||||
autocorrect: '1'
|
||||
});
|
||||
|
||||
return data.toptracks || null;
|
||||
return (data.toptracks as LastFmTopTracks) || null;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch artist top tracks from Last.fm:', error);
|
||||
return null;
|
||||
@@ -138,7 +138,7 @@ export class LastFmAPI {
|
||||
autocorrect: '1'
|
||||
});
|
||||
|
||||
return data.similarartists || null;
|
||||
return (data.similarartists as LastFmArtistInfo['similar']) || null;
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch similar artists from Last.fm:', error);
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user