Files
harmonia/Harmonia.Core/Library/IAudioLibrary.cs

201 lines
5.4 KiB
C#

using Harmonia.Core.Scanner;
using Microsoft.EntityFrameworkCore;
using SongModel = Harmonia.Core.Models.Song;
namespace Harmonia.Core.Library;
public interface IAudioLibrary
{
void AddLocation(string path);
void RemoveLocation(string path);
void RemoveLocations(string[] paths);
void Scan(string path);
void Scan(string[] paths);
event EventHandler<EventArgs>? LocationAdded;
event EventHandler<EventArgs>? LocationRemoved;
event EventHandler<EventArgs>? ScanStarted;
event EventHandler<EventArgs>? ScanFinished;
}
public abstract class AudioLibrary : IAudioLibrary
{
public event EventHandler<EventArgs>? LocationAdded;
public event EventHandler<EventArgs>? LocationRemoved;
public event EventHandler<EventArgs>? ScanStarted;
public event EventHandler<EventArgs>? ScanFinished;
protected abstract bool IncludeLocation(string path);
protected abstract void ScanLocation(string path);
public void AddLocation(string path)
{
if (IncludeLocation(path) == false)
return;
LocationAdded?.Invoke(this, new EventArgs());
}
public void RemoveLocation(string path)
{
RemoveLocations([path]);
}
public void RemoveLocations(string[] paths)
{
//foreach (string path in paths)
//{
// //if (_locations.Contains(path) == false)
// // continue;
//}
LocationRemoved?.Invoke(this, new EventArgs());
}
public void Scan(string path)
{
Scan([path]);
}
public void Scan(string[] paths)
{
ScanStarted?.Invoke(this, new EventArgs());
ScanFinished?.Invoke(this, new EventArgs());
}
}
public class AudioDatabaseLibrary(IAudioFileScanner audioFileScanner, AudioLibraryContext context) : AudioLibrary
{
protected override bool IncludeLocation(string path)
{
if (CanAddLocation(path) == false)
return false;
Location location = GetLocation(path) ?? CreateLocation(path);
ScanLocation(location);
return true;
}
private bool CanAddLocation(string path)
{
return context.Folders.Any(folder => folder.Name == path) == false;
}
private Location CreateLocation(string path)
{
Location location = new()
{
Name = path,
Type = 0
};
context.Locations.Add(location);
context.SaveChanges();
return location;
}
private Location? GetLocation(string path)
{
return context.Locations.FirstOrDefault(location => location.Name == path);
}
protected override void ScanLocation(string path)
{
Location? location = GetLocation(path);
if (location == null)
return;
ScanLocation(location);
}
private void ScanLocation(Location location)
{
SongModel[] songModels = audioFileScanner.GetSongsFromPath(location.Name);
AddFolders(location, songModels);
AddSongs(songModels);
// Remove old songs, and clear out folders that no longer hold songs
}
private void AddFolders(Location location, SongModel[] songModels)
{
string[] folderNames = [.. songModels.Select(songModel => Directory.GetParent(songModel.FileName)?.FullName ?? string.Empty)
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct()];
Folder[] folders = [.. context.Folders.Where(folder => folder.Location == location)];
}
private void AddSongs(SongModel[] songModels)
{
foreach (SongModel songModel in songModels)
{
Folder? folder = context.Folders.FirstOrDefault(x => x.Name == songModel.FileDirectory);
if (folder == null)
continue;
Song song = AddOrUpdateSong(songModel, folder);
AddOrUpdateSongTag(songModel, song);
}
}
private Song AddOrUpdateSong(SongModel songModel, Folder folder)
{
string shortFileName = Path.GetFileName(songModel.FileName);
var song = context.Songs.FirstOrDefault(x => x.Folder == folder && string.Equals(x.FileName, shortFileName, StringComparison.OrdinalIgnoreCase));
if (song == null)
{
song = new()
{
FileName = shortFileName,
Folder = folder
};
context.Songs.Add(song);
}
song.Size = (long)songModel.Size;
song.Duration = songModel.Length.Ticks;
song.Modified = songModel.LastModified;
song.BitRate = (int)songModel.BitRate;
song.SampleRate = (int)songModel.SampleRate;
return song;
}
private SongTag AddOrUpdateSongTag(SongModel songModel, Song song)
{
var songTag = context.SongTags.FirstOrDefault(x => x.Song == song);
if (songTag == null)
{
songTag = new SongTag()
{
Song = song
};
context.SongTags.Add(songTag);
}
songTag.Title = songModel.Title;
songTag.Album = songModel.Album;
songTag.Artist = string.Join(";", songModel.Artists);
songTag.AlbumArtist = string.Join(";", songModel.AlbumArtists);
songTag.TrackNumber = songModel.TrackNumber;
songTag.DiscNumber = songModel.DiscNumber;
songTag.Genre = songModel.Genre;
songTag.ReleaseDate = songModel.Year != null ? new DateTime(songModel.Year.Value, 1, 1) : null;
return songTag;
}
}