211 lines
6.0 KiB
Python
211 lines
6.0 KiB
Python
"""Stream routes for managing streaming service links."""
|
|
|
|
from flask import Blueprint, jsonify, request
|
|
|
|
from app.database import db
|
|
from app.models.stream import Stream
|
|
from app.services.decorators import require_auth
|
|
|
|
bp = Blueprint("stream", __name__)
|
|
|
|
|
|
@bp.route("/add-url", methods=["POST"])
|
|
@require_auth
|
|
def add_url():
|
|
"""Add a URL to the stream processing queue."""
|
|
try:
|
|
data = request.get_json()
|
|
|
|
if not data or "url" not in data:
|
|
return jsonify({"error": "URL is required"}), 400
|
|
|
|
url = data["url"].strip()
|
|
if not url:
|
|
return jsonify({"error": "URL cannot be empty"}), 400
|
|
|
|
# Check if URL already exists
|
|
existing_stream = Stream.query.filter_by(url=url).first()
|
|
if existing_stream:
|
|
return (
|
|
jsonify(
|
|
{
|
|
"error": "URL already exists in stream",
|
|
"stream": existing_stream.to_dict(),
|
|
}
|
|
),
|
|
409,
|
|
)
|
|
|
|
# Try to extract basic metadata to check for service/service_id duplicates
|
|
from app.services.stream_processing_service import (
|
|
StreamProcessingService,
|
|
)
|
|
|
|
try:
|
|
metadata, _ = StreamProcessingService._extract_metadata(url)
|
|
if metadata:
|
|
service = metadata.get("service")
|
|
service_id = metadata.get("service_id")
|
|
|
|
if service and service_id:
|
|
existing_service_stream = Stream.query.filter_by(
|
|
service=service, service_id=service_id
|
|
).first()
|
|
|
|
if existing_service_stream:
|
|
return (
|
|
jsonify(
|
|
{
|
|
"error": f"Stream already exists with {service} ID: {service_id}",
|
|
"existing_stream": existing_service_stream.to_dict(),
|
|
}
|
|
),
|
|
409,
|
|
)
|
|
except Exception as e:
|
|
# If metadata extraction fails here, we'll let the background process handle it
|
|
# This is just an early check to prevent obvious duplicates
|
|
pass
|
|
|
|
# Create stream entry with pending status
|
|
stream = Stream.create_stream(url=url, status="pending", commit=True)
|
|
|
|
# Add to processing queue (will be implemented next)
|
|
from app.services.stream_processing_service import (
|
|
StreamProcessingService,
|
|
)
|
|
|
|
StreamProcessingService.add_to_queue(stream.id)
|
|
|
|
return (
|
|
jsonify(
|
|
{
|
|
"message": "URL added to processing queue",
|
|
"stream": stream.to_dict(),
|
|
}
|
|
),
|
|
201,
|
|
)
|
|
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@bp.route("/", methods=["GET"])
|
|
@require_auth
|
|
def list_streams():
|
|
"""List all streams with optional filtering."""
|
|
try:
|
|
status = request.args.get("status")
|
|
service = request.args.get("service")
|
|
|
|
query = Stream.query
|
|
|
|
if status:
|
|
query = query.filter_by(status=status)
|
|
if service:
|
|
query = query.filter_by(service=service)
|
|
|
|
streams = query.order_by(Stream.created_at.desc()).all()
|
|
|
|
return (
|
|
jsonify({"streams": [stream.to_dict() for stream in streams]}),
|
|
200,
|
|
)
|
|
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@bp.route("/<int:stream_id>", methods=["GET"])
|
|
@require_auth
|
|
def get_stream(stream_id):
|
|
"""Get a specific stream by ID."""
|
|
try:
|
|
stream = Stream.query.get_or_404(stream_id)
|
|
return jsonify({"stream": stream.to_dict()}), 200
|
|
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@bp.route("/<int:stream_id>", methods=["PUT"])
|
|
@require_auth
|
|
def update_stream(stream_id):
|
|
"""Update stream metadata."""
|
|
try:
|
|
stream = Stream.query.get_or_404(stream_id)
|
|
data = request.get_json()
|
|
|
|
if not data:
|
|
return jsonify({"error": "No data provided"}), 400
|
|
|
|
# Update allowed fields
|
|
updatable_fields = [
|
|
"title",
|
|
"track",
|
|
"artist",
|
|
"album",
|
|
"genre",
|
|
"status",
|
|
]
|
|
for field in updatable_fields:
|
|
if field in data:
|
|
setattr(stream, field, data[field])
|
|
|
|
db.session.commit()
|
|
|
|
return (
|
|
jsonify(
|
|
{
|
|
"message": "Stream updated successfully",
|
|
"stream": stream.to_dict(),
|
|
}
|
|
),
|
|
200,
|
|
)
|
|
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@bp.route("/<int:stream_id>", methods=["DELETE"])
|
|
@require_auth
|
|
def delete_stream(stream_id):
|
|
"""Delete a stream."""
|
|
try:
|
|
stream = Stream.query.get_or_404(stream_id)
|
|
|
|
# If stream is being processed, mark for deletion instead
|
|
if stream.status == "processing":
|
|
stream.status = "cancelled"
|
|
db.session.commit()
|
|
return jsonify({"message": "Stream marked for cancellation"}), 200
|
|
|
|
db.session.delete(stream)
|
|
db.session.commit()
|
|
|
|
return jsonify({"message": "Stream deleted successfully"}), 200
|
|
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
|
|
@bp.route("/queue/status", methods=["GET"])
|
|
@require_auth
|
|
def queue_status():
|
|
"""Get the current processing queue status."""
|
|
try:
|
|
from app.services.stream_processing_service import (
|
|
StreamProcessingService,
|
|
)
|
|
|
|
status = StreamProcessingService.get_queue_status()
|
|
return jsonify(status), 200
|
|
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|