mirror of
https://github.com/YuzuZensai/iOS-DiscordPresence.git
synced 2026-01-06 04:33:12 +00:00
207 lines
7.4 KiB
Plaintext
207 lines
7.4 KiB
Plaintext
#import <Tweak.h>
|
|
|
|
// Variable to store value from preferences
|
|
Boolean isEnabled = false;
|
|
NSString* discordToken = nil;
|
|
|
|
SBApplication* focusedApplication = nil;
|
|
NSString* lastKnownBundleIdentifier = nil;
|
|
Boolean isDeviceLocked = true;
|
|
|
|
%hook SpringBoard
|
|
|
|
-(void)frontDisplayDidChange:(id)arg1 {
|
|
|
|
%orig;
|
|
|
|
// Switched to SpringBoard
|
|
if(arg1 == nil) {
|
|
// If switched from SpringBoard to SpringBoard, ignore
|
|
if(focusedApplication == arg1) return;
|
|
|
|
// User is not in any application, clear the presence
|
|
focusedApplication = nil;
|
|
[self updateDiscordPresence:focusedApplication withState:@"STOP"];
|
|
|
|
return;
|
|
}
|
|
|
|
// Switched to Application
|
|
else if ([arg1 isKindOfClass:[%c(SBApplication) class]]) {
|
|
SBApplication *app = arg1;
|
|
|
|
Boolean isSystemApplication = [app isSystemApplication];
|
|
Boolean isGameApplication = [self isSBApplicationAGame:app];
|
|
|
|
// Switched to itself, ignore
|
|
if (focusedApplication == app) return;
|
|
|
|
// Ignore if the application is system application or is not a game
|
|
if(isSystemApplication || !isGameApplication) {
|
|
// Remove any focused application, since the user switched to non game or system application
|
|
if(focusedApplication != nil) {
|
|
// Remove current focused application and stop the presence
|
|
focusedApplication = nil;
|
|
[self updateDiscordPresence:focusedApplication withState:@"STOP"];
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Didn't switched from one application to another, start new presence
|
|
if(focusedApplication == nil) {
|
|
focusedApplication = app;
|
|
[self updateDiscordPresence:focusedApplication withState:@"START"];
|
|
}
|
|
|
|
// Switched from one application to another, update the presence
|
|
else {
|
|
focusedApplication = app;
|
|
[self updateDiscordPresence:focusedApplication withState:@"UPDATE"];
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
%new
|
|
- (bool)isSBApplicationAGame:(SBApplication *)app {
|
|
SBApplicationInfo *appInfo = [app info];
|
|
NSArray *category = [appInfo iTunesCategoriesOrderedByRelevancy];
|
|
//NSString *categoryStr = [category componentsJoinedByString:@", "];
|
|
|
|
// Does application contains "Games" category?
|
|
return [category containsObject:@"Games"];
|
|
}
|
|
|
|
%new
|
|
-(void)updateDiscordPresence:(id)arg1 withState:(NSString *)state {
|
|
|
|
if(![arg1 isKindOfClass:[%c(SBApplication) class]] && arg1 != nil) return;
|
|
|
|
if(!isEnabled) return;
|
|
|
|
NSString *accessToken = @"";
|
|
|
|
if(discordToken != nil)
|
|
accessToken = discordToken;
|
|
|
|
// If SBApplication is passed
|
|
if(arg1 != nil) {
|
|
SBApplication *app = (SBApplication *)arg1;
|
|
[self sendRequestToDiscord:accessToken withBundleIdentifier:[app bundleIdentifier] withState:state];
|
|
}
|
|
// No SBApplication passed, only STOP should be sent
|
|
else {
|
|
if(![state isEqualToString: @"STOP"]) return;
|
|
[self sendRequestToDiscord:accessToken withBundleIdentifier:nil withState:state];
|
|
}
|
|
}
|
|
|
|
%new
|
|
-(void)sendRequestToDiscord:(NSString *)accessToken withBundleIdentifier:(NSString *)bundleIdentifier withState:(NSString *)state {
|
|
|
|
// Discord API Presences endpoint
|
|
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc]
|
|
initWithURL:[NSURL URLWithString:@"https://discord.com/api/v6/presences"]
|
|
];
|
|
|
|
// Our body payload
|
|
NSDictionary *jsonBodyDict;
|
|
if(bundleIdentifier != nil) {
|
|
jsonBodyDict = @{ @"package_name":bundleIdentifier, @"update": state };
|
|
NSLog(@"Sending: Package_name: %@ State: %@", bundleIdentifier, state);
|
|
}
|
|
else {
|
|
if(lastKnownBundleIdentifier == nil) return;
|
|
jsonBodyDict = @{ @"package_name":lastKnownBundleIdentifier, @"update": state };
|
|
NSLog(@"Sending: Package_name: %@ State: %@", lastKnownBundleIdentifier, state);
|
|
}
|
|
|
|
lastKnownBundleIdentifier = bundleIdentifier;
|
|
|
|
// Serializate to body JSON
|
|
NSData *jsonBodyData = [NSJSONSerialization dataWithJSONObject:jsonBodyDict options:kNilOptions error:nil];
|
|
if(jsonBodyData == nil) return;
|
|
|
|
//Apply the data to the body
|
|
[urlRequest setHTTPBody:jsonBodyData];
|
|
|
|
// Set the request method to POST
|
|
[urlRequest setHTTPMethod:@"POST"];
|
|
|
|
// Set headers
|
|
// Clean user token
|
|
NSString *token = [accessToken stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
[urlRequest setValue:token forHTTPHeaderField:@"Authorization"];
|
|
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
|
[urlRequest setValue:@"max-age=121" forHTTPHeaderField:@"Cache-Control"];
|
|
// Use Android useragent. Well, so it's not sus
|
|
[urlRequest setValue:@"Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/100.0.4896.127 Mobile OceanHero/6 Safari/537.36" forHTTPHeaderField:@"User-Agent"];
|
|
|
|
NSURLSession *session = [NSURLSession sharedSession];
|
|
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
|
if(httpResponse.statusCode == 204)
|
|
{
|
|
NSLog(@"Request sent to Discord successfully");
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"Error from discord, Status Code: %ld", (long)httpResponse.statusCode);
|
|
}
|
|
}];
|
|
[dataTask resume];
|
|
}
|
|
%end
|
|
|
|
%hook SBLockScreenManager
|
|
|
|
-(void)_authenticationStateChanged:(id)arg1 {
|
|
|
|
%orig;
|
|
|
|
// Get the state changed notification, and find the SBFUserAuthenticationStateWasAuthenticatedKey value
|
|
NSConcreteNotification *notification = arg1;
|
|
int state = [[[notification userInfo] objectForKey: @"SBFUserAuthenticationStateWasAuthenticatedKey"] integerValue];
|
|
|
|
isDeviceLocked = state != 0;
|
|
// We don't need to take care anything else here. The frontDisplayDidChange will take care of it
|
|
}
|
|
|
|
-(void)_sendUILockStateChangedNotification {
|
|
|
|
%orig;
|
|
|
|
// The phone is locked or focused application is nil, ignore
|
|
if(isDeviceLocked || focusedApplication == nil) return;
|
|
// If the phone is unlocked, then the user is peeking at the notification or didn't swipe up to unlock yet.
|
|
|
|
Boolean isOnLockScreen = [self isLockScreenVisible];
|
|
|
|
// Switched to the lockscreen UI
|
|
if(isOnLockScreen) {
|
|
// Remove current focused application and stop the presence
|
|
focusedApplication = nil;
|
|
[[%c(SpringBoard) sharedApplication] updateDiscordPresence:focusedApplication withState:@"STOP"];
|
|
}
|
|
}
|
|
%end
|
|
|
|
static void loadPreferences()
|
|
{
|
|
NSString *preferencesPath = @"/var/mobile/Library/Preferences/pink.kirameki.yuzu.iosdiscordpresencepreferences.plist";
|
|
NSMutableDictionary *preferences = [[NSMutableDictionary alloc] initWithContentsOfFile: preferencesPath];
|
|
if(preferences)
|
|
{
|
|
NSLog(@"Updating preferences");
|
|
|
|
isEnabled = ( [preferences objectForKey:@"isEnabled"] ? [[preferences objectForKey:@"isEnabled"] boolValue] : isEnabled );
|
|
discordToken = ( [preferences objectForKey:@"discordToken"] ? [preferences objectForKey:@"discordToken"] : discordToken );
|
|
}
|
|
}
|
|
|
|
%ctor
|
|
{
|
|
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)loadPreferences, CFSTR("pink.kirameki.yuzu.iosdiscordpresencepreferences/PreferencesChanged"), NULL, CFNotificationSuspensionBehaviorCoalesce);
|
|
loadPreferences();
|
|
} |