s
This commit is contained in:
parent
e26d298c4c
commit
aa7d40f7a0
6 changed files with 122 additions and 100 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
.env
|
||||
.cache
|
16
app.py
16
app.py
|
@ -1,13 +1,18 @@
|
|||
from flask import Flask, render_template, request, redirect, url_for, jsonify
|
||||
from flask import Flask, render_template, request, jsonify
|
||||
from spotipy import Spotify
|
||||
from spotipy.oauth2 import SpotifyOAuth
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
# Flask app
|
||||
app = Flask(__name__)
|
||||
|
||||
# Spotify API credentials
|
||||
CLIENT_ID = "f7f2841e0c26492681499a53b4eca29f"
|
||||
CLIENT_SECRET = "8e1a973438214682939b175bb9f1ed1d"
|
||||
# Spotify API credentials from environment variables
|
||||
CLIENT_ID = os.getenv("CLIENT_ID")
|
||||
CLIENT_SECRET = os.getenv("CLIENT_SECRET")
|
||||
REDIRECT_URI = "http://localhost:80/callback"
|
||||
SCOPE = "user-modify-playback-state user-read-playback-state"
|
||||
|
||||
|
@ -23,6 +28,7 @@ sp = Spotify(auth_manager=SpotifyOAuth(
|
|||
@app.route("/")
|
||||
def home():
|
||||
return render_template("index.html")
|
||||
|
||||
|
||||
@app.route("/add", methods=["GET"])
|
||||
def add_song():
|
||||
|
@ -58,7 +64,7 @@ def queue_table():
|
|||
queue.append({"track": track_name, "artist": artist_name})
|
||||
current = None
|
||||
if queue_data["currently_playing"]:
|
||||
current = {"track":queue_data["currently_playing"]["name"], "artist":queue_data["currently_playing"]["artists"][0]["name"]}
|
||||
current = {"track": queue_data["currently_playing"]["name"], "artist": queue_data["currently_playing"]["artists"][0]["name"]}
|
||||
return render_template("queue_table.html", queue=queue, length=len(queue), now_playing=current)
|
||||
|
||||
# Run the Flask app
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
Flask
|
||||
spotipy
|
||||
python-dotenv
|
2
run.bat
2
run.bat
|
@ -1 +1 @@
|
|||
python app.py
|
||||
cmd /K python -m app
|
|
@ -1,6 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
|
||||
>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Spotify Queue Manager</title>
|
||||
|
@ -10,13 +14,9 @@
|
|||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
h1 {
|
||||
color: #000000;
|
||||
}
|
||||
form {
|
||||
margin: 20px auto;
|
||||
width: 100%;
|
||||
}
|
||||
input[type="text"] {
|
||||
width: 80%;
|
||||
|
@ -25,34 +25,49 @@
|
|||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
button {
|
||||
background-color: #000000;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
.loading-spinner {
|
||||
display: none;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #000000;
|
||||
.loading-spinner.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Styling for the iframe to stretch to bottom and hide scrollbar */
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: calc(100vh); /* Adjusted to leave space for other content */
|
||||
border: none;
|
||||
margin-top: 20px;
|
||||
overflow: hidden;
|
||||
overflow: hidden; /* Hide the scrollbar */
|
||||
transition: height 0.3s ease-in-out;
|
||||
}
|
||||
/* Optional: Smooth fade on iframe content changes */
|
||||
iframe.content {
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Queue</h1>
|
||||
<form id="addSongForm" onsubmit="addSong(event)">
|
||||
<input type="text" id="songInput" name="song_name" placeholder="Adauga melodie sau artist " required>
|
||||
<button type="submit">Adauga</button>
|
||||
<input type="text" id="songInput" name="song_name" placeholder="Add song or artist" required>
|
||||
<button style="width: 10%;" class="contrast" type="submit">Add</button>
|
||||
</form>
|
||||
<div class="message" id="message"></div>
|
||||
<!-- Queue Table Embedded in an iframe -->
|
||||
<iframe src="/queue_table" id="queueIframe"></iframe>
|
||||
<!-- Now Playing Widget -->
|
||||
<p>Now Playing:</p>
|
||||
<div class="now-playing" id="nowPlaying">
|
||||
<div id="nowPlayingInfo">
|
||||
Loading now playing...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<iframe id="queueTable" src="/queue_table" scrolling="no" seamless="seamless"></iframe>
|
||||
|
||||
<script>
|
||||
// Function to handle song addition via GET request
|
||||
async function addSong(event) {
|
||||
|
@ -86,28 +101,56 @@
|
|||
songInput.value = "";
|
||||
}
|
||||
|
||||
// Reload the iframe to reflect the updated queue
|
||||
document.getElementById("queueIframe").contentWindow.location.reload();
|
||||
|
||||
setTimeout(() => {
|
||||
messageDiv.textContent = "";
|
||||
}, 3000)
|
||||
}
|
||||
// Adjust the iframe height dynamically to avoid scrollbars
|
||||
function resizeIframe() {
|
||||
const iframe = document.getElementById('queueIframe');
|
||||
iframe.style.height = iframe.contentWindow.document.body.scrollHeight+20 + 'px';
|
||||
// Show loading spinner
|
||||
const loadingSpinner = document.getElementById("loadingSpinner");
|
||||
loadingSpinner.classList.add("active");
|
||||
}
|
||||
|
||||
// Resize iframe after it loads and periodically refresh the iframe
|
||||
const iframe = document.getElementById('queueIframe');
|
||||
iframe.onload = resizeIframe;
|
||||
setInterval(() => {
|
||||
iframe.contentWindow.location.reload();
|
||||
}, 15000);
|
||||
// Function to fetch "Now Playing" information
|
||||
async function fetchNowPlaying() {
|
||||
try {
|
||||
const response = await fetch('https://lastplayed.prigoana.com/Labirint84/');
|
||||
const data = await response.json();
|
||||
|
||||
const track = data.track;
|
||||
if (track && track["@attr"] && track["@attr"].nowplaying === "true") {
|
||||
const nowPlayingInfo = document.getElementById('nowPlayingInfo');
|
||||
const nowPlayingImage = document.getElementById('nowPlayingImage');
|
||||
|
||||
nowPlayingInfo.innerHTML = `${track.name} by ${track.artist["#text"]}`;
|
||||
nowPlayingImage.innerHTML = `<img src="${track.image[2]["#text"]}" alt="${track.name}">`;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching now playing:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Call fetchNowPlaying on page load
|
||||
fetchNowPlaying();
|
||||
|
||||
// Set an interval to fetch now playing every 3 seconds
|
||||
setInterval(fetchNowPlaying, 3000);
|
||||
|
||||
// Function to update iframe content
|
||||
async function updateIframeContent() {
|
||||
try {
|
||||
const iframe = document.getElementById("queueTable");
|
||||
const response = await fetch('/queue_table');
|
||||
const html = await response.text();
|
||||
|
||||
// Replace iframe content with smooth transition
|
||||
iframe.srcdoc = html;
|
||||
|
||||
// Optionally: Apply smooth fade in for iframe content
|
||||
iframe.classList.add('content');
|
||||
} catch (error) {
|
||||
console.error('Error updating iframe:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Update iframe content every 3 seconds
|
||||
setInterval(updateIframeContent, 3000);
|
||||
|
||||
// Add event listener for resize events
|
||||
window.addEventListener('resize', resizeIframe);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,63 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
h2 {
|
||||
color: #000000;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.now-playing {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: 0;
|
||||
font-size: 1em;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
th, td {
|
||||
padding: 12px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: left;
|
||||
}
|
||||
th {
|
||||
background-color: #000000;
|
||||
color: white;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<!doctype html>
|
||||
<html lang="en" class="pico">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.fuchsia.min.css"
|
||||
>
|
||||
<title>table</title>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Track</th>
|
||||
<th>Artist</th>
|
||||
<center> <main class="container">
|
||||
<table class="striped" style="table-layout: fixed; overflow: hidden;">
|
||||
<thead style=" text-align: center;">
|
||||
<tr style=" text-align: center;">
|
||||
<th scope="row" style=" text-align: center;">Track</th>
|
||||
<th style=" text-align: center;">Artist</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</thead style=" text-align: center;">
|
||||
<tbody style=" text-align: center;">
|
||||
{% for i in range(length) %}
|
||||
<tr>
|
||||
<td>{{ i+1 }}</td>
|
||||
<td>{{ queue[i].track }}</td>
|
||||
<td>{{ queue[i].artist }}</td>
|
||||
<tr style=" text-align: center;">
|
||||
<td style=" text-align: center;">{{ queue[i].track }}</td>
|
||||
<td style=" text-align: center;">{{ queue[i].artist }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table></center>
|
||||
</table></center></main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Reference in a new issue