music-player / templates /index.html
prasanth.thangavel
Minor improvements
466bb96
<!DOCTYPE html>
<html>
<head>
<title>Music Player</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
--primary: #6200ee;
--surface: #fff;
--on-surface: #121212;
--accent: #03dac6;
--error: #b00020;
}
* {
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, system-ui, BlinkMacSystemFont;
//background: #fafafa;
color: var(--on-surface);
line-height: 1.5;
}
.sw-container {
padding: 0px;
max-width: 600px;
margin: 0 auto;
}
.sw-player {
background: var(--surface);
border-radius: 0px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
padding: 10px;
margin-bottom: 16px;
}
.sw-header {
font-size: 1.25rem;
font-weight: 600;
text-align: center;
margin-bottom: 20px;
}
.sw-audio {
width: 100%;
height: 48px;
margin: 16px 0;
}
.sw-btn-group {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin: 16px 0;
}
.sw-btn {
background: var(--primary);
color: white;
border: none;
border-radius: 24px;
padding: 12px 24px;
font-size: 0.9rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
touch-action: manipulation;
transition: transform 0.2s;
}
.sw-btn.active {
transform: scale(0.96);
background: #7722ff;
position: relative;
order: 2px solid var(--primary);
}
.sw-dropdown {
width: 100%;
padding: 12px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 1rem;
margin-bottom: 16px;
}
.sw-tracklist {
margin-top: 20px;
}
.sw-track {
padding: 16px;
margin: 8px 0;
border-radius: 12px;
background: #f5f5f5;
transition: background 0.2s;
font-size: 0.85rem; /* Added this line to reduce font size */
}
.sw-track.active {
background: #e8f5ff;
border-left: 4px solid var(--primary);
}
.sw-modal {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.6);
display: none;
align-items: center;
justify-content: center;
padding: 16px;
}
.sw-modal-content {
background: var(--surface);
width: 100%;
max-width: 400px;
border-radius: 16px;
padding: 24px;
}
.sw-input {
width: 100%;
padding: 12px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 1rem;
margin: 16px 0;
}
.sw-checkbox-list {
max-height: 300px;
overflow-y: auto;
margin: 16px 0;
border: 1px solid #e0e0e0;
border-radius: 12px;
}
.sw-checkbox-item {
padding: 12px 16px;
border-bottom: 1px solid #e0e0e0;
}
.sw-now-playing {
text-align: center;
font-size: 0.9rem;
color: #666;
margin-bottom: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sw-now-playing span {
font-weight: 500;
color: var(--primary);
}
@media (hover: hover) {
.sw-btn:hover {
background: #7722ff;
}
.sw-btn.active:hover {
background: #6200ee;
}
.sw-track {
padding: 20px;
}
</style>
</head>
<body>
<div class="sw-container">
<div class="sw-player">
<h1 class="sw-header">🎵 Music Player</h1>
<div class="sw-now-playing"><span id="swCurrentSong">No song selected</span></div>
<audio id="swAudio" class="sw-audio" controls preload="none" autoplay="false">
Your browser does not support audio playback.
</audio>
<div class="sw-btn-group">
<button class="sw-btn" onclick="swPrevious()">Previous</button>
<button class="sw-btn" onclick="swNext()">Next</button>
<button class="sw-btn" id="swLoopBtn" onclick="swToggleLoop()">🔁 Loop</button>
<button class="sw-btn" id="swShuffleBtn" onclick="swToggleShuffle()">🔀 Shuffle</button>
</div>
<select class="sw-dropdown" id="swPlaylistSelect" onchange="swChangePlaylist()">
<option value="all">All Songs</option>
</select>
<div class="sw-btn-group">
<button class="sw-btn" onclick="swShowPlaylistModal()">Create Playlist</button>
<button class="sw-btn" onclick="swDeletePlaylist()">Delete Playlist</button>
</div>
<!-- Rendered by the JavaScript swUpdateTracks() -->
<div class="sw-tracklist"></div>
</div>
</div>
<div class="sw-modal" id="swPlaylistModal">
<div class="sw-modal-content">
<h2>Create New Playlist</h2>
<input type="text" class="sw-input" id="swPlaylistName" placeholder="Playlist Name">
<div class="sw-checkbox-list" id="swSongCheckboxes"></div>
<div class="sw-btn-group">
<button class="sw-btn" onclick="swCreatePlaylist()">Save</button>
<button class="sw-btn" onclick="swCloseModal()">Cancel</button>
</div>
</div>
</div>
<script>
const swAudio = document.getElementById('swAudio');
swAudio.addEventListener('ended', swNext);
const swTracks = {{ audio_files|tojson|safe }};
let swCurrentIndex = 0;
function swPlay(file) {
const currentPlaylistTracks = swGetCurrentTracks();
const idx = currentPlaylistTracks.indexOf(file);
if (idx < 0) {
console.error("File not found in current playlist:", file);
return;
}
swCurrentIndex = idx;
swAudio.src = `/audio/${file}`;
swAudio.play();
document.getElementById('swCurrentSong').textContent = file;
swUpdateTracks();
}
function swNext() {
const currentPlaylistTracks = swGetCurrentTracks();
if (swIsShuffling) {
const currentShuffleIndex = swShuffledIndices.indexOf(swCurrentIndex);
if (currentShuffleIndex < swShuffledIndices.length - 1) {
swCurrentIndex = swShuffledIndices[currentShuffleIndex + 1];
swPlay(currentPlaylistTracks[swCurrentIndex]);
} else if (swIsLooping) {
generateShuffledIndices();
swCurrentIndex = swShuffledIndices[0];
swPlay(currentPlaylistTracks[swCurrentIndex]);
}
} else {
if (swCurrentIndex < currentPlaylistTracks.length - 1) {
swCurrentIndex++;
swPlay(currentPlaylistTracks[swCurrentIndex]);
} else if (swIsLooping) {
swCurrentIndex = 0;
swPlay(currentPlaylistTracks[swCurrentIndex]);
}
}
}
function swPrevious() {
const currentPlaylistTracks = swGetCurrentTracks();
if (swCurrentIndex > 0) {
swCurrentIndex--;
swPlay(currentPlaylistTracks[swCurrentIndex]);
}
}
function swLoadPlaylists() {
const select = document.getElementById('swPlaylistSelect');
select.innerHTML = '<option value="all">All Songs</option>';
Object.keys(swPlaylists).forEach(name => {
select.innerHTML += `<option value="${name}">${name}</option>`;
});
}
function swShowPlaylistModal() {
const modal = document.getElementById('swPlaylistModal');
const checkboxes = document.getElementById('swSongCheckboxes');
checkboxes.innerHTML = swTracks.map(song =>
`<div class="sw-checkbox-item">
<input type="checkbox" id="${song}" value="${song}">
<label for="${song}">${song}</label>
</div>`
).join('');
modal.style.display = 'flex';
}
function swCloseModal() {
document.getElementById('swPlaylistModal').style.display = 'none';
}
function swCreatePlaylist() {
const name = document.getElementById('swPlaylistName').value;
if (!name) return alert('Please enter playlist name');
const songs = Array.from(document.querySelectorAll('#swSongCheckboxes input:checked'))
.map(cb => cb.value);
if (!songs.length) return alert('Select at least one song');
swPlaylists[name] = songs;
localStorage.setItem('swPlaylists', JSON.stringify(swPlaylists));
swLoadPlaylists();
swCloseModal();
}
function swChangePlaylist() {
swCurrentPlaylist = document.getElementById('swPlaylistSelect').value;
swCurrentIndex = 0;
if (swIsShuffling) {
generateShuffledIndices();
}
swUpdateTracks();
if (swGetCurrentTracks().length > 0) {
swPlay(swGetCurrentTracks()[0]);
}
}
function swDeletePlaylist() {
if (swCurrentPlaylist === 'all') return;
delete swPlaylists[swCurrentPlaylist];
localStorage.setItem('swPlaylists', JSON.stringify(swPlaylists));
swCurrentPlaylist = 'all';
swLoadPlaylists();
swChangePlaylist();
}
function swGetCurrentTracks() {
return swCurrentPlaylist === 'all' ? swTracks : swPlaylists[swCurrentPlaylist];
}
function swUpdateTracks() {
const tracks = swGetCurrentTracks();
const trackList = document.querySelector('.sw-tracklist');
trackList.innerHTML = tracks.map((file, i) =>
`<div class="sw-track ${i === swCurrentIndex ? 'active' : ''}" onclick="swPlay('${file}')">
${file}
</div>`
).join('');
}
const swPlaylists = JSON.parse(localStorage.getItem('swPlaylists') || '{}');
let swCurrentPlaylist = 'all';
document.addEventListener('DOMContentLoaded', function() {
swLoadPlaylists();
swUpdateTracks();
if (swTracks.length > 0) {
swPlay(swTracks[0]);
} else {
document.getElementById('swCurrentSong').textContent = 'No song selected';
}
const audioElements = document.getElementsByTagName('audio');
for (let audio of audioElements) {
audio.autoplay = false;
audio.pause();
audio.currentTime = 0;
}
});
// State variables
let swIsLooping = false;
let swIsShuffling = false;
let swShuffledIndices = [];
// Load saved preferences
document.addEventListener('DOMContentLoaded', function() {
// ... existing code ...
swIsLooping = JSON.parse(localStorage.getItem('swIsLooping') || 'false');
swIsShuffling = JSON.parse(localStorage.getItem('swIsShuffling') || 'false');
updateControlButtons();
});
function swToggleLoop() {
swIsLooping = !swIsLooping;
localStorage.setItem('swIsLooping', swIsLooping);
updateControlButtons();
}
function swToggleShuffle() {
swIsShuffling = !swIsShuffling;
localStorage.setItem('swIsShuffling', swIsShuffling);
if (swIsShuffling) {
generateShuffledIndices();
}
updateControlButtons();
}
function updateControlButtons() {
document.getElementById('swLoopBtn').classList.toggle('active', swIsLooping);
document.getElementById('swShuffleBtn').classList.toggle('active', swIsShuffling);
}
function generateShuffledIndices() {
const tracks = swGetCurrentTracks();
swShuffledIndices = Array.from({length: tracks.length}, (_, i) => i);
// Fisher-Yates shuffle
for (let i = swShuffledIndices.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[swShuffledIndices[i], swShuffledIndices[j]] = [swShuffledIndices[j], swShuffledIndices[i]];
}
}
</script>
</body>
</html>