mirror of
https://github.com/arichornlover/uYouEnhanced.git
synced 2026-01-11 22:40:19 +00:00
This fixes only the crashing, not the functionality of the patch for now. Sorry to disappoint.
451 lines
17 KiB
Text
451 lines
17 KiB
Text
#import "uYouPlusPatches.h"
|
|
|
|
# pragma mark - YouTube patches
|
|
|
|
// Fix Google Sign in Patch
|
|
%group gGoogleSignInPatch
|
|
%hook NSBundle
|
|
- (NSDictionary *)infoDictionary {
|
|
NSDictionary *orig = %orig;
|
|
if ([self isEqual:NSBundle.mainBundle]) {
|
|
NSArray<NSString *> *stack = [NSThread callStackSymbols];
|
|
BOOL needsSpoof = NO;
|
|
for (NSString *frame in stack) {
|
|
if ([frame containsString:@"GIDSignIn"] ||
|
|
[frame containsString:@"GTMSessionFetcher"] ||
|
|
[frame containsString:@"GoogleSignIn"]) {
|
|
needsSpoof = YES;
|
|
break;
|
|
}
|
|
}
|
|
if (needsSpoof) {
|
|
NSMutableDictionary *patched = [orig mutableCopy];
|
|
patched[@"CFBundleIdentifier"] = @"com.google.ios.youtube";
|
|
return [patched copy];
|
|
}
|
|
}
|
|
return orig;
|
|
}
|
|
%end
|
|
%end
|
|
|
|
// Workaround for MiRO92/uYou-for-YouTube#12, qnblackcat/uYouPlus#263
|
|
%hook YTDataUtils
|
|
+ (NSMutableDictionary *)spamSignalsDictionary {
|
|
return nil;
|
|
}
|
|
+ (NSMutableDictionary *)spamSignalsDictionaryWithoutIDFA {
|
|
return nil;
|
|
}
|
|
%end
|
|
|
|
%hook YTHotConfig
|
|
- (BOOL)disableAfmaIdfaCollection { return NO; }
|
|
%end
|
|
|
|
// Reposition "Create" Tab to the Center in the Pivot Bar - qnblackcat/uYouPlus#107
|
|
/*
|
|
static void repositionCreateTab(YTIGuideResponse *response) {
|
|
NSMutableArray<YTIGuideResponseSupportedRenderers *> *renderers = [response itemsArray];
|
|
for (YTIGuideResponseSupportedRenderers *guideRenderers in renderers) {
|
|
YTIPivotBarRenderer *pivotBarRenderer = [guideRenderers pivotBarRenderer];
|
|
NSMutableArray<YTIPivotBarSupportedRenderers *> *items = [pivotBarRenderer itemsArray];
|
|
NSUInteger createIndex = [items indexOfObjectPassingTest:^BOOL(YTIPivotBarSupportedRenderers *renderers, NSUInteger idx, BOOL *stop) {
|
|
return [[[renderers pivotBarItemRenderer] pivotIdentifier] isEqualToString:@"FEuploads"];
|
|
}];
|
|
if (createIndex != NSNotFound) {
|
|
YTIPivotBarSupportedRenderers *createTab = [items objectAtIndex:createIndex];
|
|
[items removeObjectAtIndex:createIndex];
|
|
NSUInteger centerIndex = items.count / 2;
|
|
[items insertObject:createTab atIndex:centerIndex]; // Reposition the "Create" tab at the center
|
|
}
|
|
}
|
|
}
|
|
%hook YTGuideServiceCoordinator
|
|
- (void)handleResponse:(YTIGuideResponse *)response withCompletion:(id)completion {
|
|
repositionCreateTab(response);
|
|
%orig(response, completion);
|
|
}
|
|
- (void)handleResponse:(YTIGuideResponse *)response error:(id)error completion:(id)completion {
|
|
repositionCreateTab(response);
|
|
%orig(response, error, completion);
|
|
}
|
|
%end
|
|
*/
|
|
|
|
// https://github.com/PoomSmart/YouTube-X/blob/1e62b68e9027fcb849a75f54a402a530385f2a51/Tweak.x#L27
|
|
// %hook YTAdsInnerTubeContextDecorator
|
|
// - (void)decorateContext:(id)context {}
|
|
// %end
|
|
|
|
# pragma mark - uYou patches
|
|
|
|
// Workaround for qnblackcat/uYouPlus#10
|
|
%hook UIViewController
|
|
- (UITraitCollection *)traitCollection {
|
|
@try {
|
|
return %orig;
|
|
} @catch(NSException *e) {
|
|
return [UITraitCollection currentTraitCollection];
|
|
}
|
|
}
|
|
%end
|
|
|
|
// Prevent uYou player bar from showing when not playing downloaded media
|
|
%hook PlayerManager
|
|
- (void)pause {
|
|
if (isnan([self progress]))
|
|
return;
|
|
%orig;
|
|
}
|
|
%end
|
|
|
|
// Workaround for issue #54
|
|
%hook YTMainAppVideoPlayerOverlayViewController
|
|
- (void)updateRelatedVideos {
|
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"relatedVideosAtTheEndOfYTVideos"] == NO) {}
|
|
else { return %orig; }
|
|
}
|
|
%end
|
|
|
|
// YouTube Native Share - https://github.com/jkhsjdhjs/youtube-native-share - @jkhsjdhjs
|
|
typedef NS_ENUM(NSInteger, ShareEntityType) {
|
|
ShareEntityFieldVideo = 1,
|
|
ShareEntityFieldPlaylist = 2,
|
|
ShareEntityFieldChannel = 3,
|
|
ShareEntityFieldPost = 6,
|
|
ShareEntityFieldClip = 8,
|
|
ShareEntityFieldShortFlag = 10
|
|
};
|
|
|
|
static inline NSString* extractIdWithFormat(GPBUnknownFields *fields, NSInteger fieldNumber, NSString *format) {
|
|
NSArray<GPBUnknownField*> *fieldArray = [fields fields:fieldNumber];
|
|
if (!fieldArray)
|
|
return nil;
|
|
if ([fieldArray count] != 1)
|
|
return nil;
|
|
NSString *id = [[NSString alloc] initWithData:[fieldArray firstObject].lengthDelimited encoding:NSUTF8StringEncoding];
|
|
return [NSString stringWithFormat:format, id];
|
|
}
|
|
|
|
static BOOL showNativeShareSheet(NSString *serializedShareEntity, UIView *sourceView) {
|
|
GPBMessage *shareEntity = [%c(GPBMessage) deserializeFromString:serializedShareEntity];
|
|
GPBUnknownFields *fields = [[%c(GPBUnknownFields) alloc] initFromMessage:shareEntity];
|
|
NSString *shareUrl;
|
|
|
|
NSArray<GPBUnknownField*> *shareEntityClip = [fields fields:ShareEntityFieldClip];
|
|
if (shareEntityClip) {
|
|
if ([shareEntityClip count] != 1)
|
|
return NO;
|
|
GPBMessage *clipMessage = [%c(GPBMessage) parseFromData:[shareEntityClip firstObject].lengthDelimited error:nil];
|
|
shareUrl = extractIdWithFormat([[%c(GPBUnknownFields) alloc] initFromMessage:clipMessage], 1, @"https://youtube.com/clip/%@");
|
|
}
|
|
|
|
if (!shareUrl)
|
|
shareUrl = extractIdWithFormat(fields, ShareEntityFieldChannel, @"https://youtube.com/channel/%@");
|
|
|
|
if (!shareUrl) {
|
|
shareUrl = extractIdWithFormat(fields, ShareEntityFieldPlaylist, @"%@");
|
|
if (shareUrl) {
|
|
if (![shareUrl hasPrefix:@"PL"] && ![shareUrl hasPrefix:@"FL"])
|
|
shareUrl = [shareUrl stringByAppendingString:@"&playnext=1"];
|
|
shareUrl = [@"https://youtube.com/playlist?list=" stringByAppendingString:shareUrl];
|
|
}
|
|
}
|
|
|
|
if (!shareUrl) {
|
|
NSString *format = @"https://youtube.com/watch?v=%@";
|
|
if ([fields fields:ShareEntityFieldShortFlag])
|
|
format = @"https://youtube.com/shorts/%@";
|
|
shareUrl = extractIdWithFormat(fields, ShareEntityFieldVideo, format);
|
|
}
|
|
|
|
if (!shareUrl)
|
|
shareUrl = extractIdWithFormat(fields, ShareEntityFieldPost, @"https://youtube.com/post/%@");
|
|
|
|
if (!shareUrl)
|
|
return NO;
|
|
|
|
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[shareUrl] applicationActivities:nil];
|
|
activityViewController.excludedActivityTypes = @[UIActivityTypeAssignToContact, UIActivityTypePrint];
|
|
|
|
UIViewController *topViewController = [%c(YTUIUtils) topViewControllerForPresenting];
|
|
|
|
if (activityViewController.popoverPresentationController) {
|
|
activityViewController.popoverPresentationController.sourceView = topViewController.view;
|
|
activityViewController.popoverPresentationController.sourceRect = [sourceView convertRect:sourceView.bounds toView:topViewController.view];
|
|
}
|
|
|
|
[topViewController presentViewController:activityViewController animated:YES completion:nil];
|
|
|
|
return YES;
|
|
}
|
|
|
|
/* -------------------- iPad Layout -------------------- */
|
|
|
|
// %group gYouTubeNativeShare // YouTube Native Share Option - 0.2.3 - Supports YouTube v17.33.2-v19.34.2
|
|
%hook YTAccountScopedCommandResponderEvent
|
|
- (void)send {
|
|
GPBExtensionDescriptor *shareEntityEndpointDescriptor = [%c(YTIShareEntityEndpoint) shareEntityEndpoint];
|
|
if (![self.command hasExtension:shareEntityEndpointDescriptor])
|
|
return %orig;
|
|
YTIShareEntityEndpoint *shareEntityEndpoint = [self.command getExtension:shareEntityEndpointDescriptor];
|
|
if (!shareEntityEndpoint.hasSerializedShareEntity)
|
|
return %orig;
|
|
if (!showNativeShareSheet(shareEntityEndpoint.serializedShareEntity, self.fromView))
|
|
return %orig;
|
|
}
|
|
%end
|
|
|
|
|
|
/* ------------------- iPhone Layout ------------------- */
|
|
|
|
%hook ELMPBShowActionSheetCommand
|
|
- (void)executeWithCommandContext:(ELMCommandContext*)context handler:(id)_handler {
|
|
if (!self.hasOnAppear)
|
|
return %orig;
|
|
GPBExtensionDescriptor *innertubeCommandDescriptor = [%c(YTIInnertubeCommandExtensionRoot) innertubeCommand];
|
|
if (![self.onAppear hasExtension:innertubeCommandDescriptor])
|
|
return %orig;
|
|
YTICommand *innertubeCommand = [self.onAppear getExtension:innertubeCommandDescriptor];
|
|
GPBExtensionDescriptor *updateShareSheetCommandDescriptor = [%c(YTIUpdateShareSheetCommand) updateShareSheetCommand];
|
|
if(![innertubeCommand hasExtension:updateShareSheetCommandDescriptor])
|
|
return %orig;
|
|
YTIUpdateShareSheetCommand *updateShareSheetCommand = [innertubeCommand getExtension:updateShareSheetCommandDescriptor];
|
|
if (!updateShareSheetCommand.hasSerializedShareEntity)
|
|
return %orig;
|
|
if (!showNativeShareSheet(updateShareSheetCommand.serializedShareEntity, context.context.fromView))
|
|
return %orig;
|
|
}
|
|
%end
|
|
// %end
|
|
|
|
//
|
|
|
|
// iOS 16 uYou crash fix - @level3tjg: https://github.com/qnblackcat/uYouPlus/pull/224
|
|
// %group iOS16
|
|
// %hook OBPrivacyLinkButton
|
|
// %new
|
|
// - (instancetype)initWithCaption:(NSString *)caption
|
|
// buttonText:(NSString *)buttonText
|
|
// image:(UIImage *)image
|
|
// imageSize:(CGSize)imageSize
|
|
// useLargeIcon:(BOOL)useLargeIcon {
|
|
// return [self initWithCaption:caption
|
|
// buttonText:buttonText
|
|
// image:image
|
|
// imageSize:imageSize
|
|
// useLargeIcon:useLargeIcon
|
|
// displayLanguage:[NSLocale currentLocale].languageCode];
|
|
// }
|
|
// %end
|
|
// %end
|
|
|
|
// Fix uYou playback speed crashes YT v18.49.3+, see https://github.com/iCrazeiOS/uYouCrashFix
|
|
// %hook YTPlayerViewController
|
|
// %new
|
|
// -(float)currentPlaybackRateForVarispeedSwitchController:(id)arg1 {
|
|
// return [[self activeVideo] playbackRate];
|
|
// }
|
|
|
|
// %new
|
|
// -(void)varispeedSwitchController:(id)arg1 didSelectRate:(float)arg2 {
|
|
// [[self activeVideo] setPlaybackRate:arg2];
|
|
// }
|
|
// %end
|
|
|
|
// Fix streched artwork in uYou's player view - https://github.com/MiRO92/uYou-for-YouTube/issues/287
|
|
%hook ArtworkImageView
|
|
- (id)imageView {
|
|
UIImageView * imageView = %orig;
|
|
imageView.contentMode = UIViewContentModeScaleAspectFit;
|
|
// Make artwork a bit bigger
|
|
UIView *artworkImageView = imageView.superview;
|
|
if (artworkImageView != nil && !artworkImageView.translatesAutoresizingMaskIntoConstraints) {
|
|
[artworkImageView.leftAnchor constraintEqualToAnchor:artworkImageView.superview.leftAnchor constant:16].active = YES;
|
|
[artworkImageView.rightAnchor constraintEqualToAnchor:artworkImageView.superview.rightAnchor constant:-16].active = YES;
|
|
}
|
|
return imageView;
|
|
}
|
|
%end
|
|
|
|
// Fix navigation bar showing a lighter grey with default dark mode - https://github.com/therealFoxster/uYouPlus/commit/8db8197
|
|
%hook YTCommonColorPalette
|
|
- (UIColor *)brandBackgroundSolid {
|
|
return self.pageStyle == 1 ? [UIColor colorWithRed:0.05882352941176471 green:0.05882352941176471 blue:0.05882352941176471 alpha:1.0] : %orig;
|
|
}
|
|
%end
|
|
|
|
// Fix uYou's appearance not updating if the app is backgrounded
|
|
static DownloadsPagerVC *downloadsPagerVC;
|
|
static NSUInteger selectedTabIndex;
|
|
%hook DownloadsPagerVC
|
|
- (id)init {
|
|
downloadsPagerVC = %orig;
|
|
return downloadsPagerVC;
|
|
}
|
|
- (void)viewPager:(id)viewPager didChangeTabToIndex:(NSUInteger)arg1 fromTabIndex:(NSUInteger)arg2 {
|
|
%orig; selectedTabIndex = arg1;
|
|
}
|
|
%end
|
|
static void refreshUYouAppearance() {
|
|
if (!downloadsPagerVC) return;
|
|
// View pager
|
|
[downloadsPagerVC updatePageStyles];
|
|
// Views
|
|
for (UIViewController *vc in [downloadsPagerVC viewControllers]) {
|
|
if ([vc isKindOfClass:%c(DownloadingVC)]) {
|
|
// `Downloading` view
|
|
[(DownloadingVC *)vc updatePageStyles];
|
|
for (UITableViewCell *cell in [(DownloadingVC *)vc tableView].visibleCells)
|
|
if ([cell isKindOfClass:%c(DownloadingCell)])
|
|
[(DownloadingCell *)cell updatePageStyles];
|
|
}
|
|
else if ([vc isKindOfClass:%c(DownloadedVC)]) {
|
|
// `All`, `Audios`, `Videos`, `Shorts` views
|
|
[(DownloadedVC *)vc updatePageStyles];
|
|
for (UITableViewCell *cell in [(DownloadedVC *)vc tableView].visibleCells)
|
|
if ([cell isKindOfClass:%c(DownloadedCell)])
|
|
[(DownloadedCell *)cell updatePageStyles];
|
|
}
|
|
}
|
|
// View pager tabs
|
|
for (UIView *subview in [downloadsPagerVC view].subviews) {
|
|
if ([subview isKindOfClass:[UIScrollView class]]) {
|
|
UIScrollView *tabs = (UIScrollView *)subview;
|
|
NSUInteger i = 0;
|
|
for (UIView *item in tabs.subviews) {
|
|
if ([item isKindOfClass:[UILabel class]]) {
|
|
// Tab label
|
|
UILabel *tabLabel = (UILabel *)item;
|
|
if (i == selectedTabIndex) {} // Selected tab should be excluded
|
|
else [tabLabel setTextColor:[UILabel _defaultColor]];
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
%hook UIViewController
|
|
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
|
%orig;
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
refreshUYouAppearance();
|
|
});
|
|
}
|
|
%end
|
|
|
|
// Prevent uYou's playback from colliding with YouTube's
|
|
%hook PlayerVC
|
|
- (void)close {
|
|
%orig;
|
|
[[%c(PlayerManager) sharedInstance] setSource:nil];
|
|
}
|
|
%end
|
|
%hook HAMPlayerInternal
|
|
- (void)play {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[[%c(PlayerManager) sharedInstance] pause];
|
|
});
|
|
%orig;
|
|
}
|
|
%end
|
|
|
|
// Temporarily disable uYou's bouncy animation cause it's buggy
|
|
%hook SSBouncyButton
|
|
- (void)beginShrinkAnimation {}
|
|
- (void)beginEnlargeAnimation {}
|
|
%end
|
|
|
|
%hook GOODialogView
|
|
- (id)imageView {
|
|
UIImageView *imageView = %orig;
|
|
|
|
if ([[self titleLabel].text containsString:@"uYou\n"]) {
|
|
// // Invert uYou logo in download dialog if dark mode is enabled
|
|
// if ([[NSUserDefaults standardUserDefaults] integerForKey:@"page_style"] == 0)
|
|
// return imageView;
|
|
// // https://gist.github.com/coryalder/3113a43734f5e0e4b497
|
|
// UIImage *image = [imageView image];
|
|
// CIImage *ciImage = [[CIImage alloc] initWithImage:image];
|
|
// CIFilter *filter = [CIFilter filterWithName:@"CIColorInvert"];
|
|
// [filter setDefaults];
|
|
// [filter setValue:ciImage forKey:kCIInputImageKey];
|
|
// CIContext *context = [CIContext contextWithOptions:nil];
|
|
// CIImage *output = [filter outputImage];
|
|
// CGImageRef cgImage = [context createCGImage:output fromRect:[output extent]];
|
|
// UIImage *icon = [UIImage imageWithCGImage:cgImage];
|
|
// CGImageRelease(cgImage);
|
|
|
|
// Load icon_clipped.png from uYouBundle.bundle
|
|
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"uYouBundle" ofType:@"bundle"];
|
|
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
|
|
NSString *iconPath = [bundle pathForResource:@"icon_clipped" ofType:@"png"];
|
|
UIImage *icon = [UIImage imageWithContentsOfFile:iconPath];
|
|
[imageView setImage:icon];
|
|
|
|
// Resize image to 30x30
|
|
// https://stackoverflow.com/a/2658801/19227228
|
|
CGSize size = CGSizeMake(30, 30);
|
|
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
|
[icon drawInRect:CGRectMake(0, 0, size.width, size.height)];
|
|
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
|
|
[imageView setImage:resizedImage];
|
|
}
|
|
|
|
return imageView;
|
|
}
|
|
// Increase space between uYou label and video title
|
|
- (id)titleLabel {
|
|
UILabel *titleLabel = %orig;
|
|
if ([titleLabel.text containsString:@"uYou\n"] &&
|
|
![titleLabel.text containsString:@"uYou\n\n"]
|
|
) {
|
|
NSString *text = [titleLabel.text stringByReplacingOccurrencesOfString:@"uYou\n" withString:@"uYou\n\n"];
|
|
[titleLabel setText:text];
|
|
}
|
|
return titleLabel;
|
|
}
|
|
%end
|
|
|
|
%hook YTPlayerViewController
|
|
|
|
- (id)varispeedController {
|
|
id controller = %orig;
|
|
if (controller == nil && [self respondsToSelector:@selector(overlayManager)])
|
|
controller = [self.overlayManager varispeedController];
|
|
return controller;
|
|
}
|
|
|
|
%end
|
|
|
|
%ctor {
|
|
%init;
|
|
if (IS_ENABLED(kGoogleSignInPatch)) {
|
|
%init(gGoogleSignInPatch);
|
|
}
|
|
/*
|
|
if (IS_ENABLED(kYouTubeNativeShare)) {
|
|
%init(gYouTubeNativeShare);
|
|
}
|
|
*/
|
|
// if (@available(iOS 16, *)) {
|
|
// %init(iOS16);
|
|
// }
|
|
|
|
// Disable broken options
|
|
|
|
// Disable uYou's auto updates
|
|
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"automaticallyCheckForUpdates"];
|
|
|
|
// Disable uYou's welcome screen (fix #1147)
|
|
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"showedWelcomeVC"];
|
|
|
|
// Disable uYou's disable age restriction
|
|
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"disableAgeRestriction"];
|
|
|
|
// Disable uYou's playback speed controls (prevent crash on video playback https://github.com/therealFoxster/uYouPlus/issues/2#issuecomment-1894912963)
|
|
// [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"showPlaybackRate"];
|
|
}
|