added flags to livestreams 🇸🇪 🇮🇳 🇦🇶 & horizontal

This commit is contained in:
LagradOst 2022-07-25 03:18:27 +02:00
parent 8ad17143a4
commit 9b6b06437f
11 changed files with 146 additions and 29 deletions

View file

@ -99,14 +99,14 @@ object APIHolder {
RebahinProvider(), RebahinProvider(),
LayarKacaProvider(), LayarKacaProvider(),
HDTodayProvider(), HDTodayProvider(),
OpenVidsProvider(), OpenVidsProvider(),
IdlixProvider(), IdlixProvider(),
MultiplexProvider(), MultiplexProvider(),
VidSrcProvider(), VidSrcProvider(),
UakinoProvider(), UakinoProvider(),
PhimmoichillProvider(), PhimmoichillProvider(),
HDrezkaProvider(), HDrezkaProvider(),
// Metadata providers // Metadata providers
//TmdbProvider(), //TmdbProvider(),
@ -555,8 +555,10 @@ fun capitalizeStringNullable(str: String?): String? {
} }
fun fixTitle(str: String): String { fun fixTitle(str: String): String {
return str.split(" ").joinToString(" ") { it.lowercase() return str.split(" ").joinToString(" ") {
.replaceFirstChar { char -> if (char.isLowerCase()) char.titlecase(Locale.getDefault()) else it } } it.lowercase()
.replaceFirstChar { char -> if (char.isLowerCase()) char.titlecase(Locale.getDefault()) else it }
}
} }
/** https://www.imdb.com/title/tt2861424/ -> tt2861424 */ /** https://www.imdb.com/title/tt2861424/ -> tt2861424 */
@ -623,13 +625,14 @@ fun TvType.isAnimeOp(): Boolean {
data class SubtitleFile(val lang: String, val url: String) data class SubtitleFile(val lang: String, val url: String)
class HomePageResponse( data class HomePageResponse(
val items: List<HomePageList> val items: List<HomePageList>
) )
class HomePageList( data class HomePageList(
val name: String, val name: String,
var list: List<SearchResponse> var list: List<SearchResponse>,
val isHorizontalImages: Boolean = false
) )
enum class SearchQuality { enum class SearchQuality {
@ -865,6 +868,19 @@ data class MovieSearchResponse(
override var posterHeaders: Map<String, String>? = null, override var posterHeaders: Map<String, String>? = null,
) : SearchResponse ) : 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( data class TvSeriesSearchResponse(
override val name: String, override val name: String,
override val url: String, override val url: String,

View file

@ -1,13 +1,11 @@
package com.lagradost.cloudstream3.liveproviders package com.lagradost.cloudstream3.liveproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.Qualities
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements
class EjaTv : MainAPI() { class EjaTv : MainAPI() {
override var mainUrl = "https://eja.tv/" override var mainUrl = "https://eja.tv/"
@ -22,18 +20,19 @@ class EjaTv : MainAPI() {
TvType.Live TvType.Live
) )
private fun Element.toSearchResponse(): MovieSearchResponse? { private fun Element.toSearchResponse(): LiveSearchResponse? {
val link = this.select("div.alternative a").last() ?: return null val link = this.select("div.alternative a").last() ?: return null
val href = fixUrl(link.attr("href")) val href = fixUrl(link.attr("href"))
val img = this.select("div.thumb img") val img = this.selectFirst("div.thumb img")
val lang = this.selectFirst(".card-title > a")?.attr("href")?.removePrefix("?country=")
return MovieSearchResponse( return LiveSearchResponse(
// Kinda hack way to get the title // Kinda hack way to get the title
img.attr("alt").replaceFirst("Watch ", ""), img?.attr("alt")?.replaceFirst("Watch ", "") ?: return null,
href, href,
this@EjaTv.name, this@EjaTv.name,
TvType.Live, 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") "Entertainment" to mapOf("language" to language, "category" to "Entertainment")
) )
return HomePageResponse(dataMap.apmap { (title, data) -> return HomePageResponse(dataMap.apmap { (title, data) ->
println("ADDED isHorizontalImages")
val document = app.post(mainUrl, data = data).document val document = app.post(mainUrl, data = data).document
val shows = document.select("div.card-body").mapNotNull { val shows = document.select("div.card-body").mapNotNull {
it.toSearchResponse() it.toSearchResponse()
} }
HomePageList( HomePageList(
title, title,
shows shows,
isHorizontalImages = true
) )
}) })
} }

View file

@ -11,26 +11,31 @@ import com.lagradost.cloudstream3.ui.search.SearchClickCallback
import com.lagradost.cloudstream3.ui.search.SearchResponseDiffCallback import com.lagradost.cloudstream3.ui.search.SearchResponseDiffCallback
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
import com.lagradost.cloudstream3.utils.UIHelper.IsBottomLayout 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( class HomeChildItemAdapter(
val cardList: MutableList<SearchResponse>, val cardList: MutableList<SearchResponse>,
private val overrideLayout : Int? = null, private val overrideLayout: Int? = null,
private val nextFocusUp: Int? = null, private val nextFocusUp: Int? = null,
private val nextFocusDown: Int? = null, private val nextFocusDown: Int? = null,
private val clickCallback: (SearchClickCallback) -> Unit, private val clickCallback: (SearchClickCallback) -> Unit,
) : ) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() { RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var isHorizontal: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { 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( return CardViewHolder(
LayoutInflater.from(parent.context).inflate(layout, parent, false), LayoutInflater.from(parent.context).inflate(layout, parent, false),
clickCallback, clickCallback,
itemCount, itemCount,
nextFocusUp, nextFocusUp,
nextFocusDown nextFocusDown,
isHorizontal
) )
} }
@ -68,6 +73,7 @@ class HomeChildItemAdapter(
private val itemCount: Int, private val itemCount: Int,
private val nextFocusUp: Int? = null, private val nextFocusUp: Int? = null,
private val nextFocusDown: Int? = null, private val nextFocusDown: Int? = null,
private val isHorizontal: Boolean = false
) : ) :
RecyclerView.ViewHolder(itemView) { RecyclerView.ViewHolder(itemView) {
@ -80,6 +86,26 @@ class HomeChildItemAdapter(
else -> null 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( SearchResultBuilder.bind(
clickCallback, clickCallback,
card, card,

View file

@ -12,6 +12,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.* import android.widget.*
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.view.isGone
import androidx.core.view.isVisible 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
@ -505,8 +506,9 @@ class HomeFragment : Fragment() {
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList( (home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(
d?.items?.mapNotNull { d?.items?.mapNotNull {
try { try {
listHomepageItems.addAll(it.list.filterSearchResponse()) val filter = it.list.filterSearchResponse()
HomePageList(it.name, it.list.filterSearchResponse()) listHomepageItems.addAll(filter)
it.copy(list = filter)
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)
null null
@ -518,6 +520,8 @@ class HomeFragment : Fragment() {
home_loaded?.isVisible = true home_loaded?.isVisible = true
if (toggleRandomButton) { if (toggleRandomButton) {
home_random?.isVisible = listHomepageItems.isNotEmpty() home_random?.isVisible = listHomepageItems.isNotEmpty()
} else {
home_random?.isGone = true
} }
} }
is Resource.Failure -> { is Resource.Failure -> {

View file

@ -83,8 +83,11 @@ class ParentItemAdapter(
info.list.toMutableList(), info.list.toMutableList(),
clickCallback = clickCallback, clickCallback = clickCallback,
nextFocusUp = recyclerView.nextFocusUpId, nextFocusUp = recyclerView.nextFocusUpId,
nextFocusDown = recyclerView.nextFocusDownId nextFocusDown = recyclerView.nextFocusDownId,
) ).apply {
isHorizontal = info.isHorizontalImages
}
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged() //(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
moreInfo?.setOnClickListener { moreInfo?.setOnClickListener {

View file

@ -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.AppUtils.getNameFull
import com.lagradost.cloudstream3.utils.DataStoreHelper import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.UIHelper.setImage
import kotlinx.android.synthetic.main.home_result_grid.view.* import kotlinx.android.synthetic.main.home_result_grid.view.*
@ -46,6 +47,7 @@ object SearchResultBuilder {
val textIsDub: TextView? = itemView.text_is_dub val textIsDub: TextView? = itemView.text_is_dub
val textIsSub: TextView? = itemView.text_is_sub val textIsSub: TextView? = itemView.text_is_sub
val textFlag: TextView? = itemView.text_flag
val textQuality: TextView? = itemView.text_quality val textQuality: TextView? = itemView.text_quality
val shadow: View? = itemView.title_shadow val shadow: View? = itemView.title_shadow
@ -60,6 +62,7 @@ object SearchResultBuilder {
playImg?.isVisible = false playImg?.isVisible = false
textIsDub?.isVisible = false textIsDub?.isVisible = false
textIsSub?.isVisible = false textIsSub?.isVisible = false
textFlag?.isVisible = false
val showSub = showCache[textIsDub?.context?.getString(R.string.show_sub_key)] ?: 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 val showDub = showCache[textIsDub?.context?.getString(R.string.show_dub_key)] ?: false
@ -188,6 +191,14 @@ object SearchResultBuilder {
} }
when (card) { when (card) {
is LiveSearchResponse -> {
SubtitleHelper.getFlagFromIso(card.lang)?.let { flagEmoji ->
textFlag?.apply {
isVisible = true
text = flagEmoji
}
}
}
is DataStoreHelper.ResumeWatchingResult -> { is DataStoreHelper.ResumeWatchingResult -> {
val pos = card.watchPos?.fixVisual() val pos = card.watchPos?.fixVisual()
if (pos != null) { if (pos != null) {

View file

@ -116,15 +116,30 @@ object SubtitleHelper {
private const val asciiOffset = 0x41 private const val asciiOffset = 0x41
private const val offset = flagOffset - asciiOffset private const val offset = flagOffset - asciiOffset
private val flagRegex = Regex("[\uD83C\uDDE6-\uD83C\uDDFF]{2}")
fun getFlagFromIso(inp: String?): String? { fun getFlagFromIso(inp: String?): String? {
try { try {
flags[inp ?: return null]?.let { flagAscii -> val ret = getFlagFromIsoShort(flags[inp ?: return null])
val firstChar: Int = Character.codePointAt(flagAscii, 0) + offset ?: getFlagFromIsoShort(inp.uppercase()) ?: return null
val secondChar: Int = Character.codePointAt(flagAscii, 1) + offset
return (String(Character.toChars(firstChar)) + String(Character.toChars(secondChar))) return if (flagRegex.matches(ret)) {
ret
} else {
null
} }
} catch (e: Exception) {
logError(e)
return null 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) { } catch (e: Exception) {
logError(e) logError(e)
return null return null

View file

@ -90,7 +90,7 @@
tools:text="@string/quality_hd" tools:text="@string/quality_hd"
android:id="@+id/text_quality" android:id="@+id/text_quality"
style="@style/SearchBox" style="@style/SearchBox"
android:background="@drawable/type_bg_color"/> android:background="@drawable/type_bg_color" />
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
@ -117,5 +117,15 @@
style="@style/SearchBox" style="@style/SearchBox"
android:layout_gravity="end" android:layout_gravity="end"
android:background="@drawable/sub_bg_color" /> 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> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View file

@ -22,6 +22,7 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:id="@+id/image_holder"
android:layout_width="114dp" android:layout_width="114dp"
android:layout_height="180dp" android:layout_height="180dp"
android:elevation="10dp" android:elevation="10dp"
@ -105,6 +106,16 @@
style="@style/SearchBox" style="@style/SearchBox"
android:layout_gravity="end" android:layout_gravity="end"
android:background="@drawable/sub_bg_color" /> 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> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View file

@ -83,6 +83,16 @@
android:layout_gravity="end" android:layout_gravity="end"
style="@style/SearchBox" style="@style/SearchBox"
android:background="@drawable/sub_bg_color" /> 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> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>

View file

@ -58,6 +58,16 @@
android:layout_gravity="end" android:layout_gravity="end"
style="@style/SearchBox" style="@style/SearchBox"
android:background="@drawable/sub_bg_color" /> 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> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>