選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

597 行
20KB

  1. #import "Reddit.h"
  2. %group Reddit_v4_current
  3. %hook CommentTreeNode
  4. %property(assign,nonatomic)id commentTreeHeaderNode;
  5. %property(assign,nonatomic)id commentTreeCommandBarNode;
  6. %end
  7. %hook CommentTreeHeaderView
  8. -(void) layoutSubviews{
  9. %orig;
  10. [[self commentTreeNode] setCommentTreeHeaderNode:self];
  11. }
  12. %end
  13. %hook CommentTreeHeaderNode
  14. -(void) didLoad{
  15. %orig;
  16. [[self commentTreeNode] setCommentTreeHeaderNode:self];
  17. }
  18. %end
  19. %hook CommentTreeCommandBarNode
  20. -(void) didLoad{
  21. %orig;
  22. [[self commentTreeNode] setCommentTreeCommandBarNode:self];
  23. }
  24. %end
  25. %hook CommentActionSheetViewController
  26. -(void) setItems:(id) arg1{
  27. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  28. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  29. CGFloat scale = origImage.size.width / existingImageSize.width;
  30. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  31. id undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self comment]];
  32. %orig([arg1 arrayByAddingObject:undeleteItem]);
  33. [undeleteItem release];
  34. }
  35. -(void) handleDidSelectActionSheetItem:(id) arg1{
  36. %orig;
  37. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  38. [self dismissViewControllerAnimated:YES completion:nil];
  39. id commentTreeNode = [self commentTreeNode];
  40. Comment *comment = [commentTreeNode comment];
  41. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  42. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  43. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body",[[comment pk] componentsSeparatedByString:@"_"][1]]]];
  44. [request setHTTPMethod:@"GET"];
  45. [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
  46. NSString *author = @"[author]";
  47. NSString *body = @"[body]";
  48. if (data != nil && error == nil){
  49. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  50. if ([[jsonData objectForKey:@"data"] count] != 0){
  51. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  52. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"];
  53. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  54. body = @"[pushshift was unable to archive this]";
  55. }
  56. } else {
  57. body = @"[pushshift has not archived this yet]";
  58. }
  59. } else if (error != nil || data == nil){
  60. body = @"[an error occured]";
  61. }
  62. NSArray* appVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] componentsSeparatedByString:@"."];
  63. NSMutableAttributedString *bodyMutableAttributedText;
  64. id themeManager;
  65. id isNightMode;
  66. id textColor;
  67. if ([appVersion[1] integerValue] >= 45){
  68. themeManager = [[%c(ThemeManager) alloc] initWithAppSettings:[%c(AppSettings) sharedSettings]];
  69. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  70. if (isNightMode) {
  71. textColor = [[themeManager darkTheme] bodyTextColor];
  72. } else{
  73. textColor = [[themeManager lightTheme] bodyTextColor];
  74. }
  75. [themeManager release];
  76. } else if ([appVersion[1] integerValue] >= 37){
  77. themeManager = [[%c(ThemeManager) alloc] initWithTraitCollection:nil appSettings:[%c(AppSettings) sharedSettings]];
  78. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  79. if (isNightMode) {
  80. textColor = [[themeManager nightTheme] bodyTextColor];
  81. } else{
  82. textColor = [[themeManager dayTheme] bodyTextColor];
  83. }
  84. [themeManager release];
  85. } else {
  86. themeManager = [%c(ThemeManager) sharedManager];
  87. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  88. if (isNightMode) {
  89. textColor = [[themeManager nightTheme] bodyTextColor];
  90. } else{
  91. textColor = [[themeManager dayTheme] bodyTextColor];
  92. }
  93. }
  94. bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  95. [bodyMutableAttributedText beginEditing];
  96. [bodyMutableAttributedText enumerateAttribute:NSForegroundColorAttributeName inRange:NSMakeRange(0, bodyMutableAttributedText.length) options:0 usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
  97. [bodyMutableAttributedText removeAttribute:NSForegroundColorAttributeName range:range];
  98. [bodyMutableAttributedText addAttribute:NSForegroundColorAttributeName value:textColor range:range];
  99. }];
  100. [bodyMutableAttributedText endEditing];
  101. [comment setAuthor:author];
  102. [comment setBodyText:body];
  103. [comment setBodyRichTextAttributed:bodyMutableAttributedText];
  104. [comment setBodyAttributedText:bodyMutableAttributedText];
  105. [[commentTreeNode commentTreeHeaderNode] performSelectorOnMainThread:@selector(updateContentViewsForData:) withObject:comment waitUntilDone:NO];
  106. [request release];
  107. [queue release];
  108. [bodyMutableAttributedText release];
  109. }];
  110. }
  111. }
  112. %end
  113. %hook PostDetailViewController
  114. %property(strong,nonatomic) id feedPostTextWithThumbnailNode;
  115. %property(strong,nonatomic) id feedPostDetailCellNode;
  116. %end
  117. %hook FeedPostDetailCellNode
  118. -(void) didLoad{
  119. %orig;
  120. [[[self delegate] viewController] setFeedPostDetailCellNode:self];
  121. }
  122. %end
  123. %hook PostActionSheetViewController
  124. -(void) setItems:(id) arg1{
  125. Post *post = [self post];
  126. if ([post isSelfPost]){
  127. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  128. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  129. CGFloat scale = origImage.size.width / existingImageSize.width;
  130. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  131. id undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self post]];
  132. arg1 = [arg1 arrayByAddingObject:undeleteItem];
  133. [undeleteItem release];
  134. }
  135. %orig;
  136. }
  137. -(void) handleDidSelectActionSheetItem:(id) arg1{
  138. %orig;
  139. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  140. [self dismissViewControllerAnimated:YES completion:nil];
  141. Post *post = [self post];
  142. if ([post isSelfPost]){
  143. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  144. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  145. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/submission/?ids=%@&fields=author,selftext",[[post pk] componentsSeparatedByString:@"_"][1]]]];
  146. [request setHTTPMethod:@"GET"];
  147. [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
  148. NSString *author = @"[author]";
  149. NSString *body = @"[body]";
  150. if (data != nil && error == nil){
  151. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  152. if ([[jsonData objectForKey:@"data"] count] != 0){
  153. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  154. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"selftext"];
  155. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  156. body = @"[pushshift was unable to archive this]";
  157. }
  158. } else {
  159. body = @"[pushshift has not archived this yet]";
  160. }
  161. } else if (error != nil || data == nil){
  162. body = @"[an error occured]";
  163. }
  164. NSArray* appVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] componentsSeparatedByString:@"."];
  165. id themeManager;
  166. id isNightMode;
  167. id textColor;
  168. if ([appVersion[1] integerValue] >= 45){
  169. themeManager = [[%c(ThemeManager) alloc] initWithAppSettings:[%c(AppSettings) sharedSettings]];
  170. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  171. if (isNightMode) {
  172. textColor = [[themeManager darkTheme] bodyTextColor];
  173. } else{
  174. textColor = [[themeManager lightTheme] bodyTextColor];
  175. }
  176. [themeManager release];
  177. } else if ([appVersion[1] integerValue] >= 37){
  178. themeManager = [[%c(ThemeManager) alloc] initWithTraitCollection:nil appSettings:[%c(AppSettings) sharedSettings]];
  179. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  180. if (isNightMode) {
  181. textColor = [[themeManager nightTheme] bodyTextColor];
  182. } else{
  183. textColor = [[themeManager dayTheme] bodyTextColor];
  184. }
  185. [themeManager release];
  186. } else {
  187. themeManager = [%c(ThemeManager) sharedManager];
  188. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  189. if (isNightMode) {
  190. textColor = [[themeManager nightTheme] bodyTextColor];
  191. } else{
  192. textColor = [[themeManager dayTheme] bodyTextColor];
  193. }
  194. }
  195. NSMutableAttributedString *bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  196. [bodyMutableAttributedText beginEditing];
  197. [bodyMutableAttributedText enumerateAttribute:NSForegroundColorAttributeName inRange:NSMakeRange(0, bodyMutableAttributedText.length) options:0 usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
  198. [bodyMutableAttributedText removeAttribute:NSForegroundColorAttributeName range:range];
  199. [bodyMutableAttributedText addAttribute:NSForegroundColorAttributeName value:textColor range:range];
  200. }];
  201. [bodyMutableAttributedText endEditing];
  202. [post setSelfText:body];
  203. [post setAuthor:author];
  204. [post setSelfPostRichTextAttributed:bodyMutableAttributedText];
  205. [post setPreviewFeedPostTextString:bodyMutableAttributedText];
  206. if ([appVersion[1] integerValue] >= 44){
  207. [[[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] contentNode] configureSelfTextNode];
  208. } else if ([appVersion[1] integerValue] >= 38) {
  209. [[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] configureSelfTextNode];
  210. } else {
  211. [[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] configureSelfTextNode];
  212. [[[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] titleNode] configureNodes];
  213. }
  214. [request release];
  215. [queue release];
  216. [bodyMutableAttributedText release];
  217. }];
  218. }
  219. }
  220. }
  221. %end
  222. %end
  223. %group Reddit_v4_ios10
  224. %hook CommentsViewController
  225. %new
  226. -(void) updateComments{
  227. [self reloadCommentsWithNewCommentsHighlight:NO autoScroll:NO animated:NO];
  228. }
  229. %new
  230. -(void) updatePostText{
  231. [self reloadPostSection:YES];
  232. }
  233. %end
  234. %hook CommentActionSheetViewController
  235. -(void) setItems:(id) arg1{
  236. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  237. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  238. CGFloat scale = origImage.size.width / existingImageSize.width;
  239. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  240. id undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self comment]];
  241. %orig([arg1 arrayByAddingObject:undeleteItem]);
  242. [undeleteItem release];
  243. }
  244. -(void) handleDidSelectActionSheetItem:(id) arg1{
  245. %orig;
  246. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  247. [self dismissViewControllerAnimated:YES completion:nil];
  248. Comment *comment = [self comment];
  249. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  250. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  251. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body",[[comment pk] componentsSeparatedByString:@"_"][1]]]];
  252. [request setHTTPMethod:@"GET"];
  253. [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
  254. NSString *author = @"[author]";
  255. NSString *body = @"[body]";
  256. if (data != nil && error == nil){
  257. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  258. if ([[jsonData objectForKey:@"data"] count] != 0){
  259. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  260. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"];
  261. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  262. body = @"[pushshift was unable to archive this]";
  263. }
  264. } else {
  265. body = @"[pushshift has not archived this yet]";
  266. }
  267. } else if (error != nil || data == nil){
  268. body = @"[an error occured]";
  269. }
  270. NSMutableAttributedString *bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  271. [comment setAuthor:author];
  272. [comment setBodyText:body];
  273. [comment setBodyRichTextAttributed:bodyMutableAttributedText];
  274. [comment setBodyAttributedText:bodyMutableAttributedText];
  275. [[self commentActionSheetDelegate] performSelectorOnMainThread:@selector(updateComments) withObject:nil waitUntilDone:NO];
  276. [request release];
  277. [queue release];
  278. [bodyMutableAttributedText release];
  279. }];
  280. }
  281. }
  282. %end
  283. %hook PostActionSheetViewController
  284. -(void) setItems:(id) arg1{
  285. Post *post = [self post];
  286. if ([post isSelfPost]){
  287. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  288. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  289. CGFloat scale = origImage.size.width / existingImageSize.width;
  290. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  291. id undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self post]];
  292. arg1 = [arg1 arrayByAddingObject:undeleteItem];
  293. [undeleteItem release];
  294. }
  295. %orig;
  296. }
  297. -(void) handleDidSelectActionSheetItem:(id) arg1{
  298. %orig;
  299. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  300. [self dismissViewControllerAnimated:YES completion:nil];
  301. Post *post = [self post];
  302. if ([post isSelfPost]){
  303. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  304. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  305. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/submission/?ids=%@&fields=author,selftext",[[post pk] componentsSeparatedByString:@"_"][1]]]];
  306. [request setHTTPMethod:@"GET"];
  307. [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
  308. NSString *author = @"[author]";
  309. NSString *body = @"[body]";
  310. if (data != nil && error == nil){
  311. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  312. if ([[jsonData objectForKey:@"data"] count] != 0){
  313. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  314. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"selftext"];
  315. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  316. body = @"[pushshift was unable to archive this]";
  317. }
  318. } else {
  319. body = @"[pushshift has not archived this yet]";
  320. }
  321. } else if (error != nil || data == nil){
  322. body = @"[an error occured]";
  323. }
  324. NSMutableAttributedString *bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  325. [post setSelfText:body];
  326. [post setAuthor:author];
  327. [post setSelfPostRichTextAttributed:bodyMutableAttributedText];
  328. [post setPreviewFeedPostTextString:bodyMutableAttributedText];
  329. [[self postActionSheetDelegate] performSelectorOnMainThread:@selector(updatePostText) withObject:nil waitUntilDone:NO];
  330. [request release];
  331. [queue release];
  332. [bodyMutableAttributedText release];
  333. }];
  334. }
  335. }
  336. }
  337. %end
  338. %end
  339. %group Reddit_v3
  340. %hook CommentView
  341. %new
  342. -(void) buttonAction {
  343. id commentsViewController = [self delegate];
  344. id comment = [self comment];
  345. NSError* error;
  346. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  347. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body",[comment pkWithoutPrefix]]]];
  348. [request setHTTPMethod:@"GET"];
  349. NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
  350. NSString *author = @"[author]";
  351. NSString *body = @"[body]";
  352. if (data != nil && error == nil){
  353. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  354. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  355. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"];
  356. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  357. body = @"[comment was unable to be archived]";
  358. }
  359. } else if (error != nil || data == nil){
  360. body = @"[an error occured]";
  361. }
  362. [comment setValue:author forKey:@"author"];
  363. [comment setValue:[%c(MarkDownParser) attributedStringFromMarkdownString: body] forKey:@"bodyAttributedText"];
  364. [comment setValue:body forKey:@"bodyText"];
  365. [commentsViewController reloadCommentsWithNewCommentsHighlight:NO autoScroll:NO animated:NO];
  366. }
  367. -(id) initWithFrame:(id)arg1{
  368. id orig = %orig;
  369. id commandView = [self commandView];
  370. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  371. [undeleteButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
  372. UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  373. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  374. [commandView setUndeleteButton:undeleteButton];
  375. [commandView addSubview:undeleteButton];
  376. return orig;
  377. }
  378. %end
  379. %hook CommentCommandView
  380. %property (assign, nonatomic) id undeleteButton;
  381. -(void) layoutSubviews{
  382. %orig;
  383. UIButton *button = [self undeleteButton];
  384. button.frame = CGRectMake([[self overflowButton ] frame].origin.x - 32, 0, 32, 32);
  385. }
  386. %end
  387. %end
  388. %ctor{
  389. NSString* processName = [[NSProcessInfo processInfo] processName];
  390. NSArray* appVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] componentsSeparatedByString:@"."];
  391. if ([processName isEqualToString:@"Reddit"]){
  392. if ([appVersion[0] isEqualToString:@"4"]){
  393. if ([appVersion[1] integerValue] <= 32){
  394. %init(Reddit_v4_ios10);
  395. } else{
  396. %init(Reddit_v4_current);
  397. }
  398. } else if ([appVersion[0] isEqualToString:@"3"]) {
  399. %init(Reddit_v3);
  400. }
  401. }
  402. }