137 lines
4.3 KiB
Python
Executable File
137 lines
4.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Paid Content Service Health Check
|
|
|
|
Standalone script to check the health of all paid content services.
|
|
Designed to be run via systemd timer every 4 hours.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
import asyncio
|
|
from datetime import datetime
|
|
|
|
# Add parent directory to path for imports
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from modules.paid_content import (
|
|
PaidContentDBAdapter,
|
|
PaidContentAPIClient,
|
|
FanslyDirectClient,
|
|
YouTubeClient,
|
|
TwitchClient
|
|
)
|
|
from modules.unified_database import UnifiedDatabase
|
|
|
|
|
|
def log(message: str, level: str = "info"):
|
|
"""Simple logging to stdout"""
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
print(f"[{timestamp}] [{level.upper()}] {message}")
|
|
|
|
|
|
async def check_service_health(service: dict, pc_db: PaidContentDBAdapter) -> dict:
|
|
"""Check health of a single service"""
|
|
service_id = service['id']
|
|
health = {'status': 'unknown', 'message': ''}
|
|
|
|
try:
|
|
if service_id == 'youtube':
|
|
youtube = YouTubeClient()
|
|
if youtube.is_available():
|
|
health = {'status': 'healthy', 'message': 'yt-dlp is available'}
|
|
else:
|
|
health = {'status': 'down', 'message': 'yt-dlp not found'}
|
|
|
|
elif service_id == 'twitch':
|
|
twitch = TwitchClient()
|
|
if twitch.is_available():
|
|
health = {'status': 'healthy', 'message': 'yt-dlp is available for Twitch'}
|
|
else:
|
|
health = {'status': 'down', 'message': 'yt-dlp not found'}
|
|
|
|
elif service_id == 'fansly_direct':
|
|
auth_token = service.get('session_cookie')
|
|
if not auth_token:
|
|
health = {'status': 'down', 'message': 'Auth token not configured'}
|
|
else:
|
|
client = FanslyDirectClient(auth_token=auth_token)
|
|
try:
|
|
result = await client.check_auth()
|
|
if result.get('valid'):
|
|
health = {
|
|
'status': 'healthy',
|
|
'message': f"Connected as {result.get('username', 'unknown')}"
|
|
}
|
|
else:
|
|
health = {'status': 'down', 'message': result.get('error', 'Auth failed')}
|
|
finally:
|
|
await client.close()
|
|
|
|
else:
|
|
# Coomer/Kemono services
|
|
client = PaidContentAPIClient(
|
|
service_id,
|
|
session_cookie=service.get('session_cookie'),
|
|
base_url=service.get('base_url')
|
|
)
|
|
try:
|
|
health = await client.check_health()
|
|
finally:
|
|
await client.close()
|
|
|
|
# Update database
|
|
pc_db.update_service(service_id, {
|
|
'health_status': health.get('status', 'unknown'),
|
|
'last_health_check': datetime.now().isoformat()
|
|
})
|
|
|
|
return {'service_id': service_id, **health}
|
|
|
|
except Exception as e:
|
|
log(f"Health check failed for {service_id}: {e}", "error")
|
|
return {'service_id': service_id, 'status': 'error', 'message': str(e)}
|
|
|
|
|
|
async def main():
|
|
"""Main health check routine"""
|
|
log("Starting paid content service health check")
|
|
|
|
try:
|
|
# Initialize database
|
|
db = UnifiedDatabase()
|
|
pc_db = PaidContentDBAdapter(db)
|
|
|
|
# Get all services
|
|
services = pc_db.get_services()
|
|
|
|
if not services:
|
|
log("No services configured", "warning")
|
|
return 0
|
|
|
|
log(f"Checking {len(services)} services...")
|
|
|
|
# Check each service
|
|
results = []
|
|
for service in services:
|
|
result = await check_service_health(service, pc_db)
|
|
results.append(result)
|
|
status_icon = "✓" if result['status'] == 'healthy' else "✗"
|
|
log(f" {status_icon} {result['service_id']}: {result['status']} - {result.get('message', '')}")
|
|
|
|
# Summary
|
|
healthy = sum(1 for r in results if r['status'] == 'healthy')
|
|
total = len(results)
|
|
log(f"Health check complete: {healthy}/{total} services healthy")
|
|
|
|
return 0 if healthy == total else 1
|
|
|
|
except Exception as e:
|
|
log(f"Health check failed: {e}", "error")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
exit_code = asyncio.run(main())
|
|
sys.exit(exit_code)
|