added stuff to MainAPI

This commit is contained in:
LagradOst 2021-07-24 01:44:54 +02:00
parent 79328502b4
commit 8c0a6dffe9
9 changed files with 152 additions and 102 deletions

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>

View file

@ -10,13 +10,10 @@ import com.lagradost.cloudstream3.animeproviders.ShiroProvider
import com.lagradost.cloudstream3.animeproviders.TenshiProvider
import com.lagradost.cloudstream3.animeproviders.WcoProvider
import com.lagradost.cloudstream3.movieproviders.HDMProvider
import com.lagradost.cloudstream3.movieproviders.LookMovieProvider
import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider
import com.lagradost.cloudstream3.movieproviders.TrailersToProvider
import com.lagradost.cloudstream3.utils.ExtractorLink
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; rv:68.0) Gecko/20100101 Firefox/68.0"
val baseHeader = mapOf("User-Agent" to USER_AGENT)
@ -38,7 +35,7 @@ object APIHolder {
MeloMovieProvider(),
DubbedAnimeProvider(),
HDMProvider(),
LookMovieProvider(),
//LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
TrailersToProvider(),
)
@ -60,13 +57,23 @@ object APIHolder {
}
}
/**Every provider will **not** have try catch built in, so handle exceptions when calling these functions*/
abstract class MainAPI {
open val name = "NONE"
open val mainUrl = "NONE"
open val instantLinkLoading = false // THIS IS IF THE LINK IS STORED IN THE "DATA"
/**If link is stored in the "data" string, so links can be instantly loaded*/
open val instantLinkLoading = false
open val hasQuickSearch = false
open fun search(query: String): ArrayList<SearchResponse>? { // SearchResponse
/**Set false if links require referer or for some reason cant be played on a chromecast*/
open val hasChromecastSupport = true
/**If all links are m3u8 then set this to false*/
open val hasDownloadSupport = true
open fun search(query: String): ArrayList<SearchResponse>? {
return null
}
@ -78,7 +85,7 @@ abstract class MainAPI {
return null
}
// callback is fired once a link is found, will return true if method is executed successfully
/**Callback is fired once a link is found, will return true if method is executed successfully*/
open fun loadLinks(
data: String,
isCasting: Boolean,

View file

@ -10,6 +10,8 @@ class HDMProvider : MainAPI() {
get() = "HD Movies"
override val mainUrl: String
get() = "https://hdm.to"
override val hasDownloadSupport: Boolean
get() = false
override fun search(query: String): ArrayList<SearchResponse> {
val url = "$mainUrl/search/$query"

View file

@ -17,6 +17,8 @@ class MeloMovieProvider : MainAPI() {
get() = true
override val hasQuickSearch: Boolean
get() = true
override val hasChromecastSupport: Boolean
get() = false // MKV FILES CANT BE PLAYED ON A CHROMECAST
data class MeloMovieSearchResult(
@JsonProperty("id") val id: Int,

View file

@ -1,28 +1,17 @@
package com.lagradost.cloudstream3.ui.result
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.model.GlideUrl
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastState
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.UIHelper.hideSystemUI
import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable
import com.lagradost.cloudstream3.UIHelper.isConnectedToChromecast
import com.lagradost.cloudstream3.utils.getId
import com.lagradost.cloudstream3.R
import kotlinx.android.synthetic.main.result_episode.view.episode_holder
import kotlinx.android.synthetic.main.result_episode.view.episode_text
import kotlinx.android.synthetic.main.result_episode_large.view.*
@ -42,10 +31,13 @@ const val ACTION_COPY_LINK = 9
const val ACTION_SHOW_OPTIONS = 10
const val ACTION_CLICK_DEFAULT = 11
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
class EpisodeAdapter(
var cardList: List<ResultEpisode>,
val hasDownloadSupport : Boolean,
private val clickCallback: (EpisodeClickEvent) -> Unit,
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
@ -64,6 +56,7 @@ class EpisodeAdapter(
return CardViewHolder(
LayoutInflater.from(parent.context).inflate(layout, parent, false),
hasDownloadSupport,
clickCallback
)
}
@ -83,6 +76,7 @@ class EpisodeAdapter(
class CardViewHolder
constructor(
itemView: View,
private val hasDownloadSupport : Boolean,
private val clickCallback: (EpisodeClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView) {
private val episodeText: TextView = itemView.episode_text
@ -131,13 +125,7 @@ class EpisodeAdapter(
}
episodeHolder.setOnClickListener {
episodeHolder.context?.let { ctx ->
if (ctx.isConnectedToChromecast()) {
clickCallback.invoke(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card))
} else {
clickCallback.invoke(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
}
}
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
}
episodeHolder.setOnLongClickListener {
@ -146,6 +134,8 @@ class EpisodeAdapter(
return@setOnLongClickListener true
}
episodeDownload?.visibility = if(hasDownloadSupport) View.VISIBLE else View.GONE
episodeDownload?.setOnClickListener {
clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card))
}

View file

@ -227,25 +227,37 @@ class ResultFragment : Fragment() {
)
result_back.layoutParams = backParameter
if (activity?.isCastApiAvailable() == true) {
CastButtonFactory.setUpMediaRouteButton(activity, media_route_button)
val castContext = CastContext.getSharedInstance(requireActivity().applicationContext)
if (castContext.castState != CastState.NO_DEVICES_AVAILABLE) media_route_button.visibility = VISIBLE
castContext.addCastStateListener { state ->
if (media_route_button != null) {
if (state == CastState.NO_DEVICES_AVAILABLE) media_route_button.visibility = GONE else {
if (media_route_button.visibility == GONE) media_route_button.visibility = VISIBLE
}
}
}
}
// activity?.fixPaddingStatusbar(result_toolbar)
url = arguments?.getString("url")
val slug = arguments?.getString("slug")
val apiName = arguments?.getString("apiName")
val apiName = arguments?.getString("apiName") ?: return
val api = getApiFromName(apiName)
if (media_route_button != null) {
val chromecastSupport = api.hasChromecastSupport
media_route_button?.alpha = if (chromecastSupport) 1f else 0.3f
if (!chromecastSupport) {
media_route_button.setOnClickListener {
Toast.makeText(it.context, "This provider has no chromecast support", Toast.LENGTH_LONG).show()
}
}
if (activity?.isCastApiAvailable() == true) {
CastButtonFactory.setUpMediaRouteButton(activity, media_route_button)
val castContext = CastContext.getSharedInstance(requireActivity().applicationContext)
if (castContext.castState != CastState.NO_DEVICES_AVAILABLE) media_route_button.visibility = VISIBLE
castContext.addCastStateListener { state ->
if (media_route_button != null) {
if (state == CastState.NO_DEVICES_AVAILABLE) media_route_button.visibility = GONE else {
if (media_route_button.visibility == GONE) media_route_button.visibility = VISIBLE
}
}
}
}
}
result_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, _ ->
if (result_poster_blur == null) return@OnScrollChangeListener
result_poster_blur.alpha = maxOf(0f, (0.7f - scrollY / 1000f))
@ -397,7 +409,10 @@ class ResultFragment : Fragment() {
val epData = episodeClick.data
ctx.setKey(
getFolderName(DOWNLOAD_EPISODE_CACHE, (currentId ?: return@let).toString()), // 3 deep folder for faster acess
getFolderName(
DOWNLOAD_EPISODE_CACHE,
(currentId ?: return@let).toString()
), // 3 deep folder for faster acess
epData.id.toString(),
VideoDownloadHelper.DownloadEpisodeCached(
epData.name,
@ -431,6 +446,16 @@ class ResultFragment : Fragment() {
if (!isLoaded) return@main // CANT LOAD
when (episodeClick.action) {
ACTION_CLICK_DEFAULT -> {
context?.let { ctx ->
if (ctx.isConnectedToChromecast()) {
handleAction(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, episodeClick.data))
} else {
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, episodeClick.data))
}
}
}
ACTION_SHOW_OPTIONS -> {
val builder = AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
var dialog: AlertDialog? = null
@ -442,6 +467,8 @@ class ResultFragment : Fragment() {
val verifiedOptions = ArrayList<String>()
val verifiedOptionsValues = ArrayList<Int>()
val hasDownloadSupport = api.hasDownloadSupport
for (i in options.indices) {
val opv = optionsValues[i]
val op = options[i]
@ -450,6 +477,8 @@ class ResultFragment : Fragment() {
val add = when (opv) {
ACTION_CHROME_CAST_EPISODE -> isConnected
ACTION_CHROME_CAST_MIRROR -> isConnected
ACTION_DOWNLOAD_EPISODE -> hasDownloadSupport
ACTION_DOWNLOAD_MIRROR -> hasDownloadSupport
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> context?.isAppInstalled(VLC_PACKAGE) ?: false
else -> true
}
@ -482,7 +511,7 @@ class ResultFragment : Fragment() {
ACTION_PLAY_EPISODE_IN_BROWSER -> {
aquireSingeExtractorLink("Play in Browser") { link ->
val i = Intent(Intent.ACTION_VIEW)
val i = Intent(ACTION_VIEW)
i.data = Uri.parse(link.url)
startActivity(i)
}
@ -595,11 +624,11 @@ class ResultFragment : Fragment() {
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
EpisodeAdapter(
ArrayList(),
api.hasDownloadSupport,
) { episodeClick ->
handleAction(episodeClick)
}
result_episodes.adapter = adapter
result_episodes.layoutManager = GridLayoutManager(context, 1)
@ -678,17 +707,17 @@ class ResultFragment : Fragment() {
currentIsMovie = !d.isEpisodeBased()
result_openinbrower.setOnClickListener {
val i = Intent(Intent.ACTION_VIEW)
val i = Intent(ACTION_VIEW)
i.data = Uri.parse(d.url)
startActivity(i)
}
result_share.setOnClickListener {
val i = Intent(Intent.ACTION_SEND)
val i = Intent(ACTION_SEND)
i.type = "text/plain"
i.putExtra(Intent.EXTRA_SUBJECT, d.name)
i.putExtra(Intent.EXTRA_TEXT, d.url)
startActivity(Intent.createChooser(i, d.name))
i.putExtra(EXTRA_SUBJECT, d.name)
i.putExtra(EXTRA_TEXT, d.url)
startActivity(createChooser(i, d.name))
}
val metadataInfoArray = ArrayList<Pair<String, String>>()
@ -713,6 +742,8 @@ class ResultFragment : Fragment() {
val duration = d.duration
if (duration != null) metadataInfoArray.add(Pair("Duration", duration))
metadataInfoArray.add(Pair("Site", d.apiName))
if (metadataInfoArray.size > 0) {
result_metadata.visibility = VISIBLE
val text = SpannableStringBuilder()
@ -777,37 +808,23 @@ class ResultFragment : Fragment() {
}
}
when (d.type) {
TvType.Movie -> {
result_play_movie.visibility = VISIBLE
result_episodes_text.visibility = GONE
result_episodes.visibility = GONE
if (d.type == TvType.Movie && d is MovieLoadResponse) {
result_movie_parent.visibility = VISIBLE
result_episodes_text.visibility = GONE
result_episodes.visibility = GONE
result_play_movie.setOnClickListener {
val card = currentEpisodes?.first() ?: return@setOnClickListener
if (requireContext().isCastApiAvailable()) {
val castContext = CastContext.getSharedInstance(requireContext())
if (castContext.castState == CastState.CONNECTED) {
handleAction(EpisodeClickEvent(ACTION_CHROME_CAST_EPISODE, card))
} else {
handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, card))
}
} else {
handleAction(
EpisodeClickEvent(
ACTION_PLAY_EPISODE_IN_PLAYER,
card
)
) //TODO REDO TO MAIN
}
}
result_play_movie.setOnClickListener {
val card = currentEpisodes?.first() ?: return@setOnClickListener
handleAction(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
}
else -> {
result_play_movie.visibility = GONE
result_episodes_text.visibility = VISIBLE
result_episodes.visibility = VISIBLE
result_options.setOnClickListener {
val card = currentEpisodes?.first() ?: return@setOnClickListener
handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
}
} else {
result_movie_parent.visibility = GONE
result_episodes_text.visibility = VISIBLE
result_episodes.visibility = VISIBLE
}
when (d) {
@ -842,7 +859,7 @@ class ResultFragment : Fragment() {
if (url != null) {
result_reload_connection_open_in_browser.setOnClickListener {
val i = Intent(Intent.ACTION_VIEW)
val i = Intent(ACTION_VIEW)
i.data = Uri.parse(url)
startActivity(i)
}

View file

@ -165,9 +165,10 @@ class ResultViewModel : ViewModel() {
updateEpisodes(
context, mainId, arrayListOf(
context.buildResultEpisode(
d.name,
null,
0,
null,
0, null,
d.dataUrl,
d.apiName,
(mainId + 1),
@ -211,7 +212,7 @@ class ResultViewModel : ViewModel() {
suspend fun loadEpisode(
episode: ResultEpisode,
isCasting: Boolean,
) : Resource<ResultViewModel.EpisodeData> {
): Resource<EpisodeData> {
return loadEpisode(episode.id, episode.data, isCasting)
}
@ -219,7 +220,7 @@ class ResultViewModel : ViewModel() {
id: Int,
data: String,
isCasting: Boolean,
): Resource<ResultViewModel.EpisodeData> {
): Resource<EpisodeData> {
if (_allEpisodes.value?.contains(id) == true) {
_allEpisodes.value?.remove(id)
}

View file

@ -286,27 +286,56 @@
android:layout_height="wrap_content">
</com.lagradost.cloudstream3.widget.FlowLayout>
<com.google.android.material.button.MaterialButton
android:visibility="visible"
android:layout_gravity="center_vertical"
app:cornerRadius="4dp"
android:id="@+id/result_play_movie"
android:text="@string/play_movie_button"
app:rippleColor="?attr/colorPrimary"
android:textColor="?attr/textColor"
app:iconTint="?attr/textColor"
android:textAllCaps="false"
android:clickable="true"
android:focusable="true"
app:iconGravity="textStart"
app:strokeColor="?attr/textColor"
app:icon="@drawable/ic_baseline_play_arrow_24"
android:backgroundTint="@color/transparent"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
<LinearLayout
android:orientation="vertical"
android:id="@+id/result_movie_parent"
android:layout_width="match_parent"
android:layout_height="45dp">
</com.google.android.material.button.MaterialButton>
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
android:visibility="visible"
android:layout_gravity="center_vertical"
app:cornerRadius="4dp"
android:id="@+id/result_play_movie"
android:text="@string/play_movie_button"
app:rippleColor="?attr/textColor"
android:textColor="?attr/textColor"
app:iconTint="?attr/textColor"
android:textAllCaps="false"
android:clickable="true"
android:focusable="true"
app:iconGravity="textStart"
app:strokeColor="?attr/textColor"
app:icon="@drawable/ic_baseline_play_arrow_24"
android:backgroundTint="@color/transparent"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="45dp">
</com.google.android.material.button.MaterialButton>
<com.google.android.material.button.MaterialButton
android:visibility="visible"
android:layout_gravity="center_vertical"
app:cornerRadius="4dp"
android:id="@+id/result_options"
android:text="@string/options"
app:rippleColor="?attr/textColor"
android:textColor="?attr/textColor"
app:iconTint="?attr/textColor"
android:textAllCaps="false"
android:clickable="true"
android:focusable="true"
app:iconGravity="textStart"
app:strokeColor="?attr/textColor"
app:icon="@drawable/ic_baseline_play_arrow_24"
android:backgroundTint="@color/transparent"
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="45dp">
</com.google.android.material.button.MaterialButton>
</LinearLayout>
<LinearLayout android:orientation="horizontal" android:gravity="center_vertical" android:layout_width="match_parent" android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
@ -314,7 +343,7 @@
android:layout_gravity="center_vertical"
app:cornerRadius="4dp"
android:id="@+id/result_season_button"
tools:text="Bookmark"
tools:text="Subbed"
app:rippleColor="?attr/bitDarkerGrayBackground"
android:textColor="?attr/textColor"

View file

@ -41,4 +41,5 @@
<string name="download_descript">Download</string>
<string name="error_loading_links">Error Loading Links</string>
<string name="download_storage_text">Internal Storage</string>
<string name="options">Options</string>
</resources>