forked from recloudstream/cloudstream
fixed posters, trailer and anilist/mal + added option for posters
This commit is contained in:
parent
f90a5dd2cb
commit
7c7b3a3e5a
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 ->
|
||||
|
|
|
@ -736,7 +736,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…
Reference in a new issue