headless mode foundation

pull/15/head
Broque Thomas 6 months ago
parent d9e981c93e
commit bf445f9939

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import sys
import argparse
import asyncio
import time
from pathlib import Path
@ -404,18 +405,73 @@ class MainWindow(QMainWindow):
# Force accept the event to prevent hanging
event.accept()
def main():
logging_config = config_manager.get_logging_config()
log_level = logging_config.get('level', 'INFO')
log_file = logging_config.get('path', 'logs/newmusic.log')
setup_logging(level=log_level, log_file=log_file)
def run_web_app():
"""Run the application in headless web mode using Flask"""
from flask import Flask, render_template, jsonify
logger.info("Starting Soulsync application")
app = Flask(__name__, template_folder='webui', static_folder='webui/static')
if not config_manager.config_path.exists():
logger.error("Configuration file not found. Please check config/config.json")
sys.exit(1)
# Initialize service clients (same as GUI mode)
spotify_client = SpotifyClient()
plex_client = PlexClient()
jellyfin_client = JellyfinClient()
soulseek_client = SoulseekClient()
@app.route('/')
def home():
return render_template('index.html')
@app.route('/status')
def status():
"""Return service connection status as JSON"""
try:
# Check Spotify
spotify_status = spotify_client.sp is not None
# Check active media server
active_server = config_manager.get_active_media_server()
if active_server == "plex":
media_status = plex_client.is_connected()
elif active_server == "jellyfin":
media_status = jellyfin_client.is_connected()
else:
media_status = False
# Check Soulseek
soulseek_status = soulseek_client.is_configured()
return jsonify({
'spotify': spotify_status,
'media_server': media_status,
'soulseek': soulseek_status,
'active_media_server': active_server
})
except Exception as e:
logger.error(f"Error getting service status: {e}")
return jsonify({'error': str(e)}), 500
@app.route('/config')
def config_info():
"""Return basic configuration info"""
try:
validation = config_manager.validate_config()
return jsonify({
'configured': config_manager.is_configured(),
'active_media_server': config_manager.get_active_media_server(),
'validation': validation
})
except Exception as e:
logger.error(f"Error getting config info: {e}")
return jsonify({'error': str(e)}), 500
logger.info("Starting SoulSync in web mode...")
logger.info("Web interface available at http://localhost:5000")
# Run Flask app
app.run(host='0.0.0.0', port=5000, debug=False)
def run_gui_app():
"""Run the application in GUI mode using PyQt6"""
app = QApplication(sys.argv)
app.setApplicationName("SoulSync")
app.setApplicationVersion("0.6")
@ -432,5 +488,31 @@ def main():
logger.error(f"Unexpected error: {e}")
sys.exit(1)
def main():
# Parse command line arguments
parser = argparse.ArgumentParser(description='SoulSync - Music Sync & Manager')
parser.add_argument('--headless', action='store_true',
help='Run in headless mode with web interface instead of GUI')
args = parser.parse_args()
# Setup logging
logging_config = config_manager.get_logging_config()
log_level = logging_config.get('level', 'INFO')
log_file = logging_config.get('path', 'logs/newmusic.log')
setup_logging(level=log_level, log_file=log_file)
# Check configuration
if not config_manager.config_path.exists():
logger.error("Configuration file not found. Please check config/config.json")
sys.exit(1)
# Choose mode based on arguments
if args.headless:
logger.info("Starting SoulSync in headless web mode")
run_web_app()
else:
logger.info("Starting SoulSync in GUI mode")
run_gui_app()
if __name__ == "__main__":
main()

@ -9,4 +9,5 @@ mutagen>=1.47.0
Pillow>=10.0.0
aiohttp>=3.9.0
unidecode>=1.3.8
yt-dlp>=2024.12.13
yt-dlp>=2024.12.13
Flask>=3.0.0

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<title>SoulSync - Web Mode</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="container">
<h1>🎵 SoulSync - Web Mode</h1>
<p>Your music sync application is running in headless mode.</p>
<div class="status">
<h3>Service Status</h3>
<div id="status-container">
<div class="service">
<span>Spotify:</span>
<span id="spotify-status" class="disconnected">Checking...</span>
</div>
<div class="service">
<span>Media Server:</span>
<span id="media-status" class="disconnected">Checking...</span>
</div>
<div class="service">
<span>Soulseek:</span>
<span id="soulseek-status" class="disconnected">Checking...</span>
</div>
</div>
</div>
<div class="status">
<h3>Available Endpoints</h3>
<ul>
<li><a href="/status" style="color: #4caf50;">/status</a> - Service status JSON</li>
<li><a href="/config" style="color: #4caf50;">/config</a> - Configuration info</li>
</ul>
</div>
</div>
<script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>

@ -0,0 +1,26 @@
function updateStatus() {
fetch('/status')
.then(response => response.json())
.then(data => {
document.getElementById('spotify-status').textContent = data.spotify ? 'Connected' : 'Disconnected';
document.getElementById('spotify-status').className = data.spotify ? 'connected' : 'disconnected';
document.getElementById('media-status').textContent = data.media_server ? 'Connected' : 'Disconnected';
document.getElementById('media-status').className = data.media_server ? 'connected' : 'disconnected';
document.getElementById('soulseek-status').textContent = data.soulseek ? 'Connected' : 'Disconnected';
document.getElementById('soulseek-status').className = data.soulseek ? 'connected' : 'disconnected';
})
.catch(error => console.error('Error fetching status:', error));
}
// Initialize when page loads
document.addEventListener('DOMContentLoaded', function() {
// Update status immediately
updateStatus();
// Update status every 5 seconds
setInterval(updateStatus, 5000);
console.log('SoulSync Web UI loaded successfully!');
});

@ -0,0 +1,33 @@
body {
font-family: Arial, sans-serif;
margin: 40px;
background: #121212;
color: white;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.status {
padding: 20px;
background: #1e1e1e;
border-radius: 8px;
margin: 20px 0;
}
.service {
display: flex;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid #333;
}
.connected {
color: #4caf50;
}
.disconnected {
color: #f44336;
}
Loading…
Cancel
Save