mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	added site cloner
This commit is contained in:
		
							parent
							
								
									86aed5b830
								
							
						
					
					
						commit
						5f542ec81a
					
				
					 58 changed files with 391 additions and 82 deletions
				
			
		| 
						 | 
				
			
			@ -155,11 +155,11 @@
 | 
			
		|||
        <service
 | 
			
		||||
                android:name=".services.VideoDownloadService"
 | 
			
		||||
                android:enabled="true"
 | 
			
		||||
                android:exported="false"></service>
 | 
			
		||||
                android:exported="false" />
 | 
			
		||||
 | 
			
		||||
        <activity
 | 
			
		||||
                android:exported="false"
 | 
			
		||||
                android:name=".ui.ControllerActivity"></activity>
 | 
			
		||||
                android:name=".ui.ControllerActivity" />
 | 
			
		||||
 | 
			
		||||
        <provider
 | 
			
		||||
                android:name="androidx.core.content.FileProvider"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ object APIHolder {
 | 
			
		|||
 | 
			
		||||
    private const val defProvider = 0
 | 
			
		||||
 | 
			
		||||
    val allProviders by lazy {
 | 
			
		||||
    val allProviders =
 | 
			
		||||
        arrayListOf(
 | 
			
		||||
            // Movie providers
 | 
			
		||||
            ElifilmsProvider(),
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +132,7 @@ object APIHolder {
 | 
			
		|||
            NginxProvider(),
 | 
			
		||||
            OlgplyProvider(),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    fun initAll() {
 | 
			
		||||
        for (api in allProviders) {
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +142,7 @@ object APIHolder {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    var apis: List<MainAPI> = arrayListOf()
 | 
			
		||||
    private var apiMap: Map<String, Int>? = null
 | 
			
		||||
    var apiMap: Map<String, Int>? = null
 | 
			
		||||
 | 
			
		||||
    private fun initMap() {
 | 
			
		||||
        if (apiMap == null)
 | 
			
		||||
| 
						 | 
				
			
			@ -357,6 +357,7 @@ abstract class MainAPI {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    fun overrideWithNewData(data: ProvidersInfoJson) {
 | 
			
		||||
        if (!canBeOverridden) return
 | 
			
		||||
        this.name = data.name
 | 
			
		||||
        if (data.url.isNotBlank() && data.url != "NONE")
 | 
			
		||||
            this.mainUrl = data.url
 | 
			
		||||
| 
						 | 
				
			
			@ -366,10 +367,11 @@ abstract class MainAPI {
 | 
			
		|||
    open var name = "NONE"
 | 
			
		||||
    open var mainUrl = "NONE"
 | 
			
		||||
    open var storedCredentials: String? = null
 | 
			
		||||
    open var canBeOverridden: Boolean = true
 | 
			
		||||
 | 
			
		||||
    //open val uniqueId : Int by lazy { this.name.hashCode() } // in case of duplicate providers you can have a shared id
 | 
			
		||||
 | 
			
		||||
    open val lang = "en" // ISO_639_1 check SubtitleHelper
 | 
			
		||||
    open var lang = "en" // ISO_639_1 check SubtitleHelper
 | 
			
		||||
 | 
			
		||||
    /**If link is stored in the "data" string, so links can be instantly loaded*/
 | 
			
		||||
    open val instantLinkLoading = false
 | 
			
		||||
| 
						 | 
				
			
			@ -908,7 +910,7 @@ interface LoadResponse {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        fun LoadResponse.addTrailer(trailerUrls: List<String>?) {
 | 
			
		||||
            if(trailerUrls == null) return
 | 
			
		||||
            if (trailerUrls == null) return
 | 
			
		||||
            if (this.trailers == null) {
 | 
			
		||||
                this.trailers = trailerUrls
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,7 @@ import com.lagradost.cloudstream3.ui.result.ResultFragment
 | 
			
		|||
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
 | 
			
		||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
 | 
			
		||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
 | 
			
		||||
import com.lagradost.cloudstream3.ui.settings.SettingsGeneral
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
 | 
			
		||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +69,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor
 | 
			
		|||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
 | 
			
		||||
import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
 | 
			
		||||
import com.lagradost.nicehttp.Requests
 | 
			
		||||
import kotlinx.android.synthetic.main.activity_main.*
 | 
			
		||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
 | 
			
		||||
| 
						 | 
				
			
			@ -515,6 +517,26 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
 | 
			
		|||
            apis = allProviders
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            getKey<Array<SettingsGeneral.CustomSite>>(USER_PROVIDER_API)?.let { list ->
 | 
			
		||||
                list.forEach { custom ->
 | 
			
		||||
                    allProviders.firstOrNull { it.javaClass.simpleName == custom.parentJavaClass }
 | 
			
		||||
                        ?.let {
 | 
			
		||||
                            allProviders.add(it.javaClass.newInstance().apply {
 | 
			
		||||
                                name = custom.name
 | 
			
		||||
                                lang = custom.lang
 | 
			
		||||
                                mainUrl = custom.url.trimEnd('/')
 | 
			
		||||
                                canBeOverridden = false
 | 
			
		||||
                            })
 | 
			
		||||
                        }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            apis = allProviders
 | 
			
		||||
            APIHolder.apiMap = null
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            logError(e)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        loadThemes(this)
 | 
			
		||||
        updateLocale()
 | 
			
		||||
        app.initClient(this)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ import org.jsoup.nodes.Element
 | 
			
		|||
class AnimeWorldProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://www.animeworld.tv"
 | 
			
		||||
    override var name = "AnimeWorld"
 | 
			
		||||
    override val lang = "it"
 | 
			
		||||
    override var lang = "it"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class AnimefenixProvider:MainAPI() {
 | 
			
		|||
 | 
			
		||||
    override var mainUrl = "https://animefenix.com"
 | 
			
		||||
    override var name = "Animefenix"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import kotlin.collections.ArrayList
 | 
			
		|||
class AnimeflvIOProvider:MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://animeflv.io" //Also scrapes from animeid.to
 | 
			
		||||
    override var name = "Animeflv.io"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ class AnimeflvnetProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
    override var mainUrl = "https://www3.animeflv.net"
 | 
			
		||||
    override var name = "Animeflv.net"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import org.jsoup.nodes.Element
 | 
			
		|||
class DreamSubProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://dreamsub.me"
 | 
			
		||||
    override var name = "DreamSub"
 | 
			
		||||
    override val lang = "it"
 | 
			
		||||
    override var lang = "it"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ class GomunimeProvider : MainAPI() {
 | 
			
		|||
    override var name = "Gomunime"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ class JKAnimeProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
    override var mainUrl = "https://jkanime.net"
 | 
			
		||||
    override var name = "JKAnime"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ class KuramanimeProvider : MainAPI() {
 | 
			
		|||
    override var name = "Kuramanime"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class KuronimeProvider : MainAPI() {
 | 
			
		|||
    override var name = "Kuronime"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ class MonoschinosProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
    override var mainUrl = "https://monoschinos2.com"
 | 
			
		||||
    override var name = "Monoschinos"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ class MundoDonghuaProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
    override var mainUrl = "https://www.mundodonghua.com"
 | 
			
		||||
    override var name = "MundoDonghua"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ class NeonimeProvider : MainAPI() {
 | 
			
		|||
    override var name = "Neonime"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ class NontonAnimeIDProvider : MainAPI() {
 | 
			
		|||
    override var name = "NontonAnimeID"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ class OploverzProvider : MainAPI() {
 | 
			
		|||
    override var name = "Oploverz"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		|||
class CrossTmdbProvider : TmdbProvider() {
 | 
			
		||||
    override var name = "MultiMovie"
 | 
			
		||||
    override val apiName = "MultiMovie"
 | 
			
		||||
    override val lang = "en"
 | 
			
		||||
    override var lang = "en"
 | 
			
		||||
    override val useMetaLoadResponse = true
 | 
			
		||||
    override val usesWebView = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.Movie)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ import com.lagradost.cloudstream3.utils.SyncUtil
 | 
			
		|||
// wont be implemented
 | 
			
		||||
class MultiAnimeProvider : MainAPI() {
 | 
			
		||||
    override var name = "MultiAnime"
 | 
			
		||||
    override val lang = "en"
 | 
			
		||||
    override var lang = "en"
 | 
			
		||||
    override val usesWebView = true
 | 
			
		||||
    override val supportedTypes = setOf(TvType.Anime)
 | 
			
		||||
    private val syncApi: SyncAPI = aniListApi
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.Qualities
 | 
			
		|||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class AkwamProvider : MainAPI() {
 | 
			
		||||
    override val lang = "ar"
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://akwam.to"
 | 
			
		||||
    override var name = "Akwam"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.app
 | 
			
		|||
import com.lagradost.cloudstream3.utils.*
 | 
			
		||||
 | 
			
		||||
class AltadefinizioneProvider : MainAPI() {
 | 
			
		||||
    override val lang = "it"
 | 
			
		||||
    override var lang = "it"
 | 
			
		||||
    override var mainUrl = "https://altadefinizione.hair"
 | 
			
		||||
    override var name = "Altadefinizione"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		|||
import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		||||
 | 
			
		||||
class CineblogProvider : MainAPI() {
 | 
			
		||||
    override val lang = "it"
 | 
			
		||||
    override var lang = "it"
 | 
			
		||||
    override var mainUrl = "https://cb01.rip"
 | 
			
		||||
    override var name = "CineBlog"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class CinecalidadProvider:MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://cinecalidad.lol"
 | 
			
		||||
    override var name = "Cinecalidad"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class CuevanaProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://cuevana3.me"
 | 
			
		||||
    override var name = "Cuevana"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ class DoramasYTProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
    override var mainUrl = "https://doramasyt.com"
 | 
			
		||||
    override var name = "DoramasYT"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ class DramaidProvider : MainAPI() {
 | 
			
		|||
    override var name = "DramaId"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
    override val hasChromecastSupport = false
 | 
			
		||||
    override val supportedTypes = setOf(TvType.AsianDrama)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		|||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class EgyBestProvider : MainAPI() {
 | 
			
		||||
    override val lang = "ar"
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://www.egy.best"
 | 
			
		||||
    override var name = "EgyBest"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,19 +1,20 @@
 | 
			
		|||
package com.lagradost.cloudstream3.movieproviders
 | 
			
		||||
 | 
			
		||||
import com.lagradost.cloudstream3.*
 | 
			
		||||
import com.lagradost.cloudstream3.utils.*
 | 
			
		||||
import kotlin.collections.ArrayList
 | 
			
		||||
import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		||||
import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		||||
 | 
			
		||||
class ElifilmsProvider:MainAPI() {
 | 
			
		||||
class ElifilmsProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl: String = "https://elifilms.net"
 | 
			
		||||
    override var name: String = "Elifilms"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
        TvType.Movie,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override suspend fun getMainPage(): HomePageResponse {
 | 
			
		||||
        val items = ArrayList<HomePageList>()
 | 
			
		||||
        val newest = app.get(mainUrl).document.selectFirst("a.fav_link.premiera")?.attr("href")
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +43,7 @@ class ElifilmsProvider:MainAPI() {
 | 
			
		|||
        if (items.size <= 0) throw ErrorLoadingException()
 | 
			
		||||
        return HomePageResponse(items)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
        val url = "$mainUrl/?s=$query"
 | 
			
		||||
        val doc = app.get(url).document
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +54,7 @@ class ElifilmsProvider:MainAPI() {
 | 
			
		|||
            (MovieSearchResponse(name, href, this.name, TvType.Movie, poster, null))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun load(url: String): LoadResponse {
 | 
			
		||||
        val document = app.get(url, timeout = 120).document
 | 
			
		||||
        val title = document.selectFirst(".post_title h1")?.text() ?: ""
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +76,7 @@ class ElifilmsProvider:MainAPI() {
 | 
			
		|||
            tags
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override suspend fun loadLinks(
 | 
			
		||||
        data: String,
 | 
			
		||||
        isCasting: Boolean,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class EntrepeliculasyseriesProvider:MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://entrepeliculasyseries.nu"
 | 
			
		||||
    override var name = "EntrePeliculasySeries"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ class EstrenosDoramasProvider : MainAPI() {
 | 
			
		|||
 | 
			
		||||
    override var mainUrl = "https://www23.estrenosdoramas.net"
 | 
			
		||||
    override var name = "EstrenosDoramas"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
 | 
			
		|||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class FaselHDProvider : MainAPI() {
 | 
			
		||||
    override val lang = "ar"
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://faselhd.io"
 | 
			
		||||
    override var name = "FaselHD"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import org.jsoup.select.Elements
 | 
			
		|||
class FilmanProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://filman.cc"
 | 
			
		||||
    override var name = "filman.cc"
 | 
			
		||||
    override val lang = "pl"
 | 
			
		||||
    override var lang = "pl"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
        TvType.Movie,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ class FrenchStreamProvider : MainAPI() {
 | 
			
		|||
    override var name = "French Stream"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "fr"
 | 
			
		||||
    override var lang = "fr"
 | 
			
		||||
    override val supportedTypes = setOf(TvType.AnimeMovie, TvType.TvSeries, TvType.Movie)
 | 
			
		||||
 | 
			
		||||
    override suspend fun search(query: String): List<SearchResponse> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ import org.jsoup.Jsoup
 | 
			
		|||
class HDMovie5 : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://hdmovie5.mba"
 | 
			
		||||
    override var name = "HDMovie"
 | 
			
		||||
    override val lang = "hi"
 | 
			
		||||
    override var lang = "hi"
 | 
			
		||||
 | 
			
		||||
    override val hasQuickSearch = true
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ class LayarKacaProvider : MainAPI() {
 | 
			
		|||
    override var mainUrl = "https://149.56.24.226"
 | 
			
		||||
    override var name = "LayarKaca"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
        TvType.Movie,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ import org.jsoup.Jsoup
 | 
			
		|||
import org.jsoup.nodes.Element
 | 
			
		||||
 | 
			
		||||
class MyCimaProvider : MainAPI() {
 | 
			
		||||
    override val lang = "ar"
 | 
			
		||||
    override var lang = "ar"
 | 
			
		||||
    override var mainUrl = "https://mycima.tv"
 | 
			
		||||
    override var name = "MyCima"
 | 
			
		||||
    override val usesWebView = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class PeliSmartProvider: MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://pelismart.com"
 | 
			
		||||
    override var name = "PeliSmart"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class PelisflixProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://pelisflix.li"
 | 
			
		||||
    override var name = "Pelisflix"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ import org.jsoup.nodes.Element
 | 
			
		|||
class PelisplusHDProvider:MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://pelisplushd.net"
 | 
			
		||||
    override var name = "PelisplusHD"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ import org.jsoup.Jsoup
 | 
			
		|||
 */
 | 
			
		||||
 | 
			
		||||
open class PelisplusProviderTemplate : MainAPI() {
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    open val homePageUrlList = listOf<String>()
 | 
			
		||||
 | 
			
		||||
//    // mainUrl is good to have as a holder for the url to make future changes easier.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class PinoyHDXyzProvider : MainAPI() {
 | 
			
		||||
    override var name = "Pinoy-HD"
 | 
			
		||||
    override var mainUrl = "https://www.pinoy-hd.xyz"
 | 
			
		||||
    override val lang = "tl"
 | 
			
		||||
    override var lang = "tl"
 | 
			
		||||
    override val supportedTypes = setOf(TvType.AsianDrama)
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class PinoyMoviePediaProvider : MainAPI() {
 | 
			
		||||
    override var name = "Pinoy Moviepedia"
 | 
			
		||||
    override var mainUrl = "https://pinoymoviepedia.ru"
 | 
			
		||||
    override val lang = "tl"
 | 
			
		||||
    override var lang = "tl"
 | 
			
		||||
    override val supportedTypes = setOf(TvType.AsianDrama)
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ import org.jsoup.select.Elements
 | 
			
		|||
class PinoyMoviesEsProvider : MainAPI() {
 | 
			
		||||
    override var name = "Pinoy Movies"
 | 
			
		||||
    override var mainUrl = "https://pinoymovies.es"
 | 
			
		||||
    override val lang = "tl"
 | 
			
		||||
    override var lang = "tl"
 | 
			
		||||
    override val supportedTypes = setOf(TvType.AsianDrama)
 | 
			
		||||
    override val hasDownloadSupport = false
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ class RebahinProvider : MainAPI() {
 | 
			
		|||
    override var mainUrl = "http://167.88.14.149"
 | 
			
		||||
    override var name = "Rebahin"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val lang = "id"
 | 
			
		||||
    override var lang = "id"
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
    override val supportedTypes = setOf(
 | 
			
		||||
        TvType.Movie,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
 | 
			
		|||
class SeriesflixProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://seriesflix.video"
 | 
			
		||||
    override var name = "Seriesflix"
 | 
			
		||||
    override val lang = "es"
 | 
			
		||||
    override var lang = "es"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
    override val hasChromecastSupport = true
 | 
			
		||||
    override val hasDownloadSupport = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ data class TrailerElement(
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
class StreamingcommunityProvider : MainAPI() {
 | 
			
		||||
    override val lang = "it"
 | 
			
		||||
    override var lang = "it"
 | 
			
		||||
    override var mainUrl = "https://streamingcommunity.press"
 | 
			
		||||
    override var name = "Streamingcommunity"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ import com.lagradost.cloudstream3.app
 | 
			
		|||
import com.lagradost.cloudstream3.utils.*
 | 
			
		||||
 | 
			
		||||
class TantifilmProvider : MainAPI() {
 | 
			
		||||
    override val lang = "it"
 | 
			
		||||
    override var lang = "it"
 | 
			
		||||
    override var mainUrl = "https://www.tantifilm.rodeo"
 | 
			
		||||
    override var name = "Tantifilm"
 | 
			
		||||
    override val hasMainPage = true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import org.jsoup.Jsoup
 | 
			
		|||
class VfFilmProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://vf-film.me"
 | 
			
		||||
    override var name = "vf-film.me"
 | 
			
		||||
    override val lang = "fr"
 | 
			
		||||
    override var lang = "fr"
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = false
 | 
			
		||||
    override val hasChromecastSupport = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,7 @@ import org.jsoup.Jsoup
 | 
			
		|||
class VfSerieProvider : MainAPI() {
 | 
			
		||||
    override var mainUrl = "https://vf-serie.org"
 | 
			
		||||
    override var name = "vf-serie.org"
 | 
			
		||||
    override val lang = "fr"
 | 
			
		||||
    override var lang = "fr"
 | 
			
		||||
 | 
			
		||||
    override val hasQuickSearch = false
 | 
			
		||||
    override val hasMainPage = false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,12 +13,12 @@ class APIRepository(val api: MainAPI) {
 | 
			
		|||
        val noneApi = object : MainAPI() {
 | 
			
		||||
            override var name = "None"
 | 
			
		||||
            override val supportedTypes = emptySet<TvType>()
 | 
			
		||||
            override val lang = ""
 | 
			
		||||
            override var lang = ""
 | 
			
		||||
        }
 | 
			
		||||
        val randomApi = object : MainAPI() {
 | 
			
		||||
            override var name = "Random"
 | 
			
		||||
            override val supportedTypes = emptySet<TvType>()
 | 
			
		||||
            override val lang = ""
 | 
			
		||||
            override var lang = ""
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun isInvalidData(data: String): Boolean {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,12 +6,18 @@ import android.os.Build
 | 
			
		|||
import android.os.Bundle
 | 
			
		||||
import android.os.Environment
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.appcompat.app.AlertDialog
 | 
			
		||||
import androidx.preference.PreferenceFragmentCompat
 | 
			
		||||
import androidx.preference.PreferenceManager
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.hippo.unifile.UniFile
 | 
			
		||||
import com.lagradost.cloudstream3.APIHolder.allProviders
 | 
			
		||||
import com.lagradost.cloudstream3.AcraApplication
 | 
			
		||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
 | 
			
		||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
 | 
			
		||||
import com.lagradost.cloudstream3.CommonActivity.showToast
 | 
			
		||||
import com.lagradost.cloudstream3.R
 | 
			
		||||
import com.lagradost.cloudstream3.app
 | 
			
		||||
import com.lagradost.cloudstream3.mvvm.logError
 | 
			
		||||
| 
						 | 
				
			
			@ -20,9 +26,15 @@ import com.lagradost.cloudstream3.network.initClient
 | 
			
		|||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
 | 
			
		||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
 | 
			
		||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
 | 
			
		||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
 | 
			
		||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
 | 
			
		||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
 | 
			
		||||
import com.lagradost.cloudstream3.utils.USER_PROVIDER_API
 | 
			
		||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
 | 
			
		||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
 | 
			
		||||
import kotlinx.android.synthetic.main.add_remove_sites.*
 | 
			
		||||
import kotlinx.android.synthetic.main.add_site_input.*
 | 
			
		||||
import java.io.File
 | 
			
		||||
 | 
			
		||||
class SettingsGeneral : PreferenceFragmentCompat() {
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +43,17 @@ class SettingsGeneral : PreferenceFragmentCompat() {
 | 
			
		|||
        setUpToolbar(R.string.category_general)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data class CustomSite(
 | 
			
		||||
        @JsonProperty("parentJavaClass") // javaClass.simpleName
 | 
			
		||||
        val parentJavaClass: String,
 | 
			
		||||
        @JsonProperty("name")
 | 
			
		||||
        val name: String,
 | 
			
		||||
        @JsonProperty("url")
 | 
			
		||||
        val url: String,
 | 
			
		||||
        @JsonProperty("lang")
 | 
			
		||||
        val lang: String,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    // Open file picker
 | 
			
		||||
    private val pathPicker =
 | 
			
		||||
        registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +87,94 @@ class SettingsGeneral : PreferenceFragmentCompat() {
 | 
			
		|||
        setPreferencesFromResource(R.xml.settins_general, rootKey)
 | 
			
		||||
        val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
 | 
			
		||||
 | 
			
		||||
        fun getCurrent(): MutableList<CustomSite> {
 | 
			
		||||
            return getKey<Array<CustomSite>>(USER_PROVIDER_API)?.toMutableList()
 | 
			
		||||
                ?: mutableListOf()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun showAdd() {
 | 
			
		||||
            val providers = allProviders.distinctBy { it.javaClass }.sortedBy { it.name }
 | 
			
		||||
            activity?.showDialog(
 | 
			
		||||
                providers.map { "${it.name} (${it.mainUrl})" },
 | 
			
		||||
                -1,
 | 
			
		||||
                context?.getString(R.string.add_site_pref) ?: return,
 | 
			
		||||
                true,
 | 
			
		||||
                {}) { selection ->
 | 
			
		||||
                val provider = providers.getOrNull(selection) ?: return@showDialog
 | 
			
		||||
 | 
			
		||||
                val builder =
 | 
			
		||||
                    AlertDialog.Builder(context ?: return@showDialog, R.style.AlertDialogCustom)
 | 
			
		||||
                        .setView(R.layout.add_site_input)
 | 
			
		||||
 | 
			
		||||
                val dialog = builder.create()
 | 
			
		||||
                dialog.show()
 | 
			
		||||
 | 
			
		||||
                dialog.text2?.text = provider.name
 | 
			
		||||
                dialog.apply_btt?.setOnClickListener {
 | 
			
		||||
                    val name = dialog.site_name_input?.text?.toString()
 | 
			
		||||
                    val url = dialog.site_url_input?.text?.toString()
 | 
			
		||||
                    val lang = dialog.site_lang_input?.text?.toString()
 | 
			
		||||
                    val realLang = if (lang.isNullOrBlank()) provider.lang else lang
 | 
			
		||||
                    if (url.isNullOrBlank() || name.isNullOrBlank() || realLang.length != 2) {
 | 
			
		||||
                        showToast(activity, R.string.error_invalid_data, Toast.LENGTH_SHORT)
 | 
			
		||||
                        return@setOnClickListener
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    val current = getCurrent()
 | 
			
		||||
                    val newSite = CustomSite(provider.javaClass.simpleName, name, url, realLang)
 | 
			
		||||
                    current.add(newSite)
 | 
			
		||||
                    setKey(USER_PROVIDER_API, current.toTypedArray())
 | 
			
		||||
 | 
			
		||||
                    dialog.dismissSafe(activity)
 | 
			
		||||
                }
 | 
			
		||||
                dialog.cancel_btt?.setOnClickListener {
 | 
			
		||||
                    dialog.dismissSafe(activity)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun showDelete() {
 | 
			
		||||
            val current = getCurrent()
 | 
			
		||||
 | 
			
		||||
            activity?.showMultiDialog(
 | 
			
		||||
                current.map { it.name },
 | 
			
		||||
                listOf(),
 | 
			
		||||
                context?.getString(R.string.remove_site_pref) ?: return,
 | 
			
		||||
                {}) { indexes ->
 | 
			
		||||
                current.removeAll(indexes.map { current[it] })
 | 
			
		||||
                setKey(USER_PROVIDER_API, current.toTypedArray())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun showAddOrDelete() {
 | 
			
		||||
            val builder =
 | 
			
		||||
                AlertDialog.Builder(context ?: return, R.style.AlertDialogCustom)
 | 
			
		||||
                    .setView(R.layout.add_remove_sites)
 | 
			
		||||
 | 
			
		||||
            val dialog = builder.create()
 | 
			
		||||
            dialog.show()
 | 
			
		||||
 | 
			
		||||
            dialog.add_site?.setOnClickListener {
 | 
			
		||||
                showAdd()
 | 
			
		||||
                dialog.dismissSafe(activity)
 | 
			
		||||
            }
 | 
			
		||||
            dialog.remove_site?.setOnClickListener {
 | 
			
		||||
                showDelete()
 | 
			
		||||
                dialog.dismissSafe(activity)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        getPref(R.string.override_site_key)?.setOnPreferenceClickListener { _ ->
 | 
			
		||||
 | 
			
		||||
            if (getCurrent().isEmpty()) {
 | 
			
		||||
                showAdd()
 | 
			
		||||
            } else {
 | 
			
		||||
                showAddOrDelete()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return@setOnPreferenceClickListener true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        getPref(R.string.legal_notice_key)?.setOnPreferenceClickListener {
 | 
			
		||||
            val builder: AlertDialog.Builder =
 | 
			
		||||
                AlertDialog.Builder(it.context, R.style.AlertDialogCustom)
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +183,7 @@ class SettingsGeneral : PreferenceFragmentCompat() {
 | 
			
		|||
            builder.show()
 | 
			
		||||
            return@setOnPreferenceClickListener true
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        getPref(R.string.dns_key)?.setOnPreferenceClickListener {
 | 
			
		||||
            val prefNames = resources.getStringArray(R.array.dns_pref)
 | 
			
		||||
            val prefValues = resources.getIntArray(R.array.dns_pref_values)
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +288,5 @@ class SettingsGeneral : PreferenceFragmentCompat() {
 | 
			
		|||
        } catch (e: Exception) {
 | 
			
		||||
            e.printStackTrace()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
 | 
			
		|||
const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache"
 | 
			
		||||
const val VIDEO_PLAYER_BRIGHTNESS = "video_player_alpha_key"
 | 
			
		||||
const val HOMEPAGE_API = "home_api_used"
 | 
			
		||||
const val USER_PROVIDER_API = "user_custom_sites"
 | 
			
		||||
 | 
			
		||||
const val PREFERENCES_NAME = "rebuild_preference"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,23 +14,33 @@ import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
 | 
			
		|||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
 | 
			
		||||
 | 
			
		||||
object SingleSelectionHelper {
 | 
			
		||||
    fun Activity.showOptionSelectStringRes(
 | 
			
		||||
    fun Activity?.showOptionSelectStringRes(
 | 
			
		||||
        view: View?,
 | 
			
		||||
        poster: String?,
 | 
			
		||||
        options: List<Int>,
 | 
			
		||||
        tvOptions: List<Int> = listOf(),
 | 
			
		||||
        callback: (Pair<Boolean, Int>) -> Unit
 | 
			
		||||
    ) {
 | 
			
		||||
        this.showOptionSelect(view, poster, options.map { this.getString(it) },tvOptions.map { this.getString(it) }, callback)
 | 
			
		||||
        if(this == null) return
 | 
			
		||||
 | 
			
		||||
        this.showOptionSelect(
 | 
			
		||||
            view,
 | 
			
		||||
            poster,
 | 
			
		||||
            options.map { this.getString(it) },
 | 
			
		||||
            tvOptions.map { this.getString(it) },
 | 
			
		||||
            callback
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun Activity.showOptionSelect(
 | 
			
		||||
    private fun Activity?.showOptionSelect(
 | 
			
		||||
        view: View?,
 | 
			
		||||
        poster: String?,
 | 
			
		||||
        options: List<String>,
 | 
			
		||||
        tvOptions: List<String>,
 | 
			
		||||
        callback: (Pair<Boolean, Int>) -> Unit
 | 
			
		||||
    ) {
 | 
			
		||||
        if(this == null) return
 | 
			
		||||
 | 
			
		||||
        if (this.isTvSettings()) {
 | 
			
		||||
            val builder =
 | 
			
		||||
                AlertDialog.Builder(this, R.style.AlertDialogCustom)
 | 
			
		||||
| 
						 | 
				
			
			@ -41,12 +51,13 @@ object SingleSelectionHelper {
 | 
			
		|||
 | 
			
		||||
            dialog.findViewById<ListView>(R.id.listview1)?.let { listView ->
 | 
			
		||||
                listView.choiceMode = AbsListView.CHOICE_MODE_SINGLE
 | 
			
		||||
                listView.adapter = ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice_color).apply {
 | 
			
		||||
                    addAll(tvOptions)
 | 
			
		||||
                }
 | 
			
		||||
                listView.adapter =
 | 
			
		||||
                    ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice_color).apply {
 | 
			
		||||
                        addAll(tvOptions)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                listView.setOnItemClickListener { _, _, i, _ ->
 | 
			
		||||
                    callback.invoke(Pair(true,i))
 | 
			
		||||
                    callback.invoke(Pair(true, i))
 | 
			
		||||
                    dialog.dismissSafe(this)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -62,12 +73,12 @@ object SingleSelectionHelper {
 | 
			
		|||
                    s
 | 
			
		||||
                )
 | 
			
		||||
            }) {
 | 
			
		||||
                callback(Pair(false,this.itemId))
 | 
			
		||||
                callback(Pair(false, this.itemId))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun Activity.showDialog(
 | 
			
		||||
    fun Activity?.showDialog(
 | 
			
		||||
        dialog: Dialog,
 | 
			
		||||
        items: List<String>,
 | 
			
		||||
        selectedIndex: List<Int>,
 | 
			
		||||
| 
						 | 
				
			
			@ -77,6 +88,8 @@ object SingleSelectionHelper {
 | 
			
		|||
        callback: (List<Int>) -> Unit,
 | 
			
		||||
        dismissCallback: () -> Unit
 | 
			
		||||
    ) {
 | 
			
		||||
        if(this == null) return
 | 
			
		||||
 | 
			
		||||
        val realShowApply = showApply || isMultiSelect
 | 
			
		||||
        val listView = dialog.findViewById<ListView>(R.id.listview1)!!
 | 
			
		||||
        val textView = dialog.findViewById<TextView>(R.id.text1)!!
 | 
			
		||||
| 
						 | 
				
			
			@ -145,8 +158,7 @@ object SingleSelectionHelper {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private fun Activity.showInputDialog(
 | 
			
		||||
    private fun Activity?.showInputDialog(
 | 
			
		||||
        dialog: Dialog,
 | 
			
		||||
        value: String,
 | 
			
		||||
        name: String,
 | 
			
		||||
| 
						 | 
				
			
			@ -154,6 +166,8 @@ object SingleSelectionHelper {
 | 
			
		|||
        callback: (String) -> Unit,
 | 
			
		||||
        dismissCallback: () -> Unit
 | 
			
		||||
    ) {
 | 
			
		||||
        if(this == null) return
 | 
			
		||||
 | 
			
		||||
        val inputView = dialog.findViewById<EditText>(R.id.nginx_text_input)!!
 | 
			
		||||
        val textView = dialog.findViewById<TextView>(R.id.text1)!!
 | 
			
		||||
        val applyButton = dialog.findViewById<TextView>(R.id.apply_btt)!!
 | 
			
		||||
| 
						 | 
				
			
			@ -184,13 +198,15 @@ object SingleSelectionHelper {
 | 
			
		|||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun Activity.showMultiDialog(
 | 
			
		||||
    fun Activity?.showMultiDialog(
 | 
			
		||||
        items: List<String>,
 | 
			
		||||
        selectedIndex: List<Int>,
 | 
			
		||||
        name: String,
 | 
			
		||||
        dismissCallback: () -> Unit,
 | 
			
		||||
        callback: (List<Int>) -> Unit,
 | 
			
		||||
    ) {
 | 
			
		||||
        if(this == null) return
 | 
			
		||||
 | 
			
		||||
        val builder =
 | 
			
		||||
            AlertDialog.Builder(this, R.style.AlertDialogCustom)
 | 
			
		||||
                .setView(R.layout.bottom_selection_dialog)
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +216,7 @@ object SingleSelectionHelper {
 | 
			
		|||
        showDialog(dialog, items, selectedIndex, name, true, true, callback, dismissCallback)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun Activity.showDialog(
 | 
			
		||||
    fun Activity?.showDialog(
 | 
			
		||||
        items: List<String>,
 | 
			
		||||
        selectedIndex: Int,
 | 
			
		||||
        name: String,
 | 
			
		||||
| 
						 | 
				
			
			@ -208,6 +224,8 @@ object SingleSelectionHelper {
 | 
			
		|||
        dismissCallback: () -> Unit,
 | 
			
		||||
        callback: (Int) -> Unit,
 | 
			
		||||
    ) {
 | 
			
		||||
        if(this == null) return
 | 
			
		||||
 | 
			
		||||
        val builder =
 | 
			
		||||
            AlertDialog.Builder(this, R.style.AlertDialogCustom)
 | 
			
		||||
                .setView(R.layout.bottom_selection_dialog)
 | 
			
		||||
| 
						 | 
				
			
			@ -227,14 +245,15 @@ object SingleSelectionHelper {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /** Only for a low amount of items */
 | 
			
		||||
    fun Activity.showBottomDialog(
 | 
			
		||||
    fun Activity?.showBottomDialog(
 | 
			
		||||
        items: List<String>,
 | 
			
		||||
        selectedIndex: Int,
 | 
			
		||||
        name: String,
 | 
			
		||||
        showApply: Boolean,
 | 
			
		||||
         dismissCallback: () -> Unit,
 | 
			
		||||
        dismissCallback: () -> Unit,
 | 
			
		||||
        callback: (Int) -> Unit,
 | 
			
		||||
    ) {
 | 
			
		||||
        if (this == null) return
 | 
			
		||||
        val builder =
 | 
			
		||||
            BottomSheetDialog(this)
 | 
			
		||||
        builder.setContentView(R.layout.bottom_selection_dialog)
 | 
			
		||||
| 
						 | 
				
			
			@ -252,12 +271,12 @@ object SingleSelectionHelper {
 | 
			
		|||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        fun Activity.showNginxTextInputDialog(
 | 
			
		||||
            name: String,
 | 
			
		||||
            value: String,
 | 
			
		||||
            textInputType: Int?,
 | 
			
		||||
            dismissCallback: () -> Unit,
 | 
			
		||||
            callback: (String) -> Unit,
 | 
			
		||||
    fun Activity.showNginxTextInputDialog(
 | 
			
		||||
        name: String,
 | 
			
		||||
        value: String,
 | 
			
		||||
        textInputType: Int?,
 | 
			
		||||
        dismissCallback: () -> Unit,
 | 
			
		||||
        callback: (String) -> Unit,
 | 
			
		||||
    ) {
 | 
			
		||||
        val builder = BottomSheetDialog(this)  // probably the stuff at the bottom
 | 
			
		||||
        builder.setContentView(R.layout.bottom_input_dialog)  // input layout
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
<vector android:height="24dp" android:tint="#FFFFFF"
 | 
			
		||||
<vector android:height="24dp" android:tint="?attr/white"
 | 
			
		||||
    android:viewportHeight="24" android:viewportWidth="24"
 | 
			
		||||
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
 | 
			
		||||
    <path android:fillColor="@android:color/white" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								app/src/main/res/layout/add_remove_sites.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/src/main/res/layout/add_remove_sites.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/add_site"
 | 
			
		||||
            android:text="@string/add_site_pref"
 | 
			
		||||
            style="@style/SettingsItem">
 | 
			
		||||
 | 
			
		||||
        <requestFocus />
 | 
			
		||||
    </TextView>
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:id="@+id/remove_site"
 | 
			
		||||
            android:text="@string/remove_site_pref"
 | 
			
		||||
            style="@style/SettingsItem" />
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
							
								
								
									
										117
									
								
								app/src/main/res/layout/add_site_input.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								app/src/main/res/layout/add_site_input.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,117 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<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"
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_marginTop="20dp"
 | 
			
		||||
            android:layout_marginBottom="10dp"
 | 
			
		||||
            android:id="@+id/text1"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
 | 
			
		||||
            android:layout_gravity="center_vertical"
 | 
			
		||||
            android:layout_rowWeight="1"
 | 
			
		||||
 | 
			
		||||
            android:paddingStart="?android:attr/listPreferredItemPaddingStart"
 | 
			
		||||
            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
 | 
			
		||||
            android:textColor="?attr/textColor"
 | 
			
		||||
            android:textSize="20sp"
 | 
			
		||||
            android:textStyle="bold"
 | 
			
		||||
            android:text="@string/add_site_pref" />
 | 
			
		||||
 | 
			
		||||
    <TextView
 | 
			
		||||
            android:layout_marginBottom="10dp"
 | 
			
		||||
 | 
			
		||||
            android:id="@+id/text2"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
 | 
			
		||||
            android:layout_gravity="center_vertical"
 | 
			
		||||
            android:layout_rowWeight="1"
 | 
			
		||||
 | 
			
		||||
            android:paddingStart="?android:attr/listPreferredItemPaddingStart"
 | 
			
		||||
            android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
 | 
			
		||||
            android:textColor="?attr/grayTextColor"
 | 
			
		||||
            android:textSize="15sp"
 | 
			
		||||
            tools:text="Gogoanime" />
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:orientation="vertical"
 | 
			
		||||
            android:layout_marginBottom="60dp"
 | 
			
		||||
            android:layout_marginHorizontal="10dp"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:textColorHint="?attr/grayTextColor"
 | 
			
		||||
                android:hint="@string/example_site_name"
 | 
			
		||||
                android:autofillHints="username"
 | 
			
		||||
                android:id="@+id/site_name_input"
 | 
			
		||||
                android:nextFocusRight="@id/cancel_btt"
 | 
			
		||||
                android:nextFocusLeft="@id/apply_btt"
 | 
			
		||||
                android:nextFocusDown="@id/site_url_input"
 | 
			
		||||
                android:requiresFadingEdge="vertical"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:inputType="text"
 | 
			
		||||
                tools:ignore="LabelFor" />
 | 
			
		||||
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:textColorHint="?attr/grayTextColor"
 | 
			
		||||
                android:hint="@string/example_site_url"
 | 
			
		||||
                android:id="@+id/site_url_input"
 | 
			
		||||
                android:nextFocusRight="@id/cancel_btt"
 | 
			
		||||
                android:nextFocusLeft="@id/apply_btt"
 | 
			
		||||
                android:nextFocusUp="@id/site_name_input"
 | 
			
		||||
                android:nextFocusDown="@id/site_lang_input"
 | 
			
		||||
 | 
			
		||||
                android:requiresFadingEdge="vertical"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:inputType="textUri"
 | 
			
		||||
                tools:ignore="LabelFor" />
 | 
			
		||||
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:textColorHint="?attr/grayTextColor"
 | 
			
		||||
                android:hint="@string/example_lang_name"
 | 
			
		||||
                android:autofillHints="username"
 | 
			
		||||
                android:id="@+id/site_lang_input"
 | 
			
		||||
                android:nextFocusUp="@id/site_url_input"
 | 
			
		||||
                android:nextFocusRight="@id/cancel_btt"
 | 
			
		||||
                android:nextFocusLeft="@id/apply_btt"
 | 
			
		||||
                android:nextFocusDown="@id/apply_btt"
 | 
			
		||||
                android:requiresFadingEdge="vertical"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content"
 | 
			
		||||
                android:inputType="text"
 | 
			
		||||
                tools:ignore="LabelFor" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
            android:id="@+id/apply_btt_holder"
 | 
			
		||||
            android:orientation="horizontal"
 | 
			
		||||
            android:layout_gravity="bottom"
 | 
			
		||||
            android:gravity="bottom|end"
 | 
			
		||||
            android:layout_marginTop="-60dp"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="60dp">
 | 
			
		||||
 | 
			
		||||
        <com.google.android.material.button.MaterialButton
 | 
			
		||||
                style="@style/WhiteButton"
 | 
			
		||||
                android:layout_gravity="center_vertical|end"
 | 
			
		||||
                android:text="@string/add_site_pref"
 | 
			
		||||
                android:id="@+id/apply_btt"
 | 
			
		||||
                android:layout_width="wrap_content" />
 | 
			
		||||
 | 
			
		||||
        <com.google.android.material.button.MaterialButton
 | 
			
		||||
                style="@style/BlackButton"
 | 
			
		||||
                android:layout_gravity="center_vertical|end"
 | 
			
		||||
                android:text="@string/sort_cancel"
 | 
			
		||||
                android:id="@+id/cancel_btt"
 | 
			
		||||
                android:layout_width="wrap_content" />
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +50,7 @@
 | 
			
		|||
    <string name="bottom_title_key" translatable="false">bottom_title_key</string>
 | 
			
		||||
    <string name="poster_ui_key" translatable="false">poster_ui_key</string>
 | 
			
		||||
    <string name="subtitles_encoding_key" translatable="false">subtitles_encoding_key</string>
 | 
			
		||||
    <string name="override_site_key" translatable="false">override_site_key</string>
 | 
			
		||||
 | 
			
		||||
    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
 | 
			
		||||
    <string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
 | 
			
		||||
| 
						 | 
				
			
			@ -382,6 +383,10 @@
 | 
			
		|||
    <string name="dns_pref">DNS over HTTPS</string>
 | 
			
		||||
    <string name="dns_pref_summary">Useful for bypassing ISP blocks</string>
 | 
			
		||||
 | 
			
		||||
    <string name="add_site_pref">Add site</string>
 | 
			
		||||
    <string name="remove_site_pref">Remove site</string>
 | 
			
		||||
    <string name="add_site_summary">Add a clone of an existing site, with a different url</string>
 | 
			
		||||
 | 
			
		||||
    <string name="download_path_pref">Download path</string>
 | 
			
		||||
 | 
			
		||||
    <string name="nginx_url_pref">Nginx server url</string>
 | 
			
		||||
| 
						 | 
				
			
			@ -440,6 +445,9 @@
 | 
			
		|||
    <string name="example_username">MyCoolUsername</string>
 | 
			
		||||
    <string name="example_email">hello@world.com</string>
 | 
			
		||||
    <string name="example_ip">127.0.0.1</string>
 | 
			
		||||
    <string name="example_site_name">MyCoolSite</string>
 | 
			
		||||
    <string name="example_site_url">example.com</string>
 | 
			
		||||
    <string name="example_lang_name">Language code (en)</string>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    <string name="mal_account_settings" translatable="false">MAL</string>
 | 
			
		||||
| 
						 | 
				
			
			@ -529,6 +537,8 @@
 | 
			
		|||
    <string name="title">Title</string>
 | 
			
		||||
    <string name="resolution">Resolution</string>
 | 
			
		||||
    <string name="error_invalid_id">Invalid id</string>
 | 
			
		||||
    <string name="error_invalid_data">Invalid data</string>
 | 
			
		||||
    <string name="error">Error</string>
 | 
			
		||||
    <string name="subtitles_remove_captions">Remove closed captions from subtitles</string>
 | 
			
		||||
    <string name="subtitles_remove_bloat">Remove bloat from subtitles</string>
 | 
			
		||||
    <string name="extras">Extras</string>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,11 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto">
 | 
			
		||||
    <Preference
 | 
			
		||||
            android:key="@string/override_site_key"
 | 
			
		||||
            android:title="@string/add_site_pref"
 | 
			
		||||
            android:summary="@string/add_site_summary"
 | 
			
		||||
            android:icon="@drawable/ic_baseline_add_24" />
 | 
			
		||||
 | 
			
		||||
    <Preference
 | 
			
		||||
            android:key="@string/dns_key"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue