mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master'
This commit is contained in:
		
						commit
						52d81dcb2d
					
				
					 13 changed files with 108 additions and 42 deletions
				
			
		|  | @ -10,6 +10,7 @@ class SyncRepo(private val repo: SyncAPI) { | |||
|     val name = repo.name | ||||
|     val icon = repo.icon | ||||
|     val mainUrl = repo.mainUrl | ||||
|     val requiresLogin = repo.requiresLogin | ||||
| 
 | ||||
|     suspend fun score(id: String, status: SyncAPI.SyncStatus): Resource<Boolean> { | ||||
|         return safeApiCall { repo.score(id, status) } | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI { | |||
|     override val idPrefix = "anilist" | ||||
|     override var mainUrl = "https://anilist.co" | ||||
|     override val icon = R.drawable.ic_anilist_icon | ||||
|     override val requiresLogin = true | ||||
|     override val requiresLogin = false | ||||
|     override val createAccountUrl = "$mainUrl/signup" | ||||
| 
 | ||||
|     override fun loginInfo(): AuthAPI.LoginInfo? { | ||||
|  | @ -90,9 +90,9 @@ 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 = (Regex("anilist\\.co/anime/(\\d*)").find(id)?.groupValues?.getOrNull(1) | ||||
|             ?: id).toIntOrNull() ?: return null | ||||
|             ?: id).toIntOrNull() ?: throw ErrorLoadingException("Invalid internalId") | ||||
|         val season = getSeason(internalId).data.Media | ||||
| 
 | ||||
|         return SyncAPI.SyncResult( | ||||
|  |  | |||
|  | @ -26,10 +26,14 @@ object Kitsu { | |||
|     private val cache: MutableMap<Pair<String, String>, Map<Int, KitsuResponse.Node>> = | ||||
|         mutableMapOf() | ||||
| 
 | ||||
|     var isEnabled = true | ||||
| 
 | ||||
|     suspend fun getEpisodesDetails( | ||||
|         malId: String?, | ||||
|         anilistId: String? | ||||
|         anilistId: String?, | ||||
|         isResponseRequired: Boolean = true, // overrides isEnabled | ||||
|     ): Map<Int, KitsuResponse.Node>? { | ||||
|         if (!isResponseRequired && !isEnabled) return null | ||||
|         if (anilistId != null) { | ||||
|             try { | ||||
|                 val map = getKitsuEpisodesDetails(anilistId, "ANILIST_ANIME") | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI { | |||
|     override var mainUrl = "https://myanimelist.net" | ||||
|     val apiUrl = "https://api.myanimelist.net" | ||||
|     override val icon = R.drawable.mal_logo | ||||
|     override val requiresLogin = true | ||||
|     override val requiresLogin = false | ||||
| 
 | ||||
|     override val createAccountUrl = "$mainUrl/register.php" | ||||
| 
 | ||||
|  | @ -189,9 +189,11 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI { | |||
|         val internalId = id.toIntOrNull() ?: return null | ||||
|         val url = | ||||
|             "$apiUrl/v2/anime/$internalId?fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,created_at,updated_at,media_type,status,genres,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,pictures,background,related_anime,related_manga,recommendations,studios,statistics" | ||||
| 
 | ||||
|         val auth = getAuth() | ||||
|         val res = app.get( | ||||
|             url, headers = mapOf( | ||||
|                 "Authorization" to "Bearer " + (getAuth() ?: return null) | ||||
|             url, headers = if (auth == null) emptyMap() else mapOf( | ||||
|                 "Authorization" to "Bearer $auth" | ||||
|             ) | ||||
|         ).text | ||||
|         return mapper.readValue<MalAnime>(res).let { malAnime -> | ||||
|  |  | |||
|  | @ -738,7 +738,7 @@ class CS3IPlayer : IPlayer { | |||
|                     super.onPlaybackStateChanged(playbackState) | ||||
|                     when (playbackState) { | ||||
|                         Player.STATE_READY -> { | ||||
|                             requestAutoFocus?.invoke() | ||||
| 
 | ||||
|                         } | ||||
|                         Player.STATE_ENDED -> { | ||||
|                             handleEvent(CSPlayerEvent.NextEpisode) | ||||
|  |  | |||
|  | @ -46,6 +46,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey | |||
| import com.lagradost.cloudstream3.CommonActivity.getCastSession | ||||
| import com.lagradost.cloudstream3.CommonActivity.showToast | ||||
| import com.lagradost.cloudstream3.mvvm.* | ||||
| import com.lagradost.cloudstream3.syncproviders.providers.Kitsu | ||||
| import com.lagradost.cloudstream3.ui.WatchType | ||||
| import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD | ||||
| import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO | ||||
|  | @ -642,6 +643,8 @@ class ResultFragment : ResultTrailerPlayer() { | |||
|                 false | ||||
|             } | ||||
|         result_trailer_loading?.isVisible = isSuccess | ||||
|         result_smallscreen_holder?.isVisible = !isSuccess && !isFullScreenPlayer | ||||
|         result_fullscreen_holder?.isVisible = !isSuccess && isFullScreenPlayer | ||||
|     } | ||||
| 
 | ||||
|     private fun setTrailers(trailers: List<ExtractorLink>?) { | ||||
|  | @ -2114,6 +2117,9 @@ class ResultFragment : ResultTrailerPlayer() { | |||
|             val showFillers = | ||||
|                 settingsManager.getBoolean(ctx.getString(R.string.show_fillers_key), false) | ||||
| 
 | ||||
|             Kitsu.isEnabled = | ||||
|                 settingsManager.getBoolean(ctx.getString(R.string.show_kitsu_posters_key), true) | ||||
| 
 | ||||
|             val tempUrl = url | ||||
|             if (tempUrl != null) { | ||||
|                 result_reload_connectionerror.setOnClickListener { | ||||
|  |  | |||
|  | @ -54,6 +54,9 @@ open class ResultTrailerPlayer : com.lagradost.cloudstream3.ui.player.FullScreen | |||
|             } | ||||
| 
 | ||||
|             result_trailer_loading?.isVisible = false | ||||
|             result_smallscreen_holder?.isVisible = !isFullScreenPlayer | ||||
|             result_fullscreen_holder?.isVisible = isFullScreenPlayer | ||||
| 
 | ||||
|             player_background?.apply { | ||||
|                 isVisible = true | ||||
|                 layoutParams = | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ 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 | ||||
|  | @ -28,6 +29,7 @@ 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 | ||||
|  | @ -160,30 +162,35 @@ class ResultViewModel : ViewModel() { | |||
|             argamap({ | ||||
|                 addTrailer(meta.trailers) | ||||
|             }, { | ||||
| 
 | ||||
|                 if (this !is AnimeLoadResponse) return@argamap | ||||
|                 val map = getEpisodesDetails(getMalId(), getAniListId()) | ||||
|                 val map = getEpisodesDetails(getMalId(), getAniListId(), isResponseRequired = false) | ||||
|                 if (map.isNullOrEmpty()) return@argamap | ||||
|                 updateEpisodes = DubStatus.values().map { dubStatus -> | ||||
|                     val current = | ||||
|                         this.episodes[dubStatus]?.sortedBy { it.episode ?: 0 }?.toMutableList() | ||||
|                         this.episodes[dubStatus]?.mapIndexed { index, episode -> | ||||
|                             episode.apply { | ||||
|                                 this.episode = this.episode ?: (index + 1) | ||||
|                             } | ||||
|                         }?.sortedBy { it.episode ?: 0 }?.toMutableList() | ||||
|                     if (current.isNullOrEmpty()) return@map false | ||||
|                     val episodes = current.mapIndexed { index, ep -> ep.episode ?: (index + 1) } | ||||
|                     val episodeNumbers = current.map { ep -> ep.episode!! } | ||||
|                     var updateCount = 0 | ||||
|                     map.forEach { (episode, node) -> | ||||
|                         episodes.binarySearch(episode).let { index -> | ||||
|                         episodeNumbers.binarySearch(episode).let { index -> | ||||
|                             current.getOrNull(index)?.let { currentEp -> | ||||
|                                 current[index] = currentEp.apply { | ||||
|                                     updateCount++ | ||||
|                                     val currentBack = this | ||||
|                                     this.description = this.description ?: node.description?.en | ||||
|                                     this.name = this.name ?: node.titles?.canonical | ||||
|                                     this.episode = this.episode ?: node.num ?: episodes[index] | ||||
|                                     this.episode = this.episode ?: node.num ?: episodeNumbers[index] | ||||
|                                     this.posterUrl = this.posterUrl ?: node.thumbnail?.original?.url | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                     this.episodes[dubStatus] = current | ||||
| 
 | ||||
|                     updateCount > 0 | ||||
|                 }.any { it } | ||||
|             }) | ||||
|  | @ -432,6 +439,7 @@ class ResultViewModel : ViewModel() { | |||
|                     res[dubStatus]?.let { episodes -> | ||||
|                         updateEpisodes(mainId, episodes, -1) | ||||
|                     } | ||||
| 
 | ||||
|                     _dubStatus.postValue(dubStatus) | ||||
|                     _dubSubSelections.postValue(loadResponse.episodes.keys) | ||||
|                 } | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.malApi | |||
| import com.lagradost.cloudstream3.syncproviders.SyncAPI | ||||
| import com.lagradost.cloudstream3.utils.SyncUtil | ||||
| import kotlinx.coroutines.launch | ||||
| import java.util.* | ||||
| 
 | ||||
| 
 | ||||
| data class CurrentSynced( | ||||
|  | @ -178,7 +179,12 @@ class SyncViewModel : ViewModel() { | |||
|     fun modifyMaxEpisode(episodeNum: Int) { | ||||
|         Log.i(TAG, "modifyMaxEpisode = $episodeNum") | ||||
|         modifyData { status -> | ||||
|             status.copy(watchedEpisodes = maxOf(episodeNum, status.watchedEpisodes ?: return@modifyData null)) | ||||
|             status.copy( | ||||
|                 watchedEpisodes = maxOf( | ||||
|                     episodeNum, | ||||
|                     status.watchedEpisodes ?: return@modifyData null | ||||
|                 ) | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -194,7 +200,7 @@ class SyncViewModel : ViewModel() { | |||
|                                 Log.i(TAG, "modifyData ${repo.name} => $newData") | ||||
|                                 repo.score(id, newData) | ||||
|                             } | ||||
|                         } else if (result is Resource.Failure){ | ||||
|                         } else if (result is Resource.Failure) { | ||||
|                             Log.e(TAG, "modifyData getStatus error ${result.errorString}") | ||||
|                         } | ||||
|                     } | ||||
|  | @ -228,15 +234,26 @@ class SyncViewModel : ViewModel() { | |||
| 
 | ||||
|         _metaResponse.postValue(Resource.Loading()) | ||||
|         var lastError: Resource<SyncAPI.SyncResult> = Resource.Failure(false, null, null, "No data") | ||||
|         syncs.forEach { (prefix, id) -> | ||||
|         val current = syncs.toList() | ||||
| 
 | ||||
|         // shitty way to sort anilist first, as it has trailers while mal does not | ||||
|         if (syncs.containsKey(aniListApi.idPrefix)) { | ||||
|             Collections.swap(current, current.indexOfFirst { it.first == aniListApi.idPrefix }, 0) | ||||
|         } | ||||
| 
 | ||||
|         current.forEach { (prefix, id) -> | ||||
|             repos.firstOrNull { it.idPrefix == prefix }?.let { repo -> | ||||
|                 if (repo.hasAccount()) { | ||||
|                 if (!repo.requiresLogin || repo.hasAccount()) { | ||||
|                     Log.i(TAG, "updateMetadata loading ${repo.idPrefix}") | ||||
|                     val result = repo.getResult(id) | ||||
|                     if (result is Resource.Success) { | ||||
|                         _metaResponse.postValue(result) | ||||
|                         return@launch | ||||
|                     } else if (result is Resource.Failure) { | ||||
|                         Log.e(TAG, "updateMetadata error ${result.errorString}") | ||||
|                         Log.e( | ||||
|                             TAG, | ||||
|                             "updateMetadata error $id at ${repo.idPrefix} ${result.errorString}" | ||||
|                         ) | ||||
|                         lastError = result | ||||
|                     } | ||||
|                 } | ||||
|  |  | |||
							
								
								
									
										15
									
								
								app/src/main/res/drawable/kitsu_icon.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/src/main/res/drawable/kitsu_icon.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| <vector xmlns:tools="http://schemas.android.com/tools" | ||||
|         xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|         android:height="24dp" | ||||
|         android:tint="?attr/white" | ||||
|         android:viewportHeight="225" | ||||
|         android:viewportWidth="225" | ||||
|         android:width="24dp"> | ||||
|     <path | ||||
|             android:fillColor="@android:color/white" | ||||
|             android:pathData="M152.7 48.5c-6.8-2.5-14.1-4.1-21.8-4.4-12.7-0.6-24.8 2.2-35.4 7.6-0.6 0.3-1.3 0.6-2 1v36.4c0 0.5 0 2.4-0.3 4-0.7 3.7-2.9 7-6 9.1-2.6 1.8-5.6 2.6-8.8 2.5-0.6 0-1.3-0.1-1.9-0.2-1.6-0.3-3.3-0.9-3.8-1.1-1.4-0.5-21.8-8.4-31.6-12.2-1.2-0.5-2.2-0.9-3-1.2-11.7 9.9-24 21.7-35.5 35.6-0.1 0.1-0.6 0.7-0.7 0.8-1.5 2.1-1.6 5.1 0 7.4 1.2 1.7 3.1 2.7 5 2.8 1.3 0.1 2.7-0.3 3.9-1.1 0.1-0.1 0.2-0.2 0.4-0.3 12.2-8.8 25.6-15.9 39.8-21.6 1-0.5 2.2-0.8 3.3-0.7 1.6 0.1 3.1 0.7 4.3 1.9 2.3 2.3 2.4 6 0.5 8.5-0.8 1.2-1.5 2.4-2.2 3.6-7.6 12.4-13.7 25.9-18.3 40-0.1 0.4-0.2 0.7-0.3 1.1v0.1c-0.4 1.7-0.1 3.5 1 5 1.2 1.7 3.1 2.7 5.1 2.8 1.4 0.1 2.7-0.3 3.9-1.1 0.5-0.4 1-0.8 1.4-1.3 0.1-0.2 0.3-0.4 0.4-0.6 5-7.1 10.5-13.8 16.4-20 26.3-28.2 61.2-48.1 100.3-55.9 0.3-0.1 0.6-0.1 0.9-0.1 2.2 0.1 3.9 2 3.8 4.2-0.1 1.9-1.4 3.3-3.2 3.7-36.3 7.7-101.7 50.8-78.8 113.4 0.4 1 0.7 1.6 1.2 2.5 1.2 1.7 3.1 2.7 5 2.8 1.1 0 4.2-0.3 6.1-3.7 3.7-7 10.7-14.8 30.9-23.2 56.3-23.3 65.6-56.6 66.6-77.7v-1.2c0.9-31.4-18.6-58.8-46.6-69.2zm-56.5 165C91 198 91.5 183 97.6 168.7c11.7 18.9 32.1 20.5 32.1 20.5-20.9 8.7-29.1 17.3-33.5 24.3z" | ||||
|             tools:ignore="VectorPath" /> | ||||
|     <path | ||||
|             android:fillColor="@android:color/white" | ||||
|             android:pathData="M1.1 50.6c0.1 0.2 0.3 0.4 0.4 0.5 5.3 7.2 11.3 13.5 17.8 19.1 0.1 0.1 0.2 0.1 0.2 0.2 4.2 3.6 12.2 8.8 18 10.9 0 0 36.1 13.9 38 14.7 0.7 0.3 1.7 0.6 2.2 0.7 1.6 0.3 3.3 0 4.8-1s2.4-2.5 2.7-4.1c0.1-0.6 0.2-1.6 0.2-2.3V48.5c0.1-6.2-1.9-15.6-3.7-20.8 0-0.1-0.1-0.2-0.1-0.3-2.8-8.1-6.6-16-11.4-23.5l-0.3-0.6-0.1-0.1c-2-2.8-6-3.5-8.9-1.5-0.5 0.3-0.8 0.7-1.2 1.1-0.3 0.4-0.5 0.7-0.8 1.1-6.4 9.3-9 20.6-7.3 31.7-3.3 1.7-6.8 4-7.2 4.3-0.4 0.3-3.9 2.7-6.6 5.2-9.7-5.5-21.3-7.2-32.2-4.6-0.4 0.1-0.9 0.2-1.3 0.3-0.5 0.2-1 0.4-1.4 0.7-2.9 2-3.7 5.9-1.8 8.9v0.2zm63.5-40.1c3.4 5.7 6.3 11.6 8.6 17.8-4.6 0.8-9.1 2-13.5 3.6-0.6-7.5 1.1-14.9 4.9-21.4zM31.5 51.3c-3.2 3.5-5.9 7.3-8.3 11.3-4.9-4.3-9.4-9.2-13.5-14.4 7.5-1.3 15-0.2 21.8 3.1z" /> | ||||
| </vector> | ||||
|  | @ -8,6 +8,31 @@ | |||
|         android:screenOrientation="landscape" | ||||
|         tools:orientation="vertical"> | ||||
| 
 | ||||
| 
 | ||||
|     <TextView | ||||
|             android:id="@+id/player_time_text" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="200dp" | ||||
|             android:gravity="center" | ||||
|             android:shadowColor="@android:color/black" | ||||
|             android:shadowRadius="10.0" | ||||
|             android:textColor="@android:color/white" | ||||
|             android:textSize="30sp" | ||||
|             tools:text="+100" /> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|             android:id="@+id/subtitle_holder" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent"> | ||||
| 
 | ||||
|         <View | ||||
|                 android:id="@+id/shadow_overlay" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:background="@color/black_overlay" /> | ||||
|     </FrameLayout> | ||||
| 
 | ||||
| 
 | ||||
|     <FrameLayout | ||||
|             android:id="@+id/player_intro_play" | ||||
|             android:layout_width="match_parent" | ||||
|  | @ -35,29 +60,6 @@ | |||
|                 android:layout_height="60dp" /> | ||||
|     </FrameLayout> | ||||
| 
 | ||||
|     <TextView | ||||
|             android:id="@+id/player_time_text" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="200dp" | ||||
|             android:gravity="center" | ||||
|             android:shadowColor="@android:color/black" | ||||
|             android:shadowRadius="10.0" | ||||
|             android:textColor="@android:color/white" | ||||
|             android:textSize="30sp" | ||||
|             tools:text="+100" /> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|             android:id="@+id/subtitle_holder" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent"> | ||||
| 
 | ||||
|         <View | ||||
|                 android:id="@+id/shadow_overlay" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="match_parent" | ||||
|                 android:background="@color/black_overlay" /> | ||||
|     </FrameLayout> | ||||
| 
 | ||||
|     <androidx.constraintlayout.widget.ConstraintLayout | ||||
|             android:id="@+id/player_video_holder" | ||||
|             android:layout_width="match_parent" | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ | |||
|     <string name="display_sub_key" translatable="false">display_sub_key</string> | ||||
|     <string name="show_fillers_key" translatable="false">show_fillers_key</string> | ||||
|     <string name="show_trailers_key" translatable="false">show_trailers_key</string> | ||||
|     <string name="show_kitsu_posters_key" translatable="false">show_kitsu_posters_key</string> | ||||
|     <string name="random_button_key" translatable="false">random_button_key</string> | ||||
|     <string name="provider_lang_key" translatable="false">provider_lang_key</string> | ||||
|     <string name="dns_key" translatable="false">dns_key</string> | ||||
|  | @ -252,6 +253,8 @@ | |||
|     <string name="bug_report_settings_on">Sends no data</string> | ||||
|     <string name="show_fillers_settings">Show filler episode for anime</string> | ||||
|     <string name="show_trailers_settings">Show trailers</string> | ||||
|     <string name="kitsu_settings">Show posters from kitsu</string> | ||||
| 
 | ||||
|     <string name="updates_settings">Show app updates</string> | ||||
|     <string name="updates_settings_des">Automatically search for new updates on start</string> | ||||
|     <string name="uprereleases_settings">Update to prereleases</string> | ||||
|  |  | |||
|  | @ -34,6 +34,11 @@ | |||
|             android:icon="@drawable/baseline_theaters_24" | ||||
|             android:title="@string/show_trailers_settings" | ||||
|             android:defaultValue="true" /> | ||||
|     <SwitchPreference | ||||
|             android:key="@string/show_kitsu_posters_key" | ||||
|             android:icon="@drawable/kitsu_icon" | ||||
|             android:title="@string/kitsu_settings" | ||||
|             android:defaultValue="true" /> | ||||
|     <SwitchPreference | ||||
|             android:key="@string/show_fillers_key" | ||||
|             android:icon="@drawable/ic_baseline_skip_next_24" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue