parent
8080d375d0
commit
ee4e44b81a
@ -1,45 +0,0 @@
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
using Readarr.Api.V1.Artist;
|
||||
|
||||
namespace NzbDrone.Integration.Test.ApiTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ArtistEditorFixture : IntegrationTest
|
||||
{
|
||||
private void GivenExistingArtist()
|
||||
{
|
||||
foreach (var name in new[] { "Alien Ant Farm", "Kiss" })
|
||||
{
|
||||
var newArtist = Artist.Lookup(name).First();
|
||||
|
||||
newArtist.QualityProfileId = 1;
|
||||
newArtist.MetadataProfileId = 1;
|
||||
newArtist.Path = string.Format(@"C:\Test\{0}", name).AsOsAgnostic();
|
||||
|
||||
Artist.Post(newArtist);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_update_multiple_artist()
|
||||
{
|
||||
GivenExistingArtist();
|
||||
|
||||
var artist = Artist.All();
|
||||
|
||||
var artistEditor = new ArtistEditorResource
|
||||
{
|
||||
QualityProfileId = 2,
|
||||
AuthorIds = artist.Select(o => o.Id).ToList()
|
||||
};
|
||||
|
||||
var result = Artist.Editor(artistEditor);
|
||||
|
||||
result.Should().HaveCount(2);
|
||||
result.TrueForAll(s => s.QualityProfileId == 2).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace NzbDrone.Integration.Test.ApiTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ArtistLookupFixture : IntegrationTest
|
||||
{
|
||||
[TestCase("Robert Harris", "Robert Harris")]
|
||||
[TestCase("J.K. Rowling", "J.K. Rowling")]
|
||||
public void lookup_new_artist_by_name(string term, string name)
|
||||
{
|
||||
var artist = Artist.Lookup(term);
|
||||
|
||||
artist.Should().NotBeEmpty();
|
||||
artist.Should().Contain(c => c.ArtistName == name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void lookup_new_artist_by_goodreads_book_id()
|
||||
{
|
||||
var artist = Artist.Lookup("readarr:1");
|
||||
|
||||
artist.Should().NotBeEmpty();
|
||||
artist.Should().Contain(c => c.ArtistName == "J.K. Rowling");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
using Readarr.Api.V1.Author;
|
||||
|
||||
namespace NzbDrone.Integration.Test.ApiTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class AuthorEditorFixture : IntegrationTest
|
||||
{
|
||||
private void GivenExistingAuthor()
|
||||
{
|
||||
foreach (var name in new[] { "Alien Ant Farm", "Kiss" })
|
||||
{
|
||||
var newAuthor = Author.Lookup(name).First();
|
||||
|
||||
newAuthor.QualityProfileId = 1;
|
||||
newAuthor.MetadataProfileId = 1;
|
||||
newAuthor.Path = string.Format(@"C:\Test\{0}", name).AsOsAgnostic();
|
||||
|
||||
Author.Post(newAuthor);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_update_multiple_artist()
|
||||
{
|
||||
GivenExistingAuthor();
|
||||
|
||||
var author = Author.All();
|
||||
|
||||
var artistEditor = new AuthorEditorResource
|
||||
{
|
||||
QualityProfileId = 2,
|
||||
AuthorIds = author.Select(o => o.Id).ToList()
|
||||
};
|
||||
|
||||
var result = Author.Editor(artistEditor);
|
||||
|
||||
result.Should().HaveCount(2);
|
||||
result.TrueForAll(s => s.QualityProfileId == 2).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace NzbDrone.Integration.Test.ApiTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class AuthorLookupFixture : IntegrationTest
|
||||
{
|
||||
[TestCase("Robert Harris", "Robert Harris")]
|
||||
[TestCase("J.K. Rowling", "J.K. Rowling")]
|
||||
public void lookup_new_author_by_name(string term, string name)
|
||||
{
|
||||
var author = Author.Lookup(term);
|
||||
|
||||
author.Should().NotBeEmpty();
|
||||
author.Should().Contain(c => c.AuthorName == name);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void lookup_new_author_by_goodreads_book_id()
|
||||
{
|
||||
var author = Author.Lookup("readarr:1");
|
||||
|
||||
author.Should().NotBeEmpty();
|
||||
author.Should().Contain(c => c.AuthorName == "J.K. Rowling");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Readarr.Api.V1.Albums;
|
||||
using RestSharp;
|
||||
|
||||
namespace NzbDrone.Integration.Test.Client
|
||||
{
|
||||
public class AlbumClient : ClientBase<AlbumResource>
|
||||
{
|
||||
public AlbumClient(IRestClient restClient, string apiKey)
|
||||
: base(restClient, apiKey, "album")
|
||||
{
|
||||
}
|
||||
|
||||
public List<AlbumResource> GetAlbumsInArtist(int authorId)
|
||||
{
|
||||
var request = BuildRequest("?authorId=" + authorId.ToString());
|
||||
return Get<List<AlbumResource>>(request);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Api.V1.Author;
|
||||
using RestSharp;
|
||||
|
||||
namespace NzbDrone.Integration.Test.Client
|
||||
{
|
||||
public class ArtistClient : ClientBase<ArtistResource>
|
||||
public class AuthorClient : ClientBase<AuthorResource>
|
||||
{
|
||||
public ArtistClient(IRestClient restClient, string apiKey)
|
||||
public AuthorClient(IRestClient restClient, string apiKey)
|
||||
: base(restClient, apiKey)
|
||||
{
|
||||
}
|
||||
|
||||
public List<ArtistResource> Lookup(string term)
|
||||
public List<AuthorResource> Lookup(string term)
|
||||
{
|
||||
var request = BuildRequest("lookup");
|
||||
request.AddQueryParameter("term", term);
|
||||
return Get<List<ArtistResource>>(request);
|
||||
return Get<List<AuthorResource>>(request);
|
||||
}
|
||||
|
||||
public List<ArtistResource> Editor(ArtistEditorResource artist)
|
||||
public List<AuthorResource> Editor(AuthorEditorResource artist)
|
||||
{
|
||||
var request = BuildRequest("editor");
|
||||
request.AddJsonBody(artist);
|
||||
return Put<List<ArtistResource>>(request);
|
||||
return Put<List<AuthorResource>>(request);
|
||||
}
|
||||
|
||||
public ArtistResource Get(string slug, HttpStatusCode statusCode = HttpStatusCode.OK)
|
||||
public AuthorResource Get(string slug, HttpStatusCode statusCode = HttpStatusCode.OK)
|
||||
{
|
||||
var request = BuildRequest(slug);
|
||||
return Get<ArtistResource>(request, statusCode);
|
||||
return Get<AuthorResource>(request, statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public class SystemInfoClient : ClientBase<ArtistResource>
|
||||
public class SystemInfoClient : ClientBase<AuthorResource>
|
||||
{
|
||||
public SystemInfoClient(IRestClient restClient, string apiKey)
|
||||
: base(restClient, apiKey)
|
@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using Readarr.Api.V1.Books;
|
||||
using RestSharp;
|
||||
|
||||
namespace NzbDrone.Integration.Test.Client
|
||||
{
|
||||
public class BookClient : ClientBase<BookResource>
|
||||
{
|
||||
public BookClient(IRestClient restClient, string apiKey)
|
||||
: base(restClient, apiKey, "book")
|
||||
{
|
||||
}
|
||||
|
||||
public List<BookResource> GetBooksInAuthor(int authorId)
|
||||
{
|
||||
var request = BuildRequest("?authorId=" + authorId.ToString());
|
||||
return Get<List<BookResource>>(request);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Readarr.Api.V1.Albums;
|
||||
|
||||
namespace Readarr.Api.V1.AlbumStudio
|
||||
{
|
||||
public class AlbumStudioArtistResource
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public bool? Monitored { get; set; }
|
||||
public List<AlbumResource> Albums { get; set; }
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using NzbDrone.Core.Books;
|
||||
using Readarr.Http.Extensions;
|
||||
|
||||
namespace Readarr.Api.V1.AlbumStudio
|
||||
{
|
||||
public class AlbumStudioModule : ReadarrV1Module
|
||||
{
|
||||
private readonly IAuthorService _authorService;
|
||||
private readonly IBookMonitoredService _albumMonitoredService;
|
||||
|
||||
public AlbumStudioModule(IAuthorService authorService, IBookMonitoredService albumMonitoredService)
|
||||
: base("/albumstudio")
|
||||
{
|
||||
_authorService = authorService;
|
||||
_albumMonitoredService = albumMonitoredService;
|
||||
Post("/", artist => UpdateAll());
|
||||
}
|
||||
|
||||
private object UpdateAll()
|
||||
{
|
||||
//Read from request
|
||||
var request = Request.Body.FromJson<AlbumStudioResource>();
|
||||
var artistToUpdate = _authorService.GetAuthors(request.Artist.Select(s => s.Id));
|
||||
|
||||
foreach (var s in request.Artist)
|
||||
{
|
||||
var artist = artistToUpdate.Single(c => c.Id == s.Id);
|
||||
|
||||
if (s.Monitored.HasValue)
|
||||
{
|
||||
artist.Monitored = s.Monitored.Value;
|
||||
}
|
||||
|
||||
if (request.MonitoringOptions != null && request.MonitoringOptions.Monitor == MonitorTypes.None)
|
||||
{
|
||||
artist.Monitored = false;
|
||||
}
|
||||
|
||||
_albumMonitoredService.SetBookMonitoredStatus(artist, request.MonitoringOptions);
|
||||
}
|
||||
|
||||
return ResponseWithCode("ok", HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.AuthorStats;
|
||||
using NzbDrone.Core.Books;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.SignalR;
|
||||
using Readarr.Api.V1.Artist;
|
||||
using Readarr.Http;
|
||||
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public abstract class AlbumModuleWithSignalR : ReadarrRestModuleWithSignalR<AlbumResource, Book>
|
||||
{
|
||||
protected readonly IBookService _bookService;
|
||||
protected readonly IAuthorStatisticsService _artistStatisticsService;
|
||||
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
||||
protected readonly IMapCoversToLocal _coverMapper;
|
||||
|
||||
protected AlbumModuleWithSignalR(IBookService bookService,
|
||||
IAuthorStatisticsService artistStatisticsService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_bookService = bookService;
|
||||
_artistStatisticsService = artistStatisticsService;
|
||||
_coverMapper = coverMapper;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetAlbum;
|
||||
}
|
||||
|
||||
protected AlbumModuleWithSignalR(IBookService bookService,
|
||||
IAuthorStatisticsService artistStatisticsService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
string resource)
|
||||
: base(signalRBroadcaster, resource)
|
||||
{
|
||||
_bookService = bookService;
|
||||
_artistStatisticsService = artistStatisticsService;
|
||||
_coverMapper = coverMapper;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetAlbum;
|
||||
}
|
||||
|
||||
protected AlbumResource GetAlbum(int id)
|
||||
{
|
||||
var album = _bookService.GetBook(id);
|
||||
var resource = MapToResource(album, true);
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected AlbumResource MapToResource(Book album, bool includeArtist)
|
||||
{
|
||||
var resource = album.ToResource();
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
var artist = album.Author.Value;
|
||||
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
|
||||
FetchAndLinkAlbumStatistics(resource);
|
||||
MapCoversToLocal(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected List<AlbumResource> MapToResource(List<Book> albums, bool includeArtist)
|
||||
{
|
||||
var result = albums.ToResource();
|
||||
|
||||
if (includeArtist)
|
||||
{
|
||||
var artistDict = new Dictionary<int, NzbDrone.Core.Books.Author>();
|
||||
for (var i = 0; i < albums.Count; i++)
|
||||
{
|
||||
var album = albums[i];
|
||||
var resource = result[i];
|
||||
var artist = artistDict.GetValueOrDefault(albums[i].AuthorMetadataId) ?? album.Author?.Value;
|
||||
artistDict[artist.AuthorMetadataId] = artist;
|
||||
|
||||
resource.Artist = artist.ToResource();
|
||||
}
|
||||
}
|
||||
|
||||
var artistStats = _artistStatisticsService.AuthorStatistics();
|
||||
LinkArtistStatistics(result, artistStats);
|
||||
MapCoversToLocal(result.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void FetchAndLinkAlbumStatistics(AlbumResource resource)
|
||||
{
|
||||
LinkArtistStatistics(resource, _artistStatisticsService.AuthorStatistics(resource.AuthorId));
|
||||
}
|
||||
|
||||
private void LinkArtistStatistics(List<AlbumResource> resources, List<AuthorStatistics> artistStatistics)
|
||||
{
|
||||
foreach (var album in resources)
|
||||
{
|
||||
var stats = artistStatistics.SingleOrDefault(ss => ss.AuthorId == album.AuthorId);
|
||||
LinkArtistStatistics(album, stats);
|
||||
}
|
||||
}
|
||||
|
||||
private void LinkArtistStatistics(AlbumResource resource, AuthorStatistics artistStatistics)
|
||||
{
|
||||
if (artistStatistics?.BookStatistics != null)
|
||||
{
|
||||
var dictAlbumStats = artistStatistics.BookStatistics.ToDictionary(v => v.BookId);
|
||||
|
||||
resource.Statistics = dictAlbumStats.GetValueOrDefault(resource.Id).ToResource();
|
||||
}
|
||||
}
|
||||
|
||||
private void MapCoversToLocal(params AlbumResource[] albums)
|
||||
{
|
||||
foreach (var albumResource in albums)
|
||||
{
|
||||
_coverMapper.ConvertToLocalUrls(albumResource.Id, MediaCoverEntity.Book, albumResource.Images);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
using NzbDrone.Core.AuthorStats;
|
||||
|
||||
namespace Readarr.Api.V1.Albums
|
||||
{
|
||||
public class AlbumStatisticsResource
|
||||
{
|
||||
public int TrackFileCount { get; set; }
|
||||
public int TrackCount { get; set; }
|
||||
public int TotalTrackCount { get; set; }
|
||||
public long SizeOnDisk { get; set; }
|
||||
|
||||
public decimal PercentOfTracks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TrackCount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return TrackFileCount / (decimal)TrackCount * 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AlbumStatisticsResourceMapper
|
||||
{
|
||||
public static AlbumStatisticsResource ToResource(this BookStatistics model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AlbumStatisticsResource
|
||||
{
|
||||
TrackFileCount = model.BookFileCount,
|
||||
TrackCount = model.BookCount,
|
||||
SizeOnDisk = model.SizeOnDisk
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace Readarr.Api.V1.Artist
|
||||
namespace Readarr.Api.V1.Author
|
||||
{
|
||||
public class AlternateTitleResource
|
||||
{
|
@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Readarr.Api.V1.Artist
|
||||
namespace Readarr.Api.V1.Author
|
||||
{
|
||||
public class ArtistEditorDeleteResource
|
||||
public class AuthorEditorDeleteResource
|
||||
{
|
||||
public List<int> AuthorIds { get; set; }
|
||||
public bool DeleteFiles { get; set; }
|
@ -1,14 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Readarr.Api.V1.Artist
|
||||
namespace Readarr.Api.V1.Author
|
||||
{
|
||||
public class ArtistEditorResource
|
||||
public class AuthorEditorResource
|
||||
{
|
||||
public List<int> AuthorIds { get; set; }
|
||||
public bool? Monitored { get; set; }
|
||||
public int? QualityProfileId { get; set; }
|
||||
public int? MetadataProfileId { get; set; }
|
||||
public bool? AlbumFolder { get; set; }
|
||||
public string RootFolderPath { get; set; }
|
||||
public List<int> Tags { get; set; }
|
||||
public ApplyTags ApplyTags { get; set; }
|
@ -0,0 +1,43 @@
|
||||
using NzbDrone.Core.AuthorStats;
|
||||
|
||||
namespace Readarr.Api.V1.Author
|
||||
{
|
||||
public class AuthorStatisticsResource
|
||||
{
|
||||
public int BookCount { get; set; }
|
||||
public int BookFileCount { get; set; }
|
||||
public int TotalBookCount { get; set; }
|
||||
public long SizeOnDisk { get; set; }
|
||||
|
||||
public decimal PercentOfBooks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BookCount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BookFileCount / (decimal)BookCount * 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AuthorStatisticsResourceMapper
|
||||
{
|
||||
public static AuthorStatisticsResource ToResource(this AuthorStatistics model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AuthorStatisticsResource
|
||||
{
|
||||
BookCount = model.BookCount,
|
||||
BookFileCount = model.BookFileCount,
|
||||
SizeOnDisk = model.SizeOnDisk
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace Readarr.Api.V1.TrackFiles
|
||||
namespace Readarr.Api.V1.BookFiles
|
||||
{
|
||||
public class TrackFileListResource
|
||||
public class BookFileListResource
|
||||
{
|
||||
public List<int> TrackFileIds { get; set; }
|
||||
public List<int> BookFileIds { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using Readarr.Api.V1.Books;
|
||||
|
||||
namespace Readarr.Api.V1.Bookshelf
|
||||
{
|
||||
public class BookshelfAuthorResource
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public bool? Monitored { get; set; }
|
||||
public List<BookResource> Books { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using NzbDrone.Core.Books;
|
||||
using Readarr.Http.Extensions;
|
||||
|
||||
namespace Readarr.Api.V1.Bookshelf
|
||||
{
|
||||
public class BookshelfModule : ReadarrV1Module
|
||||
{
|
||||
private readonly IAuthorService _authorService;
|
||||
private readonly IBookMonitoredService _bookMonitoredService;
|
||||
|
||||
public BookshelfModule(IAuthorService authorService, IBookMonitoredService bookMonitoredService)
|
||||
: base("/bookshelf")
|
||||
{
|
||||
_authorService = authorService;
|
||||
_bookMonitoredService = bookMonitoredService;
|
||||
Post("/", artist => UpdateAll());
|
||||
}
|
||||
|
||||
private object UpdateAll()
|
||||
{
|
||||
//Read from request
|
||||
var request = Request.Body.FromJson<BookshelfResource>();
|
||||
var authorToUpdate = _authorService.GetAuthors(request.Authors.Select(s => s.Id));
|
||||
|
||||
foreach (var s in request.Authors)
|
||||
{
|
||||
var author = authorToUpdate.Single(c => c.Id == s.Id);
|
||||
|
||||
if (s.Monitored.HasValue)
|
||||
{
|
||||
author.Monitored = s.Monitored.Value;
|
||||
}
|
||||
|
||||
if (request.MonitoringOptions != null && request.MonitoringOptions.Monitor == MonitorTypes.None)
|
||||
{
|
||||
author.Monitored = false;
|
||||
}
|
||||
|
||||
_bookMonitoredService.SetBookMonitoredStatus(author, request.MonitoringOptions);
|
||||
}
|
||||
|
||||
return ResponseWithCode("ok", HttpStatusCode.Accepted);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Books;
|
||||
|
||||
namespace Readarr.Api.V1.AlbumStudio
|
||||
namespace Readarr.Api.V1.Bookshelf
|
||||
{
|
||||
public class AlbumStudioResource
|
||||
public class BookshelfResource
|
||||
{
|
||||
public List<AlbumStudioArtistResource> Artist { get; set; }
|
||||
public List<BookshelfAuthorResource> Authors { get; set; }
|
||||
public MonitoringOptions MonitoringOptions { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.AuthorStats;
|
||||
using NzbDrone.Core.Books;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.SignalR;
|
||||
using Readarr.Api.V1.Author;
|
||||
using Readarr.Http;
|
||||
|
||||
namespace Readarr.Api.V1.Books
|
||||
{
|
||||
public abstract class BookModuleWithSignalR : ReadarrRestModuleWithSignalR<BookResource, Book>
|
||||
{
|
||||
protected readonly IBookService _bookService;
|
||||
protected readonly IAuthorStatisticsService _authorStatisticsService;
|
||||
protected readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
||||
protected readonly IMapCoversToLocal _coverMapper;
|
||||
|
||||
protected BookModuleWithSignalR(IBookService bookService,
|
||||
IAuthorStatisticsService authorStatisticsService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_bookService = bookService;
|
||||
_authorStatisticsService = authorStatisticsService;
|
||||
_coverMapper = coverMapper;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetBook;
|
||||
}
|
||||
|
||||
protected BookModuleWithSignalR(IBookService bookService,
|
||||
IAuthorStatisticsService authorStatisticsService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
IUpgradableSpecification qualityUpgradableSpecification,
|
||||
IBroadcastSignalRMessage signalRBroadcaster,
|
||||
string resource)
|
||||
: base(signalRBroadcaster, resource)
|
||||
{
|
||||
_bookService = bookService;
|
||||
_authorStatisticsService = authorStatisticsService;
|
||||
_coverMapper = coverMapper;
|
||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||
|
||||
GetResourceById = GetBook;
|
||||
}
|
||||
|
||||
protected BookResource GetBook(int id)
|
||||
{
|
||||
var book = _bookService.GetBook(id);
|
||||
var resource = MapToResource(book, true);
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected BookResource MapToResource(Book book, bool includeAuthor)
|
||||
{
|
||||
var resource = book.ToResource();
|
||||
|
||||
if (includeAuthor)
|
||||
{
|
||||
var artist = book.Author.Value;
|
||||
|
||||
resource.Author = artist.ToResource();
|
||||
}
|
||||
|
||||
FetchAndLinkAlbumStatistics(resource);
|
||||
MapCoversToLocal(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
protected List<BookResource> MapToResource(List<Book> books, bool includeAuthor)
|
||||
{
|
||||
var result = books.ToResource();
|
||||
|
||||
if (includeAuthor)
|
||||
{
|
||||
var authorDict = new Dictionary<int, NzbDrone.Core.Books.Author>();
|
||||
for (var i = 0; i < books.Count; i++)
|
||||
{
|
||||
var book = books[i];
|
||||
var resource = result[i];
|
||||
var author = authorDict.GetValueOrDefault(books[i].AuthorMetadataId) ?? book.Author?.Value;
|
||||
authorDict[author.AuthorMetadataId] = author;
|
||||
|
||||
resource.Author = author.ToResource();
|
||||
}
|
||||
}
|
||||
|
||||
var authorStats = _authorStatisticsService.AuthorStatistics();
|
||||
LinkAuthorStatistics(result, authorStats);
|
||||
MapCoversToLocal(result.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void FetchAndLinkAlbumStatistics(BookResource resource)
|
||||
{
|
||||
LinkAuthorStatistics(resource, _authorStatisticsService.AuthorStatistics(resource.AuthorId));
|
||||
}
|
||||
|
||||
private void LinkAuthorStatistics(List<BookResource> resources, List<AuthorStatistics> authorStatistics)
|
||||
{
|
||||
foreach (var book in resources)
|
||||
{
|
||||
var stats = authorStatistics.SingleOrDefault(ss => ss.AuthorId == book.AuthorId);
|
||||
LinkAuthorStatistics(book, stats);
|
||||
}
|
||||
}
|
||||
|
||||
private void LinkAuthorStatistics(BookResource resource, AuthorStatistics authorStatistics)
|
||||
{
|
||||
if (authorStatistics?.BookStatistics != null)
|
||||
{
|
||||
var dictBookStats = authorStatistics.BookStatistics.ToDictionary(v => v.BookId);
|
||||
|
||||
resource.Statistics = dictBookStats.GetValueOrDefault(resource.Id).ToResource();
|
||||
}
|
||||
}
|
||||
|
||||
private void MapCoversToLocal(params BookResource[] books)
|
||||
{
|
||||
foreach (var bookResource in books)
|
||||
{
|
||||
_coverMapper.ConvertToLocalUrls(bookResource.Id, MediaCoverEntity.Book, bookResource.Images);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Readarr.Api.V1.Albums
|
||||
namespace Readarr.Api.V1.Books
|
||||
{
|
||||
public class AlbumsMonitoredResource
|
||||
public class BooksMonitoredResource
|
||||
{
|
||||
public List<int> BookIds { get; set; }
|
||||
public bool Monitored { get; set; }
|
Loading…
Reference in new issue