diff --git a/crontab_file.txt b/crontab_file.txt new file mode 100644 index 0000000..9710a3d --- /dev/null +++ b/crontab_file.txt @@ -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 diff --git a/display1.html b/display1.html new file mode 100644 index 0000000..7383614 --- /dev/null +++ b/display1.html @@ -0,0 +1,112 @@ + + + + + Now Playing + + + +

Now Playing

+ Album Art +
Nothing is playing
+

+
+ 0:00 +
+
+
+ 4:00 +
+ + + diff --git a/display2.html b/display2.html new file mode 100644 index 0000000..37b78c7 --- /dev/null +++ b/display2.html @@ -0,0 +1,112 @@ + + + + + Now Playing + + + + +

Now Playing

+ +
Nothing is playing
+

+
+ 0:00 +
+
+
+ 4:00 +
+ + + + diff --git a/htmltest.html b/htmltest.html new file mode 100644 index 0000000..8fb1e77 --- /dev/null +++ b/htmltest.html @@ -0,0 +1,90 @@ + + + + + + Simple Music Player + + + +
+
+ Song Title +
+
+ 0:00 +
+
+
+ 4:00 +
+
+ + + + diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..c064550 --- /dev/null +++ b/install.sh @@ -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." diff --git a/main1.py b/main1.py new file mode 100644 index 0000000..df6cf4b --- /dev/null +++ b/main1.py @@ -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) diff --git a/main2.py b/main2.py new file mode 100644 index 0000000..ef88b68 --- /dev/null +++ b/main2.py @@ -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) diff --git a/manage1.html b/manage1.html new file mode 100644 index 0000000..78abcdc --- /dev/null +++ b/manage1.html @@ -0,0 +1,328 @@ + + + + + Manage Queue + + + +
+

Download New Song

+
+ + + +
+
+ Album Art +
+ 0:00 +
+
+
+ 4:00 +
+
+
+ +
+

Music Queue

+ +
+ +
+
+ +
+

All Music

+ +
+ +
+
+ + + + diff --git a/manage2.html b/manage2.html new file mode 100644 index 0000000..7ced405 --- /dev/null +++ b/manage2.html @@ -0,0 +1,227 @@ + + + + + Manage Queue + + + +
+

Download New Song

+ + + +
+ +
+

Music Queue

+
+
+ +
+

All Music

+ +
+
+ + + + + diff --git a/playtest.py b/playtest.py new file mode 100644 index 0000000..3c93435 --- /dev/null +++ b/playtest.py @@ -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) diff --git a/pull_from_cloud.sh b/pull_from_cloud.sh new file mode 100644 index 0000000..992fa73 --- /dev/null +++ b/pull_from_cloud.sh @@ -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 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/style.css b/style.css new file mode 100755 index 0000000..03f7d24 --- /dev/null +++ b/style.css @@ -0,0 +1,174 @@ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +body { + background-repeat: no-repeat; + background-size: cover; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:svgjs='http://svgjs.com/svgjs' width='1440' height='560' preserveAspectRatio='none' viewBox='0 0 1440 560'%3e%3cg mask='url(%26quot%3b%23SvgjsMask1549%26quot%3b)' fill='none'%3e%3crect width='1440' height='560' x='0' y='0' fill='url(%23SvgjsLinearGradient1550)'%3e%3c/rect%3e%3cuse xlink:href='%23SvgjsSymbol1557' x='0' y='0'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsSymbol1557' x='720' y='0'%3e%3c/use%3e%3c/g%3e%3cdefs%3e%3cmask id='SvgjsMask1549'%3e%3crect width='1440' height='560' fill='white'%3e%3c/rect%3e%3c/mask%3e%3clinearGradient x1='15.28%25' y1='139.29%25' x2='84.72%25' y2='-39.29%25' gradientUnits='userSpaceOnUse' id='SvgjsLinearGradient1550'%3e%3cstop stop-color='%230e2a47' offset='0'%3e%3c/stop%3e%3cstop stop-color='rgba(0%2c 7%2c 213%2c 1)' offset='1'%3e%3c/stop%3e%3c/linearGradient%3e%3cpath d='M-1 0 a1 1 0 1 0 2 0 a1 1 0 1 0 -2 0z' id='SvgjsPath1556'%3e%3c/path%3e%3cpath d='M-3 0 a3 3 0 1 0 6 0 a3 3 0 1 0 -6 0z' id='SvgjsPath1554'%3e%3c/path%3e%3cpath d='M-5 0 a5 5 0 1 0 10 0 a5 5 0 1 0 -10 0z' id='SvgjsPath1551'%3e%3c/path%3e%3cpath d='M2 -2 L-2 2z' id='SvgjsPath1552'%3e%3c/path%3e%3cpath d='M6 -6 L-6 6z' id='SvgjsPath1553'%3e%3c/path%3e%3cpath d='M30 -30 L-30 30z' id='SvgjsPath1555'%3e%3c/path%3e%3c/defs%3e%3csymbol id='SvgjsSymbol1557'%3e%3cuse xlink:href='%23SvgjsPath1551' x='30' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='30' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='30' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='30' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='30' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='30' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='30' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='30' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='30' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1554' x='30' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='90' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1554' x='90' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='90' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='90' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='90' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='90' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='90' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='90' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='90' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='90' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='150' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='150' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='150' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='150' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='150' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='150' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1555' x='150' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)' stroke-width='3'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='150' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='150' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1554' x='150' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='210' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='210' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='210' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='210' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='210' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='210' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='210' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='210' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='210' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='210' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='270' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='270' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='270' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='270' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='270' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='270' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='270' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='270' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='270' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1555' x='270' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)' stroke-width='3'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='330' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='330' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='330' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='330' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='330' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='330' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='330' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='330' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='330' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='330' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='390' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='390' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1554' x='390' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1555' x='390' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)' stroke-width='3'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1554' x='390' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='390' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='390' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='390' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='390' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='390' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='450' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1554' x='450' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='450' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='450' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='450' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='450' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='450' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='450' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='450' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='450' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='510' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='510' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='510' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='510' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='510' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1555' x='510' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)' stroke-width='3'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='510' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='510' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='510' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='510' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='570' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='570' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='570' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='570' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='570' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='570' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='570' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='570' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='570' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1554' x='570' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='630' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='630' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='630' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1552' x='630' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='630' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='630' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='630' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='630' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='630' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='630' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='690' y='30' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='690' y='90' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='690' y='150' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1555' x='690' y='210' stroke='rgba(11%2c 102%2c 200%2c 1)' stroke-width='3'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='690' y='270' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='690' y='330' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1556' x='690' y='390' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='690' y='450' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1551' x='690' y='510' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3cuse xlink:href='%23SvgjsPath1553' x='690' y='570' stroke='rgba(11%2c 102%2c 200%2c 1)'%3e%3c/use%3e%3c/symbol%3e%3c/svg%3e"); + +} + +body * { + font-family: 'Roboto', sans-serif; +} + +#boxes * { + border: 1px solid transparent; +} + +#boxes { + display: grid; + grid-template-columns: max-content max-content; + grid-template-areas: + 'A B' + 'A C'; + gap: 32px; + place-content: center; + height: 100vh; +} + +#player01 { + grid-area: A; + padding: 50px 38px; +} + +#player01 .wrapper{ + width: 190px; +} + + +#player01 img{ + width: 190px; + height: 190px; + object-fit: cover; + border-radius: 10px; +} + +#player01 .info { + padding-top: 28px; +} + +#player02 { + grid-area: B; + height: fit-content; +} + +#player02 .controls { + display: flex; + justify-content: space-around; +} + +#player03 { + grid-area: C; +} + +#player03 .controls { + display: flex; + justify-content: space-around; +} + +.player { + background-color: #080747; + padding: 28px; + border-radius: 20px; +} + +.player img { + width: 84px; + height: 84px; + object-fit: cover; + border-radius: 10px; +} + + +.info { + color: #E1E1E6; +} + +.info p { + opacity: 0.68; + font-size: 19px; +} + +.info-wrapper { + display: flex; + align-items: center; + gap: 30px; +} + +.player h1 { + font-size: 27px; + color: #E1E1E6; + padding-bottom: 7px; +} + + +.controls { + display: flex; + justify-content: space-between; + padding-top: 20px; +} + +.track { + padding-top: 28px; + position: relative; + +} + +.track::before { +content: ''; +height: 6px; +width: 100%; +display: block; +background: #D9D9D9; +opacity: 0.3; +border-radius: 10px; +position: absolute; +} + +.track::after { + content: ''; +height: 6px; +width: 85%; +display: block; +background: #D9D9D9; +border-radius: 10px; + + +} + +.time { + opacity: 0.7; + font-size: 14px; + color: gainsboro; + + display: flex; + justify-content: space-between; + padding-top: 9.6px; +} + +@media (max-width: 670px) { + #boxes { + display:flex; + flex-direction: column; + + max-width: 270px; + margin: auto; + + + height: auto; + padding-block: 60px; + } + + + +} + + + + diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..4923401 --- /dev/null +++ b/update.sh @@ -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" diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..e6d5cb8 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +1.0.2 \ No newline at end of file