mirror of
https://github.com/faroukbmiled/RyukGram.git
synced 2026-04-29 23:57:59 +02:00
feat: Replace Domain in Instagram urls
feat: Remove user param from copied links feat: Open links in External Browser feat: Strip Instagram tracking from browser links fix: Confirm reel refresh confirmation appears on app launch #2
This commit is contained in:
@@ -25,6 +25,10 @@ A feature-rich iOS tweak for Instagram, forked from [SCInsta](https://github.com
|
||||
- Copy comment text from long-press menu **\***
|
||||
- Download GIF comments **\***
|
||||
- Profile copy button **\***
|
||||
- Replace domain in shared links — rewrite copied/shared links for embeds in Discord, Telegram, etc. with preset or custom domains **\***
|
||||
- Strip tracking params from shared links (igsh, utm) **\***
|
||||
- Open links in external browser **\***
|
||||
- Strip tracking from browser links **\***
|
||||
- Do not save recent searches
|
||||
- Use detailed (native) color picker
|
||||
- Enable liquid glass buttons
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// Rewrite Instagram share links — replace domain + optionally strip tracking params.
|
||||
// Waits for IG's async clipboard write via changeCount, then rewrites once.
|
||||
|
||||
#import "../../Utils.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#import <substrate.h>
|
||||
|
||||
static NSString *sciRewriteIGURL(NSString *url) {
|
||||
if (!url.length) return url;
|
||||
|
||||
// Domain replacement
|
||||
if ([SCIUtils getBoolPref:@"embed_links"]) {
|
||||
NSString *domain = [SCIUtils getStringPref:@"embed_link_domain"];
|
||||
if (!domain.length) domain = @"kkinstagram.com";
|
||||
if (![url containsString:domain]) {
|
||||
NSArray *igDomains = @[@"www.instagram.com", @"instagram.com", @"www.instagr.am", @"instagr.am"];
|
||||
for (NSString *d in igDomains) {
|
||||
NSRange r = [url rangeOfString:d];
|
||||
if (r.location != NSNotFound) {
|
||||
NSString *target = [d hasPrefix:@"www."]
|
||||
? [NSString stringWithFormat:@"www.%@", domain] : domain;
|
||||
url = [url stringByReplacingCharactersInRange:r withString:target];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strip tracking params
|
||||
if ([SCIUtils getBoolPref:@"strip_tracking_params"]) {
|
||||
NSURLComponents *comps = [NSURLComponents componentsWithString:url];
|
||||
if (comps.queryItems.count) {
|
||||
NSArray *strip = @[@"igsh", @"ig_rid", @"utm_source", @"utm_medium", @"utm_campaign"];
|
||||
NSMutableArray *clean = [NSMutableArray array];
|
||||
for (NSURLQueryItem *q in comps.queryItems) {
|
||||
if (![strip containsObject:q.name]) [clean addObject:q];
|
||||
}
|
||||
comps.queryItems = clean.count ? clean : nil;
|
||||
NSString *result = comps.string;
|
||||
if (result) url = result;
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
static BOOL sciShouldRewrite(void) {
|
||||
return [SCIUtils getBoolPref:@"embed_links"] || [SCIUtils getBoolPref:@"strip_tracking_params"];
|
||||
}
|
||||
|
||||
// Rewrite clipboard once after IG writes
|
||||
static void sciPollAndRewrite(NSInteger countBefore, int polls, double interval) {
|
||||
__block BOOL done = NO;
|
||||
for (int i = 0; i < polls; i++) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((interval + i * interval) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (done) return;
|
||||
if ([UIPasteboard generalPasteboard].changeCount == countBefore) return;
|
||||
NSString *clip = [UIPasteboard generalPasteboard].string;
|
||||
if (!clip || ![clip containsString:@"instagram"]) return;
|
||||
NSString *rewritten = sciRewriteIGURL(clip);
|
||||
if (![rewritten isEqualToString:clip]) {
|
||||
[UIPasteboard generalPasteboard].string = rewritten;
|
||||
done = YES;
|
||||
} else {
|
||||
done = YES;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Hooks ============
|
||||
|
||||
static void (*orig_copyLink)(id, SEL, id);
|
||||
static void new_copyLink(id self, SEL _cmd, id vc) {
|
||||
if (!sciShouldRewrite()) { orig_copyLink(self, _cmd, vc); return; }
|
||||
NSInteger countBefore = [UIPasteboard generalPasteboard].changeCount;
|
||||
orig_copyLink(self, _cmd, vc);
|
||||
sciPollAndRewrite(countBefore, 30, 0.05);
|
||||
}
|
||||
|
||||
static void (*orig_shareMore)(id, SEL, id);
|
||||
static void new_shareMore(id self, SEL _cmd, id vc) {
|
||||
if (!sciShouldRewrite()) { orig_shareMore(self, _cmd, vc); return; }
|
||||
NSInteger countBefore = [UIPasteboard generalPasteboard].changeCount;
|
||||
orig_shareMore(self, _cmd, vc);
|
||||
sciPollAndRewrite(countBefore, 120, 0.1);
|
||||
}
|
||||
|
||||
__attribute__((constructor)) static void _embedLinksInit(void) {
|
||||
Class cls = NSClassFromString(@"IGExternalShareOptionsViewController");
|
||||
if (!cls) return;
|
||||
SEL copy = NSSelectorFromString(@"_shareToClipboardFromVC:");
|
||||
if (class_getInstanceMethod(cls, copy))
|
||||
MSHookMessageEx(cls, copy, (IMP)new_copyLink, (IMP *)&orig_copyLink);
|
||||
SEL more = NSSelectorFromString(@"_shareToMoreFromVC:");
|
||||
if (class_getInstanceMethod(cls, more))
|
||||
MSHookMessageEx(cls, more, (IMP)new_shareMore, (IMP *)&orig_shareMore);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Open links in external browser + strip IG tracking from URLs
|
||||
#import "../../Utils.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
// Extract the real URL from l.instagram.com redirects and strip tracking params
|
||||
static NSURL *sciCleanBrowserURL(NSURL *url) {
|
||||
if (![SCIUtils getBoolPref:@"strip_browser_tracking"]) return url;
|
||||
if (!url) return url;
|
||||
|
||||
NSString *urlStr = url.absoluteString;
|
||||
|
||||
// Unwrap l.instagram.com/?u=ENCODED_URL&e=TRACKING redirects
|
||||
if ([url.host isEqualToString:@"l.instagram.com"]) {
|
||||
NSURLComponents *comps = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
|
||||
for (NSURLQueryItem *q in comps.queryItems) {
|
||||
if ([q.name isEqualToString:@"u"] && q.value.length) {
|
||||
NSString *decoded = [q.value stringByRemovingPercentEncoding];
|
||||
if (decoded) urlStr = decoded;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strip common tracking params from the destination URL
|
||||
NSURLComponents *comps = [NSURLComponents componentsWithString:urlStr];
|
||||
if (comps.queryItems.count) {
|
||||
NSSet *trackingParams = [NSSet setWithArray:@[
|
||||
@"utm_source", @"utm_medium", @"utm_campaign", @"utm_content",
|
||||
@"utm_term", @"utm_id", @"fbclid", @"igshid", @"igsh",
|
||||
@"ig_rid", @"campaign_id", @"ad_id", @"aem"
|
||||
]];
|
||||
NSMutableArray *clean = [NSMutableArray array];
|
||||
for (NSURLQueryItem *q in comps.queryItems) {
|
||||
if (![trackingParams containsObject:q.name]) [clean addObject:q];
|
||||
}
|
||||
comps.queryItems = clean.count ? clean : nil;
|
||||
}
|
||||
|
||||
NSURL *result = comps.URL;
|
||||
return result ?: url;
|
||||
}
|
||||
|
||||
%hook IGBrowserNavigationController
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
id session = ((id(*)(id,SEL))objc_msgSend)(self, @selector(browserSession));
|
||||
Ivar urlIvar = session ? class_getInstanceVariable([session class], "_urlRequest") : nil;
|
||||
NSURLRequest *req = urlIvar ? object_getIvar(session, urlIvar) : nil;
|
||||
NSURL *url = req.URL;
|
||||
|
||||
if (url && [SCIUtils getBoolPref:@"open_links_external"]) {
|
||||
NSURL *cleaned = sciCleanBrowserURL(url);
|
||||
[[UIApplication sharedApplication] openURL:cleaned options:@{} completionHandler:nil];
|
||||
[(UIViewController *)self dismissViewControllerAnimated:NO completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
// For in-app browser: replace the URL request with the cleaned version
|
||||
if (url && [SCIUtils getBoolPref:@"strip_browser_tracking"]) {
|
||||
NSURL *cleaned = sciCleanBrowserURL(url);
|
||||
if (![cleaned isEqual:url]) {
|
||||
NSURLRequest *cleanReq = [NSURLRequest requestWithURL:cleaned];
|
||||
object_setIvar(session, urlIvar, cleanReq);
|
||||
}
|
||||
}
|
||||
|
||||
%orig;
|
||||
}
|
||||
%end
|
||||
@@ -28,27 +28,46 @@
|
||||
}
|
||||
%end
|
||||
|
||||
static BOOL sciReelRefreshInFlight = NO;
|
||||
|
||||
%hook IGSundialFeedViewController
|
||||
- (void)_refreshReelsWithParamsForNetworkRequest:(NSInteger)arg1 userDidPullToRefresh:(BOOL)arg2 {
|
||||
if ([SCIUtils getBoolPref:@"prevent_doom_scrolling"]) {
|
||||
IGRefreshControl *_refreshControl = MSHookIvar<IGRefreshControl *>(self, "_refreshControl");
|
||||
[self refreshControlDidEndFinishLoadingAnimation:_refreshControl];
|
||||
|
||||
IGRefreshControl *rc = MSHookIvar<IGRefreshControl *>(self, "_refreshControl");
|
||||
[self refreshControlDidEndFinishLoadingAnimation:rc];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([SCIUtils getBoolPref:@"refresh_reel_confirm"]) {
|
||||
NSLog(@"[SCInsta] Reel refresh triggered");
|
||||
|
||||
[SCIUtils showConfirmation:^(void) { %orig(arg1, arg2); }
|
||||
cancelHandler:^(void) {
|
||||
IGRefreshControl *_refreshControl = MSHookIvar<IGRefreshControl *>(self, "_refreshControl");
|
||||
[self refreshControlDidEndFinishLoadingAnimation:_refreshControl];
|
||||
}
|
||||
title:@"Refresh Reels"];
|
||||
} else {
|
||||
return %orig(arg1, arg2);
|
||||
if (![(UIViewController *)self isViewLoaded] || sciReelRefreshInFlight || ![SCIUtils getBoolPref:@"refresh_reel_confirm"]) {
|
||||
%orig(arg1, arg2);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the refresh control state so pull-to-refresh can trigger again
|
||||
IGRefreshControl *rc = MSHookIvar<IGRefreshControl *>(self, "_refreshControl");
|
||||
Ivar stateIvar = class_getInstanceVariable([rc class], "_refreshState");
|
||||
if (stateIvar) {
|
||||
ptrdiff_t off = ivar_getOffset(stateIvar);
|
||||
*(NSInteger *)((char *)(__bridge void *)rc + off) = 0;
|
||||
}
|
||||
if ([rc respondsToSelector:@selector(endRefreshing)])
|
||||
((void(*)(id,SEL))objc_msgSend)(rc, @selector(endRefreshing));
|
||||
[self refreshControlDidEndFinishLoadingAnimation:rc];
|
||||
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Refresh Reels?"
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
__weak id weakSelf = self;
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Refresh" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_) {
|
||||
sciReelRefreshInFlight = YES;
|
||||
SEL rSel = @selector(_refreshReelsWithParamsForNetworkRequest:userDidPullToRefresh:);
|
||||
((void(*)(id,SEL,NSInteger,BOOL))objc_msgSend)(weakSelf, rSel, arg1, arg2);
|
||||
sciReelRefreshInFlight = NO;
|
||||
}]];
|
||||
|
||||
UIViewController *presenter = (UIViewController *)self;
|
||||
[presenter presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
%end
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface SCIEmbedDomainViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
|
||||
@end
|
||||
@@ -0,0 +1,130 @@
|
||||
#import "SCIEmbedDomainViewController.h"
|
||||
#import "../Utils.h"
|
||||
|
||||
#define SCI_CUSTOM_DOMAINS_KEY @"embed_custom_domains"
|
||||
|
||||
static NSArray *sciPresetDomains(void) {
|
||||
return @[@"kkinstagram.com", @"ddinstagram.com", @"d.ddinstagram.com", @"g.ddinstagram.com"];
|
||||
}
|
||||
|
||||
@interface SCIEmbedDomainViewController ()
|
||||
@property (nonatomic, strong) UITableView *tableView;
|
||||
@property (nonatomic, copy) NSArray<NSString *> *customDomains;
|
||||
@end
|
||||
|
||||
@implementation SCIEmbedDomainViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.title = @"Embed domain";
|
||||
self.view.backgroundColor = [UIColor systemBackgroundColor];
|
||||
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped];
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.view addSubview:self.tableView];
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[self.tableView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
|
||||
[self.tableView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
|
||||
[self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
|
||||
[self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
|
||||
]];
|
||||
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
|
||||
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addCustom)];
|
||||
|
||||
[self reload];
|
||||
}
|
||||
|
||||
- (void)reload {
|
||||
NSArray *stored = [[NSUserDefaults standardUserDefaults] arrayForKey:SCI_CUSTOM_DOMAINS_KEY];
|
||||
self.customDomains = stored ?: @[];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)addCustom {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Add custom domain"
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addTextFieldWithConfigurationHandler:^(UITextField *tf) {
|
||||
tf.placeholder = @"example.com";
|
||||
tf.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
tf.autocorrectionType = UITextAutocorrectionTypeNo;
|
||||
tf.keyboardType = UIKeyboardTypeURL;
|
||||
}];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Add" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_) {
|
||||
NSString *domain = alert.textFields.firstObject.text;
|
||||
domain = [domain stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||
domain = [domain stringByReplacingOccurrencesOfString:@"https://" withString:@""];
|
||||
domain = [domain stringByReplacingOccurrencesOfString:@"http://" withString:@""];
|
||||
while ([domain hasSuffix:@"/"]) domain = [domain substringToIndex:domain.length - 1];
|
||||
if (!domain.length || ![domain containsString:@"."]) return;
|
||||
NSMutableArray *all = [self.customDomains mutableCopy];
|
||||
if (![all containsObject:domain]) [all addObject:domain];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:all forKey:SCI_CUSTOM_DOMAINS_KEY];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:domain forKey:@"embed_link_domain"];
|
||||
[self reload];
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Table
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tv { return 2; }
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tv titleForHeaderInSection:(NSInteger)section {
|
||||
return section == 0 ? @"Presets" : @"Custom";
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
|
||||
return section == 0 ? (NSInteger)sciPresetDomains().count : (NSInteger)self.customDomains.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:@"cell"];
|
||||
if (!cell) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
|
||||
NSString *domain = indexPath.section == 0
|
||||
? sciPresetDomains()[indexPath.row]
|
||||
: self.customDomains[indexPath.row];
|
||||
cell.textLabel.text = domain;
|
||||
NSString *current = [SCIUtils getStringPref:@"embed_link_domain"];
|
||||
if (!current.length) current = @"kkinstagram.com";
|
||||
cell.accessoryType = [domain isEqualToString:current] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tv deselectRowAtIndexPath:indexPath animated:YES];
|
||||
NSString *domain = indexPath.section == 0
|
||||
? sciPresetDomains()[indexPath.row]
|
||||
: self.customDomains[indexPath.row];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:domain forKey:@"embed_link_domain"];
|
||||
[tv reloadData];
|
||||
}
|
||||
|
||||
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tv trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.section == 0) return nil;
|
||||
NSString *domain = self.customDomains[indexPath.row];
|
||||
UIContextualAction *del = [UIContextualAction
|
||||
contextualActionWithStyle:UIContextualActionStyleDestructive title:@"Delete"
|
||||
handler:^(UIContextualAction *_, UIView *__, void (^cb)(BOOL)) {
|
||||
NSMutableArray *all = [self.customDomains mutableCopy];
|
||||
[all removeObject:domain];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:all forKey:SCI_CUSTOM_DOMAINS_KEY];
|
||||
// Reset to default if deleted domain was selected
|
||||
NSString *current = [SCIUtils getStringPref:@"embed_link_domain"];
|
||||
if ([current isEqualToString:domain])
|
||||
[[NSUserDefaults standardUserDefaults] setObject:@"kkinstagram.com" forKey:@"embed_link_domain"];
|
||||
[self reload];
|
||||
cb(YES);
|
||||
}];
|
||||
return [UISwipeActionsConfiguration configurationWithActions:@[del]];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tv canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return indexPath.section == 1;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -405,6 +405,7 @@ typedef NS_ENUM(NSInteger, SCIBackupPreviewRowKind) {
|
||||
return @[
|
||||
@"excluded_threads",
|
||||
@"excluded_story_users",
|
||||
@"embed_custom_domains",
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#import "../Features/StoriesAndMessages/SCIExcludedThreads.h"
|
||||
#import "../Features/StoriesAndMessages/SCIExcludedStoryUsers.h"
|
||||
#import "SCIExcludedStoryUsersViewController.h"
|
||||
#import "SCIEmbedDomainViewController.h"
|
||||
|
||||
@implementation SCITweakSettings
|
||||
|
||||
@@ -37,13 +38,42 @@
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Hide ads" subtitle:@"Removes all ads from the Instagram app" defaultsKey:@"hide_ads"],
|
||||
[SCISetting switchCellWithTitle:@"Hide Meta AI" subtitle:@"Hides the meta ai buttons/functionality within the app" defaultsKey:@"hide_meta_ai"],
|
||||
[SCISetting switchCellWithTitle:@"Do not save recent searches" subtitle:@"Search bars will no longer save your recent searches" defaultsKey:@"no_recent_searches"],
|
||||
[SCISetting switchCellWithTitle:@"Copy description" subtitle:@"Copy description text fields by long-pressing on them" defaultsKey:@"copy_description"],
|
||||
[SCISetting switchCellWithTitle:@"Profile copy button" subtitle:@"Adds a button next to the burger menu on profiles to copy username, name or bio" defaultsKey:@"profile_copy_button"],
|
||||
[SCISetting switchCellWithTitle:@"Do not save recent searches" subtitle:@"Search bars will no longer save your recent searches" defaultsKey:@"no_recent_searches"],
|
||||
[SCISetting switchCellWithTitle:@"Use detailed color picker" subtitle:@"Long press on the eyedropper tool in stories to customize the text color more precisely" defaultsKey:@"detailed_color_picker"],
|
||||
[SCISetting switchCellWithTitle:@"Enable liquid glass buttons" subtitle:@"Enables experimental liquid glass buttons within the app" defaultsKey:@"liquid_glass_buttons" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Enable liquid glass surfaces" subtitle:@"Enables liquid glass for other elements, such as menus" defaultsKey:@"liquid_glass_surfaces" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Enable teen app icons" subtitle:@"When enabled, hold down on the Instagram logo to change the app icon" defaultsKey:@"teen_app_icons" requiresRestart:YES]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"Browser",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Open links in external browser" subtitle:@"Opens links in Safari instead of Instagram's in-app browser" defaultsKey:@"open_links_external"],
|
||||
[SCISetting switchCellWithTitle:@"Strip tracking from links" subtitle:@"Removes Instagram tracking wrappers (l.instagram.com) and UTM/fbclid params from URLs" defaultsKey:@"strip_browser_tracking"],
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"Sharing",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Replace domain in shared links" subtitle:@"Rewrites copied/shared links to use an embed-friendly domain for previews in Discord, Telegram, etc." defaultsKey:@"embed_links"],
|
||||
({
|
||||
SCISetting *s = [SCISetting buttonCellWithTitle:@"Embed domain"
|
||||
subtitle:@""
|
||||
icon:[SCISymbol symbolWithName:@"globe"]
|
||||
action:^(void) {
|
||||
UIWindow *win = nil;
|
||||
for (UIWindow *w in [UIApplication sharedApplication].windows)
|
||||
if (w.isKeyWindow) { win = w; break; }
|
||||
UIViewController *top = win.rootViewController;
|
||||
while (top.presentedViewController) top = top.presentedViewController;
|
||||
if ([top isKindOfClass:[UINavigationController class]])
|
||||
[(UINavigationController *)top pushViewController:[SCIEmbedDomainViewController new] animated:YES];
|
||||
else if (top.navigationController)
|
||||
[top.navigationController pushViewController:[SCIEmbedDomainViewController new] animated:YES];
|
||||
}];
|
||||
s.dynamicTitle = ^{ return [NSString stringWithFormat:@"Embed domain: %@", [SCIUtils getStringPref:@"embed_link_domain"] ?: @"kkinstagram.com"]; };
|
||||
s;
|
||||
}),
|
||||
[SCISetting switchCellWithTitle:@"Strip tracking params" subtitle:@"Removes igsh, utm_source, and other tracking parameters from shared links" defaultsKey:@"strip_tracking_params"],
|
||||
]
|
||||
},
|
||||
@{
|
||||
@@ -70,6 +100,15 @@
|
||||
[SCISetting switchCellWithTitle:@"Hide explore posts grid" subtitle:@"Hides the grid of suggested posts on the explore/search tab" defaultsKey:@"hide_explore_grid"],
|
||||
[SCISetting switchCellWithTitle:@"Hide trending searches" subtitle:@"Hides the trending searches under the explore search bar" defaultsKey:@"hide_trending_searches"],
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"Experimental features",
|
||||
@"footer": @"These features rely on hidden Instagram flags and may not work on all accounts or versions.",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Enable liquid glass buttons" subtitle:@"Enables experimental liquid glass buttons" defaultsKey:@"liquid_glass_buttons" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Enable liquid glass surfaces" subtitle:@"Enables liquid glass for other elements" defaultsKey:@"liquid_glass_surfaces" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Enable teen app icons" subtitle:@"Hold down on the Instagram logo to change the app icon" defaultsKey:@"teen_app_icons" requiresRestart:YES]
|
||||
]
|
||||
}]
|
||||
],
|
||||
[SCISetting navigationCellWithTitle:@"Feed"
|
||||
|
||||
@@ -68,6 +68,11 @@ BOOL dmVisualMsgsViewedButtonEnabled = false;
|
||||
@"story_seen_mode": @"button",
|
||||
@"story_audio_toggle": @(NO),
|
||||
@"settings_pause_playback": @(YES),
|
||||
@"embed_links": @(NO),
|
||||
@"embed_link_domain": @"kkinstagram.com",
|
||||
@"strip_tracking_params": @(NO),
|
||||
@"open_links_external": @(NO),
|
||||
@"strip_browser_tracking": @(NO),
|
||||
@"hide_feed_repost": @(NO),
|
||||
@"copy_comment": @(YES),
|
||||
@"download_gif_comment": @(YES)
|
||||
|
||||
Reference in New Issue
Block a user