mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
added flags to livestreams 🇸🇪 🇮🇳 🇦🇶 & horizontal
This commit is contained in:
parent
8ad17143a4
commit
9b6b06437f
11 changed files with 146 additions and 29 deletions
|
@ -555,8 +555,10 @@ fun capitalizeStringNullable(str: String?): String? {
|
|||
}
|
||||
|
||||
fun fixTitle(str: String): String {
|
||||
return str.split(" ").joinToString(" ") { it.lowercase()
|
||||
.replaceFirstChar { char -> if (char.isLowerCase()) char.titlecase(Locale.getDefault()) else it } }
|
||||
return str.split(" ").joinToString(" ") {
|
||||
it.lowercase()
|
||||
.replaceFirstChar { char -> if (char.isLowerCase()) char.titlecase(Locale.getDefault()) else it }
|
||||
}
|
||||
}
|
||||
|
||||
/** https://www.imdb.com/title/tt2861424/ -> tt2861424 */
|
||||
|
@ -623,13 +625,14 @@ fun TvType.isAnimeOp(): Boolean {
|
|||
|
||||
data class SubtitleFile(val lang: String, val url: String)
|
||||
|
||||
class HomePageResponse(
|
||||
data class HomePageResponse(
|
||||
val items: List<HomePageList>
|
||||
)
|
||||
|
||||
class HomePageList(
|
||||
data class HomePageList(
|
||||
val name: String,
|
||||
var list: List<SearchResponse>
|
||||
var list: List<SearchResponse>,
|
||||
val isHorizontalImages: Boolean = false
|
||||
)
|
||||
|
||||
enum class SearchQuality {
|
||||
|
@ -865,6 +868,19 @@ data class MovieSearchResponse(
|
|||
override var posterHeaders: Map<String, String>? = null,
|
||||
) : SearchResponse
|
||||
|
||||
data class LiveSearchResponse(
|
||||
override val name: String,
|
||||
override val url: String,
|
||||
override val apiName: String,
|
||||
override var type: TvType? = null,
|
||||
|
||||
override var posterUrl: String? = null,
|
||||
override var id: Int? = null,
|
||||
override var quality: SearchQuality? = null,
|
||||
override var posterHeaders: Map<String, String>? = null,
|
||||
val lang: String? = null,
|
||||
) : SearchResponse
|
||||
|
||||
data class TvSeriesSearchResponse(
|
||||
override val name: String,
|
||||
override val url: String,
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
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/"
|
||||
|
@ -22,18 +20,19 @@ class EjaTv : MainAPI() {
|
|||
TvType.Live
|
||||
)
|
||||
|
||||
private fun Element.toSearchResponse(): MovieSearchResponse? {
|
||||
private fun Element.toSearchResponse(): LiveSearchResponse? {
|
||||
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(
|
||||
val img = this.selectFirst("div.thumb img")
|
||||
val lang = this.selectFirst(".card-title > a")?.attr("href")?.removePrefix("?country=")
|
||||
return LiveSearchResponse(
|
||||
// Kinda hack way to get the title
|
||||
img.attr("alt").replaceFirst("Watch ", ""),
|
||||
img?.attr("alt")?.replaceFirst("Watch ", "") ?: return null,
|
||||
href,
|
||||
this@EjaTv.name,
|
||||
TvType.Live,
|
||||
fixUrl(img.attr("src"))
|
||||
fixUrl(img.attr("src")),
|
||||
lang = lang
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -46,13 +45,15 @@ class EjaTv : MainAPI() {
|
|||
"Entertainment" to mapOf("language" to language, "category" to "Entertainment")
|
||||
)
|
||||
return HomePageResponse(dataMap.apmap { (title, data) ->
|
||||
println("ADDED isHorizontalImages")
|
||||
val document = app.post(mainUrl, data = data).document
|
||||
val shows = document.select("div.card-body").mapNotNull {
|
||||
it.toSearchResponse()
|
||||
}
|
||||
HomePageList(
|
||||
title,
|
||||
shows
|
||||
shows,
|
||||
isHorizontalImages = true
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -11,26 +11,31 @@ import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
|||
import com.lagradost.cloudstream3.ui.search.SearchResponseDiffCallback
|
||||
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.IsBottomLayout
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.*
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.background_card
|
||||
import kotlinx.android.synthetic.main.home_result_grid_expanded.view.*
|
||||
|
||||
class HomeChildItemAdapter(
|
||||
val cardList: MutableList<SearchResponse>,
|
||||
private val overrideLayout : Int? = null,
|
||||
private val overrideLayout: Int? = null,
|
||||
private val nextFocusUp: Int? = null,
|
||||
private val nextFocusDown: Int? = null,
|
||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||
) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
var isHorizontal: Boolean = false
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val layout = overrideLayout ?: if(parent.context.IsBottomLayout()) R.layout.home_result_grid_expanded else R.layout.home_result_grid
|
||||
val layout = overrideLayout
|
||||
?: if (parent.context.IsBottomLayout()) R.layout.home_result_grid_expanded else R.layout.home_result_grid
|
||||
|
||||
return CardViewHolder(
|
||||
LayoutInflater.from(parent.context).inflate(layout, parent, false),
|
||||
clickCallback,
|
||||
itemCount,
|
||||
nextFocusUp,
|
||||
nextFocusDown
|
||||
nextFocusDown,
|
||||
isHorizontal
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -68,6 +73,7 @@ class HomeChildItemAdapter(
|
|||
private val itemCount: Int,
|
||||
private val nextFocusUp: Int? = null,
|
||||
private val nextFocusDown: Int? = null,
|
||||
private val isHorizontal: Boolean = false
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
|
@ -80,6 +86,26 @@ class HomeChildItemAdapter(
|
|||
else -> null
|
||||
}
|
||||
|
||||
(itemView.image_holder ?: itemView.background_card)?.apply {
|
||||
val min = 114.toPx
|
||||
val max = 180.toPx
|
||||
|
||||
layoutParams =
|
||||
layoutParams.apply {
|
||||
width = if (!isHorizontal) {
|
||||
min
|
||||
} else {
|
||||
max
|
||||
}
|
||||
height = if (!isHorizontal) {
|
||||
max
|
||||
} else {
|
||||
min
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SearchResultBuilder.bind(
|
||||
clickCallback,
|
||||
card,
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.fragment.app.Fragment
|
||||
|
@ -505,8 +506,9 @@ class HomeFragment : Fragment() {
|
|||
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(
|
||||
d?.items?.mapNotNull {
|
||||
try {
|
||||
listHomepageItems.addAll(it.list.filterSearchResponse())
|
||||
HomePageList(it.name, it.list.filterSearchResponse())
|
||||
val filter = it.list.filterSearchResponse()
|
||||
listHomepageItems.addAll(filter)
|
||||
it.copy(list = filter)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
null
|
||||
|
@ -518,6 +520,8 @@ class HomeFragment : Fragment() {
|
|||
home_loaded?.isVisible = true
|
||||
if (toggleRandomButton) {
|
||||
home_random?.isVisible = listHomepageItems.isNotEmpty()
|
||||
} else {
|
||||
home_random?.isGone = true
|
||||
}
|
||||
}
|
||||
is Resource.Failure -> {
|
||||
|
|
|
@ -83,8 +83,11 @@ class ParentItemAdapter(
|
|||
info.list.toMutableList(),
|
||||
clickCallback = clickCallback,
|
||||
nextFocusUp = recyclerView.nextFocusUpId,
|
||||
nextFocusDown = recyclerView.nextFocusDownId
|
||||
)
|
||||
nextFocusDown = recyclerView.nextFocusDownId,
|
||||
).apply {
|
||||
isHorizontal = info.isHorizontalImages
|
||||
}
|
||||
|
||||
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
||||
|
||||
moreInfo?.setOnClickListener {
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueT
|
|||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
|
||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import kotlinx.android.synthetic.main.home_result_grid.view.*
|
||||
|
||||
|
@ -46,6 +47,7 @@ object SearchResultBuilder {
|
|||
|
||||
val textIsDub: TextView? = itemView.text_is_dub
|
||||
val textIsSub: TextView? = itemView.text_is_sub
|
||||
val textFlag: TextView? = itemView.text_flag
|
||||
val textQuality: TextView? = itemView.text_quality
|
||||
val shadow: View? = itemView.title_shadow
|
||||
|
||||
|
@ -60,6 +62,7 @@ object SearchResultBuilder {
|
|||
playImg?.isVisible = false
|
||||
textIsDub?.isVisible = false
|
||||
textIsSub?.isVisible = false
|
||||
textFlag?.isVisible = false
|
||||
|
||||
val showSub = showCache[textIsDub?.context?.getString(R.string.show_sub_key)] ?: false
|
||||
val showDub = showCache[textIsDub?.context?.getString(R.string.show_dub_key)] ?: false
|
||||
|
@ -188,6 +191,14 @@ object SearchResultBuilder {
|
|||
}
|
||||
|
||||
when (card) {
|
||||
is LiveSearchResponse -> {
|
||||
SubtitleHelper.getFlagFromIso(card.lang)?.let { flagEmoji ->
|
||||
textFlag?.apply {
|
||||
isVisible = true
|
||||
text = flagEmoji
|
||||
}
|
||||
}
|
||||
}
|
||||
is DataStoreHelper.ResumeWatchingResult -> {
|
||||
val pos = card.watchPos?.fixVisual()
|
||||
if (pos != null) {
|
||||
|
|
|
@ -116,15 +116,30 @@ object SubtitleHelper {
|
|||
private const val asciiOffset = 0x41
|
||||
private const val offset = flagOffset - asciiOffset
|
||||
|
||||
private val flagRegex = Regex("[\uD83C\uDDE6-\uD83C\uDDFF]{2}")
|
||||
|
||||
fun getFlagFromIso(inp: String?): String? {
|
||||
try {
|
||||
flags[inp ?: return null]?.let { flagAscii ->
|
||||
val firstChar: Int = Character.codePointAt(flagAscii, 0) + offset
|
||||
val secondChar: Int = Character.codePointAt(flagAscii, 1) + offset
|
||||
val ret = getFlagFromIsoShort(flags[inp ?: return null])
|
||||
?: getFlagFromIsoShort(inp.uppercase()) ?: return null
|
||||
|
||||
return (String(Character.toChars(firstChar)) + String(Character.toChars(secondChar)))
|
||||
return if (flagRegex.matches(ret)) {
|
||||
ret
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getFlagFromIsoShort(flagAscii: String?): String? {
|
||||
try {
|
||||
val firstChar: Int = Character.codePointAt(flagAscii ?: return null, 0) + offset
|
||||
val secondChar: Int = Character.codePointAt(flagAscii, 1) + offset
|
||||
|
||||
return (String(Character.toChars(firstChar)) + String(Character.toChars(secondChar)))
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
return null
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
tools:text="@string/quality_hd"
|
||||
android:id="@+id/text_quality"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/type_bg_color"/>
|
||||
android:background="@drawable/type_bg_color" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
|
@ -117,5 +117,15 @@
|
|||
style="@style/SearchBox"
|
||||
android:layout_gravity="end"
|
||||
android:background="@drawable/sub_bg_color" />
|
||||
|
||||
<TextView
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/text_flag"
|
||||
tools:text="🇸🇪"
|
||||
style="@style/SearchBox"
|
||||
android:layout_gravity="end"
|
||||
android:background="@color/transparent" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/image_holder"
|
||||
android:layout_width="114dp"
|
||||
android:layout_height="180dp"
|
||||
android:elevation="10dp"
|
||||
|
@ -105,6 +106,16 @@
|
|||
style="@style/SearchBox"
|
||||
android:layout_gravity="end"
|
||||
android:background="@drawable/sub_bg_color" />
|
||||
|
||||
<TextView
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/text_flag"
|
||||
tools:text="🇸🇪"
|
||||
style="@style/SearchBox"
|
||||
android:layout_gravity="end"
|
||||
android:background="@color/transparent" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
|
|
@ -83,6 +83,16 @@
|
|||
android:layout_gravity="end"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/sub_bg_color" />
|
||||
|
||||
<TextView
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/text_flag"
|
||||
tools:text="🇸🇪"
|
||||
style="@style/SearchBox"
|
||||
android:layout_gravity="end"
|
||||
android:background="@color/transparent" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
|
|
@ -58,6 +58,16 @@
|
|||
android:layout_gravity="end"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/sub_bg_color" />
|
||||
|
||||
<TextView
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:textSize="20sp"
|
||||
android:id="@+id/text_flag"
|
||||
tools:text="🇸🇪"
|
||||
style="@style/SearchBox"
|
||||
android:layout_gravity="end"
|
||||
android:background="@color/transparent" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
|
Loading…
Reference in a new issue