teapod/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt

190 lines
6.4 KiB
Kotlin

package org.mosad.teapod.parser
import android.util.Log
import com.google.gson.JsonParser
import kotlinx.coroutines.*
import org.jsoup.Connection
import org.jsoup.Jsoup
import org.mosad.teapod.preferences.EncryptedPreferences
import org.mosad.teapod.util.DataTypes.MediaType
import org.mosad.teapod.util.GUIMedia
import org.mosad.teapod.util.StreamMedia
import kotlin.collections.ArrayList
class AoDParser {
private val baseURL = "https://www.anime-on-demand.de"
private val loginPath = "/users/sign_in"
private val libraryPath = "/animes"
companion object {
private var sessionCookies = mutableMapOf<String, String>()
private var loginSuccess = false
val mediaList = arrayListOf<GUIMedia>()
}
private fun login() = runBlocking {
val userAgent = "Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0"
withContext(Dispatchers.Default) {
// get the authenticity token
val resAuth = Jsoup.connect(baseURL + loginPath)
.header("User-Agent", userAgent)
.execute()
val authenticityToken = resAuth.parse().select("meta[name=csrf-token]").attr("content")
println("Authenticity token is: $authenticityToken")
val cookies = resAuth.cookies()
println("cookies: $cookies")
val data = mapOf(
Pair("user[login]", EncryptedPreferences.login),
Pair("user[password]", EncryptedPreferences.password),
Pair("user[remember_me]", "1"),
Pair("commit", "Einloggen"),
Pair("authenticity_token", authenticityToken)
)
val resLogin = Jsoup.connect(baseURL + loginPath)
.method(Connection.Method.POST)
.data(data)
.postDataCharset("UTF-8")
.cookies(cookies)
.execute()
//println(resLogin.body())
loginSuccess = resLogin.body().contains("Hallo, du bist jetzt angemeldet.")
println("Status: ${resLogin.statusCode()} (${resLogin.statusMessage()}), login successful: $loginSuccess")
sessionCookies = resLogin.cookies()
}
}
/**
* list all animes from the website
*/
fun listAnimes(): ArrayList<GUIMedia> = runBlocking {
if (sessionCookies.isEmpty()) login()
withContext(Dispatchers.Default) {
val resAnimes = Jsoup.connect(baseURL + libraryPath)
.cookies(sessionCookies)
.get()
//println(resAnimes)
mediaList.clear()
resAnimes.select("div.animebox").forEach {
val media = GUIMedia(
it.select("h3.animebox-title").text(),
it.select("p.animebox-image").select("img").attr("src"),
it.select("p.animebox-shorttext").text(),
it.select("p.animebox-link").select("a").attr("href")
)
mediaList.add(media)
}
println("got ${mediaList.size} anime")
return@withContext mediaList
}
}
/**
* load streams for the media path
*/
fun loadStreams(mediaPath: String): StreamMedia = runBlocking {
if (sessionCookies.isEmpty()) login()
if (!loginSuccess) {
println("please log in") // TODO
return@runBlocking StreamMedia(MediaType.OTHER)
}
withContext(Dispatchers.Default) {
val res = Jsoup.connect(baseURL + mediaPath)
.cookies(sessionCookies)
.get()
//println(res)
val playlists = res.select("input.streamstarter_html5").eachAttr("data-playlist")
val csrfToken = res.select("meta[name=csrf-token]").attr("content")
//println("first entry: ${playlists.first()}")
//println("csrf token is: $csrfToken")
val type = if (res.select("h2").eachText().filter { it == "Episoden" }.any()) {
MediaType.TVSHOW
} else {
MediaType.MOVIE
}
return@withContext loadStreamInfo(playlists.first(), csrfToken, type)
}
}
/**
* load the playlist path and parse it, read the stream info from json
*/
private fun loadStreamInfo(playlistPath: String, csrfToken: String, type: MediaType): StreamMedia = runBlocking {
withContext(Dispatchers.Default) {
val headers = mutableMapOf(
Pair("Accept", "application/json, text/javascript, */*; q=0.01"),
Pair("Accept-Language", "de,en-US;q=0.7,en;q=0.3"),
Pair("Accept-Encoding", "gzip, deflate, br"),
Pair("X-CSRF-Token", csrfToken),
Pair("X-Requested-With", "XMLHttpRequest"),
)
val res = Jsoup.connect(baseURL + playlistPath)
.ignoreContentType(true)
.cookies(sessionCookies)
.headers(headers)
.execute()
//println(res.body())
println(type)
return@withContext when (type) {
MediaType.MOVIE -> {
val movie = JsonParser.parseString(res.body()).asJsonObject
.get("playlist").asJsonArray
val streamList = arrayListOf<String>()
movie.first().asJsonObject.get("sources").asJsonArray.toList().forEach {
streamList.add(it.asJsonObject.get("file").asString)
}
StreamMedia(MediaType.MOVIE, streamList)
}
MediaType.TVSHOW -> {
val episodes = JsonParser.parseString(res.body()).asJsonObject
.get("playlist").asJsonArray
val streamList = arrayListOf<String>()
episodes.forEach {
val streamUrl = it.asJsonObject.get("sources").asJsonArray
.first().asJsonObject
.get("file").asString
streamList.add(streamUrl)
}
StreamMedia(MediaType.TVSHOW, streamList)
}
else -> {
Log.e(javaClass.name, "Wrong Type, please report this issue.")
StreamMedia(MediaType.OTHER)
}
}
}
}
}