├── .gitignore ├── ApolloAPI.plist ├── CustomAPIViewController.h ├── CustomAPIViewController.m ├── Makefile ├── README.md ├── Tweak.h ├── Tweak.x ├── control └── packages ├── com.ryannair05.apolloapi_1.0.2_iphoneos-arm.deb └── com.ryannair05.apolloapi_1.0.2_iphoneos-arm64.deb /.gitignore: -------------------------------------------------------------------------------- 1 | .theos/ 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /ApolloAPI.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.christianselig.Apollo" ); }; } 2 | -------------------------------------------------------------------------------- /CustomAPIViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface CustomAPIViewController : UIViewController 4 | @end 5 | 6 | NSString *customIdentifier; 7 | NSString *imgurAPIKey; -------------------------------------------------------------------------------- /CustomAPIViewController.m: -------------------------------------------------------------------------------- 1 | #import "CustomAPIViewController.h" 2 | 3 | @implementation CustomAPIViewController 4 | 5 | - (void)viewDidLoad { 6 | [super viewDidLoad]; 7 | 8 | self.title = @"Apollo API"; 9 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone primaryAction:[UIAction actionWithHandler:^(UIAction * action) { 10 | [self dismissViewControllerAnimated:YES completion:nil]; 11 | }]]; 12 | 13 | UIScrollView *scrollView = [[UIScrollView alloc] init]; 14 | scrollView.translatesAutoresizingMaskIntoConstraints = NO; 15 | scrollView.backgroundColor = [UIColor systemBackgroundColor]; 16 | scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; 17 | [self.view addSubview:scrollView]; 18 | 19 | [NSLayoutConstraint activateConstraints:@[ 20 | [scrollView.topAnchor constraintEqualToAnchor:self.view.topAnchor], 21 | [scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], 22 | [scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], 23 | [scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], 24 | ]]; 25 | 26 | UIStackView *stackView = [[UIStackView alloc] init]; 27 | stackView.axis = UILayoutConstraintAxisVertical; 28 | stackView.spacing = 25; 29 | stackView.translatesAutoresizingMaskIntoConstraints = NO; 30 | [scrollView addSubview:stackView]; 31 | 32 | [NSLayoutConstraint activateConstraints:@[ 33 | [stackView.topAnchor constraintEqualToAnchor:scrollView.topAnchor constant:20], 34 | [stackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20], 35 | [stackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20], 36 | [stackView.bottomAnchor constraintEqualToAnchor:scrollView.bottomAnchor constant:-20], 37 | ]]; 38 | 39 | UITextField *redditTextField = [[UITextField alloc] init]; 40 | redditTextField.placeholder = @"Reddit API Key"; 41 | redditTextField.text = customIdentifier; 42 | redditTextField.delegate = self; 43 | redditTextField.clearButtonMode = UITextFieldViewModeWhileEditing; 44 | [stackView addArrangedSubview:redditTextField]; 45 | 46 | UITextField *imgurTextField = [[UITextField alloc] init]; 47 | imgurTextField.placeholder = @"Imgur API Key"; 48 | imgurTextField.tag = 1; 49 | imgurTextField.text = imgurAPIKey; 50 | imgurTextField.delegate = self; 51 | imgurTextField.clearButtonMode = UITextFieldViewModeWhileEditing; 52 | [stackView addArrangedSubview:imgurTextField]; 53 | 54 | UIButton *websiteButton = [UIButton systemButtonWithPrimaryAction:[UIAction actionWithTitle:@"Reddit API Website" image:nil identifier:nil handler:^(UIAction * action) { 55 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://reddit.com/prefs/apps"] options:@{} completionHandler:nil]; 56 | }]]; 57 | 58 | UIButton *imgurButton = [UIButton systemButtonWithPrimaryAction:[UIAction actionWithTitle:@"Imgur API Website" image:nil identifier:@"com.ryannair05" handler:^(UIAction * action) { 59 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://api.imgur.com/oauth2/addclient"] options:@{} completionHandler:nil]; 60 | }]]; 61 | 62 | UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(websiteButtonLongPressed:)]; 63 | UILongPressGestureRecognizer *imgurPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(websiteButtonLongPressed:)]; 64 | [websiteButton addGestureRecognizer:longPressGesture]; 65 | [imgurButton addGestureRecognizer:imgurPressGesture]; 66 | [stackView addArrangedSubview:websiteButton]; 67 | [stackView addArrangedSubview:imgurButton]; 68 | 69 | UILabel *label = [[UILabel alloc] init]; 70 | label.numberOfLines = 0; 71 | NSAttributedStringMarkdownParsingOptions *markdownOptions = [[NSAttributedStringMarkdownParsingOptions alloc] init]; 72 | markdownOptions.interpretedSyntax = NSAttributedStringMarkdownInterpretedSyntaxInlineOnly; 73 | 74 | label.attributedText = [[NSAttributedString alloc] initWithMarkdownString: 75 | @"**Use your own API credentials in Apollo**\n\n" 76 | @"Creating a Reddit API credential:\n" 77 | @"*You may need to sign out of all accounts in Apollo*\n\n" 78 | @"1. Sign into your reddit account (on desktop) and go to the link above (reddit.com/prefs/apps) \n" 79 | @"2. Click the `are you a developer? create an app...` button\n" 80 | @"3. Fill in the fields \n\t- Name: *anything* \n\t- Choose `Installed App` \n\t- Description: *anything*\n\t- About url: *anything* \n\t- Redirect uri: `apollo://reddit-oauth`\n" 81 | @"4. Click `create app`\n" 82 | @"5. After creating the app you'll get a client identifier which will be a bunch of random characters. **Enter your key above**\n" 83 | @"\nFor Imgur, go to the website above and register your application using the callback URL `https://www.getpostman.com/oauth2/callback` and fill in the rest of the fields similar to step 3\n\n" 84 | @"Thanks to Ethan Arbuckle for his contributions" 85 | options:markdownOptions baseURL:nil error:nil]; 86 | 87 | [stackView addArrangedSubview:label]; 88 | 89 | NSURL *githubImageURL = [NSURL URLWithString:@"https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"]; 90 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 91 | NSData *githubImageData = [NSData dataWithContentsOfURL:githubImageURL]; 92 | UIImage *githubImage = [UIImage imageWithData:githubImageData]; 93 | const CGFloat imageSize = 40; 94 | UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(imageSize, imageSize)]; 95 | UIImage *smallGithubImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context) { 96 | [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, imageSize, imageSize) cornerRadius:5.0] addClip]; 97 | [githubImage drawInRect:CGRectMake(0, 0, imageSize, imageSize)]; 98 | }]; 99 | 100 | dispatch_async(dispatch_get_main_queue(), ^{ 101 | UIButtonConfiguration *buttonConfiguration = [UIButtonConfiguration grayButtonConfiguration]; 102 | buttonConfiguration.imagePadding = 35; 103 | 104 | UIButton *githubButton = [UIButton buttonWithConfiguration:buttonConfiguration primaryAction: 105 | [UIAction actionWithTitle:@"Open source on Github" image:smallGithubImage identifier:nil handler:^(UIAction * action) { 106 | NSURL *url = [NSURL URLWithString:@"https://github.com/ryannair05/apolloapi"]; 107 | 108 | [UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil]; 109 | }]]; 110 | 111 | if (stackView.arrangedSubviews.count <= 5) { 112 | [stackView addArrangedSubview:githubButton]; 113 | } 114 | else { 115 | [stackView insertArrangedSubview:githubButton atIndex:5]; 116 | } 117 | }); 118 | }); 119 | 120 | NSURL *twitterImageURL = [NSURL URLWithString:@"https://pbs.twimg.com/profile_images/1161080936836018176/4GUKuGlb_200x200.jpg"]; 121 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 122 | NSData *twitterImageData = [NSData dataWithContentsOfURL:twitterImageURL]; 123 | UIImage *twitterImage = [UIImage imageWithData:twitterImageData]; 124 | const CGFloat imageSize = 40; 125 | UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(imageSize, imageSize)]; 126 | UIImage *smallTwitterImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull context) { 127 | [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, imageSize, imageSize) cornerRadius:5.0] addClip]; 128 | [twitterImage drawInRect:CGRectMake(0, 0, imageSize, imageSize)]; 129 | }]; 130 | 131 | dispatch_async(dispatch_get_main_queue(), ^{ 132 | UIButtonConfiguration *buttonConfiguration = [UIButtonConfiguration grayButtonConfiguration]; 133 | buttonConfiguration.imagePadding = 30; 134 | buttonConfiguration.subtitle = @"@ryannair05"; 135 | 136 | [stackView addArrangedSubview:[UIButton buttonWithConfiguration:buttonConfiguration primaryAction: 137 | [UIAction actionWithTitle:@"Developed by Ryan Nair" image:smallTwitterImage identifier:nil handler:^(UIAction * action) { 138 | NSURL *url = [NSURL URLWithString:@"https://twitter.com/ryannair05"]; 139 | 140 | [UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil]; 141 | }]] 142 | ]; 143 | }); 144 | }); 145 | } 146 | 147 | - (void)textFieldDidEndEditing:(UITextField *)textField { 148 | if (textField.tag == 0) { 149 | customIdentifier = textField.text; 150 | CFPreferencesSetAppValue(CFSTR("customAPIKey"), (__bridge CFStringRef) customIdentifier, CFSTR("com.ryannair05.apolloapi")); 151 | } 152 | else { 153 | imgurAPIKey = textField.text; 154 | CFPreferencesSetAppValue(CFSTR("imgurAPIKey"), (__bridge CFStringRef) imgurAPIKey, CFSTR("com.ryannair05.apolloapi")); 155 | } 156 | } 157 | 158 | - (void)websiteButtonLongPressed:(UILongPressGestureRecognizer *)gestureRecognizer { 159 | if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { 160 | NSURL *activityURL; 161 | 162 | if ([[(UIButton *) gestureRecognizer.view currentTitle] compare:@"Reddit" options:NSLiteralSearch | NSAnchoredSearch] == 1) { 163 | activityURL = [NSURL URLWithString:@"https://reddit.com/prefs/apps"]; 164 | } 165 | else { 166 | activityURL = [NSURL URLWithString:@"https://api.imgur.com/oauth2/addclient"]; 167 | } 168 | 169 | [self presentViewController:[[UIActivityViewController alloc] initWithActivityItems:@[activityURL] applicationActivities:nil] animated:YES completion:nil]; 170 | } 171 | } 172 | 173 | @end -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | FINALPACKAGE = 1 2 | 3 | TARGET := iphone:clang:latest:15.0 4 | INSTALL_TARGET_PROCESSES = Apollo 5 | 6 | ARCHS = arm64 7 | 8 | THEOS_PACKAGE_SCHEME=rootless 9 | 10 | include $(THEOS)/makefiles/common.mk 11 | 12 | TWEAK_NAME = ApolloAPI 13 | 14 | ApolloAPI_FILES = CustomAPIViewController.m Tweak.x 15 | ApolloAPI_CFLAGS = -fobjc-arc 16 | 17 | include $(THEOS_MAKE_PATH)/tweak.mk 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ApolloAPI 2 | 3 | ApolloAPI allows you to set a custom Reddit and Imgur API for Apollo. With it installed, go to Settings -> General inside of Apollo and select "Custom API" in the right corner of the navigation bar. From there, you can enter your own API keys along with directions on how to get your own keys. 4 | 5 | A custom user agent can also be set by going to the user profile tab and clicking User Agent on the top right. 6 | 7 | ## Installation 8 | 9 | 1. Add this repository to your package manager: https://havoc.app 10 | 2. Install **ApolloAPI**. 11 | 12 | ## Building 13 | 14 | To build ApolloAPI, [Theos](https://github.com/theos/theos) is required. With Theos installed, simply run `make package` in the project's directory to build. 15 | 16 | ## Credits 17 | 18 | Thanks to @EthanArbuckle for making [Apollo-CustomApiCredentials](https://github.com/EthanArbuckle/Apollo-CustomApiCredentials) which inspired and helped with the initial development of ApolloAPI 19 | -------------------------------------------------------------------------------- /Tweak.h: -------------------------------------------------------------------------------- 1 | #import "CustomAPIViewController.h" 2 | #include 3 | 4 | @interface OBButtonTray : UIView 5 | @property (nonatomic,retain) UIVisualEffectView * effectView; 6 | - (void)addButton:(id)arg1; 7 | - (void)addCaptionText:(id)arg1; 8 | @end 9 | 10 | @interface OBWelcomeController : UIViewController 11 | @property (nonatomic,retain) UIView * viewIfLoaded; 12 | - (OBButtonTray *)buttonTray; 13 | - (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; 14 | - (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; 15 | @end 16 | -------------------------------------------------------------------------------- /Tweak.x: -------------------------------------------------------------------------------- 1 | #import "Tweak.h" 2 | 3 | static void (*ApolloSettingsGeneralViewController_viewDidLoad_orig)(__unsafe_unretained UIViewController* const, SEL); 4 | static void ApolloSettingsGeneralViewController_viewDidLoad_swizzle(__unsafe_unretained UIViewController* const self, SEL _cmd) { 5 | ApolloSettingsGeneralViewController_viewDidLoad_orig(self, _cmd); 6 | 7 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithPrimaryAction: 8 | [UIAction actionWithTitle:@"Custom API" image:nil identifier:nil handler:^(UIAction * action) { 9 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:[[CustomAPIViewController alloc] init]]; 10 | [self presentViewController:navController animated:YES completion:nil]; 11 | }]]; 12 | } 13 | 14 | static void (*ApolloProfileViewController_viewDidLoad_orig)(__unsafe_unretained UIViewController* const, SEL); 15 | static void ApolloProfileViewController_viewDidLoad_swizzle(__unsafe_unretained UIViewController* const self, SEL _cmd) { 16 | ApolloProfileViewController_viewDidLoad_orig(self, _cmd); 17 | 18 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithPrimaryAction: 19 | [UIAction actionWithTitle:@"User Agent" image:nil identifier:nil handler:^(UIAction * action) { 20 | 21 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"User Agent" message:@"Enter a custom user agent" preferredStyle:UIAlertControllerStyleAlert]; 22 | 23 | [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { 24 | textField.text = (__bridge_transfer NSString *) CFPreferencesCopyAppValue(CFSTR("userAgent"), CFSTR("com.ryannair05.apolloapi")) ?: @"iOS: com.christianselig.Apollo v1.15.12 (by /u/iamthatis)"; 25 | }]; 26 | 27 | UIAlertAction *doneAction = [UIAlertAction actionWithTitle:@"Done" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { 28 | UITextField *textField = alertController.textFields.firstObject; 29 | if (textField.text.length > 0) { 30 | CFPreferencesSetAppValue(CFSTR("userAgent"), (__bridge CFStringRef) textField.text, CFSTR("com.ryannair05.apolloapi")); 31 | } 32 | else { 33 | CFPreferencesSetAppValue(CFSTR("userAgent"), CFSTR("iOS: com.christianselig.Apollo v1.15.12 (by /u/iamthatis)"), CFSTR("com.ryannair05.apolloapi")); 34 | } 35 | }]; 36 | 37 | [alertController addAction:doneAction]; 38 | UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; 39 | [alertController addAction:cancelAction]; 40 | 41 | [self presentViewController:alertController animated:YES completion:nil]; 42 | }]]; 43 | } 44 | 45 | static void (*ApolloWallpaperAlertViewController_viewDidAppear_orig)(__unsafe_unretained UIViewController* const, SEL, BOOL animated); 46 | static void ApolloWallpaperAlertViewController_viewDidAppear_swizzle(__unsafe_unretained UIViewController* const self, SEL _cmd, BOOL animated) { 47 | ApolloWallpaperAlertViewController_viewDidAppear_orig(self, _cmd, animated); 48 | 49 | UITabBarController *tabBarController = (UITabBarController *) [self presentingViewController]; 50 | 51 | if ([tabBarController selectedIndex] == 0) { 52 | [tabBarController dismissViewControllerAnimated:NO completion:nil]; 53 | } 54 | else { 55 | UIButton *wallpaperButton = self.view.subviews[3]; 56 | UIButtonConfiguration *buttonConfig = [UIButtonConfiguration filledButtonConfiguration]; 57 | buttonConfig.cornerStyle = UIButtonConfigurationCornerStyleLarge; 58 | buttonConfig.attributedTitle = [[NSAttributedString alloc] initWithString:@"Dismiss" attributes: @{NSFontAttributeName : [UIFont boldSystemFontOfSize:20.0]}]; 59 | 60 | UIButton *dismissButton = [UIButton buttonWithConfiguration:buttonConfig primaryAction: 61 | [UIAction actionWithHandler:^(UIAction * action) { 62 | [tabBarController dismissViewControllerAnimated:YES completion:nil]; 63 | }]]; 64 | 65 | dismissButton.alpha = 0.0; 66 | [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionTransitionNone animations:^{ 67 | dismissButton.alpha = 1.0; 68 | } completion:nil]; 69 | 70 | [self.view addSubview:dismissButton]; 71 | dismissButton.translatesAutoresizingMaskIntoConstraints = NO; 72 | 73 | [self.view addConstraints:@[ 74 | [NSLayoutConstraint constraintWithItem:dismissButton attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:wallpaperButton attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0], 75 | [NSLayoutConstraint constraintWithItem:dismissButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:wallpaperButton attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0], 76 | [NSLayoutConstraint constraintWithItem:dismissButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:wallpaperButton attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0], 77 | [NSLayoutConstraint constraintWithItem:dismissButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:wallpaperButton attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20] 78 | ]]; 79 | } 80 | } 81 | 82 | static void (*ApolloTabBarController_viewDidAppear_orig)(__unsafe_unretained UIViewController* const, SEL, BOOL animated); 83 | static void ApolloTabBarController_viewDidAppear_swizzle(__unsafe_unretained UIViewController* const self, SEL _cmd, BOOL animated) { 84 | ApolloTabBarController_viewDidAppear_orig(self, _cmd, animated); 85 | 86 | OBWelcomeController* welcomeController = [[objc_getClass("OBWelcomeController") alloc] initWithTitle:@"Apollo API" detailText:@"Apollo API allows you to enter a custom API key " icon:[UIImage systemImageNamed:@"character.cursor.ibeam"]]; 87 | 88 | [welcomeController addBulletedListItemWithTitle:@"Settings" description:@"Go to Settings -> General and click \"Custom API\" on the navigation bar" image:[UIImage systemImageNamed:@"1.circle.fill"]]; 89 | [welcomeController addBulletedListItemWithTitle:@"Make an API" description:@"Follow the directions to make an API Key on Reddit's website and insert the key into preferences" image:[UIImage systemImageNamed:@"2.circle.fill"]]; 90 | [welcomeController addBulletedListItemWithTitle:@"Insert New API" description:@"Changes are applied immediately, but it may take logging in and out of accounts to take effect" image:[UIImage systemImageNamed:@"3.circle.fill"]]; 91 | 92 | UIButton *continueButton = [UIButton buttonWithConfiguration:[UIButtonConfiguration filledButtonConfiguration] primaryAction: 93 | [UIAction actionWithTitle:@"Continue" image:nil identifier:nil handler:^(UIAction * action) { 94 | [self dismissViewControllerAnimated:YES completion:nil]; 95 | 96 | CFPreferencesSetAppValue(CFSTR("shownWelcomeController"), kCFBooleanTrue, CFSTR("com.ryannair05.apolloapi")); 97 | method_setImplementation(class_getInstanceMethod([self class], @selector(viewDidAppear:)), (IMP)ApolloTabBarController_viewDidAppear_orig); 98 | }]]; 99 | 100 | [welcomeController.buttonTray addButton:continueButton]; 101 | 102 | UIVisualEffectView *effectWelcomeView = [[UIVisualEffectView alloc] initWithFrame:welcomeController.viewIfLoaded.bounds]; 103 | 104 | effectWelcomeView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemChromeMaterial]; 105 | 106 | [welcomeController.viewIfLoaded insertSubview:effectWelcomeView atIndex:0]; 107 | 108 | welcomeController.viewIfLoaded.backgroundColor = [UIColor clearColor]; 109 | 110 | [welcomeController.buttonTray addCaptionText:@"Enjoy using Apollo!"]; 111 | 112 | welcomeController.modalPresentationStyle = UIModalPresentationPageSheet; 113 | welcomeController.modalInPresentation = YES; 114 | [self presentViewController:welcomeController animated:YES completion:nil]; 115 | } 116 | 117 | %hook RDKOAuthCredential 118 | - (NSString *)clientIdentifier { 119 | return customIdentifier ?: %orig; 120 | } 121 | %end 122 | 123 | %hook RDKClient 124 | - (NSString *)userAgent { 125 | NSString *customUserAgent = (__bridge_transfer NSString *) CFPreferencesCopyAppValue(CFSTR("userAgent"), CFSTR("com.ryannair05.apolloapi")); 126 | return customUserAgent ?: %orig; 127 | } 128 | %end 129 | 130 | %hook NSURLSession 131 | - (NSURLSessionUploadTask*)uploadTaskWithRequest:(NSURLRequest*)request fromData:(NSData*)bodyData completionHandler:(void (^)(NSData*, NSURLResponse*, NSError*))completionHandler { 132 | if ([[[request URL] lastPathComponent] isEqualToString:@"image"]) { 133 | NSMutableURLRequest *modifiedRequest = [request mutableCopy]; 134 | [modifiedRequest setURL:[NSURL URLWithString:[@"https://api.imgur.com/3/image?client_id=" stringByAppendingString:imgurAPIKey]]]; 135 | return %orig([modifiedRequest copy], bodyData, completionHandler); 136 | } 137 | return %orig; 138 | } 139 | 140 | - (NSURLSessionDataTask*)dataTaskWithRequest:(NSURLRequest*)request completionHandler:(void (^)(NSData*, NSURLResponse*, NSError*))completionHandler { 141 | NSURL *urlRequest = [request URL]; 142 | 143 | if ([[urlRequest host] compare:@"imgur-apiv3.p" options:NSLiteralSearch | NSAnchoredSearch range:NSMakeRange(0, 13)] == NSOrderedSame) { 144 | NSMutableURLRequest *modifiedRequest = [request mutableCopy]; 145 | [modifiedRequest setURL:[NSURL URLWithString:[@"https://api.imgur.com/3/image" stringByAppendingPathComponent:[urlRequest lastPathComponent]]]]; 146 | return %orig([modifiedRequest copy], completionHandler); 147 | } 148 | return %orig; 149 | } 150 | 151 | - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData *, NSURLResponse *, NSError *))completionHandler { 152 | if ([[url host] containsString:@"apollogur"]) { 153 | NSArray *apollogurComponents = url.pathComponents; 154 | NSString *endpointType = apollogurComponents[2]; 155 | 156 | if ([endpointType isEqualToString:@"image"] || [endpointType isEqualToString:@"album"]) { 157 | NSURL *modifiedURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://api.imgur.com/3/%@/%@.json?client_id=%@", endpointType, apollogurComponents[3], imgurAPIKey]]; 158 | return %orig(modifiedURL, completionHandler); 159 | } 160 | } 161 | 162 | return %orig; 163 | } 164 | %end 165 | 166 | %ctor { 167 | %init; 168 | 169 | MSHookMessageEx(objc_getClass("Apollo.SettingsGeneralViewController"), @selector(viewDidLoad), (IMP)&ApolloSettingsGeneralViewController_viewDidLoad_swizzle, (IMP*)&ApolloSettingsGeneralViewController_viewDidLoad_orig); 170 | MSHookMessageEx(objc_getClass("Apollo.ProfileViewController"), @selector(viewDidLoad), (IMP)&ApolloProfileViewController_viewDidLoad_swizzle, (IMP*)&ApolloProfileViewController_viewDidLoad_orig); 171 | MSHookMessageEx(objc_getClass("_TtGC7SwiftUI19UIHostingControllerV6Apollo18WallpaperAlertView_"), @selector(viewDidAppear:), (IMP)&ApolloWallpaperAlertViewController_viewDidAppear_swizzle, (IMP*)&ApolloWallpaperAlertViewController_viewDidAppear_orig); 172 | customIdentifier = (__bridge_transfer NSString *) CFPreferencesCopyAppValue(CFSTR("customAPIKey"), CFSTR("com.ryannair05.apolloapi")); 173 | imgurAPIKey = (__bridge_transfer NSString *) CFPreferencesCopyAppValue(CFSTR("imgurAPIKey"), CFSTR("com.ryannair05.apolloapi")); 174 | 175 | if (!CFPreferencesGetAppBooleanValue(CFSTR("shownWelcomeController"), CFSTR("com.ryannair05.apolloapi"), NULL) && objc_getClass("OBWelcomeController")) { 176 | ApolloTabBarController_viewDidAppear_orig = (void (*)(UIViewController* const, SEL, BOOL)) method_setImplementation(class_getInstanceMethod(objc_getClass("Apollo.ApolloTabBarController"), @selector(viewDidAppear:)), (IMP)ApolloTabBarController_viewDidAppear_swizzle); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: com.ryannair05.apolloapi 2 | Name: ApolloAPI 3 | Version: 1.0.2 4 | Architecture: iphoneos-arm 5 | Description: Custom API for Apollo 6 | Maintainer: Ryan Nair 7 | Author: Ryan Nair 8 | Section: Tweaks 9 | Depends: mobilesubstrate (>= 0.9.5000), firmware (>= 15.0) 10 | -------------------------------------------------------------------------------- /packages/com.ryannair05.apolloapi_1.0.2_iphoneos-arm.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryannair05/ApolloAPI/dd39509c2278eb1e101450463e4cd1e676119076/packages/com.ryannair05.apolloapi_1.0.2_iphoneos-arm.deb -------------------------------------------------------------------------------- /packages/com.ryannair05.apolloapi_1.0.2_iphoneos-arm64.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryannair05/ApolloAPI/dd39509c2278eb1e101450463e4cd1e676119076/packages/com.ryannair05.apolloapi_1.0.2_iphoneos-arm64.deb --------------------------------------------------------------------------------