From 3738ed19bb3d93021bdc87cc7a30fa241012b257 Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Tue, 2 Apr 2024 20:28:00 -0700 Subject: [PATCH 01/14] Hide Get Youtube Premium --- Sources/uYouPlus.h | 8 ++++++++ Sources/uYouPlus.xm | 22 ++++++++++++++++++++++ Sources/uYouPlusSettings.xm | 1 + 3 files changed, 31 insertions(+) diff --git a/Sources/uYouPlus.h b/Sources/uYouPlus.h index 9e27478..acb336f 100644 --- a/Sources/uYouPlus.h +++ b/Sources/uYouPlus.h @@ -27,6 +27,7 @@ #import "Tweaks/YouTubeHeader/YTInlinePlayerBarContainerView.h" #import "Tweaks/YouTubeHeader/YTInnerTubeCollectionViewController.h" #import "Tweaks/YouTubeHeader/YTPivotBarItemView.h" +#import "Tweaks/YouTubeHeader/YTCollectionViewCell.h" // Hide buttons under the video player by @PoomSmart #import "Tweaks/YouTubeHeader/ASCollectionElement.h" @@ -64,6 +65,13 @@ @property(readonly, nonatomic) YTIIcon *iconImage; @end +// Hide Premium Promo in You tab - @bhackel +@interface YTFormattedStringLabel : UILabel +@end +@interface YTLinkCell : YTCollectionViewCell +@property(readonly, nonatomic) YTFormattedStringLabel *titleLabel; +@end + // uYouPlus @interface YTHeaderLogoController : UIView @property(readonly, nonatomic) long long pageStyle; diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index d81c284..a6c9a88 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -274,6 +274,25 @@ BOOL isAd(YTIElementRenderer *self) { - (BOOL)savedSettingShouldExpire { return NO; } %end +// Hide Premium promos in "You" and "Library" tab - @bhackel +%group gHidePremiumPromos + // Hide "Get Youtube Premium" in the "You" tab + %hook YTLinkCell + - (void)layoutSubviews { + %orig; + // Get the text label object for this cell + YTFormattedStringLabel *label = self.titleLabel; + // Check if the cell is a premium promo + if ([label.accessibilityLabel isEqualToString:@"Get YouTube Premium"]) { + // Hide the cell + self.hidden = YES; + self.frame = CGRectZero; + } + } + %end +%end + + // YTShortsProgress - https://github.com/PoomSmart/YTShortsProgress/ %hook YTShortsPlayerViewController - (BOOL)shouldAlwaysEnablePlayerBar { return YES; } @@ -1322,6 +1341,9 @@ static BOOL findCell(ASNodeController *nodeController, NSArray *ide if (IS_ENABLED(@"YTTapToSeek_enabled")) { %init(YTTTS_Tweak); } + if (IS_ENABLED(@"hidePremiumPromos_enabled")) { + %init(gHidePremiumPromos); + } // YTNoModernUI - @arichorn BOOL ytNoModernUIEnabled = IS_ENABLED(@"ytNoModernUI_enabled"); diff --git a/Sources/uYouPlusSettings.xm b/Sources/uYouPlusSettings.xm index 16b4e0a..eb65e79 100644 --- a/Sources/uYouPlusSettings.xm +++ b/Sources/uYouPlusSettings.xm @@ -275,6 +275,7 @@ extern NSBundle *uYouPlusBundle(); SWITCH_ITEM2(LOC(@"Hide `Your data in YouTube` Section"), LOC(@"App restart is required."), @"disableYourDataInYouTubeSection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Privacy` Section"), LOC(@"App restart is required."), @"disablePrivacySection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Live Chat` Section"), LOC(@"App restart is required."), @"disableLiveChatSection_enabled"); + SWITCH_ITEM2(LOC(@"Hide Premium Promos"), LOC(@"App restart is required."), @"hidePremiumPromos_enabled"); # pragma mark - UI interface options SECTION_HEADER(LOC(@"UI Interface Options")); From 13f1aa783a82e1eb3b16f1979f445fdee3a5c20d Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Tue, 2 Apr 2024 20:10:44 -0700 Subject: [PATCH 02/14] Fix building on a branch --- .github/workflows/buildapp.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/buildapp.yml b/.github/workflows/buildapp.yml index 24c8a4e..d5e397c 100644 --- a/.github/workflows/buildapp.yml +++ b/.github/workflows/buildapp.yml @@ -18,8 +18,8 @@ on: type: string uyouenhanced_version: description: "The version of uYouEnhanced (Commit ID)" - default: "main" - required: true + default: "" + required: false type: string decrypted_youtube_url: description: "The direct URL to the decrypted YouTube ipa" @@ -63,7 +63,7 @@ jobs: uses: actions/checkout@v4.1.1 with: path: main - ref: ${{ inputs.uyouenhanced_version }} + ref: ${{ github.event.inputs.uyouenhanced_version || github.ref }} submodules: recursive - name: Install Dependencies From 572ebf3e3b413e130ab9f274d9027cb07ef891eb Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Wed, 3 Apr 2024 11:24:25 -0700 Subject: [PATCH 03/14] Use language-independent method --- Sources/uYouPlus.h | 5 +++-- Sources/uYouPlus.xm | 30 +++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Sources/uYouPlus.h b/Sources/uYouPlus.h index acb336f..d45f923 100644 --- a/Sources/uYouPlus.h +++ b/Sources/uYouPlus.h @@ -66,12 +66,13 @@ @end // Hide Premium Promo in You tab - @bhackel -@interface YTFormattedStringLabel : UILabel +@interface YTIconBadgeView : UIView @end @interface YTLinkCell : YTCollectionViewCell -@property(readonly, nonatomic) YTFormattedStringLabel *titleLabel; +@property(readonly, nonatomic) YTIconBadgeView *_iconBadgeView; @end + // uYouPlus @interface YTHeaderLogoController : UIView @property(readonly, nonatomic) long long pageStyle; diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index a6c9a88..1603f64 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -280,13 +280,29 @@ BOOL isAd(YTIElementRenderer *self) { %hook YTLinkCell - (void)layoutSubviews { %orig; - // Get the text label object for this cell - YTFormattedStringLabel *label = self.titleLabel; - // Check if the cell is a premium promo - if ([label.accessibilityLabel isEqualToString:@"Get YouTube Premium"]) { - // Hide the cell - self.hidden = YES; - self.frame = CGRectZero; + // Get the badge of this cell, as it is language-independent and unique + YTIconBadgeView *badgeView = self._iconBadgeView; + // First null check for badgeView + if (!badgeView) { + return; // Early return if badgeView is nil + } + // Walk down the subviews to get to a specific view + UIView *subview = badgeView.subviews.firstObject; + // Second null check for the first subview + if (!subview) { + return; + } + UIImageView *imageView = subview.subviews.firstObject; + // Third null check for the imageView + if (!imageView) { + return; + } + // Get the description of this view + NSString *description = imageView.description; + // Check if "yt_outline_youtube_logo_icon" is in the description + if ([description containsString:@"yt_outline_youtube_logo_icon"]) { + self.hidden = YES; // Hide the cell + self.frame = CGRectZero; // Eliminate free space } } %end From f7b644457f346c2cfe0852d05cd4d3a76e4fdcbe Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Wed, 3 Apr 2024 12:19:56 -0700 Subject: [PATCH 04/14] Fix crash --- Sources/uYouPlus.xm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 1603f64..9039473 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -281,10 +281,10 @@ BOOL isAd(YTIElementRenderer *self) { - (void)layoutSubviews { %orig; // Get the badge of this cell, as it is language-independent and unique - YTIconBadgeView *badgeView = self._iconBadgeView; + YTIconBadgeView *badgeView = [self valueForKey:@"_iconBadgeView"]; // First null check for badgeView if (!badgeView) { - return; // Early return if badgeView is nil + return; } // Walk down the subviews to get to a specific view UIView *subview = badgeView.subviews.firstObject; @@ -293,12 +293,12 @@ BOOL isAd(YTIElementRenderer *self) { return; } UIImageView *imageView = subview.subviews.firstObject; - // Third null check for the imageView - if (!imageView) { + // Third null/inavlid check for the imageView + if (!imageView || ![imageView respondsToSelector:@selector(description)]) { return; } // Get the description of this view - NSString *description = imageView.description; + NSString *description = [imageView description]; // Check if "yt_outline_youtube_logo_icon" is in the description if ([description containsString:@"yt_outline_youtube_logo_icon"]) { self.hidden = YES; // Hide the cell From 12a8f227e0fd67eb39803f93701bce843d1057db Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Wed, 3 Apr 2024 21:22:18 -0700 Subject: [PATCH 05/14] Remove empty space --- Sources/uYouPlus.xm | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 9039473..188489d 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -301,8 +301,30 @@ BOOL isAd(YTIElementRenderer *self) { NSString *description = [imageView description]; // Check if "yt_outline_youtube_logo_icon" is in the description if ([description containsString:@"yt_outline_youtube_logo_icon"]) { - self.hidden = YES; // Hide the cell - self.frame = CGRectZero; // Eliminate free space + // Only perform changes once + if (self.hidden) { + return; + } + // Move all subviews that are below this one upwards to remove blank space + CGFloat viewHeight = self.frame.size.height; + bool foundThisSubview = false; + for (UIView *subview in self.superview.subviews) { + if (foundThisSubview) { + CGFloat oldX = subview.frame.origin.x; + CGFloat newY = subview.frame.origin.y - viewHeight; + CGFloat width = subview.frame.size.width; + CGFloat height = subview.frame.size.height; + subview.frame = CGRectMake(oldX, newY, width, height); + } + // If we find this subview, we know that all subviews below it are to be moved + if (subview == self) { + foundThisSubview = true; + } + } + // Remove this cell from existence + self.hidden = YES; + self.frame = CGRectZero; + [self removeFromSuperview]; } } %end From da933fd188e25b3c05fcbc0dc3488b92ddc561e1 Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:48:32 -0700 Subject: [PATCH 06/14] Better remove space implementation --- Sources/uYouPlus.xm | 129 ++++++++++++++++++++++++------------ Sources/uYouPlusSettings.xm | 2 +- 2 files changed, 86 insertions(+), 45 deletions(-) diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 188489d..a40c619 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -277,55 +277,96 @@ BOOL isAd(YTIElementRenderer *self) { // Hide Premium promos in "You" and "Library" tab - @bhackel %group gHidePremiumPromos // Hide "Get Youtube Premium" in the "You" tab - %hook YTLinkCell + %hook YTAsyncCollectionView + // Property for tracking if the cell was hidden - (void)layoutSubviews { %orig; - // Get the badge of this cell, as it is language-independent and unique - YTIconBadgeView *badgeView = [self valueForKey:@"_iconBadgeView"]; - // First null check for badgeView - if (!badgeView) { - return; - } - // Walk down the subviews to get to a specific view - UIView *subview = badgeView.subviews.firstObject; - // Second null check for the first subview - if (!subview) { - return; - } - UIImageView *imageView = subview.subviews.firstObject; - // Third null/inavlid check for the imageView - if (!imageView || ![imageView respondsToSelector:@selector(description)]) { - return; - } - // Get the description of this view - NSString *description = [imageView description]; - // Check if "yt_outline_youtube_logo_icon" is in the description - if ([description containsString:@"yt_outline_youtube_logo_icon"]) { - // Only perform changes once - if (self.hidden) { - return; + // Check each subview for the "Get YouTube Premium" cell + UIView *foundSubview = nil; + for (UIView *subview in self.subviews) { + // The cell is of type YTLinkCell + if (![subview isKindOfClass:NSClassFromString(@"YTLinkCell")]) { + continue; } - // Move all subviews that are below this one upwards to remove blank space - CGFloat viewHeight = self.frame.size.height; - bool foundThisSubview = false; - for (UIView *subview in self.superview.subviews) { - if (foundThisSubview) { - CGFloat oldX = subview.frame.origin.x; - CGFloat newY = subview.frame.origin.y - viewHeight; - CGFloat width = subview.frame.size.width; - CGFloat height = subview.frame.size.height; - subview.frame = CGRectMake(oldX, newY, width, height); - } - // If we find this subview, we know that all subviews below it are to be moved - if (subview == self) { - foundThisSubview = true; - } + // Get the badge of this cell, as it is language-independent and unique + YTIconBadgeView *badgeView = [subview valueForKey:@"_iconBadgeView"]; + if (!badgeView) { + continue; + } + // Walk down the subviews to get to a specific view + UIView *firstSubview = badgeView.subviews.firstObject; + if (!subview) { + continue; + } + UIImageView *secondSubview = firstSubview.subviews.firstObject; + if (!secondSubview || ![secondSubview respondsToSelector:@selector(description)]) { + continue; + } + // Check if "yt_outline_youtube_logo_icon" is in the description + NSString *description = secondSubview.description; + if ([description containsString:@"yt_outline_youtube_logo_icon"]) { + foundSubview = subview; + break; } - // Remove this cell from existence - self.hidden = YES; - self.frame = CGRectZero; - [self removeFromSuperview]; } + if (self.hidden) { + return; + } + + // Move all subviews that are below this cell upwards to remove blank space + CGFloat viewHeight = foundSubview.frame.size.height; + bool foundThisSubview = false; + // Create a copy of foundSubview.superview.subviews + NSArray *subviewsCopy = [foundSubview.superview.subviews copy]; + for (UIView *subview in subviewsCopy) { + if (foundThisSubview) { + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Debug" + message:@"moved a view up" + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:nil]; + + [alert addAction:okAction]; + // Find the appropriate view controller to present this alert + UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; + while (rootViewController.presentedViewController) { + rootViewController = rootViewController.presentedViewController; + } + [rootViewController presentViewController:alert animated:YES completion:nil]; + }); + CGFloat oldX = subview.frame.origin.x; + CGFloat newY = subview.frame.origin.y - viewHeight; + CGFloat width = subview.frame.size.width; + CGFloat height = subview.frame.size.height; + subview.frame = CGRectMake(oldX, newY, width, height); + } + // If we find this subview, we know that all subviews below it are to be moved + if (subview == foundSubview) { + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Debug" + message:@"found this subview" + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:nil]; + + [alert addAction:okAction]; + // Find the appropriate view controller to present this alert + UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; + while (rootViewController.presentedViewController) { + rootViewController = rootViewController.presentedViewController; + } + [rootViewController presentViewController:alert animated:YES completion:nil]; + }); + foundThisSubview = true; + } + } + // Remove this cell from existence + foundSubview.hidden = YES; + foundSubview.frame = CGRectZero; + } %end %end diff --git a/Sources/uYouPlusSettings.xm b/Sources/uYouPlusSettings.xm index eb65e79..00c8377 100644 --- a/Sources/uYouPlusSettings.xm +++ b/Sources/uYouPlusSettings.xm @@ -275,7 +275,7 @@ extern NSBundle *uYouPlusBundle(); SWITCH_ITEM2(LOC(@"Hide `Your data in YouTube` Section"), LOC(@"App restart is required."), @"disableYourDataInYouTubeSection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Privacy` Section"), LOC(@"App restart is required."), @"disablePrivacySection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Live Chat` Section"), LOC(@"App restart is required."), @"disableLiveChatSection_enabled"); - SWITCH_ITEM2(LOC(@"Hide Premium Promos"), LOC(@"App restart is required."), @"hidePremiumPromos_enabled"); + SWITCH_ITEM2(LOC(@"Hide `Get Youtube Premium` Section"), LOC(@"App restart is required."), @"hidePremiumPromos_enabled"); # pragma mark - UI interface options SECTION_HEADER(LOC(@"UI Interface Options")); From ae75588dcc2b3b6a9a3f2cc9e46f88fd7632b5cc Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Fri, 5 Apr 2024 03:38:35 -0700 Subject: [PATCH 07/14] New method using data manipulation --- Sources/uYouPlus.h | 40 +++++++- Sources/uYouPlus.xm | 196 +++++++++++++++++++++--------------- Sources/uYouPlusSettings.xm | 1 + 3 files changed, 150 insertions(+), 87 deletions(-) diff --git a/Sources/uYouPlus.h b/Sources/uYouPlus.h index d45f923..5be918e 100644 --- a/Sources/uYouPlus.h +++ b/Sources/uYouPlus.h @@ -28,6 +28,9 @@ #import "Tweaks/YouTubeHeader/YTInnerTubeCollectionViewController.h" #import "Tweaks/YouTubeHeader/YTPivotBarItemView.h" #import "Tweaks/YouTubeHeader/YTCollectionViewCell.h" +#import "Tweaks/YouTubeHeader/YTIFormattedString.h" +#import "Tweaks/YouTubeHeader/GPBMessage.h" +#import "Tweaks/YouTubeHeader/YTIStringRun.h" // Hide buttons under the video player by @PoomSmart #import "Tweaks/YouTubeHeader/ASCollectionElement.h" @@ -66,12 +69,41 @@ @end // Hide Premium Promo in You tab - @bhackel -@interface YTIconBadgeView : UIView +@interface YTIIconThumbnailRenderer : GPBMessage + @property (nonatomic, strong) YTIIcon *icon; + - (bool)hasIcon; @end -@interface YTLinkCell : YTCollectionViewCell -@property(readonly, nonatomic) YTIconBadgeView *_iconBadgeView; +@interface YTICompactListItemThumbnailSupportedRenderers : GPBMessage + @property (nonatomic, strong) YTIIconThumbnailRenderer *iconThumbnailRenderer; + - (bool)hasIconThumbnailRenderer; +@end +@interface YTICompactListItemRenderer : GPBMessage + @property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; + @property (nonatomic, strong) YTIFormattedString *title; + - (bool)hasThumbnail; + - (bool)hasTitle; +@end +@interface YTIIcon (uYouEnhanced) + - (bool)hasIconType; +@end +@interface YTICompactLinkRenderer : GPBMessage + @property (nonatomic, strong) YTIIcon *icon; + @property (nonatomic, strong) YTIFormattedString *title; + @property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; + - (bool)hasIcon; + - (bool)hasThumbnail; +@end +@interface YTIItemSectionSupportedRenderers (uYouEnhanced) + @property(readonly, nonatomic) YTICompactLinkRenderer *compactLinkRenderer; + @property(readonly, nonatomic) YTICompactListItemRenderer *compactListItemRenderer; + - (bool)hasCompactLinkRenderer; + - (bool)hasCompactListItemRenderer; +@end +@interface YTAppCollectionViewController : YTInnerTubeCollectionViewController +@end +@interface YTInnerTubeCollectionViewController (uYouEnhanced) + @property(readonly, nonatomic) YTISectionListRenderer *model; @end - // uYouPlus @interface YTHeaderLogoController : UIView diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index a40c619..57d4a6f 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -214,6 +214,7 @@ BOOL isAd(YTIElementRenderer *self) { // YTNoHoverCards: https://github.com/level3tjg/YTNoHoverCards %hook YTCreatorEndscreenView - (void)setHidden:(BOOL)hidden { + NSLog(@"bhackel debug: setHidden method called"); if (IS_ENABLED(@"hideHoverCards_enabled")) hidden = YES; %orig; @@ -274,99 +275,125 @@ BOOL isAd(YTIElementRenderer *self) { - (BOOL)savedSettingShouldExpire { return NO; } %end -// Hide Premium promos in "You" and "Library" tab - @bhackel +// Hide Premium promos in "You" tab - @bhackel %group gHidePremiumPromos // Hide "Get Youtube Premium" in the "You" tab - %hook YTAsyncCollectionView - // Property for tracking if the cell was hidden - - (void)layoutSubviews { - %orig; - // Check each subview for the "Get YouTube Premium" cell - UIView *foundSubview = nil; - for (UIView *subview in self.subviews) { - // The cell is of type YTLinkCell - if (![subview isKindOfClass:NSClassFromString(@"YTLinkCell")]) { - continue; + %hook YTAppCollectionViewController + - (void)loadWithModel:(YTISectionListRenderer *)model { + NSLog(@"bhackel debug: loadWithModel method called"); + NSMutableArray *overallContentsArray = model.contentsArray; + // Check each item in the overall array - this represents the whole You page + YTISectionListSupportedRenderers *supportedRenderers; + for (supportedRenderers in overallContentsArray) { + NSLog(@"bhackel debug: in 1st loop"); + YTIItemSectionRenderer *itemSectionRenderer = supportedRenderers.itemSectionRenderer; + // Check each subobject - this would be visible as a cell in the You page + NSMutableArray *subContentsArray = itemSectionRenderer.contentsArray; + bool found = NO; + YTIItemSectionSupportedRenderers *itemSectionSupportedRenderers; + for (itemSectionSupportedRenderers in subContentsArray) { + NSLog(@"bhackel debug: in 2nd loop"); + // Check for a link cell + if ([itemSectionSupportedRenderers hasCompactLinkRenderer]) { + NSLog(@"bhackel debug: hasCompactLinkRenderer"); + YTICompactLinkRenderer *compactLinkRenderer = [itemSectionSupportedRenderers compactLinkRenderer]; + // Check for an icon in this cell + if ([compactLinkRenderer hasIcon]) { + NSLog(@"bhackel debug: hasIcon"); + YTIIcon *icon = [compactLinkRenderer icon]; + // Check if the icon is for the premium promo + if ([icon hasIconType] && icon.iconType == 117) { + NSLog(@"bhackel debug: iconType == 117, found... :D"); + found = YES; + break; + } + } + } } - // Get the badge of this cell, as it is language-independent and unique - YTIconBadgeView *badgeView = [subview valueForKey:@"_iconBadgeView"]; - if (!badgeView) { - continue; - } - // Walk down the subviews to get to a specific view - UIView *firstSubview = badgeView.subviews.firstObject; - if (!subview) { - continue; - } - UIImageView *secondSubview = firstSubview.subviews.firstObject; - if (!secondSubview || ![secondSubview respondsToSelector:@selector(description)]) { - continue; - } - // Check if "yt_outline_youtube_logo_icon" is in the description - NSString *description = secondSubview.description; - if ([description containsString:@"yt_outline_youtube_logo_icon"]) { - foundSubview = subview; + // Remove object from array - perform outside of loop to avoid error + if (found) { + NSLog(@"bhackel debug: removing..."); + [subContentsArray removeObject:itemSectionSupportedRenderers]; break; } } - if (self.hidden) { - return; - } - - // Move all subviews that are below this cell upwards to remove blank space - CGFloat viewHeight = foundSubview.frame.size.height; - bool foundThisSubview = false; - // Create a copy of foundSubview.superview.subviews - NSArray *subviewsCopy = [foundSubview.superview.subviews copy]; - for (UIView *subview in subviewsCopy) { - if (foundThisSubview) { - dispatch_async(dispatch_get_main_queue(), ^{ - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Debug" - message:@"moved a view up" - preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:nil]; - - [alert addAction:okAction]; - // Find the appropriate view controller to present this alert - UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; - while (rootViewController.presentedViewController) { - rootViewController = rootViewController.presentedViewController; + %orig; + } + %end +%end + +// Fake premium in the You tab - @bhackel +%group gYouTabFakePremium + %hook YTAppCollectionViewController + - (void)loadWithModel:(YTISectionListRenderer *)model { + NSLog(@"bhackel debug: loadWithModel method called"); + NSUInteger yourVideosIndex = -1; + NSMutableArray *overallContentsArray = model.contentsArray; + // Check each item in the overall array - this represents the whole You page + YTISectionListSupportedRenderers *supportedRenderers; + for (supportedRenderers in overallContentsArray) { + NSLog(@"bhackel debug: in 1st loop"); + YTIItemSectionRenderer *itemSectionRenderer = supportedRenderers.itemSectionRenderer; + // Check each subobject - this would be visible as a cell in the You page + NSMutableArray *subContentsArray = itemSectionRenderer.contentsArray; + YTIItemSectionSupportedRenderers *itemSectionSupportedRenderers; + for (itemSectionSupportedRenderers in subContentsArray) { + NSLog(@"bhackel debug: in 2nd loop"); + // Check for a specific type of cell of type CompactLinkRenderer + if ([itemSectionSupportedRenderers hasCompactLinkRenderer]) { + NSLog(@"bhackel debug: hasCompactLinkRenderer"); + YTICompactLinkRenderer *compactLinkRenderer = [itemSectionSupportedRenderers compactLinkRenderer]; + // Check for an icon in this cell + if ([compactLinkRenderer hasIcon]) { + NSLog(@"bhackel debug: hasIcon"); + YTIIcon *icon = [compactLinkRenderer icon]; + // Check if the icon is for the premium promo + if ([icon hasIconType] && icon.iconType == 117) { + NSLog(@"bhackel debug: iconType == 117, found... :D"); + // Modify the icon type to be Premium + icon.iconType = 741; + // Modify the text + ((YTIStringRun *)(compactLinkRenderer.title.runsArray.firstObject)).text = @"Your Premium benefits"; + } } - [rootViewController presentViewController:alert animated:YES completion:nil]; - }); - CGFloat oldX = subview.frame.origin.x; - CGFloat newY = subview.frame.origin.y - viewHeight; - CGFloat width = subview.frame.size.width; - CGFloat height = subview.frame.size.height; - subview.frame = CGRectMake(oldX, newY, width, height); + } + // Check for a specific type of cell of type CompactListItemRenderer + if ([itemSectionSupportedRenderers hasCompactListItemRenderer]) { + NSLog(@"bhackel debug: 2 hasCompactListItemRenderer"); + YTICompactListItemRenderer *compactListItemRenderer = itemSectionSupportedRenderers.compactListItemRenderer; + if ([compactListItemRenderer hasThumbnail]) { + NSLog(@"bhackel debug: 2 hasThumbnail"); + YTICompactListItemThumbnailSupportedRenderers *thumbnail = compactListItemRenderer.thumbnail; + if ([thumbnail hasIconThumbnailRenderer]) { + NSLog(@"bhackel debug: 2 hasIconThumbnailRenderer"); + YTIIconThumbnailRenderer *iconThumbnailRenderer = thumbnail.iconThumbnailRenderer; + if ([iconThumbnailRenderer hasIcon]) { + NSLog(@"bhackel debug: 2 hasIcon"); + YTIIcon *icon = iconThumbnailRenderer.icon; + if ([icon hasIconType] && icon.iconType == 658) { + NSLog(@"bhackel debug: 2 iconType == 658, found... :D"); + // Note the index of this cell in the array + yourVideosIndex = [subContentsArray indexOfObject:itemSectionSupportedRenderers]; + } + } + } + } + } } - // If we find this subview, we know that all subviews below it are to be moved - if (subview == foundSubview) { - dispatch_async(dispatch_get_main_queue(), ^{ - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Debug" - message:@"found this subview" - preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" - style:UIAlertActionStyleDefault - handler:nil]; - - [alert addAction:okAction]; - // Find the appropriate view controller to present this alert - UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; - while (rootViewController.presentedViewController) { - rootViewController = rootViewController.presentedViewController; - } - [rootViewController presentViewController:alert animated:YES completion:nil]; - }); - foundThisSubview = true; + if (yourVideosIndex != -1) { + NSLog(@"bhackel debug: yourVideosIndex != -1"); + // Create a new cell with the same properties as the original cell + YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosIndex] copy]; + // Modify the text + ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = @"Downloads"; + // Modify the icon + newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; + // Insert the new cell at the index of the original cell + [subContentsArray insertObject:newItemSectionSupportedRenderers atIndex:yourVideosIndex + 1]; + yourVideosIndex = -1; } } - // Remove this cell from existence - foundSubview.hidden = YES; - foundSubview.frame = CGRectZero; - + %orig; } %end %end @@ -1423,6 +1450,9 @@ static BOOL findCell(ASNodeController *nodeController, NSArray *ide if (IS_ENABLED(@"hidePremiumPromos_enabled")) { %init(gHidePremiumPromos); } + if (IS_ENABLED(@"youTabFakePremium_enabled")) { + %init(gYouTabFakePremium); + } // YTNoModernUI - @arichorn BOOL ytNoModernUIEnabled = IS_ENABLED(@"ytNoModernUI_enabled"); diff --git a/Sources/uYouPlusSettings.xm b/Sources/uYouPlusSettings.xm index 00c8377..f1651e4 100644 --- a/Sources/uYouPlusSettings.xm +++ b/Sources/uYouPlusSettings.xm @@ -276,6 +276,7 @@ extern NSBundle *uYouPlusBundle(); SWITCH_ITEM2(LOC(@"Hide `Privacy` Section"), LOC(@"App restart is required."), @"disablePrivacySection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Live Chat` Section"), LOC(@"App restart is required."), @"disableLiveChatSection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Get Youtube Premium` Section"), LOC(@"App restart is required."), @"hidePremiumPromos_enabled"); + SWITCH_ITEM2(LOC(@"Fake Premium in You tab"), LOC(@"Makes it look like you have Premium. English only."), @"youTabFakePremium_enabled"); # pragma mark - UI interface options SECTION_HEADER(LOC(@"UI Interface Options")); From 12c6c4fb5a3780ea571da3454d424111803e417e Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Sun, 7 Apr 2024 14:11:53 -0500 Subject: [PATCH 08/14] Feature: Fake Premium in You tab --- Sources/uYouPlus.xm | 185 ++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 103 deletions(-) diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 57d4a6f..085e9e9 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -214,7 +214,6 @@ BOOL isAd(YTIElementRenderer *self) { // YTNoHoverCards: https://github.com/level3tjg/YTNoHoverCards %hook YTCreatorEndscreenView - (void)setHidden:(BOOL)hidden { - NSLog(@"bhackel debug: setHidden method called"); if (IS_ENABLED(@"hideHoverCards_enabled")) hidden = YES; %orig; @@ -275,127 +274,107 @@ BOOL isAd(YTIElementRenderer *self) { - (BOOL)savedSettingShouldExpire { return NO; } %end -// Hide Premium promos in "You" tab - @bhackel +// Hide "Get Youtube Premium" in "You" tab - @bhackel %group gHidePremiumPromos - // Hide "Get Youtube Premium" in the "You" tab - %hook YTAppCollectionViewController - - (void)loadWithModel:(YTISectionListRenderer *)model { - NSLog(@"bhackel debug: loadWithModel method called"); - NSMutableArray *overallContentsArray = model.contentsArray; - // Check each item in the overall array - this represents the whole You page - YTISectionListSupportedRenderers *supportedRenderers; - for (supportedRenderers in overallContentsArray) { - NSLog(@"bhackel debug: in 1st loop"); - YTIItemSectionRenderer *itemSectionRenderer = supportedRenderers.itemSectionRenderer; - // Check each subobject - this would be visible as a cell in the You page - NSMutableArray *subContentsArray = itemSectionRenderer.contentsArray; - bool found = NO; - YTIItemSectionSupportedRenderers *itemSectionSupportedRenderers; - for (itemSectionSupportedRenderers in subContentsArray) { - NSLog(@"bhackel debug: in 2nd loop"); - // Check for a link cell - if ([itemSectionSupportedRenderers hasCompactLinkRenderer]) { - NSLog(@"bhackel debug: hasCompactLinkRenderer"); - YTICompactLinkRenderer *compactLinkRenderer = [itemSectionSupportedRenderers compactLinkRenderer]; - // Check for an icon in this cell - if ([compactLinkRenderer hasIcon]) { - NSLog(@"bhackel debug: hasIcon"); - YTIIcon *icon = [compactLinkRenderer icon]; - // Check if the icon is for the premium promo - if ([icon hasIconType] && icon.iconType == 117) { - NSLog(@"bhackel debug: iconType == 117, found... :D"); - found = YES; - break; - } +%hook YTAppCollectionViewController +- (void)loadWithModel:(YTISectionListRenderer *)model { + NSMutableArray *overallContentsArray = model.contentsArray; + // Check each item in the overall array - this represents the whole You page + YTISectionListSupportedRenderers *supportedRenderers; + for (supportedRenderers in overallContentsArray) { + YTIItemSectionRenderer *itemSectionRenderer = supportedRenderers.itemSectionRenderer; + // Check each subobject - this would be visible as a cell in the You page + NSMutableArray *subContentsArray = itemSectionRenderer.contentsArray; + bool found = NO; + YTIItemSectionSupportedRenderers *itemSectionSupportedRenderers; + for (itemSectionSupportedRenderers in subContentsArray) { + // Check for a link cell + if ([itemSectionSupportedRenderers hasCompactLinkRenderer]) { + YTICompactLinkRenderer *compactLinkRenderer = [itemSectionSupportedRenderers compactLinkRenderer]; + // Check for an icon in this cell + if ([compactLinkRenderer hasIcon]) { + YTIIcon *icon = [compactLinkRenderer icon]; + // Check if the icon is for the premium promo + if ([icon hasIconType] && icon.iconType == 117) { + found = YES; + break; } } } - // Remove object from array - perform outside of loop to avoid error - if (found) { - NSLog(@"bhackel debug: removing..."); - [subContentsArray removeObject:itemSectionSupportedRenderers]; - break; - } } - %orig; + // Remove object from array - perform outside of loop to avoid error + if (found) { + [subContentsArray removeObject:itemSectionSupportedRenderers]; + break; + } } - %end + %orig; +} +%end %end // Fake premium in the You tab - @bhackel %group gYouTabFakePremium - %hook YTAppCollectionViewController - - (void)loadWithModel:(YTISectionListRenderer *)model { - NSLog(@"bhackel debug: loadWithModel method called"); - NSUInteger yourVideosIndex = -1; - NSMutableArray *overallContentsArray = model.contentsArray; - // Check each item in the overall array - this represents the whole You page - YTISectionListSupportedRenderers *supportedRenderers; - for (supportedRenderers in overallContentsArray) { - NSLog(@"bhackel debug: in 1st loop"); - YTIItemSectionRenderer *itemSectionRenderer = supportedRenderers.itemSectionRenderer; - // Check each subobject - this would be visible as a cell in the You page - NSMutableArray *subContentsArray = itemSectionRenderer.contentsArray; - YTIItemSectionSupportedRenderers *itemSectionSupportedRenderers; - for (itemSectionSupportedRenderers in subContentsArray) { - NSLog(@"bhackel debug: in 2nd loop"); - // Check for a specific type of cell of type CompactLinkRenderer - if ([itemSectionSupportedRenderers hasCompactLinkRenderer]) { - NSLog(@"bhackel debug: hasCompactLinkRenderer"); - YTICompactLinkRenderer *compactLinkRenderer = [itemSectionSupportedRenderers compactLinkRenderer]; - // Check for an icon in this cell - if ([compactLinkRenderer hasIcon]) { - NSLog(@"bhackel debug: hasIcon"); - YTIIcon *icon = [compactLinkRenderer icon]; - // Check if the icon is for the premium promo - if ([icon hasIconType] && icon.iconType == 117) { - NSLog(@"bhackel debug: iconType == 117, found... :D"); - // Modify the icon type to be Premium - icon.iconType = 741; - // Modify the text - ((YTIStringRun *)(compactLinkRenderer.title.runsArray.firstObject)).text = @"Your Premium benefits"; - } +%hook YTAppCollectionViewController +- (void)loadWithModel:(YTISectionListRenderer *)model { + NSUInteger yourVideosIndex = -1; + NSMutableArray *overallContentsArray = model.contentsArray; + // Check each item in the overall array - this represents the whole You page + YTISectionListSupportedRenderers *supportedRenderers; + for (supportedRenderers in overallContentsArray) { + YTIItemSectionRenderer *itemSectionRenderer = supportedRenderers.itemSectionRenderer; + // Check each subobject - this would be visible as a cell in the You page + NSMutableArray *subContentsArray = itemSectionRenderer.contentsArray; + YTIItemSectionSupportedRenderers *itemSectionSupportedRenderers; + for (itemSectionSupportedRenderers in subContentsArray) { + // Check for a specific type of cell of type CompactLinkRenderer + if ([itemSectionSupportedRenderers hasCompactLinkRenderer]) { + YTICompactLinkRenderer *compactLinkRenderer = [itemSectionSupportedRenderers compactLinkRenderer]; + // Check for an icon in this cell + if ([compactLinkRenderer hasIcon]) { + YTIIcon *icon = [compactLinkRenderer icon]; + // Check if the icon is for the premium promo + if ([icon hasIconType] && icon.iconType == 117) { + // Modify the icon type to be Premium + icon.iconType = 741; + // Modify the text + ((YTIStringRun *)(compactLinkRenderer.title.runsArray.firstObject)).text = @"Your Premium benefits"; } } - // Check for a specific type of cell of type CompactListItemRenderer - if ([itemSectionSupportedRenderers hasCompactListItemRenderer]) { - NSLog(@"bhackel debug: 2 hasCompactListItemRenderer"); - YTICompactListItemRenderer *compactListItemRenderer = itemSectionSupportedRenderers.compactListItemRenderer; - if ([compactListItemRenderer hasThumbnail]) { - NSLog(@"bhackel debug: 2 hasThumbnail"); - YTICompactListItemThumbnailSupportedRenderers *thumbnail = compactListItemRenderer.thumbnail; - if ([thumbnail hasIconThumbnailRenderer]) { - NSLog(@"bhackel debug: 2 hasIconThumbnailRenderer"); - YTIIconThumbnailRenderer *iconThumbnailRenderer = thumbnail.iconThumbnailRenderer; - if ([iconThumbnailRenderer hasIcon]) { - NSLog(@"bhackel debug: 2 hasIcon"); - YTIIcon *icon = iconThumbnailRenderer.icon; - if ([icon hasIconType] && icon.iconType == 658) { - NSLog(@"bhackel debug: 2 iconType == 658, found... :D"); - // Note the index of this cell in the array - yourVideosIndex = [subContentsArray indexOfObject:itemSectionSupportedRenderers]; - } + } + // Check for a specific type of cell of type CompactListItemRenderer + if ([itemSectionSupportedRenderers hasCompactListItemRenderer]) { + YTICompactListItemRenderer *compactListItemRenderer = itemSectionSupportedRenderers.compactListItemRenderer; + if ([compactListItemRenderer hasThumbnail]) { + YTICompactListItemThumbnailSupportedRenderers *thumbnail = compactListItemRenderer.thumbnail; + if ([thumbnail hasIconThumbnailRenderer]) { + YTIIconThumbnailRenderer *iconThumbnailRenderer = thumbnail.iconThumbnailRenderer; + if ([iconThumbnailRenderer hasIcon]) { + YTIIcon *icon = iconThumbnailRenderer.icon; + if ([icon hasIconType] && icon.iconType == 658) { + // Note the index of this cell in the array + yourVideosIndex = [subContentsArray indexOfObject:itemSectionSupportedRenderers]; } } } } } - if (yourVideosIndex != -1) { - NSLog(@"bhackel debug: yourVideosIndex != -1"); - // Create a new cell with the same properties as the original cell - YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosIndex] copy]; - // Modify the text - ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = @"Downloads"; - // Modify the icon - newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; - // Insert the new cell at the index of the original cell - [subContentsArray insertObject:newItemSectionSupportedRenderers atIndex:yourVideosIndex + 1]; - yourVideosIndex = -1; - } } - %orig; + if (yourVideosIndex != -1) { + // Create a new cell with the same properties as the original cell + YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosIndex] copy]; + // Modify the text + ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = @"Downloads"; + // Modify the icon + newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; + // Insert the new cell at the index of the original cell + [subContentsArray insertObject:newItemSectionSupportedRenderers atIndex:yourVideosIndex + 1]; + yourVideosIndex = -1; + } } - %end + %orig; +} +%end %end From 4a02d265eb26e05cd56c0b75802640430e82ac1a Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:09:40 -0500 Subject: [PATCH 09/14] Make changes persist with page refresh --- Sources/uYouPlus.h | 1 + Sources/uYouPlus.xm | 49 ++++++++++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/Sources/uYouPlus.h b/Sources/uYouPlus.h index 5be918e..41ca4e6 100644 --- a/Sources/uYouPlus.h +++ b/Sources/uYouPlus.h @@ -100,6 +100,7 @@ - (bool)hasCompactListItemRenderer; @end @interface YTAppCollectionViewController : YTInnerTubeCollectionViewController +- (void)uYouEnhancedFakePremiumModel:(YTISectionListRenderer *)model; @end @interface YTInnerTubeCollectionViewController (uYouEnhanced) @property(readonly, nonatomic) YTISectionListRenderer *model; diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 085e9e9..d9ae43d 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -316,8 +316,16 @@ BOOL isAd(YTIElementRenderer *self) { // Fake premium in the You tab - @bhackel %group gYouTabFakePremium %hook YTAppCollectionViewController -- (void)loadWithModel:(YTISectionListRenderer *)model { - NSUInteger yourVideosIndex = -1; +/** + * Modify a given renderer data model to fake premium in the You tab + * Replaces the "Get YouTube Premium" cell with a "Your Premium benefits" cell + * and adds a "Downloads" cell below the "Your videos" cell + * @param model The model for the You tab + * TODO Add localization support for the Get Youtube Premium and Downloads text + */ +%new +- (void)uYouEnhancedFakePremiumModel:(YTISectionListRenderer *)model { + NSUInteger yourVideosCellIndex = -1; NSMutableArray *overallContentsArray = model.contentsArray; // Check each item in the overall array - this represents the whole You page YTISectionListSupportedRenderers *supportedRenderers; @@ -327,22 +335,22 @@ BOOL isAd(YTIElementRenderer *self) { NSMutableArray *subContentsArray = itemSectionRenderer.contentsArray; YTIItemSectionSupportedRenderers *itemSectionSupportedRenderers; for (itemSectionSupportedRenderers in subContentsArray) { - // Check for a specific type of cell of type CompactLinkRenderer + // Check for Get Youtube Premium cell, which is of type CompactLinkRenderer if ([itemSectionSupportedRenderers hasCompactLinkRenderer]) { YTICompactLinkRenderer *compactLinkRenderer = [itemSectionSupportedRenderers compactLinkRenderer]; // Check for an icon in this cell if ([compactLinkRenderer hasIcon]) { YTIIcon *icon = [compactLinkRenderer icon]; - // Check if the icon is for the premium promo + // Check if the icon is for the premium advertisement - 117 is magic number for the icon if ([icon hasIconType] && icon.iconType == 117) { // Modify the icon type to be Premium - icon.iconType = 741; + icon.iconType = 741; // Magic number for premium icon // Modify the text ((YTIStringRun *)(compactLinkRenderer.title.runsArray.firstObject)).text = @"Your Premium benefits"; } } } - // Check for a specific type of cell of type CompactListItemRenderer + // Check for Your Videos cell using similar logic explained above if ([itemSectionSupportedRenderers hasCompactListItemRenderer]) { YTICompactListItemRenderer *compactListItemRenderer = itemSectionSupportedRenderers.compactListItemRenderer; if ([compactListItemRenderer hasThumbnail]) { @@ -352,26 +360,35 @@ BOOL isAd(YTIElementRenderer *self) { if ([iconThumbnailRenderer hasIcon]) { YTIIcon *icon = iconThumbnailRenderer.icon; if ([icon hasIconType] && icon.iconType == 658) { - // Note the index of this cell in the array - yourVideosIndex = [subContentsArray indexOfObject:itemSectionSupportedRenderers]; + // Store the index of this cell + yourVideosCellIndex = [subContentsArray indexOfObject:itemSectionSupportedRenderers]; } } } } } } - if (yourVideosIndex != -1) { - // Create a new cell with the same properties as the original cell - YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosIndex] copy]; - // Modify the text + if (yourVideosCellIndex != -1) { + // Create the fake Downloads page by copying the Your Videos page and modifying it + // Note that this must be done outside the loop to avoid a runtime exception + // TODO Link this to the uYou downloads page + YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosCellIndex] copy]; ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = @"Downloads"; - // Modify the icon newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; - // Insert the new cell at the index of the original cell - [subContentsArray insertObject:newItemSectionSupportedRenderers atIndex:yourVideosIndex + 1]; - yourVideosIndex = -1; + // Insert this cell after the Your Videos cell + [subContentsArray insertObject:newItemSectionSupportedRenderers atIndex:yourVideosCellIndex + 1]; + yourVideosCellIndex = -1; } } +} +- (void)loadWithModel:(YTISectionListRenderer *)model { + // This method is called on first load of the You page + [self uYouEnhancedFakePremiumModel:model]; + %orig; +} +- (void)setupSectionListWithModel:(YTISectionListRenderer *)model isLoadingMore:(BOOL)isLoadingMore isRefreshingFromContinuation:(BOOL)isRefreshingFromContinuation { + // This method is called on refresh of the You page + [self uYouEnhancedFakePremiumModel:model]; %orig; } %end From 55cfde9391155ddd31c8c378a965ef821fec0d64 Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Mon, 8 Apr 2024 22:35:48 -0400 Subject: [PATCH 10/14] Avoid adding multiple times --- Sources/uYouPlus.xm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index d9ae43d..ba97bf5 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -322,6 +322,7 @@ BOOL isAd(YTIElementRenderer *self) { * and adds a "Downloads" cell below the "Your videos" cell * @param model The model for the You tab * TODO Add localization support for the Get Youtube Premium and Downloads text + * TODO Combine with the Fake Youtube Premium logo */ %new - (void)uYouEnhancedFakePremiumModel:(YTISectionListRenderer *)model { @@ -368,7 +369,7 @@ BOOL isAd(YTIElementRenderer *self) { } } } - if (yourVideosCellIndex != -1) { + if (yourVideosCellIndex != -1 && subContentsArray[yourVideosCellIndex].accessibilityLabel == nil) { // Create the fake Downloads page by copying the Your Videos page and modifying it // Note that this must be done outside the loop to avoid a runtime exception // TODO Link this to the uYou downloads page @@ -377,6 +378,8 @@ BOOL isAd(YTIElementRenderer *self) { newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; // Insert this cell after the Your Videos cell [subContentsArray insertObject:newItemSectionSupportedRenderers atIndex:yourVideosCellIndex + 1]; + // Inject a note to not modify this again + subContentsArray[yourVideosCellIndex].accessibilityLabel = @"uYouEnhanced Modified"; yourVideosCellIndex = -1; } } From 7fbdb6c5f7ef3d916b237d69681fc000b575e916 Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Tue, 9 Apr 2024 00:02:36 -0400 Subject: [PATCH 11/14] Combine Premium Logo and fake You tab --- Sources/uYouPlus.xm | 85 ++++++++++--------------------------- Sources/uYouPlusSettings.xm | 3 +- 2 files changed, 24 insertions(+), 64 deletions(-) diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index ba97bf5..805e1c2 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -133,59 +133,6 @@ BOOL isAd(YTIElementRenderer *self) { %end %end -// YouTube Premium Logo - @arichornlover - this doesn't always function -// Modern implementation - @bhackel -%group gPremiumYouTubeLogo -%hook YTHeaderLogoController - - (void)setTopbarLogoRenderer:(id)renderer { - // Modify the type of the icon before setting the renderer - YTITopbarLogoRenderer *logoRenderer = (YTITopbarLogoRenderer *)renderer; - YTIIcon *iconImage = logoRenderer.iconImage; - iconImage.iconType = 537; // magic number for Premium icon, hopefully it doesnt change. 158 is default logo. - // Use this modified renderer - %orig(logoRenderer); - } - // For when spoofing before 18.34.5 - - (void)setPremiumLogo:(BOOL)isPremiumLogo { - isPremiumLogo = YES; - %orig; - } - - (BOOL)isPremiumLogo { - return YES; - } -%end - -/* -%hook YTHeaderLogoController -- (void)setPremiumLogo:(BOOL)isPremiumLogo { - isPremiumLogo = YES; - %orig; -} -- (BOOL)isPremiumLogo { - return YES; -} -- (void)setTopbarLogoRenderer:(id)renderer { -} -%end - -// Workaround: fix YouTube Premium Logo not working on v18.35.4 or above. -%hook YTVersionUtils // Working Version for Premium Logo -+ (NSString *)appVersion { return @"18.34.5"; } -%end - -%hook YTSettingsCell // Remove v18.34.5 Version Number - @Dayanch96 -- (void)setDetailText:(id)arg1 { - NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; - NSString *appVersion = infoDictionary[@"CFBundleShortVersionString"]; - - if ([arg1 isEqualToString:@"18.34.5"]) { - arg1 = appVersion; - } %orig(arg1); -} -%end -*/ -%end - // Fix App Group Directory by move it to document directory %hook NSFileManager - (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier { @@ -313,8 +260,28 @@ BOOL isAd(YTIElementRenderer *self) { %end %end -// Fake premium in the You tab - @bhackel -%group gYouTabFakePremium +// Fake premium - @bhackel +%group gFakePremium +// YouTube Premium Logo - @arichornlover - this doesn't always function +// Modern implementation - @bhackel +%hook YTHeaderLogoController + - (void)setTopbarLogoRenderer:(id)renderer { + // Modify the type of the icon before setting the renderer + YTITopbarLogoRenderer *logoRenderer = (YTITopbarLogoRenderer *)renderer; + YTIIcon *iconImage = logoRenderer.iconImage; + iconImage.iconType = 537; // magic number for Premium icon, hopefully it doesnt change. 158 is default logo. + // Use this modified renderer + %orig(logoRenderer); + } + // For when spoofing before 18.34.5 + - (void)setPremiumLogo:(BOOL)isPremiumLogo { + isPremiumLogo = YES; + %orig; + } + - (BOOL)isPremiumLogo { + return YES; + } +%end %hook YTAppCollectionViewController /** * Modify a given renderer data model to fake premium in the You tab @@ -1353,9 +1320,6 @@ static BOOL findCell(ASNodeController *nodeController, NSArray *ide if (IS_ENABLED(@"centerYouTubeLogo_enabled")) { %init(gCenterYouTubeLogo); } - if (IS_ENABLED(@"premiumYouTubeLogo_enabled")) { - %init(gPremiumYouTubeLogo); - } if (IS_ENABLED(@"hideSubscriptionsNotificationBadge_enabled")) { %init(gHideSubscriptionsNotificationBadge); } @@ -1450,7 +1414,7 @@ static BOOL findCell(ASNodeController *nodeController, NSArray *ide %init(gHidePremiumPromos); } if (IS_ENABLED(@"youTabFakePremium_enabled")) { - %init(gYouTabFakePremium); + %init(gFakePremium); } // YTNoModernUI - @arichorn @@ -1458,14 +1422,11 @@ static BOOL findCell(ASNodeController *nodeController, NSArray *ide if (ytNoModernUIEnabled) { NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setBool:NO forKey:@"enableVersionSpoofer_enabled"]; - [userDefaults setBool:NO forKey:@"premiumYouTubeLogo_enabled"]; } else { BOOL enableVersionSpooferEnabled = IS_ENABLED(@"enableVersionSpoofer_enabled"); - BOOL premiumYouTubeLogoEnabled = IS_ENABLED(@"premiumYouTubeLogo_enabled"); NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setBool:enableVersionSpooferEnabled forKey:@"enableVersionSpoofer_enabled"]; - [userDefaults setBool:premiumYouTubeLogoEnabled forKey:@"premiumYouTubeLogo_enabled"]; } NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; [userDefaults setBool:ytNoModernUIEnabled ? ytNoModernUIEnabled : [userDefaults boolForKey:@"fixLowContrastMode_enabled"] forKey:@"fixLowContrastMode_enabled"]; diff --git a/Sources/uYouPlusSettings.xm b/Sources/uYouPlusSettings.xm index f1651e4..90cc4a9 100644 --- a/Sources/uYouPlusSettings.xm +++ b/Sources/uYouPlusSettings.xm @@ -276,7 +276,6 @@ extern NSBundle *uYouPlusBundle(); SWITCH_ITEM2(LOC(@"Hide `Privacy` Section"), LOC(@"App restart is required."), @"disablePrivacySection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Live Chat` Section"), LOC(@"App restart is required."), @"disableLiveChatSection_enabled"); SWITCH_ITEM2(LOC(@"Hide `Get Youtube Premium` Section"), LOC(@"App restart is required."), @"hidePremiumPromos_enabled"); - SWITCH_ITEM2(LOC(@"Fake Premium in You tab"), LOC(@"Makes it look like you have Premium. English only."), @"youTabFakePremium_enabled"); # pragma mark - UI interface options SECTION_HEADER(LOC(@"UI Interface Options")); @@ -915,7 +914,7 @@ extern NSBundle *uYouPlusBundle(); # pragma mark - Miscellaneous SECTION_HEADER(LOC(@"MISCELLANEOUS")); - SWITCH_ITEM(LOC(@"YouTube Premium Logo"), LOC(@"Toggle this to use the official YouTube Premium Logo. App restart is required."), @"premiumYouTubeLogo_enabled"); + SWITCH_ITEM2(LOC(@"Fake Premium"), LOC(@"Uses Premium logo and creates fake buttons in the You tab"), @"youTabFakePremium_enabled"); // SWITCH_ITEM(LOC(@"Center YouTube Logo"), LOC(@"Toggle this to move the official YouTube Logo to the Center. App restart is required."), @"centerYouTubeLogo_enabled"); SWITCH_ITEM(LOC(@"Hide YouTube Logo"), LOC(@"Toggle this to hide the YouTube Logo in the YouTube App."), @"hideYouTubeLogo_enabled"); SWITCH_ITEM(LOC(@"ENABLE_YT_STARTUP_ANIMATION"), LOC(@"ENABLE_YT_STARTUP_ANIMATION_DESC"), @"ytStartupAnimation_enabled"); From 7932758b4df78537bad331457c157ec336fa7816 Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Mon, 8 Apr 2024 23:19:27 -0700 Subject: [PATCH 12/14] Add localization --- Localizations/uYouPlus.bundle/ar.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/cz.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/de.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/el.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/en.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/es.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/fr.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/he.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/hu.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/it.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/ja.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/ko.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/nl.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/pl.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/pt.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/ro.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/ru.lproj/Localizable.strings | 3 +++ .../uYouPlus.bundle/template.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/th.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/tr.lproj/Localizable.strings | 3 +++ Localizations/uYouPlus.bundle/vi.lproj/Localizable.strings | 3 +++ .../uYouPlus.bundle/zh_cn.lproj/Localizable.strings | 3 +++ .../uYouPlus.bundle/zh_tw.lproj/Localizable.strings | 3 +++ Sources/uYouPlus.xm | 6 ++---- 24 files changed, 71 insertions(+), 4 deletions(-) diff --git a/Localizations/uYouPlus.bundle/ar.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/ar.lproj/Localizable.strings index aa154ae..52dd93f 100644 --- a/Localizations/uYouPlus.bundle/ar.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/ar.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "إصلاح تسجيل الدخول بحساب جوجل (لمستخدمي TrollStore فقط)"; "FIX_GOOGLE_SIGNIN_DESC" = "هذا الخيار لا يعمل إلا إذا كان التطبيق مثبت بواسطة TrollStore: فعل هذا الخيار لتتمكن من تسجيل الدخول بحساب جوجل. يتطلب إعادة تشغيل التطبيق."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/cz.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/cz.lproj/Localizable.strings index ac5193c..d79f5df 100644 --- a/Localizations/uYouPlus.bundle/cz.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/cz.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Opravit přihlášení přes Google (pouze pro uživatele TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Tuto možnost zapněte pouze v případě, že se nemůžete přihlásit pomocí svého účtu Google a aplikace byla nainstalována prostřednictvím TrollStore. Pokud se můžete normálně přihlásit, ponechte ji deaktivovanou. Je vyžadován restart aplikace."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/de.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/de.lproj/Localizable.strings index 4d7a2b2..13b32b6 100755 --- a/Localizations/uYouPlus.bundle/de.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/de.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Google-Anmeldung reparieren (nur für TrollStore-Benutzer!)"; "FIX_GOOGLE_SIGNIN_DESC" = "Aktiviere diese Option nur, wenn Sie sich nicht mit Ihrem Google-Account anmelden können und die App über TrollStore installiert wurde. Wenn Sie sich normal anmelden können, halte diese Option deaktiviert! App-Neustart erforderlich!"; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/el.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/el.lproj/Localizable.strings index d262131..a9e45ad 100644 --- a/Localizations/uYouPlus.bundle/el.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/el.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Διόρθωση σύνδεσης Google (μόνο για χρήστες του TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Ενεργοποιήστε αυτήν την επιλογή μόνο όταν δεν μπορείτε να συνδεθείτε με τον λογαριασμό σας Google και η εφαρμογή έχει εγκατασταθεί μέσω του TrollStore. Εάν μπορείτε να συνδεθείτε κανονικά, διατηρήστε την απενεργοποιημένη. Απαιτείται επανεκκίνηση της εφαρμογής."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/en.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/en.lproj/Localizable.strings index 3c5c831..fd6d1ab 100644 --- a/Localizations/uYouPlus.bundle/en.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/en.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Fix Google Sign in (for TrollStore user only)"; "FIX_GOOGLE_SIGNIN_DESC" = "Only turn on this option when you can't sign in with your Google account and the app was installed via TrollStore. If you can log in normally, keep it disabled. App restart is required."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/es.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/es.lproj/Localizable.strings index 1a26678..4a1856f 100644 --- a/Localizations/uYouPlus.bundle/es.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/es.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Reparar el inicio de sesión de Google (solo para usuarios de TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Active esta opción solo cuando no pueda iniciar sesión con su cuenta de Google y la aplicación se instaló a través de TrollStore. Si puede iniciar sesión normalmente, manténgala desactivada. Es necesario reiniciar la aplicación."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/fr.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/fr.lproj/Localizable.strings index 968215d..c40bcd6 100644 --- a/Localizations/uYouPlus.bundle/fr.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/fr.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Réparer l'identification Google (pour les utilisateurs de TrollStore uniquement)"; "FIX_GOOGLE_SIGNIN_DESC" = "Activez cette option uniquement si vous ne pouvez pas vous connecter avec votre compte Google et que l'application a été installée via TrollStore. Si vous pouvez vous connecter normalement, laissez-la désactivée. Un redémarrage de l'application est nécessaire."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/he.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/he.lproj/Localizable.strings index 21e5834..944d58d 100644 --- a/Localizations/uYouPlus.bundle/he.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/he.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "תקן כניסה של Google (עבור משתמש TrollStore בלבד)"; "FIX_GOOGLE_SIGNIN_DESC" = "הפעל אפשרות זו רק כאשר אינך יכול להיכנס עם חשבון Google שלך והאפליקציה הותקנה דרך TrollStore. אם אתה יכול להתחבר כרגיל, השאר אותה מושבתת. נדרשת הפעלה מחדש של האפליקציה."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/hu.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/hu.lproj/Localizable.strings index 593c00b..5b87565 100644 --- a/Localizations/uYouPlus.bundle/hu.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/hu.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "A Google bejelentkezés javítása (csak a TrollStore-felhasználók számára)"; "FIX_GOOGLE_SIGNIN_DESC" = "Csak akkor kapcsolja be ezt az opciót, ha nem tud bejelentkezni Google-fiókjával, és az alkalmazást a TrollStore-on keresztül telepítették. Ha normálisan be tud jelentkezni, tartsa letiltva. Az alkalmazás újraindítása szükséges."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/it.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/it.lproj/Localizable.strings index 9959160..8bcaec4 100644 --- a/Localizations/uYouPlus.bundle/it.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/it.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Ripara Google Sign in (solo per utenti TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Attiva questa opzione solo quando non puoi accedere al tuo account Google e l'app è stata installata attraverso TrollStore. Se puoi accedere normalmente, tienila disabilitata. È richiesto un riavvio dell'app."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/ja.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/ja.lproj/Localizable.strings index f93b144..918e031 100644 --- a/Localizations/uYouPlus.bundle/ja.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/ja.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Googleのサインインを修正 (TrollStoreユーザーのみ)"; "FIX_GOOGLE_SIGNIN_DESC" = "Googleアカウントでサインインできない場合で、アプリがTrollStore経由でインストールされている場合のみ、このオプションをオンにしてください。通常通りサインインできる場合はオフのままにしてください。アプリの再起動が必要です。"; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/ko.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/ko.lproj/Localizable.strings index 85fd009..4e566be 100644 --- a/Localizations/uYouPlus.bundle/ko.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/ko.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "구글 로그인 문제 수정 (TrollStore 사용자만 해당)"; "FIX_GOOGLE_SIGNIN_DESC" = "TrollStore를 통해 설치된 앱에만 적용됩니다: 구글 계정으로 로그인하려면 이 설정을 켜 주세요. 앱을 다시 시작해야 합니다."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/nl.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/nl.lproj/Localizable.strings index e6ff45b..92b7a2c 100644 --- a/Localizations/uYouPlus.bundle/nl.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/nl.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Fix Inloggen met Google (Alleen voor TrollStore gebruikers)"; "FIX_GOOGLE_SIGNIN_DESC" = "Zet dit aan wanneer je niet kan inloggen met je Google account en je de app hebt geïnstalleerd met Trollstore. Als je in kan loggen laat dit dan met rust. Om dit te activeren moet je de app opnieuw opstarten."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Jouw Premium-voordelen"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/pl.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/pl.lproj/Localizable.strings index 39353b6..c654af9 100644 --- a/Localizations/uYouPlus.bundle/pl.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/pl.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Napraw logowanie się z Google (tylko dla użytkowników TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Włącz tą opcję tylko wtedy, kiedy nie możesz zalogować się swoim kontem Google, a aplikacja została zainstalowana przez TrollStore. Jeżeli da się zalogować normalnie, zostaw to wyłączone. Restart aplikacji jest wymagany."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/pt.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/pt.lproj/Localizable.strings index e9249d7..c46fdc8 100644 --- a/Localizations/uYouPlus.bundle/pt.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/pt.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Corrigir o login do Google (somente para usuários da TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Ative esta opção somente quando você não conseguir fazer login com sua conta do Google e o aplicativo foi instalado via TrollStore. Se você conseguir fazer login normalmente, mantenha-o desativado. A reinicialização do app é necessária."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/ro.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/ro.lproj/Localizable.strings index bc70470..e22a4c8 100644 --- a/Localizations/uYouPlus.bundle/ro.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/ro.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Rezolvare problemă autentificare cont Google (doar pentru utilizatorii TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Activează această opțiune doar în cazul în care nu te poți autentifica în contul tău Google și apariția a fost instalată via TrollStore. Dacă te poți autentifica fără probleme, țineți setarea dezactivată. Este necesară repornirea aplicației."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/ru.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/ru.lproj/Localizable.strings index 92913f7..2fd25b1 100644 --- a/Localizations/uYouPlus.bundle/ru.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/ru.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Исправить авторизацию (TrollStore)"; "FIX_GOOGLE_SIGNIN_DESC" = "Включите данную опцию только, если не можете войти в учетную запись Google, а приложение установлено через TrollStore. Если удается авторизоваться как обычно, оставьте данную опцию отключенной. Потребуется перезагрузка."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/template.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/template.lproj/Localizable.strings index 1565e4a..40df8ae 100644 --- a/Localizations/uYouPlus.bundle/template.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/template.lproj/Localizable.strings @@ -153,3 +153,6 @@ https://github.com/PoomSmart/Return-YouTube-Dislikes/tree/main/layout/Library/Ap "FIX_GOOGLE_SIGNIN" = "Fix Google Sign in (for TrollStore user only)"; "FIX_GOOGLE_SIGNIN_DESC" = "Only turn on this option when you can't sign in with your Google account and the app was installed via TrollStore. If you can log in normally, keep it disabled. App restart is required."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/th.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/th.lproj/Localizable.strings index af0cc34..0fe5481 100644 --- a/Localizations/uYouPlus.bundle/th.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/th.lproj/Localizable.strings @@ -137,3 +137,6 @@ "FIX_GOOGLE_SIGNIN" = "แก้ไขปัญหาการเข้าสู่ระบบบัญชี Google (ใช้ได้สำหรับผู้ใช้ TrollStore เท่านั้น)"; "FIX_GOOGLE_SIGNIN_DESC" = "ใช้ได้เฉพาะเมื่อใช้ TrollStore เพื่อติดตั้งแอปพลิเคชันนี้: หลังจากเปิดใช้งานการตั้งค่านี้ คุณสามารถเข้าสู่ระบบบัญชี Google ของคุณได้ตามปกติ และคุณต้องรีสตาร์ทแอปพลิเคชัน"; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/tr.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/tr.lproj/Localizable.strings index 26bf8b4..949cbbb 100644 --- a/Localizations/uYouPlus.bundle/tr.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/tr.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Google Oturumu Açma'yı düzeltin (yalnızca TrollStore kullanıcıları için)"; "FIX_GOOGLE_SIGNIN_DESC" = "Bu seçeneği yalnızca Google hesabınızla oturum açamadığınızda ve uygulama TrollStore aracılığıyla yüklendiyse aç. Normal olarak giriş yapabiliyorsan, devre dışı bırak. Uygulamanın yeniden başlatılması gerekir."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/vi.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/vi.lproj/Localizable.strings index 70a3c8c..ba16834 100644 --- a/Localizations/uYouPlus.bundle/vi.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/vi.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "Sửa lỗi không thể đăng nhập tài khoản Google"; "FIX_GOOGLE_SIGNIN_DESC" = "Chỉ bật tính năng này khi bạn không thể đăng nhập tài khoản Google và ứng dụng được cài qua TrollStore. Nếu bạn có thể đăng nhập bình thường thì hãy tắt tính năng này. Cần khởi động lại ứng dụng."; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/zh_cn.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/zh_cn.lproj/Localizable.strings index 465ae8c..fccf578 100644 --- a/Localizations/uYouPlus.bundle/zh_cn.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/zh_cn.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "修复 Google 账号登录问题(仅 TrollStore 用户有效)"; "FIX_GOOGLE_SIGNIN_DESC" = "仅在使用 TrollStore 安装本 App 的情况下生效:启用本设置后即可正常登录您的 Google 账号。更改本设置后需要重启 App。"; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Localizations/uYouPlus.bundle/zh_tw.lproj/Localizable.strings b/Localizations/uYouPlus.bundle/zh_tw.lproj/Localizable.strings index bed8bae..fa46497 100644 --- a/Localizations/uYouPlus.bundle/zh_tw.lproj/Localizable.strings +++ b/Localizations/uYouPlus.bundle/zh_tw.lproj/Localizable.strings @@ -138,3 +138,6 @@ "FIX_GOOGLE_SIGNIN" = "修復 Google 帳號登入問題(僅TrollStore 使用者有效)"; "FIX_GOOGLE_SIGNIN_DESC" = "僅在使用 TrollStore 安裝此應用程式時有效:啟用本設定後即可正常登入 Google 帳號,需要重新啟動應用程式。"; + +"FAKE_YOUR_PREMIUM_BENEFITS" = "Your Premium benefits"; +"FAKE_DOWNLOADS" = "Downloads"; diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 805e1c2..4a9269e 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -288,8 +288,6 @@ BOOL isAd(YTIElementRenderer *self) { * Replaces the "Get YouTube Premium" cell with a "Your Premium benefits" cell * and adds a "Downloads" cell below the "Your videos" cell * @param model The model for the You tab - * TODO Add localization support for the Get Youtube Premium and Downloads text - * TODO Combine with the Fake Youtube Premium logo */ %new - (void)uYouEnhancedFakePremiumModel:(YTISectionListRenderer *)model { @@ -314,7 +312,7 @@ BOOL isAd(YTIElementRenderer *self) { // Modify the icon type to be Premium icon.iconType = 741; // Magic number for premium icon // Modify the text - ((YTIStringRun *)(compactLinkRenderer.title.runsArray.firstObject)).text = @"Your Premium benefits"; + ((YTIStringRun *)(compactLinkRenderer.title.runsArray.firstObject)).text = LOC(@"FAKE_YOUR_PREMIUM_BENEFITS"); } } } @@ -341,7 +339,7 @@ BOOL isAd(YTIElementRenderer *self) { // Note that this must be done outside the loop to avoid a runtime exception // TODO Link this to the uYou downloads page YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosCellIndex] copy]; - ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = @"Downloads"; + ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = LOC(@"FAKE_DOWNLOADS"); newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; // Insert this cell after the Your Videos cell [subContentsArray insertObject:newItemSectionSupportedRenderers atIndex:yourVideosCellIndex + 1]; From 7c39d6659d4f4cdbd4cff7b94f8d4d8fa3158544 Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Sun, 14 Apr 2024 16:20:50 -0700 Subject: [PATCH 13/14] Add link to uYou page --- Sources/uYouPlus.h | 48 +++++++++++++++++++++++---------------- Sources/uYouPlus.xm | 41 ++++++++++++++++++++++++++++++++- Sources/uYouPlusPatches.h | 2 +- 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/Sources/uYouPlus.h b/Sources/uYouPlus.h index 0cd083d..9fd7edc 100644 --- a/Sources/uYouPlus.h +++ b/Sources/uYouPlus.h @@ -33,6 +33,7 @@ #import #import #import +#import // Hide buttons under the video player by @PoomSmart #import @@ -72,40 +73,49 @@ // Hide Premium Promo in You tab - @bhackel @interface YTIIconThumbnailRenderer : GPBMessage - @property (nonatomic, strong) YTIIcon *icon; - - (bool)hasIcon; +@property (nonatomic, strong) YTIIcon *icon; +- (bool)hasIcon; @end @interface YTICompactListItemThumbnailSupportedRenderers : GPBMessage - @property (nonatomic, strong) YTIIconThumbnailRenderer *iconThumbnailRenderer; - - (bool)hasIconThumbnailRenderer; +@property (nonatomic, strong) YTIIconThumbnailRenderer *iconThumbnailRenderer; +- (bool)hasIconThumbnailRenderer; @end @interface YTICompactListItemRenderer : GPBMessage - @property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; - @property (nonatomic, strong) YTIFormattedString *title; - - (bool)hasThumbnail; - - (bool)hasTitle; +@property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; +@property (nonatomic, strong) YTIFormattedString *title; +- (bool)hasThumbnail; +- (bool)hasTitle; @end @interface YTIIcon (uYouEnhanced) - - (bool)hasIconType; +- (bool)hasIconType; @end @interface YTICompactLinkRenderer : GPBMessage - @property (nonatomic, strong) YTIIcon *icon; - @property (nonatomic, strong) YTIFormattedString *title; - @property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; - - (bool)hasIcon; - - (bool)hasThumbnail; +@property (nonatomic, strong) YTIIcon *icon; +@property (nonatomic, strong) YTIFormattedString *title; +@property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; +- (bool)hasIcon; +- (bool)hasThumbnail; @end @interface YTIItemSectionSupportedRenderers (uYouEnhanced) - @property(readonly, nonatomic) YTICompactLinkRenderer *compactLinkRenderer; - @property(readonly, nonatomic) YTICompactListItemRenderer *compactListItemRenderer; - - (bool)hasCompactLinkRenderer; - - (bool)hasCompactListItemRenderer; +@property(readonly, nonatomic) YTICompactLinkRenderer *compactLinkRenderer; +@property(readonly, nonatomic) YTICompactListItemRenderer *compactListItemRenderer; +- (bool)hasCompactLinkRenderer; +- (bool)hasCompactListItemRenderer; @end @interface YTAppCollectionViewController : YTInnerTubeCollectionViewController - (void)uYouEnhancedFakePremiumModel:(YTISectionListRenderer *)model; @end @interface YTInnerTubeCollectionViewController (uYouEnhanced) - @property(readonly, nonatomic) YTISectionListRenderer *model; +@property(readonly, nonatomic) YTISectionListRenderer *model; +@end +@interface YTLinkCell : UICollectionViewCell +@end +@interface YTCompactListItemCellController : YTCellController +@property(nonatomic, weak, readwrite) id entry; +@end +@interface GLViewPagerViewController : UIViewController +@end +@interface DownloadsPagerVC : GLViewPagerViewController @end // uYouPlus diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 9d67e34..15a533b 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -359,7 +359,6 @@ BOOL isAd(YTIElementRenderer *self) { if (yourVideosCellIndex != -1 && subContentsArray[yourVideosCellIndex].accessibilityLabel == nil) { // Create the fake Downloads page by copying the Your Videos page and modifying it // Note that this must be done outside the loop to avoid a runtime exception - // TODO Link this to the uYou downloads page YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosCellIndex] copy]; ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = LOC(@"FAKE_DOWNLOADS"); newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; @@ -368,6 +367,8 @@ BOOL isAd(YTIElementRenderer *self) { // Inject a note to not modify this again subContentsArray[yourVideosCellIndex].accessibilityLabel = @"uYouEnhanced Modified"; yourVideosCellIndex = -1; + // Insert accessibility info into the YTLinkCell so that it can be hooked later + newItemSectionSupportedRenderers.compactListItemRenderer.title.accessibility.accessibilityData.label = @"uYouEnhanced Fake Downloads"; } } } @@ -382,6 +383,44 @@ BOOL isAd(YTIElementRenderer *self) { %orig; } %end +// Change the destination of the fake Downloads cell +%hook YTCompactListItemCellController +- (void)didSelectItem { + NSLog(@"bhackel: _handleMenuGesture"); + id entry = self.entry; + // Avoid modifying the wrong things + if (![entry isKindOfClass:NSClassFromString(@"YTICompactListItemRenderer")]) { + %orig; + return; + } + YTICompactListItemRenderer *compactListItemRenderer = (YTICompactListItemRenderer *)entry; + // Check title for accessibility label that was stored + if ([compactListItemRenderer.title.accessibility.accessibilityData.label isEqualToString:@"uYouEnhanced Fake Downloads"]) { + NSLog(@"bhackel: uYouEnhanced Fake Downloads"); + // Chatgpt generated code to show DownloadsPagerVC, which is the uYou page + // Instantiate your custom DownloadsPagerVC + // Avoid linker stuff + Class downloadsPagerVCClass = objc_getClass("DownloadsPagerVC"); + if (downloadsPagerVCClass) { + id downloadsPagerVCid = [[downloadsPagerVCClass alloc] init]; + // Now you can use `downloadsPagerVC` as needed + } + DownloadsPagerVC *downloadsPagerVC = (DownloadsPagerVC *)downloadsPagerVCid; + // Assuming you need navigation controller to push + UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + UINavigationController *navigationController = (UINavigationController *)rootViewController; + if ([navigationController isKindOfClass:[UINavigationController class]]) { + [navigationController pushViewController:downloadsPagerVC animated:YES]; + } else { + // If not in a navigation controller context, present modally + [rootViewController presentViewController:downloadsPagerVC animated:YES completion:nil]; + } + } else { + NSLog(@"bhackel: Not uYouEnhanced Fake Downloads"); + %orig; + } +} +%end %end diff --git a/Sources/uYouPlusPatches.h b/Sources/uYouPlusPatches.h index a9231b6..9bf3238 100644 --- a/Sources/uYouPlusPatches.h +++ b/Sources/uYouPlusPatches.h @@ -32,7 +32,7 @@ // @end // Fix uYou's appearance not updating if the app is backgrounded -@interface DownloadsPagerVC : UIViewController +@interface DownloadsPagerVC (uYouEnhancedPatches) - (NSArray *)viewControllers; - (void)updatePageStyles; @end From 4afa1a8e3acc41c5af7a2067c65c1336e185164d Mon Sep 17 00:00:00 2001 From: Bryce Hackel <34104885+bhackel@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:10:28 -0700 Subject: [PATCH 14/14] Revert "Add link to uYou page" This reverts commit 7c39d6659d4f4cdbd4cff7b94f8d4d8fa3158544. --- Sources/uYouPlus.h | 48 ++++++++++++++++----------------------- Sources/uYouPlus.xm | 41 +-------------------------------- Sources/uYouPlusPatches.h | 2 +- 3 files changed, 21 insertions(+), 70 deletions(-) diff --git a/Sources/uYouPlus.h b/Sources/uYouPlus.h index 9fd7edc..0cd083d 100644 --- a/Sources/uYouPlus.h +++ b/Sources/uYouPlus.h @@ -33,7 +33,6 @@ #import #import #import -#import // Hide buttons under the video player by @PoomSmart #import @@ -73,49 +72,40 @@ // Hide Premium Promo in You tab - @bhackel @interface YTIIconThumbnailRenderer : GPBMessage -@property (nonatomic, strong) YTIIcon *icon; -- (bool)hasIcon; + @property (nonatomic, strong) YTIIcon *icon; + - (bool)hasIcon; @end @interface YTICompactListItemThumbnailSupportedRenderers : GPBMessage -@property (nonatomic, strong) YTIIconThumbnailRenderer *iconThumbnailRenderer; -- (bool)hasIconThumbnailRenderer; + @property (nonatomic, strong) YTIIconThumbnailRenderer *iconThumbnailRenderer; + - (bool)hasIconThumbnailRenderer; @end @interface YTICompactListItemRenderer : GPBMessage -@property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; -@property (nonatomic, strong) YTIFormattedString *title; -- (bool)hasThumbnail; -- (bool)hasTitle; + @property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; + @property (nonatomic, strong) YTIFormattedString *title; + - (bool)hasThumbnail; + - (bool)hasTitle; @end @interface YTIIcon (uYouEnhanced) -- (bool)hasIconType; + - (bool)hasIconType; @end @interface YTICompactLinkRenderer : GPBMessage -@property (nonatomic, strong) YTIIcon *icon; -@property (nonatomic, strong) YTIFormattedString *title; -@property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; -- (bool)hasIcon; -- (bool)hasThumbnail; + @property (nonatomic, strong) YTIIcon *icon; + @property (nonatomic, strong) YTIFormattedString *title; + @property (nonatomic, strong) YTICompactListItemThumbnailSupportedRenderers *thumbnail; + - (bool)hasIcon; + - (bool)hasThumbnail; @end @interface YTIItemSectionSupportedRenderers (uYouEnhanced) -@property(readonly, nonatomic) YTICompactLinkRenderer *compactLinkRenderer; -@property(readonly, nonatomic) YTICompactListItemRenderer *compactListItemRenderer; -- (bool)hasCompactLinkRenderer; -- (bool)hasCompactListItemRenderer; + @property(readonly, nonatomic) YTICompactLinkRenderer *compactLinkRenderer; + @property(readonly, nonatomic) YTICompactListItemRenderer *compactListItemRenderer; + - (bool)hasCompactLinkRenderer; + - (bool)hasCompactListItemRenderer; @end @interface YTAppCollectionViewController : YTInnerTubeCollectionViewController - (void)uYouEnhancedFakePremiumModel:(YTISectionListRenderer *)model; @end @interface YTInnerTubeCollectionViewController (uYouEnhanced) -@property(readonly, nonatomic) YTISectionListRenderer *model; -@end -@interface YTLinkCell : UICollectionViewCell -@end -@interface YTCompactListItemCellController : YTCellController -@property(nonatomic, weak, readwrite) id entry; -@end -@interface GLViewPagerViewController : UIViewController -@end -@interface DownloadsPagerVC : GLViewPagerViewController + @property(readonly, nonatomic) YTISectionListRenderer *model; @end // uYouPlus diff --git a/Sources/uYouPlus.xm b/Sources/uYouPlus.xm index 15a533b..9d67e34 100644 --- a/Sources/uYouPlus.xm +++ b/Sources/uYouPlus.xm @@ -359,6 +359,7 @@ BOOL isAd(YTIElementRenderer *self) { if (yourVideosCellIndex != -1 && subContentsArray[yourVideosCellIndex].accessibilityLabel == nil) { // Create the fake Downloads page by copying the Your Videos page and modifying it // Note that this must be done outside the loop to avoid a runtime exception + // TODO Link this to the uYou downloads page YTIItemSectionSupportedRenderers *newItemSectionSupportedRenderers = [subContentsArray[yourVideosCellIndex] copy]; ((YTIStringRun *)(newItemSectionSupportedRenderers.compactListItemRenderer.title.runsArray.firstObject)).text = LOC(@"FAKE_DOWNLOADS"); newItemSectionSupportedRenderers.compactListItemRenderer.thumbnail.iconThumbnailRenderer.icon.iconType = 147; @@ -367,8 +368,6 @@ BOOL isAd(YTIElementRenderer *self) { // Inject a note to not modify this again subContentsArray[yourVideosCellIndex].accessibilityLabel = @"uYouEnhanced Modified"; yourVideosCellIndex = -1; - // Insert accessibility info into the YTLinkCell so that it can be hooked later - newItemSectionSupportedRenderers.compactListItemRenderer.title.accessibility.accessibilityData.label = @"uYouEnhanced Fake Downloads"; } } } @@ -383,44 +382,6 @@ BOOL isAd(YTIElementRenderer *self) { %orig; } %end -// Change the destination of the fake Downloads cell -%hook YTCompactListItemCellController -- (void)didSelectItem { - NSLog(@"bhackel: _handleMenuGesture"); - id entry = self.entry; - // Avoid modifying the wrong things - if (![entry isKindOfClass:NSClassFromString(@"YTICompactListItemRenderer")]) { - %orig; - return; - } - YTICompactListItemRenderer *compactListItemRenderer = (YTICompactListItemRenderer *)entry; - // Check title for accessibility label that was stored - if ([compactListItemRenderer.title.accessibility.accessibilityData.label isEqualToString:@"uYouEnhanced Fake Downloads"]) { - NSLog(@"bhackel: uYouEnhanced Fake Downloads"); - // Chatgpt generated code to show DownloadsPagerVC, which is the uYou page - // Instantiate your custom DownloadsPagerVC - // Avoid linker stuff - Class downloadsPagerVCClass = objc_getClass("DownloadsPagerVC"); - if (downloadsPagerVCClass) { - id downloadsPagerVCid = [[downloadsPagerVCClass alloc] init]; - // Now you can use `downloadsPagerVC` as needed - } - DownloadsPagerVC *downloadsPagerVC = (DownloadsPagerVC *)downloadsPagerVCid; - // Assuming you need navigation controller to push - UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; - UINavigationController *navigationController = (UINavigationController *)rootViewController; - if ([navigationController isKindOfClass:[UINavigationController class]]) { - [navigationController pushViewController:downloadsPagerVC animated:YES]; - } else { - // If not in a navigation controller context, present modally - [rootViewController presentViewController:downloadsPagerVC animated:YES completion:nil]; - } - } else { - NSLog(@"bhackel: Not uYouEnhanced Fake Downloads"); - %orig; - } -} -%end %end diff --git a/Sources/uYouPlusPatches.h b/Sources/uYouPlusPatches.h index 9bf3238..a9231b6 100644 --- a/Sources/uYouPlusPatches.h +++ b/Sources/uYouPlusPatches.h @@ -32,7 +32,7 @@ // @end // Fix uYou's appearance not updating if the app is backgrounded -@interface DownloadsPagerVC (uYouEnhancedPatches) +@interface DownloadsPagerVC : UIViewController - (NSArray *)viewControllers; - (void)updatePageStyles; @end