Added AudioFileScanner and AudioImageExtractor logic.
This commit is contained in:
27
Harmonia.Core/Imaging/AudioImageExtractor.cs
Normal file
27
Harmonia.Core/Imaging/AudioImageExtractor.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Harmonia.Core.Tags;
|
||||
|
||||
namespace Harmonia.Core.Imaging;
|
||||
|
||||
public class AudioImageExtractor(ITagResolver tagResolver) : IAudioImageExtractor
|
||||
{
|
||||
public SongPictureInfo ExtractImage(string fileName)
|
||||
{
|
||||
SongTagInfo songTagInfo = tagResolver.GetSongTagInfo(fileName);
|
||||
|
||||
return ExtractImage(fileName, songTagInfo);
|
||||
}
|
||||
|
||||
public SongPictureInfo ExtractImage(string fileName, SongTagInfo songTagInfo)
|
||||
{
|
||||
if (songTagInfo.FrontCover != null)
|
||||
{
|
||||
using MemoryStream memoryStream = new(songTagInfo.FrontCover.Data);
|
||||
|
||||
return SongPictureInfo.FromStream(memoryStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SongPictureInfo.FromFile(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Harmonia.Core/Imaging/IAudioImageExtractor.cs
Normal file
9
Harmonia.Core/Imaging/IAudioImageExtractor.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Harmonia.Core.Tags;
|
||||
|
||||
namespace Harmonia.Core.Imaging;
|
||||
|
||||
public interface IAudioImageExtractor
|
||||
{
|
||||
SongPictureInfo ExtractImage(string fileName);
|
||||
SongPictureInfo ExtractImage(string fileName, SongTagInfo songTagInfo);
|
||||
}
|
||||
59
Harmonia.Core/Imaging/SongPictureInfo.cs
Normal file
59
Harmonia.Core/Imaging/SongPictureInfo.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Harmonia.Core.Imaging;
|
||||
|
||||
public class SongPictureInfo : IDisposable
|
||||
{
|
||||
public required Stream Stream { get; init; }
|
||||
public string? ImageHash { get; init; }
|
||||
public required string ImageName { get; init; }
|
||||
public ulong Size { get; init; }
|
||||
|
||||
private SongPictureInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static SongPictureInfo FromStream(Stream stream)
|
||||
{
|
||||
string imageHash = ComputeImageHash(stream);
|
||||
|
||||
return GetSongPictureInfo(stream, "Embedded", imageHash);
|
||||
}
|
||||
|
||||
private static string ComputeImageHash(Stream stream)
|
||||
{
|
||||
using var md5 = MD5.Create();
|
||||
byte[] hash = md5.ComputeHash(stream);
|
||||
|
||||
return Convert.ToHexStringLower(hash);
|
||||
}
|
||||
|
||||
public static SongPictureInfo FromFile(string fileName)
|
||||
{
|
||||
using FileStream fileStream = File.OpenRead(fileName);
|
||||
|
||||
return GetSongPictureInfo(fileStream, fileName);
|
||||
}
|
||||
|
||||
private static SongPictureInfo GetSongPictureInfo(Stream stream, string imageName, string? imageHash = null)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
SongPictureInfo songPictureInfo = new()
|
||||
{
|
||||
Stream = stream,
|
||||
ImageHash = imageHash,
|
||||
ImageName = imageName,
|
||||
Size = (ulong)stream.Length
|
||||
};
|
||||
|
||||
return songPictureInfo;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stream.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
57
Harmonia.Core/Scanner/AudioFileScanner.cs
Normal file
57
Harmonia.Core/Scanner/AudioFileScanner.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Harmonia.Core.Imaging;
|
||||
using Harmonia.Core.Models;
|
||||
using Harmonia.Core.Tags;
|
||||
|
||||
namespace Harmonia.Core.Scanner;
|
||||
|
||||
public class AudioFileScanner(ITagResolver tagResolver, IAudioImageExtractor audioImageExtractor) : IAudioFileScanner
|
||||
{
|
||||
public Song[] GetSongs(string[] fileNames)
|
||||
{
|
||||
List<Song> songs = [];
|
||||
|
||||
foreach (string fileName in fileNames)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fileName) || File.Exists(fileName) == false)
|
||||
continue;
|
||||
|
||||
Song? song = GetSong(fileName);
|
||||
|
||||
if (song == null)
|
||||
continue;
|
||||
|
||||
songs.Add(song);
|
||||
}
|
||||
|
||||
return [.. songs];
|
||||
}
|
||||
|
||||
private Song GetSong(string fileName)
|
||||
{
|
||||
FileInfo fileInfo = new(fileName);
|
||||
SongTagInfo songTagInfo = tagResolver.GetSongTagInfo(fileName);
|
||||
using SongPictureInfo songPictureInfo = audioImageExtractor.ExtractImage(fileName, songTagInfo);
|
||||
|
||||
Song song = new()
|
||||
{
|
||||
FileName = fileName,
|
||||
Size = (ulong)fileInfo.Length,
|
||||
LastModified = fileInfo.LastWriteTime,
|
||||
Title = songTagInfo.Title,
|
||||
Album = songTagInfo.Album,
|
||||
Artists = songTagInfo.Artists,
|
||||
AlbumArtists = songTagInfo.AlbumArtists,
|
||||
DiscNumber = songTagInfo.DiscNumber,
|
||||
TrackNumber = songTagInfo.TrackNumber,
|
||||
Length = songTagInfo.Length,
|
||||
Year = songTagInfo.Year,
|
||||
Genre = songTagInfo.Genre,
|
||||
BitRate = songTagInfo.BitRate,
|
||||
SampleRate = songTagInfo.SampleRate,
|
||||
ImageName = songPictureInfo.ImageName,
|
||||
ImageHash = songPictureInfo.ImageHash
|
||||
};
|
||||
|
||||
return song;
|
||||
}
|
||||
}
|
||||
8
Harmonia.Core/Scanner/IAudioFileScanner.cs
Normal file
8
Harmonia.Core/Scanner/IAudioFileScanner.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Harmonia.Core.Models;
|
||||
|
||||
namespace Harmonia.Core.Scanner;
|
||||
|
||||
public interface IAudioFileScanner
|
||||
{
|
||||
Song[] GetSongs(string[] fileNames);
|
||||
}
|
||||
@@ -6,13 +6,17 @@ public class SongTagInfo
|
||||
public string? Album { get; set; }
|
||||
public List<string> Artists { get; set; } = [];
|
||||
public List<string> AlbumArtists { get; set; } = [];
|
||||
public int? DiscNumber { get; set; }
|
||||
public int? TrackNumber { get; set; }
|
||||
public byte? DiscNumber { get; set; }
|
||||
public byte? TrackNumber { get; set; }
|
||||
public TimeSpan Length { get; set; } = TimeSpan.Zero;
|
||||
public int? Year { get; set; }
|
||||
public ushort? Year { get; set; }
|
||||
public string? Genre { get; set; }
|
||||
public int BitRate { get; set; }
|
||||
public int SampleRate { get; set; }
|
||||
public uint BitRate { get; set; }
|
||||
public uint SampleRate { get; set; }
|
||||
public List<PictureTag> Pictures { get; set; } = [];
|
||||
public Dictionary<string, string> Other { get; set; } = [];
|
||||
|
||||
public PictureTag? FrontCover => Pictures.Where(x => x.PictureType != PictureType.NotAPicture)
|
||||
.OrderBy(x => x.PictureType == PictureType.FrontCover)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
@@ -8,30 +8,30 @@ public class TagLibTagResolver : ITagResolver
|
||||
|
||||
using (var tagFile = TagLib.File.Create(fileName))
|
||||
{
|
||||
int? discNumber = null;
|
||||
int? trackNumber = null;
|
||||
int? year = null;
|
||||
byte? discNumber = null;
|
||||
byte? trackNumber = null;
|
||||
ushort? year = null;
|
||||
|
||||
if (tagFile.Tag.Track > 0)
|
||||
trackNumber = Convert.ToInt32(tagFile.Tag.Track);
|
||||
trackNumber = (byte)tagFile.Tag.Track;
|
||||
|
||||
if (tagFile.Tag.Disc > 0)
|
||||
discNumber = Convert.ToInt32(tagFile.Tag.Disc);
|
||||
discNumber = (byte)tagFile.Tag.Disc;
|
||||
|
||||
if (tagFile.Tag.Year > 0)
|
||||
year = Convert.ToInt32(tagFile.Tag.Year);
|
||||
year = (ushort)tagFile.Tag.Year;
|
||||
|
||||
songTagInfo.Title = tagFile.Tag.Title;
|
||||
songTagInfo.Album = tagFile.Tag.Album;
|
||||
songTagInfo.Artists = tagFile.Tag.Performers.Select(x => x.Trim()).ToList();
|
||||
songTagInfo.AlbumArtists = tagFile.Tag.AlbumArtists.Select(x => x.Trim()).ToList();
|
||||
songTagInfo.Artists = [.. tagFile.Tag.Performers.Select(x => x.Trim())];
|
||||
songTagInfo.AlbumArtists = [.. tagFile.Tag.AlbumArtists.Select(x => x.Trim())];
|
||||
songTagInfo.DiscNumber = discNumber;
|
||||
songTagInfo.TrackNumber = trackNumber;
|
||||
songTagInfo.Length = tagFile.Properties.Duration;
|
||||
songTagInfo.Year = year;
|
||||
songTagInfo.Genre = tagFile.Tag.JoinedGenres;
|
||||
songTagInfo.BitRate = tagFile.Properties.AudioBitrate;
|
||||
songTagInfo.SampleRate = tagFile.Properties.AudioSampleRate;
|
||||
songTagInfo.BitRate = (uint)tagFile.Properties.AudioBitrate;
|
||||
songTagInfo.SampleRate = (uint)tagFile.Properties.AudioSampleRate;
|
||||
|
||||
foreach (var picture in tagFile.Tag.Pictures)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user