flask webui
This commit is contained in:
parent
6095717dd3
commit
1ecb31ae12
2 changed files with 70 additions and 14 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ta_symlink.py .
|
COPY ta_symlink.py .
|
||||||
RUN pip install --no-cache-dir requests
|
RUN pip install --no-cache-dir requests flask
|
||||||
|
EXPOSE 5000
|
||||||
CMD ["python", "ta_symlink.py"]
|
CMD ["python", "ta_symlink.py"]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
from flask import Flask, jsonify, render_template_string, request
|
||||||
|
|
||||||
# Load config from environment variables
|
# Load config from environment variables
|
||||||
API_URL = os.getenv("API_URL", "http://localhost:8457/api")
|
API_URL = os.getenv("API_URL", "http://localhost:8457/api")
|
||||||
|
|
@ -12,6 +14,10 @@ SOURCE_DIR = Path("/app/source")
|
||||||
TARGET_DIR = Path("/app/target")
|
TARGET_DIR = Path("/app/target")
|
||||||
HEADERS = {"Authorization": f"Token {API_TOKEN}"}
|
HEADERS = {"Authorization": f"Token {API_TOKEN}"}
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
processed_videos = []
|
||||||
|
|
||||||
# Utility functions
|
# Utility functions
|
||||||
def sanitize(text):
|
def sanitize(text):
|
||||||
text = text.encode("ascii", "ignore").decode()
|
text = text.encode("ascii", "ignore").decode()
|
||||||
|
|
@ -42,38 +48,31 @@ def fetch_video_metadata(video_id):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Main logic
|
# Main logic
|
||||||
def process_videos():
|
|
||||||
print("📁 Starting video processing...", flush=True)
|
|
||||||
|
|
||||||
|
def process_videos():
|
||||||
|
global processed_videos
|
||||||
|
processed_videos = []
|
||||||
try:
|
try:
|
||||||
for channel_path in SOURCE_DIR.iterdir():
|
for channel_path in SOURCE_DIR.iterdir():
|
||||||
if not channel_path.is_dir():
|
if not channel_path.is_dir():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for video_file in channel_path.glob("*.*"):
|
for video_file in channel_path.glob("*.*"):
|
||||||
video_id = video_file.stem
|
video_id = video_file.stem
|
||||||
meta = fetch_video_metadata(video_id)
|
meta = fetch_video_metadata(video_id)
|
||||||
if not meta:
|
if not meta:
|
||||||
print(f"⚠️ Skipped {video_id}: could not fetch metadata", flush=True)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
sanitized_channel_name = sanitize(meta["channel_name"])
|
sanitized_channel_name = sanitize(meta["channel_name"])
|
||||||
channel_dir = TARGET_DIR / sanitized_channel_name
|
channel_dir = TARGET_DIR / sanitized_channel_name
|
||||||
channel_dir.mkdir(parents=True, exist_ok=True)
|
channel_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
sanitized_title = sanitize(meta["title"])
|
sanitized_title = sanitize(meta["title"])
|
||||||
folder_name = f"{meta['published']} - {sanitized_title}"
|
folder_name = f"{meta['published']} - {sanitized_title}"
|
||||||
video_dir = channel_dir / folder_name
|
video_dir = channel_dir / folder_name
|
||||||
video_dir.mkdir(parents=True, exist_ok=True)
|
video_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
actual_file = next(channel_path.glob(f"{video_id}.*"), None)
|
actual_file = next(channel_path.glob(f"{video_id}.*"), None)
|
||||||
if not actual_file:
|
if not actual_file:
|
||||||
print(f"⚠️ Video file not found for {video_id} in {channel_path}", flush=True)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
host_path_root = Path("/mnt/user/tubearchives/bp")
|
host_path_root = Path("/mnt/user/tubearchives/bp")
|
||||||
host_source_path = host_path_root / actual_file.relative_to(SOURCE_DIR)
|
host_source_path = host_path_root / actual_file.relative_to(SOURCE_DIR)
|
||||||
|
|
||||||
dest_file = video_dir / f"video{actual_file.suffix}"
|
dest_file = video_dir / f"video{actual_file.suffix}"
|
||||||
try:
|
try:
|
||||||
if dest_file.exists():
|
if dest_file.exists():
|
||||||
|
|
@ -84,11 +83,67 @@ def process_videos():
|
||||||
os.symlink(host_source_path, dest_file)
|
os.symlink(host_source_path, dest_file)
|
||||||
else:
|
else:
|
||||||
os.symlink(host_source_path, dest_file)
|
os.symlink(host_source_path, dest_file)
|
||||||
print(f"✅ Linked: {dest_file}", flush=True)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
processed_videos.append({
|
||||||
|
"video_id": video_id,
|
||||||
|
"title": meta["title"],
|
||||||
|
"channel": meta["channel_name"],
|
||||||
|
"published": meta["published"],
|
||||||
|
"symlink": str(dest_file)
|
||||||
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"💥 Unhandled error: {e}", file=sys.stderr, flush=True)
|
return str(e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# Flask routes
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
return render_template_string('''
|
||||||
|
<html>
|
||||||
|
<head><title>TA Organizerr</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>TA Organizerr</h1>
|
||||||
|
<form method="post" action="/process">
|
||||||
|
<button type="submit">Process Videos</button>
|
||||||
|
</form>
|
||||||
|
<h2>Processed Videos</h2>
|
||||||
|
<ul>
|
||||||
|
{% for v in videos %}
|
||||||
|
<li>{{v.published}} - {{v.title}} ({{v.channel}}) <br>Symlink: {{v.symlink}}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
''', videos=processed_videos)
|
||||||
|
|
||||||
|
@app.route("/process", methods=["POST"])
|
||||||
|
def process():
|
||||||
|
error = process_videos()
|
||||||
|
if error:
|
||||||
|
return f"Error: {error}", 500
|
||||||
|
return render_template_string('''
|
||||||
|
<html>
|
||||||
|
<head><title>TA Organizerr</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>TA Organizerr</h1>
|
||||||
|
<form method="post" action="/process">
|
||||||
|
<button type="submit">Process Videos</button>
|
||||||
|
</form>
|
||||||
|
<h2>Processed Videos</h2>
|
||||||
|
<ul>
|
||||||
|
{% for v in videos %}
|
||||||
|
<li>{{v.published}} - {{v.title}} ({{v.channel}}) <br>Symlink: {{v.symlink}}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
''', videos=processed_videos)
|
||||||
|
|
||||||
|
@app.route("/api/videos")
|
||||||
|
def api_videos():
|
||||||
|
return jsonify(processed_videos)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
process_videos()
|
app.run(host="0.0.0.0", port=5000)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue