Add viewer_data download

This commit is contained in:
yenru0 committed 2026-03-07 23:58:53 +09:00
1 parent 58f7a22aef
commit f602523d02
2 files changed
+37 -15

No files matched your search

@@ -11,12 +11,18 @@ import io.ktor.client.request.request
import io.ktor.client.request.setBody
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpHeaders
import io.ktor.http.contentLength
import io.ktor.http.isSuccess
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.delay
import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone
import kotlinx.datetime.number
import kotlinx.datetime.todayIn
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlin.time.Clock
class NpiaDownloader {
@@ -31,12 +37,13 @@ class NpiaDownloader {
}
object Endpoints {
private const val BASE_URL = "https://novelpia.com"
const val BASE_URL = "https://novelpia.com"
const val PROC_URL = "$BASE_URL/proc"
const val LOGIN_URL = "$PROC_URL/login"
const val LOGOUT_URL = "$PROC_URL/logout"
const val EPISODE_LIST_URL = "$PROC_URL/episode_list"
const val NOVEL_URL = "$BASE_URL/novel"
const val SCRIPT_URL = "$PROC_URL/viewer_data"
}
val client = HttpClient {
@@ -52,7 +59,11 @@ class NpiaDownloader {
}
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
}
}
@@ -185,26 +196,38 @@ class NpiaDownloader {
}
suspend fun downloadEpisode(episodeId: Int): List<ScriptLineData> {
val res = client.request("https://novelpia.com/novel/viewer/$episodeId") {
val data = "size=14"
val res = client.post("${Endpoints.SCRIPT_URL}/$episodeId") {
header(HttpHeaders.Cookie, "LOGINKEY=$loginkey")
header(HttpHeaders.Origin, Endpoints.BASE_URL)
header(HttpHeaders.ContentType, "application/x-www-form-urlencoded; charset=UTF-8")
header(HttpHeaders.Referrer, "${Endpoints.BASE_URL}/viewer/$episodeId")
setBody(data)
}
if (!res.status.isSuccess()) {
throw Exception("Failed to fetch episode content: ${res.status}")
}
println(res.bodyAsText())
return listOf()
val document = Ksoup.parse(res.bodyAsText())
val draw = document.select("#novel_drawing").first()!!;
val lines: List<ScriptLineData> = draw.select(".line").map {
val imgsel = it.select("img")
if (imgsel.isNotEmpty()) {
val imageUrl = imgsel[0].attr("abs:src").ifEmpty { imgsel[0].attr("src") }
ScriptLineData.Image(imageUrl)
val json = Json.parseToJsonElement(res.bodyAsText()).jsonObject
json["s"]!!.let { scriptJson ->
val lines = mutableListOf<ScriptLineData>()
for (line in scriptJson.jsonArray) {
val lineText = line.jsonObject["text"]!!.jsonPrimitive.content.replace("&nbsp;", " ").trimEnd().replace(Regex("<p style=\'height: 0px; width: 0px; overflow: hidden; opacity: 0; display: inline-block;\'>.*?</p>"), "")
if (lineText.startsWith("<img")) {
val src = Ksoup.parse(lineText).selectFirst("img")?.attr("src") ?: continue
lines.add(ScriptLineData.Image(src))
} else {
ScriptLineData.Html(it.html())
lines.add(ScriptLineData.Html(lineText))
}
}
return lines
}
}
}
@@ -41,9 +41,8 @@ class NpiaTest {
*/
val scripts = downloader.downloadEpisode(5221545)
for (line in scripts) {
println(line)
println(line.toString())
}
downloader.logout()