use suspending functions for coroutines when possible

* fix crash, when media is selected, but MediaFragment is removed before AoDParser could load data
This commit is contained in:
Jannik 2020-11-27 11:06:16 +01:00
parent bb8c8ca85a
commit d01e87bf14
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
4 changed files with 102 additions and 109 deletions

View File

@ -110,18 +110,18 @@ object AoDParser {
* get a media by it's ID (int) * get a media by it's ID (int)
* @return Media * @return Media
*/ */
fun getMediaById(mediaId: Int): Media { suspend fun getMediaById(mediaId: Int): Media {
val media = mediaList.first { it.id == mediaId } val media = mediaList.first { it.id == mediaId }
if (media.episodes.isEmpty()) { if (media.episodes.isEmpty()) {
loadStreams(media) loadStreams(media).join()
} }
return media return media
} }
// TODO don't use jsoup here // TODO don't use jsoup here
fun sendCallback(callbackPath: String) = GlobalScope.launch { fun sendCallback(callbackPath: String) = GlobalScope.launch(Dispatchers.IO) {
val headers = mutableMapOf( val headers = mutableMapOf(
Pair("Accept", "application/json, text/javascript, */*; q=0.01"), Pair("Accept", "application/json, text/javascript, */*; q=0.01"),
Pair("Accept-Language", "de,en-US;q=0.7,en;q=0.3"), Pair("Accept-Language", "de,en-US;q=0.7,en;q=0.3"),
@ -131,13 +131,11 @@ object AoDParser {
) )
try { try {
withContext(Dispatchers.IO) {
Jsoup.connect(baseUrl + callbackPath) Jsoup.connect(baseUrl + callbackPath)
.ignoreContentType(true) .ignoreContentType(true)
.cookies(sessionCookies) .cookies(sessionCookies)
.headers(headers) .headers(headers)
.execute() .execute()
}
} catch (ex: IOException) { } catch (ex: IOException) {
Log.e(javaClass.name, "Callback for $callbackPath failed.", ex) Log.e(javaClass.name, "Callback for $callbackPath failed.", ex)
} }
@ -213,16 +211,14 @@ object AoDParser {
* 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
*/ */
private fun loadStreams(media: Media) = runBlocking { private suspend fun loadStreams(media: Media) = GlobalScope.launch(Dispatchers.IO) {
if (sessionCookies.isEmpty()) login() if (sessionCookies.isEmpty()) login()
if (!loginSuccess) { if (!loginSuccess) {
Log.w(javaClass.name, "Login, was not successful.") Log.w(javaClass.name, "Login, was not successful.")
return@runBlocking return@launch
} }
withContext(Dispatchers.Default) {
// get the media page // get the media page
val res = Jsoup.connect(baseUrl + media.link) val res = Jsoup.connect(baseUrl + media.link)
.cookies(sessionCookies) .cookies(sessionCookies)
@ -300,7 +296,7 @@ object AoDParser {
"episodenanzahl" -> { "episodenanzahl" -> {
media.info.episodesCount = row.select("td").text() media.info.episodesCount = row.select("td").text()
.substringBefore("/") .substringBefore("/")
.filter{ it.isDigit() } .filter { it.isDigit() }
.toInt() .toInt()
} }
} }
@ -324,8 +320,6 @@ object AoDParser {
} }
} }
} }
}
} }
/** /**
@ -336,7 +330,7 @@ object AoDParser {
return CompletableDeferred(AoDObject(listOf())) return CompletableDeferred(AoDObject(listOf()))
} }
return GlobalScope.async { return GlobalScope.async(Dispatchers.IO) {
val headers = mutableMapOf( val headers = mutableMapOf(
Pair("Accept", "application/json, text/javascript, */*; q=0.01"), Pair("Accept", "application/json, text/javascript, */*; q=0.01"),
Pair("Accept-Language", "de,en-US;q=0.7,en;q=0.3"), Pair("Accept-Language", "de,en-US;q=0.7,en;q=0.3"),

View File

@ -1,6 +1,7 @@
package org.mosad.teapod.player package org.mosad.teapod.player
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import kotlinx.coroutines.runBlocking
import org.mosad.teapod.parser.AoDParser import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.ui.fragments.MediaFragment import org.mosad.teapod.ui.fragments.MediaFragment
import org.mosad.teapod.util.DataTypes import org.mosad.teapod.util.DataTypes
@ -25,7 +26,10 @@ class PlayerViewModel : ViewModel() {
mediaId = iMediaId mediaId = iMediaId
episodeId = iEpisodeId episodeId = iEpisodeId
runBlocking {
media = AoDParser.getMediaById(mediaId) media = AoDParser.getMediaById(mediaId)
}
currentEpisode = media.episodes.first { it.id == episodeId } currentEpisode = media.episodes.first { it.id == episodeId }
nextEpisode = selectNextEpisode() nextEpisode = selectNextEpisode()
} }

View File

@ -49,12 +49,12 @@ class MediaFragment(private val mediaId: Int) : Fragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.frameLoading.visibility = View.VISIBLE binding.frameLoading.visibility = View.VISIBLE
GlobalScope.launch { GlobalScope.launch(Dispatchers.Main) {
// load the streams for the selected media // load the streams for the selected media
media = AoDParser.getMediaById(mediaId) media = AoDParser.getMediaById(mediaId)
tmdb = TMDBApiController().search(media.info.title, media.type) tmdb = TMDBApiController().search(media.info.title, media.type)
withContext(Dispatchers.Main) { if (this@MediaFragment.isAdded) {
updateGUI() updateGUI()
initActions() initActions()
} }

View File

@ -3,9 +3,7 @@ package org.mosad.teapod.util
import android.util.Log import android.util.Log
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParser import com.google.gson.JsonParser
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.*
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import java.net.URL import java.net.URL
import java.net.URLEncoder import java.net.URLEncoder
import org.mosad.teapod.util.DataTypes.MediaType import org.mosad.teapod.util.DataTypes.MediaType
@ -22,12 +20,12 @@ class TMDBApiController {
private val imageUrl = "https://image.tmdb.org/t/p/w500" private val imageUrl = "https://image.tmdb.org/t/p/w500"
fun search(title: String, type: MediaType): TMDBResponse { suspend fun search(title: String, type: MediaType): TMDBResponse {
val searchTerm = title.replace("(Sub)", "").trim() val searchTerm = title.replace("(Sub)", "").trim()
return when (type) { return when (type) {
MediaType.MOVIE -> searchMovie(searchTerm) MediaType.MOVIE -> searchMovie(searchTerm).await()
MediaType.TVSHOW -> searchTVShow(searchTerm) MediaType.TVSHOW -> searchTVShow(searchTerm).await()
else -> { else -> {
Log.e(javaClass.name, "Wrong Type: $type") Log.e(javaClass.name, "Wrong Type: $type")
TMDBResponse() TMDBResponse()
@ -36,17 +34,17 @@ class TMDBApiController {
} }
fun searchTVShow(title: String) = runBlocking { fun searchTVShow(title: String): Deferred<TMDBResponse> {
val url = URL("$searchTVUrl$preparedParameters&query=${URLEncoder.encode(title, "UTF-8")}") val url = URL("$searchTVUrl$preparedParameters&query=${URLEncoder.encode(title, "UTF-8")}")
GlobalScope.async { return GlobalScope.async {
val response = JsonParser.parseString(url.readText()).asJsonObject val response = JsonParser.parseString(url.readText()).asJsonObject
//println(response) //println(response)
return@async if (response.get("total_results").asInt > 0) { if (response.get("total_results").asInt > 0) {
response.get("results").asJsonArray.first().asJsonObject.let { response.get("results").asJsonArray.first().asJsonObject.let {
val id = getStringNotNull(it,"id").toInt() val id = getStringNotNull(it, "id").toInt()
val overview = getStringNotNull(it,"overview") val overview = getStringNotNull(it, "overview")
val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl) val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl)
val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl) val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl)
@ -55,18 +53,17 @@ class TMDBApiController {
} else { } else {
TMDBResponse() TMDBResponse()
} }
}.await() }
} }
fun searchMovie(title: String) = runBlocking { fun searchMovie(title: String): Deferred<TMDBResponse> {
val url = URL("$searchMovieUrl$preparedParameters&query=${URLEncoder.encode(title, "UTF-8")}") val url = URL("$searchMovieUrl$preparedParameters&query=${URLEncoder.encode(title, "UTF-8")}")
GlobalScope.async { return GlobalScope.async {
val response = JsonParser.parseString(url.readText()).asJsonObject val response = JsonParser.parseString(url.readText()).asJsonObject
//println(response) //println(response)
return@async if (response.get("total_results").asInt > 0) { if (response.get("total_results").asInt > 0) {
response.get("results").asJsonArray.first().asJsonObject.let { response.get("results").asJsonArray.first().asJsonObject.let {
val id = getStringNotNull(it,"id").toInt() val id = getStringNotNull(it,"id").toInt()
val overview = getStringNotNull(it,"overview") val overview = getStringNotNull(it,"overview")
@ -79,9 +76,7 @@ class TMDBApiController {
} else { } else {
TMDBResponse() TMDBResponse()
} }
}
}.await()
} }
/** /**