Add Basic Auth and optimize Docker build
This commit is contained in:
parent
2f8ec83cd8
commit
17153f8765
3 changed files with 50 additions and 6 deletions
19
Dockerfile
19
Dockerfile
|
|
@ -1,8 +1,17 @@
|
|||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
# 1. Install System Deps (ffmpeg) FIRST
|
||||
# These rarely change, so Docker will cache this layer forever.
|
||||
RUN apt-get update && apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/*
|
||||
RUN pip install --no-cache-dir requests flask
|
||||
RUN mkdir -p /app/data
|
||||
EXPOSE 5000
|
||||
CMD ["python", "ta_symlink.py"]
|
||||
|
||||
# 2. Install Python Deps SECOND
|
||||
# Only re-runs if requirements.txt changes
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# 3. Copy Code LAST
|
||||
# Now, if you change code, only this fast step re-runs.
|
||||
COPY . .
|
||||
|
||||
CMD ["python", "ta_symlink.py"]
|
||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
flask
|
||||
requests
|
||||
|
|
@ -6,7 +6,8 @@ import sys
|
|||
import threading
|
||||
import time
|
||||
import ipaddress
|
||||
from flask import Flask, jsonify, render_template, request, abort
|
||||
from functools import wraps
|
||||
from flask import Flask, jsonify, render_template, request, abort, Response
|
||||
|
||||
# Load config from environment variables
|
||||
API_URL = os.getenv("API_URL", "http://localhost:8457/api")
|
||||
|
|
@ -14,6 +15,8 @@ VIDEO_URL = os.getenv("VIDEO_URL", "http://localhost:8457/video/")
|
|||
API_TOKEN = os.getenv("API_TOKEN", "")
|
||||
SCAN_INTERVAL = int(os.getenv("SCAN_INTERVAL", 60)) # Default 60 minutes
|
||||
ALLOWED_IPS = [ip.strip() for ip in os.getenv("ALLOWED_IPS", "127.0.0.1").split(",")]
|
||||
UI_USERNAME = os.getenv("UI_USERNAME", "admin")
|
||||
UI_PASSWORD = os.getenv("UI_PASSWORD", "password")
|
||||
SOURCE_DIR = Path("/app/source")
|
||||
TARGET_DIR = Path("/app/target")
|
||||
HEADERS = {"Authorization": f"Token {API_TOKEN}"}
|
||||
|
|
@ -557,11 +560,33 @@ def limit_remote_addr():
|
|||
log(f"⛔ Invalid IP format: {client_ip}, Error: {e}")
|
||||
abort(403)
|
||||
|
||||
def check_auth(username, password):
|
||||
"""Checks whether a username/password combination is valid."""
|
||||
return username == UI_USERNAME and password == UI_PASSWORD
|
||||
|
||||
def authenticate():
|
||||
"""Sends a 401 response that enables basic auth"""
|
||||
return Response(
|
||||
'Could not verify your access level for that URL.\n'
|
||||
'You have to login with proper credentials', 401,
|
||||
{'WWW-Authenticate': 'Basic realm="Login Required"'})
|
||||
|
||||
def requires_auth(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
auth = request.authorization
|
||||
if not auth or not check_auth(auth.username, auth.password):
|
||||
return authenticate()
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
@app.route("/")
|
||||
@requires_auth
|
||||
def index():
|
||||
return render_template('dashboard.html')
|
||||
|
||||
@app.route("/api/status")
|
||||
@requires_auth
|
||||
def api_status():
|
||||
with get_db() as conn:
|
||||
# Get all videos from DB
|
||||
|
|
@ -589,6 +614,7 @@ def api_status():
|
|||
})
|
||||
|
||||
@app.route("/api/logs")
|
||||
@requires_auth
|
||||
def api_logs():
|
||||
start = request.args.get('start', 0, type=int)
|
||||
with log_lock:
|
||||
|
|
@ -598,26 +624,31 @@ def api_logs():
|
|||
})
|
||||
|
||||
@app.route("/api/scan", methods=["POST"])
|
||||
@requires_auth
|
||||
def api_scan():
|
||||
# Run in background to avoid blocking
|
||||
threading.Thread(target=process_videos).start()
|
||||
return jsonify({"status": "started"})
|
||||
|
||||
@app.route("/api/cleanup", methods=["POST"])
|
||||
@requires_auth
|
||||
def api_cleanup():
|
||||
threading.Thread(target=cleanup_old_folders).start()
|
||||
return jsonify({"status": "started"})
|
||||
|
||||
@app.route("/api/check-orphans", methods=["POST"])
|
||||
@requires_auth
|
||||
def api_check_orphans():
|
||||
orphaned = check_orphaned_links()
|
||||
return jsonify({"status": "complete", "orphaned": orphaned, "count": len(orphaned)})
|
||||
|
||||
@app.route("/transcode")
|
||||
@requires_auth
|
||||
def transcode_page():
|
||||
return render_template('transcoding.html')
|
||||
|
||||
@app.route("/api/transcode/videos")
|
||||
@requires_auth
|
||||
def api_transcode_videos():
|
||||
"""Get all videos that need transcoding."""
|
||||
page = request.args.get('page', 1, type=int)
|
||||
|
|
@ -650,6 +681,7 @@ def api_transcode_videos():
|
|||
})
|
||||
|
||||
@app.route("/api/transcode/start", methods=["POST"])
|
||||
@requires_auth
|
||||
def api_transcode_start():
|
||||
"""Start transcoding a video."""
|
||||
data = request.get_json()
|
||||
|
|
@ -669,6 +701,7 @@ def api_transcode_start():
|
|||
return jsonify({"message": "Transcode started", "encoder": encoder})
|
||||
|
||||
@app.route("/api/transcode/logs")
|
||||
@requires_auth
|
||||
def api_transcode_logs():
|
||||
"""Get transcode logs."""
|
||||
start = request.args.get('start', 0, type=int)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue