diff --git a/components/previews/AudioPreview.tsx b/components/previews/AudioPreview.tsx index c76962a..1d44613 100644 --- a/components/previews/AudioPreview.tsx +++ b/components/previews/AudioPreview.tsx @@ -1,9 +1,10 @@ import type { OdFileObject } from '../../types' -import { FC, useState } from 'react' +import { FC, useEffect, useRef, useState } from 'react' import ReactAudioPlayer from 'react-audio-player' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { useTranslation } from 'next-i18next' +import { useRouter } from 'next/router' import DownloadButtonGroup from '../DownloadBtnGtoup' import { DownloadBtnContainer, PreviewContainer } from './Containers' @@ -18,40 +19,83 @@ enum PlayerState { } const AudioPreview: FC<{ file: OdFileObject }> = ({ file }) => { + const { t } = useTranslation() + const { asPath } = useRouter() + + const rapRef = useRef(null) const [playerStatus, setPlayerStatus] = useState(PlayerState.Loading) - const { t } = useTranslation() + // Render audio thumbnail, and also check for broken thumbnails + const thumbnail = `/api/thumbnail?path=${asPath}&size=medium` + const [brokenThumbnail, setBrokenThumbnail] = useState(false) + + useEffect(() => { + // Manually get the HTML audio element and set onplaying event. + // - As the default event callbacks provided by the React component does not guarantee playing state to be set + // - properly when the user seeks through the timeline or the audio is buffered. + const rap = (rapRef.current as ReactAudioPlayer).audioEl.current + if (rap) { + rap.oncanplay = () => setPlayerStatus(PlayerState.Ready) + rap.onended = () => setPlayerStatus(PlayerState.Paused) + rap.onpause = () => setPlayerStatus(PlayerState.Paused) + rap.onplay = () => setPlayerStatus(PlayerState.Playing) + rap.onplaying = () => setPlayerStatus(PlayerState.Playing) + rap.onseeking = () => setPlayerStatus(PlayerState.Loading) + rap.onwaiting = () => setPlayerStatus(PlayerState.Loading) + rap.onerror = () => setPlayerStatus(PlayerState.Paused) + } + }, []) return ( <>
-
- {playerStatus === PlayerState.Loading ? ( - +
+
+ +
+ + {!brokenThumbnail ? ( +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {file.name} setBrokenThumbnail(true)} + /> +
) : ( )}
-
-
{file.name}
-
- {t('Last modified:') + ' ' + formatModifiedDateTime(file.lastModifiedDateTime)} + +
+
+
{file.name}
+
+ {t('Last modified:') + ' ' + formatModifiedDateTime(file.lastModifiedDateTime)} +
setPlayerStatus(PlayerState.Ready)} - onPlay={() => setPlayerStatus(PlayerState.Playing)} - onPause={() => setPlayerStatus(PlayerState.Paused)} - onError={() => setPlayerStatus(PlayerState.Paused)} - onEnded={() => setPlayerStatus(PlayerState.Paused)} + preload="auto" />
diff --git a/tailwind.config.js b/tailwind.config.js index 2c01c61..82525b0 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -32,6 +32,9 @@ module.exports = { gray: { 850: '#222226' } + }, + animation: { + 'spin-slow': 'spin 5s linear infinite', } } },