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() private var loginSuccess = false val mediaList = arrayListOf() } 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 = 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() 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() 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) } } } } }