Compare commits
4 Commits
63938b0139
...
140d4ea49a
| Author | SHA1 | Date | |
|---|---|---|---|
| 140d4ea49a | |||
| aa9861162d | |||
| ffe3802b25 | |||
| 3fd9e8a00c |
@@ -60,7 +60,7 @@ public abstract class Cache<TKey, TValue> : ICache<TKey, TValue> where TKey : no
|
|||||||
if (lockAcquired)
|
if (lockAcquired)
|
||||||
lockObject.Release();
|
lockObject.Release();
|
||||||
|
|
||||||
_locks.TryRemove(lockObject, out _);
|
_locks.TryRemove(actualKey, out _);
|
||||||
|
|
||||||
if (throttlerAcquired)
|
if (throttlerAcquired)
|
||||||
_throttler.Release();
|
_throttler.Release();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Harmonia.Core.Extensions;
|
using Harmonia.Core.Extensions;
|
||||||
using Harmonia.Core.Playlists;
|
|
||||||
using Harmonia.WinUI.Caching;
|
using Harmonia.WinUI.Caching;
|
||||||
using Harmonia.WinUI.Storage;
|
using Harmonia.WinUI.Storage;
|
||||||
using Harmonia.WinUI.ViewModels;
|
using Harmonia.WinUI.ViewModels;
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ public class AudioBitmapImageCache(IAudioImageExtractor audioImageExtractor) : M
|
|||||||
|
|
||||||
protected override async ValueTask<BitmapImage?> FetchAsync(Song key, CancellationToken cancellationToken)
|
protected override async ValueTask<BitmapImage?> FetchAsync(Song key, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
SongPictureInfo? songPictureInfo = await audioImageExtractor.ExtractImageAsync(key.FileName, cancellationToken);
|
SongPictureInfo? songPictureInfo = await Task.Run(
|
||||||
|
() => audioImageExtractor.ExtractImageAsync(key.FileName, cancellationToken),
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
if (songPictureInfo == null)
|
if (songPictureInfo == null)
|
||||||
return GetDefaultBitmapImage();
|
return GetDefaultBitmapImage();
|
||||||
@@ -51,8 +53,17 @@ public class AudioBitmapImageCache(IAudioImageExtractor audioImageExtractor) : M
|
|||||||
|
|
||||||
await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
|
await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
|
||||||
|
|
||||||
bitmapImage.DecodePixelWidth = GetDecodePixelWidth(bitmapImage);
|
int decodePixelWidth = GetDecodePixelWidth(bitmapImage);
|
||||||
bitmapImage.DecodePixelHeight = GetDecodePixelHeight(bitmapImage);
|
int decodePixelHeight = GetDecodePixelHeight(bitmapImage);
|
||||||
|
|
||||||
|
if (decodePixelWidth > 0 || decodePixelHeight > 0)
|
||||||
|
{
|
||||||
|
bitmapImage.DecodePixelWidth = decodePixelWidth;
|
||||||
|
bitmapImage.DecodePixelHeight = decodePixelHeight;
|
||||||
|
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
|
||||||
|
}
|
||||||
|
|
||||||
return bitmapImage;
|
return bitmapImage;
|
||||||
}
|
}
|
||||||
@@ -62,8 +73,6 @@ public class AudioBitmapImageCache(IAudioImageExtractor audioImageExtractor) : M
|
|||||||
Uri uri = new("ms-appx:///Assets/Default.png", UriKind.Absolute);
|
Uri uri = new("ms-appx:///Assets/Default.png", UriKind.Absolute);
|
||||||
|
|
||||||
BitmapImage bitmapImage = new();
|
BitmapImage bitmapImage = new();
|
||||||
bitmapImage.DecodePixelWidth = GetDecodePixelWidth(bitmapImage);
|
|
||||||
bitmapImage.DecodePixelHeight = GetDecodePixelHeight(bitmapImage);
|
|
||||||
bitmapImage.UriSource = uri;
|
bitmapImage.UriSource = uri;
|
||||||
|
|
||||||
return bitmapImage;
|
return bitmapImage;
|
||||||
@@ -99,7 +108,10 @@ public class AudioBitmapImageCache(IAudioImageExtractor audioImageExtractor) : M
|
|||||||
|
|
||||||
protected override long GetEntrySize(BitmapImage entry)
|
protected override long GetEntrySize(BitmapImage entry)
|
||||||
{
|
{
|
||||||
return entry.DecodePixelWidth * entry.DecodePixelHeight;
|
int width = entry.DecodePixelWidth > 0 ? entry.DecodePixelWidth : entry.PixelWidth;
|
||||||
|
int height = entry.DecodePixelHeight > 0 ? entry.DecodePixelHeight : entry.PixelHeight;
|
||||||
|
|
||||||
|
return (long)width * height * 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.251219" />
|
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.2.251219" />
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.28000.2270" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.28000.2526" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="2.3.1" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="2.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -20,11 +20,10 @@ using System.Linq;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Timers;
|
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Windows.ApplicationModel.DataTransfer;
|
using Windows.ApplicationModel.DataTransfer;
|
||||||
using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue;
|
using DispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue;
|
||||||
using Timer = System.Timers.Timer;
|
using DispatcherQueueTimer = Microsoft.UI.Dispatching.DispatcherQueueTimer;
|
||||||
|
|
||||||
namespace Harmonia.WinUI.ViewModels;
|
namespace Harmonia.WinUI.ViewModels;
|
||||||
|
|
||||||
@@ -40,7 +39,7 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
private readonly DispatcherQueue _dispatcherQueue;
|
private readonly DispatcherQueue _dispatcherQueue;
|
||||||
private readonly ConcurrentDictionary<int, CancellationTokenSource> _imageCancellationTokens = [];
|
private readonly ConcurrentDictionary<int, CancellationTokenSource> _imageCancellationTokens = [];
|
||||||
|
|
||||||
private Timer? _filterTimer;
|
private DispatcherQueueTimer? _filterTimer;
|
||||||
|
|
||||||
public Playlist? Playlist { get; private set; }
|
public Playlist? Playlist { get; private set; }
|
||||||
|
|
||||||
@@ -300,26 +299,19 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
if (_filterTimer == null)
|
if (_filterTimer == null)
|
||||||
{
|
{
|
||||||
_filterTimer = new Timer(300);
|
_filterTimer = _dispatcherQueue.CreateTimer();
|
||||||
_filterTimer.Elapsed += OnFilterTimerElapsed;
|
_filterTimer.Interval = TimeSpan.FromMilliseconds(300);
|
||||||
_filterTimer.Start();
|
_filterTimer.IsRepeating = false;
|
||||||
|
_filterTimer.Tick += OnFilterTimerTick;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_filterTimer.Interval = 300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnFilterTimerElapsed(object? sender, ElapsedEventArgs e)
|
|
||||||
{
|
|
||||||
if (_filterTimer == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_filterTimer.Stop();
|
_filterTimer.Stop();
|
||||||
_filterTimer.Dispose();
|
_filterTimer.Start();
|
||||||
_filterTimer = null;
|
}
|
||||||
|
|
||||||
_dispatcherQueue.TryEnqueue(UpdateFilteredSongs);
|
private void OnFilterTimerTick(DispatcherQueueTimer sender, object args)
|
||||||
|
{
|
||||||
|
UpdateFilteredSongs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateFilteredSongs()
|
private void UpdateFilteredSongs()
|
||||||
@@ -327,61 +319,59 @@ public partial class PlaylistViewModel : ViewModelBase
|
|||||||
if (Playlist == null)
|
if (Playlist == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<PlaylistSong> filteredPlaylistSongs = [.. Playlist.Songs.Where(playlistSong => IsFiltered(playlistSong.Song))];
|
string? filter = Filter;
|
||||||
//FilteredPlaylistSongs = [.. filteredPlaylistSongs];
|
HashSet<PlaylistSong> updatedFilterSet = [.. Playlist.Songs.Where(playlistSong => IsFiltered(playlistSong.Song, filter))];
|
||||||
|
|
||||||
for (int i = FilteredPlaylistSongs.Count - 1; i >= 0; i--)
|
for (int i = FilteredPlaylistSongs.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
PlaylistSong playlistSong = FilteredPlaylistSongs[i];
|
PlaylistSong playlistSong = FilteredPlaylistSongs[i];
|
||||||
|
|
||||||
bool inPlaylist = Playlist.Songs.Contains(playlistSong);
|
bool inFilterSet = updatedFilterSet.Contains(playlistSong);
|
||||||
bool inFilter = filteredPlaylistSongs.Contains(playlistSong);
|
|
||||||
|
|
||||||
if (!inPlaylist || !inFilter)
|
if (!inFilterSet)
|
||||||
{
|
FilteredPlaylistSongs.RemoveAt(i);
|
||||||
FilteredPlaylistSongs.Remove(playlistSong);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashSet<PlaylistSong> currentSet = [.. FilteredPlaylistSongs];
|
||||||
int insertionIndex = 0;
|
int insertionIndex = 0;
|
||||||
|
|
||||||
foreach (PlaylistSong playlistSong in Playlist.Songs)
|
foreach (PlaylistSong playlistSong in Playlist.Songs)
|
||||||
{
|
{
|
||||||
bool inFilter = filteredPlaylistSongs.Contains(playlistSong);
|
bool inFilterSet = updatedFilterSet.Contains(playlistSong);
|
||||||
bool inCurrentFilteredList = FilteredPlaylistSongs.Contains(playlistSong);
|
bool inCurrentSet = currentSet.Contains(playlistSong);
|
||||||
|
|
||||||
if (inFilter)
|
if (!inFilterSet)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!inCurrentSet)
|
||||||
{
|
{
|
||||||
if (!inCurrentFilteredList)
|
FilteredPlaylistSongs.Insert(insertionIndex, playlistSong);
|
||||||
{
|
|
||||||
FilteredPlaylistSongs.Insert(insertionIndex, playlistSong);
|
|
||||||
}
|
|
||||||
|
|
||||||
insertionIndex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insertionIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsFiltered(Song song)
|
private static bool IsFiltered(Song song, string? filter)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(Filter))
|
if (string.IsNullOrWhiteSpace(filter))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var shortFileName = Path.GetFileName(song.FileName);
|
var shortFileName = Path.GetFileName(song.FileName);
|
||||||
|
|
||||||
if (shortFileName.Contains(Filter, StringComparison.OrdinalIgnoreCase))
|
if (shortFileName.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(song.Title) == false && song.Title.Contains(Filter, StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrWhiteSpace(song.Title) == false && song.Title.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(song.Album) == false && song.Album.Contains(Filter, StringComparison.OrdinalIgnoreCase))
|
if (string.IsNullOrWhiteSpace(song.Album) == false && song.Album.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (song.AlbumArtists.Any(x => x.Contains(Filter, StringComparison.OrdinalIgnoreCase)))
|
if (song.AlbumArtists.Any(x => x.Contains(filter, StringComparison.OrdinalIgnoreCase)))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (song.Artists.Any(x => x.Contains(Filter, StringComparison.OrdinalIgnoreCase)))
|
if (song.Artists.Any(x => x.Contains(filter, StringComparison.OrdinalIgnoreCase)))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user