lmr
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsmediatags/3.9.5/jsmediatags.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="style.css" rel="stylesheet"/>
<div class="container">
<br>
<h1 class="text-center">local-music-repo</h1>
<p class="text-center">Select a folder with an artist's discography or an album tracklist in audio format:</p>
<div class="text-center mb-3">
<input type="file"
id="filePicker"
accept="audio/*"
multiple
webkitdirectory
directory>
</div>
<div class="text-center" id="status"></div>
<div class="playback-controls">
<button id="playAlbumBtn">Play Album</button>
<button id="stopPlaybackBtn">Stop</button>
<span id="currentAlbum"></span>
</div>
<div class="search-filters">
<input type="text" id="searchSong" placeholder="Search by song...">
<input type="text" id="searchArtist" placeholder="Search by artist...">
<input type="text" id="searchAlbum" placeholder="Search by album...">
<input type="number" id="searchDuration" placeholder="Duration (seconds)">
<button id="clearFilters">Clear Filters</button>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Artist</th>
<th scope="col">Album</th>
<th scope="col">Duration</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody id="songList">
</tbody>
</table>
</div>
<div id="nowPlayingBar" class="now-playing-bar">
<div class="now-playing-content">
<div class="now-playing-info">
<div class="album-art-placeholder" id="albumArtPlaceholder">
<span>♪</span>
</div>
<div class="song-info">
...
CSS
.row {
background: #f8f9fa;
margin-top: 20px;
}
.col {
border: solid 1px #6c757d;
padding: 10px;
}
.search-filters {
margin: 20px 0;
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
}
.search-filters input,
.search-filters button {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
}
.search-filters input {
min-width: 150px;
}
.media-player {
display: flex;
align-items: center;
gap: 10px;
}
.media-player audio {
width: 200px;
height: 40px;
}
.playback-controls {
text-align: center;
margin: 15px 0;
}
.playback-controls button {
margin: 0 5px;
padding: 8px 15px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.playback-controls button:hover {
background: #0056b3;
}
.playback-controls button:disabled {
background: #ccc;
cursor: not-allowed;
}
/* Now Playing Bar */
.now-playing-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #282828;
color: white;
padding: 10px 20px;
z-index: 1000;
display: none;
}
.now-playing-content {
display: flex;
align-items: center;
justify-content: space-between;
}
.now-playing-info {
display: flex;
align-items: center;
flex: 1;
}
.album-art-placeholder {
width: 56px;
height: 56px;
background: #404040;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
font-size: 24px;
}
.song-info {
display: flex;
flex-direction: column;
}
.song-title {
font-weight: bold;
margin-bottom: 4px;
}
.song-artist {
font-size: 14px;
color: #b3b3b3;
}
.playback-controls-main {
display: flex;
align-items: center;
gap: 15px;
}
.playback-controls-main button {
background: none;
border: none;
color: white;
font-size: 18px;
cursor: pointer;
width: 32px;
...
JavaScript
var dbName = 'lmr-26.7.2-test2';
var dbVersion = 1;
var db = null;
var allSongs = [];
var currentPlaylist = [];
var currentSongIndex = -1;
var audioContext = null;
var currentAudio = null;
var request = indexedDB.open(dbName, dbVersion);
request.onerror = function (event) {
console.error('IndexedDB error: ', event.target.error);
};
request.onupgradeneeded = function (event) {
var database = event.target.result;
if (!database.objectStoreNames.contains('Songs')) {
database.createObjectStore('Songs', { keyPath: 'id', autoIncrement: true });
}
if (!database.objectStoreNames.contains('Albums')) {
database.createObjectStore('Albums', {
keyPath: 'id',
autoIncrement: true,
});
}
};
request.onsuccess = function (event) {
db = event.target.result;
loadSongsFromDB();
document.getElementById('searchSong').addEventListener('input', filterSongs);
document
.getElementById('searchArtist')
.addEventListener('input', filterSongs);
document.getElementById('searchAlbum').addEventListener('input', filterSongs);
document
.getElementById('searchDuration')
.addEventListener('input', filterSongs);
document
.getElementById('clearFilters')
.addEventListener('click', clearFilters);
document.getElementById('playAlbumBtn').addEventListener('click', playAlbum);
document
.getElementById('stopPlaybackBtn')
.addEventListener('click', stopPlayback);
document
.getElementById('prevBtn')
.addEventListener('click', playPreviousSong);
document
.getElementById('playPauseBtn')
.addEventListener('click', togglePlayPause);
document.getElementById('nextBtn').addEventListener('click', playNextSong);
document.querySelector('.progress-bar').addEventListener('click', seekAudio);
};
document.addEventListener('DOMContentLoaded', function () {
const fileInput = document.getElementById('filePicker');
...