Add activity logging for key user actions
Introduces activity item logging for settings saves, connection tests, auto-detects, authentication flows, searches, batch cancellations, and discovery operations in web_server.py. Updates dashboard connection test API and UI to use a new endpoint and function, ensuring user actions are tracked and surfaced in the activity feed.
This commit is contained in:
parent
94d1c82674
commit
ae9f426361
3 changed files with 114 additions and 3 deletions
|
|
@ -1518,6 +1518,12 @@ def handle_settings():
|
|||
config_manager.set(f'{service}.{key}', value)
|
||||
|
||||
print("✅ Settings saved successfully via Web UI.")
|
||||
|
||||
# Add activity for settings save
|
||||
changed_services = list(new_settings.keys())
|
||||
services_text = ", ".join(changed_services)
|
||||
add_activity_item("⚙️", "Settings Updated", f"{services_text} configuration saved", "Now")
|
||||
|
||||
spotify_client._setup_client()
|
||||
plex_client.server = None
|
||||
jellyfin_client.server = None
|
||||
|
|
@ -1553,6 +1559,42 @@ def test_connection_endpoint():
|
|||
service = active_server # use the actual server name for the test
|
||||
|
||||
success, message = run_service_test(service, test_config)
|
||||
|
||||
# Add activity for connection test
|
||||
if success:
|
||||
add_activity_item("✅", "Connection Test", f"{service.title()} connection successful", "Now")
|
||||
else:
|
||||
add_activity_item("❌", "Connection Test", f"{service.title()} connection failed", "Now")
|
||||
|
||||
return jsonify({"success": success, "error": "" if success else message, "message": message if success else ""})
|
||||
|
||||
@app.route('/api/test-dashboard-connection', methods=['POST'])
|
||||
def test_dashboard_connection_endpoint():
|
||||
"""Test connection from dashboard - creates specific dashboard activity items"""
|
||||
data = request.get_json()
|
||||
service = data.get('service')
|
||||
if not service:
|
||||
return jsonify({"success": False, "error": "No service specified."}), 400
|
||||
|
||||
print(f"Received dashboard test connection request for: {service}")
|
||||
|
||||
# Get the current settings from the main config manager to test with
|
||||
test_config = config_manager.get(service, {})
|
||||
|
||||
# For media servers, the service name might be 'server'
|
||||
if service == 'server':
|
||||
active_server = config_manager.get_active_media_server()
|
||||
test_config = config_manager.get(active_server, {})
|
||||
service = active_server # use the actual server name for the test
|
||||
|
||||
success, message = run_service_test(service, test_config)
|
||||
|
||||
# Add activity for dashboard connection test (different from settings test)
|
||||
if success:
|
||||
add_activity_item("🎛️", "Dashboard Test", f"{service.title()} service verified", "Now")
|
||||
else:
|
||||
add_activity_item("⚠️", "Dashboard Test", f"{service.title()} service check failed", "Now")
|
||||
|
||||
return jsonify({"success": success, "error": "" if success else message, "message": message if success else ""})
|
||||
|
||||
@app.route('/api/detect-media-server', methods=['POST'])
|
||||
|
|
@ -1560,19 +1602,30 @@ def detect_media_server_endpoint():
|
|||
data = request.get_json()
|
||||
server_type = data.get('server_type')
|
||||
print(f"Received auto-detect request for: {server_type}")
|
||||
|
||||
# Add activity for auto-detect start
|
||||
add_activity_item("🔍", "Auto-Detect Started", f"Searching for {server_type} server", "Now")
|
||||
|
||||
found_url = run_detection(server_type)
|
||||
if found_url:
|
||||
add_activity_item("✅", "Auto-Detect Complete", f"{server_type} found at {found_url}", "Now")
|
||||
return jsonify({"success": True, "found_url": found_url})
|
||||
else:
|
||||
add_activity_item("❌", "Auto-Detect Failed", f"No {server_type} server found", "Now")
|
||||
return jsonify({"success": False, "error": f"No {server_type} server found on common local addresses."})
|
||||
|
||||
@app.route('/api/detect-soulseek', methods=['POST'])
|
||||
def detect_soulseek_endpoint():
|
||||
print("Received auto-detect request for slskd")
|
||||
|
||||
# Add activity for soulseek auto-detect start
|
||||
add_activity_item("🔍", "Auto-Detect Started", "Searching for slskd server", "Now")
|
||||
found_url = run_detection('slskd')
|
||||
if found_url:
|
||||
add_activity_item("✅", "Auto-Detect Complete", f"slskd found at {found_url}", "Now")
|
||||
return jsonify({"success": True, "found_url": found_url})
|
||||
else:
|
||||
add_activity_item("❌", "Auto-Detect Failed", "No slskd server found", "Now")
|
||||
return jsonify({"success": False, "error": "No slskd server found on common local addresses."})
|
||||
|
||||
# --- Full Tidal Authentication Flow ---
|
||||
|
|
@ -1595,12 +1648,17 @@ def auth_tidal():
|
|||
print(" tidal_client.authenticate() to start the flow.")
|
||||
print("Please follow the instructions in the console to log in to Tidal.")
|
||||
|
||||
# Add activity for authentication start
|
||||
add_activity_item("🔐", "Tidal Auth Started", "Initiating authentication flow", "Now")
|
||||
|
||||
if temp_tidal_client.authenticate():
|
||||
# Re-initialize the main client instance after successful auth
|
||||
global tidal_client
|
||||
tidal_client = TidalClient()
|
||||
add_activity_item("✅", "Tidal Auth Complete", "Successfully authenticated with Tidal", "Now")
|
||||
return "<h1>✅ Tidal Authentication Successful!</h1><p>You can now close this window and return to the SoulSync application.</p>"
|
||||
else:
|
||||
add_activity_item("❌", "Tidal Auth Failed", "Authentication with Tidal failed", "Now")
|
||||
return "<h1>❌ Tidal Authentication Failed</h1><p>Please check the console output of the server for a login URL and follow the instructions.</p>", 400
|
||||
|
||||
|
||||
|
|
@ -1674,6 +1732,9 @@ def search_music():
|
|||
|
||||
print(f"Web UI Search for: '{query}'")
|
||||
|
||||
# Add activity for search start
|
||||
add_activity_item("🔍", "Search Started", f"'{query}'", "Now")
|
||||
|
||||
try:
|
||||
tracks, albums = asyncio.run(soulseek_client.search(query))
|
||||
|
||||
|
|
@ -1694,6 +1755,10 @@ def search_music():
|
|||
# Sort by quality score
|
||||
all_results = sorted(processed_albums + processed_tracks, key=lambda x: x.get('quality_score', 0), reverse=True)
|
||||
|
||||
# Add activity for search completion
|
||||
total_results = len(all_results)
|
||||
add_activity_item("✅", "Search Complete", f"'{query}' - {total_results} results", "Now")
|
||||
|
||||
return jsonify({"results": all_results})
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -7970,6 +8035,10 @@ def cancel_batch(batch_id):
|
|||
task['status'] = 'cancelled'
|
||||
cancelled_count += 1
|
||||
|
||||
# Add activity for batch cancellation
|
||||
playlist_name = download_batches[batch_id].get('playlist_name', 'Unknown Playlist')
|
||||
add_activity_item("🚫", "Batch Cancelled", f"'{playlist_name}' - {cancelled_count} downloads cancelled", "Now")
|
||||
|
||||
print(f"✅ Cancelled batch {batch_id} with {cancelled_count} tasks")
|
||||
return jsonify({"success": True, "cancelled_tasks": cancelled_count})
|
||||
|
||||
|
|
@ -8449,6 +8518,9 @@ def start_tidal_discovery(playlist_id):
|
|||
}
|
||||
tidal_discovery_states[playlist_id] = state
|
||||
|
||||
# Add activity for discovery start
|
||||
add_activity_item("🔍", "Tidal Discovery Started", f"'{target_playlist.name}' - {len(target_playlist.tracks)} tracks", "Now")
|
||||
|
||||
# Start discovery worker
|
||||
future = tidal_discovery_executor.submit(_run_tidal_discovery_worker, playlist_id)
|
||||
state['discovery_future'] = future
|
||||
|
|
@ -8714,6 +8786,9 @@ def _run_tidal_discovery_worker(playlist_id):
|
|||
state['status'] = 'discovered'
|
||||
state['discovery_progress'] = 100
|
||||
|
||||
# Add activity for discovery completion
|
||||
add_activity_item("✅", "Tidal Discovery Complete", f"'{playlist.name}' - {successful_discoveries}/{len(playlist.tracks)} tracks found", "Now")
|
||||
|
||||
print(f"✅ Tidal discovery complete: {successful_discoveries}/{len(playlist.tracks)} tracks found")
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -8993,6 +9068,11 @@ def start_youtube_discovery(url_hash):
|
|||
state['discovery_progress'] = 0
|
||||
state['spotify_matches'] = 0
|
||||
|
||||
# Add activity for discovery start
|
||||
playlist_name = state['playlist']['name']
|
||||
track_count = len(state['playlist']['tracks'])
|
||||
add_activity_item("🔍", "YouTube Discovery Started", f"'{playlist_name}' - {track_count} tracks", "Now")
|
||||
|
||||
# Start discovery worker
|
||||
future = youtube_discovery_executor.submit(_run_youtube_discovery_worker, url_hash)
|
||||
state['discovery_future'] = future
|
||||
|
|
@ -9146,6 +9226,10 @@ def _run_youtube_discovery_worker(url_hash):
|
|||
state['status'] = 'complete'
|
||||
state['discovery_progress'] = 100
|
||||
|
||||
# Add activity for discovery completion
|
||||
playlist_name = playlist['name']
|
||||
add_activity_item("✅", "YouTube Discovery Complete", f"'{playlist_name}' - {state['spotify_matches']}/{len(tracks)} tracks found", "Now")
|
||||
|
||||
print(f"✅ YouTube discovery complete: {state['spotify_matches']}/{len(tracks)} tracks matched")
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@
|
|||
<p class="service-card-status-text" id="spotify-status-text">Disconnected</p>
|
||||
<p class="service-card-response-time" id="spotify-response-time">Response: --</p>
|
||||
<div class="service-card-footer">
|
||||
<button class="service-card-button" onclick="testConnection('spotify')">Test Connection</button>
|
||||
<button class="service-card-button" onclick="testDashboardConnection('spotify')">Test Connection</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="service-card" id="media-server-service-card">
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
<p class="service-card-status-text" id="media-server-status-text">Disconnected</p>
|
||||
<p class="service-card-response-time" id="media-server-response-time">Response: --</p>
|
||||
<div class="service-card-footer">
|
||||
<button class="service-card-button" onclick="testConnection('server')">Test Connection</button>
|
||||
<button class="service-card-button" onclick="testDashboardConnection('server')">Test Connection</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="service-card" id="soulseek-service-card">
|
||||
|
|
@ -190,7 +190,7 @@
|
|||
<p class="service-card-status-text" id="soulseek-status-text">Disconnected</p>
|
||||
<p class="service-card-response-time" id="soulseek-response-time">Response: --</p>
|
||||
<div class="service-card-footer">
|
||||
<button class="service-card-button" onclick="testConnection('soulseek')">Test Connection</button>
|
||||
<button class="service-card-button" onclick="testDashboardConnection('soulseek')">Test Connection</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -259,6 +259,7 @@ const API = {
|
|||
config: '/config',
|
||||
settings: '/api/settings',
|
||||
testConnection: '/api/test-connection',
|
||||
testDashboardConnection: '/api/test-dashboard-connection',
|
||||
playlists: '/api/playlists',
|
||||
sync: '/api/sync',
|
||||
search: '/api/search',
|
||||
|
|
@ -1511,6 +1512,32 @@ async function testConnection(service) {
|
|||
}
|
||||
}
|
||||
|
||||
// Dashboard-specific test functions that create activity items
|
||||
async function testDashboardConnection(service) {
|
||||
try {
|
||||
showLoadingOverlay(`Testing ${service} service...`);
|
||||
|
||||
const response = await fetch(API.testDashboardConnection, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ service })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showToast(`${service} service verified`, 'success');
|
||||
} else {
|
||||
showToast(`${service} service check failed: ${result.error}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error testing ${service} service:`, error);
|
||||
showToast(`Failed to test ${service} service`, 'error');
|
||||
} finally {
|
||||
hideLoadingOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
// Individual Auto-detect functions - same as GUI
|
||||
async function autoDetectPlex() {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in a new issue