From 5bfb85ac74ab6ca29d82505c38a7945f740bb5d1 Mon Sep 17 00:00:00 2001 From: lint <47455468+lint@users.noreply.github.com> Date: Tue, 10 Dec 2019 00:54:26 -0500 Subject: [PATCH] Add BaconReader support --- prefs/Resources/Root.plist | 28 ++++ tfdidthatsay.plist | Bin 199 -> 229 bytes tweak/BaconReader.h | 59 +++++++++ tweak/BaconReader.xm | 263 +++++++++++++++++++++++++++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 tweak/BaconReader.h create mode 100644 tweak/BaconReader.xm diff --git a/prefs/Resources/Root.plist b/prefs/Resources/Root.plist index b8322ce..933eab0 100644 --- a/prefs/Resources/Root.plist +++ b/prefs/Resources/Root.plist @@ -82,6 +82,20 @@ label Enable Slide + + PostNotification + com.lint.undelete.prefs.changed + cell + PSSwitchCell + default + + defaults + com.lint.undelete.prefs + key + isBaconReaderEnabled + label + Enable BaconReader + cell PSGroupCell @@ -132,6 +146,20 @@ label Slide | Deleted only + + PostNotification + com.lint.undelete.prefs.changed + cell + PSSwitchCell + default + + defaults + com.lint.undelete.prefs + key + isBaconReaderDeletedOnly + label + BaconReader | Deleted only + cell PSGroupCell diff --git a/tfdidthatsay.plist b/tfdidthatsay.plist index 7858aec207ef8f242b0b44c517d531ad3726e965..a8f55103811680037d615ea00fa0b3e161d7339e 100644 GIT binary patch delta 89 zcmX@k_>^&iEc-H6Hg*n9u8GQ3?(qVW$@#f@`FW{1`K2kTMS4z&$@zIfsfj=~2e*)@ YtcpcQe%m|-Fkoba&pvdZScd94g!z{m)p8MvS{jG7AoGj<0f diff --git a/tweak/BaconReader.h b/tweak/BaconReader.h new file mode 100644 index 0000000..d30a3db --- /dev/null +++ b/tweak/BaconReader.h @@ -0,0 +1,59 @@ + +/* -- Votable Interfaces -- */ + +@interface BRVotable +@property(strong, nonatomic) NSString *serverID; +@property(strong, nonatomic) NSAttributedString *attributedDescriptionString; +@property(assign, nonatomic) CGSize cellSize; +@end + +@interface BRComment : BRVotable +@property(strong, nonatomic) NSString *author; +@property(strong, nonatomic) NSString *body; +@property(strong, nonatomic) NSString *body_html; +@end + +@interface BRStory : BRVotable +@property(strong, nonatomic) NSString *author; +@property(strong, nonatomic) NSString *selftext; +@property(strong, nonatomic) NSString *selftext_html; +@property(assign, nonatomic) BOOL is_selfValue; +@end + +/* -- Comment Interfaces -- */ + +@interface CommentCell +@property(strong, nonatomic) id cellView; +@end + +@interface CommentCellView +@property(strong, nonatomic) id comment; +@property(strong, nonatomic) id parentDelegate; +@end + +@interface BRComposeCommentViewController : NSObject +@property(assign, nonatomic) BOOL editComment; +@end + +/* -- Post Interfaces -- */ + +@interface StoryDetailView +@property(strong, nonatomic) UITableView *tableView; +-(void) refreshTouched; +@end + +@interface StoryDetailViewController +@property(strong, nonatomic) id story; +@property(strong, nonatomic) id detailPage; + +//custom elements +-(void) handleUndeleteCommentAction; +-(void) handleUndeletePostAction; +@end + +/* -- Other Interfaces -- */ + +@interface BRUtils ++(id) attributedDescriptionForComment:(id) arg1; ++(id) createAttributedStringFromHTML:(id) arg1 options:(id) arg2; +@end diff --git a/tweak/BaconReader.xm b/tweak/BaconReader.xm new file mode 100644 index 0000000..0535ec4 --- /dev/null +++ b/tweak/BaconReader.xm @@ -0,0 +1,263 @@ + +#import "BaconReader.h" +#import "assets/MMMarkdown.h" + +static BOOL isBaconReaderEnabled; +static BOOL isBaconReaderDeletedOnly; +static CGFloat pushshiftRequestTimeoutValue; + +%group BaconReader + +BOOL shouldHaveBRUndeleteAction = NO; +NSString *tfPostSelftext; +NSString *tfPostAuthor; +id tfCommentCellView; +id tfStoryController; + + +%hook CommentCell +%end + +%hook CommentCellView +%end + +%hook StoryDetailView +%end + + +%hook BRComment + +-(BOOL) contains_htmlValue{ + return YES; +} + +-(BOOL) primitiveContains_htmlValue{ + return YES; +} + +-(BOOL) is_deletedValue{ + return NO; +} + +-(BOOL) primitiveIs_deletedValue{ + return NO; +} + +%end + + +%hook BRStory + ++(id) storyWithDictionary:(id) arg1 inContext:(id) arg2 { + id orig = %orig; + + if (tfPostSelftext){ + [orig setSelftext_html:tfPostSelftext]; + [orig setAuthor:tfPostAuthor]; + tfPostSelftext = nil; + tfPostAuthor = nil; + } + + return orig; +} + +%end + + +%hook UIViewController + +-(void) presentViewController:(id) arg1 animated:(BOOL) arg2 completion:(id) arg3 { + + if ([arg1 isKindOfClass:[UIAlertController class]] && shouldHaveBRUndeleteAction){ + + UIAlertAction *undeleteAction; + + if (tfCommentCellView){ + undeleteAction = [UIAlertAction actionWithTitle:@"TF Did That Say?" style:nil handler:^(UIAlertAction* action){[tfStoryController handleUndeleteCommentAction];}]; + } else { + undeleteAction = [UIAlertAction actionWithTitle:@"TF Did That Say?" style:nil handler:^(UIAlertAction* action){[tfStoryController handleUndeletePostAction];}]; + } + + [arg1 addAction:undeleteAction]; + } + + %orig; +} + +%end + + +%hook StoryDetailViewController + +-(void) showMoreCommentActions:(id) arg1 showAll:(BOOL) arg2 { + + NSString *commentBody = [[arg1 comment] body]; + + if ((isBaconReaderDeletedOnly && ([commentBody isEqualToString:@"[deleted]"] || [commentBody isEqualToString:@"[removed]"])) || !isBaconReaderDeletedOnly) { + shouldHaveBRUndeleteAction = YES; + tfCommentCellView = arg1; + tfStoryController = self; + tfPostSelftext = nil; + } + + %orig; + + shouldHaveBRUndeleteAction = NO; +} + +-(void) menuTouchedWithSender:(id) arg1 { + + if ([[self story] is_selfValue]){ + NSString *postBody = [[self story] selftext]; + + if ((isBaconReaderDeletedOnly && ([postBody isEqualToString:@"[deleted]"] || [postBody isEqualToString:@"[removed]"])) || !isBaconReaderDeletedOnly) { + shouldHaveBRUndeleteAction = YES; + tfCommentCellView = nil; + tfStoryController = self; + tfPostSelftext = nil; + } + } + + %orig; + + shouldHaveBRUndeleteAction = NO; +} + +%new +-(void) handleUndeleteCommentAction{ + + id comment = [tfCommentCellView comment]; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + + [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body", [comment serverID]]]]; + [request setHTTPMethod:@"GET"]; + [request setTimeoutInterval:pushshiftRequestTimeoutValue]; + + [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { + + NSString *author = @"[author]"; + NSString *body = @"[body]"; + + if (data != nil && error == nil){ + id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + if ([[jsonData objectForKey:@"data"] count] != 0){ + author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"]; + body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"]; + if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){ + body = @"[pushshift was unable to archive this]"; + } + } else { + body = @"[pushshift has not archived this yet]"; + } + } else if (error != nil || data == nil){ + body = [NSString stringWithFormat:@"[an error occured while attempting to contact pushshift api (%@)]", [error localizedDescription]]; + } + + [comment setAuthor:author]; + [comment setBody:body]; + [comment setBody_html:[%c(MMMarkdown) HTMLStringWithMarkdown:body extensions:MMMarkdownExtensionsGitHubFlavored error:nil]]; + [comment setAttributedDescriptionString:nil]; + + NSAttributedString *commentAttrString = [%c(BRUtils) attributedDescriptionForComment:comment]; + [comment setAttributedDescriptionString:commentAttrString]; + + [[[self detailPage] tableView] performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; + }]; +} + +%new +-(void) handleUndeletePostAction{ + + id post = [self story]; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + + [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/submission/?ids=%@&fields=author,selftext", [post serverID]]]]; + [request setHTTPMethod:@"GET"]; + [request setTimeoutInterval:pushshiftRequestTimeoutValue]; + + [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { + + NSString *author = @"[author]"; + NSString *body = @"[body]"; + + if (data != nil && error == nil){ + id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + if ([[jsonData objectForKey:@"data"] count] != 0){ + author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"]; + body = [[jsonData objectForKey:@"data"][0] objectForKey:@"selftext"]; + if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){ + body = @"[pushshift was unable to archive this]"; + } + } else { + body = @"[pushshift has not archived this yet]"; + } + } else if (error != nil || data == nil){ + body = [NSString stringWithFormat:@"[an error occured while attempting to contact pushshift api (%@)]", [error localizedDescription]]; + } + + tfPostAuthor = author; + tfPostSelftext = [%c(MMMarkdown) HTMLStringWithMarkdown:body extensions:MMMarkdownExtensionsGitHubFlavored error:nil]; + + [[self detailPage] performSelectorOnMainThread:@selector(refreshTouched) withObject:nil waitUntilDone:NO]; + + }]; +} + +%end + +%end + + +static void loadPrefs(){ + NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/User/Library/Preferences/com.lint.undelete.prefs.plist"]; + + if (prefs){ + + if ([prefs objectForKey:@"isBaconReaderEnabled"] != nil){ + isBaconReaderEnabled = [[prefs objectForKey:@"isBaconReaderEnabled"] boolValue]; + } else { + isBaconReaderEnabled = YES; + } + + if ([prefs objectForKey:@"requestTimeoutValue"] != nil){ + pushshiftRequestTimeoutValue = [[prefs objectForKey:@"requestTimeoutValue"] doubleValue]; + } else { + pushshiftRequestTimeoutValue = 10; + } + + if ([prefs objectForKey:@"isBaconReaderDeletedOnly"] != nil) { + isBaconReaderDeletedOnly = [[prefs objectForKey:@"isBaconReaderDeletedOnly"] boolValue]; + } else { + isBaconReaderDeletedOnly = YES; + } + + } else { + isBaconReaderEnabled = YES; + isBaconReaderDeletedOnly = YES; + pushshiftRequestTimeoutValue = 10; + } +} + +static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { + loadPrefs(); +} + + +%ctor { + loadPrefs(); + + NSString* processName = [[NSProcessInfo processInfo] processName]; + + if ([processName isEqualToString:@"BaconReader"]){ + if (isBaconReaderEnabled){ + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, prefsChanged, CFSTR("com.lint.undelete.prefs.changed"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + + %init(BaconReader, StoryDetailView = objc_getClass("BaconReader.StoryDetailView"), StoryDetailViewController = objc_getClass("BaconReader.StoryDetailViewController"), CommentCellView = objc_getClass("BaconReader.CommentCellView"), CommentCell = objc_getClass("BaconReader.CommentCell")); + } + } +} \ No newline at end of file