diff --git a/components/files/files-dialog.js b/components/files/files-dialog.js new file mode 100644 index 0000000..59d70aa --- /dev/null +++ b/components/files/files-dialog.js @@ -0,0 +1,52 @@ +import {useState} from 'react' +import PropTypes from 'prop-types' +import Button from '@mui/material/Button' +import Dialog from '@mui/material/Dialog' +import DialogActions from '@mui/material/DialogActions' +import DialogContent from '@mui/material/DialogContent' +import useMediaQuery from '@mui/material/useMediaQuery' +import {useTheme} from '@mui/material/styles' + +import DownloadForOfflineIcon from '@mui/icons-material/DownloadForOffline' +import FilesList from './files-list' + +export default function FilesDialog({files}) { + const [open, setOpen] = useState(false) + const theme = useTheme() + const fullScreen = useMediaQuery(theme.breakpoints.down('md')) + + const handleClickOpen = () => { + setOpen(true) + } + + const handleClose = () => { + setOpen(false) + } + + return ( + <> + + + + + + + + + + + ) +} + +FilesDialog.propTypes = { + files: PropTypes.array.isRequired +} diff --git a/components/files/files-list.js b/components/files/files-list.js new file mode 100644 index 0000000..3c0ba78 --- /dev/null +++ b/components/files/files-list.js @@ -0,0 +1,248 @@ +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 {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 musicFiles = files.filter(file => file.attributes.mime.startsWith('audio')) + const pdfFiles = files.filter(file => file.attributes.mime === 'application/pdf') + + const sortedMusicFiles = musicFiles.sort((a, b) => { + const extensionOrder = { + '.flac': 0, + '.ogg': 1, + '.aac': 2, + '.mp3': 3 + } + return extensionOrder[a.attributes.ext.toLowerCase()] - extensionOrder[b.attributes.ext.toLowerCase()] + }) + + const handleClick = (e, url, fileName) => { + e.stopPropagation() + FileSaver.saveAs(url, fileName) + } + + const getQuality = (extension, caption) => { + switch (extension) { + case '.ogg': + case '.aac': + case '.mp3': + return ( + Faible + ) + case '.flac': + if (caption === 'MAX') { + return ( + {caption} + ) + } + + if (caption === 'HAUTE') { + return ( + {caption} + ) + } + + return ( + Haute + ) + + default: + return + } + } + + return ( + <> + {musicFiles.length > 0 && ( + + + + + Musiques + + + + + + + + QUALITÉ + + + + + {sortedMusicFiles.map(file => ( + + + {getQuality(file.attributes.ext.toLowerCase(), file?.attributes?.caption?.toUpperCase())} + + + handleClick(e, `${apiUrl}${file.attributes.url}`, file.attributes.name)} + > + {file.attributes.name} + + ({formatSize(file.attributes.size)}) + + + ))} + +
MAX : Jusqu’à 24-bit, 96 kHz, ≃ 3000 kbps (flac)
HAUTE : 16 bits, ≃ 900 kbps (flac)

FAIBLE : 320 kbps (ogg / aac / mp3)
+
+
+ )} + + {pdfFiles.length > 0 && ( + + + + + Paroles + + + + + + + LANGUE + + + + + {pdfFiles.map(file => ( + + + + {file.attributes.caption} + + + + handleClick(e, `${apiUrl}${file.attributes.url}`, file.attributes.name)} + > + {file.attributes.name} + + ({formatSize(file.attributes.size)}) + + + ))} + +
+
+
+ )} + + ) +} + +FilesList.propTypes = { + files: PropTypes.array.isRequired +} diff --git a/components/teks/teks.js b/components/teks/teks.js index 515fcf3..6dc349e 100644 --- a/components/teks/teks.js +++ b/components/teks/teks.js @@ -16,6 +16,7 @@ import ExplicitIcon from '@mui/icons-material/Explicit' import {formatJsonString, getAlias} from '../../lib/utils/format' import LicenseModal from '../cc/license-modal' +import FilesDialog from '../files/files-dialog' import EntegreMizik from './entegre-mizik' import OkiMizik from './oki-mizik' import DiferansDialog from './diferans-dialog' @@ -183,6 +184,9 @@ export default function Teks({parole}) { )} + {parole?.files?.data && ( + + )} {(parole.okiMizikID || parole.streamAudio.length > 0 || parole.gadeEmbed) && ( diff --git a/lib/oki-api.js b/lib/oki-api.js index 4a976e6..59f18cd 100644 --- a/lib/oki-api.js +++ b/lib/oki-api.js @@ -42,6 +42,9 @@ export async function jwennTeksEpiSlug(slug) { couverture: { populate: '*' }, + files: { + populate: '*' + }, artistes: { fields: ['alias', 'slug', 'musicBrainzUrl', 'photo'], populate: { diff --git a/package.json b/package.json index b0409af..6bc59ce 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "date-fns": "^2.16.1", "dotenv": "^16.0.0", "express": "^4.17.1", + "file-saver": "^2.0.5", "lodash": "^4.17.21", "next": "^14.1.4", "next-auth": "^4.22.1", diff --git a/yarn.lock b/yarn.lock index 9dc6eec..87ea8c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4631,6 +4631,11 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-saver@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" + integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA== + filelist@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b"