feat(music): add repositories and services (#136)

Add data access and business logic layers for Music support:
- ArtistRepository/ArtistService for artist management
- AlbumRepository/AlbumService for album management
- TrackRepository/TrackService for track management
- MusicFileRepository for audio file management

Co-authored-by: admin <admin@ardentleatherworks.com>
This commit is contained in:
Cody Kickertz 2025-12-22 15:09:57 -06:00 committed by GitHub
parent b1c98b5932
commit ee0595c792
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 547 additions and 0 deletions

View file

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Music
{
public interface IAlbumRepository : IBasicRepository<Album>
{
Album FindByForeignId(string foreignAlbumId);
List<Album> FindByArtistId(int artistId);
List<Album> AlbumsBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
Album FindByPath(string path);
Dictionary<int, string> AllAlbumPaths();
Dictionary<int, List<int>> AllAlbumTags();
bool AlbumPathExists(string path);
}
public class AlbumRepository : BasicRepository<Album>, IAlbumRepository
{
public AlbumRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
}
public Album FindByForeignId(string foreignAlbumId)
{
return Query(a => a.ForeignAlbumId == foreignAlbumId).FirstOrDefault();
}
public List<Album> FindByArtistId(int artistId)
{
return Query(a => a.ArtistId == artistId);
}
public List<Album> AlbumsBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
{
var query = Query(a => a.ReleaseDate >= start && a.ReleaseDate <= end);
if (!includeUnmonitored)
{
query = query.Where(a => a.Monitored).ToList();
}
return query;
}
public Album FindByPath(string path)
{
return Query(a => a.Path == path).FirstOrDefault();
}
public Dictionary<int, string> AllAlbumPaths()
{
var albums = All();
return albums.ToDictionary(a => a.Id, a => a.Path);
}
public Dictionary<int, List<int>> AllAlbumTags()
{
var albums = All();
return albums.ToDictionary(a => a.Id, a => a.Tags.ToList());
}
public bool AlbumPathExists(string path)
{
return Query(a => a.Path == path).Any();
}
}
}

View file

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Music
{
public interface IAlbumService
{
Album GetAlbum(int albumId);
List<Album> GetAlbums(IEnumerable<int> albumIds);
PagingSpec<Album> Paged(PagingSpec<Album> pagingSpec);
Album AddAlbum(Album newAlbum);
List<Album> AddAlbums(List<Album> newAlbums);
Album FindByForeignId(string foreignAlbumId);
Album FindByPath(string path);
List<Album> FindByArtistId(int artistId);
Dictionary<int, string> AllAlbumPaths();
List<Album> GetAlbumsBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
void DeleteAlbum(int albumId, bool deleteFiles);
void DeleteAlbums(List<int> albumIds, bool deleteFiles);
List<Album> GetAllAlbums();
Dictionary<int, List<int>> AllAlbumTags();
Album UpdateAlbum(Album album);
List<Album> UpdateAlbums(List<Album> albums);
bool AlbumPathExists(string folder);
}
public class AlbumService : IAlbumService
{
private readonly IAlbumRepository _albumRepository;
public AlbumService(IAlbumRepository albumRepository)
{
_albumRepository = albumRepository;
}
public Album GetAlbum(int albumId)
{
return _albumRepository.Get(albumId);
}
public List<Album> GetAlbums(IEnumerable<int> albumIds)
{
return _albumRepository.Get(albumIds).ToList();
}
public PagingSpec<Album> Paged(PagingSpec<Album> pagingSpec)
{
return _albumRepository.GetPaged(pagingSpec);
}
public Album AddAlbum(Album newAlbum)
{
newAlbum.Added = DateTime.UtcNow;
return _albumRepository.Insert(newAlbum);
}
public List<Album> AddAlbums(List<Album> newAlbums)
{
var now = DateTime.UtcNow;
foreach (var album in newAlbums)
{
album.Added = now;
}
_albumRepository.InsertMany(newAlbums);
return newAlbums;
}
public Album FindByForeignId(string foreignAlbumId)
{
return _albumRepository.FindByForeignId(foreignAlbumId);
}
public Album FindByPath(string path)
{
return _albumRepository.FindByPath(path);
}
public List<Album> FindByArtistId(int artistId)
{
return _albumRepository.FindByArtistId(artistId);
}
public Dictionary<int, string> AllAlbumPaths()
{
return _albumRepository.AllAlbumPaths();
}
public List<Album> GetAlbumsBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
{
return _albumRepository.AlbumsBetweenDates(start, end, includeUnmonitored);
}
public void DeleteAlbum(int albumId, bool deleteFiles)
{
_albumRepository.Delete(albumId);
}
public void DeleteAlbums(List<int> albumIds, bool deleteFiles)
{
_albumRepository.DeleteMany(albumIds);
}
public List<Album> GetAllAlbums()
{
return _albumRepository.All().ToList();
}
public Dictionary<int, List<int>> AllAlbumTags()
{
return _albumRepository.AllAlbumTags();
}
public Album UpdateAlbum(Album album)
{
return _albumRepository.Update(album);
}
public List<Album> UpdateAlbums(List<Album> albums)
{
_albumRepository.UpdateMany(albums);
return albums;
}
public bool AlbumPathExists(string folder)
{
return _albumRepository.AlbumPathExists(folder);
}
}
}

View file

@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Music
{
public interface IArtistRepository : IBasicRepository<Artist>
{
Artist FindByName(string name);
Artist FindByForeignId(string foreignArtistId);
List<Artist> GetMonitored();
bool ArtistPathExists(string path);
}
public class ArtistRepository : BasicRepository<Artist>, IArtistRepository
{
public ArtistRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
}
public Artist FindByName(string name)
{
return Query(a => a.Name == name).FirstOrDefault();
}
public Artist FindByForeignId(string foreignArtistId)
{
return Query(a => a.ForeignArtistId == foreignArtistId).FirstOrDefault();
}
public List<Artist> GetMonitored()
{
return Query(a => a.Monitored);
}
public bool ArtistPathExists(string path)
{
return Query(a => a.Path == path).Any();
}
}
}

View file

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace NzbDrone.Core.Music
{
public interface IArtistService
{
Artist GetArtist(int artistId);
List<Artist> GetArtists(IEnumerable<int> artistIds);
Artist AddArtist(Artist newArtist);
List<Artist> AddArtists(List<Artist> newArtists);
Artist FindByName(string name);
Artist FindByForeignId(string foreignArtistId);
void DeleteArtist(int artistId, bool deleteFiles);
void DeleteArtists(List<int> artistIds, bool deleteFiles);
List<Artist> GetAllArtists();
List<Artist> GetMonitoredArtists();
Artist UpdateArtist(Artist artist);
List<Artist> UpdateArtists(List<Artist> artists);
bool ArtistPathExists(string path);
}
public class ArtistService : IArtistService
{
private readonly IArtistRepository _artistRepository;
public ArtistService(IArtistRepository artistRepository)
{
_artistRepository = artistRepository;
}
public Artist GetArtist(int artistId)
{
return _artistRepository.Get(artistId);
}
public List<Artist> GetArtists(IEnumerable<int> artistIds)
{
return _artistRepository.Get(artistIds).ToList();
}
public Artist AddArtist(Artist newArtist)
{
newArtist.Added = DateTime.UtcNow;
return _artistRepository.Insert(newArtist);
}
public List<Artist> AddArtists(List<Artist> newArtists)
{
var now = DateTime.UtcNow;
foreach (var artist in newArtists)
{
artist.Added = now;
}
_artistRepository.InsertMany(newArtists);
return newArtists;
}
public Artist FindByName(string name)
{
return _artistRepository.FindByName(name);
}
public Artist FindByForeignId(string foreignArtistId)
{
return _artistRepository.FindByForeignId(foreignArtistId);
}
public void DeleteArtist(int artistId, bool deleteFiles)
{
_artistRepository.Delete(artistId);
}
public void DeleteArtists(List<int> artistIds, bool deleteFiles)
{
_artistRepository.DeleteMany(artistIds);
}
public List<Artist> GetAllArtists()
{
return _artistRepository.All().ToList();
}
public List<Artist> GetMonitoredArtists()
{
return _artistRepository.GetMonitored();
}
public Artist UpdateArtist(Artist artist)
{
return _artistRepository.Update(artist);
}
public List<Artist> UpdateArtists(List<Artist> artists)
{
_artistRepository.UpdateMany(artists);
return artists;
}
public bool ArtistPathExists(string path)
{
return _artistRepository.ArtistPathExists(path);
}
}
}

View file

@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Music
{
public interface IMusicFileRepository : IBasicRepository<MusicFile>
{
List<MusicFile> GetFilesByTrackId(int trackId);
List<MusicFile> GetFilesByAlbumId(int albumId);
MusicFile GetByRelativePath(string relativePath);
}
public class MusicFileRepository : BasicRepository<MusicFile>, IMusicFileRepository
{
public MusicFileRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
}
public List<MusicFile> GetFilesByTrackId(int trackId)
{
return Query(f => f.TrackId == trackId);
}
public List<MusicFile> GetFilesByAlbumId(int albumId)
{
return Query(f => f.AlbumId == albumId);
}
public MusicFile GetByRelativePath(string relativePath)
{
return Query(f => f.RelativePath == relativePath).FirstOrDefault();
}
}
}

View file

@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Music
{
public interface ITrackRepository : IBasicRepository<Track>
{
Track FindByForeignId(string foreignTrackId);
List<Track> FindByAlbumId(int albumId);
List<Track> GetMonitored();
bool TrackPathExists(string path);
}
public class TrackRepository : BasicRepository<Track>, ITrackRepository
{
public TrackRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
}
public Track FindByForeignId(string foreignTrackId)
{
return Query(t => t.ForeignTrackId == foreignTrackId).FirstOrDefault();
}
public List<Track> FindByAlbumId(int albumId)
{
return Query(t => t.AlbumId == albumId);
}
public List<Track> GetMonitored()
{
return Query(t => t.Monitored);
}
public bool TrackPathExists(string path)
{
return Query(t => t.Path == path).Any();
}
}
}

View file

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Music
{
public interface ITrackService
{
Track GetTrack(int trackId);
List<Track> GetTracks(IEnumerable<int> trackIds);
PagingSpec<Track> Paged(PagingSpec<Track> pagingSpec);
Track AddTrack(Track newTrack);
List<Track> AddTracks(List<Track> newTracks);
Track FindByForeignId(string foreignTrackId);
List<Track> FindByAlbumId(int albumId);
void DeleteTrack(int trackId, bool deleteFiles);
void DeleteTracks(List<int> trackIds, bool deleteFiles);
List<Track> GetAllTracks();
List<Track> GetMonitoredTracks();
Track UpdateTrack(Track track);
List<Track> UpdateTracks(List<Track> tracks);
bool TrackPathExists(string path);
}
public class TrackService : ITrackService
{
private readonly ITrackRepository _trackRepository;
public TrackService(ITrackRepository trackRepository)
{
_trackRepository = trackRepository;
}
public Track GetTrack(int trackId)
{
return _trackRepository.Get(trackId);
}
public List<Track> GetTracks(IEnumerable<int> trackIds)
{
return _trackRepository.Get(trackIds).ToList();
}
public PagingSpec<Track> Paged(PagingSpec<Track> pagingSpec)
{
return _trackRepository.GetPaged(pagingSpec);
}
public Track AddTrack(Track newTrack)
{
newTrack.Added = DateTime.UtcNow;
return _trackRepository.Insert(newTrack);
}
public List<Track> AddTracks(List<Track> newTracks)
{
var now = DateTime.UtcNow;
foreach (var track in newTracks)
{
track.Added = now;
}
_trackRepository.InsertMany(newTracks);
return newTracks;
}
public Track FindByForeignId(string foreignTrackId)
{
return _trackRepository.FindByForeignId(foreignTrackId);
}
public List<Track> FindByAlbumId(int albumId)
{
return _trackRepository.FindByAlbumId(albumId);
}
public void DeleteTrack(int trackId, bool deleteFiles)
{
_trackRepository.Delete(trackId);
}
public void DeleteTracks(List<int> trackIds, bool deleteFiles)
{
_trackRepository.DeleteMany(trackIds);
}
public List<Track> GetAllTracks()
{
return _trackRepository.All().ToList();
}
public List<Track> GetMonitoredTracks()
{
return _trackRepository.GetMonitored();
}
public Track UpdateTrack(Track track)
{
return _trackRepository.Update(track);
}
public List<Track> UpdateTracks(List<Track> tracks)
{
_trackRepository.UpdateMany(tracks);
return tracks;
}
public bool TrackPathExists(string path)
{
return _trackRepository.TrackPathExists(path);
}
}
}