mirror of
				https://github.com/SoPat712/YTLitePlus.git
				synced 2025-10-30 20:34:03 -04:00 
			
		
		
		
	added files via upload
This commit is contained in:
		
							
								
								
									
										442
									
								
								Tweaks/YTABConfig/Tweak.xm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										442
									
								
								Tweaks/YTABConfig/Tweak.xm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,442 @@ | ||||
| #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" | ||||
|  | ||||
| #define Prefix @"YTABC" | ||||
| #define EnabledKey @"EnabledYTABC" | ||||
| #define GroupedKey @"GroupedYTABC" | ||||
| #define INCLUDED_CLASSES @"Included classes: YTGlobalConfig, YTColdConfig, YTHotConfig" | ||||
| #define EXCLUDED_METHODS @"Excluded settings: android*, amsterdam*, musicClient* and unplugged*" | ||||
|  | ||||
| #define _LOC(b, x) [b localizedStringForKey:x value:nil table:nil] | ||||
| #define LOC(x) _LOC(tweakBundle, x) | ||||
|  | ||||
| static const NSInteger YTABCSection = 404; | ||||
|  | ||||
| @interface YTSettingsSectionItemManager (YTABConfig) | ||||
| - (void)updateYTABCSectionWithEntry:(id)entry; | ||||
| @end | ||||
|  | ||||
| NSMutableDictionary <NSString *, NSMutableDictionary <NSString *, NSNumber *> *> *cache; | ||||
| NSUserDefaults *defaults; | ||||
| NSArray <NSString *> *allKeys; | ||||
|  | ||||
| static BOOL tweakEnabled() { | ||||
|     return [defaults boolForKey:EnabledKey]; | ||||
| } | ||||
|  | ||||
| static BOOL groupedSettings() { | ||||
|     return [defaults boolForKey:GroupedKey]; | ||||
| } | ||||
|  | ||||
| static 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) { | ||||
|     if (![allKeys containsObject:methodKey]) | ||||
|         return [[cache valueForKeyPath:[methodKey substringFromIndex:Prefix.length + 1]] boolValue]; | ||||
|     return [defaults boolForKey:methodKey]; | ||||
| } | ||||
|  | ||||
| static void setValue(NSString *method, NSString *classKey, BOOL value) { | ||||
|     [cache setValue:@(value) forKeyPath:getCacheKey(method, classKey)]; | ||||
|     [defaults setBool:value forKey:getKey(method, classKey)]; | ||||
| } | ||||
|  | ||||
| static 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; | ||||
| } | ||||
|  | ||||
| - (void)setSectionControllers { | ||||
|     %orig; | ||||
|     if (MSHookIvar<BOOL>(self, "_shouldShowSearchBar")) { | ||||
|         YTSettingsSectionController *settingsSectionController = [self settingsSectionControllers][[self valueForKey:@"_detailsCategoryID"]]; | ||||
|         if (settingsSectionController) { | ||||
|             YTSearchableSettingsViewController *searchableVC = [self valueForKey:@"_searchableSettingsViewController"]; | ||||
|             [searchableVC storeCollectionViewSections:@[settingsSectionController]]; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| %end | ||||
|  | ||||
| %end | ||||
|  | ||||
| %hook YTSettingsSectionController | ||||
|  | ||||
| - (void)setSelectedItem:(NSUInteger)selectedItem { | ||||
|     if (selectedItem != NSNotFound) %orig; | ||||
| } | ||||
|  | ||||
| %end | ||||
|  | ||||
| %hook YTAppSettingsPresentationData | ||||
|  | ||||
| + (NSArray *)settingsCategoryOrder { | ||||
|     NSArray *order = %orig; | ||||
|     NSMutableArray *mutableOrder = [order mutableCopy]; | ||||
|     [mutableOrder insertObject:@(YTABCSection) atIndex:0]; | ||||
|     return mutableOrder; | ||||
| } | ||||
|  | ||||
| %end | ||||
|  | ||||
| static NSString *getCategory(char c, NSString *method) { | ||||
|     if (c == 'e') { | ||||
|         if ([method hasPrefix:@"elements"]) return @"elements"; | ||||
|         if ([method hasPrefix:@"enable"]) return @"enable"; | ||||
|     } | ||||
|     if (c == 'i') { | ||||
|         if ([method hasPrefix:@"ios"]) return @"ios"; | ||||
|         if ([method hasPrefix:@"is"]) return @"is"; | ||||
|     } | ||||
|     if (c == 's') { | ||||
|         if ([method hasPrefix:@"shorts"]) return @"shorts"; | ||||
|         if ([method hasPrefix:@"should"]) return @"should"; | ||||
|     } | ||||
|     unichar uc = (unichar)c; | ||||
|     return [NSString stringWithCharacters:&uc length:1];; | ||||
| } | ||||
|  | ||||
| %hook YTSettingsSectionItemManager | ||||
|  | ||||
| %new(v@:@) | ||||
| - (void)updateYTABCSectionWithEntry:(id)entry { | ||||
|     NSMutableArray *sectionItems = [NSMutableArray array]; | ||||
|     int totalSettings = 0; | ||||
|     NSBundle *tweakBundle = YTABCBundle(); | ||||
|     BOOL isPhone = ![%c(YTCommonUtils) isIPad]; | ||||
|     NSString *yesText = _LOC([NSBundle mainBundle], @"settings.yes"); | ||||
|     NSString *cancelText = _LOC([NSBundle mainBundle], @"confirm.cancel"); | ||||
|     NSString *deleteText = _LOC([NSBundle mainBundle], @"search.action.delete"); | ||||
|     Class YTSettingsSectionItemClass = %c(YTSettingsSectionItem); | ||||
|     Class YTAlertViewClass = %c(YTAlertView); | ||||
|     if (tweakEnabled()) { | ||||
|         NSMutableDictionary <NSString *, NSMutableArray <YTSettingsSectionItem *> *> *properties = [NSMutableDictionary dictionary]; | ||||
|         for (NSString *classKey in cache) { | ||||
|             for (NSString *method in cache[classKey]) { | ||||
|                 char c = tolower([method characterAtIndex:0]); | ||||
|                 NSString *category = getCategory(c, method); | ||||
|                 if (![properties objectForKey:category]) properties[category] = [NSMutableArray array]; | ||||
|                 updateAllKeys(); | ||||
|                 BOOL modified = [allKeys containsObject:getKey(method, classKey)]; | ||||
|                 NSString *modifiedTitle = modified ? [NSString stringWithFormat:@"%@ *", method] : method; | ||||
|                 YTSettingsSectionItem *methodSwitch = [YTSettingsSectionItemClass switchItemWithTitle:modifiedTitle | ||||
|                     titleDescription:isPhone && method.length > 26 ? modifiedTitle : nil | ||||
|                     accessibilityIdentifier:nil | ||||
|                     switchOn:getValue(getKey(method, classKey)) | ||||
|                     switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) { | ||||
|                         setValue(method, classKey, enabled); | ||||
|                         return YES; | ||||
|                     } | ||||
|                     selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { | ||||
|                         NSString *content = [NSString stringWithFormat:@"%@.%@", classKey, method]; | ||||
|                         YTAlertView *alertView = [YTAlertViewClass confirmationDialog]; | ||||
|                         alertView.title = method; | ||||
|                         alertView.subtitle = content; | ||||
|                         [alertView addTitle:LOC(@"COPY_TO_CLIPBOARD") withAction:^{ | ||||
|                             UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; | ||||
|                             pasteboard.string = content; | ||||
|                             [[%c(YTToastResponderEvent) eventWithMessage:LOC(@"COPIED_TO_CLIPBOARD") firstResponder:[self parentResponder]] send]; | ||||
|                         }]; | ||||
|                         updateAllKeys(); | ||||
|                         NSString *key = getKey(method, classKey); | ||||
|                         if ([allKeys containsObject:key]) { | ||||
|                             [alertView addTitle:deleteText withAction:^{ | ||||
|                                 [defaults removeObjectForKey:key]; | ||||
|                                 updateAllKeys(); | ||||
|                             }]; | ||||
|                         } | ||||
|                         [alertView addCancelButton:NULL]; | ||||
|                         [alertView show]; | ||||
|                         return NO; | ||||
|                     } | ||||
|                     settingItemId:0]; | ||||
|                 [properties[category] addObject:methodSwitch]; | ||||
|             } | ||||
|         } | ||||
|         YTSettingsViewController *settingsViewController = [self valueForKey:@"_settingsViewControllerDelegate"]; | ||||
|         BOOL grouped = groupedSettings(); | ||||
|         for (NSString *category in properties) { | ||||
|             NSMutableArray <YTSettingsSectionItem *> *rows = properties[category]; | ||||
|             totalSettings += rows.count; | ||||
|             if (grouped) { | ||||
|                 NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES]; | ||||
|                 [rows sortUsingDescriptors:@[sort]]; | ||||
|                 NSString *shortTitle = [NSString stringWithFormat:@"\"%@\" (%ld)", category, rows.count]; | ||||
|                 NSString *title = [NSString stringWithFormat:@"%@ %@", LOC(@"SETTINGS_START_WITH"), shortTitle]; | ||||
|                 YTSettingsSectionItem *sectionItem = [YTSettingsSectionItemClass itemWithTitle:title accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { | ||||
|                     YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:shortTitle pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]]; | ||||
|                     [settingsViewController pushViewController:picker]; | ||||
|                     return YES; | ||||
|                 }]; | ||||
|                 [sectionItems addObject:sectionItem]; | ||||
|             } else { | ||||
|                 [sectionItems addObjectsFromArray:rows]; | ||||
|             } | ||||
|         } | ||||
|         NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES]; | ||||
|         [sectionItems sortUsingDescriptors:@[sort]]; | ||||
|         YTSettingsSectionItem *copyAll = [YTSettingsSectionItemClass itemWithTitle:LOC(@"COPY_CURRENT_SETTINGS") | ||||
|             titleDescription:LOC(@"COPY_CURRENT_SETTINGS_DESC") | ||||
|             accessibilityIdentifier:nil | ||||
|             detailTextBlock:nil | ||||
|             selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { | ||||
|                 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; | ||||
|                 NSMutableArray *content = [NSMutableArray array]; | ||||
|                 for (NSString *classKey in cache) { | ||||
|                     [cache[classKey] enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *value, BOOL* stop) { | ||||
|                         [content addObject:[NSString stringWithFormat:@"%@: %d", key, [value boolValue]]]; | ||||
|                     }]; | ||||
|                 } | ||||
|                 [content sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; | ||||
|                 [content insertObject:[NSString stringWithFormat:@"Device model: %@", [%c(YTCommonUtils) hardwareModel]] atIndex:0]; | ||||
|                 [content insertObject:[NSString stringWithFormat:@"App version: %@", [%c(YTVersionUtils) appVersion]] atIndex:0]; | ||||
|                 [content insertObject:EXCLUDED_METHODS atIndex:0]; | ||||
|                 [content insertObject:INCLUDED_CLASSES atIndex:0]; | ||||
|                 [content insertObject:[NSString stringWithFormat:@"YTABConfig version: %@", @(OS_STRINGIFY(TWEAK_VERSION))] atIndex:0]; | ||||
|                 pasteboard.string = [content componentsJoinedByString:@"\n"]; | ||||
|                 [[%c(YTToastResponderEvent) eventWithMessage:LOC(@"COPIED_TO_CLIPBOARD") firstResponder:[self parentResponder]] send]; | ||||
|                 return YES; | ||||
|             }]; | ||||
|         [sectionItems insertObject:copyAll atIndex:0]; | ||||
|         YTSettingsSectionItem *modified = [YTSettingsSectionItemClass itemWithTitle:LOC(@"VIEW_MODIFIED_SETTINGS") | ||||
|             titleDescription:LOC(@"VIEW_MODIFIED_SETTINGS_DESC") | ||||
|             accessibilityIdentifier:nil | ||||
|             detailTextBlock:nil | ||||
|             selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { | ||||
|                 NSMutableArray *features = [NSMutableArray array]; | ||||
|                 updateAllKeys(); | ||||
|                 for (NSString *key in allKeys) { | ||||
|                     if ([key hasPrefix:Prefix]) { | ||||
|                         NSString *displayKey = [key substringFromIndex:Prefix.length + 1]; | ||||
|                         [features addObject:[NSString stringWithFormat:@"%@: %d", displayKey, [defaults boolForKey:key]]]; | ||||
|                     } | ||||
|                 } | ||||
|                 [features sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; | ||||
|                 [features insertObject:[NSString stringWithFormat:LOC(@"TOTAL_MODIFIED_SETTINGS"), features.count] atIndex:0]; | ||||
|                 NSString *content = [features componentsJoinedByString:@"\n"]; | ||||
|                 YTAlertView *alertView = [YTAlertViewClass confirmationDialogWithAction:^{ | ||||
|                     UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; | ||||
|                     pasteboard.string = content; | ||||
|                     [[%c(YTToastResponderEvent) eventWithMessage:LOC(@"COPIED_TO_CLIPBOARD") firstResponder:[self parentResponder]] send]; | ||||
|                 } actionTitle:LOC(@"COPY_TO_CLIPBOARD")]; | ||||
|                 alertView.title = LOC(@"MODIFIED_SETTINGS_TITLE"); | ||||
|                 alertView.subtitle = content; | ||||
|                 [alertView show]; | ||||
|                 return YES; | ||||
|             }]; | ||||
|         [sectionItems insertObject:modified atIndex:0]; | ||||
|         YTSettingsSectionItem *reset = [YTSettingsSectionItemClass itemWithTitle:LOC(@"RESET_KILL") | ||||
|             titleDescription:LOC(@"RESET_KILL_DESC") | ||||
|             accessibilityIdentifier:nil | ||||
|             detailTextBlock:nil | ||||
|             selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { | ||||
|                 YTAlertView *alertView = [YTAlertViewClass confirmationDialogWithAction:^{ | ||||
|                     updateAllKeys(); | ||||
|                     for (NSString *key in allKeys) { | ||||
|                         if ([key hasPrefix:Prefix]) | ||||
|                             [defaults removeObjectForKey:key]; | ||||
|                     } | ||||
|                     exit(0); | ||||
|                 } actionTitle:yesText]; | ||||
|                 alertView.title = LOC(@"WARNING"); | ||||
|                 alertView.subtitle = LOC(@"APPLY_DESC"); | ||||
|                 [alertView show]; | ||||
|                 return YES; | ||||
|             }]; | ||||
|         [sectionItems insertObject:reset atIndex:0]; | ||||
|         YTSettingsSectionItem *group = [YTSettingsSectionItemClass switchItemWithTitle:LOC(@"GROUPED") | ||||
|             titleDescription:nil | ||||
|             accessibilityIdentifier:nil | ||||
|             switchOn:groupedSettings() | ||||
|             switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) { | ||||
|                 YTAlertView *alertView = [YTAlertViewClass confirmationDialogWithAction:^{ | ||||
|                         [defaults setBool:enabled forKey:GroupedKey]; | ||||
|                         exit(0); | ||||
|                     } | ||||
|                     actionTitle:yesText | ||||
|                     cancelAction:^{ | ||||
|                         [cell setSwitchOn:!enabled animated:YES]; | ||||
|                     } | ||||
|                     cancelTitle:cancelText]; | ||||
|                 alertView.title = LOC(@"WARNING"); | ||||
|                 alertView.subtitle = LOC(@"APPLY_DESC"); | ||||
|                 [alertView show]; | ||||
|                 return YES; | ||||
|             } | ||||
|             settingItemId:0]; | ||||
|         [sectionItems insertObject:group atIndex:0]; | ||||
|     } | ||||
|     YTSettingsSectionItem *thread = [YTSettingsSectionItemClass itemWithTitle:LOC(@"OPEN_MEGATHREAD") | ||||
|         titleDescription:LOC(@"OPEN_MEGATHREAD_DESC") | ||||
|         accessibilityIdentifier:nil | ||||
|         detailTextBlock:nil | ||||
|         selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { | ||||
|             return [%c(YTUIUtils) openURL:[NSURL URLWithString:@"https://github.com/PoomSmart/YTABConfig/discussions"]]; | ||||
|         }]; | ||||
|     [sectionItems insertObject:thread atIndex:0]; | ||||
|     YTSettingsSectionItem *master = [YTSettingsSectionItemClass switchItemWithTitle:LOC(@"ENABLED") | ||||
|         titleDescription:LOC(@"ENABLED_DESC") | ||||
|         accessibilityIdentifier:nil | ||||
|         switchOn:tweakEnabled() | ||||
|         switchBlock:^BOOL (YTSettingsCell *cell, BOOL enabled) { | ||||
|             [defaults setBool:enabled forKey:EnabledKey]; | ||||
|             YTAlertView *alertView = [YTAlertViewClass confirmationDialogWithAction:^{ exit(0); } | ||||
|                 actionTitle:yesText | ||||
|                 cancelAction:^{ | ||||
|                     [cell setSwitchOn:!enabled animated:YES]; | ||||
|                 } | ||||
|                 cancelTitle:cancelText]; | ||||
|             alertView.title = LOC(@"WARNING"); | ||||
|             alertView.subtitle = LOC(@"APPLY_DESC"); | ||||
|             [alertView show]; | ||||
|             return YES; | ||||
|         } | ||||
|         settingItemId:0]; | ||||
|     [sectionItems insertObject:master atIndex:0]; | ||||
|     YTSettingsViewController *delegate = [self valueForKey:@"_dataDelegate"]; | ||||
|     [delegate setSectionItems:sectionItems | ||||
|         forCategory:YTABCSection | ||||
|         title:@"A/B" | ||||
|         titleDescription:tweakEnabled() ? [NSString stringWithFormat:@"YTABConfig %@, %d feature flags.", @(OS_STRINGIFY(TWEAK_VERSION)), totalSettings] : nil | ||||
|         headerHidden:NO]; | ||||
| } | ||||
|  | ||||
| - (void)updateSectionForCategory:(NSUInteger)category withEntry:(id)entry { | ||||
|     if (category == YTABCSection) { | ||||
|         [self updateYTABCSectionWithEntry:entry]; | ||||
|         return; | ||||
|     } | ||||
|     %orig; | ||||
| } | ||||
|  | ||||
| %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; | ||||
| } | ||||
|  | ||||
| %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]; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Balackburn
					Balackburn