Skip to content

Commit

Permalink
Refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
PoomSmart committed Feb 21, 2024
1 parent 9cbb3ed commit ee0c136
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 111 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include $(THEOS)/makefiles/common.mk

TWEAK_NAME = YTABConfig

$(TWEAK_NAME)_FILES = Tweak.xm
$(TWEAK_NAME)_FILES = Settings.x Tweak.x
$(TWEAK_NAME)_CFLAGS = -fobjc-arc -DTWEAK_VERSION=$(PACKAGE_VERSION)
$(TWEAK_NAME)_FRAMEWORKS = UIKit

Expand Down
137 changes: 27 additions & 110 deletions Tweak.xm → Settings.x
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
#import <rootless.h>
#import <YouTubeHeader/YTAlertView.h>
#import <YouTubeHeader/YTAppDelegate.h>
#import <YouTubeHeader/YTCommonUtils.h>
#import <YouTubeHeader/YTUIUtils.h>
#import <YouTubeHeader/YTVersionUtils.h>
#import <YouTubeHeader/YTGlobalConfig.h>
#import <YouTubeHeader/YTColdConfig.h>
#import <YouTubeHeader/YTHotConfig.h>
#import <YouTubeHeader/YTSettingsSectionItem.h>
#import <YouTubeHeader/YTSettingsSectionItemManager.h>
#import <YouTubeHeader/YTSettingsPickerViewController.h>
#import <YouTubeHeader/YTSettingsViewController.h>
#import <YouTubeHeader/YTSearchableSettingsViewController.h>
#import <YouTubeHeader/YTToastResponderEvent.h>
#import <YouTubeHeader/YTUIUtils.h>
#import <YouTubeHeader/YTVersionUtils.h>
#import <rootless.h>

#define Prefix @"YTABC"
#define EnabledKey @"EnabledYTABC"
Expand All @@ -29,27 +25,40 @@ static const NSInteger YTABCSection = 404;
- (void)updateYTABCSectionWithEntry:(id)entry;
@end

NSMutableDictionary <NSString *, NSMutableDictionary <NSString *, NSNumber *> *> *cache;
extern NSMutableDictionary <NSString *, NSMutableDictionary <NSString *, NSNumber *> *> *cache;
NSUserDefaults *defaults;
NSArray <NSString *> *allKeys;

static BOOL tweakEnabled() {
BOOL tweakEnabled() {
return [defaults boolForKey:EnabledKey];
}

static BOOL groupedSettings() {
BOOL groupedSettings() {
return [defaults boolForKey:GroupedKey];
}

static NSString *getKey(NSString *method, NSString *classKey) {
NSBundle *YTABCBundle() {
static NSBundle *bundle = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *tweakBundlePath = [[NSBundle mainBundle] pathForResource:@"YTABC" ofType:@"bundle"];
if (tweakBundlePath)
bundle = [NSBundle bundleWithPath:tweakBundlePath];
else
bundle = [NSBundle bundleWithPath:ROOT_PATH_NS(@"/Library/Application Support/YTABC.bundle")];
});
return bundle;
}

NSString *getKey(NSString *method, NSString *classKey) {
return [NSString stringWithFormat:@"%@.%@.%@", Prefix, classKey, method];
}

static NSString *getCacheKey(NSString *method, NSString *classKey) {
return [NSString stringWithFormat:@"%@.%@", classKey, method];
}

static BOOL getValue(NSString *methodKey) {
BOOL getValue(NSString *methodKey) {
if (![allKeys containsObject:methodKey])
return [[cache valueForKeyPath:[methodKey substringFromIndex:Prefix.length + 1]] boolValue];
return [defaults boolForKey:methodKey];
Expand All @@ -65,50 +74,23 @@ static void setValueFromImport(NSString *settingKey, BOOL value) {
[defaults setBool:value forKey:[NSString stringWithFormat:@"%@.%@", Prefix, settingKey]];
}

static void updateAllKeys() {
void updateAllKeys() {
allKeys = [defaults dictionaryRepresentation].allKeys;
}

static BOOL returnFunction(id const self, SEL _cmd) {
NSString *method = NSStringFromSelector(_cmd);
NSString *methodKey = getKey(method, NSStringFromClass([self class]));
return getValue(methodKey);
}

static BOOL getValueFromInvocation(id target, SEL selector) {
NSInvocationOperation *i = [[NSInvocationOperation alloc] initWithTarget:target selector:selector object:nil];
[i start];
BOOL result = NO;
[i.result getValue:&result];
return result;
}

NSBundle *YTABCBundle() {
static NSBundle *bundle = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *tweakBundlePath = [[NSBundle mainBundle] pathForResource:@"YTABC" ofType:@"bundle"];
if (tweakBundlePath)
bundle = [NSBundle bundleWithPath:tweakBundlePath];
else
bundle = [NSBundle bundleWithPath:ROOT_PATH_NS(@"/Library/Application Support/YTABC.bundle")];
});
return bundle;
}

%group Search

%hook YTSettingsViewController

- (void)loadWithModel:(id)model fromView:(UIView *)view {
%orig;
if ([[self valueForKey:@"_detailsCategoryID"] integerValue] == YTABCSection)
MSHookIvar<BOOL>(self, "_shouldShowSearchBar") = YES;
[self setValue:@(YES) forKey:@"_shouldShowSearchBar"];
}

- (void)setSectionControllers {
%orig;
if (MSHookIvar<BOOL>(self, "_shouldShowSearchBar")) {
if ([[self valueForKey:@"_shouldShowSearchBar"] boolValue]) {
YTSettingsSectionController *settingsSectionController = [self settingsSectionControllers][[self valueForKey:@"_detailsCategoryID"]];
if (settingsSectionController) {
YTSearchableSettingsViewController *searchableVC = [self valueForKey:@"_searchableSettingsViewController"];
Expand Down Expand Up @@ -450,76 +432,11 @@ static NSString *getCategory(char c, NSString *method) {

%end

static NSMutableArray <NSString *> *getBooleanMethods(Class clz) {
NSMutableArray *allMethods = [NSMutableArray array];
unsigned int methodCount = 0;
Method *methods = class_copyMethodList(clz, &methodCount);
for (unsigned int i = 0; i < methodCount; ++i) {
Method method = methods[i];
const char *name = sel_getName(method_getName(method));
if (strstr(name, "ndroid") || strstr(name, "musicClient") || strstr(name, "amsterdam") || strstr(name, "unplugged")) continue;
const char *encoding = method_getTypeEncoding(method);
if (strcmp(encoding, "B16@0:8")) continue;
NSString *selector = [NSString stringWithUTF8String:name];
if (![allMethods containsObject:selector])
[allMethods addObject:selector];
}
free(methods);
return allMethods;
}

static void hookClass(NSObject *instance) {
if (!instance) [NSException raise:@"hookClass Invalid argument exception" format:@"Hooking the class of a non-existing instance"];
Class instanceClass = [instance class];
NSMutableArray <NSString *> *methods = getBooleanMethods(instanceClass);
NSString *classKey = NSStringFromClass(instanceClass);
NSMutableDictionary *classCache = cache[classKey] = [NSMutableDictionary new];
for (NSString *method in methods) {
SEL selector = NSSelectorFromString(method);
BOOL result = getValueFromInvocation(instance, selector);
classCache[method] = @(result);
MSHookMessageEx(instanceClass, selector, (IMP)returnFunction, NULL);
}
}

%hook YTAppDelegate

- (BOOL)application:(id)arg1 didFinishLaunchingWithOptions:(id)arg2 {
defaults = [NSUserDefaults standardUserDefaults];
if (tweakEnabled()) {
updateAllKeys();
YTGlobalConfig *globalConfig;
YTColdConfig *coldConfig;
YTHotConfig *hotConfig;
@try {
globalConfig = [self valueForKey:@"_globalConfig"];
coldConfig = [self valueForKey:@"_coldConfig"];
hotConfig = [self valueForKey:@"_hotConfig"];
} @catch (id ex) {
id settings = [self valueForKey:@"_settings"];
globalConfig = [settings valueForKey:@"_globalConfig"];
coldConfig = [settings valueForKey:@"_coldConfig"];
hotConfig = [settings valueForKey:@"_hotConfig"];
}
hookClass(globalConfig);
hookClass(coldConfig);
hookClass(hotConfig);
if (!groupedSettings()) {
%init(Search);
}
}
return %orig;
void SearchHook() {
%init(Search);
}

%end

%ctor {
NSBundle *bundle = [NSBundle bundleWithPath:[NSString stringWithFormat:@"%@/Frameworks/Module_Framework.framework", [[NSBundle mainBundle] bundlePath]]];
if (!bundle.loaded) [bundle load];
cache = [NSMutableDictionary new];
defaults = [NSUserDefaults standardUserDefaults];
%init;
}

%dtor {
[cache removeAllObjects];
}
103 changes: 103 additions & 0 deletions Tweak.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#import <YouTubeHeader/YTAppDelegate.h>
#import <YouTubeHeader/YTGlobalConfig.h>
#import <YouTubeHeader/YTColdConfig.h>
#import <YouTubeHeader/YTHotConfig.h>
#import <substrate.h>

NSMutableDictionary <NSString *, NSMutableDictionary <NSString *, NSNumber *> *> *cache;

extern void SearchHook();

extern BOOL tweakEnabled();
extern BOOL groupedSettings();

extern void updateAllKeys();
extern NSString *getKey(NSString *method, NSString *classKey);
extern BOOL getValue(NSString *methodKey);

static BOOL returnFunction(id const self, SEL _cmd) {
NSString *method = NSStringFromSelector(_cmd);
NSString *methodKey = getKey(method, NSStringFromClass([self class]));
return getValue(methodKey);
}

static BOOL getValueFromInvocation(id target, SEL selector) {
NSInvocationOperation *i = [[NSInvocationOperation alloc] initWithTarget:target selector:selector object:nil];
[i start];
BOOL result = NO;
[i.result getValue:&result];
return result;
}

static NSMutableArray <NSString *> *getBooleanMethods(Class clz) {
NSMutableArray *allMethods = [NSMutableArray array];
unsigned int methodCount = 0;
Method *methods = class_copyMethodList(clz, &methodCount);
for (unsigned int i = 0; i < methodCount; ++i) {
Method method = methods[i];
const char *name = sel_getName(method_getName(method));
if (strstr(name, "ndroid") || strstr(name, "musicClient") || strstr(name, "amsterdam") || strstr(name, "unplugged")) continue;
const char *encoding = method_getTypeEncoding(method);
if (strcmp(encoding, "B16@0:8")) continue;
NSString *selector = [NSString stringWithUTF8String:name];
if (![allMethods containsObject:selector])
[allMethods addObject:selector];
}
free(methods);
return allMethods;
}

static void hookClass(NSObject *instance) {
if (!instance) [NSException raise:@"hookClass Invalid argument exception" format:@"Hooking the class of a non-existing instance"];
Class instanceClass = [instance class];
NSMutableArray <NSString *> *methods = getBooleanMethods(instanceClass);
NSString *classKey = NSStringFromClass(instanceClass);
NSMutableDictionary *classCache = cache[classKey] = [NSMutableDictionary new];
for (NSString *method in methods) {
SEL selector = NSSelectorFromString(method);
BOOL result = getValueFromInvocation(instance, selector);
classCache[method] = @(result);
MSHookMessageEx(instanceClass, selector, (IMP)returnFunction, NULL);
}
}

%hook YTAppDelegate

- (BOOL)application:(id)arg1 didFinishLaunchingWithOptions:(id)arg2 {
if (tweakEnabled()) {
updateAllKeys();
YTGlobalConfig *globalConfig;
YTColdConfig *coldConfig;
YTHotConfig *hotConfig;
@try {
globalConfig = [self valueForKey:@"_globalConfig"];
coldConfig = [self valueForKey:@"_coldConfig"];
hotConfig = [self valueForKey:@"_hotConfig"];
} @catch (id ex) {
id settings = [self valueForKey:@"_settings"];
globalConfig = [settings valueForKey:@"_globalConfig"];
coldConfig = [settings valueForKey:@"_coldConfig"];
hotConfig = [settings valueForKey:@"_hotConfig"];
}
hookClass(globalConfig);
hookClass(coldConfig);
hookClass(hotConfig);
if (!groupedSettings()) {
SearchHook();
}
}
return %orig;
}

%end

%ctor {
NSBundle *bundle = [NSBundle bundleWithPath:[NSString stringWithFormat:@"%@/Frameworks/Module_Framework.framework", [[NSBundle mainBundle] bundlePath]]];
if (!bundle.loaded) [bundle load];
cache = [NSMutableDictionary new];
%init;
}

%dtor {
[cache removeAllObjects];
}

0 comments on commit ee0c136

Please sign in to comment.