<html lang="ko">
<head>
<meta charset="utf-8" />
<title>랜덤 음악 플레이어</title>
<style>
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto; padding: 24px; }
button { margin: 6px; padding: 8px 12px; }
.track { margin-top: 12px; }
</style>
</head>
<body>
<h1>랜덤 음악 플레이어</h1>
<div>
<button id="playBtn">재생</button>
<button id="pauseBtn">일시정지</button>
<button id="nextBtn">다음 (랜덤)</button>
<label><input type="checkbox" id="repeatChk">반복</label>
</div>
<div class="track">
현재 재생: <span id="now">-</span>
</div>
<!-- 오디오 엘리먼트 (보이지 않아도 됨) -->
<audio id="audio"></audio>
<script>
// 재생할 곡(파일 URL 또는 상대경로). 예: "music/song1.mp3"
const tracks = [
"https://www.example.com/audio/song1.mp3",
"https://www.example.com/audio/song2.mp3",
"https://www.example.com/audio/song3.mp3"
];
// DOM
const audio = document.getElementById("audio");
const playBtn = document.getElementById("playBtn");
const pauseBtn = document.getElementById("pauseBtn");
const nextBtn = document.getElementById("nextBtn");
const nowEl = document.getElementById("now");
const repeatChk = document.getElementById("repeatChk");
// 셔플 리스트와 인덱스 관리 (중복 없이 한 바퀴 돌고 다시 섞음)
let shuffled = [];
let idx = 0;
function shuffleArray(arr) {
// Fisher-Yates shuffle (original 배열을 변경하지 않음)
const a = arr.slice();
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
function resetShuffle() {
shuffled = shuffleArray(tracks);
idx = 0;
}
function playCurrent() {
if (!shuffled.length) resetShuffle();
const url = shuffled[idx];
audio.src = url;
audio.play().catch(err => {
console.warn("재생 실패(자동재생 차단 등):", err);
});
nowEl.textContent = getFilename(url);
}
function getFilename(url) {
try {
return new URL(url).pathname.split("/").pop();
} catch (e) {
return url;
}
}
function playNext() {
if (!shuffled.length) resetShuffle();
idx++;
if (idx >= shuffled.length) {
if (repeatChk.checked) {
resetShuffle();
} else {
// 재생 종료
idx = shuffled.length - 1;
audio.pause();
nowEl.textContent = "재생 종료";
return;
}
}
playCurrent();
}
// 이벤트: 트랙 끝나면 자동으로 다음 재생
audio.addEventListener("ended", () => {
playNext();
});
// 버튼 바인딩
playBtn.addEventListener("click", () => {
// 사용자 상호작용 보장 -> 브라우저가 play 허용
if (!shuffled.length) resetShuffle();
// 만약 audio.src가 비어있다면 현재 트랙 재생
if (!audio.src) {
playCurrent();
} else {
audio.play().catch(err => console.warn(err));
}
});
pauseBtn.addEventListener("click", () => {
audio.pause();
});
nextBtn.addEventListener("click", () => {
// 수동으로 다음곡 재생: 현재 인덱스 증가 후 재생
idx++;
if (idx >= shuffled.length) {
if (repeatChk.checked) resetShuffle();
else {
idx = shuffled.length - 1;
audio.pause();
nowEl.textContent = "마지막 곡";
return;
}
}
playCurrent();
});
// 페이지 로드 시 셔플 준비 (자동 재생은 하지 않음)
resetShuffle();
</script>
</body>
</html>