Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

291 lines
10KB

  1. #import "Apollo.h"
  2. static BOOL isTFDeletedOnly;
  3. static BOOL isApolloEnabled;
  4. static CGFloat pushshiftRequestTimeoutValue;
  5. %group Apollo
  6. NSDictionary* apolloBodyAttributes = nil;
  7. %hook ApolloApolloButtonNode
  8. %end
  9. %hook RKComment
  10. -(BOOL) isDeleted{
  11. return NO;
  12. }
  13. -(BOOL) isModeratorRemoved{
  14. return NO;
  15. }
  16. %end
  17. %hook MarkdownRenderer
  18. +(id) attributedStringFromHTML:(id)arg1 attributes:(id) arg2 compact:(BOOL) arg3{
  19. apolloBodyAttributes = [arg2 copy];
  20. return %orig;
  21. }
  22. %end
  23. %hook ApolloCommentCellNode
  24. %property(strong,nonatomic) id undeleteButton;
  25. %new
  26. -(void) didTapUndeleteButton:(id) sender{
  27. [sender setEnabled:NO];
  28. id bodyNode = MSHookIvar<id>(self, "bodyNode");
  29. id authorNode = MSHookIvar<id>(self, "authorNode");
  30. id authorTextNode = [authorNode subnodes][0];
  31. id comment = MSHookIvar<id>(self, "comment");
  32. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  33. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  34. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body",[[comment fullName] componentsSeparatedByString:@"_"][1]]]];
  35. [request setHTTPMethod:@"GET"];
  36. [request setTimeoutInterval:pushshiftRequestTimeoutValue];
  37. [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
  38. NSString *author = @"[author]";
  39. NSString *body = @"[body]";
  40. if (data != nil && error == nil){
  41. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  42. if ([[jsonData objectForKey:@"data"] count] != 0){
  43. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  44. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"];
  45. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  46. body = @"[pushshift was unable to archive this]";
  47. }
  48. } else {
  49. body = @"[pushshift has not archived this yet]";
  50. }
  51. } else if (error != nil || data == nil){
  52. body = [NSString stringWithFormat:@"[an error occured while attempting to contact pushshift api (%@)]", [error localizedDescription]];
  53. }
  54. id prevAuthorAttributedString = [authorTextNode attributedString];
  55. NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
  56. NSAttributedString* newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
  57. [authorTextNode setAttributedText:newAuthorAttributedString];
  58. [authorTextNode setAttributedString:newAuthorAttributedString];
  59. [comment setAuthor:author];
  60. [bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:body withAttributes:apolloBodyAttributes]];
  61. [sender setEnabled:YES];
  62. }];
  63. }
  64. -(void) didLoad {
  65. %orig;
  66. id commentBody = [MSHookIvar<id>(self, "comment") body];
  67. if ((isTFDeletedOnly && ([commentBody isEqualToString:@"[deleted]"] || [commentBody isEqualToString:@"[removed]"])) || !isTFDeletedOnly) {
  68. CGFloat imageSize = 20.0f;
  69. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  70. [undeleteButton addTarget:self action:@selector(didTapUndeleteButton:) forControlEvents:UIControlEventTouchUpInside];
  71. undeleteButton.frame = CGRectMake(0, 0, imageSize, imageSize);
  72. UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  73. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  74. [[self view] addSubview:undeleteButton];
  75. [self setUndeleteButton:undeleteButton];
  76. }
  77. }
  78. -(void) _layoutSublayouts{
  79. %orig;
  80. if ([self undeleteButton]){
  81. CGFloat imageSize = 20.0f;
  82. id moreNode = MSHookIvar<id>(self, "moreOptionsNode");
  83. id ageNode = MSHookIvar<id>(self, "ageNode");
  84. CGRect nodeFrame = [moreNode frame];
  85. CGFloat centerHeight = (nodeFrame.size.height + nodeFrame.origin.y * 2) / 2.0f;
  86. CGFloat nodeSpacing =[ageNode frame].origin.x - nodeFrame.origin.x - nodeFrame.size.width;
  87. [[self undeleteButton] setFrame:CGRectMake(nodeFrame.origin.x - imageSize - nodeSpacing, centerHeight - (imageSize / 2), imageSize, imageSize)];
  88. }
  89. }
  90. %end
  91. %hook ApolloCommentsHeaderCellNode
  92. %property(strong, nonatomic) id undeleteButton;
  93. %new
  94. -(void) didTapUndeleteButton:(id) sender{
  95. [sender setEnabled:NO];
  96. id bodyNode = MSHookIvar<id>(self, "bodyNode");
  97. id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
  98. id authorNode = MSHookIvar<id>(postInfoNode, "authorButtonNode");
  99. id authorTextNode = [authorNode subnodes][0];
  100. id post = MSHookIvar<id>(self, "link");
  101. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  102. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  103. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/submission/?ids=%@&fields=author,selftext",[[post fullName] componentsSeparatedByString:@"_"][1]]]];
  104. [request setHTTPMethod:@"GET"];
  105. [request setTimeoutInterval:pushshiftRequestTimeoutValue];
  106. [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
  107. NSString *author = @"[author]";
  108. NSString *body = @"[body]";
  109. if (data != nil && error == nil){
  110. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  111. if ([[jsonData objectForKey:@"data"] count] != 0){
  112. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  113. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"selftext"];
  114. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  115. body = @"[pushshift was unable to archive this]";
  116. }
  117. } else {
  118. body = @"[pushshift has not archived this yet]";
  119. }
  120. } else if (error != nil || data == nil){
  121. body = [NSString stringWithFormat:@"[an error occured while attempting to contact pushshift api (%@)]", [error localizedDescription]];
  122. }
  123. //MSHookIvar<NSString*>(post, "_author") = author; //Crashes when clicking on author name. You will have to search the author name to go find the profile.
  124. author = [NSString stringWithFormat:@"by %@", author];
  125. id prevAuthorAttributedString = [authorTextNode attributedString];
  126. NSDictionary *authorStringAttributes = [prevAuthorAttributedString attributesAtIndex:0 longestEffectiveRange:nil inRange:NSMakeRange(0, [prevAuthorAttributedString length])];
  127. NSAttributedString* newAuthorAttributedString = [[NSAttributedString alloc] initWithString:author attributes:authorStringAttributes];
  128. [authorTextNode setAttributedText:newAuthorAttributedString];
  129. [authorTextNode setAttributedString:newAuthorAttributedString];
  130. [bodyNode setAttributedString:[%c(MarkdownRenderer) attributedStringFromMarkdown:body withAttributes:apolloBodyAttributes]];
  131. [sender setEnabled:YES];
  132. }];
  133. }
  134. -(void) didLoad{
  135. %orig;
  136. id post = MSHookIvar<id>(self, "link");
  137. id postBody = [post selfText];
  138. if ([post isSelfPost]){
  139. if ((isTFDeletedOnly && ([postBody isEqualToString:@"[deleted]"] || [postBody isEqualToString:@"[removed]"])) || !isTFDeletedOnly) {
  140. CGFloat imageSize = 20.0f;
  141. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  142. [undeleteButton addTarget:self action:@selector(didTapUndeleteButton:) forControlEvents:UIControlEventTouchUpInside];
  143. UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  144. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  145. undeleteButton.frame = CGRectMake(0, 0, imageSize, imageSize);
  146. [[self view] addSubview:undeleteButton];
  147. [self setUndeleteButton:undeleteButton];
  148. }
  149. }
  150. }
  151. -(void) _layoutSublayouts{
  152. %orig;
  153. if ([self undeleteButton]){
  154. CGFloat imageSize = 20.0f;
  155. id postInfoNode = MSHookIvar<id>(self, "postInfoNode");
  156. id ageNode = MSHookIvar<id>(postInfoNode, "ageButtonNode");
  157. CGFloat centerHeight = [postInfoNode frame].origin.y + ([ageNode frame].size.height + [ageNode frame].origin.y * 2) / 2.0f;
  158. CGFloat buttonXPos = [postInfoNode frame].origin.x + [postInfoNode frame].size.width - imageSize;
  159. [[self undeleteButton] setFrame:CGRectMake(buttonXPos, centerHeight - (imageSize / 2), imageSize, imageSize)];
  160. }
  161. }
  162. %end
  163. %end
  164. static void loadPrefs(){
  165. NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/User/Library/Preferences/com.lint.undelete.prefs.plist"];
  166. if (prefs){
  167. if ([prefs objectForKey:@"isApolloEnabled"] != nil) {
  168. isApolloEnabled = [[prefs objectForKey:@"isApolloEnabled"] boolValue];
  169. } else {
  170. isApolloEnabled = YES;
  171. }
  172. if ([prefs objectForKey:@"isTFDeletedOnly"] != nil) {
  173. isTFDeletedOnly = [[prefs objectForKey:@"isTFDeletedOnly"] boolValue];
  174. } else {
  175. isTFDeletedOnly = YES;
  176. }
  177. if ([prefs objectForKey:@"requestTimeoutValue"] != nil){
  178. pushshiftRequestTimeoutValue = [[prefs objectForKey:@"requestTimeoutValue"] doubleValue];
  179. } else {
  180. pushshiftRequestTimeoutValue = 10;
  181. }
  182. } else {
  183. isApolloEnabled = YES;
  184. isTFDeletedOnly = YES;
  185. pushshiftRequestTimeoutValue = 10;
  186. }
  187. }
  188. static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
  189. loadPrefs();
  190. }
  191. %ctor {
  192. loadPrefs();
  193. NSString* processName = [[NSProcessInfo processInfo] processName];
  194. if ([processName isEqualToString:@"Apollo"]){
  195. if (isApolloEnabled){
  196. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, prefsChanged, CFSTR("com.lint.undelete.prefs.changed"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
  197. %init(Apollo, ApolloCommentsHeaderCellNode = objc_getClass("Apollo.CommentsHeaderCellNode"), ApolloCommentCellNode = objc_getClass("Apollo.CommentCellNode"), ApolloApolloButtonNode = objc_getClass("Apollo.ApolloButtonNode"));
  198. }
  199. }
  200. }