Add the html file, basic socketio structure
This commit is contained in:
parent
9bcf3ddb60
commit
a1ee1d9a8d
4
main1.py
4
main1.py
@ -19,6 +19,10 @@ music_directory = os.path.expanduser('~/Music') # Adjust path as necessary
|
||||
def index():
|
||||
return render_template('manage1.html')
|
||||
|
||||
@app.route('/admin')
|
||||
def index():
|
||||
return render_template('manage1.html')
|
||||
|
||||
@app.route('/display')
|
||||
def display():
|
||||
return render_template('display1.html')
|
||||
|
||||
72
main3.py
Normal file
72
main3.py
Normal file
@ -0,0 +1,72 @@
|
||||
from flask import Flask, render_template
|
||||
from flask_socketio import SocketIO, emit
|
||||
from flask_cors import CORS
|
||||
import yt_dlp
|
||||
import vlc
|
||||
import time
|
||||
import os
|
||||
import eyed3
|
||||
|
||||
home_directory = os.path.expanduser("~")
|
||||
#app = Flask(__name__,template_folder=home_directory)
|
||||
app = Flask(__name__, template_folder=(home_directory + "/Code/GR/GR-Jukebox"))
|
||||
socketio = SocketIO(app, cors_allowed_origins="*")
|
||||
CORS(app)
|
||||
player = vlc.MediaPlayer()
|
||||
music_queue = []
|
||||
title_queue = []
|
||||
music_directory = os.path.expanduser('~/Music')
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('manage1.html')
|
||||
|
||||
@app.route('/display')
|
||||
def display():
|
||||
return render_template('display1.html')
|
||||
|
||||
@socketio.on('list_music')
|
||||
def list_music():
|
||||
music_files = []
|
||||
for filename in os.listdir(music_directory):
|
||||
if filename.endswith('.mp3'):
|
||||
path = os.path.join(music_directory, filename)
|
||||
audiofile = eyed3.load(path)
|
||||
title = audiofile.tag.title if audiofile.tag else 'Unknown Title'
|
||||
music_files.append({'id': filename.split('.')[0], 'title': title})
|
||||
emit('music_list', music_files)
|
||||
|
||||
@socketio.on('download')
|
||||
def download(data):
|
||||
url = data['youtube_url']
|
||||
# ... existing download logic ...
|
||||
emit('download_status', {'status': 'success', 'message': 'Song added successfully'})
|
||||
|
||||
@socketio.on('play')
|
||||
def play(data):
|
||||
global playing_thread
|
||||
music_queue.append(data['songId'])
|
||||
title_queue.append(data['songTitle'])
|
||||
if not playing_thread:
|
||||
# ... existing play logic ...
|
||||
emit('play_status', {'status': 'success', 'message': 'Playing song'})
|
||||
|
||||
@socketio.on('get_queue')
|
||||
def get_queue():
|
||||
emit('queue', [{'id': idx, 'title': title} for idx, title in enumerate(title_queue)])
|
||||
|
||||
@socketio.on('remove_from_queue')
|
||||
def remove_from_queue(data):
|
||||
song_id = int(data['songId'])
|
||||
# ... existing remove logic ...
|
||||
emit('remove_status', {'status': 'success', 'message': 'Song removed successfully'})
|
||||
|
||||
@socketio.on('current')
|
||||
def current():
|
||||
if len(title_queue) > 0:
|
||||
emit('current_song', {'title': title_queue[0]})
|
||||
else:
|
||||
emit('current_song', {'title': 'Nothing is playing'})
|
||||
|
||||
if __name__ == "__main__":
|
||||
socketio.run(app, host='0.0.0.0', debug=True, port=5000)
|
||||
890
music-dashboard.html
Normal file
890
music-dashboard.html
Normal file
@ -0,0 +1,890 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Legendary Music Player</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #121212;
|
||||
color: #ffffff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.music-player {
|
||||
width: 90%;
|
||||
max-width: 1200px;
|
||||
background-color: #1f1f1f;
|
||||
border-radius: 15px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.top-panel {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
background-color: #292929;
|
||||
border-bottom: 1px solid #444;
|
||||
}
|
||||
|
||||
.top-panel input[type="text"] {
|
||||
flex-grow: 1;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.top-panel button {
|
||||
padding: 12px 25px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
background-color: #f1c40f;
|
||||
color: #121212;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.top-panel button:hover {
|
||||
background-color: #e1b308;
|
||||
}
|
||||
|
||||
.top-panel button::after {
|
||||
content: attr(data-tooltip);
|
||||
position: absolute;
|
||||
bottom: -30px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
color: #fff;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.top-panel button:hover::after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.nav-panel {
|
||||
width: 25%;
|
||||
background-color: #212121;
|
||||
padding: 20px;
|
||||
border-right: 1px solid #444;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nav-panel .nav-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.nav-panel .nav-bar button {
|
||||
flex: 1;
|
||||
margin: 0 5px;
|
||||
padding: 12px 0;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
background-color: #f1c40f;
|
||||
color: #121212;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-panel .nav-bar button:hover {
|
||||
background-color: #e1b308;
|
||||
}
|
||||
|
||||
.nav-panel .search-bar {
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.nav-panel .music-list {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.nav-panel .music-list ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav-panel .music-list li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #444;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.nav-panel .music-list li:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.nav-panel .music-list li .music-title {
|
||||
flex-grow: 1;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-panel .music-list li .delete-button {
|
||||
margin-left: 10px;
|
||||
font-size: 16px;
|
||||
color: #f1c40f;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content-panel {
|
||||
width: 75%;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.content-panel .current-song {
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.content-panel .current-song h2 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.content-panel .current-song p {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
color: #f1c40f;
|
||||
}
|
||||
|
||||
.content-panel .current-song img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
border-radius: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.content-panel .queue {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-panel .queue h3 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.content-panel .queue ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-panel .queue li {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #444;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
cursor: pointer;
|
||||
background-color: #2a2a2a;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.content-panel .queue li:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.content-panel .queue li.active {
|
||||
background-color: #444;
|
||||
color: #f1c40f;
|
||||
}
|
||||
|
||||
.content-panel .queue li .song-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.content-panel .queue li .song-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.content-panel .queue li .song-artist {
|
||||
font-size: 14px;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.content-panel .queue li .buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.content-panel .queue li .play-button,
|
||||
.content-panel .queue li .delete-button {
|
||||
font-size: 16px;
|
||||
color: #f1c40f;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.player-controls {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.player-controls button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #f1c40f;
|
||||
font-size: 24px;
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.player-controls button:hover {
|
||||
color: #e1b308;
|
||||
}
|
||||
|
||||
.player-controls button.active {
|
||||
color: #e1b308;
|
||||
}
|
||||
|
||||
.player-controls button::after {
|
||||
content: attr(data-tooltip);
|
||||
position: absolute;
|
||||
bottom: -30px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
color: #fff;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
display: none;
|
||||
z-index: 1269;
|
||||
}
|
||||
|
||||
.player-controls button:hover::after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.seek-bar {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.seek-bar .progress-bar {
|
||||
width: 100%;
|
||||
height: 12.69px;
|
||||
background: #333;
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.seek-bar .progress {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #f1c40f, #e1b308);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 15px rgba(241, 196, 15, 0.7);
|
||||
}
|
||||
|
||||
.seek-bar .thumb {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: linear-gradient(90deg, #ffd119, #e1b308);
|
||||
border-radius: 50%;
|
||||
border: 2px solid #121212;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 15px rgba(255, 209, 25, 0.7);
|
||||
}
|
||||
|
||||
.song-duration {
|
||||
font-size: 14px;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
border-radius: 10px;
|
||||
background-color: #212121;
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
|
||||
.queue-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 400px;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.queue-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 300px;
|
||||
height: 12.69rem;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
margin-top: -0.869rem;
|
||||
}
|
||||
|
||||
.spark {
|
||||
position: absolute;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: #ffd119;
|
||||
border-radius: 50%;
|
||||
animation: spark 0.5s linear infinite;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes spark {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate(50px, -50px);
|
||||
}
|
||||
}
|
||||
|
||||
.spark-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.spark-container.active .spark {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.spark-container .spark {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="music-player" id="music-player">
|
||||
<div class="top-panel">
|
||||
<input type="text" id="youtube-url" placeholder="Add song from YouTube URL" />
|
||||
<button onclick="addSongFromURL()" data-tooltip="Add song from YouTube URL">Add</button>
|
||||
<input type="file" id="audio-upload" style="display: none;" accept="audio/*" />
|
||||
<button onclick="document.getElementById('audio-upload').click()" data-tooltip="Upload an audio file">Upload</button>
|
||||
</div>
|
||||
<div class="main-content">
|
||||
<div class="nav-panel">
|
||||
<div class="nav-bar">
|
||||
<button onclick="showAllMusic()">All Music</button>
|
||||
<button onclick="showPlaylists()">Playlists</button>
|
||||
</div>
|
||||
<input type="text" class="search-bar" placeholder="Search..." oninput="searchMusic(event)" />
|
||||
<div class="music-list">
|
||||
<ul id="music-list">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-panel">
|
||||
<div class="current-song">
|
||||
<h2>Currently Playing</h2>
|
||||
<p id="current-song-title">No song playing</p>
|
||||
<img id="current-song-image" src="" alt="" style="display: none;" />
|
||||
</div>
|
||||
<canvas id="visualizer"></canvas>
|
||||
<div class="player-controls">
|
||||
<button onclick="prevSong()" data-tooltip="Previous song"><i class="fas fa-backward"></i></button>
|
||||
<button onclick="rewindSong()" data-tooltip="Rewind song"><i class="fas fa-undo"></i></button>
|
||||
<button onclick="togglePlayPause()" data-tooltip="Play/Pause"><i id="play-pause-icon" class="fas fa-play"></i></button>
|
||||
<button onclick="nextSong()" data-tooltip="Next song"><i class="fas fa-forward"></i></button>
|
||||
<div id="repeat-container" class="spark-container">
|
||||
<button onclick="toggleRepeat()" id="repeat-button" data-tooltip="Repeat"><i id="repeat-icon" class="fas fa-redo"></i></button>
|
||||
<div class="spark"></div>
|
||||
<div class="spark"></div>
|
||||
<div class="spark"></div>
|
||||
<div class="spark"></div>
|
||||
<div class="spark"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="seek-bar">
|
||||
<span id="current-time" class="song-duration">0:00</span>
|
||||
<div class="progress-bar" id="progress-bar" onclick="seekTo(event)">
|
||||
<div class="progress" id="progress"></div>
|
||||
<div class="thumb" id="thumb"></div>
|
||||
</div>
|
||||
<span id="total-duration" class="song-duration">0:00</span>
|
||||
</div>
|
||||
<div class="queue-container">
|
||||
<h3>Queue</h3>
|
||||
|
||||
<div class="queue-view">
|
||||
<div class="queue">
|
||||
<ul id="queue-list">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<audio id="audio-player" style="display: none;" ontimeupdate="updateSeekBar()" onloadedmetadata="updateDuration()">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let queue = [];
|
||||
let currentIndex = 0;
|
||||
let isPlaying = false;
|
||||
let isRepeating = false;
|
||||
let isDragging = false;
|
||||
|
||||
const audioContext = new(window.AudioContext || window.webkitAudioContext)();
|
||||
const audioPlayer = document.getElementById('audio-player');
|
||||
const analyser = audioContext.createAnalyser();
|
||||
const source = audioContext.createMediaElementSource(audioPlayer);
|
||||
source.connect(analyser);
|
||||
analyser.connect(audioContext.destination);
|
||||
|
||||
const canvas = document.getElementById('visualizer');
|
||||
const canvasContext = canvas.getContext('2d');
|
||||
const musicPlayer = document.getElementById('music-player');
|
||||
analyser.fftSize = 256;
|
||||
const bufferLength = analyser.frequencyBinCount;
|
||||
const dataArray = new Uint8Array(bufferLength);
|
||||
|
||||
function drawVisualizer() {
|
||||
requestAnimationFrame(drawVisualizer);
|
||||
analyser.getByteFrequencyData(dataArray);
|
||||
|
||||
canvasContext.fillStyle = '#212121';
|
||||
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const barWidth = (canvas.width / bufferLength) * 2.5;
|
||||
let barHeight;
|
||||
let x = 0;
|
||||
|
||||
for (let i = 0; i < bufferLength; i++)
|
||||
{
|
||||
barHeight = dataArray[i];
|
||||
|
||||
canvasContext.fillStyle = 'rgba(241, 196, 15, 0.869)';
|
||||
canvasContext.fillRect(x, canvas.height - barHeight / 2, barWidth, barHeight / 2);
|
||||
|
||||
let colorIntensity = 255 - barHeight;
|
||||
let toneColor = `rgba(${colorIntensity}, ${colorIntensity * 0.569}, 15, 0.369)`;
|
||||
canvasContext.fillStyle = toneColor;
|
||||
canvasContext.fillRect(x, canvas.height - barHeight / 2, barWidth, barHeight / 2);
|
||||
|
||||
x += barWidth + 1;
|
||||
}
|
||||
}
|
||||
|
||||
function addSongFromURL() {
|
||||
const url = document.getElementById('youtube-url').value;
|
||||
if (url) {
|
||||
queue.push({
|
||||
title: `Song ${queue.length + 1}`,
|
||||
artist: 'Artist',
|
||||
url,
|
||||
image: ''
|
||||
});
|
||||
updateQueue();
|
||||
document.getElementById('youtube-url').value = '';
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('audio-upload').addEventListener('change', function(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
const url = URL.createObjectURL(file);
|
||||
queue.push({
|
||||
title: file.name,
|
||||
artist: 'Uploaded File',
|
||||
url
|
||||
});
|
||||
updateQueue();
|
||||
}
|
||||
});
|
||||
|
||||
function updateQueue() {
|
||||
const queueList = document.getElementById('queue-list');
|
||||
queueList.innerHTML = '';
|
||||
queue.forEach((song, index) => {
|
||||
const li = document.createElement('li');
|
||||
li.classList.toggle('active', index === currentIndex);
|
||||
li.innerHTML = `
|
||||
<div class="song-info">
|
||||
<span class="song-title">${song.title}</span>
|
||||
<span class="song-artist">${song.artist}</span>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<span class="play-button" onclick="playSong(${index})"><i class="fas fa-play"></i></span>
|
||||
<span class="delete-button" onclick="deleteSong(${index})"><i class="fas fa-trash"></i></span>
|
||||
</div>
|
||||
`;
|
||||
queueList.appendChild(li);
|
||||
});
|
||||
makeQueueSortable();
|
||||
}
|
||||
|
||||
function makeQueueSortable() {
|
||||
Sortable.create(document.getElementById('queue-list'), {
|
||||
onEnd: function(evt) {
|
||||
const [movedItem] = queue.splice(evt.oldIndex, 1);
|
||||
queue.splice(evt.newIndex, 0, movedItem);
|
||||
updateQueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function playSong(index) {
|
||||
currentIndex = index;
|
||||
const currentSong = queue[index];
|
||||
document.getElementById('current-song-title').textContent = `${currentSong.title} - ${currentSong.artist}`;
|
||||
audioPlayer.src = currentSong.url;
|
||||
audioPlayer.style.display = 'none';
|
||||
audioPlayer.play().then(() => {
|
||||
audioContext.resume();
|
||||
});
|
||||
isPlaying = true;
|
||||
updatePlayPauseIcon();
|
||||
updateQueue();
|
||||
resetSeekBar();
|
||||
if (currentSong.image) {
|
||||
document.getElementById('current-song-image').src = currentSong.image;
|
||||
document.getElementById('current-song-image').style.display = 'block';
|
||||
} else {
|
||||
document.getElementById('current-song-image').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function deleteSong(index) {
|
||||
queue.splice(index, 1);
|
||||
if (index === currentIndex && queue.length > 0) {
|
||||
currentIndex = (index === queue.length) ? index - 1 : index;
|
||||
playSong(currentIndex);
|
||||
} else if (queue.length === 0) {
|
||||
document.getElementById('current-song-title').textContent = 'No song playing';
|
||||
document.getElementById('current-song-image').style.display = 'none';
|
||||
isPlaying = false;
|
||||
updatePlayPauseIcon();
|
||||
resetSeekBar();
|
||||
}
|
||||
updateQueue();
|
||||
}
|
||||
|
||||
function togglePlayPause() {
|
||||
if (isPlaying) {
|
||||
audioPlayer.pause();
|
||||
isPlaying = false;
|
||||
} else {
|
||||
if (queue.length > 0 && audioPlayer.src === "") {
|
||||
playSong(currentIndex);
|
||||
} else {
|
||||
audioPlayer.play().then(() => {
|
||||
audioContext.resume();
|
||||
});
|
||||
}
|
||||
isPlaying = true;
|
||||
}
|
||||
updatePlayPauseIcon();
|
||||
}
|
||||
|
||||
function updatePlayPauseIcon() {
|
||||
const icon = document.getElementById('play-pause-icon');
|
||||
if (isPlaying) {
|
||||
icon.classList.remove('fa-play');
|
||||
icon.classList.add('fa-pause');
|
||||
} else {
|
||||
icon.classList.remove('fa-pause');
|
||||
icon.classList.add('fa-play');
|
||||
}
|
||||
}
|
||||
|
||||
function prevSong() {
|
||||
currentIndex = (currentIndex > 0) ? currentIndex - 1 : queue.length - 1;
|
||||
playSong(currentIndex);
|
||||
}
|
||||
|
||||
function nextSong() {
|
||||
currentIndex = (currentIndex < queue.length - 1) ? currentIndex + 1 : 0;
|
||||
playSong(currentIndex);
|
||||
}
|
||||
|
||||
function rewindSong() {
|
||||
audioPlayer.currentTime = 0;
|
||||
}
|
||||
|
||||
function toggleRepeat() {
|
||||
isRepeating = !isRepeating;
|
||||
const icon = document.getElementById('repeat-icon');
|
||||
const button = document.getElementById('repeat-button');
|
||||
const container = document.getElementById('repeat-container');
|
||||
if (isRepeating) {
|
||||
icon.classList.add('active');
|
||||
button.classList.add('active');
|
||||
container.classList.add('active');
|
||||
startSparks();
|
||||
} else {
|
||||
icon.classList.remove('active');
|
||||
button.classList.remove('active');
|
||||
container.classList.remove('active');
|
||||
stopSparks();
|
||||
}
|
||||
}
|
||||
|
||||
function startSparks() {
|
||||
document.querySelectorAll('.spark').forEach(spark => {
|
||||
spark.style.animation = `spark 0.5s linear infinite`;
|
||||
});
|
||||
}
|
||||
|
||||
function stopSparks() {
|
||||
document.querySelectorAll('.spark').forEach(spark => {
|
||||
spark.style.animation = '';
|
||||
});
|
||||
}
|
||||
|
||||
function seekTo(event) {
|
||||
if (!isDragging) {
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const rect = progressBar.getBoundingClientRect();
|
||||
const offsetX = event.clientX - rect.left;
|
||||
const percentage = offsetX / progressBar.clientWidth;
|
||||
const seekTo = audioPlayer.duration * percentage;
|
||||
audioPlayer.currentTime = seekTo;
|
||||
}
|
||||
}
|
||||
|
||||
function startDrag() {
|
||||
isDragging = true;
|
||||
}
|
||||
|
||||
function stopDrag() {
|
||||
isDragging = false;
|
||||
}
|
||||
|
||||
function dragThumb(event) {
|
||||
if (isDragging) {
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const rect = progressBar.getBoundingClientRect();
|
||||
const offsetX = event.clientX - rect.left;
|
||||
const percentage = Math.min(Math.max(offsetX / progressBar.clientWidth, 0), 100);
|
||||
const seekTo = audioPlayer.duration * percentage;
|
||||
audioPlayer.currentTime = seekTo;
|
||||
}
|
||||
}
|
||||
|
||||
function updateSeekBar() {
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const progress = document.getElementById('progress');
|
||||
const thumb = document.getElementById('thumb');
|
||||
const value = (audioPlayer.currentTime / audioPlayer.duration) * 100;
|
||||
progress.style.width = `${value}%`;
|
||||
thumb.style.left = `${value}%`;
|
||||
|
||||
const currentMinutes = Math.floor(audioPlayer.currentTime / 60);
|
||||
const currentSeconds = Math.floor(audioPlayer.currentTime % 60);
|
||||
document.getElementById('current-time').textContent = `${currentMinutes}:${currentSeconds < 10 ? '0' : ''}${currentSeconds}`;
|
||||
}
|
||||
|
||||
function resetSeekBar() {
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const progress = document.getElementById('progress');
|
||||
const thumb = document.getElementById('thumb');
|
||||
progress.style.width = '0';
|
||||
thumb.style.left = '0';
|
||||
document.getElementById('current-time').textContent = '0:00';
|
||||
document.getElementById('total-duration').textContent = '0:00';
|
||||
}
|
||||
|
||||
function updateDuration() {
|
||||
const totalMinutes = Math.floor(audioPlayer.duration / 60);
|
||||
const totalSeconds = Math.floor(audioPlayer.duration % 60);
|
||||
document.getElementById('total-duration').textContent = `${totalMinutes}:${totalSeconds < 10 ? '0' : ''}${totalSeconds}`;
|
||||
}
|
||||
|
||||
function showAllMusic() {
|
||||
const musicList = document.getElementById('music-list');
|
||||
musicList.innerHTML = '';
|
||||
for (let i = 1; i <= 20; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = `
|
||||
<span class="music-title">All Music ${i}</span>
|
||||
<span class="delete-button" onclick="deleteMusicItem(this)"><i class="fas fa-trash"></i></span>
|
||||
`;
|
||||
musicList.appendChild(li);
|
||||
}
|
||||
}
|
||||
|
||||
function showPlaylists() {
|
||||
const musicList = document.getElementById('music-list');
|
||||
musicList.innerHTML = '';
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = `
|
||||
<span class="music-title">Playlist ${i}</span>
|
||||
<span class="delete-button" onclick="deleteMusicItem(this)"><i class="fas fa-trash"></i></span>
|
||||
`;
|
||||
musicList.appendChild(li);
|
||||
}
|
||||
}
|
||||
|
||||
function deleteMusicItem(element) {
|
||||
const listItem = element.closest('li');
|
||||
listItem.remove();
|
||||
}
|
||||
|
||||
function searchMusic(event) {
|
||||
const query = event.target.value.toLowerCase();
|
||||
const musicList = document.getElementById('music-list');
|
||||
const musicItems = musicList.getElementsByTagName('li');
|
||||
const queueList = document.getElementById('queue-list');
|
||||
const queueItems = queueList.getElementsByTagName('li');
|
||||
|
||||
for (let item of musicItems) {
|
||||
const text = item.textContent.toLowerCase();
|
||||
item.style.display = text.includes(query) ? '' : 'none';
|
||||
}
|
||||
|
||||
for (let item of queueItems) {
|
||||
const text = item.textContent.toLowerCase();
|
||||
item.style.display = text.includes(query) ? '' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function calculateTilt(element, event) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
const centerX = rect.width / 2;
|
||||
const centerY = rect.height / 2;
|
||||
const deltaX = (x - centerX) / centerX;
|
||||
const deltaY = (y - centerY) / centerY;
|
||||
return {
|
||||
rotateX: deltaY * -10,
|
||||
rotateY: deltaX * 10
|
||||
};
|
||||
}
|
||||
|
||||
canvas.addEventListener('mousemove', (event) => {
|
||||
const {
|
||||
rotateX,
|
||||
rotateY
|
||||
} = calculateTilt(canvas, event);
|
||||
canvas.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
|
||||
});
|
||||
|
||||
canvas.addEventListener('mouseleave', () => {
|
||||
canvas.style.transform = 'perspective(1000px) rotateX(0) rotateY(0)';
|
||||
});
|
||||
|
||||
musicPlayer.addEventListener('mousemove', (event) => {
|
||||
const {
|
||||
rotateX,
|
||||
rotateY
|
||||
} = calculateTilt(musicPlayer, event);
|
||||
musicPlayer.style.transform = `perspective(1000px) rotateX(${rotateX / 12.69}deg) rotateY(${rotateY / 12.69}deg)`;
|
||||
});
|
||||
|
||||
musicPlayer.addEventListener('mouseleave', () => {
|
||||
musicPlayer.style.transform = 'perspective(1000px) rotateX(0) rotateY(0)';
|
||||
});
|
||||
|
||||
audioPlayer.addEventListener('ended', function() {
|
||||
if (isRepeating) {
|
||||
playSong(currentIndex);
|
||||
} else {
|
||||
queue.splice(currentIndex, 1);
|
||||
if (queue.length > 0) {
|
||||
if (currentIndex >= queue.length) {
|
||||
currentIndex = 0;
|
||||
}
|
||||
playSong(currentIndex);
|
||||
} else {
|
||||
document.getElementById('current-song-title').textContent = 'No song playing';
|
||||
document.getElementById('current-song-image').style.display = 'none';
|
||||
isPlaying = false;
|
||||
updatePlayPauseIcon();
|
||||
updateQueue();
|
||||
resetSeekBar();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
drawVisualizer();
|
||||
makeQueueSortable();
|
||||
|
||||
const thumb = document.getElementById('thumb');
|
||||
thumb.addEventListener('mousedown', startDrag);
|
||||
document.addEventListener('mouseup', stopDrag);
|
||||
document.addEventListener('mousemove', dragThumb);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user