fix: Resolve scrolling and audio playback issues
- Fix scrolling on Music Storage page by adding proper overflow handling - Add height constraints and flex layout for better tab panel scrolling - Update streaming endpoint to use presigned URLs instead of direct URLs - Improve audio error handling with better error messages - Update MusicPlayer component with dark theme styling - Add loading indicators and error states for better UX - Fix audio playback for files synced from S3 subdirectories The Music Storage page now has proper scrolling behavior and audio playback should work correctly for all music files.
This commit is contained in:
parent
3317a69004
commit
1bb1f7d0d5
@ -235,10 +235,11 @@ router.get('/:id/stream', async (req, res) => {
|
|||||||
return res.status(404).json({ error: 'Music file not found' });
|
return res.status(404).json({ error: 'Music file not found' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const streamingUrl = await s3Service.getStreamingUrl(musicFile.s3Key);
|
// Use presigned URL for secure access instead of direct URL
|
||||||
|
const presignedUrl = await s3Service.getPresignedUrl(musicFile.s3Key, 3600); // 1 hour expiry
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
streamingUrl,
|
streamingUrl: presignedUrl,
|
||||||
musicFile,
|
musicFile,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -185,7 +185,7 @@ export const MusicPlayer: React.FC<MusicPlayerProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack spacing={4} align="stretch" w="full" p={4} bg="gray.50" borderRadius="lg">
|
<VStack spacing={4} align="stretch" w="full" p={4} bg="gray.800" borderRadius="lg" borderColor="gray.700" borderWidth="1px">
|
||||||
{/* Audio element */}
|
{/* Audio element */}
|
||||||
<audio
|
<audio
|
||||||
ref={audioRef}
|
ref={audioRef}
|
||||||
@ -197,21 +197,23 @@ export const MusicPlayer: React.FC<MusicPlayerProps> = ({
|
|||||||
console.error('Audio error:', e);
|
console.error('Audio error:', e);
|
||||||
toast({
|
toast({
|
||||||
title: 'Playback Error',
|
title: 'Playback Error',
|
||||||
description: 'Failed to play audio file',
|
description: 'Failed to play audio file. The file may be corrupted or the streaming URL may have expired.',
|
||||||
status: 'error',
|
status: 'error',
|
||||||
duration: 3000,
|
duration: 5000,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
onLoadStart={() => setIsLoading(true)}
|
||||||
|
onCanPlay={() => setIsLoading(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Track info */}
|
{/* Track info */}
|
||||||
<VStack spacing={1} align="center">
|
<VStack spacing={1} align="center">
|
||||||
<Text fontWeight="bold" fontSize="lg" noOfLines={1}>
|
<Text fontWeight="bold" fontSize="lg" noOfLines={1} color="white">
|
||||||
{musicFile.title || musicFile.originalName}
|
{musicFile.title || musicFile.originalName}
|
||||||
</Text>
|
</Text>
|
||||||
{musicFile.artist && (
|
{musicFile.artist && (
|
||||||
<Text fontSize="sm" color="gray.600" noOfLines={1}>
|
<Text fontSize="sm" color="gray.400" noOfLines={1}>
|
||||||
{musicFile.artist}
|
{musicFile.artist}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
@ -230,13 +232,14 @@ export const MusicPlayer: React.FC<MusicPlayerProps> = ({
|
|||||||
onChange={handleSeek}
|
onChange={handleSeek}
|
||||||
isDisabled={isLoading}
|
isDisabled={isLoading}
|
||||||
size="sm"
|
size="sm"
|
||||||
|
colorScheme="blue"
|
||||||
>
|
>
|
||||||
<SliderTrack>
|
<SliderTrack bg="gray.700">
|
||||||
<SliderFilledTrack />
|
<SliderFilledTrack bg="blue.400" />
|
||||||
</SliderTrack>
|
</SliderTrack>
|
||||||
<SliderThumb />
|
<SliderThumb bg="blue.400" />
|
||||||
</Slider>
|
</Slider>
|
||||||
<HStack justify="space-between" w="full" fontSize="xs" color="gray.600">
|
<HStack justify="space-between" w="full" fontSize="xs" color="gray.400">
|
||||||
<Text>{formatTime(currentTime)}</Text>
|
<Text>{formatTime(currentTime)}</Text>
|
||||||
<Text>{formatTime(duration)}</Text>
|
<Text>{formatTime(duration)}</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
@ -250,6 +253,8 @@ export const MusicPlayer: React.FC<MusicPlayerProps> = ({
|
|||||||
onClick={skipBackward}
|
onClick={skipBackward}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
color="gray.400"
|
||||||
|
_hover={{ bg: "gray.700" }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -260,6 +265,7 @@ export const MusicPlayer: React.FC<MusicPlayerProps> = ({
|
|||||||
colorScheme="blue"
|
colorScheme="blue"
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
isDisabled={!streamingUrl}
|
isDisabled={!streamingUrl}
|
||||||
|
_hover={{ bg: "blue.700" }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -268,6 +274,8 @@ export const MusicPlayer: React.FC<MusicPlayerProps> = ({
|
|||||||
onClick={skipForward}
|
onClick={skipForward}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
color="gray.400"
|
||||||
|
_hover={{ bg: "gray.700" }}
|
||||||
/>
|
/>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
@ -279,21 +287,40 @@ export const MusicPlayer: React.FC<MusicPlayerProps> = ({
|
|||||||
onClick={toggleMute}
|
onClick={toggleMute}
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
color="gray.400"
|
||||||
|
_hover={{ bg: "gray.700" }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Slider
|
<Slider
|
||||||
value={isMuted ? 0 : volume}
|
value={isMuted ? 0 : volume}
|
||||||
|
onChange={handleVolumeChange}
|
||||||
|
min={0}
|
||||||
max={1}
|
max={1}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
onChange={handleVolumeChange}
|
|
||||||
size="sm"
|
size="sm"
|
||||||
w="100px"
|
w="100px"
|
||||||
|
colorScheme="blue"
|
||||||
>
|
>
|
||||||
<SliderTrack>
|
<SliderTrack bg="gray.700">
|
||||||
<SliderFilledTrack />
|
<SliderFilledTrack bg="blue.400" />
|
||||||
</SliderTrack>
|
</SliderTrack>
|
||||||
<SliderThumb />
|
<SliderThumb bg="blue.400" />
|
||||||
</Slider>
|
</Slider>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
|
{/* Loading indicator */}
|
||||||
|
{isLoading && (
|
||||||
|
<Text fontSize="sm" color="gray.500" textAlign="center">
|
||||||
|
Loading audio...
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Error state */}
|
||||||
|
{!streamingUrl && (
|
||||||
|
<Text fontSize="sm" color="red.400" textAlign="center">
|
||||||
|
Unable to load audio file
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -178,6 +178,8 @@ export const MusicStorage: React.FC = () => {
|
|||||||
minH="100vh"
|
minH="100vh"
|
||||||
bg="gray.900"
|
bg="gray.900"
|
||||||
color="gray.100"
|
color="gray.100"
|
||||||
|
overflowY="auto"
|
||||||
|
height="100vh"
|
||||||
>
|
>
|
||||||
<VStack spacing={6} align="stretch">
|
<VStack spacing={6} align="stretch">
|
||||||
<Heading size="lg" textAlign="center" color="white">
|
<Heading size="lg" textAlign="center" color="white">
|
||||||
@ -195,8 +197,8 @@ export const MusicStorage: React.FC = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
<Tabs variant="enclosed" colorScheme="blue">
|
<Tabs variant="enclosed" colorScheme="blue" height="calc(100vh - 200px)" display="flex" flexDirection="column">
|
||||||
<TabList bg="gray.800" borderColor="gray.700">
|
<TabList bg="gray.800" borderColor="gray.700" flexShrink={0}>
|
||||||
<Tab color="gray.300" _selected={{ bg: "gray.700", color: "white", borderColor: "gray.600" }}>
|
<Tab color="gray.300" _selected={{ bg: "gray.700", color: "white", borderColor: "gray.600" }}>
|
||||||
Upload Music
|
Upload Music
|
||||||
</Tab>
|
</Tab>
|
||||||
@ -211,9 +213,9 @@ export const MusicStorage: React.FC = () => {
|
|||||||
</Tab>
|
</Tab>
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabPanels>
|
<TabPanels flex={1} overflow="hidden">
|
||||||
{/* Upload Tab */}
|
{/* Upload Tab */}
|
||||||
<TabPanel bg="gray.900">
|
<TabPanel bg="gray.900" height="100%" overflowY="auto">
|
||||||
<VStack spacing={6} align="stretch">
|
<VStack spacing={6} align="stretch">
|
||||||
<Box>
|
<Box>
|
||||||
<Heading size="md" mb={4} color="white">
|
<Heading size="md" mb={4} color="white">
|
||||||
@ -229,7 +231,7 @@ export const MusicStorage: React.FC = () => {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
{/* Library Tab */}
|
{/* Library Tab */}
|
||||||
<TabPanel bg="gray.900">
|
<TabPanel bg="gray.900" height="100%" overflowY="auto">
|
||||||
<VStack spacing={4} align="stretch">
|
<VStack spacing={4} align="stretch">
|
||||||
<HStack justify="space-between">
|
<HStack justify="space-between">
|
||||||
<Heading size="md" color="white">Music Library</Heading>
|
<Heading size="md" color="white">Music Library</Heading>
|
||||||
@ -335,12 +337,12 @@ export const MusicStorage: React.FC = () => {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
{/* Song Matching Tab */}
|
{/* Song Matching Tab */}
|
||||||
<TabPanel bg="gray.900">
|
<TabPanel bg="gray.900" height="100%" overflowY="auto">
|
||||||
<SongMatching />
|
<SongMatching />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
{/* Player Tab */}
|
{/* Player Tab */}
|
||||||
<TabPanel bg="gray.900">
|
<TabPanel bg="gray.900" height="100%" overflowY="auto">
|
||||||
<VStack spacing={4} align="stretch">
|
<VStack spacing={4} align="stretch">
|
||||||
<Heading size="md" color="white">Music Player</Heading>
|
<Heading size="md" color="white">Music Player</Heading>
|
||||||
{selectedFile ? (
|
{selectedFile ? (
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user