mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
fillers
This commit is contained in:
parent
bc1653e8c1
commit
989d7666be
8 changed files with 178 additions and 33 deletions
|
@ -351,6 +351,7 @@ data class AnimeEpisode(
|
||||||
val date: String? = null,
|
val date: String? = null,
|
||||||
val rating: Int? = null,
|
val rating: Int? = null,
|
||||||
val descript: String? = null,
|
val descript: String? = null,
|
||||||
|
val episode : Int? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class TorrentLoadResponse(
|
data class TorrentLoadResponse(
|
||||||
|
|
|
@ -141,7 +141,7 @@ class EpisodeAdapter(
|
||||||
localCard = card
|
localCard = card
|
||||||
|
|
||||||
val name = if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
|
val name = if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
|
||||||
episodeText.text = name
|
episodeText.text = if(card.isFiller == true) episodeText.context.getString(R.string.filler_format).format(name) else name
|
||||||
episodeText.isSelected = true // is needed for text repeating
|
episodeText.isSelected = true // is needed for text repeating
|
||||||
|
|
||||||
val displayPos = card.getDisplayPosition()
|
val displayPos = card.getDisplayPosition()
|
||||||
|
|
|
@ -22,9 +22,11 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import androidx.core.text.color
|
import androidx.core.text.color
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
|
@ -35,6 +37,7 @@ import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||||
import com.lagradost.cloudstream3.APIHolder.getId
|
import com.lagradost.cloudstream3.APIHolder.getId
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
||||||
|
import com.lagradost.cloudstream3.MainActivity.Companion.updateLocale
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.ui.WatchType
|
import com.lagradost.cloudstream3.ui.WatchType
|
||||||
|
@ -92,6 +95,7 @@ data class ResultEpisode(
|
||||||
val duration: Long, // duration in MS
|
val duration: Long, // duration in MS
|
||||||
val rating: Int?,
|
val rating: Int?,
|
||||||
val descript: String?,
|
val descript: String?,
|
||||||
|
val isFiller: Boolean?,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ResultEpisode.getRealPosition(): Long {
|
fun ResultEpisode.getRealPosition(): Long {
|
||||||
|
@ -121,6 +125,7 @@ fun Context.buildResultEpisode(
|
||||||
index: Int,
|
index: Int,
|
||||||
rating: Int?,
|
rating: Int?,
|
||||||
descript: String?,
|
descript: String?,
|
||||||
|
isFiller: Boolean?,
|
||||||
): ResultEpisode {
|
): ResultEpisode {
|
||||||
val posDur = getViewPos(id)
|
val posDur = getViewPos(id)
|
||||||
return ResultEpisode(
|
return ResultEpisode(
|
||||||
|
@ -136,6 +141,7 @@ fun Context.buildResultEpisode(
|
||||||
posDur?.duration ?: 0,
|
posDur?.duration ?: 0,
|
||||||
rating,
|
rating,
|
||||||
descript,
|
descript,
|
||||||
|
isFiller
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,9 +448,11 @@ class ResultFragment : Fragment() {
|
||||||
if (isMovie) null else episodeClick.data.episode
|
if (isMovie) null else episodeClick.data.episode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
val folder = when (currentType) {
|
val folder = when (currentType) {
|
||||||
TvType.Anime -> "Anime/$titleName"
|
TvType.Anime -> "Anime/$titleName"
|
||||||
TvType.Movie -> "Movies"
|
TvType.Movie -> "Movies"
|
||||||
|
TvType.AnimeMovie -> "Movies"
|
||||||
TvType.TvSeries -> "TVSeries/$titleName"
|
TvType.TvSeries -> "TVSeries/$titleName"
|
||||||
TvType.ONA -> "ONA"
|
TvType.ONA -> "ONA"
|
||||||
TvType.Cartoon -> "Cartoons/$titleName"
|
TvType.Cartoon -> "Cartoons/$titleName"
|
||||||
|
@ -817,11 +825,22 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.publicEpisodes) { episodes ->
|
observe(viewModel.publicEpisodes) { episodes ->
|
||||||
if (result_episodes == null || result_episodes.adapter == null) return@observe
|
when (episodes) {
|
||||||
currentEpisodes = episodes
|
is Resource.Failure -> {
|
||||||
(result_episodes?.adapter as EpisodeAdapter?)?.cardList = episodes
|
result_episode_loading.isVisible = false
|
||||||
(result_episodes?.adapter as EpisodeAdapter?)?.updateLayout()
|
}
|
||||||
(result_episodes?.adapter as EpisodeAdapter?)?.notifyDataSetChanged()
|
is Resource.Loading -> {
|
||||||
|
result_episode_loading.isVisible = true
|
||||||
|
}
|
||||||
|
is Resource.Success -> {
|
||||||
|
result_episode_loading.isVisible = false
|
||||||
|
if (result_episodes == null || result_episodes.adapter == null) return@observe
|
||||||
|
currentEpisodes = episodes.value
|
||||||
|
(result_episodes?.adapter as EpisodeAdapter?)?.cardList = episodes.value
|
||||||
|
(result_episodes?.adapter as EpisodeAdapter?)?.updateLayout()
|
||||||
|
(result_episodes?.adapter as EpisodeAdapter?)?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.selectedRange) { range ->
|
observe(viewModel.selectedRange) { range ->
|
||||||
|
@ -856,6 +875,10 @@ class ResultFragment : Fragment() {
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
val d = data.value
|
val d = data.value
|
||||||
if (d is LoadResponse) {
|
if (d is LoadResponse) {
|
||||||
|
if (d !is AnimeLoadResponse && result_episode_loading.isVisible) { // no episode loading when not anime
|
||||||
|
result_episode_loading.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
updateVisStatus(2)
|
updateVisStatus(2)
|
||||||
|
|
||||||
result_vpn?.text = when (api.vpnStatus) {
|
result_vpn?.text = when (api.vpnStatus) {
|
||||||
|
@ -1034,7 +1057,8 @@ class ResultFragment : Fragment() {
|
||||||
0L,
|
0L,
|
||||||
0L,
|
0L,
|
||||||
null,
|
null,
|
||||||
null
|
null,
|
||||||
|
null,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1073,25 +1097,28 @@ class ResultFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val tempUrl = url
|
context?.let { ctx ->
|
||||||
if (tempUrl != null) {
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
|
||||||
result_reload_connectionerror.setOnClickListener {
|
val showFillers = settingsManager.getBoolean(ctx.getString(R.string.show_fillers_key), true)
|
||||||
viewModel.load(it.context, tempUrl, apiName)
|
|
||||||
}
|
|
||||||
|
|
||||||
result_reload_connection_open_in_browser.setOnClickListener {
|
val tempUrl = url
|
||||||
val i = Intent(ACTION_VIEW)
|
if (tempUrl != null) {
|
||||||
i.data = Uri.parse(tempUrl)
|
result_reload_connectionerror.setOnClickListener {
|
||||||
try {
|
viewModel.load(it.context, tempUrl, apiName, showFillers)
|
||||||
startActivity(i)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (viewModel.resultResponse.value == null) {
|
result_reload_connection_open_in_browser.setOnClickListener {
|
||||||
context?.let { ctx ->
|
val i = Intent(ACTION_VIEW)
|
||||||
viewModel.load(ctx, tempUrl, apiName)
|
i.data = Uri.parse(tempUrl)
|
||||||
|
try {
|
||||||
|
startActivity(i)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewModel.resultResponse.value == null) {
|
||||||
|
viewModel.load(ctx, tempUrl, apiName, showFillers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.FillerEpisodeCheck.getFillerEpisodes
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -39,7 +40,7 @@ class ResultViewModel : ViewModel() {
|
||||||
private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
||||||
private val episodeById: MutableLiveData<HashMap<Int, Int>> = MutableLiveData() // lookup by ID to get Index
|
private val episodeById: MutableLiveData<HashMap<Int, Int>> = MutableLiveData() // lookup by ID to get Index
|
||||||
|
|
||||||
private val _publicEpisodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData()
|
private val _publicEpisodes: MutableLiveData<Resource<List<ResultEpisode>>> = MutableLiveData()
|
||||||
private val _publicEpisodesCount: MutableLiveData<Int> = MutableLiveData() // before the sorting
|
private val _publicEpisodesCount: MutableLiveData<Int> = MutableLiveData() // before the sorting
|
||||||
private val _rangeOptions: MutableLiveData<List<String>> = MutableLiveData()
|
private val _rangeOptions: MutableLiveData<List<String>> = MutableLiveData()
|
||||||
val selectedRange: MutableLiveData<String> = MutableLiveData()
|
val selectedRange: MutableLiveData<String> = MutableLiveData()
|
||||||
|
@ -48,7 +49,7 @@ class ResultViewModel : ViewModel() {
|
||||||
|
|
||||||
val resultResponse: LiveData<Resource<Any?>> get() = _resultResponse
|
val resultResponse: LiveData<Resource<Any?>> get() = _resultResponse
|
||||||
val episodes: LiveData<List<ResultEpisode>> get() = _episodes
|
val episodes: LiveData<List<ResultEpisode>> get() = _episodes
|
||||||
val publicEpisodes: LiveData<List<ResultEpisode>> get() = _publicEpisodes
|
val publicEpisodes: LiveData<Resource<List<ResultEpisode>>> get() = _publicEpisodes
|
||||||
val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount
|
val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount
|
||||||
|
|
||||||
private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData()
|
private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData()
|
||||||
|
@ -106,7 +107,7 @@ class ResultViewModel : ViewModel() {
|
||||||
val seasons = seasonTypes.toList().map { it.first }.sortedBy { it }
|
val seasons = seasonTypes.toList().map { it.first }.sortedBy { it }
|
||||||
seasonSelections.postValue(seasons)
|
seasonSelections.postValue(seasons)
|
||||||
if (seasons.isEmpty()) { // WHAT THE FUCK DID YOU DO????? HOW DID YOU DO THIS
|
if (seasons.isEmpty()) { // WHAT THE FUCK DID YOU DO????? HOW DID YOU DO THIS
|
||||||
_publicEpisodes.postValue(ArrayList())
|
_publicEpisodes.postValue(Resource.Success( ArrayList()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ class ResultViewModel : ViewModel() {
|
||||||
selectedRange.postValue(allRange)
|
selectedRange.postValue(allRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
_publicEpisodes.postValue(currentList)
|
_publicEpisodes.postValue(Resource.Success( currentList))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun changeSeason(context: Context, selection: Int?) {
|
fun changeSeason(context: Context, selection: Int?) {
|
||||||
|
@ -224,17 +225,18 @@ class ResultViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterName(name : String?) : String? {
|
private fun filterName(name: String?): String? {
|
||||||
if(name == null) return null
|
if (name == null) return null
|
||||||
Regex("[eE]pisode [0-9]*(.*)").find(name)?.groupValues?.get(1)?.let {
|
Regex("[eE]pisode [0-9]*(.*)").find(name)?.groupValues?.get(1)?.let {
|
||||||
if(it.isEmpty())
|
if (it.isEmpty())
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
fun load(context: Context, url: String, apiName: String) = viewModelScope.launch {
|
fun load(context: Context, url: String, apiName: String, showFillers : Boolean) = viewModelScope.launch {
|
||||||
_resultResponse.postValue(Resource.Loading(url))
|
_resultResponse.postValue(Resource.Loading(url))
|
||||||
|
_publicEpisodes.postValue(Resource.Loading())
|
||||||
|
|
||||||
_apiName.postValue(apiName)
|
_apiName.postValue(apiName)
|
||||||
val api = getApiFromName(apiName)
|
val api = getApiFromName(apiName)
|
||||||
|
@ -273,14 +275,17 @@ class ResultViewModel : ViewModel() {
|
||||||
|
|
||||||
val dataList = (if (isDub) d.dubEpisodes else d.subEpisodes)
|
val dataList = (if (isDub) d.dubEpisodes else d.subEpisodes)
|
||||||
|
|
||||||
|
val fillerEpisodes = if(showFillers) safeApiCall { getFillerEpisodes(d.name) } else null
|
||||||
|
|
||||||
if (dataList != null) { // TODO dub and sub at the same time
|
if (dataList != null) { // TODO dub and sub at the same time
|
||||||
val episodes = ArrayList<ResultEpisode>()
|
val episodes = ArrayList<ResultEpisode>()
|
||||||
for ((index, i) in dataList.withIndex()) {
|
for ((index, i) in dataList.withIndex()) {
|
||||||
|
val episode = i.episode ?: (index + 1);
|
||||||
episodes.add(
|
episodes.add(
|
||||||
context.buildResultEpisode(
|
context.buildResultEpisode(
|
||||||
filterName(i.name),
|
filterName(i.name),
|
||||||
i.posterUrl,
|
i.posterUrl,
|
||||||
index + 1, //TODO MAKE ABLE TO NOT HAVE SOME EPISODE
|
episode,
|
||||||
null, // TODO FIX SEASON
|
null, // TODO FIX SEASON
|
||||||
i.url,
|
i.url,
|
||||||
apiName,
|
apiName,
|
||||||
|
@ -288,6 +293,10 @@ class ResultViewModel : ViewModel() {
|
||||||
index,
|
index,
|
||||||
i.rating,
|
i.rating,
|
||||||
i.descript,
|
i.descript,
|
||||||
|
if (fillerEpisodes is Resource.Success) fillerEpisodes.value?.let {
|
||||||
|
it.contains(episode) && it[episode] == true
|
||||||
|
}
|
||||||
|
?: false else false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -309,7 +318,8 @@ class ResultViewModel : ViewModel() {
|
||||||
(mainId + index + 1).hashCode(),
|
(mainId + index + 1).hashCode(),
|
||||||
index,
|
index,
|
||||||
i.rating,
|
i.rating,
|
||||||
i.descript
|
i.descript,
|
||||||
|
null,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -329,6 +339,7 @@ class ResultViewModel : ViewModel() {
|
||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
)
|
)
|
||||||
), -1
|
), -1
|
||||||
)
|
)
|
||||||
|
@ -347,6 +358,7 @@ class ResultViewModel : ViewModel() {
|
||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
)
|
)
|
||||||
), -1
|
), -1
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
|
object FillerEpisodeCheck {
|
||||||
|
private const val MAIN_URL = "https://www.animefillerlist.com"
|
||||||
|
|
||||||
|
var list: HashMap<String, String>? = null
|
||||||
|
|
||||||
|
private fun fixName(name: String): String {
|
||||||
|
return name.toLowerCase(Locale.ROOT)/*.replace(" ", "")*/.replace("-", " ").replace("[^a-zA-Z0-9 ]".toRegex(), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFillerList(): Boolean {
|
||||||
|
if (list != null) return true
|
||||||
|
try {
|
||||||
|
val result = khttp.get("$MAIN_URL/shows")
|
||||||
|
val documented = Jsoup.parse(result.text)
|
||||||
|
val localHTMLList = documented.select("div#ShowList > div.Group > ul > li > a")
|
||||||
|
val localList = HashMap<String, String>()
|
||||||
|
for (i in localHTMLList) {
|
||||||
|
val name = i.text()
|
||||||
|
|
||||||
|
if (name.toLowerCase(Locale.ROOT).contains("manga only")) continue
|
||||||
|
|
||||||
|
val href = i.attr("href")
|
||||||
|
if (name.isNullOrEmpty() || href.isNullOrEmpty()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val values = "(.*) \\((.*)\\)".toRegex().matchEntire(name)?.groups
|
||||||
|
if (values != null) {
|
||||||
|
for (index in 1 until values.size) {
|
||||||
|
val localName = values[index]?.value ?: continue
|
||||||
|
localList[fixName(localName)] = href
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
localList[fixName(name)] = href
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (localList.size > 0) {
|
||||||
|
list = localList
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFillerEpisodes(query: String): HashMap<Int, Boolean>? {
|
||||||
|
try {
|
||||||
|
if (!getFillerList()) return null
|
||||||
|
val localList = list ?: return null
|
||||||
|
|
||||||
|
// Strips these from the name
|
||||||
|
val blackList = listOf(
|
||||||
|
"TV Dubbed",
|
||||||
|
"(Dub)",
|
||||||
|
"Subbed",
|
||||||
|
"(TV)",
|
||||||
|
"(Uncensored)",
|
||||||
|
"(Censored)",
|
||||||
|
"(\\d+)" // year
|
||||||
|
)
|
||||||
|
val blackListRegex =
|
||||||
|
Regex(""" (${blackList.joinToString(separator = "|").replace("(", "\\(").replace(")", "\\)")})""")
|
||||||
|
|
||||||
|
val realQuery = fixName(query.replace(blackListRegex, "")).replace("shippuuden", "shippuden")
|
||||||
|
if (!localList.containsKey(realQuery)) return null
|
||||||
|
val href = localList[realQuery]?.replace(MAIN_URL, "") ?: return null // JUST IN CASE
|
||||||
|
val result = khttp.get("$MAIN_URL$href")
|
||||||
|
val documented = Jsoup.parse(result.text) ?: return null
|
||||||
|
val hashMap = HashMap<Int, Boolean>()
|
||||||
|
documented.select("table.EpisodeList > tbody > tr").forEach {
|
||||||
|
val type = it.selectFirst("td.Type > span").text() == "Filler"
|
||||||
|
val episodeNumber = it.selectFirst("td.Number").text().toIntOrNull()
|
||||||
|
if (episodeNumber != null) {
|
||||||
|
hashMap[episodeNumber] = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hashMap
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -435,6 +435,13 @@
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar"
|
||||||
|
android:id="@+id/result_episode_loading"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp">
|
||||||
|
</androidx.core.widget.ContentLoadingProgressBar>
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:layout_marginTop="0dp"
|
android:layout_marginTop="0dp"
|
||||||
android:paddingBottom="100dp"
|
android:paddingBottom="100dp"
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<string name="double_tap_enabled_key" translatable="false">double_tap_enabled_key</string>
|
<string name="double_tap_enabled_key" translatable="false">double_tap_enabled_key</string>
|
||||||
<string name="swipe_vertical_enabled_key" translatable="false">swipe_vertical_enabled_key</string>
|
<string name="swipe_vertical_enabled_key" translatable="false">swipe_vertical_enabled_key</string>
|
||||||
<string name="display_sub_key" translatable="false">display_sub_key</string>
|
<string name="display_sub_key" translatable="false">display_sub_key</string>
|
||||||
|
<string name="show_fillers_key" translatable="false">show_fillers_key</string>
|
||||||
|
|
||||||
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
||||||
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
|
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
<string name="player_speed_text_format" formatted="true">Speed (%.2fx)</string>
|
<string name="player_speed_text_format" formatted="true">Speed (%.2fx)</string>
|
||||||
<string name="rated_format" formatted="true">Rated: %.1f</string>
|
<string name="rated_format" formatted="true">Rated: %.1f</string>
|
||||||
<string name="new_update_format" formatted="true">New update found!\n%s -> %s</string>
|
<string name="new_update_format" formatted="true">New update found!\n%s -> %s</string>
|
||||||
|
<string name="filler_format" formatted="true">(Filler) %s</string>
|
||||||
|
|
||||||
<string name="app_name">CloudStream</string>
|
<string name="app_name">CloudStream</string>
|
||||||
<string name="title_home">Home</string>
|
<string name="title_home">Home</string>
|
||||||
|
@ -169,6 +171,7 @@
|
||||||
<string name="advanced_search_des">Gives you the search results separated by provider</string>
|
<string name="advanced_search_des">Gives you the search results separated by provider</string>
|
||||||
<string name="bug_report_settings_off">Only sends data on crashes</string>
|
<string name="bug_report_settings_off">Only sends data on crashes</string>
|
||||||
<string name="bug_report_settings_on">Sends no data</string>
|
<string name="bug_report_settings_on">Sends no data</string>
|
||||||
|
<string name="show_fillers_settings">Show filler episode for anime</string>
|
||||||
<string name="updates_settings">Show app updates</string>
|
<string name="updates_settings">Show app updates</string>
|
||||||
<string name="updates_settings_des">Automatically search for new updates on start</string>
|
<string name="updates_settings_des">Automatically search for new updates on start</string>
|
||||||
<string name="uprereleases_settings">Update to prereleases</string>
|
<string name="uprereleases_settings">Update to prereleases</string>
|
||||||
|
|
|
@ -103,6 +103,11 @@
|
||||||
android:title="@string/app_language"
|
android:title="@string/app_language"
|
||||||
android:icon="@drawable/ic_baseline_language_24">
|
android:icon="@drawable/ic_baseline_language_24">
|
||||||
</Preference>
|
</Preference>
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="@string/show_fillers_key"
|
||||||
|
android:icon="@drawable/ic_baseline_skip_next_24"
|
||||||
|
android:title="@string/show_fillers_settings"
|
||||||
|
android:defaultValue="true"/>
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="acra.disable"
|
android:key="acra.disable"
|
||||||
android:icon="@drawable/ic_baseline_bug_report_24"
|
android:icon="@drawable/ic_baseline_bug_report_24"
|
||||||
|
|
Loading…
Reference in a new issue