merge GUIMedia and StreamMedia into Media, parse episode title from aod

This commit is contained in:
Jannik 2020-10-12 17:52:24 +02:00
parent 0fc1d8b5c2
commit ae20e74702
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
7 changed files with 64 additions and 77 deletions

View File

@ -17,7 +17,7 @@ import org.mosad.teapod.ui.components.LoginDialog
import org.mosad.teapod.ui.home.HomeFragment import org.mosad.teapod.ui.home.HomeFragment
import org.mosad.teapod.ui.library.LibraryFragment import org.mosad.teapod.ui.library.LibraryFragment
import org.mosad.teapod.ui.search.SearchFragment import org.mosad.teapod.ui.search.SearchFragment
import org.mosad.teapod.util.GUIMedia import org.mosad.teapod.util.Media
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener { class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {
@ -87,10 +87,10 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
} }
} }
fun showDetailFragment(media: GUIMedia) { fun showDetailFragment(media: Media) {
val streamMedia = AoDParser().loadStreams(media.link) // load the streams for the selected media media.episodes = AoDParser().loadStreams(media) // load the streams for the selected media
val mediaFragment = MediaFragment(media, streamMedia) val mediaFragment = MediaFragment(media)
supportFragmentManager.commit { supportFragmentManager.commit {
add(R.id.nav_host_fragment, mediaFragment, "MediaFragment") add(R.id.nav_host_fragment, mediaFragment, "MediaFragment")
addToBackStack(null) addToBackStack(null)

View File

@ -7,8 +7,9 @@ import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.mosad.teapod.preferences.EncryptedPreferences import org.mosad.teapod.preferences.EncryptedPreferences
import org.mosad.teapod.util.DataTypes.MediaType import org.mosad.teapod.util.DataTypes.MediaType
import org.mosad.teapod.util.GUIMedia import org.mosad.teapod.util.Episode
import org.mosad.teapod.util.StreamMedia import org.mosad.teapod.util.Media
import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class AoDParser { class AoDParser {
@ -21,7 +22,7 @@ class AoDParser {
private var sessionCookies = mutableMapOf<String, String>() private var sessionCookies = mutableMapOf<String, String>()
private var loginSuccess = false private var loginSuccess = false
val mediaList = arrayListOf<GUIMedia>() val mediaList = arrayListOf<Media>()
} }
private fun login() = runBlocking { private fun login() = runBlocking {
@ -67,7 +68,7 @@ class AoDParser {
/** /**
* list all animes from the website * list all animes from the website
*/ */
fun listAnimes(): ArrayList<GUIMedia> = runBlocking { fun listAnimes(): ArrayList<Media> = runBlocking {
if (sessionCookies.isEmpty()) login() if (sessionCookies.isEmpty()) login()
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
@ -79,13 +80,19 @@ class AoDParser {
mediaList.clear() mediaList.clear()
resAnimes.select("div.animebox").forEach { resAnimes.select("div.animebox").forEach {
val media = GUIMedia( val type = if (it.select("p.animebox-link").select("a").text().toLowerCase(Locale.ROOT) == "zur serie") {
it.select("h3.animebox-title").text(), MediaType.TVSHOW
it.select("p.animebox-image").select("img").attr("src"), } else {
it.select("p.animebox-shorttext").text(), MediaType.MOVIE
it.select("p.animebox-link").select("a").attr("href") }
)
val media = Media(
it.select("h3.animebox-title").text(),
it.select("p.animebox-link").select("a").attr("href"),
type,
it.select("p.animebox-image").select("img").attr("src"),
it.select("p.animebox-shorttext").text()
)
mediaList.add(media) mediaList.add(media)
} }
@ -98,17 +105,17 @@ class AoDParser {
/** /**
* load streams for the media path * load streams for the media path
*/ */
fun loadStreams(mediaPath: String): StreamMedia = runBlocking { fun loadStreams(media: Media): List<Episode> = runBlocking {
if (sessionCookies.isEmpty()) login() if (sessionCookies.isEmpty()) login()
if (!loginSuccess) { if (!loginSuccess) {
println("please log in") // TODO println("please log in") // TODO
return@runBlocking StreamMedia(MediaType.OTHER) return@runBlocking listOf()
} }
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
val res = Jsoup.connect(baseURL + mediaPath) val res = Jsoup.connect(baseURL + media.link)
.cookies(sessionCookies) .cookies(sessionCookies)
.get() .get()
@ -120,20 +127,14 @@ class AoDParser {
//println("first entry: ${playlists.first()}") //println("first entry: ${playlists.first()}")
//println("csrf token is: $csrfToken") //println("csrf token is: $csrfToken")
val type = if (res.select("h2").eachText().filter { it == "Episoden" }.any()) { return@withContext loadStreamInfo(playlists.first(), csrfToken, media.type)
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 * load the playlist path and parse it, read the stream info from json
*/ */
private fun loadStreamInfo(playlistPath: String, csrfToken: String, type: MediaType): StreamMedia = runBlocking { private fun loadStreamInfo(playlistPath: String, csrfToken: String, type: MediaType): List<Episode> = runBlocking {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
val headers = mutableMapOf( val headers = mutableMapOf(
Pair("Accept", "application/json, text/javascript, */*; q=0.01"), Pair("Accept", "application/json, text/javascript, */*; q=0.01"),
@ -151,36 +152,36 @@ class AoDParser {
//println(res.body()) //println(res.body())
println(type)
return@withContext when (type) { return@withContext when (type) {
MediaType.MOVIE -> { MediaType.MOVIE -> {
val movie = JsonParser.parseString(res.body()).asJsonObject val movie = JsonParser.parseString(res.body()).asJsonObject
.get("playlist").asJsonArray .get("playlist").asJsonArray
val streamList = arrayListOf<String>() movie.first().asJsonObject.get("sources").asJsonArray.toList().map {
movie.first().asJsonObject.get("sources").asJsonArray.toList().forEach { Episode(streamUrl = it.asJsonObject.get("file").asString)
streamList.add(it.asJsonObject.get("file").asString)
} }
StreamMedia(MediaType.MOVIE, streamList)
} }
MediaType.TVSHOW -> { MediaType.TVSHOW -> {
val episodes = JsonParser.parseString(res.body()).asJsonObject val episodesJson = JsonParser.parseString(res.body()).asJsonObject
.get("playlist").asJsonArray .get("playlist").asJsonArray
val streamList = arrayListOf<String>()
episodes.forEach { episodesJson.map {
val streamUrl = it.asJsonObject.get("sources").asJsonArray val episodeStream = it.asJsonObject.get("sources").asJsonArray
.first().asJsonObject .first().asJsonObject
.get("file").asString .get("file").asString
streamList.add(streamUrl) val episodeTitle = it.asJsonObject.get("title").asString
Episode(
episodeTitle,
episodeStream
)
} }
StreamMedia(MediaType.TVSHOW, streamList)
} }
else -> { else -> {
Log.e(javaClass.name, "Wrong Type, please report this issue.") Log.e(javaClass.name, "Wrong Type, please report this issue.")
StreamMedia(MediaType.OTHER) listOf()
} }
} }
} }

View File

@ -14,10 +14,9 @@ import org.mosad.teapod.MainActivity
import org.mosad.teapod.R import org.mosad.teapod.R
import org.mosad.teapod.util.DataTypes.MediaType import org.mosad.teapod.util.DataTypes.MediaType
import org.mosad.teapod.util.EpisodesAdapter import org.mosad.teapod.util.EpisodesAdapter
import org.mosad.teapod.util.GUIMedia import org.mosad.teapod.util.Media
import org.mosad.teapod.util.StreamMedia
class MediaFragment(private val guiMedia: GUIMedia, private val streamMedia: StreamMedia) : Fragment() { class MediaFragment(private val media: Media) : Fragment() {
private lateinit var adapterRecEpisodes: EpisodesAdapter private lateinit var adapterRecEpisodes: EpisodesAdapter
private lateinit var viewManager: RecyclerView.LayoutManager private lateinit var viewManager: RecyclerView.LayoutManager
@ -31,53 +30,47 @@ class MediaFragment(private val guiMedia: GUIMedia, private val streamMedia: Str
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// generic gui // generic gui
Glide.with(requireContext()).load(guiMedia.posterLink).into(image_poster) Glide.with(requireContext()).load(media.posterLink).into(image_poster)
text_title.text = guiMedia.title text_title.text = media.title
text_desc.text = guiMedia.shortDesc text_desc.text = media.shortDesc
// specific gui // specific gui
if (streamMedia.type == MediaType.TVSHOW) { if (media.type == MediaType.TVSHOW) {
val episodes = streamMedia.streams.mapIndexed { index, _ -> // TODO
"${guiMedia.title} - Ep. ${index + 1}" val episodeTitles = media.episodes.map { it.title }
}
adapterRecEpisodes = EpisodesAdapter(episodeTitles)
adapterRecEpisodes = EpisodesAdapter(episodes)
viewManager = LinearLayoutManager(context) viewManager = LinearLayoutManager(context)
recycler_episodes.layoutManager = viewManager recycler_episodes.layoutManager = viewManager
recycler_episodes.adapter = adapterRecEpisodes recycler_episodes.adapter = adapterRecEpisodes
} else if (streamMedia.type == MediaType.MOVIE) { } else if (media.type == MediaType.MOVIE) {
recycler_episodes.visibility = View.GONE recycler_episodes.visibility = View.GONE
} }
println("media streams: ${streamMedia.streams}") println("media streams: ${media.episodes}")
initActions() initActions()
} }
private fun initActions() { private fun initActions() {
button_play.setOnClickListener { button_play.setOnClickListener {
onClickButtonPlay() when (media.type) {
MediaType.MOVIE -> playStream(media.episodes.first().streamUrl)
MediaType.TVSHOW -> playStream(media.episodes.first().streamUrl)
MediaType.OTHER -> Log.e(javaClass.name, "Wrong Type, please report this issue.")
}
} }
// set onItemClick only in adapter is initialized // set onItemClick only in adapter is initialized
if (this::adapterRecEpisodes.isInitialized) { if (this::adapterRecEpisodes.isInitialized) {
adapterRecEpisodes.onItemClick = { item, position -> adapterRecEpisodes.onItemClick = { item, position ->
playStream(streamMedia.streams[position]) playStream(media.episodes[position].streamUrl)
} }
} }
} }
private fun onClickButtonPlay() {
when (streamMedia.type) {
MediaType.MOVIE -> playStream(streamMedia.streams.first())
MediaType.TVSHOW -> playStream(streamMedia.streams.first())
MediaType.OTHER -> Log.e(javaClass.name, "Wrong Type, please report this issue.")
}
}
private fun playStream(url: String) { private fun playStream(url: String) {
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity
mainActivity.startPlayer(url) mainActivity.startPlayer(url)

View File

@ -11,7 +11,7 @@ import org.mosad.teapod.MainActivity
import org.mosad.teapod.R import org.mosad.teapod.R
import org.mosad.teapod.parser.AoDParser import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.util.CustomAdapter import org.mosad.teapod.util.CustomAdapter
import org.mosad.teapod.util.GUIMedia import org.mosad.teapod.util.Media
class LibraryFragment : Fragment() { class LibraryFragment : Fragment() {
@ -41,7 +41,7 @@ class LibraryFragment : Fragment() {
private fun initActions() { private fun initActions() {
list_library.setOnItemClickListener { _, _, position, _ -> list_library.setOnItemClickListener { _, _, position, _ ->
val media = adapter.getItem(position) as GUIMedia val media = adapter.getItem(position) as Media
println("selected item is: ${media.title}") println("selected item is: ${media.title}")
val mainActivity = activity as MainActivity val mainActivity = activity as MainActivity

View File

@ -12,7 +12,7 @@ import org.mosad.teapod.MainActivity
import org.mosad.teapod.R import org.mosad.teapod.R
import org.mosad.teapod.parser.AoDParser import org.mosad.teapod.parser.AoDParser
import org.mosad.teapod.util.CustomAdapter import org.mosad.teapod.util.CustomAdapter
import org.mosad.teapod.util.GUIMedia import org.mosad.teapod.util.Media
class SearchFragment : Fragment() { class SearchFragment : Fragment() {
@ -55,7 +55,7 @@ class SearchFragment : Fragment() {
}) })
list_search.setOnItemClickListener { _, _, position, _ -> list_search.setOnItemClickListener { _, _, position, _ ->
val media = adapter.getItem(position) as GUIMedia val media = adapter.getItem(position) as Media
println("selected item is: ${media.title}") println("selected item is: ${media.title}")

View File

@ -1,21 +1,15 @@
package org.mosad.teapod.util package org.mosad.teapod.util
import android.content.Context import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.* import android.widget.*
import androidx.core.content.res.ResourcesCompat
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import org.mosad.teapod.R import org.mosad.teapod.R
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class CustomAdapter(val context: Context, private val originalMedia: ArrayList<GUIMedia>) : BaseAdapter(), Filterable { class CustomAdapter(val context: Context, private val originalMedia: ArrayList<Media>) : BaseAdapter(), Filterable {
private var filteredMedia = originalMedia.map { it.copy() } private var filteredMedia = originalMedia.map { it.copy() }
private val customFilter = CustomFilter() private val customFilter = CustomFilter()
@ -68,7 +62,7 @@ class CustomAdapter(val context: Context, private val originalMedia: ArrayList<G
} }
override fun publishResults(constraint: CharSequence?, results: FilterResults?) { override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
filteredMedia = results?.values as ArrayList<GUIMedia> filteredMedia = results?.values as ArrayList<Media>
notifyDataSetChanged() notifyDataSetChanged()
} }

View File

@ -8,11 +8,10 @@ class DataTypes {
} }
} }
// TODO rework: add type, episodes list with episode title, if type == MOVIE the first episode will be the movie stream data class Media(val title: String, val link: String, val type: DataTypes.MediaType, val posterLink: String, val shortDesc : String, var episodes: List<Episode> = listOf()) {
data class GUIMedia(val title: String, val posterLink: String, val shortDesc : String, val link: String) {
override fun toString(): String { override fun toString(): String {
return title return title
} }
} }
data class StreamMedia(val type: DataTypes.MediaType, val streams: ArrayList<String> = arrayListOf()) data class Episode(val title: String = "", val streamUrl: String = "", var watched: Boolean = false)