import {useState, useEffect} from 'react'
import PropTypes from 'prop-types'
import List from '@mui/material/List'
import ListSubheader from '@mui/material/ListSubheader'
import Typography from '@mui/material/Typography'
import Box from '@mui/material/Box'
import Skeleton from '@mui/material/Skeleton'
import {useTheme, useColorScheme, styled} from '@mui/material/styles'
import Table from '@mui/material/Table'
import TableHead from '@mui/material/TableHead'
import TableBody from '@mui/material/TableBody'
import TableCell, {tableCellClasses} from '@mui/material/TableCell'
import TableRow from '@mui/material/TableRow'
import TableContainer from '@mui/material/TableContainer'
import Paper from '@mui/material/Paper'
import FileSaver from 'file-saver'
import DescriptionIcon from '@mui/icons-material/Description'
import LibraryMusicIcon from '@mui/icons-material/LibraryMusic'
import {Link} from '@mui/material'
const apiUrl = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'
const StyledTableCell = styled(TableCell)(({theme}) => ({
[`&.${tableCellClasses.head}`]: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
},
}))
const StyledTableRow = styled(TableRow)(({theme}) => ({
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.action.hover,
},
'&:last-child td, &:last-child th': {
border: 0,
},
}))
function formatSize(size) {
if (size < 1000) {
return Math.round(size) + ' Kb'
}
const mbSize = size / 1000
return Math.round(mbSize) + ' Mb'
}
export default function FilesList({files}) {
const theme = useTheme()
const {mode} = useColorScheme()
const [audioMeta, setAudioMeta] = useState({})
const musicFiles = files.filter(file => file.mime.startsWith('audio'))
const pdfFiles = files.filter(file => file.mime === 'application/pdf')
const sortedMusicFiles = musicFiles.sort((a, b) => {
const extensionOrder = {
'.flac': 0,
'.ogg': 1,
'.aac': 2,
'.mp3': 3
}
return extensionOrder[a.ext.toLowerCase()] - extensionOrder[b.ext.toLowerCase()]
})
useEffect(() => {
const audioFiles = files.filter(f => f.mime.startsWith('audio'))
if (audioFiles.length === 0) return
let cancelled = false
async function fetchAllMeta() {
const mm = await import('music-metadata-browser')
const results = {}
await Promise.all(
audioFiles.map(async file => {
try {
const meta = await mm.fetchFromUrl(`${apiUrl}${file.url}`, {skipCovers: true})
results[file.id] = meta.format
} catch {
results[file.id] = null
}
})
)
if (!cancelled) setAudioMeta(results)
}
fetchAllMeta()
return () => {
cancelled = true
}
}, [files])
const losslessFormats = new Set(['.flac', '.wav', '.aiff', '.alac'])
const qualityBadge = ext => {
const isHaute = losslessFormats.has(ext.toLowerCase())
return (
{isHaute ? 'Haute' : 'Faible'}
)
}
const renderMeta = file => {
const format = file.ext.replace('.', '').toUpperCase()
if (!(file.id in audioMeta)) {
return
}
const meta = audioMeta[file.id]
const sampleRate = meta?.sampleRate ? `${meta.sampleRate / 1000} kHz` : null
const bitDepth = meta?.bitsPerSample ? `${meta.bitsPerSample} bits` : null
const bitrate = meta?.bitrate ? `${Math.round(meta.bitrate / 1000)} kbps` : null
const details = [sampleRate, bitDepth ?? bitrate].filter(Boolean).join(' ยท ')
return (
{qualityBadge(file.ext)}
{format}
{details && {details}}
)
}
const handleClick = (e, url, fileName) => {
e.stopPropagation()
FileSaver.saveAs(url, fileName)
}
return (
<>
{musicFiles.length > 0 && (
Musiques
FORMAT
{sortedMusicFiles.map(file => (
{renderMeta(file)}
handleClick(e, `${apiUrl}${file.url}`, file.name)}
>
{file.name}
({formatSize(file.size)})
))}
)}
{pdfFiles.length > 0 && (
Paroles
LANGUE
{pdfFiles.map(file => (
{file.caption}
handleClick(e, `${apiUrl}${file.url}`, file.name)}
>
{file.name}
({formatSize(file.size)})
))}
)}
>
)
}
FilesList.propTypes = {
files: PropTypes.array.isRequired
}