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 com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.mosad.teapod.parser.AoDParser import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.preferences.EncryptedPreferences 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.components.LoginDialog
import org.mosad.teapod.ui.fragments.HomeFragment import org.mosad.teapod.ui.fragments.*
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.util.StorageController import org.mosad.teapod.util.StorageController
import org.mosad.teapod.util.TMDBApiController import org.mosad.teapod.util.TMDBApiController
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
@ -117,27 +110,11 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
showLoginDialog(true) showLoginDialog(true)
} else { } else {
// try to login in, as most sites can only bee loaded once loged in // 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) StorageController.load(this)
AoDParser.initialLoading()
// 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
} }
Log.i(javaClass.name, "login and list in $time ms") 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 // 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 tmdb = TMDBApiController().search(media.info.title, media.type)
val mediaFragment = MediaFragment(media, tmdb) val mediaFragment = MediaFragment(media, tmdb)
@ -182,7 +159,7 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
LoginDialog(this, firstTry).positiveButton { LoginDialog(this, firstTry).positiveButton {
EncryptedPreferences.saveCredentials(login, password, context) EncryptedPreferences.saveCredentials(login, password, context)
if (!AoDParser().login()) { if (!AoDParser.login()) {
showLoginDialog(false) showLoginDialog(false)
Log.w(javaClass.name, "Login failed, please try again.") 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 package org.mosad.teapod.parser
import android.util.Log import android.util.Log
@ -13,26 +35,21 @@ import org.mosad.teapod.util.Media
import java.io.IOException import java.io.IOException
import java.util.* import java.util.*
/** object AoDParser {
* maybe AoDParser as object would be useful
*/
class AoDParser {
private val baseUrl = "https://www.anime-on-demand.de" private const val baseUrl = "https://www.anime-on-demand.de"
private val loginPath = "/users/sign_in" private const val loginPath = "/users/sign_in"
private val libraryPath = "/animes" 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 sessionCookies = mutableMapOf<String, String>()
private var csrfToken: String = "" private var csrfToken: String = ""
private var sessionCookies = mutableMapOf<String, String>() private var loginSuccess = false
private var loginSuccess = false
val mediaList = arrayListOf<Media>() val mediaList = arrayListOf<Media>()
val itemMediaList = arrayListOf<ItemMedia>() val itemMediaList = arrayListOf<ItemMedia>()
val newEpisodesList = arrayListOf<ItemMedia>() val newEpisodesList = arrayListOf<ItemMedia>()
}
fun login(): Boolean = runBlocking { 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() if (sessionCookies.isEmpty()) login()
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
@ -109,12 +181,13 @@ class AoDParser {
} }
Log.i(javaClass.name, "Total library size is: ${mediaList.size}") 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() if (sessionCookies.isEmpty()) login()
withContext(Dispatchers.Default) { 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 * load streams for the media path, movies have one episode
* @param media is used as call ba reference * @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 { LoginDialog(requireContext(), firstTry).positiveButton {
EncryptedPreferences.saveCredentials(login, password, context) EncryptedPreferences.saveCredentials(login, password, context)
if (!AoDParser().login()) { if (!AoDParser.login()) {
showLoginDialog(false) showLoginDialog(false)
Log.w(javaClass.name, "Login failed, please try again.") 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) playStream(media.episodes[position].streamUrl)
// update watched state // update watched state
AoDParser().sendCallback(media.episodes[position].watchedCallback) AoDParser.sendCallback(media.episodes[position].watchedCallback)
adapterRecEpisodes.updateWatchedState(true, position) adapterRecEpisodes.updateWatchedState(true, position)
adapterRecEpisodes.notifyDataSetChanged() adapterRecEpisodes.notifyDataSetChanged()
} }