mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-16 07:43:56 +00:00
Compare commits
37 Commits
v5.31.0-de
...
v5.31.2-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e578347277 | ||
|
|
294b2dce2e | ||
|
|
aa37105ea3 | ||
|
|
eb57a2697b | ||
|
|
19bc5b63c5 | ||
|
|
2b93ff6cfc | ||
|
|
cc6984e919 | ||
|
|
8bf575e778 | ||
|
|
2e625ee1a2 | ||
|
|
6bcba48ee7 | ||
|
|
c3034edc43 | ||
|
|
82255a09d3 | ||
|
|
594dce13cd | ||
|
|
479e205808 | ||
|
|
3d1b7e8101 | ||
|
|
e951184b7a | ||
|
|
d088b1e7ed | ||
|
|
a38f635514 | ||
|
|
b3e6c215cc | ||
|
|
c9cc3d5c41 | ||
|
|
536e64565c | ||
|
|
65cbf3c1eb | ||
|
|
61c1a7a75a | ||
|
|
1e39db06b8 | ||
|
|
e019f83232 | ||
|
|
3b57a5f8c0 | ||
|
|
eafe3dfc45 | ||
|
|
d56d8d990c | ||
|
|
37a8682901 | ||
|
|
11ba7d4e3e | ||
|
|
6833d37c26 | ||
|
|
e6f72bcb7d | ||
|
|
e8a227c082 | ||
|
|
0472ec2830 | ||
|
|
6412a5cb1a | ||
|
|
cc548689ac | ||
|
|
a3d47e72e3 |
28
.github/dependabot.yml
vendored
28
.github/dependabot.yml
vendored
@@ -1,22 +1,26 @@
|
||||
version: 2
|
||||
multi-ecosystem-groups:
|
||||
dependency:
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: dev
|
||||
labels: [ ]
|
||||
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
labels: []
|
||||
multi-ecosystem-group: "dependency"
|
||||
directory: /
|
||||
target-branch: dev
|
||||
schedule:
|
||||
interval: monthly
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: npm
|
||||
labels: []
|
||||
multi-ecosystem-group: "dependency"
|
||||
directory: /
|
||||
target-branch: dev
|
||||
schedule:
|
||||
interval: monthly
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: gradle
|
||||
labels: []
|
||||
multi-ecosystem-group: "dependency"
|
||||
directory: /
|
||||
target-branch: dev
|
||||
schedule:
|
||||
interval: monthly
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
2
.github/workflows/build_pull_request.yml
vendored
2
.github/workflows/build_pull_request.yml
vendored
@@ -13,8 +13,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
|
||||
1
.github/workflows/pull_strings.yml
vendored
1
.github/workflows/pull_strings.yml
vendored
@@ -17,7 +17,6 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: dev
|
||||
fetch-depth: 0
|
||||
clean: true
|
||||
|
||||
- name: Pull strings
|
||||
|
||||
2
.github/workflows/push_strings.yml
vendored
2
.github/workflows/push_strings.yml
vendored
@@ -15,8 +15,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Preprocess strings
|
||||
env:
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -19,8 +19,6 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
|
||||
120
CHANGELOG.md
120
CHANGELOG.md
@@ -1,3 +1,123 @@
|
||||
## [5.31.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.31.2-dev.2...v5.31.2-dev.3) (2025-07-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Disable double tap actions:** Remove old incompatible targets ([857053e](https://github.com/ReVanced/revanced-patches/commit/857053e29b72ded10a84b0ac693fa107705342d9))
|
||||
|
||||
## [5.31.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.31.2-dev.1...v5.31.2-dev.2) (2025-07-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide layout components:** Show correct custom header logo if 'Hide YouTube Doodles' is enabled ([#5431](https://github.com/ReVanced/revanced-patches/issues/5431)) ([20cc141](https://github.com/ReVanced/revanced-patches/commit/20cc141e61f75de1a1749247c4f4aed167dee8ea))
|
||||
|
||||
## [5.31.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.1...v5.31.2-dev.1) (2025-07-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide layout components:** Hide quick actions does not work ([#5423](https://github.com/ReVanced/revanced-patches/issues/5423)) ([9c66729](https://github.com/ReVanced/revanced-patches/commit/9c6672946d44001e106bdac9041e2d79ef3f6ab2))
|
||||
|
||||
## [5.31.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.0...v5.31.1) (2025-07-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Spotify - Unlock Premium:** Fix hiding context menu ads for latest version ([#5415](https://github.com/ReVanced/revanced-patches/issues/5415)) ([dcde393](https://github.com/ReVanced/revanced-patches/commit/dcde3935bde3172576d0f9f5ff9eb62ecfff7dfe))
|
||||
|
||||
## [5.31.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.0...v5.31.1-dev.1) (2025-07-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Spotify - Unlock Premium:** Fix hiding context menu ads for latest version ([#5415](https://github.com/ReVanced/revanced-patches/issues/5415)) ([dcde393](https://github.com/ReVanced/revanced-patches/commit/dcde3935bde3172576d0f9f5ff9eb62ecfff7dfe))
|
||||
|
||||
# [5.31.0](https://github.com/ReVanced/revanced-patches/compare/v5.30.0...v5.31.0) (2025-07-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Bacon Reader - Spoof client:** Use www instead of ssl API to fix auth related issues ([#5402](https://github.com/ReVanced/revanced-patches/issues/5402)) ([72459bb](https://github.com/ReVanced/revanced-patches/commit/72459bb2eaf4691e32822dfdd1db3240e2fe98dd))
|
||||
* Correctly name `Enable ROM signature spoofing` patch ([d85881a](https://github.com/ReVanced/revanced-patches/commit/d85881a6768232a999534677bebb248e640fe5ab))
|
||||
* Fix accidental changes ([e2ac841](https://github.com/ReVanced/revanced-patches/commit/e2ac8419756e3c7d62e2c0430a2918a3c1c63666))
|
||||
* Fix refactoring typo ([ec0ae42](https://github.com/ReVanced/revanced-patches/commit/ec0ae42496628cdeb2a639020fce94316b41b751))
|
||||
* Handle empty list of announcements ([de9d720](https://github.com/ReVanced/revanced-patches/commit/de9d7209f4e818a618a7fd9000013ae8ebd728f2))
|
||||
* **SoundCloud:** Constrain patches to last working app target ([e8ea89f](https://github.com/ReVanced/revanced-patches/commit/e8ea89fc1a3f0531a0af7529663f13328aca4fe7))
|
||||
* **Spotify - Unlock Premium:** Remove wrongfully hidden non ad browse sections ([#5403](https://github.com/ReVanced/revanced-patches/issues/5403)) ([8633544](https://github.com/ReVanced/revanced-patches/commit/8633544decc0814d7a548fbc5576b4bdd1d7eee0))
|
||||
* **Spotify:** Remove other ads type from the browse screen ([#5333](https://github.com/ReVanced/revanced-patches/issues/5333)) ([c68533a](https://github.com/ReVanced/revanced-patches/commit/c68533a33a399ca813380b5c9ccddce434ceadf8))
|
||||
* **Sync for Reddit - Spoof client:** Use www instead of ssl API to fix auth related issues ([#5392](https://github.com/ReVanced/revanced-patches/issues/5392)) ([47e6b62](https://github.com/ReVanced/revanced-patches/commit/47e6b62f3d8b07960cfb2963f441222d3e67df92))
|
||||
* **YouTube - Hide ads:** Hide new type of general ad ([#5345](https://github.com/ReVanced/revanced-patches/issues/5345)) ([f23716b](https://github.com/ReVanced/revanced-patches/commit/f23716bc52c03d8d0271bfe38b19247e6de7021d))
|
||||
* **YouTube - Hide layout components:** Do not hide playlist sort button if 'Hide AI comments summary' is on ([5f3e48e](https://github.com/ReVanced/revanced-patches/commit/5f3e48ec5853f6439800ef58239291c34bcab5f6))
|
||||
* **YouTube - Playback speed:** Allow custom speeds with 0.01x precision ([#5360](https://github.com/ReVanced/revanced-patches/issues/5360)) ([0eecef0](https://github.com/ReVanced/revanced-patches/commit/0eecef00fc93d2a217944978e29dce82e3134e35))
|
||||
* **YouTube - Slide to seek:** Show tap and hold 2x speed overlay when active ([#5398](https://github.com/ReVanced/revanced-patches/issues/5398)) ([dbc9c5f](https://github.com/ReVanced/revanced-patches/commit/dbc9c5f00c1f5bbb95f8822667cc1ac3c613fa00))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Cricbuzz - Hide ads:** Hide Cricbuzz11 UI elements ([#5381](https://github.com/ReVanced/revanced-patches/issues/5381)) ([a42c98f](https://github.com/ReVanced/revanced-patches/commit/a42c98f8b51fd37d815fd38b75a2b7ccc4fb049b))
|
||||
* **Lightroom:** Constrain patches to last working version ([#5335](https://github.com/ReVanced/revanced-patches/issues/5335)) ([32ce70e](https://github.com/ReVanced/revanced-patches/commit/32ce70e994f354b9a569376bb89eb38b3190e6f9))
|
||||
* **Spotify - Spoof client:** Fix issues like songs skipping by spoofing to iOS ([#5388](https://github.com/ReVanced/revanced-patches/issues/5388)) ([e36d4c1](https://github.com/ReVanced/revanced-patches/commit/e36d4c1986b58815c7659e6ef44011166873f9c8))
|
||||
* **Spotify:** Remove support for old versions ([#5404](https://github.com/ReVanced/revanced-patches/issues/5404)) ([9d31238](https://github.com/ReVanced/revanced-patches/commit/9d31238803a45e957472760fc40c3862da2cf3f0))
|
||||
* **YouTube - Change header:** Add in-app setting to change the app header ([#5346](https://github.com/ReVanced/revanced-patches/issues/5346)) ([9ba45b6](https://github.com/ReVanced/revanced-patches/commit/9ba45b6680595d732b47e8fa54bee98b7c7af179))
|
||||
* **YouTube - Hide layout components:** Add `Hide channel links preview` and `Hide 'Visit Community' button` in channel page ([#5320](https://github.com/ReVanced/revanced-patches/issues/5320)) ([9d9cce3](https://github.com/ReVanced/revanced-patches/commit/9d9cce3ec5550b2fea88df745f1700bb2f17eb9e))
|
||||
* **YouTube:** Disable two-finger tap gesture for skipping chapters ([#5374](https://github.com/ReVanced/revanced-patches/issues/5374)) ([71db0a2](https://github.com/ReVanced/revanced-patches/commit/71db0a2661b5f76eb5048cdeed83f26fbfdf4fee))
|
||||
|
||||
# [5.31.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.16...v5.31.0-dev.17) (2025-07-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Spotify - Unlock Premium:** Remove wrongfully hidden non ad browse sections ([#5403](https://github.com/ReVanced/revanced-patches/issues/5403)) ([8633544](https://github.com/ReVanced/revanced-patches/commit/8633544decc0814d7a548fbc5576b4bdd1d7eee0))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Spotify:** Remove support for old versions ([#5404](https://github.com/ReVanced/revanced-patches/issues/5404)) ([9d31238](https://github.com/ReVanced/revanced-patches/commit/9d31238803a45e957472760fc40c3862da2cf3f0))
|
||||
|
||||
# [5.31.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.15...v5.31.0-dev.16) (2025-07-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Spotify - Spoof client:** Fix issues like songs skipping by spoofing to iOS ([#5388](https://github.com/ReVanced/revanced-patches/issues/5388)) ([e36d4c1](https://github.com/ReVanced/revanced-patches/commit/e36d4c1986b58815c7659e6ef44011166873f9c8))
|
||||
* **YouTube:** Disable two-finger tap gesture for skipping chapters ([#5374](https://github.com/ReVanced/revanced-patches/issues/5374)) ([71db0a2](https://github.com/ReVanced/revanced-patches/commit/71db0a2661b5f76eb5048cdeed83f26fbfdf4fee))
|
||||
|
||||
# [5.31.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.14...v5.31.0-dev.15) (2025-07-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Handle empty list of announcements ([de9d720](https://github.com/ReVanced/revanced-patches/commit/de9d7209f4e818a618a7fd9000013ae8ebd728f2))
|
||||
|
||||
# [5.31.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.13...v5.31.0-dev.14) (2025-07-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Bacon Reader - Spoof client:** Use www instead of ssl API to fix auth related issues ([#5402](https://github.com/ReVanced/revanced-patches/issues/5402)) ([72459bb](https://github.com/ReVanced/revanced-patches/commit/72459bb2eaf4691e32822dfdd1db3240e2fe98dd))
|
||||
|
||||
# [5.31.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.12...v5.31.0-dev.13) (2025-07-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Slide to seek:** Show tap and hold 2x speed overlay when active ([#5398](https://github.com/ReVanced/revanced-patches/issues/5398)) ([dbc9c5f](https://github.com/ReVanced/revanced-patches/commit/dbc9c5f00c1f5bbb95f8822667cc1ac3c613fa00))
|
||||
|
||||
# [5.31.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.11...v5.31.0-dev.12) (2025-07-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Sync for Reddit - Spoof client:** Use www instead of ssl API to fix auth related issues ([#5392](https://github.com/ReVanced/revanced-patches/issues/5392)) ([47e6b62](https://github.com/ReVanced/revanced-patches/commit/47e6b62f3d8b07960cfb2963f441222d3e67df92))
|
||||
|
||||
# [5.31.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.10...v5.31.0-dev.11) (2025-07-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Cricbuzz - Hide ads:** Hide Cricbuzz11 UI elements ([#5381](https://github.com/ReVanced/revanced-patches/issues/5381)) ([a42c98f](https://github.com/ReVanced/revanced-patches/commit/a42c98f8b51fd37d815fd38b75a2b7ccc4fb049b))
|
||||
|
||||
# [5.31.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.9...v5.31.0-dev.10) (2025-07-09)
|
||||
|
||||
|
||||
|
||||
4
extensions/cricbuzz/build.gradle.kts
Normal file
4
extensions/cricbuzz/build.gradle.kts
Normal file
@@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
compileOnly(project(":extensions:cricbuzz:stub"))
|
||||
}
|
||||
1
extensions/cricbuzz/src/main/AndroidManifest.xml
Normal file
1
extensions/cricbuzz/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,28 @@
|
||||
package app.revanced.extension.cricbuzz.ads;
|
||||
|
||||
import com.cricbuzz.android.data.rest.model.BottomBar;
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class HideAdsPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void filterCb11(List<BottomBar> list) {
|
||||
try {
|
||||
Iterator<BottomBar> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
BottomBar bar = iterator.next();
|
||||
if (bar.getName().equals("Cricbuzz11")) {
|
||||
Logger.printInfo(() -> "Removing Cricbuzz11 bar: " + bar);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "filterCb11 failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
17
extensions/cricbuzz/stub/build.gradle.kts
Normal file
17
extensions/cricbuzz/stub/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.library)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
1
extensions/cricbuzz/stub/src/main/AndroidManifest.xml
Normal file
1
extensions/cricbuzz/stub/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.cricbuzz.android.data.rest.model;
|
||||
|
||||
public final class BottomBar {
|
||||
public final String getName() { throw new UnsupportedOperationException(); }
|
||||
}
|
||||
@@ -7,7 +7,6 @@ dependencies {
|
||||
compileOnly(project(":extensions:spotify:stub"))
|
||||
compileOnly(libs.annotation)
|
||||
|
||||
implementation(project(":extensions:spotify:utils"))
|
||||
implementation(libs.nanohttpd)
|
||||
implementation(libs.protobuf.javalite)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package app.revanced.extension.spotify.layout.hide.createbutton;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.spotify.shared.ComponentFilters.*;
|
||||
import app.revanced.extension.spotify.shared.ComponentFilters.ComponentFilter;
|
||||
import app.revanced.extension.spotify.shared.ComponentFilters.ResourceIdComponentFilter;
|
||||
import app.revanced.extension.spotify.shared.ComponentFilters.StringComponentFilter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class HideCreateButtonPatch {
|
||||
@@ -53,7 +55,9 @@ public final class HideCreateButtonPatch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
} catch (Throwable ex) {
|
||||
// Catch Throwable as calling toString can cause crashes with wrongfully generated code that throws
|
||||
// NoSuchMethod errors.
|
||||
Logger.printException(() -> "returnNullIfIsCreateButton failure", ex);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package app.revanced.extension.spotify.misc.fix;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.spotify.misc.fix.clienttoken.data.v0.ClienttokenHttp.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import static app.revanced.extension.spotify.misc.fix.Constants.*;
|
||||
|
||||
class ClientTokenService {
|
||||
private static final String IOS_CLIENT_ID = "58bd3c95768941ea9eb4350aaa033eb3";
|
||||
private static final String IOS_USER_AGENT;
|
||||
|
||||
static {
|
||||
String clientVersion = getClientVersion();
|
||||
int commitHashIndex = clientVersion.lastIndexOf(".");
|
||||
String version = clientVersion.substring(
|
||||
clientVersion.indexOf("-") + 1,
|
||||
clientVersion.lastIndexOf(".", commitHashIndex - 1)
|
||||
);
|
||||
|
||||
IOS_USER_AGENT = "Spotify/" + version + " iOS/" + getSystemVersion() + " (" + getHardwareMachine() + ")";
|
||||
}
|
||||
|
||||
private static final ConnectivitySdkData.Builder IOS_CONNECTIVITY_SDK_DATA =
|
||||
ConnectivitySdkData.newBuilder()
|
||||
.setPlatformSpecificData(PlatformSpecificData.newBuilder()
|
||||
.setIos(NativeIOSData.newBuilder()
|
||||
.setHwMachine(getHardwareMachine())
|
||||
.setSystemVersion(getSystemVersion())
|
||||
)
|
||||
);
|
||||
|
||||
private static final ClientDataRequest.Builder IOS_CLIENT_DATA_REQUEST =
|
||||
ClientDataRequest.newBuilder()
|
||||
.setClientVersion(getClientVersion())
|
||||
.setClientId(IOS_CLIENT_ID);
|
||||
|
||||
private static final ClientTokenRequest.Builder IOS_CLIENT_TOKEN_REQUEST =
|
||||
ClientTokenRequest.newBuilder()
|
||||
.setRequestType(ClientTokenRequestType.REQUEST_CLIENT_DATA_REQUEST);
|
||||
|
||||
|
||||
@NonNull
|
||||
static ClientTokenRequest newIOSClientTokenRequest(String deviceId) {
|
||||
Logger.printInfo(() -> "Creating new iOS client token request with device ID: " + deviceId);
|
||||
|
||||
return IOS_CLIENT_TOKEN_REQUEST
|
||||
.setClientData(IOS_CLIENT_DATA_REQUEST
|
||||
.setConnectivitySdkData(IOS_CONNECTIVITY_SDK_DATA
|
||||
.setDeviceId(deviceId)
|
||||
)
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ClientTokenResponse getClientTokenResponse(@NonNull ClientTokenRequest request) {
|
||||
if (request.getRequestType() == ClientTokenRequestType.REQUEST_CLIENT_DATA_REQUEST) {
|
||||
Logger.printInfo(() -> "Requesting iOS client token");
|
||||
String deviceId = request.getClientData().getConnectivitySdkData().getDeviceId();
|
||||
request = newIOSClientTokenRequest(deviceId);
|
||||
}
|
||||
|
||||
ClientTokenResponse response;
|
||||
try {
|
||||
response = requestClientToken(request);
|
||||
} catch (IOException ex) {
|
||||
Logger.printException(() -> "Failed to handle request", ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static ClientTokenResponse requestClientToken(@NonNull ClientTokenRequest request) throws IOException {
|
||||
HttpURLConnection urlConnection = (HttpURLConnection) new URL(CLIENT_TOKEN_API_URL).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-protobuf");
|
||||
urlConnection.setRequestProperty("Accept", "application/x-protobuf");
|
||||
urlConnection.setRequestProperty("User-Agent", IOS_USER_AGENT);
|
||||
|
||||
byte[] requestArray = request.toByteArray();
|
||||
urlConnection.setFixedLengthStreamingMode(requestArray.length);
|
||||
urlConnection.getOutputStream().write(requestArray);
|
||||
|
||||
try (InputStream inputStream = urlConnection.getInputStream()) {
|
||||
return ClientTokenResponse.parseFrom(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static ClientTokenResponse serveClientTokenRequest(@NonNull InputStream inputStream) {
|
||||
ClientTokenRequest request;
|
||||
try {
|
||||
request = ClientTokenRequest.parseFrom(inputStream);
|
||||
} catch (IOException ex) {
|
||||
Logger.printException(() -> "Failed to parse request from input stream", ex);
|
||||
return null;
|
||||
}
|
||||
Logger.printInfo(() -> "Request of type: " + request.getRequestType());
|
||||
|
||||
ClientTokenResponse response = getClientTokenResponse(request);
|
||||
if (response != null) Logger.printInfo(() -> "Response of type: " + response.getResponseType());
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package app.revanced.extension.spotify.misc.fix;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
class Constants {
|
||||
static final String CLIENT_TOKEN_API_PATH = "/v1/clienttoken";
|
||||
static final String CLIENT_TOKEN_API_URL = "https://clienttoken.spotify.com" + CLIENT_TOKEN_API_PATH;
|
||||
|
||||
// Modified by a patch. Do not touch.
|
||||
@NonNull
|
||||
static String getClientVersion() {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Modified by a patch. Do not touch.
|
||||
@NonNull
|
||||
static String getSystemVersion() {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Modified by a patch. Do not touch.
|
||||
@NonNull
|
||||
static String getHardwareMachine() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package app.revanced.extension.spotify.misc.fix;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.spotify.login5.v4.proto.Login5.*;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
import static app.revanced.extension.spotify.misc.fix.Session.FAILED_TO_RENEW_SESSION;
|
||||
import static fi.iki.elonen.NanoHTTPD.Response.Status.INTERNAL_ERROR;
|
||||
|
||||
class LoginRequestListener extends NanoHTTPD {
|
||||
LoginRequestListener(int port) {
|
||||
super(port);
|
||||
|
||||
try {
|
||||
start();
|
||||
} catch (IOException ex) {
|
||||
Logger.printException(() -> "Failed to start login request listener on port " + port, ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Response serve(IHTTPSession request) {
|
||||
Logger.printInfo(() -> "Serving request for URI: " + request.getUri());
|
||||
|
||||
InputStream requestBodyInputStream = getRequestBodyInputStream(request);
|
||||
|
||||
LoginRequest loginRequest;
|
||||
try {
|
||||
loginRequest = LoginRequest.parseFrom(requestBodyInputStream);
|
||||
} catch (IOException ex) {
|
||||
Logger.printException(() -> "Failed to parse LoginRequest", ex);
|
||||
return newResponse(INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
MessageLite loginResponse;
|
||||
|
||||
// A request may be made concurrently by Spotify,
|
||||
// however a webview can only handle one request at a time due to singleton cookie manager.
|
||||
// Therefore, synchronize to ensure that only one webview handles the request at a time.
|
||||
synchronized (this) {
|
||||
try {
|
||||
loginResponse = getLoginResponse(loginRequest);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "Failed to get login response", ex);
|
||||
return newResponse(INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
return newResponse(Response.Status.OK, loginResponse);
|
||||
}
|
||||
|
||||
|
||||
private static LoginResponse getLoginResponse(@NonNull LoginRequest loginRequest) {
|
||||
Session session;
|
||||
|
||||
if (!loginRequest.hasStoredCredential()) {
|
||||
Logger.printInfo(() -> "Received request for initial login");
|
||||
session = WebApp.currentSession; // Session obtained from WebApp.launchLogin, can be null if still in progress.
|
||||
} else {
|
||||
Logger.printInfo(() -> "Received request to restore saved session");
|
||||
session = Session.read(loginRequest.getStoredCredential().getUsername());
|
||||
}
|
||||
|
||||
return toLoginResponse(session);
|
||||
}
|
||||
|
||||
private static LoginResponse toLoginResponse(@Nullable Session session) {
|
||||
LoginResponse.Builder builder = LoginResponse.newBuilder();
|
||||
|
||||
if (session == null) {
|
||||
Logger.printException(() -> "Session is null. An initial login may still be in progress, returning try again later error");
|
||||
builder.setError(LoginError.TRY_AGAIN_LATER);
|
||||
} else if (session.accessTokenExpired()) {
|
||||
Logger.printInfo(() -> "Access token expired, renewing session");
|
||||
WebApp.renewSessionBlocking(session.cookies);
|
||||
return toLoginResponse(WebApp.currentSession);
|
||||
} else if (session.username == null) {
|
||||
Logger.printException(() -> "Session username is null, likely caused by invalid cookies, returning invalid credentials error");
|
||||
session.delete();
|
||||
builder.setError(LoginError.INVALID_CREDENTIALS);
|
||||
} else if (session == FAILED_TO_RENEW_SESSION) {
|
||||
Logger.printException(() -> "Failed to renew session, likely caused by a timeout, returning try again later error");
|
||||
builder.setError(LoginError.TRY_AGAIN_LATER);
|
||||
} else {
|
||||
session.save();
|
||||
Logger.printInfo(() -> "Returning session for username: " + session.username);
|
||||
builder.setOk(LoginOk.newBuilder()
|
||||
.setUsername(session.username)
|
||||
.setAccessToken(session.accessToken)
|
||||
.setStoredCredential(ByteString.fromHex("00")) // Placeholder, as it cannot be null or empty.
|
||||
.setAccessTokenExpiresIn(session.accessTokenExpiresInSeconds())
|
||||
.build());
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static InputStream limitedInputStream(InputStream inputStream, long contentLength) {
|
||||
return new FilterInputStream(inputStream) {
|
||||
private long remaining = contentLength;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (remaining <= 0) return -1;
|
||||
int result = super.read();
|
||||
if (result != -1) remaining--;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (remaining <= 0) return -1;
|
||||
len = (int) Math.min(len, remaining);
|
||||
int result = super.read(b, off, len);
|
||||
if (result != -1) remaining -= result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static InputStream getRequestBodyInputStream(@NonNull IHTTPSession request) {
|
||||
long requestContentLength =
|
||||
Long.parseLong(Objects.requireNonNull(request.getHeaders().get("content-length")));
|
||||
return limitedInputStream(request.getInputStream(), requestContentLength);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
@NonNull
|
||||
private static Response newResponse(Response.Status status) {
|
||||
return newResponse(status, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Response newResponse(Response.IStatus status, MessageLite messageLite) {
|
||||
if (messageLite == null) {
|
||||
return newFixedLengthResponse(status, "application/x-protobuf", null);
|
||||
}
|
||||
|
||||
byte[] messageBytes = messageLite.toByteArray();
|
||||
InputStream stream = new ByteArrayInputStream(messageBytes);
|
||||
return newFixedLengthResponse(status, "application/x-protobuf", stream, messageBytes.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package app.revanced.extension.spotify.misc.fix;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.spotify.misc.fix.clienttoken.data.v0.ClienttokenHttp.ClientTokenResponse;
|
||||
import com.google.protobuf.MessageLite;
|
||||
import fi.iki.elonen.NanoHTTPD;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
import static app.revanced.extension.spotify.misc.fix.ClientTokenService.serveClientTokenRequest;
|
||||
import static app.revanced.extension.spotify.misc.fix.Constants.CLIENT_TOKEN_API_PATH;
|
||||
import static fi.iki.elonen.NanoHTTPD.Response.Status.INTERNAL_ERROR;
|
||||
|
||||
class RequestListener extends NanoHTTPD {
|
||||
RequestListener(int port) {
|
||||
super(port);
|
||||
|
||||
try {
|
||||
start();
|
||||
} catch (IOException ex) {
|
||||
Logger.printException(() -> "Failed to start request listener on port " + port, ex);
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Response serve(@NonNull IHTTPSession session) {
|
||||
String uri = session.getUri();
|
||||
if (!uri.equals(CLIENT_TOKEN_API_PATH)) return INTERNAL_ERROR_RESPONSE;
|
||||
|
||||
Logger.printInfo(() -> "Serving request for URI: " + uri);
|
||||
|
||||
ClientTokenResponse response = serveClientTokenRequest(getInputStream(session));
|
||||
if (response != null) return newResponse(Response.Status.OK, response);
|
||||
|
||||
Logger.printException(() -> "Failed to serve client token request");
|
||||
return INTERNAL_ERROR_RESPONSE;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static InputStream newLimitedInputStream(InputStream inputStream, long contentLength) {
|
||||
return new FilterInputStream(inputStream) {
|
||||
private long remaining = contentLength;
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (remaining <= 0) return -1;
|
||||
int result = super.read();
|
||||
if (result != -1) remaining--;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (remaining <= 0) return -1;
|
||||
len = (int) Math.min(len, remaining);
|
||||
int result = super.read(b, off, len);
|
||||
if (result != -1) remaining -= result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static InputStream getInputStream(@NonNull IHTTPSession session) {
|
||||
long requestContentLength = Long.parseLong(Objects.requireNonNull(session.getHeaders().get("content-length")));
|
||||
return newLimitedInputStream(session.getInputStream(), requestContentLength);
|
||||
}
|
||||
|
||||
private static final Response INTERNAL_ERROR_RESPONSE = newResponse(INTERNAL_ERROR);
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
@NonNull
|
||||
private static Response newResponse(Response.Status status) {
|
||||
return newResponse(status, null);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Response newResponse(Response.IStatus status, MessageLite messageLite) {
|
||||
if (messageLite == null) {
|
||||
return newFixedLengthResponse(status, "application/x-protobuf", null);
|
||||
}
|
||||
|
||||
byte[] messageBytes = messageLite.toByteArray();
|
||||
InputStream stream = new ByteArrayInputStream(messageBytes);
|
||||
return newFixedLengthResponse(status, "application/x-protobuf", stream, messageBytes.length);
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
package app.revanced.extension.spotify.misc.fix;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import static android.content.Context.MODE_PRIVATE;
|
||||
|
||||
class Session {
|
||||
/**
|
||||
* Username of the account. Null if this session does not have an authenticated user.
|
||||
*/
|
||||
@Nullable
|
||||
final String username;
|
||||
/**
|
||||
* Access token for this session.
|
||||
*/
|
||||
final String accessToken;
|
||||
/**
|
||||
* Session expiration timestamp in milliseconds.
|
||||
*/
|
||||
final Long expirationTime;
|
||||
/**
|
||||
* Authentication cookies for this session.
|
||||
*/
|
||||
final String cookies;
|
||||
|
||||
/**
|
||||
* Session that represents a failed attempt to renew the session.
|
||||
*/
|
||||
static final Session FAILED_TO_RENEW_SESSION = new Session("", "", "");
|
||||
|
||||
/**
|
||||
* @param username Username of the account. Empty if this session does not have an authenticated user.
|
||||
* @param accessToken Access token for this session.
|
||||
* @param cookies Authentication cookies for this session.
|
||||
*/
|
||||
Session(@Nullable String username, String accessToken, String cookies) {
|
||||
this(username, accessToken, System.currentTimeMillis() + 60 * 60 * 1000, cookies);
|
||||
}
|
||||
|
||||
private Session(@Nullable String username, String accessToken, long expirationTime, String cookies) {
|
||||
this.username = username;
|
||||
this.accessToken = accessToken;
|
||||
this.expirationTime = expirationTime;
|
||||
this.cookies = cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of milliseconds until the access token expires.
|
||||
*/
|
||||
long accessTokenExpiresInMillis() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
return expirationTime - currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of seconds until the access token expires.
|
||||
*/
|
||||
int accessTokenExpiresInSeconds() {
|
||||
return (int) accessTokenExpiresInMillis() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the access token has expired, false otherwise.
|
||||
*/
|
||||
boolean accessTokenExpired() {
|
||||
return accessTokenExpiresInMillis() <= 0;
|
||||
}
|
||||
|
||||
void save() {
|
||||
Logger.printInfo(() -> "Saving session: " + this);
|
||||
|
||||
SharedPreferences.Editor editor = Utils.getContext().getSharedPreferences("revanced", MODE_PRIVATE).edit();
|
||||
|
||||
String json;
|
||||
try {
|
||||
json = new JSONObject()
|
||||
.put("accessToken", accessToken)
|
||||
.put("expirationTime", expirationTime)
|
||||
.put("cookies", cookies).toString();
|
||||
} catch (JSONException ex) {
|
||||
Logger.printException(() -> "Failed to convert session to stored credential", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
editor.putString("session_" + username, json);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
void delete() {
|
||||
Logger.printInfo(() -> "Deleting saved session for username: " + username);
|
||||
SharedPreferences.Editor editor = Utils.getContext().getSharedPreferences("revanced", MODE_PRIVATE).edit();
|
||||
editor.remove("session_" + username);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Session read(String username) {
|
||||
Logger.printInfo(() -> "Reading saved session for username: " + username);
|
||||
|
||||
SharedPreferences sharedPreferences = Utils.getContext().getSharedPreferences("revanced", MODE_PRIVATE);
|
||||
String savedJson = sharedPreferences.getString("session_" + username, null);
|
||||
if (savedJson == null) {
|
||||
Logger.printInfo(() -> "No session found in shared preferences");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject json = new JSONObject(savedJson);
|
||||
String accessToken = json.getString("accessToken");
|
||||
long expirationTime = json.getLong("expirationTime");
|
||||
String cookies = json.getString("cookies");
|
||||
|
||||
return new Session(username, accessToken, expirationTime, cookies);
|
||||
} catch (JSONException ex) {
|
||||
Logger.printException(() -> "Failed to read session from shared preferences", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Session(" +
|
||||
"username=" + username +
|
||||
", accessToken=" + accessToken +
|
||||
", expirationTime=" + expirationTime +
|
||||
", cookies=" + cookies +
|
||||
')';
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,15 @@
|
||||
package app.revanced.extension.spotify.misc.fix;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofClientPatch {
|
||||
private static LoginRequestListener listener;
|
||||
private static RequestListener listener;
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <br>
|
||||
* Launch login server.
|
||||
* Injection point. Launch requests listener server.
|
||||
*/
|
||||
public static void launchListener(int port) {
|
||||
public synchronized static void launchListener(int port) {
|
||||
if (listener != null) {
|
||||
Logger.printInfo(() -> "Listener already running on port " + port);
|
||||
return;
|
||||
@@ -21,34 +17,9 @@ public class SpoofClientPatch {
|
||||
|
||||
try {
|
||||
Logger.printInfo(() -> "Launching listener on port " + port);
|
||||
listener = new LoginRequestListener(port);
|
||||
listener = new RequestListener(port);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "launchListener failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <br>
|
||||
* Launch login web view.
|
||||
*/
|
||||
public static void launchLogin(LayoutInflater inflater) {
|
||||
try {
|
||||
WebApp.launchLogin(inflater.getContext());
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "launchLogin failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <br>
|
||||
* Set handler to call the native login after the webview login.
|
||||
*/
|
||||
public static void setNativeLoginHandler(View startLoginButton) {
|
||||
WebApp.nativeLoginHandler = (() -> {
|
||||
startLoginButton.setSoundEffectsEnabled(false);
|
||||
startLoginButton.performClick();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
package app.revanced.extension.spotify.misc.fix;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Build;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.webkit.*;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.spotify.UserAgent;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static app.revanced.extension.spotify.misc.fix.Session.FAILED_TO_RENEW_SESSION;
|
||||
|
||||
class WebApp {
|
||||
private static final String OPEN_SPOTIFY_COM = "open.spotify.com";
|
||||
private static final String OPEN_SPOTIFY_COM_URL = "https://" + OPEN_SPOTIFY_COM;
|
||||
private static final String OPEN_SPOTIFY_COM_PREFERENCES_URL = OPEN_SPOTIFY_COM_URL + "/preferences";
|
||||
private static final String ACCOUNTS_SPOTIFY_COM_LOGIN_URL = "https://accounts.spotify.com/login?allow_password=1"
|
||||
+ "&continue=https%3A%2F%2Fopen.spotify.com%2Fpreferences";
|
||||
|
||||
private static final int GET_SESSION_TIMEOUT_SECONDS = 10;
|
||||
private static final String JAVASCRIPT_INTERFACE_NAME = "androidInterface";
|
||||
private static final String USER_AGENT = getWebUserAgent();
|
||||
|
||||
/**
|
||||
* A session obtained from the webview after logging in.
|
||||
*/
|
||||
@Nullable
|
||||
static volatile Session currentSession = null;
|
||||
|
||||
/**
|
||||
* Current webview in use. Any use of the object must be done on the main thread.
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static volatile WebView currentWebView;
|
||||
|
||||
interface NativeLoginHandler {
|
||||
void login();
|
||||
}
|
||||
|
||||
static NativeLoginHandler nativeLoginHandler;
|
||||
|
||||
static void launchLogin(Context context) {
|
||||
final Dialog dialog = newDialog(context);
|
||||
|
||||
Utils.runOnBackgroundThread(() -> {
|
||||
Logger.printInfo(() -> "Launching login");
|
||||
|
||||
// A session must be obtained from a login. Repeat until a session is acquired.
|
||||
boolean isAcquired = false;
|
||||
do {
|
||||
CountDownLatch onLoggedInLatch = new CountDownLatch(1);
|
||||
CountDownLatch getSessionLatch = new CountDownLatch(1);
|
||||
|
||||
// Can't use Utils.getContext() here, because autofill won't work.
|
||||
// See https://stackoverflow.com/a/79182053/11213244.
|
||||
launchWebView(context, ACCOUNTS_SPOTIFY_COM_LOGIN_URL, new WebViewCallback() {
|
||||
@Override
|
||||
void onInitialized(WebView webView) {
|
||||
super.onInitialized(webView);
|
||||
|
||||
dialog.setContentView(webView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
void onLoggedIn(String cookies) {
|
||||
onLoggedInLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
void onReceivedSession(Session session) {
|
||||
super.onReceivedSession(session);
|
||||
|
||||
getSessionLatch.countDown();
|
||||
dialog.dismiss();
|
||||
|
||||
try {
|
||||
nativeLoginHandler.login();
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "nativeLoginHandler failure", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
// Wait indefinitely until the user logs in.
|
||||
onLoggedInLatch.await();
|
||||
// Wait until the session is received, or timeout.
|
||||
isAcquired = getSessionLatch.await(GET_SESSION_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.printException(() -> "Login interrupted", ex);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} while (!isAcquired);
|
||||
});
|
||||
}
|
||||
|
||||
static void renewSessionBlocking(String cookies) {
|
||||
Logger.printInfo(() -> "Renewing session with cookies: " + cookies);
|
||||
|
||||
CountDownLatch getSessionLatch = new CountDownLatch(1);
|
||||
|
||||
launchWebView(Utils.getContext(), OPEN_SPOTIFY_COM_PREFERENCES_URL, new WebViewCallback() {
|
||||
@Override
|
||||
public void onInitialized(WebView webView) {
|
||||
setCookies(cookies);
|
||||
super.onInitialized(webView);
|
||||
}
|
||||
|
||||
public void onReceivedSession(Session session) {
|
||||
super.onReceivedSession(session);
|
||||
getSessionLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
boolean isAcquired = false;
|
||||
try {
|
||||
isAcquired = getSessionLatch.await(GET_SESSION_TIMEOUT_SECONDS, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ex) {
|
||||
Logger.printException(() -> "Session renewal interrupted", ex);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
if (!isAcquired) {
|
||||
Logger.printException(() -> "Failed to retrieve session within " + GET_SESSION_TIMEOUT_SECONDS + " seconds");
|
||||
currentSession = FAILED_TO_RENEW_SESSION;
|
||||
destructWebView();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All methods are called on the main thread.
|
||||
*/
|
||||
abstract static class WebViewCallback {
|
||||
void onInitialized(WebView webView) {
|
||||
currentWebView = webView;
|
||||
currentSession = null; // Reset current session.
|
||||
}
|
||||
|
||||
void onLoggedIn(String cookies) {
|
||||
}
|
||||
|
||||
void onReceivedSession(Session session) {
|
||||
Logger.printInfo(() -> "Received session: " + session);
|
||||
currentSession = session;
|
||||
|
||||
destructWebView();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
private static void launchWebView(
|
||||
Context context,
|
||||
String initialUrl,
|
||||
WebViewCallback webViewCallback
|
||||
) {
|
||||
Utils.runOnMainThreadNowOrLater(() -> {
|
||||
WebView webView = new WebView(context);
|
||||
WebSettings settings = webView.getSettings();
|
||||
settings.setDomStorageEnabled(true);
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setUserAgentString(USER_AGENT);
|
||||
|
||||
// WebViewClient is always called off the main thread,
|
||||
// but callback interface methods are called on the main thread.
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
|
||||
if (OPEN_SPOTIFY_COM.equals(request.getUrl().getHost())) {
|
||||
Utils.runOnMainThread(() -> webViewCallback.onLoggedIn(getCurrentCookies()));
|
||||
}
|
||||
|
||||
return super.shouldInterceptRequest(view, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
Logger.printInfo(() -> "Page started loading: " + url);
|
||||
|
||||
if (!url.startsWith(OPEN_SPOTIFY_COM_URL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.printInfo(() -> "Evaluating script to get session on url: " + url);
|
||||
String getSessionScript = "Object.defineProperty(Object.prototype, \"_username\", {" +
|
||||
" configurable: true," +
|
||||
" set(username) {" +
|
||||
" accessToken = this._builder?.accessToken;" +
|
||||
" if (accessToken) {" +
|
||||
" " + JAVASCRIPT_INTERFACE_NAME + ".getSession(username, accessToken);" +
|
||||
" delete Object.prototype._username;" +
|
||||
" }" +
|
||||
" " +
|
||||
" Object.defineProperty(this, \"_username\", {" +
|
||||
" configurable: true," +
|
||||
" enumerable: true," +
|
||||
" writable: true," +
|
||||
" value: username" +
|
||||
" })" +
|
||||
" " +
|
||||
" }" +
|
||||
"});" +
|
||||
"if (new URLSearchParams(window.location.search).get('_authfailed') != null) {" +
|
||||
" " + JAVASCRIPT_INTERFACE_NAME + ".getSession(null, null);" +
|
||||
"}";
|
||||
|
||||
view.evaluateJavascript(getSessionScript, null);
|
||||
}
|
||||
});
|
||||
|
||||
webView.addJavascriptInterface(new Object() {
|
||||
@SuppressWarnings("unused")
|
||||
@JavascriptInterface
|
||||
public void getSession(String username, String accessToken) {
|
||||
Session session = new Session(username, accessToken, getCurrentCookies());
|
||||
Utils.runOnMainThread(() -> webViewCallback.onReceivedSession(session));
|
||||
}
|
||||
}, JAVASCRIPT_INTERFACE_NAME);
|
||||
|
||||
CookieManager.getInstance().removeAllCookies((anyRemoved) -> {
|
||||
Logger.printInfo(() -> "Loading URL: " + initialUrl);
|
||||
webView.loadUrl(initialUrl);
|
||||
|
||||
Logger.printInfo(() -> "WebView initialized with user agent: " + USER_AGENT);
|
||||
webViewCallback.onInitialized(webView);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void destructWebView() {
|
||||
Utils.runOnMainThreadNowOrLater(() -> {
|
||||
currentWebView.stopLoading();
|
||||
currentWebView.destroy();
|
||||
currentWebView = null;
|
||||
});
|
||||
}
|
||||
|
||||
private static String getWebUserAgent() {
|
||||
String userAgentString = WebSettings.getDefaultUserAgent(Utils.getContext());
|
||||
try {
|
||||
return new UserAgent(userAgentString)
|
||||
.withCommentReplaced("Android", "Windows NT 10.0; Win64; x64")
|
||||
.withoutProduct("Mobile")
|
||||
.toString();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
userAgentString = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edge/137.0.0.0";
|
||||
String fallback = userAgentString;
|
||||
Logger.printException(() -> "Failed to get user agent, falling back to " + fallback, ex);
|
||||
}
|
||||
|
||||
return userAgentString;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Dialog newDialog(Context context) {
|
||||
Dialog dialog = new Dialog(context, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
|
||||
dialog.setCancelable(false);
|
||||
|
||||
// Ensure that the keyboard does not cover the webview content.
|
||||
Window window = dialog.getWindow();
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window.getDecorView().setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getInsets(WindowInsets.Type.ime()).bottom);
|
||||
|
||||
return WindowInsets.CONSUMED;
|
||||
});
|
||||
} else {
|
||||
// TODO: Implement for lower Android versions.
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
private static String getCurrentCookies() {
|
||||
CookieManager cookieManager = CookieManager.getInstance();
|
||||
return cookieManager.getCookie(OPEN_SPOTIFY_COM_URL);
|
||||
}
|
||||
|
||||
private static void setCookies(@NonNull String cookies) {
|
||||
CookieManager cookieManager = CookieManager.getInstance();
|
||||
|
||||
String[] cookiesList = cookies.split(";");
|
||||
for (String cookie : cookiesList) {
|
||||
cookieManager.setCookie(OPEN_SPOTIFY_COM_URL, cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package spotify.clienttoken.data.v0;
|
||||
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
option java_package = "app.revanced.extension.spotify.misc.fix.clienttoken.data.v0";
|
||||
|
||||
message ClientTokenRequest {
|
||||
ClientTokenRequestType request_type = 1;
|
||||
|
||||
oneof request {
|
||||
ClientDataRequest client_data = 2;
|
||||
}
|
||||
}
|
||||
|
||||
enum ClientTokenRequestType {
|
||||
REQUEST_UNKNOWN = 0;
|
||||
REQUEST_CLIENT_DATA_REQUEST = 1;
|
||||
REQUEST_CHALLENGE_ANSWERS_REQUEST = 2;
|
||||
}
|
||||
|
||||
message ClientDataRequest {
|
||||
string client_version = 1;
|
||||
string client_id = 2;
|
||||
|
||||
oneof data {
|
||||
ConnectivitySdkData connectivity_sdk_data = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message ConnectivitySdkData {
|
||||
PlatformSpecificData platform_specific_data = 1;
|
||||
string device_id = 2;
|
||||
}
|
||||
|
||||
message PlatformSpecificData {
|
||||
oneof data {
|
||||
NativeIOSData ios = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message NativeIOSData {
|
||||
int32 user_interface_idiom = 1;
|
||||
bool target_iphone_simulator = 2;
|
||||
string hw_machine = 3;
|
||||
string system_version = 4;
|
||||
string simulator_model_identifier = 5;
|
||||
}
|
||||
|
||||
message ClientTokenResponse {
|
||||
ClientTokenResponseType response_type = 1;
|
||||
|
||||
oneof response {
|
||||
GrantedTokenResponse granted_token = 2;
|
||||
}
|
||||
}
|
||||
|
||||
enum ClientTokenResponseType {
|
||||
RESPONSE_UNKNOWN = 0;
|
||||
RESPONSE_GRANTED_TOKEN_RESPONSE = 1;
|
||||
RESPONSE_CHALLENGES_RESPONSE = 2;
|
||||
}
|
||||
|
||||
message GrantedTokenResponse {
|
||||
string token = 1;
|
||||
int32 expires_after_seconds = 2;
|
||||
int32 refresh_after_seconds = 3;
|
||||
repeated TokenDomain domains = 4;
|
||||
}
|
||||
|
||||
message TokenDomain {
|
||||
string domain = 1;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package spotify.login5.v4;
|
||||
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
option java_package = "app.revanced.extension.spotify.login5.v4.proto";
|
||||
|
||||
message StoredCredential {
|
||||
string username = 1;
|
||||
bytes data = 2;
|
||||
}
|
||||
|
||||
message LoginRequest {
|
||||
oneof login_method {
|
||||
StoredCredential stored_credential = 100;
|
||||
}
|
||||
}
|
||||
|
||||
message LoginOk {
|
||||
string username = 1;
|
||||
string access_token = 2;
|
||||
bytes stored_credential = 3;
|
||||
int32 access_token_expires_in = 4;
|
||||
}
|
||||
|
||||
message LoginResponse {
|
||||
oneof response {
|
||||
LoginOk ok = 1;
|
||||
LoginError error = 2;
|
||||
}
|
||||
}
|
||||
|
||||
enum LoginError {
|
||||
UNKNOWN_ERROR = 0;
|
||||
INVALID_CREDENTIALS = 1;
|
||||
BAD_REQUEST = 2;
|
||||
UNSUPPORTED_LOGIN_PROTOCOL = 3;
|
||||
TIMEOUT = 4;
|
||||
UNKNOWN_IDENTIFIER = 5;
|
||||
TOO_MANY_ATTEMPTS = 6;
|
||||
INVALID_PHONENUMBER = 7;
|
||||
TRY_AGAIN_LATER = 8;
|
||||
}
|
||||
@@ -2,7 +2,5 @@ package com.spotify.browsita.v1.resolved;
|
||||
|
||||
public final class Section {
|
||||
public static final int BRAND_ADS_FIELD_NUMBER = 6;
|
||||
public static final int PROMOTION_V1_FIELD_NUMBER = 3;
|
||||
public static final int PROMOTION_V3_FIELD_NUMBER = 5;
|
||||
public int sectionTypeCase_;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.spotify.useraccount.v1;
|
||||
|
||||
/**
|
||||
* Used for target 8.6.98.900. Class is still present in newer app targets.
|
||||
*/
|
||||
public class AccountAttribute {
|
||||
public Object value_;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
plugins {
|
||||
java
|
||||
antlr
|
||||
}
|
||||
|
||||
dependencies {
|
||||
antlr(libs.antlr4)
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
tasks {
|
||||
generateGrammarSource {
|
||||
arguments = listOf("-visitor")
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
grammar UserAgent;
|
||||
|
||||
@header { package app.revanced.extension.spotify; }
|
||||
|
||||
userAgent
|
||||
: product (WS product)* EOF
|
||||
;
|
||||
|
||||
product
|
||||
: name ('/' version)? (WS comment)?
|
||||
;
|
||||
|
||||
name
|
||||
: STRING
|
||||
;
|
||||
|
||||
version
|
||||
: STRING ('.' STRING)*
|
||||
;
|
||||
|
||||
comment
|
||||
: COMMENT
|
||||
;
|
||||
|
||||
COMMENT
|
||||
: '(' ~ ')'* ')'
|
||||
;
|
||||
|
||||
STRING
|
||||
: [a-zA-Z0-9]+
|
||||
;
|
||||
|
||||
WS
|
||||
: [ \r\n]+
|
||||
;
|
||||
@@ -1,60 +0,0 @@
|
||||
package app.revanced.extension.spotify;
|
||||
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.TokenStreamRewriter;
|
||||
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||
|
||||
public class UserAgent {
|
||||
private final UserAgentParser.UserAgentContext tree;
|
||||
private final TokenStreamRewriter rewriter;
|
||||
private final ParseTreeWalker walker;
|
||||
|
||||
public UserAgent(String userAgentString) {
|
||||
CharStream input = CharStreams.fromString(userAgentString);
|
||||
UserAgentLexer lexer = new UserAgentLexer(input);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
|
||||
tree = new UserAgentParser(tokens).userAgent();
|
||||
walker = new ParseTreeWalker();
|
||||
rewriter = new TokenStreamRewriter(tokens);
|
||||
}
|
||||
|
||||
public UserAgent withoutProduct(String name) {
|
||||
walker.walk(new UserAgentBaseListener() {
|
||||
@Override
|
||||
public void exitProduct(UserAgentParser.ProductContext ctx) {
|
||||
if (!ctx.name().getText().contains(name)) return;
|
||||
|
||||
int startIndex = ctx.getStart().getTokenIndex();
|
||||
if (startIndex != 0) startIndex -= 1; // Also remove the preceding whitespace.
|
||||
|
||||
int stopIndex = ctx.getStop().getTokenIndex();
|
||||
|
||||
|
||||
rewriter.delete(startIndex, stopIndex);
|
||||
}
|
||||
}, tree);
|
||||
|
||||
return new UserAgent(rewriter.getText().trim());
|
||||
}
|
||||
|
||||
public UserAgent withCommentReplaced(String containing, String replacement) {
|
||||
walker.walk(new UserAgentBaseListener() {
|
||||
@Override
|
||||
public void exitComment(UserAgentParser.CommentContext ctx) {
|
||||
if (ctx.getText().contains(containing)) {
|
||||
rewriter.replace(ctx.getStart(), ctx.getStop(), "(" + replacement + ")");
|
||||
}
|
||||
}
|
||||
}, tree);
|
||||
|
||||
return new UserAgent(rewriter.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return rewriter.getText();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package app.revanced.extension.youtube.patches;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@@ -11,18 +14,21 @@ import app.revanced.extension.youtube.settings.Settings;
|
||||
public class ChangeHeaderPatch {
|
||||
|
||||
public enum HeaderLogo {
|
||||
DEFAULT(null),
|
||||
REGULAR("ytWordmarkHeader"),
|
||||
PREMIUM("ytPremiumWordmarkHeader"),
|
||||
REVANCED("revanced_header_logo"),
|
||||
REVANCED_MINIMAL("revanced_header_logo_minimal"),
|
||||
CUSTOM("custom_header");
|
||||
DEFAULT(null, null),
|
||||
REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"),
|
||||
PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"),
|
||||
REVANCED("revanced_header_logo", "revanced_header_logo"),
|
||||
REVANCED_MINIMAL("revanced_header_logo_minimal", "revanced_header_logo_minimal"),
|
||||
CUSTOM("custom_header", "custom_header");
|
||||
|
||||
@Nullable
|
||||
private final String resourceName;
|
||||
private final String attributeName;
|
||||
@Nullable
|
||||
private final String drawableName;
|
||||
|
||||
HeaderLogo(@Nullable String resourceName) {
|
||||
this.resourceName = resourceName;
|
||||
HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) {
|
||||
this.attributeName = attributeName;
|
||||
this.drawableName = drawableName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,24 +36,66 @@ public class ChangeHeaderPatch {
|
||||
*/
|
||||
@Nullable
|
||||
private Integer getAttributeId() {
|
||||
if (resourceName == null) {
|
||||
if (attributeName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int identifier = Utils.getResourceIdentifier(resourceName, "attr");
|
||||
// Identifier is zero if custom header setting was included in imported settings
|
||||
// and a custom image was not included during patching.
|
||||
return identifier == 0 ? null : identifier;
|
||||
final int identifier = Utils.getResourceIdentifier(attributeName, "attr");
|
||||
if (identifier == 0) {
|
||||
// Identifier is zero if custom header setting was included in imported settings
|
||||
// and a custom image was not included during patching.
|
||||
Logger.printDebug(() -> "Could not find attribute: " + drawableName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
}
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Drawable getDrawable() {
|
||||
if (drawableName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String drawableFullName = drawableName + (Utils.isDarkModeEnabled()
|
||||
? "_dark"
|
||||
: "_light");
|
||||
|
||||
final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable");
|
||||
if (identifier == 0) {
|
||||
Logger.printDebug(() -> "Could not find drawable: " + drawableFullName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
}
|
||||
return Utils.getContext().getDrawable(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static final Integer headerLogoResource = Settings.HEADER_LOGO.get().getAttributeId();
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static int getHeaderAttributeId(int original) {
|
||||
return Objects.requireNonNullElse(headerLogoResource, original);
|
||||
return Objects.requireNonNullElse(Settings.HEADER_LOGO.get().getAttributeId(), original);
|
||||
}
|
||||
|
||||
public static Drawable getDrawable(Drawable original) {
|
||||
Drawable logo = Settings.HEADER_LOGO.get().getDrawable();
|
||||
if (logo != null) {
|
||||
return logo;
|
||||
}
|
||||
|
||||
// TODO: If 'Hide Doodles' is enabled, this will force the regular logo regardless
|
||||
// what account the user has. This can be improved the next time a Doodle is
|
||||
// active and the attribute id is passed to this method so the correct
|
||||
// regular/premium logo is returned.
|
||||
logo = HeaderLogo.REGULAR.getDrawable();
|
||||
if (logo != null) {
|
||||
return logo;
|
||||
}
|
||||
|
||||
// Should never happen.
|
||||
Logger.printException(() -> "Could not find regular header logo resource");
|
||||
return original;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.extension.youtube.patches;
|
||||
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class DisableDoubleTapActionsPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*
|
||||
* @return If "should skip to chapter start" flag is set.
|
||||
*/
|
||||
public static boolean disableDoubleTapChapters(boolean original) {
|
||||
return original && !Settings.DISABLE_CHAPTER_SKIP_DOUBLE_TAP.get();
|
||||
}
|
||||
}
|
||||
@@ -59,10 +59,11 @@ public final class AnnouncementsPatch {
|
||||
int id = Settings.ANNOUNCEMENT_LAST_ID.defaultValue;
|
||||
try {
|
||||
final var announcementIds = new JSONArray(jsonString);
|
||||
if (announcementIds.length() == 0) return true;
|
||||
|
||||
id = announcementIds.getJSONObject(0).getInt("id");
|
||||
|
||||
} catch (Throwable ex) {
|
||||
Logger.printException(() -> "Failed to parse announcement IDs", ex);
|
||||
Logger.printException(() -> "Failed to parse announcement ID", ex);
|
||||
}
|
||||
|
||||
// Do not show the announcement, if the last announcement id is the same as the current one.
|
||||
|
||||
@@ -10,8 +10,8 @@ import static app.revanced.extension.shared.requests.Route.Method.GET;
|
||||
|
||||
public class AnnouncementsRoutes {
|
||||
private static final String ANNOUNCEMENTS_PROVIDER = "https://api.revanced.app/v4";
|
||||
public static final Route GET_LATEST_ANNOUNCEMENT_IDS = new Route(GET, "/announcements/latest/id?tag=youtube");
|
||||
public static final Route GET_LATEST_ANNOUNCEMENTS = new Route(GET, "/announcements/latest?tag=youtube");
|
||||
public static final Route GET_LATEST_ANNOUNCEMENT_IDS = new Route(GET, "/announcements/latest/id?tag=\uD83C\uDF9E\uFE0F%20YouTube");
|
||||
public static final Route GET_LATEST_ANNOUNCEMENTS = new Route(GET, "/announcements/latest?tag=\uD83C\uDF9E\uFE0F%20YouTube");
|
||||
|
||||
private AnnouncementsRoutes() {
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButt
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.youtube.StringTrieSearch;
|
||||
import app.revanced.extension.youtube.patches.ChangeHeaderPatch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.youtube.shared.NavigationBar;
|
||||
import app.revanced.extension.youtube.shared.PlayerType;
|
||||
@@ -291,6 +293,7 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
notifyMe,
|
||||
paidPromotion,
|
||||
playables,
|
||||
quickActions,
|
||||
relatedVideos,
|
||||
singleItemInformationPanel,
|
||||
subscribersCommunityGuidelines,
|
||||
@@ -436,13 +439,11 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
@Nullable
|
||||
public static Drawable hideYoodles(Drawable animatedYoodle) {
|
||||
if (HIDE_DOODLES_ENABLED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return animatedYoodle;
|
||||
public static void setDoodleDrawable(ImageView imageView, Drawable original) {
|
||||
Drawable replacement = HIDE_DOODLES_ENABLED
|
||||
? ChangeHeaderPatch.getDrawable(original)
|
||||
: original;
|
||||
imageView.setImageDrawable(replacement);
|
||||
}
|
||||
|
||||
private static final boolean HIDE_SHOW_MORE_BUTTON_ENABLED = Settings.HIDE_SHOW_MORE_BUTTON.get();
|
||||
|
||||
@@ -146,6 +146,7 @@ public class Settings extends BaseSettings {
|
||||
public static final BooleanSetting COPY_VIDEO_URL = new BooleanSetting("revanced_copy_video_url", FALSE);
|
||||
public static final BooleanSetting COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_copy_video_url_timestamp", TRUE);
|
||||
public static final BooleanSetting DISABLE_AUTO_CAPTIONS = new BooleanSetting("revanced_disable_auto_captions", FALSE, true);
|
||||
public static final BooleanSetting DISABLE_CHAPTER_SKIP_DOUBLE_TAP = new BooleanSetting("revanced_disable_chapter_skip_double_tap", FALSE);
|
||||
public static final BooleanSetting DISABLE_FULLSCREEN_AMBIENT_MODE = new BooleanSetting("revanced_disable_fullscreen_ambient_mode", TRUE, true);
|
||||
public static final BooleanSetting DISABLE_ROLLING_NUMBER_ANIMATIONS = new BooleanSetting("revanced_disable_rolling_number_animations", FALSE);
|
||||
public static final EnumSetting<FullscreenMode> EXIT_FULLSCREEN = new EnumSetting<>("revanced_exit_fullscreen", FullscreenMode.DISABLED);
|
||||
|
||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
||||
org.gradle.parallel = true
|
||||
android.useAndroidX = true
|
||||
kotlin.code.style = official
|
||||
version = 5.31.0-dev.10
|
||||
version = 5.31.2-dev.3
|
||||
|
||||
@@ -168,6 +168,10 @@ public final class app/revanced/patches/cricbuzz/ads/DisableAdsPatchKt {
|
||||
public static final fun getDisableAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/cricbuzz/misc/extension/ExtensionPatchKt {
|
||||
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/crunchyroll/ads/HideAdsPatchKt {
|
||||
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -900,6 +904,10 @@ public final class app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPa
|
||||
public static final fun userAgentClientSpoofPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/shared/misc/string/ReplaceStringPatchKt {
|
||||
public static final fun replaceStringPatch (Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatchKt {
|
||||
public static final fun getRemoveFileSizeLimitPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -1228,6 +1236,11 @@ public final class app/revanced/patches/youtube/interaction/dialog/RemoveViewerD
|
||||
public static final fun getRemoveViewerDiscretionDialogPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/interaction/doubletap/DisableChapterSkipDoubleTapPatchKt {
|
||||
public static final fun getDisableChapterSkipDoubleTapPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public static final fun getDisableDoubleTapActionsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/interaction/downloads/DownloadsPatchKt {
|
||||
public static final fun getDownloadsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
@@ -3,24 +3,38 @@ package app.revanced.patches.cricbuzz.ads
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.cricbuzz.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.returnEarly
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/cricbuzz/ads/HideAdsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val disableAdsPatch = bytecodePatch (
|
||||
name = "Hide ads",
|
||||
) {
|
||||
compatibleWith("com.cricbuzz.android"("6.23.02"))
|
||||
compatibleWith("com.cricbuzz.android"("6.24.01"))
|
||||
|
||||
dependsOn(sharedExtensionPatch)
|
||||
|
||||
execute {
|
||||
userStateSwitchFingerprint.method.apply {
|
||||
val opcodeIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_OBJECT)
|
||||
val register = getInstruction<OneRegisterInstruction>(opcodeIndex).registerA
|
||||
userStateSwitchFingerprint.method.returnEarly(true)
|
||||
|
||||
addInstruction(
|
||||
opcodeIndex + 1,
|
||||
"const-string v$register, \"ACTIVE\""
|
||||
// Remove region-specific Cricbuzz11 elements.
|
||||
cb11ConstructorFingerprint.method.addInstruction(0, "const/4 p7, 0x0")
|
||||
getBottomBarFingerprint.method.apply {
|
||||
val getIndex = indexOfFirstInstructionOrThrow() {
|
||||
opcode == Opcode.IGET_OBJECT && getReference<FieldReference>()?.name == "bottomBar"
|
||||
}
|
||||
val getRegister = getInstruction<TwoRegisterInstruction>(getIndex).registerA
|
||||
|
||||
addInstruction(getIndex + 1,
|
||||
"invoke-static { v$getRegister }, $EXTENSION_CLASS_DESCRIPTOR->filterCb11(Ljava/util/List;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,30 @@ import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val userStateSwitchFingerprint = fingerprint {
|
||||
strings("key.user.state", "NA")
|
||||
opcodes(Opcode.SPARSE_SWITCH)
|
||||
strings("key.user.state", "NA")
|
||||
}
|
||||
|
||||
internal val cb11ConstructorFingerprint = fingerprint {
|
||||
parameters(
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/String;",
|
||||
"I",
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/String;",
|
||||
"Z",
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/String;",
|
||||
"L"
|
||||
)
|
||||
custom { _, classDef ->
|
||||
classDef.endsWith("CB11Details;")
|
||||
}
|
||||
}
|
||||
|
||||
internal val getBottomBarFingerprint = fingerprint {
|
||||
custom { method, classDef ->
|
||||
method.name == "getBottomBar" && classDef.endsWith("HomeMenu;")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package app.revanced.patches.cricbuzz.misc.extension
|
||||
|
||||
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
|
||||
|
||||
val sharedExtensionPatch = sharedExtensionPatch("cricbuzz", applicationInitHook)
|
||||
@@ -0,0 +1,9 @@
|
||||
package app.revanced.patches.cricbuzz.misc.extension
|
||||
|
||||
import app.revanced.patches.shared.misc.extension.extensionHook
|
||||
|
||||
internal val applicationInitHook = extensionHook {
|
||||
custom { method, classDef ->
|
||||
method.name == "onCreate" && classDef.endsWith("/NyitoActivity;")
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,16 @@ import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patches.reddit.customclients.spoofClientPatch
|
||||
import app.revanced.patches.shared.misc.string.replaceStringPatch
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
val spoofClientPatch = spoofClientPatch(redirectUri = "http://baconreader.com/auth") { clientIdOption ->
|
||||
dependsOn(
|
||||
// Redirects from SSL to WWW domain are bugged causing auth problems.
|
||||
// Manually rewrite the URLs to fix this.
|
||||
replaceStringPatch("ssl.reddit.com", "www.reddit.com")
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.onelouder.baconreader",
|
||||
"com.onelouder.baconreader.premium",
|
||||
|
||||
@@ -61,7 +61,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl
|
||||
// region Patch miscellaneous.
|
||||
|
||||
// Reddit messed up and does not append a redirect uri to the authorization url to old.reddit.com/login.
|
||||
// Replace old.reddit.com with ssl.reddit.com to fix this.
|
||||
// Replace old.reddit.com with www.reddit.com to fix this.
|
||||
buildAuthorizationStringFingerprint.method.apply {
|
||||
val index = indexOfFirstInstructionOrThrow {
|
||||
getReference<StringReference>()?.contains("old.reddit.com") == true
|
||||
@@ -70,7 +70,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
replaceInstruction(
|
||||
index,
|
||||
"const-string v$targetRegister, \"https://ssl.reddit.com/api/v1/authorize.compact\"",
|
||||
"const-string v$targetRegister, \"https://www.reddit.com/api/v1/authorize.compact\"",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patches.reddit.customclients.spoofClientPatch
|
||||
import app.revanced.patches.reddit.customclients.sync.detection.piracy.disablePiracyDetectionPatch
|
||||
import app.revanced.patches.shared.misc.string.replaceStringPatch
|
||||
import app.revanced.util.returnEarly
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
@@ -13,7 +14,12 @@ import java.util.Base64
|
||||
val spoofClientPatch = spoofClientPatch(
|
||||
redirectUri = "http://redditsync/auth",
|
||||
) { clientIdOption ->
|
||||
dependsOn(disablePiracyDetectionPatch)
|
||||
dependsOn(
|
||||
disablePiracyDetectionPatch,
|
||||
// Redirects from SSL to WWW domain are bugged causing auth problems.
|
||||
// Manually rewrite the URLs to fix this.
|
||||
replaceStringPatch("ssl.reddit.com", "www.reddit.com")
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.laurencedawson.reddit_sync",
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package app.revanced.patches.shared.misc.string
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.ReferenceType
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
import kotlin.text.contains
|
||||
|
||||
fun replaceStringPatch(
|
||||
from: String,
|
||||
to: String
|
||||
) = bytecodePatch(
|
||||
description = "Replaces occurrences of '$from' with '$to' in string references.",
|
||||
) {
|
||||
dependsOn(
|
||||
transformInstructionsPatch(
|
||||
filterMap = filterMap@{ _, _, instruction, instructionIndex ->
|
||||
if (instruction.opcode.referenceType != ReferenceType.STRING) return@filterMap null
|
||||
|
||||
val stringReference = instruction.getReference<StringReference>()!!.string
|
||||
if (from !in stringReference) return@filterMap null
|
||||
|
||||
Triple(instructionIndex, instruction as OneRegisterInstruction, stringReference)
|
||||
},
|
||||
transform = transform@{ mutableMethod, entry ->
|
||||
val (instructionIndex, instruction, stringReference) = entry
|
||||
|
||||
val newString = stringReference.replace(from, to)
|
||||
mutableMethod.replaceInstruction(
|
||||
instructionIndex,
|
||||
"${instruction.opcode.name} v${instruction.registerA}, \"$newString\"",
|
||||
)
|
||||
},
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -6,12 +6,10 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import java.util.logging.Logger
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/spotify/layout/hide/createbutton/HideCreateButtonPatch;"
|
||||
@@ -26,13 +24,6 @@ val hideCreateButtonPatch = bytecodePatch(
|
||||
dependsOn(sharedExtensionPatch)
|
||||
|
||||
execute {
|
||||
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"Create button does not exist in legacy app target. No changes applied."
|
||||
)
|
||||
return@execute
|
||||
}
|
||||
|
||||
val oldNavigationBarAddItemMethod = oldNavigationBarAddItemFingerprint.originalMethodOrNull
|
||||
// Only throw the fingerprint error when oldNavigationBarAddItemMethod does not exist.
|
||||
val navigationBarItemSetClassDef = if (oldNavigationBarAddItemMethod == null) {
|
||||
|
||||
@@ -7,8 +7,8 @@ import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
import app.revanced.util.*
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import org.w3c.dom.Element
|
||||
@@ -19,12 +19,6 @@ private val customThemeBytecodePatch = bytecodePatch {
|
||||
dependsOn(sharedExtensionPatch)
|
||||
|
||||
execute {
|
||||
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
// Bytecode changes are not needed for legacy app target.
|
||||
// Player background color is changed with existing resource patch.
|
||||
return@execute
|
||||
}
|
||||
|
||||
val colorSpaceUtilsClassDef = colorSpaceUtilsClassFingerprint.originalClassDef
|
||||
|
||||
// Hook a util method that converts ARGB to RGBA in the sRGB color space to replace hardcoded accent colors.
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package app.revanced.patches.spotify.lite.ondemand
|
||||
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import app.revanced.patcher.fingerprint
|
||||
|
||||
internal val onDemandFingerprint = fingerprint(fuzzyPatternScanThreshold = 2) {
|
||||
returns("L")
|
||||
parameters()
|
||||
opcodes(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IPUT,
|
||||
Opcode.RETURN_OBJECT,
|
||||
)
|
||||
}
|
||||
@@ -1,21 +1,9 @@
|
||||
package app.revanced.patches.spotify.lite.ondemand
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
|
||||
@Deprecated("Patch no longer works and will be deleted soon")
|
||||
@Suppress("unused")
|
||||
val onDemandPatch = bytecodePatch(
|
||||
description = "Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.",
|
||||
) {
|
||||
compatibleWith("com.spotify.lite")
|
||||
|
||||
execute {
|
||||
// Spoof a premium account
|
||||
|
||||
onDemandFingerprint.method.addInstruction(
|
||||
onDemandFingerprint.patternMatch!!.endIndex - 1,
|
||||
"const/4 v0, 0x2",
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@ package app.revanced.patches.spotify.misc
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
@@ -13,25 +12,13 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||
|
||||
context(BytecodePatchContext)
|
||||
internal val accountAttributeFingerprint get() = fingerprint {
|
||||
custom { _, classDef ->
|
||||
classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
"Lcom/spotify/useraccount/v1/AccountAttribute;"
|
||||
} else {
|
||||
"Lcom/spotify/remoteconfig/internal/AccountAttribute;"
|
||||
}
|
||||
}
|
||||
custom { _, classDef -> classDef.type == "Lcom/spotify/remoteconfig/internal/AccountAttribute;" }
|
||||
}
|
||||
|
||||
context(BytecodePatchContext)
|
||||
internal val productStateProtoGetMapFingerprint get() = fingerprint {
|
||||
returns("Ljava/util/Map;")
|
||||
custom { _, classDef ->
|
||||
classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
"Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;"
|
||||
} else {
|
||||
"Lcom/spotify/remoteconfig/internal/ProductStateProto;"
|
||||
}
|
||||
}
|
||||
custom { _, classDef -> classDef.type == "Lcom/spotify/remoteconfig/internal/ProductStateProto;" }
|
||||
}
|
||||
|
||||
internal val buildQueryParametersFingerprint = fingerprint {
|
||||
@@ -62,8 +49,8 @@ internal val contextMenuViewModelConstructorFingerprint = fingerprint {
|
||||
/**
|
||||
* Used to find the interface name of a context menu item.
|
||||
*/
|
||||
internal val browsePodcastsContextMenuItemClassFingerprint = fingerprint {
|
||||
strings("browse_podcast_item", "ui_navigate")
|
||||
internal val removeAdsContextMenuItemClassFingerprint = fingerprint {
|
||||
strings("remove_ads_item", "ui_navigate")
|
||||
}
|
||||
|
||||
internal const val CONTEXT_MENU_ITEM_CLASS_DESCRIPTOR_PLACEHOLDER = "Lapp/revanced/ContextMenuItemPlaceholder;"
|
||||
@@ -90,14 +77,14 @@ internal val contextFromJsonFingerprint = fingerprint {
|
||||
)
|
||||
custom { method, classDef ->
|
||||
method.name == "fromJson" &&
|
||||
classDef.endsWith("voiceassistants/playermodels/ContextJsonAdapter;")
|
||||
classDef.type.endsWith("voiceassistants/playermodels/ContextJsonAdapter;")
|
||||
}
|
||||
}
|
||||
|
||||
internal val readPlayerOptionOverridesFingerprint = fingerprint {
|
||||
custom { method, classDef ->
|
||||
method.name == "readPlayerOptionOverrides" &&
|
||||
classDef.endsWith("voiceassistants/playermodels/PreparePlayOptionsJsonAdapter;")
|
||||
classDef.type.endsWith("voiceassistants/playermodels/PreparePlayOptionsJsonAdapter;")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,21 +106,21 @@ internal val abstractProtobufListEnsureIsMutableFingerprint = fingerprint {
|
||||
|
||||
internal fun structureGetSectionsFingerprint(className: String) = fingerprint {
|
||||
custom { method, classDef ->
|
||||
classDef.endsWith(className) && method.indexOfFirstInstruction {
|
||||
classDef.type.endsWith(className) && method.indexOfFirstInstruction {
|
||||
opcode == Opcode.IGET_OBJECT && getReference<FieldReference>()?.name == "sections_"
|
||||
} >= 0
|
||||
}
|
||||
}
|
||||
|
||||
internal val homeSectionFingerprint = fingerprint {
|
||||
custom { _, classDef -> classDef.endsWith("homeapi/proto/Section;") }
|
||||
custom { _, classDef -> classDef.type.endsWith("homeapi/proto/Section;") }
|
||||
}
|
||||
|
||||
internal val homeStructureGetSectionsFingerprint =
|
||||
structureGetSectionsFingerprint("homeapi/proto/HomeStructure;")
|
||||
|
||||
internal val browseSectionFingerprint = fingerprint {
|
||||
custom { _, classDef-> classDef.endsWith("browsita/v1/resolved/Section;") }
|
||||
custom { _, classDef-> classDef.type.endsWith("browsita/v1/resolved/Section;") }
|
||||
}
|
||||
|
||||
internal val browseStructureGetSectionsFingerprint =
|
||||
|
||||
@@ -7,37 +7,12 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal val getPackageInfoFingerprint = fingerprint {
|
||||
strings(
|
||||
"Failed to get the application signatures"
|
||||
)
|
||||
}
|
||||
|
||||
internal val loadOrbitLibraryFingerprint = fingerprint {
|
||||
strings("/liborbit-jni-spotify.so")
|
||||
}
|
||||
|
||||
internal val startupPageLayoutInflateFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("Landroid/view/View;")
|
||||
parameters("Landroid/view/LayoutInflater;", "Landroid/view/ViewGroup;", "Landroid/os/Bundle;")
|
||||
strings("blueprintContainer", "gradient", "valuePropositionTextView")
|
||||
}
|
||||
|
||||
internal val renderStartLoginScreenFingerprint = fingerprint {
|
||||
strings("authenticationButtonFactory", "MORE_OPTIONS")
|
||||
}
|
||||
|
||||
internal val renderSecondLoginScreenFingerprint = fingerprint {
|
||||
strings("authenticationButtonFactory", "intent_login")
|
||||
}
|
||||
|
||||
internal val renderThirdLoginScreenFingerprint = fingerprint {
|
||||
strings("EMAIL_OR_USERNAME", "listener")
|
||||
}
|
||||
|
||||
internal val thirdLoginScreenLoginOnClickFingerprint = fingerprint {
|
||||
strings("login", "listener", "none")
|
||||
internal val extensionFixConstantsFingerprint = fingerprint {
|
||||
custom { _, classDef -> classDef.type == "Lapp/revanced/extension/spotify/misc/fix/Constants;" }
|
||||
}
|
||||
|
||||
internal val runIntegrityVerificationFingerprint = fingerprint {
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
package app.revanced.patches.spotify.misc.fix
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.intOption
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patches.shared.misc.hex.HexPatchBuilder
|
||||
import app.revanced.patches.shared.misc.hex.hexPatch
|
||||
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.*
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import app.revanced.util.returnEarly
|
||||
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/misc/fix/SpoofClientPatch;"
|
||||
|
||||
@@ -25,16 +19,40 @@ val spoofClientPatch = bytecodePatch(
|
||||
val requestListenerPort by intOption(
|
||||
key = "requestListenerPort",
|
||||
default = 4345,
|
||||
title = " Login request listener port",
|
||||
description = "The port to use for the listener that intercepts and handles login requests. " +
|
||||
"Port must be between 0 and 65535.",
|
||||
required = true,
|
||||
title = "Request listener port",
|
||||
description = "The port to use for the listener that intercepts and handles spoofed requests. " +
|
||||
"Port must be between 0 and 65535. " +
|
||||
"Do not change this option, if you do not know what you are doing.",
|
||||
validator = {
|
||||
it!!
|
||||
!(it < 0 || it > 65535)
|
||||
}
|
||||
)
|
||||
|
||||
val clientVersion by stringOption(
|
||||
key = "clientVersion",
|
||||
default = "iphone-9.0.58.558.g200011c",
|
||||
title = "Client version",
|
||||
description = "The client version used for spoofing the client token. " +
|
||||
"Do not change this option, if you do not know what you are doing."
|
||||
)
|
||||
|
||||
val hardwareMachine by stringOption(
|
||||
key = "hardwareMachine",
|
||||
default = "iPhone16,1",
|
||||
title = "Hardware machine",
|
||||
description = "The hardware machine used for spoofing the client token. " +
|
||||
"Do not change this option, if you do not know what you are doing."
|
||||
)
|
||||
|
||||
val systemVersion by stringOption(
|
||||
key = "systemVersion",
|
||||
default = "17.7.2",
|
||||
title = "System version",
|
||||
description = "The system version used for spoofing the client token. " +
|
||||
"Do not change this option, if you do not know what you are doing."
|
||||
)
|
||||
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
hexPatch(ignoreMissingTargetFiles = true, block = fun HexPatchBuilder.() {
|
||||
@@ -44,10 +62,8 @@ val spoofClientPatch = bytecodePatch(
|
||||
"x86",
|
||||
"x86_64"
|
||||
).forEach { architecture ->
|
||||
"https://login5.spotify.com/v3/login" to "http://127.0.0.1:$requestListenerPort/v3/login" inFile
|
||||
"lib/$architecture/liborbit-jni-spotify.so"
|
||||
|
||||
"https://login5.spotify.com/v4/login" to "http://127.0.0.1:$requestListenerPort/v4/login" inFile
|
||||
"https://clienttoken.spotify.com/v1/clienttoken" to
|
||||
"http://127.0.0.1:$requestListenerPort/v1/clienttoken" inFile
|
||||
"lib/$architecture/liborbit-jni-spotify.so"
|
||||
}
|
||||
})
|
||||
@@ -56,51 +72,6 @@ val spoofClientPatch = bytecodePatch(
|
||||
compatibleWith("com.spotify.music")
|
||||
|
||||
execute {
|
||||
// region Spoof package info.
|
||||
|
||||
getPackageInfoFingerprint.method.apply {
|
||||
// region Spoof signature.
|
||||
|
||||
val failedToGetSignaturesStringIndex =
|
||||
getPackageInfoFingerprint.stringMatches!!.first().index
|
||||
|
||||
val concatSignaturesIndex = indexOfFirstInstructionReversedOrThrow(
|
||||
failedToGetSignaturesStringIndex,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
)
|
||||
|
||||
val signatureRegister = getInstruction<OneRegisterInstruction>(concatSignaturesIndex).registerA
|
||||
val expectedSignature = "d6a6dced4a85f24204bf9505ccc1fce114cadb32"
|
||||
|
||||
replaceInstruction(concatSignaturesIndex, "const-string v$signatureRegister, \"$expectedSignature\"")
|
||||
|
||||
// endregion
|
||||
|
||||
// region Spoof installer name.
|
||||
|
||||
val expectedInstallerName = "com.android.vending"
|
||||
|
||||
findInstructionIndicesReversedOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.name == "getInstallerPackageName" || reference?.name == "getInstallingPackageName"
|
||||
}.forEach { index ->
|
||||
val returnObjectIndex = index + 1
|
||||
|
||||
val installerPackageNameRegister = getInstruction<OneRegisterInstruction>(
|
||||
returnObjectIndex
|
||||
).registerA
|
||||
|
||||
addInstruction(
|
||||
returnObjectIndex + 1,
|
||||
"const-string v$installerPackageNameRegister, \"$expectedInstallerName\""
|
||||
)
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Spoof client.
|
||||
|
||||
loadOrbitLibraryFingerprint.method.addInstructions(
|
||||
@@ -111,72 +82,12 @@ val spoofClientPatch = bytecodePatch(
|
||||
"""
|
||||
)
|
||||
|
||||
startupPageLayoutInflateFingerprint.method.apply {
|
||||
val openLoginWebViewDescriptor =
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->launchLogin(Landroid/view/LayoutInflater;)V"
|
||||
|
||||
addInstructions(
|
||||
0,
|
||||
"invoke-static/range { p1 .. p1 }, $openLoginWebViewDescriptor"
|
||||
)
|
||||
}
|
||||
|
||||
renderStartLoginScreenFingerprint.method.apply {
|
||||
val onEventIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_INTERFACE && getReference<MethodReference>()?.name == "getView"
|
||||
}
|
||||
|
||||
val buttonRegister = getInstruction<OneRegisterInstruction>(onEventIndex + 1).registerA
|
||||
|
||||
addInstruction(
|
||||
onEventIndex + 2,
|
||||
"invoke-static { v$buttonRegister }, $EXTENSION_CLASS_DESCRIPTOR->setNativeLoginHandler(Landroid/view/View;)V"
|
||||
)
|
||||
}
|
||||
|
||||
renderSecondLoginScreenFingerprint.method.apply {
|
||||
val getViewIndex = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_INTERFACE && getReference<MethodReference>()?.name == "getView"
|
||||
}
|
||||
|
||||
val buttonRegister = getInstruction<OneRegisterInstruction>(getViewIndex + 1).registerA
|
||||
|
||||
// Early return the render for loop since the first item of the loop is the login button.
|
||||
addInstructions(
|
||||
getViewIndex + 2,
|
||||
"""
|
||||
invoke-virtual { v$buttonRegister }, Landroid/view/View;->performClick()Z
|
||||
return-void
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
renderThirdLoginScreenFingerprint.method.apply {
|
||||
val invokeSetListenerIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.definingClass == "Landroid/view/View;" && reference.name == "setOnClickListener"
|
||||
}
|
||||
|
||||
val buttonRegister = getInstruction<FiveRegisterInstruction>(invokeSetListenerIndex).registerC
|
||||
|
||||
addInstruction(
|
||||
invokeSetListenerIndex + 1,
|
||||
"invoke-virtual { v$buttonRegister }, Landroid/view/View;->performClick()Z"
|
||||
)
|
||||
}
|
||||
|
||||
thirdLoginScreenLoginOnClickFingerprint.method.apply {
|
||||
// Use placeholder credentials to pass the login screen.
|
||||
val loginActionIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN_VOID) - 1
|
||||
val loginActionInstruction = getInstruction<FiveRegisterInstruction>(loginActionIndex)
|
||||
|
||||
addInstructions(
|
||||
loginActionIndex,
|
||||
"""
|
||||
const-string v${loginActionInstruction.registerD}, "placeholder"
|
||||
const-string v${loginActionInstruction.registerE}, "placeholder"
|
||||
"""
|
||||
)
|
||||
mapOf(
|
||||
"getClientVersion" to clientVersion!!,
|
||||
"getSystemVersion" to systemVersion!!,
|
||||
"getHardwareMachine" to hardwareMachine!!
|
||||
).forEach { (methodName, value) ->
|
||||
extensionFixConstantsFingerprint.classDef.methods.single { it.name == methodName }.returnEarly(value)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
@@ -6,7 +6,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
@@ -57,16 +56,10 @@ val changeLyricsProviderPatch = bytecodePatch(
|
||||
}
|
||||
|
||||
execute {
|
||||
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
Logger.getLogger(this::class.java.name).severe(
|
||||
"Change lyrics provider patch is not supported for this target version."
|
||||
)
|
||||
return@execute
|
||||
}
|
||||
|
||||
val httpClientBuilderMethod = httpClientBuilderFingerprint.originalMethod
|
||||
|
||||
// region Create a modified copy of the HTTP client builder method with the custom lyrics provider host.
|
||||
|
||||
val patchedHttpClientBuilderMethod = with(httpClientBuilderMethod) {
|
||||
val invokeBuildUrlIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.returnType == "Lokhttp3/HttpUrl;"
|
||||
@@ -89,9 +82,11 @@ val changeLyricsProviderPatch = bytecodePatch(
|
||||
httpClientBuilderFingerprint.classDef.methods.add(this)
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
// region Replace the call to the HTTP client builder method used exclusively for lyrics by the modified one.
|
||||
|
||||
getLyricsHttpClientFingerprint(httpClientBuilderMethod).method.apply {
|
||||
val getLyricsHttpClientIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>() == httpClientBuilderMethod
|
||||
@@ -118,6 +113,7 @@ val changeLyricsProviderPatch = bytecodePatch(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ internal val shareCopyUrlFingerprint = fingerprint {
|
||||
}
|
||||
}
|
||||
|
||||
internal val shareCopyUrlLegacyFingerprint = fingerprint {
|
||||
internal val oldShareCopyUrlFingerprint = fingerprint {
|
||||
returns("Ljava/lang/Object;")
|
||||
parameters("Ljava/lang/Object;")
|
||||
strings("clipboard", "createNewSession failed")
|
||||
@@ -38,7 +38,7 @@ internal val formatAndroidShareSheetUrlFingerprint = fingerprint {
|
||||
}
|
||||
}
|
||||
|
||||
internal val formatAndroidShareSheetUrlLegacyFingerprint = fingerprint {
|
||||
internal val oldFormatAndroidShareSheetUrlFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC)
|
||||
returns("Ljava/lang/String;")
|
||||
parameters("Lcom/spotify/share/social/sharedata/ShareData;", "Ljava/lang/String;")
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package app.revanced.patches.spotify.misc.privacy
|
||||
|
||||
import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
@@ -28,10 +26,10 @@ val sanitizeSharingLinksPatch = bytecodePatch(
|
||||
val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"sanitizeUrl(Ljava/lang/String;)Ljava/lang/String;"
|
||||
|
||||
val copyFingerprint = if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
shareCopyUrlLegacyFingerprint
|
||||
} else {
|
||||
val copyFingerprint = if (shareCopyUrlFingerprint.originalMethodOrNull != null) {
|
||||
shareCopyUrlFingerprint
|
||||
} else {
|
||||
oldShareCopyUrlFingerprint
|
||||
}
|
||||
|
||||
copyFingerprint.method.apply {
|
||||
@@ -50,15 +48,10 @@ val sanitizeSharingLinksPatch = bytecodePatch(
|
||||
}
|
||||
|
||||
// Android native share sheet is used for all other quick share types (X, WhatsApp, etc).
|
||||
val shareUrlParameter : String
|
||||
val shareSheetFingerprint : Fingerprint
|
||||
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
shareSheetFingerprint = formatAndroidShareSheetUrlLegacyFingerprint
|
||||
shareUrlParameter = "p2"
|
||||
} else {
|
||||
shareSheetFingerprint = formatAndroidShareSheetUrlFingerprint
|
||||
val methodAccessFlags = formatAndroidShareSheetUrlFingerprint.originalMethod.accessFlags
|
||||
shareUrlParameter = if (AccessFlags.STATIC.isSet(methodAccessFlags)) {
|
||||
val shareUrlParameter: String
|
||||
val shareSheetFingerprint = if (formatAndroidShareSheetUrlFingerprint.originalMethodOrNull != null) {
|
||||
val methodAccessFlags = formatAndroidShareSheetUrlFingerprint.originalMethod
|
||||
shareUrlParameter = if (AccessFlags.STATIC.isSet(methodAccessFlags.accessFlags)) {
|
||||
// In newer implementations the method is static, so p0 is not `this`.
|
||||
"p1"
|
||||
} else {
|
||||
@@ -66,6 +59,11 @@ val sanitizeSharingLinksPatch = bytecodePatch(
|
||||
// For that reason, add one to the parameter register.
|
||||
"p2"
|
||||
}
|
||||
|
||||
formatAndroidShareSheetUrlFingerprint
|
||||
} else {
|
||||
shareUrlParameter = "p2"
|
||||
oldFormatAndroidShareSheetUrlFingerprint
|
||||
}
|
||||
|
||||
shareSheetFingerprint.method.addInstructions(
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package app.revanced.patches.spotify.misc.widgets
|
||||
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.spotify.shared.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
import app.revanced.util.returnEarly
|
||||
import java.util.logging.Logger
|
||||
|
||||
@Suppress("unused")
|
||||
val fixThirdPartyLaunchersWidgets = bytecodePatch(
|
||||
@@ -13,14 +11,6 @@ val fixThirdPartyLaunchersWidgets = bytecodePatch(
|
||||
compatibleWith("com.spotify.music")
|
||||
|
||||
execute {
|
||||
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||
// The permission check does not exist in legacy versions.
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"Legacy app target does not have any third party launcher restrictions. No changes applied."
|
||||
)
|
||||
return@execute
|
||||
}
|
||||
|
||||
// Only system app launchers are granted the BIND_APPWIDGET permission.
|
||||
// Override the method that checks for it to always return true, as this permission is not actually required
|
||||
// for the widgets to work.
|
||||
|
||||
@@ -1,38 +1,15 @@
|
||||
package app.revanced.patches.spotify.shared
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivity;"
|
||||
|
||||
/**
|
||||
* Main activity of target 8.6.98.900.
|
||||
*/
|
||||
internal const val SPOTIFY_MAIN_ACTIVITY_LEGACY = "Lcom/spotify/music/MainActivity;"
|
||||
|
||||
internal val mainActivityOnCreateFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
parameters("Landroid/os/Bundle;")
|
||||
custom { method, classDef ->
|
||||
method.name == "onCreate" && (classDef.type == SPOTIFY_MAIN_ACTIVITY
|
||||
|| classDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY)
|
||||
method.name == "onCreate" && classDef.type == SPOTIFY_MAIN_ACTIVITY
|
||||
}
|
||||
}
|
||||
|
||||
private var isLegacyAppTarget: Boolean? = null
|
||||
|
||||
/**
|
||||
* If patching a legacy 8.x target. This may also be set if patching slightly older/newer app targets,
|
||||
* but the only legacy target of interest is 8.6.98.900 as it's the last version that
|
||||
* supports Spotify integration on Kenwood/Pioneer car stereos.
|
||||
*/
|
||||
context(BytecodePatchContext)
|
||||
internal val IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
get(): Boolean {
|
||||
if (isLegacyAppTarget == null) {
|
||||
isLegacyAppTarget = mainActivityOnCreateFingerprint.originalClassDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY
|
||||
}
|
||||
return isLegacyAppTarget!!
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package app.revanced.patches.youtube.interaction.doubletap
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/DisableDoubleTapActionsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val disableDoubleTapActionsPatch = bytecodePatch(
|
||||
name = "Disable double tap actions",
|
||||
description = "Adds an option to disable player double tap gestures.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"20.07.39",
|
||||
"20.12.46",
|
||||
"20.13.41",
|
||||
)
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("youtube", "interaction.doubletap.disableDoubleTapActionsPatch")
|
||||
|
||||
PreferenceScreen.PLAYER.addPreferences(
|
||||
SwitchPreference("revanced_disable_chapter_skip_double_tap"),
|
||||
)
|
||||
|
||||
val doubleTapInfoGetSeekSourceFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Z")
|
||||
returns(seekTypeEnumFingerprint.originalClassDef.type)
|
||||
opcodes(
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.RETURN_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.RETURN_OBJECT,
|
||||
)
|
||||
custom { _, classDef ->
|
||||
classDef.fields.count() == 4
|
||||
}
|
||||
}
|
||||
|
||||
// Force isChapterSeek flag to false.
|
||||
doubleTapInfoGetSeekSourceFingerprint.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->disableDoubleTapChapters(Z)Z
|
||||
move-result p1
|
||||
"""
|
||||
)
|
||||
|
||||
doubleTapInfoCtorFingerprint.match(
|
||||
doubleTapInfoGetSeekSourceFingerprint.classDef
|
||||
).method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static { p3 }, $EXTENSION_CLASS_DESCRIPTOR->disableDoubleTapChapters(Z)Z
|
||||
move-result p3
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Patch was renamed", ReplaceWith("disableDoubleTapActionsPatch"))
|
||||
val disableChapterSkipDoubleTapPatch = bytecodePatch {
|
||||
dependsOn(disableDoubleTapActionsPatch)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package app.revanced.patches.youtube.interaction.doubletap
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val seekTypeEnumFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||
strings(
|
||||
"SEEK_SOURCE_SEEK_TO_NEXT_CHAPTER",
|
||||
"SEEK_SOURCE_SEEK_TO_PREVIOUS_CHAPTER"
|
||||
)
|
||||
}
|
||||
|
||||
internal val doubleTapInfoCtorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
parameters(
|
||||
"Landroid/view/MotionEvent;",
|
||||
"I",
|
||||
"Z",
|
||||
"Lj\$/time/Duration;"
|
||||
)
|
||||
}
|
||||
@@ -73,12 +73,9 @@ val enableSlideToSeekPatch = bytecodePatch(
|
||||
|
||||
// Disable the double speed seek gesture.
|
||||
if (is_19_17_or_greater) {
|
||||
arrayOf(
|
||||
disableFastForwardGestureFingerprint,
|
||||
disableFastForwardNoticeFingerprint,
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.method.apply {
|
||||
val targetIndex = fingerprint.patternMatch!!.endIndex
|
||||
disableFastForwardGestureFingerprint.let {
|
||||
it.method.apply {
|
||||
val targetIndex = it.patternMatch!!.endIndex
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
|
||||
@@ -3,14 +3,12 @@ package app.revanced.patches.youtube.interaction.seekbar
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.containsLiteralInstruction
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import app.revanced.util.indexOfFirstInstructionReversed
|
||||
import app.revanced.util.literal
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
|
||||
internal val swipingUpGestureParentFingerprint = fingerprint {
|
||||
returns("Z")
|
||||
@@ -59,25 +57,6 @@ internal val disableFastForwardGestureFingerprint = fingerprint {
|
||||
}
|
||||
}
|
||||
|
||||
internal val disableFastForwardNoticeFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
parameters()
|
||||
opcodes(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
)
|
||||
custom { method, _ ->
|
||||
method.name == "run" && method.indexOfFirstInstruction {
|
||||
// In later targets the code is found in different methods with different strings.
|
||||
val string = getReference<StringReference>()?.string
|
||||
string == "Failed to easy seek haptics vibrate." || string == "search_landing_cache_key"
|
||||
} >= 0
|
||||
}
|
||||
}
|
||||
|
||||
internal val onTouchEventHandlerFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.PUBLIC)
|
||||
returns("Z")
|
||||
|
||||
@@ -22,6 +22,8 @@ import app.revanced.util.forEachLiteralValueInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import java.io.File
|
||||
|
||||
private val variants = arrayOf("light", "dark")
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;"
|
||||
|
||||
@@ -29,6 +31,17 @@ private val changeHeaderBytecodePatch = bytecodePatch {
|
||||
dependsOn(resourceMappingPatch)
|
||||
|
||||
execute {
|
||||
// Resources are not used during patching, but extension code uses these
|
||||
// images so verify they exist.
|
||||
arrayOf(
|
||||
"yt_ringo2_wordmark_header",
|
||||
"yt_ringo2_premium_wordmark_header"
|
||||
).forEach { resource ->
|
||||
variants.forEach { theme ->
|
||||
resourceMappings["drawable", resource + "_" + theme]
|
||||
}
|
||||
}
|
||||
|
||||
arrayOf(
|
||||
"ytWordmarkHeader",
|
||||
"ytPremiumWordmarkHeader"
|
||||
@@ -57,7 +70,6 @@ private val targetResourceDirectoryNames = mapOf(
|
||||
"mdpi" to "129px x 48px"
|
||||
).mapKeys { (dpi, _) -> "drawable-$dpi" }
|
||||
|
||||
private val variants = arrayOf("light", "dark")
|
||||
|
||||
/**
|
||||
* Header logos built into this patch.
|
||||
|
||||
@@ -8,6 +8,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
@@ -379,16 +380,13 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
||||
findInstructionIndicesReversedOrThrow {
|
||||
getReference<MethodReference>()?.name == "setImageDrawable"
|
||||
}.forEach { insertIndex ->
|
||||
val register = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
|
||||
val drawableRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
|
||||
val imageViewRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
|
||||
|
||||
addInstructionsWithLabels(
|
||||
replaceInstruction(
|
||||
insertIndex,
|
||||
"""
|
||||
invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideYoodles(Landroid/graphics/drawable/Drawable;)Landroid/graphics/drawable/Drawable;
|
||||
move-result-object v$register
|
||||
if-eqz v$register, :hide
|
||||
""",
|
||||
ExternalLabel("hide", getInstruction(insertIndex + 1)),
|
||||
"invoke-static { v$imageViewRegister, v$drawableRegister }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->" +
|
||||
"setDoodleDrawable(Landroid/widget/ImageView;Landroid/graphics/drawable/Drawable;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||
import app.revanced.patches.youtube.interaction.seekbar.disableFastForwardNoticeFingerprint
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
|
||||
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package app.revanced.patches.youtube.video.speed.custom
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
|
||||
internal val speedLimiterFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
@@ -19,3 +22,16 @@ internal val speedLimiterFingerprint = fingerprint {
|
||||
Opcode.INVOKE_STATIC,
|
||||
)
|
||||
}
|
||||
|
||||
internal val disableFastForwardNoticeFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
parameters()
|
||||
custom { method, _ ->
|
||||
method.name == "run" && method.indexOfFirstInstruction {
|
||||
// In later targets the code is found in different methods with different strings.
|
||||
val string = getReference<StringReference>()?.string
|
||||
string == "Failed to easy seek haptics vibrate." || string == "search_landing_cache_key"
|
||||
} >= 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -453,6 +453,11 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">سيتم عرض مربع الحوار</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">وهذا لا يتجاوز قيود السن. بل يقبلها تلقائيًا.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">تعطيل تخطي الفصل بالنقر المزدوج</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">لا يمكن للنقر المزدوج مطلقًا أن يؤدي إلى تخطي الفصل التالي/السابق</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">يمكن للنقر المزدوج أن يؤدي أحيانًا إلى تخطي الفصل التالي/السابق</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">التنزيلات الخارجية</string>
|
||||
<string name="revanced_external_downloader_screen_summary">إعدادات لاستخدام أداة التنزيل الخارجية</string>
|
||||
@@ -697,9 +702,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_cast_button_title">إخفاء زر البث</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">تم إخفاء زر البث</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">يتم عرض زر البث</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">إخفاء خلفية أزرار التحكم في المشغل</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">تم إخفاء خلفية أزرار التحكم في المشغل</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">تم إظهار خلفية أزرار التحكم في المشغل</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">إخفاء خلفية عناصر التحكم بالمشغل</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">خلفية عناصر تحكم المشغل مخفية</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">يتم عرض خلفية عناصر التحكم بالمشغل</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">إخفاء زري \"السابق\" و \"التالي\"</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">تم إخفاء الأزرار</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">يتم عرض الأزرار</string>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -168,7 +168,17 @@ Gözlənilməz hallardan xəbərdar olmayacaqsınız."</string>
|
||||
<string name="revanced_hide_feed_survey_summary_on">Axın sorğuları gizlidir</string>
|
||||
<string name="revanced_hide_feed_survey_summary_off">Axın sorğuları göstərilir</string>
|
||||
<string name="revanced_hide_floating_microphone_button_title">Üzən mikrofon düyməsini gizlət</string>
|
||||
<string name="revanced_hide_floating_microphone_button_summary_on">Axtarışda üzən mikrofon düyməsi gizlidir</string>
|
||||
<string name="revanced_hide_floating_microphone_button_summary_off">Üzən mikrofon düyməsi axtarışda göstərilir</string>
|
||||
<string name="revanced_hide_horizontal_shelves_title">Üfüqi hissələri gizlət</string>
|
||||
<string name="revanced_hide_horizontal_shelves_summary_on">"Üfüqi cərgələr gizlidir, məsələn:
|
||||
• Son xəbərlər
|
||||
• İzləməyə davam et
|
||||
• Daha çox kanal kəşf et
|
||||
• Ən uyğun
|
||||
• Alış-veriş
|
||||
• Yenidən izləyin"</string>
|
||||
<string name="revanced_hide_horizontal_shelves_summary_off">Üfüqi cərgələr görünür</string>
|
||||
<string name="revanced_hide_image_shelf_title">Şəkil cərgəsin gizlət</string>
|
||||
<string name="revanced_hide_image_shelf_summary_on">Şəkil cərgəsi axtarış nəticələrində gizlidir</string>
|
||||
<string name="revanced_hide_image_shelf_summary_off">Şəkil cərgəsi axtarış nəticələrində görünür</string>
|
||||
@@ -184,18 +194,27 @@ Gözlənilməz hallardan xəbərdar olmayacaqsınız."</string>
|
||||
<!-- 'Notify me' should be translated using the same localized wording YouTube displays.
|
||||
This item appear in the subscription feed for future livestreams or unreleased videos. -->
|
||||
<string name="revanced_hide_notify_me_button_title">\"Mənə bildir\" düyməsini gizlət</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_on">Mənə bildir düyməsi gizlidir</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_off">Mənə bildir düyməsi görünür</string>
|
||||
<string name="revanced_hide_playables_title">Oynadılan elementləri gizlət</string>
|
||||
<string name="revanced_hide_playables_summary_on">Oynadılanlar gizlidir</string>
|
||||
<string name="revanced_hide_playables_summary_off">Oynadılanlar göstərilir</string>
|
||||
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
|
||||
This button usually appears when searching for a YT creator. -->
|
||||
<string name="revanced_hide_show_more_button_title">\'Daha çox göstər\' düyməsini gizlət</string>
|
||||
<string name="revanced_hide_show_more_button_summary_on">Daha çox göstər düyməsi axtarış nəticələrində gizlidir</string>
|
||||
<string name="revanced_hide_show_more_button_summary_off">Daha çox göstər düyməsi axtarış nəticələrində görünür</string>
|
||||
<string name="revanced_hide_ticket_shelf_title">Bilet bölməsin gizlət</string>
|
||||
<string name="revanced_hide_ticket_shelf_summary_on">Bilet bölməsi gizlidir</string>
|
||||
<string name="revanced_hide_ticket_shelf_summary_off">Bilet bölməsi görünür</string>
|
||||
<!-- 'People also watched' and 'You might also like' should be translated using the same localized wording YouTube displays. -->
|
||||
<string name="revanced_hide_video_recommendation_labels_title">Video tövsiyə etiketlərini gizlət</string>
|
||||
<string name="revanced_hide_video_recommendation_labels_summary_on">\'İnsanlar həmçinin izləyiblər\' və \'Bunu da bəyənə bilərsiniz\' etiketləri axtarış nəticələrində gizlədilib</string>
|
||||
<string name="revanced_hide_video_recommendation_labels_summary_off">\'İnsanlar həmçinin izləyiblər\' və \'Bunu da bəyənə bilərsiniz\' etiketləri axtarış nəticələrində görünür</string>
|
||||
<!-- https://logos.fandom.com/wiki/YouTube/Yoodles -->
|
||||
<string name="revanced_hide_doodles_title">YouTube Doodle-ları gizlət</string>
|
||||
<string name="revanced_hide_doodles_summary_on">YouTube Doodles animasiyası simvolda gizlidir</string>
|
||||
<string name="revanced_hide_doodles_summary_off">YouTube Doodles animasiyası simvolda görünür</string>
|
||||
<string name="revanced_hide_doodles_user_dialog_message">"YouTube Doodle-ları hər il bir neçə gün görünür.
|
||||
|
||||
Əgər hazırda bölgənizdə Doodle göstərilirsə və bu gizlətmə seçimi aktivdirsə, axtarış cizgisi aşağısındakı filtr sahəsi də gizlədiləcək."</string>
|
||||
@@ -214,6 +233,8 @@ Gözlənilməz hallardan xəbərdar olmayacaqsınız."</string>
|
||||
<!-- 'Join' should be translated using the same localized wording YouTube displays.
|
||||
This appears in the video player for certain videos. -->
|
||||
<string name="revanced_hide_join_membership_button_title">Qoşul düyməsin gizlət</string>
|
||||
<string name="revanced_hide_join_membership_button_summary_on">Qoşul düyməsi gizlidir</string>
|
||||
<string name="revanced_hide_join_membership_button_summary_off">Qoşul düyməsi görünür</string>
|
||||
<string name="revanced_hide_medical_panels_title">Tibbi lövhələri gizlət</string>
|
||||
<string name="revanced_hide_medical_panels_summary_on">Tibbi lövhələr gizlidir</string>
|
||||
<string name="revanced_hide_medical_panels_summary_off">Tibbi lövhələr göstərilir</string>
|
||||
@@ -371,7 +392,11 @@ Məhdudiyyətlər
|
||||
</patch>
|
||||
<patch id="ad.general.hideAdsResourcePatch">
|
||||
<string name="revanced_hide_creator_store_shelf_title">Yaradıcı mağaza bölümün gizlət</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">Yaradıcı alış-veriş cərgəsi video oynadıcı altında gizlidir</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">Yaradıcı alış-veriş cərgəsi video oynadıcı altında görünür</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza etiketini gizlət</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_on">Son ekran alış-veriş etiketi gizlədilib</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_off">Son ekran alış-veriş etiketi görünür</string>
|
||||
<string name="revanced_hide_fullscreen_ads_title">Tam ekran reklamlarını gizlət</string>
|
||||
<string name="revanced_hide_fullscreen_ads_summary_on">"Tam ekran reklamları gizlidir
|
||||
|
||||
@@ -392,8 +417,12 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_on">Özünə sponsorluq edilən kartlar gizlidir</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_off">Özünə sponsorluq edilən kartlar göstərilir</string>
|
||||
<string name="revanced_hide_shopping_links_title">Alış-veriş linklərini gizlət</string>
|
||||
<string name="revanced_hide_shopping_links_summary_on">Alış-veriş linkləri video təsvirdə gizlidir</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">Alış-veriş linkləri video təsvirdə görünür</string>
|
||||
<!-- 'View products' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_view_products_banner_title">“Məhsullara baxın” panelin gizlət</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_on">Məhsullara baxış etiketi video örtüyündə gizlidir</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_off">Məhsullara baxış etiketi video örtüyündə görünür</string>
|
||||
<string name="revanced_hide_web_search_results_title">Veb axtarış nəticələrini gizlət</string>
|
||||
<string name="revanced_hide_web_search_results_summary_on">Veb axtarış nəticələri gizlədilir</string>
|
||||
<string name="revanced_hide_web_search_results_summary_off">Veb axtarış nəticələri göstərilir</string>
|
||||
@@ -424,6 +453,11 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Dialoq göstərilir</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Bu, yaş məhdudiyyətini ötürmür. Sadəcə birbaşa qəbul edir.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Cüt toxunuşla fəsil ötürməsini qapat</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Cüt toxunma heç vaxt növbəti/əvvəlki fəsilə keçidi zorlaya bilməz</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Cüt toxunma bəzən növbəti/əvvəlki fəsilə keçidi zorlaya bilər</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Xarici yükləmələr</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Xarici yükləyici istifadəsi üçün tənzimləmələr</string>
|
||||
@@ -668,9 +702,9 @@ Audio trek seçimin göstərmək üçün \"Video axınları saxtalaşdır\"ı iO
|
||||
<string name="revanced_hide_cast_button_title">Yayımla düyməsini gizlət</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Yayım düyməsi gizlidir</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Yayım düyməsi göstərilir</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Oynadıcı idarəetmə düymələri fonunu gizlət</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Oynadıcı idarəetmə düymələri fonu gizlidir</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Oynadıcı idarəetmə düymələri fonu görünür</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Oynadıcı idarəetmələri fonunu gizlət</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Oynadıcı idarəetmə fonu gizlədilib</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Oynadıcı idarəetmə fonu görünür</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Əvvəlki və Növbəti düymələrin gizlət</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Düymələr gizlidir</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Düymələr göstərilir</string>
|
||||
@@ -707,7 +741,13 @@ Audio trek seçimin göstərmək üçün \"Video axınları saxtalaşdır\"ı iO
|
||||
<string name="revanced_shorts_player_screen_title">Shorts oynadıcı</string>
|
||||
<string name="revanced_shorts_player_screen_summary">Shorts oynadıcıda hissəcikləri gizlət və ya göstər</string>
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the Home tab. -->
|
||||
<string name="revanced_hide_shorts_home_title">Shorts-u Ev axınında gizlət</string>
|
||||
<string name="revanced_hide_shorts_home_summary_on">Ev axını və əlaqəli videolarda gizlidir</string>
|
||||
<string name="revanced_hide_shorts_home_summary_off">Ev axını və əlaqəli videolarda görünür</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the Subscriptions tab. -->
|
||||
<string name="revanced_hide_shorts_subscriptions_title">Shorts-u Abunəliklər axınında gizlət</string>
|
||||
<string name="revanced_hide_shorts_subscriptions_summary_on">Abunəliklər axınında gizlidir</string>
|
||||
<string name="revanced_hide_shorts_subscriptions_summary_off">Abunəliklər axınında görünür</string>
|
||||
<string name="revanced_hide_shorts_search_title">Axtarış nəticələrindəki \"Shorts\"u gizlət</string>
|
||||
<string name="revanced_hide_shorts_search_summary_on">Axtarış nəticələrində gizlidir</string>
|
||||
<string name="revanced_hide_shorts_search_summary_off">Axtarış nəticələrində görünür</string>
|
||||
@@ -715,6 +755,8 @@ Audio trek seçimin göstərmək üçün \"Video axınları saxtalaşdır\"ı iO
|
||||
<string name="revanced_hide_shorts_history_summary_on">Baxış tarixçəsində gizlidir</string>
|
||||
<string name="revanced_hide_shorts_history_summary_off">Baxış tarixçəsində göstərilib</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_title">Super Təşəkkür Al düyməsini gizlət</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_on">Super Təşəkkürlər Al düyməsi gizlidir</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_off">Super Təşəkkürlər Al düyməsi görünür</string>
|
||||
<string name="revanced_hide_shorts_effect_button_title">Effekt düyməsini gizlət</string>
|
||||
<string name="revanced_hide_shorts_effect_button_summary_on">Effekt düyməsi gizlidir</string>
|
||||
<string name="revanced_hide_shorts_effect_button_summary_off">Effekt düyməsi görünür</string>
|
||||
@@ -797,7 +839,11 @@ Audio trek seçimin göstərmək üçün \"Video axınları saxtalaşdır\"ı iO
|
||||
<string name="revanced_hide_shorts_channel_bar_summary_on">Kanal çubuğu gizlidir</string>
|
||||
<string name="revanced_hide_shorts_channel_bar_summary_off">Kanal çubuğu göstərilir</string>
|
||||
<string name="revanced_hide_shorts_video_title_title">Video başlığını gizlət</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_on">Video başlığı gizlidir</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_off">Video başlığı görünür</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_title">Səs üst məlumat etiketini gizlət</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_summary_on">Səs üst məlumat etiketi gizlədilib</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_summary_off">Səs üst məlumat etiketi görünür</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_title">Video keçidi etiketini gizlət</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_summary_on">Video linki etiketi gizlidir</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_summary_off">Video link etiketi göstərilir</string>
|
||||
@@ -813,6 +859,9 @@ Avtomatik oynatma YouTube ayarlarında dəyişdirilə bilər: Ayarlar → Oxunu
|
||||
<string name="revanced_end_screen_suggested_video_summary_off">Son ekranda bildirilən video göstərilir</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.relatedvideooverlay.hideRelatedVideoOverlayPatch">
|
||||
<string name="revanced_hide_related_videos_overlay_title">Əlaqəli videolar örtüyünü gizlət</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">Əlaqəli videolar yerləşməsi tam ekranda gizlidir</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_off">Əlaqəli videolar yerləşməsi tam ekranda görünür</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.time.hideTimestampPatch">
|
||||
<string name="revanced_hide_timestamp_title">Video vaxt möhürünü gizlət</string>
|
||||
@@ -1279,8 +1328,10 @@ Bunu aktivləşdirmə, bəzi regionlarda əngəllənib silinən şəkilləri dü
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the Home tab. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">Ev paneli</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the Subscriptions tab. -->
|
||||
<string name="revanced_alt_thumbnail_subscription_title">Abunəliklər bölməsi</string>
|
||||
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (Library) tab. -->
|
||||
<string name="revanced_alt_thumbnail_library_title">\"Siz\" paneli</string>
|
||||
<string name="revanced_alt_thumbnail_player_title">Oynadıcı pleylistləri & tövsiyələri</string>
|
||||
<string name="revanced_alt_thumbnail_search_title">Axtarış nəticələri</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_1">Orijinal miniatürlər</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow & Orijinal miniatürlər</string>
|
||||
@@ -1496,6 +1547,7 @@ AVC maksimum 1080p görüntü imkanına malikdir, Opus audio kodlama olmur və v
|
||||
<string name="revanced_block_video_ads_summary_off">Video reklamlar bloklanmır</string>
|
||||
</patch>
|
||||
<patch id="chat.antidelete.showDeletedMessagesPatch">
|
||||
<string name="revanced_deleted_msg">Məlumat silindi</string>
|
||||
<string name="revanced_show_deleted_messages_title">Silinən mesajları göstər</string>
|
||||
<string name="revanced_show_deleted_messages_entry_1">Silinən mesajlar göstərilməsin</string>
|
||||
<string name="revanced_show_deleted_messages_entry_2">Silinmiş mesajları boz panel arxasında gizlət</string>
|
||||
@@ -1516,8 +1568,11 @@ AVC maksimum 1080p görüntü imkanına malikdir, Opus audio kodlama olmur və v
|
||||
<string name="revanced_settings">ReVanced Tənzimləmələri</string>
|
||||
<string name="revanced_about_title">Haqqında</string>
|
||||
<string name="revanced_about_summary">ReVanced Haqqında</string>
|
||||
<string name="revanced_ads_screen_title">Reklam Əngəlləmə</string>
|
||||
<string name="revanced_ads_screen_summary">Reklam Əngəlləmə tənzimləmələri</string>
|
||||
<string name="revanced_chat_screen_title">Söhbət</string>
|
||||
<string name="revanced_chat_screen_summary">Söhbət tənzimləmələri</string>
|
||||
<string name="revanced_misc_screen_title">Çoxvariantlı</string>
|
||||
<string name="revanced_misc_screen_summary">Müxtəlif tənzimləmələr</string>
|
||||
<string name="revanced_general_category_title">Ümumi tənzimləmələr</string>
|
||||
<string name="revanced_other_category_title">Digər tənzimləmələr</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Будзе паказана дыялогавае акно</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Гэта не абыходзіць узроставае абмежаванне. Ён проста прымае гэта аўтаматычна.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Адключыць прапуск раздзела па двайным націску</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Двайны націск ніколі не можа выклікаць прапуск да наступнага/папярэдняга раздзела</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Двайны націск можа час ад часу выклікаць прапуск да наступнага/папярэдняга раздзела</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Знешнія загрузкі</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Налады для выкарыстання вонкавага загрузніка</string>
|
||||
@@ -697,9 +702,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_cast_button_title">Схаваць кнопку «Трансляцыя»</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Кнопка Cast схавана</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Паказана кнопка Cast</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Схаваць фон кнопак кіравання прайгравальнікам</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Фон кнопак кіравання прайгравальнікам схаваны</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Фон кнопак кіравання прайгравальнікам паказаны</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Схаваць фон элементаў кіравання прайгравальнікам</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Фон элементаў кіравання плэерам схаваны</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Фон элементаў кіравання паказаны</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Схаваць папярэднія & кнопкі «Далей»</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Кнопкі схаваныя</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Паказваюцца кнопкі</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Диалоговият прозорец ще бъде показан</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Тази функция не заобикаля възрастовото ограничение. Тя просто приема възрастовата граница автоматично.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Деактивиране на пропускане на глава с двойно докосване</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Двойното докосване никога не може да предизвика пропускане до следваща/предишна глава</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Двойното докосване може понякога да предизвика пропускане до следваща/предишна глава</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Външни изтегляния</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Настройки за използване на външно приложение за изтегляне</string>
|
||||
@@ -697,9 +702,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_cast_button_title">Скриване на бутона Cast</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Бутонът за предаване е скрит</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Бутонът за предаване се показва</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Скриване на фона на бутоните за управление на плейъра</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Фонът на бутоните за управление на плейъра е скрит</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Фонът на бутоните за управление на плейъра е показан</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Скриване на фона на контролите на плейъра</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Фонът на контролите на плейъра е скрит</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Фонът на контролите на плейъра е показан</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Скриване на бутоните \"Предишен и Следващ\"</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Бутоните са скрити</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Бутоните се показват</string>
|
||||
|
||||
@@ -449,6 +449,11 @@ MicroG-এর জন্য ব্যাটারি অপ্টিমাইজ
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">ডায়ালগ প্রদর্শিত হবে</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">এটি বয়সের সীমাবদ্ধতাকে বাইপাস করে না। এটা শুধু স্বয়ংক্রিয়ভাবে গ্রহণ করে।</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">ডাবল ট্যাপ অধ্যায় স্কিপ অক্ষম করুন</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">ডাবল ট্যাপ কখনও পরবর্তী/পূর্ববর্তী অধ্যায়ে স্কিপ ট্রিগার করতে পারে না</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">ডাবল ট্যাপ মাঝে মাঝে পরবর্তী/পূর্ববর্তী অধ্যায়ে স্কিপ ট্রিগার করতে পারে</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">বাহিরে ডাউনলোড</string>
|
||||
<string name="revanced_external_downloader_screen_summary">বাহিরের ডাউনলোডার ব্যবহার করার সেটিং</string>
|
||||
@@ -693,9 +698,9 @@ MicroG-এর জন্য ব্যাটারি অপ্টিমাইজ
|
||||
<string name="revanced_hide_cast_button_title">কাস্ট বোতামটি লুকান</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">কাস্ট বাটন লুকিয়ে রয়েছে</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">কাস্ট বাটন প্রদর্শিত হয়েছে</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">প্লেয়ার কন্ট্রোল বোতামগুলির পটভূমি লুকান</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">প্লেয়ার কন্ট্রোল বোতামগুলির পটভূমি লুকানো আছে</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">প্লেয়ার কন্ট্রোল বোতামগুলির পটভূমি দেখানো হয়েছে</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">প্লেয়ার কন্ট্রোল ব্যাকগ্রাউন্ড লুকান</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">প্লেয়ার নিয়ন্ত্রণের পটভূমি লুকানো আছে</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">প্লেয়ার কন্ট্রোল ব্যাকগ্রাউন্ড দেখানো হয়েছে</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">পূর্ববর্তী লুকান & পরবর্তী বোতাম</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">বোতাম লুকানো হয়</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">বোতাম দেখানো হয়</string>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -453,6 +453,11 @@ Tato funkce je dostupná pouze pro starší zařízení"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Dialog bude zobrazen</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Tímto krokem neobcházíte věkové omezení. Pouze jej automaticky akceptujete.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Zakázat přeskočení kapitoly dvojitým klepnutím</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Dvojité klepnutí nikdy nespustí přeskočení na další/předchozí kapitolu</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Dvojité klepnutí může občas spustit přeskočení na další/předchozí kapitolu</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Externí stahování</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Nastavení pro použití externího stahování</string>
|
||||
@@ -697,9 +702,9 @@ Chcete-li zobrazit nabídku zvukové stopy, změňte možnost „Zfalšovat stre
|
||||
<string name="revanced_hide_cast_button_title">Skrýt tlačítko Odeslat</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Tlačítko pro odesílání je skryto</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Tlačítko vysílání je viditelné</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Skrýt pozadí ovládacích tlačítek přehrávače</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Pozadí ovládacích tlačítek přehrávače je skryté</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Zobrazuje se pozadí ovládacích tlačítek přehrávače</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Skrýt pozadí ovládacích prvků přehrávače</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Pozadí ovládacích prvků přehrávače je skryto</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Pozadí ovládacích prvků přehrávače je zobrazeno</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Skrýt tlačítka Předchozí a Další</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Tlačítka jsou skryta</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Tlačítka jsou zobrazena</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Denne funktion er kun tilgængelig for ældre enheder"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Dialog vil blive vist</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Dette går ikke uden om aldersbegrænsningen. Det accepterer bare det automatisk.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Deaktiver dobbeltklik kapitelspring</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Dobbeltklik kan aldrig udløse et spring til næste/forrige kapitel</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Dobbeltklik kan lejlighedsvis udløse et spring til næste/forrige kapitel</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Eksterne downloads</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Indstillinger for brug af en ekstern downloader</string>
|
||||
@@ -697,9 +702,9 @@ For at vise lydspormenuen skal du ændre \"Spoof videostream\" til iOS TV"</stri
|
||||
<string name="revanced_hide_cast_button_title">Skjul Cast-knappen</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Cast-knappen er skjult</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Cast knap er vist</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Skjul baggrunden for afspillerens kontrolknapper</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Baggrunden for afspillerens kontrolknapper er skjult</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Baggrunden for afspillerens kontrolknapper vises</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Skjul baggrund for afspillerkontroller</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Baggrund for afspilningskontroller er skjult</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Baggrund for afspillerkontroller vises</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Skjul Forrige & Næste knapper</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Knapper er skjult</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Knapper vises</string>
|
||||
|
||||
@@ -448,6 +448,11 @@ Diese Funktion ist nur für ältere Geräte verfügbar"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Dialog wird angezeigt</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Dies umgeht nicht die Altersbeschränkung, sondern akzeptiert sie nur automatisch.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Doppeltippen zum Kapitelüberspringen deaktivieren</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Doppeltippen kann niemals ein Überspringen zum nächsten/vorherigen Kapitel auslösen</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Doppeltippen kann gelegentlich ein Überspringen zum nächsten/vorherigen Kapitel auslösen</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Externe Downloads</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Einstellungen für die Verwendung eines externen Downloaders</string>
|
||||
@@ -690,9 +695,9 @@ Um das Audiotrack-Menü anzuzeigen, ändere \"Video-Streams fälschen\" zu iOS T
|
||||
<string name="revanced_hide_cast_button_title">Cast-Button ausblenden</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Der Cast button ist ausgeblendet</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Der Cast button wird angezeigt</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Hintergrund der Player-Steuerungstasten ausblenden</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Hintergrund der Player-Steuerungstasten ist ausgeblendet</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Hintergrund der Player-Steuerungstasten wird angezeigt</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Hintergrund der Player-Steuerelemente ausblenden</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Hintergrund der Wiedergabesteuerung ist ausgeblendet</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Hintergrund der Player-Steuerelemente wird angezeigt</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Vorherige & Nächste Tasten ausblenden</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Buttons sind ausgeblendet</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Tasten werden angezeigt</string>
|
||||
|
||||
@@ -75,7 +75,7 @@ Second \"item\" text"</string>
|
||||
|
||||
Ακολουθήστε τον οδηγό \"Don't kill my app\" για το τηλέφωνό σας και εφαρμόστε τις οδηγίες στο MicroG.
|
||||
|
||||
Αυτό είναι απαραίτητο για τη λειτουργία της εφαρμογής."</string>
|
||||
Αυτό είναι απαραίτητο για τη σωστή λειτουργία της εφαρμογής."</string>
|
||||
<string name="gms_core_dialog_open_website_text">Άνοιγμα ιστοσελίδας</string>
|
||||
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"Οι βελτιστοποιήσεις μπαταρίας πρέπει να απενεργοποιηθούν για το MicroG GmsCore ώστε να αποφευχθούν προβλήματα.
|
||||
|
||||
@@ -282,17 +282,17 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_description_components_screen_title">Περιγραφή βίντεο</string>
|
||||
<string name="revanced_hide_description_components_screen_summary">Απόκρυψη ή εμφάνιση στοιχείων περιγραφής βίντεο</string>
|
||||
<string name="revanced_hide_filter_bar_screen_title">Γραμμή φίλτρων</string>
|
||||
<string name="revanced_hide_filter_bar_screen_summary">Απόκρυψη ή εμφάνιση της γραμμής φίλτρων στις ροές, στο ιστορικό, στα αποτελέσματα αναζήτησης και στα σχετικά βίντεο</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_title">Απόκρυψη στις ροές</string>
|
||||
<string name="revanced_hide_filter_bar_screen_summary">Απόκρυψη ή εμφάνιση της γραμμής φίλτρων στις ροές, στο ιστορικό παρακολούθησης, στα αποτελέσματα αναζήτησης και στα σχετικά βίντεο</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_title">Γραμμή κατηγοριών στις ροές</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_history_title">Απόκρυψη στο ιστορικό</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_history_title">Γραμμή κατηγοριών στο ιστορικό παρακολούθησης</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_history_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_history_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_search_title">Απόκρυψη στα αποτελέσματα αναζήτησης</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_search_title">Γραμμή κατηγοριών στα αποτελέσματα αναζήτησης</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_search_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_search_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_title">Απόκρυψη στα σχετικά βίντεο</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_title">Γραμμή κατηγοριών στα σχετικά βίντεο</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_channel_screen_title">Σελίδα καναλιού</string>
|
||||
@@ -312,7 +312,7 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_visit_community_button_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_visit_community_button_summary_off">Εμφανίζεται</string>
|
||||
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_visit_store_button_title">Κουμπί «Επίσκεψη στο κατάστημα» στη σελίδα καναλιού</string>
|
||||
<string name="revanced_hide_visit_store_button_title">Κουμπί «Επίσκεψη στο κατάστημα»</string>
|
||||
<string name="revanced_hide_visit_store_button_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_visit_store_button_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_comments_screen_title">Σχόλια</string>
|
||||
@@ -358,9 +358,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_custom_filter_toast_invalid_syntax">Μη έγκυρο προσαρμοσμένο φίλτρο: %s</string>
|
||||
<string name="revanced_hide_keyword_content_screen_title">Απόκρυψη περιεχομένου λέξεων-κλειδιών</string>
|
||||
<string name="revanced_hide_keyword_content_screen_summary">Απόκρυψη βίντεο ροής και αναζήτησης χρησιμοποιώντας φίλτρα λέξεων-κλειδιών</string>
|
||||
<string name="revanced_hide_keyword_content_home_title">Φιλτράρισμα αρχικής σελίδας</string>
|
||||
<string name="revanced_hide_keyword_content_home_summary_on">Τα βίντεο στην αρχική σελίδα φιλτράρονται με τη χρήση λέξεων-κλειδιών</string>
|
||||
<string name="revanced_hide_keyword_content_home_summary_off">Τα βίντεο στην αρχική σελίδα δε φιλτράρονται από λέξεις-κλειδιά</string>
|
||||
<string name="revanced_hide_keyword_content_home_title">Φιλτράρισμα αρχικής ροής</string>
|
||||
<string name="revanced_hide_keyword_content_home_summary_on">Τα βίντεο στην αρχική ροή φιλτράρονται με τη χρήση λέξεων-κλειδιών</string>
|
||||
<string name="revanced_hide_keyword_content_home_summary_off">Τα βίντεο στην αρχική ροή δε φιλτράρονται από λέξεις-κλειδιά</string>
|
||||
<string name="revanced_hide_keyword_content_search_title">Φιλτράρισμα αποτελεσμάτων αναζήτησης</string>
|
||||
<string name="revanced_hide_keyword_content_search_summary_on">Τα αποτελέσματα αναζήτησης φιλτράρονται με τη χρήση λέξεων-κλειδιών</string>
|
||||
<string name="revanced_hide_keyword_content_search_summary_off">Τα αποτελέσματα αναζήτησης δε φιλτράρονται από λέξεις-κλειδιά</string>
|
||||
@@ -379,8 +379,8 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_keyword_content_about_summary">"Οι καρτέλες «Αρχική», «Εγγραφές» και τα αποτελέσματα αναζήτησης φιλτράρονται για απόκρυψη περιεχομένου που ταιριάζει με τις λέξεις-κλειδιά
|
||||
|
||||
Περιορισμοί:
|
||||
• Τα Shorts δεν γίνεται να κρύβονται με βάση το όνομα καναλιού
|
||||
• Κάποια στοιχεία UI ενδέχεται να μην κρύβονται
|
||||
• Δεν γίνεται απόκρυψη των Shorts με βάση το όνομα καναλιού
|
||||
• Κάποια στοιχεία UI ενδέχεται να μην είναι κρυμμένα
|
||||
• Η αναζήτηση για μια λέξη-κλειδί ενδέχεται να μην εμφανίζει κανένα αποτέλεσμα"</string>
|
||||
<string name="revanced_hide_keyword_content_about_whole_words_title">Ταίριασμα ολόκληρων λέξεων</string>
|
||||
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
|
||||
@@ -455,6 +455,11 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Αυτό δεν παρακάμπτει τον ηλικιακό περιορισμό. Απλώς τον αποδέχεται αυτόματα.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Απενεργοποίηση παράλειψης κεφαλαίου με διπλό πάτημα</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Το διπλό πάτημα δεν παράλειπει στο επόμενο/προηγούμενο κεφάλαιο</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Το διπλό πάτημα μπορεί περιστασιακά να παραλείψει στο επόμενο/προηγούμενο κεφάλαιο</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Εξωτερικές λήψεις</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Ρυθμίσεις για χρήση εξωτερικού προγράμματος λήψης</string>
|
||||
@@ -738,7 +743,7 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_shorts_player_screen_title">Οθόνη αναπαραγωγής Shorts</string>
|
||||
<string name="revanced_shorts_player_screen_summary">Απόκρυψη ή εμφάνιση στοιχείων στην οθόνη αναπαραγωγής Shorts</string>
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the Home tab. -->
|
||||
<string name="revanced_hide_shorts_home_title">Shorts στην αρχική σελίδα και στα σχετικά βίντεο</string>
|
||||
<string name="revanced_hide_shorts_home_title">Shorts στην αρχική ροή και στα σχετικά βίντεο</string>
|
||||
<string name="revanced_hide_shorts_home_summary_on">Κρυμμένα</string>
|
||||
<string name="revanced_hide_shorts_home_summary_off">Εμφανίζονται</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the Subscriptions tab. -->
|
||||
@@ -803,7 +808,7 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_shorts_use_sound_button_title">Κουμπί «Χρήση αυτού του ήχου»</string>
|
||||
<string name="revanced_hide_shorts_use_sound_button_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_shorts_use_sound_button_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_shorts_use_template_button_title">Κουμπί «Χρήση προτύπου»</string>
|
||||
<string name="revanced_hide_shorts_use_template_button_title">Κουμπί «Χρήση αυτού του προτύπου»</string>
|
||||
<string name="revanced_hide_shorts_use_template_button_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_shorts_use_template_button_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_shorts_like_fountain_title">Εφέ κουμπιού «Μου αρέσει»</string>
|
||||
@@ -857,8 +862,8 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_end_screen_suggested_video_summary_off">Εμφανίζεται</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.relatedvideooverlay.hideRelatedVideoOverlayPatch">
|
||||
<string name="revanced_hide_related_videos_overlay_title">Προεπισκόπηση σχετικών βίντεο στην πλήρη οθόνη</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_related_videos_overlay_title">Πλαίσιο σχετικών βίντεο στην πλήρη οθόνη</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_off">Εμφανίζεται</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.time.hideTimestampPatch">
|
||||
@@ -880,8 +885,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.player.fullscreen.openVideosFullscreen">
|
||||
<string name="revanced_open_videos_fullscreen_portrait_title">Άνοιγμα των βίντεο σε πλήρη οθόνη με κατακόρυφη προβολή</string>
|
||||
<string name="revanced_open_videos_fullscreen_portrait_summary_on">Τα βίντεο ανοίγουν σε λειτουργία πλήρους οθόνης</string>
|
||||
<string name="revanced_open_videos_fullscreen_portrait_summary_off">Τα βίντεο δεν ανοίγουν σε λειτουργία πλήρους οθόνης</string>
|
||||
<string name="revanced_open_videos_fullscreen_portrait_summary_on">Τα βίντεο ανοίγουν αυτόματα σε λειτουργία πλήρους οθόνης</string>
|
||||
<string name="revanced_open_videos_fullscreen_portrait_summary_off">Τα βίντεο δεν ανοίγουν αυτόματα σε λειτουργία πλήρους οθόνης</string>
|
||||
</patch>
|
||||
<patch id="layout.player.overlay.customPlayerOverlayOpacityResourcePatch">
|
||||
<string name="revanced_player_overlay_opacity_title">Αδιαφάνεια φόντου οθόνης αναπαραγωγής</string>
|
||||
@@ -1114,7 +1119,7 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_sb_new_segment_disabled_category">Η κατηγορία είναι απενεργοποιημένη στις ρυθμίσεις. Ενεργοποιήστε την κατηγορία για υποβολή.</string>
|
||||
<string name="revanced_sb_new_segment_title">Νέο τμήμα SponsorBlock</string>
|
||||
<string name="revanced_sb_new_segment_mark_time_as_question">Ορισμός %s ως αρχή ή τέλος ενός νέου τμήματος;</string>
|
||||
<string name="revanced_sb_new_segment_mark_start">Έναρξη</string>
|
||||
<string name="revanced_sb_new_segment_mark_start">Αρχή</string>
|
||||
<string name="revanced_sb_new_segment_mark_end">Τέλος</string>
|
||||
<string name="revanced_sb_new_segment_now">Τώρα</string>
|
||||
<string name="revanced_sb_new_segment_time_start">Χρόνος έναρξης του τμήματος</string>
|
||||
@@ -1178,9 +1183,9 @@ Second \"item\" text"</string>
|
||||
• Η ροή οργανώνεται ανά θέματα και κανάλια"</string>
|
||||
</patch>
|
||||
<patch id="layout.spoofappversion.spoofAppVersionPatch">
|
||||
<string name="revanced_spoof_app_version_title">Τροποποίηση έκδοσης εφαρμογής</string>
|
||||
<string name="revanced_spoof_app_version_summary_on">Η έκδοση τροποποιείται</string>
|
||||
<string name="revanced_spoof_app_version_summary_off">Η έκδοση δεν τροποποιείται</string>
|
||||
<string name="revanced_spoof_app_version_title">Παραποίηση έκδοσης εφαρμογής</string>
|
||||
<string name="revanced_spoof_app_version_summary_on">Η έκδοση παραποιείται</string>
|
||||
<string name="revanced_spoof_app_version_summary_off">Η έκδοση δεν παραποιείται</string>
|
||||
<string name="revanced_spoof_app_version_user_dialog_message">"Η έκδοση της εφαρμογής YouTube θα παραποιηθεί σε παλιότερη.
|
||||
|
||||
Αυτό θα αλλάξει την εμφάνιση και τα χαρακτηριστικά της εφαρμογής, αλλά ενδέχεται να εμφανιστούν άγνωστες παρενέργειες.
|
||||
@@ -1188,7 +1193,7 @@ Second \"item\" text"</string>
|
||||
Αν αργότερα απενεργοποιηθεί, συνιστάται η εκκαθάριση δεδομένων της εφαρμογής για την αποφυγή σφαλμάτων UI."</string>
|
||||
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
|
||||
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch. -->
|
||||
<string name="revanced_spoof_app_version_target_title">Έκδοση τροποποίησης της εφαρμογής</string>
|
||||
<string name="revanced_spoof_app_version_target_title">Έκδοση παραποίησης της εφαρμογής</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_1">19.35.36 - Επαναφορά των παλιών εικονιδίων της οθόνης αναπαραγωγής Shorts</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_2">19.01.34 - Επαναφορά παλιών εικονιδίων γραμμής πλοήγησης</string>
|
||||
</patch>
|
||||
@@ -1323,7 +1328,7 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.alternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the Home tab. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">Αρχική σελίδα</string>
|
||||
<string name="revanced_alt_thumbnail_home_title">Καρτέλα «Αρχική»</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the Subscriptions tab. -->
|
||||
<string name="revanced_alt_thumbnail_subscription_title">Καρτέλα «Εγγραφές»</string>
|
||||
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (Library) tab. -->
|
||||
|
||||
@@ -193,9 +193,9 @@ Sin embargo, si activas esto, también se registrarán algunos datos del usuario
|
||||
<string name="revanced_hide_notify_me_button_title">Ocultar el botón \'Notificarme\'</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_on">El botón Notificarme está oculto</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_off">El botón Notificarme está visible</string>
|
||||
<string name="revanced_hide_playables_title">Ocultar los reproducibles</string>
|
||||
<string name="revanced_hide_playables_summary_on">Los reproducibles están ocultos</string>
|
||||
<string name="revanced_hide_playables_summary_off">Se muestran los reproducibles</string>
|
||||
<string name="revanced_hide_playables_title">Ocultar jugables</string>
|
||||
<string name="revanced_hide_playables_summary_on">Los jugables están ocultos</string>
|
||||
<string name="revanced_hide_playables_summary_off">Los jugables están visibles</string>
|
||||
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
|
||||
This button usually appears when searching for a YT creator. -->
|
||||
<string name="revanced_hide_show_more_button_title">Ocultar botón \'Mostrar más\'</string>
|
||||
@@ -450,6 +450,11 @@ Esta función solo está disponible para dispositivos antiguos"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Se mostrará el diálogo</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Esto no pasa por alto la restricción de edad, sino que simplemente la acepta automáticamente.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Deshabilitar el salto de capítulo con doble toque</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">El doble toque nunca puede activar un salto al capítulo siguiente/anterior</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">El doble toque puede ocasionalmente activar un salto al capítulo siguiente/anterior</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Descargas externa</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Configuración para el uso de un descargador externo</string>
|
||||
@@ -694,9 +699,9 @@ Para mostrar el menú de la pista de audio, cambia \"Suplantar transmisiones de
|
||||
<string name="revanced_hide_cast_button_title">Ocultar el botón Transmitir</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">El botón de envío a otros dispositivos está oculto</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">El botón de envío a otros dispositivos es visible</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Ocultar el fondo de los botones de control del reproductor</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">El fondo de los botones de control del reproductor está oculto</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Se muestra el fondo de los botones de control del reproductor</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Ocultar fondo de los controles del reproductor</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">El fondo de los controles del reproductor está oculto</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Se muestra el fondo de los controles del reproductor</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Ocultar botones Anterior & Siguiente</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Los botones están ocultos</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Los botones se muestran</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ See funktsioon on saadaval ainult vanemates seadmetes"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Dialoog kuvatakse</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">See ei mööda vanusepiirangust. See lihtsalt aktsepteerib seda automaatselt.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Keela topeltpuudutusega peatüki vahelejätmine</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Topeltpuudutus ei saa kunagi käivitada järgmise/eelmise peatüki vahelejätmist</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Topeltpuudutus võib aeg-ajalt käivitada järgmise/eelmise peatüki vahelejätmise</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Välised allalaadimised</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Seaded välise allalaadija kasutamiseks</string>
|
||||
@@ -698,8 +703,8 @@ Heliriba menüü kuvamiseks muutke valikut „Võltsitud videovoogedastus“ vä
|
||||
<string name="revanced_hide_cast_button_summary_on">Ülekandmise nupp on peidetud</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Ülekandmise nupp on nähtav</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Peida pleieri juhtnuppude taust</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Pleieri juhtnuppude taust on peidetud</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Pleieri juhtnuppude taust on näidatud</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Mängija juhtnuppude taust on peidetud</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Pleieri juhtnuppude taust on nähtav</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Peida eelmine & järgmine nupp</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Nupud on peidetud</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Nupud on nähtavad</string>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -115,6 +115,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -161,11 +161,20 @@ Et saa ilmoituksia odottamattomista tapahtumista."</string>
|
||||
<string name="revanced_hide_crowdfunding_box_title">Piilota joukkorahoituslaatikko</string>
|
||||
<string name="revanced_hide_crowdfunding_box_summary_on">Joukkorahoituslaatikko on piilotettu</string>
|
||||
<string name="revanced_hide_crowdfunding_box_summary_off">Joukkorahoituslaatikko näytetään</string>
|
||||
<string name="revanced_hide_expandable_card_title">Piilota laajennettava kortti</string>
|
||||
<string name="revanced_hide_expandable_card_summary_on">Laajennettava kortti on piilotettu videoiden alla</string>
|
||||
<string name="revanced_hide_expandable_card_summary_off">Laajennettava kortti näytetään videoiden alla</string>
|
||||
<string name="revanced_hide_feed_survey_title">Piilota syötteen kyselyt</string>
|
||||
<string name="revanced_hide_feed_survey_summary_on">Syötteen kyselyt on piilotettu</string>
|
||||
<string name="revanced_hide_feed_survey_summary_off">Syötteen kyselyt näytetään</string>
|
||||
<string name="revanced_hide_floating_microphone_button_title">Piilota kelluva mikrofonipainike</string>
|
||||
<string name="revanced_hide_floating_microphone_button_summary_on">Kelluva mikrofonipainike on piilotettu haussa</string>
|
||||
<string name="revanced_hide_floating_microphone_button_summary_off">Kelluva mikrofonipainike näytetään haussa</string>
|
||||
<string name="revanced_hide_horizontal_shelves_title">Piilota vaakasuuntaiset hyllyt</string>
|
||||
<string name="revanced_hide_horizontal_shelves_summary_off">Vaakasuuntaiset hyllyt näytetään</string>
|
||||
<string name="revanced_hide_image_shelf_title">Piilota kuvahylly</string>
|
||||
<string name="revanced_hide_image_shelf_summary_on">Kuvahylly on piilotettu hakutuloksissa</string>
|
||||
<string name="revanced_hide_image_shelf_summary_off">Kuvahylly näytetään hakutuloksissa</string>
|
||||
<string name="revanced_hide_latest_posts_title">Piilota uusimmat postaukset</string>
|
||||
<string name="revanced_hide_latest_posts_summary_on">Uusimmat postaukset on piilotettu</string>
|
||||
<string name="revanced_hide_latest_posts_summary_off">Uusimmat postaukset näytetään</string>
|
||||
@@ -178,18 +187,25 @@ Et saa ilmoituksia odottamattomista tapahtumista."</string>
|
||||
<!-- 'Notify me' should be translated using the same localized wording YouTube displays.
|
||||
This item appear in the subscription feed for future livestreams or unreleased videos. -->
|
||||
<string name="revanced_hide_notify_me_button_title">Piilota \"Ilmoita minulle\" -painike</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_on">Ilmoita minulle -painike on piilotettu</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_off">Ilmoita minulle -painike näytetään</string>
|
||||
<string name="revanced_hide_playables_title">Piilota Pelattavat</string>
|
||||
<string name="revanced_hide_playables_summary_on">Pelattavat on piilotettu</string>
|
||||
<string name="revanced_hide_playables_summary_off">Pelattavat näytetään</string>
|
||||
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
|
||||
This button usually appears when searching for a YT creator. -->
|
||||
<string name="revanced_hide_show_more_button_title">Piilota \"Näytä lisää\" -painike</string>
|
||||
<string name="revanced_hide_show_more_button_summary_on">Näytä lisää -painike on piilotettu hakutuloksissa</string>
|
||||
<string name="revanced_hide_show_more_button_summary_off">Näytä lisää -painike näytetään hakutuloksissa</string>
|
||||
<string name="revanced_hide_ticket_shelf_title">Piilota lippuhylly</string>
|
||||
<string name="revanced_hide_ticket_shelf_summary_on">Lippuhylly on piilotettu</string>
|
||||
<string name="revanced_hide_ticket_shelf_summary_off">Lippuhylly näytetään</string>
|
||||
<!-- 'People also watched' and 'You might also like' should be translated using the same localized wording YouTube displays. -->
|
||||
<string name="revanced_hide_video_recommendation_labels_title">Piilota videosuositusten tunnisteet</string>
|
||||
<!-- https://logos.fandom.com/wiki/YouTube/Yoodles -->
|
||||
<string name="revanced_hide_doodles_title">Piilota YouTube Doodlet</string>
|
||||
<string name="revanced_hide_doodles_summary_on">Logon YouTube Doodles -animaatio on piilotettu</string>
|
||||
<string name="revanced_hide_doodles_summary_off">Logon YouTube Doodles -animaatio näytetään</string>
|
||||
<string name="revanced_hide_doodles_user_dialog_message">"YouTube Doodlet näkyvät muutamana päivänä vuodessa.
|
||||
|
||||
Jos Doodle näkyy tällä hetkellä alueellasi ja tämä piilotusasetus on käytössä, myös hakupalkin alla oleva suodatinpalkki piilotetaan."</string>
|
||||
@@ -208,10 +224,18 @@ Jos Doodle näkyy tällä hetkellä alueellasi ja tämä piilotusasetus on käyt
|
||||
<!-- 'Join' should be translated using the same localized wording YouTube displays.
|
||||
This appears in the video player for certain videos. -->
|
||||
<string name="revanced_hide_join_membership_button_title">Piilota Liity-painike</string>
|
||||
<string name="revanced_hide_join_membership_button_summary_on">Liity-painike on piilotettu</string>
|
||||
<string name="revanced_hide_join_membership_button_summary_off">Liity-painike näytetään</string>
|
||||
<string name="revanced_hide_medical_panels_title">Piilota lääketieteelliset paneelit</string>
|
||||
<string name="revanced_hide_medical_panels_summary_on">Lääketieteelliset paneelit on piilotettu</string>
|
||||
<string name="revanced_hide_medical_panels_summary_off">Lääketieteelliset paneelit näytetään</string>
|
||||
<string name="revanced_hide_subscribers_community_guidelines_title">Piilota tilaajien ohjeet</string>
|
||||
<string name="revanced_hide_quick_actions_title">Piilota pikatoiminnot</string>
|
||||
<string name="revanced_hide_quick_actions_summary_on">Pikatoiminnot on piilotettu kokoruututilassa</string>
|
||||
<string name="revanced_hide_quick_actions_summary_off">Pikatoiminnot näytetään kokoruututilassa</string>
|
||||
<string name="revanced_hide_related_videos_title">Piilota liittyvät videot</string>
|
||||
<string name="revanced_hide_related_videos_summary_on">Liittyvät videot on piilotettu pikatoiminnoissa</string>
|
||||
<string name="revanced_hide_related_videos_summary_off">Liittyvät videot näytetään pikatoiminnoissa</string>
|
||||
<string name="revanced_hide_subscribers_community_guidelines_title">Piilota tilaajien säännöt</string>
|
||||
<string name="revanced_hide_subscribers_community_guidelines_summary_on">Tilaajien yhteisön säännöt on piilotettu</string>
|
||||
<string name="revanced_hide_subscribers_community_guidelines_summary_off">Tilaajien yhteisön säännöt näytetään</string>
|
||||
<string name="revanced_hide_timed_reactions_title">Piilota ajoitetut reaktiot</string>
|
||||
@@ -260,11 +284,26 @@ Jos Doodle näkyy tällä hetkellä alueellasi ja tämä piilotusasetus on käyt
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_title">Piilota liittyvissä videoissa</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_on">Piilotettu liittyvissä videoissa</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">Näytetään liittyvissä videoissa</string>
|
||||
<string name="revanced_channel_screen_title">Kanavasivu</string>
|
||||
<string name="revanced_channel_screen_summary">Piilota tai näytä kanavasivun osia</string>
|
||||
<!-- 'For You' should be translated using the same localized wording YouTube displays. -->
|
||||
<string name="revanced_hide_for_you_shelf_title">Piilota \"\'Sinulle\" -hylly</string>
|
||||
<string name="revanced_hide_for_you_shelf_summary_on">Sinulle-hylly on piilotettu</string>
|
||||
<string name="revanced_hide_for_you_shelf_summary_off">Sinulle-hylly näytetään</string>
|
||||
<string name="revanced_hide_links_preview_title">Piilota linkkien esikatselu</string>
|
||||
<string name="revanced_hide_links_preview_summary_on">Linkkien esikatselu on piilotettu</string>
|
||||
<string name="revanced_hide_links_preview_summary_off">Linkkien esikatselu näytetään</string>
|
||||
<string name="revanced_hide_members_shelf_title">Piilota jäsenhylly</string>
|
||||
<string name="revanced_hide_members_shelf_summary_on">Jäsenhylly on piilotettu</string>
|
||||
<string name="revanced_hide_members_shelf_summary_off">Jäsenhylly näytetään</string>
|
||||
<!-- 'Visit Community' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_visit_community_button_title">Piilota \"Tutustu yhteisöön\" -painike</string>
|
||||
<string name="revanced_hide_visit_community_button_summary_on">\"Tutustu yhteisöön\" -painike on piilotettu</string>
|
||||
<string name="revanced_hide_visit_community_button_summary_off">\"Tutustu yhteisöön\" -painike näytetään</string>
|
||||
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_visit_store_button_title">Piilota \"Vieraile kaupassa\" -painike kanavasivuilla</string>
|
||||
<string name="revanced_hide_visit_store_button_summary_on">Kaupan \"Näytä kaikki\" -painike on piilotettu</string>
|
||||
<string name="revanced_hide_visit_store_button_summary_off">Kaupan \"Näytä kaikki\" -painike näytetään</string>
|
||||
<string name="revanced_comments_screen_title">Kommentit</string>
|
||||
<string name="revanced_comments_screen_summary">Piilota tai näytä kommenttiosion osia</string>
|
||||
<string name="revanced_hide_comments_ai_chat_summary_title">Piilota tekoälyn luoma chat-yhteenveto</string>
|
||||
@@ -273,12 +312,18 @@ Jos Doodle näkyy tällä hetkellä alueellasi ja tämä piilotusasetus on käyt
|
||||
<string name="revanced_hide_comments_ai_summary_title">Piilota tekoälyn luoma kommenttiyhteenveto</string>
|
||||
<string name="revanced_hide_comments_ai_summary_summary_on">Kommenttien yhteenveto on piilotettu</string>
|
||||
<string name="revanced_hide_comments_ai_summary_summary_off">Kommenttien yhteenveto näytetään</string>
|
||||
<string name="revanced_hide_comments_channel_guidelines_title">Piilota kanavan säännöt</string>
|
||||
<string name="revanced_hide_comments_channel_guidelines_summary_on">Kanavan säännöt on piilotettu</string>
|
||||
<string name="revanced_hide_comments_channel_guidelines_summary_off">Kanavan säännöt näytetään</string>
|
||||
<string name="revanced_hide_comments_by_members_header_title">Piilota \"Jäsenten kommentit\" -ylätunniste</string>
|
||||
<string name="revanced_hide_comments_by_members_header_summary_on">Jäsenten kommentit -ylätunniste on piilotettu</string>
|
||||
<string name="revanced_hide_comments_by_members_header_summary_off">Jäsenten kommentit -ylätunniste näytetään</string>
|
||||
<string name="revanced_hide_comments_section_title">Piilota kommenttiosio</string>
|
||||
<string name="revanced_hide_comments_section_summary_on">Kommenttiosio on piilotettu</string>
|
||||
<string name="revanced_hide_comments_section_summary_off">Kommenttiosio näytetään</string>
|
||||
<string name="revanced_hide_comments_community_guidelines_title">Piilota yhteisön säännöt</string>
|
||||
<string name="revanced_hide_comments_community_guidelines_summary_on">Yhteisön säännöt on piilotettu</string>
|
||||
<string name="revanced_hide_comments_community_guidelines_summary_off">Yhteisön säännöt näytetään</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_title">Piilota \"Luo Shorts-video\" -painike</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_summary_on">Luo Shorts-video -painike on piilotettu</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_summary_off">Luo Shorts-video -painike näytetään</string>
|
||||
@@ -288,6 +333,7 @@ Jos Doodle näkyy tällä hetkellä alueellasi ja tämä piilotusasetus on käyt
|
||||
<string name="revanced_hide_comments_thanks_button_title">Piilota Kiitos-painike</string>
|
||||
<string name="revanced_hide_comments_thanks_button_summary_on">Kiitos-painike on piilotettu</string>
|
||||
<string name="revanced_hide_comments_thanks_button_summary_off">Kiitos-painike näytetään</string>
|
||||
<string name="revanced_hide_comments_timestamp_button_title">Piilota aikaleima-painike</string>
|
||||
<string name="revanced_hide_comments_timestamp_button_summary_on">Aikaleimapainike on piilotettu</string>
|
||||
<string name="revanced_hide_comments_timestamp_button_summary_off">Aikaleimapainike näytetään</string>
|
||||
<string name="revanced_custom_filter_screen_title">Mukautettu suodatin</string>
|
||||
@@ -336,7 +382,12 @@ Rajoitukset
|
||||
<string name="revanced_hide_keyword_toast_invalid_broad">Avainsana piilottaa kaikki videot: %s</string>
|
||||
</patch>
|
||||
<patch id="ad.general.hideAdsResourcePatch">
|
||||
<string name="revanced_hide_creator_store_shelf_title">Piilota sisällöntuottajan kauppahylly</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">Sisällöntuottajan kauppahylly videosoittimen alla on piilotettu</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">Sisällöntuottajan kauppahylly videosoittimen alla näytetään</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">Piilota loppunäytön kauppabanneri</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_on">Loppunäytön kauppabanneri on piilotettu</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_off">Loppunäytön kauppabanneri näytetään</string>
|
||||
<string name="revanced_hide_fullscreen_ads_title">Piilota koko näytön mainokset</string>
|
||||
<string name="revanced_hide_fullscreen_ads_summary_on">"Koko näytön mainokset on piilotettu
|
||||
|
||||
@@ -356,7 +407,13 @@ Tämä ominaisuus on käytettävissä vain vanhemmilla laitteilla"</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_title">Piilota itse-sponsoroidut kortit</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_on">Itse-sponsoroidut kortit ovat piilotettu</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_off">Itse-sponsoroidut kortit näytetään</string>
|
||||
<string name="revanced_hide_shopping_links_title">Piilota ostoslinkit</string>
|
||||
<string name="revanced_hide_shopping_links_summary_on">Ostoslinkit videon kuvauksessa on piilotettu</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">Ostoslinkit videon kuvauksessa näytetään</string>
|
||||
<!-- 'View products' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_view_products_banner_title">Piilota \"Näytä tuotteet\" -banneri</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_on">Videon peittokuvan tuotebannerit on piilotettu</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_off">Videon peittokuvan tuotebannerit näytetään</string>
|
||||
<string name="revanced_hide_web_search_results_title">Piilota verkkohakutulokset</string>
|
||||
<string name="revanced_hide_web_search_results_summary_on">Verkkohakutulokset on piilotettu</string>
|
||||
<string name="revanced_hide_web_search_results_summary_off">Verkkohakutulokset näytetään</string>
|
||||
@@ -387,6 +444,8 @@ Tämä ominaisuus on käytettävissä vain vanhemmilla laitteilla"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Valintaikkuna näytetään</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Tämä ei ohita ikärajoitusta. Se vain hyväksyy sen automaattisesti.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Ulkoiset lataukset</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Asetukset ulkoisen lataajan käyttämiselle</string>
|
||||
@@ -628,9 +687,6 @@ Jos haluat nähdä sen, aseta \"Naamioi videovirrat\" iOS TV:ksi"</string>
|
||||
<string name="revanced_hide_cast_button_title">Piilota Cast-painike</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Cast-painike on piilotettu</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Cast-painike näytetään</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Piilota soittimen ohjauspainikkeiden tausta</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Soittimen ohjauspainikkeiden tausta on piilotettu</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Soittimen ohjauspainikkeiden tausta näytetään</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Piilota Edellinen & Seuraava -painikkeet</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Painikkeet on piilotettu</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Painikkeet näytetään</string>
|
||||
@@ -667,7 +723,13 @@ Jos haluat nähdä sen, aseta \"Naamioi videovirrat\" iOS TV:ksi"</string>
|
||||
<string name="revanced_shorts_player_screen_title">Shorts-soitin</string>
|
||||
<string name="revanced_shorts_player_screen_summary">Piilota tai näytä Shorts-soittimen osia</string>
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the Home tab. -->
|
||||
<string name="revanced_hide_shorts_home_title">Piilota Shortsit kotisyötteessä</string>
|
||||
<string name="revanced_hide_shorts_home_summary_on">Piilotettu kotisyötteessä ja liittyvissä videoissa</string>
|
||||
<string name="revanced_hide_shorts_home_summary_off">Näytetään kotisyötteessä ja liittyvissä videoissa</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the Subscriptions tab. -->
|
||||
<string name="revanced_hide_shorts_subscriptions_title">Piilota Shortsit Tilaukset-syötteessä</string>
|
||||
<string name="revanced_hide_shorts_subscriptions_summary_on">Piilotettu tilaukset-syötteessä</string>
|
||||
<string name="revanced_hide_shorts_subscriptions_summary_off">Näytetään tilaukset-syötteessä</string>
|
||||
<string name="revanced_hide_shorts_search_title">Piilota Shortsit hakutuloksissa</string>
|
||||
<string name="revanced_hide_shorts_search_summary_on">Piilotettu hakutuloksissa</string>
|
||||
<string name="revanced_hide_shorts_search_summary_off">Näytetään hakutuloksissa</string>
|
||||
@@ -675,6 +737,8 @@ Jos haluat nähdä sen, aseta \"Naamioi videovirrat\" iOS TV:ksi"</string>
|
||||
<string name="revanced_hide_shorts_history_summary_on">Piilotettu katseluhistoriassa</string>
|
||||
<string name="revanced_hide_shorts_history_summary_off">Näytetään katseluhistoriassa</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_title">Piilota Osta Superkiitos -painike</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_on">Osta Superkiitos -painike on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_off">Osta Superkiitos -painike näytetään</string>
|
||||
<string name="revanced_hide_shorts_effect_button_title">Piilota Tehoste-painike</string>
|
||||
<string name="revanced_hide_shorts_effect_button_summary_on">Tehoste-painike on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_effect_button_summary_off">Tehoste-painike näytetään</string>
|
||||
@@ -706,9 +770,9 @@ Jos haluat nähdä sen, aseta \"Naamioi videovirrat\" iOS TV:ksi"</string>
|
||||
<string name="revanced_hide_shorts_search_suggestions_title">Piilota hakuehdotukset</string>
|
||||
<string name="revanced_hide_shorts_search_suggestions_summary_on">Hakuehdotukset on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_search_suggestions_summary_off">Hakuehdotukset näytetään</string>
|
||||
<string name="revanced_hide_shorts_shop_button_title">Piilota Shopping-painike</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_on">Shopping-painike on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_off">Shopping-painike näytetään</string>
|
||||
<string name="revanced_hide_shorts_shop_button_title">Piilota Kauppa-painike</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_on">Kauppa-painike on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_off">Kauppa-painike näytetään</string>
|
||||
<string name="revanced_hide_shorts_stickers_title">Piilota tarrat</string>
|
||||
<string name="revanced_hide_shorts_stickers_summary_on">Tarrat on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_stickers_summary_off">Tarrat näytetään</string>
|
||||
@@ -757,7 +821,12 @@ Jos haluat nähdä sen, aseta \"Naamioi videovirrat\" iOS TV:ksi"</string>
|
||||
<string name="revanced_hide_shorts_channel_bar_summary_on">Kanavapalkki on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_channel_bar_summary_off">Kanavapalkki näytetään</string>
|
||||
<string name="revanced_hide_shorts_video_title_title">Piilota videon otsikko</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_on">Videon otsikko on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_off">Videon otsikko näytetään</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_title">Piilota äänen metadata-tunniste</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_summary_on">Äänen metatietojen tunniste on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_summary_off">Äänen metatietojen tunniste näytetään</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_title">Piilota videolinkin tunniste</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_summary_on">Videolinkin tunniste on piilotettu</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_summary_off">Videolinkin tunniste näytetään</string>
|
||||
<string name="revanced_hide_shorts_navigation_bar_title">Piilota navigointipalkki</string>
|
||||
@@ -773,6 +842,9 @@ Asetukset → Toisto → Toista seuraava video automaattisesti"</string>
|
||||
<string name="revanced_end_screen_suggested_video_summary_off">Loppunäytön ehdotettu video näytetään</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.relatedvideooverlay.hideRelatedVideoOverlayPatch">
|
||||
<string name="revanced_hide_related_videos_overlay_title">Piilota liittyvät videot -peittokuva</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">Liittyvät videot -peittokuva on piilotettu kokoruututilassa</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_off">Liittyvät videot -peittokuva näytetään kokoruututilassa</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.time.hideTimestampPatch">
|
||||
<string name="revanced_hide_timestamp_title">Piilota videon aikaleima</string>
|
||||
@@ -885,7 +957,13 @@ Tämä ominaisuus toimii parhaiten, kun videon laatu on 720p tai alhaisempi ja k
|
||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button">Piilota ohita-painike automaattisesti</string>
|
||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_on">Ohita-painike piiloutuu muutaman sekunnin kuluttua</string>
|
||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_off">Ohita-painike näytetään koko osion ajan</string>
|
||||
<string name="revanced_sb_auto_hide_skip_button_duration">Ohita-painikkeen kesto</string>
|
||||
<string name="revanced_sb_auto_hide_skip_button_duration_sum">Kuinka kauan ohita- ja ohita-kohokohtaan-painikkeita näytetään ennen automaattista piilottamista</string>
|
||||
<string name="revanced_sb_general_skiptoast">Näytä kumoa ohitus -ponnahdusilmoitus</string>
|
||||
<string name="revanced_sb_general_skiptoast_sum_on">Ponnahdusilmoitus näytetään, kun osio ohitetaan automaattisesti. Napauta ponnahdusilmoitusta kumotaksesi ohituksen</string>
|
||||
<string name="revanced_sb_general_skiptoast_sum_off">Ponnahdusilmoitusta ei näytetä</string>
|
||||
<string name="revanced_sb_toast_on_skip_duration">Ohita-ponnahdusilmoituksen kesto</string>
|
||||
<string name="revanced_sb_toast_on_skip_duration_sum">Kuinka kauan kumoa ohitus -ponnahdusilmoitus näytetään</string>
|
||||
<string name="revanced_sb_duration_1s">1 sekunti</string>
|
||||
<string name="revanced_sb_duration_2s">2 sekuntia</string>
|
||||
<string name="revanced_sb_duration_3s">3 sekuntia</string>
|
||||
@@ -1215,7 +1293,12 @@ Minisoitin voidaan vetää pois näytöltä vasemmalle tai oikealle"</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Virheellinen etenemispalkin väriarvo</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Ylätunnisteen logo</string>
|
||||
<string name="revanced_header_logo_entry_1">Oletus</string>
|
||||
<string name="revanced_header_logo_entry_2">Tavallinen</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced-minimaalinen</string>
|
||||
<string name="revanced_header_logo_entry_6">Mukautettu</string>
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
|
||||
<string name="revanced_bypass_image_region_restrictions_title">Ohita kuvien alueelliset rajoitukset</string>
|
||||
@@ -1228,8 +1311,10 @@ Tämä voi korjata puuttuvat kuvat, jotka on estetty tietyillä alueilla"</strin
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the Home tab. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">Koti-välilehti</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the Subscriptions tab. -->
|
||||
<string name="revanced_alt_thumbnail_subscription_title">Tilaukset-välilehti</string>
|
||||
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (Library) tab. -->
|
||||
<string name="revanced_alt_thumbnail_library_title">Sinä-välilehti</string>
|
||||
<string name="revanced_alt_thumbnail_player_title">Soittimen soittolistat ja suositukset</string>
|
||||
<string name="revanced_alt_thumbnail_search_title">Hakutulokset</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_1">Alkuperäiset pikkukuvat</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_2">Alkuperäiset ja DeArrow-pikkukuvat</string>
|
||||
@@ -1446,6 +1531,7 @@ AVC:n maksimiresoluutio on 1080p, Opus-äänikoodekki ei ole käytettävissä, j
|
||||
<string name="revanced_block_video_ads_summary_off">Videomainoksia ei estetä</string>
|
||||
</patch>
|
||||
<patch id="chat.antidelete.showDeletedMessagesPatch">
|
||||
<string name="revanced_deleted_msg">Viesti poistettiin</string>
|
||||
<string name="revanced_show_deleted_messages_title">Näytä poistetut viestit</string>
|
||||
<string name="revanced_show_deleted_messages_entry_1">Älä näytä poistettuja viestejä</string>
|
||||
<string name="revanced_show_deleted_messages_entry_2">Piilota poistetut viestit spoilereilla</string>
|
||||
@@ -1466,6 +1552,8 @@ AVC:n maksimiresoluutio on 1080p, Opus-äänikoodekki ei ole käytettävissä, j
|
||||
<string name="revanced_settings">ReVanced-asetukset</string>
|
||||
<string name="revanced_about_title">Tietoja</string>
|
||||
<string name="revanced_about_summary">Tietoja ReVancedista</string>
|
||||
<string name="revanced_ads_screen_title">Mainostenesto</string>
|
||||
<string name="revanced_ads_screen_summary">Mainostenestoasetukset</string>
|
||||
<string name="revanced_chat_screen_title">Chat</string>
|
||||
<string name="revanced_chat_screen_summary">Chat-asetukset</string>
|
||||
<string name="revanced_misc_screen_title">Sekalaiset</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Ang tampok na ito ay magagamit lamang para sa mga mas lumang device"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Ipapakita ang dialog</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Hindi nito nilalampasan ang paghihigpit sa edad. Awtomatiko lang itong tinatanggap.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Huwag paganahin ang paglaktaw ng kabanata sa doble tap</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Ang doble tap ay hindi kailanman maaaring mag-trigger ng paglaktaw sa susunod/nakaraang kabanata</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Ang doble tap ay paminsan-minsan ay maaaring mag-trigger ng paglaktaw sa susunod/nakaraang kabanata</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Mga panlabas na pag-download</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Mga setting para sa paggamit ng external na downloader</string>
|
||||
@@ -695,9 +700,9 @@ Upang ipakita ang menu ng Audio track, baguhin ang 'Spoof video streams' sa iOS
|
||||
<string name="revanced_hide_cast_button_title">Itago ang Cast button</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Ang buton ng Cast ay nakatago</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Nakikita ang cast button</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Itago ang background ng mga button ng kontrol ng player</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Nakatago ang background ng mga button ng kontrol ng player</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Ipinapakita ang background ng mga button ng kontrol ng player</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Itago ang background ng mga kontrol ng manlalaro</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Nakatago ang background ng mga kontrol ng manlalaro</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Ipinapakita ang background ng mga kontrol ng manlalaro</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Itago ang Nakaraan at Susunod na mga pindutan</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Nakatago ang mga pindutan</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Ang mga pindutan ay ipinapakita</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Cette fonctionnalité est disponible uniquement pour les appareils anciens"</str
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Le message sera affiché</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Cette option ne contourne pas la vérification de l\'âge. Elle est juste confirmée automatiquement.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Désactiver le double appui pour sauter les chapitres</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Le double appui ne peut jamais déclencher un saut au chapitre suivant/précédent</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Le double appui peut occasionnellement déclencher un saut au chapitre suivant/précédent</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Téléchargements externes</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Paramètres pour l\'utilisation d\'un outil externe de téléchargement</string>
|
||||
@@ -570,7 +575,7 @@ Réglez le volume en balayant verticalement sur le côté droit de l'écran"</st
|
||||
<string name="revanced_hide_thanks_button_summary_off">Le bouton Merci est affiché</string>
|
||||
<!-- 'Ask' should be translated with the same localized wording that YouTube displays.
|
||||
This button only shows up if the user ip is from specific region such as the USA or EU. -->
|
||||
<string name="revanced_hide_ask_button_title">Masquer Demander</string>
|
||||
<string name="revanced_hide_ask_button_title">Masquer \"Demander\"</string>
|
||||
<string name="revanced_hide_ask_button_summary_on">Le bouton Demander est masqué</string>
|
||||
<string name="revanced_hide_ask_button_summary_off">Le bouton Demander est affiché</string>
|
||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||
@@ -697,9 +702,9 @@ Pour afficher le menu Piste audio, définissez \"Falsifier les flux vidéo\" sur
|
||||
<string name="revanced_hide_cast_button_title">Masquer le bouton Caster</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Le bouton Caster est masqué</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Le bouton Caster est affiché</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Masquer l\'arrière-plan des boutons de commande du lecteur</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">L\'arrière-plan des boutons de commande du lecteur est masqué</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">L\'arrière-plan des boutons de commande du lecteur est affiché</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Masquer l\'arrière-plan des commandes du lecteur</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">L\'arrière-plan des commandes du lecteur est masqué</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">L\'arrière-plan des commandes du lecteur est affiché</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Masquer les boutons Précédent et Suivant</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Les boutons sont masqués</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Les boutons sont affichés</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Níl an ghné seo ar fáil ach do ghléasanna níos sine"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Taispeánfar dialóg</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Ní sheachnaíonn sé seo an srian aoise. Ní ghlacann sé leis go huathoibríoch.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Díchumasaigh scipeáil caibidle le sconna dúbailte</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Ní féidir le sconna dúbailte scipeáil chuig an gcéad chaibidil eile/roimhe seo a spreagadh go deo</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Is féidir le sconna dúbailte scipeáil chuig an gcéad chaibidil eile/roimhe seo a spreagadh ó am go chéile</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Íosluchtaigh seachtracha</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Socruithe chun íoslódálaí seachtrach a úsáid</string>
|
||||
@@ -697,9 +702,9 @@ Chun roghchlár na rian fuaime a thaispeáint, athraigh 'Srutháin físeáin bhr
|
||||
<string name="revanced_hide_cast_button_title">Folaigh cnaipe an Chasta</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Tá cnaipe teilgthe i bhfolach</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Taispeántar cnaipe teilgthe</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Folaigh cúlra cnaipí rialaithe an tseinnteora</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Tá cúlra cnaipí rialaithe an tseinnteora folaithe</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Taispeántar cúlra cnaipí rialaithe an tseinnteora</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Folaigh cúlra rialuithe an imreora</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Tá cúlra rialuithe an imreora i bhfolach</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Taispeántar cúlra rialuithe an imreora</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Folaigh Cnaipí Roimhe & Ar Aghaidh</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Tá cnaipí i bhfolach</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Taispeántar cnaipí</string>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -453,6 +453,11 @@ Ez a funkció csak régebbi eszközökön érhető el"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">A párbeszédpanel megjelenik</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Ez nem kerüli meg a korhatárt, csak automatikusan elfogadja.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Dupla koppintásos fejezetátugrás letiltása</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">A dupla koppintás soha nem indíthatja el a következő/előző fejezetre való ugrást</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">A dupla koppintás alkalmanként elindíthatja a következő/előző fejezetre való ugrást</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Külső letöltések</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Beállítások külső letöltő használatához</string>
|
||||
@@ -697,9 +702,9 @@ Az audiosáv menü megjelenítéséhez módosítsa a \"Videófolyamok hamisítá
|
||||
<string name="revanced_hide_cast_button_title">Küldés gomb elrejtése</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Az átküldés gomb rejtve van</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Az átküldés gomb látható</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">A lejátszó vezérlőgombjainak hátterének elrejtése</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">A lejátszó vezérlőgombjainak háttere rejtve</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">A lejátszó vezérlőgombjainak háttere látható</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Lejátszóvezérlők hátterének elrejtése</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">A lejátszóvezérlők háttere rejtett</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">A lejátszóvezérlők háttere látható</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Az Előző és a Következő gombok elrejtése</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">A gombok elrejtve</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">A gombok megjelennek</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ MicroG-ի համար մարտկոցի օպտիմալացումը անջատել
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Զրույցը կցուցադրվի</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Սա չի խուսափում տարիքային սահմանափակումից։ Այն պարզապես ավտոմատ կերպով ընդունում է այն։</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Անջատել կրկնակի հպումով գլուխը բաց թողնելը</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Կրկնակի հպումը երբեք չի կարող առաջացնել հաջորդ/նախորդ գլուխն անցնելը</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Կրկնակի հպումը երբեմն կարող է առաջացնել հաջորդ/նախորդ գլուխն անցնելը</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Արտաքին ներբեռնումներ</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Արտաքին ներբեռնող օգտագործելու համար կարգավորումներ</string>
|
||||
@@ -697,9 +702,9 @@ MicroG-ի համար մարտկոցի օպտիմալացումը անջատել
|
||||
<string name="revanced_hide_cast_button_title">Թաքցնել Cast կոճակը</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Թափոնելու կոճակը թաքցված է</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Թափոնելու կոճակը երևում է</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Թաքցնել նվագարկչի կառավարման կոճակների ֆոնը</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Նվագարկչի կառավարման կոճակների ֆոնը թաքնված է</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Նվագարկչի կառավարման կոճակների ֆոնը ցուցադրվում է</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Թաքցնել նվագարկչի կառավարման վահանակի ֆոնը</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Նվագարկչի կառավարման վահանակի ֆոնը թաքնված է</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Նվագարկչի կառավարման վահանակի ֆոնը ցուցադրվում է</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Թաքցնել \"Նախորդ\" և \"Հաջորդ\" կոճակները</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Կոճակները թաքցված են</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Կոճակները երևում են</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Fitur ini hanya tersedia untuk perangkat yang lebih lama"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Dialog akan ditampilkan</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Ini tidak mengabaikan batasan usia. Ini hanya menerimanya secara otomatis.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Nonaktifkan lewati bab dengan ketuk dua kali</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Ketuk dua kali tidak akan pernah memicu lewati ke bab berikutnya/sebelumnya</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Ketuk dua kali terkadang dapat memicu lewati ke bab berikutnya/sebelumnya</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Unduhan eksternal</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Pengaturan untuk menggunakan pengunduh eksternal</string>
|
||||
@@ -697,9 +702,9 @@ Untuk menampilkan menu trek Audio, ubah 'Spoof aliran video' ke iOS TV"</string>
|
||||
<string name="revanced_hide_cast_button_title">Sembunyikan tombol Transmisi</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Tombol transmisi disembunyikan</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Tombol transmisi ditampilkan</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Sembunyikan latar belakang tombol kontrol pemutar</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Latar belakang tombol kontrol pemutar disembunyikan</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Latar belakang tombol kontrol pemutar ditampilkan</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Sembunyikan latar belakang kontrol pemutar</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Latar belakang kontrol pemutar disembunyikan</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Latar belakang kontrol pemutar ditampilkan</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Sembunyikan tombol Sebelumnya & Berikutnya</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">Tombol disembunyikan</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">Tombol ditampilkan</string>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -453,6 +453,11 @@ Questa funzione è disponibile solo per i dispositivi più vecchi"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">La finestra di dialogo verrà mostrata </string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Questo non aggira la restrizione di età. Lo accetta solo automaticamente.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">Disabilita salto capitolo con doppio tocco</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">Il doppio tocco non può mai attivare il salto al capitolo successivo/precedente</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">Il doppio tocco può occasionalmente attivare il salto al capitolo successivo/precedente</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Download esterni</string>
|
||||
<string name="revanced_external_downloader_screen_summary">Impostazioni per l\'utilizzo di un downloader esterno</string>
|
||||
@@ -697,9 +702,9 @@ Per mostrare il menu della traccia audio, cambia \"Spoof video streams\" in iOS
|
||||
<string name="revanced_hide_cast_button_title">Nascondi il pulsante Trasmetti</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Il pulsante Trasmetti è nascosto</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Il pulsante Trasmetti è visibile</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Nascondi sfondo dei pulsanti di controllo del player</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Lo sfondo dei pulsanti di controllo del player è nascosto</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Lo sfondo dei pulsanti di controllo del player è mostrato</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">Nascondi lo sfondo dei controlli del player</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">Lo sfondo dei controlli del player è nascosto</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">Lo sfondo dei controlli del player è mostrato</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">Nascondi i pulsanti Precedente e Successivo</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">I pulsanti sono nascosti</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">I pulsanti sono visibili</string>
|
||||
|
||||
@@ -453,6 +453,11 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">דו-שיח יוצג</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">זה לא עוקף את מגבלת הגיל. זה רק מסכים לזה באופן אוטומטי.</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">ביטול דילוג פרקים בלחיצה כפולה</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">לחיצה כפולה לעולם לא תפעיל דילוג לפרק הבא/הקודם</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">לחיצה כפולה יכולה להפעיל מדי פעם דילוג לפרק הבא/הקודם</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">הורדות חיצוניות</string>
|
||||
<string name="revanced_external_downloader_screen_summary">הגדרות לשימוש במוריד חיצונית</string>
|
||||
@@ -697,9 +702,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_cast_button_title">הסתר לחצן העברה</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">לחצן העברה מוסתר</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">לחצן העברה מוצג</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">הסתר רקע של לחצני שליטה בנגן</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">רקע לחצני השליטה בנגן מוסתר</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">רקע לחצני השליטה בנגן מוצג</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">הסתר רקע פקדי נגן</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">רקע פקדי הנגן מוסתר</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">רקע פקדי הנגן מוצג</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">הסתר לחצני הקודם & הבא</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">הלחצנים מוסתרים</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">הלחצנים מוצגים</string>
|
||||
|
||||
@@ -33,7 +33,7 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsResourcePatch">
|
||||
<string name="revanced_settings_submenu_title">設定</string>
|
||||
<string name="revanced_settings_confirm_user_dialog_title">本当に続行しますか?</string>
|
||||
<string name="revanced_settings_confirm_user_dialog_title">続行してもよろしいですか?</string>
|
||||
<string name="revanced_settings_reset">リセット</string>
|
||||
<string name="revanced_settings_reset_color">色をリセット</string>
|
||||
<string name="revanced_settings_color_invalid">色の値が無効です</string>
|
||||
@@ -174,7 +174,7 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
<string name="revanced_hide_horizontal_shelves_title">横スクロール欄を非表示</string>
|
||||
<string name="revanced_hide_horizontal_shelves_summary_on">"横スクロール欄は表示されません
|
||||
例:
|
||||
・緊急ニュース
|
||||
・ニュース速報
|
||||
・続きを見る
|
||||
・他のチャンネルを探す
|
||||
・関連が強い
|
||||
@@ -301,9 +301,9 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
<string name="revanced_hide_for_you_shelf_title">「おすすめ」欄を非表示</string>
|
||||
<string name="revanced_hide_for_you_shelf_summary_on">「おすすめ」欄は表示されません</string>
|
||||
<string name="revanced_hide_for_you_shelf_summary_off">「おすすめ」欄は表示されます</string>
|
||||
<string name="revanced_hide_links_preview_title">リンク プレビューを非表示</string>
|
||||
<string name="revanced_hide_links_preview_summary_on">リンク プレビューは表示されません</string>
|
||||
<string name="revanced_hide_links_preview_summary_off">リンク プレビューは表示されます</string>
|
||||
<string name="revanced_hide_links_preview_title">リンク集のプレビューを非表示</string>
|
||||
<string name="revanced_hide_links_preview_summary_on">リンク集のプレビューは表示されません</string>
|
||||
<string name="revanced_hide_links_preview_summary_off">リンク集のプレビューは表示されます</string>
|
||||
<string name="revanced_hide_members_shelf_title">メンバー欄を非表示</string>
|
||||
<string name="revanced_hide_members_shelf_summary_on">メンバー欄は表示されません</string>
|
||||
<string name="revanced_hide_members_shelf_summary_off">メンバー欄は表示されます</string>
|
||||
@@ -394,8 +394,8 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
</patch>
|
||||
<patch id="ad.general.hideAdsResourcePatch">
|
||||
<string name="revanced_hide_creator_store_shelf_title">クリエイターのストア欄を非表示</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">動画プレーヤー下のクリエイターのストア欄は表示されません</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">動画プレーヤー下のクリエイターのストア欄は表示されます</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_on">動画プレーヤー下にあるクリエイターのストア欄は表示されません</string>
|
||||
<string name="revanced_hide_creator_store_shelf_summary_off">動画プレーヤー下にあるクリエイターのストア欄は表示されます</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">終了画面のストアバナーを非表示</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_on">終了画面のストアバナーは表示されません</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_off">終了画面のストアバナーは表示されます</string>
|
||||
@@ -412,17 +412,17 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
<string name="revanced_hide_merchandise_banners_title">商品バナーを非表示</string>
|
||||
<string name="revanced_hide_merchandise_banners_summary_on">商品バナーは表示されません</string>
|
||||
<string name="revanced_hide_merchandise_banners_summary_off">商品バナーは表示されます</string>
|
||||
<string name="revanced_hide_paid_promotion_label_title">「プロモーションを含みます」ボタンを非表示</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_on">プレーヤー画面の「プロモーションを含みます」ボタンは表示されません</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_off">プレーヤー画面の「プロモーションを含みます」ボタンは表示されます</string>
|
||||
<string name="revanced_hide_paid_promotion_label_title">「プロモーションを含みます」ラベルを非表示</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_on">「プロモーションを含みます」ラベルは表示されません</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_off">「プロモーションを含みます」ラベルは表示されます</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_title">自己スポンサー カードを非表示</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_on">自己スポンサー カードは表示されません</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_off">自己スポンサー カードは表示されます</string>
|
||||
<string name="revanced_hide_shopping_links_title">商品へのリンクを非表示</string>
|
||||
<string name="revanced_hide_shopping_links_summary_on">動画の概要欄の商品へのリンクは表示されません</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">動画の概要欄の商品へのリンクは表示されます</string>
|
||||
<string name="revanced_hide_shopping_links_summary_on">動画の概要欄にある商品へのリンクは表示されません</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">動画の概要欄にある商品へのリンクは表示されます</string>
|
||||
<!-- 'View products' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_view_products_banner_title">「商品を表示」ボタンを非表示</string>
|
||||
<string name="revanced_hide_view_products_banner_title">「商品を表示」バナーを非表示</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_on">動画オーバーレイの「商品を表示」バナーは表示されません</string>
|
||||
<string name="revanced_hide_view_products_banner_summary_off">動画オーバーレイの「商品を表示」バナーは表示されます</string>
|
||||
<string name="revanced_hide_web_search_results_title">ウェブ検索結果を非表示</string>
|
||||
@@ -455,6 +455,11 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">ダイアログは表示されます</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">この機能によって年齢制限が回避される訳ではありません。自動的に承認するだけです。</string>
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
<string name="revanced_disable_chapter_skip_double_tap_title">ダブルタップ時のチャプター スキップを無効化</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_on">ダブルタップしたときに、次または前のチャプターへスキップしてしまうことはありません</string>
|
||||
<string name="revanced_disable_chapter_skip_double_tap_summary_off">ダブルタップしたときに、たまに次または前のチャプターへスキップしてしまうことがあります</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">外部ダウンロード</string>
|
||||
<string name="revanced_external_downloader_screen_summary">外部ダウンローダーの設定</string>
|
||||
@@ -533,8 +538,8 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
</patch>
|
||||
<patch id="layout.autocaptions.autoCaptionsPatch">
|
||||
<string name="revanced_disable_auto_captions_title">自動字幕表示を無効化</string>
|
||||
<string name="revanced_disable_auto_captions_summary_on">動画を開いた際の自動字幕表示は、無効です</string>
|
||||
<string name="revanced_disable_auto_captions_summary_off">動画を開いた際の自動字幕表示は、有効です</string>
|
||||
<string name="revanced_disable_auto_captions_summary_on">動画を開いた際の自動字幕表示は無効です</string>
|
||||
<string name="revanced_disable_auto_captions_summary_off">動画を開いた際の自動字幕表示は有効です</string>
|
||||
</patch>
|
||||
<patch id="layout.buttons.action.hideButtonsPatch">
|
||||
<string name="revanced_hide_buttons_screen_title">アクション ボタン</string>
|
||||
@@ -699,9 +704,9 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
<string name="revanced_hide_cast_button_title">キャストボタンを非表示</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">キャストボタンはオーバーレイに表示されません</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">キャストボタンはオーバーレイに表示されます</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">プレーヤーのコントロール ボタンの背景を非表示</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">プレーヤーのコントロール ボタンの背景は表示されません</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">プレーヤーのコントロール ボタンの背景は表示されます</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_title">プレーヤーのコントロールの背景を非表示</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_on">プレーヤーのコントロールの背景は表示されません</string>
|
||||
<string name="revanced_hide_player_control_buttons_background_summary_off">プレーヤーのコントロールの背景は表示されます</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_title">前の動画ボタンと次の動画ボタンを非表示</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_on">前の動画ボタンと次の動画ボタンは表示されません</string>
|
||||
<string name="revanced_hide_player_previous_next_buttons_summary_off">前の動画ボタンと次の動画ボタンは表示されます</string>
|
||||
@@ -868,8 +873,8 @@ GmsCore の電池の最適化を無効にしても、バッテリーの使用に
|
||||
</patch>
|
||||
<patch id="layout.panels.popup.playerPopupPanelsPatch">
|
||||
<string name="revanced_hide_player_popup_panels_title">プレーヤー ポップアップ パネルを非表示</string>
|
||||
<string name="revanced_hide_player_popup_panels_summary_on">動画を開いた際のプレイリストやチャット欄などのプレーヤー ポップアップ パネルは、表示されません</string>
|
||||
<string name="revanced_hide_player_popup_panels_summary_off">動画を開いた際のプレイリストやチャット欄などのプレーヤー ポップアップ パネルは、表示されます</string>
|
||||
<string name="revanced_hide_player_popup_panels_summary_on">動画を開いた際のプレイリストやチャット欄などのプレーヤー ポップアップ パネルは表示されません</string>
|
||||
<string name="revanced_hide_player_popup_panels_summary_off">動画を開いた際のプレイリストやチャット欄などのプレーヤー ポップアップ パネルは表示されます</string>
|
||||
</patch>
|
||||
<patch id="layout.player.fullscreen.exitFullscreenPatch">
|
||||
<string name="revanced_exit_fullscreen_title">再生終了時に全画面表示を解除する</string>
|
||||
@@ -1338,8 +1343,8 @@ Automotive レイアウト
|
||||
|
||||
詳細については、ここをタップしてください"</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_title">API 利用不可時にトーストを表示</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_on">DeArrow が利用できない場合は、トーストが表示されます</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_off">DeArrow が利用できない場合でも、トーストは表示されません</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_on">DeArrow が利用できない場合は、トーストポップアップが表示されます</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_off">DeArrow が利用できない場合でも、トースト ポップアップは表示されません</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_api_url_title">DeArrow API のエンドポイント</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_api_url_summary">DeArrow がサムネイルのキャッシュを取得するエンドポイントの URL</string>
|
||||
<string name="revanced_alt_thumbnail_stills_about_title">静止画サムネイル</string>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
@@ -68,6 +68,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.removeViewerDiscretionDialogPatch">
|
||||
</patch>
|
||||
<patch id="interaction.doubletap.disableChapterSkipDoubleTapPatch">
|
||||
</patch>
|
||||
<patch id="interaction.downloads.downloadsResourcePatch">
|
||||
<!-- 'Download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title'. -->
|
||||
</patch>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user