functioning
This commit is contained in:
58
app.py
58
app.py
@@ -1,3 +1,5 @@
|
|||||||
|
import os
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
from flask import Flask, render_template, request, redirect, url_for
|
from flask import Flask, render_template, request, redirect, url_for
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
@@ -8,6 +10,13 @@ app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///dashboard.db'
|
|||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
UPLOAD_FOLDER = 'static/uploads'
|
||||||
|
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
||||||
|
|
||||||
|
# Ensure the upload folder exists
|
||||||
|
if not os.path.exists(UPLOAD_FOLDER):
|
||||||
|
os.makedirs(UPLOAD_FOLDER)
|
||||||
|
|
||||||
# Modele pentru baza de date
|
# Modele pentru baza de date
|
||||||
class Player(db.Model):
|
class Player(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@@ -96,12 +105,61 @@ def upload_content():
|
|||||||
groups = Group.query.all()
|
groups = Group.query.all()
|
||||||
return render_template('upload_content.html', players=players, groups=groups)
|
return render_template('upload_content.html', players=players, groups=groups)
|
||||||
|
|
||||||
|
# ...existing code...
|
||||||
|
|
||||||
|
@app.route('/content/<int:content_id>/edit', methods=['POST'])
|
||||||
|
def edit_content(content_id):
|
||||||
|
content = Content.query.get_or_404(content_id)
|
||||||
|
new_duration = int(request.form['duration'])
|
||||||
|
content.duration = new_duration
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('player_page', player_id=content.player_id))
|
||||||
|
|
||||||
|
@app.route('/content/<int:content_id>/delete', methods=['POST'])
|
||||||
|
def delete_content(content_id):
|
||||||
|
content = Content.query.get_or_404(content_id)
|
||||||
|
player_id = content.player_id
|
||||||
|
db.session.delete(content)
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('player_page', player_id=player_id))
|
||||||
|
|
||||||
|
# ...existing code...
|
||||||
|
|
||||||
|
@app.route('/player/<int:player_id>/fullscreen')
|
||||||
|
def player_fullscreen(player_id):
|
||||||
|
player = Player.query.get_or_404(player_id)
|
||||||
|
content = Content.query.filter_by(player_id=player_id).all()
|
||||||
|
return render_template('player_fullscreen.html', player=player, content=content)
|
||||||
|
|
||||||
@app.route('/player/<int:player_id>')
|
@app.route('/player/<int:player_id>')
|
||||||
def player_page(player_id):
|
def player_page(player_id):
|
||||||
player = Player.query.get_or_404(player_id)
|
player = Player.query.get_or_404(player_id)
|
||||||
content = Content.query.filter_by(player_id=player_id).all()
|
content = Content.query.filter_by(player_id=player_id).all()
|
||||||
return render_template('player_page.html', player=player, content=content)
|
return render_template('player_page.html', player=player, content=content)
|
||||||
|
|
||||||
|
@app.route('/player/<int:player_id>/upload', methods=['POST'])
|
||||||
|
def upload_content_to_player(player_id):
|
||||||
|
player = Player.query.get_or_404(player_id)
|
||||||
|
files = request.files.getlist('files')
|
||||||
|
duration = int(request.form['duration'])
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
filename = secure_filename(file.filename)
|
||||||
|
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||||
|
file.save(file_path)
|
||||||
|
new_content = Content(file_name=filename, duration=duration, player_id=player_id)
|
||||||
|
db.session.add(new_content)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('player_page', player_id=player_id))
|
||||||
|
|
||||||
|
@app.route('/player/<int:player_id>/delete', methods=['POST'])
|
||||||
|
def delete_player(player_id):
|
||||||
|
player = Player.query.get_or_404(player_id)
|
||||||
|
db.session.delete(player)
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all() # Creează toate tabelele
|
db.create_all() # Creează toate tabelele
|
||||||
|
|||||||
Binary file not shown.
10
models.py
Normal file
10
models.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from app import db
|
||||||
|
|
||||||
|
class Content(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
file_name = db.Column(db.String(120), nullable=False)
|
||||||
|
duration = db.Column(db.Integer, nullable=False)
|
||||||
|
player_id = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=True)
|
||||||
|
group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=True)
|
||||||
|
|
||||||
|
# other models...
|
||||||
BIN
static/uploads/moto.jpg
Normal file
BIN
static/uploads/moto.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
BIN
static/uploads/mure1.jpg
Normal file
BIN
static/uploads/mure1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
@@ -18,12 +18,22 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{% for player in players %}
|
{% for player in players %}
|
||||||
|
<!-- ...existing code... -->
|
||||||
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<div>
|
<div>
|
||||||
<strong>{{ player.username }}</strong> ({{ player.ip }})
|
<strong>{{ player.username }}</strong> ({{ player.ip }})
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
<a href="{{ url_for('player_page', player_id=player.id) }}" class="btn btn-sm btn-secondary">View Schedule</a>
|
<a href="{{ url_for('player_page', player_id=player.id) }}" class="btn btn-sm btn-secondary">View Schedule</a>
|
||||||
|
<a href="{{ url_for('player_fullscreen', player_id=player.id) }}" class="btn btn-sm btn-primary">Full Screen</a>
|
||||||
|
<form action="{{ url_for('delete_player', player_id=player.id) }}" method="post" style="display:inline;">
|
||||||
|
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this player?');">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<!-- ...existing code... -->
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
|
|||||||
49
templates/player_fullscreen.html
Normal file
49
templates/player_fullscreen.html
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Player Fullscreen Schedule</title>
|
||||||
|
<style>
|
||||||
|
body, html {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
img.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="content">
|
||||||
|
{% for item in content %}
|
||||||
|
<img src="{{ url_for('static', filename='uploads/' ~ item.file_name) }}" alt="Content Image" data-duration="{{ item.duration }}">
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const images = document.querySelectorAll('#content img');
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
function showNextImage() {
|
||||||
|
images.forEach((img, i) => {
|
||||||
|
img.classList.toggle('active', i === index);
|
||||||
|
});
|
||||||
|
const duration = images[index].getAttribute('data-duration') * 1000;
|
||||||
|
index = (index + 1) % images.length;
|
||||||
|
setTimeout(showNextImage, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (images.length > 0) {
|
||||||
|
images[0].classList.add('active');
|
||||||
|
showNextImage();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -2,14 +2,64 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Player Schedule</title>
|
<title>Player Schedule</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Player Schedule</h1>
|
<div class="container py-5">
|
||||||
<ul>
|
<h1 class="text-center mb-4">Player Schedule for {{ player.username }}</h1>
|
||||||
{% for item in schedule %}
|
|
||||||
<li>{{ item.file }} - {{ item.duration }} seconds</li>
|
<!-- Schedule Section -->
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h2>Schedule</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for item in content %}
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
{{ item.file_name }} - {{ item.duration }} seconds
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<!-- Edit Duration Form -->
|
||||||
|
<form action="{{ url_for('edit_content', content_id=item.id) }}" method="post" class="d-inline">
|
||||||
|
<input type="number" name="duration" value="{{ item.duration }}" class="form-control d-inline-block" style="width: 80px;" required>
|
||||||
|
<button type="submit" class="btn btn-sm btn-warning">Edit</button>
|
||||||
|
</form>
|
||||||
|
<!-- Delete Resource Form -->
|
||||||
|
<form action="{{ url_for('delete_content', content_id=item.id) }}" method="post" class="d-inline">
|
||||||
|
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this resource?');">Delete</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<a href="{{ url_for('dashboard') }}">Back to Dashboard</a>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upload Section -->
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header bg-success text-white">
|
||||||
|
<h2>Upload Content</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form action="{{ url_for('upload_content_to_player', player_id=player.id) }}" method="post" enctype="multipart/form-data">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="files" class="form-label">Select Images</label>
|
||||||
|
<input type="file" class="form-control" id="files" name="files" multiple required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="duration" class="form-label">Display Duration (seconds)</label>
|
||||||
|
<input type="number" class="form-control" id="duration" name="duration" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Upload</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary">Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user