Compare commits
No commits in common. "1847403254bf1d8b5202948c97d07d1e3f1d7aec" and "497320c0823f010216cec19305d8c129ca4a6a22" have entirely different histories.
1847403254
...
497320c082
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,3 @@
|
|||||||
.env
|
.env
|
||||||
env/*
|
env/*
|
||||||
.git
|
.git
|
||||||
db/*
|
|
||||||
|
@ -5,12 +5,6 @@ FROM python:3.10-slim
|
|||||||
ENV LISTEN_ADDRESS="0.0.0.0" \
|
ENV LISTEN_ADDRESS="0.0.0.0" \
|
||||||
LISTEN_PORT=8080
|
LISTEN_PORT=8080
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
build-essential \
|
|
||||||
libpq-dev \
|
|
||||||
gcc \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Set the working directory in the container
|
# Set the working directory in the container
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
@ -13,19 +13,6 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- mpv-youtube-queue-server
|
- mpv-youtube-queue-server
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
db:
|
|
||||||
image: lscr.io/linuxserver/mariadb:latest
|
|
||||||
container_name: mpv-youtube-queue-db
|
|
||||||
networks:
|
|
||||||
- mpv-youtube-queue-server
|
|
||||||
volumes:
|
|
||||||
- ./db:/config
|
|
||||||
environment:
|
|
||||||
- MYSQL_DATABASE=mpv
|
|
||||||
- MYSQL_USER=mpvuser
|
|
||||||
- MYSQL_PASSWORD=SecretPassword
|
|
||||||
ports:
|
|
||||||
- 3306:3306
|
|
||||||
networks:
|
networks:
|
||||||
mpv-youtube-queue-server:
|
mpv-youtube-queue-server:
|
||||||
external: true
|
external: true
|
||||||
|
15
env.example
15
env.example
@ -1,11 +1,12 @@
|
|||||||
LISTEN_ADDRESS=0.0.0.0 # Lisen on all interfaces
|
LISTEN_ADDRESS=0.0.0.0 # Lisen on all interfaces
|
||||||
LISTEN_PORT=8080 # Internal port number
|
LISTEN_PORT=8080 # Internal port number
|
||||||
MPV_SOCKET=/tmp/mpvsocket # Path to mpv socket
|
MPV_SOCKET=/tmp/mpvsocket # Path to mpv socket
|
||||||
LOGLEVEL=info
|
|
||||||
|
|
||||||
# Options:
|
# MySQL connection info
|
||||||
# mysql+pymysql://<user>:<password>@<host>[:<port>]/<dbname> - works with MySQL and Mariadb
|
MYSQL_HOST=localhost
|
||||||
# postgresql+psycopg2://user:password@host:port/dbname[?key=value&key=value...]
|
MYSQL_USER=mpvuser
|
||||||
# sqlite:///path
|
MYSQL_PASSWORD=SecretPassword
|
||||||
# oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
|
MYSQL_DATABASE=mpv
|
||||||
DATABASE_URL=mysql+pymysql://user:password@localhost:3306/mpv
|
MYSQL_PORT=3306
|
||||||
|
|
||||||
|
LOGLEVEL=info
|
||||||
|
@ -10,7 +10,10 @@ Restart=on-failure
|
|||||||
Environment="MPV_SOCKET=/tmp/mpvsocket"
|
Environment="MPV_SOCKET=/tmp/mpvsocket"
|
||||||
Environment="LISTEN_ADDRESS=0.0.0.0"
|
Environment="LISTEN_ADDRESS=0.0.0.0"
|
||||||
Environment="LISTEN_PORT=42069"
|
Environment="LISTEN_PORT=42069"
|
||||||
Environment="DATABASE_URL=mysql+mysqldb://user:password@localhost:3306/mpv"
|
Environment="MYSQL_HOST=http://localhost"
|
||||||
|
Environment="MYSQL_USER=mpvuser"
|
||||||
|
Environment="MYSQL_PASSWORD=SecretPassword"
|
||||||
|
Environment="MYSQL_PORT=3306"
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
@ -1,18 +1,10 @@
|
|||||||
blinker==1.8.2
|
blinker==1.8.2
|
||||||
cffi==1.17.1
|
|
||||||
click==8.1.7
|
click==8.1.7
|
||||||
cryptography==43.0.1
|
|
||||||
Flask==3.0.3
|
Flask==3.0.3
|
||||||
greenlet==3.0.3
|
|
||||||
gunicorn==23.0.0
|
gunicorn==23.0.0
|
||||||
itsdangerous==2.2.0
|
itsdangerous==2.2.0
|
||||||
Jinja2==3.1.4
|
Jinja2==3.1.4
|
||||||
MarkupSafe==2.1.5
|
MarkupSafe==2.1.5
|
||||||
oracledb==2.4.1
|
mysql-connector-python==9.0.0
|
||||||
packaging==24.1
|
packaging==24.1
|
||||||
psycopg2-binary==2.9.9
|
|
||||||
pycparser==2.22
|
|
||||||
PyMySQL==1.1.1
|
|
||||||
SQLAlchemy==2.0.34
|
|
||||||
typing_extensions==4.12.2
|
|
||||||
Werkzeug==3.0.4
|
Werkzeug==3.0.4
|
||||||
|
137
server.py
137
server.py
@ -3,17 +3,22 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
import urllib.parse
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
import mysql.connector
|
||||||
from flask import Flask, jsonify, request
|
from flask import Flask, jsonify, request
|
||||||
from sqlalchemy import Column, DateTime, Integer, String, create_engine, exc
|
from mysql.connector import Error
|
||||||
from sqlalchemy.orm import declarative_base, sessionmaker
|
|
||||||
from sqlalchemy.sql import func
|
|
||||||
|
|
||||||
# Set up basic logging
|
# Set up basic logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Ensure Flask doesn't duplicate log messages
|
||||||
|
log = logging.getLogger("werkzeug")
|
||||||
|
log.setLevel(logging.ERROR)
|
||||||
|
|
||||||
# Flask app
|
# Flask app
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@ -24,11 +29,16 @@ app.logger.setLevel(logging.getLogger().level)
|
|||||||
SOCKET_RETRY_DELAY = 5 # Time in seconds between retries to connect to the socket
|
SOCKET_RETRY_DELAY = 5 # Time in seconds between retries to connect to the socket
|
||||||
MAX_RETRIES = 10 # Maximum number of retries to connect to the socket
|
MAX_RETRIES = 10 # Maximum number of retries to connect to the socket
|
||||||
|
|
||||||
# Configuration from environment variables
|
# Configuration
|
||||||
LISTEN_ADDRESS = os.getenv("LISTEN_ADDRESS", "0.0.0.0")
|
|
||||||
LISTEN_PORT = int(os.getenv("LISTEN_PORT", "8080"))
|
|
||||||
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./mpv.db")
|
|
||||||
MPV_SOCKET: str = os.getenv("MPV_SOCKET", "/tmp/mpvsocket")
|
MPV_SOCKET: str = os.getenv("MPV_SOCKET", "/tmp/mpvsocket")
|
||||||
|
HOST_NAME: str = os.getenv("HOST_NAME", "0.0.0.0")
|
||||||
|
PORT_NUMBER: int = int(os.getenv("PORT_NUMBER", "8080"))
|
||||||
|
# MySQL Configuration
|
||||||
|
MYSQL_HOST: str = os.getenv("MYSQL_HOST", "localhost")
|
||||||
|
MYSQL_DATABASE: str = os.getenv("MYSQL_DATABASE", "your_database")
|
||||||
|
MYSQL_USER: str = os.getenv("MYSQL_USER", "your_username")
|
||||||
|
MYSQL_PASSWORD: str = os.getenv("MYSQL_PASSWORD", "your_password")
|
||||||
|
MYSQL_PORT: int = int(os.getenv("MYSQL_PORT", "3306"))
|
||||||
LOGLEVEL = os.getenv("LOGLEVEL", "INFO").strip().upper()
|
LOGLEVEL = os.getenv("LOGLEVEL", "INFO").strip().upper()
|
||||||
|
|
||||||
if LOGLEVEL == "DEBUG":
|
if LOGLEVEL == "DEBUG":
|
||||||
@ -40,29 +50,53 @@ elif LOGLEVEL == "ERROR":
|
|||||||
else:
|
else:
|
||||||
logging.getLogger().setLevel(logging.INFO)
|
logging.getLogger().setLevel(logging.INFO)
|
||||||
|
|
||||||
# Set up SQLAlchemy
|
|
||||||
Base = declarative_base()
|
|
||||||
engine = create_engine(DATABASE_URL)
|
|
||||||
Session = sessionmaker(bind=engine)
|
|
||||||
session = Session()
|
|
||||||
|
|
||||||
|
def get_mysql_connection():
|
||||||
class WatchHistory(Base):
|
"""Get a MySQL database connection."""
|
||||||
__tablename__ = "watch_history"
|
try:
|
||||||
|
logging.debug(
|
||||||
whid = Column(Integer, primary_key=True, autoincrement=True)
|
f"Connection information: {MYSQL_HOST}, {MYSQL_USER}, {MYSQL_PORT}"
|
||||||
video_url = Column(String(255), nullable=False)
|
|
||||||
video_name = Column(String(255), nullable=False)
|
|
||||||
channel_url = Column(String(255), nullable=False)
|
|
||||||
channel_name = Column(String(255), nullable=False)
|
|
||||||
watch_date = Column(DateTime, nullable=False, server_default=func.now())
|
|
||||||
created_by = Column(
|
|
||||||
String(100), nullable=False, server_default="mpv-youtube-queue-server"
|
|
||||||
)
|
)
|
||||||
|
connection = mysql.connector.connect(
|
||||||
|
host=MYSQL_HOST,
|
||||||
|
user=MYSQL_USER,
|
||||||
|
password=MYSQL_PASSWORD,
|
||||||
|
port=MYSQL_PORT,
|
||||||
|
)
|
||||||
|
if connection.is_connected():
|
||||||
|
logging.info("Connected to MySQL database")
|
||||||
|
return connection
|
||||||
|
except Error as e:
|
||||||
|
logging.error(f"Error while connecting to MySQL: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# Ensure tables exist
|
def ensure_watch_history_table_exists():
|
||||||
Base.metadata.create_all(engine)
|
"""Ensure the watch_history table exists in the mpv schema, otherwise create it."""
|
||||||
|
connection = get_mysql_connection()
|
||||||
|
if connection:
|
||||||
|
try:
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("CREATE DATABASE IF NOT EXISTS mpv")
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS mpv.watch_history (
|
||||||
|
whid INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
video_url VARCHAR(255) NOT NULL,
|
||||||
|
video_name VARCHAR(255) NOT NULL,
|
||||||
|
channel_url VARCHAR(255) NOT NULL,
|
||||||
|
channel_name VARCHAR(255) NOT NULL,
|
||||||
|
watch_date DATE NOT NULL
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
connection.commit()
|
||||||
|
logging.info("Ensured watch_history table exists")
|
||||||
|
except Error as e:
|
||||||
|
logging.error(f"Failed to ensure watch_history table exists: {e}")
|
||||||
|
finally:
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
|
||||||
def send_to_mpv(command):
|
def send_to_mpv(command):
|
||||||
@ -95,27 +129,45 @@ def add_video():
|
|||||||
video_name: str = data.get("video_name")
|
video_name: str = data.get("video_name")
|
||||||
channel_url: str = data.get("channel_url")
|
channel_url: str = data.get("channel_url")
|
||||||
channel_name: str = data.get("channel_name")
|
channel_name: str = data.get("channel_name")
|
||||||
|
watch_date: date = date.today().strftime("%Y-%m-%d")
|
||||||
|
|
||||||
if video_url and video_name and channel_url and channel_name:
|
if video_url and video_name and channel_url and channel_name and watch_date:
|
||||||
logging.debug(f"Received data: {data}")
|
logging.debug(f"Received data: {data}")
|
||||||
|
logging.debug(f"Watch date: {watch_date}")
|
||||||
|
|
||||||
|
# Insert the data into the MySQL database
|
||||||
|
connection = get_mysql_connection()
|
||||||
|
if connection:
|
||||||
try:
|
try:
|
||||||
new_entry = WatchHistory(
|
query = """
|
||||||
video_url=video_url,
|
INSERT INTO mpv.watch_history (video_url, video_name, channel_url, channel_name, watch_date)
|
||||||
video_name=video_name,
|
VALUES (%s, %s, %s, %s, %s)
|
||||||
channel_url=channel_url,
|
"""
|
||||||
channel_name=channel_name,
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
query,
|
||||||
|
(
|
||||||
|
video_url,
|
||||||
|
video_name,
|
||||||
|
channel_url,
|
||||||
|
channel_name,
|
||||||
|
watch_date,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
session.add(new_entry)
|
connection.commit()
|
||||||
session.commit()
|
logging.info("Data inserted into MySQL database")
|
||||||
logging.debug(
|
return (
|
||||||
f"{video_name} by {channel_name} inserted into the database successfully"
|
jsonify(message="Data added to mpv queue and database"),
|
||||||
|
200,
|
||||||
)
|
)
|
||||||
return jsonify(message="Data added to mpv queue and database"), 200
|
except Error as e:
|
||||||
except exc.SQLAlchemyError as e:
|
logging.error(f"Failed to insert data into MySQL database: {e}")
|
||||||
session.rollback()
|
|
||||||
logging.error(f"Failed to insert data into database: {e}")
|
|
||||||
return jsonify(message="Failed to add data to database"), 500
|
return jsonify(message="Failed to add data to database"), 500
|
||||||
|
finally:
|
||||||
|
cursor.close()
|
||||||
|
connection.close()
|
||||||
|
else:
|
||||||
|
return jsonify(message="Failed to connect to MySQL database"), 500
|
||||||
else:
|
else:
|
||||||
logging.error("Missing required data fields")
|
logging.error("Missing required data fields")
|
||||||
return jsonify(message="Missing required data fields"), 400
|
return jsonify(message="Missing required data fields"), 400
|
||||||
@ -145,9 +197,10 @@ def handle_request():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logging.info(f"Starting server on {LISTEN_ADDRESS}:{LISTEN_PORT}...")
|
logging.info(f"Starting server on {HOST_NAME}:{PORT_NUMBER}...")
|
||||||
|
ensure_watch_history_table_exists()
|
||||||
try:
|
try:
|
||||||
app.run(host=LISTEN_ADDRESS, port=LISTEN_PORT)
|
app.run(host=HOST_NAME, port=PORT_NUMBER)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception(f"Error occurred: {e}")
|
logging.exception(f"Error occurred: {e}")
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
Loading…
Reference in New Issue
Block a user