feat(opds): browse by collection

This commit is contained in:
Gauthier Roebroeck 2020-06-25 12:26:51 +08:00
parent ca91af7792
commit 15f9c8257e

View file

@ -7,12 +7,14 @@ import org.gotson.komga.domain.model.BookSearch
import org.gotson.komga.domain.model.Library
import org.gotson.komga.domain.model.Media
import org.gotson.komga.domain.model.Series
import org.gotson.komga.domain.model.SeriesCollection
import org.gotson.komga.domain.model.SeriesMetadata
import org.gotson.komga.domain.model.SeriesSearch
import org.gotson.komga.domain.persistence.BookMetadataRepository
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.SeriesCollectionRepository
import org.gotson.komga.domain.persistence.SeriesMetadataRepository
import org.gotson.komga.domain.persistence.SeriesRepository
import org.gotson.komga.infrastructure.security.KomgaPrincipal
@ -54,17 +56,20 @@ private const val ROUTE_CATALOG = "catalog"
private const val ROUTE_SERIES_ALL = "series"
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_SEARCH = "search"
private const val ID_SERIES_ALL = "allSeries"
private const val ID_SERIES_LATEST = "latestSeries"
private const val ID_LIBRARIES_ALL = "allLibraries"
private const val ID_COLLECTIONS_ALL = "allCollections"
@RestController
@RequestMapping(value = [ROUTE_BASE], produces = [MediaType.APPLICATION_ATOM_XML_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE])
class OpdsController(
servletContext: ServletContext,
private val libraryRepository: LibraryRepository,
private val collectionRepository: SeriesCollectionRepository,
private val seriesRepository: SeriesRepository,
private val seriesMetadataRepository: SeriesMetadataRepository,
private val bookRepository: BookRepository,
@ -113,6 +118,13 @@ class OpdsController(
id = ID_LIBRARIES_ALL,
content = "Browse by library",
link = OpdsLinkFeedNavigation(OpdsLinkRel.SUBSECTION, "$routeBase$ROUTE_LIBRARIES_ALL")
),
OpdsEntryNavigation(
title = "All collections",
updated = ZonedDateTime.now(),
id = ID_COLLECTIONS_ALL,
content = "Browse by collection",
link = OpdsLinkFeedNavigation(OpdsLinkRel.SUBSECTION, "$routeBase$ROUTE_COLLECTIONS_ALL")
)
)
)
@ -207,6 +219,29 @@ class OpdsController(
)
}
@GetMapping(ROUTE_COLLECTIONS_ALL)
fun getCollections(
@AuthenticationPrincipal principal: KomgaPrincipal
): OpdsFeed {
val collections =
if (principal.user.sharedAllLibraries) {
collectionRepository.findAll()
} else {
collectionRepository.findAllByLibraries(principal.user.sharedLibrariesIds, principal.user.sharedLibrariesIds)
}
return OpdsFeedNavigation(
id = ID_COLLECTIONS_ALL,
title = "All collections",
updated = ZonedDateTime.now(),
author = komgaAuthor,
links = listOf(
OpdsLinkFeedNavigation(OpdsLinkRel.SELF, "$routeBase$ROUTE_COLLECTIONS_ALL"),
linkStart
),
entries = collections.map { it.toOpdsEntry() }
)
}
@GetMapping("series/{id}")
fun getOneSeries(
@AuthenticationPrincipal principal: KomgaPrincipal,
@ -268,6 +303,35 @@ class OpdsController(
)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
@GetMapping("collections/{id}")
fun getOneCollection(
@AuthenticationPrincipal principal: KomgaPrincipal,
@PathVariable id: Long
): OpdsFeed {
return collectionRepository.findByIdOrNull(id, principal.user.getAuthorizedLibraryIds(null))?.let { collection ->
val series = collection.seriesIds.mapNotNull { seriesRepository.findByIdOrNull(it) }
.map { SeriesWithInfo(it, seriesMetadataRepository.findById(it.id)) }
val sorted =
if (!collection.ordered) series.sortedBy { it.metadata.titleSort }
else series
val entries = sorted.map { it.toOpdsEntry() }
OpdsFeedNavigation(
id = collection.id.toString(),
title = collection.name,
updated = collection.lastModifiedDate.atZone(ZoneId.systemDefault()) ?: ZonedDateTime.now(),
author = komgaAuthor,
links = listOf(
OpdsLinkFeedNavigation(OpdsLinkRel.SELF, "${routeBase}collections/$id"),
linkStart
),
entries = entries
)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
private fun SeriesWithInfo.toOpdsEntry(): OpdsEntryNavigation =
OpdsEntryNavigation(
@ -317,6 +381,16 @@ class OpdsController(
)
}
private fun SeriesCollection.toOpdsEntry(): OpdsEntryNavigation {
return OpdsEntryNavigation(
title = name,
updated = lastModifiedDate.atZone(ZoneId.systemDefault()) ?: ZonedDateTime.now(),
id = id.toString(),
content = "",
link = OpdsLinkFeedNavigation(OpdsLinkRel.SUBSECTION, "${routeBase}collections/$id")
)
}
private fun shouldPrependBookNumbers(userAgent: String) =
userAgent.contains("chunky", ignoreCase = true)