mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge branch 'recloudstream:master' into master
This commit is contained in:
commit
daf7a5fb83
60 changed files with 1333 additions and 360 deletions
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,8 +1,8 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Report provider bug
|
- name: Request a new provider or report bug with an existing provider
|
||||||
url: https://github.com/recloudstream
|
url: https://github.com/recloudstream
|
||||||
about: Please do not report any provider bugs here. This repository does not contain any providers. Please find the appropriate repository and report your issue there or join the discord.
|
about: Please do not report any provider bugs here or request new providers. This repository does not contain any providers. Please find the appropriate repository and report your issue there or join the discord.
|
||||||
- name: Discord
|
- name: Discord
|
||||||
url: https://discord.gg/5Hus6fM
|
url: https://discord.gg/5Hus6fM
|
||||||
about: Join our discord for faster support on smaller issues.
|
about: Join our discord for faster support on smaller issues.
|
||||||
|
|
2
.github/workflows/issue_action.yml
vendored
2
.github/workflows/issue_action.yml
vendored
|
@ -2,7 +2,7 @@ name: Issue automatic actions
|
||||||
|
|
||||||
on:
|
on:
|
||||||
issues:
|
issues:
|
||||||
types: [opened, edited]
|
types: [opened]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
issue-moderator:
|
issue-moderator:
|
||||||
|
|
|
@ -21,6 +21,12 @@
|
||||||
android:name="android.software.leanback"
|
android:name="android.software.leanback"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
|
<queries>
|
||||||
|
<package android:name="org.videolan.vlc" />
|
||||||
|
<package android:name="com.instantbits.cast.webvideo" />
|
||||||
|
<package android:name="is.xyz.mpv" />
|
||||||
|
</queries>
|
||||||
|
|
||||||
<!--TODO https://stackoverflow.com/questions/41799732/chromecast-button-not-visible-in-android-->
|
<!--TODO https://stackoverflow.com/questions/41799732/chromecast-button-not-visible-in-android-->
|
||||||
<application
|
<application
|
||||||
android:name=".AcraApplication"
|
android:name=".AcraApplication"
|
||||||
|
|
|
@ -10,16 +10,22 @@ import android.util.Log
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.MainThread
|
import androidx.annotation.MainThread
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.android.gms.cast.framework.CastSession
|
import com.google.android.gms.cast.framework.CastSession
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.ui.player.PlayerEventType
|
import com.lagradost.cloudstream3.ui.player.PlayerEventType
|
||||||
|
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||||
import com.lagradost.cloudstream3.ui.result.UiText
|
import com.lagradost.cloudstream3.ui.result.UiText
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
|
||||||
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
import com.lagradost.cloudstream3.utils.Event
|
import com.lagradost.cloudstream3.utils.Event
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper
|
import com.lagradost.cloudstream3.utils.UIHelper
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
|
import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
|
||||||
|
@ -34,6 +40,7 @@ object CommonActivity {
|
||||||
return (this as MainActivity?)?.mSessionManager?.currentCastSession
|
return (this as MainActivity?)?.mSessionManager?.currentCastSession
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var canEnterPipMode: Boolean = false
|
var canEnterPipMode: Boolean = false
|
||||||
var canShowPipMode: Boolean = false
|
var canShowPipMode: Boolean = false
|
||||||
var isInPIPMode: Boolean = false
|
var isInPIPMode: Boolean = false
|
||||||
|
@ -117,7 +124,7 @@ object CommonActivity {
|
||||||
setLocale(this, localeCode)
|
setLocale(this, localeCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun init(act: Activity?) {
|
fun init(act: ComponentActivity?) {
|
||||||
if (act == null) return
|
if (act == null) return
|
||||||
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
|
//https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission
|
||||||
//https://developer.android.com/guide/topics/ui/picture-in-picture
|
//https://developer.android.com/guide/topics/ui/picture-in-picture
|
||||||
|
@ -129,6 +136,22 @@ object CommonActivity {
|
||||||
act.updateLocale()
|
act.updateLocale()
|
||||||
act.updateTv()
|
act.updateTv()
|
||||||
NewPipe.init(DownloaderTestImpl.getInstance())
|
NewPipe.init(DownloaderTestImpl.getInstance())
|
||||||
|
|
||||||
|
for (resumeApp in resumeApps) {
|
||||||
|
resumeApp.launcher =
|
||||||
|
act.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||||
|
val resultCode = result.resultCode
|
||||||
|
val data = result.data
|
||||||
|
if (resultCode == AppCompatActivity.RESULT_OK && data != null && resumeApp.position != null && resumeApp.duration != null) {
|
||||||
|
val pos = data.getLongExtra(resumeApp.position, -1L)
|
||||||
|
val dur = data.getLongExtra(resumeApp.duration, -1L)
|
||||||
|
if (dur > 0L && pos > 0L)
|
||||||
|
DataStoreHelper.setViewPos(getKey(resumeApp.lastId), pos, dur)
|
||||||
|
removeKey(resumeApp.lastId)
|
||||||
|
ResultFragment.updateUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Activity.enterPIPMode() {
|
private fun Activity.enterPIPMode() {
|
||||||
|
|
|
@ -17,13 +17,11 @@ import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
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.SubtitleHelper
|
||||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.collections.MutableList
|
|
||||||
|
|
||||||
const val USER_AGENT =
|
const val USER_AGENT =
|
||||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
||||||
|
@ -193,17 +191,26 @@ object APIHolder {
|
||||||
return list.filter { names.contains(it) }.map { DubStatus.valueOf(it) }.toHashSet()
|
return list.filter { names.contains(it) }.map { DubStatus.valueOf(it) }.toHashSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the activated provider languages
|
||||||
|
* Used to obey the preference provider_lang_key
|
||||||
|
* but it turned out too complicated and unnecessary with extensions.
|
||||||
|
**/
|
||||||
fun Context.getApiProviderLangSettings(): HashSet<String> {
|
fun Context.getApiProviderLangSettings(): HashSet<String> {
|
||||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
val langs = apis.map { it.lang }.toSet()
|
||||||
val hashSet = HashSet<String>()
|
.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }
|
||||||
hashSet.add("en") // def is only en
|
return langs.toHashSet()
|
||||||
val list = settingsManager.getStringSet(
|
|
||||||
this.getString(R.string.provider_lang_key),
|
|
||||||
hashSet.toMutableSet()
|
|
||||||
)
|
|
||||||
|
|
||||||
if (list.isNullOrEmpty()) return hashSet
|
// val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
return list.toHashSet()
|
// val hashSet = HashSet<String>()
|
||||||
|
// hashSet.add("en") // def is only en
|
||||||
|
// val list = settingsManager.getStringSet(
|
||||||
|
// this.getString(R.string.provider_lang_key),
|
||||||
|
// hashSet.toMutableSet()
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// if (list.isNullOrEmpty()) return hashSet
|
||||||
|
// return list.toHashSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getApiTypeSettings(): HashSet<TvType> {
|
fun Context.getApiTypeSettings(): HashSet<TvType> {
|
||||||
|
@ -326,13 +333,24 @@ data class SettingsJson(
|
||||||
data class MainPageData(
|
data class MainPageData(
|
||||||
val name: String,
|
val name: String,
|
||||||
val data: String,
|
val data: String,
|
||||||
|
val horizontalImages: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
data class MainPageRequest(
|
data class MainPageRequest(
|
||||||
val name: String,
|
val name: String,
|
||||||
val data: String,
|
val data: String,
|
||||||
|
val horizontalImages: Boolean,
|
||||||
|
//TODO genre selection or smth
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun mainPage(url: String, name: String, horizontalImages: Boolean = false): MainPageData {
|
||||||
|
return MainPageData(name = name, data = url, horizontalImages = horizontalImages)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mainPageOf(vararg elements: MainPageData): List<MainPageData> {
|
||||||
|
return elements.toList()
|
||||||
|
}
|
||||||
|
|
||||||
/** return list of MainPageData with url to name, make for more readable code */
|
/** return list of MainPageData with url to name, make for more readable code */
|
||||||
fun mainPageOf(vararg elements: Pair<String, String>): List<MainPageData> {
|
fun mainPageOf(vararg elements: Pair<String, String>): List<MainPageData> {
|
||||||
return elements.map { (url, name) -> MainPageData(name = name, data = url) }
|
return elements.map { (url, name) -> MainPageData(name = name, data = url) }
|
||||||
|
@ -341,7 +359,7 @@ fun mainPageOf(vararg elements: Pair<String, String>): List<MainPageData> {
|
||||||
fun newHomePageResponse(
|
fun newHomePageResponse(
|
||||||
name: String,
|
name: String,
|
||||||
list: List<SearchResponse>,
|
list: List<SearchResponse>,
|
||||||
hasNext: Boolean? = null
|
hasNext: Boolean? = null,
|
||||||
): HomePageResponse {
|
): HomePageResponse {
|
||||||
return HomePageResponse(
|
return HomePageResponse(
|
||||||
listOf(HomePageList(name, list)),
|
listOf(HomePageList(name, list)),
|
||||||
|
@ -349,6 +367,17 @@ fun newHomePageResponse(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun newHomePageResponse(
|
||||||
|
data: MainPageRequest,
|
||||||
|
list: List<SearchResponse>,
|
||||||
|
hasNext: Boolean? = null,
|
||||||
|
): HomePageResponse {
|
||||||
|
return HomePageResponse(
|
||||||
|
listOf(HomePageList(data.name, list, data.horizontalImages)),
|
||||||
|
hasNext = hasNext ?: list.isNotEmpty()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun newHomePageResponse(list: HomePageList, hasNext: Boolean? = null): HomePageResponse {
|
fun newHomePageResponse(list: HomePageList, hasNext: Boolean? = null): HomePageResponse {
|
||||||
return HomePageResponse(listOf(list), hasNext = hasNext ?: list.list.isNotEmpty())
|
return HomePageResponse(listOf(list), hasNext = hasNext ?: list.list.isNotEmpty())
|
||||||
}
|
}
|
||||||
|
@ -383,7 +412,19 @@ abstract class MainAPI {
|
||||||
open var storedCredentials: String? = null
|
open var storedCredentials: String? = null
|
||||||
open var canBeOverridden: Boolean = true
|
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
|
/** if this is turned on then it will request the homepage one after the other,
|
||||||
|
used to delay if they block many request at the same time*/
|
||||||
|
open var sequentialMainPage: Boolean = false
|
||||||
|
|
||||||
|
/** in milliseconds, this can be used to add more delay between homepage requests
|
||||||
|
* on first load if sequentialMainPage is turned on */
|
||||||
|
open var sequentialMainPageDelay: Long = 0L
|
||||||
|
|
||||||
|
/** in milliseconds, this can be used to add more delay between homepage requests when scrolling */
|
||||||
|
open var sequentialMainPageScrollDelay: Long = 0L
|
||||||
|
|
||||||
|
/** used to keep track when last homepage request was in unixtime ms */
|
||||||
|
var lastHomepageRequest: Long = 0L
|
||||||
|
|
||||||
open var lang = "en" // ISO_639_1 check SubtitleHelper
|
open var lang = "en" // ISO_639_1 check SubtitleHelper
|
||||||
|
|
||||||
|
@ -416,7 +457,8 @@ abstract class MainAPI {
|
||||||
open val vpnStatus = VPNStatus.None
|
open val vpnStatus = VPNStatus.None
|
||||||
open val providerType = ProviderType.DirectProvider
|
open val providerType = ProviderType.DirectProvider
|
||||||
|
|
||||||
open val mainPage = listOf(MainPageData("", ""))
|
//emptyList<MainPageData>() //
|
||||||
|
open val mainPage = listOf(MainPageData("", "", false))
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
open suspend fun getMainPage(
|
open suspend fun getMainPage(
|
||||||
|
|
|
@ -10,7 +10,7 @@ import android.view.KeyEvent
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.Toast
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
@ -35,6 +35,8 @@ import com.lagradost.cloudstream3.APIHolder.apis
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.initAll
|
import com.lagradost.cloudstream3.APIHolder.initAll
|
||||||
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.loadThemes
|
import com.lagradost.cloudstream3.CommonActivity.loadThemes
|
||||||
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
|
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
|
||||||
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
|
||||||
|
@ -53,7 +55,6 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStri
|
||||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.inAppAuths
|
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.inAppAuths
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
|
@ -67,10 +68,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||||
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
|
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos
|
|
||||||
import com.lagradost.cloudstream3.utils.Event
|
import com.lagradost.cloudstream3.utils.Event
|
||||||
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
import com.lagradost.cloudstream3.utils.IOnBackPressed
|
||||||
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
||||||
|
@ -95,17 +94,65 @@ import java.nio.charset.Charset
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
const val VLC_PACKAGE = "org.videolan.vlc"
|
//https://github.com/videolan/vlc-android/blob/3706c4be2da6800b3d26344fc04fab03ffa4b860/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt#L1898
|
||||||
const val VLC_INTENT_ACTION_RESULT = "org.videolan.vlc.player.result"
|
//https://wiki.videolan.org/Android_Player_Intents/
|
||||||
val VLC_COMPONENT: ComponentName =
|
|
||||||
ComponentName(VLC_PACKAGE, "org.videolan.vlc.gui.video.VideoPlayerActivity")
|
|
||||||
const val VLC_REQUEST_CODE = 42
|
|
||||||
|
|
||||||
const val VLC_FROM_START = -1
|
//https://github.com/mpv-android/mpv-android/blob/0eb3cdc6f1632636b9c30d52ec50e4b017661980/app/src/main/java/is/xyz/mpv/MPVActivity.kt#L904
|
||||||
const val VLC_FROM_PROGRESS = -2
|
//https://mpv-android.github.io/mpv-android/intent.html
|
||||||
const val VLC_EXTRA_POSITION_OUT = "extra_position"
|
|
||||||
const val VLC_EXTRA_DURATION_OUT = "extra_duration"
|
// https://www.webvideocaster.com/integrations
|
||||||
const val VLC_LAST_ID_KEY = "vlc_last_open_id"
|
|
||||||
|
//https://github.com/jellyfin/jellyfin-android/blob/6cbf0edf84a3da82347c8d59b5d5590749da81a9/app/src/main/java/org/jellyfin/mobile/bridge/ExternalPlayer.kt#L225
|
||||||
|
|
||||||
|
const val VLC_PACKAGE = "org.videolan.vlc"
|
||||||
|
const val MPV_PACKAGE = "is.xyz.mpv"
|
||||||
|
const val WEB_VIDEO_CAST_PACKAGE = "com.instantbits.cast.webvideo"
|
||||||
|
|
||||||
|
val VLC_COMPONENT = ComponentName(VLC_PACKAGE, "$VLC_PACKAGE.gui.video.VideoPlayerActivity")
|
||||||
|
val MPV_COMPONENT = ComponentName(MPV_PACKAGE, "$MPV_PACKAGE.MPVActivity")
|
||||||
|
|
||||||
|
//TODO REFACTOR AF
|
||||||
|
data class ResultResume(
|
||||||
|
val packageString: String,
|
||||||
|
val action: String = Intent.ACTION_VIEW,
|
||||||
|
val position: String? = null,
|
||||||
|
val duration: String? = null,
|
||||||
|
var launcher: ActivityResultLauncher<Intent>? = null,
|
||||||
|
) {
|
||||||
|
val lastId get() = "${packageString}_last_open_id"
|
||||||
|
suspend fun launch(id: Int?, callback: suspend Intent.() -> Unit) {
|
||||||
|
val intent = Intent(action)
|
||||||
|
|
||||||
|
if (id != null)
|
||||||
|
setKey(lastId, id)
|
||||||
|
else
|
||||||
|
removeKey(lastId)
|
||||||
|
|
||||||
|
intent.setPackage(packageString)
|
||||||
|
callback.invoke(intent)
|
||||||
|
launcher?.launch(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val VLC = ResultResume(
|
||||||
|
VLC_PACKAGE,
|
||||||
|
"org.videolan.vlc.player.result",
|
||||||
|
"extra_position",
|
||||||
|
"extra_duration",
|
||||||
|
)
|
||||||
|
|
||||||
|
val MPV = ResultResume(
|
||||||
|
MPV_PACKAGE,
|
||||||
|
//"is.xyz.mpv.MPVActivity.result", // resume not working :pensive:
|
||||||
|
position = "position",
|
||||||
|
duration = "duration",
|
||||||
|
)
|
||||||
|
|
||||||
|
val WEB_VIDEO = ResultResume(WEB_VIDEO_CAST_PACKAGE)
|
||||||
|
|
||||||
|
val resumeApps = arrayOf(
|
||||||
|
VLC, MPV, WEB_VIDEO
|
||||||
|
)
|
||||||
|
|
||||||
// Short name for requests client to make it nicer to use
|
// Short name for requests client to make it nicer to use
|
||||||
|
|
||||||
|
@ -372,31 +419,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (requestCode == VLC_REQUEST_CODE) {
|
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
|
||||||
val pos: Long =
|
|
||||||
data.getLongExtra(
|
|
||||||
VLC_EXTRA_POSITION_OUT,
|
|
||||||
-1
|
|
||||||
) //Last position in media when player exited
|
|
||||||
val dur: Long =
|
|
||||||
data.getLongExtra(
|
|
||||||
VLC_EXTRA_DURATION_OUT,
|
|
||||||
-1
|
|
||||||
) //Last position in media when player exited
|
|
||||||
val id = getKey<Int>(VLC_LAST_ID_KEY)
|
|
||||||
println("SET KEY $id at $pos / $dur")
|
|
||||||
if (dur > 0 && pos > 0) {
|
|
||||||
setViewPos(id, pos, dur)
|
|
||||||
}
|
|
||||||
removeKey(VLC_LAST_ID_KEY)
|
|
||||||
ResultFragment.updateUI()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
val broadcastIntent = Intent()
|
val broadcastIntent = Intent()
|
||||||
broadcastIntent.action = "restart_service"
|
broadcastIntent.action = "restart_service"
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
|
|
||||||
|
class Vidmolyme : Vidmoly() {
|
||||||
|
override val mainUrl = "https://vidmoly.me"
|
||||||
|
}
|
||||||
|
|
||||||
|
open class Vidmoly : ExtractorApi() {
|
||||||
|
override val name = "Vidmoly"
|
||||||
|
override val mainUrl = "https://vidmoly.to"
|
||||||
|
override val requiresReferer = true
|
||||||
|
|
||||||
|
private fun String.addMarks(str: String): String {
|
||||||
|
return this.replace(Regex("\"?$str\"?"), "\"$str\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getUrl(
|
||||||
|
url: String,
|
||||||
|
referer: String?,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
|
val script = app.get(
|
||||||
|
url,
|
||||||
|
referer = referer,
|
||||||
|
).document.select("script")
|
||||||
|
.find { it.data().contains("sources:") }?.data()
|
||||||
|
val videoData = script?.substringAfter("sources: [")
|
||||||
|
?.substringBefore("],")?.addMarks("file")
|
||||||
|
val subData = script?.substringAfter("tracks: [")?.substringBefore("]")?.addMarks("file")
|
||||||
|
?.addMarks("label")?.addMarks("kind")
|
||||||
|
|
||||||
|
tryParseJson<Source>(videoData)?.file?.let { m3uLink ->
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
name,
|
||||||
|
m3uLink,
|
||||||
|
"$mainUrl/"
|
||||||
|
).forEach(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
tryParseJson<List<SubSource>>("[${subData}]")
|
||||||
|
?.filter { it.kind == "captions" }?.map {
|
||||||
|
subtitleCallback.invoke(
|
||||||
|
SubtitleFile(
|
||||||
|
it.label.toString(),
|
||||||
|
fixUrl(it.file.toString())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class Source(
|
||||||
|
@JsonProperty("file") val file: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class SubSource(
|
||||||
|
@JsonProperty("file") val file: String? = null,
|
||||||
|
@JsonProperty("label") val label: String? = null,
|
||||||
|
@JsonProperty("kind") val kind: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
|
||||||
|
open class Voe : ExtractorApi() {
|
||||||
|
override val name = "Voe"
|
||||||
|
override val mainUrl = "https://voe.sx"
|
||||||
|
override val requiresReferer = true
|
||||||
|
|
||||||
|
override suspend fun getUrl(
|
||||||
|
url: String,
|
||||||
|
referer: String?,
|
||||||
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
|
callback: (ExtractorLink) -> Unit
|
||||||
|
) {
|
||||||
|
val res = app.get(url, referer = referer).document
|
||||||
|
val link = res.select("script").find { it.data().contains("const sources") }?.data()
|
||||||
|
?.substringAfter("\"hls\": \"")?.substringBefore("\",")
|
||||||
|
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
name,
|
||||||
|
link ?: return,
|
||||||
|
"$mainUrl/",
|
||||||
|
headers = mapOf("Origin" to "$mainUrl/")
|
||||||
|
).forEach(callback)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ import com.lagradost.cloudstream3.APIHolder.removePluginMapping
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
|
||||||
import com.lagradost.cloudstream3.mvvm.debugPrint
|
import com.lagradost.cloudstream3.mvvm.debugPrint
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
|
@ -123,6 +124,10 @@ object PluginManager {
|
||||||
val plugins = getPluginsOnline().filter {
|
val plugins = getPluginsOnline().filter {
|
||||||
!it.filePath.contains(repositoryPath)
|
!it.filePath.contains(repositoryPath)
|
||||||
}
|
}
|
||||||
|
val file = File(repositoryPath)
|
||||||
|
normalSafeApiCall {
|
||||||
|
if (file.exists()) file.deleteRecursively()
|
||||||
|
}
|
||||||
setKey(PLUGINS_KEY, plugins)
|
setKey(PLUGINS_KEY, plugins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,8 +179,16 @@ object PluginManager {
|
||||||
val onlineData: Pair<String, SitePlugin>,
|
val onlineData: Pair<String, SitePlugin>,
|
||||||
) {
|
) {
|
||||||
val isOutdated =
|
val isOutdated =
|
||||||
onlineData.second.version != savedData.version || onlineData.second.version == PLUGIN_VERSION_ALWAYS_UPDATE
|
onlineData.second.version > savedData.version || onlineData.second.version == PLUGIN_VERSION_ALWAYS_UPDATE
|
||||||
val isDisabled = onlineData.second.status == PROVIDER_STATUS_DOWN
|
val isDisabled = onlineData.second.status == PROVIDER_STATUS_DOWN
|
||||||
|
|
||||||
|
fun validOnlineData(context: Context): Boolean {
|
||||||
|
return getPluginPath(
|
||||||
|
context,
|
||||||
|
savedData.internalName,
|
||||||
|
onlineData.first
|
||||||
|
).absolutePath == savedData.filePath
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// var allCurrentOutDatedPlugins: Set<OnlinePluginData> = emptySet()
|
// var allCurrentOutDatedPlugins: Set<OnlinePluginData> = emptySet()
|
||||||
|
@ -225,6 +238,8 @@ object PluginManager {
|
||||||
.filter { onlineData -> savedData.internalName == onlineData.second.internalName }
|
.filter { onlineData -> savedData.internalName == onlineData.second.internalName }
|
||||||
.map { onlineData ->
|
.map { onlineData ->
|
||||||
OnlinePluginData(savedData, onlineData)
|
OnlinePluginData(savedData, onlineData)
|
||||||
|
}.filter {
|
||||||
|
it.validOnlineData(activity)
|
||||||
}
|
}
|
||||||
}.flatten().distinctBy { it.onlineData.second.url }
|
}.flatten().distinctBy { it.onlineData.second.url }
|
||||||
|
|
||||||
|
@ -416,6 +431,18 @@ object PluginManager {
|
||||||
) + "." + name.hashCode()
|
) + "." + name.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should not be changed as it is used to also detect if a plugin is installed!
|
||||||
|
**/
|
||||||
|
fun getPluginPath(
|
||||||
|
context: Context,
|
||||||
|
internalName: String,
|
||||||
|
repositoryUrl: String
|
||||||
|
): File {
|
||||||
|
val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique
|
||||||
|
val fileName = getPluginSanitizedFileName(internalName)
|
||||||
|
return File("${context.filesDir}/${ONLINE_PLUGINS_FOLDER}/${folderName}/$fileName.cs3")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for fresh installs
|
* Used for fresh installs
|
||||||
|
@ -426,9 +453,7 @@ object PluginManager {
|
||||||
internalName: String,
|
internalName: String,
|
||||||
repositoryUrl: String
|
repositoryUrl: String
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique
|
val file = getPluginPath(activity, internalName, repositoryUrl)
|
||||||
val fileName = getPluginSanitizedFileName(internalName)
|
|
||||||
val file = File("${activity.filesDir}/${ONLINE_PLUGINS_FOLDER}/${folderName}/$fileName.cs3")
|
|
||||||
downloadAndLoadPlugin(activity, pluginUrl, internalName, file)
|
downloadAndLoadPlugin(activity, pluginUrl, internalName, file)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -454,7 +479,13 @@ object PluginManager {
|
||||||
return loadPlugin(
|
return loadPlugin(
|
||||||
activity,
|
activity,
|
||||||
newFile ?: return false,
|
newFile ?: return false,
|
||||||
PluginData(internalName, pluginUrl, true, newFile.absolutePath, PLUGIN_VERSION_NOT_SET)
|
PluginData(
|
||||||
|
internalName,
|
||||||
|
pluginUrl,
|
||||||
|
true,
|
||||||
|
newFile.absolutePath,
|
||||||
|
PLUGIN_VERSION_NOT_SET
|
||||||
|
)
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
@ -462,18 +493,13 @@ object PluginManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
suspend fun deletePlugin(file: File): Boolean {
|
||||||
* @param isFilePath will treat the pluginUrl as as the filepath instead of url
|
val list = (getPluginsLocal() + getPluginsOnline()).filter { it.filePath == file.absolutePath }
|
||||||
* */
|
|
||||||
suspend fun deletePlugin(pluginIdentifier: String, isFilePath: Boolean): Boolean {
|
|
||||||
val data =
|
|
||||||
(if (isFilePath) (getPluginsLocal() + getPluginsOnline()).firstOrNull { it.filePath == pluginIdentifier }
|
|
||||||
else getPluginsOnline().firstOrNull { it.url == pluginIdentifier }) ?: return false
|
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
if (File(data.filePath).delete()) {
|
if (File(file.absolutePath).delete()) {
|
||||||
unloadPlugin(data.filePath)
|
unloadPlugin(file.absolutePath)
|
||||||
deletePluginData(data)
|
list.forEach { deletePluginData(it) }
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package com.lagradost.cloudstream3.ui
|
package com.lagradost.cloudstream3.ui
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
class APIRepository(val api: MainAPI) {
|
class APIRepository(val api: MainAPI) {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -62,12 +64,39 @@ class APIRepository(val api: MainAPI) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun waitForHomeDelay() {
|
||||||
|
val delta = api.sequentialMainPageScrollDelay + api.lastHomepageRequest - unixTimeMS
|
||||||
|
if (delta < 0) return
|
||||||
|
delay(delta)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun getMainPage(page: Int, nameIndex: Int? = null): Resource<List<HomePageResponse?>> {
|
suspend fun getMainPage(page: Int, nameIndex: Int? = null): Resource<List<HomePageResponse?>> {
|
||||||
return safeApiCall {
|
return safeApiCall {
|
||||||
|
api.lastHomepageRequest = unixTimeMS
|
||||||
|
|
||||||
nameIndex?.let { api.mainPage.getOrNull(it) }?.let { data ->
|
nameIndex?.let { api.mainPage.getOrNull(it) }?.let { data ->
|
||||||
listOf(api.getMainPage(page, MainPageRequest(data.name, data.data)))
|
listOf(api.getMainPage(page, MainPageRequest(data.name, data.data, data.horizontalImages)))
|
||||||
} ?: api.mainPage.apmap { data ->
|
} ?: run {
|
||||||
api.getMainPage(page, MainPageRequest(data.name, data.data))
|
if (api.sequentialMainPage) {
|
||||||
|
var first = true
|
||||||
|
api.mainPage.map { data ->
|
||||||
|
if (!first) // dont want to sleep on first request
|
||||||
|
delay(api.sequentialMainPageDelay)
|
||||||
|
first = false
|
||||||
|
|
||||||
|
api.getMainPage(
|
||||||
|
page,
|
||||||
|
MainPageRequest(data.name, data.data, data.horizontalImages)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
api.mainPage.apmap { data ->
|
||||||
|
api.getMainPage(
|
||||||
|
page,
|
||||||
|
MainPageRequest(data.name, data.data, data.horizontalImages)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -521,16 +521,13 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Disable Random button, if its toggled off on settings
|
//Load value for toggling Random button. Hide at startup
|
||||||
context?.let {
|
context?.let {
|
||||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
|
||||||
toggleRandomButton =
|
toggleRandomButton =
|
||||||
settingsManager.getBoolean(getString(R.string.random_button_key), false)
|
settingsManager.getBoolean(getString(R.string.random_button_key), false)
|
||||||
home_random?.isVisible = toggleRandomButton
|
|
||||||
if (!toggleRandomButton) {
|
|
||||||
home_random?.visibility = View.GONE
|
home_random?.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
observe(homeViewModel.apiName) { apiName ->
|
observe(homeViewModel.apiName) { apiName ->
|
||||||
currentApiName = apiName
|
currentApiName = apiName
|
||||||
|
@ -626,6 +623,7 @@ class HomeFragment : Fragment() {
|
||||||
home_loading_shimmer?.stopShimmer()
|
home_loading_shimmer?.stopShimmer()
|
||||||
|
|
||||||
val d = data.value
|
val d = data.value
|
||||||
|
val mutableListOfResponse = mutableListOf<SearchResponse>()
|
||||||
listHomepageItems.clear()
|
listHomepageItems.clear()
|
||||||
|
|
||||||
// println("ITEMCOUNT: ${d.values.size} ${home_master_recycler?.adapter?.itemCount}")
|
// println("ITEMCOUNT: ${d.values.size} ${home_master_recycler?.adapter?.itemCount}")
|
||||||
|
@ -638,6 +636,11 @@ class HomeFragment : Fragment() {
|
||||||
home_loading_error?.isVisible = false
|
home_loading_error?.isVisible = false
|
||||||
home_loaded?.isVisible = true
|
home_loaded?.isVisible = true
|
||||||
if (toggleRandomButton) {
|
if (toggleRandomButton) {
|
||||||
|
//Flatten list
|
||||||
|
d.values.forEach { dlist ->
|
||||||
|
mutableListOfResponse.addAll(dlist.list.list)
|
||||||
|
}
|
||||||
|
listHomepageItems.addAll(mutableListOfResponse.distinctBy { it.url })
|
||||||
home_random?.isVisible = listHomepageItems.isNotEmpty()
|
home_random?.isVisible = listHomepageItems.isNotEmpty()
|
||||||
} else {
|
} else {
|
||||||
home_random?.isGone = true
|
home_random?.isGone = true
|
||||||
|
|
|
@ -162,6 +162,8 @@ class HomeViewModel : ViewModel() {
|
||||||
lock += name
|
lock += name
|
||||||
|
|
||||||
repo?.apply {
|
repo?.apply {
|
||||||
|
waitForHomeDelay()
|
||||||
|
|
||||||
expandable[name]?.let { current ->
|
expandable[name]?.let { current ->
|
||||||
debugAssert({ !current.hasNext }) {
|
debugAssert({ !current.hasNext }) {
|
||||||
"Expand called when not needed"
|
"Expand called when not needed"
|
||||||
|
@ -276,9 +278,6 @@ class HomeViewModel : ViewModel() {
|
||||||
if (preferredApiName == noneApi.name) {
|
if (preferredApiName == noneApi.name) {
|
||||||
setKey(USER_SELECTED_HOMEPAGE_API, noneApi.name)
|
setKey(USER_SELECTED_HOMEPAGE_API, noneApi.name)
|
||||||
loadAndCancel(noneApi)
|
loadAndCancel(noneApi)
|
||||||
// If the plugin isn't loaded yet. (Does not set the key)
|
|
||||||
} else if (api == null) {
|
|
||||||
loadAndCancel(noneApi)
|
|
||||||
} else if (preferredApiName == randomApi.name) {
|
} else if (preferredApiName == randomApi.name) {
|
||||||
val validAPIs = context?.filterProviderByPreferredMedia()
|
val validAPIs = context?.filterProviderByPreferredMedia()
|
||||||
if (validAPIs.isNullOrEmpty()) {
|
if (validAPIs.isNullOrEmpty()) {
|
||||||
|
@ -289,6 +288,9 @@ class HomeViewModel : ViewModel() {
|
||||||
loadAndCancel(apiRandom)
|
loadAndCancel(apiRandom)
|
||||||
setKey(USER_SELECTED_HOMEPAGE_API, apiRandom.name)
|
setKey(USER_SELECTED_HOMEPAGE_API, apiRandom.name)
|
||||||
}
|
}
|
||||||
|
// If the plugin isn't loaded yet. (Does not set the key)
|
||||||
|
} else if (api == null) {
|
||||||
|
loadAndCancel(noneApi)
|
||||||
} else {
|
} else {
|
||||||
setKey(USER_SELECTED_HOMEPAGE_API, api.name)
|
setKey(USER_SELECTED_HOMEPAGE_API, api.name)
|
||||||
loadAndCancel(api)
|
loadAndCancel(api)
|
||||||
|
|
|
@ -58,6 +58,7 @@ import kotlinx.android.synthetic.main.player_select_source_and_subs.*
|
||||||
import kotlinx.android.synthetic.main.player_select_source_and_subs.subtitles_click_settings
|
import kotlinx.android.synthetic.main.player_select_source_and_subs.subtitles_click_settings
|
||||||
import kotlinx.android.synthetic.main.player_select_tracks.*
|
import kotlinx.android.synthetic.main.player_select_tracks.*
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
class GeneratorPlayer : FullScreenPlayer() {
|
class GeneratorPlayer : FullScreenPlayer() {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -115,10 +116,11 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
|
|
||||||
override fun onTracksInfoChanged() {
|
override fun onTracksInfoChanged() {
|
||||||
val tracks = player.getVideoTracks()
|
val tracks = player.getVideoTracks()
|
||||||
player_tracks_btt?.isVisible = tracks.allVideoTracks.size > 1 || tracks.allAudioTracks.size > 1
|
player_tracks_btt?.isVisible =
|
||||||
|
tracks.allVideoTracks.size > 1 || tracks.allAudioTracks.size > 1
|
||||||
// Only set the preferred language if it is available.
|
// Only set the preferred language if it is available.
|
||||||
// Otherwise it may give some users audio track init failed!
|
// Otherwise it may give some users audio track init failed!
|
||||||
if (tracks.allAudioTracks.any { it.language == preferredAudioTrackLanguage }){
|
if (tracks.allAudioTracks.any { it.language == preferredAudioTrackLanguage }) {
|
||||||
player.setPreferredAudioTrack(preferredAudioTrackLanguage)
|
player.setPreferredAudioTrack(preferredAudioTrackLanguage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -602,9 +604,21 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
subtitleList.setItemChecked(subtitleIndex, true)
|
subtitleList.setItemChecked(subtitleIndex, true)
|
||||||
|
|
||||||
subtitleList.setOnItemClickListener { _, _, which, _ ->
|
subtitleList.setOnItemClickListener { _, _, which, _ ->
|
||||||
|
if (which > currentSubtitles.size) {
|
||||||
|
// Since android TV is funky the setOnItemClickListener will be triggered
|
||||||
|
// instead of setOnClickListener when selecting. To override this we programmatically
|
||||||
|
// click the view when selecting an item outside the list.
|
||||||
|
|
||||||
|
// Cheeky way of getting the view at that position to click it
|
||||||
|
// to avoid keeping track of the various footers.
|
||||||
|
// getChildAt() gives null :(
|
||||||
|
val child = subtitleList.adapter.getView(which, null, subtitleList)
|
||||||
|
child?.performClick()
|
||||||
|
} else {
|
||||||
subtitleIndex = which
|
subtitleIndex = which
|
||||||
subtitleList.setItemChecked(which, true)
|
subtitleList.setItemChecked(which, true)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sourceDialog.cancel_btt?.setOnClickListener {
|
sourceDialog.cancel_btt?.setOnClickListener {
|
||||||
sourceDialog.dismissSafe(activity)
|
sourceDialog.dismissSafe(activity)
|
||||||
|
@ -762,7 +776,8 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||||
// audioArrayAdapter.add(ctx.getString(R.string.no_subtitles))
|
// audioArrayAdapter.add(ctx.getString(R.string.no_subtitles))
|
||||||
audioArrayAdapter.addAll(currentAudioTracks.mapIndexed { index, format ->
|
audioArrayAdapter.addAll(currentAudioTracks.mapIndexed { index, format ->
|
||||||
format.label ?: format.language?.let { fromTwoLettersToLanguage(it) } ?: index.toString()
|
format.label ?: format.language?.let { fromTwoLettersToLanguage(it) }
|
||||||
|
?: index.toString()
|
||||||
})
|
})
|
||||||
|
|
||||||
audioList.adapter = audioArrayAdapter
|
audioList.adapter = audioArrayAdapter
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -9,6 +10,7 @@ import android.widget.TextView
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.ContentLoadingProgressBar
|
import androidx.core.widget.ContentLoadingProgressBar
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
|
@ -53,6 +55,10 @@ const val ACTION_SHOW_DESCRIPTION = 15
|
||||||
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE = 13
|
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE = 13
|
||||||
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14
|
const val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14
|
||||||
|
|
||||||
|
const val ACTION_PLAY_EPISODE_IN_WEB_VIDEO = 16
|
||||||
|
const val ACTION_PLAY_EPISODE_IN_MPV = 17
|
||||||
|
|
||||||
|
|
||||||
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
||||||
|
|
||||||
class EpisodeAdapter(
|
class EpisodeAdapter(
|
||||||
|
@ -60,6 +66,25 @@ class EpisodeAdapter(
|
||||||
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
||||||
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* @return ACTION_PLAY_EPISODE_IN_PLAYER, ACTION_PLAY_EPISODE_IN_BROWSER or ACTION_PLAY_EPISODE_IN_VLC_PLAYER depending on player settings.
|
||||||
|
* See array.xml/player_pref_values
|
||||||
|
**/
|
||||||
|
fun getPlayerAction(context: Context): Int {
|
||||||
|
|
||||||
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
return when (settingsManager.getInt(context.getString(R.string.player_pref_key), 1)) {
|
||||||
|
1 -> ACTION_PLAY_EPISODE_IN_PLAYER
|
||||||
|
2 -> ACTION_PLAY_EPISODE_IN_VLC_PLAYER
|
||||||
|
3 -> ACTION_PLAY_EPISODE_IN_BROWSER
|
||||||
|
4 -> ACTION_PLAY_EPISODE_IN_WEB_VIDEO
|
||||||
|
5 -> ACTION_PLAY_EPISODE_IN_MPV
|
||||||
|
else -> ACTION_PLAY_EPISODE_IN_PLAYER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cardList: MutableList<ResultEpisode> = mutableListOf()
|
var cardList: MutableList<ResultEpisode> = mutableListOf()
|
||||||
|
|
||||||
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
|
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
|
||||||
|
|
|
@ -38,6 +38,7 @@ import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
|
||||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||||
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
|
||||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||||
|
import com.lagradost.cloudstream3.ui.result.EpisodeAdapter.Companion.getPlayerAction
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
@ -455,7 +456,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
val apiName: String,
|
val apiName: String,
|
||||||
val showFillers: Boolean,
|
val showFillers: Boolean,
|
||||||
val dubStatus: DubStatus,
|
val dubStatus: DubStatus,
|
||||||
val start: AutoResume?
|
val start: AutoResume?,
|
||||||
|
val playerAction: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getStoredData(context: Context): StoredData? {
|
private fun getStoredData(context: Context): StoredData? {
|
||||||
|
@ -469,6 +471,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
) DubStatus.Dubbed else DubStatus.Subbed
|
) DubStatus.Dubbed else DubStatus.Subbed
|
||||||
val startAction = arguments?.getInt(START_ACTION_BUNDLE)
|
val startAction = arguments?.getInt(START_ACTION_BUNDLE)
|
||||||
|
|
||||||
|
val playerAction = getPlayerAction(context)
|
||||||
|
|
||||||
val start = startAction?.let { action ->
|
val start = startAction?.let { action ->
|
||||||
val startValue = arguments?.getInt(START_VALUE_BUNDLE)
|
val startValue = arguments?.getInt(START_VALUE_BUNDLE)
|
||||||
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
|
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
|
||||||
|
@ -483,7 +487,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
season = resumeSeason
|
season = resumeSeason
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return StoredData(url, apiName, showFillers, dubStatus, start)
|
return StoredData(url, apiName, showFillers, dubStatus, start, playerAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadViewModel(success: Boolean = false) {
|
private fun reloadViewModel(success: Boolean = false) {
|
||||||
|
@ -774,7 +778,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
||||||
viewModel.handleAction(
|
viewModel.handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(
|
EpisodeClickEvent(
|
||||||
ACTION_PLAY_EPISODE_IN_PLAYER, value.result
|
storedData?.playerAction ?: ACTION_PLAY_EPISODE_IN_PLAYER,
|
||||||
|
value.result
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
package com.lagradost.cloudstream3.ui.result
|
package com.lagradost.cloudstream3.ui.result
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ClipData
|
import android.content.*
|
||||||
import android.content.ClipboardManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
@ -16,6 +15,7 @@ import androidx.lifecycle.viewModelScope
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.APIHolder.getId
|
import com.lagradost.cloudstream3.APIHolder.getId
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTime
|
import com.lagradost.cloudstream3.APIHolder.unixTime
|
||||||
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
import com.lagradost.cloudstream3.CommonActivity.getCastSession
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
@ -33,6 +33,7 @@ import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
|
||||||
import com.lagradost.cloudstream3.ui.player.IGenerator
|
import com.lagradost.cloudstream3.ui.player.IGenerator
|
||||||
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
|
||||||
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
import com.lagradost.cloudstream3.ui.player.SubtitleData
|
||||||
|
import com.lagradost.cloudstream3.ui.result.EpisodeAdapter.Companion.getPlayerAction
|
||||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
||||||
import com.lagradost.cloudstream3.utils.*
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||||
|
@ -43,7 +44,6 @@ import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWork
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDub
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultEpisode
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultEpisode
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason
|
||||||
|
@ -52,9 +52,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setDub
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setDub
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultEpisode
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultEpisode
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason
|
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
|
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.Math.abs
|
import java.lang.Math.abs
|
||||||
|
@ -615,7 +613,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
|
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
|
||||||
|
|
||||||
// SET VISUAL KEYS
|
// SET VISUAL KEYS
|
||||||
AcraApplication.setKey(
|
setKey(
|
||||||
DOWNLOAD_HEADER_CACHE,
|
DOWNLOAD_HEADER_CACHE,
|
||||||
parentId.toString(),
|
parentId.toString(),
|
||||||
VideoDownloadHelper.DownloadHeaderCached(
|
VideoDownloadHelper.DownloadHeaderCached(
|
||||||
|
@ -629,7 +627,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
AcraApplication.setKey(
|
setKey(
|
||||||
DataStore.getFolderName(
|
DataStore.getFolderName(
|
||||||
DOWNLOAD_EPISODE_CACHE,
|
DOWNLOAD_EPISODE_CACHE,
|
||||||
parentId.toString()
|
parentId.toString()
|
||||||
|
@ -956,71 +954,156 @@ class ResultViewModel2 : ViewModel() {
|
||||||
return LinkLoadingResult(sortUrls(links), sortSubs(subs))
|
return LinkLoadingResult(sortUrls(links), sortSubs(subs))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun playWithVlc(act: Activity?, data: LinkLoadingResult, id: Int) = ioSafe {
|
private fun launchActivity(
|
||||||
if (act == null) return@ioSafe
|
activity: Activity?,
|
||||||
if (data.links.isEmpty()) {
|
resumeApp: ResultResume,
|
||||||
showToast(act, R.string.no_links_found_toast, Toast.LENGTH_SHORT)
|
id: Int? = null,
|
||||||
return@ioSafe
|
work: suspend (Intent.(Activity) -> Unit)
|
||||||
}
|
): Job? {
|
||||||
|
val act = activity ?: return null
|
||||||
|
return CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
if (!act.checkWrite()) {
|
resumeApp.launch(id) {
|
||||||
act.requestRW()
|
work(act)
|
||||||
if (act.checkWrite()) return@ioSafe
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
logError(t)
|
||||||
|
main {
|
||||||
|
if (t is ActivityNotFoundException) {
|
||||||
|
showToast(activity, txt(R.string.app_not_found_error), Toast.LENGTH_LONG)
|
||||||
|
} else {
|
||||||
|
showToast(activity, t.toString(), Toast.LENGTH_LONG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun playInWebVideo(
|
||||||
|
activity: Activity?,
|
||||||
|
link: ExtractorLink,
|
||||||
|
title: String?,
|
||||||
|
posterUrl: String?,
|
||||||
|
subtitles: List<SubtitleData>
|
||||||
|
) = launchActivity(activity, WEB_VIDEO) {
|
||||||
|
setDataAndType(Uri.parse(link.url), "video/*")
|
||||||
|
|
||||||
|
putExtra("subs", subtitles.map { it.url.toUri() }.toTypedArray())
|
||||||
|
title?.let { putExtra("title", title) }
|
||||||
|
posterUrl?.let { putExtra("poster", posterUrl) }
|
||||||
|
val headers = Bundle().apply {
|
||||||
|
if (link.referer.isNotBlank())
|
||||||
|
putString("Referer", link.referer)
|
||||||
|
putString("User-Agent", USER_AGENT)
|
||||||
|
for ((key, value) in link.headers) {
|
||||||
|
putString(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putExtra("android.media.intent.extra.HTTP_HEADERS", headers)
|
||||||
|
putExtra("secure_uri", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun playWithMpv(
|
||||||
|
activity: Activity?,
|
||||||
|
id: Int,
|
||||||
|
link: ExtractorLink,
|
||||||
|
subtitles: List<SubtitleData>,
|
||||||
|
resume: Boolean = true,
|
||||||
|
) = launchActivity(activity, MPV, id) {
|
||||||
|
putExtra("subs", subtitles.map { it.url.toUri() }.toTypedArray())
|
||||||
|
putExtra("subs.name", subtitles.map { it.name }.toTypedArray())
|
||||||
|
putExtra("subs.filename", subtitles.map { it.name }.toTypedArray())
|
||||||
|
setDataAndType(Uri.parse(link.url), "video/*")
|
||||||
|
component = MPV_COMPONENT
|
||||||
|
putExtra("secure_uri", true)
|
||||||
|
putExtra("return_result", true)
|
||||||
|
val position = getViewPos(id)?.position
|
||||||
|
if (resume && position != null)
|
||||||
|
putExtra("position", position.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://wiki.videolan.org/Android_Player_Intents/
|
||||||
|
private fun playWithVlc(
|
||||||
|
activity: Activity?,
|
||||||
|
data: LinkLoadingResult,
|
||||||
|
id: Int,
|
||||||
|
resume: Boolean = true,
|
||||||
|
// if it is only a single link then resume works correctly
|
||||||
|
singleFile: Boolean? = null
|
||||||
|
) = launchActivity(activity, VLC, id) { act ->
|
||||||
|
addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||||
|
|
||||||
val outputDir = act.cacheDir
|
val outputDir = act.cacheDir
|
||||||
val outputFile = withContext(Dispatchers.IO) {
|
|
||||||
File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
if (singleFile ?: (data.links.size == 1)) {
|
||||||
}
|
setDataAndType(data.links.first().url.toUri(), "video/*")
|
||||||
|
} else {
|
||||||
|
val outputFile = File.createTempFile("mirrorlist", ".m3u8", outputDir)
|
||||||
|
|
||||||
var text = "#EXTM3U"
|
var text = "#EXTM3U"
|
||||||
for (sub in data.subs) {
|
|
||||||
text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.name}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.name}\",URI=\"${sub.url}\""
|
// With subtitles it doesn't work for no reason :(
|
||||||
}
|
// for (sub in data.subs) {
|
||||||
|
// text += "\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"subs\",NAME=\"${sub.name}\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\"${sub.name}\",URI=\"${sub.url}\""
|
||||||
|
// }
|
||||||
for (link in data.links) {
|
for (link in data.links) {
|
||||||
text += "\n#EXTINF:, ${link.name}\n${link.url}"
|
text += "\n#EXTINF:, ${link.name}\n${link.url}"
|
||||||
}
|
}
|
||||||
outputFile.writeText(text)
|
outputFile.writeText(text)
|
||||||
|
|
||||||
val vlcIntent = Intent(VLC_INTENT_ACTION_RESULT)
|
setDataAndType(
|
||||||
|
|
||||||
vlcIntent.setPackage(VLC_PACKAGE)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
vlcIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
|
||||||
|
|
||||||
vlcIntent.setDataAndType(
|
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
act,
|
act,
|
||||||
act.applicationContext.packageName + ".provider",
|
act.applicationContext.packageName + ".provider",
|
||||||
outputFile
|
outputFile
|
||||||
), "video/*"
|
), "video/*"
|
||||||
)
|
)
|
||||||
|
|
||||||
val startId = VLC_FROM_PROGRESS
|
|
||||||
|
|
||||||
var position = startId
|
|
||||||
if (startId == VLC_FROM_START) {
|
|
||||||
position = 1
|
|
||||||
} else if (startId == VLC_FROM_PROGRESS) {
|
|
||||||
position = 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vlcIntent.putExtra("position", position)
|
val position = if (resume) {
|
||||||
|
getViewPos(id)?.position ?: 0L
|
||||||
vlcIntent.component = VLC_COMPONENT
|
} else {
|
||||||
act.setKey(VLC_LAST_ID_KEY, id)
|
1L
|
||||||
act.startActivityForResult(vlcIntent, VLC_REQUEST_CODE)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError(e)
|
|
||||||
showToast(act, e.toString(), Toast.LENGTH_LONG)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleAction(activity: Activity?, click: EpisodeClickEvent) = viewModelScope.launchSafe {
|
component = VLC_COMPONENT
|
||||||
|
|
||||||
|
putExtra("from_start", !resume)
|
||||||
|
putExtra("position", position)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun handleAction(activity: Activity?, click: EpisodeClickEvent) =
|
||||||
|
viewModelScope.launchSafe {
|
||||||
handleEpisodeClickEvent(activity, click)
|
handleEpisodeClickEvent(activity, click)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ExternalApp(
|
||||||
|
val packageString: String,
|
||||||
|
val name: Int,
|
||||||
|
val action: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val apps = listOf(
|
||||||
|
ExternalApp(
|
||||||
|
VLC_PACKAGE,
|
||||||
|
R.string.player_settings_play_in_vlc,
|
||||||
|
ACTION_PLAY_EPISODE_IN_VLC_PLAYER
|
||||||
|
), ExternalApp(
|
||||||
|
WEB_VIDEO_CAST_PACKAGE,
|
||||||
|
R.string.player_settings_play_in_web,
|
||||||
|
ACTION_PLAY_EPISODE_IN_WEB_VIDEO
|
||||||
|
),
|
||||||
|
ExternalApp(
|
||||||
|
MPV_PACKAGE,
|
||||||
|
R.string.player_settings_play_in_mpv,
|
||||||
|
ACTION_PLAY_EPISODE_IN_MPV
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private suspend fun handleEpisodeClickEvent(activity: Activity?, click: EpisodeClickEvent) {
|
private suspend fun handleEpisodeClickEvent(activity: Activity?, click: EpisodeClickEvent) {
|
||||||
when (click.action) {
|
when (click.action) {
|
||||||
ACTION_SHOW_OPTIONS -> {
|
ACTION_SHOW_OPTIONS -> {
|
||||||
|
@ -1035,9 +1118,17 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
options.add(txt(R.string.episode_action_play_in_app) to ACTION_PLAY_EPISODE_IN_PLAYER)
|
options.add(txt(R.string.episode_action_play_in_app) to ACTION_PLAY_EPISODE_IN_PLAYER)
|
||||||
|
|
||||||
if (activity?.isAppInstalled(VLC_PACKAGE) == true) {
|
for (app in apps) {
|
||||||
options.add(txt(R.string.episode_action_play_in_vlc) to ACTION_PLAY_EPISODE_IN_VLC_PLAYER)
|
if (activity?.isAppInstalled(app.packageString) == true) {
|
||||||
|
options.add(
|
||||||
|
txt(
|
||||||
|
R.string.episode_action_play_in_format,
|
||||||
|
txt(app.name)
|
||||||
|
) to app.action
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
options.addAll(
|
options.addAll(
|
||||||
listOf(
|
listOf(
|
||||||
txt(R.string.episode_action_play_in_browser) to ACTION_PLAY_EPISODE_IN_BROWSER,
|
txt(R.string.episode_action_play_in_browser) to ACTION_PLAY_EPISODE_IN_BROWSER,
|
||||||
|
@ -1073,9 +1164,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
click.copy(action = ACTION_CHROME_CAST_EPISODE)
|
click.copy(action = ACTION_CHROME_CAST_EPISODE)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
val action = getPlayerAction(ctx)
|
||||||
handleEpisodeClickEvent(
|
handleEpisodeClickEvent(
|
||||||
activity,
|
activity,
|
||||||
click.copy(action = ACTION_PLAY_EPISODE_IN_PLAYER)
|
click.copy(action = action)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1212,6 +1304,11 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}
|
}
|
||||||
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> {
|
ACTION_PLAY_EPISODE_IN_VLC_PLAYER -> {
|
||||||
loadLinks(click.data, isVisible = true, isCasting = true) { links ->
|
loadLinks(click.data, isVisible = true, isCasting = true) { links ->
|
||||||
|
if (links.links.isEmpty()) {
|
||||||
|
showToast(activity, R.string.no_links_found_toast, Toast.LENGTH_SHORT)
|
||||||
|
return@loadLinks
|
||||||
|
}
|
||||||
|
|
||||||
playWithVlc(
|
playWithVlc(
|
||||||
activity,
|
activity,
|
||||||
links,
|
links,
|
||||||
|
@ -1219,6 +1316,37 @@ class ResultViewModel2 : ViewModel() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ACTION_PLAY_EPISODE_IN_WEB_VIDEO -> acquireSingleLink(
|
||||||
|
click.data,
|
||||||
|
isCasting = true,
|
||||||
|
txt(
|
||||||
|
R.string.episode_action_play_in_format,
|
||||||
|
txt(R.string.player_settings_play_in_web)
|
||||||
|
)
|
||||||
|
) { (result, index) ->
|
||||||
|
playInWebVideo(
|
||||||
|
activity,
|
||||||
|
result.links[index],
|
||||||
|
click.data.name ?: click.data.headerName,
|
||||||
|
click.data.poster,
|
||||||
|
result.subs
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ACTION_PLAY_EPISODE_IN_MPV -> acquireSingleLink(
|
||||||
|
click.data,
|
||||||
|
isCasting = true,
|
||||||
|
txt(
|
||||||
|
R.string.episode_action_play_in_format,
|
||||||
|
txt(R.string.player_settings_play_in_mpv)
|
||||||
|
)
|
||||||
|
) { (result, index) ->
|
||||||
|
playWithMpv(
|
||||||
|
activity,
|
||||||
|
click.data.id,
|
||||||
|
result.links[index],
|
||||||
|
result.subs
|
||||||
|
)
|
||||||
|
}
|
||||||
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
ACTION_PLAY_EPISODE_IN_PLAYER -> {
|
||||||
val data = currentResponse?.syncData?.toList() ?: emptyList()
|
val data = currentResponse?.syncData?.toList() ?: emptyList()
|
||||||
val list =
|
val list =
|
||||||
|
@ -1284,7 +1412,11 @@ class ResultViewModel2 : ViewModel() {
|
||||||
}, {
|
}, {
|
||||||
if (this !is AnimeLoadResponse) return@argamap
|
if (this !is AnimeLoadResponse) return@argamap
|
||||||
val map =
|
val map =
|
||||||
Kitsu.getEpisodesDetails(getMalId(), getAniListId(), isResponseRequired = false)
|
Kitsu.getEpisodesDetails(
|
||||||
|
getMalId(),
|
||||||
|
getAniListId(),
|
||||||
|
isResponseRequired = false
|
||||||
|
)
|
||||||
if (map.isNullOrEmpty()) return@argamap
|
if (map.isNullOrEmpty()) return@argamap
|
||||||
updateEpisodes = DubStatus.values().map { dubStatus ->
|
updateEpisodes = DubStatus.values().map { dubStatus ->
|
||||||
val current =
|
val current =
|
||||||
|
@ -1304,8 +1436,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
val currentBack = this
|
val currentBack = this
|
||||||
this.description = this.description ?: node.description?.en
|
this.description = this.description ?: node.description?.en
|
||||||
this.name = this.name ?: node.titles?.canonical
|
this.name = this.name ?: node.titles?.canonical
|
||||||
this.episode = this.episode ?: node.num ?: episodeNumbers[index]
|
this.episode =
|
||||||
this.posterUrl = this.posterUrl ?: node.thumbnail?.original?.url
|
this.episode ?: node.num ?: episodeNumbers[index]
|
||||||
|
this.posterUrl =
|
||||||
|
this.posterUrl ?: node.thumbnail?.original?.url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1592,7 +1726,9 @@ class ResultViewModel2 : ViewModel() {
|
||||||
val idIndex = ep.key.id
|
val idIndex = ep.key.id
|
||||||
for ((index, i) in ep.value.withIndex()) {
|
for ((index, i) in ep.value.withIndex()) {
|
||||||
val episode = i.episode ?: (index + 1)
|
val episode = i.episode ?: (index + 1)
|
||||||
val id = mainId + episode + idIndex * 1_000_000 + (i.season?.times(10_000) ?: 0)
|
val id =
|
||||||
|
mainId + episode + idIndex * 1_000_000 + (i.season?.times(10_000)
|
||||||
|
?: 0)
|
||||||
if (!existingEpisodes.contains(id)) {
|
if (!existingEpisodes.contains(id)) {
|
||||||
existingEpisodes.add(id)
|
existingEpisodes.add(id)
|
||||||
val seasonData = loadResponse.seasonNames.getSeason(i.season)
|
val seasonData = loadResponse.seasonNames.getSeason(i.season)
|
||||||
|
@ -1888,7 +2024,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
if (ep.getWatchProgress() > 0.9) continue
|
if (ep.getWatchProgress() > 0.9) continue
|
||||||
handleAction(
|
handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep)
|
EpisodeClickEvent(
|
||||||
|
getPlayerAction(activity),
|
||||||
|
ep
|
||||||
|
)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -1905,7 +2044,10 @@ class ResultViewModel2 : ViewModel() {
|
||||||
?: return@launchSafe
|
?: return@launchSafe
|
||||||
handleAction(
|
handleAction(
|
||||||
activity,
|
activity,
|
||||||
EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, episode)
|
EpisodeClickEvent(
|
||||||
|
getPlayerAction(activity),
|
||||||
|
episode
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1983,7 +2125,7 @@ class ResultViewModel2 : ViewModel() {
|
||||||
preferStartEpisode = getResultEpisode(mainId)
|
preferStartEpisode = getResultEpisode(mainId)
|
||||||
preferStartSeason = getResultSeason(mainId)
|
preferStartSeason = getResultSeason(mainId)
|
||||||
|
|
||||||
AcraApplication.setKey(
|
setKey(
|
||||||
DOWNLOAD_HEADER_CACHE,
|
DOWNLOAD_HEADER_CACHE,
|
||||||
mainId.toString(),
|
mainId.toString(),
|
||||||
VideoDownloadHelper.DownloadHeaderCached(
|
VideoDownloadHelper.DownloadHeaderCached(
|
||||||
|
|
|
@ -113,6 +113,22 @@ class SettingsPlayer : PreferenceFragmentCompat() {
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPref(R.string.player_pref_key)?.setOnPreferenceClickListener {
|
||||||
|
val prefNames = resources.getStringArray(R.array.player_pref_names)
|
||||||
|
val prefValues = resources.getIntArray(R.array.player_pref_values)
|
||||||
|
val current = settingsManager.getInt(getString(R.string.player_pref_key), 1)
|
||||||
|
|
||||||
|
activity?.showBottomDialog(
|
||||||
|
prefNames.toList(),
|
||||||
|
prefValues.indexOf(current),
|
||||||
|
getString(R.string.player_pref),
|
||||||
|
true,
|
||||||
|
{}) {
|
||||||
|
settingsManager.edit().putInt(getString(R.string.player_pref_key), prefValues[it]).apply()
|
||||||
|
}
|
||||||
|
return@setOnPreferenceClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
getPref(R.string.subtitle_settings_key)?.setOnPreferenceClickListener {
|
getPref(R.string.subtitle_settings_key)?.setOnPreferenceClickListener {
|
||||||
SubtitlesFragment.push(activity, false)
|
SubtitlesFragment.push(activity, false)
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
|
|
|
@ -16,7 +16,6 @@ import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
|
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
@ -25,7 +24,6 @@ import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||||
import com.lagradost.cloudstream3.ui.result.setText
|
import com.lagradost.cloudstream3.ui.result.setText
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.downloadAllPluginsDialog
|
import com.lagradost.cloudstream3.utils.AppUtils.downloadAllPluginsDialog
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
|
@ -34,7 +32,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
import com.lagradost.cloudstream3.widget.LinearRecycleViewLayoutManager
|
import com.lagradost.cloudstream3.widget.LinearRecycleViewLayoutManager
|
||||||
import kotlinx.android.synthetic.main.add_repo_input.*
|
import kotlinx.android.synthetic.main.add_repo_input.*
|
||||||
import kotlinx.android.synthetic.main.fragment_extensions.*
|
import kotlinx.android.synthetic.main.fragment_extensions.*
|
||||||
import kotlinx.android.synthetic.main.fragment_extensions.list_repositories
|
|
||||||
|
|
||||||
const val PUBLIC_REPOSITORIES_LIST = "https://recloudstream.github.io/repos/"
|
const val PUBLIC_REPOSITORIES_LIST = "https://recloudstream.github.io/repos/"
|
||||||
|
|
||||||
|
@ -128,20 +125,20 @@ class ExtensionsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list_repositories?.setOnClickListener {
|
// list_repositories?.setOnClickListener {
|
||||||
// Open webview on tv if browser fails
|
// // Open webview on tv if browser fails
|
||||||
val isTv = isTvSettings()
|
// val isTv = isTvSettings()
|
||||||
openBrowser(PUBLIC_REPOSITORIES_LIST, isTv, this)
|
// openBrowser(PUBLIC_REPOSITORIES_LIST, isTv, this)
|
||||||
|
//
|
||||||
// Set clipboard on TV because the browser might not exist or work properly
|
// // Set clipboard on TV because the browser might not exist or work properly
|
||||||
if (isTv) {
|
// if (isTv) {
|
||||||
val serviceClipboard =
|
// val serviceClipboard =
|
||||||
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?)
|
// (activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?)
|
||||||
?: return@setOnClickListener
|
// ?: return@setOnClickListener
|
||||||
val clip = ClipData.newPlainText("Repository url", PUBLIC_REPOSITORIES_LIST)
|
// val clip = ClipData.newPlainText("Repository url", PUBLIC_REPOSITORIES_LIST)
|
||||||
serviceClipboard.setPrimaryClip(clip)
|
// serviceClipboard.setPrimaryClip(clip)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
observe(extensionViewModel.pluginStats) {
|
observe(extensionViewModel.pluginStats) {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -200,11 +197,11 @@ class ExtensionsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.list_repositories?.setOnClickListener {
|
// dialog.list_repositories?.setOnClickListener {
|
||||||
// Open webview on tv if browser fails
|
// // Open webview on tv if browser fails
|
||||||
openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)
|
// openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)
|
||||||
dialog.dismissSafe()
|
// dialog.dismissSafe()
|
||||||
}
|
// }
|
||||||
|
|
||||||
// dialog.text2?.text = provider.name
|
// dialog.text2?.text = provider.name
|
||||||
dialog.apply_btt?.setOnClickListener secondListener@{
|
dialog.apply_btt?.setOnClickListener secondListener@{
|
||||||
|
@ -235,6 +232,11 @@ class ExtensionsFragment : Fragment() {
|
||||||
val isTv = isTrueTvSettings()
|
val isTv = isTrueTvSettings()
|
||||||
add_repo_button?.isGone = isTv
|
add_repo_button?.isGone = isTv
|
||||||
add_repo_button_imageview_holder?.isVisible = isTv
|
add_repo_button_imageview_holder?.isVisible = isTv
|
||||||
|
|
||||||
|
// Band-aid for Fire TV
|
||||||
|
plugin_storage_appbar?.isFocusableInTouchMode = isTv
|
||||||
|
add_repo_button_imageview?.isFocusableInTouchMode = isTv
|
||||||
|
|
||||||
add_repo_button?.setOnClickListener(addRepositoryClick)
|
add_repo_button?.setOnClickListener(addRepositoryClick)
|
||||||
add_repo_button_imageview?.setOnClickListener(addRepositoryClick)
|
add_repo_button_imageview?.setOnClickListener(addRepositoryClick)
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ class PluginsFragment : Fragment() {
|
||||||
pluginViewModel.updatePluginListLocal()
|
pluginViewModel.updatePluginListLocal()
|
||||||
tv_types_scroll_view?.isVisible = false
|
tv_types_scroll_view?.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
pluginViewModel.updatePluginList(url)
|
pluginViewModel.updatePluginList(context, url)
|
||||||
tv_types_scroll_view?.isVisible = true
|
tv_types_scroll_view?.isVisible = true
|
||||||
|
|
||||||
// 💀💀💀💀💀💀💀 Recyclerview when
|
// 💀💀💀💀💀💀💀 Recyclerview when
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.lagradost.cloudstream3.ui.settings.extensions
|
package com.lagradost.cloudstream3.ui.settings.extensions
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
|
@ -11,16 +12,16 @@ import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.apmap
|
import com.lagradost.cloudstream3.apmap
|
||||||
import com.lagradost.cloudstream3.mvvm.launchSafe
|
import com.lagradost.cloudstream3.mvvm.launchSafe
|
||||||
import com.lagradost.cloudstream3.plugins.PluginData
|
|
||||||
import com.lagradost.cloudstream3.plugins.PluginManager
|
import com.lagradost.cloudstream3.plugins.PluginManager
|
||||||
|
import com.lagradost.cloudstream3.plugins.PluginManager.getPluginPath
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||||
import com.lagradost.cloudstream3.plugins.SitePlugin
|
import com.lagradost.cloudstream3.plugins.SitePlugin
|
||||||
import com.lagradost.cloudstream3.ui.result.txt
|
import com.lagradost.cloudstream3.ui.result.txt
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
|
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import me.xdrop.fuzzywuzzy.FuzzySearch
|
import me.xdrop.fuzzywuzzy.FuzzySearch
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
typealias Plugin = Pair<String, SitePlugin>
|
typealias Plugin = Pair<String, SitePlugin>
|
||||||
/**
|
/**
|
||||||
|
@ -45,8 +46,12 @@ class PluginsViewModel : ViewModel() {
|
||||||
private val repositoryCache: MutableMap<String, List<Plugin>> = mutableMapOf()
|
private val repositoryCache: MutableMap<String, List<Plugin>> = mutableMapOf()
|
||||||
const val TAG = "PLG"
|
const val TAG = "PLG"
|
||||||
|
|
||||||
private fun isDownloaded(plugin: Plugin, data: Set<String>? = null): Boolean {
|
private fun isDownloaded(
|
||||||
return (data ?: getDownloads()).contains(plugin.second.internalName)
|
context: Context,
|
||||||
|
pluginName: String,
|
||||||
|
repositoryUrl: String
|
||||||
|
): Boolean {
|
||||||
|
return getPluginPath(context, pluginName, repositoryUrl).exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getPlugins(
|
private suspend fun getPlugins(
|
||||||
|
@ -63,24 +68,21 @@ class PluginsViewModel : ViewModel() {
|
||||||
?.also { repositoryCache[repositoryUrl] = it } ?: emptyList()
|
?.also { repositoryCache[repositoryUrl] = it } ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStoredPlugins(): Array<PluginData> {
|
|
||||||
return PluginManager.getPluginsOnline()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDownloads(): Set<String> {
|
|
||||||
return getStoredPlugins().map { it.internalName }.toSet()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param viewModel optional, updates the plugins livedata for that viewModel if included
|
* @param viewModel optional, updates the plugins livedata for that viewModel if included
|
||||||
* */
|
* */
|
||||||
fun downloadAll(activity: Activity?, repositoryUrl: String, viewModel: PluginsViewModel?) =
|
fun downloadAll(activity: Activity?, repositoryUrl: String, viewModel: PluginsViewModel?) =
|
||||||
ioSafe {
|
ioSafe {
|
||||||
if (activity == null) return@ioSafe
|
if (activity == null) return@ioSafe
|
||||||
val stored = getDownloads()
|
|
||||||
val plugins = getPlugins(repositoryUrl)
|
val plugins = getPlugins(repositoryUrl)
|
||||||
|
|
||||||
plugins.filter { plugin -> !isDownloaded(plugin, stored) }.also { list ->
|
plugins.filter { plugin ->
|
||||||
|
!isDownloaded(
|
||||||
|
activity,
|
||||||
|
plugin.second.internalName,
|
||||||
|
repositoryUrl
|
||||||
|
)
|
||||||
|
}.also { list ->
|
||||||
main {
|
main {
|
||||||
showToast(
|
showToast(
|
||||||
activity,
|
activity,
|
||||||
|
@ -103,7 +105,7 @@ class PluginsViewModel : ViewModel() {
|
||||||
PluginManager.downloadAndLoadPlugin(
|
PluginManager.downloadAndLoadPlugin(
|
||||||
activity,
|
activity,
|
||||||
metadata.url,
|
metadata.url,
|
||||||
metadata.name,
|
metadata.internalName,
|
||||||
repo
|
repo
|
||||||
)
|
)
|
||||||
}.main { list ->
|
}.main { list ->
|
||||||
|
@ -117,7 +119,7 @@ class PluginsViewModel : ViewModel() {
|
||||||
),
|
),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
)
|
)
|
||||||
viewModel?.updatePluginListPrivate(repositoryUrl)
|
viewModel?.updatePluginListPrivate(activity, repositoryUrl)
|
||||||
} else if (list.isNotEmpty()) {
|
} else if (list.isNotEmpty()) {
|
||||||
showToast(activity, R.string.download_failed, Toast.LENGTH_SHORT)
|
showToast(activity, R.string.download_failed, Toast.LENGTH_SHORT)
|
||||||
}
|
}
|
||||||
|
@ -140,11 +142,14 @@ class PluginsViewModel : ViewModel() {
|
||||||
if (activity == null) return@ioSafe
|
if (activity == null) return@ioSafe
|
||||||
val (repo, metadata) = plugin
|
val (repo, metadata) = plugin
|
||||||
|
|
||||||
val (success, message) = if (isDownloaded(plugin) || isLocal) {
|
val file = if (isLocal) File(plugin.second.url) else getPluginPath(
|
||||||
PluginManager.deletePlugin(
|
activity,
|
||||||
metadata.url,
|
plugin.second.internalName,
|
||||||
isLocal
|
plugin.first
|
||||||
) to R.string.plugin_deleted
|
)
|
||||||
|
|
||||||
|
val (success, message) = if (file.exists()) {
|
||||||
|
PluginManager.deletePlugin(file) to R.string.plugin_deleted
|
||||||
} else {
|
} else {
|
||||||
PluginManager.downloadAndLoadPlugin(
|
PluginManager.downloadAndLoadPlugin(
|
||||||
activity,
|
activity,
|
||||||
|
@ -165,18 +170,19 @@ class PluginsViewModel : ViewModel() {
|
||||||
if (isLocal)
|
if (isLocal)
|
||||||
updatePluginListLocal()
|
updatePluginListLocal()
|
||||||
else
|
else
|
||||||
updatePluginListPrivate(repositoryUrl)
|
updatePluginListPrivate(activity, repositoryUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun updatePluginListPrivate(repositoryUrl: String) {
|
private suspend fun updatePluginListPrivate(context: Context, repositoryUrl: String) {
|
||||||
val stored = getDownloads()
|
|
||||||
val plugins = getPlugins(repositoryUrl)
|
val plugins = getPlugins(repositoryUrl)
|
||||||
val list = plugins.map { plugin ->
|
val list = plugins.map { plugin ->
|
||||||
PluginViewData(plugin, isDownloaded(plugin, stored))
|
PluginViewData(plugin, isDownloaded(context, plugin.second.internalName, plugin.first))
|
||||||
}
|
}
|
||||||
|
|
||||||
this.plugins = list
|
this.plugins = list
|
||||||
_filteredPlugins.postValue(false to list.filterTvTypes().filterLang().sortByQuery(currentQuery))
|
_filteredPlugins.postValue(
|
||||||
|
false to list.filterTvTypes().filterLang().sortByQuery(currentQuery)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perhaps can be optimized?
|
// Perhaps can be optimized?
|
||||||
|
@ -184,7 +190,8 @@ class PluginsViewModel : ViewModel() {
|
||||||
if (tvTypes.isEmpty()) return this
|
if (tvTypes.isEmpty()) return this
|
||||||
return this.filter {
|
return this.filter {
|
||||||
(it.plugin.second.tvTypes?.any { type -> tvTypes.contains(type) } == true) ||
|
(it.plugin.second.tvTypes?.any { type -> tvTypes.contains(type) } == true) ||
|
||||||
(tvTypes.contains("Others") && (it.plugin.second.tvTypes ?: emptyList()).isEmpty())
|
(tvTypes.contains("Others") && (it.plugin.second.tvTypes
|
||||||
|
?: emptyList()).isEmpty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,17 +215,22 @@ class PluginsViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateFilteredPlugins() {
|
fun updateFilteredPlugins() {
|
||||||
_filteredPlugins.postValue(false to plugins.filterTvTypes().filterLang().sortByQuery(currentQuery))
|
_filteredPlugins.postValue(
|
||||||
|
false to plugins.filterTvTypes().filterLang().sortByQuery(currentQuery)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updatePluginList(repositoryUrl: String) = viewModelScope.launchSafe {
|
fun updatePluginList(context: Context?, repositoryUrl: String) = viewModelScope.launchSafe {
|
||||||
|
if (context == null) return@launchSafe
|
||||||
Log.i(TAG, "updatePluginList = $repositoryUrl")
|
Log.i(TAG, "updatePluginList = $repositoryUrl")
|
||||||
updatePluginListPrivate(repositoryUrl)
|
updatePluginListPrivate(context, repositoryUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(query: String?) {
|
fun search(query: String?) {
|
||||||
currentQuery = query
|
currentQuery = query
|
||||||
_filteredPlugins.postValue(true to (filteredPlugins.value?.second?.sortByQuery(query) ?: emptyList()))
|
_filteredPlugins.postValue(
|
||||||
|
true to (filteredPlugins.value?.second?.sortByQuery(query) ?: emptyList())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -234,6 +246,8 @@ class PluginsViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins = downloadedPlugins
|
plugins = downloadedPlugins
|
||||||
_filteredPlugins.postValue(false to downloadedPlugins.filterTvTypes().filterLang().sortByQuery(currentQuery))
|
_filteredPlugins.postValue(
|
||||||
|
false to downloadedPlugins.filterTvTypes().filterLang().sortByQuery(currentQuery)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,21 +7,16 @@ import android.view.ViewGroup
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
|
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
import com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
import com.lagradost.cloudstream3.plugins.RepositoryManager
|
||||||
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
|
||||||
import com.lagradost.cloudstream3.ui.settings.extensions.PUBLIC_REPOSITORIES_LIST
|
|
||||||
import com.lagradost.cloudstream3.ui.settings.extensions.PluginsViewModel
|
import com.lagradost.cloudstream3.ui.settings.extensions.PluginsViewModel
|
||||||
import com.lagradost.cloudstream3.ui.settings.extensions.RepoAdapter
|
import com.lagradost.cloudstream3.ui.settings.extensions.RepoAdapter
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
||||||
import kotlinx.android.synthetic.main.fragment_extensions.blank_repo_screen
|
import kotlinx.android.synthetic.main.fragment_extensions.blank_repo_screen
|
||||||
import kotlinx.android.synthetic.main.fragment_extensions.list_repositories
|
|
||||||
import kotlinx.android.synthetic.main.fragment_extensions.repo_recycler_view
|
import kotlinx.android.synthetic.main.fragment_extensions.repo_recycler_view
|
||||||
import kotlinx.android.synthetic.main.fragment_setup_extensions.*
|
|
||||||
import kotlinx.android.synthetic.main.fragment_setup_media.next_btt
|
import kotlinx.android.synthetic.main.fragment_setup_media.next_btt
|
||||||
import kotlinx.android.synthetic.main.fragment_setup_media.prev_btt
|
import kotlinx.android.synthetic.main.fragment_setup_media.prev_btt
|
||||||
import kotlinx.android.synthetic.main.fragment_setup_media.setup_root
|
import kotlinx.android.synthetic.main.fragment_setup_media.setup_root
|
||||||
|
@ -64,18 +59,19 @@ class SetupFragmentExtensions : Fragment() {
|
||||||
val hasRepos = repositories.isNotEmpty()
|
val hasRepos = repositories.isNotEmpty()
|
||||||
repo_recycler_view?.isVisible = hasRepos
|
repo_recycler_view?.isVisible = hasRepos
|
||||||
blank_repo_screen?.isVisible = !hasRepos
|
blank_repo_screen?.isVisible = !hasRepos
|
||||||
view_public_repositories_button?.isVisible = hasRepos
|
// view_public_repositories_button?.isVisible = hasRepos
|
||||||
|
|
||||||
if (hasRepos) {
|
if (hasRepos) {
|
||||||
repo_recycler_view?.adapter = RepoAdapter(true, {}, {
|
repo_recycler_view?.adapter = RepoAdapter(true, {}, {
|
||||||
PluginsViewModel.downloadAll(activity, it.url, null)
|
PluginsViewModel.downloadAll(activity, it.url, null)
|
||||||
}).apply { updateList(repositories) }
|
}).apply { updateList(repositories) }
|
||||||
} else {
|
|
||||||
list_repositories?.setOnClickListener {
|
|
||||||
// Open webview on tv if browser fails
|
|
||||||
openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// else {
|
||||||
|
// list_repositories?.setOnClickListener {
|
||||||
|
// // Open webview on tv if browser fails
|
||||||
|
// openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +80,9 @@ class SetupFragmentExtensions : Fragment() {
|
||||||
context?.fixPaddingStatusbar(setup_root)
|
context?.fixPaddingStatusbar(setup_root)
|
||||||
val isSetup = arguments?.getBoolean(SETUP_EXTENSION_BUNDLE_IS_SETUP) ?: false
|
val isSetup = arguments?.getBoolean(SETUP_EXTENSION_BUNDLE_IS_SETUP) ?: false
|
||||||
|
|
||||||
view_public_repositories_button?.setOnClickListener {
|
// view_public_repositories_button?.setOnClickListener {
|
||||||
openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)
|
// openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)
|
||||||
}
|
// }
|
||||||
|
|
||||||
with(context) {
|
with(context) {
|
||||||
if (this == null) return
|
if (this == null) return
|
||||||
|
@ -100,7 +96,7 @@ class SetupFragmentExtensions : Fragment() {
|
||||||
next_btt?.setOnClickListener {
|
next_btt?.setOnClickListener {
|
||||||
// Continue setup
|
// Continue setup
|
||||||
if (isSetup)
|
if (isSetup)
|
||||||
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_provider_languages)
|
findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_media)
|
||||||
else
|
else
|
||||||
findNavController().navigate(R.id.navigation_home)
|
findNavController().navigate(R.id.navigation_home)
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ class SetupFragmentLanguage : Fragment() {
|
||||||
&& PluginManager.getPluginsLocal().isEmpty()
|
&& PluginManager.getPluginsLocal().isEmpty()
|
||||||
//&& PREBUILT_REPOSITORIES.isNotEmpty()
|
//&& PREBUILT_REPOSITORIES.isNotEmpty()
|
||||||
) R.id.action_navigation_global_to_navigation_setup_extensions
|
) R.id.action_navigation_global_to_navigation_setup_extensions
|
||||||
else R.id.action_navigation_setup_language_to_navigation_setup_provider_languages
|
else R.id.action_navigation_setup_language_to_navigation_setup_media
|
||||||
|
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
nextDestination,
|
nextDestination,
|
||||||
|
|
|
@ -135,7 +135,8 @@ class SubtitlesFragment : Fragment() {
|
||||||
it.mkdir()
|
it.mkdir()
|
||||||
}
|
}
|
||||||
return fontDir.list()?.mapNotNull {
|
return fontDir.list()?.mapNotNull {
|
||||||
if (it.endsWith(".ttf")) {
|
// No idea which formats are supported, but these should be.
|
||||||
|
if (it.endsWith(".ttf") || it.endsWith(".otf")) {
|
||||||
File(fontDir.absolutePath + "/" + it)
|
File(fontDir.absolutePath + "/" + it)
|
||||||
} else null
|
} else null
|
||||||
} ?: listOf()
|
} ?: listOf()
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package com.lagradost.cloudstream3.utils
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.lagradost.cloudstream3.SubtitleFile
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.TvType
|
|
||||||
import com.lagradost.cloudstream3.USER_AGENT
|
|
||||||
import com.lagradost.cloudstream3.app
|
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.extractors.*
|
import com.lagradost.cloudstream3.extractors.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -323,6 +320,9 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
||||||
Embedgram(),
|
Embedgram(),
|
||||||
Mvidoo(),
|
Mvidoo(),
|
||||||
Streamplay(),
|
Streamplay(),
|
||||||
|
Vidmoly(),
|
||||||
|
Vidmolyme(),
|
||||||
|
Voe(),
|
||||||
|
|
||||||
Gdriveplayerapi(),
|
Gdriveplayerapi(),
|
||||||
Gdriveplayerapp(),
|
Gdriveplayerapp(),
|
||||||
|
@ -399,6 +399,28 @@ suspend fun getPostForm(requestUrl: String, html: String): String? {
|
||||||
).text
|
).text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ExtractorApi.fixUrl(url: String): String {
|
||||||
|
if (url.startsWith("http") ||
|
||||||
|
// Do not fix JSON objects when passed as urls.
|
||||||
|
url.startsWith("{\"")
|
||||||
|
) {
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
if (url.isEmpty()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
val startsWithNoHttp = url.startsWith("//")
|
||||||
|
if (startsWithNoHttp) {
|
||||||
|
return "https:$url"
|
||||||
|
} else {
|
||||||
|
if (url.startsWith('/')) {
|
||||||
|
return mainUrl + url
|
||||||
|
}
|
||||||
|
return "$mainUrl/$url"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ExtractorApi {
|
abstract class ExtractorApi {
|
||||||
abstract val name: String
|
abstract val name: String
|
||||||
abstract val mainUrl: String
|
abstract val mainUrl: String
|
||||||
|
|
|
@ -28,15 +28,15 @@
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<!-- <com.google.android.material.button.MaterialButton-->
|
||||||
android:nextFocusDown="@id/repo_name_input"
|
<!-- android:nextFocusDown="@id/repo_name_input"-->
|
||||||
android:id="@+id/list_repositories"
|
<!-- android:id="@+id/list_repositories"-->
|
||||||
android:nextFocusLeft="@id/apply_btt"
|
<!-- android:nextFocusLeft="@id/apply_btt"-->
|
||||||
android:nextFocusRight="@id/cancel_btt"
|
<!-- android:nextFocusRight="@id/cancel_btt"-->
|
||||||
style="@style/WhiteButton"
|
<!-- style="@style/WhiteButton"-->
|
||||||
android:layout_width="wrap_content"
|
<!-- android:layout_width="wrap_content"-->
|
||||||
android:layout_gravity="center_vertical"
|
<!-- android:layout_gravity="center_vertical"-->
|
||||||
android:text="@string/view_public_repositories_button_short" />
|
<!-- android:text="@string/view_public_repositories_button_short" />-->
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -70,7 +70,6 @@
|
||||||
android:autofillHints="username"
|
android:autofillHints="username"
|
||||||
android:hint="@string/repository_name_hint"
|
android:hint="@string/repository_name_hint"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
android:nextFocusUp="@id/list_repositories"
|
|
||||||
android:nextFocusLeft="@id/apply_btt"
|
android:nextFocusLeft="@id/apply_btt"
|
||||||
android:nextFocusRight="@id/cancel_btt"
|
android:nextFocusRight="@id/cancel_btt"
|
||||||
android:nextFocusDown="@id/site_url_input"
|
android:nextFocusDown="@id/site_url_input"
|
||||||
|
|
|
@ -47,15 +47,16 @@
|
||||||
android:text="@string/blank_repo_message"
|
android:text="@string/blank_repo_message"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<!-- <com.google.android.material.button.MaterialButton-->
|
||||||
android:id="@+id/list_repositories"
|
<!-- android:id="@+id/list_repositories"-->
|
||||||
style="@style/WhiteButton"
|
<!-- style="@style/WhiteButton"-->
|
||||||
android:layout_width="wrap_content"
|
<!-- android:layout_width="wrap_content"-->
|
||||||
android:nextFocusDown="@id/add_repo_button"
|
<!-- android:nextFocusDown="@id/add_repo_button"-->
|
||||||
android:text="@string/view_public_repositories_button" />
|
<!-- android:text="@string/view_public_repositories_button" />-->
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
android:focusable="true"
|
||||||
android:id="@+id/plugin_storage_appbar"
|
android:id="@+id/plugin_storage_appbar"
|
||||||
android:nextFocusRight="@id/add_repo_button_imageview"
|
android:nextFocusRight="@id/add_repo_button_imageview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -185,6 +186,7 @@
|
||||||
android:background="@drawable/outline_drawable"
|
android:background="@drawable/outline_drawable"
|
||||||
android:nextFocusLeft="@id/plugin_storage_appbar"
|
android:nextFocusLeft="@id/plugin_storage_appbar"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
android:focusable="true"
|
||||||
|
|
||||||
android:id="@+id/add_repo_button_imageview"
|
android:id="@+id/add_repo_button_imageview"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
|
|
|
@ -44,11 +44,11 @@
|
||||||
android:text="@string/blank_repo_message"
|
android:text="@string/blank_repo_message"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<!-- <com.google.android.material.button.MaterialButton-->
|
||||||
android:id="@+id/list_repositories"
|
<!-- android:id="@+id/list_repositories"-->
|
||||||
style="@style/WhiteButton"
|
<!-- style="@style/WhiteButton"-->
|
||||||
android:layout_width="wrap_content"
|
<!-- android:layout_width="wrap_content"-->
|
||||||
android:text="@string/view_public_repositories_button" />
|
<!-- android:text="@string/view_public_repositories_button" />-->
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -68,12 +68,12 @@
|
||||||
android:gravity="bottom|end"
|
android:gravity="bottom|end"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<!-- <com.google.android.material.button.MaterialButton-->
|
||||||
android:id="@+id/view_public_repositories_button"
|
<!-- android:id="@+id/view_public_repositories_button"-->
|
||||||
style="@style/WhiteButton"
|
<!-- style="@style/WhiteButton"-->
|
||||||
android:layout_width="wrap_content"
|
<!-- android:layout_width="wrap_content"-->
|
||||||
android:layout_gravity="center_vertical|end"
|
<!-- android:layout_gravity="center_vertical|end"-->
|
||||||
android:text="@string/add_repository" />
|
<!-- android:text="@string/add_repository" />-->
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/next_btt"
|
android:id="@+id/next_btt"
|
||||||
|
|
|
@ -522,6 +522,13 @@
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_navigation_setup_language_to_navigation_setup_media"
|
||||||
|
app:destination="@id/navigation_setup_media"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<action
|
<action
|
||||||
|
@ -553,6 +560,13 @@
|
||||||
app:exitAnim="@anim/exit_anim"
|
app:exitAnim="@anim/exit_anim"
|
||||||
app:popEnterAnim="@anim/enter_anim"
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
app:popExitAnim="@anim/exit_anim" />
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_navigation_setup_extensions_to_navigation_setup_media"
|
||||||
|
app:destination="@id/navigation_setup_media"
|
||||||
|
app:enterAnim="@anim/enter_anim"
|
||||||
|
app:exitAnim="@anim/exit_anim"
|
||||||
|
app:popEnterAnim="@anim/enter_anim"
|
||||||
|
app:popExitAnim="@anim/exit_anim" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
|
|
@ -13,16 +13,16 @@
|
||||||
|
|
||||||
<!-- TRANSLATE, BUT DON'T FORGET FORMAT -->
|
<!-- TRANSLATE, BUT DON'T FORGET FORMAT -->
|
||||||
<string name="player_speed_text_format" formatted="true">سرعة (%.2fx)</string>
|
<string name="player_speed_text_format" formatted="true">سرعة (%.2fx)</string>
|
||||||
<string name="rated_format" formatted="true">Rated: %.1f</string>
|
<string name="rated_format" formatted="true">تقييم: %.1f</string>
|
||||||
|
|
||||||
<string name="new_update_format" formatted="true">!تم إيجاد تحديث جديد\n%s -> %s</string>
|
<string name="new_update_format" formatted="true">!تم العثور علي تحديث جديد\n%s -> %s</string>
|
||||||
<string name="duration_format" formatted="true">%d دقيقة</string>
|
<string name="duration_format" formatted="true">%d دقيقة</string>
|
||||||
|
|
||||||
<string name="app_name">CloudStream</string>
|
<string name="app_name">CloudStream</string>
|
||||||
<string name="play_with_app_name">تشغيل بواسطة CloudStream</string>
|
<string name="play_with_app_name">تشغيل بواسطة CloudStream</string>
|
||||||
<string name="title_home">الصفحة الرئيسية</string>
|
<string name="title_home">الصفحة الرئيسية</string>
|
||||||
<string name="title_search">البحث</string>
|
<string name="title_search">البحث</string>
|
||||||
<string name="title_downloads">التحميلات</string>
|
<string name="title_downloads">التنزيلات</string>
|
||||||
<string name="title_settings">الإعدادات</string>
|
<string name="title_settings">الإعدادات</string>
|
||||||
|
|
||||||
<string name="search_hint">…بحث</string>
|
<string name="search_hint">…بحث</string>
|
||||||
|
@ -210,14 +210,14 @@
|
||||||
<string name="no_season">لا موسم</string>
|
<string name="no_season">لا موسم</string>
|
||||||
<string name="episode">حلقة</string>
|
<string name="episode">حلقة</string>
|
||||||
<string name="episodes">حلقات</string>
|
<string name="episodes">حلقات</string>
|
||||||
<string name="season_short">ح</string>
|
<string name="season_short">م</string>
|
||||||
<string name="episode_short">م</string>
|
<string name="episode_short">ح</string>
|
||||||
<string name="no_episodes_found">لم يتم العثور على أي حلقات</string>
|
<string name="no_episodes_found">لم يتم العثور على أي حلقات</string>
|
||||||
|
|
||||||
<string name="delete_file">حذف الملف</string>
|
<string name="delete_file">حذف الملف</string>
|
||||||
<string name="delete">حذف</string>
|
<string name="delete">حذف</string>
|
||||||
<string name="pause">إيقاف مؤقت</string>
|
<string name="pause">إيقاف مؤقت</string>
|
||||||
<string name="resume">أكمل</string>
|
<string name="resume">إستئناف</string>
|
||||||
<string name="go_back_30">-٣٠</string>
|
<string name="go_back_30">-٣٠</string>
|
||||||
<string name="go_forward_30">+٣٠</string>
|
<string name="go_forward_30">+٣٠</string>
|
||||||
<string name="delete_message">سوف يتم الحذف نهائيا %s\nهل أنت متأكد?</string>
|
<string name="delete_message">سوف يتم الحذف نهائيا %s\nهل أنت متأكد?</string>
|
||||||
|
@ -274,7 +274,7 @@
|
||||||
<string name="episode_action_chromecast_episode">حلقة كروم كاست</string>
|
<string name="episode_action_chromecast_episode">حلقة كروم كاست</string>
|
||||||
<string name="episode_action_chromecast_mirror">مرآة كروم كاست</string>
|
<string name="episode_action_chromecast_mirror">مرآة كروم كاست</string>
|
||||||
<string name="episode_action_play_in_app">تشغيل في التطبيق</string>
|
<string name="episode_action_play_in_app">تشغيل في التطبيق</string>
|
||||||
<string name="episode_action_play_in_vlc">VLC تشغيل في</string>
|
<string name="episode_action_play_in_format">%s تشغيل في</string>
|
||||||
<string name="episode_action_play_in_browser">تشغيل في الويب </string>
|
<string name="episode_action_play_in_browser">تشغيل في الويب </string>
|
||||||
<string name="episode_action_copy_link">نسخ الرابط</string>
|
<string name="episode_action_copy_link">نسخ الرابط</string>
|
||||||
<string name="episode_action_auto_download">التحميل التلقائي</string>
|
<string name="episode_action_auto_download">التحميل التلقائي</string>
|
||||||
|
@ -292,7 +292,7 @@
|
||||||
<string name="show_title_key" translatable="false">show_title_key</string>
|
<string name="show_title_key" translatable="false">show_title_key</string>
|
||||||
<string name="poster_ui_settings">التحكم في عناصر الواجهة علي الملصق </string>
|
<string name="poster_ui_settings">التحكم في عناصر الواجهة علي الملصق </string>
|
||||||
|
|
||||||
<string name="no_update_found">لم يتم العثور على تحديث</string>
|
<string name="no_update_found">لم يتم العثور على تحديثات</string>
|
||||||
<string name="check_for_update">تحقق من التحديثات</string>
|
<string name="check_for_update">تحقق من التحديثات</string>
|
||||||
|
|
||||||
<string name="video_lock">قفل</string>
|
<string name="video_lock">قفل</string>
|
||||||
|
@ -404,7 +404,7 @@
|
||||||
<string name="add_sync">إضافة تتبع</string>
|
<string name="add_sync">إضافة تتبع</string>
|
||||||
<string name="added_sync_format" formatted="true">تم إضافة %s</string>
|
<string name="added_sync_format" formatted="true">تم إضافة %s</string>
|
||||||
<string name="upload_sync">مزامنة</string>
|
<string name="upload_sync">مزامنة</string>
|
||||||
<string name="sync_score">مقيّم</string>
|
<string name="sync_score">تقييم</string>
|
||||||
<string name="sync_score_format" formatted="true">%d / 10</string>
|
<string name="sync_score_format" formatted="true">%d / 10</string>
|
||||||
<string name="sync_total_episodes_none">/??</string>
|
<string name="sync_total_episodes_none">/??</string>
|
||||||
<string name="sync_total_episodes_some" formatted="true">/%d</string>
|
<string name="sync_total_episodes_some" formatted="true">/%d</string>
|
||||||
|
@ -538,4 +538,5 @@
|
||||||
<string name="extension_language">اللغة</string>
|
<string name="extension_language">اللغة</string>
|
||||||
|
|
||||||
<string name="hls_playlist">قائمة HLS</string>
|
<string name="hls_playlist">قائمة HLS</string>
|
||||||
|
<string name="player_pref">مُشغل الفيديو المفضل</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -279,7 +279,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Episódio pelo Chromecast</string>
|
<string name="episode_action_chromecast_episode">Episódio pelo Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Alternativa pelo Chromecast</string>
|
<string name="episode_action_chromecast_mirror">Alternativa pelo Chromecast</string>
|
||||||
<string name="episode_action_play_in_app">Assistir no App</string>
|
<string name="episode_action_play_in_app">Assistir no App</string>
|
||||||
<string name="episode_action_play_in_vlc">Assistir no VLC</string>
|
<string name="episode_action_play_in_format">Assistir no %s</string>
|
||||||
<string name="episode_action_play_in_browser">Assistir no navegador</string>
|
<string name="episode_action_play_in_browser">Assistir no navegador</string>
|
||||||
<string name="episode_action_copy_link">Copiar link</string>
|
<string name="episode_action_copy_link">Copiar link</string>
|
||||||
<string name="episode_action_auto_download">Auto download</string>
|
<string name="episode_action_auto_download">Auto download</string>
|
||||||
|
|
|
@ -268,7 +268,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecastovat epizodu</string>
|
<string name="episode_action_chromecast_episode">Chromecastovat epizodu</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast jako zrcadlo</string>
|
<string name="episode_action_chromecast_mirror">Chromecast jako zrcadlo</string>
|
||||||
<string name="episode_action_play_in_app">Přehrát v aplikace</string>
|
<string name="episode_action_play_in_app">Přehrát v aplikace</string>
|
||||||
<string name="episode_action_play_in_vlc">Přehrát ve VLC</string>
|
<string name="episode_action_play_in_format">Přehrát ve %s</string>
|
||||||
<string name="episode_action_play_in_browser">Přehrát v prohlížeči</string>
|
<string name="episode_action_play_in_browser">Přehrát v prohlížeči</string>
|
||||||
<string name="episode_action_copy_link">Zkopírovat odkaz</string>
|
<string name="episode_action_copy_link">Zkopírovat odkaz</string>
|
||||||
<string name="episode_action_auto_download">Automaticky stáhnout</string>
|
<string name="episode_action_auto_download">Automaticky stáhnout</string>
|
||||||
|
|
|
@ -281,7 +281,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast-Episode</string>
|
<string name="episode_action_chromecast_episode">Chromecast-Episode</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecastmirror</string>
|
<string name="episode_action_chromecast_mirror">Chromecastmirror</string>
|
||||||
<string name="episode_action_play_in_app">In App wiedergeben</string>
|
<string name="episode_action_play_in_app">In App wiedergeben</string>
|
||||||
<string name="episode_action_play_in_vlc">In VLC wiedergeben</string>
|
<string name="episode_action_play_in_format">In %s wiedergeben</string>
|
||||||
<string name="episode_action_play_in_browser">In Browser wiedergeben</string>
|
<string name="episode_action_play_in_browser">In Browser wiedergeben</string>
|
||||||
<string name="episode_action_copy_link">Link kopieren</string>
|
<string name="episode_action_copy_link">Link kopieren</string>
|
||||||
<string name="episode_action_auto_download">Auto Download</string>
|
<string name="episode_action_auto_download">Auto Download</string>
|
||||||
|
|
|
@ -5,39 +5,39 @@
|
||||||
<string name="title_search">Αναζήτηση</string>
|
<string name="title_search">Αναζήτηση</string>
|
||||||
<string name="title_downloads">Λήψεις</string>
|
<string name="title_downloads">Λήψεις</string>
|
||||||
<string name="title_settings">Ρυθμίσεις</string>
|
<string name="title_settings">Ρυθμίσεις</string>
|
||||||
<string name="search_hint">Ψάξε…</string>
|
<string name="play_with_app_name">Άνοιγμα με CloudStream</string>
|
||||||
|
<string name="search_hint">Αναζήτηση…</string>
|
||||||
<string name="search_poster_img_des">Πόστερ</string>
|
<string name="search_poster_img_des">Πόστερ</string>
|
||||||
<string name="no_data">Χωρίς δεδομένα</string>
|
<string name="no_data">Χωρίς δεδομένα</string>
|
||||||
<string name="episode_more_options_des">Περισσότερες Επιλογές</string>
|
<string name="episode_more_options_des">Περισσότερες Επιλογές</string>
|
||||||
<string name="go_back_img_des">Πίσω</string>
|
<string name="go_back_img_des">Πίσω</string>
|
||||||
<string name="next_episode">Επόμενο Επισόδειο</string>
|
<string name="next_episode">Επόμενο Επεισόδιο</string>
|
||||||
<string name="result_poster_img_des">Πόστερ</string>
|
<string name="result_poster_img_des">Πόστερ</string>
|
||||||
<string name="synopsis">Πλοκή</string>
|
<string name="result_tags">Κατηγορίες</string>
|
||||||
<string name="result_tags">Genres</string>
|
<string name="result_share">Κοινοποίηση</string>
|
||||||
<string name="result_share">Μοίρασε</string>
|
|
||||||
<string name="result_open_in_browser">Άνοιγμα στον περιηγητή</string>
|
<string name="result_open_in_browser">Άνοιγμα στον περιηγητή</string>
|
||||||
<string name="skip_loading">Προσπέραση φορτώματος</string>
|
<string name="skip_loading">Παράλειψη φόρτωσης</string>
|
||||||
<string name="loading">Φόρτωση…</string>
|
<string name="loading">Φόρτωση…</string>
|
||||||
|
|
||||||
<string name="type_watching">Watching</string>
|
<string name="type_watching">Παρακολούθηση</string>
|
||||||
<string name="type_on_hold">On-Hold</string>
|
<string name="type_on_hold">Σε αναμονή</string>
|
||||||
<string name="type_completed">Completed</string>
|
<string name="type_completed">Ολοκληρώθηκε</string>
|
||||||
<string name="type_dropped">Dropped</string>
|
<string name="type_dropped">Διακόπηκε</string>
|
||||||
<string name="type_plan_to_watch">Plan to Watch</string>
|
<string name="type_plan_to_watch">Για παρακολούθηση</string>
|
||||||
<string name="type_none">None</string>
|
<string name="type_none">Τίποτα</string>
|
||||||
|
|
||||||
<string name="play_movie_button">Αναπαραγωγή Ταινείας</string>
|
<string name="play_movie_button">Αναπαραγωγή Ταινίας</string>
|
||||||
<string name="play_torrent_button">Μετάδοση Torrent</string>
|
<string name="play_torrent_button">Μετάδοση Torrent</string>
|
||||||
<string name="pick_source">Πηγές</string>
|
<string name="pick_source">Πηγές</string>
|
||||||
<string name="pick_subtitle">Υπότιτλοι</string>
|
<string name="pick_subtitle">Υπότιτλοι</string>
|
||||||
<string name="reload_error">Ξανά φόρτωσε…</string>
|
<string name="reload_error">Προσπάθεια επανασύνδεσης…</string>
|
||||||
<string name="go_back">Πίσω</string>
|
<string name="go_back">Πίσω</string>
|
||||||
<string name="episode_poster_img_des">Πόστερ</string>
|
<string name="episode_poster_img_des">Πόστερ</string>
|
||||||
<string name="play_episode">Αναπαραγωγή Επισοδείου</string>
|
<string name="play_episode">Αναπαραγωγή Επεισοδίου</string>
|
||||||
<!--<string name="need_storage">Δώσε άδεια για την λήψη επισοδείου</string>-->
|
<!--<string name="need_storage">Απαιτείται άδεια για την λήψη επεισοδίου</string>-->
|
||||||
<string name="download">Λήξη</string>
|
<string name="download">Λήψη</string>
|
||||||
<string name="error_loading_links_toast">Σφάλμα φόρτωσεις συνδέσμων</string>
|
<string name="error_loading_links_toast">Σφάλμα φόρτωσης συνδέσμων</string>
|
||||||
<string name="download_storage_text">Εσωτερικός χώρος</string>
|
<string name="download_storage_text">Εσωτερικός χώρος αποθήκευσης</string>
|
||||||
<!--<string name="options">Επιλογές</string>-->
|
<!--<string name="options">Επιλογές</string>-->
|
||||||
|
|
||||||
<string name="app_dubbed_text">Dub</string>
|
<string name="app_dubbed_text">Dub</string>
|
||||||
|
@ -50,77 +50,372 @@
|
||||||
|
|
||||||
<string name="acra_report_toast">Λυπούμαστε, η εφαρμογή κατέρρευσε. Μια ανώνυμη αναφορά σφαλμάτων θα σταλεί στους προγραμματιστές</string>
|
<string name="acra_report_toast">Λυπούμαστε, η εφαρμογή κατέρρευσε. Μια ανώνυμη αναφορά σφαλμάτων θα σταλεί στους προγραμματιστές</string>
|
||||||
<string name="pref_disable_acra">Απενεργοποιήστε την αυτόματη αναφορά σφαλμάτων</string>
|
<string name="pref_disable_acra">Απενεργοποιήστε την αυτόματη αναφορά σφαλμάτων</string>
|
||||||
|
<string name="show_log_cat">Εμφάνιση logcat 🐈</string>
|
||||||
<string name="home_more_info">Παραπάνω πληροφορίες</string>
|
<string name="home_more_info">Παραπάνω πληροφορίες</string>
|
||||||
<string name="home_expanded_hide">Κρύψιμο</string>
|
<string name="home_expanded_hide">Απόκρυψη</string>
|
||||||
<string name="home_main_poster_img_des">Κύριο Πόστερ</string>
|
<string name="home_main_poster_img_des">Κύριο Πόστερ</string>
|
||||||
<string name="home_play">Αναπαραγωγή</string>
|
<string name="home_play">Αναπαραγωγή</string>
|
||||||
<string name="home_info">Πληροφορίες</string>
|
<string name="home_info">Πληροφορίες</string>
|
||||||
<string name="home_next_random_img_des">Next Random</string>
|
<string name="home_next_random_img_des">Next Random</string>
|
||||||
<string name="home_change_provider_img_des">Change Provider</string>
|
<string name="home_change_provider_img_des">Αλλαγή Παρόχου</string>
|
||||||
<string name="filter_bookmarks">Filter Bookmarks</string>
|
<string name="filter_bookmarks">Φιλτράρισμα Σελιδοδεικτών</string>
|
||||||
<string name="error_bookmarks_text">Bookmarks</string>
|
<string name="error_bookmarks_text">Σελιδοδείκτες</string>
|
||||||
<string name="action_remove_from_bookmarks">Remove</string>
|
<string name="action_remove_from_bookmarks">Αφαίρεση</string>
|
||||||
<string name="play_episode_toast">Αναπαραγωγή Episode</string>
|
<string name="play_episode_toast">Αναπαραγωγή Επεισοδίου</string>
|
||||||
<string name="sort_apply">Υποβολή</string>
|
<string name="sort_apply">Υποβολή</string>
|
||||||
<string name="sort_cancel">Ακύρωση</string>
|
<string name="sort_cancel">Ακύρωση</string>
|
||||||
<string name="player_speed">Ταχύτητα αναπαραγωγής</string>
|
<string name="player_speed">Ταχύτητα αναπαραγωγής</string>
|
||||||
<string name="subtitles_settings">Ρυθμίσεις υπότιτλων</string>
|
<string name="subtitles_settings">Ρυθμίσεις υπότιτλων</string>
|
||||||
<string name="subs_text_color">Χρώμα κείμενου</string>
|
<string name="subs_text_color">Χρώμα κειμένου</string>
|
||||||
<string name="subs_outline_color">Χρώμα περιγράμματος</string>
|
<string name="subs_outline_color">Χρώμα περιγράμματος</string>
|
||||||
<string name="subs_background_color">Χρώμα φόντου</string>
|
<string name="subs_background_color">Χρώμα φόντου</string>
|
||||||
<string name="subs_window_color">Χρώμα παραθύρου</string>
|
<string name="subs_window_color">Χρώμα παραθύρου</string>
|
||||||
<string name="subs_edge_type">Τύπος άκρων</string>
|
<string name="subs_edge_type">Τύπος άκρων</string>
|
||||||
<string name="subs_subtitle_elevation">Ύψωση υπότιτλων</string>
|
<string name="subs_subtitle_elevation">Ύψωση υπότιτλων</string>
|
||||||
<string name="subs_default_reset_toast">Επαναφορά στην προεπιλεγμένη τιμή</string>
|
<string name="subs_default_reset_toast">Επαναφορά στις προεπιλεγμένες τιμές</string>
|
||||||
<string name="preview_background_img_des">Προεπισκόπηση φόντου</string>
|
<string name="preview_background_img_des">Προεπισκόπηση φόντου</string>
|
||||||
<string name="subs_font">Γραμματοσειρά</string>
|
<string name="subs_font">Γραμματοσειρά</string>
|
||||||
<string name="search_provider_text_providers">Αναζήτηση με τους παρόχους</string>
|
<string name="search_provider_text_providers">Αναζήτηση βάσει παρόχων</string>
|
||||||
<string name="search_provider_text_types">Αναζήτηση με τύπους</string>
|
<string name="search_provider_text_types">Αναζήτηση βάσει τύπων</string>
|
||||||
<string name="benene_count_text">%d Benenes given to devs</string>
|
<string name="benene_count_text">%d μπανάνες δόθηκαν στους προγραμματιστές</string>
|
||||||
<string name="benene_count_text_none">No Benenes given</string>
|
<string name="benene_count_text_none">Καμία μπανάνα δεν δόθηκε</string>
|
||||||
|
|
||||||
<string name="subs_auto_select_language">Αυτόματη επιλογή γλώσσας</string>
|
<string name="subs_auto_select_language">Αυτόματη επιλογή γλώσσας</string>
|
||||||
<string name="subs_download_languages">Λήψη γλωσσών</string>
|
<string name="subs_download_languages">Λήψη γλωσσών</string>
|
||||||
<string name="subs_hold_to_reset_to_default">Κρατήστε πατημένο για επαναφορά στα προεπιλεγμένα</string>
|
<string name="subs_hold_to_reset_to_default">Κρατήστε πατημένο για επαναφορά στις προεπιλεγμένες τιμές</string>
|
||||||
<string name="continue_watching">Συνέχεια Παρακολούθησης</string>
|
<string name="continue_watching">Συνέχεια Παρακολούθησης</string>
|
||||||
|
|
||||||
<string name="action_remove_watching">Αφαίρεση</string>
|
<string name="action_remove_watching">Αφαίρεση</string>
|
||||||
<string name="action_open_watching">Παραπάνω Πληροφορίες</string>
|
<string name="action_open_watching">Επιπλέον Πληροφορίες</string>
|
||||||
|
|
||||||
<string name="vpn_might_be_needed">A VPN might be needed for this provider to work correctly</string>
|
<string name="vpn_might_be_needed">Η χρήση ενός VPN ίσως χρειαστεί για την ομαλή λειτουργία του τρέχοντος παρόχου</string>
|
||||||
<string name="vpn_torrent">This providers is a torrent, a VPN is recommended</string>
|
<string name="vpn_torrent">Πρόκειται για torrent, η χρήση ενός VPN συνιστάται</string>
|
||||||
<string name="torrent_plot">Περιγραφή</string>
|
<string name="torrent_plot">Περιγραφή</string>
|
||||||
<string name="normal_no_plot">Δεν βρέθηκε περιγραφή</string>
|
<string name="normal_no_plot">Δεν βρέθηκε περιγραφή</string>
|
||||||
<string name="torrent_no_plot">Δεν βρέθηκε περιγραφή</string>
|
<string name="torrent_no_plot">Δεν βρέθηκε περιγραφή</string>
|
||||||
|
|
||||||
<string name="picture_in_picture">Picture-in-picture</string>
|
<string name="picture_in_picture">Εικόνα-σε-Εικόνα</string>
|
||||||
<string name="picture_in_picture_des">Συνεχίζει την αναπαραγωγή σε ένα μίνι παίκτη πάνω από άλλες εφαρμογές</string>
|
<string name="picture_in_picture_des">Συνεχίζει την αναπαραγωγή σε ένα μίνι παράθυρο πάνω από άλλες εφαρμογές</string>
|
||||||
<string name="player_size_settings">Αλλαγή μεγέθους παίκτη</string>
|
<string name="player_size_settings">Αλλαγή μεγέθους παραθύρου</string>
|
||||||
<string name="player_size_settings_des">Αφαίρεση μαύρων περιγραμμάτων</string>
|
<string name="player_size_settings_des">Αφαίρεση μαύρων περιγραμμάτων</string>
|
||||||
<string name="player_subtitles_settings">Υπότιτλοι</string>
|
<string name="player_subtitles_settings">Υπότιτλοι</string>
|
||||||
<string name="player_subtitles_settings_des">Ρυθμίσεις υποτίτλων του παίκτη</string>
|
<string name="player_subtitles_settings_des">Ρυθμίσεις υποτίτλων του προγράμματος αναπαραγωγής</string>
|
||||||
|
<string name="chromecast_subtitles_settings">Chromecast Υπότιτλοι</string>
|
||||||
|
<string name="chromecast_subtitles_settings_des">Ρυθμίσεις Chromecast υποτίτλων</string>
|
||||||
<string name="eigengraumode_settings">Eigengrau Mode</string>
|
<string name="eigengraumode_settings">Eigengrau Mode</string>
|
||||||
<string name="eigengraumode_settings_des">Προσθέτει την επιλογή ταχύτητας στον παίκτη</string>
|
<string name="eigengraumode_settings_des">Προσθέτει την επιλογή ταχύτητας στο πρόγραμμα αναπαραγωγής</string>
|
||||||
<string name="swipe_to_seek_settings">Σύρετε για seek</string>
|
<string name="swipe_to_seek_settings">Σύρετε για αναζήτηση</string>
|
||||||
<string name="swipe_to_seek_settings_des">Σύρετε αριστερά ή δεξιά για να ελέγξετε τον χρόνο στον παίκτη</string>
|
<string name="swipe_to_seek_settings_des">Σύρετε αριστερά ή δεξιά για να ελέγξετε τον χρόνο στην κάτω μπάρα</string>
|
||||||
<string name="swipe_to_change_settings">Σύρετε για να αλλάξετε ρυθμίσεις</string>
|
<string name="swipe_to_change_settings">Σύρετε για να αλλάξετε ρυθμίσεις</string>
|
||||||
<string name="swipe_to_change_settings_des">Σύρετε αριστερά ή δεξιά για να αλλάξετε τη φωτεινότητα ή την ένταση</string>
|
<string name="swipe_to_change_settings_des">Σύρετε αριστερά ή δεξιά για να αλλάξετε τη φωτεινότητα ή την ένταση</string>
|
||||||
<string name="double_tap_to_seek_settings">Διπλό πάτημα για seek</string>
|
<string name="double_tap_to_seek_settings">Διπλό πάτημα για αναζήτηση</string>
|
||||||
<string name="double_tap_to_seek_settings_des">Διπλό πάτημα στα αριστερά ή δεξιά για seek μπροστά ή πίσω</string>
|
<string name="double_tap_to_seek_settings_des">Διπλό πάτημα στα αριστερά ή δεξιά για αναζήτηση μπροστά ή πίσω</string>
|
||||||
<string name="search">Αναζήτηση</string>
|
<string name="search">Αναζήτηση</string>
|
||||||
<string name="settings_info">Πληροφορείες</string>
|
<string name="settings_info">Πληροφορίες</string>
|
||||||
<string name="advanced_search">Προχωρημένη Αναζήτηση</string>
|
<string name="advanced_search">Προχωρημένη Αναζήτηση</string>
|
||||||
<string name="advanced_search_des">Δίνει τα αποτελέσματα αναζήτησης χωρισμένα ανά πάροχο</string>
|
<string name="advanced_search_des">Δίνει τα αποτελέσματα αναζήτησης ταξινομημένα ανά πάροχο</string>
|
||||||
<string name="bug_report_settings_off">Αποστέλλει δεδομένα μόνο για σφάλματα</string>
|
<string name="bug_report_settings_off">Αποστέλλει δεδομένα μόνο για σφάλματα</string>
|
||||||
<string name="bug_report_settings_on">Δεν στέλνει δεδομένα</string>
|
<string name="bug_report_settings_on">Δεν στέλνει δεδομένα</string>
|
||||||
<string name="updates_settings">Εμφάνιση ενημερώσεων</string>
|
<string name="updates_settings">Εμφάνιση ενημερώσεων</string>
|
||||||
<string name="updates_settings_des">Αυτόματη αναζήτηση νέων ενημερώσεων</string>
|
<string name="updates_settings_des">Αυτόματη αναζήτηση νέων ενημερώσεων</string>
|
||||||
<string name="uprereleases_settings">Ενημέρωση σε προ-εκδόσεις</string>
|
<string name="uprereleases_settings">Ενημέρωση σε προ-εκδόσεις (beta)</string>
|
||||||
<string name="uprereleases_settings_des">Αναζητήστε ενημερώσεις προ-εκδόσεων αντί για κανονικές εκδόσεις</string>
|
<string name="uprereleases_settings_des">Αναζητήστε ενημερώσεις προ-εκδόσεων (beta) αντί για σταθερές εκδόσεις</string>
|
||||||
<string name="github">Github</string>
|
<string name="github">Github</string>
|
||||||
<string name="lightnovel">Light novel app by the same devs</string>
|
<string name="lightnovel">Ελαφριά novel εφαρμογή από τους ίδιους προγραμματιστές</string>
|
||||||
<string name="anim">Anime app by the same devs</string>
|
<string name="anim">Anime εφαρμογή από τους ίδιους προγραμματιστές</string>
|
||||||
<string name="discord">Join Discord</string>
|
<string name="discord">Εγγραφείτε στο Discord</string>
|
||||||
<string name="benene">Δώσε benene στους devs</string>
|
<string name="benene">Δώστε μπανάνα στους προγραμματιστές</string>
|
||||||
<string name="benene_des">Βenene δώθηκε</string>
|
<string name="benene_des">Μπανάνα δόθηκε δώθηκε</string>
|
||||||
|
|
||||||
|
<string name="player_speed_text_format" formatted="true">Ταχύτητα (%.2fx)</string>
|
||||||
|
<string name="rated_format" formatted="true">Βαθμολογία: %.1f</string>
|
||||||
|
<string name="new_update_format" formatted="true">Νέα ενημέρωση διαθέσιμη!\n%s -> %s</string>
|
||||||
|
|
||||||
|
<string name="double_tap_to_pause_settings_des">Πάτημα στη μέση για παύση</string>
|
||||||
|
<string name="use_system_brightness_settings">Χρήση φωτεινότητας συστήματος</string>
|
||||||
|
<string name="use_system_brightness_settings_des">Χρήση φωτεινότητας συστήματος στο ενσωματωμένο πρόγραμμα αναπαραγωγής αντί να εφαρμοστεί το προεπιλεγμένο σκούρο επικάλυμμα
|
||||||
|
</string>
|
||||||
|
|
||||||
|
<string name="episode_sync_settings">Ενημέρωση προόδου παρακολούθησης</string>
|
||||||
|
<string name="episode_sync_settings_des">Αυτόματος συγχρονισμός της προόδου του τρέχοντος επεισοδίου</string>
|
||||||
|
|
||||||
|
<string name="restore_settings">Επαναφορά δεδομένων από αντίγραφο ασφαλείας</string>
|
||||||
|
|
||||||
|
<string name="backup_settings">Αντίγραφα ασφαλείας</string>
|
||||||
|
<string name="restore_success">Τα αντίγραφα ασφαλείας φορτώθηκαν</string>
|
||||||
|
<string name="restore_failed_format" formatted="true">Η επαναφορά αντιγράφων ασφαλαείας απέτυχε από το αρχείο %s</string>
|
||||||
|
<string name="backup_success">Επιτυχής αποθήκευση δεδομένων</string>
|
||||||
|
<string name="backup_failed">Δεν έχει δοθεί άδεια για πρόσβαση στον αποθηκευτικό χώρο, προσπαθήστε ξανά</string>
|
||||||
|
<string name="backup_failed_error_format">Σφάλμα δημιουργίας αντιγράφων ασφαλείας %s</string>
|
||||||
|
|
||||||
|
<string name="category_account">Λογαριασμοί</string>
|
||||||
|
<string name="category_updates">Ενημερώσεις και αντίγραφα ασφαλείας</string>
|
||||||
|
|
||||||
|
<string name="show_fillers_settings">Εμφάνιση filler επεισοδίου για anime</string>
|
||||||
|
<string name="show_trailers_settings">Εμφάνιση trailers</string>
|
||||||
|
<string name="kitsu_settings">Εμφάνιση posters από kitsu</string>
|
||||||
|
<string name="pref_filter_search_quality">Απόκρυψη επιλεγμένης ποιότητας βίντεο στα αποτελέσματα αναζήτησης</string>
|
||||||
|
|
||||||
|
<string name="app_language">App Language</string>
|
||||||
|
|
||||||
|
<string name="no_chromecast_support_toast">Αυτός ο πάροχος δεν έχει υποστήριξη Chromecast</string>
|
||||||
|
<string name="no_links_found_toast">Δεν βρέθηκαν διαθέσιμοι σύνδεσμοι</string>
|
||||||
|
<string name="copy_link_toast">Ο σύνδεσμος αντιγράφηκε στο πρόχειρο</string>
|
||||||
|
|
||||||
|
<string name="season">Season</string>
|
||||||
|
<string name="season_format">%s %d%s</string>
|
||||||
|
<string name="no_season">No Season</string>
|
||||||
|
<string name="episode">Episode</string>
|
||||||
|
<string name="episodes">Episodes</string>
|
||||||
|
<string name="episodes_range">%d-%d</string>
|
||||||
|
<string name="episode_format" formatted="true">%d %s</string>
|
||||||
|
<string name="season_short">S</string>
|
||||||
|
<string name="episode_short">E</string>
|
||||||
|
<string name="no_episodes_found">No Episodes found</string>
|
||||||
|
|
||||||
|
<string name="delete_file">Διαγραφή αρχείου</string>
|
||||||
|
<string name="delete">Διαγραφή</string>
|
||||||
|
<string name="pause">Πάυση</string>
|
||||||
|
<string name="resume">Συνέχιση</string>
|
||||||
|
<string name="delete_message" formatted="true">Αυτό θα διαγράψει μόνιμα το %s\nΕπιβεβαίωση;</string>
|
||||||
|
<string name="resume_time_left" formatted="true">%dm\nαπομένουν</string>
|
||||||
|
|
||||||
|
<string name="status_ongoing">Σε εξέλιξη</string>
|
||||||
|
<string name="status">Κατάσταση</string>
|
||||||
|
<string name="year">Έτος</string>
|
||||||
|
<string name="duration">Διάρκεια</string>
|
||||||
|
<string name="site">Ιστότοπος</string>
|
||||||
|
<string name="synopsis">Περίληψη</string>
|
||||||
|
|
||||||
|
<string name="queued">προστέθηκε στην ουρά</string>
|
||||||
|
<string name="no_subtitles">Δεν υπάρχουν διαθέσιμοι υπότιτλοι</string>
|
||||||
|
<string name="default_subtitles">Προεπιλεγμένοι υπότιτλοι</string>
|
||||||
|
|
||||||
|
<string name="free_storage">Ελέυθερος</string>
|
||||||
|
<string name="used_storage">Σε χρήση</string>
|
||||||
|
<string name="app_storage">Εφαρμογή</string>
|
||||||
|
|
||||||
|
<string name="movies">Ταινίες</string>
|
||||||
|
<string name="tv_series">Τηλεοπτικές Σειρές</string>
|
||||||
|
<string name="cartoons">Κινούμενα σχέδια</string>
|
||||||
|
<string name="torrent">Torrents</string>
|
||||||
|
<string name="documentaries">Ντοκιμαντέρ</string>
|
||||||
|
<string name="asian_drama">Ασιατικά Δράμα</string>
|
||||||
|
<string name="livestreams">Ζωντανές ροές</string>
|
||||||
|
<string name="others">Άλλα</string>
|
||||||
|
|
||||||
|
<string name="movies_singular">Ταινία</string>
|
||||||
|
<string name="tv_series_singular">Σειρά</string>
|
||||||
|
<string name="cartoons_singular">Cartoon</string>
|
||||||
|
<string name="documentaries_singular">Ντοκιμαντέρ</string>
|
||||||
|
<string name="asian_drama_singular">Ασιατικό Δράμα</string>
|
||||||
|
<string name="live_singular">Ζωντανή ροή</string>
|
||||||
|
<string name="other_singular">Άλλο</string>
|
||||||
|
|
||||||
|
<string name="source_error">Σφάλμα πηγής</string>
|
||||||
|
<string name="remote_error">Απομακρυσμένο σφάλμα</string>
|
||||||
|
<string name="render_error">Σφάλμα απόδοσης</string>
|
||||||
|
<string name="unexpected_error">Μη αναμενόμενο σφάλμα αναπαραγωγής</string>
|
||||||
|
<string name="storage_error">Σφάλμα λήψης, επιβεβαιώστε ότι η άδεια αποθήκευσης είναι ενεργοποιημένη</string>
|
||||||
|
|
||||||
|
<string name="episode_action_chromecast_episode">Chromecast επεισόδο</string>
|
||||||
|
<string name="episode_action_play_in_app">Αναπαραγωγή εντός της εφαρμογής</string>
|
||||||
|
<string name="episode_action_play_in_format">Αναπαραγωγή σε %s</string>
|
||||||
|
<string name="episode_action_play_in_browser">Αναπαραγωγή στον περιηγητή</string>
|
||||||
|
<string name="episode_action_copy_link">Αντιγραφή συνδέσμου</string>
|
||||||
|
<string name="episode_action_auto_download">Αυτόματη λήψη</string>
|
||||||
|
<string name="episode_action_download_mirror">Λήψη mirror</string>
|
||||||
|
<string name="episode_action_reload_links">Επαναφόρτωση συνδέσμων</string>
|
||||||
|
<string name="episode_action_download_subtitle">Λήψη υποτίτλων</string>
|
||||||
|
|
||||||
|
<string name="show_hd">Ποιότητα</string>
|
||||||
|
<string name="show_dub">Dub</string>
|
||||||
|
<string name="show_sub">Sub</string>
|
||||||
|
<string name="show_title">Τίτλος</string>
|
||||||
|
<string name="poster_ui_settings">Εναλλαγή των στοιχείων UI στο poster</string>
|
||||||
|
|
||||||
|
<string name="video_lock">Κλείδωμα</string>
|
||||||
|
<string name="video_aspect_ratio_resize">Αλλαγή μεγέθους</string>
|
||||||
|
<string name="video_source">Πηγή</string>
|
||||||
|
<string name="video_skip_op">Παράλειψη OP</string>
|
||||||
|
|
||||||
|
<string name="dont_show_again">Να μην εμφανιστεί ξανά</string>
|
||||||
|
<string name="skip_update">Παράλειψη της τρέχουσας ενημέρωσης</string>
|
||||||
|
<string name="update">Ενημέρωση</string>
|
||||||
|
<string name="watch_quality_pref">Προτίμηση ποιότητας παρακολούθησης</string>
|
||||||
|
<string name="limit_title">Μέγιστοι χαρακτήρες για τίτλο</string>
|
||||||
|
<string name="limit_title_rez">Ανάλυση αναπαραγωγής βίντεο</string>
|
||||||
|
|
||||||
|
<string name="video_buffer_size_settings">Μέγεθος buffer βίντεο</string>
|
||||||
|
<string name="video_buffer_length_settings">Μήκος buffer βίντεο</string>
|
||||||
|
<string name="video_buffer_disk_settings">Προσωρινή μνήμη βίντεο στο δίσκο</string>
|
||||||
|
<string name="video_buffer_clear_settings">Εκκαθάριση προσωρινής μνήμης βίντεο και εικόνων</string>
|
||||||
|
|
||||||
|
<string name="video_ram_description">Θα προκαλέσει τυχαία σφάλματα εάν οριστεί πολύ ψηλά. Μην το αλλάξετε εάν έχετε χαμηλή ποσότητα μνήμης ram, όπως σε Android TV ή παλιό τηλέφωνο</string>
|
||||||
|
<string name="video_disk_description">Μπορεί να προκαλέσει προβλήματα σε συστήματα με χαμηλό αποθηκευτικό χώρο, όπως σε συσκευές Android TV, εάν τον ρυθμίσετε πολύ ψηλά</string>
|
||||||
|
|
||||||
|
<string name="dns_pref_summary">Χρήσιμο για παράκαμψη μπλοκ ISP</string>
|
||||||
|
|
||||||
|
<string name="add_site_pref">Αντίγραφο ιστοτόπου</string>
|
||||||
|
<string name="remove_site_pref">Αφαίρεση ιστοτόπου</string>
|
||||||
|
<string name="add_site_summary">Προσθήκη αντιγράφου ενός υπάρχοντος ιστοτόπου, με έναν διαφορετικό σύνδεσμο</string>
|
||||||
|
|
||||||
|
<string name="download_path_pref">Διαδρομή λήψης</string>
|
||||||
|
|
||||||
|
<string name="display_subbed_dubbed_settings">Εμφάνιση Dubbed/Subbed Anime</string>
|
||||||
|
|
||||||
|
<string name="resize_fit">Προσαρμογή στην οθόνη</string>
|
||||||
|
<string name="resize_fill">Τέντωμα</string>
|
||||||
|
<string name="resize_zoom">Μεγέθυνση</string>
|
||||||
|
|
||||||
|
<string name="legal_notice">Αποποίηση ευθυνών</string>
|
||||||
|
|
||||||
|
<string name="category_general">Γενικά</string>
|
||||||
|
<string name="random_button_settings">Τυχαίο κουμπί</string>
|
||||||
|
<string name="random_button_settings_desc">Εμφάνιση τυχαίου κουμπιού στην Αρχική οθόνη</string>
|
||||||
|
<string name="provider_lang_settings">Γλώσσες παρόχων</string>
|
||||||
|
<string name="app_layout">Διάταξη εφαρμογής</string>
|
||||||
|
<string name="preferred_media_settings">Προτιμώμενα μέσα</string>
|
||||||
|
<string name="enable_nsfw_on_providers">Ενεργοποίηση NSFW σε υποστηριζόμενους παρόχους</string>
|
||||||
|
<string name="subtitles_encoding">Κωδικοποίηση υποτίτλων</string>
|
||||||
|
<string name="category_providers">Πάροχοι</string>
|
||||||
|
<string name="category_ui">Διάταξη</string>
|
||||||
|
|
||||||
|
<string name="automatic">Αυτόματο</string>
|
||||||
|
<string name="tv_layout">Διάταξη TV</string>
|
||||||
|
<string name="phone_layout">Διάταξη τηλεφώνου</string>
|
||||||
|
<string name="emulator_layout">Διάταξη emulator</string>
|
||||||
|
|
||||||
|
<string name="primary_color_settings">Πρωτεύον χρώμα</string>
|
||||||
|
<string name="app_theme_settings">Θέμα εφαρμογής</string>
|
||||||
|
<string name="bottom_title_settings">Τοποθεσία τίτλου Poster</string>
|
||||||
|
<string name="bottom_title_settings_des">Τοποθετήστε τον τίτλο κάτω από το poster</string>
|
||||||
|
|
||||||
|
<string name="example_lang_name">Κωδικός γλώσσας (el)</string>
|
||||||
|
|
||||||
|
<string name="account">Λογαριασμός</string>
|
||||||
|
<string name="logout">Αποσύνδεση</string>
|
||||||
|
<string name="login">Σύνδεση</string>
|
||||||
|
<string name="switch_account">Εναλλαγή λογαριασμού</string>
|
||||||
|
<string name="add_account">Προσθήκη λογαριασμού</string>
|
||||||
|
<string name="create_account">Δημιουργία λογαριασμού</string>
|
||||||
|
<string name="add_sync">Προσθήκη παρακολούθησης</string>
|
||||||
|
<string name="added_sync_format" formatted="true">Προστέθηκε %s</string>
|
||||||
|
<string name="upload_sync">Συγχρονισμός</string>
|
||||||
|
<string name="sync_score">Βαθμολογήθηκε</string>
|
||||||
|
<string name="authenticated_user" formatted="true">Πιστοποιήθηκε %s</string>
|
||||||
|
<string name="authenticated_user_fail" formatted="true">Αποτυχία πιστοποίησης σε %s</string>
|
||||||
|
|
||||||
|
<string name="none">Τίποτα</string>
|
||||||
|
<string name="normal">Κανονικά</string>
|
||||||
|
<string name="all">Όλα</string>
|
||||||
|
<string name="max">Μέγιστο</string>
|
||||||
|
<string name="min">Ελάχιστο</string>
|
||||||
|
<string name="subtitles_outline">Περίγραμμα</string>
|
||||||
|
<string name="subtitles_depressed">Σε κατάθλιψη</string>
|
||||||
|
<string name="subtitles_shadow">Σκιά</string>
|
||||||
|
<string name="subtitles_raised">Ανεβασμένοι</string>
|
||||||
|
<string name="subtitle_offset">Συγχρονισμός υποτίτλων</string>
|
||||||
|
<string name="subtitle_offset_hint">1000ms</string>
|
||||||
|
<string name="subtitle_offset_title">Καθυστέρηση υποτίτλων</string>
|
||||||
|
<string name="subtitle_offset_extra_hint_later_format">Χρησιμοποιήστε αυτό αν οι υπότιτλοι εμφανίζονται %dms πολύ νωρίς</string>
|
||||||
|
<string name="subtitle_offset_extra_hint_before_format">Χρησιμοποιήστε αυτό αν οι υπότιτλοι εμφανίζονται %dms πολύ αργά</string>
|
||||||
|
<string name="subtitle_offset_extra_hint_none_format">Καμία καθυστέρηση υποτίτλων</string>
|
||||||
|
|
||||||
|
<string name="recommended">Συνιστώμενο</string>
|
||||||
|
<string name="player_loaded_subtitles" formatted="true">Φόρτωση %s</string>
|
||||||
|
<string name="player_load_subtitles">Φόρτωση από αρχείο</string>
|
||||||
|
<string name="player_load_subtitles_online">Φόρτωση από το Ίντερνετ</string>
|
||||||
|
<string name="downloaded_file">Λήψη αρχείου</string>
|
||||||
|
<string name="actor_main">Κύριο</string>
|
||||||
|
<string name="actor_supporting">Υποστηρίζεται</string>
|
||||||
|
<string name="actor_background">Φόντο</string>
|
||||||
|
|
||||||
|
<string name="home_source">Πηγή</string>
|
||||||
|
<string name="home_random">Τυχαίο</string>
|
||||||
|
|
||||||
|
<string name="coming_soon">Έρχεται σύντομα…</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="poster_image">Εικόνα Poster</string>
|
||||||
|
<string name="category_player">Πρόγραμμα αναπαραγωγής</string>
|
||||||
|
<string name="resolution_and_title">Ανάλυση και τίτλος</string>
|
||||||
|
<string name="title">Τίτλος</string>
|
||||||
|
<string name="resolution">Ανάλυση</string>
|
||||||
|
<string name="error_invalid_id">Μη έγκυρο id</string>
|
||||||
|
<string name="error_invalid_data">Μη έγκυρα δεδομένα</string>
|
||||||
|
<string name="error_invalid_url">Μη έγκυρος σύνδεσμος</string>
|
||||||
|
<string name="error">Σφάλμα</string>
|
||||||
|
<string name="subtitles_remove_captions">Αφαίρεση closed captions (για άτομα με προβλήματα ακοής) από τους υπότιτλους</string>
|
||||||
|
<string name="subtitles_remove_bloat">Αφαίρεση bloat από τους υπότιτλους</string>
|
||||||
|
<string name="subtitles_filter_lang">Φιλτράρισμα ανά την προτεινόμενη γλώσσα του μέσου</string>
|
||||||
|
<string name="extras">Έξτρα</string>
|
||||||
|
<string name="trailer">Τρέιλερ</string>
|
||||||
|
<string name="network_adress_example">Σύνδεσμος για stream</string>
|
||||||
|
<string name="referer">Παραπομπή</string>
|
||||||
|
<string name="next">Επόμενο</string>
|
||||||
|
<string name="provider_languages_tip">Παρακολούθηση βίντεο σε αυτή την γλώσσα</string>
|
||||||
|
<string name="previous">Προηγούμενο</string>
|
||||||
|
<string name="skip_setup">Παράλειψη διαμόρφωσης</string>
|
||||||
|
<string name="app_layout_subtext">Αλλαγή της εμφάνισης της συσκευής για να ταιριάζει με την συσκευή σας</string>
|
||||||
|
<string name="crash_reporting_title">Αναφορά κατάρρευσης</string>
|
||||||
|
<string name="preferred_media_subtext">Τι θα θέλατε να δείτε</string>
|
||||||
|
<string name="setup_done">Έγινε</string>
|
||||||
|
<string name="extensions">Πρόσθετα</string>
|
||||||
|
<string name="add_repository">Προσθήκη αποθετηρίου</string>
|
||||||
|
<string name="repository_name_hint">Όνομα αποθετηρίου</string>
|
||||||
|
<string name="repository_url_hint">Σύνδεσμος αποθετηρίου</string>
|
||||||
|
<string name="plugin_loaded">Το πρόσθετο φορτώθηκε</string>
|
||||||
|
<string name="plugin_deleted">Το πρόσθετο διαγράφηκε</string>
|
||||||
|
<string name="plugin_load_fail" formatted="true">Απέτυχε να φορτωθεί το %s</string>
|
||||||
|
<string name="batch_download_start_format" formatted="true">Ξεκίνησε η λήψη %d %s</string>
|
||||||
|
<string name="batch_download_finish_format" formatted="true">Κατέβηκε το %d %s επιτυχώς</string>
|
||||||
|
<string name="batch_download_nothing_to_download_format" formatted="true">Όλα τα %s έχουν ήδη κατέβει</string>
|
||||||
|
<string name="batch_download">Μαζική λήψη</string>
|
||||||
|
<string name="plugin_singular">Πρόσθετο</string>
|
||||||
|
<string name="plugin">Πρόσθετα</string>
|
||||||
|
<string name="delete_repository_plugins">Αυτό θα διαγράψει όλα τα πρόσθετα του αποθετηρίου</string>
|
||||||
|
<string name="delete_repository">Διαγραφή αποθετηρίου</string>
|
||||||
|
<string name="setup_extensions_subtext">Λήψη της λίστας των ιστοσελίδων που θέλετε να δείτε</string>
|
||||||
|
<string name="plugins_downloaded" formatted="true">Κατέβηκε: %d</string>
|
||||||
|
<string name="plugins_disabled" formatted="true">Απενεργοποιήθηκε: %d</string>
|
||||||
|
<string name="plugins_not_downloaded" formatted="true">Δεν κατέβηκε: %d</string>
|
||||||
|
<string name="plugins_updated" formatted="true">Ενημερώθηκαν %d πρόσθετα</string>
|
||||||
|
<string name="blank_repo_message">Προσθήκη ενός αποθετηρίου για να εγκαταστήσετε πρόσθετα ιστοσελίδας</string>
|
||||||
|
<string name="view_public_repositories_button">Προβολή αποθετηρίων κοινότητας</string>
|
||||||
|
<string name="view_public_repositories_button_short">Δημόσια λίστα</string>
|
||||||
|
<string name="uppercase_all_subtitles">Κεφαλοποίηση υποτίτλων</string>
|
||||||
|
|
||||||
|
<string name="download_all_plugins_from_repo">Λήψη όλων των προσθέτων από αυτό το αποθετήριο;</string>
|
||||||
|
<string name="single_plugin_disabled" formatted="true">%s (Απενεργοποιήθηκε)</string>
|
||||||
|
<string name="tracks">Κομμάτια</string>
|
||||||
|
<string name="audio_tracks">Ηχητικά κομμάτια</string>
|
||||||
|
<string name="video_tracks">Κομμάτια βίντεο</string>
|
||||||
|
<string name="apply_on_restart">Εφαρμογή στην επανεκκίνηση</string>
|
||||||
|
|
||||||
|
<string name="safe_mode_title">Η ασφαλής λειτουργία ενεργοποιήθηκε</string>
|
||||||
|
<string name="safe_mode_description">Ένα μη αντιστρέψιμο σφάλμα συνέβη και απενεργοποιήσαμε όλα τα πρόσθετα, ώστε να μπορέσετε να διαπιστώσετε ποιο πρόσθετο προκάλεσε αυτή τη κατάρρευση.</string>
|
||||||
|
<string name="safe_mode_crash_info">Προβολή πληροφορίας κατάρρευσης</string>
|
||||||
|
|
||||||
|
<string name="extension_rating" formatted="true">Βαθμολογία: %s</string>
|
||||||
|
<string name="extension_description">Περιγραφή</string>
|
||||||
|
<string name="extension_version">Έκδοση</string>
|
||||||
|
<string name="extension_status">Κατάσταση</string>
|
||||||
|
<string name="extension_size">Μέγεθος</string>
|
||||||
|
<string name="extension_authors">Συγγραφείς</string>
|
||||||
|
<string name="extension_types">Υποστηρίζονται</string>
|
||||||
|
<string name="extension_language">Γλώσσα</string>
|
||||||
|
<string name="extension_install_first">Εγκατάσταση προσθέτου πρώτα</string>
|
||||||
|
|
||||||
|
<string name="hls_playlist">HLS Playlist</string>
|
||||||
|
|
||||||
|
<string name="player_pref">Προτεινόμενο πρόγραμμα αναπαραγωγής</string>
|
||||||
|
<string name="player_settings_play_in_app">Ενσωματωμένο πρόγραμμα αναπαραγωγής</string>
|
||||||
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
|
<string name="player_settings_play_in_mpv">MPV</string>
|
||||||
|
<string name="player_settings_play_in_web">Web Video Cast</string>
|
||||||
|
<string name="player_settings_play_in_browser">Περιηγητής</string>
|
||||||
|
<string name="app_not_found_error">Η εφαρμογή δεν βρέθηκε</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -156,7 +156,7 @@
|
||||||
<item>@string/episode_action_chromecast_episode</item>
|
<item>@string/episode_action_chromecast_episode</item>
|
||||||
<item>@string/episode_action_chromecast_mirror</item>
|
<item>@string/episode_action_chromecast_mirror</item>
|
||||||
<item>@string/episode_action_play_in_app</item>
|
<item>@string/episode_action_play_in_app</item>
|
||||||
<item>@string/episode_action_play_in_vlc</item>
|
<item>@string/episode_action_play_in_format</item>
|
||||||
<item>@string/episode_action_play_in_browser</item>
|
<item>@string/episode_action_play_in_browser</item>
|
||||||
<item>@string/episode_action_copy_link</item>
|
<item>@string/episode_action_copy_link</item>
|
||||||
<item>@string/episode_action_auto_download</item>
|
<item>@string/episode_action_auto_download</item>
|
||||||
|
|
|
@ -269,7 +269,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Episodio Chromecast</string>
|
<string name="episode_action_chromecast_episode">Episodio Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Espejo Chromecast</string>
|
<string name="episode_action_chromecast_mirror">Espejo Chromecast</string>
|
||||||
<string name="episode_action_play_in_app">Reproducir en la app</string>
|
<string name="episode_action_play_in_app">Reproducir en la app</string>
|
||||||
<string name="episode_action_play_in_vlc">Reproducir en VLC</string>
|
<string name="episode_action_play_in_format">Reproducir en %s</string>
|
||||||
<string name="episode_action_play_in_browser">Reproducir en el navegador</string>
|
<string name="episode_action_play_in_browser">Reproducir en el navegador</string>
|
||||||
<string name="episode_action_copy_link">Copiar enlace</string>
|
<string name="episode_action_copy_link">Copiar enlace</string>
|
||||||
<string name="episode_action_auto_download">Descarga automática</string>
|
<string name="episode_action_auto_download">Descarga automática</string>
|
||||||
|
|
|
@ -164,7 +164,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Episode Chromecast</string>
|
<string name="episode_action_chromecast_episode">Episode Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Miroir Chromecast</string>
|
<string name="episode_action_chromecast_mirror">Miroir Chromecast</string>
|
||||||
<string name="episode_action_play_in_app">Lecture dans l\'application</string>
|
<string name="episode_action_play_in_app">Lecture dans l\'application</string>
|
||||||
<string name="episode_action_play_in_vlc">Lecture dans VLC</string>
|
<string name="episode_action_play_in_format">Lecture dans %s</string>
|
||||||
<string name="episode_action_play_in_browser">Lecture dans le navigateur</string>
|
<string name="episode_action_play_in_browser">Lecture dans le navigateur</string>
|
||||||
<string name="episode_action_copy_link">Copier le lien</string>
|
<string name="episode_action_copy_link">Copier le lien</string>
|
||||||
<string name="episode_action_auto_download">Téléchargement Automatique</string>
|
<string name="episode_action_auto_download">Téléchargement Automatique</string>
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
<string name="episode_action_chromecast_episode">क्रोमकास्ट एपिसोड</string>
|
<string name="episode_action_chromecast_episode">क्रोमकास्ट एपिसोड</string>
|
||||||
<string name="episode_action_chromecast_mirror">कक्रोमकास्ट मिरर</string>
|
<string name="episode_action_chromecast_mirror">कक्रोमकास्ट मिरर</string>
|
||||||
<string name="episode_action_play_in_app">एप्प मैं चलाये</string>
|
<string name="episode_action_play_in_app">एप्प मैं चलाये</string>
|
||||||
<string name="episode_action_play_in_vlc">VLC में चलाए</string>
|
<string name="episode_action_play_in_format">%s में चलाए</string>
|
||||||
<string name="episode_action_play_in_browser">Browser में चलाए</string>
|
<string name="episode_action_play_in_browser">Browser में चलाए</string>
|
||||||
<string name="episode_action_copy_link">लिंक कॉपी करें</string>
|
<string name="episode_action_copy_link">लिंक कॉपी करें</string>
|
||||||
<string name="episode_action_auto_download">डाउनलोड करे</string>
|
<string name="episode_action_auto_download">डाउनलोड करे</string>
|
||||||
|
|
|
@ -299,7 +299,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast epizoda</string>
|
<string name="episode_action_chromecast_episode">Chromecast epizoda</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
||||||
<string name="episode_action_play_in_app">Pokreni u aplikaciji</string>
|
<string name="episode_action_play_in_app">Pokreni u aplikaciji</string>
|
||||||
<string name="episode_action_play_in_vlc">Pokreni u VLC-u</string>
|
<string name="episode_action_play_in_format">Pokreni u %s</string>
|
||||||
<string name="episode_action_play_in_browser">Pokreni u pregledniku</string>
|
<string name="episode_action_play_in_browser">Pokreni u pregledniku</string>
|
||||||
<string name="episode_action_copy_link">Kopiraj poveznicu</string>
|
<string name="episode_action_copy_link">Kopiraj poveznicu</string>
|
||||||
<string name="episode_action_auto_download">Automatsko preuzimanje</string>
|
<string name="episode_action_auto_download">Automatsko preuzimanje</string>
|
||||||
|
|
|
@ -264,7 +264,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Episode Chromecast</string>
|
<string name="episode_action_chromecast_episode">Episode Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Mirror Chromecast</string>
|
<string name="episode_action_chromecast_mirror">Mirror Chromecast</string>
|
||||||
<string name="episode_action_play_in_app">Putar di aplikasi</string>
|
<string name="episode_action_play_in_app">Putar di aplikasi</string>
|
||||||
<string name="episode_action_play_in_vlc">Putar di VLC</string>
|
<string name="episode_action_play_in_format">Putar di %s</string>
|
||||||
<string name="episode_action_play_in_browser">Putar di browser</string>
|
<string name="episode_action_play_in_browser">Putar di browser</string>
|
||||||
<string name="episode_action_copy_link">Salin tautan</string>
|
<string name="episode_action_copy_link">Salin tautan</string>
|
||||||
<string name="episode_action_auto_download">Download otomatis</string>
|
<string name="episode_action_auto_download">Download otomatis</string>
|
||||||
|
|
|
@ -271,7 +271,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast</string>
|
<string name="episode_action_chromecast_episode">Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
||||||
<string name="episode_action_play_in_app">Riproduci in app</string>
|
<string name="episode_action_play_in_app">Riproduci in app</string>
|
||||||
<string name="episode_action_play_in_vlc">Riproduci in VLC</string>
|
<string name="episode_action_play_in_format">Riproduci in %s</string>
|
||||||
<string name="episode_action_play_in_browser">Riproduci nel browser</string>
|
<string name="episode_action_play_in_browser">Riproduci nel browser</string>
|
||||||
<string name="episode_action_copy_link">Copia link</string>
|
<string name="episode_action_copy_link">Copia link</string>
|
||||||
<string name="episode_action_auto_download">Download</string>
|
<string name="episode_action_auto_download">Download</string>
|
||||||
|
|
|
@ -190,7 +190,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Епизода на Chromecast</string>
|
<string name="episode_action_chromecast_episode">Епизода на Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Огледало на Chromecastr</string>
|
<string name="episode_action_chromecast_mirror">Огледало на Chromecastr</string>
|
||||||
<string name="episode_action_play_in_app">Пушти во апликацијата</string>
|
<string name="episode_action_play_in_app">Пушти во апликацијата</string>
|
||||||
<string name="episode_action_play_in_vlc">Пушти на VLC</string>
|
<string name="episode_action_play_in_format">Пушти на %s</string>
|
||||||
<string name="episode_action_play_in_browser">Пушти на прелистувач</string>
|
<string name="episode_action_play_in_browser">Пушти на прелистувач</string>
|
||||||
<string name="episode_action_copy_link">Копирај линк</string>
|
<string name="episode_action_copy_link">Копирај линк</string>
|
||||||
<string name="episode_action_auto_download">Авто превземање</string>
|
<string name="episode_action_auto_download">Авто превземање</string>
|
||||||
|
|
|
@ -175,7 +175,7 @@
|
||||||
<!-- <string name="episode_action_chomecast_episode">Chromecast Episode</string>
|
<!-- <string name="episode_action_chomecast_episode">Chromecast Episode</string>
|
||||||
<string name="episode_action_chomecast_mirror">Chromecast Mirror</string> -->
|
<string name="episode_action_chomecast_mirror">Chromecast Mirror</string> -->
|
||||||
<string name="episode_action_play_in_app">ആപ്പിൽ പ്ലേയ് ചെയ്യുക</string>
|
<string name="episode_action_play_in_app">ആപ്പിൽ പ്ലേയ് ചെയ്യുക</string>
|
||||||
<string name="episode_action_play_in_vlc">VLCയിൽ പ്ലേയ് ചെയ്യുക</string>
|
<string name="episode_action_play_in_format">%sയിൽ പ്ലേയ് ചെയ്യുക</string>
|
||||||
<string name="episode_action_play_in_browser">ബ്രൗസറിൽ പ്ലേയ് ചെയ്യുക</string>
|
<string name="episode_action_play_in_browser">ബ്രൗസറിൽ പ്ലേയ് ചെയ്യുക</string>
|
||||||
<string name="episode_action_copy_link">ലിങ്ക് പകർത്തുക</string>
|
<string name="episode_action_copy_link">ലിങ്ക് പകർത്തുക</string>
|
||||||
<string name="episode_action_auto_download">ഡൌൺലോഡ് ചെയ്യൂ</string>
|
<string name="episode_action_auto_download">ഡൌൺലോഡ് ചെയ്യൂ</string>
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
<string name="episode_action_chromecast_episode">aauugghhooo-ahah ohaaauugghh</string>
|
<string name="episode_action_chromecast_episode">aauugghhooo-ahah ohaaauugghh</string>
|
||||||
<string name="episode_action_chromecast_mirror">aoohaaahhu ahouuhhh</string>
|
<string name="episode_action_chromecast_mirror">aoohaaahhu ahouuhhh</string>
|
||||||
<string name="episode_action_play_in_app">ooo-ahahaauuh aaahhu</string>
|
<string name="episode_action_play_in_app">ooo-ahahaauuh aaahhu</string>
|
||||||
<string name="episode_action_play_in_vlc">ooo-ahah ohaauuh</string>
|
<string name="episode_action_play_in_format">ooo-ahah ohaauuh</string>
|
||||||
<string name="episode_action_play_in_browser">ahoha ooo-ahahohoohah oooohh</string>
|
<string name="episode_action_play_in_browser">ahoha ooo-ahahohoohah oooohh</string>
|
||||||
<string name="episode_action_copy_link">aauugghhahhaauugghh</string>
|
<string name="episode_action_copy_link">aauugghhahhaauugghh</string>
|
||||||
<string name="episode_action_auto_download">aaaghhoooohh aaahhu ahooo</string>
|
<string name="episode_action_auto_download">aaaghhoooohh aaahhu ahooo</string>
|
||||||
|
|
|
@ -274,7 +274,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast aflevering</string>
|
<string name="episode_action_chromecast_episode">Chromecast aflevering</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
||||||
<string name="episode_action_play_in_app">Speel in app</string>
|
<string name="episode_action_play_in_app">Speel in app</string>
|
||||||
<string name="episode_action_play_in_vlc">Speel in VLC</string>
|
<string name="episode_action_play_in_format">Speel in %s</string>
|
||||||
<string name="episode_action_play_in_browser">Speel in browser</string>
|
<string name="episode_action_play_in_browser">Speel in browser</string>
|
||||||
<string name="episode_action_copy_link">Kopieer link</string>
|
<string name="episode_action_copy_link">Kopieer link</string>
|
||||||
<string name="episode_action_auto_download">Automatisch downloaden</string>
|
<string name="episode_action_auto_download">Automatisch downloaden</string>
|
||||||
|
|
|
@ -196,7 +196,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Støpt Episode</string>
|
<string name="episode_action_chromecast_episode">Støpt Episode</string>
|
||||||
<string name="episode_action_chromecast_mirror">Støpt Speil</string>
|
<string name="episode_action_chromecast_mirror">Støpt Speil</string>
|
||||||
<string name="episode_action_play_in_app">Spill i appen</string>
|
<string name="episode_action_play_in_app">Spill i appen</string>
|
||||||
<string name="episode_action_play_in_vlc">Spill i VLC</string>
|
<string name="episode_action_play_in_format">Spill i %s</string>
|
||||||
<string name="episode_action_play_in_browser">Spill i nettleseren</string>
|
<string name="episode_action_play_in_browser">Spill i nettleseren</string>
|
||||||
<string name="episode_action_copy_link">Kopier link</string>
|
<string name="episode_action_copy_link">Kopier link</string>
|
||||||
<string name="episode_action_auto_download">Automatisk nedlasting</string>
|
<string name="episode_action_auto_download">Automatisk nedlasting</string>
|
||||||
|
|
|
@ -165,7 +165,7 @@
|
||||||
<item>@string/episode_action_chromecast_episode</item>
|
<item>@string/episode_action_chromecast_episode</item>
|
||||||
<item>@string/episode_action_chromecast_mirror</item>
|
<item>@string/episode_action_chromecast_mirror</item>
|
||||||
<item>@string/episode_action_play_in_app</item>
|
<item>@string/episode_action_play_in_app</item>
|
||||||
<item>@string/episode_action_play_in_vlc</item>
|
<item>@string/episode_action_play_in_format</item>
|
||||||
<item>@string/episode_action_play_in_browser</item>
|
<item>@string/episode_action_play_in_browser</item>
|
||||||
<item>@string/episode_action_copy_link</item>
|
<item>@string/episode_action_copy_link</item>
|
||||||
<item>@string/episode_action_auto_download</item>
|
<item>@string/episode_action_auto_download</item>
|
||||||
|
|
|
@ -252,7 +252,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast odcinka</string>
|
<string name="episode_action_chromecast_episode">Chromecast odcinka</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast mirroru</string>
|
<string name="episode_action_chromecast_mirror">Chromecast mirroru</string>
|
||||||
<string name="episode_action_play_in_app">Odtwórz w aplikacji</string>
|
<string name="episode_action_play_in_app">Odtwórz w aplikacji</string>
|
||||||
<string name="episode_action_play_in_vlc">Odtwórz w VLC</string>
|
<string name="episode_action_play_in_format">Odtwórz w %s</string>
|
||||||
<string name="episode_action_play_in_browser">Odtwórz w przeglądarce</string>
|
<string name="episode_action_play_in_browser">Odtwórz w przeglądarce</string>
|
||||||
<string name="episode_action_copy_link">Kopiuj link</string>
|
<string name="episode_action_copy_link">Kopiuj link</string>
|
||||||
<string name="episode_action_auto_download">Automatyczne pobieranie</string>
|
<string name="episode_action_auto_download">Automatyczne pobieranie</string>
|
||||||
|
|
|
@ -268,7 +268,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Episódio pelo Chromecast</string>
|
<string name="episode_action_chromecast_episode">Episódio pelo Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Alternativa pelo Chromecast</string>
|
<string name="episode_action_chromecast_mirror">Alternativa pelo Chromecast</string>
|
||||||
<string name="episode_action_play_in_app">Reproduzir na app</string>
|
<string name="episode_action_play_in_app">Reproduzir na app</string>
|
||||||
<string name="episode_action_play_in_vlc">Reproduzir no VLC</string>
|
<string name="episode_action_play_in_format">Reproduzir no %s</string>
|
||||||
<string name="episode_action_play_in_browser">Reproduzir no navegador</string>
|
<string name="episode_action_play_in_browser">Reproduzir no navegador</string>
|
||||||
<string name="episode_action_copy_link">Copiar link</string>
|
<string name="episode_action_copy_link">Copiar link</string>
|
||||||
<string name="episode_action_auto_download">Transferência Automática</string>
|
<string name="episode_action_auto_download">Transferência Automática</string>
|
||||||
|
|
|
@ -267,7 +267,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast</string>
|
<string name="episode_action_chromecast_episode">Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast alternativ</string>
|
<string name="episode_action_chromecast_mirror">Chromecast alternativ</string>
|
||||||
<string name="episode_action_play_in_app">Redă în Aplicație</string>
|
<string name="episode_action_play_in_app">Redă în Aplicație</string>
|
||||||
<string name="episode_action_play_in_vlc">Redă în VLC</string>
|
<string name="episode_action_play_in_format">Redă în %s</string>
|
||||||
<string name="episode_action_play_in_browser">Redă în Browser</string>
|
<string name="episode_action_play_in_browser">Redă în Browser</string>
|
||||||
<string name="episode_action_copy_link">Copiază link-ul</string>
|
<string name="episode_action_copy_link">Copiază link-ul</string>
|
||||||
<string name="episode_action_auto_download">Auto-descărcare</string>
|
<string name="episode_action_auto_download">Auto-descărcare</string>
|
||||||
|
|
|
@ -167,7 +167,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecasta ett Avsnitt</string>
|
<string name="episode_action_chromecast_episode">Chromecasta ett Avsnitt</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecasta en Länk</string>
|
<string name="episode_action_chromecast_mirror">Chromecasta en Länk</string>
|
||||||
<string name="episode_action_play_in_app">Spela upp i appen</string>
|
<string name="episode_action_play_in_app">Spela upp i appen</string>
|
||||||
<string name="episode_action_play_in_vlc">Spela upp i VLC</string>
|
<string name="episode_action_play_in_format">Spela upp i %s</string>
|
||||||
<string name="episode_action_play_in_browser">Spela upp i webbläsaren</string>
|
<string name="episode_action_play_in_browser">Spela upp i webbläsaren</string>
|
||||||
<string name="episode_action_copy_link">Kopiera länk</string>
|
<string name="episode_action_copy_link">Kopiera länk</string>
|
||||||
<string name="episode_action_auto_download">Automatisk nerladdning</string>
|
<string name="episode_action_auto_download">Automatisk nerladdning</string>
|
||||||
|
|
|
@ -204,7 +204,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast Episode</string>
|
<string name="episode_action_chromecast_episode">Chromecast Episode</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast Mirror</string>
|
<string name="episode_action_chromecast_mirror">Chromecast Mirror</string>
|
||||||
<string name="episode_action_play_in_app">I-play sa App</string>
|
<string name="episode_action_play_in_app">I-play sa App</string>
|
||||||
<string name="episode_action_play_in_vlc">I-play sa VLC</string>
|
<string name="episode_action_play_in_format">I-play sa %s</string>
|
||||||
<string name="episode_action_play_in_browser">I-play sa browser</string>
|
<string name="episode_action_play_in_browser">I-play sa browser</string>
|
||||||
<string name="episode_action_copy_link">Kopyahin ang Link</string>
|
<string name="episode_action_copy_link">Kopyahin ang Link</string>
|
||||||
<string name="episode_action_auto_download">Awtomatiking i-download</string>
|
<string name="episode_action_auto_download">Awtomatiking i-download</string>
|
||||||
|
|
|
@ -14,6 +14,41 @@
|
||||||
<item>@id/cast_button_type_forward_30_seconds</item>
|
<item>@id/cast_button_type_forward_30_seconds</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<array name="dns_pref">
|
||||||
|
<item>@string/none</item>
|
||||||
|
<item>Google</item>
|
||||||
|
<item>Cloudflare</item>
|
||||||
|
<!-- <item>OpenDns</item>-->
|
||||||
|
<item>AdGuard</item>
|
||||||
|
<item>DNS.WATCH</item>
|
||||||
|
<item>Quad9</item>
|
||||||
|
</array>
|
||||||
|
<array name="dns_pref_values">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<!-- <item>3</item>-->
|
||||||
|
<item>4</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>6</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="player_pref_names">
|
||||||
|
<item>@string/player_settings_play_in_app</item>
|
||||||
|
<item>@string/player_settings_play_in_vlc</item>
|
||||||
|
<item>@string/player_settings_play_in_mpv</item>
|
||||||
|
<item>@string/player_settings_play_in_web</item>
|
||||||
|
<item>@string/player_settings_play_in_browser</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="player_pref_values">
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>4</item>
|
||||||
|
<item>3</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
<array name="limit_title_rez_pref_names">
|
<array name="limit_title_rez_pref_names">
|
||||||
<item>@string/resolution_and_title</item>
|
<item>@string/resolution_and_title</item>
|
||||||
<item>@string/title</item>
|
<item>@string/title</item>
|
||||||
|
@ -156,7 +191,7 @@
|
||||||
<item>@string/episode_action_chromecast_episode</item>
|
<item>@string/episode_action_chromecast_episode</item>
|
||||||
<item>@string/episode_action_chromecast_mirror</item>
|
<item>@string/episode_action_chromecast_mirror</item>
|
||||||
<item>@string/episode_action_play_in_app</item>
|
<item>@string/episode_action_play_in_app</item>
|
||||||
<item>@string/episode_action_play_in_vlc</item>
|
<item>@string/episode_action_play_in_format</item>
|
||||||
<item>@string/episode_action_play_in_browser</item>
|
<item>@string/episode_action_play_in_browser</item>
|
||||||
<item>@string/episode_action_copy_link</item>
|
<item>@string/episode_action_copy_link</item>
|
||||||
<item>@string/episode_action_auto_download</item>
|
<item>@string/episode_action_auto_download</item>
|
||||||
|
@ -210,7 +245,7 @@
|
||||||
<item>Parti</item>
|
<item>Parti</item>
|
||||||
<item>Pembe</item>
|
<item>Pembe</item>
|
||||||
<item>Material You</item>
|
<item>Material You</item>
|
||||||
<item>Material You (Secondary)</item>
|
<item>Material You (İkincil)</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="themes_overlay_names_values">
|
<string-array name="themes_overlay_names_values">
|
||||||
<item>Normal</item>
|
<item>Normal</item>
|
||||||
|
@ -233,7 +268,6 @@
|
||||||
<item>Monet2</item>
|
<item>Monet2</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
|
||||||
<string-array name="themes_names">
|
<string-array name="themes_names">
|
||||||
<item>Koyu</item>
|
<item>Koyu</item>
|
||||||
<item>Gri</item>
|
<item>Gri</item>
|
||||||
|
@ -249,6 +283,14 @@
|
||||||
<item>Monet</item>
|
<item>Monet</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="extension_statuses">
|
||||||
|
<item>Çöktü</item>
|
||||||
|
<!-- "Ok" is usually capitalized as "OK". Ok android studio 🤓-->
|
||||||
|
<item>Ok</item>
|
||||||
|
<item>Yavaş</item>
|
||||||
|
<item>Beta</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->
|
<!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->
|
||||||
<string-array name="subtitles_encoding_list" tools:ignore="TypographyDashes">
|
<string-array name="subtitles_encoding_list" tools:ignore="TypographyDashes">
|
||||||
<item>@string/automatic</item>
|
<item>@string/automatic</item>
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
<!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
|
<!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
|
||||||
<resources>
|
<resources>
|
||||||
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
||||||
|
<string name="extra_info_format" formatted="true" translatable="false">%d %s | %s</string>
|
||||||
|
<string name="storage_size_format" formatted="true" translatable="false">%s • %s</string>
|
||||||
|
<string name="download_size_format" formatted="true" translatable="false">%s / %s</string>
|
||||||
|
<string name="episode_name_format" formatted="true" translatable="false">%s %s</string>
|
||||||
|
<string name="ffw_text_format" formatted="true" translatable="false">+%d</string>
|
||||||
|
<string name="rew_text_format" formatted="true" translatable="false">-%d</string>
|
||||||
|
<string name="ffw_text_regular_format" formatted="true" translatable="false">%d</string>
|
||||||
|
<string name="rew_text_regular_format" formatted="true" translatable="false">%d</string>
|
||||||
|
<string name="rating_format" formatted="true" translatable="false">%.1f/10.0</string>
|
||||||
|
<string name="year_format" formatted="true" translatable="false">%d</string>
|
||||||
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
|
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
|
||||||
<string name="cast_format" formatted="true">Cast: %s</string>
|
<string name="cast_format" formatted="true">Cast: %s</string>
|
||||||
<string name="next_episode_format" formatted="true">Bölüm %d şu tarihte yayınlanacak: </string>
|
<string name="next_episode_format" formatted="true">Bölüm %d şu tarihte yayınlanacak: </string>
|
||||||
|
@ -14,7 +24,9 @@
|
||||||
<string name="episode_poster_img_des">Episode Poster</string>
|
<string name="episode_poster_img_des">Episode Poster</string>
|
||||||
<string name="home_main_poster_img_des">Main Poster</string>
|
<string name="home_main_poster_img_des">Main Poster</string>
|
||||||
<string name="home_next_random_img_des">Next Random</string>
|
<string name="home_next_random_img_des">Next Random</string>
|
||||||
|
<string name="episode_play_img_des" translatable="false">@string/play_episode</string>
|
||||||
<string name="go_back_img_des">Go back</string>
|
<string name="go_back_img_des">Go back</string>
|
||||||
|
<string name="change_providers_img_des" translatable="false">@string/home_change_provider_img_des</string>
|
||||||
<string name="home_change_provider_img_des">Change Provider</string>
|
<string name="home_change_provider_img_des">Change Provider</string>
|
||||||
<string name="preview_background_img_des">Preview Background</string>
|
<string name="preview_background_img_des">Preview Background</string>
|
||||||
|
|
||||||
|
@ -38,6 +50,7 @@
|
||||||
<string name="no_data">Veri yok</string>
|
<string name="no_data">Veri yok</string>
|
||||||
<string name="episode_more_options_des">Daha fazla seçenek</string>
|
<string name="episode_more_options_des">Daha fazla seçenek</string>
|
||||||
<string name="next_episode">Sonraki bölüm</string>
|
<string name="next_episode">Sonraki bölüm</string>
|
||||||
|
<string name="result_plot" translatable="false">@string/synopsis</string>
|
||||||
<string name="result_tags">Türler</string>
|
<string name="result_tags">Türler</string>
|
||||||
<string name="result_share">Paylaş</string>
|
<string name="result_share">Paylaş</string>
|
||||||
<string name="result_open_in_browser">Tarayıcıda aç</string>
|
<string name="result_open_in_browser">Tarayıcıda aç</string>
|
||||||
|
@ -70,6 +83,7 @@
|
||||||
<string name="download_failed">İndirme başarısız oldu</string>
|
<string name="download_failed">İndirme başarısız oldu</string>
|
||||||
<string name="download_canceled">İndirme iptal edildi</string>
|
<string name="download_canceled">İndirme iptal edildi</string>
|
||||||
<string name="download_done">İndirme bitti</string>
|
<string name="download_done">İndirme bitti</string>
|
||||||
|
<string name="download_format" translatable="false">%s - %s</string>
|
||||||
<string name="stream">Yayınla</string>
|
<string name="stream">Yayınla</string>
|
||||||
|
|
||||||
<string name="error_loading_links_toast">Bağlantılar yüklenirken hata oluştu</string>
|
<string name="error_loading_links_toast">Bağlantılar yüklenirken hata oluştu</string>
|
||||||
|
@ -149,11 +163,15 @@
|
||||||
<string name="chromecast_subtitles_settings_des">Chromecast alt yazı ayarları</string>
|
<string name="chromecast_subtitles_settings_des">Chromecast alt yazı ayarları</string>
|
||||||
|
|
||||||
<string name="eigengraumode_settings">Eigengravy modu</string>
|
<string name="eigengraumode_settings">Eigengravy modu</string>
|
||||||
<string name="eigengraumode_settings_des">Oynatıcıya bir hız seçeneği ekler</string>
|
<string name="eigengraumode_settings_des">Oynatıcıya bir hız seçeneği ekle</string>
|
||||||
<string name="swipe_to_seek_settings">Gözlemek için kaydır</string>
|
<string name="swipe_to_seek_settings">Gözlemek için kaydır</string>
|
||||||
<string name="swipe_to_seek_settings_des">Zamanı ayarlamak için sağa veya sola kaydır</string>
|
<string name="swipe_to_seek_settings_des">Zamanı ayarlamak için sağa veya sola kaydır</string>
|
||||||
<string name="swipe_to_change_settings">Ayarları değiştirmek için kaydır</string>
|
<string name="swipe_to_change_settings">Ayarları değiştirmek için kaydır</string>
|
||||||
<string name="swipe_to_change_settings_des">Sol ve sağ taraftan kaydırarak parlaklık ve sesi ayarla</string>
|
<string name="swipe_to_change_settings_des">Sol ve sağ taraftan kaydırarak parlaklık ve sesi ayarla</string>
|
||||||
|
|
||||||
|
<string name="autoplay_next_settings">Sonraki bölümü otomatik oynat</string>
|
||||||
|
<string name="autoplay_next_settings_des">Mevcut bölüm bittiğinde sonraki bölüme başla</string>
|
||||||
|
|
||||||
<string name="double_tap_to_seek_settings">Gözlemek için çift tıkla</string>
|
<string name="double_tap_to_seek_settings">Gözlemek için çift tıkla</string>
|
||||||
<string name="double_tap_to_pause_settings">Durdurmak için çift tıkla</string>
|
<string name="double_tap_to_pause_settings">Durdurmak için çift tıkla</string>
|
||||||
<string name="double_tap_to_seek_amount_settings">Oynatıcı gözleme miktarı</string>
|
<string name="double_tap_to_seek_amount_settings">Oynatıcı gözleme miktarı</string>
|
||||||
|
@ -180,13 +198,15 @@
|
||||||
|
|
||||||
<string name="settings_info">Bilgi</string>
|
<string name="settings_info">Bilgi</string>
|
||||||
<string name="advanced_search">Gelişmiş arama</string>
|
<string name="advanced_search">Gelişmiş arama</string>
|
||||||
<string name="advanced_search_des">Sağlayıcılara göre ayrılmış arama sonuçlarını verir</string>
|
<string name="advanced_search_des">Sağlayıcılara göre ayrılmış arama sonuçlarını ver</string>
|
||||||
<string name="bug_report_settings_off">Yalnızca çökmelerle ilgili verileri gönderir</string>
|
<string name="bug_report_settings_off">Yalnızca çökmelerle ilgili verileri gönderir</string>
|
||||||
<string name="bug_report_settings_on">Hiç veri göndermez</string>
|
<string name="bug_report_settings_on">Hiç veri göndermez</string>
|
||||||
<string name="show_fillers_settings">Anime için filler bölümleri gösterir</string>
|
<string name="show_fillers_settings">Anime için filler bölümleri gösterir</string>
|
||||||
<string name="show_trailers_settings">Fragmanları göster</string>
|
<string name="show_trailers_settings">Fragmanları göster</string>
|
||||||
<string name="kitsu_settings">Kitsu\'dan posterleri göster</string>
|
<string name="kitsu_settings">Kitsu\'dan posterleri göster</string>
|
||||||
|
<string name="pref_filter_search_quality">Arama sonuçlarında seçilen video kalitelerini gizle</string>
|
||||||
|
|
||||||
|
<string name="automatic_plugin_updates">Otomatik eklenti güncellemeleri</string>
|
||||||
<string name="updates_settings">Uygulama güncellemelerini göster</string>
|
<string name="updates_settings">Uygulama güncellemelerini göster</string>
|
||||||
<string name="updates_settings_des">Başlangıçta yeni güncellemeleri otomatik olarak ara</string>
|
<string name="updates_settings_des">Başlangıçta yeni güncellemeleri otomatik olarak ara</string>
|
||||||
<string name="uprereleases_settings">Ön sürümlere güncelle</string>
|
<string name="uprereleases_settings">Ön sürümlere güncelle</string>
|
||||||
|
@ -208,15 +228,19 @@
|
||||||
<string name="acra_report_toast">Üzgünüz, uygulama çöktü. Geliştiricilere isimsiz bir hata raporu gönderilecek</string>
|
<string name="acra_report_toast">Üzgünüz, uygulama çöktü. Geliştiricilere isimsiz bir hata raporu gönderilecek</string>
|
||||||
|
|
||||||
<string name="season">Sezon</string>
|
<string name="season">Sezon</string>
|
||||||
|
<string name="season_format">%s %d%s</string>
|
||||||
<string name="no_season">Sezon yok</string>
|
<string name="no_season">Sezon yok</string>
|
||||||
<string name="episode">Bölüm</string>
|
<string name="episode">Bölüm</string>
|
||||||
<string name="episodes">Bölümler</string>
|
<string name="episodes">Bölümler</string>
|
||||||
|
<string name="episodes_range">%d-%d</string>
|
||||||
|
<string name="episode_format" formatted="true">%d %s</string>
|
||||||
<string name="season_short">S</string>
|
<string name="season_short">S</string>
|
||||||
<string name="episode_short">B</string>
|
<string name="episode_short">B</string>
|
||||||
<string name="no_episodes_found">Bölüm bulunamadı</string>
|
<string name="no_episodes_found">Bölüm bulunamadı</string>
|
||||||
|
|
||||||
<string name="delete_file">Dosyayı sil</string>
|
<string name="delete_file">Dosyayı sil</string>
|
||||||
<string name="delete">Sil</string>
|
<string name="delete">Sil</string>
|
||||||
|
<string name="cancel" translatable="false">@string/sort_cancel</string>
|
||||||
<string name="pause">Durdur</string>
|
<string name="pause">Durdur</string>
|
||||||
<string name="resume">Sürdür</string>
|
<string name="resume">Sürdür</string>
|
||||||
<string name="go_back_30">-30</string>
|
<string name="go_back_30">-30</string>
|
||||||
|
@ -251,6 +275,8 @@
|
||||||
<string name="ova">OVA</string>
|
<string name="ova">OVA</string>
|
||||||
<string name="asian_drama">Asya dramaları</string>
|
<string name="asian_drama">Asya dramaları</string>
|
||||||
<string name="livestreams">Canlı yayınlar</string>
|
<string name="livestreams">Canlı yayınlar</string>
|
||||||
|
<string name="nsfw">NSFW</string>
|
||||||
|
<string name="others">Diğerleri</string>
|
||||||
|
|
||||||
<!--singular-->
|
<!--singular-->
|
||||||
<string name="movies_singular">Film</string>
|
<string name="movies_singular">Film</string>
|
||||||
|
@ -262,6 +288,8 @@
|
||||||
<string name="documentaries_singular">Belgesel</string>
|
<string name="documentaries_singular">Belgesel</string>
|
||||||
<string name="asian_drama_singular">Asya draması</string>
|
<string name="asian_drama_singular">Asya draması</string>
|
||||||
<string name="live_singular">Canlı yayın</string>
|
<string name="live_singular">Canlı yayın</string>
|
||||||
|
<string name="nsfw_singular">NSFW</string>
|
||||||
|
<string name="other_singular">Video</string>
|
||||||
|
|
||||||
<string name="source_error">Kaynak hatası</string>
|
<string name="source_error">Kaynak hatası</string>
|
||||||
<string name="remote_error">Sunucu hatası</string>
|
<string name="remote_error">Sunucu hatası</string>
|
||||||
|
@ -272,7 +300,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Bölümü Chromecast ile yayınla</string>
|
<string name="episode_action_chromecast_episode">Bölümü Chromecast ile yayınla</string>
|
||||||
<string name="episode_action_chromecast_mirror">Bağlantıyı Chromecast ile yayınla</string>
|
<string name="episode_action_chromecast_mirror">Bağlantıyı Chromecast ile yayınla</string>
|
||||||
<string name="episode_action_play_in_app">Uygulamada oynat</string>
|
<string name="episode_action_play_in_app">Uygulamada oynat</string>
|
||||||
<string name="episode_action_play_in_vlc">VLC\'de oynat</string>
|
<string name="episode_action_play_in_format">%s\'de\/da oynat</string>
|
||||||
<string name="episode_action_play_in_browser">Tarayıcıda oynat</string>
|
<string name="episode_action_play_in_browser">Tarayıcıda oynat</string>
|
||||||
<string name="episode_action_copy_link">Linki kopyala</string>
|
<string name="episode_action_copy_link">Linki kopyala</string>
|
||||||
<string name="episode_action_auto_download">Otomatik indir</string>
|
<string name="episode_action_auto_download">Otomatik indir</string>
|
||||||
|
@ -284,6 +312,10 @@
|
||||||
<string name="show_dub">Dublaj etiketi</string>
|
<string name="show_dub">Dublaj etiketi</string>
|
||||||
<string name="show_sub">Alt yazı etiketi</string>
|
<string name="show_sub">Alt yazı etiketi</string>
|
||||||
<string name="show_title">Başlık</string>
|
<string name="show_title">Başlık</string>
|
||||||
|
<string name="show_hd_key" translatable="false">show_hd_key</string>
|
||||||
|
<string name="show_dub_key" translatable="false">show_dub_key</string>
|
||||||
|
<string name="show_sub_key" translatable="false">show_sub_key</string>
|
||||||
|
<string name="show_title_key" translatable="false">show_title_key</string>
|
||||||
<string name="poster_ui_settings">Poster üzerindeki öğeler</string>
|
<string name="poster_ui_settings">Poster üzerindeki öğeler</string>
|
||||||
|
|
||||||
<string name="no_update_found">Güncelleme bulunamadı</string>
|
<string name="no_update_found">Güncelleme bulunamadı</string>
|
||||||
|
@ -327,6 +359,7 @@
|
||||||
<string name="resize_zoom">Yakınlaştır</string>
|
<string name="resize_zoom">Yakınlaştır</string>
|
||||||
|
|
||||||
<string name="legal_notice">Disclaimer</string>
|
<string name="legal_notice">Disclaimer</string>
|
||||||
|
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
|
||||||
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
|
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
|
||||||
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
|
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
|
||||||
|
|
||||||
|
@ -349,7 +382,9 @@
|
||||||
<string name="provider_lang_settings">Sağlayıcı dilleri</string>
|
<string name="provider_lang_settings">Sağlayıcı dilleri</string>
|
||||||
<string name="app_layout">Uygulama düzeni</string>
|
<string name="app_layout">Uygulama düzeni</string>
|
||||||
<string name="preferred_media_settings">Tercih edilen medya</string>
|
<string name="preferred_media_settings">Tercih edilen medya</string>
|
||||||
|
<string name="enable_nsfw_on_providers">Desteklenen sağlayıcılarda NSFW\'yi etkinleştir</string>
|
||||||
<string name="subtitles_encoding">Alt yazı kodlaması</string>
|
<string name="subtitles_encoding">Alt yazı kodlaması</string>
|
||||||
|
<string name="category_providers">Sağlayıcılar</string>
|
||||||
<string name="category_ui">Düzen</string>
|
<string name="category_ui">Düzen</string>
|
||||||
|
|
||||||
<string name="automatic">Otomatik</string>
|
<string name="automatic">Otomatik</string>
|
||||||
|
@ -364,6 +399,10 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- account stuff -->
|
<!-- account stuff -->
|
||||||
|
<string name="anilist_key" translatable="false">anilist_key</string>
|
||||||
|
<string name="mal_key" translatable="false">mal_key</string>
|
||||||
|
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
|
||||||
|
<string name="nginx_key" translatable="false">nginx_key</string>
|
||||||
<string name="example_password">şifre123</string>
|
<string name="example_password">şifre123</string>
|
||||||
<string name="example_username">HavalıKullanıcıAdı</string>
|
<string name="example_username">HavalıKullanıcıAdı</string>
|
||||||
<string name="example_email">hello@world.com</string>
|
<string name="example_email">hello@world.com</string>
|
||||||
|
@ -403,6 +442,7 @@
|
||||||
<string name="all">Hepsi</string>
|
<string name="all">Hepsi</string>
|
||||||
<string name="max">Maksimum</string>
|
<string name="max">Maksimum</string>
|
||||||
<string name="min">Minimum</string>
|
<string name="min">Minimum</string>
|
||||||
|
<string name="subtitles_none" translatable="false">@string/none</string>
|
||||||
<string name="subtitles_outline">Dış hat</string>
|
<string name="subtitles_outline">Dış hat</string>
|
||||||
<string name="subtitles_depressed">Çökmüş</string>
|
<string name="subtitles_depressed">Çökmüş</string>
|
||||||
<string name="subtitles_shadow">Gölge</string>
|
<string name="subtitles_shadow">Gölge</string>
|
||||||
|
@ -464,6 +504,7 @@
|
||||||
<string name="error">Hata</string>
|
<string name="error">Hata</string>
|
||||||
<string name="subtitles_remove_captions">Alt yazılardan seçmeli alt yazıyı kaldır</string>
|
<string name="subtitles_remove_captions">Alt yazılardan seçmeli alt yazıyı kaldır</string>
|
||||||
<string name="subtitles_remove_bloat">Alt yazılardaki şişkinliği kaldır</string>
|
<string name="subtitles_remove_bloat">Alt yazılardaki şişkinliği kaldır</string>
|
||||||
|
<string name="subtitles_filter_lang">Tercih edilen medya diline göre filtrele</string>
|
||||||
<string name="extras">Ekstralar</string>
|
<string name="extras">Ekstralar</string>
|
||||||
<string name="trailer">Fragman</string>
|
<string name="trailer">Fragman</string>
|
||||||
<string name="network_adress_example">Yayına bağlan</string>
|
<string name="network_adress_example">Yayına bağlan</string>
|
||||||
|
@ -476,5 +517,61 @@
|
||||||
<string name="crash_reporting_title">Çökme raporları</string>
|
<string name="crash_reporting_title">Çökme raporları</string>
|
||||||
<string name="preferred_media_subtext">Ne izlemek istiyorsunuz?</string>
|
<string name="preferred_media_subtext">Ne izlemek istiyorsunuz?</string>
|
||||||
<string name="setup_done">Bitti</string>
|
<string name="setup_done">Bitti</string>
|
||||||
|
<string name="extensions">Eklentiler</string>
|
||||||
|
<string name="add_repository">Depo ekle</string>
|
||||||
|
<string name="repository_name_hint">Depo ismi</string>
|
||||||
|
<string name="repository_url_hint">Depo URL\'i</string>
|
||||||
|
<string name="plugin_loaded">Eklenti yüklendi</string>
|
||||||
|
<string name="plugin_deleted">Eklenti silindi</string>
|
||||||
|
<string name="plugin_load_fail" formatted="true">%s yüklenemedi</string>
|
||||||
|
<string name="is_adult">+18</string>
|
||||||
|
<string name="batch_download_start_format" formatted="true">%d %s indirilmeye başlandı</string>
|
||||||
|
<string name="batch_download_finish_format" formatted="true">%d %s başarıyla indirildi</string>
|
||||||
|
<string name="batch_download_nothing_to_download_format" formatted="true">%s\'nin tamamı zaten indirildi</string>
|
||||||
|
<string name="batch_download">Toplu indir</string>
|
||||||
|
<string name="plugin_singular">eklenti</string>
|
||||||
|
<string name="plugin">eklentiler</string>
|
||||||
|
<string name="delete_repository_plugins">Bu aynı zamanda tüm depo eklentilerini de siler</string>
|
||||||
|
<string name="delete_repository">Depoyu sil</string>
|
||||||
|
<string name="setup_extensions_subtext">Kullanmak istediğiniz sitelerin listesini indirin</string>
|
||||||
|
<string name="plugins_downloaded" formatted="true">İndirilen: %d</string>
|
||||||
|
<string name="plugins_disabled" formatted="true">Devre dışı: %d</string>
|
||||||
|
<string name="plugins_not_downloaded" formatted="true">İndirilmeyen: %d</string>
|
||||||
|
<string name="plugins_updated" formatted="true">%d eklenti(ler) güncellendi</string>
|
||||||
|
<string name="blank_repo_message">Site eklentilerini yüklemek için bir depo ekleyin</string>
|
||||||
|
<string name="view_public_repositories_button">Topluluk depolarını görüntüle</string>
|
||||||
|
<string name="view_public_repositories_button_short">Herkese açık liste</string>
|
||||||
|
<string name="uppercase_all_subtitles">Tüm alt yazılar büyük harf</string>
|
||||||
|
|
||||||
|
<string name="download_all_plugins_from_repo">Bu depodaki tüm eklentiler indirilsin mi?</string>
|
||||||
|
<string name="single_plugin_disabled" formatted="true">%s devre dışı bırakıldı</string>
|
||||||
|
<string name="tracks">Parçalar</string>
|
||||||
|
<string name="audio_tracks">Ses parçaları</string>
|
||||||
|
<string name="video_tracks">Video parçaları</string>
|
||||||
|
<string name="apply_on_restart">Yeniden başlatmada uygula</string>
|
||||||
|
|
||||||
|
<string name="safe_mode_title">Güvenli mod etkin</string>
|
||||||
|
<string name="safe_mode_description">Kurtarılamaz bir çökme meydana geldi ve soruna neden olan eklentiyi bulup kaldırabilmeniz için tüm eklentileri otomatik olarak devre dışı bıraktık.</string>
|
||||||
|
<string name="safe_mode_crash_info">Çökme bilgisini göster</string>
|
||||||
|
|
||||||
|
<string name="extension_rating" formatted="true">Puan: %s</string>
|
||||||
|
<string name="extension_description">Açıklama</string>
|
||||||
|
<string name="extension_version">Versiyon</string>
|
||||||
|
<string name="extension_status">Durum</string>
|
||||||
|
<string name="extension_size">Boyut</string>
|
||||||
|
<string name="extension_authors">Geliştiriciler</string>
|
||||||
|
<string name="extension_types">Desteklenen</string>
|
||||||
|
<string name="extension_language">Dil</string>
|
||||||
|
<string name="extension_install_first">Önce eklentiyi yükleyin</string>
|
||||||
|
|
||||||
|
<string name="hls_playlist">HLS Oynatma Listesi</string>
|
||||||
|
|
||||||
|
<string name="player_pref">Tercih edilen video oynatıcısı</string>
|
||||||
|
<string name="player_settings_play_in_app">Dahili oynatıcı</string>
|
||||||
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
|
<string name="player_settings_play_in_mpv">MPV</string>
|
||||||
|
<string name="player_settings_play_in_web">Web Video Yayını</string>
|
||||||
|
<string name="player_settings_play_in_browser">Tarayıcı</string>
|
||||||
|
<string name="app_not_found_error">Uygulama bulunamadı</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@
|
||||||
<item>@string/episode_action_chromecast_episode</item>
|
<item>@string/episode_action_chromecast_episode</item>
|
||||||
<item>@string/episode_action_chromecast_mirror</item>
|
<item>@string/episode_action_chromecast_mirror</item>
|
||||||
<item>@string/episode_action_play_in_app</item>
|
<item>@string/episode_action_play_in_app</item>
|
||||||
<item>@string/episode_action_play_in_vlc</item>
|
<item>@string/episode_action_play_in_format</item>
|
||||||
<item>@string/episode_action_play_in_browser</item>
|
<item>@string/episode_action_play_in_browser</item>
|
||||||
<item>@string/episode_action_copy_link</item>
|
<item>@string/episode_action_copy_link</item>
|
||||||
<item>@string/episode_action_auto_download</item>
|
<item>@string/episode_action_auto_download</item>
|
||||||
|
|
|
@ -292,7 +292,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Tập Chromecast</string>
|
<string name="episode_action_chromecast_episode">Tập Chromecast</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chiếu Chromecast</string>
|
<string name="episode_action_chromecast_mirror">Chiếu Chromecast</string>
|
||||||
<string name="episode_action_play_in_app">Xem với trình phát mặc định</string>
|
<string name="episode_action_play_in_app">Xem với trình phát mặc định</string>
|
||||||
<string name="episode_action_play_in_vlc">Xem với trình phát VLC</string>
|
<string name="episode_action_play_in_format">Xem với trình phát %s</string>
|
||||||
<string name="episode_action_play_in_browser">Xem tại trình duyệt</string>
|
<string name="episode_action_play_in_browser">Xem tại trình duyệt</string>
|
||||||
<string name="episode_action_copy_link">Sao chép liên kết</string>
|
<string name="episode_action_copy_link">Sao chép liên kết</string>
|
||||||
<string name="episode_action_auto_download">Tự động tải xuống</string>
|
<string name="episode_action_auto_download">Tự động tải xuống</string>
|
||||||
|
|
|
@ -303,7 +303,7 @@
|
||||||
<string name="episode_action_chromecast_episode">投屏剧集</string>
|
<string name="episode_action_chromecast_episode">投屏剧集</string>
|
||||||
<string name="episode_action_chromecast_mirror">投屏镜像</string>
|
<string name="episode_action_chromecast_mirror">投屏镜像</string>
|
||||||
<string name="episode_action_play_in_app">在应用中播放</string>
|
<string name="episode_action_play_in_app">在应用中播放</string>
|
||||||
<string name="episode_action_play_in_vlc">在 VLC 中播放</string>
|
<string name="episode_action_play_in_format">在 %s 中播放</string>
|
||||||
<string name="episode_action_play_in_browser">在浏览器中播放</string>
|
<string name="episode_action_play_in_browser">在浏览器中播放</string>
|
||||||
<string name="episode_action_copy_link">复制链接</string>
|
<string name="episode_action_copy_link">复制链接</string>
|
||||||
<string name="episode_action_auto_download">自动下载</string>
|
<string name="episode_action_auto_download">自动下载</string>
|
||||||
|
|
|
@ -33,6 +33,22 @@
|
||||||
<item>6</item>
|
<item>6</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<array name="player_pref_names">
|
||||||
|
<item>@string/player_settings_play_in_app</item>
|
||||||
|
<item>@string/player_settings_play_in_vlc</item>
|
||||||
|
<item>@string/player_settings_play_in_mpv</item>
|
||||||
|
<item>@string/player_settings_play_in_web</item>
|
||||||
|
<item>@string/player_settings_play_in_browser</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<array name="player_pref_values">
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>5</item>
|
||||||
|
<item>4</item>
|
||||||
|
<item>3</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
<array name="limit_title_rez_pref_names">
|
<array name="limit_title_rez_pref_names">
|
||||||
<item>@string/resolution_and_title</item>
|
<item>@string/resolution_and_title</item>
|
||||||
<item>@string/title</item>
|
<item>@string/title</item>
|
||||||
|
@ -175,7 +191,7 @@
|
||||||
<item>@string/episode_action_chromecast_episode</item>
|
<item>@string/episode_action_chromecast_episode</item>
|
||||||
<item>@string/episode_action_chromecast_mirror</item>
|
<item>@string/episode_action_chromecast_mirror</item>
|
||||||
<item>@string/episode_action_play_in_app</item>
|
<item>@string/episode_action_play_in_app</item>
|
||||||
<item>@string/episode_action_play_in_vlc</item>
|
<item>@string/episode_action_play_in_format</item>
|
||||||
<item>@string/episode_action_play_in_browser</item>
|
<item>@string/episode_action_play_in_browser</item>
|
||||||
<item>@string/episode_action_copy_link</item>
|
<item>@string/episode_action_copy_link</item>
|
||||||
<item>@string/episode_action_auto_download</item>
|
<item>@string/episode_action_auto_download</item>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<string name="subtitle_settings_key" translatable="false">subtitle_settings_key</string>
|
<string name="subtitle_settings_key" translatable="false">subtitle_settings_key</string>
|
||||||
<string name="subtitle_settings_chromecast_key" translatable="false">subtitle_settings_chromecast_key</string>
|
<string name="subtitle_settings_chromecast_key" translatable="false">subtitle_settings_chromecast_key</string>
|
||||||
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
|
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
|
||||||
|
<string name="player_pref_key" translatable="false">player_pref_key</string>
|
||||||
<string name="prefer_limit_title_key" translatable="false">prefer_limit_title_key</string>
|
<string name="prefer_limit_title_key" translatable="false">prefer_limit_title_key</string>
|
||||||
<string name="prefer_limit_title_rez_key" translatable="false">prefer_limit_title_rez_key</string>
|
<string name="prefer_limit_title_rez_key" translatable="false">prefer_limit_title_rez_key</string>
|
||||||
<string name="video_buffer_size_key" translatable="false">video_buffer_size_key</string>
|
<string name="video_buffer_size_key" translatable="false">video_buffer_size_key</string>
|
||||||
|
@ -363,7 +364,7 @@
|
||||||
<string name="episode_action_chromecast_episode">Chromecast episode</string>
|
<string name="episode_action_chromecast_episode">Chromecast episode</string>
|
||||||
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
<string name="episode_action_chromecast_mirror">Chromecast mirror</string>
|
||||||
<string name="episode_action_play_in_app">Play in app</string>
|
<string name="episode_action_play_in_app">Play in app</string>
|
||||||
<string name="episode_action_play_in_vlc">Play in VLC</string>
|
<string name="episode_action_play_in_format">Play in %s</string>
|
||||||
<string name="episode_action_play_in_browser">Play in browser</string>
|
<string name="episode_action_play_in_browser">Play in browser</string>
|
||||||
<string name="episode_action_copy_link">Copy link</string>
|
<string name="episode_action_copy_link">Copy link</string>
|
||||||
<string name="episode_action_auto_download">Auto download</string>
|
<string name="episode_action_auto_download">Auto download</string>
|
||||||
|
@ -601,7 +602,7 @@
|
||||||
<string name="plugins_disabled" formatted="true">Disabled: %d</string>
|
<string name="plugins_disabled" formatted="true">Disabled: %d</string>
|
||||||
<string name="plugins_not_downloaded" formatted="true">Not downloaded: %d</string>
|
<string name="plugins_not_downloaded" formatted="true">Not downloaded: %d</string>
|
||||||
<string name="plugins_updated" formatted="true">Updated %d plugins</string>
|
<string name="plugins_updated" formatted="true">Updated %d plugins</string>
|
||||||
<string name="blank_repo_message">Add a repository to install site extensions</string>
|
<string name="blank_repo_message">CloudStream has no sites installed by default. You need to install the sites from repositories.\n\nBecause of a brainless DMCA takedown by Sky Uk Limited 🤮 we cannot link the repository sites in app.\n\nJoin our discord for links or search online.</string>
|
||||||
<string name="view_public_repositories_button">View community repositories</string>
|
<string name="view_public_repositories_button">View community repositories</string>
|
||||||
<string name="view_public_repositories_button_short">Public list</string>
|
<string name="view_public_repositories_button_short">Public list</string>
|
||||||
<string name="uppercase_all_subtitles">Uppercase all subtitles</string>
|
<string name="uppercase_all_subtitles">Uppercase all subtitles</string>
|
||||||
|
@ -628,4 +629,12 @@
|
||||||
<string name="extension_install_first">Install the extension first</string>
|
<string name="extension_install_first">Install the extension first</string>
|
||||||
|
|
||||||
<string name="hls_playlist">HLS Playlist</string>
|
<string name="hls_playlist">HLS Playlist</string>
|
||||||
|
|
||||||
|
<string name="player_pref">Preferred video player</string>
|
||||||
|
<string name="player_settings_play_in_app">Internal player</string>
|
||||||
|
<string name="player_settings_play_in_vlc">VLC</string>
|
||||||
|
<string name="player_settings_play_in_mpv">MPV</string>
|
||||||
|
<string name="player_settings_play_in_web">Web Video Cast</string>
|
||||||
|
<string name="player_settings_play_in_browser">Browser</string>
|
||||||
|
<string name="app_not_found_error">App not found</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -18,6 +18,11 @@
|
||||||
android:title="@string/watch_quality_pref"
|
android:title="@string/watch_quality_pref"
|
||||||
android:icon="@drawable/ic_baseline_hd_24" />
|
android:icon="@drawable/ic_baseline_hd_24" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="@string/player_pref_key"
|
||||||
|
android:title="@string/player_pref"
|
||||||
|
android:icon="@drawable/netflix_play" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/prefer_limit_title_key"
|
android:key="@string/prefer_limit_title_key"
|
||||||
android:title="@string/limit_title"
|
android:title="@string/limit_title"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<Preference
|
<Preference
|
||||||
|
app:isPreferenceVisible="false"
|
||||||
android:icon="@drawable/ic_baseline_language_24"
|
android:icon="@drawable/ic_baseline_language_24"
|
||||||
android:key="@string/provider_lang_key"
|
android:key="@string/provider_lang_key"
|
||||||
android:title="@string/provider_lang_settings" />
|
android:title="@string/provider_lang_settings" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue