From 63a444bd81c1ac9696032c75fee3730a5c69fe9d Mon Sep 17 00:00:00 2001 From: Aria Moradi Date: Thu, 4 Feb 2021 03:42:30 +0330 Subject: [PATCH] calling HttpSource.imageRequest now --- .../kanade/tachiyomi/network/NetworkHelper.kt | 5 +- .../tachiyomi/network/OkHttpExtensions.kt | 17 ++-- .../tachiyomi/source/online/HttpSource.kt | 2 +- .../main/kotlin/ir/armor/tachidesk/Main.kt | 21 +++-- .../ir/armor/tachidesk/database/DBMangaer.kt | 2 + .../database/dataclass/ChapterDataClass.kt | 1 + .../tachidesk/database/table/ChapterTable.kt | 4 + .../database/table/ExtensionTable.kt | 4 + .../tachidesk/database/table/MangaTable.kt | 4 + .../tachidesk/database/table/PageTable.kt | 15 ++++ .../tachidesk/database/table/SourceTable.kt | 4 + .../kotlin/ir/armor/tachidesk/util/Chapter.kt | 38 ++++---- .../kotlin/ir/armor/tachidesk/util/File.kt | 24 ++++- .../kotlin/ir/armor/tachidesk/util/Manga.kt | 12 ++- .../ir/armor/tachidesk/util/MangaDexHelper.kt | 8 +- .../kotlin/ir/armor/tachidesk/util/Page.kt | 88 +++++++++++++++++++ webUI/react/src/screens/Reader.tsx | 38 ++++---- webUI/react/src/typings.d.ts | 1 + 18 files changed, 219 insertions(+), 69 deletions(-) create mode 100644 server/src/main/kotlin/ir/armor/tachidesk/database/table/PageTable.kt create mode 100644 server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt index df1e07e..cacc0a8 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -4,8 +4,10 @@ package eu.kanade.tachiyomi.network // import eu.kanade.tachiyomi.BuildConfig // import eu.kanade.tachiyomi.data.preference.PreferencesHelper import android.content.Context +import okhttp3.Dispatcher // import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient +import java.util.concurrent.Executors // import okhttp3.dnsoverhttps.DnsOverHttps // import okhttp3.logging.HttpLoggingInterceptor // import uy.kohesive.injekt.injectLazy @@ -26,7 +28,8 @@ class NetworkHelper(context: Context) { .cookieJar(cookieManager) // .cache(Cache(cacheDir, cacheSize)) .connectTimeout(30, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) + .readTimeout(5, TimeUnit.MINUTES) + .writeTimeout(5, TimeUnit.MINUTES) // .dispatcher(Dispatcher(Executors.newFixedThreadPool(1))) // .addInterceptor(UserAgentInterceptor()) diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index ec921eb..1e2c6d4 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -80,17 +80,18 @@ fun Call.asObservable(): Observable { // } fun Call.asObservableSuccess(): Observable { - return asObservable().doOnNext { response -> - if (!response.isSuccessful) { - response.close() - throw Exception("HTTP error ${response.code}") - } - } + return asObservable() +// .doOnNext { response -> +// if (!response.isSuccessful) { +// response.close() +// throw Exception("HTTP error ${response.code}") +// } +// } } // fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call { // val progressClient = newBuilder() -// .cache(null) +// .cache(nasObservableSuccessull) // .addNetworkInterceptor { chain -> // val originalResponse = chain.proceed(chain.request()) // originalResponse.newBuilder() @@ -104,7 +105,7 @@ fun Call.asObservableSuccess(): Observable { fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call { val progressClient = newBuilder() - .cache(null) +// .cache(null) // .addNetworkInterceptor { chain -> // val originalResponse = chain.proceed(chain.request()) // originalResponse.newBuilder() diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt index 7379989..9263b13 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt @@ -311,7 +311,7 @@ abstract class HttpSource : CatalogueSource { * * @param page the chapter whose page list has to be fetched */ - protected open fun imageRequest(page: Page): Request { + open fun imageRequest(page: Page): Request { return GET(page.imageUrl!!, headers) } diff --git a/server/src/main/kotlin/ir/armor/tachidesk/Main.kt b/server/src/main/kotlin/ir/armor/tachidesk/Main.kt index 30260c9..663f4b0 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/Main.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/Main.kt @@ -7,12 +7,12 @@ package ir.armor.tachidesk import eu.kanade.tachiyomi.App import io.javalin.Javalin import ir.armor.tachidesk.util.applicationSetup +import ir.armor.tachidesk.util.getChapter import ir.armor.tachidesk.util.getChapterList import ir.armor.tachidesk.util.getExtensionList import ir.armor.tachidesk.util.getManga import ir.armor.tachidesk.util.getMangaList -// import ir.armor.tachidesk.util.getMangaUpdateQueueThread -import ir.armor.tachidesk.util.getPages +import ir.armor.tachidesk.util.getPageImage import ir.armor.tachidesk.util.getSource import ir.armor.tachidesk.util.getSourceList import ir.armor.tachidesk.util.getThumbnail @@ -119,6 +119,14 @@ class Main { ctx.json(getManga(mangaId)) } + app.get("api/v1/manga/:mangaId/thumbnail") { ctx -> + val mangaId = ctx.pathParam("mangaId").toInt() + val result = getThumbnail(mangaId) + + ctx.result(result.first) + ctx.header("content-type", result.second) + } + app.get("/api/v1/manga/:mangaId/chapters") { ctx -> val mangaId = ctx.pathParam("mangaId").toInt() ctx.json(getChapterList(mangaId)) @@ -127,13 +135,14 @@ class Main { app.get("/api/v1/manga/:mangaId/chapter/:chapterId") { ctx -> val chapterId = ctx.pathParam("chapterId").toInt() val mangaId = ctx.pathParam("mangaId").toInt() - ctx.json(getPages(chapterId, mangaId)) + ctx.json(getChapter(chapterId, mangaId)) } - app.get("api/v1/manga/:mangaId/thumbnail") { ctx -> + app.get("/api/v1/manga/:mangaId/chapter/:chapterId/page/:index") { ctx -> + val chapterId = ctx.pathParam("chapterId").toInt() val mangaId = ctx.pathParam("mangaId").toInt() - println("got request for: $mangaId") - val result = getThumbnail(mangaId) + val index = ctx.pathParam("index").toInt() + val result = getPageImage(mangaId, chapterId, index) ctx.result(result.first) ctx.header("content-type", result.second) diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt index 14c35e1..169a55b 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/DBMangaer.kt @@ -8,6 +8,7 @@ import ir.armor.tachidesk.Config import ir.armor.tachidesk.database.table.ChapterTable import ir.armor.tachidesk.database.table.ExtensionsTable import ir.armor.tachidesk.database.table.MangaTable +import ir.armor.tachidesk.database.table.PageTable import ir.armor.tachidesk.database.table.SourceTable import org.jetbrains.exposed.sql.Database import org.jetbrains.exposed.sql.SchemaUtils @@ -30,5 +31,6 @@ fun makeDataBaseTables() { SchemaUtils.create(SourceTable) SchemaUtils.create(MangaTable) SchemaUtils.create(ChapterTable) + SchemaUtils.create(PageTable) } } diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/ChapterDataClass.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/ChapterDataClass.kt index c3ca046..0a64bf5 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/ChapterDataClass.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/dataclass/ChapterDataClass.kt @@ -12,4 +12,5 @@ data class ChapterDataClass( val chapter_number: Float, val scanlator: String?, val mangaId: Int, + val pageCount: Int? = null, ) diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/table/ChapterTable.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/table/ChapterTable.kt index d0599c0..111cccd 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/table/ChapterTable.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/table/ChapterTable.kt @@ -1,5 +1,9 @@ package ir.armor.tachidesk.database.table +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + import org.jetbrains.exposed.dao.id.IntIdTable object ChapterTable : IntIdTable() { diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/table/ExtensionTable.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/table/ExtensionTable.kt index 1c32152..7cbdbc4 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/table/ExtensionTable.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/table/ExtensionTable.kt @@ -1,5 +1,9 @@ package ir.armor.tachidesk.database.table +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + import org.jetbrains.exposed.dao.id.IntIdTable object ExtensionsTable : IntIdTable() { diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/table/MangaTable.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/table/MangaTable.kt index 40f261f..cd8d6bb 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/table/MangaTable.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/table/MangaTable.kt @@ -1,5 +1,9 @@ package ir.armor.tachidesk.database.table +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + import eu.kanade.tachiyomi.source.model.SManga import org.jetbrains.exposed.dao.id.IntIdTable diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/table/PageTable.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/table/PageTable.kt new file mode 100644 index 0000000..35ab8a0 --- /dev/null +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/table/PageTable.kt @@ -0,0 +1,15 @@ +package ir.armor.tachidesk.database.table + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import org.jetbrains.exposed.dao.id.IntIdTable + +object PageTable : IntIdTable() { + val index = integer("index") + val url = varchar("url", 2048) + val imageUrl = varchar("imageUrl", 2048).nullable() + + val chapter = reference("chapter", ChapterTable) +} diff --git a/server/src/main/kotlin/ir/armor/tachidesk/database/table/SourceTable.kt b/server/src/main/kotlin/ir/armor/tachidesk/database/table/SourceTable.kt index 125a617..d664c4d 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/database/table/SourceTable.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/database/table/SourceTable.kt @@ -1,5 +1,9 @@ package ir.armor.tachidesk.database.table +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + import org.jetbrains.exposed.dao.id.IdTable object SourceTable : IdTable() { diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Chapter.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Chapter.kt index 11b5016..a82ccc5 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/Chapter.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Chapter.kt @@ -4,14 +4,14 @@ package ir.armor.tachidesk.util * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.source.online.HttpSource import ir.armor.tachidesk.database.dataclass.ChapterDataClass -import ir.armor.tachidesk.database.dataclass.PageDataClass import ir.armor.tachidesk.database.table.ChapterTable import ir.armor.tachidesk.database.table.MangaTable +import ir.armor.tachidesk.database.table.PageTable +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.insert import org.jetbrains.exposed.sql.insertAndGetId import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.transactions.transaction @@ -57,14 +57,14 @@ fun getChapterList(mangaId: Int): List { } } -fun getPages(chapterId: Int, mangaId: Int): Pair> { +fun getChapter(chapterId: Int, mangaId: Int): ChapterDataClass { return transaction { val chapterEntry = ChapterTable.select { ChapterTable.id eq chapterId }.firstOrNull()!! assert(mangaId == chapterEntry[ChapterTable.manga].value) // sanity check val mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value) - val pagesList = source.fetchPageList( + val pageList = source.fetchPageList( SChapter.create().apply { url = chapterEntry[ChapterTable.url] name = chapterEntry[ChapterTable.name] @@ -78,22 +78,24 @@ fun getPages(chapterId: Int, mangaId: Int): Pair + val pageEntry = transaction { PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq page.index) }.firstOrNull() } + if (pageEntry == null) { + transaction { + PageTable.insert { + it[index] = page.index + it[url] = page.url + it[imageUrl] = page.imageUrl + it[this.chapter] = chapterId + } + } + } } - return@transaction Pair(chapter, pages) + return@transaction chapter } } - -fun getTrueImageUrl(page: Page, source: HttpSource): String { - return if (page.imageUrl == null) { - source.fetchImageUrl(page).toBlocking().first()!! - } else page.imageUrl!! -} diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/File.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/File.kt index 0be7d68..41b7692 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/File.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/File.kt @@ -1,15 +1,23 @@ package ir.armor.tachidesk.util +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import okio.BufferedSource +import okio.buffer +import okio.sink import java.io.BufferedInputStream import java.io.File import java.io.FileInputStream import java.io.InputStream +import java.io.OutputStream import java.nio.file.Files import java.nio.file.Paths fun writeStream(fileStream: InputStream, path: String) { Files.newOutputStream(Paths.get(path)).use { os -> - val buffer = ByteArray(1024) + val buffer = ByteArray(128 * 1024) var len: Int while (fileStream.read(buffer).also { len = it } > 0) { os.write(buffer, 0, len) @@ -28,3 +36,17 @@ fun findFileNameStartingWith(directoryPath: String, fileName: String): String? { } return null } + +/** + * Saves the given source to an output stream and closes both resources. + * + * @param stream the stream where the source is copied. + */ +fun BufferedSource.saveTo(stream: OutputStream) { + use { input -> + stream.sink().buffer().use { + it.writeAll(input) + it.flush() + } + } +} diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt index 274260c..e4e0a08 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Manga.kt @@ -85,14 +85,14 @@ fun getManga(mangaId: Int, proxyThumbnail: Boolean = true): MangaDataClass { fun getThumbnail(mangaId: Int): Pair { val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! } - var filePath = Config.thumbnailsRoot + "/$mangaId" + var filePath = "${Config.thumbnailsRoot}/$mangaId." val potentialCache = findFileNameStartingWith(Config.thumbnailsRoot, mangaId.toString()) if (potentialCache != null) { println("using cached thumbnail file") return Pair( pathToInputStream(potentialCache), - "image/${potentialCache.substringAfter("$mangaId.")}" + "image/${potentialCache.substringAfter(filePath)}" ) } @@ -108,11 +108,9 @@ fun getThumbnail(mangaId: Int): Pair { GET(thumbnailUrl, source.headers) ).execute() - println(response.code) - if (response.code == 200) { val contentType = response.headers["content-type"]!! - filePath += "." + contentType.substringAfter("image/") + filePath += contentType.substringAfter("image/") writeStream(response.body!!.byteStream(), filePath) @@ -126,9 +124,9 @@ fun getThumbnail(mangaId: Int): Pair { } fun getMangaDir(mangaId: Int): String { - val mangaEntry = MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! + val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! } val sourceId = mangaEntry[MangaTable.sourceReference].value - val sourceEntry = SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()!! + val sourceEntry = transaction { SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()!! } val mangaTitle = mangaEntry[MangaTable.title] val sourceName = sourceEntry[SourceTable.name] diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/MangaDexHelper.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/MangaDexHelper.kt index 1cdb230..f8115ec 100644 --- a/server/src/main/kotlin/ir/armor/tachidesk/util/MangaDexHelper.kt +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/MangaDexHelper.kt @@ -1,15 +1,15 @@ package ir.armor.tachidesk.util +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.online.HttpSource import okhttp3.FormBody import okhttp3.OkHttpClient import java.net.URLEncoder -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - class MangaDexHelper(private val mangaDexSource: HttpSource) { private fun clientBuilder(): OkHttpClient = clientBuilder(0) diff --git a/server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt b/server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt new file mode 100644 index 0000000..0a6e1b8 --- /dev/null +++ b/server/src/main/kotlin/ir/armor/tachidesk/util/Page.kt @@ -0,0 +1,88 @@ +package ir.armor.tachidesk.util + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.newCallWithProgress +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.online.HttpSource +import ir.armor.tachidesk.database.table.ChapterTable +import ir.armor.tachidesk.database.table.MangaTable +import ir.armor.tachidesk.database.table.PageTable +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.select +import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.sql.update +import java.io.File +import java.io.InputStream +import java.nio.file.Files +import java.nio.file.Paths + +fun getTrueImageUrl(page: Page, source: HttpSource): String { + if (page.imageUrl == null) { + page.imageUrl = source.fetchImageUrl(page).toBlocking().first()!! + } + return page.imageUrl!! +} + +fun getPageImage(mangaId: Int, chapterId: Int, index: Int): Pair { + val mangaEntry = transaction { MangaTable.select { MangaTable.id eq mangaId }.firstOrNull()!! } + val source = getHttpSource(mangaEntry[MangaTable.sourceReference].value) + val chapterEntry = transaction { ChapterTable.select { ChapterTable.id eq chapterId }.firstOrNull()!! } + val pageEntry = transaction { PageTable.select { (PageTable.chapter eq chapterId) and (PageTable.index eq index) }.firstOrNull()!! } + + val tachiPage = Page( + pageEntry[PageTable.index], + pageEntry[PageTable.url], + pageEntry[PageTable.imageUrl] + ) + + if (pageEntry[PageTable.imageUrl] == null) { + transaction { + PageTable.update({ (PageTable.chapter eq chapterId) and (PageTable.index eq index) }) { + it[imageUrl] = getTrueImageUrl(tachiPage, source) + } + } + } + + val saveDir = getMangaDir(mangaId) + "/" + chapterEntry[ChapterTable.chapter_number] + File(saveDir).mkdirs() + var filePath = "$saveDir/$index." + + val potentialCache = findFileNameStartingWith(saveDir, index.toString()) + if (potentialCache != null) { + println("using cached page file for $index") + return Pair( + pathToInputStream(potentialCache), + "image/${potentialCache.substringAfter("$filePath")}" + ) + } + + // Note: line bellow somehow closes the okhttp reqest! +// val response = source.fetchImage(tachiPage).toBlocking().first() + // Note: also this which is the same +// val response = source.client.newCallWithProgress(source.imageRequest(tachiPage), tachiPage) +// .asObservableSuccess().toBlocking().first() + val response = source.client.newCall(source.imageRequest(tachiPage)).execute() + + if (response.code == 200) { + val contentType = response.headers["content-type"]!! + filePath += contentType.substringAfter("image/") + + Files.newOutputStream(Paths.get(filePath)).use { os -> + + response.body!!.source().saveTo(os) + } + +// writeStream(response.body!!.source(), filePath) + + return Pair( + pathToInputStream(filePath), + contentType + ) + } else { + throw Exception("request error! ${response.code}") + } +} diff --git a/webUI/react/src/screens/Reader.tsx b/webUI/react/src/screens/Reader.tsx index c8f6535..357b292 100644 --- a/webUI/react/src/screens/Reader.tsx +++ b/webUI/react/src/screens/Reader.tsx @@ -14,44 +14,36 @@ const style = { backgroundColor: '#343a40', } as React.CSSProperties; -interface IPage { - index: number - imageUrl: string -} - -interface IData { - first: IChapter - second: IPage[] -} +const range = (n:number) => Array.from({ length: n }, (value, key) => key); export default function Reader() { const { setTitle } = useContext(NavBarTitle); - const [pages, setPages] = useState([]); + const [pageCount, setPageCount] = useState(-1); const { chapterId, mangaId } = useParams<{chapterId: string, mangaId: string}>(); useEffect(() => { fetch(`http://127.0.0.1:4567/api/v1/manga/${mangaId}/chapter/${chapterId}`) .then((response) => response.json()) - .then((data:IData) => { - setTitle(data.first.name); - setPages(data.second); + .then((data:IChapter) => { + setTitle(data.name); + setPageCount(data.pageCount); }); }, []); - pages.sort((a, b) => (a.index - b.index)); - - let mapped; - if (pages.length === 0) { - mapped =

wait

; - } else { - mapped = pages.map(({ imageUrl }) => ( -
- f + if (pageCount === -1) { + return ( +
+

wait

- )); + ); } + const mapped = range(pageCount).map((index) => ( +
+ f +
+ )); return (
{mapped} diff --git a/webUI/react/src/typings.d.ts b/webUI/react/src/typings.d.ts index c4b209d..11c6cec 100644 --- a/webUI/react/src/typings.d.ts +++ b/webUI/react/src/typings.d.ts @@ -34,4 +34,5 @@ interface IChapter { chapter_number: number scanlator: String mangaId: number + pageCount: number }