feat: improve files info
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
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'
|
||||
@@ -49,6 +51,7 @@ function formatSize(size) {
|
||||
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')
|
||||
@@ -63,86 +66,81 @@ export default function FilesList({files}) {
|
||||
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 (
|
||||
<Typography variant='caption' sx={{
|
||||
backgroundColor: isHaute ? '#07332f' : '#393940',
|
||||
color: isHaute ? '#21feec' : '#fff',
|
||||
borderRadius: '0.66rem',
|
||||
border: mode === 'dark' ? `1px solid ${isHaute ? '#21feec' : '#fff'}` : 'none',
|
||||
padding: '0.15rem 0.5rem',
|
||||
fontWeight: 'bold',
|
||||
letterSpacing: '0.05rem',
|
||||
textTransform: 'uppercase',
|
||||
}}>{isHaute ? 'Haute' : 'Faible'}</Typography>
|
||||
)
|
||||
}
|
||||
|
||||
const renderMeta = file => {
|
||||
const format = file.ext.replace('.', '').toUpperCase()
|
||||
|
||||
if (!(file.id in audioMeta)) {
|
||||
return <Skeleton variant='text' width={80} />
|
||||
}
|
||||
|
||||
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 (
|
||||
<Box display='flex' flexDirection='column' gap={0.5}>
|
||||
<Box display='flex' alignItems='center' gap={1}>
|
||||
{qualityBadge(file.ext)}
|
||||
<Typography variant='caption' sx={{fontWeight: 'bold', ml: 1}}>{format}</Typography>
|
||||
</Box>
|
||||
{details && <Typography variant='caption' sx={{color: 'text.secondary'}}>{details}</Typography>}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const handleClick = (e, url, fileName) => {
|
||||
e.stopPropagation()
|
||||
FileSaver.saveAs(url, fileName)
|
||||
}
|
||||
|
||||
const getQuality = (extension, caption) => {
|
||||
switch (extension) {
|
||||
case '.ogg':
|
||||
case '.aac':
|
||||
case '.mp3':
|
||||
return (
|
||||
<Typography sx={{
|
||||
backgroundColor: '#393940',
|
||||
color: '#fff',
|
||||
borderRadius: '0.66rem',
|
||||
border: mode === 'dark' ? '1px solid #fff' : 'none',
|
||||
fontSize: '0.75rem',
|
||||
letterSpacing: '0.1rem',
|
||||
padding: '0.2515rem 0.6707rem',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
>Faible</Typography>
|
||||
)
|
||||
case '.flac':
|
||||
if (caption === 'MAX') {
|
||||
return (
|
||||
<Typography sx={{
|
||||
backgroundColor: '#332619',
|
||||
color: '#ffbe7d',
|
||||
borderRadius: '0.66rem',
|
||||
border: mode === 'dark' ? '1px solid #ffbe7d' : 'none',
|
||||
fontSize: '0.75rem',
|
||||
letterSpacing: '0.1rem',
|
||||
padding: '0.2515rem 0.6707rem',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>{caption}</Typography>
|
||||
)
|
||||
}
|
||||
|
||||
if (caption === 'HAUTE') {
|
||||
return (
|
||||
<Typography sx={{
|
||||
backgroundColor: '#07332f',
|
||||
color: '#21feec',
|
||||
borderRadius: '0.66rem',
|
||||
border: mode === 'dark' ? '1px solid #21feec' : 'none',
|
||||
fontSize: '0.75rem',
|
||||
letterSpacing: '0.1rem',
|
||||
padding: '0.2515rem 0.6707rem',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
>{caption}</Typography>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography sx={{
|
||||
backgroundColor: '#07332f',
|
||||
color: '#21feec',
|
||||
borderRadius: '0.66rem',
|
||||
border: mode === 'dark' ? '1px solid #21feec' : 'none',
|
||||
fontSize: '0.75rem',
|
||||
letterSpacing: '0.1rem',
|
||||
padding: '0.2515rem 0.6707rem',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
>Haute</Typography>
|
||||
)
|
||||
|
||||
default:
|
||||
return <DescriptionIcon sx={{marginRight: 1}} />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{musicFiles.length > 0 && (
|
||||
@@ -159,10 +157,9 @@ export default function FilesList({files}) {
|
||||
</ListSubheader>
|
||||
<TableContainer component={Paper}>
|
||||
<Table size='small' aria-label='Musiques'>
|
||||
<caption><small><strong>MAX</strong> : <i>Jusqu’à 24-bit, 96 kHz, ≃ 3000 kbps (flac)</i><br /> <strong>HAUTE</strong> : <i>16 bits, ≃ 900 kbps (flac)</i></small><br /> <small><strong>FAIBLE</strong> : <i>320 kbps (ogg / aac / mp3)</i></small></caption>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<StyledTableCell align='center'>QUALITÉ</StyledTableCell>
|
||||
<StyledTableCell align='center'>FORMAT</StyledTableCell>
|
||||
<StyledTableCell />
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
@@ -170,7 +167,7 @@ export default function FilesList({files}) {
|
||||
{sortedMusicFiles.map(file => (
|
||||
<StyledTableRow key={file.id}>
|
||||
<StyledTableCell>
|
||||
{getQuality(file.ext.toLowerCase(), file?.caption?.toUpperCase())}
|
||||
{renderMeta(file)}
|
||||
</StyledTableCell>
|
||||
<StyledTableCell align='left'>
|
||||
<Link
|
||||
|
||||
Reference in New Issue
Block a user