mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-24 11:11:03 +00:00
Compare commits
14 Commits
v4.12.0-de
...
v4.12.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62c47665e4 | ||
|
|
7acb6cdc96 | ||
|
|
a5d32c3da3 | ||
|
|
a4b0e76755 | ||
|
|
0a7b2c5ec2 | ||
|
|
eed856d64c | ||
|
|
e8d481397f | ||
|
|
d0eceb3e36 | ||
|
|
8886fc4f54 | ||
|
|
fb4256f17c | ||
|
|
98f9bba7ed | ||
|
|
8e72067dcb | ||
|
|
d87f36e7e2 | ||
|
|
4432fe65df |
2
.github/workflows/pull_strings.yml
vendored
2
.github/workflows/pull_strings.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
ref: dev
|
ref: dev
|
||||||
|
|
||||||
- name: Pull strings
|
- name: Pull strings
|
||||||
uses: crowdin/github-action@v1
|
uses: crowdin/github-action@v2
|
||||||
with:
|
with:
|
||||||
config: crowdin.yml
|
config: crowdin.yml
|
||||||
download_translations: true
|
download_translations: true
|
||||||
|
|||||||
2
.github/workflows/push_strings.yml
vendored
2
.github/workflows/push_strings.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Push strings
|
- name: Push strings
|
||||||
uses: crowdin/github-action@v1
|
uses: crowdin/github-action@v2
|
||||||
with:
|
with:
|
||||||
config: crowdin.yml
|
config: crowdin.yml
|
||||||
upload_sources: true
|
upload_sources: true
|
||||||
|
|||||||
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,3 +1,45 @@
|
|||||||
|
# [4.12.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.10...v4.12.0-dev.11) (2024-07-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Bypass image region restrictions:** Move setting to `Misc` menu ([094ae59](https://github.com/ReVanced/revanced-patches/commit/094ae59fc92663fff6c5d6f5cbece41822a326f9))
|
||||||
|
|
||||||
|
# [4.12.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.9...v4.12.0-dev.10) (2024-07-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Client Spoof:** Restore missing high qualities by spoofing the iOS client user agent ([#3468](https://github.com/ReVanced/revanced-patches/issues/3468)) ([0e6ae5f](https://github.com/ReVanced/revanced-patches/commit/0e6ae5fee752a76604cf9b95f9a76c0cbe5f7dae))
|
||||||
|
|
||||||
|
# [4.12.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.8...v4.12.0-dev.9) (2024-07-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof client:** Fix tracking history on brand accounts ([#3480](https://github.com/ReVanced/revanced-patches/issues/3480)) ([69c1f16](https://github.com/ReVanced/revanced-patches/commit/69c1f16f7eb0d5759a44f7f7a09b1757ce8f61dd))
|
||||||
|
|
||||||
|
# [4.12.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.7...v4.12.0-dev.8) (2024-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - SponsorBlock:** Correctly show minute timestamp when creating a new segment ([d74c366](https://github.com/ReVanced/revanced-patches/commit/d74c366dbf5f25c20fbfc5a0157c3c15dda82a16))
|
||||||
|
|
||||||
|
# [4.12.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.6...v4.12.0-dev.7) (2024-07-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **SoundCloud - Enable offline sync:** Stop crashing by reversing order of patching instructions from last to first to retain indices ([63b6ced](https://github.com/ReVanced/revanced-patches/commit/63b6cede5fa5bcf377ced422da4e861996a41f0d))
|
||||||
|
|
||||||
|
# [4.12.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.5...v4.12.0-dev.6) (2024-07-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add `Spoof build info` patch ([e7829b4](https://github.com/ReVanced/revanced-patches/commit/e7829b41e782c9feda23b9d6acf48bae277d24d9))
|
||||||
|
|
||||||
# [4.12.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.4...v4.12.0-dev.5) (2024-07-20)
|
# [4.12.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.4...v4.12.0-dev.5) (2024-07-20)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,42 @@ public final class app/revanced/patches/all/location/hide/HideMockLocationPatch
|
|||||||
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Pair;)V
|
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Pair;)V
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class app/revanced/patches/all/misc/build/BaseSpoofBuildInfoPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
|
||||||
|
public fun <init> ()V
|
||||||
|
public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object;
|
||||||
|
public fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Lkotlin/Pair;
|
||||||
|
protected fun getBoard ()Ljava/lang/String;
|
||||||
|
protected fun getBootloader ()Ljava/lang/String;
|
||||||
|
protected fun getBrand ()Ljava/lang/String;
|
||||||
|
protected fun getCpuAbi ()Ljava/lang/String;
|
||||||
|
protected fun getCpuAbi2 ()Ljava/lang/String;
|
||||||
|
protected fun getDevice ()Ljava/lang/String;
|
||||||
|
protected fun getDisplay ()Ljava/lang/String;
|
||||||
|
protected fun getFingerprint ()Ljava/lang/String;
|
||||||
|
protected fun getHardware ()Ljava/lang/String;
|
||||||
|
protected fun getHost ()Ljava/lang/String;
|
||||||
|
protected fun getId ()Ljava/lang/String;
|
||||||
|
protected fun getManufacturer ()Ljava/lang/String;
|
||||||
|
protected fun getModel ()Ljava/lang/String;
|
||||||
|
protected fun getOdmSku ()Ljava/lang/String;
|
||||||
|
protected fun getProduct ()Ljava/lang/String;
|
||||||
|
protected fun getRadio ()Ljava/lang/String;
|
||||||
|
protected fun getSerial ()Ljava/lang/String;
|
||||||
|
protected fun getSku ()Ljava/lang/String;
|
||||||
|
protected fun getSocManufacturer ()Ljava/lang/String;
|
||||||
|
protected fun getSocModel ()Ljava/lang/String;
|
||||||
|
protected fun getTags ()Ljava/lang/String;
|
||||||
|
protected fun getTime ()Ljava/lang/Long;
|
||||||
|
protected fun getType ()Ljava/lang/String;
|
||||||
|
protected fun getUser ()Ljava/lang/String;
|
||||||
|
public synthetic fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Object;)V
|
||||||
|
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Pair;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/all/misc/build/SpoofBuildInfoPatch : app/revanced/patches/all/misc/build/BaseSpoofBuildInfoPatch {
|
||||||
|
public fun <init> ()V
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch : app/revanced/patcher/patch/ResourcePatch {
|
public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch : app/revanced/patcher/patch/ResourcePatch {
|
||||||
public static final field INSTANCE Lapp/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch;
|
public static final field INSTANCE Lapp/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch;
|
||||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 4.12.0-dev.5
|
version = 4.12.0-dev.11
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
revanced-patcher = "19.3.1"
|
revanced-patcher = "19.3.1"
|
||||||
#noinspection GradleDependency
|
#noinspection GradleDependency
|
||||||
smali = "3.0.5" # 3.0.7 breaks binary compatibility. Tracking https://github.com/google/smali/issues/58.
|
smali = "3.0.5" # 3.0.7 breaks binary compatibility. Tracking https://github.com/google/smali/issues/58.
|
||||||
guava = "33.1.0-jre"
|
guava = "33.2.1-jre"
|
||||||
gson = "2.10.1"
|
gson = "2.11.0"
|
||||||
binary-compatibility-validator = "0.14.0"
|
binary-compatibility-validator = "0.15.1"
|
||||||
kotlin = "2.0.0"
|
kotlin = "2.0.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|||||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
|
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
2152
package-lock.json
generated
2152
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
|||||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"gradle-semantic-release-plugin": "^1.9.1",
|
"gradle-semantic-release-plugin": "^1.9.2",
|
||||||
"semantic-release": "^23.0.8"
|
"semantic-release": "^24.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package app.revanced.patches.all.misc.build
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
|
||||||
|
abstract class BaseSpoofBuildInfoPatch : BaseTransformInstructionsPatch<Pair<Int, Pair<String, String>>>() {
|
||||||
|
// The build information supported32BitAbis, supported64BitAbis, and supportedAbis are not supported for now,
|
||||||
|
// because initializing an array in transform is a bit more complex.
|
||||||
|
|
||||||
|
protected open val board: String? = null
|
||||||
|
|
||||||
|
protected open val bootloader: String? = null
|
||||||
|
|
||||||
|
protected open val brand: String? = null
|
||||||
|
|
||||||
|
protected open val cpuAbi: String? = null
|
||||||
|
|
||||||
|
protected open val cpuAbi2: String? = null
|
||||||
|
|
||||||
|
protected open val device: String? = null
|
||||||
|
|
||||||
|
protected open val display: String? = null
|
||||||
|
|
||||||
|
protected open val fingerprint: String? = null
|
||||||
|
|
||||||
|
protected open val hardware: String? = null
|
||||||
|
|
||||||
|
protected open val host: String? = null
|
||||||
|
|
||||||
|
protected open val id: String? = null
|
||||||
|
|
||||||
|
protected open val manufacturer: String? = null
|
||||||
|
|
||||||
|
protected open val model: String? = null
|
||||||
|
|
||||||
|
protected open val odmSku: String? = null
|
||||||
|
|
||||||
|
protected open val product: String? = null
|
||||||
|
|
||||||
|
protected open val radio: String? = null
|
||||||
|
|
||||||
|
protected open val serial: String? = null
|
||||||
|
|
||||||
|
protected open val sku: String? = null
|
||||||
|
|
||||||
|
protected open val socManufacturer: String? = null
|
||||||
|
|
||||||
|
protected open val socModel: String? = null
|
||||||
|
|
||||||
|
protected open val tags: String? = null
|
||||||
|
|
||||||
|
protected open val time: Long? = null
|
||||||
|
|
||||||
|
protected open val type: String? = null
|
||||||
|
|
||||||
|
protected open val user: String? = null
|
||||||
|
|
||||||
|
|
||||||
|
// Lazy, so that patch options above are initialized before they are accessed.
|
||||||
|
private val replacements: Map<String, Pair<String, String>> by lazy {
|
||||||
|
buildMap {
|
||||||
|
if (board != null) put("BOARD", "const-string" to "\"$board\"")
|
||||||
|
if (bootloader != null) put("BOOTLOADER", "const-string" to "\"$bootloader\"")
|
||||||
|
if (brand != null) put("BRAND", "const-string" to "\"$brand\"")
|
||||||
|
if (cpuAbi != null) put("CPU_ABI", "const-string" to "\"$cpuAbi\"")
|
||||||
|
if (cpuAbi2 != null) put("CPU_ABI2", "const-string" to "\"$cpuAbi2\"")
|
||||||
|
if (device != null) put("DEVICE", "const-string" to "\"$device\"")
|
||||||
|
if (display != null) put("DISPLAY", "const-string" to "\"$display\"")
|
||||||
|
if (fingerprint != null) put("FINGERPRINT", "const-string" to "\"$fingerprint\"")
|
||||||
|
if (hardware != null) put("HARDWARE", "const-string" to "\"$hardware\"")
|
||||||
|
if (host != null) put("HOST", "const-string" to "\"$host\"")
|
||||||
|
if (id != null) put("ID", "const-string" to "\"$id\"")
|
||||||
|
if (manufacturer != null) put("MANUFACTURER", "const-string" to "\"$manufacturer\"")
|
||||||
|
if (model != null) put("MODEL", "const-string" to "\"$model\"")
|
||||||
|
if (odmSku != null) put("ODM_SKU", "const-string" to "\"$odmSku\"")
|
||||||
|
if (product != null) put("PRODUCT", "const-string" to "\"$product\"")
|
||||||
|
if (radio != null) put("RADIO", "const-string" to "\"$radio\"")
|
||||||
|
if (serial != null) put("SERIAL", "const-string" to "\"$serial\"")
|
||||||
|
if (sku != null) put("SKU", "const-string" to "\"$sku\"")
|
||||||
|
if (socManufacturer != null) put("SOC_MANUFACTURER", "const-string" to "\"$socManufacturer\"")
|
||||||
|
if (socModel != null) put("SOC_MODEL", "const-string" to "\"$socModel\"")
|
||||||
|
if (tags != null) put("TAGS", "const-string" to "\"$tags\"")
|
||||||
|
if (time != null) put("TIME", "const-wide" to "$time")
|
||||||
|
if (type != null) put("TYPE", "const-string" to "\"$type\"")
|
||||||
|
if (user != null) put("USER", "const-string" to "\"$user\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun filterMap(
|
||||||
|
classDef: ClassDef,
|
||||||
|
method: Method,
|
||||||
|
instruction: Instruction,
|
||||||
|
instructionIndex: Int
|
||||||
|
): Pair<Int, Pair<String, String>>? {
|
||||||
|
val reference = instruction.getReference<FieldReference>() ?: return null
|
||||||
|
if (reference.definingClass != BUILD_CLASS_DESCRIPTOR) return null
|
||||||
|
|
||||||
|
return replacements[reference.name]?.let { instructionIndex to it }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transform(mutableMethod: MutableMethod, entry: Pair<Int, Pair<String, String>>) {
|
||||||
|
val (index, replacement) = entry
|
||||||
|
val (opcode, operand) = replacement
|
||||||
|
val register = mutableMethod.getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
|
mutableMethod.replaceInstruction(index, "$opcode v$register, $operand")
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val BUILD_CLASS_DESCRIPTOR = "Landroid/os/Build;"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
package app.revanced.patches.all.misc.build
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
|
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.longPatchOption
|
||||||
|
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||||
|
|
||||||
|
@Patch(
|
||||||
|
name = "Spoof build info",
|
||||||
|
description = "Spoof the information about the current build.",
|
||||||
|
use = false
|
||||||
|
)
|
||||||
|
@Suppress("unused")
|
||||||
|
class SpoofBuildInfoPatch : BaseSpoofBuildInfoPatch() {
|
||||||
|
override val board by stringPatchOption(
|
||||||
|
key = "board",
|
||||||
|
default = null,
|
||||||
|
title = "Board",
|
||||||
|
description = "The name of the underlying board, like \"goldfish\"."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val bootloader by stringPatchOption(
|
||||||
|
key = "bootloader",
|
||||||
|
default = null,
|
||||||
|
title = "Bootloader",
|
||||||
|
description = "The system bootloader version number."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val brand by stringPatchOption(
|
||||||
|
key = "brand",
|
||||||
|
default = null,
|
||||||
|
title = "Brand",
|
||||||
|
description = "The consumer-visible brand with which the product/hardware will be associated, if any."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val cpuAbi by stringPatchOption(
|
||||||
|
key = "cpu-abi",
|
||||||
|
default = null,
|
||||||
|
title = "CPU ABI",
|
||||||
|
description = "This field was deprecated in API level 21. Use SUPPORTED_ABIS instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val cpuAbi2 by stringPatchOption(
|
||||||
|
key = "cpu-abi-2",
|
||||||
|
default = null,
|
||||||
|
title = "CPU ABI 2",
|
||||||
|
description = "This field was deprecated in API level 21. Use SUPPORTED_ABIS instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val device by stringPatchOption(
|
||||||
|
key = "device",
|
||||||
|
default = null,
|
||||||
|
title = "Device",
|
||||||
|
description = "The name of the industrial design."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val display by stringPatchOption(
|
||||||
|
key = "display",
|
||||||
|
default = null,
|
||||||
|
title = "Display",
|
||||||
|
description = "A build ID string meant for displaying to the user."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val fingerprint by stringPatchOption(
|
||||||
|
key = "fingerprint",
|
||||||
|
default = null,
|
||||||
|
title = "Fingerprint",
|
||||||
|
description = "A string that uniquely identifies this build."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val hardware by stringPatchOption(
|
||||||
|
key = "hardware",
|
||||||
|
default = null,
|
||||||
|
title = "Hardware",
|
||||||
|
description = "The name of the hardware (from the kernel command line or /proc)."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val host by stringPatchOption(
|
||||||
|
key = "host",
|
||||||
|
default = null,
|
||||||
|
title = "Host",
|
||||||
|
description = "The host."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val id by stringPatchOption(
|
||||||
|
key = "id",
|
||||||
|
default = null,
|
||||||
|
title = "ID",
|
||||||
|
description = "Either a changelist number, or a label like \"M4-rc20\"."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val manufacturer by stringPatchOption(
|
||||||
|
key = "manufacturer",
|
||||||
|
default = null,
|
||||||
|
title = "Manufacturer",
|
||||||
|
description = "The manufacturer of the product/hardware."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val model by stringPatchOption(
|
||||||
|
key = "model",
|
||||||
|
default = null,
|
||||||
|
title = "Model",
|
||||||
|
description = "The end-user-visible name for the end product."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val odmSku by stringPatchOption(
|
||||||
|
key = "odm-sku",
|
||||||
|
default = null,
|
||||||
|
title = "ODM SKU",
|
||||||
|
description = "The SKU of the device as set by the original design manufacturer (ODM)."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val product by stringPatchOption(
|
||||||
|
key = "product",
|
||||||
|
default = null,
|
||||||
|
title = "Product",
|
||||||
|
description = "The name of the overall product."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val radio by stringPatchOption(
|
||||||
|
key = "radio",
|
||||||
|
default = null,
|
||||||
|
title = "Radio",
|
||||||
|
description = "This field was deprecated in API level 15. " +
|
||||||
|
"The radio firmware version is frequently not available when this class is initialized, " +
|
||||||
|
"leading to a blank or \"unknown\" value for this string. Use getRadioVersion() instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val serial by stringPatchOption(
|
||||||
|
key = "serial",
|
||||||
|
default = null,
|
||||||
|
title = "Serial",
|
||||||
|
description = "This field was deprecated in API level 26. Use getSerial() instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val sku by stringPatchOption(
|
||||||
|
key = "sku",
|
||||||
|
default = null,
|
||||||
|
title = "SKU",
|
||||||
|
description = "The SKU of the hardware (from the kernel command line)."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val socManufacturer by stringPatchOption(
|
||||||
|
key = "soc-manufacturer",
|
||||||
|
default = null,
|
||||||
|
title = "SOC Manufacturer",
|
||||||
|
description = "The manufacturer of the device's primary system-on-chip."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val socModel by stringPatchOption(
|
||||||
|
key = "soc-model",
|
||||||
|
default = null,
|
||||||
|
title = "SOC Model",
|
||||||
|
description = "The model name of the device's primary system-on-chip."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val tags by stringPatchOption(
|
||||||
|
key = "tags",
|
||||||
|
default = null,
|
||||||
|
title = "Tags",
|
||||||
|
description = "Comma-separated tags describing the build, like \"unsigned,debug\"."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val time by longPatchOption(
|
||||||
|
key = "time",
|
||||||
|
default = null,
|
||||||
|
title = "Time",
|
||||||
|
description = "The time at which the build was produced, given in milliseconds since the UNIX epoch."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val type by stringPatchOption(
|
||||||
|
key = "type",
|
||||||
|
default = null,
|
||||||
|
title = "Type",
|
||||||
|
description = "The type of build, like \"user\" or \"eng\"."
|
||||||
|
)
|
||||||
|
|
||||||
|
override val user by stringPatchOption(
|
||||||
|
key = "user",
|
||||||
|
default = null,
|
||||||
|
title = "User",
|
||||||
|
description = "The user."
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -73,7 +73,7 @@ object EnableOfflineSyncPatch : BytecodePatch(
|
|||||||
// The first three null checks need to be patched.
|
// The first three null checks need to be patched.
|
||||||
getInstructions().asSequence().filter {
|
getInstructions().asSequence().filter {
|
||||||
it.opcode == Opcode.IF_EQZ
|
it.opcode == Opcode.IF_EQZ
|
||||||
}.take(3).map { it.location.index }.forEach { nullCheckIndex ->
|
}.take(3).toList().map { it.location.index }.asReversed().forEach { nullCheckIndex ->
|
||||||
val headerStringRegister = getInstruction<OneRegisterInstruction>(nullCheckIndex).registerA
|
val headerStringRegister = getInstruction<OneRegisterInstruction>(nullCheckIndex).registerA
|
||||||
|
|
||||||
addInstruction(nullCheckIndex, "const-string v$headerStringRegister, \"\"")
|
addInstruction(nullCheckIndex, "const-string v$headerStringRegister, \"\"")
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ object BypassImageRegionRestrictions : BytecodePatch(emptySet()) {
|
|||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||||
SwitchPreference("revanced_bypass_image_region_restrictions")
|
SwitchPreference("revanced_bypass_image_region_restrictions")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchException
|
import app.revanced.patcher.patch.PatchException
|
||||||
@@ -77,18 +78,29 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
SetPlayerRequestClientTypeFingerprint,
|
SetPlayerRequestClientTypeFingerprint,
|
||||||
CreatePlayerRequestBodyFingerprint,
|
CreatePlayerRequestBodyFingerprint,
|
||||||
CreatePlayerRequestBodyWithModelFingerprint,
|
CreatePlayerRequestBodyWithModelFingerprint,
|
||||||
|
CreatePlayerRequestBodyWithVersionReleaseFingerprint,
|
||||||
|
|
||||||
// Player gesture config.
|
// Player gesture config.
|
||||||
PlayerGestureConfigSyntheticFingerprint,
|
PlayerGestureConfigSyntheticFingerprint,
|
||||||
|
|
||||||
// Player speed menu item.
|
// Player speed menu item.
|
||||||
CreatePlaybackSpeedMenuItemFingerprint,
|
CreatePlaybackSpeedMenuItemFingerprint,
|
||||||
|
|
||||||
|
// Video qualities missing.
|
||||||
|
BuildRequestFingerprint,
|
||||||
|
|
||||||
|
// Watch history.
|
||||||
|
GetTrackingUriFingerprint,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/youtube/patches/spoof/SpoofClientPatch;"
|
"Lapp/revanced/integrations/youtube/patches/spoof/SpoofClientPatch;"
|
||||||
private const val CLIENT_INFO_CLASS_DESCRIPTOR =
|
private const val CLIENT_INFO_CLASS_DESCRIPTOR =
|
||||||
"Lcom/google/protos/youtube/api/innertube/InnertubeContext\$ClientInfo;"
|
"Lcom/google/protos/youtube/api/innertube/InnertubeContext\$ClientInfo;"
|
||||||
|
private const val REQUEST_CLASS_DESCRIPTOR =
|
||||||
|
"Lorg/chromium/net/ExperimentalUrlRequest;"
|
||||||
|
private const val REQUEST_BUILDER_CLASS_DESCRIPTOR =
|
||||||
|
"Lorg/chromium/net/ExperimentalUrlRequest\$Builder;"
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
@@ -153,7 +165,7 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
.getInstructions().find { instruction ->
|
.getInstructions().find { instruction ->
|
||||||
// requestMessage.clientInfo = clientInfoBuilder.build();
|
// requestMessage.clientInfo = clientInfoBuilder.build();
|
||||||
instruction.opcode == Opcode.IPUT_OBJECT &&
|
instruction.opcode == Opcode.IPUT_OBJECT &&
|
||||||
instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
|
instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||||
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
|
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
|
||||||
|
|
||||||
// Client info object's client type field.
|
// Client info object's client type field.
|
||||||
@@ -164,13 +176,15 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
// Client info object's client version field.
|
// Client info object's client version field.
|
||||||
val clientInfoClientVersionField = result.mutableMethod
|
val clientInfoClientVersionField = result.mutableMethod
|
||||||
.getInstruction(result.scanResult.stringsScanResult!!.matches.first().index + 1)
|
.getInstruction(result.scanResult.stringsScanResult!!.matches.first().index + 1)
|
||||||
.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientVersionField")
|
.getReference<FieldReference>()
|
||||||
|
?: throw PatchException("Could not find clientInfoClientVersionField")
|
||||||
|
|
||||||
Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField)
|
Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField)
|
||||||
}
|
}
|
||||||
|
|
||||||
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
|
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
|
||||||
val getClientModelIndex = CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method)
|
val getClientModelIndex =
|
||||||
|
CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method)
|
||||||
|
|
||||||
// The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
|
// The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
|
||||||
val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getClientModelIndex) {
|
val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getClientModelIndex) {
|
||||||
@@ -181,6 +195,19 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
?: throw PatchException("Could not find clientInfoClientModelField")
|
?: throw PatchException("Could not find clientInfoClientModelField")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val clientInfoOsVersionField = CreatePlayerRequestBodyWithVersionReleaseFingerprint.resultOrThrow().let {
|
||||||
|
val getOsVersionIndex =
|
||||||
|
CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction(it.method)
|
||||||
|
|
||||||
|
// The next IPUT_OBJECT instruction after getting the client os version is setting the client os version field.
|
||||||
|
val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getOsVersionIndex) {
|
||||||
|
opcode == Opcode.IPUT_OBJECT
|
||||||
|
}
|
||||||
|
|
||||||
|
it.mutableMethod.getInstruction(index).getReference<FieldReference>()
|
||||||
|
?: throw PatchException("Could not find clientInfoOsVersionField")
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Spoof client type for /player requests.
|
// region Spoof client type for /player requests.
|
||||||
@@ -198,7 +225,7 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
addInstruction(
|
addInstruction(
|
||||||
checkCastIndex + 1,
|
checkCastIndex + 1,
|
||||||
"invoke-static { v$requestMessageInstanceRegister }," +
|
"invoke-static { v$requestMessageInstanceRegister }," +
|
||||||
" ${result.classDef.type}->$setClientInfoMethodName($clientInfoContainerClassName)V",
|
" ${result.classDef.type}->$setClientInfoMethodName($clientInfoContainerClassName)V",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +267,12 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String;
|
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String;
|
||||||
move-result-object v1
|
move-result-object v1
|
||||||
iput-object v1, v0, $clientInfoClientVersionField
|
iput-object v1, v0, $clientInfoClientVersionField
|
||||||
|
|
||||||
|
# Set client os version to the spoofed value.
|
||||||
|
iget-object v1, v0, $clientInfoOsVersionField
|
||||||
|
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getOsVersion(Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v1
|
||||||
|
iput-object v1, v0, $clientInfoOsVersionField
|
||||||
|
|
||||||
:disabled
|
:disabled
|
||||||
return-void
|
return-void
|
||||||
@@ -291,7 +324,8 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
|
|
||||||
it.mutableMethod.apply {
|
it.mutableMethod.apply {
|
||||||
// Find the conditional check if the playback speed menu item is not created.
|
// Find the conditional check if the playback speed menu item is not created.
|
||||||
val shouldCreateMenuIndex = indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ }
|
val shouldCreateMenuIndex =
|
||||||
|
indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ }
|
||||||
val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
|
val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
|
||||||
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
@@ -305,5 +339,47 @@ object SpoofClientPatch : BytecodePatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// Fix watch history if spoofing to iOS.
|
||||||
|
|
||||||
|
GetTrackingUriFingerprint.resultOrThrow().let {
|
||||||
|
it.mutableMethod.apply {
|
||||||
|
val returnUrlIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
|
val urlRegister = getInstruction<OneRegisterInstruction>(returnUrlIndex).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
returnUrlIndex,
|
||||||
|
"""
|
||||||
|
invoke-static { v$urlRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideTrackingUrl(Landroid/net/Uri;)Landroid/net/Uri;
|
||||||
|
move-result-object v$urlRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Fix video qualities missing, if spoofing to iOS by overriding the user agent.
|
||||||
|
|
||||||
|
BuildRequestFingerprint.resultOrThrow().let { result ->
|
||||||
|
result.mutableMethod.apply {
|
||||||
|
val buildRequestIndex = getInstructions().lastIndex - 2
|
||||||
|
val requestBuilderRegister = getInstruction<FiveRegisterInstruction>(buildRequestIndex).registerC
|
||||||
|
|
||||||
|
val newRequestBuilderIndex = result.scanResult.patternScanResult!!.endIndex
|
||||||
|
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
|
||||||
|
|
||||||
|
// Replace "requestBuilder.build(): Request" with "overrideUserAgent(requestBuilder, url): Request".
|
||||||
|
replaceInstruction(
|
||||||
|
buildRequestIndex,
|
||||||
|
"invoke-static { v$requestBuilderRegister, v$urlRegister }, " +
|
||||||
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->" +
|
||||||
|
"overrideUserAgent(${REQUEST_BUILDER_CLASS_DESCRIPTOR}Ljava/lang/String;)" +
|
||||||
|
REQUEST_CLASS_DESCRIPTOR
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal object BuildRequestFingerprint : MethodFingerprint(
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
|
returnType = "Lorg/chromium/net/UrlRequest;",
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction
|
||||||
|
import app.revanced.util.containsWideLiteralInstructionValue
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
|
||||||
|
internal object CreatePlayerRequestBodyWithVersionReleaseFingerprint : MethodFingerprint(
|
||||||
|
returnType = "L",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf(),
|
||||||
|
customFingerprint = { methodDef, _ ->
|
||||||
|
methodDef.containsWideLiteralInstructionValue(1073741824) &&
|
||||||
|
indexOfBuildVersionReleaseInstruction(methodDef) >= 0
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
fun indexOfBuildVersionReleaseInstruction(methodDef: Method) =
|
||||||
|
methodDef.indexOfFirstInstruction {
|
||||||
|
val reference = getReference<FieldReference>()
|
||||||
|
reference?.definingClass == "Landroid/os/Build\$VERSION;" &&
|
||||||
|
reference.name == "RELEASE" &&
|
||||||
|
reference.type == "Ljava/lang/String;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal object GetTrackingUriFingerprint : MethodFingerprint(
|
||||||
|
returnType = "Landroid/net/Uri;",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = emptyList(),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.RETURN_OBJECT
|
||||||
|
),
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
classDef.endsWith("TrackingUrlModel;")
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -870,9 +870,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
|||||||
<string name="revanced_sb_new_segment_choose_category">Choose the segment category</string>
|
<string name="revanced_sb_new_segment_choose_category">Choose the segment category</string>
|
||||||
<string name="revanced_sb_new_segment_disabled_category">Category is disabled in settings. Enable category to submit.</string>
|
<string name="revanced_sb_new_segment_disabled_category">Category is disabled in settings. Enable category to submit.</string>
|
||||||
<string name="revanced_sb_new_segment_title">New SponsorBlock segment</string>
|
<string name="revanced_sb_new_segment_title">New SponsorBlock segment</string>
|
||||||
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
|
<string name="revanced_sb_new_segment_mark_time_as_question">Set %s as the start or end of a new segment?</string>
|
||||||
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
|
|
||||||
<string name="revanced_sb_new_segment_mark_time_as_question">Set %1$02d:%2$02d:%3$03d as the start or end of a new segment?</string>
|
|
||||||
<string name="revanced_sb_new_segment_mark_start">start</string>
|
<string name="revanced_sb_new_segment_mark_start">start</string>
|
||||||
<string name="revanced_sb_new_segment_mark_end">end</string>
|
<string name="revanced_sb_new_segment_mark_end">end</string>
|
||||||
<string name="revanced_sb_new_segment_now">now</string>
|
<string name="revanced_sb_new_segment_now">now</string>
|
||||||
@@ -1134,8 +1132,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
|||||||
<string name="revanced_spoof_client_summary_off">Client is not spoofed\n\nVideo playback may not work</string>
|
<string name="revanced_spoof_client_summary_off">Client is not spoofed\n\nVideo playback may not work</string>
|
||||||
<string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
|
<string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
|
||||||
<string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
|
<string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
|
||||||
<string name="revanced_spoof_client_use_ios_summary_on">Client is currently spoofed to iOS\n\nSide effects include:\n• No HDR video\n• Watch history may not work\n• Higher video qualities may be missing\n• Live streams cannot play as audio only\n• Live streams not available on Android 8.0</string>
|
<string name="revanced_spoof_client_use_ios_summary_on">Client is currently spoofed to iOS\n\nSide effects include:\n• No HDR video\n• Higher video qualities may be missing\n• Live streams cannot play as audio only</string>
|
||||||
<string name="revanced_spoof_client_use_ios_summary_off">Client is currently spoofed to Android VR\n\nSide effects include:\n• No HDR video\n• Kids videos do not playback\n• Paused videos can randomly resume\n• Low quality Shorts seekbar thumbnails\n• Download action button is always hidden\n• End screen cards are always hidden</string>
|
<string name="revanced_spoof_client_use_ios_summary_off">Client is currently spoofed to Android VR\n\nSide effects include:\n• No HDR video\n• Kids videos do not playback\n• Paused videos can randomly resume\n• Low quality Shorts seekbar thumbnails\n• Download action button is hidden\n• End screen cards are hidden</string>
|
||||||
<string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
|
<string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
|
||||||
<string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
|
<string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
|
||||||
</patch>
|
</patch>
|
||||||
|
|||||||
Reference in New Issue
Block a user