mirror of
https://github.com/gotson/komga.git
synced 2025-12-20 23:45:11 +01:00
parent
84ff250030
commit
93cec4e4e5
6 changed files with 55 additions and 1 deletions
11
komga-webui/package-lock.json
generated
11
komga-webui/package-lock.json
generated
|
|
@ -12,6 +12,7 @@
|
|||
"core-js": "^3.6.5",
|
||||
"date-fns": "^2.19.0",
|
||||
"jquery": "^3.5.1",
|
||||
"js-file-downloader": "^1.1.16",
|
||||
"language-tags": "^1.0.5",
|
||||
"lodash": "^4.17.19",
|
||||
"qs": "^6.9.4",
|
||||
|
|
@ -13480,6 +13481,11 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/js-file-downloader": {
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/js-file-downloader/-/js-file-downloader-1.1.16.tgz",
|
||||
"integrity": "sha512-vj4ZpHvFJI7J7SluyreHzaAVZDrPulRcwjMMOUve1KOEB4oxYAiQZXzgmu2lPbMTqKlf7U91MNZYRMTq7DsMfQ=="
|
||||
},
|
||||
"node_modules/js-message": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
|
||||
|
|
@ -32242,6 +32248,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"js-file-downloader": {
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/js-file-downloader/-/js-file-downloader-1.1.16.tgz",
|
||||
"integrity": "sha512-vj4ZpHvFJI7J7SluyreHzaAVZDrPulRcwjMMOUve1KOEB4oxYAiQZXzgmu2lPbMTqKlf7U91MNZYRMTq7DsMfQ=="
|
||||
},
|
||||
"js-message": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"core-js": "^3.6.5",
|
||||
"date-fns": "^2.19.0",
|
||||
"jquery": "^3.5.1",
|
||||
"js-file-downloader": "^1.1.16",
|
||||
"language-tags": "^1.0.5",
|
||||
"lodash": "^4.17.19",
|
||||
"qs": "^6.9.4",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
"cycling_page_layout": "Cycling Page Layout",
|
||||
"cycling_scale": "Cycling Scale",
|
||||
"cycling_side_padding": "Cycling Side Padding",
|
||||
"download_current_page": "Download current page",
|
||||
"end_of_book": "You've reached the end of the book.",
|
||||
"from_series_metadata": "from series metadata",
|
||||
"move_next": "Click or press \"Next\" again to move to the next book.",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,19 @@
|
|||
>
|
||||
<v-icon>mdi-cog</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-menu offset-y>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-btn icon v-on="on" @click.prevent="">
|
||||
<v-icon>mdi-dots-vertical</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item @click="downloadCurrentPage">
|
||||
<v-list-item-title>{{ $t('bookreader.download_current_page') }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-toolbar>
|
||||
</v-slide-y-transition>
|
||||
|
||||
|
|
@ -290,6 +303,7 @@ import {shortcutsSettingsContinuous} from '@/functions/shortcuts/continuous-read
|
|||
import {BookDto, PageDto, PageDtoWithUrl} from '@/types/komga-books'
|
||||
import {Context, ContextOrigin} from '@/types/context'
|
||||
import {SeriesDto} from "@/types/komga-series";
|
||||
import jsFileDownloader from "js-file-downloader"
|
||||
|
||||
const cookieFit = 'webreader.fit'
|
||||
const cookieContinuousReaderFit = 'webreader.continuousReaderFit'
|
||||
|
|
@ -484,6 +498,9 @@ export default Vue.extend({
|
|||
contextReadList (): boolean {
|
||||
return this.context.origin === ContextOrigin.READLIST
|
||||
},
|
||||
currentPage(): PageDtoWithUrl {
|
||||
return this.pages[this.page - 1]
|
||||
},
|
||||
|
||||
animations: {
|
||||
get: function (): boolean {
|
||||
|
|
@ -782,6 +799,12 @@ export default Vue.extend({
|
|||
async markProgress (page: number) {
|
||||
await this.$komgaBooks.updateReadProgress(this.bookId, { page: page })
|
||||
},
|
||||
downloadCurrentPage() {
|
||||
new jsFileDownloader({
|
||||
url: this.currentPage.url,
|
||||
withCredentials: true,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -36,4 +36,11 @@ class ContentDetector(
|
|||
|
||||
fun isImage(mediaType: String): Boolean =
|
||||
mediaType.startsWith("image/")
|
||||
|
||||
fun mediaTypeToExtension(mediaType: String): String? =
|
||||
try {
|
||||
tika.mimeRepository.forName(mediaType).extension
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import org.gotson.komga.domain.persistence.ReadListRepository
|
|||
import org.gotson.komga.domain.service.BookLifecycle
|
||||
import org.gotson.komga.infrastructure.image.ImageType
|
||||
import org.gotson.komga.infrastructure.jooq.UnpagedSorted
|
||||
import org.gotson.komga.infrastructure.mediacontainer.ContentDetector
|
||||
import org.gotson.komga.infrastructure.security.KomgaPrincipal
|
||||
import org.gotson.komga.infrastructure.swagger.PageableAsQueryParam
|
||||
import org.gotson.komga.infrastructure.swagger.PageableWithoutSortAsQueryParam
|
||||
|
|
@ -78,7 +79,8 @@ class BookController(
|
|||
private val bookMetadataRepository: BookMetadataRepository,
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val bookDtoRepository: BookDtoRepository,
|
||||
private val readListRepository: ReadListRepository
|
||||
private val readListRepository: ReadListRepository,
|
||||
private val contentDetector: ContentDetector,
|
||||
) {
|
||||
|
||||
@PageableAsQueryParam
|
||||
|
|
@ -342,6 +344,15 @@ class BookController(
|
|||
val pageContent = bookLifecycle.getBookPage(book, pageNum, convertFormat)
|
||||
|
||||
ResponseEntity.ok()
|
||||
.headers(
|
||||
HttpHeaders().apply {
|
||||
val extension = contentDetector.mediaTypeToExtension(pageContent.mediaType) ?: "jpeg"
|
||||
val imageFileName = "${book.name}-$pageNum$extension"
|
||||
contentDisposition = ContentDisposition.builder("inline")
|
||||
.filename(imageFileName)
|
||||
.build()
|
||||
}
|
||||
)
|
||||
.contentType(getMediaTypeOrDefault(pageContent.mediaType))
|
||||
.setNotModified(media)
|
||||
.body(pageContent.content)
|
||||
|
|
|
|||
Loading…
Reference in a new issue