diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt index 974c779af9..fb42c9b084 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookLifecycle.kt @@ -459,15 +459,18 @@ class BookLifecycle( // match progression with positions val matchingPositions = extension.positions.filter { it.href == href } val matchedPosition = - matchingPositions.firstOrNull { it.locations!!.progression == newProgression.locator.locations!!.progression } - ?: run { - // no exact match - val before = matchingPositions.filter { it.locations!!.progression!! < newProgression.locator.locations!!.progression!! }.maxByOrNull { it.locations!!.position!! } - val after = matchingPositions.filter { it.locations!!.progression!! > newProgression.locator.locations!!.progression!! }.minByOrNull { it.locations!!.position!! } - if (before == null || after == null || before.locations!!.position!! > after.locations!!.position!!) - throw IllegalArgumentException("Invalid progression") - before - } + if (extension.isFixedLayout && matchingPositions.size == 1) + matchingPositions.first() + else + matchingPositions.firstOrNull { it.locations!!.progression == newProgression.locator.locations!!.progression } + ?: run { + // no exact match + val before = matchingPositions.filter { it.locations!!.progression!! < newProgression.locator.locations!!.progression!! }.maxByOrNull { it.locations!!.position!! } + val after = matchingPositions.filter { it.locations!!.progression!! > newProgression.locator.locations!!.progression!! }.minByOrNull { it.locations!!.position!! } + if (before == null || after == null || before.locations!!.position!! > after.locations!!.position!!) + throw IllegalArgumentException("Invalid progression") + before + } val totalProgression = matchedPosition.locations?.totalProgression ReadProgress( diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt index 1287cf85f6..62627e7bb4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt @@ -35,6 +35,7 @@ import org.gotson.komga.interfaces.api.kobo.dto.ChangedEntitlementDto 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.ReadingStateDto +import org.gotson.komga.interfaces.api.kobo.dto.ReadingStateStateUpdateDto import org.gotson.komga.interfaces.api.kobo.dto.ReadingStateUpdateResultDto import org.gotson.komga.interfaces.api.kobo.dto.RequestResultDto import org.gotson.komga.interfaces.api.kobo.dto.ResourcesDto @@ -382,17 +383,18 @@ class KoboController( fun updateState( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - @RequestBody koboUpdate: ReadingStateDto, + @RequestBody body: ReadingStateStateUpdateDto, @RequestHeader(name = X_KOBO_DEVICEID, required = false) koboDeviceId: String = "unknown", ): ResponseEntity<*> { val book = bookRepository.findByIdOrNull(bookId) ?: if (koboProxy.isEnabled()) - return koboProxy.proxyCurrentRequest(koboUpdate) + return koboProxy.proxyCurrentRequest(body) else throw ResponseStatusException(HttpStatus.NOT_FOUND) - if (koboUpdate.currentBookmark.location == null) throw ResponseStatusException(HttpStatus.BAD_REQUEST) + val koboUpdate = body.readingStates.firstOrNull() ?: throw ResponseStatusException(HttpStatus.BAD_REQUEST) + if (koboUpdate.currentBookmark.location == null || koboUpdate.currentBookmark.contentSourceProgressPercent == null) throw ResponseStatusException(HttpStatus.BAD_REQUEST) // convert the Kobo update request to an R2Progression val r2Progression = @@ -411,7 +413,7 @@ class KoboController( type = "application/xhtml+xml", locations = R2Locator.Location( - progression = koboUpdate.currentBookmark.progressPercent, + progression = koboUpdate.currentBookmark.contentSourceProgressPercent / 100, ), ), ) @@ -433,6 +435,7 @@ class KoboController( ), ) } catch (e: Exception) { + logger.error(e) { "Could not update progression" } RequestResultDto( requestResult = ResultDto.FAILURE, updateResults = diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt index f2f0dd5c2d..29bd507425 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateDto.kt @@ -8,14 +8,14 @@ import java.time.ZonedDateTime @JsonNaming(PropertyNamingStrategies.UpperCamelCaseStrategy::class) data class ReadingStateDto( - val created: ZonedDateTime, + val created: ZonedDateTime? = null, val currentBookmark: BookmarkDto, val entitlementId: String, val lastModified: ZonedDateTime, /** * From CW: apparently always equals to lastModified */ - val priorityTimestamp: ZonedDateTime, + val priorityTimestamp: ZonedDateTime? = null, val statistics: StatisticsDto, val statusInfo: StatusInfoDto, ) @@ -29,8 +29,8 @@ fun ReadProgress.toDto() = currentBookmark = BookmarkDto( lastModified = this.lastModifiedDate.toUTCZoned(), - progressPercent = this.locator?.locations?.totalProgression, - contentSourceProgressPercent = this.locator?.locations?.progression, + progressPercent = this.locator?.locations?.totalProgression?.times(100), + contentSourceProgressPercent = this.locator?.locations?.progression?.times(100), location = this.locator?.let { LocationDto(source = it.href) }, ), statistics = diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateStateUpdateDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateStateUpdateDto.kt new file mode 100644 index 0000000000..dd9150e78f --- /dev/null +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/ReadingStateStateUpdateDto.kt @@ -0,0 +1,9 @@ +package org.gotson.komga.interfaces.api.kobo.dto + +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming + +@JsonNaming(PropertyNamingStrategies.UpperCamelCaseStrategy::class) +data class ReadingStateStateUpdateDto( + val readingStates: Collection = emptyList(), +) diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusDto.kt index 89025b132e..dabedde8c5 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusDto.kt @@ -8,6 +8,10 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming enum class StatusDto { @JsonProperty("ReadyToRead") READY_TO_READ, + + @JsonProperty("Finished") FINISHED, + + @JsonProperty("Reading") READING, } diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusInfoDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusInfoDto.kt index c8d8732f02..1a784555ab 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusInfoDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/dto/StatusInfoDto.kt @@ -10,7 +10,7 @@ import java.time.ZonedDateTime data class StatusInfoDto( val lastModified: ZonedDateTime, val status: StatusDto, - val timesStartedReading: Int, + val timesStartedReading: Int? = null, val lastTimeFinished: ZonedDateTime? = null, val lastTimeStartedReading: ZonedDateTime? = null, )