diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesSearch.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesSearch.kt index 842ba1e93..b3d44d84b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesSearch.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/SeriesSearch.kt @@ -4,7 +4,8 @@ open class SeriesSearch( val libraryIds: Collection? = null, val collectionIds: Collection? = null, val searchTerm: String? = null, - val metadataStatus: Collection? = null + val metadataStatus: Collection? = null, + val publishers: Collection? = null ) class SeriesSearchWithReadProgress( @@ -12,7 +13,7 @@ class SeriesSearchWithReadProgress( collectionIds: Collection? = null, searchTerm: String? = null, metadataStatus: Collection? = null, - val publishers: Collection? = null, + publishers: Collection? = null, val languages: Collection? = null, val genres: Collection? = null, val tags: Collection? = null, @@ -22,5 +23,6 @@ class SeriesSearchWithReadProgress( libraryIds = libraryIds, collectionIds = collectionIds, searchTerm = searchTerm, - metadataStatus = metadataStatus + metadataStatus = metadataStatus, + publishers = publishers ) diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt b/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt index f37f52b7e..3121fbaed 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/persistence/ReferentialRepository.kt @@ -18,6 +18,7 @@ interface ReferentialRepository { fun findAllPublishers(): Set fun findAllPublishersByLibrary(libraryId: String): Set + fun findAllPublishersByLibraries(libraryIds: Set): Set fun findAllPublishersByCollection(collectionId: String): Set fun findAllAgeRatings(): Set diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReferentialDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReferentialDao.kt index 55b44b8ad..ed6929ff2 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReferentialDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/ReferentialDao.kt @@ -125,6 +125,15 @@ class ReferentialDao( .orderBy(sd.PUBLISHER) .fetchSet(sd.PUBLISHER) + override fun findAllPublishersByLibraries(libraryIds: Set): Set = + 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 = dsl.selectDistinct(sd.PUBLISHER) .from(sd) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt index b217ac07e..aa9755598 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/SeriesDao.kt @@ -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 } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/opds/OpdsController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/opds/OpdsController.kt index a84881bbc..aca0aba0a 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/opds/OpdsController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/opds/OpdsController.kt @@ -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? ): 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,