merge GUIMedia and StreamMedia into Media, parse episode title from aod
This commit is contained in:
		| @ -17,7 +17,7 @@ import org.mosad.teapod.ui.components.LoginDialog | ||||
| import org.mosad.teapod.ui.home.HomeFragment | ||||
| import org.mosad.teapod.ui.library.LibraryFragment | ||||
| import org.mosad.teapod.ui.search.SearchFragment | ||||
| import org.mosad.teapod.util.GUIMedia | ||||
| import org.mosad.teapod.util.Media | ||||
|  | ||||
| class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener { | ||||
|  | ||||
| @ -87,10 +87,10 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun showDetailFragment(media: GUIMedia) { | ||||
|         val streamMedia = AoDParser().loadStreams(media.link) // load the streams for the selected media | ||||
|     fun showDetailFragment(media: Media) { | ||||
|         media.episodes = AoDParser().loadStreams(media) // load the streams for the selected media | ||||
|  | ||||
|         val mediaFragment = MediaFragment(media, streamMedia) | ||||
|         val mediaFragment = MediaFragment(media) | ||||
|         supportFragmentManager.commit { | ||||
|             add(R.id.nav_host_fragment, mediaFragment, "MediaFragment") | ||||
|             addToBackStack(null) | ||||
|  | ||||
| @ -7,8 +7,9 @@ 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 org.mosad.teapod.util.Episode | ||||
| import org.mosad.teapod.util.Media | ||||
| import java.util.* | ||||
| import kotlin.collections.ArrayList | ||||
|  | ||||
| class AoDParser { | ||||
| @ -21,7 +22,7 @@ class AoDParser { | ||||
|         private var sessionCookies = mutableMapOf<String, String>() | ||||
|         private var loginSuccess = false | ||||
|  | ||||
|         val mediaList = arrayListOf<GUIMedia>() | ||||
|         val mediaList = arrayListOf<Media>() | ||||
|     } | ||||
|  | ||||
|     private fun login() = runBlocking { | ||||
| @ -67,7 +68,7 @@ class AoDParser { | ||||
|     /** | ||||
|      * list all animes from the website | ||||
|      */ | ||||
|     fun listAnimes(): ArrayList<GUIMedia>  = runBlocking { | ||||
|     fun listAnimes(): ArrayList<Media>  = runBlocking { | ||||
|         if (sessionCookies.isEmpty()) login() | ||||
|  | ||||
|         withContext(Dispatchers.Default) { | ||||
| @ -79,13 +80,19 @@ class AoDParser { | ||||
|  | ||||
|             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") | ||||
|                 ) | ||||
|                 val type = if (it.select("p.animebox-link").select("a").text().toLowerCase(Locale.ROOT) == "zur serie") { | ||||
|                     MediaType.TVSHOW | ||||
|                 } else { | ||||
|                     MediaType.MOVIE | ||||
|                 } | ||||
|  | ||||
|                 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) | ||||
|             } | ||||
|  | ||||
| @ -98,17 +105,17 @@ class AoDParser { | ||||
|     /** | ||||
|      * load streams for the media path | ||||
|      */ | ||||
|     fun loadStreams(mediaPath: String): StreamMedia = runBlocking { | ||||
|     fun loadStreams(media: Media): List<Episode> = runBlocking { | ||||
|         if (sessionCookies.isEmpty()) login() | ||||
|  | ||||
|         if (!loginSuccess) { | ||||
|             println("please log in") // TODO | ||||
|             return@runBlocking StreamMedia(MediaType.OTHER) | ||||
|             return@runBlocking listOf() | ||||
|         } | ||||
|  | ||||
|         withContext(Dispatchers.Default) { | ||||
|  | ||||
|             val res = Jsoup.connect(baseURL + mediaPath) | ||||
|             val res = Jsoup.connect(baseURL + media.link) | ||||
|                 .cookies(sessionCookies) | ||||
|                 .get() | ||||
|  | ||||
| @ -120,20 +127,14 @@ class AoDParser { | ||||
|             //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) | ||||
|             return@withContext loadStreamInfo(playlists.first(), csrfToken, media.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 { | ||||
|     private fun loadStreamInfo(playlistPath: String, csrfToken: String, type: MediaType): List<Episode> = runBlocking { | ||||
|         withContext(Dispatchers.Default) { | ||||
|             val headers = mutableMapOf( | ||||
|                 Pair("Accept", "application/json, text/javascript, */*; q=0.01"), | ||||
| @ -151,36 +152,36 @@ class AoDParser { | ||||
|  | ||||
|             //println(res.body()) | ||||
|  | ||||
|             println(type) | ||||
|             return@withContext when (type) { | ||||
|                 MediaType.MOVIE -> { | ||||
|                     val movie = JsonParser.parseString(res.body()).asJsonObject | ||||
|                         .get("playlist").asJsonArray | ||||
|  | ||||
|                     val streamList = arrayListOf<String>() | ||||
|                     movie.first().asJsonObject.get("sources").asJsonArray.toList().forEach { | ||||
|                         streamList.add(it.asJsonObject.get("file").asString) | ||||
|                     movie.first().asJsonObject.get("sources").asJsonArray.toList().map { | ||||
|                         Episode(streamUrl = it.asJsonObject.get("file").asString) | ||||
|                     } | ||||
|  | ||||
|                     StreamMedia(MediaType.MOVIE, streamList) | ||||
|                 } | ||||
|                 MediaType.TVSHOW -> { | ||||
|                     val episodes = JsonParser.parseString(res.body()).asJsonObject | ||||
|                     val episodesJson = JsonParser.parseString(res.body()).asJsonObject | ||||
|                         .get("playlist").asJsonArray | ||||
|  | ||||
|                     val streamList = arrayListOf<String>() | ||||
|                     episodes.forEach { | ||||
|                         val streamUrl = it.asJsonObject.get("sources").asJsonArray | ||||
|  | ||||
|                     episodesJson.map { | ||||
|                         val episodeStream = it.asJsonObject.get("sources").asJsonArray | ||||
|                             .first().asJsonObject | ||||
|                             .get("file").asString | ||||
|                         streamList.add(streamUrl) | ||||
|                         val episodeTitle = it.asJsonObject.get("title").asString | ||||
|  | ||||
|                         Episode( | ||||
|                             episodeTitle, | ||||
|                             episodeStream | ||||
|                         ) | ||||
|                     } | ||||
|  | ||||
|                     StreamMedia(MediaType.TVSHOW, streamList) | ||||
|                 } | ||||
|                 else -> { | ||||
|                     Log.e(javaClass.name, "Wrong Type, please report this issue.") | ||||
|                     StreamMedia(MediaType.OTHER) | ||||
|                     listOf() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -14,10 +14,9 @@ import org.mosad.teapod.MainActivity | ||||
| import org.mosad.teapod.R | ||||
| import org.mosad.teapod.util.DataTypes.MediaType | ||||
| import org.mosad.teapod.util.EpisodesAdapter | ||||
| import org.mosad.teapod.util.GUIMedia | ||||
| import org.mosad.teapod.util.StreamMedia | ||||
| import org.mosad.teapod.util.Media | ||||
|  | ||||
| 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 viewManager: RecyclerView.LayoutManager | ||||
| @ -31,53 +30,47 @@ class MediaFragment(private val guiMedia: GUIMedia, private val streamMedia: Str | ||||
|         super.onViewCreated(view, savedInstanceState) | ||||
|  | ||||
|         // generic gui | ||||
|         Glide.with(requireContext()).load(guiMedia.posterLink).into(image_poster) | ||||
|         text_title.text = guiMedia.title | ||||
|         text_desc.text = guiMedia.shortDesc | ||||
|         Glide.with(requireContext()).load(media.posterLink).into(image_poster) | ||||
|         text_title.text = media.title | ||||
|         text_desc.text = media.shortDesc | ||||
|  | ||||
|         // specific gui | ||||
|         if (streamMedia.type == MediaType.TVSHOW) { | ||||
|             val episodes = streamMedia.streams.mapIndexed { index, _ -> | ||||
|                 "${guiMedia.title} - Ep. ${index + 1}" | ||||
|             } | ||||
|         if (media.type == MediaType.TVSHOW) { | ||||
|             // TODO | ||||
|             val episodeTitles = media.episodes.map { it.title } | ||||
|  | ||||
|  | ||||
|             adapterRecEpisodes = EpisodesAdapter(episodes) | ||||
|             adapterRecEpisodes = EpisodesAdapter(episodeTitles) | ||||
|             viewManager = LinearLayoutManager(context) | ||||
|             recycler_episodes.layoutManager = viewManager | ||||
|             recycler_episodes.adapter = adapterRecEpisodes | ||||
|  | ||||
|         } else if (streamMedia.type == MediaType.MOVIE) { | ||||
|         } else if (media.type == MediaType.MOVIE) { | ||||
|             recycler_episodes.visibility = View.GONE | ||||
|         } | ||||
|  | ||||
|  | ||||
|         println("media streams: ${streamMedia.streams}") | ||||
|         println("media streams: ${media.episodes}") | ||||
|  | ||||
|         initActions() | ||||
|     } | ||||
|  | ||||
|     private fun initActions() { | ||||
|         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 | ||||
|         if (this::adapterRecEpisodes.isInitialized) { | ||||
|             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) { | ||||
|         val mainActivity = activity as MainActivity | ||||
|         mainActivity.startPlayer(url) | ||||
|  | ||||
| @ -11,7 +11,7 @@ import org.mosad.teapod.MainActivity | ||||
| import org.mosad.teapod.R | ||||
| import org.mosad.teapod.parser.AoDParser | ||||
| import org.mosad.teapod.util.CustomAdapter | ||||
| import org.mosad.teapod.util.GUIMedia | ||||
| import org.mosad.teapod.util.Media | ||||
|  | ||||
| class LibraryFragment : Fragment() { | ||||
|  | ||||
| @ -41,7 +41,7 @@ class LibraryFragment : Fragment() { | ||||
|  | ||||
|     private fun initActions() { | ||||
|         list_library.setOnItemClickListener { _, _, position, _ -> | ||||
|             val media = adapter.getItem(position) as GUIMedia | ||||
|             val media = adapter.getItem(position) as Media | ||||
|             println("selected item is: ${media.title}") | ||||
|  | ||||
|             val mainActivity = activity as MainActivity | ||||
|  | ||||
| @ -12,7 +12,7 @@ import org.mosad.teapod.MainActivity | ||||
| import org.mosad.teapod.R | ||||
| import org.mosad.teapod.parser.AoDParser | ||||
| import org.mosad.teapod.util.CustomAdapter | ||||
| import org.mosad.teapod.util.GUIMedia | ||||
| import org.mosad.teapod.util.Media | ||||
|  | ||||
| class SearchFragment : Fragment() { | ||||
|  | ||||
| @ -55,7 +55,7 @@ class SearchFragment : Fragment() { | ||||
|         }) | ||||
|  | ||||
|         list_search.setOnItemClickListener { _, _, position, _ -> | ||||
|             val media = adapter.getItem(position) as GUIMedia | ||||
|             val media = adapter.getItem(position) as Media | ||||
|  | ||||
|             println("selected item is: ${media.title}") | ||||
|  | ||||
|  | ||||
| @ -1,21 +1,15 @@ | ||||
| package org.mosad.teapod.util | ||||
|  | ||||
| import android.content.Context | ||||
| import android.graphics.Bitmap | ||||
| import android.graphics.drawable.Drawable | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import android.widget.* | ||||
| import androidx.core.content.res.ResourcesCompat | ||||
| 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 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 val customFilter = CustomFilter() | ||||
| @ -68,7 +62,7 @@ class CustomAdapter(val context: Context, private val originalMedia: ArrayList<G | ||||
|         } | ||||
|  | ||||
|         override fun publishResults(constraint: CharSequence?, results: FilterResults?) { | ||||
|             filteredMedia = results?.values as ArrayList<GUIMedia> | ||||
|             filteredMedia = results?.values as ArrayList<Media> | ||||
|             notifyDataSetChanged() | ||||
|         } | ||||
|  | ||||
|  | ||||
| @ -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 GUIMedia(val title: String, val posterLink: String, val shortDesc : String, val link: String) { | ||||
| data class Media(val title: String, val link: String, val type: DataTypes.MediaType, val posterLink: String, val shortDesc : String, var episodes: List<Episode> = listOf()) { | ||||
|     override fun toString(): String { | ||||
|         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) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user