mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-05 16:58:59 +00:00
213 lines
8.3 KiB
Objective-C
213 lines
8.3 KiB
Objective-C
//
|
|
// OfflineFetchText.m
|
|
// NewsBlur
|
|
//
|
|
// Created by David Sinclair on 2019-10-25.
|
|
// Copyright © 2019 NewsBlur. All rights reserved.
|
|
//
|
|
|
|
#import "OfflineFetchText.h"
|
|
#import "FMDatabase.h"
|
|
#import "FMDatabaseAdditions.h"
|
|
#import "Utilities.h"
|
|
#import "NSObject+SBJSON.h"
|
|
#import "NewsBlur-Swift.h"
|
|
|
|
@implementation OfflineFetchText
|
|
|
|
- (void)main {
|
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
self.appDelegate = [NewsBlurAppDelegate sharedAppDelegate];
|
|
});
|
|
|
|
while (YES) {
|
|
BOOL fetched = [self fetchText];
|
|
if (!fetched) break;
|
|
}
|
|
}
|
|
|
|
- (BOOL)fetchText {
|
|
if (self.isCancelled) {
|
|
NSLog(@"Text cancelled.");
|
|
return NO;
|
|
}
|
|
|
|
NSLog(@"Fetching text...");
|
|
NSArray *pendingTextDictionaries = [self uncachedTextDictionaries];
|
|
|
|
if (![[[NSUserDefaults standardUserDefaults]
|
|
objectForKey:@"offline_text_download"] boolValue] ||
|
|
![[[NSUserDefaults standardUserDefaults]
|
|
objectForKey:@"offline_allowed"] boolValue] ||
|
|
[pendingTextDictionaries count] == 0) {
|
|
NSLog(@"Finished caching text. %ld total", (long)self.appDelegate.totalUncachedTextCount);
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"offline_image_download"]) {
|
|
[self.appDelegate.feedsViewController showCachingNotifier:@"Images" progress:0 hoursBack:1];
|
|
[self.appDelegate startOfflineFetchImages];
|
|
} else {
|
|
[self.appDelegate.feedsViewController showDoneNotifier];
|
|
[self.appDelegate.feedsViewController hideNotifier];
|
|
[self.appDelegate finishBackground];
|
|
}
|
|
});
|
|
return NO;
|
|
}
|
|
|
|
if (![self.appDelegate isReachableForOffline]) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[self.appDelegate.feedsViewController showDoneNotifier];
|
|
[self.appDelegate.feedsViewController hideNotifier];
|
|
});
|
|
return NO;
|
|
}
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@/rss_feeds/original_text", self.appDelegate.url];
|
|
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
|
|
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
|
|
|
|
dispatch_group_t group = dispatch_group_create();
|
|
|
|
for (NSDictionary *pendingTextDictionary in pendingTextDictionaries) {
|
|
id storyHash = pendingTextDictionary[@"story_hash"];
|
|
id feedId = pendingTextDictionary[@"story_feed_id"];
|
|
NSInteger storyTimestamp = [pendingTextDictionary[@"story_timestamp"] integerValue];
|
|
|
|
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
|
[params setObject:storyHash forKey:@"story_id"];
|
|
[params setObject:feedId forKey:@"feed_id"];
|
|
|
|
dispatch_group_enter(group);
|
|
// NSLog(@" ---> Fetching offline text: %@", urlString);
|
|
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
|
// NSLog(@" ---> Fetched %@: %@", storyHash, urlString);
|
|
NSString *text = [responseObject objectForKey:@"original_text"];
|
|
|
|
if ([text isKindOfClass:[NSString class]]) {
|
|
[self storeText:text forStoryHash:storyHash storyTimestamp:storyTimestamp];
|
|
} else {
|
|
[self storeFailedTextForStoryHash:storyHash];
|
|
}
|
|
dispatch_group_leave(group);
|
|
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
|
// NSLog(@" ---> Failed to fetch text %@: %@", storyHash, urlString);
|
|
[self storeFailedTextForStoryHash:storyHash];
|
|
dispatch_group_leave(group);
|
|
}];
|
|
}
|
|
|
|
// dispatch_sync(dispatch_get_main_queue(), ^{
|
|
// [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
|
|
// });
|
|
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
|
NSLog(@"Queue finished: %ld total (%ld remaining)", (long)self.appDelegate.totalUncachedTextCount, (long)self.appDelegate.remainingUncachedTextCount);
|
|
|
|
[self updateProgress];
|
|
|
|
// dispatch_async(dispatch_get_main_queue(), ^{
|
|
// [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
|
|
// });
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (NSArray *)uncachedTextDictionaries {
|
|
NSMutableArray *pendingTextDictionaries = [NSMutableArray array];
|
|
|
|
[self.appDelegate.database inDatabase:^(FMDatabase *db) {
|
|
NSString *commonQuery = @"FROM cached_text c "
|
|
"INNER JOIN unread_hashes u ON (c.story_hash = u.story_hash) "
|
|
"WHERE c.text_json is null ";
|
|
int count = [db intForQuery:[NSString stringWithFormat:@"SELECT COUNT(1) %@", commonQuery]];
|
|
if (self.appDelegate.totalUncachedTextCount == 0) {
|
|
self.appDelegate.totalUncachedTextCount = count;
|
|
self.appDelegate.remainingUncachedTextCount = self.appDelegate.totalUncachedTextCount;
|
|
} else {
|
|
self.appDelegate.remainingUncachedTextCount = count;
|
|
}
|
|
|
|
int limit = 120;
|
|
NSString *order;
|
|
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"default_order"] isEqualToString:@"oldest"]) {
|
|
order = @"ASC";
|
|
} else {
|
|
order = @"DESC";
|
|
}
|
|
NSString *sql = [NSString stringWithFormat:@"SELECT * %@ ORDER BY u.story_timestamp %@ LIMIT %d", commonQuery, order, limit];
|
|
FMResultSet *cursor = [db executeQuery:sql];
|
|
|
|
while ([cursor next]) {
|
|
[pendingTextDictionaries addObject:[cursor resultDictionary]];
|
|
}
|
|
|
|
[cursor close];
|
|
}];
|
|
|
|
return pendingTextDictionaries;
|
|
}
|
|
|
|
- (void)updateProgress {
|
|
if (self.isCancelled) return;
|
|
|
|
NSInteger start = (NSInteger)[[NSDate date] timeIntervalSince1970];
|
|
NSInteger end = self.appDelegate.latestCachedTextDate;
|
|
NSInteger seconds = start - (end ? end : start);
|
|
__block int hours = (int)round(seconds / 60.f / 60.f);
|
|
|
|
__block float progress = 0.f;
|
|
if (self.appDelegate.totalUncachedTextCount) {
|
|
progress = 1.f - ((float)self.appDelegate.remainingUncachedTextCount /
|
|
(float)self.appDelegate.totalUncachedTextCount);
|
|
}
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[self.appDelegate.feedsViewController showCachingNotifier:@"Text" progress:progress hoursBack:hours];
|
|
});
|
|
}
|
|
|
|
- (void)storeText:(NSString *)text forStoryHash:(NSString *)storyHash storyTimestamp:(NSInteger)storyTimestamp {
|
|
if (self.isCancelled) {
|
|
NSLog(@"Text cancelled.");
|
|
return;
|
|
}
|
|
|
|
NSDictionary *textDictionary = @{@"text" : text};
|
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,
|
|
(unsigned long)NULL), ^{
|
|
[self storeTextDictionary:textDictionary forStoryHash:storyHash];
|
|
|
|
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"default_order"] isEqualToString:@"oldest"]) {
|
|
if (storyTimestamp > self.appDelegate.latestCachedTextDate) {
|
|
self.appDelegate.latestCachedTextDate = storyTimestamp;
|
|
}
|
|
} else {
|
|
if (!self.appDelegate.latestCachedTextDate || storyTimestamp < self.appDelegate.latestCachedTextDate) {
|
|
self.appDelegate.latestCachedTextDate = storyTimestamp;
|
|
}
|
|
}
|
|
|
|
@synchronized (self) {
|
|
self.appDelegate.remainingUncachedTextCount--;
|
|
if (self.appDelegate.remainingUncachedTextCount % 10 == 0) {
|
|
[self updateProgress];
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)storeFailedTextForStoryHash:(NSString *)storyHash {
|
|
NSDictionary *textDictionary = @{@"failed" : @YES};
|
|
|
|
[self storeTextDictionary:textDictionary forStoryHash:storyHash];
|
|
}
|
|
|
|
- (void)storeTextDictionary:(NSDictionary *)textDictionary forStoryHash:(NSString *)storyHash {
|
|
[self.appDelegate.database inDatabase:^(FMDatabase *db) {
|
|
[db executeUpdate:@"UPDATE cached_text SET text_json = ? WHERE story_hash = ?",
|
|
[textDictionary JSONRepresentation],
|
|
storyHash];
|
|
}];
|
|
}
|
|
|
|
@end
|