mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-29 05:10:20 +02:00
feat(YouTube/Alternative thumbnails): matches official ReVanced code
This commit is contained in:
parent
819348054b
commit
752c1df838
@ -3,18 +3,30 @@ package app.revanced.patches.youtube.alternativethumbnails.general
|
|||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.CronetURLRequestCallbackOnResponseStartedFingerprint
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.CronetURLRequestCallbackOnSucceededFingerprint
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.MessageDigestImageUrlFingerprint
|
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.MessageDigestImageUrlFingerprint
|
||||||
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.MessageDigestImageUrlParentFingerprint
|
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.MessageDigestImageUrlParentFingerprint
|
||||||
|
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.RequestFingerprint
|
||||||
|
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.request.callback.OnFailureFingerprint
|
||||||
|
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.request.callback.OnResponseStartedFingerprint
|
||||||
|
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.request.callback.OnSucceededFingerprint
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.ALTERNATIVE_THUMBNAILS
|
import app.revanced.patches.youtube.utils.integrations.Constants.ALTERNATIVE_THUMBNAILS
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
|
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
|
||||||
import app.revanced.util.copyXmlNode
|
import app.revanced.util.copyXmlNode
|
||||||
import app.revanced.util.exception
|
import app.revanced.util.exception
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Alternative thumbnails",
|
name = "Alternative thumbnails",
|
||||||
@ -50,53 +62,123 @@ import app.revanced.util.exception
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object AlternativeThumbnailsPatch : BytecodePatch(
|
object AlternativeThumbnailsPatch : BytecodePatch(
|
||||||
setOf(
|
setOf(
|
||||||
CronetURLRequestCallbackOnResponseStartedFingerprint,
|
MessageDigestImageUrlParentFingerprint,
|
||||||
MessageDigestImageUrlParentFingerprint
|
OnResponseStartedFingerprint,
|
||||||
|
RequestFingerprint,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
private lateinit var loadImageUrlMethod: MutableMethod
|
||||||
|
private var loadImageUrlIndex = 0
|
||||||
|
|
||||||
|
private lateinit var loadImageSuccessCallbackMethod: MutableMethod
|
||||||
|
private var loadImageSuccessCallbackIndex = 0
|
||||||
|
|
||||||
|
private lateinit var loadImageErrorCallbackMethod: MutableMethod
|
||||||
|
private var loadImageErrorCallbackIndex = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param highPriority If the hook should be called before all other hooks.
|
||||||
|
*/
|
||||||
|
@Suppress("SameParameterValue")
|
||||||
|
private fun addImageUrlHook(targetMethodClass: String, highPriority: Boolean) {
|
||||||
|
loadImageUrlMethod.addInstructions(
|
||||||
|
if (highPriority) 0 else loadImageUrlIndex,
|
||||||
|
"""
|
||||||
|
invoke-static { p1 }, $targetMethodClass->overrideImageURL(Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object p1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
loadImageUrlIndex += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a connection completed, which includes normal 200 responses but also includes
|
||||||
|
* status 404 and other error like http responses.
|
||||||
|
*/
|
||||||
|
@Suppress("SameParameterValue")
|
||||||
|
private fun addImageUrlSuccessCallbackHook(targetMethodClass: String) {
|
||||||
|
loadImageSuccessCallbackMethod.addInstruction(
|
||||||
|
loadImageSuccessCallbackIndex++,
|
||||||
|
"invoke-static { p1, p2 }, $targetMethodClass->handleCronetSuccess(" +
|
||||||
|
"Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;)V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a connection outright failed to complete any connection.
|
||||||
|
*/
|
||||||
|
@Suppress("SameParameterValue")
|
||||||
|
private fun addImageUrlErrorCallbackHook(targetMethodClass: String) {
|
||||||
|
loadImageErrorCallbackMethod.addInstruction(
|
||||||
|
loadImageErrorCallbackIndex++,
|
||||||
|
"invoke-static { p1, p2, p3 }, $targetMethodClass->handleCronetFailure(" +
|
||||||
|
"Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;Ljava/io/IOException;)V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
|
||||||
/**
|
fun MethodFingerprint.getResultOrThrow() =
|
||||||
* Hook should should come first.
|
result ?: throw exception
|
||||||
*/
|
|
||||||
MessageDigestImageUrlParentFingerprint.result?.let { parentResult ->
|
fun MethodFingerprint.alsoResolve(fingerprint: MethodFingerprint) =
|
||||||
MessageDigestImageUrlFingerprint.also {
|
also { resolve(context, fingerprint.getResultOrThrow().classDef) }.getResultOrThrow()
|
||||||
it.resolve(
|
|
||||||
context,
|
fun MethodFingerprint.resolveAndLetMutableMethod(
|
||||||
parentResult.classDef
|
fingerprint: MethodFingerprint,
|
||||||
)
|
block: (MutableMethod) -> Unit
|
||||||
}.result?.let {
|
) = alsoResolve(fingerprint).also { block(it.mutableMethod) }
|
||||||
it.mutableMethod.apply {
|
|
||||||
|
MessageDigestImageUrlFingerprint.resolveAndLetMutableMethod(MessageDigestImageUrlParentFingerprint) {
|
||||||
|
loadImageUrlMethod = it
|
||||||
|
addImageUrlHook(ALTERNATIVE_THUMBNAILS, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
OnSucceededFingerprint.resolveAndLetMutableMethod(OnResponseStartedFingerprint) {
|
||||||
|
loadImageSuccessCallbackMethod = it
|
||||||
|
addImageUrlSuccessCallbackHook(ALTERNATIVE_THUMBNAILS)
|
||||||
|
}
|
||||||
|
|
||||||
|
OnFailureFingerprint.resolveAndLetMutableMethod(OnResponseStartedFingerprint) {
|
||||||
|
loadImageErrorCallbackMethod = it
|
||||||
|
addImageUrlErrorCallbackHook(ALTERNATIVE_THUMBNAILS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The URL is required for the failure callback hook, but the URL field is obfuscated.
|
||||||
|
// Add a helper get method that returns the URL field.
|
||||||
|
RequestFingerprint.getResultOrThrow().apply {
|
||||||
|
// The url is the only string field that is set inside the constructor.
|
||||||
|
val urlFieldInstruction = mutableMethod.getInstructions().first {
|
||||||
|
if (it.opcode != Opcode.IPUT_OBJECT)
|
||||||
|
return@first false
|
||||||
|
|
||||||
|
val reference = (it as ReferenceInstruction).reference as FieldReference
|
||||||
|
reference.type == "Ljava/lang/String;"
|
||||||
|
} as ReferenceInstruction
|
||||||
|
|
||||||
|
val urlFieldName = (urlFieldInstruction.reference as FieldReference).name
|
||||||
|
val definingClass = RequestFingerprint.IMPLEMENTATION_CLASS_NAME
|
||||||
|
val addedMethodName = "getHookedUrl"
|
||||||
|
mutableClass.methods.add(
|
||||||
|
ImmutableMethod(
|
||||||
|
definingClass,
|
||||||
|
addedMethodName,
|
||||||
|
emptyList(),
|
||||||
|
"Ljava/lang/String;",
|
||||||
|
AccessFlags.PUBLIC.value,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
MutableMethodImplementation(2)
|
||||||
|
).toMutable().apply {
|
||||||
addInstructions(
|
addInstructions(
|
||||||
0, """
|
"""
|
||||||
invoke-static { p1 }, $ALTERNATIVE_THUMBNAILS->overrideImageURL(Ljava/lang/String;)Ljava/lang/String;
|
iget-object v0, p0, $definingClass->${urlFieldName}:Ljava/lang/String;
|
||||||
move-result-object p1
|
return-object v0
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} ?: throw MessageDigestImageUrlFingerprint.exception
|
)
|
||||||
} ?: throw MessageDigestImageUrlParentFingerprint.exception
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a connection completed, which includes normal 200 responses but also includes
|
|
||||||
* status 404 and other error like http responses.
|
|
||||||
*/
|
|
||||||
CronetURLRequestCallbackOnResponseStartedFingerprint.result?.let { parentResult ->
|
|
||||||
CronetURLRequestCallbackOnSucceededFingerprint.also {
|
|
||||||
it.resolve(
|
|
||||||
context,
|
|
||||||
parentResult.classDef
|
|
||||||
)
|
|
||||||
}.result?.let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
addInstruction(
|
|
||||||
0,
|
|
||||||
"invoke-static { p2 }, $ALTERNATIVE_THUMBNAILS->handleCronetSuccess(Lorg/chromium/net/UrlResponseInfo;)V"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} ?: throw CronetURLRequestCallbackOnSucceededFingerprint.exception
|
|
||||||
} ?: throw CronetURLRequestCallbackOnResponseStartedFingerprint.exception
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy arrays
|
* Copy arrays
|
||||||
|
@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
|
|||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
object MessageDigestImageUrlFingerprint : MethodFingerprint(
|
internal object MessageDigestImageUrlFingerprint : MethodFingerprint(
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
parameters = listOf("Ljava/lang/String;", "L")
|
parameters = listOf("Ljava/lang/String;", "L")
|
||||||
)
|
)
|
@ -4,9 +4,9 @@ import app.revanced.patcher.extensions.or
|
|||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
object MessageDigestImageUrlParentFingerprint : MethodFingerprint(
|
internal object MessageDigestImageUrlParentFingerprint : MethodFingerprint(
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
returnType = "Ljava/lang/String;",
|
returnType = "Ljava/lang/String;",
|
||||||
parameters = emptyList(),
|
parameters = emptyList(),
|
||||||
strings = listOf("@#&=*+-_.,:!?()/~'%;\$"),
|
strings = listOf("@#&=*+-_.,:!?()/~'%;\$"),
|
||||||
)
|
)
|
@ -0,0 +1,16 @@
|
|||||||
|
package app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.RequestFingerprint.IMPLEMENTATION_CLASS_NAME
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal object RequestFingerprint : MethodFingerprint(
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
classDef.type == IMPLEMENTATION_CLASS_NAME
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const val IMPLEMENTATION_CLASS_NAME = "Lorg/chromium/net/impl/CronetUrlRequest;"
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.request.callback
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal object OnFailureFingerprint : MethodFingerprint(
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf(
|
||||||
|
"Lorg/chromium/net/UrlRequest;",
|
||||||
|
"Lorg/chromium/net/UrlResponseInfo;",
|
||||||
|
"Lorg/chromium/net/CronetException;"
|
||||||
|
),
|
||||||
|
customFingerprint = { methodDef, _ ->
|
||||||
|
methodDef.name == "onFailed"
|
||||||
|
}
|
||||||
|
)
|
@ -1,14 +1,14 @@
|
|||||||
package app.revanced.patches.youtube.alternativethumbnails.general.fingerprints
|
package app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.request.callback
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
// Acts as a parent fingerprint.
|
// Acts as a parent fingerprint.
|
||||||
object CronetURLRequestCallbackOnResponseStartedFingerprint : MethodFingerprint(
|
internal object OnResponseStartedFingerprint : MethodFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;"),
|
parameters = listOf("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;"),
|
||||||
strings = listOf(
|
strings = listOf(
|
||||||
"Content-Length",
|
"Content-Length",
|
||||||
"Content-Type",
|
"Content-Type",
|
@ -1,13 +1,13 @@
|
|||||||
package app.revanced.patches.youtube.alternativethumbnails.general.fingerprints
|
package app.revanced.patches.youtube.alternativethumbnails.general.fingerprints.cronet.request.callback
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
object CronetURLRequestCallbackOnSucceededFingerprint : MethodFingerprint(
|
internal object OnSucceededFingerprint : MethodFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;"),
|
parameters = listOf("Lorg/chromium/net/UrlRequest;", "Lorg/chromium/net/UrlResponseInfo;"),
|
||||||
customFingerprint = { methodDef, _ ->
|
customFingerprint = { methodDef, _ ->
|
||||||
methodDef.name == "onSucceeded"
|
methodDef.name == "onSucceeded"
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string-array name="revanced_alt_thumbnail_type_entries">
|
<string-array name="revanced_alt_thumbnail_type_entries">
|
||||||
<item>@string/revanced_alt_thumbnail_type_entry_1</item>
|
<item>@string/revanced_alt_thumbnail_stills_time_entry_1</item>
|
||||||
<item>@string/revanced_alt_thumbnail_type_entry_2</item>
|
<item>@string/revanced_alt_thumbnail_stills_time_entry_2</item>
|
||||||
<item>@string/revanced_alt_thumbnail_type_entry_3</item>
|
<item>@string/revanced_alt_thumbnail_stills_time_entry_3</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_alt_thumbnail_type_entry_values">
|
<string-array name="revanced_alt_thumbnail_stills_time_entry_values">
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
<item>3</item>
|
<item>3</item>
|
||||||
|
@ -8,21 +8,42 @@
|
|||||||
|
|
||||||
<string name="revanced_ads">Ads</string>
|
<string name="revanced_ads">Ads</string>
|
||||||
<string name="revanced_alt_thumbnails">Alternative thumbnails</string>
|
<string name="revanced_alt_thumbnails">Alternative thumbnails</string>
|
||||||
<string name="revanced_alt_thumbnail_about_summary">A feature that replaced default video thumbnails with Alternative ones to reduce sensationalism.</string>
|
<string name="revanced_alt_thumbnail_about_status_dearrow">"Showing DeArrow thumbnails.
|
||||||
<string name="revanced_alt_thumbnail_about_title">About</string>
|
If a video has no DeArrow thumbnails then the original YouTube thumbnails are shown."</string>
|
||||||
<string name="revanced_alt_thumbnail_dearrow_summary_off">Thumbnails is generated without external API.</string>
|
<string name="revanced_alt_thumbnail_about_status_dearrow_stills">"Showing DeArrow thumbnails.
|
||||||
<string name="revanced_alt_thumbnail_dearrow_summary_on">Thumbnails is generated using DeArrow API.</string>
|
If a video has no DeArrow thumbnails then still video captures are shown."</string>
|
||||||
<string name="revanced_alt_thumbnail_dearrow_title">Using DeArrow API</string>
|
<string name="revanced_alt_thumbnail_about_status_disabled">Showing original YouTube thumbnails.</string>
|
||||||
<string name="revanced_alt_thumbnail_enabled_summary_off">Original YouTube thumbnails shown.</string>
|
<string name="revanced_alt_thumbnail_about_status_stills">Showing still video captures.</string>
|
||||||
<string name="revanced_alt_thumbnail_enabled_summary_on">YouTube thumbnails replaced with Alternative ones.</string>
|
<string name="revanced_alt_thumbnail_about_title">Thumbnails in use</string>
|
||||||
<string name="revanced_alt_thumbnail_enabled_title">Enable alternative thumbnails</string>
|
<string name="revanced_alt_thumbnail_dearrow_about_summary">"DeArrow provides crowd sourced thumbnails for YouTube videos. These thumbnails are often more relevant than those provided by YouTube. If enabled, video URLs will be sent to the API server and no other data is sent.
|
||||||
<string name="revanced_alt_thumbnail_skip_checking_summary_off">Thumbnails will be checked if exist or not before replacing.</string>
|
|
||||||
<string name="revanced_alt_thumbnail_skip_checking_summary_on">Thumbnails will load faster, but some video will show blank thumbnails.</string>
|
Tap here to learn more about DeArrow."</string>
|
||||||
<string name="revanced_alt_thumbnail_skip_checking_title">Skip checking for thumbnails</string>
|
<string name="revanced_alt_thumbnail_dearrow_about_title">About DeArrow</string>
|
||||||
<string name="revanced_alt_thumbnail_type_entry_1">Beginning of video</string>
|
<string name="revanced_alt_thumbnail_dearrow_api_url_summary">"The URL of the DeArrow thumbnail cache endpoint. Do not change this unless you know what you're doing."</string>
|
||||||
<string name="revanced_alt_thumbnail_type_entry_2">Middle of video</string>
|
<string name="revanced_alt_thumbnail_dearrow_api_url_title">DeArrow API endpoint</string>
|
||||||
<string name="revanced_alt_thumbnail_type_entry_3">End of video</string>
|
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_off">Toast not shown if DeArrow is not available.</string>
|
||||||
<string name="revanced_alt_thumbnail_type_title">Video time to take the still from</string>
|
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_on">Toast shown if DeArrow is not available.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_dearrow_connection_toast_title">Show toast if API is not available</string>
|
||||||
|
<string name="revanced_alt_thumbnail_dearrow_error">DeArrow temporarily not available. (status code: %s)</string>
|
||||||
|
<string name="revanced_alt_thumbnail_dearrow_error_generic">DeArrow temporarily not available.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_dearrow_summary_off">Not using DeArrow.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_dearrow_summary_on">Using DeArrow.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_dearrow_title">Enable DeArrow</string>
|
||||||
|
<string name="revanced_alt_thumbnail_preference_screen_summary">Video thumbnail settings.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_preference_screen_title">Alternative thumbnails</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills">Still video captures</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_about_summary">Still captures are taken from the beginning / middle / end of each video. These images are built into YouTube and no external API is used.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_about_title">About still video captures</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_fast_summary_off">Using high quality still captures.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_fast_summary_on">Using medium quality still captures. Thumbnails will load faster, but live streams, unreleased, or very old videos may show blank thumbnails.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_fast_title">Use fast still captures</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_summary_off">Not using YouTube video still captures.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_summary_on">Using YouTube video still captures.</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_time_entry_1">Beginning of video</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_time_entry_2">Middle of video</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_time_entry_3">End of video</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_time_title">Video time to take the still from</string>
|
||||||
|
<string name="revanced_alt_thumbnail_stills_title">Enable still video captures</string>
|
||||||
<string name="revanced_append_time_stamp_information_summary_off">Append time stamp information is disabled.</string>
|
<string name="revanced_append_time_stamp_information_summary_off">Append time stamp information is disabled.</string>
|
||||||
<string name="revanced_append_time_stamp_information_summary_on">Append time stamp information is enabled.</string>
|
<string name="revanced_append_time_stamp_information_summary_on">Append time stamp information is enabled.</string>
|
||||||
<string name="revanced_append_time_stamp_information_title">Append time stamp information</string>
|
<string name="revanced_append_time_stamp_information_title">Append time stamp information</string>
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
<string name="pref_app_language_dialog_message_no_lang_name">This will change the language used in the app including buttons, text and dialogs, but will not change the language of ReVanced Extended settings.</string>
|
<string name="pref_app_language_dialog_message_no_lang_name">This will change the language used in the app including buttons, text and dialogs, but will not change the language of ReVanced Extended settings.</string>
|
||||||
<string name="pref_app_language_system_default">System default</string>
|
<string name="pref_app_language_system_default">System default</string>
|
||||||
|
|
||||||
|
<string name="revanced_alt_thumbnail_dearrow">DeArrow</string>
|
||||||
|
|
||||||
<string name="revanced_extended_settings_title">ReVanced Extended</string>
|
<string name="revanced_extended_settings_title">ReVanced Extended</string>
|
||||||
|
|
||||||
<string name="revanced_hide_account_menu_filter_strings_summary">@string/revanced_custom_filter_strings_summary</string>
|
<string name="revanced_hide_account_menu_filter_strings_summary">@string/revanced_custom_filter_strings_summary</string>
|
||||||
|
@ -32,11 +32,19 @@
|
|||||||
<!-- PREFERENCE: ALTERNATIVE_THUMBNAILS_SETTINGS
|
<!-- PREFERENCE: ALTERNATIVE_THUMBNAILS_SETTINGS
|
||||||
<PreferenceScreen android:title="@string/revanced_alt_thumbnails" android:key="alt_thumbnails">
|
<PreferenceScreen android:title="@string/revanced_alt_thumbnails" android:key="alt_thumbnails">
|
||||||
<Preference android:title=" " android:selectable="false" android:summary="@string/revanced_alt_thumbnails" />
|
<Preference android:title=" " android:selectable="false" android:summary="@string/revanced_alt_thumbnails" />
|
||||||
<SwitchPreference android:title="@string/revanced_alt_thumbnail_enabled_title" android:key="revanced_alt_thumbnail_enabled" android:defaultValue="false" android:summaryOn="@string/revanced_alt_thumbnail_enabled_summary_on" android:summaryOff="@string/revanced_alt_thumbnail_enabled_summary_off" />
|
<app.revanced.integrations.settingsmenu.AlternativeThumbnailsStatusPreference android:title="@string/revanced_alt_thumbnail_about_title" />
|
||||||
<SwitchPreference android:title="@string/revanced_alt_thumbnail_dearrow_title" android:key="revanced_alt_thumbnail_dearrow" android:defaultValue="false" android:summaryOn="@string/revanced_alt_thumbnail_dearrow_summary_on" android:summaryOff="@string/revanced_alt_thumbnail_dearrow_summary_off" />
|
|
||||||
<ListPreference android:title="@string/revanced_alt_thumbnail_type_title" android:key="revanced_alt_thumbnail_type" android:entries="@array/revanced_alt_thumbnail_type_entries" android:defaultValue="1" android:entryValues="@array/revanced_alt_thumbnail_type_entry_values" />
|
<Preference android:title=" " android:selectable="false" android:summary="@string/revanced_alt_thumbnail_dearrow" />
|
||||||
<SwitchPreference android:title="@string/revanced_alt_thumbnail_skip_checking_title" android:key="revanced_alt_thumbnail_skip_checking" android:defaultValue="false" android:summaryOn="@string/revanced_alt_thumbnail_skip_checking_summary_on" android:summaryOff="@string/revanced_alt_thumbnail_skip_checking_summary_off" />
|
<SwitchPreference android:title="@string/revanced_alt_thumbnail_dearrow_title" android:key="revanced_alt_thumbnail_dearrow" android:summaryOn="@string/revanced_alt_thumbnail_dearrow_summary_on" android:summaryOff="@string/revanced_alt_thumbnail_dearrow_summary_off" />
|
||||||
<Preference android:title="@string/revanced_alt_thumbnail_about_title" android:selectable="false" android:summary="@string/revanced_alt_thumbnail_about_summary" />
|
<SwitchPreference android:title="@string/revanced_alt_thumbnail_dearrow_connection_toast_title" android:key="revanced_alt_thumbnail_dearrow_connection_toast" android:summaryOn="@string/revanced_alt_thumbnail_dearrow_connection_toast_summary_on" android:summaryOff="@string/revanced_alt_thumbnail_dearrow_connection_toast_summary_off" />
|
||||||
|
<app.revanced.integrations.settingsmenu.ResettableEditTextPreference android:title="@string/revanced_alt_thumbnail_dearrow_api_url_title" android:key="revanced_alt_thumbnail_dearrow_api_url" android:summary="@string/revanced_alt_thumbnail_dearrow_api_url_summary" android:inputType="text" />
|
||||||
|
<app.revanced.integrations.settingsmenu.AlternativeThumbnailsAboutDeArrowPreference android:title="@string/revanced_alt_thumbnail_dearrow_about_title" android:selectable="true" android:summary="@string/revanced_alt_thumbnail_dearrow_about_summary" />
|
||||||
|
|
||||||
|
<Preference android:title=" " android:selectable="false" android:summary="@string/revanced_alt_thumbnail_stills" />
|
||||||
|
<SwitchPreference android:title="@string/revanced_alt_thumbnail_stills_title" android:key="revanced_alt_thumbnail_stills" android:summaryOn="@string/revanced_alt_thumbnail_stills_summary_on" android:summaryOff="@string/revanced_alt_thumbnail_stills_summary_off" />
|
||||||
|
<ListPreference android:entries="@array/revanced_alt_thumbnail_type_entries" android:title="@string/revanced_alt_thumbnail_stills_time_title" android:key="revanced_alt_thumbnail_stills_time" android:entryValues="@array/revanced_alt_thumbnail_stills_time_entry_values" />
|
||||||
|
<SwitchPreference android:title="@string/revanced_alt_thumbnail_stills_fast_title" android:key="revanced_alt_thumbnail_stills_fast" android:summaryOn="@string/revanced_alt_thumbnail_stills_fast_summary_on" android:summaryOff="@string/revanced_alt_thumbnail_stills_fast_summary_off" />
|
||||||
|
<Preference android:title="@string/revanced_alt_thumbnail_stills_about_title" android:selectable="true" android:summary="@string/revanced_alt_thumbnail_stills_about_summary" />
|
||||||
</PreferenceScreen>PREFERENCE: ALTERNATIVE_THUMBNAILS_SETTINGS -->
|
</PreferenceScreen>PREFERENCE: ALTERNATIVE_THUMBNAILS_SETTINGS -->
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user