mirror of
https://github.com/viq/NewsBlur.git
synced 2025-11-11 00:41:01 +00:00
Fixed offline images not appearing
- Adjusted the timeout and caching of images. - Cleans up cached image URLs if needed. - When offline, now replaces an uncached image with a blank image, to avoid the broken image. - When online, now loads the remote image if no cached image. - Experimented with using cleaner cache filenames, but that wasn’t needed (it initially looked like the MD5 was changing between invocations). - Now uses “jpeg” for the cache extension, since the image URL can have parameter junk that messes with caching.
This commit is contained in:
parent
cdaec2487f
commit
a4f827d7f0
8 changed files with 68 additions and 12 deletions
|
|
@ -4738,7 +4738,7 @@
|
|||
feedIds = @[[storiesCollection.activeFeed objectForKey:@"id"]];
|
||||
}
|
||||
NSString *sql = [NSString stringWithFormat:@"SELECT c.image_url, c.story_hash FROM cached_images c "
|
||||
"WHERE c.image_cached = 1 AND c.failed is null AND c.story_feed_id in (\"%@\")",
|
||||
"WHERE c.image_cached = 1 AND c.story_feed_id in (\"%@\")",
|
||||
[feedIds componentsJoinedByString:@"\",\""]];
|
||||
FMResultSet *cursor = [db executeQuery:sql];
|
||||
|
||||
|
|
|
|||
|
|
@ -515,20 +515,38 @@
|
|||
contentWidthClass, (int)floorf(CGRectGetWidth(self.view.frame))];
|
||||
|
||||
// if (appDelegate.feedsViewController.isOffline) {
|
||||
NSFileManager *manager = [NSFileManager defaultManager];
|
||||
NSString *storyHash = [self.activeStory objectForKey:@"story_hash"];
|
||||
NSArray *imageUrls = [appDelegate.activeCachedImages objectForKey:storyHash];
|
||||
// NSLog(@"📚 imageUrls: %@", imageUrls);
|
||||
NSLog(@"📚 %@ %@ imageUrls: %@", activeStory[@"story_title"], storyHash, imageUrls);
|
||||
if (imageUrls) {
|
||||
NSString *storyImagesDirectory = [appDelegate.documentsURL.path
|
||||
stringByAppendingPathComponent:@"story_images"];
|
||||
for (NSString *imageUrl in imageUrls) {
|
||||
NSURL *cachedUrl = [NSURL fileURLWithPath:storyImagesDirectory];
|
||||
// cachedUrl = [cachedUrl URLByAppendingPathComponent:[Utilities md5:imageUrl storyHash:storyHash]];
|
||||
cachedUrl = [cachedUrl URLByAppendingPathComponent:[Utilities md5:imageUrl]];
|
||||
cachedUrl = [cachedUrl URLByAppendingPathExtension:imageUrl.pathExtension];
|
||||
cachedUrl = [cachedUrl URLByAppendingPathExtension:@"jpeg"];
|
||||
|
||||
if (![manager fileExistsAtPath:cachedUrl.path]) {
|
||||
if (appDelegate.feedsViewController.isOffline) {
|
||||
cachedUrl = [[NSBundle mainBundle] URLForResource:@"blank" withExtension:@"png"];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"📚 %@ %@ imageURL: %@ cachedURL: %@", activeStory[@"story_title"], storyHash, imageUrl, cachedUrl);
|
||||
|
||||
storyContent = [storyContent
|
||||
stringByReplacingOccurrencesOfString:imageUrl
|
||||
withString:cachedUrl.absoluteString];
|
||||
|
||||
NSString *escapedURL = [imageUrl stringByEncodingHTMLEntities];
|
||||
|
||||
storyContent = [storyContent
|
||||
stringByReplacingOccurrencesOfString:escapedURL
|
||||
withString:cachedUrl.absoluteString];
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor
|
|||
+ (UIImage *)templateImageNamed:(NSString *)imageName sized:(CGFloat)size;
|
||||
+ (UIImage *)imageNamed:(NSString *)imageName sized:(CGFloat)size;
|
||||
+ (UIImage *)imageWithImage:(UIImage *)image convertToSize:(CGSize)size;
|
||||
//+ (NSString *)md5:(NSString *)string storyHash:(NSString *)storyHash;
|
||||
+ (NSString *)md5:(NSString *)string;
|
||||
+ (NSString *)formatLongDateFromTimestamp:(NSInteger)timestamp;
|
||||
+ (NSString *)formatShortDateFromTimestamp:(NSInteger)timestamp;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,32 @@ void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor
|
|||
return destImage;
|
||||
}
|
||||
|
||||
// These methods were an experiment in replacing the offline image filenames while tracing the images not appearing; an improvement, but skip for now; keep for future consideration.
|
||||
|
||||
//+ (NSString *)removeIllegalCharactersForFilename:(NSString *)filename {
|
||||
// NSCharacterSet *illegalCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@"\\/:"];
|
||||
// NSString *cleanedFilename = [[filename componentsSeparatedByCharactersInSet:illegalCharacterSet] componentsJoinedByString:@"-"];
|
||||
//
|
||||
// return cleanedFilename;
|
||||
//}
|
||||
//
|
||||
//+ (NSUInteger)checksum:(NSString *)string {
|
||||
// NSUInteger base = string.length;
|
||||
// NSUInteger result = base * base;
|
||||
//
|
||||
// for (NSUInteger i = 0; i < string.length; i++) {
|
||||
// result = (result + ([string characterAtIndex:i] * (i + 34)) + (732 * i) + (base * (i + 83))) % 999999999;
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
//}
|
||||
//
|
||||
//+ (NSString *)md5:(NSString *)string storyHash:(NSString *)storyHash {
|
||||
// NSUInteger checksum = [self checksum:string];
|
||||
// NSString *cleanedStoryHash = [self removeIllegalCharactersForFilename:storyHash];
|
||||
// return [NSString stringWithFormat:@"%@-%@-%@", cleanedStoryHash, @(checksum), [self md5:string]];
|
||||
//}
|
||||
|
||||
+ (NSString *)md5:(NSString *)string {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
|
|
|||
|
|
@ -58,34 +58,36 @@
|
|||
});
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
|
||||
[manager.requestSerializer setTimeoutInterval:5];
|
||||
[manager.requestSerializer setTimeoutInterval:10];
|
||||
manager.responseSerializer = [AFImageResponseSerializer serializer];
|
||||
manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
|
||||
for (NSArray *urlArray in urls) {
|
||||
NSString *urlString = [[urlArray objectAtIndex:0] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
||||
NSString *urlString = [urlArray objectAtIndex:0];
|
||||
NSString *storyHash = [urlArray objectAtIndex:1];
|
||||
NSInteger storyTimestamp = [[urlArray objectAtIndex:2] integerValue];
|
||||
dispatch_group_enter(group);
|
||||
// NSLog(@" ---> Fetching offline image: %@", urlString);
|
||||
if (![NSURL URLWithString:urlString]) {
|
||||
urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
|
||||
}
|
||||
NSLog(@"📚 Fetching offline %@ image: %@", storyHash, urlString);
|
||||
[manager GET:urlString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
// NSLog(@" ---> Fetched %@: %@", storyHash, urlString);
|
||||
NSLog(@"📚 Fetched %@: %@", storyHash, urlString);
|
||||
UIImage *image = (UIImage *)responseObject;
|
||||
[self storeCachedImage:urlString withImage:image storyHash:storyHash storyTimestamp:storyTimestamp];
|
||||
dispatch_group_leave(group);
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
// NSLog(@" ---> Failed to fetch image %@: %@", storyHash, urlString);
|
||||
NSLog(@"📚 Failed to fetch image %@: %@ %@", storyHash, urlString, error);
|
||||
[self storeFailedImage:storyHash];
|
||||
dispatch_group_leave(group);
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
// dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
// [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
|
||||
// });
|
||||
|
|
@ -167,16 +169,19 @@
|
|||
(unsigned long)NULL), ^{
|
||||
|
||||
NSData *responseData = UIImageJPEGRepresentation(image, 0.6);
|
||||
// NSString *md5Url = [Utilities md5:imageUrl storyHash:storyHash];
|
||||
NSString *md5Url = [Utilities md5:imageUrl];
|
||||
// NSLog(@"Storing image: %@ (%d bytes - %d in queue)", storyHash, [responseData length], [imageDownloadOperationQueue requestsCount]);
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *cacheDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"story_images"];
|
||||
NSString *fullPath = [cacheDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", md5Url, [imageUrl pathExtension]]];
|
||||
NSString *fullPath = [[cacheDirectory stringByAppendingPathComponent:md5Url] stringByAppendingPathExtension:@"jpeg"];
|
||||
|
||||
[fileManager createFileAtPath:fullPath contents:responseData attributes:nil];
|
||||
|
||||
NSLog(@"📚 stored storyHash: %@ imageURL: %@ cachedURL: %@", storyHash, imageUrl, fullPath);
|
||||
|
||||
[self.appDelegate.database inDatabase:^(FMDatabase *db) {
|
||||
[db executeUpdate:@"UPDATE cached_images SET "
|
||||
"image_cached = 1 WHERE story_hash = ?",
|
||||
|
|
|
|||
|
|
@ -747,6 +747,8 @@
|
|||
177551DF238E228A00E27818 /* Old NewsBlur Latest.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 177551D3238E228A00E27818 /* Old NewsBlur Latest.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
177D017D28B05D9500F2F2DB /* StoryPagesCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 177D017C28B05D9500F2F2DB /* StoryPagesCollectionCell.swift */; };
|
||||
17813FB723AC6E450057FB16 /* WidgetErrorTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17CE3F0523AC529B003152EF /* WidgetErrorTableViewCell.xib */; };
|
||||
1781B97F2C9D332B00C8F344 /* blank.png in Resources */ = {isa = PBXBuildFile; fileRef = 1781B97E2C9D332B00C8F344 /* blank.png */; };
|
||||
1781B9802C9D332B00C8F344 /* blank.png in Resources */ = {isa = PBXBuildFile; fileRef = 1781B97E2C9D332B00C8F344 /* blank.png */; };
|
||||
178552492A1F115800A8CD92 /* FeedDetailTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 178552472A1F115800A8CD92 /* FeedDetailTableCell.m */; };
|
||||
1785524A2A1F115800A8CD92 /* FeedDetailTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 178552472A1F115800A8CD92 /* FeedDetailTableCell.m */; };
|
||||
1785524C2A21693300A8CD92 /* FeedDetailLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1785524B2A21693300A8CD92 /* FeedDetailLoadingView.swift */; };
|
||||
|
|
@ -1547,6 +1549,7 @@
|
|||
177551DC238E228A00E27818 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
177551E3238E26BF00E27818 /* Widget Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Widget Extension.entitlements"; sourceTree = "<group>"; };
|
||||
177D017C28B05D9500F2F2DB /* StoryPagesCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryPagesCollectionCell.swift; sourceTree = "<group>"; };
|
||||
1781B97E2C9D332B00C8F344 /* blank.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = blank.png; sourceTree = "<group>"; };
|
||||
178552472A1F115800A8CD92 /* FeedDetailTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FeedDetailTableCell.m; sourceTree = "<group>"; };
|
||||
178552482A1F115800A8CD92 /* FeedDetailTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeedDetailTableCell.h; sourceTree = "<group>"; };
|
||||
1785524B2A21693300A8CD92 /* FeedDetailLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedDetailLoadingView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -2878,6 +2881,7 @@
|
|||
FFB1F69C1FBD1B2D001DA171 /* white_fade.png */,
|
||||
FF9D59331FBC08DB00823C10 /* Shiloh.jpg */,
|
||||
17E2AEB22863FECF000FAB5B /* Lyric.jpg */,
|
||||
1781B97E2C9D332B00C8F344 /* blank.png */,
|
||||
FF3FA8941BB26B6A001F7C32 /* copy_link@2x.png */,
|
||||
FF83FF121FB54692008DAC0F /* g_icn_buffer.png */,
|
||||
FF83FF0E1FB54691008DAC0F /* g_icn_eating.png */,
|
||||
|
|
@ -4441,6 +4445,7 @@
|
|||
175792042930605500490924 /* theme_color_dark-sel.png in Resources */,
|
||||
175792052930605500490924 /* traverse_background_left@2x.png in Resources */,
|
||||
175792062930605500490924 /* g_icn_offline.png in Resources */,
|
||||
1781B9802C9D332B00C8F344 /* blank.png in Resources */,
|
||||
175792072930605500490924 /* triangle.png in Resources */,
|
||||
175792082930605500490924 /* g_icn_offline@2x.png in Resources */,
|
||||
175792092930605500490924 /* columns_double@2x.png in Resources */,
|
||||
|
|
@ -4867,6 +4872,7 @@
|
|||
FF83FF1A1FB54693008DAC0F /* g_icn_buffer.png in Resources */,
|
||||
17E2AEDD286556CC000FAB5B /* icons8-security-wi-fi-100.png in Resources */,
|
||||
17432C7A1C533DCC003F8FD6 /* FeedChooserViewController.xib in Resources */,
|
||||
1781B97F2C9D332B00C8F344 /* blank.png in Resources */,
|
||||
FFDD847F16E887D3000AA0A2 /* g_icn_folder@2x.png in Resources */,
|
||||
1740C6881C10FD75005EA453 /* theme_color_dark.png in Resources */,
|
||||
FFDD848016E887D3000AA0A2 /* g_icn_hidden.png in Resources */,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
NSString *storyImagesDirectory = [[paths objectAtIndex:0]
|
||||
stringByAppendingPathComponent:@"story_images"];
|
||||
NSString *cachedImage = [[storyImagesDirectory
|
||||
stringByAppendingPathComponent:[Utilities md5:pathString]] stringByAppendingPathExtension:[pathString pathExtension]];
|
||||
stringByAppendingPathComponent:[Utilities md5:pathString]] stringByAppendingPathExtension:@"jpeg"];
|
||||
return cachedImage;
|
||||
}
|
||||
|
||||
|
|
|
|||
BIN
clients/ios/Resources/blank.png
Normal file
BIN
clients/ios/Resources/blank.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 928 B |
Loading…
Add table
Reference in a new issue