Initial release
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
ifeq ($(ROOTLESS),1)
|
||||||
|
THEOS_PACKAGE_SCHEME=rootless
|
||||||
|
endif
|
||||||
|
|
||||||
|
DEBUG=0
|
||||||
|
FINALPACKAGE=1
|
||||||
|
ARCHS = arm64
|
||||||
|
PACKAGE_VERSION = 1.0
|
||||||
|
TARGET := iphone:clang:latest:11.0
|
||||||
|
|
||||||
|
include $(THEOS)/makefiles/common.mk
|
||||||
|
|
||||||
|
TWEAK_NAME = YTLite
|
||||||
|
$(TWEAK_NAME)_FRAMEWORKS = UIKit Foundation
|
||||||
|
$(TWEAK_NAME)_CFLAGS = -fobjc-arc -DTWEAK_VERSION=$(PACKAGE_VERSION)
|
||||||
|
$(TWEAK_NAME)_FILES = YTLite.x Settings.x
|
||||||
|
|
||||||
|
include $(THEOS_MAKE_PATH)/tweak.mk
|
||||||
+226
@@ -0,0 +1,226 @@
|
|||||||
|
#import "YTLite.h"
|
||||||
|
|
||||||
|
@interface YTSettingsSectionItemManager (YTLite)
|
||||||
|
- (void)updateYTLiteSectionWithEntry:(id)entry;
|
||||||
|
@end
|
||||||
|
|
||||||
|
static const NSInteger YTLiteSection = 789;
|
||||||
|
|
||||||
|
NSBundle *YTLiteBundle() {
|
||||||
|
static NSBundle *bundle = nil;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
NSString *tweakBundlePath = [[NSBundle mainBundle] pathForResource:@"YTLite" ofType:@"bundle"];
|
||||||
|
if (tweakBundlePath)
|
||||||
|
bundle = [NSBundle bundleWithPath:tweakBundlePath];
|
||||||
|
else
|
||||||
|
bundle = [NSBundle bundleWithPath:ROOT_PATH_NS("/Library/Application Support/YTLite.bundle")];
|
||||||
|
});
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
%hook YTAppSettingsPresentationData
|
||||||
|
+ (NSArray *)settingsCategoryOrder {
|
||||||
|
NSArray *order = %orig;
|
||||||
|
NSMutableArray *mutableOrder = [order mutableCopy];
|
||||||
|
NSUInteger insertIndex = [order indexOfObject:@(1)];
|
||||||
|
if (insertIndex != NSNotFound)
|
||||||
|
[mutableOrder insertObject:@(YTLiteSection) atIndex:insertIndex + 1];
|
||||||
|
return mutableOrder;
|
||||||
|
}
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTSettingsSectionController
|
||||||
|
- (void)setSelectedItem:(NSUInteger)selectedItem {
|
||||||
|
if (selectedItem != NSNotFound) %orig;
|
||||||
|
}
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTSettingsSectionItemManager
|
||||||
|
%new
|
||||||
|
- (void)updatePrefsForKey:(NSString *)key enabled:(BOOL)enabled {
|
||||||
|
NSString *prefsPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"YTLite.plist"];
|
||||||
|
NSMutableDictionary *prefs = [NSMutableDictionary dictionaryWithContentsOfFile:prefsPath];
|
||||||
|
|
||||||
|
if (!prefs) prefs = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
[prefs setObject:@(enabled) forKey:key];
|
||||||
|
[prefs writeToFile:prefsPath atomically:NO];
|
||||||
|
|
||||||
|
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.dvntm.ytlite.prefschanged"), NULL, NULL, YES);
|
||||||
|
}
|
||||||
|
|
||||||
|
%new(v@:@)
|
||||||
|
- (void)updateYTLiteSectionWithEntry:(id)entry {
|
||||||
|
NSMutableArray *sectionItems = [NSMutableArray array];
|
||||||
|
Class YTSettingsSectionItemClass = %c(YTSettingsSectionItem);
|
||||||
|
YTSettingsViewController *settingsViewController = [self valueForKey:@"_settingsViewControllerDelegate"];
|
||||||
|
|
||||||
|
YTSettingsSectionItem *general = [YTSettingsSectionItemClass itemWithTitle:LOC(@"General")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
detailTextBlock:^NSString *() {
|
||||||
|
return @"‣";
|
||||||
|
}
|
||||||
|
selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
|
||||||
|
NSArray <YTSettingsSectionItem *> *rows = @[
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"RemoveAds")
|
||||||
|
titleDescription:LOC(@"RemoveAdsDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kNoAds
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"noAds" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0],
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"BackgroundPlayback")
|
||||||
|
titleDescription:LOC(@"BackgroundPlaybackDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kBackgroundPlayback
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"backgroundPlayback" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0]
|
||||||
|
];
|
||||||
|
|
||||||
|
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"General") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]];
|
||||||
|
[settingsViewController pushViewController:picker];
|
||||||
|
return YES;
|
||||||
|
}];
|
||||||
|
[sectionItems addObject:general];
|
||||||
|
|
||||||
|
YTSettingsSectionItem *navbar = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Navbar")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
detailTextBlock:^NSString *() {
|
||||||
|
return @"‣";
|
||||||
|
}
|
||||||
|
selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
|
||||||
|
NSArray <YTSettingsSectionItem *> *rows = @[
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"RemoveCast")
|
||||||
|
titleDescription:LOC(@"RemoveCastDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kNoCast
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"noCast" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0],
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"RemoveNotifications")
|
||||||
|
titleDescription:LOC(@"RemoveNotificationsDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kNoNotifsButton
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"removeNotifsButton" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0],
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"RemoveSearch")
|
||||||
|
titleDescription:LOC(@"RemoveSearchDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kNoSearchButton
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"removeSearchButton" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0]
|
||||||
|
];
|
||||||
|
|
||||||
|
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Navbar") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]];
|
||||||
|
[settingsViewController pushViewController:picker];
|
||||||
|
return YES;
|
||||||
|
}];
|
||||||
|
[sectionItems addObject:navbar];
|
||||||
|
|
||||||
|
YTSettingsSectionItem *tabbar = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Tabbar")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
detailTextBlock:^NSString *() {
|
||||||
|
return @"‣";
|
||||||
|
}
|
||||||
|
selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
|
||||||
|
NSArray <YTSettingsSectionItem *> *rows = @[
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"RemoveLabels")
|
||||||
|
titleDescription:LOC(@"RemoveLabelsDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kRemoveLabels
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"removeLabels" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0],
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"HideShortsTab")
|
||||||
|
titleDescription:LOC(@"HideShortsTabDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kRemoveShorts
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"removeShorts" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0],
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"HideSubscriptionsTab")
|
||||||
|
titleDescription:LOC(@"HideSubscriptionsTabDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kRemoveSubscriptions
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"removeSubscriptions" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0],
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"HideUploadButton")
|
||||||
|
titleDescription:LOC(@"HideUploadButtonDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kRemoveUploads
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"removeUploads" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0],
|
||||||
|
[YTSettingsSectionItemClass switchItemWithTitle:LOC(@"HideLibraryTab")
|
||||||
|
titleDescription:LOC(@"HideLibraryTabDesc")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
switchOn:kRemoveLibrary
|
||||||
|
switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) {
|
||||||
|
[self updatePrefsForKey:@"removeLibrary" enabled:enabled];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
settingItemId:0]
|
||||||
|
];
|
||||||
|
|
||||||
|
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Tabbar") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]];
|
||||||
|
[settingsViewController pushViewController:picker];
|
||||||
|
return YES;
|
||||||
|
}];
|
||||||
|
[sectionItems addObject:tabbar];
|
||||||
|
|
||||||
|
YTSettingsSectionItem *ps = [%c(YTSettingsSectionItem) itemWithTitle:@"PoomSmart" titleDescription:@"YouTube-X, YTNoPremium, YouTubeHeaders" accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
|
||||||
|
return [%c(YTUIUtils) openURL:[NSURL URLWithString:@"https://github.com/PoomSmart/"]];
|
||||||
|
}];
|
||||||
|
|
||||||
|
YTSettingsSectionItem *dayanch96 = [%c(YTSettingsSectionItem) itemWithTitle:@"Dayanch96" titleDescription:LOC(@"Developer") accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
|
||||||
|
return [%c(YTUIUtils) openURL:[NSURL URLWithString:@"https://github.com/Dayanch96/"]];
|
||||||
|
}];
|
||||||
|
|
||||||
|
YTSettingsSectionItem *version = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Version")
|
||||||
|
accessibilityIdentifier:nil
|
||||||
|
detailTextBlock:^NSString *() {
|
||||||
|
return @(OS_STRINGIFY(TWEAK_VERSION));
|
||||||
|
}
|
||||||
|
selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) {
|
||||||
|
NSArray <YTSettingsSectionItem *> *rows = @[ps, dayanch96];
|
||||||
|
|
||||||
|
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"About") pickerSectionTitle:LOC(@"Credits") rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]];
|
||||||
|
[settingsViewController pushViewController:picker];
|
||||||
|
return YES;
|
||||||
|
}];
|
||||||
|
[sectionItems addObject:version];
|
||||||
|
|
||||||
|
[settingsViewController setSectionItems:sectionItems forCategory:YTLiteSection title:@"YTLite" titleDescription:nil headerHidden:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)updateSectionForCategory:(NSUInteger)category withEntry:(id)entry {
|
||||||
|
if (category == YTLiteSection) {
|
||||||
|
[self updateYTLiteSectionWithEntry:entry];
|
||||||
|
return;
|
||||||
|
} %orig;
|
||||||
|
}
|
||||||
|
%end
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <rootless.h>
|
||||||
|
#import "../YouTubeHeader/YTIPivotBarSupportedRenderers.h"
|
||||||
|
#import "../YouTubeHeader/YTIPivotBarRenderer.h"
|
||||||
|
#import "../YouTubeHeader/YTISectionListRenderer.h"
|
||||||
|
#import "../YouTubeHeader/YTQTMButton.h"
|
||||||
|
#import "../YouTubeHeader/YTSettingsViewController.h"
|
||||||
|
#import "../YouTubeHeader/YTSettingsSectionItem.h"
|
||||||
|
#import "../YouTubeHeader/YTSettingsSectionItemManager.h"
|
||||||
|
#import "../YouTubeHeader/YTSettingsPickerViewController.h"
|
||||||
|
#import "../YouTubeHeader/YTUIUtils.h"
|
||||||
|
|
||||||
|
extern NSBundle *YTLiteBundle();
|
||||||
|
|
||||||
|
static inline NSString *LOC(NSString *key) {
|
||||||
|
NSBundle *tweakBundle = YTLiteBundle();
|
||||||
|
return [tweakBundle localizedStringForKey:key value:nil table:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL kNoAds;
|
||||||
|
BOOL kBackgroundPlayback;
|
||||||
|
BOOL kNoCast;
|
||||||
|
BOOL kNoNotifsButton;
|
||||||
|
BOOL kNoSearchButton;
|
||||||
|
BOOL kRemoveLabels;
|
||||||
|
BOOL kRemoveShorts;
|
||||||
|
BOOL kRemoveSubscriptions;
|
||||||
|
BOOL kRemoveUploads;
|
||||||
|
BOOL kRemoveLibrary;
|
||||||
|
|
||||||
|
@interface YTPivotBarView : UIView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface YTPivotBarItemView : UIView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface YTRightNavigationButtons : UIView
|
||||||
|
@property (nonatomic, strong) YTQTMButton *notificationButton;
|
||||||
|
@property (nonatomic, strong) YTQTMButton *searchButton;
|
||||||
|
@end
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Filter</key>
|
||||||
|
<dict>
|
||||||
|
<key>Bundles</key>
|
||||||
|
<array>
|
||||||
|
<string>com.google.ios.youtube</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
#import "YTLite.h"
|
||||||
|
|
||||||
|
// YouTube-X (https://github.com/PoomSmart/YouTube-X/)
|
||||||
|
// Background Playback
|
||||||
|
%hook YTIPlayabilityStatus
|
||||||
|
- (BOOL)isPlayableInBackground { return kBackgroundPlayback ? YES : NO; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook MLVideo
|
||||||
|
- (BOOL)playableInBackground { return kBackgroundPlayback ? YES : NO; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Disable Ads
|
||||||
|
%hook YTIPlayerResponse
|
||||||
|
- (BOOL)isMonetized { return kNoAds ? NO : YES; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTDataUtils
|
||||||
|
+ (id)spamSignalsDictionary { return kNoAds ? nil : %orig; }
|
||||||
|
+ (id)spamSignalsDictionaryWithoutIDFA { return kNoAds ? nil : %orig; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTAdsInnerTubeContextDecorator
|
||||||
|
- (void)decorateContext:(id)context { if (!kNoAds) %orig; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTAccountScopedAdsInnerTubeContextDecorator
|
||||||
|
- (void)decorateContext:(id)context { if (!kNoAds) %orig; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
BOOL isAd(YTIElementRenderer *self) {
|
||||||
|
if (self == nil) return NO;
|
||||||
|
if (self.hasCompatibilityOptions && self.compatibilityOptions.hasAdLoggingData) return YES;
|
||||||
|
NSString *description = [self description];
|
||||||
|
if (([description containsString:@"brand_promo"]
|
||||||
|
|| [description containsString:@"product_carousel"]
|
||||||
|
|| [description containsString:@"product_engagement_panel"]
|
||||||
|
|| [description containsString:@"product_item"]) && kNoAds)
|
||||||
|
return YES;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
%hook YTSectionListViewController
|
||||||
|
- (void)loadWithModel:(YTISectionListRenderer *)model {
|
||||||
|
if (kNoAds) {
|
||||||
|
NSMutableArray <YTISectionListSupportedRenderers *> *contentsArray = model.contentsArray;
|
||||||
|
NSIndexSet *removeIndexes = [contentsArray indexesOfObjectsPassingTest:^BOOL(YTISectionListSupportedRenderers *renderers, NSUInteger idx, BOOL *stop) {
|
||||||
|
YTIItemSectionRenderer *sectionRenderer = renderers.itemSectionRenderer;
|
||||||
|
YTIItemSectionSupportedRenderers *firstObject = [sectionRenderer.contentsArray firstObject];
|
||||||
|
return firstObject.hasPromotedVideoRenderer || firstObject.hasCompactPromotedVideoRenderer || firstObject.hasPromotedVideoInlineMutedRenderer || isAd(firstObject.elementRenderer);
|
||||||
|
}];
|
||||||
|
[contentsArray removeObjectsAtIndexes:removeIndexes];
|
||||||
|
} %orig;
|
||||||
|
}
|
||||||
|
%end
|
||||||
|
|
||||||
|
// NOYTPremium (https://github.com/PoomSmart/NoYTPremium)
|
||||||
|
// Alert
|
||||||
|
%hook YTCommerceEventGroupHandler
|
||||||
|
- (void)addEventHandlers {}
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Full-screen
|
||||||
|
%hook YTInterstitialPromoEventGroupHandler
|
||||||
|
- (void)addEventHandlers {}
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTPromosheetEventGroupHandler
|
||||||
|
- (void)addEventHandlers {}
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTPromoThrottleController
|
||||||
|
- (BOOL)canShowThrottledPromo { return NO; }
|
||||||
|
- (BOOL)canShowThrottledPromoWithFrequencyCap:(id)arg1 { return NO; }
|
||||||
|
- (BOOL)canShowThrottledPromoWithFrequencyCaps:(id)arg1 { return NO; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTIShowFullscreenInterstitialCommand
|
||||||
|
- (BOOL)shouldThrottleInterstitial { return YES; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
// "Try new features" in settings
|
||||||
|
%hook YTSettingsSectionItemManager
|
||||||
|
- (void)updatePremiumEarlyAccessSectionWithEntry:(id)arg1 {}
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Survey
|
||||||
|
%hook YTSurveyController
|
||||||
|
- (void)showSurveyWithRenderer:(id)arg1 surveyParentResponder:(id)arg2 {}
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Statement banner
|
||||||
|
%hook YTPremiumSeasonCardCellController
|
||||||
|
- (void)setCell:(id)arg1 { arg1 = NULL; %orig; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTPremiumSeasonCardView
|
||||||
|
- (long long)accessibilityElementCount { return 0; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Navbar Stuff
|
||||||
|
// Disable Cast
|
||||||
|
%hook MDXPlaybackRouteButtonController
|
||||||
|
- (BOOL)isPersistentCastIconEnabled { return kNoCast ? NO : YES; }
|
||||||
|
- (void)updateRouteButton:(id)arg1 { if (!kNoCast) %orig; }
|
||||||
|
- (void)updateAllRouteButtons { if (!kNoCast) %orig; }
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTSettings
|
||||||
|
- (void)setDisableMDXDeviceDiscovery:(BOOL)arg1 { %orig(kNoCast); }
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Hide Cast, Notifications and Search Buttons
|
||||||
|
%hook YTRightNavigationButtons
|
||||||
|
- (void)layoutSubviews {
|
||||||
|
%orig;
|
||||||
|
if (kNoCast && self.subviews.count > 1 && [self.subviews[1].accessibilityIdentifier isEqualToString:@"id.mdx.playbackroute.button"]) self.subviews[1].hidden = YES; // Hide icon immediately
|
||||||
|
if (kNoNotifsButton) self.notificationButton.hidden = YES;
|
||||||
|
if (kNoSearchButton) self.searchButton.hidden = YES;
|
||||||
|
}
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Remove Tabs
|
||||||
|
%hook YTPivotBarView
|
||||||
|
- (void)setRenderer:(YTIPivotBarRenderer *)renderer {
|
||||||
|
NSMutableArray <YTIPivotBarSupportedRenderers *> *items = [renderer itemsArray];
|
||||||
|
|
||||||
|
NSDictionary *identifiersToRemove = @{
|
||||||
|
@"FEshorts": @(kRemoveShorts),
|
||||||
|
@"FEsubscriptions": @(kRemoveSubscriptions),
|
||||||
|
@"FEuploads": @(kRemoveUploads),
|
||||||
|
@"FElibrary": @(kRemoveLibrary)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (NSString *identifier in identifiersToRemove) {
|
||||||
|
BOOL shouldRemoveItem = [identifiersToRemove[identifier] boolValue];
|
||||||
|
NSUInteger index = [items indexOfObjectPassingTest:^BOOL(YTIPivotBarSupportedRenderers *renderers, NSUInteger idx, BOOL *stop) {
|
||||||
|
if ([identifier isEqualToString:@"FEuploads"]) {
|
||||||
|
return shouldRemoveItem && [[[renderers pivotBarIconOnlyItemRenderer] pivotIdentifier] isEqualToString:identifier];
|
||||||
|
} else {
|
||||||
|
return shouldRemoveItem && [[[renderers pivotBarItemRenderer] pivotIdentifier] isEqualToString:identifier];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (index != NSNotFound) {
|
||||||
|
[items removeObjectAtIndex:index];
|
||||||
|
}
|
||||||
|
} %orig;
|
||||||
|
}
|
||||||
|
%end
|
||||||
|
|
||||||
|
// Hide Tab Labels
|
||||||
|
BOOL hasHomeBar = NO;
|
||||||
|
CGFloat pivotBarViewHeight;
|
||||||
|
|
||||||
|
%hook YTPivotBarView
|
||||||
|
- (void)layoutSubviews {
|
||||||
|
%orig;
|
||||||
|
pivotBarViewHeight = self.frame.size.height;
|
||||||
|
}
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook YTPivotBarItemView
|
||||||
|
- (void)layoutSubviews {
|
||||||
|
%orig;
|
||||||
|
|
||||||
|
CGFloat pivotBarAccessibilityControlWidth;
|
||||||
|
|
||||||
|
if (kRemoveLabels) {
|
||||||
|
for (UIView *subview in self.subviews) {
|
||||||
|
if ([subview isKindOfClass:NSClassFromString(@"YTPivotBarItemViewAccessibilityControl")]) {
|
||||||
|
pivotBarAccessibilityControlWidth = CGRectGetWidth(subview.frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UIView *subview in self.subviews) {
|
||||||
|
if ([subview isKindOfClass:NSClassFromString(@"YTQTMButton")]) {
|
||||||
|
for (UIView *buttonSubview in subview.subviews) {
|
||||||
|
if ([buttonSubview isKindOfClass:[UILabel class]]) {
|
||||||
|
[buttonSubview removeFromSuperview];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UIImageView *imageView = nil;
|
||||||
|
for (UIView *buttonSubview in subview.subviews) {
|
||||||
|
if ([buttonSubview isKindOfClass:[UIImageView class]]) {
|
||||||
|
imageView = (UIImageView *)buttonSubview;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageView) {
|
||||||
|
CGFloat imageViewHeight = imageView.image.size.height;
|
||||||
|
CGFloat imageViewWidth = imageView.image.size.width;
|
||||||
|
CGRect buttonFrame = subview.frame;
|
||||||
|
|
||||||
|
if (@available(iOS 13.0, *)) {
|
||||||
|
UIWindowScene *mainWindowScene = (UIWindowScene *)[[[UIApplication sharedApplication] connectedScenes] anyObject];
|
||||||
|
if (mainWindowScene) {
|
||||||
|
UIEdgeInsets safeAreaInsets = mainWindowScene.windows.firstObject.safeAreaInsets;
|
||||||
|
if (safeAreaInsets.bottom > 0) {
|
||||||
|
hasHomeBar = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CGFloat yOffset = hasHomeBar ? 15.0 : 0.0;
|
||||||
|
CGFloat xOffset = (pivotBarAccessibilityControlWidth - imageViewWidth) / 2.0;
|
||||||
|
|
||||||
|
buttonFrame.origin.y = (pivotBarViewHeight - imageViewHeight - yOffset) / 2.0;
|
||||||
|
buttonFrame.origin.x = xOffset;
|
||||||
|
|
||||||
|
buttonFrame.size.height = imageViewHeight;
|
||||||
|
buttonFrame.size.width = imageViewWidth;
|
||||||
|
|
||||||
|
subview.frame = buttonFrame;
|
||||||
|
subview.bounds = CGRectMake(0, 0, imageViewWidth, imageViewHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%end
|
||||||
|
|
||||||
|
static void reloadPrefs() {
|
||||||
|
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"YTLite.plist"];
|
||||||
|
NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:path];
|
||||||
|
|
||||||
|
kNoAds = (prefs[@"noAds"] != nil) ? [prefs[@"noAds"] boolValue] : YES;
|
||||||
|
kBackgroundPlayback = (prefs[@"backgroundPlayback"] != nil) ? [prefs[@"backgroundPlayback"] boolValue] : YES;
|
||||||
|
kNoCast = [prefs[@"noCast"] boolValue] ?: NO;
|
||||||
|
kNoNotifsButton = [prefs[@"removeNotifsButton"] boolValue] ?: NO;
|
||||||
|
kNoSearchButton = [prefs[@"removeSearchButton"] boolValue] ?: NO;
|
||||||
|
kRemoveLabels = [prefs[@"removeLabels"] boolValue] ?: NO;
|
||||||
|
kRemoveShorts = [prefs[@"removeShorts"] boolValue] ?: NO;
|
||||||
|
kRemoveSubscriptions = [prefs[@"removeSubscriptions"] boolValue] ?: NO;
|
||||||
|
kRemoveUploads = (prefs[@"removeUploads"] != nil) ? [prefs[@"removeUploads"] boolValue] : YES;
|
||||||
|
kRemoveLibrary = [prefs[@"removeLibrary"] boolValue] ?: NO;
|
||||||
|
|
||||||
|
NSDictionary *newSettings = @{
|
||||||
|
@"noAds" : @(kNoAds),
|
||||||
|
@"backgroundPlayback" : @(kBackgroundPlayback),
|
||||||
|
@"noCast" : @(kNoCast),
|
||||||
|
@"removeNotifsButton" : @(kNoNotifsButton),
|
||||||
|
@"removeSearchButton" : @(kNoSearchButton),
|
||||||
|
@"removeLabels" : @(kRemoveLabels),
|
||||||
|
@"removeShorts" : @(kRemoveShorts),
|
||||||
|
@"removeSubscriptions" : @(kRemoveSubscriptions),
|
||||||
|
@"removeUploads" : @(kRemoveUploads),
|
||||||
|
@"removeLibrary" : @(kRemoveLibrary)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (![newSettings isEqualToDictionary:prefs]) [newSettings writeToFile:path atomically:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
|
||||||
|
reloadPrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
%ctor {
|
||||||
|
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)prefsChanged, CFSTR("com.dvntm.ytlite.prefschanged"), NULL, CFNotificationSuspensionBehaviorCoalesce);
|
||||||
|
reloadPrefs();
|
||||||
|
%init;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Package: com.dvntm.ytlite
|
||||||
|
Name: YTLite
|
||||||
|
Depends: mobilesubstrate
|
||||||
|
Version: 0.0.1
|
||||||
|
Architecture: iphoneos-arm
|
||||||
|
Description: Lightweight YouTube Enhancer
|
||||||
|
Maintainer: dvntm
|
||||||
|
Author: dvntm
|
||||||
|
Section: Tweaks
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0.0</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.dvntm.ytlite</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>YTLite</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>BNDL</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>YTLite</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
"General" = "General";
|
||||||
|
"RemoveAds" = "Remove ads";
|
||||||
|
"RemoveAdsDesc" = "Removes in-app ads.";
|
||||||
|
"BackgroundPlayback" = "Background playback";
|
||||||
|
"BackgroundPlaybackDesc" = "Enables background playback.";
|
||||||
|
|
||||||
|
"Navbar" = "Navigation bar";
|
||||||
|
"RemoveCast" = "Hide Cast button";
|
||||||
|
"RemoveCastDesc" = "Hides Cast button from the Navigation bar.";
|
||||||
|
"RemoveNotifications" = "Hide Notifications button";
|
||||||
|
"RemoveNotificationsDesc" = "Hides Notifications button from the Navigation bar.";
|
||||||
|
"RemoveSearch" = "Hide Search button";
|
||||||
|
"RemoveSearchDesc" = "Hides Search button from the Navigation bar.";
|
||||||
|
|
||||||
|
"Tabbar" = "Tab bar";
|
||||||
|
"RemoveLabels" = "Remove labels";
|
||||||
|
"RemoveLabelsDesc" = "Removes tab labels.";
|
||||||
|
"HideShortsTab" = "Hide Shorts tab";
|
||||||
|
"HideShortsTabDesc" = "Hides Shorts tab from the Tab bar";
|
||||||
|
"HideSubscriptionsTab" = "Hide Subscriptions tab";
|
||||||
|
"HideSubscriptionsTabDesc" = "Hides Subscriptions tab from the Tab bar";
|
||||||
|
"HideUploadButton" = "Hide Upload button";
|
||||||
|
"HideUploadButtonDesc" = "Hides Upload button from the Tab bar";
|
||||||
|
"HideLibraryTab" = "Hide Library tab";
|
||||||
|
"HideLibraryTabDesc" = "Hides Library tab from the Tab bar";
|
||||||
|
|
||||||
|
"Version" = "Version";
|
||||||
|
"About" = "About";
|
||||||
|
"Credits" = "Credits";
|
||||||
|
"Developer" = "YTLite developer";
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
"General" = "Основные";
|
||||||
|
"RemoveAds" = "Убрать рекламу";
|
||||||
|
"RemoveAdsDesc" = "Убирает рекламу в приложении.";
|
||||||
|
"BackgroundPlayback" = "Фоновое воспроизведение";
|
||||||
|
"BackgroundPlaybackDesc" = "Активирует фоновое воспроизведение.";
|
||||||
|
|
||||||
|
"Navbar" = "Панель навигации";
|
||||||
|
"RemoveCast" = "Скрыть «Трансляция»";
|
||||||
|
"RemoveCastDesc" = "Скрывает кнопку трансляции с панели навигации.";
|
||||||
|
"RemoveNotifications" = "Скрыть «Уведомления»";
|
||||||
|
"RemoveNotificationsDesc" = "Скрывает кнопку уведомлений с панели навигации.";
|
||||||
|
"RemoveSearch" = "Скрыть «Поиск»";
|
||||||
|
"RemoveSearchDesc" = "Скрвыает кнопку поиска с панели навигации.";
|
||||||
|
|
||||||
|
"Tabbar" = "Панель вкладок";
|
||||||
|
"RemoveLabels" = "Скрыть названия";
|
||||||
|
"RemoveLabelsDesc" = "Скрывает названия вкладок.";
|
||||||
|
"HideShortsTab" = "Скрыть «Shorts»";
|
||||||
|
"HideShortsTabDesc" = "Скрывает вкладку «Shorts» с панели вкладок.";
|
||||||
|
"HideSubscriptionsTab" = "Скрыть «Подписки»";
|
||||||
|
"HideSubscriptionsTabDesc" = "Скрывает вкладку «Подписки» с панели вкладок.";
|
||||||
|
"HideUploadButton" = "Скрыть «Создать» (+)";
|
||||||
|
"HideUploadButtonDesc" = "Скрывает кнопку «Создать» с панели вкладок.";
|
||||||
|
"HideLibraryTab" = "Скрыть «Библиотеку»";
|
||||||
|
"HideLibraryTabDesc" = "Скрывает вкладку «Библиотека» с панели вкладок.";
|
||||||
|
|
||||||
|
"Version" = "Версия";
|
||||||
|
"About" = "О твике";
|
||||||
|
"Credits" = "Авторы";
|
||||||
|
"Developer" = "Разработчик твика";
|
||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user