import { useEffect, useRef, useState } from "react"; import { ListMusic, Pause, Play } from "lucide-react"; import { useSite } from "@site/lib/site-context"; /** * 이 숙소의 노래 — 헤더의 작은 플레이어. * * ★ 무엇인가 · 무엇이 아닌가 * 발행할 때 이 숙소의 사실로 쓴 가사에 곡을 붙여 만든 노래다(백엔드 `song_service`). * 배경음악처럼 **저절로 틀지 않는다** — 손님이 누를 때만 난다. 자동 재생은 브라우저가 * 막기도 하거니와, 막지 않는 경우가 더 나쁘다(소리가 갑자기 나는 페이지는 닫힌다). * * ★ 곡이 없으면 아무것도 그리지 않는다. * 발행은 노래를 기다리므로 보통은 있다. 그래도 없을 수 있다 — 키가 없거나(SUNO_API_KEY), * 작곡이 실패하거나, 옛 버전으로 구운 사이트다. 그때 빈 플레이어를 그리면 손님에게는 * **고장난 버튼**이다. 없으면 없는 대로 둔다. * * ★ 가사를 함께 싣는다. * 무슨 노래인지 읽히지 않으면 아무도 누르지 않는다. 그리고 이 가사는 화면에 있는 편이 * 검색·AI 쪽에도 맞다 — 오디오 안의 말은 크롤러가 못 듣는다. * * ★ 패널은 조건부 렌더가 아니라 `hidden` 으로 여닫는다. * `{open && ...}` 로 두면 **닫힌 동안 곡 제목과 가사가 DOM 에 아예 없다.** 서버 렌더 결과가 * 곧 크롤러가 읽는 전부인데(정적 발행), 그러면 이 노래는 검색·AI 쪽에 존재하지 않는 것과 * 같아진다 — 오디오 안의 말은 크롤러가 못 듣기 때문에 가사가 유일한 단서다. * 그래서 markup 은 늘 있고, 보이고 안 보이고만 바뀐다. */ export function SongPlayer() { const payload = useSite(); const songs = payload.songs ?? []; const [open, setOpen] = useState(false); const [playing, setPlaying] = useState(null); const audioRef = useRef(null); // 페이지를 떠나거나 컴포넌트가 사라질 때 소리를 끊는다 — 리액트가 노드를 지워도 // 재생 중인 오디오는 계속 난다(브라우저가 소리를 DOM 과 함께 정리하지 않는다). useEffect(() => () => audioRef.current?.pause(), []); if (songs.length === 0) return null; const toggle = (songId: string, url: string) => { const audio = audioRef.current; if (!audio) return; if (playing === songId) { audio.pause(); setPlaying(null); return; } // 다른 곡을 누르면 하던 것을 끊고 갈아탄다. audio.src = url; // 재생은 거절될 수 있다(자동재생 정책·네트워크). 그때 '재생 중' 으로 표시해 두면 // 소리는 안 나는데 멈춤 버튼만 보인다 — 성공했을 때만 상태를 바꾼다. void audio.play().then( () => setPlaying(songId), () => setPlaying(null), ); }; // 가사는 **고른 곡**의 것을 보여준다. 아직 아무것도 안 눌렀으면(서버 렌더 포함) 첫 곡이다 — // 그래야 크롤러가 읽는 HTML 에도 가사가 들어간다. const current = songs.find((song) => song.songId === playing) ?? songs[0]; return (
{/* ★ 오디오 태그는 패널 밖에 둔다. 패널 안에 두면 목록을 닫는 순간 노드가 사라져 듣던 노래가 끊긴다 — 닫고 계속 듣는 것이 이 플레이어의 기본 사용법이다. ★ preload="none": 아무도 안 누를 수도 있는 파일을 모든 방문자에게 내려받게 하지 않는다. */} {/* ★ 첫 곡의 주소를 markup 에 박아 둔다. 누를 때 비로소 src 를 넣으면 **서버 렌더 결과에 오디오 주소가 한 글자도 없다** — 크롤러에게 이 페이지는 소리 없는 페이지다. preload="none" 이라 주소만 있고 받아 오지는 않는다. */}
); }