Compare commits

..

3 Commits

Author SHA1 Message Date
1847403254
remove creation_date column 2024-09-06 02:55:10 -07:00
badcee8d7c
update requirements 2024-09-06 02:15:33 -07:00
ksyasuda
1c0eb91333
update to use sqlalchemy
- change from mysql-connector-python to sqlalchemy
    - allow for connection to sqlite3, mysql, mariadb, postgres, and
oracle databases
- change `DATE` columns to `DATETIME` type
- add WHO columns
- install database connectors and required packages
2024-09-06 02:14:12 -07:00
8 changed files with 86 additions and 115 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.env
env/*
.git
db/*

View File

@ -5,6 +5,12 @@ FROM python:3.10-slim
ENV LISTEN_ADDRESS="0.0.0.0" \
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
WORKDIR /app

View File

@ -1 +1 @@
0.0.2
0.1.0

View File

@ -13,6 +13,19 @@ services:
networks:
- mpv-youtube-queue-server
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:
mpv-youtube-queue-server:
external: true

View File

@ -1,12 +1,11 @@
LISTEN_ADDRESS=0.0.0.0 # Lisen on all interfaces
LISTEN_PORT=8080 # Internal port number
MPV_SOCKET=/tmp/mpvsocket # Path to mpv socket
# MySQL connection info
MYSQL_HOST=localhost
MYSQL_USER=mpvuser
MYSQL_PASSWORD=SecretPassword
MYSQL_DATABASE=mpv
MYSQL_PORT=3306
LOGLEVEL=info
# Options:
# mysql+pymysql://<user>:<password>@<host>[:<port>]/<dbname> - works with MySQL and Mariadb
# postgresql+psycopg2://user:password@host:port/dbname[?key=value&key=value...]
# sqlite:///path
# oracle+oracledb://user:pass@hostname:port[/dbname][?service_name=<service>[&key=value&key=value...]]
DATABASE_URL=mysql+pymysql://user:password@localhost:3306/mpv

View File

@ -10,10 +10,7 @@ Restart=on-failure
Environment="MPV_SOCKET=/tmp/mpvsocket"
Environment="LISTEN_ADDRESS=0.0.0.0"
Environment="LISTEN_PORT=42069"
Environment="MYSQL_HOST=http://localhost"
Environment="MYSQL_USER=mpvuser"
Environment="MYSQL_PASSWORD=SecretPassword"
Environment="MYSQL_PORT=3306"
Environment="DATABASE_URL=mysql+mysqldb://user:password@localhost:3306/mpv"
[Install]
WantedBy=multi-user.target

View File

@ -1,10 +1,18 @@
blinker==1.8.2
cffi==1.17.1
click==8.1.7
cryptography==43.0.1
Flask==3.0.3
greenlet==3.0.3
gunicorn==23.0.0
itsdangerous==2.2.0
Jinja2==3.1.4
MarkupSafe==2.1.5
mysql-connector-python==9.0.0
oracledb==2.4.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

149
server.py
View File

@ -3,22 +3,17 @@ import logging
import os
import socket
import time
import urllib.parse
from datetime import date
import mysql.connector
from flask import Flask, jsonify, request
from mysql.connector import Error
from sqlalchemy import Column, DateTime, Integer, String, create_engine, exc
from sqlalchemy.orm import declarative_base, sessionmaker
from sqlalchemy.sql import func
# Set up basic logging
logging.basicConfig(
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
app = Flask(__name__)
@ -29,16 +24,11 @@ app.logger.setLevel(logging.getLogger().level)
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
# Configuration
# Configuration from environment variables
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")
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()
if LOGLEVEL == "DEBUG":
@ -50,53 +40,29 @@ elif LOGLEVEL == "ERROR":
else:
logging.getLogger().setLevel(logging.INFO)
def get_mysql_connection():
"""Get a MySQL database connection."""
try:
logging.debug(
f"Connection information: {MYSQL_HOST}, {MYSQL_USER}, {MYSQL_PORT}"
)
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
# Set up SQLAlchemy
Base = declarative_base()
engine = create_engine(DATABASE_URL)
Session = sessionmaker(bind=engine)
session = Session()
def ensure_watch_history_table_exists():
"""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()
class WatchHistory(Base):
__tablename__ = "watch_history"
whid = Column(Integer, primary_key=True, autoincrement=True)
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"
)
# Ensure tables exist
Base.metadata.create_all(engine)
def send_to_mpv(command):
@ -129,45 +95,27 @@ def add_video():
video_name: str = data.get("video_name")
channel_url: str = data.get("channel_url")
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 and watch_date:
if video_url and video_name and channel_url and channel_name:
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:
query = """
INSERT INTO mpv.watch_history (video_url, video_name, channel_url, channel_name, watch_date)
VALUES (%s, %s, %s, %s, %s)
"""
cursor = connection.cursor()
cursor.execute(
query,
(
video_url,
video_name,
channel_url,
channel_name,
watch_date,
),
)
connection.commit()
logging.info("Data inserted into MySQL database")
return (
jsonify(message="Data added to mpv queue and database"),
200,
)
except Error as e:
logging.error(f"Failed to insert data into MySQL database: {e}")
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
try:
new_entry = WatchHistory(
video_url=video_url,
video_name=video_name,
channel_url=channel_url,
channel_name=channel_name,
)
session.add(new_entry)
session.commit()
logging.debug(
f"{video_name} by {channel_name} inserted into the database successfully"
)
return jsonify(message="Data added to mpv queue and database"), 200
except exc.SQLAlchemyError as e:
session.rollback()
logging.error(f"Failed to insert data into database: {e}")
return jsonify(message="Failed to add data to database"), 500
else:
logging.error("Missing required data fields")
return jsonify(message="Missing required data fields"), 400
@ -197,10 +145,9 @@ def handle_request():
if __name__ == "__main__":
logging.info(f"Starting server on {HOST_NAME}:{PORT_NUMBER}...")
ensure_watch_history_table_exists()
logging.info(f"Starting server on {LISTEN_ADDRESS}:{LISTEN_PORT}...")
try:
app.run(host=HOST_NAME, port=PORT_NUMBER)
app.run(host=LISTEN_ADDRESS, port=LISTEN_PORT)
except Exception as e:
logging.exception(f"Error occurred: {e}")
except KeyboardInterrupt: