Files
VoiceRSSSummary/frontend/src/components/EpisodePlayer.tsx

80 lines
2.3 KiB
TypeScript

import { useEffect, useState } from "react";
interface Episode {
id: string;
title: string;
pubDate: string;
audioPath: string;
sourceLink: string;
}
export default function EpisodePlayer() {
const [episodes, setEpisodes] = useState<Episode[]>([]);
const [selectedEpisode, setSelectedEpisode] = useState<Episode | null>(null);
const [audioUrl, setAudioUrl] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
fetchEpisodes();
}, []);
const fetchEpisodes = async () => {
try {
const response = await fetch("/api/episodes");
if (!response.ok) {
throw new Error("エピソードの取得に失敗しました");
}
const data = await response.json();
setEpisodes(data);
setLoading(false);
} catch (err) {
setError(err instanceof Error ? err.message : "エラーが発生しました");
setLoading(false);
}
};
const handlePlay = (episode: Episode) => {
setSelectedEpisode(episode);
setAudioUrl(`/podcast_audio/${episode.audioPath}`);
};
if (loading) return <div>...</div>;
if (error) return <div className="text-red-500">: {error}</div>;
return (
<div className="space-y-4">
<h3 className="text-lg font-medium"></h3>
<div className="space-y-2">
{episodes.map((episode) => (
<div
key={episode.id}
className="flex justify-between items-center p-2 hover:bg-gray-50 rounded"
>
<span>{episode.title}</span>
<button
onClick={() => handlePlay(episode)}
className="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600"
>
</button>
</div>
))}
</div>
{selectedEpisode && (
<div className="mt-6">
<h4 className="text-md font-semibold mb-2">
: {selectedEpisode.title}
</h4>
{audioUrl ? (
<audio src={audioUrl} controls className="w-full" />
) : (
<div>...</div>
)}
</div>
)}
</div>
);
}