headless mode foundation
This commit is contained in:
parent
d9e981c93e
commit
bf445f9939
5 changed files with 193 additions and 10 deletions
100
main.py
100
main.py
|
|
@ -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
|
||||
41
webui/index.html
Normal file
41
webui/index.html
Normal file
|
|
@ -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>
|
||||
26
webui/static/script.js
Normal file
26
webui/static/script.js
Normal file
|
|
@ -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!');
|
||||
});
|
||||
33
webui/static/style.css
Normal file
33
webui/static/style.css
Normal file
|
|
@ -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…
Reference in a new issue