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');

 ...