diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 106ddea0..89f6cf75 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -10,7 +10,6 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.KotlinModule -import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId import com.lagradost.cloudstream3.animeproviders.* import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider import com.lagradost.cloudstream3.movieproviders.* @@ -93,6 +92,7 @@ object APIHolder { TantifilmProvider(), CineblogProvider(), AltadefinizioneProvider(), + FilmpertuttiProvider(), HDMovie5(), RebahinProvider(), LayarKacaProvider(), @@ -899,11 +899,11 @@ interface LoadResponse { this.actors = actors?.map { actor -> ActorData(actor) } } - fun LoadResponse.getMalId() : String? { + fun LoadResponse.getMalId(): String? { return this.syncData[malIdPrefix] } - fun LoadResponse.getAniListId() : String? { + fun LoadResponse.getAniListId(): String? { return this.syncData[aniListIdPrefix] } @@ -1004,7 +1004,7 @@ interface LoadResponse { fun LoadResponse?.isEpisodeBased(): Boolean { if (this == null) return false - return (this is AnimeLoadResponse || this is TvSeriesLoadResponse) && this.type.isEpisodeBased() + return this is EpisodeResponse && this.type.isEpisodeBased() } fun LoadResponse?.isAnimeBased(): Boolean { @@ -1017,6 +1017,17 @@ fun TvType?.isEpisodeBased(): Boolean { return (this == TvType.TvSeries || this == TvType.Anime) } + +data class NextAiring( + val episode: Int, + val unixTime: Long, +) + +interface EpisodeResponse { + var showStatus: ShowStatus? + var nextAiring: NextAiring? +} + data class TorrentLoadResponse( override var name: String, override var url: String, @@ -1050,7 +1061,7 @@ data class AnimeLoadResponse( override var year: Int? = null, var episodes: MutableMap> = mutableMapOf(), - var showStatus: ShowStatus? = null, + override var showStatus: ShowStatus? = null, override var plot: String? = null, override var tags: List? = null, @@ -1064,7 +1075,8 @@ data class AnimeLoadResponse( override var comingSoon: Boolean = false, override var syncData: MutableMap = mutableMapOf(), override var posterHeaders: Map? = null, -) : LoadResponse + override var nextAiring: NextAiring? = null, +) : LoadResponse, EpisodeResponse fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List?) { if (episodes == null) return @@ -1222,7 +1234,7 @@ data class TvSeriesLoadResponse( override var year: Int? = null, override var plot: String? = null, - var showStatus: ShowStatus? = null, + override var showStatus: ShowStatus? = null, override var rating: Int? = null, override var tags: List? = null, override var duration: Int? = null, @@ -1232,7 +1244,8 @@ data class TvSeriesLoadResponse( override var comingSoon: Boolean = false, override var syncData: MutableMap = mutableMapOf(), override var posterHeaders: Map? = null, -) : LoadResponse + override var nextAiring: NextAiring? = null, +) : LoadResponse, EpisodeResponse suspend fun MainAPI.newTvSeriesLoadResponse( name: String, diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt index eb6bb014..c5eaf40e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt @@ -14,6 +14,9 @@ class DoodCxExtractor : DoodLaExtractor() { class DoodShExtractor : DoodLaExtractor() { override var mainUrl = "https://dood.sh" } +class DoodWatchExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.watch" +} class DoodPmExtractor : DoodLaExtractor() { override var mainUrl = "https://dood.pm" diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/MixDrop.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/MixDrop.kt index e7ddd180..cd7e2e26 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/MixDrop.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/MixDrop.kt @@ -10,6 +10,9 @@ class MixDropBz : MixDrop(){ class MixDropCh : MixDrop(){ override var mainUrl = "https://mixdrop.ch" } +class MixDropTo : MixDrop(){ + override var mainUrl = "https://mixdrop.to" +} open class MixDrop : ExtractorApi() { override var name = "MixDrop" diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AltadefinizioneProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AltadefinizioneProvider.kt index d8ac1985..3b260fdb 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AltadefinizioneProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AltadefinizioneProvider.kt @@ -114,7 +114,7 @@ class AltadefinizioneProvider : MainAPI() { val tags: List = document.select("#details > li:nth-child(1) > a").map { it.text() } - val trailerurl = document.selectFirst("#showtrailer > div > div > iframe")!!.attr("src") + val trailerurl = document.selectFirst("#showtrailer > div > div > iframe")?.attr("src") return newMovieLoadResponse( title, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CineblogProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CineblogProvider.kt index 50bc4244..cd0b3908 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CineblogProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CineblogProvider.kt @@ -5,6 +5,7 @@ import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor + class CineblogProvider : MainAPI() { override var lang = "it" override var mainUrl = "https://cb01.rip" @@ -28,6 +29,7 @@ class CineblogProvider : MainAPI() { val home = soup.select("article.item.movies").map { val title = it.selectFirst("div.data > h3 > a")!!.text().substringBefore("(") val link = it.selectFirst("div.poster > a")!!.attr("href") + val quality = getQualityFromString(it.selectFirst("span.quality")?.text()) TvSeriesSearchResponse( title, link, @@ -36,6 +38,7 @@ class CineblogProvider : MainAPI() { it.selectFirst("img")!!.attr("src"), null, null, + quality = quality ) } @@ -82,8 +85,7 @@ class CineblogProvider : MainAPI() { href, this.name, TvType.Movie, - poster, - null + poster ) } @@ -96,7 +98,6 @@ class CineblogProvider : MainAPI() { val title = document.selectFirst("div.data > h1")!!.text().substringBefore("(") val description = document.select("#info > div.wp-content > p").html().toString() val rating = null - var year = document.selectFirst(" div.data > div.extra > span.date")!!.text().substringAfter(",") .filter { it.isDigit() } if (year.length > 4) { @@ -114,8 +115,7 @@ class CineblogProvider : MainAPI() { href, this.name, TvType.Movie, - posterUrl, - null + posterUrl ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmpertuttiProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmpertuttiProvider.kt new file mode 100644 index 00000000..36cd2b30 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmpertuttiProvider.kt @@ -0,0 +1,240 @@ +package com.lagradost.cloudstream3.movieproviders +import androidx.core.text.parseAsHtml +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer +import com.lagradost.cloudstream3.LoadResponse.Companion.addRating +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.nicehttp.NiceResponse +import org.jsoup.nodes.Element + + +class FilmpertuttiProvider : MainAPI() { + override var lang = "it" + override var mainUrl = "https://www.filmpertutti.buzz" + override var name = "Filmpertutti" + override val hasMainPage = true + override val hasChromecastSupport = true + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries + ) + + override suspend fun getMainPage(): HomePageResponse { + val items = ArrayList() + val urls = listOf( + Pair("$mainUrl/category/serie-tv/", "Serie Tv"), + Pair("$mainUrl/category/film/azione/", "Azione"), + Pair("$mainUrl/category/film/avventura/", "Avventura"), + ) + for ((url, name) in urls) { + try { + val soup = app.get(url).document + val home = soup.select("ul.posts > li").map { + val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(").substringBeforeLast("[") + val link = it.selectFirst("a")!!.attr("href") + val image = it.selectFirst("a")!!.attr("data-thumbnail") + val qualitydata = it.selectFirst("div.hd") + val quality = if (qualitydata!= null) { + getQualityFromString(qualitydata?.text()) + } + else { + null + } + newTvSeriesSearchResponse( + title, + link) { + this.posterUrl = image + this.quality = quality + } + } + + items.add(HomePageList(name, home)) + } catch (e: Exception) { + logError(e) + } + } + if (items.size <= 0) throw ErrorLoadingException() + return HomePageResponse(items) + } + + override suspend fun search(query: String): List { + val queryformatted = query.replace(" ", "+") + val url = "$mainUrl/?s=$queryformatted" + val doc = app.get(url).document + return doc.select("ul.posts > li").map { + val title = it.selectFirst("div.title")!!.text().substringBeforeLast("(").substringBeforeLast("[") + val link = it.selectFirst("a")!!.attr("href") + val image = it.selectFirst("a")!!.attr("data-thumbnail") + val quality = getQualityFromString(it.selectFirst("div.hd")?.text()) + + MovieSearchResponse( + title, + link, + this.name, + quality = quality, + posterUrl = image + ) + } + } + + override suspend fun load(url: String): LoadResponse { + val document = app.get(url).document + val type = + if (document.selectFirst("a.taxonomy.category")!!.attr("href").contains("serie-tv") + .not() + ) TvType.Movie else TvType.TvSeries + val title = document.selectFirst("#content > h1")!!.text().substringBeforeLast("(") + .substringBeforeLast("[") + + val description = document.selectFirst("i.fa.fa-file-text-o.fa-fw")?.parent()?.nextSibling()?.toString()?.parseAsHtml().toString() + + + val rating = document.selectFirst("div.rating > div.value")?.text() + + val year = + document.selectFirst("#content > h1")?.text()?.substringAfterLast("(")?.filter { it.isDigit() }?.toIntOrNull() ?: + description.substringAfter("trasmessa nel").take(6).filter { it.isDigit() }.toIntOrNull() ?: + (document.selectFirst("i.fa.fa-calendar.fa-fw")?.parent()?.nextSibling() as Element?)?.text()?.substringAfterLast(" ")?.filter { it.isDigit() }?.toIntOrNull() + + + val poster = document.selectFirst("div.meta > div > img")?.attr("data-src") + + + val trailerurl = document.selectFirst("div.youtube-player")?.attr("data-id")?.let{ urldata-> + "https://www.youtube.com/watch?v=$urldata" + } + + if (type == TvType.TvSeries) { + + val episodeList = ArrayList() + document.select("div.accordion-item").filter{it.selectFirst("#season > ul > li.s_title > span")!!.text().isNotEmpty()}.map { element -> + val season = + element.selectFirst("#season > ul > li.s_title > span")!!.text().toInt() + element.select("div.episode-wrap").map { episode -> + val href = + episode.select("#links > div > div > table > tbody:nth-child(2) > tr") + .map { it.selectFirst("a")!!.attr("href") }.toJson() + val epNum = episode.selectFirst("li.season-no")!!.text().substringAfter("x") + .filter { it.isDigit() }.toIntOrNull() + val epTitle = episode.selectFirst("li.other_link > a")?.text() + + val posterUrl = episode.selectFirst("figure > img")?.attr("data-src") + episodeList.add( + Episode( + href, + epTitle, + season, + epNum, + posterUrl, + ) + ) + } + } + return newTvSeriesLoadResponse( + title, + url, type, episodeList + ) { + this.posterUrl = poster + this.year = year + this.plot = description + addRating(rating) + addTrailer(trailerurl) + } + } else { + + val urls0 = document.select("div.embed-player") + val urls = if (urls0.isNotEmpty()){ + urls0.map { it.attr("data-id") }.toJson() + } + else{ document.select("#info > ul > li ").mapNotNull { it.selectFirst("a")?.attr("href") }.toJson() } + + return newMovieLoadResponse( + title, + url, + type, + urls + ) { + posterUrl = fixUrlNull(poster) + this.year = year + this.plot = description + addRating(rating) + addTrailer(trailerurl) + + } + } + } + +// to be updated when UnshortenUrl is ready + suspend fun unshorten_linkup(uri: String): String { + var r: NiceResponse? = null + var uri = uri + when{ + uri.contains("/tv/") -> uri = uri.replace("/tv/", "/tva/") + uri.contains("delta") -> uri = uri.replace("/delta/", "/adelta/") + (uri.contains("/ga/") || uri.contains("/ga2/")) -> uri = base64Decode(uri.split('/').last()).trim() + uri.contains("/speedx/") -> uri = uri.replace("http://linkup.pro/speedx", "http://speedvideo.net") + else -> { + r = app.get(uri, allowRedirects = true) + uri = r.url + val link = + Regex("]*src=\\'([^'>]*)\\'[^<>]*>").find(r.text)?.value ?: + Regex("""action="(?:[^/]+.*?/[^/]+/([a-zA-Z0-9_]+))">""").find(r.text)?.value ?: + Regex("""href","((.|\\n)*?)"""").findAll(r.text).elementAtOrNull(1)?.groupValues?.get(1) + + if (link!=null) { + uri = link + } + } + } + + val short = Regex("""^https?://.*?(https?://.*)""").find(uri)?.value + if (short!=null){ + uri = short + } + if (r==null){ + r = app.get( + uri, + allowRedirects = false) + if (r.headers["location"]!= null){ + uri = r.headers["location"].toString() + } + } + if (uri.contains("snip.")) { + if (uri.contains("out_generator")) { + uri = Regex("url=(.*)\$").find(uri)!!.value + } + else if (uri.contains("/decode/")) { + uri = app.get(uri, allowRedirects = true).url + } + } + return uri + } + + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + tryParseJson>(data)?.forEach { id -> + if (id.contains("buckler")){ + val id2 = unshorten_linkup(id).trim().replace("/v/","/e/").replace("/f/","/e/") + loadExtractor(id2, data, callback) + } + else if (id.contains("isecure")){ + val doc1 = app.get(id).document + val id2 = doc1.selectFirst("iframe")!!.attr("src") + loadExtractor(id2, data, callback) + } + else{ + loadExtractor(id, data, callback) + } + } + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TantiFilmProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TantiFilmProvider.kt index 8227bcd2..84035a14 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TantiFilmProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TantiFilmProvider.kt @@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer class TantifilmProvider : MainAPI() { override var lang = "it" - override var mainUrl = "https://www.tantifilm.rodeo" + override var mainUrl = "https://www.tantifilm.pics" override var name = "Tantifilm" override val hasMainPage = true override val hasChromecastSupport = true diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/SyncAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/SyncAPI.kt index 87da6219..5aa56a02 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/SyncAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/SyncAPI.kt @@ -36,11 +36,6 @@ interface SyncAPI : OAuth2API { override var id: Int? = null, ) : SearchResponse - data class SyncNextAiring( - val episode: Int, - val unixTime: Long, - ) - data class SyncStatus( val status: Int, /** 1-10 */ @@ -63,7 +58,7 @@ interface SyncAPI : OAuth2API { var duration: Int? = null, var synopsis: String? = null, var airStatus: ShowStatus? = null, - var nextAiring: SyncNextAiring? = null, + var nextAiring: NextAiring? = null, var studio: List? = null, var genres: List? = null, var synonyms: List? = null, diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 471447e8..0490d3b5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -98,7 +98,7 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { return SyncAPI.SyncResult( season.id.toString(), nextAiring = season.nextAiringEpisode?.let { - SyncAPI.SyncNextAiring( + NextAiring( it.episode ?: return@let null, (it.timeUntilAiring ?: return@let null) + unixTime ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index 3a63a78d..bdbfcb9c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -300,14 +300,14 @@ class CS3IPlayer : IPlayer { saveData() exoPlayer?.pause() - releasePlayer() + //releasePlayer() } override fun onPause() { Log.i(TAG, "onPause") saveData() exoPlayer?.pause() - releasePlayer() + //releasePlayer() } override fun onResume(context: Context) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt index bd94560a..a83e5269 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt @@ -88,6 +88,7 @@ const val DOUBLE_TAB_PAUSE_PERCENTAGE = 0.15 // in both directions open class FullScreenPlayer : AbstractPlayerFragment() { protected open var lockRotation = true protected open var isFullScreenPlayer = true + protected open var isTv = false // state of player UI protected var isShowing = false @@ -1055,7 +1056,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() { // netflix capture back and hide ~monke KeyEvent.KEYCODE_BACK -> { - if (isShowing) { + if (isShowing && isTv) { onClickChange() return true } @@ -1257,6 +1258,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() { player_intro_play?.setOnClickListener { player_intro_play?.isGone = true player.handleEvent(CSPlayerEvent.Play) + updateUIVisibility() } // it is !not! a bug that you cant touch the right side, it does not register inputs on navbar or status bar diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index 506a9cbe..67adad76 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -914,8 +914,9 @@ class GeneratorPlayer : FullScreenPlayer() { savedInstanceState: Bundle? ): View? { // this is used instead of layout-television to follow the settings and some TV devices are not classified as TV for some reason + isTv = context?.isTvSettings() == true layout = - if (context?.isTvSettings() == true) R.layout.fragment_player_tv else R.layout.fragment_player + if (isTv) R.layout.fragment_player_tv else R.layout.fragment_player viewModel = ViewModelProvider(this)[PlayerGeneratorViewModel::class.java] sync = ViewModelProvider(this)[SyncViewModel::class.java] diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt index 0ca7bf63..20035ac4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt @@ -41,6 +41,7 @@ import com.google.android.material.button.MaterialButton import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.APIHolder.getId +import com.lagradost.cloudstream3.APIHolder.unixTime import com.lagradost.cloudstream3.APIHolder.updateHasTrailers import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.getCastSession @@ -100,6 +101,8 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import java.io.File +import java.util.concurrent.TimeUnit + const val MAX_SYNO_LENGH = 1000 @@ -654,6 +657,55 @@ class ResultFragment : ResultTrailerPlayer() { loadTrailer() } + private fun setNextEpisode(nextAiring: NextAiring?) { + result_next_airing_holder?.isVisible = + if (nextAiring == null || nextAiring.episode <= 0 || nextAiring.unixTime <= unixTime) { + false + } else { + val seconds = nextAiring.unixTime - unixTime + val days = TimeUnit.SECONDS.toDays(seconds) + val hours: Long = TimeUnit.SECONDS.toHours(seconds) - days * 24 + val minute = + TimeUnit.SECONDS.toMinutes(seconds) - TimeUnit.SECONDS.toHours(seconds) * 60 + // val second = + // TimeUnit.SECONDS.toSeconds(seconds) - TimeUnit.SECONDS.toMinutes(seconds) * 60 + try { + val ctx = context + if (ctx == null) { + false + } else { + when { + days > 0 -> { + ctx.getString(R.string.next_episode_time_day_format).format( + days, + hours, + minute + ) + } + hours > 0 -> ctx.getString(R.string.next_episode_time_hour_format) + .format( + hours, + minute + ) + minute > 0 -> ctx.getString(R.string.next_episode_time_min_format) + .format( + minute + ) + else -> null + }?.also { text -> + result_next_airing_time?.text = text + result_next_airing?.text = + ctx.getString(R.string.next_episode_format).format(nextAiring.episode) + } != null + } + } catch (e: Exception) { // mistranslation + result_next_airing_holder?.isVisible = false + logError(e) + false + } + } + } + private fun setActors(actors: List?) { if (actors.isNullOrEmpty()) { result_cast_text?.isVisible = false @@ -1801,7 +1853,7 @@ class ResultFragment : ResultTrailerPlayer() { setRating(d.rating) setRecommendations(d.recommendations, null) setActors(d.actors) - + setNextEpisode(if (d is EpisodeResponse) d.nextAiring else null) setTrailers(d.trailers) if (syncModel.addSyncs(d.syncData)) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultTrailerPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultTrailerPlayer.kt index 83fedf23..0e326767 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultTrailerPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultTrailerPlayer.kt @@ -85,7 +85,6 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen isFullScreenPlayer = fullscreen lockRotation = fullscreen player_fullscreen?.setImageResource(if (fullscreen) R.drawable.baseline_fullscreen_exit_24 else R.drawable.baseline_fullscreen_24) - uiReset() if (fullscreen) { enterFullscreen() result_top_bar?.isVisible = false @@ -106,6 +105,7 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen exitFullscreen() } fixPlayerSize() + uiReset() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt index ca5d27b2..ec4f6fab 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt @@ -5,7 +5,6 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull @@ -29,7 +28,6 @@ import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.player.IGenerator import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator import com.lagradost.cloudstream3.ui.player.SubtitleData -import com.lagradost.cloudstream3.ui.search.SearchResultBuilder import com.lagradost.cloudstream3.utils.Coroutines.ioWork import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE import com.lagradost.cloudstream3.utils.DataStoreHelper @@ -144,6 +142,10 @@ class ResultViewModel : ViewModel() { posterUrl = posterUrl ?: meta.posterUrl ?: meta.backgroundPosterUrl actors = actors ?: meta.actors + if (this is EpisodeResponse) { + nextAiring = nextAiring ?: meta.nextAiring + } + for ((k, v) in syncs ?: emptyMap()) { syncData[k] = v } @@ -162,7 +164,6 @@ class ResultViewModel : ViewModel() { argamap({ addTrailer(meta.trailers) }, { - if (this !is AnimeLoadResponse) return@argamap val map = getEpisodesDetails(getMalId(), getAniListId(), isResponseRequired = false) if (map.isNullOrEmpty()) return@argamap diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 48622b22..e2b76354 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -140,6 +140,8 @@ val extractorApis: Array = arrayOf( //mixdrop extractors MixDropBz(), MixDropCh(), + MixDropTo(), + MixDrop(), Mcloud(), @@ -186,6 +188,7 @@ val extractorApis: Array = arrayOf( DoodLaExtractor(), DoodWsExtractor(), DoodShExtractor(), + DoodWatchExtractor(), AsianLoad(), diff --git a/app/src/main/res/layout/fragment_result.xml b/app/src/main/res/layout/fragment_result.xml index 3a9de7ad..9024858f 100644 --- a/app/src/main/res/layout/fragment_result.xml +++ b/app/src/main/res/layout/fragment_result.xml @@ -139,6 +139,7 @@ android:orientation="vertical"> + app:shimmer_highlight_alpha="0.3"> + + + + + + + + + %d %s Ep %d Cast: %s + Episode %d will be released in + %dd %dh %dm + %dh %dm + %dm Poster diff --git a/docs/providers.json b/docs/providers.json index e8e550cc..e87eaf62 100644 --- a/docs/providers.json +++ b/docs/providers.json @@ -184,6 +184,12 @@ "status": 1, "url": "https://filman.cc" }, + "FilmpertuttiProvider": { + "language": "it", + "name": "Filmpertutti", + "status": 1, + "url": "https://www.filmpertutti.buzz" + }, "FmoviesToProvider": { "language": "en", "name": "Fmovies.to", @@ -420,7 +426,7 @@ "language": "it", "name": "Tantifilm", "status": 1, - "url": "https://www.tantifilm.rodeo" + "url": "https://www.tantifilm.pics" }, "TenshiProvider": { "language": "en",