made AoDParser an object

This commit is contained in:
Jannik 2020-10-19 19:59:53 +02:00
parent a25ec81f6b
commit 4c274eb062
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
4 changed files with 101 additions and 84 deletions

View File

@ -32,18 +32,11 @@ import androidx.fragment.app.commit
import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.preferences.EncryptedPreferences
import org.mosad.teapod.ui.fragments.MediaFragment
import org.mosad.teapod.ui.fragments.AccountFragment
import org.mosad.teapod.ui.components.LoginDialog
import org.mosad.teapod.ui.fragments.HomeFragment
import org.mosad.teapod.ui.fragments.LibraryFragment
import org.mosad.teapod.ui.fragments.SearchFragment
import org.mosad.teapod.ui.fragments.LoadingFragment
import org.mosad.teapod.ui.fragments.*
import org.mosad.teapod.util.StorageController
import org.mosad.teapod.util.TMDBApiController
import kotlin.system.measureTimeMillis
@ -117,27 +110,11 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
showLoginDialog(true)
} else {
// try to login in, as most sites can only bee loaded once loged in
if (!AoDParser().login()) showLoginDialog(false)
if (!AoDParser.login()) showLoginDialog(false)
}
StorageController.load(this)
// move to AoDParser
val newEPJob = GlobalScope.async {
AoDParser().listNewEpisodes()
}
val listJob = GlobalScope.async {
AoDParser().listAnimes() // initially load all media
}
runBlocking {
newEPJob.await()
listJob.await()
}
// TODO load home screen, can be parallel to listAnimes
AoDParser.initialLoading()
}
Log.i(javaClass.name, "login and list in $time ms")
}
@ -156,7 +133,7 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
}
// load the streams for the selected media
val media = AoDParser().getMediaById(mediaId)
val media = AoDParser.getMediaById(mediaId)
val tmdb = TMDBApiController().search(media.info.title, media.type)
val mediaFragment = MediaFragment(media, tmdb)
@ -182,7 +159,7 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
LoginDialog(this, firstTry).positiveButton {
EncryptedPreferences.saveCredentials(login, password, context)
if (!AoDParser().login()) {
if (!AoDParser.login()) {
showLoginDialog(false)
Log.w(javaClass.name, "Login failed, please try again.")
}

View File

@ -1,3 +1,25 @@
/**
* Teapod
*
* Copyright 2020 <seil0@mosad.xyz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*/
package org.mosad.teapod.parser
import android.util.Log
@ -13,26 +35,21 @@ import org.mosad.teapod.util.Media
import java.io.IOException
import java.util.*
/**
* maybe AoDParser as object would be useful
*/
class AoDParser {
object AoDParser {
private val baseUrl = "https://www.anime-on-demand.de"
private val loginPath = "/users/sign_in"
private val libraryPath = "/animes"
private const val baseUrl = "https://www.anime-on-demand.de"
private const val loginPath = "/users/sign_in"
private const val libraryPath = "/animes"
private val userAgent = "Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0"
private const val userAgent = "Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0"
companion object {
private var csrfToken: String = ""
private var sessionCookies = mutableMapOf<String, String>()
private var loginSuccess = false
private var sessionCookies = mutableMapOf<String, String>()
private var csrfToken: String = ""
private var loginSuccess = false
val mediaList = arrayListOf<Media>()
val itemMediaList = arrayListOf<ItemMedia>()
val newEpisodesList = arrayListOf<ItemMedia>()
}
val mediaList = arrayListOf<Media>()
val itemMediaList = arrayListOf<ItemMedia>()
val newEpisodesList = arrayListOf<ItemMedia>()
fun login(): Boolean = runBlocking {
@ -74,9 +91,64 @@ class AoDParser {
}
/**
* list all animes from the website
* initially load all media and home screen data
* -> blocking
*/
fun listAnimes(): ArrayList<Media> = runBlocking {
fun initialLoading() = runBlocking {
val newEPJob = GlobalScope.async {
listNewEpisodes()
}
val listJob = GlobalScope.async {
listAnimes()
}
newEPJob.await()
listJob.await()
}
/**
* get a media by it's ID (int)
* @return Media
*/
fun getMediaById(mediaId: Int): Media {
val media = mediaList.first { it.id == mediaId }
if (media.episodes.isEmpty()) {
loadStreams(media)
}
return media
}
// TODO don't use jsoup here
fun sendCallback(callbackPath: String) = GlobalScope.launch {
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"),
)
try {
withContext(Dispatchers.IO) {
Jsoup.connect(baseUrl + callbackPath)
.ignoreContentType(true)
.cookies(sessionCookies)
.headers(headers)
.execute()
}
} catch (ex: IOException) {
Log.e(javaClass.name, "Callback for $callbackPath failed.", ex)
}
}
/**
* load all media from aod into itemMediaList and mediaList
*/
private fun listAnimes() = runBlocking {
if (sessionCookies.isEmpty()) login()
withContext(Dispatchers.Default) {
@ -109,12 +181,13 @@ class AoDParser {
}
Log.i(javaClass.name, "Total library size is: ${mediaList.size}")
return@withContext mediaList
}
}
fun listNewEpisodes() = runBlocking {
/**
* load all new episodes from AoD into newEpisodesList
*/
private fun listNewEpisodes() = runBlocking {
if (sessionCookies.isEmpty()) login()
withContext(Dispatchers.Default) {
@ -137,16 +210,6 @@ class AoDParser {
}
}
fun getMediaById(mediaId: Int): Media {
val media = mediaList.first { it.id == mediaId }
if (media.episodes.isEmpty()) {
loadStreams(media)
}
return media
}
/**
* load streams for the media path, movies have one episode
* @param media is used as call ba reference
@ -283,27 +346,4 @@ class AoDParser {
}
}
fun sendCallback(callbackPath: String) = GlobalScope.launch {
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"),
)
try {
withContext(Dispatchers.IO) {
Jsoup.connect(baseUrl + callbackPath)
.ignoreContentType(true)
.cookies(sessionCookies)
.headers(headers)
.execute()
}
} catch (ex: IOException) {
Log.e(javaClass.name, "Callback for $callbackPath failed.", ex)
}
}
}

View File

@ -57,7 +57,7 @@ class AccountFragment : Fragment() {
LoginDialog(requireContext(), firstTry).positiveButton {
EncryptedPreferences.saveCredentials(login, password, context)
if (!AoDParser().login()) {
if (!AoDParser.login()) {
showLoginDialog(false)
Log.w(javaClass.name, "Login failed, please try again.")
}

View File

@ -117,7 +117,7 @@ class MediaFragment(private val media: Media, private val tmdb: TMDBResponse) :
playStream(media.episodes[position].streamUrl)
// update watched state
AoDParser().sendCallback(media.episodes[position].watchedCallback)
AoDParser.sendCallback(media.episodes[position].watchedCallback)
adapterRecEpisodes.updateWatchedState(true, position)
adapterRecEpisodes.notifyDataSetChanged()
}