Fix quality setting and device name display issues (#34)

- Clear both L1 memory and L2 disk caches when quality setting changes
  This ensures cached tracks at wrong quality are removed
- Fix device name not showing in popup on first hover
  Now refreshes status on each hover instead of only when null
- Add quality downgrade indicator when stream quality is lower than
  track's original quality (shows yellow arrow with tooltip)
- Store original track quality values for comparison with actual stream
This commit is contained in:
vicrodh committed 2026-01-31 23:46:02 -06:00
1 parent 8b7e4dab27
commit ae81b1c3c4
7 files changed
+78 -12

No files matched your search

+8 -2
View File
@@ -199,14 +199,20 @@ impl AudioCache {
);
}
/// Clear all cached data
/// Clear all cached data (both L1 memory and L2 disk caches)
pub fn clear(&self) {
let mut state = self.state.lock().unwrap();
state.tracks.clear();
state.access_order.clear();
state.current_size = 0;
state.fetching.clear();
log::info!("Cache cleared");
log::info!("L1 memory cache cleared");
// Also clear L2 disk cache if present
if let Some(ref playback_cache) = self.playback_cache {
playback_cache.clear();
log::info!("L2 playback cache cleared");
}
}
/// Get cache statistics
+4 -5
View File
@@ -161,12 +161,11 @@
}
}
// Update outputStatus when hovering to get fresh device name
// Always refresh status when hovering to get fresh device name
// The device name is only set when playback starts, so we need to re-fetch
$effect(() => {
if (isHovering && !outputStatus) {
invoke<AudioOutputStatus>('get_audio_output_status')
.then(status => outputStatus = status)
.catch(() => {});
if (isHovering) {
loadStatus();
}
});
+5 -1
View File
@@ -31,6 +31,8 @@
qualityLevel: number;
bitDepth?: number;
samplingRate?: number;
originalBitDepth?: number;
originalSamplingRate?: number;
format?: string;
isPlaying: boolean;
onTogglePlay: () => void;
@@ -72,6 +74,8 @@
qualityLevel,
bitDepth,
samplingRate,
originalBitDepth,
originalSamplingRate,
format,
isPlaying,
onTogglePlay,
@@ -257,7 +261,7 @@
<h3 class="album">{album}</h3>
</div>
<div class="quality-info">
<QualityBadge {quality} {bitDepth} samplingRate={displaySamplingRate} {format} />
<QualityBadge {quality} {bitDepth} samplingRate={displaySamplingRate} {originalBitDepth} {originalSamplingRate} {format} />
</div>
</div>
+5 -1
View File
@@ -37,6 +37,8 @@
qualityLevel?: number;
bitDepth?: number;
samplingRate?: number;
originalBitDepth?: number;
originalSamplingRate?: number;
format?: string;
isPlaying?: boolean;
onTogglePlay?: () => void;
@@ -76,6 +78,8 @@
qualityLevel = 0,
bitDepth,
samplingRate,
originalBitDepth,
originalSamplingRate,
format,
isPlaying = false,
onTogglePlay,
@@ -320,7 +324,7 @@
</div>
<div class="quality-indicator">
<QualityBadge {quality} {bitDepth} {samplingRate} {format} />
<QualityBadge {quality} {bitDepth} {samplingRate} {originalBitDepth} {originalSamplingRate} {format} />
<div class="audio-badges-row">
<AudioOutputBadges {samplingRate} />
</div>
+41 -2
View File
@@ -3,6 +3,8 @@
quality?: string;
bitDepth?: number;
samplingRate?: number;
originalBitDepth?: number;
originalSamplingRate?: number;
format?: string;
compact?: boolean;
}
@@ -11,10 +13,27 @@
quality = '',
bitDepth,
samplingRate,
originalBitDepth,
originalSamplingRate,
format,
compact = false
}: Props = $props();
// Check if quality was downgraded due to settings
const isDowngraded = $derived.by(() => {
// Need both original and current values to compare
if (!originalSamplingRate || !samplingRate) return false;
// Significant difference (more than 10% lower)
return samplingRate < originalSamplingRate * 0.9;
});
// Format original quality for tooltip
const originalQualityText = $derived.by(() => {
if (!isDowngraded || !originalSamplingRate) return '';
const depth = originalBitDepth || 24;
return `${depth}-bit / ${originalSamplingRate} kHz`;
});
// Determine quality tier
const tier = $derived.by(() => {
const fmt = (format || quality || '').toLowerCase();
@@ -116,7 +135,11 @@
{compactText}
</span>
{:else}
<div class="quality-badge" title="{tierLabel}: {displayText}">
<div
class="quality-badge"
class:downgraded={isDowngraded}
title={isDowngraded ? `Playing at ${displayText} (original: ${originalQualityText})` : `${tierLabel}: ${displayText}`}
>
<!-- Icon -->
<img
src={iconPath}
@@ -127,7 +150,12 @@
<!-- Text -->
<div class="badge-text">
<span class="tier-label">{tierLabel}</span>
<span class="tier-label">
{tierLabel}
{#if isDowngraded}
<span class="downgrade-indicator">↓</span>
{/if}
</span>
<span class="quality-info">{displayText}</span>
</div>
</div>
@@ -210,4 +238,15 @@
font-weight: 100;
color: #999999;
}
/* Downgrade indicator styles */
.quality-badge.downgraded {
border-color: rgba(234, 179, 8, 0.3);
}
.downgrade-indicator {
color: #eab308;
font-weight: 600;
margin-left: 2px;
}
</style>
+11 -1
View File
@@ -51,6 +51,9 @@ export interface PlayingTrack {
artistId?: number;
// ISRC for MusicBrainz/ListenBrainz enrichment
isrc?: string;
// Original track quality from metadata (for comparison with actual stream)
originalBitDepth?: number;
originalSamplingRate?: number;
}
interface BackendPlaybackState {
@@ -192,14 +195,21 @@ export function getPlayerState(): PlayerState {
/**
* Set the current track (called when starting playback)
* Preserves original quality values for comparison with actual stream
*/
export function setCurrentTrack(track: PlayingTrack | null): void {
currentTrack = track;
if (track) {
// Store original quality values before they might be overwritten by stream events
currentTrack = {
...track,
originalBitDepth: track.bitDepth,
originalSamplingRate: track.samplingRate
};
duration = track.duration;
currentTime = 0;
queueEnded = false;
} else {
currentTrack = null;
duration = 0;
currentTime = 0;
}
+4
View File
@@ -2993,6 +2993,8 @@
quality={currentTrack.quality}
bitDepth={currentTrack.bitDepth}
samplingRate={currentTrack.samplingRate}
originalBitDepth={currentTrack.originalBitDepth}
originalSamplingRate={currentTrack.originalSamplingRate}
format={currentTrack.format}
{isPlaying}
onTogglePlay={togglePlay}
@@ -3078,6 +3080,8 @@
qualityLevel={currentTrack.quality.includes('24') ? 5 : 3}
bitDepth={currentTrack.bitDepth}
samplingRate={currentTrack.samplingRate}
originalBitDepth={currentTrack.originalBitDepth}
originalSamplingRate={currentTrack.originalSamplingRate}
format={currentTrack.format}
{isPlaying}
onTogglePlay={togglePlay}