| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- //
- // WBFeedHelper.m
- // YYKitExample
- //
- // Created by ibireme on 15/9/5.
- // Copyright (c) 2015 ibireme. All rights reserved.
- //
- #import "WBStatusHelper.h"
- @implementation WBStatusHelper
- + (NSBundle *)bundle {
- static NSBundle *bundle;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- NSString *path = [[NSBundle mainBundle] pathForResource:@"ResourceWeibo" ofType:@"bundle"];
- bundle = [NSBundle bundleWithPath:path];
- });
- return bundle;
- }
- + (NSBundle *)emoticonBundle {
- static NSBundle *bundle;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"EmoticonWeibo" ofType:@"bundle"];
- bundle = [NSBundle bundleWithPath:bundlePath];
- });
- return bundle;
- }
- + (YYMemoryCache *)imageCache {
- static YYMemoryCache *cache;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- cache = [YYMemoryCache new];
- cache.shouldRemoveAllObjectsOnMemoryWarning = NO;
- cache.shouldRemoveAllObjectsWhenEnteringBackground = NO;
- cache.name = @"WeiboImageCache";
- });
- return cache;
- }
- + (UIImage *)imageNamed:(NSString *)name {
- if (!name) return nil;
- UIImage *image = [[self imageCache] objectForKey:name];
- if (image) return image;
- NSString *ext = name.pathExtension;
- if (ext.length == 0) ext = @"png";
- NSString *path = [[self bundle] pathForScaledResource:name ofType:ext];
- if (!path) return nil;
- image = [UIImage imageWithContentsOfFile:path];
- image = [image imageByDecoded];
- if (!image) return nil;
- [[self imageCache] setObject:image forKey:name];
- return image;
- }
- + (UIImage *)imageWithPath:(NSString *)path {
- if (!path) return nil;
- UIImage *image = [[self imageCache] objectForKey:path];
- if (image) return image;
- if (path.pathScale == 1) {
- // 查找 @2x @3x 的图片
- NSArray *scales = [NSBundle preferredScales];
- for (NSNumber *scale in scales) {
- image = [UIImage imageWithContentsOfFile:[path stringByAppendingPathScale:scale.floatValue]];
- if (image) break;
- }
- } else {
- image = [UIImage imageWithContentsOfFile:path];
- }
- if (image) {
- image = [image imageByDecoded];
- [[self imageCache] setObject:image forKey:path];
- }
- return image;
- }
- + (YYWebImageManager *)avatarImageManager {
- static YYWebImageManager *manager;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- NSString *path = [[UIApplication sharedApplication].cachesPath stringByAppendingPathComponent:@"weibo.avatar"];
- YYImageCache *cache = [[YYImageCache alloc] initWithPath:path];
- manager = [[YYWebImageManager alloc] initWithCache:cache queue:[YYWebImageManager sharedManager].queue];
- manager.sharedTransformBlock = ^(UIImage *image, NSURL *url) {
- if (!image) return image;
- return [image imageByRoundCornerRadius:100]; // a large value
- };
- });
- return manager;
- }
- + (NSString *)stringWithTimelineDate:(NSDate *)date {
- if (!date) return @"";
-
- static NSDateFormatter *formatterYesterday;
- static NSDateFormatter *formatterSameYear;
- static NSDateFormatter *formatterFullDate;
-
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- formatterYesterday = [[NSDateFormatter alloc] init];
- [formatterYesterday setDateFormat:@"昨天 HH:mm"];
- [formatterYesterday setLocale:[NSLocale currentLocale]];
-
- formatterSameYear = [[NSDateFormatter alloc] init];
- [formatterSameYear setDateFormat:@"M-d"];
- [formatterSameYear setLocale:[NSLocale currentLocale]];
-
- formatterFullDate = [[NSDateFormatter alloc] init];
- [formatterFullDate setDateFormat:@"yy-M-dd"];
- [formatterFullDate setLocale:[NSLocale currentLocale]];
- });
-
- NSDate *now = [NSDate new];
- NSTimeInterval delta = now.timeIntervalSince1970 - date.timeIntervalSince1970;
- if (delta < -60 * 10) { // 本地时间有问题
- return [formatterFullDate stringFromDate:date];
- } else if (delta < 60 * 10) { // 10分钟内
- return @"刚刚";
- } else if (delta < 60 * 60) { // 1小时内
- return [NSString stringWithFormat:@"%d分钟前", (int)(delta / 60.0)];
- } else if (date.isToday) {
- return [NSString stringWithFormat:@"%d小时前", (int)(delta / 60.0 / 60.0)];
- } else if (date.isYesterday) {
- return [formatterYesterday stringFromDate:date];
- } else if (date.year == now.year) {
- return [formatterSameYear stringFromDate:date];
- } else {
- return [formatterFullDate stringFromDate:date];
- }
- }
- + (NSURL *)defaultURLForImageURL:(id)imageURL {
- /*
- 微博 API 提供的图片 URL 有时并不能直接用,需要做一些字符串替换:
- http://u1.sinaimg.cn/upload/2014/11/04/common_icon_membership_level6.png //input
- http://u1.sinaimg.cn/upload/2014/11/04/common_icon_membership_level6_default.png //output
-
- http://img.t.sinajs.cn/t6/skin/public/feed_cover/star_003_y.png?version=2015080302 //input
- http://img.t.sinajs.cn/t6/skin/public/feed_cover/star_003_os7.png?version=2015080302 //output
- */
-
- if (!imageURL) return nil;
- NSString *link = nil;
- if ([imageURL isKindOfClass:[NSURL class]]) {
- link = ((NSURL *)imageURL).absoluteString;
- } else if ([imageURL isKindOfClass:[NSString class]]) {
- link = imageURL;
- }
- if (link.length == 0) return nil;
-
- if ([link hasSuffix:@".png"]) {
- // add "_default"
- if (![link hasSuffix:@"_default.png"]) {
- NSString *sub = [link substringToIndex:link.length - 4];
- link = [sub stringByAppendingFormat:@"_default.png"];
- }
- } else {
- // replace "_y.png" with "_os7.png"
- NSRange range = [link rangeOfString:@"_y.png?version"];
- if (range.location != NSNotFound) {
- NSMutableString *mutable = link.mutableCopy;
- [mutable replaceCharactersInRange:NSMakeRange(range.location + 1, 1) withString:@"os7"];
- link = mutable;
- }
- }
-
- return [NSURL URLWithString:link];
- }
- + (NSString *)shortedNumberDesc:(NSUInteger)number {
- // should be localized
- if (number <= 9999) return [NSString stringWithFormat:@"%d", (int)number];
- if (number <= 9999999) return [NSString stringWithFormat:@"%d万", (int)(number / 10000)];
- return [NSString stringWithFormat:@"%d千万", (int)(number / 10000000)];
- }
- + (NSRegularExpression *)regexAt {
- static NSRegularExpression *regex;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- // 微博的 At 只允许 英文数字下划线连字符,和 unicode 4E00~9FA5 范围内的中文字符,这里保持和微博一致。。
- // 目前中文字符范围比这个大
- regex = [NSRegularExpression regularExpressionWithPattern:@"@[-_a-zA-Z0-9\u4E00-\u9FA5]+" options:kNilOptions error:NULL];
- });
- return regex;
- }
- + (NSRegularExpression *)regexTopic {
- static NSRegularExpression *regex;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- regex = [NSRegularExpression regularExpressionWithPattern:@"#[^@#]+?#" options:kNilOptions error:NULL];
- });
- return regex;
- }
- + (NSRegularExpression *)regexEmoticon {
- static NSRegularExpression *regex;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- regex = [NSRegularExpression regularExpressionWithPattern:@"\\[[^ \\[\\]]+?\\]" options:kNilOptions error:NULL];
- });
- return regex;
- }
- + (NSDictionary *)emoticonDic {
- static NSMutableDictionary *dic;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- NSString *emoticonBundlePath = [[NSBundle mainBundle] pathForResource:@"EmoticonWeibo" ofType:@"bundle"];
- dic = [self _emoticonDicFromPath:emoticonBundlePath];
- });
- return dic;
- }
- + (NSMutableDictionary *)_emoticonDicFromPath:(NSString *)path {
- NSMutableDictionary *dic = [NSMutableDictionary new];
- WBEmoticonGroup *group = nil;
- NSString *jsonPath = [path stringByAppendingPathComponent:@"info.json"];
- NSData *json = [NSData dataWithContentsOfFile:jsonPath];
- if (json.length) {
- group = [WBEmoticonGroup modelWithJSON:json];
- }
- if (!group) {
- NSString *plistPath = [path stringByAppendingPathComponent:@"info.plist"];
- NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistPath];
- if (plist.count) {
- group = [WBEmoticonGroup modelWithJSON:plist];
- }
- }
- for (WBEmoticon *emoticon in group.emoticons) {
- if (emoticon.png.length == 0) continue;
- NSString *pngPath = [path stringByAppendingPathComponent:emoticon.png];
- if (emoticon.chs) dic[emoticon.chs] = pngPath;
- if (emoticon.cht) dic[emoticon.cht] = pngPath;
- }
-
- NSArray *folders = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
- for (NSString *folder in folders) {
- if (folder.length == 0) continue;
- NSDictionary *subDic = [self _emoticonDicFromPath:[path stringByAppendingPathComponent:folder]];
- if (subDic) {
- [dic addEntriesFromDictionary:subDic];
- }
- }
- return dic;
- }
- + (NSArray<WBEmoticonGroup *> *)emoticonGroups {
- static NSMutableArray *groups;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- NSString *emoticonBundlePath = [[NSBundle mainBundle] pathForResource:@"EmoticonWeibo" ofType:@"bundle"];
- NSString *emoticonPlistPath = [emoticonBundlePath stringByAppendingPathComponent:@"emoticons.plist"];
- NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:emoticonPlistPath];
- NSArray *packages = plist[@"packages"];
- groups = (NSMutableArray *)[NSArray modelArrayWithClass:[WBEmoticonGroup class] json:packages];
-
- NSMutableDictionary *groupDic = [NSMutableDictionary new];
- for (int i = 0, max = (int)groups.count; i < max; i++) {
- WBEmoticonGroup *group = groups[i];
- if (group.groupID.length == 0) {
- [groups removeObjectAtIndex:i];
- i--;
- max--;
- continue;
- }
- NSString *path = [emoticonBundlePath stringByAppendingPathComponent:group.groupID];
- NSString *infoPlistPath = [path stringByAppendingPathComponent:@"info.plist"];
- NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
- [group modelSetWithDictionary:info];
- if (group.emoticons.count == 0) {
- i--;
- max--;
- continue;
- }
- groupDic[group.groupID] = group;
- }
-
- NSArray<NSString *> *additionals = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[emoticonBundlePath stringByAppendingPathComponent:@"additional"] error:nil];
- for (NSString *path in additionals) {
- WBEmoticonGroup *group = groupDic[path];
- if (!group) continue;
- NSString *infoJSONPath = [[[emoticonBundlePath stringByAppendingPathComponent:@"additional"] stringByAppendingPathComponent:path] stringByAppendingPathComponent:@"info.json"];
- NSData *infoJSON = [NSData dataWithContentsOfFile:infoJSONPath];
- WBEmoticonGroup *addGroup = [WBEmoticonGroup modelWithJSON:infoJSON];
- if (addGroup.emoticons.count) {
- for (WBEmoticon *emoticon in addGroup.emoticons) {
- emoticon.group = group;
- }
- [((NSMutableArray *)group.emoticons) insertObjects:addGroup.emoticons atIndex:0];
- }
- }
- });
- return groups;
- }
- /*
- weibo.app 里面的正则,有兴趣的可以参考下:
-
- HTTP链接 (例如 http://www.weibo.com ):
- ([hH]ttp[s]{0,1})://[a-zA-Z0-9\.\-]+\.([a-zA-Z]{2,4})(:\d+)?(/[a-zA-Z0-9\-~!@#$%^&*+?:_/=<>.',;]*)?
- ([hH]ttp[s]{0,1})://[a-zA-Z0-9\.\-]+\.([a-zA-Z]{2,4})(:\d+)?(/[a-zA-Z0-9\-~!@#$%^&*+?:_/=<>]*)?
- (?i)https?://[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+([-A-Z0-9a-z_\$\.\+!\*\(\)/,:;@&=\?~#%]*)*
- ^http?://[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+(\/[\w-. \/\?%@&+=\u4e00-\u9fa5]*)?$
-
- 链接 (例如 www.baidu.com/s?wd=test ):
- ^[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+([-A-Z0-9a-z_\$\.\+!\*\(\)/,:;@&=\?~#%]*)*
-
- 邮箱 (例如 sjobs@apple.com ):
- \b([a-zA-Z0-9%_.+\-]{1,32})@([a-zA-Z0-9.\-]+?\.[a-zA-Z]{2,6})\b
- \b([a-zA-Z0-9%_.+\-]+)@([a-zA-Z0-9.\-]+?\.[a-zA-Z]{2,6})\b
- ([a-zA-Z0-9%_.+\-]+)@([a-zA-Z0-9.\-]+?\.[a-zA-Z]{2,6})
-
- 电话号码 (例如 18612345678):
- ^[1-9][0-9]{4,11}$
-
- At (例如 @王思聪 ):
- @([\x{4e00}-\x{9fa5}A-Za-z0-9_\-]+)
-
- 话题 (例如 #奇葩说# ):
- #([^@]+?)#
-
- 表情 (例如 [呵呵] ):
- \[([^ \[]*?)]
-
- 匹配单个字符 (中英文数字下划线连字符)
- [\x{4e00}-\x{9fa5}A-Za-z0-9_\-]
-
- 匹配回复 (例如 回复@王思聪: ):
- \x{56de}\x{590d}@([\x{4e00}-\x{9fa5}A-Za-z0-9_\-]+)(\x{0020}\x{7684}\x{8d5e})?:
-
- */
- @end
|