feat(opds): browse series by publishers

closes #332
This commit is contained in:
Gauthier Roebroeck 2020-09-28 17:59:51 +08:00
parent e3bb8bc7ae
commit f3fcab41e4
5 changed files with 61 additions and 6 deletions

View file

@ -4,7 +4,8 @@ open class SeriesSearch(
val libraryIds: Collection<String>? = null,
val collectionIds: Collection<Long>? = null,
val searchTerm: String? = null,
val metadataStatus: Collection<SeriesMetadata.Status>? = null
val metadataStatus: Collection<SeriesMetadata.Status>? = null,
val publishers: Collection<String>? = null
)
class SeriesSearchWithReadProgress(
@ -12,7 +13,7 @@ class SeriesSearchWithReadProgress(
collectionIds: Collection<Long>? = null,
searchTerm: String? = null,
metadataStatus: Collection<SeriesMetadata.Status>? = null,
val publishers: Collection<String>? = null,
publishers: Collection<String>? = null,
val languages: Collection<String>? = null,
val genres: Collection<String>? = null,
val tags: Collection<String>? = null,
@ -22,5 +23,6 @@ class SeriesSearchWithReadProgress(
libraryIds = libraryIds,
collectionIds = collectionIds,
searchTerm = searchTerm,
metadataStatus = metadataStatus
metadataStatus = metadataStatus,
publishers = publishers
)

View file

@ -18,6 +18,7 @@ interface ReferentialRepository {
fun findAllPublishers(): Set<String>
fun findAllPublishersByLibrary(libraryId: String): Set<String>
fun findAllPublishersByLibraries(libraryIds: Set<String>): Set<String>
fun findAllPublishersByCollection(collectionId: String): Set<String>
fun findAllAgeRatings(): Set<Int?>

View file

@ -125,6 +125,15 @@ class ReferentialDao(
.orderBy(sd.PUBLISHER)
.fetchSet(sd.PUBLISHER)
override fun findAllPublishersByLibraries(libraryIds: Set<String>): Set<String> =
dsl.selectDistinct(sd.PUBLISHER)
.from(sd)
.leftJoin(s).on(sd.SERIES_ID.eq(s.ID))
.where(sd.PUBLISHER.ne(""))
.and(s.LIBRARY_ID.`in`(libraryIds))
.orderBy(sd.PUBLISHER)
.fetchSet(sd.PUBLISHER)
override fun findAllPublishersByCollection(collectionId: String): Set<String> =
dsl.selectDistinct(sd.PUBLISHER)
.from(sd)

View file

@ -131,6 +131,7 @@ class SeriesDao(
if (!collectionIds.isNullOrEmpty()) c = c.and(cs.COLLECTION_ID.`in`(collectionIds))
searchTerm?.let { c = c.and(d.TITLE.containsIgnoreCase(it)) }
if (!metadataStatus.isNullOrEmpty()) c = c.and(d.STATUS.`in`(metadataStatus))
if (!publishers.isNullOrEmpty()) c = c.and(DSL.lower(d.PUBLISHER).`in`(publishers.map { it.toLowerCase() }))
return c
}

View file

@ -16,6 +16,7 @@ import org.gotson.komga.domain.persistence.BookRepository
import org.gotson.komga.domain.persistence.LibraryRepository
import org.gotson.komga.domain.persistence.MediaRepository
import org.gotson.komga.domain.persistence.ReadListRepository
import org.gotson.komga.domain.persistence.ReferentialRepository
import org.gotson.komga.domain.persistence.SeriesCollectionRepository
import org.gotson.komga.domain.persistence.SeriesMetadataRepository
import org.gotson.komga.domain.persistence.SeriesRepository
@ -62,6 +63,7 @@ private const val ROUTE_SERIES_LATEST = "series/latest"
private const val ROUTE_LIBRARIES_ALL = "libraries"
private const val ROUTE_COLLECTIONS_ALL = "collections"
private const val ROUTE_READLISTS_ALL = "readlists"
private const val ROUTE_PUBLISHERS_ALL = "publishers"
private const val ROUTE_SEARCH = "search"
private const val ID_SERIES_ALL = "allSeries"
@ -69,6 +71,7 @@ private const val ID_SERIES_LATEST = "latestSeries"
private const val ID_LIBRARIES_ALL = "allLibraries"
private const val ID_COLLECTIONS_ALL = "allCollections"
private const val ID_READLISTS_ALL = "allReadLists"
private const val ID_PUBLISHERS_ALL = "allPublishers"
@RestController
@RequestMapping(value = [ROUTE_BASE], produces = [MediaType.APPLICATION_ATOM_XML_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE])
@ -81,7 +84,8 @@ class OpdsController(
private val seriesMetadataRepository: SeriesMetadataRepository,
private val bookRepository: BookRepository,
private val bookMetadataRepository: BookMetadataRepository,
private val mediaRepository: MediaRepository
private val mediaRepository: MediaRepository,
private val referentialRepository: ReferentialRepository
) {
private val routeBase = "${servletContext.contextPath}$ROUTE_BASE"
@ -139,6 +143,13 @@ class OpdsController(
id = ID_READLISTS_ALL,
content = "Browse by read lists",
link = OpdsLinkFeedNavigation(OpdsLinkRel.SUBSECTION, "$routeBase$ROUTE_READLISTS_ALL")
),
OpdsEntryNavigation(
title = "All publishers",
updated = ZonedDateTime.now(),
id = ID_PUBLISHERS_ALL,
content = "Browse by publishers",
link = OpdsLinkFeedNavigation(OpdsLinkRel.SUBSECTION, "$routeBase$ROUTE_PUBLISHERS_ALL")
)
)
)
@ -158,11 +169,13 @@ class OpdsController(
@GetMapping(ROUTE_SERIES_ALL)
fun getAllSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
@RequestParam("search") searchTerm: String?
@RequestParam(name = "search", required = false) searchTerm: String?,
@RequestParam(name = "publisher", required = false) publishers: List<String>?
): OpdsFeed {
val seriesSearch = SeriesSearch(
libraryIds = principal.user.getAuthorizedLibraryIds(null),
searchTerm = searchTerm
searchTerm = searchTerm,
publishers = publishers
)
val entries = seriesRepository.findAll(seriesSearch)
@ -281,6 +294,35 @@ class OpdsController(
)
}
@GetMapping(ROUTE_PUBLISHERS_ALL)
fun getPublishers(
@AuthenticationPrincipal principal: KomgaPrincipal
): OpdsFeed {
val publishers =
if (principal.user.sharedAllLibraries) referentialRepository.findAllPublishers()
else referentialRepository.findAllPublishersByLibraries(principal.user.sharedLibrariesIds)
return OpdsFeedNavigation(
id = ID_PUBLISHERS_ALL,
title = "All publishers",
updated = ZonedDateTime.now(),
author = komgaAuthor,
links = listOf(
OpdsLinkFeedNavigation(OpdsLinkRel.SELF, "$routeBase$ROUTE_PUBLISHERS_ALL"),
linkStart
),
entries = publishers.map {
OpdsEntryNavigation(
title = it,
updated = ZonedDateTime.now(),
id = "publisher:$it",
content = "",
link = OpdsLinkFeedNavigation(OpdsLinkRel.SUBSECTION, "$routeBase$ROUTE_SERIES_ALL?publisher=$it")
)
}
)
}
@GetMapping("series/{id}")
fun getOneSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,