feat: Add export library button to front page - Add download icon button next to settings cog - Export current library to XML format compatible with Rekordbox - Auto-generate filename with current date - Disable button when no songs are available - Provides easy way to backup and share library data
This commit is contained in:
parent
060d339e78
commit
1cba4e0eeb
@ -1,5 +1,5 @@
|
|||||||
import { Box, Button, Flex, Heading, Spinner, Text, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, VStack } from "@chakra-ui/react";
|
import { Box, Button, Flex, Heading, Spinner, Text, useBreakpointValue, IconButton, Drawer, DrawerBody, DrawerHeader, DrawerOverlay, DrawerContent, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, VStack } from "@chakra-ui/react";
|
||||||
import { ChevronLeftIcon, ChevronRightIcon, SettingsIcon } from "@chakra-ui/icons";
|
import { ChevronLeftIcon, ChevronRightIcon, SettingsIcon, DownloadIcon } from "@chakra-ui/icons";
|
||||||
import React, { useState, useRef, useEffect, useCallback } from "react";
|
import React, { useState, useRef, useEffect, useCallback } from "react";
|
||||||
import { useNavigate, useLocation, Routes, Route } from "react-router-dom";
|
import { useNavigate, useLocation, Routes, Route } from "react-router-dom";
|
||||||
import { PaginatedSongList } from "./components/PaginatedSongList";
|
import { PaginatedSongList } from "./components/PaginatedSongList";
|
||||||
@ -9,6 +9,7 @@ import { Configuration } from "./pages/Configuration";
|
|||||||
import { useXmlParser } from "./hooks/useXmlParser";
|
import { useXmlParser } from "./hooks/useXmlParser";
|
||||||
import { usePaginatedSongs } from "./hooks/usePaginatedSongs";
|
import { usePaginatedSongs } from "./hooks/usePaginatedSongs";
|
||||||
import { formatTotalDuration } from "./utils/formatters";
|
import { formatTotalDuration } from "./utils/formatters";
|
||||||
|
import { exportToXml } from "./services/xmlService";
|
||||||
|
|
||||||
import { api } from "./services/api";
|
import { api } from "./services/api";
|
||||||
import type { Song, PlaylistNode } from "./types/interfaces";
|
import type { Song, PlaylistNode } from "./types/interfaces";
|
||||||
@ -114,6 +115,24 @@ export default function RekordboxReader() {
|
|||||||
searchQuery
|
searchQuery
|
||||||
} = usePaginatedSongs({ pageSize: 50, playlistName: currentPlaylist });
|
} = usePaginatedSongs({ pageSize: 50, playlistName: currentPlaylist });
|
||||||
|
|
||||||
|
// Export library to XML
|
||||||
|
const handleExportLibrary = useCallback(() => {
|
||||||
|
try {
|
||||||
|
const xmlContent = exportToXml(songs, playlists);
|
||||||
|
const blob = new Blob([xmlContent], { type: 'application/xml' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `rekordbox-library-${new Date().toISOString().split('T')[0]}.xml`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to export library:', error);
|
||||||
|
}
|
||||||
|
}, [songs, playlists]);
|
||||||
|
|
||||||
// Check if database is initialized (has songs or playlists) - moved after useDisclosure
|
// Check if database is initialized (has songs or playlists) - moved after useDisclosure
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkDatabaseInitialized = async () => {
|
const checkDatabaseInitialized = async () => {
|
||||||
@ -464,12 +483,24 @@ export default function RekordboxReader() {
|
|||||||
Rekordbox Reader
|
Rekordbox Reader
|
||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
|
{/* Export Library Button */}
|
||||||
|
<IconButton
|
||||||
|
icon={<DownloadIcon />}
|
||||||
|
aria-label="Export Library"
|
||||||
|
variant="ghost"
|
||||||
|
ml="auto"
|
||||||
|
mr={2}
|
||||||
|
color="gray.300"
|
||||||
|
_hover={{ color: "white", bg: "whiteAlpha.200" }}
|
||||||
|
onClick={handleExportLibrary}
|
||||||
|
isDisabled={songs.length === 0}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Configuration Button */}
|
{/* Configuration Button */}
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<SettingsIcon />}
|
icon={<SettingsIcon />}
|
||||||
aria-label="Configuration"
|
aria-label="Configuration"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
ml="auto"
|
|
||||||
color="gray.300"
|
color="gray.300"
|
||||||
_hover={{ color: "white", bg: "whiteAlpha.200" }}
|
_hover={{ color: "white", bg: "whiteAlpha.200" }}
|
||||||
onClick={() => navigate('/config')}
|
onClick={() => navigate('/config')}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user