Skip to content
This repository was archived by the owner on Dec 11, 2024. It is now read-only.

feat: Merge RVX v1.12.1-dev.1 #27

Merged
merged 11 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package app.revanced.integrations.music.patches.components;

import androidx.annotation.Nullable;

import app.revanced.integrations.shared.patches.components.Filter;
import app.revanced.integrations.shared.patches.components.StringFilterGroup;
import app.revanced.integrations.music.patches.misc.ShareSheetPatch;
import app.revanced.integrations.music.settings.Settings;

/**
* Abuse LithoFilter for {@link ShareSheetPatch}.
*/
public final class ShareSheetMenuFilter extends Filter {
// Must be volatile or synchronized, as litho filtering runs off main thread and this field is then access from the main thread.
public static volatile boolean isShareSheetMenuVisible;

public ShareSheetMenuFilter() {
addIdentifierCallbacks(
new StringFilterGroup(
Settings.CHANGE_SHARE_SHEET,
"share_sheet_container.eml"
)
);
}

@Override
public boolean isFiltered(String path, @Nullable String identifier, String allValue, byte[] protobufBufferArray,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
isShareSheetMenuVisible = true;

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package app.revanced.integrations.music.patches.misc;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

import app.revanced.integrations.music.patches.components.ShareSheetMenuFilter;
import app.revanced.integrations.music.settings.Settings;
import app.revanced.integrations.shared.utils.Logger;
import app.revanced.integrations.shared.utils.Utils;

@SuppressWarnings("unused")
public class ShareSheetPatch {
/**
* Injection point.
*/
public static void onShareSheetMenuCreate(final RecyclerView recyclerView) {
if (!Settings.CHANGE_SHARE_SHEET.get())
return;

recyclerView.getViewTreeObserver().addOnDrawListener(() -> {
try {
if (!ShareSheetMenuFilter.isShareSheetMenuVisible)
return;
if (!(recyclerView.getChildAt(0) instanceof ViewGroup shareContainer)) {
return;
}
if (!(shareContainer.getChildAt(shareContainer.getChildCount() - 1) instanceof ViewGroup shareWithOtherAppsView)) {
return;
}
ShareSheetMenuFilter.isShareSheetMenuVisible = false;

recyclerView.setVisibility(View.GONE);
Utils.clickView(shareWithOtherAppsView);
} catch (Exception ex) {
Logger.printException(() -> "onShareSheetMenuCreate failure", ex);
}
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,9 @@ public class Settings extends BaseSettings {


// PreferenceScreen: Miscellaneous
public static final BooleanSetting ENABLE_OPUS_CODEC = new BooleanSetting("revanced_enable_opus_codec", FALSE, true);
public static final BooleanSetting CHANGE_SHARE_SHEET = new BooleanSetting("revanced_change_share_sheet", FALSE, true);
public static final BooleanSetting ENABLE_CAIRO_SPLASH_ANIMATION = new BooleanSetting("revanced_enable_cairo_splash_animation", FALSE, true);
public static final BooleanSetting ENABLE_OPUS_CODEC = new BooleanSetting("revanced_enable_opus_codec", FALSE, true);
public static final BooleanSetting SANITIZE_SHARING_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE, true);
public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import androidx.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;

import java.util.regex.Pattern;

import app.revanced.integrations.shared.patches.components.Filter;
Expand Down Expand Up @@ -105,7 +107,7 @@ public boolean isFiltered(String path, @Nullable String identifier, String allVa
}
return false;
} else if (matchedGroup == comments) {
if (path.startsWith("home_video_with_context.eml")) {
if (StringUtils.startsWithAny(path, "home_video_with_context", "video_lockup_with_attachment")) {
if (Settings.HIDE_COMMENTS_SECTION_IN_HOME_FEED.get()) {
return super.isFiltered(path, identifier, allValue, protobufBufferArray, matchedGroup, contentType, contentIndex);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package app.revanced.integrations.youtube.patches.general;

import app.revanced.integrations.shared.settings.BooleanSetting;
import app.revanced.integrations.shared.utils.Logger;
import app.revanced.integrations.youtube.settings.Settings;
import app.revanced.integrations.youtube.utils.VideoUtils;

@SuppressWarnings("unused")
public final class DownloadActionsPatch extends VideoUtils {

private static final BooleanSetting overrideVideoDownloadButton =
Settings.OVERRIDE_VIDEO_DOWNLOAD_BUTTON;

private static final BooleanSetting overridePlaylistDownloadButton =
Settings.OVERRIDE_PLAYLIST_DOWNLOAD_BUTTON;

/**
* Injection point.
* <p>
* Called from the in app download hook,
* for both the player action button (below the video)
* and the 'Download video' flyout option for feed videos.
* <p>
* Appears to always be called from the main thread.
*/
public static boolean inAppVideoDownloadButtonOnClick(String videoId) {
try {
if (!overrideVideoDownloadButton.get()) {
return false;
}
if (videoId == null || videoId.isEmpty()) {
return false;
}
launchVideoExternalDownloader(videoId);

return true;
} catch (Exception ex) {
Logger.printException(() -> "inAppVideoDownloadButtonOnClick failure", ex);
}
return false;
}

/**
* Injection point.
* <p>
* Called from the in app playlist download hook.
* <p>
* Appears to always be called from the main thread.
*/
public static String inAppPlaylistDownloadButtonOnClick(String playlistId) {
try {
if (!overridePlaylistDownloadButton.get()) {
return playlistId;
}
if (playlistId == null || playlistId.isEmpty()) {
return playlistId;
}
launchPlaylistExternalDownloader(playlistId);

return "";
} catch (Exception ex) {
Logger.printException(() -> "inAppPlaylistDownloadButtonOnClick failure", ex);
}
return playlistId;
}

/**
* Injection point.
*/
public static boolean overridePlaylistDownloadButtonVisibility() {
return overridePlaylistDownloadButton.get();
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ public final class LiveStreamRenderer {
public final String videoId;
public final String client;
public final boolean playabilityOk;
public final boolean isLive;
public final boolean isLiveStream;

public LiveStreamRenderer(String videoId, String client, boolean playabilityOk, boolean isLive) {
public LiveStreamRenderer(String videoId, String client, boolean playabilityOk, boolean isLiveStream) {
this.videoId = videoId;
this.client = client;
this.playabilityOk = playabilityOk;
this.isLive = isLive;
this.isLiveStream = isLiveStream;
}

@NotNull
Expand All @@ -25,7 +25,7 @@ public String toString() {
"videoId=" + videoId +
", client=" + client +
", playabilityOk=" + playabilityOk +
", isLive=" + isLive +
", isLiveStream=" + isLiveStream +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -127,7 +129,7 @@ private static ClientType getSpoofClientType() {
}
LiveStreamRenderer renderer = getLiveStreamRenderer(false);
if (renderer != null) {
if (renderer.isLive) {
if (renderer.isLiveStream) {
lastSpoofedClientType = Settings.SPOOF_CLIENT_LIVESTREAM.get();
return lastSpoofedClientType;
}
Expand Down Expand Up @@ -227,6 +229,16 @@ public static boolean forceCreatePlaybackSpeedMenu(boolean original) {
return original;
}

/**
* Injection point.
* When spoofing the client to iOS, background audio only playback of livestreams fails.
* Return true to force enable audio background play.
*/
public static boolean overrideBackgroundAudioPlayback() {
return SPOOF_CLIENT_ENABLED &&
BackgroundPlaybackPatch.playbackIsNotShort();
}

/**
* Injection point.
* When spoofing the client to Android TV the playback speed menu is missing from the player response.
Expand All @@ -240,6 +252,104 @@ public static boolean forceCreatePlaybackSpeedMenuReversed(boolean original) {
return original;
}

private static final Uri VIDEO_STATS_PLAYBACK_URI = Uri.parse("https://www.youtube.com/api/stats/playback?ns=yt&ver=2&final=1");

private static final String PARAM_DOC_ID = "docid";
private static final String PARAM_LEN = "len";
private static final String PARAM_CPN = "cpn";

private static final String PARAM_EVENT_ID = "ei";
private static final String PARAM_VM = "vm";
private static final String PARAM_OF = "of";

private static String mDocId;
private static String mLen;
private static String mCpn;
private static String mEventId;
private static String mVisitorMonitoringData;
private static String mOfParam;

/**
* Injection point.
*/
public static void setCpn(String cpn) {
if (SPOOF_CLIENT_ENABLED && !Objects.equals(mCpn, cpn)) {
mCpn = cpn;
}
}

/**
* Injection point.
*
* Parse parameters from the Tracking URL.
* See <a href="https://github.com/yuliskov/MediaServiceCore/blob/d83b56d98f75ba24eef0bf31073c72c3db2f9cb0/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/videoinfo/models/VideoInfo.java#L327">yuliskov/MediaServiceCore</a>.
*/
public static void setTrackingUriParameter(Uri trackingUri) {
try {
if (SPOOF_CLIENT_ENABLED) {
String path = trackingUri.getPath();

if (path == null || (!path.contains("playback") && !path.contains("watchtime"))) {
return;
}

mDocId = getQueryParameter(trackingUri, PARAM_DOC_ID);
mLen = getQueryParameter(trackingUri, PARAM_LEN);
mEventId = getQueryParameter(trackingUri, PARAM_EVENT_ID);
mVisitorMonitoringData = getQueryParameter(trackingUri, PARAM_VM);
mOfParam = getQueryParameter(trackingUri, PARAM_OF);

Logger.printDebug(() -> "docId: " + mDocId + ", len: " + mLen + ", eventId: " + mEventId + ", visitorMonitoringData: " + mVisitorMonitoringData + ", of: " + mOfParam);
}
} catch (Exception ex) {
Logger.printException(() -> "setTrackingUriParameter failure", ex);
}
}

/**
* Injection point.
* This only works on YouTube 18.38.45 or earlier.
*
* Build a Tracking URL.
* This does not include the last watched time.
* See <a href="https://github.com/yuliskov/MediaServiceCore/blob/d83b56d98f75ba24eef0bf31073c72c3db2f9cb0/youtubeapi/src/main/java/com/liskovsoft/youtubeapi/track/TrackingService.java#L72">yuliskov/MediaServiceCore</a>.
*/
public static Uri overrideTrackingUrl(Uri trackingUrl) {
try {
if (SPOOF_CLIENT_ENABLED &&
getSpoofClientType() == ClientType.IOS &&
trackingUrl.toString().contains("youtube.com/csi") &&
!StringUtils.isAnyEmpty(mDocId, mLen, mCpn, mEventId, mVisitorMonitoringData, mOfParam)
) {
final Uri videoStatsPlaybackUri = VIDEO_STATS_PLAYBACK_URI
.buildUpon()
.appendQueryParameter(PARAM_DOC_ID, mDocId)
.appendQueryParameter(PARAM_LEN, mLen)
.appendQueryParameter(PARAM_CPN, mCpn)
.appendQueryParameter(PARAM_EVENT_ID, mEventId)
.appendQueryParameter(PARAM_VM, mVisitorMonitoringData)
.appendQueryParameter(PARAM_OF, mOfParam)
.build();

Logger.printDebug(() -> "Replaced: '" + trackingUrl + "' with: '" + videoStatsPlaybackUri + "'");
return videoStatsPlaybackUri;
}
} catch (Exception ex) {
Logger.printException(() -> "overrideTrackingUrl failure", ex);
}

return trackingUrl;
}

private static String getQueryParameter(Uri uri, String key) {
List<String> queryParams = uri.getQueryParameters(key);
if (queryParams == null || queryParams.isEmpty()) {
return "";
} else {
return queryParams.get(0);
}
}

/**
* Injection point.
*/
Expand Down
Loading
Loading