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 7858aec..a8f5510 100644
Binary files a/tfdidthatsay.plist and b/tfdidthatsay.plist differ
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