improved history page
This commit is contained in:
@@ -1 +0,0 @@
|
||||
docker buildx build --push --platform linux/amd64,linux/arm64 --build-arg CACHE_BUST=$(date +%s) --tag cooldockerizer93/spotizerr:dev .
|
||||
@@ -1 +0,0 @@
|
||||
docker buildx build --push --platform linux/amd64,linux/arm64 --build-arg CACHE_BUST=$(date +%s) --tag cooldockerizer93/spotizerr:latest .
|
||||
@@ -160,6 +160,28 @@ def _log_task_to_history(task_id, final_status_str, error_msg=None):
|
||||
logger.warning(f"History: No task_info found for task_id {task_id}. Cannot log to history.")
|
||||
return
|
||||
|
||||
# Determine service_used and quality_profile
|
||||
main_service_name = str(task_info.get('main', 'Unknown')).capitalize() # e.g. Spotify, Deezer from their respective .env values
|
||||
fallback_service_name = str(task_info.get('fallback', '')).capitalize()
|
||||
|
||||
service_used_str = main_service_name
|
||||
if task_info.get('fallback') and fallback_service_name: # Check if fallback was configured
|
||||
# Try to infer actual service used if possible, otherwise show configured.
|
||||
# This part is a placeholder for more accurate determination if deezspot gives explicit feedback.
|
||||
# For now, we assume 'main' was used unless an error hints otherwise.
|
||||
# A more robust solution would involve deezspot callback providing this.
|
||||
service_used_str = f"{main_service_name} (Fallback: {fallback_service_name})"
|
||||
# If error message indicates fallback, we could try to parse it.
|
||||
# e.g. if error_msg and "fallback" in error_msg.lower(): service_used_str = f"{fallback_service_name} (Used Fallback)"
|
||||
|
||||
# Determine quality profile (primarily from the 'quality' field)
|
||||
# 'quality' usually holds the primary service's quality (e.g., spotifyQuality, deezerQuality)
|
||||
quality_profile_str = str(task_info.get('quality', 'N/A'))
|
||||
|
||||
# Get convertTo and bitrate
|
||||
convert_to_str = str(task_info.get('convertTo', '')) # Empty string if None or not present
|
||||
bitrate_str = str(task_info.get('bitrate', '')) # Empty string if None or not present
|
||||
|
||||
# Extract Spotify ID from item URL if possible
|
||||
spotify_id = None
|
||||
item_url = task_info.get('url', '')
|
||||
@@ -185,7 +207,11 @@ def _log_task_to_history(task_id, final_status_str, error_msg=None):
|
||||
'timestamp_added': task_info.get('created_at', time.time()),
|
||||
'timestamp_completed': last_status_obj.get('timestamp', time.time()) if last_status_obj else time.time(),
|
||||
'original_request_json': json.dumps(task_info.get('original_request', {})),
|
||||
'last_status_obj_json': json.dumps(last_status_obj if last_status_obj else {})
|
||||
'last_status_obj_json': json.dumps(last_status_obj if last_status_obj else {}),
|
||||
'service_used': service_used_str,
|
||||
'quality_profile': quality_profile_str,
|
||||
'convert_to': convert_to_str if convert_to_str else None, # Store None if empty string
|
||||
'bitrate': bitrate_str if bitrate_str else None # Store None if empty string
|
||||
}
|
||||
add_entry_to_history(history_entry)
|
||||
except Exception as e:
|
||||
|
||||
@@ -29,7 +29,11 @@ def init_history_db():
|
||||
timestamp_added REAL,
|
||||
timestamp_completed REAL,
|
||||
original_request_json TEXT,
|
||||
last_status_obj_json TEXT
|
||||
last_status_obj_json TEXT,
|
||||
service_used TEXT,
|
||||
quality_profile TEXT,
|
||||
convert_to TEXT,
|
||||
bitrate TEXT
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
@@ -51,7 +55,8 @@ def add_entry_to_history(history_data: dict):
|
||||
'task_id', 'download_type', 'item_name', 'item_artist', 'item_album',
|
||||
'item_url', 'spotify_id', 'status_final', 'error_message',
|
||||
'timestamp_added', 'timestamp_completed', 'original_request_json',
|
||||
'last_status_obj_json'
|
||||
'last_status_obj_json', 'service_used', 'quality_profile',
|
||||
'convert_to', 'bitrate'
|
||||
]
|
||||
# Ensure all keys are present, filling with None if not
|
||||
for key in required_keys:
|
||||
@@ -66,14 +71,17 @@ def add_entry_to_history(history_data: dict):
|
||||
task_id, download_type, item_name, item_artist, item_album,
|
||||
item_url, spotify_id, status_final, error_message,
|
||||
timestamp_added, timestamp_completed, original_request_json,
|
||||
last_status_obj_json
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
last_status_obj_json, service_used, quality_profile,
|
||||
convert_to, bitrate
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
history_data['task_id'], history_data['download_type'], history_data['item_name'],
|
||||
history_data['item_artist'], history_data['item_album'], history_data['item_url'],
|
||||
history_data['spotify_id'], history_data['status_final'], history_data['error_message'],
|
||||
history_data['timestamp_added'], history_data['timestamp_completed'],
|
||||
history_data['original_request_json'], history_data['last_status_obj_json']
|
||||
history_data['original_request_json'], history_data['last_status_obj_json'],
|
||||
history_data['service_used'], history_data['quality_profile'],
|
||||
history_data['convert_to'], history_data['bitrate']
|
||||
))
|
||||
conn.commit()
|
||||
logger.info(f"Added/Updated history for task_id: {history_data['task_id']}, status: {history_data['status_final']}")
|
||||
@@ -131,7 +139,8 @@ def get_history_entries(limit=25, offset=0, sort_by='timestamp_completed', sort_
|
||||
# Validate sort_by and sort_order to prevent SQL injection
|
||||
valid_sort_columns = [
|
||||
'task_id', 'download_type', 'item_name', 'item_artist', 'item_album',
|
||||
'item_url', 'status_final', 'timestamp_added', 'timestamp_completed'
|
||||
'item_url', 'status_final', 'timestamp_added', 'timestamp_completed',
|
||||
'service_used', 'quality_profile', 'convert_to', 'bitrate'
|
||||
]
|
||||
if sort_by not in valid_sort_columns:
|
||||
sort_by = 'timestamp_completed' # Default sort
|
||||
@@ -175,7 +184,11 @@ if __name__ == '__main__':
|
||||
'timestamp_added': time.time() - 3600,
|
||||
'timestamp_completed': time.time(),
|
||||
'original_request_json': json.dumps({'param1': 'value1'}),
|
||||
'last_status_obj_json': json.dumps({'status': 'complete', 'message': 'Finished!'})
|
||||
'last_status_obj_json': json.dumps({'status': 'complete', 'message': 'Finished!'}),
|
||||
'service_used': 'Spotify (Primary)',
|
||||
'quality_profile': 'NORMAL',
|
||||
'convert_to': None,
|
||||
'bitrate': None
|
||||
}
|
||||
add_entry_to_history(sample_data_complete)
|
||||
|
||||
@@ -192,7 +205,11 @@ if __name__ == '__main__':
|
||||
'timestamp_added': time.time() - 7200,
|
||||
'timestamp_completed': time.time() - 60,
|
||||
'original_request_json': json.dumps({'param2': 'value2'}),
|
||||
'last_status_obj_json': json.dumps({'status': 'error', 'error': 'Network issue'})
|
||||
'last_status_obj_json': json.dumps({'status': 'error', 'error': 'Network issue'}),
|
||||
'service_used': 'Deezer',
|
||||
'quality_profile': 'MP3_320',
|
||||
'convert_to': 'mp3',
|
||||
'bitrate': '320'
|
||||
}
|
||||
add_entry_to_history(sample_data_error)
|
||||
|
||||
@@ -210,7 +227,11 @@ if __name__ == '__main__':
|
||||
'timestamp_added': time.time() - 3600,
|
||||
'timestamp_completed': time.time() + 100, # Updated completion time
|
||||
'original_request_json': json.dumps({'param1': 'value1', 'new_param': 'added'}),
|
||||
'last_status_obj_json': json.dumps({'status': 'complete', 'message': 'Finished! With update.'})
|
||||
'last_status_obj_json': json.dumps({'status': 'complete', 'message': 'Finished! With update.'}),
|
||||
'service_used': 'Spotify (Deezer Fallback)',
|
||||
'quality_profile': 'HIGH',
|
||||
'convert_to': 'flac',
|
||||
'bitrate': None
|
||||
}
|
||||
add_entry_to_history(updated_data_complete)
|
||||
|
||||
|
||||
@@ -41,10 +41,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
totalEntries = data.total_count;
|
||||
currentPage = Math.floor(offset / limit) + 1;
|
||||
updatePagination();
|
||||
updateSortIndicators();
|
||||
} catch (error) {
|
||||
console.error('Error fetching history:', error);
|
||||
if (historyTableBody) {
|
||||
historyTableBody.innerHTML = '<tr><td colspan="7">Error loading history.</td></tr>';
|
||||
historyTableBody.innerHTML = '<tr><td colspan="9">Error loading history.</td></tr>';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +55,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
historyTableBody.innerHTML = ''; // Clear existing rows
|
||||
if (!entries || entries.length === 0) {
|
||||
historyTableBody.innerHTML = '<tr><td colspan="7">No history entries found.</td></tr>';
|
||||
historyTableBody.innerHTML = '<tr><td colspan="9">No history entries found.</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,6 +64,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
row.insertCell().textContent = entry.item_name || 'N/A';
|
||||
row.insertCell().textContent = entry.item_artist || 'N/A';
|
||||
row.insertCell().textContent = entry.download_type ? entry.download_type.charAt(0).toUpperCase() + entry.download_type.slice(1) : 'N/A';
|
||||
row.insertCell().textContent = entry.service_used || 'N/A';
|
||||
// Construct Quality display string
|
||||
let qualityDisplay = entry.quality_profile || 'N/A';
|
||||
if (entry.convert_to) {
|
||||
qualityDisplay = `${entry.convert_to.toUpperCase()}`;
|
||||
if (entry.bitrate) {
|
||||
qualityDisplay += ` ${entry.bitrate}k`;
|
||||
}
|
||||
qualityDisplay += ` (${entry.quality_profile || 'Original'})`;
|
||||
} else if (entry.bitrate) { // Case where convert_to might not be set, but bitrate is (e.g. for OGG Vorbis quality settings)
|
||||
qualityDisplay = `${entry.bitrate}k (${entry.quality_profile || 'Profile'})`;
|
||||
}
|
||||
row.insertCell().textContent = qualityDisplay;
|
||||
|
||||
const statusCell = row.insertCell();
|
||||
statusCell.textContent = entry.status_final || 'N/A';
|
||||
@@ -91,7 +105,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
errorDetailsDiv = document.createElement('div');
|
||||
errorDetailsDiv.className = 'error-details';
|
||||
const newCell = row.insertCell(); // This will append to the end of the row
|
||||
newCell.colSpan = 7; // Span across all columns
|
||||
newCell.colSpan = 9; // Span across all columns
|
||||
newCell.appendChild(errorDetailsDiv);
|
||||
// Visually, this new cell will be after the 'Details' button cell.
|
||||
// To make it appear as part of the status cell or below the row, more complex DOM manipulation or CSS would be needed.
|
||||
@@ -122,6 +136,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
`Album: ${entry.item_album || 'N/A'}\n` +
|
||||
`URL: ${entry.item_url}\n` +
|
||||
`Spotify ID: ${entry.spotify_id || 'N/A'}\n` +
|
||||
`Service Used: ${entry.service_used || 'N/A'}\n` +
|
||||
`Quality Profile (Original): ${entry.quality_profile || 'N/A'}\n` +
|
||||
`ConvertTo: ${entry.convert_to || 'N/A'}\n` +
|
||||
`Bitrate: ${entry.bitrate ? entry.bitrate + 'k' : 'N/A'}\n` +
|
||||
`Status: ${entry.status_final}\n` +
|
||||
`Error: ${entry.error_message || 'None'}\n` +
|
||||
`Added: ${new Date(entry.timestamp_added * 1000).toLocaleString()}\n` +
|
||||
@@ -146,6 +164,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
});
|
||||
|
||||
function updateSortIndicators() {
|
||||
document.querySelectorAll('th[data-sort]').forEach(headerCell => {
|
||||
const th = headerCell as HTMLElement;
|
||||
th.classList.remove('sort-asc', 'sort-desc');
|
||||
if (th.dataset.sort === currentSortBy) {
|
||||
th.classList.add(currentSortOrder === 'ASC' ? 'sort-asc' : 'sort-desc');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prevButton?.addEventListener('click', () => fetchHistory(currentPage - 1));
|
||||
nextButton?.addEventListener('click', () => fetchHistory(currentPage + 1));
|
||||
limitSelect?.addEventListener('change', (e) => {
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
<th data-sort="item_name">Name</th>
|
||||
<th data-sort="item_artist">Artist</th>
|
||||
<th data-sort="download_type">Type</th>
|
||||
<th data-sort="service_used">Service</th>
|
||||
<th data-sort="quality_profile">Quality</th>
|
||||
<th data-sort="status_final">Status</th>
|
||||
<th data-sort="timestamp_added">Date Added</th>
|
||||
<th data-sort="timestamp_completed">Date Completed/Ended</th>
|
||||
|
||||
Reference in New Issue
Block a user