Add viewer_data download
This commit is contained in:
@@ -11,12 +11,18 @@ import io.ktor.client.request.request
|
|||||||
import io.ktor.client.request.setBody
|
import io.ktor.client.request.setBody
|
||||||
import io.ktor.client.statement.bodyAsText
|
import io.ktor.client.statement.bodyAsText
|
||||||
import io.ktor.http.HttpHeaders
|
import io.ktor.http.HttpHeaders
|
||||||
|
import io.ktor.http.contentLength
|
||||||
import io.ktor.http.isSuccess
|
import io.ktor.http.isSuccess
|
||||||
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
import kotlinx.datetime.number
|
import kotlinx.datetime.number
|
||||||
import kotlinx.datetime.todayIn
|
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
|
import kotlin.time.Clock
|
||||||
|
|
||||||
class NpiaDownloader {
|
class NpiaDownloader {
|
||||||
@@ -31,12 +37,13 @@ class NpiaDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Endpoints {
|
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 PROC_URL = "$BASE_URL/proc"
|
||||||
const val LOGIN_URL = "$PROC_URL/login"
|
const val LOGIN_URL = "$PROC_URL/login"
|
||||||
const val LOGOUT_URL = "$PROC_URL/logout"
|
const val LOGOUT_URL = "$PROC_URL/logout"
|
||||||
const val EPISODE_LIST_URL = "$PROC_URL/episode_list"
|
const val EPISODE_LIST_URL = "$PROC_URL/episode_list"
|
||||||
const val NOVEL_URL = "$BASE_URL/novel"
|
const val NOVEL_URL = "$BASE_URL/novel"
|
||||||
|
const val SCRIPT_URL = "$PROC_URL/viewer_data"
|
||||||
}
|
}
|
||||||
|
|
||||||
val client = HttpClient {
|
val client = HttpClient {
|
||||||
@@ -52,7 +59,11 @@ class NpiaDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
|
json(Json {
|
||||||
|
prettyPrint = true
|
||||||
|
isLenient = true
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,26 +196,38 @@ class NpiaDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun downloadEpisode(episodeId: Int): List<ScriptLineData> {
|
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.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()) {
|
if (!res.status.isSuccess()) {
|
||||||
throw Exception("Failed to fetch episode content: ${res.status}")
|
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)
|
|
||||||
} else {
|
|
||||||
ScriptLineData.Html(it.html())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
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(" ", " ").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 {
|
||||||
|
|
||||||
|
lines.add(ScriptLineData.Html(lineText))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,9 +41,8 @@ class NpiaTest {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
val scripts = downloader.downloadEpisode(5221545)
|
val scripts = downloader.downloadEpisode(5221545)
|
||||||
|
|
||||||
for (line in scripts) {
|
for (line in scripts) {
|
||||||
println(line)
|
println(line.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
downloader.logout()
|
downloader.logout()
|
||||||
|
|||||||
Reference in New Issue
Block a user