"""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("/", 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("/", 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("/", 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