Updated SongPictureInfo use to async copy of picture data stream. Update other classes accordingly.

This commit is contained in:
2025-03-02 23:28:28 -05:00
parent 1a9c1a5478
commit 0675131195
11 changed files with 178 additions and 149 deletions

View File

@@ -30,11 +30,11 @@ public class AudioImageMemoryCache(IAudioImageExtractor audioImageExtractor) : M
return null;
}
protected override ValueTask<SongPictureInfo?> FetchAsync(Song key, CancellationToken cancellationToken)
protected override async ValueTask<SongPictureInfo?> FetchAsync(Song key, CancellationToken cancellationToken)
{
SongPictureInfo? songPictureInfo = audioImageExtractor.ExtractImage(key.FileName);
SongPictureInfo? songPictureInfo = await audioImageExtractor.ExtractImageAsync(key.FileName, cancellationToken);
return ValueTask.FromResult(songPictureInfo);
return songPictureInfo;
}
protected override long GetEntrySize(SongPictureInfo entry)

View File

@@ -46,20 +46,20 @@ public class AudioImageExtractor : IAudioImageExtractor
];
}
public SongPictureInfo? ExtractImage(string path)
public async Task<SongPictureInfo?> ExtractImageAsync(string path, CancellationToken cancellationToken)
{
SongTagInfo songTagInfo = _tagResolver.GetSongTagInfo(path);
return ExtractImage(path, songTagInfo);
return await ExtractImageAsync(path, songTagInfo, cancellationToken);
}
public SongPictureInfo? ExtractImage(string path, SongTagInfo songTagInfo)
public async Task<SongPictureInfo?> ExtractImageAsync(string path, SongTagInfo songTagInfo, CancellationToken cancellationToken)
{
if (songTagInfo.FrontCover != null)
{
using MemoryStream memoryStream = new(songTagInfo.FrontCover.Data);
return SongPictureInfo.FromStream(memoryStream);
return await SongPictureInfo.FromStreamAsync(memoryStream, cancellationToken);
}
else
{
@@ -68,7 +68,7 @@ public class AudioImageExtractor : IAudioImageExtractor
if (string.IsNullOrWhiteSpace(imagePath))
return null;
return SongPictureInfo.FromFile(path);
return await SongPictureInfo.FromFileAsync(path, cancellationToken);
}
}

View File

@@ -4,6 +4,6 @@ namespace Harmonia.Core.Imaging;
public interface IAudioImageExtractor
{
SongPictureInfo? ExtractImage(string path);
SongPictureInfo? ExtractImage(string path, SongTagInfo songTagInfo);
Task<SongPictureInfo?> ExtractImageAsync(string path, CancellationToken cancellationToken);
Task<SongPictureInfo?> ExtractImageAsync(string path, SongTagInfo songTagInfo, CancellationToken cancellationToken);
}

View File

@@ -2,23 +2,23 @@
namespace Harmonia.Core.Imaging;
public class SongPictureInfo : IDisposable
public class SongPictureInfo
{
public required Stream Stream { get; init; }
public string? ImageHash { get; init; }
public required byte[] Data { get; init; }
public string? ImageHash { get; private set; }
public required string ImageName { get; init; }
public long Size { get; init; }
public long Size => Data.Length;
private SongPictureInfo()
{
}
public static SongPictureInfo FromStream(Stream stream)
public static async Task<SongPictureInfo> FromStreamAsync(Stream stream, CancellationToken cancellationToken)
{
string imageHash = ComputeImageHash(stream);
return GetSongPictureInfo(stream, "Embedded", imageHash);
return await GetSongPictureInfoAsync(stream, "Embedded", imageHash, cancellationToken);
}
private static string ComputeImageHash(Stream stream)
@@ -29,31 +29,30 @@ public class SongPictureInfo : IDisposable
return Convert.ToHexStringLower(hash);
}
public static SongPictureInfo FromFile(string fileName)
public static async Task<SongPictureInfo> FromFileAsync(string fileName, CancellationToken cancellationToken)
{
using FileStream fileStream = File.OpenRead(fileName);
return GetSongPictureInfo(fileStream, fileName);
return await GetSongPictureInfoAsync(fileStream, fileName, cancellationToken: cancellationToken);
}
private static SongPictureInfo GetSongPictureInfo(Stream stream, string imageName, string? imageHash = null)
private static async Task<SongPictureInfo> GetSongPictureInfoAsync(Stream stream, string imageName, string? imageHash = null, CancellationToken cancellationToken = default)
{
return new()
{
Data = await GetImageDataAsync(stream, cancellationToken),
ImageHash = imageHash,
ImageName = imageName
};
}
public static async Task<byte[]> GetImageDataAsync(Stream stream, CancellationToken cancellationToken)
{
stream.Seek(0, SeekOrigin.Begin);
SongPictureInfo songPictureInfo = new()
{
Stream = stream,
ImageHash = imageHash,
ImageName = imageName,
Size = stream.Length
};
using MemoryStream memoryStream = new();
await stream.CopyToAsync(memoryStream, cancellationToken);
return songPictureInfo;
}
public void Dispose()
{
Stream.Dispose();
GC.SuppressFinalize(this);
return memoryStream.ToArray();
}
}

View File

@@ -6,7 +6,7 @@ namespace Harmonia.Core.Library;
public interface IAudioLibrary
{
void AddLocation(string path);
ValueTask AddLocationAsync(string path, CancellationToken cancellationToken);
void RemoveLocation(string path);
void RemoveLocations(string[] paths);
void Scan(string path);
@@ -25,12 +25,12 @@ public abstract class AudioLibrary : IAudioLibrary
public event EventHandler<EventArgs>? ScanStarted;
public event EventHandler<EventArgs>? ScanFinished;
protected abstract bool IncludeLocation(string path);
protected abstract void ScanLocation(string path);
protected abstract ValueTask<bool> IncludeLocationAsync(string path, CancellationToken cancellationToken);
protected abstract ValueTask ScanLocationAsync(string path, CancellationToken cancellationToken);
public void AddLocation(string path)
public async ValueTask AddLocationAsync(string path, CancellationToken cancellationToken)
{
if (IncludeLocation(path) == false)
if (await IncludeLocationAsync(path, cancellationToken) == false)
return;
LocationAdded?.Invoke(this, new EventArgs());
@@ -69,13 +69,13 @@ public abstract class AudioLibrary : IAudioLibrary
public class AudioDatabaseLibrary(IAudioFileScanner audioFileScanner, AudioLibraryContext context) : AudioLibrary
{
protected override bool IncludeLocation(string path)
protected override async ValueTask<bool> IncludeLocationAsync(string path, CancellationToken cancellationToken)
{
if (CanAddLocation(path) == false)
return false;
Location location = GetLocation(path) ?? CreateLocation(path);
ScanLocation(location);
await ScanLocationAsync(location, cancellationToken);
return true;
}
@@ -104,19 +104,19 @@ public class AudioDatabaseLibrary(IAudioFileScanner audioFileScanner, AudioLibra
return context.Locations.FirstOrDefault(location => location.Name == path);
}
protected override void ScanLocation(string path)
protected override async ValueTask ScanLocationAsync(string path, CancellationToken cancellationToken)
{
Location? location = GetLocation(path);
if (location == null)
return;
ScanLocation(location);
await ScanLocationAsync(location, cancellationToken);
}
private void ScanLocation(Location location)
private async ValueTask ScanLocationAsync(Location location, CancellationToken cancellationToken)
{
SongModel[] songModels = audioFileScanner.GetSongsFromPath(location.Name);
SongModel[] songModels = await audioFileScanner.GetSongsFromPathAsync(location.Name, cancellationToken);
AddFolders(location, songModels);
AddSongs(songModels);

View File

@@ -7,7 +7,7 @@ namespace Harmonia.Core.Scanner;
public class AudioFileScanner(IAudioEngine audioEngine, ITagResolver tagResolver, IAudioImageExtractor audioImageExtractor) : IAudioFileScanner
{
public Song[] GetSongs(string[] fileNames)
public async Task<Song[]> GetSongsAsync(string[] fileNames, CancellationToken cancellationToken)
{
List<Song> songs = [];
@@ -16,7 +16,7 @@ public class AudioFileScanner(IAudioEngine audioEngine, ITagResolver tagResolver
if (string.IsNullOrWhiteSpace(fileName) || File.Exists(fileName) == false)
continue;
Song? song = GetSong(fileName);
Song? song = await GetSongAsync(fileName, cancellationToken);
if (song == null)
continue;
@@ -27,11 +27,12 @@ public class AudioFileScanner(IAudioEngine audioEngine, ITagResolver tagResolver
return [.. songs];
}
private Song GetSong(string fileName)
private async Task<Song> GetSongAsync(string fileName, CancellationToken cancellationToken)
{
FileInfo fileInfo = new(fileName);
SongTagInfo songTagInfo = tagResolver.GetSongTagInfo(fileName);
using SongPictureInfo? songPictureInfo = audioImageExtractor.ExtractImage(fileName, songTagInfo);
//using SongPictureInfo? songPictureInfo = audioImageExtractor.ExtractImage(fileName, songTagInfo);
SongPictureInfo? songPictureInfo = await audioImageExtractor.ExtractImageAsync(fileName, songTagInfo, cancellationToken);
Song song = new()
{
@@ -56,12 +57,12 @@ public class AudioFileScanner(IAudioEngine audioEngine, ITagResolver tagResolver
return song;
}
public Song[] GetSongsFromPath(string path)
public async Task<Song[]> GetSongsFromPathAsync(string path, CancellationToken cancellationToken)
{
FileInfo[] fileInfoList = GetAllFilesFromDirectory(path);
string[] fileNames = [.. fileInfoList.Select(x => x.FullName)];
return GetSongs(fileNames);
return await GetSongsAsync(fileNames, cancellationToken);
}
private FileInfo[] GetAllFilesFromDirectory(string directoryName)

View File

@@ -4,6 +4,6 @@ namespace Harmonia.Core.Scanner;
public interface IAudioFileScanner
{
Song[] GetSongs(string[] fileNames);
Song[] GetSongsFromPath(string path);
Task<Song[]> GetSongsAsync(string[] fileNames, CancellationToken cancellationToken);
Task<Song[]> GetSongsFromPathAsync(string path, CancellationToken cancellationToken);
}