Add viewer_data download

This commit is contained in:
2026-03-07 23:58:53 +09:00
parent 58f7a22aef
commit f602523d02
2 changed files with 41 additions and 19 deletions

View File

@@ -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
}
}
}

View File

@@ -41,9 +41,8 @@ class NpiaTest {
*/
val scripts = downloader.downloadEpisode(5221545)
for (line in scripts) {
println(line)
println(line.toString())
}
downloader.logout()