feat(kobo): provide KEPUB format download url if book is kepub

This commit is contained in:
Gauthier Roebroeck 2024-09-19 15:49:15 +08:00
parent 12e243683f
commit 9e8a525554
4 changed files with 44 additions and 22 deletions

View file

@ -4,8 +4,6 @@ import com.fasterxml.jackson.databind.ObjectMapper
import org.gotson.komga.domain.model.MediaExtensionEpub
import org.gotson.komga.infrastructure.jooq.deserializeMediaExtension
import org.gotson.komga.interfaces.api.kobo.dto.ContributorDto
import org.gotson.komga.interfaces.api.kobo.dto.DownloadUrlDto
import org.gotson.komga.interfaces.api.kobo.dto.FormatDto
import org.gotson.komga.interfaces.api.kobo.dto.KoboBookMetadataDto
import org.gotson.komga.interfaces.api.kobo.dto.KoboSeriesDto
import org.gotson.komga.interfaces.api.kobo.dto.PublisherDto
@ -13,7 +11,6 @@ import org.gotson.komga.interfaces.api.kobo.persistence.KoboDtoRepository
import org.gotson.komga.jooq.main.Tables
import org.jooq.DSLContext
import org.springframework.stereotype.Component
import org.springframework.web.util.UriBuilder
import java.time.ZoneId
@Component
@ -29,7 +26,6 @@ class KoboDtoDao(
override fun findBookMetadataByIds(
bookIds: Collection<String>,
downloadUriBuilder: UriBuilder,
): Collection<KoboBookMetadataDto> {
val records =
dsl.select(
@ -77,19 +73,6 @@ class KoboDtoDao(
crossRevisionId = dr.bookId,
// if null or empty Kobo will not update it, force it to blank
description = dr.summary.ifEmpty { " " },
downloadUrls =
listOf(
DownloadUrlDto(
format = if (mediaExtension?.isFixedLayout == true) FormatDto.EPUB3FL else FormatDto.EPUB3,
size = br.fileSize,
url = downloadUriBuilder.build(dr.bookId).toURL().toString(),
),
DownloadUrlDto(
format = FormatDto.EPUB,
size = br.fileSize,
url = downloadUriBuilder.build(dr.bookId).toURL().toString(),
),
),
entitlementId = dr.bookId,
isbn = dr.isbn.ifBlank { null },
language = sr.language.take(2).ifBlank { "en" },
@ -109,6 +92,8 @@ class KoboDtoDao(
title = dr.title,
workId = dr.bookId,
isKepub = mr.epubIsKepub,
isPrePaginated = mediaExtension?.isFixedLayout == true,
fileSize = br.fileSize
)
}
}

View file

@ -40,6 +40,8 @@ import org.gotson.komga.interfaces.api.kobo.dto.ChangedProductMetadataDto
import org.gotson.komga.interfaces.api.kobo.dto.ChangedReadingStateDto
import org.gotson.komga.interfaces.api.kobo.dto.ChangedTagDto
import org.gotson.komga.interfaces.api.kobo.dto.DeletedTagDto
import org.gotson.komga.interfaces.api.kobo.dto.DownloadUrlDto
import org.gotson.komga.interfaces.api.kobo.dto.FormatDto
import org.gotson.komga.interfaces.api.kobo.dto.KoboBookMetadataDto
import org.gotson.komga.interfaces.api.kobo.dto.NewEntitlementDto
import org.gotson.komga.interfaces.api.kobo.dto.NewTagDto
@ -231,6 +233,7 @@ class KoboController(
logger.debug { "Library sync from SyncPoint $fromSyncPoint, to SyncPoint: $toSyncPoint" }
var shouldContinueSync: Boolean
val downloadUriBuilder = getDownloadUrlBuilder(authToken)
val syncResultKomga: Collection<SyncResultDto> =
if (fromSyncPoint != null) {
// find books added/changed/removed and map to DTO
@ -298,7 +301,8 @@ class KoboController(
logger.debug { "Library sync: ${booksAdded.numberOfElements} books added, ${booksChanged.numberOfElements} books changed, ${booksRemoved.numberOfElements} books removed, ${changedReadingState.numberOfElements} books with changed reading state, $readListsAdded readlists added, $readListsChanged readlists changed, $readListsRemoved removed" }
val metadata = koboDtoRepository.findBookMetadataByIds((booksAdded.content + booksChanged.content).map { it.bookId }, getDownloadUrlBuilder(authToken)).associateBy { it.entitlementId }
val metadata = koboDtoRepository.findBookMetadataByIds((booksAdded.content + booksChanged.content).map { it.bookId }).associateBy { it.entitlementId }
.mapValues { it.value.withDownloadUrls(downloadUriBuilder) }
val readProgress = readProgressRepository.findAllByBookIdsAndUserId((booksAdded.content + booksChanged.content + changedReadingState.content).map { it.bookId }, principal.user.id).associateBy { it.bookId }
val readListsBooks = syncPointRepository.findBookIdsByReadListIds(toSyncPoint.id, (readListsAdded.content + readListsChanged.content).map { it.readListId }).groupBy { it.readListId }
@ -389,7 +393,8 @@ class KoboController(
logger.debug { "Library sync: ${books.numberOfElements} books, ${readLists.numberOfElements} readlists" }
val metadata = koboDtoRepository.findBookMetadataByIds(books.content.map { it.bookId }, getDownloadUrlBuilder(authToken)).associateBy { it.entitlementId }
val metadata = koboDtoRepository.findBookMetadataByIds(books.content.map { it.bookId }).associateBy { it.entitlementId }
.mapValues { it.value.withDownloadUrls(downloadUriBuilder) }
val readProgress = readProgressRepository.findAllByBookIdsAndUserId(books.content.map { it.bookId }, principal.user.id).associateBy { it.bookId }
val readListsBooks = syncPointRepository.findBookIdsByReadListIds(toSyncPoint.id, readLists.content.map { it.readListId }).groupBy { it.readListId }
@ -462,7 +467,7 @@ class KoboController(
if (!bookRepository.existsById(bookId) && koboProxy.isEnabled())
koboProxy.proxyCurrentRequest()
else
ResponseEntity.ok(koboDtoRepository.findBookMetadataByIds(listOf(bookId), getDownloadUrlBuilder(authToken)))
ResponseEntity.ok(koboDtoRepository.findBookMetadataByIds(listOf(bookId)).map { it.withDownloadUrls(getDownloadUrlBuilder(authToken)) })
/**
* @return an array of [ReadingStateDto]
@ -621,6 +626,30 @@ class KoboController(
private fun getDownloadUrlBuilder(token: String): UriBuilder =
ServletUriComponentsBuilder.fromCurrentContextPath().pathSegment("kobo", token, "v1", "books", "{bookId}", "file", "epub")
private fun KoboBookMetadataDto.withDownloadUrls(downloadUriBuilder: UriBuilder) =
this.copy(
downloadUrls = buildList {
add(
DownloadUrlDto(
format = when {
isPrePaginated -> FormatDto.EPUB3FL
isKepub -> FormatDto.KEPUB
else -> FormatDto.EPUB3
},
size = fileSize,
url = downloadUriBuilder.build(entitlementId, false).toURL().toString(),
),
)
add(
DownloadUrlDto(
format = FormatDto.EPUB,
size = fileSize,
url = downloadUriBuilder.build(entitlementId, false).toURL().toString(),
),
)
},
)
/**
* Retrieve a SyncPoint by ID, and verifies it belongs to the same userId
*/
@ -644,6 +673,9 @@ class KoboController(
revisionId = bookId,
workId = bookId,
title = bookId,
isKepub = false,
isPrePaginated = false,
fileSize = 0,
)
private fun getEmptyReadProgressForBook(book: Book): ReadingStateDto {

View file

@ -1,5 +1,6 @@
package org.gotson.komga.interfaces.api.kobo.dto
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.annotation.JsonNaming
@ -40,4 +41,10 @@ data class KoboBookMetadataDto(
val subTitle: String? = null,
val title: String,
val workId: String,
@JsonIgnore
val isKepub: Boolean,
@JsonIgnore
val isPrePaginated: Boolean,
@JsonIgnore
val fileSize: Long,
)

View file

@ -1,11 +1,9 @@
package org.gotson.komga.interfaces.api.kobo.persistence
import org.gotson.komga.interfaces.api.kobo.dto.KoboBookMetadataDto
import org.springframework.web.util.UriBuilder
interface KoboDtoRepository {
fun findBookMetadataByIds(
bookIds: Collection<String>,
downloadUriBuilder: UriBuilder,
): Collection<KoboBookMetadataDto>
}