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:
@@ -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 () => {
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user