Initial migration

This commit is contained in:
Wesley Neuhaus 2024-08-06 20:52:02 -04:00
parent 21a9ec3cf2
commit 9bcf3ddb60
15 changed files with 1508 additions and 0 deletions

25
crontab_file.txt Normal file
View File

@ -0,0 +1,25 @@
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
@reboot $HOME/update.sh >> $HOME/logfile.log
@reboot sleep 10 && DISPLAY=:0 firefox --kiosk http://localhost:5000/display

112
display1.html Normal file
View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Now Playing</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 0;
background-color: #0f0f0f;
display: flex;
align-items: center;
height: 100vh;
margin: 0;
flex-direction: column;
}
h1 {
color: #999;
font-size: 5vw;
}
span{
color:#999;
font-size: 1vw;
margin: 1vw;
}
#now-playing {
font-size: 3vw;
color: #007bff;
}
.progress-container {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
height: 5vh;
width: 75vw;
}
.progress-bar {
width: 100%;
background-color: #eee;
height: 2vh;
border-radius: 1vh;
overflow: hidden;
}
.progress {
height: 2vh;
background-color: #007BFF;
width: 0%;
border-radius: 1vh;
transition: width 0.5s ease;
}
#album-art {
/*width: 200px; /* Adjust width as needed */
height: 20vh; /* Maintain aspect ratio */
width: auto;
border-radius: 1vh; /* Rounded corners */
margin-bottom: 1vh; /* Space between the image and text */
}
</style>
</head>
<body>
<h1>Now Playing</h1>
<img id="album-art" src="mao.jpg" alt="Album Art">
<div id="now-playing">Nothing is playing</div>
<h1></h1>
<div class="progress-container">
<span id="current-time">0:00</span>
<div class="progress-bar">
<div class="progress" id="progress" style="width: 0%;"></div>
</div>
<span id="duration">4:00</span>
</div>
<script>
function fetchNowPlaying() {
fetch('/current')
.then(response => response.json())
.then(data => {
document.getElementById('now-playing').textContent = data.title || 'Nothing is playing';
});
}
setInterval(fetchNowPlaying, 1000);
fetchNowPlaying();
function updateProgressBar(percentage) {
const progressBar = document.getElementById('progress');
progressBar.style.width = percentage + '%';
}
// Example: Update progress bar every second
setInterval(function() {
// This would be dynamic, typically set by the current play time over total duration
const currentTime = 60; // current time in seconds
const duration = 240; // total duration in seconds
const percentage = (currentTime / duration) * 100;
updateProgressBar(percentage);
// Update time display
document.getElementById('current-time').innerText = formatTime(currentTime);
document.getElementById('duration').innerText = formatTime(duration);
}, 1000);
function formatTime(seconds) {
const min = Math.floor(seconds / 60);
const sec = seconds % 60;
return `${min}:${sec < 10 ? '0' : ''}${sec}`;
}
</script>
</body>
</html>

112
display2.html Normal file
View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Now Playing</title>
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js">-->
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 0;
background-color: #0f0f0f;
display: flex;
align-items: center;
height: 100vh;
margin: 0;
flex-direction: column;
}
h1 {
color: #999;
font-size: 5vw;
}
span{
color:#999;
font-size: 1vw;
margin: 1vw;
}
#now-playing {
font-size: 3vw;
color: #007bff;
}
.progress-container {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
height: 5vh;
width: 75vw;
}
.progress-bar {
width: 100%;
background-color: #eee;
height: 2vh;
border-radius: 1vh;
overflow: hidden;
}
.progress {
height: 2vh;
background-color: #007BFF;
width: 0%;
border-radius: 1vh;
transition: width 0.5s ease;
}
#album-art {
height: 20vh;
width: auto;
border-radius: 1vh;
margin-bottom: 1vh;
}
</style>
</head>
<body>
<h1>Now Playing</h1>
<img id="album-art" src="mao.jpg">
<div id="now-playing">Nothing is playing</div>
<h1></h1>
<div class="progress-container">
<span id="current-time">0:00</span>
<div class="progress-bar">
<div class="progress" id="progress" style="width: 0%;"></div>
</div>
<span id="duration">4:00</span>
</div>
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
<script>
const socket = io(); // Connect to WebSocket server
socket.on('connect', function() {
console.log('Connected to WebSocket server!');
loadCurrent();
});
socket.on('current', function(data) {
console.log(data);
document.getElementById('now-playing').textContent = data.title || 'Nothing is playing';
});
socket.on('progress_update', function(data) {
updateProgressBar(data.percentage);
document.getElementById('current-time').innerText = formatTime(data.current_time);
document.getElementById('duration').innerText = formatTime(data.total_duration);
});
function updateProgressBar(percentage) {
const progressBar = document.getElementById('progress');
progressBar.style.width = percentage + '%';
}
function formatTime(seconds) {
const min = Math.floor(seconds / 60);
const sec = seconds % 60;
return `${min}:${sec < 10 ? '0' : ''}${sec}`;
}
function loadCurrent() {
socket.emit('current_song');
}
</script>
</body>
</html>

90
htmltest.html Normal file
View File

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Music Player</title>
<style>
.music-player {
width: 80%;
margin: auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.info, .progress-container {
display: flex;
align-items: center;
justify-content: space-between;
}
.progress-container {
position: relative;
height: 20px;
}
.progress-bar {
width: 100%;
background-color: #eee;
height: 8px;
border-radius: 4px;
overflow: hidden;
}
.progress {
height: 8px;
background-color: #007BFF;
width: 0%;
border-radius: 4px;
transition: width 0.5s ease;
}
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 20px;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<div class="music-player">
<div class="info">
<span id="song-title">Song Title</span>
</div>
<div class="progress-container">
<span id="current-time">0:00</span>
<div class="progress-bar">
<div class="progress" id="progress" style="width: 0%;"></div>
</div>
<span id="duration">4:00</span>
</div>
</div>
<script>
function updateProgressBar(percentage) {
const progressBar = document.getElementById('progress');
progressBar.style.width = percentage + '%';
}
// Example: Update progress bar every second
setInterval(function() {
// This would be dynamic, typically set by the current play time over total duration
const currentTime = 60; // current time in seconds
const duration = 240; // total duration in seconds
const percentage = (currentTime / duration) * 100;
updateProgressBar(percentage);
// Update time display
document.getElementById('current-time').innerText = formatTime(currentTime);
document.getElementById('duration').innerText = formatTime(duration);
}, 1000);
function formatTime(seconds) {
const min = Math.floor(seconds / 60);
const sec = seconds % 60;
return `${min}:${sec < 10 ? '0' : ''}${sec}`;
}
</script>
</body>
</html>

22
install.sh Normal file
View File

@ -0,0 +1,22 @@
#!/bin/bash
# Use /bin/bash to run this script, even when called manually
SOURCE_DIR="$HOME/GR-Jukebox"
TARGET_DIR="$HOME"
for file in $SOURCE_DIR/*; do
filename=$(basename "$file")
if [ "$filename" != "install.sh" ]; then
# Move the file
cp -f "$file" "$TARGET_DIR/"
# Check if the file should be executable (modify this condition to fit your needs)
if [[ "$filename" == *.sh || "$filename" == *.py ]]; then
chmod +x "$TARGET_DIR/$filename"
fi
fi
done
crontab crontab_file.txt
echo "Installation complete. All files have been moved to $TARGET_DIR."

137
main1.py Normal file
View File

@ -0,0 +1,137 @@
from flask import Flask, render_template, request, redirect, url_for, jsonify
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"))
CORS(app, resources={r"/*": {"origins": "*"}})
player = vlc.MediaPlayer()
music_queue = []
title_queue = []
music_directory = os.path.expanduser('~/Music') # Adjust path as necessary
@app.route('/')
def index():
return render_template('manage1.html')
@app.route('/display')
def display():
return render_template('display1.html')
@app.route('/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})
return jsonify(music_files)
@app.route('/download', methods=['POST'])
def download():
url = request.form['youtube_url']
if 'youtube.com' in url:
video_id = url.split('=')[1][:11] # Extract the video ID from the YouTube URL
elif 'youtu.be' in url:
video_id = url.split('youtu.be/')[1][:11]
else:
return jsonify({'status': 'error', 'message': 'Invalid YouTube URL'})
output_path = os.path.expanduser(f'{home_directory}/Music/{video_id}.mp3') # Path where the file will be saved
if not os.path.exists(output_path):
print("Downloading...")
# Configure yt-dlp to download best audio quality
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
'noplaylist': True,
'quiet': True,
'outtmpl': output_path[:-4] # Use the custom path as the output template
}
# Use yt-dlp to extract information and download the audio file
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=True)
title = info.get('title') # Extract the title from video information
# Load the downloaded file using eyed3 and add ID3 tags
audiofile = eyed3.load(output_path)
if audiofile.tag is None: # Create an ID3 tag if none exist
audiofile.tag = eyed3.id3.Tag()
audiofile.tag.file_info = eyed3.id3.FileInfo(output_path)
print(f"Downloaded: {title}")
audiofile.tag.title = title
audiofile.tag.save() # Save the metadata
#return redirect(url_for('index')) # Redirect back to the main page
return jsonify({'status': 'success', 'message': 'Song added successfully'})
playing_thread = False
@app.route('/play', methods=['POST'])
def play():
global music_queue
global title_queue
global playing_thread
global player
music_queue.append(request.json['songId'])
title_queue.append(request.json['songTitle'])
if not playing_thread:
while len(music_queue) > 0:
playing_thread = True
player = vlc.MediaPlayer(f'{home_directory}/Music/{music_queue[0]}.mp3')
player.play()
# Wait for the audio to start playing and check periodically if it is still playing
time.sleep(1) # Short initial delay to allow playback to start
while player.is_playing():
print('Playing...')
time.sleep(0.5) # Check every second if it is still playing
player.stop()
music_queue.pop(0)
title_queue.pop(0)
playing_thread = False
return jsonify({'status': 'success', 'message': 'Playing song'})
@app.route('/queue')
def get_queue():
global title_queue
return jsonify([{'id': idx, 'title': title} for idx, title in enumerate(title_queue)])
@app.route('/remove_from_queue', methods=['POST'])
def remove_from_queue():
global music_queue
global title_queue
global player
data = request.json
song_id = int(data['songId'])
try:
#del music_queue[song_id]
#del title_queue[song_id]
if song_id == 0:
player.stop()
else:
music_queue.pop(song_id)
title_queue.pop(song_id)
return jsonify({'status': 'success', 'message': 'Song removed successfully'})
except IndexError:
return jsonify({'status': 'error', 'message': 'Invalid song ID'}), 400
@app.route('/current')
def current():
global title_queue
if len(title_queue) > 0:
return {'title': title_queue[0]}
return {'title': 'Nothing is playing'}
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True, port=5000)

154
main2.py Normal file
View File

@ -0,0 +1,154 @@
from flask import Flask, render_template, jsonify
from flask_socketio import SocketIO, emit
from flask_cors import CORS
import yt_dlp
import vlc
import os
import eyed3
import time
home_directory = os.path.expanduser("~")
music_directory = os.path.expanduser('~/Music') # Adjust path as necessary
#app = Flask(__name__,template_folder=home_directory)
app = Flask(__name__, template_folder=f"{home_directory}/Code/GR/GR-Jukebox")
CORS(app, resources={r"/*": {"origins": "*"}})
socketio = SocketIO(app)
player = vlc.MediaPlayer()
music_queue = []
title_queue = []
@socketio.on('connect')
def handle_connect():
emit('response', {'message': 'Connected to WebSocket server'})
@socketio.on('list_music')
def handle_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})
print({'music_files':music_files})
emit('music_list', {'music_files': music_files})
@socketio.on('download')
def handle_download(data):
url = data['youtube_url']
if 'youtube.com' in url:
video_id = url.split('=')[1][:11] # Extract the video ID from the YouTube URL
elif 'youtu.be' in url:
video_id = url.split('youtu.be/')[1][:11]
else:
#return jsonify({'status': 'error', 'message': 'Invalid YouTube URL'})
emit('download_status', {'status': 'error', 'message': 'Invalid YouTube URL'})
output_path = os.path.expanduser(f'{home_directory}/Music/{video_id}.mp3') # Path where the file will be saved
if not os.path.exists(output_path):
print("Downloading...")
# Configure yt-dlp to download best audio quality
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
'noplaylist': True,
'quiet': True,
'outtmpl': output_path[:-4] # Use the custom path as the output template
}
# Use yt-dlp to extract information and download the audio file
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=True)
title = info.get('title') # Extract the title from video information
# Load the downloaded file using eyed3 and add ID3 tags
audiofile = eyed3.load(output_path)
if audiofile.tag is None: # Create an ID3 tag if none exist
audiofile.tag = eyed3.id3.Tag()
audiofile.tag.file_info = eyed3.id3.FileInfo(output_path)
print(f"Downloaded: {title}")
audiofile.tag.title = title
audiofile.tag.save() # Save the metadata
emit('download_status', {'status': 'success', 'message': 'Song added successfully'})
playing_thread = False
@socketio.on('play')
def handle_play(data):
global music_queue
global title_queue
global playing_thread
global player
music_queue.append(data['songId'])
title_queue.append(data['songTitle'])
if not playing_thread:
while len(music_queue) > 0:
playing_thread = True
player = vlc.MediaPlayer(f'{home_directory}/Music/{music_queue[0]}.mp3')
player.play()
print(f"Playing: {title_queue[0]}")
emit('current', {'title': title_queue[0]})
emit('queue', [{'id': idx, 'title': title} for idx, title in enumerate(title_queue)])
# Wait for the audio to start playing and check periodically if it is still playing
time.sleep(1) # Short initial delay to allow playback to start
while player.is_playing():
#print('Playing...')
time.sleep(0.5) # Check every second if it is still playing
#emit('time', {'time': player.get_time()})
#print(player.get_time())
#print(player.get_length())
#print((player.get_time()/player.get_length()))
emit('time', {'time': (player.get_time()/player.get_length())})
player.stop()
music_queue.pop(0)
title_queue.pop(0)
playing_thread = False
emit('play_return', {'status': 'success', 'message': 'Playing song'})
@socketio.on('get_queue')
def handle_get_queue():
emit('queue', [{'id': idx, 'title': title} for idx, title in enumerate(title_queue)])
@socketio.on('remove_from_queue')
def handle_remove_from_queue(data):
global music_queue
global title_queue
global player
#data = request.json
song_id = int(data['songId'])
try:
#del music_queue[song_id]
#del title_queue[song_id]
if song_id == 0:
player.stop()
else:
music_queue.pop(song_id)
title_queue.pop(song_id)
#return jsonify({'status': 'success', 'message': 'Song removed successfully'})
emit('remove_return', {'status': 'success', 'message': 'Song removed successfully'})
except IndexError:
#return jsonify({'status': 'error', 'message': 'Invalid song ID'}), 400
emit('remove_return', {'status': 'error', 'message': 'Invalid song ID'})
@socketio.on('current_song')
def handle_current_song():
if title_queue:
emit('current', {'title': title_queue[0]})
else:
emit('current', {'title': 'Nothing is playing'})
@app.route('/')
def index():
return render_template('manage2.html')
@app.route('/display')
def display():
return render_template('display2.html')
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', debug=True, port=5000)

328
manage1.html Normal file
View File

@ -0,0 +1,328 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Manage Queue</title>
<style>
body {
display: flex;
margin: 0;
padding: 0;
height: 100vh;
background-color: #0f0f0f;
}
.column {
flex: 1;
padding: 10px;
align-items: center;
text-align: center;
}
#musicQueue, #allMusic {
height: 80vh;
overflow-y: auto;
}
.queueItem {
padding: 5px;
margin: 5px;
background-color: #f0f0f0;
border-radius: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
.queueItem button {
margin-left: 10px;
}
input[type="text"] {
width: calc(100% - 22px); /* Full width minus padding and border */
padding: 10px;
box-sizing: border-box;
}
.loader {
border: 5px solid #f3f3f3; /* Light grey */
border-top: 5px solid #3498db; /* Blue */
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 2s linear infinite;
}
.musicItem {
padding: 5px;
margin: 5px;
background-color: #f0f0f0;
border-radius: 5px;
display: flex;
align-items: center;
}
.musicItem button {
margin-right: 10px; /* Adds space between the button and the title */
}
.musicItem span {
flex-grow: 1; /* Allows the title span to take up the remaining space */
text-align: left; /* Ensures text is left-aligned */
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Hide loader by default */
.hidden {
display: none;
}
h2 {
color: #999;
font-size: 3vh;
}
.progress-container {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
height: 5vh;
width: 30vw;
}
.progress-bar {
width: 100%;
background-color: #eee;
height: 2vh;
border-radius: 1vh;
overflow: hidden;
}
.progress {
height: 2vh;
background-color: #007BFF;
width: 0%;
border-radius: 1vh;
transition: width 0.5s ease;
}
#album-art {
/*width: 200px; /* Adjust width as needed */
height: 20vh; /* Maintain aspect ratio */
width: auto;
border-radius: 1vh; /* Rounded corners */
margin-bottom: 1vh; /* Space between the image and text */
}
span{
color:#999;
font-size: 1vw;
margin: 1vw;
}
</style>
</head>
<body>
<div class="column">
<h2>Download New Song</h2>
<form id="downloadForm">
<input type="text" id="youtubeUrl" name="youtube_url" placeholder="Enter YouTube URL here" required>
<button type="button" id="downloadButton" onclick="submitDownload()">Download</button>
<div id="loader" class="loader hidden"></div>
</form>
<div>
<img id="album-art" src="mao.jpg" alt="Album Art">
<div class="progress-container">
<span id="current-time">0:00</span>
<div class="progress-bar">
<div class="progress" id="progress" style="width: 0%;"></div>
</div>
<span id="duration">4:00</span>
</div>
</div>
</div>
<div class="column" id="queueControls">
<h2>Music Queue</h2>
<!--<button onclick="skipTrack()">Skip</button>
<button onclick="toggleLoop()">Loop</button>
<button onclick="toggleShuffle()">Shuffle</button>
<button onclick="clearQueue()">Clear</button>-->
<div id="musicQueue">
<!-- Dynamically filled with JavaScript -->
</div>
</div>
<div class="column">
<h2>All Music</h2>
<input type="text" id="searchMusic" placeholder="Search music..." onkeyup="filterMusic()">
<div id="allMusic">
<!-- Dynamically filled with JavaScript -->
</div>
</div>
<script>
function skipTrack() {
// Implementation of skipping the current track
}
function toggleLoop() {
// Toggle loop mode
}
function toggleShuffle() {
// Toggle shuffle mode
}
function clearQueue() {
// Clear the entire queue
}
function playSong(songId, songTitle) {
fetch('/play', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ songId: songId, songTitle: songTitle })
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to add song to queue');
}
return response.json();
})
.then(data => {
console.log('Song added to queue:', data);
})
.catch(error => console.error('Error adding song to queue:', error));
loadQueue(); // Reloads the queue after a song is added
}
function loadMusic() {
const musicList = document.getElementById('allMusic');
//musicList.innerHTML = ''; // Clear the list before populating it again
fetch('/music')
.then(response => response.json())
.then(musicFiles => {
musicList.innerHTML = '';
musicFiles.forEach(song => {
const div = document.createElement('div');
div.className = 'musicItem';
// Create a button for adding to the queue
const addButton = document.createElement('button');
addButton.textContent = 'Add to Queue';
addButton.onclick = function() { playSong(song.id,song.title); };
// Create a span to hold the song title
const titleSpan = document.createElement('span');
titleSpan.textContent = song.title;
// Append the button and title to the div
div.appendChild(addButton);
div.appendChild(titleSpan);
musicList.appendChild(div);
});
})
.catch(error => console.error('Failed to load music:', error));
}
function filterMusic() {
const search = document.getElementById('searchMusic').value.toLowerCase();
const musicItems = document.getElementById('allMusic').getElementsByClassName('musicItem');
for (let i = 0; i < musicItems.length; i++) {
let item = musicItems[i];
let text = item.textContent || item.innerText;
if (text.toLowerCase().indexOf(search) > -1) {
item.style.display = "";
} else {
item.style.display = "none";
}
}
}
function loadQueue() {
const queueElement = document.getElementById('musicQueue');
//queueElement.innerHTML = ''; // Clear the queue before loading new items
fetch('/queue')
.then(response => response.json())
.then(queue => {
queueElement.innerHTML = '';
queue.forEach(song => {
const div = document.createElement('div');
div.className = 'queueItem';
// Create a button for removing from the queue
const removeButton = document.createElement('button');
removeButton.textContent = 'Remove';
removeButton.onclick = function() { removeFromQueue(song.id); };
// Create a span to hold the song title
const titleSpan = document.createElement('span');
titleSpan.textContent = song.title;
// Append the button and title to the div
div.appendChild(removeButton);
div.appendChild(titleSpan);
queueElement.appendChild(div);
});
})
.catch(error => console.error('Failed to load queue:', error));
}
function removeFromQueue(songId) {
fetch('/remove_from_queue', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ songId: songId })
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to remove song from queue');
}
loadQueue(); // Reloads the queue after removing a song
})
.catch(error => console.error('Error removing song from queue:', error));
}
function submitDownload() {
const formData = new FormData(document.getElementById('downloadForm'));
const loader = document.getElementById('loader');
const youtubeUrl = document.getElementById('youtubeUrl');
const downloadButton = document.getElementById('downloadButton');
youtubeUrl.disabled = true;
downloadButton.disabled = true;
loader.classList.remove('hidden'); // Show the loader
fetch('/download', {
method: 'POST',
body: formData
})
.then(response => {
youtubeUrl.disabled = false;
downloadButton.disabled = false;
loader.classList.add('hidden'); // Hide the loader
youtubeUrl.value = ''; // Clear the input field
if (response.ok) {
loadMusic(); // Reloads the music list after successful download
} else {
throw new Error('Failed to download song');
}
})
.catch(error => {
console.error('Error:', error);
youtubeUrl.disabled = false;
downloadButton.disabled = false;
loader.classList.add('hidden'); // Ensure loader is hidden on error
});
}
setInterval(loadQueue, 1000);
//setInterval(loadMusic, 5000);
document.addEventListener('DOMContentLoaded', loadMusic); // Ensure music loads when the page is ready
// Functionality to dynamically populate queues and handle music items could be added here.
</script>
</body>
</html>

227
manage2.html Normal file
View File

@ -0,0 +1,227 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Manage Queue</title>
<style>
body {
display: flex;
margin: 0;
padding: 0;
height: 100vh;
background-color: #0f0f0f;
}
.column {
flex: 1;
padding: 10px;
align-items: center;
text-align: center;
}
#musicQueue, #allMusic {
height: 80vh;
overflow-y: auto;
}
.queueItem {
padding: 5px;
margin: 5px;
background-color: #f0f0f0;
border-radius: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
.queueItem button {
margin-left: 10px;
}
input[type="text"] {
width: calc(100% - 22px); /* Full width minus padding and border */
padding: 10px;
box-sizing: border-box;
}
.loader {
border: 5px solid #f3f3f3; /* Light grey */
border-top: 5px solid #3498db; /* Blue */
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 2s linear infinite;
}
.musicItem {
padding: 5px;
margin: 5px;
background-color: #f0f0f0;
border-radius: 5px;
display: flex;
align-items: center;
}
.musicItem button {
margin-right: 10px; /* Adds space between the button and the title */
}
.musicItem span {
flex-grow: 1; /* Allows the title span to take up the remaining space */
text-align: left; /* Ensures text is left-aligned */
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Hide loader by default */
.hidden {
display: none;
}
h2 {
color: #999;
font-size: 3vh;
}
.progress-container {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
height: 5vh;
width: 30vw;
}
.progress-bar {
width: 100%;
background-color: #eee;
height: 2vh;
border-radius: 1vh;
overflow: hidden;
}
.progress {
height: 2vh;
background-color: #007BFF;
width: 0%;
border-radius: 1vh;
transition: width 0.5s ease;
}
#album-art {
/*width: 200px; /* Adjust width as needed */
height: 20vh; /* Maintain aspect ratio */
width: auto;
border-radius: 1vh; /* Rounded corners */
margin-bottom: 1vh; /* Space between the image and text */
}
span{
color:#999;
font-size: 1vw;
margin: 1vw;
}
</style>
</head>
<body>
<div class="column">
<h2>Download New Song</h2>
<input type="text" id="youtubeUrl" placeholder="Enter YouTube URL here" required>
<button id="downloadButton" onclick="submitDownload()">Download</button>
<div id="loader" class="loader hidden"></div>
</div>
<div class="column" id="queueControls">
<h2>Music Queue</h2>
<div id="musicQueue"></div>
</div>
<div class="column">
<h2>All Music</h2>
<input type="text" id="searchMusic" placeholder="Search music..." onkeyup="filterMusic()">
<div id="allMusic"></div>
</div>
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
<script>
const socket = io(); // Connect to WebSocket server
socket.on('connect', function() {
console.log('Connected to WebSocket server!');
loadMusic(); // Load music when connected
loadQueue(); // Load queue when connected
});
socket.on('music_list', function(data) {
//console.log(data)
//console.log(data.music_files)
populateMusicList(data.music_files);
});
socket.on('queue', function(data) {
//console.log(data)
//populateQueue(data.queue);
populateQueue(data);
});
function submitDownload() {
const youtubeUrl = document.getElementById('youtubeUrl').value;
socket.emit('download', { youtube_url: youtubeUrl });
}
function playSong(songId, songTitle) {
socket.emit('play', { songId: songId, songTitle: songTitle });
}
function removeFromQueue(songId) {
socket.emit('remove_from_queue', { songId: songId });
}
function loadMusic() {
socket.emit('list_music');
}
function loadQueue() {
socket.emit('get_queue');
}
function populateMusicList(musicFiles) {
console.log(musicFiles);
const musicList = document.getElementById('allMusic');
musicList.innerHTML = ''; // Clear the list before populating
musicFiles.forEach(song => {
const div = document.createElement('div');
div.className = 'musicItem';
const addButton = document.createElement('button');
addButton.textContent = 'Add to Queue';
addButton.onclick = () => playSong(song.id, song.title);
const titleSpan = document.createElement('span');
titleSpan.textContent = song.title;
div.appendChild(addButton);
div.appendChild(titleSpan);
musicList.appendChild(div);
});
}
function populateQueue(queue) {
const queueElement = document.getElementById('musicQueue');
queueElement.innerHTML = ''; // Clear the queue before loading new items
queue.forEach(song => {
const div = document.createElement('div');
div.className = 'queueItem';
const removeButton = document.createElement('button');
removeButton.textContent = 'Remove';
removeButton.onclick = () => removeFromQueue(song.id);
const titleSpan = document.createElement('span');
titleSpan.textContent = song.title;
div.appendChild(removeButton);
div.appendChild(titleSpan);
queueElement.appendChild(div);
});
}
function filterMusic() {
const search = document.getElementById('searchMusic').value.toLowerCase();
const musicItems = document.querySelectorAll('.musicItem');
musicItems.forEach(item => {
const isVisible = item.textContent.toLowerCase().includes(search);
item.style.display = isVisible ? '' : 'none';
});
}
</script>
</body>
</html>

55
playtest.py Normal file
View File

@ -0,0 +1,55 @@
import os
import yt_dlp
import vlc
import time
import eyed3
def download_and_play(url):
video_id = url.split('=')[1][:11] # Extract the video ID from the YouTube URL
output_path = os.path.expanduser(f'/home/generalized/Music/{video_id}.mp3') # Path where the file will be saved
if not os.path.exists(output_path):
print("Downloading...")
# Configure yt-dlp to download best audio quality
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
'noplaylist': True,
'quiet': True,
'outtmpl': output_path[:-4] # Use the custom path as the output template
}
# Use yt-dlp to extract information and download the audio file
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=True)
title = info.get('title') # Extract the title from video information
# Load the downloaded file using eyed3 and add ID3 tags
audiofile = eyed3.load(output_path)
if audiofile.tag is None: # Create an ID3 tag if none exist
audiofile.tag = eyed3.id3.Tag()
audiofile.tag.file_info = eyed3.id3.FileInfo(output_path)
print(f"Downloaded: {title}")
audiofile.tag.title = title
audiofile.tag.save() # Save the metadata
# Use VLC to play the downloaded audio file
player = vlc.MediaPlayer(output_path)
player.play()
# Wait for the audio to start playing and check periodically if it is still playing
time.sleep(1) # Short initial delay to allow playback to start
while player.is_playing():
time.sleep(1) # Check every second if it is still playing
player.stop() # Stop playing after the audio is done
if __name__ == "__main__":
#youtube_url = "https://www.youtube.com/watch?v=szeXkBYq5HU"
youtube_url = "https://www.youtube.com/watch?v=BYiraKCTViY&list=PLdQb1ybxFDih_SbfzdjGIlf3Tylztpc4Q"
download_and_play(youtube_url)

36
pull_from_cloud.sh Normal file
View File

@ -0,0 +1,36 @@
#!/bin/bash
# Define directories and files
REPO_DIR="$HOME/GR-Jukebox"
VERSION_FILE_PATH="$REPO_DIR/version.txt"
INSTALLED_VERSION_FILE="$HOME/version.txt"
# Function to get version from a file
get_version() {
if [[ -f "$1" ]]; then
cat "$1"
else
echo "0"
fi
}
# Read the currently installed version and the version in the repository
INSTALLED_VERSION=$(get_version "$INSTALLED_VERSION_FILE")
REPO_VERSION=$(get_version "$VERSION_FILE_PATH")
# Check network connectivity to github.com
while ! ping -c 1 -W 1 git-codecommit.us-east-2.amazonaws.com > /dev/null; do
echo "Waiting for amazonaws.com - network interface might be down..."
sleep 1
done
# Fetch and compare the latest version on GitHub without pulling all files
cd "$REPO_DIR"
git fetch origin
REMOTE_VERSION=$(git show origin/master:version.txt)
if [[ "$INSTALLED_VERSION" != "$REMOTE_VERSION" ]]; then
echo "New version available on AWS. Starting download in background."
# Pull the latest changes from the remote repository
( git pull origin master & )
fi

0
requirements.txt Normal file
View File

174
style.css Executable file

File diff suppressed because one or more lines are too long

35
update.sh Normal file
View File

@ -0,0 +1,35 @@
#!/bin/bash
# Define directories and files
REPO_DIR="$HOME/GR-Jukebox"
VERSION_FILE_PATH="$REPO_DIR/version.txt"
INSTALLED_VERSION_FILE="$HOME/version.txt"
# Function to get version from a file
get_version() {
if [[ -f "$1" ]]; then
cat "$1"
else
echo "0"
fi
}
# Read the currently installed version and the version in the repository
INSTALLED_VERSION=$(get_version "$INSTALLED_VERSION_FILE")
REPO_VERSION=$(get_version "$VERSION_FILE_PATH")
echo "Installed version: $INSTALLED_VERSION"
# Check if installed version matches the version in the repository directory
if [[ "$INSTALLED_VERSION" != "$REPO_VERSION" ]]; then
echo "Version mismatch. Running install script and exiting updater."
echo "New version: $REPO_VERSION"
/bin/bash "$REPO_DIR/install.sh"
( /bin/bash "$HOME/update.sh" & )
exit 0
fi
( /bin/bash "$HOME/pull_from_cloud.sh" & )
source "$HOME/jukebox/bin/activate"
python3 "$HOME/main1.py"

1
version.txt Normal file
View File

@ -0,0 +1 @@
1.0.2