Feat: handle decode errors (#425)

* show decode error

* handle loading error in post audio/recording

* tweak

* upgrade deps

* fix logout

* update build-enjoy-app.yml
This commit is contained in:
an-lee
2024-03-18 18:53:16 +08:00
committed by GitHub
parent 251eada86b
commit 3b770eaf3e
11 changed files with 441 additions and 100 deletions

View File

@@ -14,6 +14,8 @@ import {
} from "@vidstack/react/player/layouts/default";
export const STORAGE_WORKER_ENDPOINT = "https://enjoy-storage.baizhiheizi.com";
import { TimelineEntry } from "echogarden/dist/utilities/Timeline.d.js";
import { t } from "i18next";
import { XCircleIcon } from "lucide-react";
export const PostAudio = (props: {
audio: Partial<MediumType>;
@@ -23,6 +25,7 @@ export const PostAudio = (props: {
const [currentTime, setCurrentTime] = useState<number>(0);
const { webApi } = useContext(AppSettingsProviderContext);
const [transcription, setTranscription] = useState<TranscriptionType>();
const [error, setError] = useState<string>(null);
const currentTranscription = transcription?.result["transcript"]
? (transcription.result?.timeline || []).find(
@@ -45,6 +48,22 @@ export const PostAudio = (props: {
});
}, [audio.md5]);
if (error) {
return (
<div className="w-full rounded-lg p-4 border">
<div className="flex items-center justify-center mb-2">
<XCircleIcon className="w-4 h-4 text-destructive" />
</div>
<div className="select-text break-all text-center text-sm text-muted-foreground mb-4">
{error}
</div>
<div className="flex items-center justify-center">
<Button onClick={() => setError(null)}>{t("retry")}</Button>
</div>
</div>
);
}
return (
<div className="w-full">
{audio.sourceUrl.startsWith(STORAGE_WORKER_ENDPOINT) ? (
@@ -53,6 +72,7 @@ export const PostAudio = (props: {
setCurrentTime={setCurrentTime}
audio={audio}
height={height}
onError={(err) => setError(err.message)}
/>
) : (
<MediaPlayer
@@ -60,6 +80,7 @@ export const PostAudio = (props: {
setCurrentTime(_currentTime);
}}
src={audio.sourceUrl}
onError={(err) => setError(err.message)}
>
<MediaProvider />
<DefaultAudioLayout icons={defaultLayoutIcons} />
@@ -88,8 +109,9 @@ const WavesurferPlayer = (props: {
height?: number;
currentTime: number;
setCurrentTime: (currentTime: number) => void;
onError?: (error: Error) => void;
}) => {
const { audio, height = 80, currentTime, setCurrentTime } = props;
const { audio, height = 80, onError, setCurrentTime } = props;
const [initialized, setInitialized] = useState(false);
const [isPlaying, setIsPlaying] = useState(false);
const [wavesurfer, setWavesurfer] = useState(null);
@@ -162,6 +184,9 @@ const WavesurferPlayer = (props: {
}, 1000);
setInitialized(true);
}),
wavesurfer.on("error", (err: Error) => {
onError(err);
}),
];
return () => {

View File

@@ -6,6 +6,8 @@ import { Button, Skeleton } from "@renderer/components/ui";
import { PlayIcon, PauseIcon } from "lucide-react";
import { useIntersectionObserver } from "@uidotdev/usehooks";
import { secondsToTimestamp } from "@renderer/lib/utils";
import { t } from "i18next";
import { XCircleIcon } from "lucide-react";
export const PostRecording = (props: {
recording: RecordingType;
@@ -20,6 +22,7 @@ export const PostRecording = (props: {
threshold: 1,
});
const [duration, setDuration] = useState<number>(0);
const [error, setError] = useState<string>(null);
const onPlayClick = useCallback(() => {
wavesurfer.isPlaying() ? wavesurfer.pause() : wavesurfer.play();
@@ -31,6 +34,7 @@ export const PostRecording = (props: {
if (!entry?.isIntersecting) return;
if (!recording.src) return;
if (wavesurfer) return;
if (error) return;
const ws = WaveSurfer.create({
container: containerRef.current,
@@ -48,7 +52,11 @@ export const PostRecording = (props: {
});
setWavesurfer(ws);
}, [recording.src, entry]);
return () => {
setWavesurfer(null);
};
}, [recording.src, entry, error]);
useEffect(() => {
if (!wavesurfer) return;
@@ -84,6 +92,9 @@ export const PostRecording = (props: {
}, 1000);
setInitialized(true);
}),
wavesurfer.on("error", (err: Error) => {
setError(err.message);
}),
];
return () => {
@@ -92,6 +103,22 @@ export const PostRecording = (props: {
};
}, [wavesurfer]);
if (error) {
return (
<div className="w-full bg-sky-500/30 rounded-lg p-4 border">
<div className="flex items-center justify-center mb-2">
<XCircleIcon className="w-4 h-4 text-destructive" />
</div>
<div className="select-text break-all text-center text-sm text-muted-foreground mb-4">
{error}
</div>
<div className="flex items-center justify-center">
<Button onClick={() => setError(null)}>{t("retry")}</Button>
</div>
</div>
);
}
return (
<div className="w-full">
<div className="flex justify-end">