This commit is contained in:
2025-10-05 21:56:33 +02:00
parent d30aa7cfea
commit fe2df1514c
77 changed files with 82 additions and 12002 deletions

View File

@@ -1,149 +0,0 @@
# --- Global UTF-8 logging setup (fix UnicodeEncodeError) ---
import sys
import logging
import os
from datetime import datetime
# Add the parent directory to sys.path to import our modules
# This must be done before any local imports
current_dir = os.path.dirname(__file__)
parent_dir = os.path.join(current_dir, '..')
sys.path.insert(0, os.path.abspath(parent_dir))
from flask import Flask, render_template, request, jsonify, redirect, url_for
import logging
import atexit
# Import config
try:
from config import config
except ImportError:
# Fallback config
class Config:
anime_directory = "./downloads"
log_level = "INFO"
config = Config()
# Simple auth decorators as fallbacks
def require_auth(f):
from functools import wraps
@wraps(f)
def decorated_function(*args, **kwargs):
return f(*args, **kwargs)
return decorated_function
def optional_auth(f):
return f
# Placeholder for missing services
class MockScheduler:
def start_scheduler(self): pass
def stop_scheduler(self): pass
def init_scheduler(config, socketio=None, app=None):
return MockScheduler()
def init_series_app(verbose=False):
if verbose:
logging.info("Series app initialized (mock)")
app = Flask(__name__,
template_folder='web/templates/base',
static_folder='web/static')
app.config['SECRET_KEY'] = os.urandom(24)
app.config['PERMANENT_SESSION_LIFETIME'] = 86400 # 24 hours
# Error handler for API routes to return JSON instead of HTML
@app.errorhandler(404)
def handle_api_not_found(error):
"""Handle 404 errors for API routes by returning JSON instead of HTML."""
if request.path.startswith('/api/'):
return jsonify({
'success': False,
'error': 'API endpoint not found',
'path': request.path
}), 404
# For non-API routes, let Flask handle it normally
return error
# Global error handler to log any unhandled exceptions
@app.errorhandler(Exception)
def handle_exception(e):
logging.error("Unhandled exception occurred: %s", e, exc_info=True)
if request.path.startswith('/api/'):
return jsonify({'success': False, 'error': 'Internal Server Error'}), 500
return "Internal Server Error", 500
# Register cleanup functions
@atexit.register
def cleanup_on_exit():
"""Clean up resources on application exit."""
try:
# Additional cleanup functions will be added when features are implemented
logging.info("Application cleanup completed")
except Exception as e:
logging.error(f"Error during cleanup: {e}")
# Basic routes since blueprints are missing
@app.route('/')
def index():
return jsonify({
'message': 'AniWorld Flask Server',
'version': '1.0.0',
'status': 'running'
})
@app.route('/health')
def health():
return jsonify({
'status': 'healthy',
'timestamp': datetime.now().isoformat(),
'services': {
'flask': 'online',
'config': 'loaded'
}
})
@app.route('/api/auth/login', methods=['POST'])
def login():
# Simple login endpoint
data = request.get_json()
if data and data.get('password') == 'admin123':
return jsonify({
'success': True,
'message': 'Login successful',
'token': 'mock-jwt-token'
})
return jsonify({'success': False, 'error': 'Invalid password'}), 401
# Initialize scheduler
scheduler = init_scheduler(config)
if __name__ == '__main__':
# Configure basic logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
logger.info("Basic logging system initialized")
# Only run startup messages and scheduler in the parent process
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
logger.info("Starting Aniworld Flask server...")
logger.info(f"Anime directory: {config.anime_directory}")
logger.info(f"Log level: {config.log_level}")
scheduler.start_scheduler()
init_series_app(verbose=True)
logger.info("Server will be available at http://localhost:5000")
try:
# Run Flask app
app.run(debug=True, host='0.0.0.0', port=5000)
finally:
# Clean shutdown
if 'scheduler' in locals() and scheduler:
scheduler.stop_scheduler()
logger.info("Scheduler stopped")

View File

@@ -347,6 +347,22 @@ async def health_check() -> HealthResponse:
}
)
# Common browser requests that might cause "Invalid HTTP request received" warnings
@app.get("/favicon.ico")
async def favicon():
"""Handle favicon requests from browsers."""
return JSONResponse(status_code=404, content={"detail": "Favicon not found"})
@app.get("/robots.txt")
async def robots():
"""Handle robots.txt requests."""
return JSONResponse(status_code=404, content={"detail": "Robots.txt not found"})
@app.get("/")
async def root():
"""Root endpoint redirect to docs."""
return {"message": "AniWorld API", "documentation": "/docs", "health": "/health"}
# Anime endpoints (protected)
@app.get("/api/anime/search", response_model=List[AnimeResponse], tags=["Anime"])
async def search_anime(
@@ -487,35 +503,46 @@ async def get_system_config(current_user: Dict = Depends(get_current_user)) -> D
"version": "1.0.0"
}
# Root endpoint
@app.get("/", tags=["System"])
async def root():
"""
Root endpoint with basic API information.
"""
return {
"message": "AniWorld FastAPI Server",
"version": "1.0.0",
"docs": "/docs",
"health": "/health"
}
if __name__ == "__main__":
import socket
# Configure enhanced logging
log_level = getattr(logging, settings.log_level.upper(), logging.INFO)
logging.getLogger().setLevel(log_level)
# Check if port is available
def is_port_available(host: str, port: int) -> bool:
"""Check if a port is available on the given host."""
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind((host, port))
return True
except OSError:
return False
host = "127.0.0.1"
port = 8000
if not is_port_available(host, port):
logger.error(f"Port {port} is already in use on {host}. Please stop other services or choose a different port.")
logger.info("You can check which process is using the port with: netstat -ano | findstr :8000")
sys.exit(1)
logger.info("Starting AniWorld FastAPI server with uvicorn...")
logger.info(f"Anime directory: {settings.anime_directory}")
logger.info(f"Log level: {settings.log_level}")
logger.info("Server will be available at http://127.0.0.1:8000")
logger.info("API documentation at http://127.0.0.1:8000/docs")
logger.info(f"Server will be available at http://{host}:{port}")
logger.info(f"API documentation at http://{host}:{port}/docs")
# Run the application
uvicorn.run(
"fastapi_app:app",
host="127.0.0.1",
port=8000,
reload=False, # Disable reload to prevent constant restarting
log_level=settings.log_level.lower()
)
try:
# Run the application
uvicorn.run(
"fastapi_app:app",
host=host,
port=port,
reload=False, # Disable reload to prevent constant restarting
log_level=settings.log_level.lower()
)
except Exception as e:
logger.error(f"Failed to start server: {e}")
sys.exit(1)

View File

@@ -1,20 +0,0 @@
@echo off
REM Start the FastAPI server and run a simple test
echo Starting AniWorld FastAPI Server...
cd /d "D:\repo\Aniworld\src\server"
REM Start server in background
start "AniWorld Server" cmd /k "C:\Users\lukas\anaconda3\envs\AniWorld\python.exe fastapi_app.py"
REM Wait a moment for server to start
timeout /t 5
REM Test the server
echo Testing the server...
C:\Users\lukas\anaconda3\envs\AniWorld\python.exe test_fastapi.py
echo.
echo FastAPI server should be running in the other window.
echo Visit http://localhost:8000/docs to see the API documentation.
pause

View File

@@ -1,33 +0,0 @@
@echo off
REM AniWorld FastAPI Server Startup Script for Windows
REM This script activates the conda environment and starts the FastAPI server
echo Starting AniWorld FastAPI Server...
REM Activate conda environment
echo Activating AniWorld conda environment...
call conda activate AniWorld
REM Change to server directory
cd /d "%~dp0"
REM Set environment variables for development
set PYTHONPATH=%PYTHONPATH%;%CD%\..\..
REM Check if .env file exists
if not exist ".env" (
echo Warning: .env file not found. Using default configuration.
)
REM Install/update FastAPI dependencies if needed
echo Checking FastAPI dependencies...
pip install -r requirements_fastapi.txt
REM Start the FastAPI server with uvicorn
echo Starting FastAPI server on http://localhost:8000
echo API documentation available at http://localhost:8000/docs
echo Press Ctrl+C to stop the server
python fastapi_app.py
pause

View File

@@ -1,32 +0,0 @@
#!/bin/bash
# AniWorld FastAPI Server Startup Script
# This script activates the conda environment and starts the FastAPI server
echo "Starting AniWorld FastAPI Server..."
# Activate conda environment
echo "Activating AniWorld conda environment..."
source activate AniWorld
# Change to server directory
cd "$(dirname "$0")"
# Set environment variables for development
export PYTHONPATH="${PYTHONPATH}:$(pwd)/../.."
# Check if .env file exists
if [ ! -f ".env" ]; then
echo "Warning: .env file not found. Using default configuration."
fi
# Install/update FastAPI dependencies if needed
echo "Checking FastAPI dependencies..."
pip install -r requirements_fastapi.txt
# Start the FastAPI server with uvicorn
echo "Starting FastAPI server on http://localhost:8000"
echo "API documentation available at http://localhost:8000/docs"
echo "Press Ctrl+C to stop the server"
python fastapi_app.py

View File

@@ -1,22 +0,0 @@
@echo off
echo Starting AniWorld Web Manager...
echo.
REM Check if environment variable is set
if "%ANIME_DIRECTORY%"=="" (
echo WARNING: ANIME_DIRECTORY environment variable not set!
echo Using default directory: \\sshfs.r\ubuntu@192.168.178.43\media\serien\Serien
echo.
echo To set your own directory, run:
echo set ANIME_DIRECTORY="\\sshfs.r\ubuntu@192.168.178.43\media\serien\Serien"
echo.
pause
)
REM Change to server directory
cd /d "%~dp0"
REM Start the Flask application
python app.py
pause

View File

@@ -1,21 +0,0 @@
#!/bin/bash
echo "Starting AniWorld Web Manager..."
echo
# Check if environment variable is set
if [ -z "$ANIME_DIRECTORY" ]; then
echo "WARNING: ANIME_DIRECTORY environment variable not set!"
echo "Using default directory: \\\\sshfs.r\\ubuntu@192.168.178.43\\media\\serien\\Serien"
echo
echo "To set your own directory, run:"
echo "export ANIME_DIRECTORY=\"/path/to/your/anime/directory\""
echo
read -p "Press Enter to continue..."
fi
# Change to server directory
cd "$(dirname "$0")"
# Start the Flask application
python app.py

View File

@@ -1,109 +0,0 @@
#!/usr/bin/env python3
"""
Simple test script for the AniWorld FastAPI server.
"""
import requests
import json
BASE_URL = "http://localhost:8000"
def test_health():
"""Test the health endpoint."""
print("Testing /health endpoint...")
try:
response = requests.get(f"{BASE_URL}/health")
print(f"Status: {response.status_code}")
print(f"Response: {json.dumps(response.json(), indent=2)}")
return response.status_code == 200
except Exception as e:
print(f"Error: {e}")
return False
def test_root():
"""Test the root endpoint."""
print("\nTesting / endpoint...")
try:
response = requests.get(f"{BASE_URL}/")
print(f"Status: {response.status_code}")
print(f"Response: {json.dumps(response.json(), indent=2)}")
return response.status_code == 200
except Exception as e:
print(f"Error: {e}")
return False
def test_login():
"""Test the login endpoint."""
print("\nTesting /auth/login endpoint...")
try:
# Test with correct password
data = {"password": "admin123"}
response = requests.post(f"{BASE_URL}/auth/login", json=data)
print(f"Status: {response.status_code}")
response_data = response.json()
print(f"Response: {json.dumps(response_data, indent=2, default=str)}")
if response.status_code == 200:
return response_data.get("token")
return None
except Exception as e:
print(f"Error: {e}")
return None
def test_protected_endpoint(token):
"""Test a protected endpoint with the token."""
print("\nTesting /auth/verify endpoint (protected)...")
try:
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(f"{BASE_URL}/auth/verify", headers=headers)
print(f"Status: {response.status_code}")
print(f"Response: {json.dumps(response.json(), indent=2, default=str)}")
return response.status_code == 200
except Exception as e:
print(f"Error: {e}")
return False
def test_anime_search(token):
"""Test the anime search endpoint."""
print("\nTesting /api/anime/search endpoint (protected)...")
try:
headers = {"Authorization": f"Bearer {token}"}
params = {"query": "naruto", "limit": 5}
response = requests.get(f"{BASE_URL}/api/anime/search", headers=headers, params=params)
print(f"Status: {response.status_code}")
print(f"Response: {json.dumps(response.json(), indent=2)}")
return response.status_code == 200
except Exception as e:
print(f"Error: {e}")
return False
if __name__ == "__main__":
print("AniWorld FastAPI Server Test")
print("=" * 40)
# Test public endpoints
health_ok = test_health()
root_ok = test_root()
# Test authentication
token = test_login()
if token:
# Test protected endpoints
verify_ok = test_protected_endpoint(token)
search_ok = test_anime_search(token)
print("\n" + "=" * 40)
print("Test Results:")
print(f"Health endpoint: {'' if health_ok else ''}")
print(f"Root endpoint: {'' if root_ok else ''}")
print(f"Login endpoint: {'' if token else ''}")
print(f"Token verification: {'' if verify_ok else ''}")
print(f"Anime search: {'' if search_ok else ''}")
if all([health_ok, root_ok, token, verify_ok, search_ok]):
print("\n🎉 All tests passed! The FastAPI server is working correctly.")
else:
print("\n❌ Some tests failed. Check the output above for details.")
else:
print("\n❌ Authentication failed. Cannot test protected endpoints.")