refactor: extract BaseMediaService<T> base class (#137)

* refactor: extract BaseMediaService<T> base class

Extract common CRUD operations into BaseMediaService<T>:
- Get, GetAll, Paged, Add, AddMany, Delete, DeleteMany, Update, UpdateMany
- SetAddedTimestamp with reflection for non-MediaItem types
- Virtual event hooks (OnItemAdded, OnItemDeleted, etc.)

Migrate services to use base class:
- BookService: 180 → 89 lines
- AudiobookService: 192 → 93 lines
- AlbumService: 132 → 58 lines
- ArtistService: 107 → 50 lines
- TrackService: 114 → 50 lines

Net reduction: ~385 lines

* chore: cleanup stale files and fix branding

Remove IDE/editor config files that should not be tracked:
- .vscode/, frontend/.vscode/, src/.idea/
- azure-pipelines.yml (obsolete CI)
- Empty localization files (bs, ta, et, lt, sr, es_MX)

Remove unused npm packages:
- react-addons-shallow-compare
- react-async-script

Fix remaining Radarr→Aletheia branding:
- ConsoleApp.cs error messages
- openapi.json title/description/license
- FileNameBuilder.cs default release group

---------

Co-authored-by: admin <admin@ardentleatherworks.com>
This commit is contained in:
Cody Kickertz 2025-12-22 15:37:23 -06:00 committed by GitHub
parent ee0595c792
commit 330ed32f11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 261 additions and 1909 deletions

View file

@ -1,7 +0,0 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"ms-dotnettools.csdevkit",
"ms-vscode-remote.remote-containers"
]
}

26
.vscode/launch.json vendored
View file

@ -1,26 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
"name": "Run Radarr",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build dotnet",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/_output/net8.0/Radarr",
"args": [],
"cwd": "${workspaceFolder}",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "integratedTerminal",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}

44
.vscode/tasks.json vendored
View file

@ -1,44 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build dotnet",
"command": "dotnet",
"type": "process",
"args": [
"msbuild",
"-restore",
"${workspaceFolder}/src/Radarr.sln",
"-p:GenerateFullPaths=true",
"-p:Configuration=Debug",
"-p:Platform=Posix",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/src/Radarr.sln",
"-property:GenerateFullPaths=true",
"-consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/src/Radarr.sln"
],
"problemMatcher": "$msCompile"
}
]
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +0,0 @@
{
"recommendations": [
"stylelint.vscode-stylelint",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

View file

@ -1,23 +0,0 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.insertFinalNewline": true,
"files.exclude": {
"**/node_modules": true,
"**/*.d.css": true
},
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
},
"typescript.preferences.quoteStyle": "single",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
}

View file

@ -55,8 +55,6 @@
"prop-types": "15.8.1",
"qs": "6.13.0",
"react": "18.3.1",
"react-addons-shallow-compare": "15.6.3",
"react-async-script": "1.2.0",
"react-autosuggest": "10.1.0",
"react-custom-scrollbars-2": "4.5.0",
"react-dnd": "14.0.4",

View file

@ -1 +0,0 @@
NzbDrone

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ContentModelUserStore">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
</component>
</project>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$/ExternalModules/CurlSharp" vcs="Git" />
</component>
</project>

View file

@ -53,7 +53,7 @@ public static void Main(string[] args)
{
System.Console.WriteLine("");
System.Console.WriteLine("");
Logger.Fatal(ex.Message + " This can happen if another instance of Radarr is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
Logger.Fatal(ex.Message + " This can happen if another instance of Aletheia is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
Exit(ExitCodes.RecoverableFailure, startupArgs);
}
catch (IOException ex)
@ -62,7 +62,7 @@ public static void Main(string[] args)
{
System.Console.WriteLine("");
System.Console.WriteLine("");
Logger.Fatal(ex.Message + " This can happen if another instance of Radarr is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
Logger.Fatal(ex.Message + " This can happen if another instance of Aletheia is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
Exit(ExitCodes.RecoverableFailure, startupArgs);
}
else

View file

@ -1,17 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Audiobooks.Events;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaItems;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Audiobooks
{
public interface IAudiobookService
public interface IAudiobookService : IBaseMediaService<Audiobook>
{
Audiobook GetAudiobook(int audiobookId);
List<Audiobook> GetAudiobooks(IEnumerable<int> audiobookIds);
PagingSpec<Audiobook> Paged(PagingSpec<Audiobook> pagingSpec);
Audiobook AddAudiobook(Audiobook newAudiobook);
List<Audiobook> AddAudiobooks(List<Audiobook> newAudiobooks);
Audiobook FindByIsbn(string isbn);
@ -34,159 +33,61 @@ public interface IAudiobookService
bool AudiobookPathExists(string folder);
}
public class AudiobookService : IAudiobookService
public class AudiobookService : BaseMediaService<Audiobook>, IAudiobookService
{
private readonly IAudiobookRepository _audiobookRepository;
private readonly IEventAggregator _eventAggregator;
public AudiobookService(IAudiobookRepository audiobookRepository,
IEventAggregator eventAggregator)
public AudiobookService(IAudiobookRepository audiobookRepository, IEventAggregator eventAggregator)
{
_audiobookRepository = audiobookRepository;
_eventAggregator = eventAggregator;
}
public Audiobook GetAudiobook(int audiobookId)
{
return _audiobookRepository.Get(audiobookId);
}
protected override IBasicRepository<Audiobook> Repository => _audiobookRepository;
protected override IEventAggregator EventAggregator => _eventAggregator;
public List<Audiobook> GetAudiobooks(IEnumerable<int> audiobookIds)
{
return _audiobookRepository.Get(audiobookIds).ToList();
}
public PagingSpec<Audiobook> Paged(PagingSpec<Audiobook> pagingSpec)
{
return _audiobookRepository.GetPaged(pagingSpec);
}
public Audiobook AddAudiobook(Audiobook newAudiobook)
{
newAudiobook.Added = DateTime.UtcNow;
var audiobook = _audiobookRepository.Insert(newAudiobook);
_eventAggregator.PublishEvent(new AudiobookAddedEvent(GetAudiobook(audiobook.Id)));
return audiobook;
}
public List<Audiobook> AddAudiobooks(List<Audiobook> newAudiobooks)
{
var now = DateTime.UtcNow;
foreach (var audiobook in newAudiobooks)
{
audiobook.Added = now;
}
_audiobookRepository.InsertMany(newAudiobooks);
_eventAggregator.PublishEvent(new AudiobooksImportedEvent(newAudiobooks));
return newAudiobooks;
}
public Audiobook FindByIsbn(string isbn)
{
return _audiobookRepository.FindByIsbn(isbn);
}
public Audiobook FindByIsbn13(string isbn13)
{
return _audiobookRepository.FindByIsbn13(isbn13);
}
public Audiobook FindByAsin(string asin)
{
return _audiobookRepository.FindByAsin(asin);
}
public Audiobook FindByForeignId(string foreignAudiobookId)
{
return _audiobookRepository.FindByForeignId(foreignAudiobookId);
}
public Audiobook FindByPath(string path)
{
return _audiobookRepository.FindByPath(path);
}
public List<Audiobook> FindByAuthorId(int authorId)
{
return _audiobookRepository.FindByAuthorId(authorId);
}
public List<Audiobook> FindBySeriesId(int seriesId)
{
return _audiobookRepository.FindBySeriesId(seriesId);
}
public List<Audiobook> FindByBookId(int bookId)
{
return _audiobookRepository.FindByBookId(bookId);
}
public List<Audiobook> FindByNarrator(string narrator)
{
return _audiobookRepository.FindByNarrator(narrator);
}
public Dictionary<int, string> AllAudiobookPaths()
{
return _audiobookRepository.AllAudiobookPaths();
}
public Audiobook GetAudiobook(int audiobookId) => Get(audiobookId);
public List<Audiobook> GetAudiobooks(IEnumerable<int> audiobookIds) => Get(audiobookIds);
public Audiobook AddAudiobook(Audiobook newAudiobook) => Add(newAudiobook);
public List<Audiobook> AddAudiobooks(List<Audiobook> newAudiobooks) => AddMany(newAudiobooks);
public void DeleteAudiobook(int audiobookId, bool deleteFiles) => Delete(audiobookId, deleteFiles);
public void DeleteAudiobooks(List<int> audiobookIds, bool deleteFiles) => DeleteMany(audiobookIds, deleteFiles);
public List<Audiobook> GetAllAudiobooks() => GetAll();
public Audiobook UpdateAudiobook(Audiobook audiobook) => Update(audiobook);
public List<Audiobook> UpdateAudiobooks(List<Audiobook> audiobooks) => UpdateMany(audiobooks);
public Audiobook FindByIsbn(string isbn) => _audiobookRepository.FindByIsbn(isbn);
public Audiobook FindByIsbn13(string isbn13) => _audiobookRepository.FindByIsbn13(isbn13);
public Audiobook FindByAsin(string asin) => _audiobookRepository.FindByAsin(asin);
public Audiobook FindByForeignId(string foreignAudiobookId) => _audiobookRepository.FindByForeignId(foreignAudiobookId);
public Audiobook FindByPath(string path) => _audiobookRepository.FindByPath(path);
public List<Audiobook> FindByAuthorId(int authorId) => _audiobookRepository.FindByAuthorId(authorId);
public List<Audiobook> FindBySeriesId(int seriesId) => _audiobookRepository.FindBySeriesId(seriesId);
public List<Audiobook> FindByBookId(int bookId) => _audiobookRepository.FindByBookId(bookId);
public List<Audiobook> FindByNarrator(string narrator) => _audiobookRepository.FindByNarrator(narrator);
public Dictionary<int, string> AllAudiobookPaths() => _audiobookRepository.AllAudiobookPaths();
public List<Audiobook> GetAudiobooksBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
{
return _audiobookRepository.AudiobooksBetweenDates(start, end, includeUnmonitored);
}
=> _audiobookRepository.AudiobooksBetweenDates(start, end, includeUnmonitored);
public Dictionary<int, List<int>> AllAudiobookTags() => _audiobookRepository.AllAudiobookTags();
public bool AudiobookPathExists(string folder) => _audiobookRepository.AudiobookPathExists(folder);
public void DeleteAudiobook(int audiobookId, bool deleteFiles)
{
var audiobook = _audiobookRepository.Get(audiobookId);
_audiobookRepository.Delete(audiobookId);
_eventAggregator.PublishEvent(new AudiobookDeletedEvent(audiobook, deleteFiles));
}
protected override void OnItemAdded(Audiobook item)
=> _eventAggregator.PublishEvent(new AudiobookAddedEvent(item));
public void DeleteAudiobooks(List<int> audiobookIds, bool deleteFiles)
{
var audiobooks = _audiobookRepository.Get(audiobookIds).ToList();
_audiobookRepository.DeleteMany(audiobookIds);
_eventAggregator.PublishEvent(new AudiobooksDeletedEvent(audiobooks, deleteFiles));
}
protected override void OnItemsImported(List<Audiobook> items)
=> _eventAggregator.PublishEvent(new AudiobooksImportedEvent(items));
public List<Audiobook> GetAllAudiobooks()
{
return _audiobookRepository.All().ToList();
}
protected override void OnItemDeleted(Audiobook item, bool deleteFiles)
=> _eventAggregator.PublishEvent(new AudiobookDeletedEvent(item, deleteFiles));
public Dictionary<int, List<int>> AllAudiobookTags()
{
return _audiobookRepository.AllAudiobookTags();
}
protected override void OnItemsDeleted(List<Audiobook> items, bool deleteFiles)
=> _eventAggregator.PublishEvent(new AudiobooksDeletedEvent(items, deleteFiles));
public Audiobook UpdateAudiobook(Audiobook audiobook)
{
var storedAudiobook = GetAudiobook(audiobook.Id);
var updatedAudiobook = _audiobookRepository.Update(audiobook);
protected override void OnItemEdited(Audiobook updated, Audiobook stored)
=> _eventAggregator.PublishEvent(new AudiobookEditedEvent(updated, stored));
_eventAggregator.PublishEvent(new AudiobookEditedEvent(updatedAudiobook, storedAudiobook));
return updatedAudiobook;
}
public List<Audiobook> UpdateAudiobooks(List<Audiobook> audiobooks)
{
_audiobookRepository.UpdateMany(audiobooks);
_eventAggregator.PublishEvent(new AudiobooksBulkEditedEvent(audiobooks));
return audiobooks;
}
public bool AudiobookPathExists(string folder)
{
return _audiobookRepository.AudiobookPathExists(folder);
}
protected override void OnItemsBulkEdited(List<Audiobook> items)
=> _eventAggregator.PublishEvent(new AudiobooksBulkEditedEvent(items));
}
}

View file

@ -1,17 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Books.Events;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaItems;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Books
{
public interface IBookService
public interface IBookService : IBaseMediaService<Book>
{
Book GetBook(int bookId);
List<Book> GetBooks(IEnumerable<int> bookIds);
PagingSpec<Book> Paged(PagingSpec<Book> pagingSpec);
Book AddBook(Book newBook);
List<Book> AddBooks(List<Book> newBooks);
Book FindByIsbn(string isbn);
@ -32,149 +31,59 @@ public interface IBookService
bool BookPathExists(string folder);
}
public class BookService : IBookService
public class BookService : BaseMediaService<Book>, IBookService
{
private readonly IBookRepository _bookRepository;
private readonly IEventAggregator _eventAggregator;
public BookService(IBookRepository bookRepository,
IEventAggregator eventAggregator)
public BookService(IBookRepository bookRepository, IEventAggregator eventAggregator)
{
_bookRepository = bookRepository;
_eventAggregator = eventAggregator;
}
public Book GetBook(int bookId)
{
return _bookRepository.Get(bookId);
}
protected override IBasicRepository<Book> Repository => _bookRepository;
protected override IEventAggregator EventAggregator => _eventAggregator;
public List<Book> GetBooks(IEnumerable<int> bookIds)
{
return _bookRepository.Get(bookIds).ToList();
}
public PagingSpec<Book> Paged(PagingSpec<Book> pagingSpec)
{
return _bookRepository.GetPaged(pagingSpec);
}
public Book AddBook(Book newBook)
{
newBook.Added = DateTime.UtcNow;
var book = _bookRepository.Insert(newBook);
_eventAggregator.PublishEvent(new BookAddedEvent(GetBook(book.Id)));
return book;
}
public List<Book> AddBooks(List<Book> newBooks)
{
var now = DateTime.UtcNow;
foreach (var book in newBooks)
{
book.Added = now;
}
_bookRepository.InsertMany(newBooks);
_eventAggregator.PublishEvent(new BooksImportedEvent(newBooks));
return newBooks;
}
public Book FindByIsbn(string isbn)
{
return _bookRepository.FindByIsbn(isbn);
}
public Book FindByIsbn13(string isbn13)
{
return _bookRepository.FindByIsbn13(isbn13);
}
public Book FindByAsin(string asin)
{
return _bookRepository.FindByAsin(asin);
}
public Book FindByForeignId(string foreignBookId)
{
return _bookRepository.FindByForeignId(foreignBookId);
}
public Book FindByPath(string path)
{
return _bookRepository.FindByPath(path);
}
public List<Book> FindByAuthorId(int authorId)
{
return _bookRepository.FindByAuthorId(authorId);
}
public List<Book> FindBySeriesId(int seriesId)
{
return _bookRepository.FindBySeriesId(seriesId);
}
public Dictionary<int, string> AllBookPaths()
{
return _bookRepository.AllBookPaths();
}
public Book GetBook(int bookId) => Get(bookId);
public List<Book> GetBooks(IEnumerable<int> bookIds) => Get(bookIds);
public Book AddBook(Book newBook) => Add(newBook);
public List<Book> AddBooks(List<Book> newBooks) => AddMany(newBooks);
public void DeleteBook(int bookId, bool deleteFiles) => Delete(bookId, deleteFiles);
public void DeleteBooks(List<int> bookIds, bool deleteFiles) => DeleteMany(bookIds, deleteFiles);
public List<Book> GetAllBooks() => GetAll();
public Book UpdateBook(Book book) => Update(book);
public List<Book> UpdateBooks(List<Book> books) => UpdateMany(books);
public Book FindByIsbn(string isbn) => _bookRepository.FindByIsbn(isbn);
public Book FindByIsbn13(string isbn13) => _bookRepository.FindByIsbn13(isbn13);
public Book FindByAsin(string asin) => _bookRepository.FindByAsin(asin);
public Book FindByForeignId(string foreignBookId) => _bookRepository.FindByForeignId(foreignBookId);
public Book FindByPath(string path) => _bookRepository.FindByPath(path);
public List<Book> FindByAuthorId(int authorId) => _bookRepository.FindByAuthorId(authorId);
public List<Book> FindBySeriesId(int seriesId) => _bookRepository.FindBySeriesId(seriesId);
public Dictionary<int, string> AllBookPaths() => _bookRepository.AllBookPaths();
public List<Book> GetBooksBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
{
return _bookRepository.BooksBetweenDates(start, end, includeUnmonitored);
}
=> _bookRepository.BooksBetweenDates(start, end, includeUnmonitored);
public Dictionary<int, List<int>> AllBookTags() => _bookRepository.AllBookTags();
public bool BookPathExists(string folder) => _bookRepository.BookPathExists(folder);
public void DeleteBook(int bookId, bool deleteFiles)
{
var book = _bookRepository.Get(bookId);
_bookRepository.Delete(bookId);
_eventAggregator.PublishEvent(new BookDeletedEvent(book, deleteFiles));
}
protected override void OnItemAdded(Book item)
=> _eventAggregator.PublishEvent(new BookAddedEvent(item));
public void DeleteBooks(List<int> bookIds, bool deleteFiles)
{
var books = _bookRepository.Get(bookIds).ToList();
_bookRepository.DeleteMany(bookIds);
_eventAggregator.PublishEvent(new BooksDeletedEvent(books, deleteFiles));
}
protected override void OnItemsImported(List<Book> items)
=> _eventAggregator.PublishEvent(new BooksImportedEvent(items));
public List<Book> GetAllBooks()
{
return _bookRepository.All().ToList();
}
protected override void OnItemDeleted(Book item, bool deleteFiles)
=> _eventAggregator.PublishEvent(new BookDeletedEvent(item, deleteFiles));
public Dictionary<int, List<int>> AllBookTags()
{
return _bookRepository.AllBookTags();
}
protected override void OnItemsDeleted(List<Book> items, bool deleteFiles)
=> _eventAggregator.PublishEvent(new BooksDeletedEvent(items, deleteFiles));
public Book UpdateBook(Book book)
{
var storedBook = GetBook(book.Id);
var updatedBook = _bookRepository.Update(book);
protected override void OnItemEdited(Book updated, Book stored)
=> _eventAggregator.PublishEvent(new BookEditedEvent(updated, stored));
_eventAggregator.PublishEvent(new BookEditedEvent(updatedBook, storedBook));
return updatedBook;
}
public List<Book> UpdateBooks(List<Book> books)
{
_bookRepository.UpdateMany(books);
_eventAggregator.PublishEvent(new BooksBulkEditedEvent(books));
return books;
}
public bool BookPathExists(string folder)
{
return _bookRepository.BookPathExists(folder);
}
protected override void OnItemsBulkEdited(List<Book> items)
=> _eventAggregator.PublishEvent(new BooksBulkEditedEvent(items));
}
}

View file

@ -1 +0,0 @@
{}

View file

@ -1 +0,0 @@
{}

View file

@ -1 +0,0 @@
{}

View file

@ -1 +0,0 @@
{}

View file

@ -1 +0,0 @@
{}

View file

@ -1 +0,0 @@
{}

View file

@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.MediaItems
{
public interface IBaseMediaService<T> where T : ModelBase
{
T Get(int id);
List<T> Get(IEnumerable<int> ids);
PagingSpec<T> Paged(PagingSpec<T> pagingSpec);
T Add(T item);
List<T> AddMany(List<T> items);
void Delete(int id, bool deleteFiles);
void DeleteMany(List<int> ids, bool deleteFiles);
List<T> GetAll();
T Update(T item);
List<T> UpdateMany(List<T> items);
}
public abstract class BaseMediaService<T> : IBaseMediaService<T> where T : ModelBase
{
protected abstract IBasicRepository<T> Repository { get; }
protected virtual IEventAggregator EventAggregator => null;
public T Get(int id)
{
return Repository.Get(id);
}
public List<T> Get(IEnumerable<int> ids)
{
return Repository.Get(ids).ToList();
}
public PagingSpec<T> Paged(PagingSpec<T> pagingSpec)
{
return Repository.GetPaged(pagingSpec);
}
public virtual T Add(T item)
{
SetAddedTimestamp(item);
var inserted = Repository.Insert(item);
OnItemAdded(Get(inserted.Id));
return inserted;
}
public virtual List<T> AddMany(List<T> items)
{
var now = DateTime.UtcNow;
foreach (var item in items)
{
SetAddedTimestamp(item, now);
}
Repository.InsertMany(items);
OnItemsImported(items);
return items;
}
public virtual void Delete(int id, bool deleteFiles)
{
var item = Repository.Get(id);
Repository.Delete(id);
OnItemDeleted(item, deleteFiles);
}
public virtual void DeleteMany(List<int> ids, bool deleteFiles)
{
var items = Repository.Get(ids).ToList();
Repository.DeleteMany(ids);
OnItemsDeleted(items, deleteFiles);
}
public List<T> GetAll()
{
return Repository.All().ToList();
}
public virtual T Update(T item)
{
var stored = Get(item.Id);
var updated = Repository.Update(item);
OnItemEdited(updated, stored);
return updated;
}
public virtual List<T> UpdateMany(List<T> items)
{
Repository.UpdateMany(items);
OnItemsBulkEdited(items);
return items;
}
protected virtual void SetAddedTimestamp(T item, DateTime? timestamp = null)
{
var ts = timestamp ?? DateTime.UtcNow;
if (item is MediaItem mediaItem)
{
mediaItem.Added = ts;
return;
}
var addedProperty = item.GetType().GetProperty("Added");
if (addedProperty != null && addedProperty.PropertyType == typeof(DateTime) && addedProperty.CanWrite)
{
addedProperty.SetValue(item, ts);
}
}
protected virtual void OnItemAdded(T item) { }
protected virtual void OnItemsImported(List<T> items) { }
protected virtual void OnItemDeleted(T item, bool deleteFiles) { }
protected virtual void OnItemsDeleted(List<T> items, bool deleteFiles) { }
protected virtual void OnItemEdited(T updated, T stored) { }
protected virtual void OnItemsBulkEdited(List<T> items) { }
}
}

View file

@ -1,15 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaItems;
namespace NzbDrone.Core.Music
{
public interface IAlbumService
public interface IAlbumService : IBaseMediaService<Album>
{
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);
@ -26,7 +25,7 @@ public interface IAlbumService
bool AlbumPathExists(string folder);
}
public class AlbumService : IAlbumService
public class AlbumService : BaseMediaService<Album>, IAlbumService
{
private readonly IAlbumRepository _albumRepository;
@ -35,98 +34,25 @@ public AlbumService(IAlbumRepository albumRepository)
_albumRepository = albumRepository;
}
public Album GetAlbum(int albumId)
{
return _albumRepository.Get(albumId);
}
protected override IBasicRepository<Album> Repository => _albumRepository;
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 Album GetAlbum(int albumId) => Get(albumId);
public List<Album> GetAlbums(IEnumerable<int> albumIds) => Get(albumIds);
public Album AddAlbum(Album newAlbum) => Add(newAlbum);
public List<Album> AddAlbums(List<Album> newAlbums) => AddMany(newAlbums);
public void DeleteAlbum(int albumId, bool deleteFiles) => Delete(albumId, deleteFiles);
public void DeleteAlbums(List<int> albumIds, bool deleteFiles) => DeleteMany(albumIds, deleteFiles);
public List<Album> GetAllAlbums() => GetAll();
public Album UpdateAlbum(Album album) => Update(album);
public List<Album> UpdateAlbums(List<Album> albums) => UpdateMany(albums);
public Album FindByForeignId(string foreignAlbumId) => _albumRepository.FindByForeignId(foreignAlbumId);
public Album FindByPath(string path) => _albumRepository.FindByPath(path);
public List<Album> FindByArtistId(int artistId) => _albumRepository.FindByArtistId(artistId);
public Dictionary<int, string> AllAlbumPaths() => _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);
}
=> _albumRepository.AlbumsBetweenDates(start, end, includeUnmonitored);
public Dictionary<int, List<int>> AllAlbumTags() => _albumRepository.AllAlbumTags();
public bool AlbumPathExists(string folder) => _albumRepository.AlbumPathExists(folder);
}
}

View file

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaItems;
namespace NzbDrone.Core.Music
{
public interface IArtistService
public interface IArtistService : IBaseMediaService<Artist>
{
Artist GetArtist(int artistId);
List<Artist> GetArtists(IEnumerable<int> artistIds);
@ -21,7 +21,7 @@ public interface IArtistService
bool ArtistPathExists(string path);
}
public class ArtistService : IArtistService
public class ArtistService : BaseMediaService<Artist>, IArtistService
{
private readonly IArtistRepository _artistRepository;
@ -30,78 +30,21 @@ public ArtistService(IArtistRepository artistRepository)
_artistRepository = artistRepository;
}
public Artist GetArtist(int artistId)
{
return _artistRepository.Get(artistId);
}
protected override IBasicRepository<Artist> Repository => _artistRepository;
public List<Artist> GetArtists(IEnumerable<int> artistIds)
{
return _artistRepository.Get(artistIds).ToList();
}
public Artist GetArtist(int artistId) => Get(artistId);
public List<Artist> GetArtists(IEnumerable<int> artistIds) => Get(artistIds);
public Artist AddArtist(Artist newArtist) => Add(newArtist);
public List<Artist> AddArtists(List<Artist> newArtists) => AddMany(newArtists);
public void DeleteArtist(int artistId, bool deleteFiles) => Delete(artistId, deleteFiles);
public void DeleteArtists(List<int> artistIds, bool deleteFiles) => DeleteMany(artistIds, deleteFiles);
public List<Artist> GetAllArtists() => GetAll();
public Artist UpdateArtist(Artist artist) => Update(artist);
public List<Artist> UpdateArtists(List<Artist> artists) => UpdateMany(artists);
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);
}
public Artist FindByName(string name) => _artistRepository.FindByName(name);
public Artist FindByForeignId(string foreignArtistId) => _artistRepository.FindByForeignId(foreignArtistId);
public List<Artist> GetMonitoredArtists() => _artistRepository.GetMonitored();
public bool ArtistPathExists(string path) => _artistRepository.ArtistPathExists(path);
}
}

View file

@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaItems;
namespace NzbDrone.Core.Music
{
public interface ITrackService
public interface ITrackService : IBaseMediaService<Track>
{
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);
@ -23,7 +21,7 @@ public interface ITrackService
bool TrackPathExists(string path);
}
public class TrackService : ITrackService
public class TrackService : BaseMediaService<Track>, ITrackService
{
private readonly ITrackRepository _trackRepository;
@ -32,83 +30,21 @@ public TrackService(ITrackRepository trackRepository)
_trackRepository = trackRepository;
}
public Track GetTrack(int trackId)
{
return _trackRepository.Get(trackId);
}
protected override IBasicRepository<Track> Repository => _trackRepository;
public List<Track> GetTracks(IEnumerable<int> trackIds)
{
return _trackRepository.Get(trackIds).ToList();
}
public Track GetTrack(int trackId) => Get(trackId);
public List<Track> GetTracks(IEnumerable<int> trackIds) => Get(trackIds);
public Track AddTrack(Track newTrack) => Add(newTrack);
public List<Track> AddTracks(List<Track> newTracks) => AddMany(newTracks);
public void DeleteTrack(int trackId, bool deleteFiles) => Delete(trackId, deleteFiles);
public void DeleteTracks(List<int> trackIds, bool deleteFiles) => DeleteMany(trackIds, deleteFiles);
public List<Track> GetAllTracks() => GetAll();
public Track UpdateTrack(Track track) => Update(track);
public List<Track> UpdateTracks(List<Track> tracks) => UpdateMany(tracks);
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);
}
public Track FindByForeignId(string foreignTrackId) => _trackRepository.FindByForeignId(foreignTrackId);
public List<Track> FindByAlbumId(int albumId) => _trackRepository.FindByAlbumId(albumId);
public List<Track> GetMonitoredTracks() => _trackRepository.GetMonitored();
public bool TrackPathExists(string path) => _trackRepository.TrackPathExists(path);
}
}

View file

@ -342,7 +342,7 @@ private void AddMovieFileTokens(Dictionary<string, Func<TokenMatch, string>> tok
{
tokenHandlers["{Original Title}"] = m => GetOriginalTitle(movieFile, multipleTokens);
tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(movieFile, multipleTokens);
tokenHandlers["{Release Group}"] = m => movieFile.ReleaseGroup.IsNullOrWhiteSpace() ? m.DefaultValue("Radarr") : Truncate(movieFile.ReleaseGroup, m.CustomFormat);
tokenHandlers["{Release Group}"] = m => movieFile.ReleaseGroup.IsNullOrWhiteSpace() ? m.DefaultValue("Aletheia") : Truncate(movieFile.ReleaseGroup, m.CustomFormat);
}
private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Movie movie, MovieFile movieFile)

View file

@ -1,11 +1,11 @@
{
"openapi": "3.0.4",
"info": {
"title": "Radarr",
"description": "Radarr API docs",
"title": "Aletheia",
"description": "Aletheia API docs",
"license": {
"name": "GPL-3.0",
"url": "https://github.com/Radarr/Radarr/blob/develop/LICENSE"
"url": "https://github.com/cheir-mneme/aletheia/blob/develop/LICENSE"
},
"version": "3.0.0"
},