almost final app
This commit is contained in:
BIN
app/__pycache__/app.cpython-312.pyc
Executable file → Normal file
BIN
app/__pycache__/app.cpython-312.pyc
Executable file → Normal file
Binary file not shown.
22
app/app.py
22
app/app.py
@@ -4,6 +4,8 @@ import os
|
|||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
import logging
|
import logging
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
@@ -217,7 +219,27 @@ def initialize_playlist():
|
|||||||
download_playlist_files_from_server()
|
download_playlist_files_from_server()
|
||||||
Logger.info("Playlist initialization complete.")
|
Logger.info("Playlist initialization complete.")
|
||||||
|
|
||||||
|
# Function to check for playlist updates every 5 minutes
|
||||||
|
def periodic_playlist_check():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
Logger.info("Checking for playlist updates...")
|
||||||
|
# Download the playlist files from the server
|
||||||
|
download_playlist_files_from_server()
|
||||||
|
# Create the updated playlist with local file paths
|
||||||
|
create_updated_playlist()
|
||||||
|
Logger.info("Playlist check complete.")
|
||||||
|
except Exception as e:
|
||||||
|
Logger.error(f"Error during playlist check: {e}")
|
||||||
|
time.sleep(300) # Wait for 5 minutes (300 seconds) before checking again
|
||||||
|
|
||||||
|
# Start the periodic playlist check in a background thread
|
||||||
|
def start_playlist_check_thread():
|
||||||
|
thread = threading.Thread(target=periodic_playlist_check, daemon=True)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
initialize_playlist() # Check and download playlist on startup
|
initialize_playlist() # Check and download playlist on startup
|
||||||
create_updated_playlist() # Create the updated playlist
|
create_updated_playlist() # Create the updated playlist
|
||||||
|
start_playlist_check_thread() # Start the background thread for periodic checks
|
||||||
app.run(host='0.0.0.0', port=1025)
|
app.run(host='0.0.0.0', port=1025)
|
||||||
21
app/run_app.sh
Normal file
21
app/run_app.sh
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit immediately if a command exits with a non-zero status
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Activate the virtual environment
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# Run the Gunicorn server
|
||||||
|
echo "Starting Gunicorn server..."
|
||||||
|
python3 run_gunicorn.py &
|
||||||
|
|
||||||
|
# Wait for 5 seconds to ensure the server is up
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Launch Chromium in fullscreen and kiosk mode
|
||||||
|
echo "Launching Chromium in fullscreen and kiosk mode..."
|
||||||
|
chromium-browser --kiosk --start-fullscreen http://localhost:1025
|
||||||
|
|
||||||
|
# Deactivate the virtual environment when done
|
||||||
|
deactivate
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
overflow: hidden; /* Prevent scrolling */
|
||||||
}
|
}
|
||||||
.playlist-container {
|
.playlist-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@@ -22,30 +23,32 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: black;
|
background-color: black;
|
||||||
|
position: relative; /* Enable positioning of child elements */
|
||||||
}
|
}
|
||||||
ul {
|
.playlist-container img,
|
||||||
list-style-type: none;
|
.playlist-container video {
|
||||||
padding: 0;
|
max-width: 100%;
|
||||||
display: none; /* Hide the playlist list */
|
max-height: 100%;
|
||||||
|
object-fit: contain; /* Ensure content fits within the container */
|
||||||
}
|
}
|
||||||
.controls-wrapper {
|
.controls-wrapper {
|
||||||
|
position: fixed; /* Fix the controls at the bottom of the page */
|
||||||
|
bottom: 0; /* Align to the bottom */
|
||||||
|
left: 0; /* Align to the left */
|
||||||
|
width: 100%; /* Full width */
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 33.33%; /* 1/3 of the page width */
|
gap: 15px; /* Space between buttons */
|
||||||
margin: 0 auto;
|
padding: 10px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5); /* Increased transparency */
|
||||||
|
border-top: 2px solid #444; /* Add a border at the top */
|
||||||
|
z-index: 100; /* Ensure buttons are above the media */
|
||||||
transition: opacity 0.5s ease; /* Smooth fade effect */
|
transition: opacity 0.5s ease; /* Smooth fade effect */
|
||||||
}
|
}
|
||||||
.controls-wrapper.hidden {
|
.controls-wrapper.hidden {
|
||||||
opacity: 0; /* Hide the buttons */
|
opacity: 0; /* Hide the buttons */
|
||||||
pointer-events: none; /* Disable interaction when hidden */
|
pointer-events: none; /* Disable interaction when hidden */
|
||||||
}
|
}
|
||||||
.controls {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 15px; /* Space between buttons */
|
|
||||||
padding: 10px;
|
|
||||||
background-color: #222;
|
|
||||||
}
|
|
||||||
button {
|
button {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@@ -62,10 +65,6 @@
|
|||||||
button i {
|
button i {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
img, video {
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<!-- Add Font Awesome for icons -->
|
<!-- Add Font Awesome for icons -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||||
@@ -75,22 +74,24 @@
|
|||||||
<!-- Content will be dynamically added here -->
|
<!-- Content will be dynamically added here -->
|
||||||
</div>
|
</div>
|
||||||
<div class="controls-wrapper" id="controls-wrapper">
|
<div class="controls-wrapper" id="controls-wrapper">
|
||||||
<div class="controls">
|
<button onclick="previousMedia()"><i class="fas fa-step-backward"></i></button> <!-- Previous -->
|
||||||
<button onclick="previousMedia()"><i class="fas fa-step-backward"></i></button> <!-- Previous -->
|
<button onclick="refreshPlaylist()"><i class="fas fa-sync-alt"></i></button> <!-- Refresh Playlist -->
|
||||||
<button onclick="loadPlaylist()"><i class="fas fa-sync-alt"></i></button> <!-- Refresh Playlist -->
|
<button id="playPauseButton" onclick="togglePlayPause()"><i class="fas fa-play"></i></button> <!-- Play/Pause -->
|
||||||
<button onclick="playMedia()"><i class="fas fa-play"></i></button> <!-- Play -->
|
<button onclick="nextMedia()"><i class="fas fa-step-forward"></i></button> <!-- Next -->
|
||||||
<button onclick="nextMedia()"><i class="fas fa-step-forward"></i></button> <!-- Next -->
|
<button onclick="stopMedia()"><i class="fas fa-stop"></i></button> <!-- Stop -->
|
||||||
<button onclick="stopMedia()"><i class="fas fa-stop"></i></button> <!-- Stop -->
|
<button onclick="goToSettings()"><i class="fas fa-cog"></i></button> <!-- Settings -->
|
||||||
<button onclick="goToSettings()"><i class="fas fa-cog"></i></button> <!-- Settings -->
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const apiBase = 'http://localhost:1025'; // Update to match your Flask app's port
|
const apiBase = 'http://localhost:1025'; // Update to match your Flask app's port
|
||||||
const playlistContainer = document.getElementById('playlist-container');
|
const playlistContainer = document.getElementById('playlist-container');
|
||||||
|
const controlsWrapper = document.getElementById('controls-wrapper');
|
||||||
|
const playPauseButton = document.getElementById('playPauseButton');
|
||||||
let playlist = [];
|
let playlist = [];
|
||||||
let currentIndex = 0;
|
let currentIndex = 0;
|
||||||
let playbackInterval;
|
let playbackInterval;
|
||||||
|
let inactivityTimer;
|
||||||
|
let isPaused = false;
|
||||||
|
|
||||||
// Function to load the playlist from updated_playlist.json
|
// Function to load the playlist from updated_playlist.json
|
||||||
async function loadPlaylist() {
|
async function loadPlaylist() {
|
||||||
@@ -100,9 +101,12 @@
|
|||||||
throw new Error(`Failed to load playlist: ${response.statusText}`);
|
throw new Error(`Failed to load playlist: ${response.statusText}`);
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
playlist = data; // Use the updated playlist
|
if (JSON.stringify(data) !== JSON.stringify(playlist)) {
|
||||||
console.log("Loaded playlist:", playlist); // Debug log
|
playlist = data; // Update the playlist only if it has changed
|
||||||
startPlaylist(); // Start playing the playlist after loading
|
console.log("Playlist updated:", playlist); // Debug log
|
||||||
|
currentIndex = 0; // Reset to the first item
|
||||||
|
startPlaylist(); // Restart the playlist
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading playlist:", error);
|
console.error("Error loading playlist:", error);
|
||||||
}
|
}
|
||||||
@@ -133,9 +137,11 @@
|
|||||||
|
|
||||||
// Display the image for the specified duration
|
// Display the image for the specified duration
|
||||||
playbackInterval = setTimeout(() => {
|
playbackInterval = setTimeout(() => {
|
||||||
currentIndex++;
|
if (!isPaused) {
|
||||||
playCurrentItem();
|
currentIndex++;
|
||||||
}, currentItem.duration * 1000);
|
playCurrentItem();
|
||||||
|
}
|
||||||
|
}, currentItem.duration * 1000 + (isPaused ? 10000 : 0)); // Add 10 seconds if paused
|
||||||
} else if (currentItem.type === 'video') {
|
} else if (currentItem.type === 'video') {
|
||||||
const video = document.createElement('video');
|
const video = document.createElement('video');
|
||||||
video.src = currentItem.url;
|
video.src = currentItem.url;
|
||||||
@@ -145,8 +151,10 @@
|
|||||||
|
|
||||||
// Play the video and move to the next item after it ends
|
// Play the video and move to the next item after it ends
|
||||||
video.onended = () => {
|
video.onended = () => {
|
||||||
currentIndex++;
|
if (!isPaused) {
|
||||||
playCurrentItem();
|
currentIndex++;
|
||||||
|
playCurrentItem();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,6 +172,22 @@
|
|||||||
playCurrentItem();
|
playCurrentItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to refresh the playlist
|
||||||
|
function refreshPlaylist() {
|
||||||
|
loadPlaylist(); // Reload the playlist
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to toggle play/pause
|
||||||
|
function togglePlayPause() {
|
||||||
|
isPaused = !isPaused;
|
||||||
|
if (isPaused) {
|
||||||
|
playPauseButton.innerHTML = '<i class="fas fa-pause"></i>'; // Change to pause icon
|
||||||
|
} else {
|
||||||
|
playPauseButton.innerHTML = '<i class="fas fa-play"></i>'; // Change to play icon
|
||||||
|
playCurrentItem(); // Resume playback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function to play the next item
|
// Function to play the next item
|
||||||
function nextMedia() {
|
function nextMedia() {
|
||||||
stopMedia();
|
stopMedia();
|
||||||
@@ -175,8 +199,30 @@
|
|||||||
window.location.href = '/static/settings.html';
|
window.location.href = '/static/settings.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to hide controls after inactivity
|
||||||
|
function hideControls() {
|
||||||
|
controlsWrapper.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to reset inactivity timer
|
||||||
|
function resetInactivityTimer() {
|
||||||
|
controlsWrapper.classList.remove('hidden'); // Show controls
|
||||||
|
clearTimeout(inactivityTimer); // Clear the previous timer
|
||||||
|
inactivityTimer = setTimeout(hideControls, 10000); // Set a new timer for 10 seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listeners for mouse movement
|
||||||
|
document.addEventListener('mousemove', resetInactivityTimer);
|
||||||
|
document.addEventListener('keydown', resetInactivityTimer);
|
||||||
|
|
||||||
|
// Initialize inactivity timer on page load
|
||||||
|
resetInactivityTimer();
|
||||||
|
|
||||||
// Load playlist on page load
|
// Load playlist on page load
|
||||||
loadPlaylist();
|
loadPlaylist();
|
||||||
|
|
||||||
|
// Start periodic playlist reload
|
||||||
|
setInterval(loadPlaylist, 300000); // Check every 5 minutes (300,000 ms)
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user