updated solution
This commit is contained in:
21
.env.example
Normal file
21
.env.example
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# .env - Flask environment variables
|
||||||
|
|
||||||
|
# Flask secret key (change this to something secure in production)
|
||||||
|
SECRET_KEY=Ana_Are_Multe_Mere-Si_Nu_Are_Pere
|
||||||
|
|
||||||
|
# Flask environment: development or production
|
||||||
|
FLASK_ENV=development
|
||||||
|
|
||||||
|
# Database location (optional, defaults to instance/dashboard.db)
|
||||||
|
# SQLALCHEMY_DATABASE_URI=sqlite:///instance/dashboard.db
|
||||||
|
|
||||||
|
# Default admin user credentials (used for auto-creation)
|
||||||
|
DEFAULT_USER=admin
|
||||||
|
DEFAULT_PASSWORD=1234
|
||||||
|
|
||||||
|
# Flask server settings
|
||||||
|
HOST=0.0.0.0
|
||||||
|
PORT=5000
|
||||||
|
|
||||||
|
# Maximum upload size (in bytes, 2GB)
|
||||||
|
MAX_CONTENT_LENGTH=2147483648
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
digiscreen/
|
digiscreen/
|
||||||
|
.env
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
31
app.py
31
app.py
@@ -7,9 +7,13 @@ from werkzeug.utils import secure_filename
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
from extensions import db, bcrypt, login_manager
|
from extensions import db, bcrypt, login_manager
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment variables from .env file
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
# First import models
|
# First import models
|
||||||
from models import User, Player, Content, Group, ServerLog
|
from models import User, Player, Group, Content, ServerLog, group_player
|
||||||
|
|
||||||
# Then import utilities that use the models
|
# Then import utilities that use the models
|
||||||
from flask_login import login_user, logout_user, login_required, current_user
|
from flask_login import login_user, logout_user, login_required, current_user
|
||||||
@@ -47,8 +51,10 @@ app = Flask(__name__, instance_relative_config=True)
|
|||||||
# Set the secret key from environment variable or use a default value
|
# Set the secret key from environment variable or use a default value
|
||||||
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'Ana_Are_Multe_Mere-Si_Nu_Are_Pere')
|
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'Ana_Are_Multe_Mere-Si_Nu_Are_Pere')
|
||||||
|
|
||||||
# Configure the database location to be in the instance folder
|
instance_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'instance'))
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(app.instance_path, 'dashboard.db')
|
os.makedirs(instance_dir, exist_ok=True)
|
||||||
|
db_path = os.path.join(instance_dir, 'dashboard.db')
|
||||||
|
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
|
|
||||||
# Set maximum content length to 1GB
|
# Set maximum content length to 1GB
|
||||||
@@ -56,6 +62,7 @@ app.config['MAX_CONTENT_LENGTH'] = 2048 * 2048 * 2048 # 2GB, adjust as needed
|
|||||||
|
|
||||||
# Ensure the instance folder exists
|
# Ensure the instance folder exists
|
||||||
os.makedirs(app.instance_path, exist_ok=True)
|
os.makedirs(app.instance_path, exist_ok=True)
|
||||||
|
os.makedirs(instance_dir, exist_ok=True)
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
bcrypt.init_app(app)
|
bcrypt.init_app(app)
|
||||||
@@ -68,8 +75,9 @@ app.config['UPLOAD_FOLDERLOGO'] = UPLOAD_FOLDERLOGO
|
|||||||
|
|
||||||
# Ensure the upload folder exists
|
# Ensure the upload folder exists
|
||||||
if not os.path.exists(UPLOAD_FOLDER):
|
if not os.path.exists(UPLOAD_FOLDER):
|
||||||
os.makedirs(UPLOAD_FOLDER)
|
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||||||
os.makedirs(UPLOAD_FOLDERLOGO)
|
if not os.path.exists(UPLOAD_FOLDERLOGO):
|
||||||
|
os.makedirs(UPLOAD_FOLDERLOGO, exist_ok=True)
|
||||||
|
|
||||||
login_manager.login_view = 'login'
|
login_manager.login_view = 'login'
|
||||||
|
|
||||||
@@ -303,7 +311,8 @@ def add_player():
|
|||||||
hostname = request.form['hostname']
|
hostname = request.form['hostname']
|
||||||
password = bcrypt.generate_password_hash(request.form['password']).decode('utf-8')
|
password = bcrypt.generate_password_hash(request.form['password']).decode('utf-8')
|
||||||
quickconnect_password = bcrypt.generate_password_hash(request.form['quickconnect_password']).decode('utf-8')
|
quickconnect_password = bcrypt.generate_password_hash(request.form['quickconnect_password']).decode('utf-8')
|
||||||
add_player_util(username, hostname, password, quickconnect_password)
|
orientation = request.form.get('orientation', 'Landscape') # <-- Get orientation
|
||||||
|
add_player_util(username, hostname, password, quickconnect_password, orientation) # <-- Pass orientation
|
||||||
flash(f'Player "{username}" added successfully.', 'success')
|
flash(f'Player "{username}" added successfully.', 'success')
|
||||||
return redirect(url_for('dashboard'))
|
return redirect(url_for('dashboard'))
|
||||||
return render_template('add_player.html')
|
return render_template('add_player.html')
|
||||||
@@ -637,6 +646,16 @@ def create_admin(username, password):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
print(f"Admin user '{username}' created successfully.")
|
print(f"Admin user '{username}' created successfully.")
|
||||||
|
|
||||||
|
from models.create_default_user import create_default_user
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
try:
|
||||||
|
db.session.execute(db.select(User).limit(1))
|
||||||
|
except Exception as e:
|
||||||
|
print("Database not initialized or missing tables. Re-initializing...")
|
||||||
|
db.create_all()
|
||||||
|
# Always ensure default user exists
|
||||||
|
create_default_user(db, User, bcrypt)
|
||||||
|
|
||||||
# Add this at the end of app.py
|
# Add this at the end of app.py
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
14
clear_db.py
14
clear_db.py
@@ -1,14 +0,0 @@
|
|||||||
import os
|
|
||||||
from flask import Flask
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
|
|
||||||
# Create a minimal Flask app just for clearing the database
|
|
||||||
app = Flask(__name__)
|
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///instance/dashboard.db'
|
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
|
||||||
db = SQLAlchemy(app)
|
|
||||||
|
|
||||||
with app.app_context():
|
|
||||||
db.reflect() # This loads all tables from the database
|
|
||||||
db.drop_all()
|
|
||||||
print("Dropped all tables successfully.")
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from app import app, db, User, bcrypt
|
|
||||||
|
|
||||||
# Create the default user
|
|
||||||
username = 'admin'
|
|
||||||
password = '1234'
|
|
||||||
hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
|
|
||||||
|
|
||||||
with app.app_context():
|
|
||||||
# Delete the existing user if it exists
|
|
||||||
existing_user = User.query.filter_by(username=username).first()
|
|
||||||
if existing_user:
|
|
||||||
db.session.delete(existing_user)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
# Add the new user to the database
|
|
||||||
default_user = User(username=username, password=hashed_password, role='admin')
|
|
||||||
db.session.add(default_user)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
print(f"Default user '{username}' created with password '{password}'")
|
|
||||||
Binary file not shown.
77
models.py
77
models.py
@@ -1,77 +0,0 @@
|
|||||||
from extensions import db
|
|
||||||
from flask_bcrypt import Bcrypt
|
|
||||||
from flask_login import UserMixin
|
|
||||||
import datetime # Add this import
|
|
||||||
|
|
||||||
bcrypt = Bcrypt()
|
|
||||||
|
|
||||||
# Add this new model
|
|
||||||
class ServerLog(db.Model):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
action = db.Column(db.String(255), nullable=False)
|
|
||||||
timestamp = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"<ServerLog {self.action}>"
|
|
||||||
|
|
||||||
class Content(db.Model):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
file_name = db.Column(db.String(255), nullable=False)
|
|
||||||
duration = db.Column(db.Integer, nullable=False)
|
|
||||||
player_id = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=False)
|
|
||||||
position = db.Column(db.Integer, default=0) # This field must exist
|
|
||||||
|
|
||||||
class Player(db.Model):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
username = db.Column(db.String(255), nullable=False)
|
|
||||||
hostname = db.Column(db.String(255), nullable=False)
|
|
||||||
password = db.Column(db.String(255), nullable=False)
|
|
||||||
quickconnect_password = db.Column(db.String(255), nullable=True)
|
|
||||||
playlist_version = db.Column(db.Integer, default=1) # Make sure this exists
|
|
||||||
locked_to_group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=True)
|
|
||||||
locked_to_group = db.relationship('Group', foreign_keys=[locked_to_group_id], backref='locked_players')
|
|
||||||
|
|
||||||
def verify_quickconnect_code(self, code):
|
|
||||||
return bcrypt.check_password_hash(self.quickconnect_password, code)
|
|
||||||
|
|
||||||
class User(db.Model, UserMixin):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
username = db.Column(db.String(80), unique=True, nullable=False)
|
|
||||||
password = db.Column(db.String(120), nullable=False)
|
|
||||||
role = db.Column(db.String(80), nullable=False)
|
|
||||||
theme = db.Column(db.String(80), default='light')
|
|
||||||
|
|
||||||
def set_password(self, password):
|
|
||||||
self.password = bcrypt.generate_password_hash(password).decode('utf-8')
|
|
||||||
|
|
||||||
def check_password(self, password):
|
|
||||||
return bcrypt.check_password_hash(self.password, password)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_active(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_authenticated(self):
|
|
||||||
return True
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_anonymous(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_id(self):
|
|
||||||
return str(self.id)
|
|
||||||
|
|
||||||
class Group(db.Model):
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
name = db.Column(db.String(100), nullable=False, unique=True)
|
|
||||||
players = db.relationship('Player', secondary='group_player', backref='groups')
|
|
||||||
playlist_version = db.Column(db.Integer, default=0) # Playlist version counter
|
|
||||||
|
|
||||||
# Association table for many-to-many relationship between Group and Player
|
|
||||||
group_player = db.Table('group_player',
|
|
||||||
db.Column('group_id', db.Integer, db.ForeignKey('group.id'), primary_key=True),
|
|
||||||
db.Column('player_id', db.Integer, db.ForeignKey('player.id'), primary_key=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
# other models...
|
|
||||||
5
models/__init__.py
Normal file
5
models/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from .user import User
|
||||||
|
from .player import Player
|
||||||
|
from .group import Group, group_player
|
||||||
|
from .content import Content
|
||||||
|
from .server_log import ServerLog
|
||||||
BIN
models/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
models/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/content.cpython-311.pyc
Normal file
BIN
models/__pycache__/content.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/create_default_user.cpython-311.pyc
Normal file
BIN
models/__pycache__/create_default_user.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/group.cpython-311.pyc
Normal file
BIN
models/__pycache__/group.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/player.cpython-311.pyc
Normal file
BIN
models/__pycache__/player.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/server_log.cpython-311.pyc
Normal file
BIN
models/__pycache__/server_log.cpython-311.pyc
Normal file
Binary file not shown.
BIN
models/__pycache__/user.cpython-311.pyc
Normal file
BIN
models/__pycache__/user.cpython-311.pyc
Normal file
Binary file not shown.
21
models/clear_db.py
Normal file
21
models/clear_db.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import os
|
||||||
|
from flask import Flask
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
# Ensure the instance directory exists (relative to project root)
|
||||||
|
instance_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'instance'))
|
||||||
|
os.makedirs(instance_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Set the correct database URI
|
||||||
|
db_path = os.path.join(instance_dir, 'dashboard.db')
|
||||||
|
print(f"Using database at: {db_path}")
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'
|
||||||
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
db.reflect() # This loads all tables from the database
|
||||||
|
db.drop_all()
|
||||||
|
print("Dropped all tables successfully.")
|
||||||
8
models/content.py
Normal file
8
models/content.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from extensions import db
|
||||||
|
|
||||||
|
class Content(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
file_name = db.Column(db.String(255), nullable=False)
|
||||||
|
duration = db.Column(db.Integer, nullable=False)
|
||||||
|
player_id = db.Column(db.Integer, db.ForeignKey('player.id'), nullable=False)
|
||||||
|
position = db.Column(db.Integer, default=0)
|
||||||
18
models/create_default_user.py
Normal file
18
models/create_default_user.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#from app import app, db, User, bcrypt
|
||||||
|
import os
|
||||||
|
|
||||||
|
def create_default_user(db, User, bcrypt):
|
||||||
|
username = os.getenv('DEFAULT_USER', 'admin')
|
||||||
|
password = os.getenv('DEFAULT_PASSWORD', '1234')
|
||||||
|
hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
|
||||||
|
existing_user = User.query.filter_by(username=username).first()
|
||||||
|
if not existing_user:
|
||||||
|
default_user = User(username=username, password=hashed_password, role='admin')
|
||||||
|
db.session.add(default_user)
|
||||||
|
db.session.commit()
|
||||||
|
print(f"Default user '{username}' created with password '{password}'")
|
||||||
|
else:
|
||||||
|
print(f"Default user '{username}' already exists.")
|
||||||
|
|
||||||
|
#with app.app_context():
|
||||||
|
# create_default_user(db, User, bcrypt)
|
||||||
13
models/group.py
Normal file
13
models/group.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from extensions import db
|
||||||
|
|
||||||
|
class Group(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
name = db.Column(db.String(100), nullable=False, unique=True)
|
||||||
|
orientation = db.Column(db.String(16), nullable=False, default='Landscape') # <-- Add this line
|
||||||
|
players = db.relationship('Player', secondary='group_player', backref='groups')
|
||||||
|
playlist_version = db.Column(db.Integer, default=0)
|
||||||
|
|
||||||
|
group_player = db.Table('group_player',
|
||||||
|
db.Column('group_id', db.Integer, db.ForeignKey('group.id'), primary_key=True),
|
||||||
|
db.Column('player_id', db.Integer, db.ForeignKey('player.id'), primary_key=True)
|
||||||
|
)
|
||||||
18
models/player.py
Normal file
18
models/player.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from extensions import db
|
||||||
|
from flask_bcrypt import Bcrypt
|
||||||
|
|
||||||
|
bcrypt = Bcrypt()
|
||||||
|
|
||||||
|
class Player(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
username = db.Column(db.String(255), nullable=False)
|
||||||
|
hostname = db.Column(db.String(255), nullable=False)
|
||||||
|
password = db.Column(db.String(255), nullable=False)
|
||||||
|
quickconnect_password = db.Column(db.String(255), nullable=True)
|
||||||
|
playlist_version = db.Column(db.Integer, default=1)
|
||||||
|
locked_to_group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=True)
|
||||||
|
locked_to_group = db.relationship('Group', foreign_keys=[locked_to_group_id], backref='locked_players')
|
||||||
|
orientation = db.Column(db.String(16), nullable=False, default='Landscape') # <-- Add this line
|
||||||
|
|
||||||
|
def verify_quickconnect_code(self, code):
|
||||||
|
return bcrypt.check_password_hash(self.quickconnect_password, code)
|
||||||
10
models/server_log.py
Normal file
10
models/server_log.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from extensions import db
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
class ServerLog(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
action = db.Column(db.String(255), nullable=False)
|
||||||
|
timestamp = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<ServerLog {self.action}>"
|
||||||
33
models/user.py
Normal file
33
models/user.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
from extensions import db
|
||||||
|
from flask_bcrypt import Bcrypt
|
||||||
|
from flask_login import UserMixin
|
||||||
|
|
||||||
|
bcrypt = Bcrypt()
|
||||||
|
|
||||||
|
class User(db.Model, UserMixin):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
username = db.Column(db.String(80), unique=True, nullable=False)
|
||||||
|
password = db.Column(db.String(120), nullable=False)
|
||||||
|
role = db.Column(db.String(80), nullable=False)
|
||||||
|
theme = db.Column(db.String(80), default='light')
|
||||||
|
|
||||||
|
def set_password(self, password):
|
||||||
|
self.password = bcrypt.generate_password_hash(password).decode('utf-8')
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
return bcrypt.check_password_hash(self.password, password)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_active(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_authenticated(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_anonymous(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_id(self):
|
||||||
|
return str(self.id)
|
||||||
@@ -60,6 +60,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 col-12">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="orientation" class="form-label">Orientation</label>
|
||||||
|
<select class="form-control {{ 'dark-mode' if theme == 'dark' else '' }}" id="orientation" name="orientation" required>
|
||||||
|
<option value="Landscape" selected>Landscape</option>
|
||||||
|
<option value="Portret">Portret</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<button type="submit" class="btn btn-primary">Add Player</button>
|
<button type="submit" class="btn btn-primary">Add Player</button>
|
||||||
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary mt-3">Back to Dashboard</a>
|
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary mt-3">Back to Dashboard</a>
|
||||||
|
|||||||
60
test_api.py
60
test_api.py
@@ -1,60 +0,0 @@
|
|||||||
import requests
|
|
||||||
import os
|
|
||||||
|
|
||||||
# Replace with the actual server IP address or domain name, hostname, and quick connect code
|
|
||||||
server_ip = 'http://localhost:5000'
|
|
||||||
hostname = 'rpi-tv11'
|
|
||||||
quickconnect_code = '8887779'
|
|
||||||
|
|
||||||
# Construct the URL for the playlist API
|
|
||||||
url = f'{server_ip}/api/playlists'
|
|
||||||
params = {
|
|
||||||
'hostname': hostname,
|
|
||||||
'quickconnect_code': quickconnect_code
|
|
||||||
}
|
|
||||||
|
|
||||||
# Make the GET request to the API
|
|
||||||
response = requests.get(url, params=params)
|
|
||||||
|
|
||||||
# Print the raw response content and status code for debugging
|
|
||||||
print(f'Status Code: {response.status_code}')
|
|
||||||
print(f'Response Content: {response.text}')
|
|
||||||
|
|
||||||
# Check if the request was successful
|
|
||||||
if response.status_code == 200:
|
|
||||||
try:
|
|
||||||
# Parse the JSON response
|
|
||||||
response_data = response.json()
|
|
||||||
playlist = response_data.get('playlist', [])
|
|
||||||
playlist_version = response_data.get('playlist_version', None)
|
|
||||||
|
|
||||||
print(f'Playlist Version: {playlist_version}')
|
|
||||||
print(f'Playlist: {playlist}')
|
|
||||||
|
|
||||||
# Define the local folder for saving files
|
|
||||||
local_folder = './static/resurse'
|
|
||||||
if not os.path.exists(local_folder):
|
|
||||||
os.makedirs(local_folder)
|
|
||||||
|
|
||||||
# Download each file in the playlist
|
|
||||||
for media in playlist:
|
|
||||||
file_name = media.get('file_name', '')
|
|
||||||
file_url = media.get('url', '')
|
|
||||||
duration = media.get('duration', 10) # Default duration if not provided
|
|
||||||
local_file_path = os.path.join(local_folder, file_name)
|
|
||||||
|
|
||||||
print(f'Downloading {file_name} from {file_url}...')
|
|
||||||
try:
|
|
||||||
file_response = requests.get(file_url, timeout=10)
|
|
||||||
if file_response.status_code == 200:
|
|
||||||
with open(local_file_path, 'wb') as file:
|
|
||||||
file.write(file_response.content)
|
|
||||||
print(f'Successfully downloaded {file_name} to {local_file_path}')
|
|
||||||
else:
|
|
||||||
print(f'Failed to download {file_name}. Status Code: {file_response.status_code}')
|
|
||||||
except requests.exceptions.RequestException as e:
|
|
||||||
print(f'Error downloading {file_name}: {e}')
|
|
||||||
except requests.exceptions.JSONDecodeError as e:
|
|
||||||
print(f'Failed to parse JSON response: {e}')
|
|
||||||
else:
|
|
||||||
print(f'Failed to retrieve playlist. Status Code: {response.status_code}')
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -8,28 +8,29 @@ from utils.logger import (
|
|||||||
log_content_duration_changed, log_content_added
|
log_content_duration_changed, log_content_added
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_group(name, player_ids):
|
def create_group(name, player_ids, orientation='Landscape'):
|
||||||
"""
|
"""
|
||||||
Create a new group with the given name and add selected players to it.
|
Create a new group with the given name, orientation, and add selected players.
|
||||||
Clears individual playlists of players and locks them to the group.
|
Only players with the same orientation can be added.
|
||||||
"""
|
"""
|
||||||
new_group = Group(name=name)
|
# Check all players have the same orientation
|
||||||
|
for player_id in player_ids:
|
||||||
|
player = Player.query.get(player_id)
|
||||||
|
if player and player.orientation != orientation:
|
||||||
|
raise ValueError(f"Player '{player.username}' has orientation '{player.orientation}', which does not match group orientation '{orientation}'.")
|
||||||
|
|
||||||
|
new_group = Group(name=name, orientation=orientation)
|
||||||
db.session.add(new_group)
|
db.session.add(new_group)
|
||||||
db.session.flush() # Get the group ID
|
db.session.flush() # Get the group ID
|
||||||
|
|
||||||
# Add players to the group and lock them
|
# Add players to the group and lock them
|
||||||
for player_id in player_ids:
|
for player_id in player_ids:
|
||||||
player = Player.query.get(player_id)
|
player = Player.query.get(player_id)
|
||||||
if player:
|
if player:
|
||||||
# Add player to group
|
|
||||||
new_group.players.append(player)
|
new_group.players.append(player)
|
||||||
|
|
||||||
# Delete player's individual playlist
|
|
||||||
Content.query.filter_by(player_id=player.id).delete()
|
Content.query.filter_by(player_id=player.id).delete()
|
||||||
|
|
||||||
# Lock player to this group
|
|
||||||
player.locked_to_group_id = new_group.id
|
player.locked_to_group_id = new_group.id
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
log_group_created(name)
|
log_group_created(name)
|
||||||
return new_group
|
return new_group
|
||||||
@@ -106,7 +107,7 @@ def delete_group(group_id):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
log_group_deleted(group_name)
|
log_group_deleted(group_name)
|
||||||
|
|
||||||
def add_player(username, hostname, password, quickconnect_password):
|
def add_player(username, hostname, password, quickconnect_password, orientation='Landscape'):
|
||||||
"""
|
"""
|
||||||
Add a new player with the given details.
|
Add a new player with the given details.
|
||||||
"""
|
"""
|
||||||
@@ -120,7 +121,8 @@ def add_player(username, hostname, password, quickconnect_password):
|
|||||||
username=username,
|
username=username,
|
||||||
hostname=hostname,
|
hostname=hostname,
|
||||||
password=hashed_password,
|
password=hashed_password,
|
||||||
quickconnect_password=hashed_quickconnect
|
quickconnect_password=hashed_quickconnect,
|
||||||
|
orientation=orientation
|
||||||
)
|
)
|
||||||
|
|
||||||
db.session.add(new_player)
|
db.session.add(new_player)
|
||||||
|
|||||||
Reference in New Issue
Block a user