fixed #832 and fixed #835

This commit is contained in:
LagradOst 2022-03-21 00:59:17 +01:00
parent c2ba8dc7e4
commit 2870ad435f
9 changed files with 444 additions and 394 deletions

View file

@ -281,7 +281,8 @@ object APIHolder {
3 = restricted, must donate 30 benenes to use 3 = restricted, must donate 30 benenes to use
*/ */
const val PROVIDER_STATUS_KEY = "PROVIDER_STATUS_KEY" const val PROVIDER_STATUS_KEY = "PROVIDER_STATUS_KEY"
const val PROVIDER_STATUS_URL = "https://raw.githubusercontent.com/LagradOst/CloudStream-3/master/providers.json" const val PROVIDER_STATUS_URL =
"https://raw.githubusercontent.com/LagradOst/CloudStream-3/master/providers.json"
const val PROVIDER_STATUS_BETA_ONLY = 3 const val PROVIDER_STATUS_BETA_ONLY = 3
const val PROVIDER_STATUS_SLOW = 2 const val PROVIDER_STATUS_SLOW = 2
const val PROVIDER_STATUS_OK = 1 const val PROVIDER_STATUS_OK = 1
@ -540,13 +541,28 @@ class HomePageList(
var list: List<SearchResponse> var list: List<SearchResponse>
) )
enum class SearchQuality {
//https://en.wikipedia.org/wiki/Pirated_movie_release_types
Cam,
CamRip,
HdCam,
Telesync, // TS
WorkPrint,
Telecine, // TC
HQ,
HD,
BlueRay,
DVD,
}
interface SearchResponse { interface SearchResponse {
val name: String val name: String
val url: String val url: String
val apiName: String val apiName: String
val type: TvType? var type: TvType?
val posterUrl: String? var posterUrl: String?
val id: Int? var id: Int?
var quality : SearchQuality?
} }
enum class ActorRole { enum class ActorRole {
@ -571,49 +587,53 @@ data class AnimeSearchResponse(
override val name: String, override val name: String,
override val url: String, override val url: String,
override val apiName: String, override val apiName: String,
override val type: TvType, override var type: TvType?,
override val posterUrl: String?, override var posterUrl: String?,
val year: Int? = null, val year: Int? = null,
val dubStatus: EnumSet<DubStatus>? = null, val dubStatus: EnumSet<DubStatus>? = null,
val otherName: String? = null, val otherName: String? = null,
val dubEpisodes: Int? = null, val dubEpisodes: Int? = null,
val subEpisodes: Int? = null, val subEpisodes: Int? = null,
override val id: Int? = null, override var id: Int? = null,
override var quality: SearchQuality? = null,
) : SearchResponse ) : SearchResponse
data class TorrentSearchResponse( data class TorrentSearchResponse(
override val name: String, override val name: String,
override val url: String, override val url: String,
override val apiName: String, override val apiName: String,
override val type: TvType, override var type: TvType?,
override val posterUrl: String?, override var posterUrl: String?,
override val id: Int? = null, override var id: Int? = null,
override var quality: SearchQuality? = null,
) : SearchResponse ) : SearchResponse
data class MovieSearchResponse( data class MovieSearchResponse(
override val name: String, override val name: String,
override val url: String, override val url: String,
override val apiName: String, override val apiName: String,
override val type: TvType, override var type: TvType?,
override val posterUrl: String?, override var posterUrl: String?,
val year: Int? = null, val year: Int? = null,
override val id: Int? = null, override var id: Int? = null,
override var quality: SearchQuality? = null,
) : SearchResponse ) : SearchResponse
data class TvSeriesSearchResponse( data class TvSeriesSearchResponse(
override val name: String, override val name: String,
override val url: String, override val url: String,
override val apiName: String, override val apiName: String,
override val type: TvType, override var type: TvType?,
override val posterUrl: String?, override var posterUrl: String?,
val year: Int?, val year: Int?,
val episodes: Int?, val episodes: Int?,
override val id: Int? = null, override var id: Int? = null,
override var quality: SearchQuality? = null,
) : SearchResponse ) : SearchResponse
interface LoadResponse { interface LoadResponse {
@ -630,6 +650,7 @@ interface LoadResponse {
val trailerUrl: String? val trailerUrl: String?
var recommendations: List<SearchResponse>? var recommendations: List<SearchResponse>?
var actors: List<ActorData>? var actors: List<ActorData>?
var comingSoon: Boolean
companion object { companion object {
@JvmName("addActorNames") @JvmName("addActorNames")
@ -715,6 +736,7 @@ data class TorrentLoadResponse(
override var trailerUrl: String? = null, override var trailerUrl: String? = null,
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false,
) : LoadResponse ) : LoadResponse
data class AnimeLoadResponse( data class AnimeLoadResponse(
@ -742,6 +764,7 @@ data class AnimeLoadResponse(
override var trailerUrl: String? = null, override var trailerUrl: String? = null,
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false,
) : LoadResponse ) : LoadResponse
fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<AnimeEpisode>?) { fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<AnimeEpisode>?) {
@ -753,13 +776,31 @@ fun MainAPI.newAnimeLoadResponse(
name: String, name: String,
url: String, url: String,
type: TvType, type: TvType,
initializer: AnimeLoadResponse.() -> Unit = { } comingSoonIfNone : Boolean,
initializer: AnimeLoadResponse.() -> Unit = { },
): AnimeLoadResponse { ): AnimeLoadResponse {
val builder = AnimeLoadResponse(name = name, url = url, apiName = this.name, type = type) val builder = AnimeLoadResponse(name = name, url = url, apiName = this.name, type = type)
builder.initializer() builder.initializer()
if(comingSoonIfNone) {
builder.comingSoon = true
for (key in builder.episodes.keys)
if(!builder.episodes[key].isNullOrEmpty()) {
builder.comingSoon = false
break
}
}
return builder return builder
} }
fun MainAPI.newAnimeLoadResponse(
name: String,
url: String,
type: TvType,
initializer: AnimeLoadResponse.() -> Unit = { },
): AnimeLoadResponse {
return newAnimeLoadResponse(name, url, type, true, initializer)
}
data class MovieLoadResponse( data class MovieLoadResponse(
override var name: String, override var name: String,
override var url: String, override var url: String,
@ -778,6 +819,7 @@ data class MovieLoadResponse(
override var trailerUrl: String? = null, override var trailerUrl: String? = null,
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false,
) : LoadResponse ) : LoadResponse
fun MainAPI.newMovieLoadResponse( fun MainAPI.newMovieLoadResponse(
@ -792,7 +834,8 @@ fun MainAPI.newMovieLoadResponse(
url = url, url = url,
apiName = this.name, apiName = this.name,
type = type, type = type,
dataUrl = dataUrl dataUrl = dataUrl,
comingSoon = dataUrl.isBlank()
) )
builder.initializer() builder.initializer()
return builder return builder
@ -828,6 +871,7 @@ data class TvSeriesLoadResponse(
override var trailerUrl: String? = null, override var trailerUrl: String? = null,
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false,
) : LoadResponse ) : LoadResponse
fun MainAPI.newTvSeriesLoadResponse( fun MainAPI.newTvSeriesLoadResponse(
@ -842,7 +886,8 @@ fun MainAPI.newTvSeriesLoadResponse(
url = url, url = url,
apiName = this.name, apiName = this.name,
type = type, type = type,
episodes = episodes episodes = episodes,
comingSoon = episodes.isEmpty(),
) )
builder.initializer() builder.initializer()
return builder return builder

View file

@ -157,7 +157,7 @@ open class SflixProvider() : MainAPI() {
val dataId = details.attr("data-id") val dataId = details.attr("data-id")
val id = if (dataId.isNullOrEmpty()) val id = if (dataId.isNullOrEmpty())
idRegex.find(url)?.groupValues?.get(1) idRegex.find(url)?.groupValues?.get(1)
?: throw RuntimeException("Unable to get id from '$url'") ?: throw ErrorLoadingException("Unable to get id from '$url'")
else dataId else dataId
val recommendations = val recommendations =
@ -199,6 +199,8 @@ open class SflixProvider() : MainAPI() {
} }
} }
val comingSoon = sourceIds.isEmpty()
return newMovieLoadResponse(title, url, TvType.Movie, sourceIds.toJson()) { return newMovieLoadResponse(title, url, TvType.Movie, sourceIds.toJson()) {
this.year = year this.year = year
this.posterUrl = posterUrl this.posterUrl = posterUrl
@ -207,6 +209,7 @@ open class SflixProvider() : MainAPI() {
addActors(cast) addActors(cast)
this.tags = tags this.tags = tags
this.recommendations = recommendations this.recommendations = recommendations
this.comingSoon = comingSoon
} }
} else { } else {
val seasonsDocument = app.get("$mainUrl/ajax/v2/tv/seasons/$id").document val seasonsDocument = app.get("$mainUrl/ajax/v2/tv/seasons/$id").document
@ -252,6 +255,7 @@ open class SflixProvider() : MainAPI() {
) )
} }
} }
return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) {
this.posterUrl = posterUrl this.posterUrl = posterUrl
this.year = year this.year = year

View file

@ -1375,7 +1375,8 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
val sourceDialog = sourceBuilder.create() val sourceDialog = sourceBuilder.create()
sourceDialog.show() sourceDialog.show()
sourceDialog.findViewById<ImageView?>(R.id.imgPoster)?.apply { sourceDialog.findViewById<ImageView?>(R.id.imgPoster)
?.apply {
setImageBitmap(bitmap) setImageBitmap(bitmap)
setOnClickListener { setOnClickListener {
sourceDialog.dismissSafe() sourceDialog.dismissSafe()
@ -1423,6 +1424,11 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
//result_tag_holder?.visibility = GONE //result_tag_holder?.visibility = GONE
// result_status.visibility = GONE // result_status.visibility = GONE
d.comingSoon.let { soon ->
result_coming_soon?.isVisible = soon
result_data_holder?.isGone = soon
}
val tags = d.tags val tags = d.tags
if (tags.isNullOrEmpty()) { if (tags.isNullOrEmpty()) {
//result_tag_holder?.visibility = GONE //result_tag_holder?.visibility = GONE

View file

@ -150,7 +150,7 @@ object SearchResultBuilder {
playImg?.visibility = View.VISIBLE playImg?.visibility = View.VISIBLE
if (!card.type.isMovieType()) { if (card.type?.isMovieType() == false) {
cardText?.text = cardText?.text =
cardText?.context?.getNameFull(card.name, card.episode, card.season) cardText?.context?.getNameFull(card.name, card.episode, card.season)
} }

View file

@ -4,11 +4,8 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.ErrorLoadingException
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.SyncApis
@ -54,9 +51,10 @@ class SearchViewModel : ViewModel() {
override val name: String, override val name: String,
override val url: String, override val url: String,
override val apiName: String, override val apiName: String,
override val type: TvType?, override var type: TvType?,
override val posterUrl: String?, override var posterUrl: String?,
override val id: Int?, override var id: Int?,
override var quality: SearchQuality? = null
) : SearchResponse ) : SearchResponse
private fun SyncAPI.SyncSearchResult.toSearchResponse(): SyncSearchResultSearchResponse { private fun SyncAPI.SyncSearchResult.toSearchResponse(): SyncSearchResultSearchResponse {

View file

@ -63,7 +63,7 @@ object AppUtils {
context: Context, context: Context,
card: DataStoreHelper.ResumeWatchingResult card: DataStoreHelper.ResumeWatchingResult
): WatchNextProgram { ): WatchNextProgram {
val isSeries = !card.type.isMovieType() val isSeries = card.type?.isMovieType() == false
val title = if (isSeries) { val title = if (isSeries) {
context.getNameFull(card.name, card.episode, card.season) context.getNameFull(card.name, card.episode, card.season)
} else { } else {

View file

@ -6,6 +6,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.DubStatus import com.lagradost.cloudstream3.DubStatus
import com.lagradost.cloudstream3.SearchQuality
import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
@ -33,31 +34,33 @@ object DataStoreHelper {
} }
data class BookmarkedData( data class BookmarkedData(
@JsonProperty("id") override val id: Int?, @JsonProperty("id") override var id: Int?,
@JsonProperty("bookmarkedTime") val bookmarkedTime: Long, @JsonProperty("bookmarkedTime") val bookmarkedTime: Long,
@JsonProperty("latestUpdatedTime") val latestUpdatedTime: Long, @JsonProperty("latestUpdatedTime") val latestUpdatedTime: Long,
@JsonProperty("name") override val name: String, @JsonProperty("name") override val name: String,
@JsonProperty("url") override val url: String, @JsonProperty("url") override val url: String,
@JsonProperty("apiName") override val apiName: String, @JsonProperty("apiName") override val apiName: String,
@JsonProperty("type") override val type: TvType, @JsonProperty("type") override var type: TvType? = null,
@JsonProperty("posterUrl") override val posterUrl: String?, @JsonProperty("posterUrl") override var posterUrl: String?,
@JsonProperty("year") val year: Int?, @JsonProperty("year") val year: Int?,
@JsonProperty("quality") override var quality: SearchQuality? = null
) : SearchResponse ) : SearchResponse
data class ResumeWatchingResult( data class ResumeWatchingResult(
@JsonProperty("name") override val name: String, @JsonProperty("name") override val name: String,
@JsonProperty("url") override val url: String, @JsonProperty("url") override val url: String,
@JsonProperty("apiName") override val apiName: String, @JsonProperty("apiName") override val apiName: String,
@JsonProperty("type") override val type: TvType, @JsonProperty("type") override var type: TvType? = null,
@JsonProperty("posterUrl") override val posterUrl: String?, @JsonProperty("posterUrl") override var posterUrl: String?,
@JsonProperty("watchPos") val watchPos: PosDur?, @JsonProperty("watchPos") val watchPos: PosDur?,
@JsonProperty("id") override val id: Int?, @JsonProperty("id") override var id: Int?,
@JsonProperty("parentId") val parentId: Int?, @JsonProperty("parentId") val parentId: Int?,
@JsonProperty("episode") val episode: Int?, @JsonProperty("episode") val episode: Int?,
@JsonProperty("season") val season: Int?, @JsonProperty("season") val season: Int?,
@JsonProperty("isFromDownload") val isFromDownload: Boolean, @JsonProperty("isFromDownload") val isFromDownload: Boolean,
@JsonProperty("quality") override var quality: SearchQuality? = null
) : SearchResponse ) : SearchResponse
var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION

View file

@ -459,6 +459,24 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<TextView
android:paddingTop="50dp"
android:visibility="gone"
android:textColor="?attr/textColor"
android:id="@+id/result_coming_soon"
android:textSize="20sp"
android:gravity="center"
android:textStyle="bold"
android:layout_gravity="center"
android:text="@string/coming_soon"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:orientation="vertical"
android:id="@+id/result_data_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:visibility="gone" android:visibility="gone"
android:text="@string/add_sync" android:text="@string/add_sync"
@ -706,44 +724,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:ignore="RtlSymmetry" /> tools:ignore="RtlSymmetry" />
</LinearLayout> </LinearLayout>
<!--<TextView
android:visibility="gone"
android:drawableLeft="@drawable/ic_baseline_play_arrow_24"
android:gravity="center_vertical"
android:textSize="20sp"
android:textColor="?attr/textColor"
android:text="More like this"
android:layout_width="wrap_content" android:layout_height="60dp">
</TextView>
<com.google.android.material.tabs.TabLayout
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabTextColor="?attr/textColor"
android:foreground="@color/transparent"
android:backgroundTint="@color/transparent"
app:tabIndicatorGravity="top"
android:textAllCaps="false"
app:tabIconTint="?attr/textColor"
app:tabIndicatorColor="?attr/textColor"
android:id="@+id/result_tabs"
app:tabGravity="start">
<com.google.android.material.tabs.TabItem
android:text="Episodes"
android:icon="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.google.android.material.tabs.TabItem>
<com.google.android.material.tabs.TabItem
android:text="Sync"
android:icon="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.google.android.material.tabs.TabItem>
</com.google.android.material.tabs.TabLayout>-->
<LinearLayout <LinearLayout
android:id="@+id/result_episodes_tab" android:id="@+id/result_episodes_tab"
@ -861,6 +841,8 @@
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View file

@ -429,5 +429,17 @@
<string name="actor_background">Background</string> <string name="actor_background">Background</string>
<string name="home_source">Source</string> <string name="home_source">Source</string>
<string name="coming_soon">Coming soon…</string>
<string name="quality_cam">Cam</string>
<string name="quality_cam_rip">Cam</string>
<string name="quality_cam_hd">Cam</string>
<string name="quality_hq">HQ</string>
<string name="quality_hd">HD</string>
<string name="quality_ts">TS</string>
<string name="quality_tc">TC</string>
<string name="quality_blueray">BlueRay</string>
<string name="quality_workprint">WP</string>
<string name="quality_dvd">DVD</string>
<string name="poster_image">Poster Image</string> <string name="poster_image">Poster Image</string>
</resources> </resources>