chore: merge branch dev to main (#321)

This commit is contained in:
oSumAtrIX 2023-02-22 06:49:37 +01:00 committed by GitHub
commit 5ed7170018
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 427 additions and 38 deletions

View File

@ -34,7 +34,7 @@
[
"@saithodev/semantic-release-backmerge",
{
branches: [{from: "main", to: "dev"}],
backmergeBranches: [{"from": "dev", "to": "main"}],
clearWorkspace: true
}
]

View File

@ -1,3 +1,49 @@
# [0.98.0-dev.5](https://github.com/revanced/revanced-integrations/compare/v0.98.0-dev.4...v0.98.0-dev.5) (2023-02-22)
### Features
* **youtube/open-links-directly:** skip every redirect url ([2d73b8b](https://github.com/revanced/revanced-integrations/commit/2d73b8b29b14ab9ce20fa33ea4ebfa66984c5903))
# [0.98.0-dev.4](https://github.com/revanced/revanced-integrations/compare/v0.98.0-dev.3...v0.98.0-dev.4) (2023-02-22)
### Bug Fixes
* remove nullable annotation in Kotlin code ([b5a29fd](https://github.com/revanced/revanced-integrations/commit/b5a29fdce195ab47edd61d1d684def1ac919297c))
# [0.98.0-dev.3](https://github.com/revanced/revanced-integrations/compare/v0.98.0-dev.2...v0.98.0-dev.3) (2023-02-22)
### Bug Fixes
* **twitter:** make `hide-ads` patch compatible with any version ([6655988](https://github.com/revanced/revanced-integrations/commit/665598836abfcead9c5e68ce7831a4137465df39))
### Features
* **twitter:** `hide-recommended-users` patch ([96eea3d](https://github.com/revanced/revanced-integrations/commit/96eea3d4fc096f389840481b146dcf1542cb9c43))
# [0.98.0-dev.2](https://github.com/revanced/revanced-integrations/compare/v0.98.0-dev.1...v0.98.0-dev.2) (2023-02-20)
### Bug Fixes
* **youtube/hide-watch-in-vr:** fix descriptions ([96fcc0b](https://github.com/revanced/revanced-integrations/commit/96fcc0b1c70c277c99a99db9ca2d50f649a41a70))
### Features
* **youtube/general-ads:** hide channel bar ([35c4266](https://github.com/revanced/revanced-integrations/commit/35c4266e8b8ad7cf9fb5d14cf6cbc8ae65cc78df))
* **youtube/general-ads:** hide horizontal video shelf ([fd975ec](https://github.com/revanced/revanced-integrations/commit/fd975ecd2a91ea7ac713d3b7badf373c7d53ad5c))
# [0.98.0-dev.1](https://github.com/revanced/revanced-integrations/compare/v0.97.0...v0.98.0-dev.1) (2023-02-18)
### Features
* **youtube/general-ads:** hide full-screen feed banner ([da1572c](https://github.com/revanced/revanced-integrations/commit/da1572c28d20e2549d0e2a68591f23bb68d8cc9c))
# [0.97.0](https://github.com/revanced/revanced-integrations/compare/v0.96.2...v0.97.0) (2023-02-14)

View File

@ -1,6 +1,3 @@
import java.io.FileInputStream
import java.util.Properties
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
@ -47,7 +44,7 @@ android {
dependencies {
compileOnly(project(mapOf("path" to ":dummy")))
compileOnly("androidx.annotation:annotation:1.5.0")
compileOnly("androidx.appcompat:appcompat:1.5.1")
compileOnly("androidx.appcompat:appcompat:1.6.1")
compileOnly("com.squareup.okhttp3:okhttp:5.0.0-alpha.11")
compileOnly("com.squareup.retrofit2:retrofit:2.9.0")
}

View File

@ -1,13 +1,10 @@
package app.revanced.integrations.patches;
import android.view.View;
import app.revanced.integrations.settings.SettingsEnum;
public class FullscreenPanelsRemoverPatch {
public static int getFullscreenPanelsVisibility() {
return SettingsEnum.HIDE_FULLSCREEN_PANELS.getBoolean() ? View.GONE : View.VISIBLE;
}
}

View File

@ -33,11 +33,13 @@ public final class GeneralAdsPatch extends Filter {
var infoPanel = new BlockRule(SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL, "publisher_transparency_panel", "single_item_information_panel");
var latestPosts = new BlockRule(SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS, "post_shelf");
var channelGuidelines = new BlockRule(SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner");
var artistCard = new BlockRule(SettingsEnum.HIDE_ARTIST_CARD, "official_card");
var artistCard = new BlockRule(SettingsEnum.HIDE_ARTIST_CARDS, "official_card");
var selfSponsor = new BlockRule(SettingsEnum.ADREMOVER_SELF_SPONSOR_REMOVAL, "cta_shelf_card");
var chapterTeaser = new BlockRule(SettingsEnum.ADREMOVER_CHAPTER_TEASER_REMOVAL, "expandable_metadata");
var viewProducts = new BlockRule(SettingsEnum.ADREMOVER_VIEW_PRODUCTS, "product_item", "products_in_video");
var webLinkPanel = new BlockRule(SettingsEnum.ADREMOVER_WEB_SEARCH_RESULTS, "web_link_panel");
var horizontalVideoShelf = new BlockRule(SettingsEnum.ADREMOVER_HORIZONTAL_VIDEO_SHELF, "horizontal_video_shelf");
var channelBar = new BlockRule(SettingsEnum.ADREMOVER_CHANNEL_BAR, "channel_bar");
var graySeparator = new BlockRule(SettingsEnum.ADREMOVER_GRAY_SEPARATOR,
"cell_divider" // layout residue (gray line above the buttoned ad),
);
@ -53,7 +55,9 @@ public final class GeneralAdsPatch extends Filter {
"banner_text_icon",
"square_image_layout",
"watch_metadata_app_promo",
"video_display_full_layout"
"video_display_full_layout",
"hero_promo_image",
"statement_banner"
);
var movieAds = new BlockRule(
SettingsEnum.ADREMOVER_MOVIE_REMOVAL,
@ -67,6 +71,7 @@ public final class GeneralAdsPatch extends Filter {
this.pathRegister.registerAll(
generalAds,
buttonedAd,
channelBar,
communityPosts,
paidContent,
latestPosts,
@ -83,6 +88,7 @@ public final class GeneralAdsPatch extends Filter {
artistCard,
selfSponsor,
webLinkPanel,
horizontalVideoShelf,
subscribersCommunityGuidelines,
channelMemberShelf
);

View File

@ -1,16 +1,15 @@
package app.revanced.integrations.patches;
import android.view.View;
import app.revanced.integrations.settings.SettingsEnum;
public class HideInfocardsPatch {
public static void hideInfocardsIncognito(View view) {
public class HideInfoCardsPatch {
public static void hideInfoCardsIncognito(View view) {
if (!SettingsEnum.HIDE_INFO_CARDS.getBoolean()) return;
view.setVisibility(View.GONE);
}
public static boolean hideInfocardsMethodCall() {
public static boolean hideInfoCardsMethodCall() {
return SettingsEnum.HIDE_INFO_CARDS.getBoolean();
}
}

View File

@ -0,0 +1,9 @@
package app.revanced.integrations.patches;
import app.revanced.integrations.settings.SettingsEnum;
public class HideSeekbarPatch {
public static boolean hideSeekbar() {
return SettingsEnum.HIDE_SEEKBAR.getBoolean();
}
}

View File

@ -1,10 +0,0 @@
package app.revanced.integrations.patches;
import app.revanced.integrations.settings.SettingsEnum;
public class HideTimeAndSeekbarPatch {
//Used by app.revanced.patches.youtube.layout.hidetimeandseekbar.patch.HideTimeAndSeekbarPatch
public static boolean hideTimeAndSeekbar() {
return SettingsEnum.HIDE_TIME_AND_SEEKBAR.getBoolean();
}
}

View File

@ -0,0 +1,9 @@
package app.revanced.integrations.patches;
import app.revanced.integrations.settings.SettingsEnum;
public class HideTimePatch {
public static boolean hideTime() {
return SettingsEnum.HIDE_TIME.getBoolean();
}
}

View File

@ -2,9 +2,8 @@ package app.revanced.integrations.patches;
import app.revanced.integrations.settings.SettingsEnum;
public class HideWatchinVRPatch {
//Used by app.revanced.patches.youtube.layout.watchinvr.patch.HideWatchinVRPatch
public static boolean hideWatchinVR() {
public class HideWatchInVRPatch {
public static boolean hideWatchInVR() {
return SettingsEnum.HIDE_WATCH_IN_VR.getBoolean();
}
}

View File

@ -1,18 +1,25 @@
package app.revanced.integrations.patches;
import java.net.URLDecoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.net.Uri;
import app.revanced.integrations.settings.SettingsEnum;
public class OpenLinksDirectlyPatch {
private static final String YOUTUBE_REDIRECT_PATH = "redirect";
public static String parseRedirectUri(String uri) {
/**
* Parses the given YouTube redirect uri by extracting the redirect query.
*
* @param uri The YouTube redirect uri.
* @return The redirect query.
*/
public static Uri parseRedirectUri(String uri) {
if (SettingsEnum.OPEN_LINKS_DIRECTLY.getBoolean()) {
Matcher matcher = Pattern.compile("&q=(http.+?)&v=").matcher(uri);
return matcher.find() ? URLDecoder.decode(matcher.group(1)) : uri;
final var parsed = Uri.parse(uri);
if (parsed.getPath().equals(YOUTUBE_REDIRECT_PATH))
Uri.parse(parsed.getQueryParameter("q"));
}
return uri;
return Uri.parse(uri);
}
}

View File

@ -54,6 +54,8 @@ public enum SettingsEnum {
ADREMOVER_GRAY_SEPARATOR("revanced_adremover_separator", true, ReturnType.BOOLEAN),
ADREMOVER_VIEW_PRODUCTS("revanced_adremover_view_products", true, ReturnType.BOOLEAN),
ADREMOVER_WEB_SEARCH_RESULTS("revanced_adremover_web_search_result", true, ReturnType.BOOLEAN),
ADREMOVER_HORIZONTAL_VIDEO_SHELF("revanced_horizontal_video_shelf", true, ReturnType.BOOLEAN),
ADREMOVER_CHANNEL_BAR("revanced_hide_channel_bar", false, ReturnType.BOOLEAN),
// Action buttons
HIDE_LIKE_BUTTON("revanced_hide_like_button", false, ReturnType.BOOLEAN, false),
@ -70,7 +72,7 @@ public enum SettingsEnum {
SPOOF_APP_VERSION("revanced_spoof_app_version", false, ReturnType.BOOLEAN, true),
WIDE_SEARCHBAR("revanced_wide_searchbar", false, ReturnType.BOOLEAN, true),
HIDE_ALBUM_CARDS("revanced_hide_album_cards", false, ReturnType.BOOLEAN, true),
HIDE_ARTIST_CARD("revanced_hide_artist_card", false, ReturnType.BOOLEAN),
HIDE_ARTIST_CARDS("revanced_hide_artist_cards", false, ReturnType.BOOLEAN),
HIDE_AUTOPLAY_BUTTON("revanced_hide_autoplay_button", true, ReturnType.BOOLEAN, true),
HIDE_VIDEO_WATERMARK("revanced_hide_video_watermark", true, ReturnType.BOOLEAN),
HIDE_CAPTIONS_BUTTON("revanced_hide_captions_button", false, ReturnType.BOOLEAN),
@ -87,7 +89,8 @@ public enum SettingsEnum {
HIDE_REEL_BUTTON("revanced_hide_reel_button", true, ReturnType.BOOLEAN, true),
HIDE_SHORTS_BUTTON("revanced_hide_shorts_button", true, ReturnType.BOOLEAN, true),
HIDE_SHORTS_COMMENTS_BUTTON("revanced_hide_shorts_comments_button", false, ReturnType.BOOLEAN),
HIDE_TIME_AND_SEEKBAR("revanced_hide_time_and_seekbar", false, ReturnType.BOOLEAN),
HIDE_TIME("revanced_hide_time", false, ReturnType.BOOLEAN),
HIDE_SEEKBAR("revanced_hide_seekbar", false, ReturnType.BOOLEAN),
HIDE_WATCH_IN_VR("revanced_hide_watch_in_vr", false, ReturnType.BOOLEAN, true),
HIDE_BREAKING_NEWS("revanced_hide_breaking_news", true, ReturnType.BOOLEAN, true),
HIDE_PLAYER_BUTTONS("revanced_hide_player_buttons", false, ReturnType.BOOLEAN, false),

View File

@ -0,0 +1,9 @@
package app.revanced.twitter.patches.hook.json
import org.json.JSONObject
abstract class BaseJsonHook : JsonHook {
abstract fun apply(json: JSONObject)
override fun transform(json: JSONObject) = json.apply { apply(json) }
}

View File

@ -0,0 +1,15 @@
package app.revanced.twitter.patches.hook.json
import app.revanced.twitter.patches.hook.patch.Hook
import org.json.JSONObject
interface JsonHook : Hook<JSONObject> {
/**
* Transform a JSONObject.
*
* @param json The JSONObject.
*/
fun transform(json: JSONObject): JSONObject
override fun hook(type: JSONObject) = transform(type)
}

View File

@ -0,0 +1,28 @@
package app.revanced.twitter.patches.hook.json
import app.revanced.twitter.utils.json.JsonUtils.parseJson
import app.revanced.twitter.utils.stream.StreamUtils
import org.json.JSONException
import java.io.IOException
import java.io.InputStream
object JsonHookPatch {
private val hooks = buildList<JsonHook> {
// Modified by corresponding patch.
}
@JvmStatic
fun parseJsonHook(jsonInputStream: InputStream): InputStream {
var jsonObject = try {
parseJson(jsonInputStream)
} catch (ignored: IOException) {
return jsonInputStream // Unreachable.
} catch (ignored: JSONException) {
return jsonInputStream
}
for (hook in hooks) jsonObject = hook.hook(jsonObject)
return StreamUtils.fromString(jsonObject.toString())
}
}

View File

@ -0,0 +1,9 @@
package app.revanced.twitter.patches.hook.patch
interface Hook<T> {
/**
* Hook the given type.
* @param type The type to hook
*/
fun hook(type: T): T
}

View File

@ -0,0 +1,15 @@
package app.revanced.twitter.patches.hook.patch.ads
import app.revanced.twitter.patches.hook.json.BaseJsonHook
import app.revanced.twitter.patches.hook.twifucker.TwiFucker
import org.json.JSONObject
object AdsHook : BaseJsonHook() {
/**
* Strips JSONObject from promoted ads.
*
* @param json The JSONObject.
*/
override fun apply(json: JSONObject) = TwiFucker.hidePromotedAds(json)
}

View File

@ -0,0 +1,15 @@
package app.revanced.twitter.patches.hook.patch.recommendation
import app.revanced.twitter.patches.hook.json.BaseJsonHook
import app.revanced.twitter.patches.hook.twifucker.TwiFucker
import org.json.JSONObject
object RecommendedUsersHook : BaseJsonHook() {
/**
* Strips JSONObject from recommended users.
*
* @param json The JSONObject.
*/
override fun apply(json: JSONObject) = TwiFucker.hideRecommendedUsers(json)
}

View File

@ -0,0 +1,177 @@
package app.revanced.twitter.patches.hook.twifucker
import android.util.Log
import app.revanced.twitter.patches.hook.twifucker.TwiFuckerUtils.forEach
import app.revanced.twitter.patches.hook.twifucker.TwiFuckerUtils.forEachIndexed
import org.json.JSONArray
import org.json.JSONObject
// https://raw.githubusercontent.com/Dr-TSNG/TwiFucker/880cdf1c1622e54ab45561ffcb4f53d94ed97bae/app/src/main/java/icu/nullptr/twifucker/hook/JsonHook.kt
internal object TwiFucker {
// root
private fun JSONObject.jsonGetInstructions(): JSONArray? =
optJSONObject("timeline")?.optJSONArray("instructions")
private fun JSONObject.jsonGetData(): JSONObject? = optJSONObject("data")
private fun JSONObject.jsonHasRecommendedUsers(): Boolean = has("recommended_users")
private fun JSONObject.jsonRemoveRecommendedUsers() {
remove("recommended_users")
}
private fun JSONObject.jsonCheckAndRemoveRecommendedUsers() {
if (jsonHasRecommendedUsers()) {
Log.d("revanced", "Handle recommended users: $this")
jsonRemoveRecommendedUsers()
}
}
private fun JSONObject.jsonHasThreads(): Boolean = has("threads")
private fun JSONObject.jsonRemoveThreads() {
remove("threads")
}
private fun JSONObject.jsonCheckAndRemoveThreads() {
if (jsonHasThreads()) {
Log.d("revabced", "Handle threads: $this")
jsonRemoveThreads()
}
}
// data
private fun JSONObject.dataGetInstructions(): JSONArray? {
val timeline = optJSONObject("user_result")?.optJSONObject("result")
?.optJSONObject("timeline_response")?.optJSONObject("timeline")
?: optJSONObject("timeline_response")?.optJSONObject("timeline")
?: optJSONObject("timeline_response")
return timeline?.optJSONArray("instructions")
}
private fun JSONObject.dataCheckAndRemove() {
dataGetInstructions()?.forEach { instruction ->
instruction.instructionCheckAndRemove()
}
}
private fun JSONObject.dataGetLegacy(): JSONObject? =
optJSONObject("tweet_result")?.optJSONObject("result")?.let {
if (it.has("tweet")) {
it.optJSONObject("tweet")
} else {
it
}
}?.optJSONObject("legacy")
// entry
private fun JSONObject.entryHasPromotedMetadata(): Boolean =
optJSONObject("content")?.optJSONObject("item")?.optJSONObject("content")
?.optJSONObject("tweet")
?.has("promotedMetadata") == true || optJSONObject("content")?.optJSONObject("content")
?.has("tweetPromotedMetadata") == true || optJSONObject("item")?.optJSONObject("content")
?.has("tweetPromotedMetadata") == true
private fun JSONObject.entryGetContentItems(): JSONArray? =
optJSONObject("content")?.optJSONArray("items")
?: optJSONObject("content")?.optJSONObject("timelineModule")?.optJSONArray("items")
private fun JSONObject.entryIsTweetDetailRelatedTweets(): Boolean =
optString("entryId").startsWith("tweetdetailrelatedtweets-")
private fun JSONObject.entryGetTrends(): JSONArray? =
optJSONObject("content")?.optJSONObject("timelineModule")?.optJSONArray("items")
// trend
private fun JSONObject.trendHasPromotedMetadata(): Boolean =
optJSONObject("item")?.optJSONObject("content")?.optJSONObject("trend")
?.has("promotedMetadata") == true
private fun JSONArray.trendRemoveAds() {
val trendRemoveIndex = mutableListOf<Int>()
forEachIndexed { trendIndex, trend ->
if (trend.trendHasPromotedMetadata()) {
Log.d("revanced", "Handle trends ads $trendIndex $trend")
trendRemoveIndex.add(trendIndex)
}
}
for (i in trendRemoveIndex.asReversed()) {
remove(i)
}
}
// instruction
private fun JSONObject.instructionTimelineAddEntries(): JSONArray? = optJSONArray("entries")
private fun JSONObject.instructionGetAddEntries(): JSONArray? =
optJSONObject("addEntries")?.optJSONArray("entries")
private fun JSONObject.instructionCheckAndRemove() {
instructionTimelineAddEntries()?.entriesRemoveAnnoyance()
instructionGetAddEntries()?.entriesRemoveAnnoyance()
}
// entries
private fun JSONArray.entriesRemoveTimelineAds() {
val removeIndex = mutableListOf<Int>()
forEachIndexed { entryIndex, entry ->
entry.entryGetTrends()?.trendRemoveAds()
if (entry.entryHasPromotedMetadata()) {
Log.d("revanced", "Handle timeline ads $entryIndex $entry")
removeIndex.add(entryIndex)
}
val innerRemoveIndex = mutableListOf<Int>()
val contentItems = entry.entryGetContentItems()
contentItems?.forEachIndexed inner@{ itemIndex, item ->
if (item.entryHasPromotedMetadata()) {
Log.d("revanced", "Handle timeline replies ads $entryIndex $entry")
if (contentItems.length() == 1) {
removeIndex.add(entryIndex)
} else {
innerRemoveIndex.add(itemIndex)
}
return@inner
}
}
for (i in innerRemoveIndex.asReversed()) {
contentItems?.remove(i)
}
}
for (i in removeIndex.reversed()) {
remove(i)
}
}
private fun JSONArray.entriesRemoveTweetDetailRelatedTweets() {
val removeIndex = mutableListOf<Int>()
forEachIndexed { entryIndex, entry ->
if (entry.entryIsTweetDetailRelatedTweets()) {
Log.d("revanced", "Handle tweet detail related tweets $entryIndex $entry")
removeIndex.add(entryIndex)
}
}
for (i in removeIndex.reversed()) {
remove(i)
}
}
private fun JSONArray.entriesRemoveAnnoyance() {
entriesRemoveTimelineAds()
entriesRemoveTweetDetailRelatedTweets()
}
fun hideRecommendedUsers(json: JSONObject) {
json.jsonCheckAndRemoveRecommendedUsers()
}
fun hidePromotedAds(json: JSONObject) {
json.jsonGetInstructions()?.forEach { instruction ->
instruction.instructionCheckAndRemove()
}
json.jsonGetData()?.dataCheckAndRemove()
}
}

View File

@ -0,0 +1,22 @@
package app.revanced.twitter.patches.hook.twifucker
import org.json.JSONArray
import org.json.JSONObject
internal object TwiFuckerUtils {
inline fun JSONArray.forEach(action: (JSONObject) -> Unit) {
(0 until this.length()).forEach { i ->
if (this[i] is JSONObject) {
action(this[i] as JSONObject)
}
}
}
inline fun JSONArray.forEachIndexed(action: (index: Int, JSONObject) -> Unit) {
(0 until this.length()).forEach { i ->
if (this[i] is JSONObject) {
action(i, this[i] as JSONObject)
}
}
}
}

View File

@ -0,0 +1,13 @@
package app.revanced.twitter.utils.json
import app.revanced.twitter.utils.stream.StreamUtils
import org.json.JSONException
import org.json.JSONObject
import java.io.IOException
import java.io.InputStream
object JsonUtils {
@JvmStatic
@Throws(IOException::class, JSONException::class)
fun parseJson(jsonInputStream: InputStream) = JSONObject(StreamUtils.toString(jsonInputStream))
}

View File

@ -0,0 +1,24 @@
package app.revanced.twitter.utils.stream
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
object StreamUtils {
@Throws(IOException::class)
fun toString(inputStream: InputStream): String {
ByteArrayOutputStream().use { result ->
val buffer = ByteArray(1024)
var length: Int
while (inputStream.read(buffer).also { length = it } != -1) {
result.write(buffer, 0, length)
}
return result.toString()
}
}
fun fromString(string: String): InputStream {
return ByteArrayInputStream(string.toByteArray())
}
}

View File

@ -1,3 +1,3 @@
org.gradle.jvmargs = -Xmx2048m
android.useAndroidX = true
version = 0.97.0
version = 0.98.0-dev.5