Christmas Songs 🎄

Top player · Search · Filter · Drag to reorder · No refresh

Loading first song…

Add Your Song

]; let songs = []; let currentFilter = "All"; let currentVideoId = null; /* ELEMENTS */ const playerIframe = document.getElementById("player"); const currentTitleEl = document.getElementById("currentTitle"); const searchInput = document.getElementById("searchInput"); const openYTBtn = document.getElementById("openYTBtn"); const stopBtn = document.getElementById("stopBtn"); /* INIT */ function init() { let saved = localStorage.getItem(KEY); if (saved) { songs = JSON.parse(saved); } else { songs = defaultSongs; save(); } render(); // Auto-load first song if (songs.length > 0) { setPlayerToSong(songs[0], true); // autoplay=true } else { currentTitleEl.textContent = "Select a song to play."; } } /* SAVE */ function save() { localStorage.setItem(KEY, JSON.stringify(songs)); } /* BUILD EMBED URL */ function buildEmbedUrl(id, autoplay=true) { const params = new URLSearchParams({ autoplay: autoplay ? "1" : "0", rel: "0", modestbranding: "1" }); return `https://www.youtube.com/embed/${id}?${params.toString()}`; } /* SET PLAYER */ function setPlayerToSong(song, autoplay=true) { currentVideoId = song.id; playerIframe.src = buildEmbedUrl(song.id, autoplay); currentTitleEl.textContent = song.title; } /* OPEN ON YOUTUBE */ openYTBtn.addEventListener("click", () => { if (!currentVideoId) return; window.open("https://www.youtube.com/watch?v=" + currentVideoId, "_blank"); }); /* STOP BUTTON */ stopBtn.addEventListener("click", () => { playerIframe.src = ""; currentTitleEl.textContent = "Playback stopped. Select a song to play."; }); /* FILTER */ function setFilter(f) { currentFilter = f; document.querySelectorAll(".filter button").forEach(btn => btn.classList.remove("active") ); document.getElementById("f-" + f).classList.add("active"); render(); } /* RESTORE DEFAULTS (merges missing defaults, keeps custom) */ function restoreDefaults() { defaultSongs.forEach(d => { if (!songs.find(s => s.id === d.id)) { songs.unshift(d); } }); save(); render(); } /* EXTRACT ID */ function extractId(url) { const patterns = [/v=([^&]+)/, /youtu\.be\/([^?]+)/, /embed\/([^?]+)/]; for (let p of patterns) { const m = url.match(p); if (m) return m[1]; } return null; } /* ADD SONG */ function addSong() { const title = document.getElementById("songTitle").value.trim(); const url = document.getElementById("songUrl").value.trim(); const id = extractId(url); if (!title || !id) { alert("Invalid title or YouTube link."); return; } songs.push({ id, title, cat:"Custom" }); save(); render(); document.getElementById("songTitle").value = ""; document.getElementById("songUrl").value = ""; } /* DELETE SONG */ function deleteSong(index) { songs.splice(index, 1); save(); render(); // If current video was deleted, just leave player as-is (no reset required) } /* DRAG SORT */ let draggedIndex = null; function handleDragStart(e, index) { draggedIndex = index; e.target.classList.add("dragging"); } function handleDragEnd(e) { e.target.classList.remove("dragging"); } function handleDragOver(e, index) { e.preventDefault(); if (draggedIndex === null || draggedIndex === index) return; const draggedItem = songs[draggedIndex]; songs.splice(draggedIndex, 1); songs.splice(index, 0, draggedItem); draggedIndex = index; save(); render(); } /* RENDER PLAYLIST */ function render() { const grid = document.getElementById("songGrid"); grid.innerHTML = ""; const search = searchInput.value.toLowerCase(); const filtered = songs.filter(s => (currentFilter === "All" || s.cat === currentFilter) && s.title.toLowerCase().includes(search) ); filtered.forEach(s => { const realIndex = songs.indexOf(s); const card = document.createElement("div"); card.className = "card"; card.draggable = true; card.ondragstart = e => handleDragStart(e, realIndex); card.ondragend = handleDragEnd; card.ondragover = e => handleDragOver(e, realIndex); card.innerHTML = `
${s.title}
${s.title}
${s.cat}
`; // Click card → play in top player card.onclick = () => setPlayerToSong(s, true); grid.appendChild(card); }); } /* START */ init();