forked from recloudstream/cloudstream
		
	sync fixes + UI
This commit is contained in:
		
							parent
							
								
									a933aa8493
								
							
						
					
					
						commit
						4447196ebc
					
				
					 13 changed files with 556 additions and 372 deletions
				
			
		|  | @ -693,13 +693,13 @@ interface LoadResponse { | ||||||
|     val url: String |     val url: String | ||||||
|     val apiName: String |     val apiName: String | ||||||
|     val type: TvType |     val type: TvType | ||||||
|     val posterUrl: String? |     var posterUrl: String? | ||||||
|     val year: Int? |     val year: Int? | ||||||
|     val plot: String? |     var plot: String? | ||||||
|     val rating: Int? // 1-1000 |     var rating: Int? // 1-1000 | ||||||
|     val tags: List<String>? |     var tags: List<String>? | ||||||
|     var duration: Int? // in minutes |     var duration: Int? // in minutes | ||||||
|     val trailerUrl: String? |     var trailerUrl: String? | ||||||
|     var recommendations: List<SearchResponse>? |     var recommendations: List<SearchResponse>? | ||||||
|     var actors: List<ActorData>? |     var actors: List<ActorData>? | ||||||
|     var comingSoon: Boolean |     var comingSoon: Boolean | ||||||
|  |  | ||||||
|  | @ -73,6 +73,8 @@ interface SyncAPI : OAuth2API { | ||||||
|         var synonyms: List<String>? = null, |         var synonyms: List<String>? = null, | ||||||
|         var trailerUrl: String? = null, |         var trailerUrl: String? = null, | ||||||
|         var isAdult : Boolean? = null, |         var isAdult : Boolean? = null, | ||||||
|  |         var posterUrl: String? = null, | ||||||
|  |         var backgroundPosterUrl : String? = null, | ||||||
| 
 | 
 | ||||||
|         /** In unixtime */ |         /** In unixtime */ | ||||||
|         var startDate: Long? = null, |         var startDate: Long? = null, | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ import com.lagradost.cloudstream3.mvvm.safeApiCall | ||||||
| class SyncRepo(private val repo: SyncAPI) { | class SyncRepo(private val repo: SyncAPI) { | ||||||
|     val idPrefix = repo.idPrefix |     val idPrefix = repo.idPrefix | ||||||
|     val name = repo.name |     val name = repo.name | ||||||
|  |     val icon = repo.icon | ||||||
| 
 | 
 | ||||||
|     suspend fun score(id: String, status: SyncAPI.SyncStatus): Resource<Boolean> { |     suspend fun score(id: String, status: SyncAPI.SyncStatus): Resource<Boolean> { | ||||||
|         return safeApiCall { repo.score(id, status) } |         return safeApiCall { repo.score(id, status) } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.getKey | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys | import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser | import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | ||||||
|  | import com.lagradost.cloudstream3.ErrorLoadingException | ||||||
| import com.lagradost.cloudstream3.R | import com.lagradost.cloudstream3.R | ||||||
| import com.lagradost.cloudstream3.app | import com.lagradost.cloudstream3.app | ||||||
| import com.lagradost.cloudstream3.mvvm.logError | import com.lagradost.cloudstream3.mvvm.logError | ||||||
|  | @ -20,6 +21,7 @@ import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.unixTime | ||||||
| import com.lagradost.cloudstream3.syncproviders.SyncAPI | import com.lagradost.cloudstream3.syncproviders.SyncAPI | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.splitQuery | import com.lagradost.cloudstream3.utils.AppUtils.splitQuery | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||||
|  | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson | ||||||
| import com.lagradost.cloudstream3.utils.Coroutines.ioSafe | import com.lagradost.cloudstream3.utils.Coroutines.ioSafe | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject | import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject | ||||||
| import java.net.URL | import java.net.URL | ||||||
|  | @ -86,7 +88,7 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { | ||||||
| 
 | 
 | ||||||
|     override suspend fun getResult(id: String): SyncAPI.SyncResult? { |     override suspend fun getResult(id: String): SyncAPI.SyncResult? { | ||||||
|         val internalId = id.toIntOrNull() ?: return null |         val internalId = id.toIntOrNull() ?: return null | ||||||
|         val season = getSeason(internalId)?.data?.Media ?: return null |         val season = getSeason(internalId).data?.Media ?: throw ErrorLoadingException("No media") | ||||||
| 
 | 
 | ||||||
|         return SyncAPI.SyncResult( |         return SyncAPI.SyncResult( | ||||||
|             season.id.toString(), |             season.id.toString(), | ||||||
|  | @ -100,7 +102,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { | ||||||
|             synonyms = season.synonyms, |             synonyms = season.synonyms, | ||||||
|             isAdult = season.isAdult, |             isAdult = season.isAdult, | ||||||
|             totalEpisodes = season.episodes, |             totalEpisodes = season.episodes, | ||||||
|             //synopsis = season. |             synopsis = season.description, | ||||||
|  | 
 | ||||||
|             //TODO REST |             //TODO REST | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  | @ -295,28 +298,42 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { | ||||||
|             return fromIntToAnimeStatus(aniListStatusString.indexOf(string)) |             return fromIntToAnimeStatus(aniListStatusString.indexOf(string)) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| 
 |         private suspend fun getSeason(id: Int): SeasonResponse { | ||||||
|         private suspend fun getSeason(id: Int): SeasonResponse? { |  | ||||||
|             val q = """ |             val q = """ | ||||||
|                query (${'$'}id: Int = $id) { |                query (${'$'}id: Int = $id) { | ||||||
|                    Media (id: ${'$'}id, type: ANIME) { |                    Media (id: ${'$'}id, type: ANIME) { | ||||||
|                        id |                        id | ||||||
|                        idMal |                        idMal | ||||||
|                        coverImage |                        coverImage { | ||||||
|  |                            extraLarge | ||||||
|  |                            large | ||||||
|  |                            medium | ||||||
|  |                            color | ||||||
|  |                        } | ||||||
|                        duration |                        duration | ||||||
|                        episodes |                        episodes | ||||||
|                        genres |                        genres | ||||||
|                        synonyms |                        synonyms | ||||||
|                        averageScore |                        averageScore | ||||||
|                        isAdult |                        isAdult | ||||||
|                        trailer |                        description(asHtml: false) | ||||||
|  |                        trailer { | ||||||
|  |                            id | ||||||
|  |                            site | ||||||
|  |                            thumbnail | ||||||
|  |                        } | ||||||
|                        relations { |                        relations { | ||||||
|                             edges { |                             edges { | ||||||
|                                  id |                                  id | ||||||
|                                  relationType(version: 2) |                                  relationType(version: 2) | ||||||
|                                  node { |                                  node { | ||||||
|                                       id |                                       id | ||||||
|                                       coverImage |                                       coverImage { | ||||||
|  |                                           extraLarge | ||||||
|  |                                           large | ||||||
|  |                                           medium | ||||||
|  |                                           color | ||||||
|  |                                       } | ||||||
|                                  } |                                  } | ||||||
|                             } |                             } | ||||||
|                        } |                        } | ||||||
|  | @ -328,19 +345,13 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { | ||||||
|                    } |                    } | ||||||
|                } |                } | ||||||
|         """ |         """ | ||||||
| 
 |  | ||||||
|             val data = app.post( |             val data = app.post( | ||||||
|                 "https://graphql.anilist.co", |                 "https://graphql.anilist.co", | ||||||
|                 data = mapOf("query" to q), |                 data = mapOf("query" to q), | ||||||
|                 cacheTime = 0, |                 cacheTime = 0, | ||||||
|             ).text |             ).text | ||||||
|             if (data == "") return null | 
 | ||||||
|             return try { |             return tryParseJson(data) ?: throw ErrorLoadingException("Error parsing $data") | ||||||
|                 mapper.readValue(data) |  | ||||||
|             } catch (e: Exception) { |  | ||||||
|                 logError(e) |  | ||||||
|                 null |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -661,15 +672,13 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { | ||||||
|         val seasons = mutableListOf<SeasonResponse?>() |         val seasons = mutableListOf<SeasonResponse?>() | ||||||
|         suspend fun getSeasonRecursive(id: Int) { |         suspend fun getSeasonRecursive(id: Int) { | ||||||
|             val season = getSeason(id) |             val season = getSeason(id) | ||||||
|             if (season != null) { |             seasons.add(season) | ||||||
|                 seasons.add(season) |             if (season.data?.Media?.format?.startsWith("TV") == true) { | ||||||
|                 if (season.data?.Media?.format?.startsWith("TV") == true) { |                 season.data.Media.relations?.edges?.forEach { | ||||||
|                     season.data.Media.relations?.edges?.forEach { |                     if (it.node?.format != null) { | ||||||
|                         if (it.node?.format != null) { |                         if (it.relationType == "SEQUEL" && it.node.format.startsWith("TV")) { | ||||||
|                             if (it.relationType == "SEQUEL" && it.node.format.startsWith("TV")) { |                             getSeasonRecursive(it.node.id) | ||||||
|                                 getSeasonRecursive(it.node.id) |                             return@forEach | ||||||
|                                 return@forEach |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -701,8 +710,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { | ||||||
|         @JsonProperty("averageScore") val averageScore: Int?, |         @JsonProperty("averageScore") val averageScore: Int?, | ||||||
|         @JsonProperty("isAdult") val isAdult: Boolean?, |         @JsonProperty("isAdult") val isAdult: Boolean?, | ||||||
|         @JsonProperty("trailer") val trailer: MediaTrailer?, |         @JsonProperty("trailer") val trailer: MediaTrailer?, | ||||||
| 
 |         @JsonProperty("description") val description: String?, | ||||||
|         ) |     ) | ||||||
| 
 | 
 | ||||||
|     data class MediaTrailer( |     data class MediaTrailer( | ||||||
|         @JsonProperty("id") val id: String?, |         @JsonProperty("id") val id: String?, | ||||||
|  |  | ||||||
|  | @ -0,0 +1,82 @@ | ||||||
|  | package com.lagradost.cloudstream3.ui.result | ||||||
|  | 
 | ||||||
|  | import android.view.LayoutInflater | ||||||
|  | import android.view.View | ||||||
|  | import android.view.ViewGroup | ||||||
|  | import android.widget.ImageView | ||||||
|  | import androidx.recyclerview.widget.DiffUtil | ||||||
|  | import androidx.recyclerview.widget.RecyclerView | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | class ImageAdapter(context: Context, val resource: Int) : ArrayAdapter<Int>(context, resource) { | ||||||
|  |     override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { | ||||||
|  |         val newConvertView = convertView ?: run { | ||||||
|  |             val mInflater = context | ||||||
|  |                 .getSystemService(Activity.LAYOUT_INFLATER_SERVICE) as LayoutInflater | ||||||
|  |             mInflater.inflate(resource, null) | ||||||
|  |         } | ||||||
|  |         getItem(position)?.let { (newConvertView as? ImageView?)?.setImageResource(it) } | ||||||
|  |         return newConvertView | ||||||
|  |     } | ||||||
|  | }*/ | ||||||
|  | 
 | ||||||
|  | class ImageAdapter( | ||||||
|  |     val layout: Int, | ||||||
|  | ) : | ||||||
|  |     RecyclerView.Adapter<RecyclerView.ViewHolder>() { | ||||||
|  |     private val images: MutableList<Int> = mutableListOf() | ||||||
|  | 
 | ||||||
|  |     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { | ||||||
|  |         return ImageViewHolder( | ||||||
|  |             LayoutInflater.from(parent.context).inflate(layout, parent, false) | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { | ||||||
|  |         when (holder) { | ||||||
|  |             is ImageViewHolder -> { | ||||||
|  |                 holder.bind(images[position]) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun getItemCount(): Int { | ||||||
|  |         return images.size | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun getItemId(position: Int): Long { | ||||||
|  |         return images[position].toLong() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun updateList(newList: List<Int>) { | ||||||
|  |         val diffResult = DiffUtil.calculateDiff( | ||||||
|  |             DiffCallback(this.images, newList) | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         images.clear() | ||||||
|  |         images.addAll(newList) | ||||||
|  | 
 | ||||||
|  |         diffResult.dispatchUpdatesTo(this) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     class ImageViewHolder | ||||||
|  |     constructor(itemView: View) : | ||||||
|  |         RecyclerView.ViewHolder(itemView) { | ||||||
|  |         fun bind(img: Int) { | ||||||
|  |             (itemView as? ImageView?)?.setImageResource(img) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class DiffCallback<T>(private val oldList: List<T>, private val newList: List<T>) : | ||||||
|  |     DiffUtil.Callback() { | ||||||
|  |     override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = | ||||||
|  |         oldList[oldItemPosition] == newList[newItemPosition] | ||||||
|  | 
 | ||||||
|  |     override fun getOldListSize() = oldList.size | ||||||
|  | 
 | ||||||
|  |     override fun getNewListSize() = newList.size | ||||||
|  | 
 | ||||||
|  |     override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = | ||||||
|  |         oldList[oldItemPosition] == newList[newItemPosition] | ||||||
|  | } | ||||||
|  | @ -636,7 +636,6 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | ||||||
|         val apiName = arguments?.getString("apiName") ?: return |         val apiName = arguments?.getString("apiName") ?: return | ||||||
|         startAction = arguments?.getInt("startAction") ?: START_ACTION_NORMAL |         startAction = arguments?.getInt("startAction") ?: START_ACTION_NORMAL | ||||||
|         startValue = arguments?.getInt("startValue") ?: START_VALUE_NORMAL |         startValue = arguments?.getInt("startValue") ?: START_VALUE_NORMAL | ||||||
| 
 |  | ||||||
|         syncModel.addFromUrl(url) |         syncModel.addFromUrl(url) | ||||||
| 
 | 
 | ||||||
|         val api = getApiFromName(apiName) |         val api = getApiFromName(apiName) | ||||||
|  | @ -1198,17 +1197,26 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         val imgAdapter = ImageAdapter(R.layout.result_mini_image) | ||||||
|  |         result_mini_sync?.adapter = imgAdapter | ||||||
| 
 | 
 | ||||||
|         observe(syncModel.synced) { list -> |         observe(syncModel.synced) { list -> | ||||||
|             result_sync_names?.text = |             result_sync_names?.text = | ||||||
|                 list.filter { it.isSynced && it.hasAccount }.joinToString { it.name } |                 list.filter { it.isSynced && it.hasAccount }.joinToString { it.name } | ||||||
|  | 
 | ||||||
|  |             val newList = list.filter { it.isSynced } | ||||||
|  |             result_mini_sync?.isVisible = newList.isNotEmpty() | ||||||
|  |             (result_mini_sync?.adapter as? ImageAdapter?)?.updateList(newList.map { it.icon }) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         var currentSyncProgress = 0 | ||||||
|         observe(syncModel.metadata) { meta -> |         observe(syncModel.metadata) { meta -> | ||||||
|             when (meta) { |             when (meta) { | ||||||
|                 is Resource.Success -> { |                 is Resource.Success -> { | ||||||
|                     val d = meta.value |                     val d = meta.value | ||||||
|                     result_sync_episodes?.max = (d.totalEpisodes ?: 0) * 1000 |                     result_sync_episodes?.max = (d.totalEpisodes ?: 0) * 1000 | ||||||
|  |                     result_sync_episodes?.progress = currentSyncProgress * 1000 | ||||||
|  | 
 | ||||||
|                     normalSafeApiCall { |                     normalSafeApiCall { | ||||||
|                         val ctx = result_sync_max_episodes?.context |                         val ctx = result_sync_max_episodes?.context | ||||||
|                         result_sync_max_episodes?.text = |                         result_sync_max_episodes?.text = | ||||||
|  | @ -1218,6 +1226,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | ||||||
|                                 ctx?.getString(R.string.sync_total_episodes_none) |                                 ctx?.getString(R.string.sync_total_episodes_none) | ||||||
|                             } |                             } | ||||||
|                     } |                     } | ||||||
|  |                     viewModel.setMeta(d) | ||||||
|                 } |                 } | ||||||
|                 is Resource.Loading -> { |                 is Resource.Loading -> { | ||||||
|                     result_sync_max_episodes?.text = |                     result_sync_max_episodes?.text = | ||||||
|  | @ -1249,6 +1258,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | ||||||
|                     result_sync_rating?.value = d.score?.toFloat() ?: 0.0f |                     result_sync_rating?.value = d.score?.toFloat() ?: 0.0f | ||||||
|                     result_sync_check?.setItemChecked(d.status + 1, true) |                     result_sync_check?.setItemChecked(d.status + 1, true) | ||||||
|                     val watchedEpisodes = d.watchedEpisodes ?: 0 |                     val watchedEpisodes = d.watchedEpisodes ?: 0 | ||||||
|  |                     currentSyncProgress = watchedEpisodes | ||||||
|                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |                     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { | ||||||
|                         result_sync_episodes?.setProgress(watchedEpisodes * 1000, true) |                         result_sync_episodes?.setProgress(watchedEpisodes * 1000, true) | ||||||
|                     } else { |                     } else { | ||||||
|  | @ -1447,372 +1457,369 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | ||||||
|             currentId = it |             currentId = it | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         observe(viewModel.resultResponse) { data -> |         observe(viewModel.result) { data -> | ||||||
|             when (data) { |             when (data) { | ||||||
|                 is Resource.Success -> { |                 is Resource.Success -> { | ||||||
|                     val d = data.value |                     val d = data.value | ||||||
|                     if (d is LoadResponse) { |                     if (d !is AnimeLoadResponse && result_episode_loading.isVisible) { // no episode loading when not anime | ||||||
|                         if (d !is AnimeLoadResponse && result_episode_loading.isVisible) { // no episode loading when not anime |                         result_episode_loading.isVisible = false | ||||||
|                             result_episode_loading.isVisible = false |                     } | ||||||
|  | 
 | ||||||
|  |                     updateVisStatus(2) | ||||||
|  | 
 | ||||||
|  |                     result_vpn?.text = when (api.vpnStatus) { | ||||||
|  |                         VPNStatus.MightBeNeeded -> getString(R.string.vpn_might_be_needed) | ||||||
|  |                         VPNStatus.Torrent -> getString(R.string.vpn_torrent) | ||||||
|  |                         else -> "" | ||||||
|  |                     } | ||||||
|  |                     result_vpn?.isGone = api.vpnStatus == VPNStatus.None | ||||||
|  | 
 | ||||||
|  |                     result_info?.text = when (api.providerType) { | ||||||
|  |                         ProviderType.MetaProvider -> getString(R.string.provider_info_meta) | ||||||
|  |                         else -> "" | ||||||
|  |                     } | ||||||
|  |                     result_info?.isVisible = api.providerType == ProviderType.MetaProvider | ||||||
|  | 
 | ||||||
|  |                     if (d.type.isEpisodeBased()) { | ||||||
|  |                         val ep = d as? TvSeriesLoadResponse | ||||||
|  |                         val epCount = ep?.episodes?.size ?: 1 | ||||||
|  |                         if (epCount < 1) { | ||||||
|  |                             result_info?.text = getString(R.string.no_episodes_found) | ||||||
|  |                             result_info?.isVisible = true | ||||||
|                         } |                         } | ||||||
|  |                     } | ||||||
| 
 | 
 | ||||||
|                         updateVisStatus(2) |                     currentHeaderName = d.name | ||||||
|  |                     currentType = d.type | ||||||
| 
 | 
 | ||||||
|                         result_vpn?.text = when (api.vpnStatus) { |                     currentPoster = d.posterUrl | ||||||
|                             VPNStatus.MightBeNeeded -> getString(R.string.vpn_might_be_needed) |                     currentIsMovie = !d.isEpisodeBased() | ||||||
|                             VPNStatus.Torrent -> getString(R.string.vpn_torrent) | 
 | ||||||
|                             else -> "" |                     result_open_in_browser?.setOnClickListener { | ||||||
|  |                         val i = Intent(ACTION_VIEW) | ||||||
|  |                         i.data = Uri.parse(d.url) | ||||||
|  |                         try { | ||||||
|  |                             startActivity(i) | ||||||
|  |                         } catch (e: Exception) { | ||||||
|  |                             logError(e) | ||||||
|                         } |                         } | ||||||
|                         result_vpn?.isGone = api.vpnStatus == VPNStatus.None |                     } | ||||||
| 
 | 
 | ||||||
|                         result_info?.text = when (api.providerType) { |                     result_search?.setOnClickListener { | ||||||
|                             ProviderType.MetaProvider -> getString(R.string.provider_info_meta) |                         QuickSearchFragment.pushSearch(activity, d.name) | ||||||
|                             else -> "" |                     } | ||||||
|  | 
 | ||||||
|  |                     result_share?.setOnClickListener { | ||||||
|  |                         try { | ||||||
|  |                             val i = Intent(ACTION_SEND) | ||||||
|  |                             i.type = "text/plain" | ||||||
|  |                             i.putExtra(EXTRA_SUBJECT, d.name) | ||||||
|  |                             i.putExtra(EXTRA_TEXT, d.url) | ||||||
|  |                             startActivity(createChooser(i, d.name)) | ||||||
|  |                         } catch (e: Exception) { | ||||||
|  |                             logError(e) | ||||||
|                         } |                         } | ||||||
|                         result_info?.isVisible = api.providerType == ProviderType.MetaProvider |                     } | ||||||
| 
 | 
 | ||||||
|                         if (d.type.isEpisodeBased()) { |                     val showStatus = when (d) { | ||||||
|                             val ep = d as? TvSeriesLoadResponse |                         is TvSeriesLoadResponse -> d.showStatus | ||||||
|                             val epCount = ep?.episodes?.size ?: 1 |                         is AnimeLoadResponse -> d.showStatus | ||||||
|                             if (epCount < 1) { |                         else -> null | ||||||
|                                 result_info?.text = getString(R.string.no_episodes_found) |                     } | ||||||
|                                 result_info?.isVisible = true | 
 | ||||||
|  |                     setShow(showStatus) | ||||||
|  |                     setDuration(d.duration) | ||||||
|  |                     setYear(d.year) | ||||||
|  |                     setRating(d.rating) | ||||||
|  |                     setRecommendations(d.recommendations) | ||||||
|  |                     setActors(d.actors) | ||||||
|  | 
 | ||||||
|  |                     if (SettingsFragment.accountEnabled) | ||||||
|  |                         if (d is AnimeLoadResponse) { | ||||||
|  |                             if ( | ||||||
|  |                                 setMalSync(d.malId) | ||||||
|  |                                 || | ||||||
|  |                                 setAniListSync(d.anilistId) | ||||||
|  |                             ) { | ||||||
|  |                                 syncModel.updateMetaAndUser() | ||||||
|  |                             } else { | ||||||
|  |                                 syncModel.addFromUrl(d.url) | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         currentHeaderName = d.name |                     result_meta_site?.text = d.apiName | ||||||
|                         currentType = d.type |  | ||||||
| 
 | 
 | ||||||
|                         currentPoster = d.posterUrl |                     val posterImageLink = d.posterUrl | ||||||
|                         currentIsMovie = !d.isEpisodeBased() |                     if (!posterImageLink.isNullOrEmpty()) { | ||||||
| 
 |                         result_poster?.setImage(posterImageLink) | ||||||
|                         result_open_in_browser?.setOnClickListener { |                         result_poster_blur?.setImageBlur(posterImageLink, 10, 3) | ||||||
|                             val i = Intent(ACTION_VIEW) |                         //Full screen view of Poster image | ||||||
|                             i.data = Uri.parse(d.url) |                         result_poster_holder?.setOnClickListener { | ||||||
|                             try { |                             try { | ||||||
|                                 startActivity(i) |                                 context?.let { ctx -> | ||||||
|                             } catch (e: Exception) { |                                     val bitmap = result_poster.drawable.toBitmap() | ||||||
|                                 logError(e) |                                     val sourceBuilder = AlertDialog.Builder(ctx) | ||||||
|                             } |                                     sourceBuilder.setView(R.layout.result_poster) | ||||||
|                         } |  | ||||||
| 
 | 
 | ||||||
|                         result_search?.setOnClickListener { |                                     val sourceDialog = sourceBuilder.create() | ||||||
|                             QuickSearchFragment.pushSearch(activity, d.name) |                                     sourceDialog.show() | ||||||
|                         } |  | ||||||
| 
 | 
 | ||||||
|                         result_share?.setOnClickListener { |                                     sourceDialog.findViewById<ImageView?>(R.id.imgPoster) | ||||||
|                             try { |                                         ?.apply { | ||||||
|                                 val i = Intent(ACTION_SEND) |                                             setImageBitmap(bitmap) | ||||||
|                                 i.type = "text/plain" |                                             setOnClickListener { | ||||||
|                                 i.putExtra(EXTRA_SUBJECT, d.name) |                                                 sourceDialog.dismissSafe() | ||||||
|                                 i.putExtra(EXTRA_TEXT, d.url) |  | ||||||
|                                 startActivity(createChooser(i, d.name)) |  | ||||||
|                             } catch (e: Exception) { |  | ||||||
|                                 logError(e) |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         val showStatus = when (d) { |  | ||||||
|                             is TvSeriesLoadResponse -> d.showStatus |  | ||||||
|                             is AnimeLoadResponse -> d.showStatus |  | ||||||
|                             else -> null |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         setShow(showStatus) |  | ||||||
|                         setDuration(d.duration) |  | ||||||
|                         setYear(d.year) |  | ||||||
|                         setRating(d.rating) |  | ||||||
|                         setRecommendations(d.recommendations) |  | ||||||
|                         setActors(d.actors) |  | ||||||
| 
 |  | ||||||
|                         if (SettingsFragment.accountEnabled) |  | ||||||
|                             if (d is AnimeLoadResponse) { |  | ||||||
|                                 if ( |  | ||||||
|                                     setMalSync(d.malId) |  | ||||||
|                                     || |  | ||||||
|                                     setAniListSync(d.anilistId) |  | ||||||
|                                 ) { |  | ||||||
|                                     syncModel.updateMetaAndUser() |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
| 
 |  | ||||||
|                         result_meta_site?.text = d.apiName |  | ||||||
| 
 |  | ||||||
|                         val posterImageLink = d.posterUrl |  | ||||||
|                         if (!posterImageLink.isNullOrEmpty()) { |  | ||||||
|                             result_poster?.setImage(posterImageLink) |  | ||||||
|                             result_poster_blur?.setImageBlur(posterImageLink, 10, 3) |  | ||||||
|                             //Full screen view of Poster image |  | ||||||
|                             result_poster_holder?.setOnClickListener { |  | ||||||
|                                 try { |  | ||||||
|                                     context?.let { ctx -> |  | ||||||
|                                         val bitmap = result_poster.drawable.toBitmap() |  | ||||||
|                                         val sourceBuilder = AlertDialog.Builder(ctx) |  | ||||||
|                                         sourceBuilder.setView(R.layout.result_poster) |  | ||||||
| 
 |  | ||||||
|                                         val sourceDialog = sourceBuilder.create() |  | ||||||
|                                         sourceDialog.show() |  | ||||||
| 
 |  | ||||||
|                                         sourceDialog.findViewById<ImageView?>(R.id.imgPoster) |  | ||||||
|                                             ?.apply { |  | ||||||
|                                                 setImageBitmap(bitmap) |  | ||||||
|                                                 setOnClickListener { |  | ||||||
|                                                     sourceDialog.dismissSafe() |  | ||||||
|                                                 } |  | ||||||
|                                             } |                                             } | ||||||
|                                     } |                                         } | ||||||
|                                 } catch (e: Exception) { |  | ||||||
|                                     logError(e) |  | ||||||
|                                 } |                                 } | ||||||
|  |                             } catch (e: Exception) { | ||||||
|  |                                 logError(e) | ||||||
|                             } |                             } | ||||||
|                         } else { |  | ||||||
|                             result_poster?.setImageResource(R.drawable.default_cover) |  | ||||||
|                             result_poster_blur?.setImageResource(R.drawable.default_cover) |  | ||||||
|                         } |                         } | ||||||
|  |                     } else { | ||||||
|  |                         result_poster?.setImageResource(R.drawable.default_cover) | ||||||
|  |                         result_poster_blur?.setImageResource(R.drawable.default_cover) | ||||||
|  |                     } | ||||||
| 
 | 
 | ||||||
|                         result_poster_holder?.visibility = VISIBLE |                     result_poster_holder?.visibility = VISIBLE | ||||||
| 
 | 
 | ||||||
|                         /*result_play_movie?.text = |                     /*result_play_movie?.text = | ||||||
|                             if (d.type == TvType.Torrent) getString(R.string.play_torrent_button) else getString( |                         if (d.type == TvType.Torrent) getString(R.string.play_torrent_button) else getString( | ||||||
|                                 R.string.play_movie_button |                             R.string.play_movie_button | ||||||
|                             )*/ |                         )*/ | ||||||
|                         //result_plot_header?.text = |                     //result_plot_header?.text = | ||||||
|                         //    if (d.type == TvType.Torrent) getString(R.string.torrent_plot) else getString(R.string.result_plot) |                     //    if (d.type == TvType.Torrent) getString(R.string.torrent_plot) else getString(R.string.result_plot) | ||||||
|                         if (!d.plot.isNullOrEmpty()) { |                     if (!d.plot.isNullOrEmpty()) { | ||||||
|                             var syno = d.plot!! |                         var syno = d.plot!! | ||||||
|                             if (syno.length > MAX_SYNO_LENGH) { |                         if (syno.length > MAX_SYNO_LENGH) { | ||||||
|                                 syno = syno.substring(0, MAX_SYNO_LENGH) + "..." |                             syno = syno.substring(0, MAX_SYNO_LENGH) + "..." | ||||||
|                             } |  | ||||||
|                             result_descript.setOnClickListener { |  | ||||||
|                                 val builder: AlertDialog.Builder = |  | ||||||
|                                     AlertDialog.Builder(requireContext()) |  | ||||||
|                                 builder.setMessage(d.plot) |  | ||||||
|                                     .setTitle(if (d.type == TvType.Torrent) R.string.torrent_plot else R.string.result_plot) |  | ||||||
|                                     .show() |  | ||||||
|                             } |  | ||||||
|                             result_descript.text = syno |  | ||||||
|                         } else { |  | ||||||
|                             result_descript.text = |  | ||||||
|                                 if (d.type == TvType.Torrent) getString(R.string.torrent_no_plot) else getString( |  | ||||||
|                                     R.string.normal_no_plot |  | ||||||
|                                 ) |  | ||||||
|                         } |                         } | ||||||
|  |                         result_descript.setOnClickListener { | ||||||
|  |                             val builder: AlertDialog.Builder = | ||||||
|  |                                 AlertDialog.Builder(requireContext()) | ||||||
|  |                             builder.setMessage(d.plot) | ||||||
|  |                                 .setTitle(if (d.type == TvType.Torrent) R.string.torrent_plot else R.string.result_plot) | ||||||
|  |                                 .show() | ||||||
|  |                         } | ||||||
|  |                         result_descript.text = syno | ||||||
|  |                     } else { | ||||||
|  |                         result_descript.text = | ||||||
|  |                             if (d.type == TvType.Torrent) getString(R.string.torrent_no_plot) else getString( | ||||||
|  |                                 R.string.normal_no_plot | ||||||
|  |                             ) | ||||||
|  |                     } | ||||||
| 
 | 
 | ||||||
|                         result_tag?.removeAllViews() |                     result_tag?.removeAllViews() | ||||||
|  |                     //result_tag_holder?.visibility = GONE | ||||||
|  |                     // result_status.visibility = GONE | ||||||
|  | 
 | ||||||
|  |                     d.comingSoon.let { soon -> | ||||||
|  |                         result_coming_soon?.isVisible = soon | ||||||
|  |                         result_data_holder?.isGone = soon | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     val tags = d.tags | ||||||
|  |                     if (tags.isNullOrEmpty()) { | ||||||
|                         //result_tag_holder?.visibility = GONE |                         //result_tag_holder?.visibility = GONE | ||||||
|                         // result_status.visibility = GONE |                     } else { | ||||||
|  |                         //result_tag_holder?.visibility = VISIBLE | ||||||
| 
 | 
 | ||||||
|                         d.comingSoon.let { soon -> |                         for ((index, tag) in tags.withIndex()) { | ||||||
|                             result_coming_soon?.isVisible = soon |                             val viewBtt = layoutInflater.inflate(R.layout.result_tag, null) | ||||||
|                             result_data_holder?.isGone = soon |                             val btt = viewBtt.findViewById<MaterialButton>(R.id.result_tag_card) | ||||||
|  |                             btt.text = tag | ||||||
|  | 
 | ||||||
|  |                             result_tag?.addView(viewBtt, index) | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     if (d.type.isMovieType()) { | ||||||
|  |                         val hasDownloadSupport = api.hasDownloadSupport | ||||||
|  |                         lateFixDownloadButton(true) | ||||||
|  | 
 | ||||||
|  |                         result_play_movie?.setOnClickListener { | ||||||
|  |                             val card = | ||||||
|  |                                 currentEpisodes?.firstOrNull() ?: return@setOnClickListener | ||||||
|  |                             handleAction(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card)) | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         val tags = d.tags |                         result_play_movie?.setOnLongClickListener { | ||||||
|                         if (tags.isNullOrEmpty()) { |                             val card = currentEpisodes?.firstOrNull() | ||||||
|                             //result_tag_holder?.visibility = GONE |                                 ?: return@setOnLongClickListener true | ||||||
|                         } else { |                             handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) | ||||||
|                             //result_tag_holder?.visibility = VISIBLE |                             return@setOnLongClickListener true | ||||||
| 
 |  | ||||||
|                             for ((index, tag) in tags.withIndex()) { |  | ||||||
|                                 val viewBtt = layoutInflater.inflate(R.layout.result_tag, null) |  | ||||||
|                                 val btt = viewBtt.findViewById<MaterialButton>(R.id.result_tag_card) |  | ||||||
|                                 btt.text = tag |  | ||||||
| 
 |  | ||||||
|                                 result_tag?.addView(viewBtt, index) |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (d.type.isMovieType()) { |                         result_download_movie?.setOnLongClickListener { | ||||||
|                             val hasDownloadSupport = api.hasDownloadSupport |                             val card = currentEpisodes?.firstOrNull() | ||||||
|                             lateFixDownloadButton(true) |                                 ?: return@setOnLongClickListener true | ||||||
| 
 |                             handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) | ||||||
|                             result_play_movie?.setOnClickListener { |                             return@setOnLongClickListener true | ||||||
|                                 val card = |                         } | ||||||
|                                     currentEpisodes?.firstOrNull() ?: return@setOnClickListener |  | ||||||
|                                 handleAction(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card)) |  | ||||||
|                             } |  | ||||||
| 
 |  | ||||||
|                             result_play_movie?.setOnLongClickListener { |  | ||||||
|                                 val card = currentEpisodes?.firstOrNull() |  | ||||||
|                                     ?: return@setOnLongClickListener true |  | ||||||
|                                 handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) |  | ||||||
|                                 return@setOnLongClickListener true |  | ||||||
|                             } |  | ||||||
| 
 |  | ||||||
|                             result_download_movie?.setOnLongClickListener { |  | ||||||
|                                 val card = currentEpisodes?.firstOrNull() |  | ||||||
|                                     ?: return@setOnLongClickListener true |  | ||||||
|                                 handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) |  | ||||||
|                                 return@setOnLongClickListener true |  | ||||||
|                             } |  | ||||||
| 
 | 
 | ||||||
| //                            result_options.setOnClickListener { | //                            result_options.setOnClickListener { | ||||||
| //                                val card = currentEpisodes?.first() ?: return@setOnClickListener | //                                val card = currentEpisodes?.first() ?: return@setOnClickListener | ||||||
| //                                handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) | //                                handleAction(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card)) | ||||||
| //                            } | //                            } | ||||||
| 
 | 
 | ||||||
|                             result_download_movie?.visibility = |                         result_download_movie?.visibility = | ||||||
|                                 if (hasDownloadSupport) VISIBLE else GONE |                             if (hasDownloadSupport) VISIBLE else GONE | ||||||
|                             if (hasDownloadSupport) { |                         if (hasDownloadSupport) { | ||||||
|                                 val localId = d.getId() |                             val localId = d.getId() | ||||||
|                                 val file = |                             val file = | ||||||
|                                     VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( |                                 VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( | ||||||
|                                         requireContext(), |                                     requireContext(), | ||||||
|                                         localId |                                     localId | ||||||
|                                     ) |                                 ) | ||||||
|                                 downloadButton?.dispose() |                             downloadButton?.dispose() | ||||||
|                                 downloadButton = EasyDownloadButton() |                             downloadButton = EasyDownloadButton() | ||||||
|                                 downloadButton?.setUpMoreButton( |                             downloadButton?.setUpMoreButton( | ||||||
|                                     file?.fileLength, |                                 file?.fileLength, | ||||||
|                                     file?.totalBytes, |                                 file?.totalBytes, | ||||||
|                                     result_movie_progress_downloaded, |                                 result_movie_progress_downloaded, | ||||||
|                                     result_movie_download_icon, |                                 result_movie_download_icon, | ||||||
|                                     result_movie_download_text, |                                 result_movie_download_text, | ||||||
|                                     result_movie_download_text_precentage, |                                 result_movie_download_text_precentage, | ||||||
|                                     result_download_movie, |                                 result_download_movie, | ||||||
|                                     true, |                                 true, | ||||||
|                                     VideoDownloadHelper.DownloadEpisodeCached( |                                 VideoDownloadHelper.DownloadEpisodeCached( | ||||||
|                                         d.name, |                                     d.name, | ||||||
|                                         d.posterUrl, |                                     d.posterUrl, | ||||||
|                                         0, |                                     0, | ||||||
|                                         null, |                                     null, | ||||||
|                                         localId, |                                     localId, | ||||||
|                                         localId, |                                     localId, | ||||||
|                                         d.rating, |                                     d.rating, | ||||||
|                                         d.plot, |                                     d.plot, | ||||||
|                                         System.currentTimeMillis(), |                                     System.currentTimeMillis(), | ||||||
|                                     ) |                                 ) | ||||||
|                                 ) { downloadClickEvent -> |                             ) { downloadClickEvent -> | ||||||
|                                     if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) { |                                 if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) { | ||||||
|                                         currentEpisodes?.firstOrNull()?.let { episode -> |                                     currentEpisodes?.firstOrNull()?.let { episode -> | ||||||
|                                             handleAction( |                                         handleAction( | ||||||
|                                                 EpisodeClickEvent( |                                             EpisodeClickEvent( | ||||||
|                                                     ACTION_DOWNLOAD_EPISODE, |                                                 ACTION_DOWNLOAD_EPISODE, | ||||||
|                                                     ResultEpisode( |                                                 ResultEpisode( | ||||||
|                                                         d.name, |                                                     d.name, | ||||||
|                                                         d.name, |                                                     d.name, | ||||||
|                                                         null, |                                                     null, | ||||||
|                                                         0, |                                                     0, | ||||||
|                                                         null, |                                                     null, | ||||||
|                                                         episode.data, |                                                     episode.data, | ||||||
|                                                         d.apiName, |                                                     d.apiName, | ||||||
|                                                         localId, |                                                     localId, | ||||||
|                                                         0, |                                                     0, | ||||||
|                                                         0L, |                                                     0L, | ||||||
|                                                         0L, |                                                     0L, | ||||||
|                                                         null, |                                                     null, | ||||||
|                                                         null, |                                                     null, | ||||||
|                                                         null, |                                                     null, | ||||||
|                                                         d.type, |                                                     d.type, | ||||||
|                                                         localId, |                                                     localId, | ||||||
|                                                     ) |  | ||||||
|                                                 ) |                                                 ) | ||||||
|                                             ) |                                             ) | ||||||
|                                         } |  | ||||||
|                                     } else { |  | ||||||
|                                         handleDownloadClick( |  | ||||||
|                                             activity, |  | ||||||
|                                             currentHeaderName, |  | ||||||
|                                             downloadClickEvent |  | ||||||
|                                         ) |                                         ) | ||||||
|                                     } |                                     } | ||||||
|                                 } |                                 } else { | ||||||
| 
 |                                     handleDownloadClick( | ||||||
|                                 result_download_movie?.setOnLongClickListener { |                                         activity, | ||||||
|                                     val card = |                                         currentHeaderName, | ||||||
|                                         currentEpisodes?.firstOrNull() |                                         downloadClickEvent | ||||||
|                                             ?: return@setOnLongClickListener false |  | ||||||
|                                     handleAction(EpisodeClickEvent(ACTION_DOWNLOAD_MIRROR, card)) |  | ||||||
|                                     return@setOnLongClickListener true |  | ||||||
|                                 } |  | ||||||
| 
 |  | ||||||
|                                 /*downloadButton?.setUpMaterialButton( |  | ||||||
|                                     file?.fileLength, |  | ||||||
|                                     file?.totalBytes, |  | ||||||
|                                     result_movie_progress_downloaded, |  | ||||||
|                                     result_download_movie, |  | ||||||
|                                     null, //result_movie_text_progress |  | ||||||
|                                     VideoDownloadHelper.DownloadEpisodeCached( |  | ||||||
|                                         d.name, |  | ||||||
|                                         d.posterUrl, |  | ||||||
|                                         0, |  | ||||||
|                                         null, |  | ||||||
|                                         localId, |  | ||||||
|                                         localId, |  | ||||||
|                                         d.rating, |  | ||||||
|                                         d.plot, |  | ||||||
|                                         System.currentTimeMillis(), |  | ||||||
|                                     ) |                                     ) | ||||||
|                                 ) { downloadClickEvent -> |                                 } | ||||||
|                                     if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) { |                             } | ||||||
|                                         currentEpisodes?.firstOrNull()?.let { episode -> | 
 | ||||||
|                                             handleAction( |                             result_download_movie?.setOnLongClickListener { | ||||||
|                                                 EpisodeClickEvent( |                                 val card = | ||||||
|                                                     ACTION_DOWNLOAD_EPISODE, |                                     currentEpisodes?.firstOrNull() | ||||||
|                                                     ResultEpisode( |                                         ?: return@setOnLongClickListener false | ||||||
|                                                         d.name, |                                 handleAction(EpisodeClickEvent(ACTION_DOWNLOAD_MIRROR, card)) | ||||||
|                                                         d.name, |                                 return@setOnLongClickListener true | ||||||
|                                                         null, |                             } | ||||||
|                                                         0, | 
 | ||||||
|                                                         null, |                             /*downloadButton?.setUpMaterialButton( | ||||||
|                                                         episode.data, |                                 file?.fileLength, | ||||||
|                                                         d.apiName, |                                 file?.totalBytes, | ||||||
|                                                         localId, |                                 result_movie_progress_downloaded, | ||||||
|                                                         0, |                                 result_download_movie, | ||||||
|                                                         0L, |                                 null, //result_movie_text_progress | ||||||
|                                                         0L, |                                 VideoDownloadHelper.DownloadEpisodeCached( | ||||||
|                                                         null, |                                     d.name, | ||||||
|                                                         null, |                                     d.posterUrl, | ||||||
|                                                         null, |                                     0, | ||||||
|                                                         d.type, |                                     null, | ||||||
|                                                         localId, |                                     localId, | ||||||
|                                                     ) |                                     localId, | ||||||
|  |                                     d.rating, | ||||||
|  |                                     d.plot, | ||||||
|  |                                     System.currentTimeMillis(), | ||||||
|  |                                 ) | ||||||
|  |                             ) { downloadClickEvent -> | ||||||
|  |                                 if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) { | ||||||
|  |                                     currentEpisodes?.firstOrNull()?.let { episode -> | ||||||
|  |                                         handleAction( | ||||||
|  |                                             EpisodeClickEvent( | ||||||
|  |                                                 ACTION_DOWNLOAD_EPISODE, | ||||||
|  |                                                 ResultEpisode( | ||||||
|  |                                                     d.name, | ||||||
|  |                                                     d.name, | ||||||
|  |                                                     null, | ||||||
|  |                                                     0, | ||||||
|  |                                                     null, | ||||||
|  |                                                     episode.data, | ||||||
|  |                                                     d.apiName, | ||||||
|  |                                                     localId, | ||||||
|  |                                                     0, | ||||||
|  |                                                     0L, | ||||||
|  |                                                     0L, | ||||||
|  |                                                     null, | ||||||
|  |                                                     null, | ||||||
|  |                                                     null, | ||||||
|  |                                                     d.type, | ||||||
|  |                                                     localId, | ||||||
|                                                 ) |                                                 ) | ||||||
|                                             ) |                                             ) | ||||||
|                                         } |  | ||||||
|                                     } else { |  | ||||||
|                                         handleDownloadClick( |  | ||||||
|                                             activity, |  | ||||||
|                                             currentHeaderName, |  | ||||||
|                                             downloadClickEvent |  | ||||||
|                                         ) |                                         ) | ||||||
|                                     } |                                     } | ||||||
|                                 }*/ |                                 } else { | ||||||
|                             } |                                     handleDownloadClick( | ||||||
|                         } else { |                                         activity, | ||||||
|                             lateFixDownloadButton(false) |                                         currentHeaderName, | ||||||
|                         } |                                         downloadClickEvent | ||||||
| 
 |                                     ) | ||||||
|                         context?.getString( |                                 } | ||||||
|                             when (d.type) { |                             }*/ | ||||||
|                                 TvType.TvSeries -> R.string.tv_series_singular |  | ||||||
|                                 TvType.Anime -> R.string.anime_singular |  | ||||||
|                                 TvType.OVA -> R.string.ova_singular |  | ||||||
|                                 TvType.AnimeMovie -> R.string.movies_singular |  | ||||||
|                                 TvType.Cartoon -> R.string.cartoons_singular |  | ||||||
|                                 TvType.Documentary -> R.string.documentaries_singular |  | ||||||
|                                 TvType.Movie -> R.string.movies_singular |  | ||||||
|                                 TvType.Torrent -> R.string.torrent_singular |  | ||||||
|                                 TvType.AsianDrama -> R.string.asian_drama_singular |  | ||||||
|                             } |  | ||||||
|                         )?.let { |  | ||||||
|                             result_meta_type?.text = it |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|                         when (d) { |  | ||||||
|                             is AnimeLoadResponse -> { |  | ||||||
| 
 |  | ||||||
|                                 // val preferEnglish = true |  | ||||||
|                                 //val titleName = (if (preferEnglish) d.engName else d.japName) ?: d.name |  | ||||||
|                                 val titleName = d.name |  | ||||||
|                                 result_title.text = titleName |  | ||||||
|                                 //result_toolbar.title = titleName |  | ||||||
|                             } |  | ||||||
|                             else -> result_title.text = d.name |  | ||||||
|                         } |                         } | ||||||
|                     } else { |                     } else { | ||||||
|                         updateVisStatus(1) |                         lateFixDownloadButton(false) | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     context?.getString( | ||||||
|  |                         when (d.type) { | ||||||
|  |                             TvType.TvSeries -> R.string.tv_series_singular | ||||||
|  |                             TvType.Anime -> R.string.anime_singular | ||||||
|  |                             TvType.OVA -> R.string.ova_singular | ||||||
|  |                             TvType.AnimeMovie -> R.string.movies_singular | ||||||
|  |                             TvType.Cartoon -> R.string.cartoons_singular | ||||||
|  |                             TvType.Documentary -> R.string.documentaries_singular | ||||||
|  |                             TvType.Movie -> R.string.movies_singular | ||||||
|  |                             TvType.Torrent -> R.string.torrent_singular | ||||||
|  |                             TvType.AsianDrama -> R.string.asian_drama_singular | ||||||
|  |                         } | ||||||
|  |                     )?.let { | ||||||
|  |                         result_meta_type?.text = it | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     when (d) { | ||||||
|  |                         is AnimeLoadResponse -> { | ||||||
|  | 
 | ||||||
|  |                             // val preferEnglish = true | ||||||
|  |                             //val titleName = (if (preferEnglish) d.engName else d.japName) ?: d.name | ||||||
|  |                             val titleName = d.name | ||||||
|  |                             result_title.text = titleName | ||||||
|  |                             //result_toolbar.title = titleName | ||||||
|  |                         } | ||||||
|  |                         else -> result_title.text = d.name | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 is Resource.Failure -> { |                 is Resource.Failure -> { | ||||||
|  | @ -1873,7 +1880,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | ||||||
|                     it.context?.openBrowser(tempUrl) |                     it.context?.openBrowser(tempUrl) | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (restart || viewModel.resultResponse.value == null) { |                 if (restart || viewModel.result.value == null) { | ||||||
|                     //viewModel.clear() |                     //viewModel.clear() | ||||||
|                     viewModel.load(tempUrl, apiName, showFillers) |                     viewModel.load(tempUrl, apiName, showFillers) | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| package com.lagradost.cloudstream3.ui.result | package com.lagradost.cloudstream3.ui.result | ||||||
| 
 | 
 | ||||||
| import android.content.Context | import android.util.Log | ||||||
| import androidx.lifecycle.LiveData | import androidx.lifecycle.LiveData | ||||||
| import androidx.lifecycle.MutableLiveData | import androidx.lifecycle.MutableLiveData | ||||||
| import androidx.lifecycle.ViewModel | import androidx.lifecycle.ViewModel | ||||||
|  | @ -12,6 +12,7 @@ import com.lagradost.cloudstream3.APIHolder.getId | ||||||
| import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | ||||||
| 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.SyncAPI | ||||||
| import com.lagradost.cloudstream3.ui.APIRepository | import com.lagradost.cloudstream3.ui.APIRepository | ||||||
| import com.lagradost.cloudstream3.ui.WatchType | import com.lagradost.cloudstream3.ui.WatchType | ||||||
| import com.lagradost.cloudstream3.ui.player.IGenerator | import com.lagradost.cloudstream3.ui.player.IGenerator | ||||||
|  | @ -43,7 +44,7 @@ class ResultViewModel : ViewModel() { | ||||||
|     private var repo: APIRepository? = null |     private var repo: APIRepository? = null | ||||||
|     private var generator: IGenerator? = null |     private var generator: IGenerator? = null | ||||||
| 
 | 
 | ||||||
|     private val _resultResponse: MutableLiveData<Resource<Any?>> = MutableLiveData() |     private val _resultResponse: MutableLiveData<Resource<LoadResponse>> = MutableLiveData() | ||||||
|     private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData() |     private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData() | ||||||
|     private val episodeById: MutableLiveData<HashMap<Int, Int>> = |     private val episodeById: MutableLiveData<HashMap<Int, Int>> = | ||||||
|         MutableLiveData() // lookup by ID to get Index |         MutableLiveData() // lookup by ID to get Index | ||||||
|  | @ -55,7 +56,8 @@ class ResultViewModel : ViewModel() { | ||||||
|     private val selectedRangeInt: MutableLiveData<Int> = MutableLiveData() |     private val selectedRangeInt: MutableLiveData<Int> = MutableLiveData() | ||||||
|     val rangeOptions: LiveData<List<String>> = _rangeOptions |     val rangeOptions: LiveData<List<String>> = _rangeOptions | ||||||
| 
 | 
 | ||||||
|     val resultResponse: LiveData<Resource<Any?>> get() = _resultResponse |     val result: LiveData<Resource<LoadResponse>> get() = _resultResponse | ||||||
|  | 
 | ||||||
|     val episodes: LiveData<List<ResultEpisode>> get() = _episodes |     val episodes: LiveData<List<ResultEpisode>> get() = _episodes | ||||||
|     val publicEpisodes: LiveData<Resource<List<ResultEpisode>>> get() = _publicEpisodes |     val publicEpisodes: LiveData<Resource<List<ResultEpisode>>> get() = _publicEpisodes | ||||||
|     val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount |     val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount | ||||||
|  | @ -106,6 +108,41 @@ class ResultViewModel : ViewModel() { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     companion object { | ||||||
|  |         const val TAG = "RVM" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     var lastMeta: SyncAPI.SyncResult? = null | ||||||
|  |     private fun applyMeta(resp: LoadResponse, meta: SyncAPI.SyncResult?): LoadResponse { | ||||||
|  |         if (meta == null) return resp | ||||||
|  |         lastMeta = meta | ||||||
|  |         return resp.apply { | ||||||
|  |             Log.i(TAG, "applyMeta") | ||||||
|  | 
 | ||||||
|  |             duration = duration ?: meta.duration | ||||||
|  |             rating = rating ?: meta.publicScore | ||||||
|  |             tags = tags ?: meta.genres | ||||||
|  |             plot = if (plot.isNullOrBlank()) meta.synopsis else plot | ||||||
|  |             trailerUrl = trailerUrl ?: meta.trailerUrl | ||||||
|  |             posterUrl = posterUrl ?: meta.posterUrl ?: meta.backgroundPosterUrl | ||||||
|  |             actors = actors ?: meta.actors?.map { | ||||||
|  |                 ActorData( | ||||||
|  |                     Actor( | ||||||
|  |                         name = it.name, | ||||||
|  |                         image = it.posterUrl | ||||||
|  |                     ) | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun setMeta(meta: SyncAPI.SyncResult) { | ||||||
|  |         Log.i(TAG, "setMeta") | ||||||
|  |         (result.value as? Resource.Success<LoadResponse>?)?.value?.let { resp -> | ||||||
|  |             _resultResponse.postValue(Resource.Success(applyMeta(resp, meta))) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private fun loadWatchStatus(localId: Int? = null) { |     private fun loadWatchStatus(localId: Int? = null) { | ||||||
|         val currentId = localId ?: id.value ?: return |         val currentId = localId ?: id.value ?: return | ||||||
|         val currentWatch = getResultWatchState(currentId) |         val currentWatch = getResultWatchState(currentId) | ||||||
|  | @ -289,7 +326,7 @@ class ResultViewModel : ViewModel() { | ||||||
| 
 | 
 | ||||||
|         when (data) { |         when (data) { | ||||||
|             is Resource.Success -> { |             is Resource.Success -> { | ||||||
|                 val d = data.value |                 val d = applyMeta(data.value, lastMeta) | ||||||
|                 page.postValue(d) |                 page.postValue(d) | ||||||
|                 val mainId = d.getId() |                 val mainId = d.getId() | ||||||
|                 id.postValue(mainId) |                 id.postValue(mainId) | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ data class CurrentSynced( | ||||||
|     val idPrefix: String, |     val idPrefix: String, | ||||||
|     val isSynced: Boolean, |     val isSynced: Boolean, | ||||||
|     val hasAccount: Boolean, |     val hasAccount: Boolean, | ||||||
|  |     val icon : Int, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| class SyncViewModel : ViewModel() { | class SyncViewModel : ViewModel() { | ||||||
|  | @ -48,7 +49,8 @@ class SyncViewModel : ViewModel() { | ||||||
|                 it.name, |                 it.name, | ||||||
|                 it.idPrefix, |                 it.idPrefix, | ||||||
|                 syncIds.containsKey(it.idPrefix), |                 syncIds.containsKey(it.idPrefix), | ||||||
|                 it.hasAccount() |                 it.hasAccount(), | ||||||
|  |                 it.icon, | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -67,8 +69,13 @@ class SyncViewModel : ViewModel() { | ||||||
|         updateSynced() |         updateSynced() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     var hasAddedFromUrl : HashSet<String> = hashSetOf() | ||||||
|  | 
 | ||||||
|     fun addFromUrl(url: String?) = viewModelScope.launch { |     fun addFromUrl(url: String?) = viewModelScope.launch { | ||||||
|  |         if(url == null || hasAddedFromUrl.contains(url)) return@launch | ||||||
|         SyncUtil.getIdsFromUrl(url)?.let { (malId, aniListId) -> |         SyncUtil.getIdsFromUrl(url)?.let { (malId, aniListId) -> | ||||||
|  |             hasAddedFromUrl.add(url) | ||||||
|  | 
 | ||||||
|             setMalId(malId) |             setMalId(malId) | ||||||
|             setAniListId(aniListId) |             setAniListId(aniListId) | ||||||
|             if (malId != null || aniListId != null) { |             if (malId != null || aniListId != null) { | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| package com.lagradost.cloudstream3.utils | package com.lagradost.cloudstream3.utils | ||||||
| 
 | 
 | ||||||
|  | import android.util.Log | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
| import com.fasterxml.jackson.module.kotlin.readValue | import com.fasterxml.jackson.module.kotlin.readValue | ||||||
| import com.lagradost.cloudstream3.app | import com.lagradost.cloudstream3.app | ||||||
|  | @ -14,6 +15,8 @@ object SyncUtil { | ||||||
|         Regex("""(twist\.moe)/a/([^/?]*)"""), |         Regex("""(twist\.moe)/a/([^/?]*)"""), | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|  |     private const val TAG = "SNC" | ||||||
|  | 
 | ||||||
|     private const val GOGOANIME = "Gogoanime" |     private const val GOGOANIME = "Gogoanime" | ||||||
|     private const val NINE_ANIME = "9anime" |     private const val NINE_ANIME = "9anime" | ||||||
|     private const val TWIST_MOE = "Twistmoe" |     private const val TWIST_MOE = "Twistmoe" | ||||||
|  | @ -28,6 +31,7 @@ object SyncUtil { | ||||||
| 
 | 
 | ||||||
|     suspend fun getIdsFromUrl(url: String?): Pair<String?, String?>? { |     suspend fun getIdsFromUrl(url: String?): Pair<String?, String?>? { | ||||||
|         if (url == null) return null |         if (url == null) return null | ||||||
|  |         Log.i(TAG, "getIdsFromUrl $url") | ||||||
| 
 | 
 | ||||||
|         for (regex in regexs) { |         for (regex in regexs) { | ||||||
|             regex.find(url)?.let { match -> |             regex.find(url)?.let { match -> | ||||||
|  | @ -51,6 +55,7 @@ object SyncUtil { | ||||||
|         slug: String, |         slug: String, | ||||||
|         site: String = "GogoanimeGogoanime" |         site: String = "GogoanimeGogoanime" | ||||||
|     ): Pair<String?, String?>? { |     ): Pair<String?, String?>? { | ||||||
|  |         Log.i(TAG, "getIdsFromSlug $slug $site") | ||||||
|         try { |         try { | ||||||
|             //Gogoanime, Twistmoe and 9anime |             //Gogoanime, Twistmoe and 9anime | ||||||
|             val url = |             val url = | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|         android:width="24dp" |         android:width="20dp" | ||||||
|         android:height="24dp" |         android:height="20dp" | ||||||
|         android:viewportWidth="172" |         android:viewportWidth="172" | ||||||
|         android:viewportHeight="172" |         android:viewportHeight="172" | ||||||
|         android:tint="?attr/white" |         android:tint="?attr/white" | ||||||
|  |  | ||||||
|  | @ -375,6 +375,7 @@ | ||||||
|                         </LinearLayout> |                         </LinearLayout> | ||||||
|                     </LinearLayout> |                     </LinearLayout> | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|                     <com.google.android.material.button.MaterialButton |                     <com.google.android.material.button.MaterialButton | ||||||
|                             android:id="@+id/result_bookmark_button" |                             android:id="@+id/result_bookmark_button" | ||||||
|                             style="@style/BlackButton" |                             style="@style/BlackButton" | ||||||
|  |  | ||||||
|  | @ -12,22 +12,45 @@ | ||||||
|             android:paddingEnd="@dimen/result_padding" |             android:paddingEnd="@dimen/result_padding" | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="wrap_content"> |             android:layout_height="wrap_content"> | ||||||
|  |         <LinearLayout | ||||||
|  |                 android:orientation="horizontal" | ||||||
|  |                 android:gravity="center_vertical" | ||||||
|  |                 android:layout_gravity="center_vertical" | ||||||
|  |                 android:layout_width="wrap_content" | ||||||
|  |                 android:layout_height="wrap_content"> | ||||||
|  |             <ImageView | ||||||
|  |                     android:nextFocusDown="@id/result_bookmark_button" | ||||||
|  |                     android:nextFocusRight="@id/result_share" | ||||||
|  |                     android:background="?android:attr/selectableItemBackgroundBorderless" | ||||||
| 
 | 
 | ||||||
|         <ImageView |                     android:id="@+id/result_back" | ||||||
|                 android:nextFocusDown="@id/result_bookmark_button" |                     android:clickable="true" | ||||||
|                 android:nextFocusRight="@id/result_share" |                     android:focusable="true" | ||||||
|                 android:background="?android:attr/selectableItemBackgroundBorderless" |  | ||||||
| 
 | 
 | ||||||
|                 android:id="@+id/result_back" |                     android:layout_width="30dp" | ||||||
|                 android:clickable="true" |                     android:layout_height="30dp" | ||||||
|                 android:focusable="true" |                     android:layout_gravity="center_vertical|start" | ||||||
| 
 |                     android:src="@drawable/ic_baseline_arrow_back_24" | ||||||
|                 android:layout_width="30dp" |                     android:contentDescription="@string/go_back" | ||||||
|                 android:layout_height="30dp" |                     app:tint="?attr/white" /> | ||||||
|                 android:layout_gravity="center_vertical|start" |             <androidx.recyclerview.widget.RecyclerView | ||||||
|                 android:src="@drawable/ic_baseline_arrow_back_24" |                     android:paddingStart="10dp" | ||||||
|                 android:contentDescription="@string/go_back" |                     android:paddingEnd="10dp" | ||||||
|                 app:tint="?attr/white" /> |                     android:id="@+id/result_mini_sync" | ||||||
|  |                     android:layout_width="match_parent" | ||||||
|  |                     android:descendantFocusability="afterDescendants" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:fadingEdge="horizontal" | ||||||
|  |                     android:focusableInTouchMode="false" | ||||||
|  |                     android:focusable="false" | ||||||
|  |                     android:layout_gravity="center" | ||||||
|  |                     android:orientation="horizontal" | ||||||
|  |                     android:paddingTop="5dp" | ||||||
|  |                     android:requiresFadingEdge="horizontal" | ||||||
|  |                     app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | ||||||
|  |                     tools:itemCount="2" | ||||||
|  |                     tools:listitem="@layout/result_mini_image" /> | ||||||
|  |         </LinearLayout> | ||||||
| 
 | 
 | ||||||
|         <LinearLayout |         <LinearLayout | ||||||
|                 android:gravity="end" |                 android:gravity="end" | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								app/src/main/res/layout/result_mini_image.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/layout/result_mini_image.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <ImageView xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |         xmlns:app="http://schemas.android.com/apk/res-auto" | ||||||
|  |         xmlns:tools="http://schemas.android.com/tools" | ||||||
|  |         android:layout_width="35dp" | ||||||
|  |         android:layout_height="35dp" | ||||||
|  |         android:layout_gravity="center" | ||||||
|  |         tools:src="@drawable/ic_anilist_icon" | ||||||
|  |         app:tint="?attr/white"> | ||||||
|  | </ImageView> | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue