first version of the web reader

This commit is contained in:
Gauthier Roebroeck 2019-12-24 16:05:19 +08:00
parent 2d41c5387d
commit 5628babcc5
4 changed files with 133 additions and 1 deletions

View file

@ -38,8 +38,16 @@
<v-icon>mdi-file-download</v-icon>
</v-btn>
</v-col>
<v-col cols="1">
<v-btn icon
title="Read book"
class="pb-1"
:to="{name: 'read-book', params: { bookId: bookId}}">
<v-icon>mdi-book-open-page-variant</v-icon>
</v-btn>
</v-col>
<v-col>
<v-icon class="mr-2 pb-1">mdi-book-open-page-variant</v-icon>
<v-icon class="mr-2 pb-1">mdi-book-open</v-icon>
<span class="body-2">{{ book.metadata.pagesCount }} pages</span>
</v-col>
</v-row>

View file

@ -93,6 +93,12 @@ const router = new Router({
name: 'login',
component: () => import(/* webpackChunkName: "login" */ './views/Login.vue')
},
{
path: '/book/:bookId/read',
name: 'read-book',
component: () => import(/* webpackChunkName: "read-book" */ './views/BookReader.vue'),
props: (route) => ({ bookId: Number(route.params.bookId) })
},
{
path: '*',
name: 'notfound',

View file

@ -16,6 +16,12 @@ interface BookMetadataDto {
pagesCount: number
}
interface PageDto {
number: number,
fileName: string,
mediaType: string
}
interface BookFormat {
type: string,
color: string

View file

@ -0,0 +1,112 @@
<template>
<div v-if="pages.length > 0">
<v-btn icon @click="closeBook">
<v-icon>mdi-close</v-icon>
</v-btn>
<v-btn icon @click="prev" :disabled="!canPrev">
<v-icon>mdi-chevron-left</v-icon>
</v-btn>
<v-btn icon @click="next" :disabled="!canNext">
<v-icon>mdi-chevron-right</v-icon>
</v-btn>
<transition name="slide-x-transition">
<v-img :src="getPageUrl(currentPage)"
:key="getPageUrl(currentPage)"
contain
:max-height="$vuetify.breakpoint.height"
:max-width="$vuetify.breakpoint.width"
/>
</transition>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'BookReader',
data: () => {
return {
baseURL: process.env.VUE_APP_KOMGA_API_URL ? process.env.VUE_APP_KOMGA_API_URL : window.location.origin,
book: {} as BookDto,
pages: [] as PageDto[],
supportedMediaTypes: ['image/jpeg', 'image/png', 'image/webp', 'image/gif'],
convertTo: 'png',
currentPage: 1
}
},
async created () {
this.book = await this.$komgaBooks.getBook(this.bookId)
this.pages = await this.$komgaBooks.getBookPages(this.bookId)
},
props: {
bookId: {
type: Number,
required: true
}
},
async beforeRouteUpdate (to, from, next) {
if (to.params.bookId !== from.params.bookId) {
this.book = await this.$komgaBooks.getBook(Number(to.params.bookId))
}
next()
},
watch: {
currentPage (val) {
this.updateRoute()
this.preloadNext()
}
},
computed: {
canPrev (): boolean {
return this.currentPage > 1
},
canNext (): boolean {
return this.currentPage < this.book.metadata.pagesCount
}
},
methods: {
getPageUrl (pageNum: number): string {
const page = this.pages[pageNum - 1]
let url = `${this.baseURL}/api/v1/books/${this.bookId}/pages/${page.number}`
if (!this.supportedMediaTypes.includes(page.mediaType)) {
url += `?convert=${this.convertTo}`
}
return url
},
prev () {
if (this.canPrev) {
this.currentPage -= 1
}
},
next () {
if (this.canNext) {
this.currentPage += 1
}
},
preloadNext () {
if (this.canNext) {
const img = new Image()
img.src = this.getPageUrl(this.currentPage + 1)
}
},
updateRoute () {
this.$router.replace({
name: this.$route.name,
params: { bookId: this.$route.params.bookId },
query: { page: this.currentPage.toString() }
})
},
closeBook () {
this.$router.back()
}
}
})
</script>
<style scoped>
</style>