#93: Add flac support #101

Merged
kdeng00 merged 25 commits from tsk-93 into master 2024-07-27 13:19:12 -04:00
50 changed files with 787 additions and 493 deletions
+13
View File
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "8.0.7",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
+4
View File
@@ -9,3 +9,7 @@
/obj
/obj/*
/Icarus.txt
/appsettings.json
/appsettings.Development.json
appsettings.Development.json
appsettings.json
+1 -5
View File
@@ -1,7 +1,3 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Icarus.Authorization;
@@ -18,7 +14,7 @@ public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
}
var scopes = context.User.FindFirst(c =>
c.Type == "scope" && c.Issuer == requirement.Issuer).Value.Split(' ');
c.Type == "scope" && c.Issuer == requirement.Issuer)!.Value.Split(' ');
if (scopes.Any(s => s == requirement.Scope))
{
+6
View File
@@ -2,6 +2,9 @@ namespace Icarus.Constants;
public class FileExtensions
{
// Contains the default audio file extension with period at the beginning
public static string DEFAULT_AUDIO_EXTENSION = WAV_EXTENSION!;
// Contains file extension with period at the beginning
public static string MP3_EXTENSION = ".mp3";
@@ -11,6 +14,9 @@ public class FileExtensions
// Contains file extension with period at the beginning
public static string JPG_EXTENSION = ".jpg";
// Contains file extension with period at the beginning
public static string FLAC_EXTENSION = ".flac";
// Contains file extension with period at the beginning
public static string ZIP_EXTENSION = ".zip";
}
+15 -15
View File
@@ -6,7 +6,7 @@ namespace Icarus.Controllers.Managers;
public class AlbumManager : BaseManager
{
#region Fields
private AlbumContext _albumContext;
private AlbumContext? _albumContext;
#endregion
@@ -19,7 +19,7 @@ public class AlbumManager : BaseManager
{
_config = config;
_connectionString = _config.GetConnectionString("DefaultConnection");
_albumContext = new AlbumContext(_connectionString);
_albumContext = new AlbumContext(_connectionString!);
}
#endregion
@@ -33,11 +33,11 @@ public class AlbumManager : BaseManager
album.Title = song.AlbumTitle;
album.AlbumArtist = song.Artist;
album.Year = song.Year.Value;
album.Year = song.Year!.Value;
var albumTitle = song.AlbumTitle;
var albumArtist = song.Artist;
var albumRetrieved = _albumContext.Albums.FirstOrDefault(alb => alb.Title.Equals(albumTitle) && alb.AlbumArtist.Equals(albumArtist));
var albumRetrieved = _albumContext!.Albums!.FirstOrDefault(alb => alb.Title!.Equals(albumTitle) && alb.AlbumArtist!.Equals(albumArtist));
if (albumRetrieved == null)
{
@@ -58,7 +58,7 @@ public class AlbumManager : BaseManager
public void DeleteAlbumFromDatabase(Song song)
{
var album = _albumContext.Albums.FirstOrDefault(alb => alb.Title.Equals(song.AlbumTitle));
var album = _albumContext!.Albums!.FirstOrDefault(alb => alb.Title!.Equals(song.AlbumTitle));
if (album == null)
{
@@ -72,7 +72,7 @@ public class AlbumManager : BaseManager
public Album UpdateAlbumInDatabase(Song oldSong, Song newSong)
{
var albumRecord = _albumContext.Albums.FirstOrDefault(alb => alb.Title.Equals(oldSong.AlbumTitle));
var albumRecord = _albumContext!.Albums!.FirstOrDefault(alb => alb.Title!.Equals(oldSong.AlbumTitle));
var oldAlbumTitle = oldSong.AlbumTitle;
var oldAlbumArtist = oldSong.Artist;
var newAlbumTitle = newSong.AlbumTitle;
@@ -86,16 +86,16 @@ public class AlbumManager : BaseManager
newAlbumTitle = oldAlbumTitle;
if ((string.IsNullOrEmpty(newAlbumTitle) && string.IsNullOrEmpty(newAlbumArtist) ||
oldAlbumTitle.Equals(newAlbumTitle) && oldAlbumArtist.Equals(newAlbumArtist)))
oldAlbumTitle!.Equals(newAlbumTitle) && oldAlbumArtist!.Equals(newAlbumArtist)))
{
_logger.Info("No change to the song's album");
return albumRecord;
return albumRecord!;
}
info = "Change to the song's album";
_logger.Info(info);
var existingAlbumRecord = _albumContext.Albums.FirstOrDefault(alb => alb.Title.Equals(oldSong.AlbumTitle));
var existingAlbumRecord = _albumContext.Albums!.FirstOrDefault(alb => alb.Title!.Equals(oldSong.AlbumTitle));
if (existingAlbumRecord == null)
{
_logger.Info("Creating new album record");
@@ -104,7 +104,7 @@ public class AlbumManager : BaseManager
{
Title = newAlbumTitle,
AlbumArtist = newAlbumArtist,
Year = newSong.Year.Value
Year = newSong.Year!.Value
};
_albumContext.Add(newAlbumRecord);
@@ -116,8 +116,8 @@ public class AlbumManager : BaseManager
{
_logger.Info("Updating existing album record");
existingAlbumRecord = _albumContext.Albums.FirstOrDefault(alb => alb.Title.Equals(newSong.AlbumTitle));
existingAlbumRecord.AlbumArtist = newAlbumArtist;
existingAlbumRecord = _albumContext.Albums!.FirstOrDefault(alb => alb.Title!.Equals(newSong.AlbumTitle));
existingAlbumRecord!.AlbumArtist = newAlbumArtist;
_albumContext.Update(existingAlbumRecord);
_albumContext.SaveChanges();
@@ -130,15 +130,15 @@ public class AlbumManager : BaseManager
{
if (SongsInAlbum(album) <= 1)
{
_albumContext.Remove(album);
_albumContext!.Remove(album);
_albumContext.SaveChanges();
}
}
private int SongsInAlbum(Album album)
{
var sngContext = new SongContext(_connectionString);
var songs = sngContext.Songs.Where(sng => sng.AlbumId == album.Id).ToList();
var sngContext = new SongContext(_connectionString!);
var songs = sngContext!.Songs!.Where(sng => sng.AlbumId == album.Id).ToList();
return songs.Count;
}
+16 -16
View File
@@ -6,7 +6,7 @@ namespace Icarus.Controllers.Managers;
public class ArtistManager : BaseManager
{
#region Fields
private ArtistContext _artistContext;
private ArtistContext? _artistContext;
#endregion
@@ -19,7 +19,7 @@ public class ArtistManager : BaseManager
{
_config = config;
_connectionString = _config.GetConnectionString("DefaultConnection");
_artistContext = new ArtistContext(_connectionString);
_artistContext = new ArtistContext(_connectionString!);
}
#endregion
@@ -35,7 +35,7 @@ public class ArtistManager : BaseManager
SongCount = 1
};
var artistRetrieved = _artistContext.Artists.FirstOrDefault(art => art.Name.Equals(artist.Name));
var artistRetrieved = _artistContext!.Artists.FirstOrDefault(art => art.Name!.Equals(artist.Name));
if (artistRetrieved == null)
{
@@ -53,11 +53,11 @@ public class ArtistManager : BaseManager
public Artist UpdateArtistInDatabase(Song oldSongRecord, Song newSongRecord)
{
var oldArtistRecord = _artistContext.Artists.FirstOrDefault(art => art.Name.Equals(oldSongRecord.AlbumTitle));
var oldArtistName = oldArtistRecord.Name;
var oldArtistRecord = _artistContext!.Artists.FirstOrDefault(art => art.Name!.Equals(oldSongRecord.AlbumTitle));
var oldArtistName = oldArtistRecord!.Name;
var newArtistName = newSongRecord.Artist;
if (string.IsNullOrEmpty(newArtistName) || oldArtistName.Equals(newArtistName))
if (string.IsNullOrEmpty(newArtistName) || oldArtistName!.Equals(newArtistName))
{
_logger.Info("No change to the song's Artist");
return oldArtistRecord;
@@ -73,7 +73,7 @@ public class ArtistManager : BaseManager
_artistContext.SaveChanges();
}
if (!(_artistContext.Artists.FirstOrDefault(art => art.Name.Equals(oldSongRecord.AlbumTitle)) != null))
if (!(_artistContext.Artists.FirstOrDefault(art => art.Name!.Equals(oldSongRecord.AlbumTitle)) != null))
{
_logger.Info("Creating new artist record");
@@ -91,36 +91,36 @@ public class ArtistManager : BaseManager
{
_logger.Info("Updating existing artist record");
var existingArtistRecord = _artistContext.Artists.FirstOrDefault(art => art.Name.Equals(newSongRecord.AlbumTitle));
var existingArtistRecord = _artistContext.Artists.FirstOrDefault(art => art.Name!.Equals(newSongRecord.AlbumTitle));
_artistContext.Update(existingArtistRecord);
_artistContext.Update(existingArtistRecord!);
_artistContext.SaveChanges();
return existingArtistRecord;
return existingArtistRecord!;
}
}
public void DeleteArtistFromDatabase(Song song)
{
if (!(_artistContext.Artists.FirstOrDefault(art => art.Name.Equals(song.Artist)) != null))
if (!(_artistContext!.Artists.FirstOrDefault(art => art.Name!.Equals(song.Artist)) != null))
{
_logger.Info("Cannot delete the artist record because it does not exist");
return;
}
var artist = _artistContext.Artists.FirstOrDefault(art => art.Name.Equals(song.Artist));
var artist = _artistContext.Artists.FirstOrDefault(art => art.Name!.Equals(song.Artist));
if (SongsOfArtist(artist) <= 1)
if (SongsOfArtist(artist!) <= 1)
{
_artistContext.Remove(artist);
_artistContext!.Remove(artist!);
_artistContext.SaveChanges();
}
}
private int SongsOfArtist(Artist artist)
{
var sngContext = new SongContext(_connectionString);
var songs = sngContext.Songs.Where(sng => sng.ArtistId == artist.Id).ToList();
var sngContext = new SongContext(_connectionString!);
var songs = sngContext.Songs!.Where(sng => sng.ArtistId == artist.Id).ToList();
return songs.Count;
}
+2 -2
View File
@@ -7,7 +7,7 @@ public class BaseManager
{
#region Fields
protected static Logger _logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
protected IConfiguration _config;
protected string _connectionString;
protected IConfiguration? _config;
protected string? _connectionString;
#endregion
}
+19 -16
View File
@@ -8,9 +8,10 @@ namespace Icarus.Controllers.Managers;
public class CoverArtManager : BaseManager
{
#region Fields
private string _rootCoverArtPath;
private CoverArtContext _coverArtContext;
private byte[] _stockCoverArt = null;
private string? _rootCoverArtPath;
private CoverArtContext? _coverArtContext;
private byte[]? _stockCoverArt = null;
private const string? _filename = "CoverArt.png";
#endregion
@@ -29,7 +30,7 @@ public class CoverArtManager : BaseManager
public void SaveCoverArtToDatabase(ref Song song, ref CoverArt coverArt)
{
_logger.Info("Saving cover art record to the database");
_coverArtContext.Add(coverArt);
_coverArtContext!.Add(coverArt);
_coverArtContext.SaveChanges();
song.CoverArtId = coverArt.Id;
@@ -38,7 +39,7 @@ public class CoverArtManager : BaseManager
{
_logger.Info("Attempting to delete cover art from the database");
_coverArtContext.Attach(coverArt);
_coverArtContext!.Attach(coverArt);
_coverArtContext.Remove(coverArt);
_coverArtContext.SaveChanges();
}
@@ -46,7 +47,7 @@ public class CoverArtManager : BaseManager
{
try
{
var stockCoverArtPath = _rootCoverArtPath + "CoverArt.png";
var stockCoverArtPath = _rootCoverArtPath + _filename;
if (!string.Equals(stockCoverArtPath, coverArt.ImagePath(),
StringComparison.CurrentCultureIgnoreCase))
{
@@ -67,17 +68,17 @@ public class CoverArtManager : BaseManager
}
}
public CoverArt SaveCoverArt(Song song)
public CoverArt? SaveCoverArt(Song song)
{
try
{
var dirMgr = new DirectoryManager(_rootCoverArtPath);
var dirMgr = new DirectoryManager(_rootCoverArtPath!);
var defaultExtension = ".png";
dirMgr.CreateDirectory(song);
var coverArt = new CoverArt
{
SongTitle = song.Title
SongTitle = song.Title!
};
var segment = coverArt.GenerateFilename(0);
@@ -102,7 +103,7 @@ public class CoverArtManager : BaseManager
metaData.UpdateCoverArt(song, coverArt);
coverArt.Directory = this._rootCoverArtPath;
coverArt.Filename = $"{segment}{defaultExtension}";
File.WriteAllBytes(coverArt.ImagePath(), _stockCoverArt);
File.WriteAllBytes(coverArt.ImagePath(), _stockCoverArt!);
}
coverArt.Type = metaData.CoverArtFileExtensionType(coverArt);
@@ -131,7 +132,7 @@ public class CoverArtManager : BaseManager
try
{
MetadataRetriever metaData = new MetadataRetriever();
var dirMgr = new DirectoryManager(_rootCoverArtPath);
var dirMgr = new DirectoryManager(_rootCoverArtPath!);
cover.Type = metaData.FileExtensionType(data);
var defaultExtension = "." + cover.Type;
dirMgr.CreateDirectory(song);
@@ -157,21 +158,23 @@ public class CoverArtManager : BaseManager
public CoverArt GetCoverArt(Song song)
{
return _coverArtContext.CoverArtImages.FirstOrDefault(cov => cov.SongTitle.Equals(song.Title));
var title = song.Title;
var cov = _coverArtContext!.CoverArtImages!.FirstOrDefault(cov => cov.SongTitle!.Equals(title));
return cov!;
}
private void Initialize()
{
_coverArtContext = new CoverArtContext(_connectionString);
_coverArtContext = new CoverArtContext(_connectionString!);
var path = DirectoryPaths.CoverArtDirectory + DirectoryPaths.CoverArtFilename;
if (System.IO.File.Exists(path))
_stockCoverArt = File.ReadAllBytes(path);
if (!File.Exists(_rootCoverArtPath + "CoverArt.png"))
if (!File.Exists(_rootCoverArtPath + _filename))
{
File.WriteAllBytes(_rootCoverArtPath + "CoverArt.png",
_stockCoverArt);
File.WriteAllBytes(_rootCoverArtPath + _filename,
_stockCoverArt!);
Console.WriteLine("Copied Stock Cover Art");
}
}
+15 -15
View File
@@ -7,14 +7,14 @@ namespace Icarus.Controllers.Managers;
public class DirectoryManager : BaseManager
{
#region Fields
private Song _song;
private string _rootSongDirectory;
private string _songDirectory;
private Song? _song;
private string? _rootSongDirectory;
private string? _songDirectory;
#endregion
#region Properties
public string SongDirectory
public string? SongDirectory
{
get => _songDirectory;
set => _songDirectory = value;
@@ -65,7 +65,7 @@ public class DirectoryManager : BaseManager
public void CreateDirectory()
{
this.CreateDirectory(_song);
this.CreateDirectory(_song!);
}
public void CreateDirectory(Song song)
@@ -187,9 +187,9 @@ public class DirectoryManager : BaseManager
private class DirEnt
{
public string Pre { get; set;}
public string Path { get; set; }
public string Post { get; set; }
public string? Pre { get; set;}
public string? Path { get; set; }
public string? Post { get; set; }
}
private void GenerateDirectories(List<DirEnt> dirs)
@@ -197,7 +197,7 @@ public class DirectoryManager : BaseManager
foreach (var di in dirs)
{
_logger.Info(di.Pre);
Directory.CreateDirectory(di.Path);
Directory.CreateDirectory(di.Path!);
_logger.Info(di.Post);
}
}
@@ -207,10 +207,10 @@ public class DirectoryManager : BaseManager
switch (dirTypes)
{
case DirectoryType.Music:
_rootSongDirectory = _config.GetValue<string>("RootMusicPath");
_rootSongDirectory = _config!.GetValue<string>("RootMusicPath")!;
break;
case DirectoryType.CoverArt:
_rootSongDirectory = _config.GetValue<string>("CoverArtPath");
_rootSongDirectory = _config!.GetValue<string>("CoverArtPath")!;
break;
}
}
@@ -222,12 +222,12 @@ public class DirectoryManager : BaseManager
private string AlbumDirectory()
{
return AlbumDirectory(_song);
return AlbumDirectory(_song!);
}
private string AlbumDirectory(Song song)
{
var directory = ArtistDirectory(song);
var segment = SerializeValue(song.AlbumTitle);
var segment = SerializeValue(song.AlbumTitle!);
directory += $@"{segment}/";
Console.WriteLine($"Album directory {directory}");
@@ -235,12 +235,12 @@ public class DirectoryManager : BaseManager
}
private string ArtistDirectory()
{
return ArtistDirectory(_song);
return ArtistDirectory(_song!);
}
private string ArtistDirectory(Song song)
{
var directory = _rootSongDirectory;
var segment = SerializeValue(song.Artist);
var segment = SerializeValue(song.Artist!);
directory += $@"{segment}/";
Console.WriteLine($"Artist directory {directory}");
+16 -16
View File
@@ -6,7 +6,7 @@ namespace Icarus.Controllers.Managers;
public class GenreManager : BaseManager
{
#region Fields
private GenreContext _genreContext;
private GenreContext? _genreContext;
#endregion
@@ -19,7 +19,7 @@ public class GenreManager : BaseManager
{
_config = config;
_connectionString = _config.GetConnectionString("DefaultConnection");
_genreContext = new GenreContext(_connectionString);
_genreContext = new GenreContext(_connectionString!);
}
#endregion
@@ -36,7 +36,7 @@ public class GenreManager : BaseManager
};
var genreName = song.Genre;
var genreRetrieved = _genreContext.Genres.FirstOrDefault(gnr => gnr.GenreName.Equals(genreName));
var genreRetrieved = _genreContext!.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(genreName));
if (genreRetrieved == null)
{
@@ -53,11 +53,11 @@ public class GenreManager : BaseManager
public Genre UpdateGenreInDatabase(Song oldSongRecord, Song newSongRecord)
{
var oldGenreRecord = _genreContext.Genres.FirstOrDefault(gnr => gnr.GenreName.Equals(oldSongRecord.Genre));
var oldGenreName = oldGenreRecord.GenreName;
var oldGenreRecord = _genreContext!.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(oldSongRecord.Genre));
var oldGenreName = oldGenreRecord!.GenreName;
var newGenreName = newSongRecord.Genre;
if (string.IsNullOrEmpty(newGenreName) || oldGenreName.Equals(newGenreName))
if (string.IsNullOrEmpty(newGenreName) || oldGenreName!.Equals(newGenreName))
{
_logger.Info("No change to the song's Genre");
return oldGenreRecord;
@@ -73,7 +73,7 @@ public class GenreManager : BaseManager
_genreContext.SaveChanges();
}
if (!(_genreContext.Genres.FirstOrDefault(gnr => gnr.GenreName.Equals(oldSongRecord.Genre)) != null))
if (!(_genreContext.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(oldSongRecord.Genre)) != null))
{
_logger.Info("Creating new genre record");
@@ -91,36 +91,36 @@ public class GenreManager : BaseManager
{
_logger.Info("Updating existing genre record");
var existingGenreRecord = _genreContext.Genres.FirstOrDefault(gnr => gnr.GenreName.Equals(oldGenreRecord.GenreName));
var existingGenreRecord = _genreContext.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(oldGenreRecord.GenreName));
_genreContext.Update(existingGenreRecord);
_genreContext.Update(existingGenreRecord!);
_genreContext.SaveChanges();
return existingGenreRecord;
return existingGenreRecord!;
}
}
public void DeleteGenreFromDatabase(Song song)
{
if (!(_genreContext.Genres.FirstOrDefault(gnr => gnr.GenreName.Equals(song.Genre)) != null))
if (!(_genreContext!.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(song.Genre)) != null))
{
_logger.Info("Cannot delete the genre record because it does not exist");
return;
}
var genre = _genreContext.Genres.FirstOrDefault(gnr => gnr.GenreName.Equals(song.Genre));
var genre = _genreContext.Genres!.FirstOrDefault(gnr => gnr.GenreName!.Equals(song.Genre));
if (SongsInGenre(genre) <= 1)
if (SongsInGenre(genre!) <= 1)
{
_genreContext.Remove(genre);
_genreContext.Remove(genre!);
_genreContext.SaveChanges();
}
}
private int SongsInGenre(Genre genre)
{
var sngContext = new SongContext(_connectionString);
var songs = sngContext.Songs.Where(sng => sng.GenreId == genre.Id).ToList();
var sngContext = new SongContext(_connectionString!);
var songs = sngContext.Songs!.Where(sng => sng.GenreId == genre.Id).ToList();
return songs.Count;
}
+124 -86
View File
@@ -9,26 +9,26 @@ namespace Icarus.Controllers.Managers;
public class SongManager : BaseManager
{
#region Fields
private string _tempDirectoryRoot;
private string _archiveDirectoryRoot;
private string _compressedSongFilename;
private string _message;
private SongContext _songContext;
private string? _tempDirectoryRoot;
private string? _archiveDirectoryRoot;
private string? _compressedSongFilename;
private string? _message;
private SongContext? _songContext;
#endregion
#region Properties
public string ArchiveDirectoryRoot
public string? ArchiveDirectoryRoot
{
get => _archiveDirectoryRoot;
set => _archiveDirectoryRoot = value;
}
public string CompressedSongFilename
public string? CompressedSongFilename
{
get => _compressedSongFilename;
set => _compressedSongFilename = value;
}
public string Message
public string? Message
{
get => _message;
set => _message = value;
@@ -64,7 +64,7 @@ public class SongManager : BaseManager
try
{
var oldSongRecord = _songContext.RetrieveRecord(song);
var oldSongRecord = _songContext!.RetrieveRecord(song);
song.Filename = oldSongRecord.Filename;
song.SongDirectory = oldSongRecord.SongDirectory;
@@ -73,19 +73,19 @@ public class SongManager : BaseManager
var updatedSong = updateMetadata.UpdatedSongRecord;
var albMgr = new AlbumManager(_config);
var gnrMgr = new GenreManager(_config);
var artMgr = new ArtistManager(_config);
var updatedAlbum = albMgr.UpdateAlbumInDatabase(oldSongRecord, updatedSong);
var albMgr = new AlbumManager(_config!);
var gnrMgr = new GenreManager(_config!);
var artMgr = new ArtistManager(_config!);
var updatedAlbum = albMgr.UpdateAlbumInDatabase(oldSongRecord, updatedSong!);
oldSongRecord.AlbumId = updatedAlbum.Id;
var updatedArtist = artMgr.UpdateArtistInDatabase(oldSongRecord, updatedSong);
var updatedArtist = artMgr.UpdateArtistInDatabase(oldSongRecord, updatedSong!);
oldSongRecord.ArtistId = updatedArtist.Id;
var updatedGenre = gnrMgr.UpdateGenreInDatabase(oldSongRecord, updatedSong);
var updatedGenre = gnrMgr.UpdateGenreInDatabase(oldSongRecord, updatedSong!);
oldSongRecord.GenreId = updatedGenre.Id;
UpdateSongInDatabase(ref oldSongRecord, ref updatedSong, ref result);
UpdateSongInDatabase(ref oldSongRecord, ref updatedSong!, ref result);
DeleteEmptyDirectories(ref oldSongRecord, ref updatedSong);
}
@@ -109,7 +109,7 @@ public class SongManager : BaseManager
var songPath = songMetaData.SongPath();
File.Delete(songPath);
successful = true;
DirectoryManager dirMgr = new DirectoryManager(_config, songMetaData);
DirectoryManager dirMgr = new DirectoryManager(_config!, songMetaData);
dirMgr.DeleteEmptyDirectories();
Console.WriteLine("Song successfully deleted");
}
@@ -123,7 +123,7 @@ public class SongManager : BaseManager
public bool DoesSongExist(Song song)
{
if (!_songContext.DoesRecordExist(song))
if (!_songContext!.DoesRecordExist(song))
{
return false;
}
@@ -142,7 +142,7 @@ public class SongManager : BaseManager
}
_logger.Info("Song deleted from the filesystem");
var coverMgr = new CoverArtManager(_config);
var coverMgr = new CoverArtManager(_config!);
var coverArt = coverMgr.GetCoverArt(song);
coverMgr.DeleteCoverArt(coverArt);
@@ -166,11 +166,11 @@ public class SongManager : BaseManager
var song = await SaveSongTemp(songFile);
DirectoryManager dirMgr = new DirectoryManager(_config, song);
DirectoryManager dirMgr = new DirectoryManager(_config!, song);
dirMgr.CreateDirectory();
var tempPath = song.SongPath();
song.Filename = song.GenerateFilename(1);
song.Filename = song.GenerateFilename(true, AudioFileExtensionsType.WAV);
var filePath = $"{dirMgr.SongDirectory}{song.Filename}";
_logger.Info($"Absolute song path: {filePath}");
@@ -178,27 +178,15 @@ public class SongManager : BaseManager
await Task.Run(() =>
{
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
var songBytes = System.IO.File.ReadAllBytes(tempPath);
_logger.Info("Saving song to the filesystem");
fileStream.Write(songBytes, 0, songBytes.Count());
System.IO.File.Delete(tempPath);
_logger.Info("Deleting temp file");
_logger.Info("Song successfully saved to filesystem");
}
this.MoveSongToFinalDestination(tempPath, filePath);
});
song.SongDirectory = dirMgr.SongDirectory;
var coverMgr = new CoverArtManager(_config);
var coverMgr = new CoverArtManager(_config!);
var coverArt = coverMgr.SaveCoverArt(song);
coverMgr.SaveCoverArtToDatabase(ref song, ref coverArt);
SaveSongToDatabase(song);
SaveSongToDatabase(song, coverArt);
}
catch (Exception ex)
{
@@ -207,14 +195,28 @@ public class SongManager : BaseManager
}
}
public void SaveSongToFileSystem(IFormFile songFile, IFormFile coverArtData, Song song)
// Change the name of this method to only focus on wav files
public Song SaveSongToFileSystem(IFormFile songFile, IFormFile coverArtData, Song song)
{
if (string.IsNullOrEmpty(song.SongDirectory))
{
song.SongDirectory = _tempDirectoryRoot;
song.DateCreated = DateTime.Now;
}
if (string.IsNullOrEmpty(song.Filename))
{
song.Filename = song.GenerateFilename(1);
switch (song.AudioType)
{
case "wav":
song.Filename = song.GenerateFilename(true, AudioFileExtensionsType.WAV);
break;
case "flac":
song.Filename = song.GenerateFilename(true, AudioFileExtensionsType.FLAC);
break;
default:
song.Filename = song.GenerateFilename(true, AudioFileExtensionsType.Default);
break;
}
}
_logger.Info($"Temporary directory: {_tempDirectoryRoot}");
@@ -223,16 +225,19 @@ public class SongManager : BaseManager
_logger.Info("Temporary song path: {0}", tempPath);
if (!System.IO.File.Exists(tempPath))
{
using (var filestream = new FileStream(tempPath, FileMode.Create))
{
_logger.Info("Saving song to temporary directory");
songFile.CopyTo(filestream);
}
}
var coverMgr = new CoverArtManager(_config);
var coverMgr = new CoverArtManager(_config!);
var coverArt = coverMgr.SaveCoverArt(coverArtData, song);
DirectoryManager dirMgr = new DirectoryManager(_config, song);
DirectoryManager dirMgr = new DirectoryManager(_config!, song);
dirMgr.CreateDirectory();
song.SongDirectory = dirMgr.SongDirectory;
@@ -240,24 +245,66 @@ public class SongManager : BaseManager
var filePath = song.SongPath();
_logger.Info($"Absolute song path: {filePath}");
using (var fileStream = new FileStream(filePath, FileMode.Create))
this.MoveSongToFinalDestination(tempPath, filePath);
SaveSongToDatabase(song, coverArt);
return song;
}
public Song SaveFlacSongToFileSystem(IFormFile songFile, IFormFile coverArtData, Song song)
{
var songBytes = System.IO.File.ReadAllBytes(tempPath);
// Save temp song (Should already be saved to the filesystem by the time it gets to this method)
// Save cover art
// Update the song's metadata with the song object
// Save song to its final directory
// Save cover art to the database
// Save song to the database
var coverMgr = new CoverArtManager(_config!);
var coverArt = coverMgr.SaveCoverArt(coverArtData, song);
var meta = new Utilities.MetadataRetriever();
meta.UpdateMetadata(song, song);
DirectoryManager dirMgr = new DirectoryManager(_config!, song);
dirMgr.CreateDirectory();
var tempPath = song.SongPath();
song.SongDirectory = dirMgr.SongDirectory;
song.Filename = song.GenerateFilename(true, AudioFileExtensionsType.FLAC);
var filePath = song.SongPath();
_logger.Info($"Absolute song path: {filePath}");
this.MoveSongToFinalDestination(tempPath, filePath);
SaveSongToDatabase(song, coverArt);
return song;
}
private void MoveSongToFinalDestination(string sourcePath, string targetPath)
{
using (var fileStream = new FileStream(targetPath, FileMode.Create))
{
var songBytes = System.IO.File.ReadAllBytes(sourcePath);
try
{
if (System.IO.File.Exists(filePath) && System.IO.File.Exists(tempPath) && fileStream.Length > 0)
if (System.IO.File.Exists(sourcePath) && System.IO.File.Exists(sourcePath) && fileStream.Length > 0)
{
System.IO.File.Delete(tempPath);
_logger.Info("Deleted temp song from filesystem: {0}", tempPath);
System.IO.File.Delete(sourcePath);
_logger.Info("Deleted temp song from filesystem: {0}", sourcePath);
}
else
{
fileStream.Write(songBytes, 0, songBytes.Count());
_logger.Info("Saved song to filesystem: {0}", filePath);
_logger.Info("Saved song to filesystem: {0}", targetPath);
System.IO.File.Delete(tempPath);
_logger.Info("Deleted temp song from filesystem: {0}", tempPath);
System.IO.File.Delete(sourcePath);
_logger.Info("Deleted temp song from filesystem: {0}", sourcePath);
}
}
catch (Exception ex)
@@ -268,13 +315,8 @@ public class SongManager : BaseManager
_logger.Info("Song successfully saved to filesystem");
}
coverMgr.SaveCoverArtToDatabase(ref song, ref coverArt);
SaveSongToDatabase(song);
}
public async Task<SongData> RetrieveSong(Song songMetaData)
{
var song = new SongData();
@@ -304,28 +346,21 @@ public class SongManager : BaseManager
Data = uncompressedSong
};
}
private async Task<Song> SaveSongTemp(IFormFile songFile)
public async Task<Song> SaveSongTemp(IFormFile songFile)
{
var song = new Song();
_logger.Info("Assigning song filename");
song.SongDirectory = _tempDirectoryRoot;
var filename = song.GenerateFilename(1);
var song = new Song { SongDirectory = this._tempDirectoryRoot! };
var filename = await song.GenerateFilenameAsync(false) + "-" + songFile.FileName;
song.Filename = filename;
var songPath = song.SongPath();
using (var filestream = new FileStream(song.SongPath(), FileMode.Create))
using (var filestream = new FileStream(songPath, FileMode.Create))
{
_logger.Info("Saving temp song: {0}", song.SongPath());
_logger.Info("Saving temp song: {0}", songPath);
await songFile.CopyToAsync(filestream);
}
await Task.Run(() =>
{
MetadataRetriever meta = new MetadataRetriever();
song = meta.RetrieveMetaData(song.SongPath());
});
song.SongDirectory = _tempDirectoryRoot;
song.DateCreated = DateTime.Now;
song.Filename = filename;
return song;
}
@@ -339,9 +374,9 @@ public class SongManager : BaseManager
var currentGenre = currentSong.Genre;
var currentYear = currentSong.Year;
if (!currentTitle.Equals(songUpdates.Title) || !currentArtist.Equals(songUpdates.Artist) ||
!currentAlbum.Equals(songUpdates.AlbumTitle) ||
!currentGenre.Equals(songUpdates.Genre) || currentYear != songUpdates.Year)
if (!currentTitle!.Equals(songUpdates.Title) || !currentArtist!.Equals(songUpdates.Artist) ||
!currentAlbum!.Equals(songUpdates.AlbumTitle) ||
!currentGenre!.Equals(songUpdates.Genre) || currentYear != songUpdates.Year)
return true;
return false;
@@ -349,7 +384,7 @@ public class SongManager : BaseManager
private void DeleteEmptyDirectories(ref Song oldSong, ref Song updatedSong)
{
DirectoryManager mgr = new DirectoryManager(_config);
DirectoryManager mgr = new DirectoryManager(_config!);
_logger.Info("Checking to see if there are any directories to delete");
mgr.DeleteEmptyDirectories(oldSong);
@@ -359,8 +394,8 @@ public class SongManager : BaseManager
{
try
{
_connectionString = _config.GetConnectionString("DefaultConnection");
_songContext = new SongContext(_connectionString);
_connectionString = _config!.GetConnectionString("DefaultConnection");
_songContext = new SongContext(_connectionString!);
}
catch (Exception ex)
{
@@ -370,13 +405,14 @@ public class SongManager : BaseManager
private void SaveSongToDatabase(Song song)
private void SaveSongToDatabase(Song song, CoverArt? cover)
{
_logger.Info("Starting process to save the song to the database");
var albumMgr = new AlbumManager(_config);
var artistMgr = new ArtistManager(_config);
var genreMgr = new GenreManager(_config);
var albumMgr = new AlbumManager(_config!);
var artistMgr = new ArtistManager(_config!);
var genreMgr = new GenreManager(_config!);
var coverMgr = new CoverArtManager(_config!);
albumMgr.SaveAlbumToDatabase(ref song);
artistMgr.SaveArtistToDatabase(ref song);
genreMgr.SaveGenreToDatabase(ref song);
@@ -384,8 +420,10 @@ public class SongManager : BaseManager
var info = "Saving Song to DB";
_logger.Info(info);
_songContext.Add(song);
_songContext.SaveChanges();
_songContext!.Add(song);
_songContext!.SaveChanges();
coverMgr.SaveCoverArtToDatabase(ref song, ref cover!);
}
@@ -430,7 +468,7 @@ public class SongManager : BaseManager
{
var updatedSongRecord = oldSongRecord;
var songContext = new SongContext(_connectionString);
var songContext = new SongContext(_connectionString!);
if (!SongRecordChanged(oldSongRecord, newSongRecord))
{
@@ -470,18 +508,18 @@ public class SongManager : BaseManager
newSongRecord = updatedSongRecord;
result.Message = "Successfully updated song";
result.SongTitle = updatedSongRecord.Title;
result.SongTitle = updatedSongRecord.Title!;
}
private void DeleteSongFromDatabase(Song song)
{
_logger.Info("Starting process to delete records related to the song from the database");
var albumMgr = new AlbumManager(_config);
var artistMgr = new ArtistManager(_config);
var genreMgr = new GenreManager(_config);
var sngContext = new SongContext(_connectionString);
sngContext.Songs.Remove(song);
var albumMgr = new AlbumManager(_config!);
var artistMgr = new ArtistManager(_config!);
var genreMgr = new GenreManager(_config!);
var sngContext = new SongContext(_connectionString!);
sngContext.Songs!.Remove(song);
sngContext.SaveChanges();
artistMgr.DeleteArtistFromDatabase(song);
albumMgr.DeleteAlbumFromDatabase(song);
+23 -23
View File
@@ -15,16 +15,16 @@ namespace Icarus.Controllers.Managers;
public class TokenManager : BaseManager
{
#region Fields
private string _clientId;
private string _clientSecret;
private string _privateKeyPath = string.Empty;
private string _privateKey = string.Empty;
private string _publicKeyPath = string.Empty;
private string _publicKey = string.Empty;
private string _audience;
private string _grantType;
private string _url;
private string SUCCESSFUL_TOKEN_MESSAGE = "Successfully retrieved token";
private string? _clientId;
private string? _clientSecret;
private string? _privateKeyPath = string.Empty;
private string? _privateKey = string.Empty;
private string? _publicKeyPath = string.Empty;
private string? _publicKey = string.Empty;
private string? _audience;
private string? _grantType;
private string? _url;
private string? SUCCESSFUL_TOKEN_MESSAGE = "Successfully retrieved token";
#endregion
@@ -46,7 +46,7 @@ public class TokenManager : BaseManager
{
_logger.Info("Preparing Auth0 API request");
var client = new RestClient(_url);
var client = new RestClient(_url!);
var request = new RestRequest("oauth/token", Method.POST);
var tokenRequest = RetrieveTokenRequest();
@@ -68,7 +68,7 @@ public class TokenManager : BaseManager
.DeserializeObject<TokenTierOne>(response.Content);
_logger.Info("Response deserialized");
return this.InitializeLoginResult(user, tokenResult);
return this.InitializeLoginResult(user, tokenResult!);
}
@@ -80,7 +80,7 @@ public class TokenManager : BaseManager
payload.Add(new Claim("user_id", user.Id.ToString(), ClaimValueTypes.Integer));
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_config["JWT:Secret"]);
var key = Encoding.ASCII.GetBytes(_config!["JWT:Secret"]!);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
@@ -101,7 +101,7 @@ public class TokenManager : BaseManager
return cl.Type.Equals("exp");
});
var expiredDate = DateTime.Parse(expClaim.Value);
var expiredDate = DateTime.Parse(expClaim!.Value);
var exp = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds);
tokenResult.Expiration = Convert.ToInt32(exp);
@@ -197,7 +197,7 @@ public class TokenManager : BaseManager
var expiredDate = currentDate.AddMinutes(expLimit);
var issuer = "http://localhost:5002";
var audience = "http://localhost:5002";
var subject = _config["JWT:Subject"];
var subject = _config!["JWT:Subject"];
var claim = new List<System.Security.Claims.Claim>()
{
@@ -205,7 +205,7 @@ public class TokenManager : BaseManager
new Claim(JwtRegisteredClaimNames.Exp, expiredDate.ToString()),
new Claim(JwtRegisteredClaimNames.Aud, audience),
new Claim(JwtRegisteredClaimNames.Iss, issuer),
new Claim(JwtRegisteredClaimNames.Sub, subject),
new Claim(JwtRegisteredClaimNames.Sub, subject!),
new Claim(JwtRegisteredClaimNames.Iat, currentDate.ToString())
};
@@ -233,7 +233,7 @@ public class TokenManager : BaseManager
{
_logger.Info("Analyzing Auth0 information");
_clientId = _config["Auth0:ClientId"];
_clientId = _config!["Auth0:ClientId"];
_clientSecret = _config["Auth0:ClientSecret"];
_audience = _config["Auth0:ApiIdentifier"];
_grantType = "client_credentials";
@@ -258,23 +258,23 @@ public class TokenManager : BaseManager
private class TokenRequest
{
[JsonProperty("client_id")]
public string ClientId { get; set; }
public string? ClientId { get; set; }
[JsonProperty("client_secret")]
public string ClientSecret { get; set; }
public string? ClientSecret { get; set; }
[JsonProperty("audience")]
public string Audience { get; set; }
public string? Audience { get; set; }
[JsonProperty("grant_type")]
public string GrantType { get; set; }
public string? GrantType { get; set; }
}
private class TokenTierOne
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
public string? AccessToken { get; set; }
[JsonProperty("expires_in")]
public int Expiration { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
public string? TokenType { get; set; }
}
#endregion
}
+82 -93
View File
@@ -8,25 +8,27 @@ namespace Icarus.Controllers.Utilities;
public class MetadataRetriever
{
#region Fields
private static NLog.Logger _logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
private Song _updatedSong;
private string _message;
private string _title;
private string _artist;
private string _album;
private string _genre;
private static NLog.Logger? _logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
private List<string>? _supportedAudioFileTypes = new List<string> {"wav", "flac"};
private List<string>? _supportedImageFileTypes = new List<string> {"jpeg", "jpg", "png"};
private Song? _updatedSong;
private string? _message;
private string? _title;
private string? _artist;
private string? _album;
private string? _genre;
private int _year;
private int _duration;
#endregion
#region Properties
public Song UpdatedSongRecord
public Song? UpdatedSongRecord
{
get => _updatedSong;
set => _updatedSong = value;
}
public string Message
public string? Message
{
get => _message;
set => _message = value;
@@ -39,32 +41,6 @@ public class MetadataRetriever
#region Methods
public static void PrintMetadata(Song song)
{
Console.WriteLine("\n\nMetadata of the song:");
Console.WriteLine($"ID: {song.Id}");
Console.WriteLine($"Title: {song.Title}");
Console.WriteLine($"Artist: {song.Artist}");
Console.WriteLine($"Album: {song.AlbumTitle}");
Console.WriteLine($"Genre: {song.Genre}");
Console.WriteLine($"Year: {song.Year}");
Console.WriteLine($"Duration: {song.Duration}");
Console.WriteLine($"AlbumID: {song.AlbumId}");
Console.WriteLine($"ArtistID: {song.ArtistId}");
Console.WriteLine($"GenreID: {song.GenreId}");
Console.WriteLine($"Song Path: {song.SongPath()}");
Console.WriteLine($"Filename: {song.Filename}");
Console.WriteLine("\n");
_logger.Info("Metadata of the song");
_logger.Info($"Title: {song.Title}");
_logger.Info($"Artist: {song.Artist}");
_logger.Info($"Album: {song.AlbumTitle}");
_logger.Info($"Genre: {song.Genre}");
_logger.Info($"Year: {song.Year}");
_logger.Info($"Duration: {song.Duration}");
}
public string CoverArtFileExtensionType(CoverArt cover)
{
Console.WriteLine("Retrieving CoverArt file extension type");
@@ -106,6 +82,52 @@ public class MetadataRetriever
}
}
public string FileExtensionType(string path)
{
var extensionRaw = System.IO.Path.GetExtension(path);
if (extensionRaw[0] == '.')
{
return extensionRaw.Substring(1);
}
else
{
return extensionRaw;
}
}
public bool IsSupportedFile(IFormFile file)
{
var supportedTypes = this._supportedAudioFileTypes;
this._supportedImageFileTypes!.ForEach(t =>
{
if (!supportedTypes!.Contains(t))
{
supportedTypes.Add(t);
}
});
var extensionType = this.FileExtensionType(file).ToLower();
return supportedTypes!.Contains(extensionType);
}
public bool IsSupportedFile(string path)
{
var supportedTypes = this._supportedAudioFileTypes;
this._supportedImageFileTypes!.ForEach(t =>
{
if (!supportedTypes!.Contains(t))
{
supportedTypes.Add(t);
}
});
var extensionType = this.FileExtensionType(path).ToLower();
return supportedTypes!.Contains(extensionType);
}
public Song RetrieveMetaData(string filePath)
{
Song song = new Song();
@@ -140,7 +162,7 @@ public class MetadataRetriever
var msg = ex.Message;
Console.WriteLine("An error occurred in MetadataRetriever");
Console.WriteLine(msg);
_logger.Error(msg, "An error occurred in MetadataRetriever");
_logger!.Error(msg, "An error occurred in MetadataRetriever");
}
return song;
@@ -148,9 +170,8 @@ public class MetadataRetriever
public int RetrieveSongDuration(string filepath)
{
var duration = 0;
var fileTag = TagLib.File.Create(filepath);
duration = (int)fileTag.Properties.Duration.TotalSeconds;
var duration = (int)fileTag.Properties.Duration.TotalSeconds;
return duration;
}
@@ -161,17 +182,21 @@ public class MetadataRetriever
{
Console.WriteLine("Fetching image");
var tag = TagLib.File.Create(song.SongPath());
byte[] imgBytes = tag.Tag.Pictures[0].Data.Data;
return imgBytes;
if (tag.Tag.Pictures.Count() == 0)
{
return [];
}
return tag.Tag.Pictures[0].Data.Data;
}
catch (Exception ex)
{
var msg = ex.Message;
_logger.Error(msg, "An error occurred in MetadataRetriever");
_logger!.Error(msg, "An error occurred in MetadataRetriever");
}
return null;
return [];
}
@@ -188,7 +213,7 @@ public class MetadataRetriever
{
var msg = ex.Message;
Console.WriteLine($"An error occurred: {msg}");
_logger.Error(msg, "An error occurred");
_logger!.Error(msg, "An error occurred");
Message = "Failed to update metadata";
}
}
@@ -227,7 +252,7 @@ public class MetadataRetriever
try
{
Console.WriteLine($"Updating metadata of {title}");
_logger.Info($"Updating metadata of {title}");
_logger!.Info($"Updating metadata of {title}");
foreach (var key in checkedValues.Keys)
{
@@ -237,43 +262,43 @@ public class MetadataRetriever
switch (key.ToLower())
{
case "title":
_updatedSong.Title = title;
_updatedSong!.Title = title;
fileTag.Tag.Title = title;
break;
case "artists":
_updatedSong.Artist = artist;
_updatedSong!.Artist = artist;
fileTag.Tag.Performers = new []{artist};
break;
case "album":
_updatedSong.AlbumTitle = album;
_updatedSong!.AlbumTitle = album;
fileTag.Tag.Album = album;
break;
case "genre":
_updatedSong.Genre = genre;
_updatedSong!.Genre = genre;
fileTag.Tag.Genres = new []{genre};
break;
case "year":
_updatedSong.Year = year;
fileTag.Tag.Year = (uint)year;
_updatedSong!.Year = year;
fileTag.Tag.Year = (uint)year!;
break;
case "albumartist":
_updatedSong.AlbumArtist = albumArtist;
_updatedSong!.AlbumArtist = albumArtist;
fileTag.Tag.AlbumArtists = new []{albumArtist};
break;
case "track":
_updatedSong.Track = track;
_updatedSong!.Track = track;
fileTag.Tag.Track = (uint)(track);
break;
case "trackcount":
_updatedSong.TrackCount = trackCount;
_updatedSong!.TrackCount = trackCount;
fileTag.Tag.TrackCount = (uint)(trackCount);
break;
case "disc":
_updatedSong.Disc = disc;
_updatedSong!.Disc = disc;
fileTag.Tag.Disc = (uint)(disc);
break;
case "disccount":
_updatedSong.DiscCount = discCount;
_updatedSong!.DiscCount = discCount;
fileTag.Tag.DiscCount = (uint)(discCount);
break;
}
@@ -288,55 +313,19 @@ public class MetadataRetriever
{
var msg = ex.Message;
Console.WriteLine($"An error occurred:\n{msg}");
_logger.Error(msg, "An error occurred");
_logger!.Error(msg, "An error occurred");
}
}
private void InitializeUpdatedSong(Song song)
{
_updatedSong = song;
}
private void PrintMetadata()
{
Console.WriteLine("\n\nMetadata of the song:");
Console.WriteLine($"Title: {_title}");
Console.WriteLine($"Artist: {_artist}");
Console.WriteLine($"Album: {_album}");
Console.WriteLine($"Genre: {_genre}");
Console.WriteLine($"Year: {_year}");
Console.WriteLine($"Duration: {_duration}\n\n");
_logger.Info("Metadata of the song");
_logger.Info($"Title: {_title}");
_logger.Info($"Artist: {_artist}");
_logger.Info($"Album: {_album}");
_logger.Info($"Genre: {_genre}");
_logger.Info($"Year: {_year}");
_logger.Info($"Duration: {_duration}");
}
private void PrintMetadata(Song song, string message)
{
Console.WriteLine($"\n\n{message}");
Console.WriteLine($"Title: {song.Title}");
Console.WriteLine($"Artist: {song.Artist}");
Console.WriteLine($"Album: {song.AlbumTitle}");
Console.WriteLine($"Genre: {song.Genre}");
Console.WriteLine($"Year: {song.Year}");
Console.WriteLine($"Duration: {song.Duration}\n\n");
_logger.Info(message);
_logger.Info($"Title: {_title}");
_logger.Info($"Artist: {_artist}");
_logger.Info($"Album: {_album}");
_logger.Info($"Genre: {_genre}");
_logger.Info($"Year: {_year}");
_logger.Info($"Duration: {_duration}");
}
private SortedDictionary<string, bool> CheckSongValues(Song song)
{
var songValues = new SortedDictionary<string, bool>();
Console.WriteLine("Checking for null data");
_logger.Info("Checking for null data");
_logger!.Info("Checking for null data");
try
{
+1 -1
View File
@@ -60,7 +60,7 @@ public class PasswordEncryption
_logger.Error(exMsg, "An error occurred");
}
return null;
return string.Empty;
}
string GenerateHash(string password, byte[] salt)
+15 -12
View File
@@ -1,5 +1,3 @@
using Ionic.Zip;
using Icarus.Models;
namespace Icarus.Controllers.Utilities;
@@ -7,14 +5,14 @@ namespace Icarus.Controllers.Utilities;
public class SongCompression
{
#region Fields
string _compressedSongFilename;
string _tempDirectory;
byte[] _uncompressedSong;
string? _compressedSongFilename;
string? _tempDirectory;
byte[]? _uncompressedSong;
#endregion
#region Propterties
public string CompressedSongFilename
public string? CompressedSongFilename
{
get => _compressedSongFilename;
set => _compressedSongFilename = value;
@@ -63,10 +61,15 @@ public class SongCompression
try
{
using (ZipFile zip = new ZipFile())
using (var fi = new FileStream(songDetails.SongPath(), FileMode.Open))
{
zip.AddFile(songDetails.SongPath());
zip.Save(tmpZipFilePath);
using (var z = new Ionic.Zlib.ZlibStream(fi, Ionic.Zlib.CompressionMode.Compress))
{
using (var tr = new FileStream(tmpZipFilePath, FileMode.CreateNew))
{
z.CopyTo(tr);
}
}
}
Console.WriteLine("Successfully compressed");
@@ -78,7 +81,7 @@ public class SongCompression
Console.WriteLine(exMsg);
}
if (songDetails.Filename.Contains(Constants.FileExtensions.WAV_EXTENSION))
if (songDetails.Filename!.Contains(Constants.FileExtensions.WAV_EXTENSION))
{
_compressedSongFilename = StripExtension(songDetails.Filename);
}
@@ -89,7 +92,7 @@ public class SongCompression
// Method not being used
public byte[] CompressedSong(byte[] uncompressedSong)
{
byte[] compressedSong = null;
byte[]? compressedSong = null;
try
{
Console.WriteLine("Song has been successfully compressed");
@@ -101,7 +104,7 @@ public class SongCompression
Console.WriteLine(exMsg);
}
return compressedSong;
return compressedSong!;
}
+5 -5
View File
@@ -12,8 +12,8 @@ namespace Icarus.Controllers.V1;
public class AlbumController : BaseController
{
#region Fields
private readonly ILogger<AlbumController> _logger;
private string _connectionString;
private readonly ILogger<AlbumController>? _logger;
private string? _connectionString;
#endregion
@@ -35,9 +35,9 @@ public class AlbumController : BaseController
[HttpGet]
public IActionResult GetAlbums()
{
var albumContext = new AlbumContext(_connectionString);
var albumContext = new AlbumContext(_connectionString!);
var albums = albumContext.Albums.ToList();
var albums = albumContext.Albums!.ToList();
if (albums.Count > 0)
return Ok(albums);
@@ -50,7 +50,7 @@ public class AlbumController : BaseController
{
Album album = new Album{ Id = id };
var albumContext = new AlbumContext(_connectionString);
var albumContext = new AlbumContext(_connectionString!);
if (albumContext.DoesRecordExist(album))
{
+4 -4
View File
@@ -12,8 +12,8 @@ namespace Icarus.Controllers.V1;
public class ArtistController : BaseController
{
#region Fields
private readonly ILogger<ArtistController> _logger;
private string _connectionString;
private readonly ILogger<ArtistController>? _logger;
private string? _connectionString;
#endregion
@@ -35,7 +35,7 @@ public class ArtistController : BaseController
[HttpGet]
public IActionResult GetArtists()
{
var artistContext = new ArtistContext(_connectionString);
var artistContext = new ArtistContext(_connectionString!);
var artists = artistContext.Artists.ToList();
@@ -50,7 +50,7 @@ public class ArtistController : BaseController
{
Artist artist = new Artist { Id = id };
var artistContext = new ArtistContext(_connectionString);
var artistContext = new ArtistContext(_connectionString!);
if (artistContext.DoesRecordExist(artist))
{
+1 -1
View File
@@ -6,7 +6,7 @@ namespace Icarus.Controllers.V1;
public class BaseController : ControllerBase
{
#region Fiends
protected IConfiguration _config;
protected IConfiguration? _config;
#endregion
+12 -12
View File
@@ -13,8 +13,8 @@ namespace Icarus.Controllers.V1;
public class CoverArtController : BaseController
{
#region Fields
private readonly ILogger<CoverArtController> _logger;
private string _connectionString;
private readonly ILogger<CoverArtController>? _logger;
private string? _connectionString;
#endregion
@@ -32,18 +32,18 @@ public class CoverArtController : BaseController
[HttpGet]
public IActionResult GetCoverArts()
{
var coverArtContext = new CoverArtContext(_connectionString);
var coverArtContext = new CoverArtContext(_connectionString!);
var coverArtRecords = coverArtContext.CoverArtImages.ToList();
var coverArtRecords = coverArtContext.CoverArtImages!.ToList();
if (coverArtRecords == null)
{
_logger.LogInformation("No cover art records");
_logger!.LogInformation("No cover art records");
return NotFound();
}
else
{
_logger.LogInformation("Found cover art records");
_logger!.LogInformation("Found cover art records");
return Ok(coverArtRecords);
}
}
@@ -53,13 +53,13 @@ public class CoverArtController : BaseController
{
var coverArt = new CoverArt { Id = id };
var coverArtContext = new CoverArtContext(_connectionString);
var coverArtContext = new CoverArtContext(_connectionString!);
coverArt = coverArtContext.RetrieveRecord(coverArt);
if (coverArt != null)
{
_logger.LogInformation("Found cover art record");
_logger!.LogInformation("Found cover art record");
var coverArtBytes = System.IO.File.ReadAllBytes(
coverArt.ImagePath());
@@ -68,7 +68,7 @@ public class CoverArtController : BaseController
}
else
{
_logger.LogInformation("Cover art not found");
_logger!.LogInformation("Cover art not found");
return NotFound();
}
}
@@ -76,13 +76,13 @@ public class CoverArtController : BaseController
[HttpGet("data/download/{id}")]
public async Task<IActionResult> Download(int id, [FromQuery] bool? randomizeFilename)
{
var songContext = new SongContext(_connectionString);
var covMgr = new CoverArtManager(this._config);
var songContext = new SongContext(_connectionString!);
var covMgr = new CoverArtManager(this._config!);
var songMetaData = songContext.RetrieveRecord(new Song { Id = id});
var c = covMgr.GetCoverArt(songMetaData);
var filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.JPG_EXTENSION, songMetaData.Title, randomizeFilename);
var filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.JPG_EXTENSION, songMetaData.Title!, randomizeFilename);
var data = await c.GetData();
+5 -5
View File
@@ -12,8 +12,8 @@ namespace Icarus.Controllers.V1;
public class GenreController : BaseController
{
#region Fields
private readonly ILogger<GenreController> _logger;
private string _connectionString;
private readonly ILogger<GenreController>? _logger;
private string? _connectionString;
#endregion
@@ -35,9 +35,9 @@ public class GenreController : BaseController
[HttpGet]
public IActionResult GetGenres()
{
var genreStore = new GenreContext(_connectionString);
var genreStore = new GenreContext(_connectionString!);
var genres = genreStore.Genres.ToList();
var genres = genreStore!.Genres!.ToList();
if (genres.Count > 0)
{
@@ -54,7 +54,7 @@ public class GenreController : BaseController
{
var genre = new Genre { Id = id };
var genreStore = new GenreContext(_connectionString);
var genreStore = new GenreContext(_connectionString!);
if (genreStore.DoesRecordExist(genre))
{
+9 -9
View File
@@ -17,8 +17,8 @@ namespace Icarus.Controllers.V1;
public class LoginController : ControllerBase
{
#region Fields
private string _connectionString;
private IConfiguration _config;
private string? _connectionString;
private IConfiguration? _config;
private ILogger<LoginController> _logger;
#endregion
@@ -41,7 +41,7 @@ public class LoginController : ControllerBase
[HttpPost]
public IActionResult Login([FromBody] User user)
{
var context = new UserContext(_connectionString);
var context = new UserContext(_connectionString!);
_logger.LogInformation("Starting process of validating credentials");
@@ -55,12 +55,12 @@ public class LoginController : ControllerBase
try
{
if (context.Users.FirstOrDefault(usr => usr.Username.Equals(user.Username)) != null)
if (context.Users.FirstOrDefault(usr => usr.Username!.Equals(user.Username)) != null)
{
user = context.Users.FirstOrDefault(usr => usr.Username.Equals(user.Username));
user = context.Users.FirstOrDefault(usr => usr.Username!.Equals(user.Username))!;
var validatePass = new PasswordEncryption();
var validated = validatePass.VerifyPassword(user, password);
var validated = validatePass.VerifyPassword(user!, password!);
if (!validated)
{
loginRes.Message = message;
@@ -71,9 +71,9 @@ public class LoginController : ControllerBase
_logger.LogInformation("Successfully validated user credentials");
TokenManager tk = new TokenManager(_config);
TokenManager tk = new TokenManager(_config!);
loginRes = tk.LoginSymmetric(user);
loginRes = tk.LoginSymmetric(user!);
return Ok(loginRes);
}
@@ -87,7 +87,7 @@ public class LoginController : ControllerBase
catch (Exception ex)
{
_logger.LogError("An error occurred: {0}", ex.Message);
_logger.LogError("Inner Exception: {0}", ex.InnerException.Message);
_logger.LogError("Inner Exception: {0}", ex.InnerException!.Message);
}
return NotFound(loginRes);
+5 -4
View File
@@ -11,7 +11,7 @@ namespace Icarus.Controllers.V1;
public class RegisterController : ControllerBase
{
#region Fields
private IConfiguration _config;
private IConfiguration? _config;
#endregion
@@ -35,11 +35,12 @@ public class RegisterController : ControllerBase
user.Status = "Registered";
user.DateCreated = DateTime.Now;
UserContext context = null;
UserContext? context = null;
try
{
context = new UserContext(_config.GetConnectionString("DefaultConnection"));
var connString = _config!.GetConnectionString("DefaultConnection");
context = new UserContext(connString!);
context.Add(user);
context.SaveChanges();
}
@@ -56,7 +57,7 @@ public class RegisterController : ControllerBase
Username = user.Username
};
if (context.Users.FirstOrDefault(sng => sng.Username.Equals(user.Username)) != null)
if (context!.Users.FirstOrDefault(sng => sng.Username!.Equals(user.Username)) != null)
{
registerResult.Message = "Successful registration";
registerResult.SuccessfullyRegistered = true;
@@ -14,9 +14,9 @@ namespace Icarus.Controllers.V1;
public class SongCompressedDataController : BaseController
{
#region Fields
private string _connectionString;
private string _songTempDir;
private string _archiveDir;
private string? _connectionString;
private string? _songTempDir;
private string? _archiveDir;
#endregion
@@ -39,9 +39,9 @@ public class SongCompressedDataController : BaseController
[HttpGet("{id}")]
public async Task<IActionResult> DownloadCompressedSong(int id, [FromQuery] bool? randomizeFilename)
{
var context = new SongContext(_connectionString);
var context = new SongContext(_connectionString!);
SongCompression cmp = new SongCompression(_archiveDir);
SongCompression cmp = new SongCompression(_archiveDir!);
Console.WriteLine($"Archive directory root: {_archiveDir}");
@@ -49,9 +49,9 @@ public class SongCompressedDataController : BaseController
var sng = context.RetrieveRecord(new Song{ Id = id });
SongData song = await cmp.RetrieveCompressedSong(sng);
var filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.ZIP_EXTENSION, sng.Title, randomizeFilename);
var filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.ZIP_EXTENSION, sng.Title!, randomizeFilename);
return File(song.Data, "application/x-msdownload", filename);
return File(song.Data!, "application/x-msdownload", filename);
}
#endregion
}
+9 -9
View File
@@ -13,9 +13,9 @@ namespace Icarus.Controllers.V1;
public class SongController : BaseController
{
#region Fields
private readonly ILogger<SongController> _logger;
private string _connectionString;
private SongManager _songMgr;
private readonly ILogger<SongController>? _logger;
private string? _connectionString;
private SongManager? _songMgr;
#endregion
@@ -40,11 +40,11 @@ public class SongController : BaseController
public IActionResult GetSongs()
{
Console.WriteLine("Attemtping to retrieve songs");
_logger.LogInformation("Attempting to retrieve songs");
_logger!.LogInformation("Attempting to retrieve songs");
var context = new SongContext(_connectionString);
var context = new SongContext(_connectionString!);
var songs = context.Songs.ToList();
var songs = context.Songs!.ToList();
if (songs.Count > 0)
{
@@ -59,7 +59,7 @@ public class SongController : BaseController
[HttpGet("{id}")]
public IActionResult GetSong(int id)
{
var context = new SongContext(_connectionString);
var context = new SongContext(_connectionString!);
var song = context.RetrieveRecord(new Song{ Id = id });
@@ -76,9 +76,9 @@ public class SongController : BaseController
{
song.Id = id;
Console.WriteLine("Retrieving filepath of song");
_logger.LogInformation("Retrieving filepath of song");
_logger!.LogInformation("Retrieving filepath of song");
if (!_songMgr.DoesSongExist(song))
if (!_songMgr!.DoesSongExist(song))
{
return NotFound(new SongResult
{
+77 -32
View File
@@ -13,10 +13,10 @@ namespace Icarus.Controllers.V1;
public class SongDataController : BaseController
{
#region Fields
private string _connectionString;
private ILogger<SongDataController> _logger;
private SongManager _songMgr;
private string _songTempDir;
private string? _connectionString;
private ILogger<SongDataController>? _logger;
private SongManager? _songMgr;
private string? _songTempDir;
#endregion
@@ -31,7 +31,7 @@ public class SongDataController : BaseController
_connectionString = _config.GetConnectionString("DefaultConnection");
_logger = logger;
_songTempDir = _config.GetValue<string>("TemporaryMusicPath");
_songMgr = new SongManager(config, _songTempDir);
_songMgr = new SongManager(config, _songTempDir!);
}
#endregion
@@ -39,13 +39,29 @@ public class SongDataController : BaseController
[HttpGet("download/{id}")]
public IActionResult Download(int id, [FromQuery] bool? randomizeFilename)
{
var songContext = new SongContext(_connectionString);
var songContext = new SongContext(_connectionString!);
var songMetaData = songContext.RetrieveRecord(new Song { Id = id});
var song = _songMgr.RetrieveSong(songMetaData).Result;
var filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.WAV_EXTENSION, songMetaData.Title, randomizeFilename);
var song = _songMgr!.RetrieveSong(songMetaData).Result;
string filename;
return File(song.Data, "application/x-msdownload", filename);
switch (songMetaData.AudioType)
{
case "wav":
filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.WAV_EXTENSION,
songMetaData.Title!, randomizeFilename);
break;
case "flac":
filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.FLAC_EXTENSION,
songMetaData.Title!, randomizeFilename);
break;
default:
filename = DirectoryManager.GenerateDownloadFilename(10, Constants.FileExtensions.DEFAULT_AUDIO_EXTENSION,
songMetaData.Title!, randomizeFilename);
break;
}
return File(song.Data!, "application/x-msdownload", filename);
}
// Assumes that the song already has metadata such as
@@ -65,20 +81,17 @@ public class SongDataController : BaseController
{
try
{
// Console.WriteLine("Uploading song...");
_logger.LogInformation("Uploading song...");
_logger!.LogInformation("Uploading song...");
var uploads = _songTempDir;
// Console.WriteLine($"Song Root Path {uploads}");
_logger.LogInformation($"Song root path {uploads}");
_logger!.LogInformation($"Song root path {uploads}");
foreach (var sng in songData)
if (sng.Length > 0)
{
// Console.WriteLine($"Song filename {sng.FileName}");
_logger.LogInformation($"Song filename {sng.FileName}");
_logger!.LogInformation($"Song filename {sng.FileName}");
_songMgr.SaveSongToFileSystem(sng).Wait();
_songMgr!.SaveSongToFileSystem(sng).Wait();
}
return Ok();
@@ -86,7 +99,7 @@ public class SongDataController : BaseController
catch (Exception ex)
{
var msg = ex.Message;
_logger.LogError(msg, "An error occurred");
_logger!.LogError(msg, "An error occurred");
}
return NotFound();
@@ -101,35 +114,67 @@ public class SongDataController : BaseController
{
try
{
if (up.SongData.Length > 0 && up.CoverArtData.Length > 0 && !string.IsNullOrEmpty(up.SongFile))
if (up.SongData!.Length > 0 && up.CoverArtData!.Length > 0 && !string.IsNullOrEmpty(up.SongFile))
{
var meta = new Utilities.MetadataRetriever();
var tmpSong = this._songMgr!.SaveSongTemp(up.SongData).Result;
if (!meta.IsSupportedFile(tmpSong.SongPath()) && !meta.IsSupportedFile(up.CoverArtData))
{
return BadRequest("Media is not supported");
}
else if (!meta.IsSupportedFile(tmpSong.SongPath()))
{
return BadRequest("Song is not supported");
}
else if (!meta.IsSupportedFile(up.CoverArtData))
{
return BadRequest("Cover art is not supported");
}
var song = Newtonsoft.Json.JsonConvert.DeserializeObject<Song>(up.SongFile);
var tokMgr = new TokenManager(this._config);
var tokMgr = new TokenManager(this._config!);
var accessToken = Request.Headers["Authorization"];
var userId = tokMgr.RetrieveUserIdFromToken(accessToken);
var userId = tokMgr.RetrieveUserIdFromToken(accessToken!);
if (userId != -1)
{
song.UserId = userId;
song!.UserId = userId;
}
_logger.LogInformation($"Song title: {song.Title}");
_logger!.LogInformation($"Song title: {song!.Title}");
_songMgr.SaveSongToFileSystem(up.SongData, up.CoverArtData, song);
song.Filename = tmpSong.Filename;
song.SongDirectory = tmpSong.SongDirectory;
song.DateCreated = tmpSong.DateCreated;
song.AudioType = meta.FileExtensionType(tmpSong.SongPath());
switch (song.AudioType)
{
case "wav":
song = _songMgr.SaveSongToFileSystem(up.SongData, up.CoverArtData, song);
break;
case "flac":
song = _songMgr.SaveFlacSongToFileSystem(up.SongData, up.CoverArtData, song);
break;
default:
return BadRequest();
}
return Ok(song);
}
}
catch (Exception ex)
{
_logger.LogError(ex.Message, "An error occurred");
_logger!.LogError(ex.Message, "An error occurred");
}
return Ok();
return BadRequest();
}
[HttpDelete("delete/{id}")]
public IActionResult DeleteSong(int id)
{
var songContext = new SongContext(_connectionString);
var songContext = new SongContext(_connectionString!);
var songMetaData = new Song{ Id = id };
Console.WriteLine($"Id {songMetaData.Id}");
@@ -138,14 +183,14 @@ public class SongDataController : BaseController
if (string.IsNullOrEmpty(songMetaData.Title))
{
_logger.LogInformation("Song does not exist");
_logger!.LogInformation("Song does not exist");
return NotFound("Song does not exist");
}
else
{
_logger.LogInformation("Starting process of deleting song from the filesystem and database");
_logger!.LogInformation("Starting process of deleting song from the filesystem and database");
_songMgr.DeleteSong(songMetaData);
_songMgr!.DeleteSong(songMetaData);
return Ok(songMetaData);
}
@@ -155,11 +200,11 @@ public class SongDataController : BaseController
public class UploadSongWithDataForm
{
[FromForm(Name = "file")]
public IFormFile SongData { get; set; }
public IFormFile? SongData { get; set; }
// NOTE: Think about making this optional and if it is not provided, use the stock cover art
[FromForm(Name = "cover")]
public IFormFile CoverArtData { get; set; }
public IFormFile? CoverArtData { get; set; }
[FromForm(Name = "metadata")]
public string SongFile { get; set; }
public string? SongFile { get; set; }
}
}
+5 -5
View File
@@ -11,7 +11,7 @@ namespace Icarus.Controllers.V1;
public class SongStreamController : BaseController
{
#region Fields
private ILogger<SongStreamController> _logger;
private ILogger<SongStreamController>? _logger;
#endregion
@@ -32,11 +32,11 @@ public class SongStreamController : BaseController
[HttpGet("{id}")]
public async Task<IActionResult> StreamSong(int id)
{
var context = new SongContext(_config.GetConnectionString("DefaultConnection"));
var context = new SongContext(_config!.GetConnectionString("DefaultConnection")!);
var song = context.Songs.FirstOrDefault(sng => sng.Id == id);
var song = context.Songs!.FirstOrDefault(sng => sng.Id == id);
var stream = new FileStream(song.SongPath(), FileMode.Open, FileAccess.Read);
var stream = new FileStream(song!.SongPath(), FileMode.Open, FileAccess.Read);
stream.Position = 0;
var filename = song.Filename;
@@ -45,7 +45,7 @@ public class SongStreamController : BaseController
filename = song.GenerateFilename();
}
_logger.LogInformation("Starting to stream song...>");
_logger!.LogInformation("Starting to stream song...>");
Console.WriteLine("Starting to streamsong...");
return await Task.Run(() => {
+4 -3
View File
@@ -6,7 +6,7 @@ namespace Icarus.Database.Contexts;
public class AlbumContext : DbContext
{
public DbSet<Album> Albums { get; set; }
public DbSet<Album>? Albums { get; set; }
public AlbumContext(DbContextOptions<AlbumContext> options) : base(options) { }
public AlbumContext(string connString) : base(new DbContextOptionsBuilder<AlbumContext>()
@@ -22,11 +22,12 @@ public class AlbumContext : DbContext
public Album RetrieveRecord(Album album)
{
return Albums.FirstOrDefault(alb => alb.Id == album.Id);
var albm = Albums!.FirstOrDefault(alb => alb.Id == album.Id);
return albm!;
}
public bool DoesRecordExist(Album album)
{
return Albums.FirstOrDefault(alb => alb.Id == album.Id) != null ? true : false;
return Albums!.FirstOrDefault(alb => alb.Id == album.Id) != null ? true : false;
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ public class ArtistContext : DbContext
public Artist RetrieveRecord(Artist artist)
{
return Artists.FirstOrDefault(arst => arst.Id == artist.Id);
return Artists.FirstOrDefault(arst => arst.Id == artist.Id)!;
}
+5 -3
View File
@@ -6,7 +6,9 @@ namespace Icarus.Database.Contexts;
public class CoverArtContext : DbContext
{
public DbSet<CoverArt> CoverArtImages { get; set; }
#region Properties
public DbSet<CoverArt>? CoverArtImages { get; set; }
#endregion
public CoverArtContext(DbContextOptions<CoverArtContext> options) : base(options) { }
public CoverArtContext(string connString) : base(new DbContextOptionsBuilder<CoverArtContext>()
@@ -22,11 +24,11 @@ public class CoverArtContext : DbContext
public CoverArt RetrieveRecord(CoverArt cover)
{
return CoverArtImages.FirstOrDefault(cov => cov.Id == cover.Id);
return CoverArtImages!.FirstOrDefault(cov => cov.Id == cover.Id)!;
}
public bool DoesRecordExist(CoverArt cover)
{
return CoverArtImages.FirstOrDefault(cov => cov.Id == cover.Id) != null ? true : false;
return CoverArtImages!.FirstOrDefault(cov => cov.Id == cover.Id) != null ? true : false;
}
}
+7 -3
View File
@@ -6,7 +6,10 @@ namespace Icarus.Database.Contexts;
public class GenreContext : DbContext
{
public DbSet<Genre> Genres { get; set; }
#region Properties
public DbSet<Genre>? Genres { get; set; }
#endregion
public GenreContext(DbContextOptions<GenreContext> options) : base(options) { }
public GenreContext(string connString) : base(new DbContextOptionsBuilder<GenreContext>()
.UseMySQL(connString).Options)
@@ -22,11 +25,12 @@ public class GenreContext : DbContext
public Genre RetrieveRecord(Genre genre)
{
return Genres.FirstOrDefault(gnr => gnr.Id == genre.Id);
var gnre = Genres!.FirstOrDefault(gnr => gnr.Id == genre.Id);
return gnre!;
}
public bool DoesRecordExist(Genre genre)
{
return Genres.FirstOrDefault(gnr => gnr.Id == genre.Id) != null ? true : false;
return Genres!.FirstOrDefault(gnr => gnr.Id == genre.Id) != null ? true : false;
}
}
+4 -3
View File
@@ -6,7 +6,7 @@ namespace Icarus.Database.Contexts;
public class SongContext : DbContext
{
public DbSet<Song> Songs { get; set; }
public DbSet<Song>? Songs { get; set; }
public SongContext(string connString) : base(new DbContextOptionsBuilder<SongContext>()
.UseMySQL(connString).Options)
@@ -41,12 +41,13 @@ public class SongContext : DbContext
public Song RetrieveRecord(Song song)
{
return Songs.FirstOrDefault(sng => sng.Id == song.Id);
var sng = Songs!.FirstOrDefault(sng => sng.Id == song.Id);
return sng!;
}
public bool DoesRecordExist(Song song)
{
return Songs.FirstOrDefault(sng => sng.Id == song.Id) != null ? true : false;
return Songs!.FirstOrDefault(sng => sng.Id == song.Id) != null ? true : false;
}
}
+1 -1
View File
@@ -32,7 +32,7 @@ public class UserContext : DbContext
public User RetrieveRecord(User user)
{
return Users.FirstOrDefault(usr => usr.Id == user.Id);
return Users.FirstOrDefault(usr => usr.Id == user.Id)!;
}
public bool DoesRecordExist(User user)
+2 -2
View File
@@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<Version>0.1.10</Version>
</PropertyGroup>
@@ -10,10 +11,9 @@
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
<PackageReference Include="DotNetZip" Version="1.15.0" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="File.TypeChecker" Version="4.1.1" />
<PackageReference Include="ID3" Version="0.6.0" />
<PackageReference Include="Iconic.Zlib.Netstandard" Version="1.0.0" />
<PackageReference Include="JWT" Version="10.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
+4 -2
View File
@@ -6,16 +6,18 @@ namespace Icarus.Models;
public class Album
{
#region Properties
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
public string? Title { get; set; }
[JsonProperty("album_artist")]
[Column("Artist")]
public string AlbumArtist { get; set; }
public string? AlbumArtist { get; set; }
[JsonProperty("song_count")]
[NotMapped]
public int SongCount { get; set; }
[JsonProperty("year")]
public int Year { get; set; }
#endregion
}
+3 -1
View File
@@ -6,12 +6,14 @@ namespace Icarus.Models;
public class Artist
{
#region Properties
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
[Column("Artist")]
public string Name { get; set; }
public string? Name { get; set; }
[JsonProperty("song_count")]
[NotMapped]
public int SongCount { get; set; }
#endregion
}
+1 -1
View File
@@ -5,5 +5,5 @@ namespace Icarus.Models;
public class BaseResult
{
[JsonProperty("message")]
public string Message { get; set; }
public string? Message { get; set; }
}
+5 -5
View File
@@ -8,13 +8,13 @@ public class CoverArt
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("title")]
public string SongTitle { get; set; }
public string? SongTitle { get; set; }
[JsonIgnore]
public string Directory { get; set; }
public string? Directory { get; set; }
[JsonProperty("filename")]
public string Filename { get; set; }
public string? Filename { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
public string? Type { get; set; }
#endregion
@@ -23,7 +23,7 @@ public class CoverArt
{
var fullPath = this.Directory;
if (fullPath[fullPath.Length -1] != '/')
if (fullPath![fullPath.Length -1] != '/')
{
fullPath += "/";
}
+3 -1
View File
@@ -6,12 +6,14 @@ namespace Icarus.Models;
public class Genre
{
#region Properties
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("genre")]
[Column("Category")]
public string GenreName { get; set; }
public string? GenreName { get; set; }
[JsonProperty("song_count")]
[NotMapped]
public int SongCount { get; set; }
#endregion
}
+5 -3
View File
@@ -4,14 +4,16 @@ namespace Icarus.Models;
public class LoginResult : BaseResult
{
#region Properties
[JsonProperty("user_id")]
public int UserId { get; set; }
[JsonProperty("username")]
public string Username { get; set; }
public string? Username { get; set; }
[JsonProperty("token")]
public string Token { get; set; }
public string? Token { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
public string? TokenType { get; set; }
[JsonProperty("expiration")]
public int Expiration { get; set; }
#endregion
}
+3 -1
View File
@@ -4,8 +4,10 @@ namespace Icarus.Models;
public class RegisterResult : BaseResult
{
#region Properties
[JsonProperty("username")]
public string Username { get; set; }
public string? Username { get; set; }
[JsonProperty("successfully_registered")]
public bool SuccessfullyRegistered { get; set; }
#endregion
}
+56 -14
View File
@@ -10,24 +10,26 @@ public class Song
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
public string? Title { get; set; }
[JsonProperty("album")]
[Column("Album")]
public string AlbumTitle { get; set; }
public string? AlbumTitle { get; set; }
[JsonProperty("artist")]
public string Artist { get; set; }
public string? Artist { get; set; }
[JsonProperty("album_artist")]
public string AlbumArtist { get; set; }
public string? AlbumArtist { get; set; }
[JsonProperty("year")]
public int? Year { get; set; }
[JsonProperty("genre")]
public string Genre { get; set; }
public string? Genre { get; set; }
[JsonProperty("duration")]
public int Duration { get; set; }
[JsonProperty("filename")]
public string Filename { get; set; }
public string? Filename { get; set; }
[JsonIgnore]
public string SongDirectory { get; set; }
public string? SongDirectory { get; set; }
[JsonProperty("audio_type")]
public string? AudioType { get; set; }
[JsonProperty("track")]
public int Track { get; set; } = 0;
[JsonProperty("track_count")]
@@ -56,11 +58,29 @@ public class Song
#region Methods
public void PrintMetadata()
{
Console.WriteLine("\n\nMetadata of the song:");
Console.WriteLine($"ID: {this.Id}");
Console.WriteLine($"Title: {this.Title}");
Console.WriteLine($"Artist: {this.Artist}");
Console.WriteLine($"Album: {this.AlbumTitle}");
Console.WriteLine($"Genre: {this.Genre}");
Console.WriteLine($"Year: {this.Year}");
Console.WriteLine($"Duration: {this.Duration}");
Console.WriteLine($"AlbumID: {this.AlbumId}");
Console.WriteLine($"ArtistID: {this.ArtistId}");
Console.WriteLine($"GenreID: {this.GenreId}");
Console.WriteLine($"Song Path: {this.SongPath()}");
Console.WriteLine($"Filename: {this.Filename}");
Console.WriteLine("\n");
}
public string SongPath()
{
var fullPath = SongDirectory;
if (fullPath[fullPath.Length -1] != '/')
if (fullPath![fullPath.Length -1] != '/')
{
fullPath += "/";
}
@@ -70,26 +90,41 @@ public class Song
return fullPath;
}
public string GenerateFilename(int flag = 0)
public string GenerateFilename(bool includeExtension = false, AudioFileExtensionsType flag = AudioFileExtensionsType.Default)
{
int length = Constants.DirectoryPaths.FILENAME_LENGTH;
string chars = Constants.DirectoryPaths.FILENAME_CHARACTERS;
var filename = this.Generate(length, chars);
var extension = Icarus.Constants.FileExtensions.WAV_EXTENSION;
var extension = this.DetermineFileExtension(flag);
return flag == 0 ? filename : $"{filename}{extension}";
return includeExtension ? $"{filename}{extension}" : filename;
}
public async Task<string> GenerateFilenameAsync(int flag = 0)
public async Task<string> GenerateFilenameAsync(bool includeExtension = false, AudioFileExtensionsType flag = AudioFileExtensionsType.Default)
{
int length = Constants.DirectoryPaths.FILENAME_LENGTH;
string chars = Constants.DirectoryPaths.FILENAME_CHARACTERS;
var extension = Icarus.Constants.FileExtensions.WAV_EXTENSION;
var extension = this.DetermineFileExtension(flag);
var filename = await Task.Run(() =>
{
return this.Generate(length, chars);
});
return flag == 0 ? filename : $"{filename}{extension}";
return includeExtension ? $"{filename}{extension}" : filename;
}
private string DetermineFileExtension(AudioFileExtensionsType flag)
{
switch (flag)
{
case AudioFileExtensionsType.Default:
return Constants.FileExtensions.DEFAULT_AUDIO_EXTENSION;
case AudioFileExtensionsType.WAV:
return Constants.FileExtensions.WAV_EXTENSION;
case AudioFileExtensionsType.FLAC:
return Constants.FileExtensions.FLAC_EXTENSION;
default:
return "";
}
}
private string Generate(int length, string chars)
@@ -101,3 +136,10 @@ public class Song
}
#endregion
}
public enum AudioFileExtensionsType
{
Default = 0,
WAV = 1,
FLAC = 2
}
+3 -1
View File
@@ -2,7 +2,9 @@ namespace Icarus.Models;
public class SongData
{
#region Properties
public int ID { get; set; }
public byte[] Data { get; set; }
public byte[]? Data { get; set; }
public int SongID { get; set; }
#endregion
}
+4 -2
View File
@@ -4,8 +4,10 @@ namespace Icarus.Models;
public class SongResult
{
#region Properties
[JsonProperty("message")]
public string Message { get; set; }
public string? Message { get; set; }
[JsonProperty("song_title")]
public string SongTitle { get; set; }
public string? SongTitle { get; set; }
#endregion
}
+6 -14
View File
@@ -1,6 +1,3 @@
using System;
using System.Linq;
using Newtonsoft.Json;
@@ -10,13 +7,13 @@ public class Token
{
#region Properties
[JsonProperty("scope")]
public string Scope { get; set; }
public string? Scope { get; set; }
[JsonProperty("exp")]
public int Expiration { get; set; }
[JsonProperty("aud")]
public string Audience { get; set; }
public string? Audience { get; set; }
[JsonProperty("iss")]
public string Issuer { get; set; }
public string? Issuer { get; set; }
[JsonProperty("iat")]
public int Issued { get; set; }
#endregion
@@ -24,29 +21,24 @@ public class Token
#region Methods
public bool TokenExpired()
{
var result = false;
var currentDate = DateTime.Now;
var currentDateInSeconds = Math.Floor((currentDate - DateTime.UnixEpoch).TotalSeconds);
result = (currentDateInSeconds >= Expiration) ? true : false;
var result = (currentDateInSeconds >= Expiration) ? true : false;
return result;
}
public bool ContainsScope(string desiredScope)
{
var result = false;
result = Scope.Contains(desiredScope);
var result = Scope!.Contains(desiredScope);
return result;
}
public bool Erroneous()
{
var result = true;
Func<string, bool> isEmpty = a => string.IsNullOrEmpty(a);
result = (!isEmpty(Scope) && !isEmpty(Audience) && !isEmpty(Issuer) &&
var result = (!isEmpty(Scope!) && !isEmpty(Audience!) && !isEmpty(Issuer!) &&
Expiration > 0 && Issued > 0) ? false : true;
return result;
+10 -10
View File
@@ -14,39 +14,39 @@ public class User
[Key]
public int Id { get; set; }
[JsonProperty("username")]
public string Username { get; set; }
public string? Username { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
public string? Password { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
public string? Email { get; set; }
[JsonProperty("phone")]
[Column("Phone")]
public string Phone { get; set; }
public string? Phone { get; set; }
[JsonProperty("firstname")]
public string Firstname { get; set; }
public string? Firstname { get; set; }
[JsonProperty("lastname")]
public string Lastname { get; set; }
public string? Lastname { get; set; }
[JsonProperty("email_verified")]
[NotMapped]
public bool EmailVerified { get; set; }
[JsonProperty("date_created")]
public DateTime DateCreated { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
public string? Status { get; set; }
[JsonProperty("last_login")]
public DateTime? LastLogin { get; set; }
[JsonIgnore]
[NotMapped]
public System.Collections.Generic.IEnumerable<string> Roles { get; set; }
public System.Collections.Generic.IEnumerable<string>? Roles { get; set; }
#endregion
#region Methods
public System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> Claims()
{
var claims = new System.Collections.Generic.List<System.Security.Claims.Claim> { new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name, Username) };
claims.AddRange(Roles.Select(role => new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, role)));
var claims = new System.Collections.Generic.List<System.Security.Claims.Claim> { new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name, Username!) };
claims.AddRange(Roles!.Select(role => new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, role)));
return claims;
}
+7 -7
View File
@@ -64,16 +64,16 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJw
ValidateLifetime = true,
ValidAudience = Configuration["JWT:Audience"],
ValidIssuer = Configuration["JWT:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]))
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]!))
};
});
builder.Services.AddDbContext<SongContext>(options => options.UseMySQL(connString));
builder.Services.AddDbContext<AlbumContext>(options => options.UseMySQL(connString));
builder.Services.AddDbContext<ArtistContext>(options => options.UseMySQL(connString));
builder.Services.AddDbContext<UserContext>(options => options.UseMySQL(connString));
builder.Services.AddDbContext<GenreContext>(options => options.UseMySQL(connString));
builder.Services.AddDbContext<CoverArtContext>(options => options.UseMySQL(connString));
builder.Services.AddDbContext<SongContext>(options => options.UseMySQL(connString!));
builder.Services.AddDbContext<AlbumContext>(options => options.UseMySQL(connString!));
builder.Services.AddDbContext<ArtistContext>(options => options.UseMySQL(connString!));
builder.Services.AddDbContext<UserContext>(options => options.UseMySQL(connString!));
builder.Services.AddDbContext<GenreContext>(options => options.UseMySQL(connString!));
builder.Services.AddDbContext<CoverArtContext>(options => options.UseMySQL(connString!));
builder.Services.AddControllers()
.AddNewtonsoftJson();
+3 -4
View File
@@ -16,8 +16,7 @@ One can interface with Icarus the music server either by:
* [MySql](https://www.nuget.org/packages/MySql.Data/)
* OpenSSL
* BCrypt.Net-Next
* DotNetZip
* ID3
* Iconic.Zlib.Netstandard
* JWT
* Microsoft.AspNetCore.Authentication.JwtBearer
* Microsoft.AspNetCore.Mvc.NewtonsoftJson
@@ -126,11 +125,11 @@ scripts/Migrations/Linux/AddUpdate.sh
```
Or you can manually add the migrations like so for each migration:
```shell
dotnet-ef migrations Add InitialCreate --context UserContext
dotnet dotnet-ef migrations Add InitialCreate --context UserContext
```
Then update the migrations to the database like so<sup>*</sup>:
```shell
dotnet-ef database update --context UserContext
dotnet dotnet-ef database update --context UserContext
```
All of the contexts can be found in Database/Contexts folder.
+13 -12
View File
@@ -1,28 +1,29 @@
echo "Adding migrations..."
echo "Adding User migration"
~/.dotnet/tools/dotnet-ef migrations add User --context UserContext
dotnet dotnet-ef migrations add User --context UserContext
echo "Adding Album migration"
~/.dotnet/tools/dotnet-ef migrations add Album --context AlbumContext
dotnet dotnet-ef migrations add Album --context AlbumContext
echo "Adding Artist migration"
~/.dotnet/tools/dotnet-ef migrations add Artist --context ArtistContext
dotnet dotnet-ef migrations add Artist --context ArtistContext
echo "Adding Genre migration"
~/.dotnet/tools/dotnet-ef migrations add Genre --context GenreContext
dotnet dotnet-ef migrations add Genre --context GenreContext
echo "Adding Cover art migration"
~/.dotnet/tools/dotnet-ef migrations add CoverArt --context CoverArtContext
dotnet dotnet-ef migrations add CoverArt --context CoverArtContext
echo "Adding Song migration"
~/.dotnet/tools/dotnet-ef migrations add Song --context SongContext
dotnet dotnet-ef migrations add Song --context SongContext
echo "Updating migrations.."
echo "Updating User migration"
~/.dotnet/tools/dotnet-ef database update --context UserContext
dotnet dotnet-ef database update --context UserContext
echo "Updating Album migration"
~/.dotnet/tools/dotnet-ef database update --context AlbumContext
dotnet dotnet-ef database update --context AlbumContext
echo "Updating Artist migration"
~/.dotnet/tools/dotnet-ef database update --context ArtistContext
dotnet dotnet-ef database update --context ArtistContext
echo "Updating Genre migration"
~/.dotnet/tools/dotnet-ef database update --context GenreContext
dotnet dotnet-ef database update --context GenreContext
echo "Updating Cover art migration"
~/.dotnet/tools/dotnet-ef database update --context CoverArtContext
dotnet dotnet-ef database update --context CoverArtContext
echo "Updating Song migration"
~/.dotnet/tools/dotnet-ef database update --context SongContext
dotnet dotnet-ef database update --context SongContext
@@ -0,0 +1,3 @@
drop database Icarus;
create database Icarus;
+137
View File
@@ -0,0 +1,137 @@
#!/usr/bin/zsh
#
# Working directory
# Output directory
# Folder name creation
# Sub-folder name creation
#
# Validation
# Check if WORK_DIR is an actual directory
# Check if OUTPUT_DIR exists
# Check if the Folder and Sub folder has been created
# Check if WORK_DIR contains .wav files
#
# Conversion
# Convert wav files to flac files
# Create folder and sub folder if it does not exist
# Move the converted flac files to the sub folder
#
# Final
# Check if OUTPUT_DIR has the folder structure. Delete if so
# Move the folder and sub folder to OUTPUT_DIR
if [[ $# -eq 0 ]]; then
my_text="No arguments provided. Provide four arguments:\n"
my_text+="script.zsh \"working_dir\" \"output_dir\" \"folder_name\" \"sub_folder_name\""
echo "$my_text"
exit
fi
if [[ ! -n "$2" ]]; then
echo "The \"output_dir\" has not been provided"
exit
fi
if [[ ! -n "$3" ]]; then
echo "The \"folder_name\" has not been provided"
exit
fi
if [[ ! -n "$4" ]]; then
echo "The \"sub_folder_name\" has not been provided"
exit
fi
WORK_DIR=$1
OUTPUT_DIR=$2
FOLDER=$3
SUB_FOLDER=$4
# Validation
if [[ ! -d $WORK_DIR ]]; then
echo "$WORK_DIR is not a directory"
exit
fi
if [[ ! -d $OUTPUT_DIR ]]; then
echo "$OUTPUT_DIR does not exist"
exit
fi
FOLDER_DIR="$OUTPUT_DIR/$FOLDER"
if [[ ! -d $FOLDER_DIR ]]; then
echo "$FOLDER_DIR directory does not exist. Creating directory"
mkdir $FOLDER_DIR
echo "Created $FOLDER_DIR directory"
fi
FOLDER_DIR="$FOLDER_DIR/$SUB_FOLDER"
if [[ ! -d $FOLDER_DIR ]]; then
echo "$FOLDER_DIR directory does not exist. Creating directory"
mkdir $FOLDER_DIR
echo "Created $FOLDER_DIR directory"
fi
# Find all files matching the pattern in the directory
matched_files=( "$WORK_DIR"/*.wav )
# Check if any files were found
if [[ ${#matched_files[@]} -gt 0 ]]; then
echo "Files matching the pattern exist in the directory:"
else
echo "No files matching the pattern were found."
exit
fi
echo "Working directory: $WORK_DIR"
echo "Output directory: $OUTPUT_DIR"
echo "Folder name: $FOLDER"
echo "Sub folder name: $SUB_FOLDER"
# Conversion
i=1
for file in "${matched_files[@]}"; do
file_output="track"
if [[ $i -lt 10 ]]; then
file_output="track0$i.flac"
else
file_output="track$i.flac"
fi
echo "$i file: $file"
output_file_path="$FOLDER_DIR/$file_output"
echo "Output file path: $output_file_path"
echo "Converting wav file to flac"
flac --best $file -o $output_file_path
ALBUM_FILE="$WORK_DIR/new-album.json"
TARGET_ALBUM_FILE="$FOLDER_DIR/album.json"
if [[ -f $ALBUM_FILE ]]; then
echo "Copying album file"
cp -a $ALBUM_FILE $TARGET_ALBUM_FILE
fi
matched_img_files=( "$WORK_DIR"/*.[j,J,p,P][p,P,n,N]* )
# Check if any files were found
if [[ ${#matched_img_files[@]} -gt 0 ]]; then
echo "Files matching the pattern exist in the directory:"
echo "Copying cover art file(s)"
for img_file in "${matched_img_files[@]}"; do
cp -a $img_file $FOLDER_DIR
done
fi
i=$((i + 1))
done