|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using Microsoft.AspNetCore.StaticFiles;
|
|
|
|
|
using NzbDrone.Common.Extensions;
|
|
|
|
|
using NzbDrone.Core.Books;
|
|
|
|
|
using NzbDrone.Core.Datastore;
|
|
|
|
|
using NzbDrone.Core.MediaCover;
|
|
|
|
@ -40,88 +41,183 @@ namespace Readarr.Api.V1.OPDS
|
|
|
|
|
[HttpGet]
|
|
|
|
|
public OPDSCatalogResource GetOPDSCatalog()
|
|
|
|
|
{
|
|
|
|
|
/*var metadataTask = Task.Run(() => _authorService.GetAllAuthors());
|
|
|
|
|
var books = _bookService.GetAllBooks();
|
|
|
|
|
var authors = metadataTask.GetAwaiter().GetResult().ToDictionary(x => x.AuthorMetadataId);
|
|
|
|
|
var catalog = OPDSResourceMapper.ToOPDSCatalogResource();
|
|
|
|
|
return catalog;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var book in books)
|
|
|
|
|
protected bool IsDigitsOnly(string str)
|
|
|
|
|
{
|
|
|
|
|
foreach (var c in str)
|
|
|
|
|
{
|
|
|
|
|
book.Author = authors[book.AuthorMetadataId];
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
var catalog = OPDSResourceMapper.ToOPDSCatalogResource();
|
|
|
|
|
if (c < '0' || c > '9')
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//catalog.Publications = MapToResource(books, wanted);
|
|
|
|
|
return catalog;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// /opds/publications
|
|
|
|
|
[HttpGet("publications")]
|
|
|
|
|
public OPDSPublicationsResource GetOPDSPublications([FromQuery] int? page,
|
|
|
|
|
[FromQuery] int? itemsPerPage)
|
|
|
|
|
// /opds/publications/search
|
|
|
|
|
[HttpGet("publications/search")]
|
|
|
|
|
public OPDSPublicationsResource GetOPDSPublicationsForQuery([FromQuery] PagingRequestResource paging, [FromQuery] string query, [FromQuery] string title, [FromQuery] string author)
|
|
|
|
|
{
|
|
|
|
|
if (itemsPerPage == null)
|
|
|
|
|
var pagingResource = new PagingResource<OPDSPublicationResource>(paging);
|
|
|
|
|
var pagingSpec = new PagingSpec<Book>
|
|
|
|
|
{
|
|
|
|
|
itemsPerPage = 10;
|
|
|
|
|
Page = pagingResource.Page,
|
|
|
|
|
PageSize = pagingResource.PageSize,
|
|
|
|
|
SortKey = pagingResource.SortKey,
|
|
|
|
|
SortDirection = pagingResource.SortDirection
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (query.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
query = query.ToLower();
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Title.Contains(query) || v.Author.Value.CleanName.Contains(query));
|
|
|
|
|
}
|
|
|
|
|
else if (itemsPerPage < 10)
|
|
|
|
|
else if (title.IsNotNullOrWhiteSpace() && author.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
itemsPerPage = 10;
|
|
|
|
|
title = title.ToLower();
|
|
|
|
|
author = author.ToLower();
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Title.Contains(title) && v.Author.Value.CleanName.Contains(author));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (page == null)
|
|
|
|
|
else if (title.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
page = 1;
|
|
|
|
|
itemsPerPage = 100000;
|
|
|
|
|
title = title.ToLower();
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Title.Contains(title));
|
|
|
|
|
}
|
|
|
|
|
else if (author.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
author = author.ToLower();
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Author.Value.CleanName.Contains(author));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new BadRequestException("No search term specified in query");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pagingSpec = _bookService.BooksWithFiles(pagingSpec);
|
|
|
|
|
|
|
|
|
|
var publications = OPDSResourceMapper.ToOPDSPublicationsResource(pagingSpec.Page, pagingSpec.PageSize, pagingSpec.TotalRecords);
|
|
|
|
|
publications.Publications = MapToResource(pagingSpec.Records);
|
|
|
|
|
|
|
|
|
|
return publications;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// /opds/publications
|
|
|
|
|
[HttpGet("publications")]
|
|
|
|
|
public OPDSPublicationsResource GetOPDSPublications([FromQuery] PagingRequestResource paging)
|
|
|
|
|
{
|
|
|
|
|
var pagingResource = new PagingResource<OPDSPublicationResource>(paging);
|
|
|
|
|
var pagingSpec = new PagingSpec<Book>
|
|
|
|
|
{
|
|
|
|
|
Page = (int)page,
|
|
|
|
|
PageSize = (int)itemsPerPage,
|
|
|
|
|
SortKey = "Id",
|
|
|
|
|
SortDirection = SortDirection.Default
|
|
|
|
|
Page = pagingResource.Page,
|
|
|
|
|
PageSize = pagingResource.PageSize,
|
|
|
|
|
SortKey = pagingResource.SortKey,
|
|
|
|
|
SortDirection = pagingResource.SortDirection
|
|
|
|
|
};
|
|
|
|
|
pagingSpec = _bookService.BooksWithFiles(pagingSpec);
|
|
|
|
|
|
|
|
|
|
var publications = OPDSResourceMapper.ToOPDSPublicationsResource((int)page, (int)itemsPerPage, pagingSpec.TotalRecords);
|
|
|
|
|
publications.Publications = MapToResource(pagingSpec.Records, true);
|
|
|
|
|
var publications = OPDSResourceMapper.ToOPDSPublicationsResource(pagingSpec.Page, pagingSpec.PageSize, pagingSpec.TotalRecords);
|
|
|
|
|
publications.Publications = MapToResource(pagingSpec.Records);
|
|
|
|
|
|
|
|
|
|
return publications;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// /opds/wanted
|
|
|
|
|
[HttpGet("wanted")]
|
|
|
|
|
public OPDSPublicationsResource GetOPDSWantedPublications([FromQuery] int? page,
|
|
|
|
|
[FromQuery] int? itemsPerPage)
|
|
|
|
|
// /opds/monitored
|
|
|
|
|
[HttpGet("monitored")]
|
|
|
|
|
public OPDSPublicationsResource GetOPDSMonitoredPublications([FromQuery] PagingRequestResource paging)
|
|
|
|
|
{
|
|
|
|
|
if (itemsPerPage == null)
|
|
|
|
|
{
|
|
|
|
|
itemsPerPage = 10;
|
|
|
|
|
}
|
|
|
|
|
else if (itemsPerPage < 10)
|
|
|
|
|
var pagingResource = new PagingResource<OPDSPublicationResource>(paging);
|
|
|
|
|
var pagingSpec = new PagingSpec<Book>
|
|
|
|
|
{
|
|
|
|
|
itemsPerPage = 10;
|
|
|
|
|
}
|
|
|
|
|
Page = pagingResource.Page,
|
|
|
|
|
PageSize = pagingResource.PageSize,
|
|
|
|
|
SortKey = pagingResource.SortKey,
|
|
|
|
|
SortDirection = pagingResource.SortDirection
|
|
|
|
|
};
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Author.Value.Monitored == true);
|
|
|
|
|
pagingSpec = _bookService.BooksWithoutFiles(pagingSpec);
|
|
|
|
|
|
|
|
|
|
if (page == null)
|
|
|
|
|
var publications = OPDSResourceMapper.ToOPDSPublicationsResource(pagingSpec.Page, pagingSpec.PageSize, pagingSpec.TotalRecords);
|
|
|
|
|
publications.Publications = MapToResource(pagingSpec.Records);
|
|
|
|
|
return publications;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// /opds/monitored
|
|
|
|
|
[HttpGet("unmonitored")]
|
|
|
|
|
public OPDSPublicationsResource GetOPDSUnmonitoredPublications([FromQuery] PagingRequestResource paging)
|
|
|
|
|
{
|
|
|
|
|
var pagingResource = new PagingResource<OPDSPublicationResource>(paging);
|
|
|
|
|
var pagingSpec = new PagingSpec<Book>
|
|
|
|
|
{
|
|
|
|
|
page = 1;
|
|
|
|
|
itemsPerPage = 100000;
|
|
|
|
|
}
|
|
|
|
|
Page = pagingResource.Page,
|
|
|
|
|
PageSize = pagingResource.PageSize,
|
|
|
|
|
SortKey = pagingResource.SortKey,
|
|
|
|
|
SortDirection = pagingResource.SortDirection
|
|
|
|
|
};
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Monitored == false);
|
|
|
|
|
pagingSpec = _bookService.BooksWithoutFiles(pagingSpec);
|
|
|
|
|
|
|
|
|
|
var publications = OPDSResourceMapper.ToOPDSPublicationsResource(pagingSpec.Page, pagingSpec.PageSize, pagingSpec.TotalRecords);
|
|
|
|
|
publications.Publications = MapToResource(pagingSpec.Records);
|
|
|
|
|
return publications;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// /opds/publications/search
|
|
|
|
|
[HttpGet("unmonitored/search")]
|
|
|
|
|
public OPDSPublicationsResource GetOPDSUnmonitoredForQuery([FromQuery] PagingRequestResource paging, [FromQuery] string query, [FromQuery] string title, [FromQuery] string author)
|
|
|
|
|
{
|
|
|
|
|
var pagingResource = new PagingResource<OPDSPublicationResource>(paging);
|
|
|
|
|
var pagingSpec = new PagingSpec<Book>
|
|
|
|
|
{
|
|
|
|
|
Page = (int)page,
|
|
|
|
|
PageSize = (int)itemsPerPage,
|
|
|
|
|
SortKey = "Id",
|
|
|
|
|
SortDirection = SortDirection.Default
|
|
|
|
|
Page = pagingResource.Page,
|
|
|
|
|
PageSize = pagingResource.PageSize,
|
|
|
|
|
SortKey = pagingResource.SortKey,
|
|
|
|
|
SortDirection = pagingResource.SortDirection
|
|
|
|
|
};
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Monitored == true);
|
|
|
|
|
|
|
|
|
|
if (query.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
query = query.ToLower();
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Title.Contains(query) || v.Author.Value.CleanName.Contains(query));
|
|
|
|
|
}
|
|
|
|
|
else if (title.IsNotNullOrWhiteSpace() && author.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
title = title.ToLower();
|
|
|
|
|
author = author.ToLower();
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Title.Contains(title) && v.Author.Value.CleanName.Contains(author));
|
|
|
|
|
}
|
|
|
|
|
else if (title.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
title = title.ToLower();
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Title.Contains(title));
|
|
|
|
|
}
|
|
|
|
|
else if (author.IsNotNullOrWhiteSpace())
|
|
|
|
|
{
|
|
|
|
|
author = author.ToLower();
|
|
|
|
|
if (IsDigitsOnly(author))
|
|
|
|
|
{
|
|
|
|
|
var authorId = int.Parse(author);
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.AuthorMetadataId == authorId);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Author.Value.CleanName.Contains(author));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new BadRequestException("No search term specified in query");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pagingSpec.FilterExpressions.Add(v => v.Monitored == false);
|
|
|
|
|
pagingSpec = _bookService.BooksWithoutFiles(pagingSpec);
|
|
|
|
|
|
|
|
|
|
var publications = OPDSResourceMapper.ToOPDSPublicationsResource((int)page, (int)itemsPerPage, pagingSpec.TotalRecords);
|
|
|
|
|
publications.Publications = MapToResource(pagingSpec.Records, true);
|
|
|
|
|
var publications = OPDSResourceMapper.ToOPDSPublicationsResource(pagingSpec.Page, pagingSpec.PageSize, pagingSpec.TotalRecords);
|
|
|
|
|
publications.Publications = MapToResource(pagingSpec.Records);
|
|
|
|
|
|
|
|
|
|
return publications;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -150,7 +246,7 @@ namespace Readarr.Api.V1.OPDS
|
|
|
|
|
return OPDSResourceMapper.ToOPDSPublicationResource(book, bookfiles, ebookEdition, images);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected List<OPDSPublicationResource> MapToResource(List<Book> books, bool wanted)
|
|
|
|
|
protected List<OPDSPublicationResource> MapToResource(List<Book> books)
|
|
|
|
|
{
|
|
|
|
|
var publications = new List<OPDSPublicationResource>();
|
|
|
|
|
var metadataTask = Task.Run(() => _authorService.GetAllAuthors());
|
|
|
|
@ -161,9 +257,10 @@ namespace Readarr.Api.V1.OPDS
|
|
|
|
|
var bookfiles = _mediaFileService.GetFilesByBook(book.Id);
|
|
|
|
|
var selectedEdition = book.Editions?.Value.Where(x => x.Monitored).SingleOrDefault();
|
|
|
|
|
var ebookEdition = book.Editions?.Value.Where(x => x.IsEbook).FirstOrDefault();
|
|
|
|
|
var anyEdition = book.Editions?.Value.FirstOrDefault();
|
|
|
|
|
var covers = selectedEdition?.Images ?? new List<MediaCover>();
|
|
|
|
|
_coverMapper.ConvertToLocalUrls(book.Id, MediaCoverEntity.Book, covers);
|
|
|
|
|
var publication = OPDSResourceMapper.ToOPDSPublicationResource(book, bookfiles, ebookEdition, covers);
|
|
|
|
|
var publication = OPDSResourceMapper.ToOPDSPublicationResource(book, bookfiles, ebookEdition ?? selectedEdition ?? anyEdition, covers);
|
|
|
|
|
publications.Add(publication);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|