Add login support (#1340)
This commit is contained in:
parent
611c48d96f
commit
f4e38d617a
@ -1,11 +1,12 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlinx-serialization'
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
extName = 'hanime.tv'
|
extName = 'hanime.tv'
|
||||||
pkgNameSuffix = 'en.hanime'
|
pkgNameSuffix = 'en.hanime'
|
||||||
extClass = '.Hanime'
|
extClass = '.Hanime'
|
||||||
extVersionCode = 15
|
extVersionCode = 16
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
|||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonArray
|
import kotlinx.serialization.json.JsonArray
|
||||||
@ -25,11 +26,13 @@ import kotlinx.serialization.json.jsonObject
|
|||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import kotlinx.serialization.json.long
|
import kotlinx.serialization.json.long
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -45,6 +48,8 @@ class Hanime : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
private var authCookie: String? = null
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
@ -69,8 +74,9 @@ class Hanime : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
private val popularRequestHeaders =
|
private val popularRequestHeaders =
|
||||||
Headers.headersOf("authority", "search.htv-services.com", "accept", "application/json, text/plain, */*", "content-type", "application/json;charset=UTF-8")
|
Headers.headersOf("authority", "search.htv-services.com", "accept", "application/json, text/plain, */*", "content-type", "application/json;charset=UTF-8")
|
||||||
|
|
||||||
override fun popularAnimeRequest(page: Int): Request =
|
override fun popularAnimeRequest(page: Int): Request {
|
||||||
POST("https://search.htv-services.com/", popularRequestHeaders, searchRequestBody("", page, AnimeFilterList()))
|
return POST("https://search.htv-services.com/", popularRequestHeaders, searchRequestBody("", page, AnimeFilterList()))
|
||||||
|
}
|
||||||
|
|
||||||
override fun popularAnimeParse(response: Response): AnimesPage {
|
override fun popularAnimeParse(response: Response): AnimesPage {
|
||||||
val responseString = response.body!!.string()
|
val responseString = response.body!!.string()
|
||||||
@ -127,6 +133,41 @@ class Hanime : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
return GET(episode.url)
|
return GET(episode.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
||||||
|
setAuthCookie()
|
||||||
|
|
||||||
|
if (authCookie != null) {
|
||||||
|
return fetchVideoListPremium(episode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.fetchVideoList(episode)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchVideoListPremium(episode: SEpisode): Observable<List<Video>> {
|
||||||
|
val videoList = mutableListOf<Video>()
|
||||||
|
val id = episode.url.substringAfter("?id=")
|
||||||
|
val headers = headers.newBuilder()
|
||||||
|
.add("cookie", authCookie!!)
|
||||||
|
val document = client.newCall(
|
||||||
|
GET("$baseUrl/videos/hentai/$id", headers = headers.build())
|
||||||
|
).execute().asJsoup()
|
||||||
|
val data = document.selectFirst("script:containsData(__NUXT__)").data()
|
||||||
|
.substringAfter("__NUXT__=").substringBeforeLast(";")
|
||||||
|
val parsed = json.decodeFromString<WindowNuxt>(data)
|
||||||
|
parsed.state.data.video.videos_manifest.servers.forEach { server ->
|
||||||
|
server.streams.forEach { stream ->
|
||||||
|
videoList.add(
|
||||||
|
Video(
|
||||||
|
stream.url,
|
||||||
|
stream.height + "p",
|
||||||
|
stream.url
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Observable.just(videoList)
|
||||||
|
}
|
||||||
|
|
||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val responseString = response.body!!.string()
|
val responseString = response.body!!.string()
|
||||||
val jObject = json.decodeFromString<JsonObject>(responseString)
|
val jObject = json.decodeFromString<JsonObject>(responseString)
|
||||||
@ -182,6 +223,15 @@ class Hanime : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
return listOf(episode)
|
return listOf(episode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setAuthCookie() {
|
||||||
|
if (authCookie == null) {
|
||||||
|
val cookieList = client.cookieJar.loadForRequest(baseUrl.toHttpUrl())
|
||||||
|
if (cookieList.isNotEmpty()) {
|
||||||
|
cookieList.firstOrNull { it.name == "htv3session" }?.let { authCookie = "${it.name}=${it.value}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun latestSearchRequestBody(page: Int): RequestBody {
|
private fun latestSearchRequestBody(page: Int): RequestBody {
|
||||||
return """
|
return """
|
||||||
{"search_text": "",
|
{"search_text": "",
|
||||||
@ -535,4 +585,40 @@ class Hanime : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
screen.addPreference(videoQualityPref)
|
screen.addPreference(videoQualityPref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class WindowNuxt(
|
||||||
|
val state: State
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class State(
|
||||||
|
val data: Data
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class Data(
|
||||||
|
val video: DataVideo
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class DataVideo(
|
||||||
|
val videos_manifest: VideosManifest
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class VideosManifest(
|
||||||
|
val servers: List<Server>
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class Server(
|
||||||
|
val streams: List<Stream>
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class Stream(
|
||||||
|
val height: String,
|
||||||
|
val url: String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user