forked from recloudstream/cloudstream
Added Eja.tv (live tv from all over the world)
This commit is contained in:
parent
36b30c289a
commit
b5cfc2db1c
11 changed files with 416 additions and 206 deletions
|
@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||||
import com.lagradost.cloudstream3.animeproviders.*
|
import com.lagradost.cloudstream3.animeproviders.*
|
||||||
|
import com.lagradost.cloudstream3.liveproviders.EjaTv
|
||||||
import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider
|
import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider
|
||||||
import com.lagradost.cloudstream3.movieproviders.*
|
import com.lagradost.cloudstream3.movieproviders.*
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
@ -65,6 +66,7 @@ object APIHolder {
|
||||||
FrenchStreamProvider(),
|
FrenchStreamProvider(),
|
||||||
AsianLoadProvider(),
|
AsianLoadProvider(),
|
||||||
AsiaFlixProvider(), // This should be removed in favor of asianembed.io, same source
|
AsiaFlixProvider(), // This should be removed in favor of asianembed.io, same source
|
||||||
|
EjaTv(),
|
||||||
BflixProvider(),
|
BflixProvider(),
|
||||||
FmoviesToProvider(),
|
FmoviesToProvider(),
|
||||||
SflixProProvider(),
|
SflixProProvider(),
|
||||||
|
@ -600,11 +602,16 @@ enum class TvType {
|
||||||
Torrent,
|
Torrent,
|
||||||
Documentary,
|
Documentary,
|
||||||
AsianDrama,
|
AsianDrama,
|
||||||
|
Live,
|
||||||
}
|
}
|
||||||
|
|
||||||
// IN CASE OF FUTURE ANIME MOVIE OR SMTH
|
// IN CASE OF FUTURE ANIME MOVIE OR SMTH
|
||||||
fun TvType.isMovieType(): Boolean {
|
fun TvType.isMovieType(): Boolean {
|
||||||
return this == TvType.Movie || this == TvType.AnimeMovie || this == TvType.Torrent
|
return this == TvType.Movie || this == TvType.AnimeMovie || this == TvType.Torrent || this == TvType.Live
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TvType.isLiveStream(): Boolean {
|
||||||
|
return this == TvType.Live
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns if the type has an anime opening
|
// returns if the type has an anime opening
|
||||||
|
@ -1117,6 +1124,28 @@ suspend fun MainAPI.newAnimeLoadResponse(
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class LiveStreamLoadResponse(
|
||||||
|
override var name: String,
|
||||||
|
override var url: String,
|
||||||
|
override var apiName: String,
|
||||||
|
var dataUrl: String,
|
||||||
|
|
||||||
|
override var posterUrl: String? = null,
|
||||||
|
override var year: Int? = null,
|
||||||
|
override var plot: String? = null,
|
||||||
|
|
||||||
|
override var type: TvType = TvType.Live,
|
||||||
|
override var rating: Int? = null,
|
||||||
|
override var tags: List<String>? = null,
|
||||||
|
override var duration: Int? = null,
|
||||||
|
override var trailers: List<ExtractorLink>? = null,
|
||||||
|
override var recommendations: List<SearchResponse>? = null,
|
||||||
|
override var actors: List<ActorData>? = null,
|
||||||
|
override var comingSoon: Boolean = false,
|
||||||
|
override var syncData: MutableMap<String, String> = mutableMapOf(),
|
||||||
|
override var posterHeaders: Map<String, String>? = null,
|
||||||
|
) : LoadResponse
|
||||||
|
|
||||||
data class MovieLoadResponse(
|
data class MovieLoadResponse(
|
||||||
override var name: String,
|
override var name: String,
|
||||||
override var url: String,
|
override var url: String,
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
package com.lagradost.cloudstream3.liveproviders
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import org.jsoup.select.Elements
|
||||||
|
|
||||||
|
class EjaTv : MainAPI() {
|
||||||
|
override var mainUrl = "https://eja.tv/"
|
||||||
|
override var name = "Eja.tv"
|
||||||
|
|
||||||
|
// Universal language?
|
||||||
|
override var lang = "en"
|
||||||
|
override val hasDownloadSupport = false
|
||||||
|
|
||||||
|
override val hasMainPage = true
|
||||||
|
override val supportedTypes = setOf(
|
||||||
|
TvType.Live
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun Element.toSearchResponse(): MovieSearchResponse? {
|
||||||
|
val link = this.select("div.alternative a").last() ?: return null
|
||||||
|
val href = fixUrl(link.attr("href"))
|
||||||
|
val img = this.select("div.thumb img")
|
||||||
|
|
||||||
|
return MovieSearchResponse(
|
||||||
|
// Kinda hack way to get the title
|
||||||
|
img.attr("alt").replaceFirst("Watch ", ""),
|
||||||
|
href,
|
||||||
|
this@EjaTv.name,
|
||||||
|
TvType.Live,
|
||||||
|
fixUrl(img.attr("src"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getMainPage(): HomePageResponse {
|
||||||
|
// Maybe this based on app language or as setting?
|
||||||
|
val language = "English"
|
||||||
|
val dataMap = mapOf(
|
||||||
|
"News" to mapOf("language" to language, "category" to "News"),
|
||||||
|
"Sports" to mapOf("language" to language, "category" to "Sports"),
|
||||||
|
"Entertainment" to mapOf("language" to language, "category" to "Entertainment")
|
||||||
|
)
|
||||||
|
return HomePageResponse(dataMap.apmap { (title, data) ->
|
||||||
|
val document = app.post(mainUrl, data = data).document
|
||||||
|
val shows = document.select("div.card-body").mapNotNull {
|
||||||
|
it.toSearchResponse()
|
||||||
|
}
|
||||||
|
HomePageList(
|
||||||
|
title,
|
||||||
|
shows
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun search(query: String): List<SearchResponse> {
|
||||||
|
return app.post(
|
||||||
|
mainUrl, data = mapOf("search" to query)
|
||||||
|
).document.select("div.card-body").mapNotNull {
|
||||||
|
it.toSearchResponse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun load(url: String): LoadResponse {
|
||||||
|
val doc = app.get(url).document
|
||||||
|
val sections =
|
||||||
|
doc.select("li.list-group-item.d-flex.justify-content-between.align-items-center")
|
||||||
|
|
||||||
|
val link = fixUrl(sections.last()!!.select("a").attr("href"))
|
||||||
|
|
||||||
|
val title = doc.select("h5.text-center").text()
|
||||||
|
val poster = fixUrl(doc.select("p.text-center img").attr("src"))
|
||||||
|
|
||||||
|
val summary = sections.subList(0, 3).joinToString("<br>") {
|
||||||
|
val innerText = it.ownText().trim()
|
||||||
|
val outerText = it.select("a").text().trim()
|
||||||
|
"$innerText: $outerText"
|
||||||
|
}
|
||||||
|
|
||||||
|
return LiveStreamLoadResponse(
|
||||||
|
title,
|
||||||
|
url,
|
||||||
|
this.name,
|
||||||
|
LoadData(link, title).toJson(),
|
||||||
|
poster,
|
||||||
|
plot = summary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class LoadData(
|
||||||
|
val url: String,
|
||||||
|
val title: String
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun loadLinks(
|
||||||
|
data: String,
|
||||||
|
isCasting: Boolean,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
val loadData = parseJson<LoadData>(data)
|
||||||
|
|
||||||
|
callback.invoke(
|
||||||
|
ExtractorLink(
|
||||||
|
this.name,
|
||||||
|
loadData.title,
|
||||||
|
loadData.url,
|
||||||
|
"",
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
isM3u8 = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -164,6 +164,7 @@ class HomeFragment : Fragment() {
|
||||||
docs: MaterialButton?,
|
docs: MaterialButton?,
|
||||||
movies: MaterialButton?,
|
movies: MaterialButton?,
|
||||||
asian: MaterialButton?,
|
asian: MaterialButton?,
|
||||||
|
livestream: MaterialButton?,
|
||||||
): List<Pair<MaterialButton?, List<TvType>>> {
|
): List<Pair<MaterialButton?, List<TvType>>> {
|
||||||
return listOf(
|
return listOf(
|
||||||
Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)),
|
Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)),
|
||||||
|
@ -172,6 +173,7 @@ class HomeFragment : Fragment() {
|
||||||
Pair(docs, listOf(TvType.Documentary)),
|
Pair(docs, listOf(TvType.Documentary)),
|
||||||
Pair(movies, listOf(TvType.Movie, TvType.Torrent)),
|
Pair(movies, listOf(TvType.Movie, TvType.Torrent)),
|
||||||
Pair(asian, listOf(TvType.AsianDrama)),
|
Pair(asian, listOf(TvType.AsianDrama)),
|
||||||
|
Pair(livestream, listOf(TvType.Live)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,10 +207,11 @@ class HomeFragment : Fragment() {
|
||||||
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
|
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
|
||||||
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
|
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
|
||||||
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
|
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
|
||||||
|
val livestream = dialog.findViewById<MaterialButton>(R.id.home_select_livestreams)
|
||||||
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
|
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
|
||||||
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
|
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
|
||||||
|
|
||||||
val pairList = getPairList(anime, cartoons, tvs, docs, movies, asian)
|
val pairList = getPairList(anime, cartoons, tvs, docs, movies, asian, livestream)
|
||||||
|
|
||||||
cancelBtt?.setOnClickListener {
|
cancelBtt?.setOnClickListener {
|
||||||
dialog.dismissSafe()
|
dialog.dismissSafe()
|
||||||
|
|
|
@ -817,6 +817,7 @@ class CS3IPlayer : IPlayer {
|
||||||
// Concatenated sources (non 1 periodCount) bypasses the invalid check as exoPlayer.duration gives only the current period
|
// Concatenated sources (non 1 periodCount) bypasses the invalid check as exoPlayer.duration gives only the current period
|
||||||
// If you can get the total time that'd be better, but this is already niche.
|
// If you can get the total time that'd be better, but this is already niche.
|
||||||
&& exoPlayer?.currentTimeline?.periodCount == 1
|
&& exoPlayer?.currentTimeline?.periodCount == 1
|
||||||
|
&& exoPlayer?.isCurrentMediaItemLive != true
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
|
|
|
@ -364,7 +364,8 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
activity?.showDialog(
|
activity?.showDialog(
|
||||||
languages.map { it.languageName },
|
languages.map { it.languageName },
|
||||||
lang639_1.indexOf(currentLanguageTwoLetters),
|
lang639_1.indexOf(currentLanguageTwoLetters),
|
||||||
view?.context?.getString(R.string.subs_subtitle_languages) ?: return@setOnClickListener,
|
view?.context?.getString(R.string.subs_subtitle_languages)
|
||||||
|
?: return@setOnClickListener,
|
||||||
true,
|
true,
|
||||||
{ }
|
{ }
|
||||||
) { index ->
|
) { index ->
|
||||||
|
@ -721,6 +722,9 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
var maxEpisodeSet: Int? = null
|
var maxEpisodeSet: Int? = null
|
||||||
|
|
||||||
override fun playerPositionChanged(posDur: Pair<Long, Long>) {
|
override fun playerPositionChanged(posDur: Pair<Long, Long>) {
|
||||||
|
// Don't save livestream data
|
||||||
|
if ((currentMeta as? ResultEpisode)?.tvType?.isLiveStream() == true) return
|
||||||
|
|
||||||
val (position, duration) = posDur
|
val (position, duration) = posDur
|
||||||
viewModel.getId()?.let {
|
viewModel.getId()?.let {
|
||||||
DataStoreHelper.setViewPos(it, position, duration)
|
DataStoreHelper.setViewPos(it, position, duration)
|
||||||
|
|
|
@ -303,6 +303,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
TvType.Torrent -> "Torrent"
|
TvType.Torrent -> "Torrent"
|
||||||
TvType.Documentary -> "Documentaries"
|
TvType.Documentary -> "Documentaries"
|
||||||
TvType.AsianDrama -> "AsianDrama"
|
TvType.AsianDrama -> "AsianDrama"
|
||||||
|
TvType.Live -> "LiveStreams"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1665,10 +1666,15 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
result_resume_progress_holder?.isVisible = isProgressVisible
|
result_resume_progress_holder?.isVisible = isProgressVisible
|
||||||
context?.getString(if (isProgressVisible) R.string.resume else R.string.play_movie_button)
|
context?.getString(
|
||||||
?.let {
|
when {
|
||||||
result_play_movie?.text = it
|
currentType?.isLiveStream() == true -> R.string.play_livestream_button
|
||||||
|
isProgressVisible -> R.string.resume
|
||||||
|
else -> R.string.play_movie_button
|
||||||
}
|
}
|
||||||
|
)?.let {
|
||||||
|
result_play_movie?.text = it
|
||||||
|
}
|
||||||
//println("startAction = $startAction")
|
//println("startAction = $startAction")
|
||||||
|
|
||||||
when (startAction) {
|
when (startAction) {
|
||||||
|
@ -1943,10 +1949,10 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
|
|
||||||
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.Live) getString(R.string.play_livestream_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)
|
||||||
val syno = d.plot
|
val syno = d.plot
|
||||||
|
@ -2130,6 +2136,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
||||||
TvType.Movie -> R.string.movies_singular
|
TvType.Movie -> R.string.movies_singular
|
||||||
TvType.Torrent -> R.string.torrent_singular
|
TvType.Torrent -> R.string.torrent_singular
|
||||||
TvType.AsianDrama -> R.string.asian_drama_singular
|
TvType.AsianDrama -> R.string.asian_drama_singular
|
||||||
|
TvType.Live -> R.string.live_singular
|
||||||
}
|
}
|
||||||
)?.let {
|
)?.let {
|
||||||
result_meta_type?.text = it
|
result_meta_type?.text = it
|
||||||
|
|
|
@ -498,6 +498,26 @@ class ResultViewModel : ViewModel() {
|
||||||
updateEpisodes(mainId, listOf(it), -1)
|
updateEpisodes(mainId, listOf(it), -1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is LiveStreamLoadResponse -> {
|
||||||
|
buildResultEpisode(
|
||||||
|
loadResponse.name,
|
||||||
|
loadResponse.name,
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
loadResponse.dataUrl,
|
||||||
|
loadResponse.apiName,
|
||||||
|
(mainId), // HAS SAME ID
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
loadResponse.type,
|
||||||
|
mainId
|
||||||
|
).let {
|
||||||
|
updateEpisodes(mainId, listOf(it), -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
is TorrentLoadResponse -> {
|
is TorrentLoadResponse -> {
|
||||||
updateEpisodes(
|
updateEpisodes(
|
||||||
mainId, listOf(
|
mainId, listOf(
|
||||||
|
|
|
@ -167,11 +167,21 @@ class SearchFragment : Fragment() {
|
||||||
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
|
val docs = dialog.findViewById<MaterialButton>(R.id.home_select_documentaries)
|
||||||
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
|
val movies = dialog.findViewById<MaterialButton>(R.id.home_select_movies)
|
||||||
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
|
val asian = dialog.findViewById<MaterialButton>(R.id.home_select_asian)
|
||||||
|
val livestream =
|
||||||
|
dialog.findViewById<MaterialButton>(R.id.home_select_livestreams)
|
||||||
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
|
val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)
|
||||||
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
|
val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)
|
||||||
|
|
||||||
val pairList =
|
val pairList =
|
||||||
HomeFragment.getPairList(anime, cartoons, tvs, docs, movies, asian)
|
HomeFragment.getPairList(
|
||||||
|
anime,
|
||||||
|
cartoons,
|
||||||
|
tvs,
|
||||||
|
docs,
|
||||||
|
movies,
|
||||||
|
asian,
|
||||||
|
livestream
|
||||||
|
)
|
||||||
|
|
||||||
cancelBtt?.setOnClickListener {
|
cancelBtt?.setOnClickListener {
|
||||||
dialog.dismissSafe()
|
dialog.dismissSafe()
|
||||||
|
@ -287,6 +297,7 @@ class SearchFragment : Fragment() {
|
||||||
search_select_documentaries,
|
search_select_documentaries,
|
||||||
search_select_movies,
|
search_select_movies,
|
||||||
search_select_asian,
|
search_select_asian,
|
||||||
|
search_select_livestreams
|
||||||
)
|
)
|
||||||
|
|
||||||
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
|
val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }
|
||||||
|
|
|
@ -1,61 +1,61 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/searchRoot"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:id="@+id/searchRoot"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.search.SearchFragment"
|
android:layout_marginTop="@dimen/navbar_height"
|
||||||
android:orientation="vertical"
|
android:background="?attr/primaryGrayBackground"
|
||||||
android:background="?attr/primaryGrayBackground"
|
android:orientation="vertical"
|
||||||
android:layout_marginTop="@dimen/navbar_height">
|
tools:context=".ui.search.SearchFragment">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:visibility="visible"
|
android:layout_width="match_parent"
|
||||||
android:layout_margin="10dp"
|
android:layout_height="40dp"
|
||||||
android:background="@drawable/search_background"
|
android:layout_margin="10dp"
|
||||||
android:layout_width="match_parent"
|
android:background="@drawable/search_background"
|
||||||
android:layout_height="40dp">
|
android:visibility="visible">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="30dp"
|
||||||
android:layout_marginEnd="30dp"
|
android:layout_gravity="center_vertical"
|
||||||
android:layout_height="30dp">
|
android:layout_marginEnd="30dp">
|
||||||
|
|
||||||
<androidx.appcompat.widget.SearchView
|
<androidx.appcompat.widget.SearchView
|
||||||
android:nextFocusUp="@id/nav_rail_view"
|
android:id="@+id/main_search"
|
||||||
android:nextFocusRight="@id/search_filter"
|
android:layout_width="match_parent"
|
||||||
android:nextFocusLeft="@id/nav_rail_view"
|
android:layout_height="match_parent"
|
||||||
android:nextFocusDown="@id/search_autofit_results"
|
android:layout_gravity="center_vertical"
|
||||||
|
|
||||||
android:imeOptions="actionSearch"
|
android:iconifiedByDefault="false"
|
||||||
android:inputType="text"
|
android:imeOptions="actionSearch"
|
||||||
|
|
||||||
android:id="@+id/main_search"
|
android:inputType="text"
|
||||||
app:queryBackground="@color/transparent"
|
android:nextFocusLeft="@id/nav_rail_view"
|
||||||
|
|
||||||
app:searchIcon="@drawable/search_icon"
|
android:nextFocusRight="@id/search_filter"
|
||||||
android:paddingStart="-10dp"
|
android:nextFocusUp="@id/nav_rail_view"
|
||||||
android:iconifiedByDefault="false"
|
android:nextFocusDown="@id/search_autofit_results"
|
||||||
app:queryHint="@string/search_hint"
|
android:paddingStart="-10dp"
|
||||||
android:layout_width="match_parent"
|
app:iconifiedByDefault="false"
|
||||||
android:layout_height="match_parent"
|
app:queryBackground="@color/transparent"
|
||||||
android:layout_gravity="center_vertical"
|
app:queryHint="@string/search_hint"
|
||||||
app:iconifiedByDefault="false"
|
app:searchIcon="@drawable/search_icon"
|
||||||
tools:ignore="RtlSymmetry">
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
<requestFocus />
|
<requestFocus />
|
||||||
|
|
||||||
<androidx.core.widget.ContentLoadingProgressBar
|
<androidx.core.widget.ContentLoadingProgressBar
|
||||||
android:id="@+id/search_loading_bar"
|
android:id="@+id/search_loading_bar"
|
||||||
android:layout_width="20dp"
|
style="@style/Widget.AppCompat.ProgressBar"
|
||||||
android:layout_height="20dp"
|
android:layout_width="20dp"
|
||||||
android:layout_marginStart="-35dp"
|
android:layout_height="20dp"
|
||||||
style="@style/Widget.AppCompat.ProgressBar"
|
android:layout_gravity="center"
|
||||||
android:foregroundTint="@color/white"
|
android:layout_marginStart="-35dp"
|
||||||
android:progressTint="@color/white"
|
android:foregroundTint="@color/white"
|
||||||
android:layout_gravity="center">
|
android:progressTint="@color/white">
|
||||||
|
|
||||||
</androidx.core.widget.ContentLoadingProgressBar>
|
</androidx.core.widget.ContentLoadingProgressBar>
|
||||||
<!--app:queryHint="@string/search_hint"
|
<!--app:queryHint="@string/search_hint"
|
||||||
|
@ -66,120 +66,126 @@
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:nextFocusUp="@id/nav_rail_view"
|
android:id="@+id/search_filter"
|
||||||
android:nextFocusRight="@id/main_search"
|
android:layout_width="25dp"
|
||||||
android:nextFocusLeft="@id/main_search"
|
android:layout_height="25dp"
|
||||||
android:nextFocusDown="@id/search_autofit_results"
|
android:layout_gravity="end|center_vertical"
|
||||||
|
|
||||||
android:id="@+id/search_filter"
|
android:layout_margin="10dp"
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
android:background="?selectableItemBackgroundBorderless"
|
||||||
android:src="@drawable/ic_baseline_tune_24"
|
android:contentDescription="@string/change_providers_img_des"
|
||||||
android:layout_width="25dp"
|
android:nextFocusLeft="@id/main_search"
|
||||||
android:layout_height="25dp"
|
android:nextFocusRight="@id/main_search"
|
||||||
android:layout_margin="10dp"
|
android:nextFocusUp="@id/nav_rail_view"
|
||||||
android:layout_gravity="end|center_vertical"
|
android:nextFocusDown="@id/search_autofit_results"
|
||||||
app:tint="?attr/textColor"
|
android:src="@drawable/ic_baseline_tune_24"
|
||||||
android:contentDescription="@string/change_providers_img_des" />
|
app:tint="?attr/textColor" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:paddingStart="10dp"
|
android:layout_width="wrap_content"
|
||||||
android:paddingEnd="10dp"
|
android:layout_height="wrap_content"
|
||||||
android:fadingEdge="horizontal"
|
android:fadingEdge="horizontal"
|
||||||
android:requiresFadingEdge="horizontal"
|
android:paddingStart="10dp"
|
||||||
android:layout_width="wrap_content"
|
android:paddingEnd="10dp"
|
||||||
android:layout_height="wrap_content">
|
android:requiresFadingEdge="horizontal">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="horizontal"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusRight="@id/search_select_tv_series"
|
android:id="@+id/search_select_movies"
|
||||||
|
|
||||||
android:id="@+id/search_select_movies"
|
style="@style/RoundedSelectableButton"
|
||||||
android:text="@string/movies"
|
android:nextFocusRight="@id/search_select_tv_series"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/movies" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/search_select_movies"
|
android:id="@+id/search_select_tv_series"
|
||||||
android:nextFocusRight="@id/search_select_anime"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/search_select_tv_series"
|
android:nextFocusLeft="@id/search_select_movies"
|
||||||
android:text="@string/tv_series"
|
android:nextFocusRight="@id/search_select_anime"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/tv_series" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/search_select_tv_series"
|
android:id="@+id/search_select_anime"
|
||||||
android:nextFocusRight="@id/search_select_asian"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/search_select_anime"
|
android:nextFocusLeft="@id/search_select_tv_series"
|
||||||
android:text="@string/anime"
|
android:nextFocusRight="@id/search_select_asian"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/anime" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/search_select_anime"
|
android:id="@+id/search_select_asian"
|
||||||
android:nextFocusRight="@id/search_select_cartoons"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/search_select_asian"
|
android:nextFocusLeft="@id/search_select_anime"
|
||||||
android:text="@string/asian_drama"
|
android:nextFocusRight="@id/search_select_cartoons"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/asian_drama" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/search_select_asian"
|
android:id="@+id/search_select_cartoons"
|
||||||
android:nextFocusRight="@id/search_select_documentaries"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/search_select_cartoons"
|
android:nextFocusLeft="@id/search_select_asian"
|
||||||
android:text="@string/cartoons"
|
android:nextFocusRight="@id/search_select_documentaries"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/cartoons" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/search_select_cartoons"
|
android:id="@+id/search_select_documentaries"
|
||||||
|
|
||||||
android:id="@+id/search_select_documentaries"
|
style="@style/RoundedSelectableButton"
|
||||||
android:text="@string/documentaries"
|
android:nextFocusLeft="@id/search_select_cartoons"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/documentaries" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/search_select_livestreams"
|
||||||
|
style="@style/RoundedSelectableButton"
|
||||||
|
android:nextFocusLeft="@id/search_select_documentaries"
|
||||||
|
android:text="@string/livestreams" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
|
||||||
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||||
android:visibility="gone"
|
android:id="@+id/search_autofit_results"
|
||||||
android:nextFocusLeft="@id/nav_rail_view"
|
android:layout_width="match_parent"
|
||||||
android:descendantFocusability="afterDescendants"
|
android:layout_height="match_parent"
|
||||||
|
|
||||||
android:background="?attr/primaryBlackBackground"
|
android:background="?attr/primaryBlackBackground"
|
||||||
android:layout_width="match_parent"
|
android:clipToPadding="false"
|
||||||
android:layout_height="match_parent"
|
android:descendantFocusability="afterDescendants"
|
||||||
android:clipToPadding="false"
|
android:nextFocusLeft="@id/nav_rail_view"
|
||||||
android:paddingStart="8dp"
|
android:orientation="vertical"
|
||||||
android:paddingTop="5dp"
|
android:paddingStart="8dp"
|
||||||
app:spanCount="3"
|
android:paddingTop="5dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:id="@+id/search_autofit_results"
|
android:visibility="gone"
|
||||||
tools:listitem="@layout/search_result_grid"
|
app:spanCount="3"
|
||||||
android:orientation="vertical" />
|
tools:listitem="@layout/search_result_grid" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:visibility="gone"
|
android:id="@+id/search_master_recycler"
|
||||||
android:nextFocusLeft="@id/nav_rail_view"
|
android:layout_width="match_parent"
|
||||||
android:descendantFocusability="afterDescendants"
|
android:layout_height="match_parent"
|
||||||
|
|
||||||
android:background="?attr/primaryBlackBackground"
|
android:background="?attr/primaryBlackBackground"
|
||||||
android:id="@+id/search_master_recycler"
|
android:descendantFocusability="afterDescendants"
|
||||||
android:layout_width="match_parent"
|
android:nextFocusLeft="@id/nav_rail_view"
|
||||||
android:layout_height="match_parent"
|
android:visibility="gone"
|
||||||
tools:listitem="@layout/homepage_parent" />
|
tools:listitem="@layout/homepage_parent" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:visibility="visible"
|
android:id="@+id/search_history_recycler"
|
||||||
android:nextFocusLeft="@id/nav_rail_view"
|
android:layout_width="match_parent"
|
||||||
android:descendantFocusability="afterDescendants"
|
android:layout_height="match_parent"
|
||||||
|
|
||||||
android:background="?attr/primaryBlackBackground"
|
android:background="?attr/primaryBlackBackground"
|
||||||
android:id="@+id/search_history_recycler"
|
android:descendantFocusability="afterDescendants"
|
||||||
android:layout_width="match_parent"
|
android:nextFocusLeft="@id/nav_rail_view"
|
||||||
android:layout_height="match_parent"
|
android:visibility="visible"
|
||||||
tools:listitem="@layout/search_history_item" />
|
tools:listitem="@layout/search_history_item" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -1,40 +1,40 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
android:clipToPadding="false"
|
android:id="@+id/listview1"
|
||||||
android:nextFocusRight="@id/cancel_btt"
|
android:layout_width="match_parent"
|
||||||
android:nextFocusLeft="@id/apply_btt"
|
android:layout_height="wrap_content"
|
||||||
|
|
||||||
android:id="@+id/listview1"
|
android:layout_rowWeight="1"
|
||||||
android:layout_marginBottom="60dp"
|
android:layout_marginTop="10dp"
|
||||||
android:minHeight="0dp"
|
android:layout_marginBottom="60dp"
|
||||||
android:layout_marginTop="10dp"
|
android:clipToPadding="false"
|
||||||
android:requiresFadingEdge="vertical"
|
android:minHeight="0dp"
|
||||||
tools:listitem="@layout/sort_bottom_single_choice"
|
android:nextFocusLeft="@id/apply_btt"
|
||||||
android:layout_width="match_parent"
|
android:nextFocusRight="@id/cancel_btt"
|
||||||
android:layout_height="wrap_content"
|
android:requiresFadingEdge="vertical"
|
||||||
android:layout_rowWeight="1" />
|
tools:listitem="@layout/sort_bottom_single_choice" />
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
android:layout_marginTop="-60dp"
|
android:layout_width="wrap_content"
|
||||||
android:paddingStart="10dp"
|
android:layout_height="wrap_content"
|
||||||
android:paddingEnd="10dp"
|
android:layout_marginTop="-60dp"
|
||||||
android:clipToPadding="true"
|
android:clipToPadding="true"
|
||||||
android:fadingEdge="horizontal"
|
android:fadingEdge="horizontal"
|
||||||
android:requiresFadingEdge="horizontal"
|
android:paddingStart="10dp"
|
||||||
android:layout_width="wrap_content"
|
android:paddingEnd="10dp"
|
||||||
android:layout_height="wrap_content">
|
android:requiresFadingEdge="horizontal">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="horizontal"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:orientation="horizontal">
|
||||||
<!-- android:minWidth="0dp"
|
<!-- android:minWidth="0dp"
|
||||||
app:iconTint="?attr/textColor"
|
app:iconTint="?attr/textColor"
|
||||||
android:insetLeft="0dp"
|
android:insetLeft="0dp"
|
||||||
|
@ -51,74 +51,81 @@
|
||||||
android:id="@+id/home_select_none"
|
android:id="@+id/home_select_none"
|
||||||
style="@style/RoundedSelectableButtonIcon"/>-->
|
style="@style/RoundedSelectableButtonIcon"/>-->
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusRight="@id/home_select_tv_series"
|
android:id="@+id/home_select_movies"
|
||||||
|
|
||||||
android:id="@+id/home_select_movies"
|
style="@style/RoundedSelectableButton"
|
||||||
android:text="@string/movies"
|
android:nextFocusRight="@id/home_select_tv_series"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/movies" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/home_select_movies"
|
android:id="@+id/home_select_tv_series"
|
||||||
android:nextFocusRight="@id/home_select_anime"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/home_select_tv_series"
|
android:nextFocusLeft="@id/home_select_movies"
|
||||||
android:text="@string/tv_series"
|
android:nextFocusRight="@id/home_select_anime"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/tv_series" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/home_select_tv_series"
|
android:id="@+id/home_select_anime"
|
||||||
android:nextFocusRight="@id/home_select_asian"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/home_select_anime"
|
android:nextFocusLeft="@id/home_select_tv_series"
|
||||||
android:text="@string/anime"
|
android:nextFocusRight="@id/home_select_asian"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/anime" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/home_select_anime"
|
android:id="@+id/home_select_asian"
|
||||||
android:nextFocusRight="@id/home_select_cartoons"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/home_select_asian"
|
android:nextFocusLeft="@id/home_select_anime"
|
||||||
android:text="@string/asian_drama"
|
android:nextFocusRight="@id/home_select_cartoons"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/asian_drama" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/home_select_asian"
|
android:id="@+id/home_select_cartoons"
|
||||||
android:nextFocusRight="@id/home_select_documentaries"
|
style="@style/RoundedSelectableButton"
|
||||||
|
|
||||||
android:id="@+id/home_select_cartoons"
|
android:nextFocusLeft="@id/home_select_asian"
|
||||||
android:text="@string/cartoons"
|
android:nextFocusRight="@id/home_select_documentaries"
|
||||||
style="@style/RoundedSelectableButton" />
|
android:text="@string/cartoons" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:nextFocusLeft="@id/home_select_cartoons"
|
android:id="@+id/home_select_documentaries"
|
||||||
|
|
||||||
|
style="@style/RoundedSelectableButton"
|
||||||
|
android:nextFocusLeft="@id/home_select_cartoons"
|
||||||
|
android:text="@string/documentaries" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/home_select_livestreams"
|
||||||
|
style="@style/RoundedSelectableButton"
|
||||||
|
android:nextFocusLeft="@id/home_select_documentaries"
|
||||||
|
android:text="@string/livestreams" />
|
||||||
|
|
||||||
android:id="@+id/home_select_documentaries"
|
|
||||||
android:text="@string/documentaries"
|
|
||||||
style="@style/RoundedSelectableButton" />
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:visibility="gone"
|
android:id="@+id/apply_btt_holder"
|
||||||
android:id="@+id/apply_btt_holder"
|
android:layout_width="match_parent"
|
||||||
android:orientation="horizontal"
|
android:layout_height="60dp"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:gravity="bottom|end"
|
android:gravity="bottom|end"
|
||||||
android:layout_width="match_parent"
|
android:orientation="horizontal"
|
||||||
android:layout_height="60dp">
|
android:visibility="gone">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
style="@style/WhiteButton"
|
android:id="@+id/apply_btt"
|
||||||
android:layout_gravity="center_vertical|end"
|
style="@style/WhiteButton"
|
||||||
android:text="@string/sort_apply"
|
android:layout_width="wrap_content"
|
||||||
android:id="@+id/apply_btt"
|
android:layout_gravity="center_vertical|end"
|
||||||
android:layout_width="wrap_content" />
|
android:text="@string/sort_apply" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
style="@style/BlackButton"
|
android:id="@+id/cancel_btt"
|
||||||
android:layout_gravity="center_vertical|end"
|
style="@style/BlackButton"
|
||||||
android:text="@string/sort_cancel"
|
android:layout_width="wrap_content"
|
||||||
android:id="@+id/cancel_btt"
|
android:layout_gravity="center_vertical|end"
|
||||||
android:layout_width="wrap_content" />
|
android:text="@string/sort_cancel" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -119,6 +119,7 @@
|
||||||
<string name="type_re_watching">Rewatching</string>
|
<string name="type_re_watching">Rewatching</string>
|
||||||
|
|
||||||
<string name="play_movie_button">Play Movie</string>
|
<string name="play_movie_button">Play Movie</string>
|
||||||
|
<string name="play_livestream_button">Play Livestream</string>
|
||||||
<string name="play_torrent_button">Stream Torrent</string>
|
<string name="play_torrent_button">Stream Torrent</string>
|
||||||
<string name="pick_source">Sources</string>
|
<string name="pick_source">Sources</string>
|
||||||
<string name="pick_subtitle">Subtitles</string>
|
<string name="pick_subtitle">Subtitles</string>
|
||||||
|
@ -327,6 +328,7 @@
|
||||||
<string name="documentaries">Documentaries</string>
|
<string name="documentaries">Documentaries</string>
|
||||||
<string name="ova">OVA</string>
|
<string name="ova">OVA</string>
|
||||||
<string name="asian_drama">Asian Dramas</string>
|
<string name="asian_drama">Asian Dramas</string>
|
||||||
|
<string name="livestreams">Livestreams</string>
|
||||||
|
|
||||||
<!--singular-->
|
<!--singular-->
|
||||||
<string name="movies_singular">Movie</string>
|
<string name="movies_singular">Movie</string>
|
||||||
|
@ -337,6 +339,7 @@
|
||||||
<string name="torrent_singular">Torrent</string>
|
<string name="torrent_singular">Torrent</string>
|
||||||
<string name="documentaries_singular">Documentary</string>
|
<string name="documentaries_singular">Documentary</string>
|
||||||
<string name="asian_drama_singular">Asian Drama</string>
|
<string name="asian_drama_singular">Asian Drama</string>
|
||||||
|
<string name="live_singular">Livestream</string>
|
||||||
|
|
||||||
<string name="source_error">Source error</string>
|
<string name="source_error">Source error</string>
|
||||||
<string name="remote_error">Remote error</string>
|
<string name="remote_error">Remote error</string>
|
||||||
|
|
Loading…
Reference in a new issue