因为我们公司APP有国外的用户,所以我们APP播放器的字幕需要我们苦逼的程序员实现多语言字幕,客户可以随时切换,看需求完全合理,
问题:给已有的播放器添加字幕,支持多语言,客户随时可以切换
解决:
注:关于UI搭建相关的操作我这里就不多讲解,只说VTT解析的部分,
第一步:发送请求给服务器获取vtt文件地址
文件地址(大部分都是vtt结尾)第二步:使用该地址去读取文件
NSString *text = [NSString stringWithContentsOfURL:[NSURL URLWithString:url] encoding:NSUTF8StringEncoding error:nil];
注:如果使用该方法读取文件获取的text=null的话,是后端提供的文件格式有误,让后端修改,如果后端不懂怎么改格式的话那就跟我一样下一步操作,vtt格式本质上就是txt文本,
第三步:mac上用终端创建txt文本(如正常读取文件,请略过这一步)
注:用终端创建的txt文件,本地先测试一下,正常发给后端按照这个格式上传(后端其实就是修改后缀直接上传就行)
( 1 )打开终端,cd 到想要创建 txt 文本文件的目录(如桌面)
cd /Users/userName/Desktop
( 2 )使用 vi 创建 txt 文本文件
sudo vi fileName.txt
( 3 )保存退出
:wq
第四步:获得数据解析
vtt文本格式( 1 )首先去掉前面和后面多余的字符串留下如下的格式数组
编号
时间
内容
空格
NSString *text = [NSString stringWithContentsOfURL:[NSURL URLWithString:url] encoding:NSUTF8StringEncoding error:nil];
if ([text containsString:@"WEBVTT"]) {
text = [text stringByReplacingOccurrencesOfString:@"WEBVTT" withString:@""];
}
NSMutableArray *textMutiArr = [NSMutableArray arrayWithArray:[text componentsSeparatedByString:@"\r\n"]];
if (textMutiArr.count >= 2 && [textMutiArr[0] isEqualToString:@""] && [textMutiArr[0] isEqualToString:textMutiArr[1]]) {
[textMutiArr removeObjectsInRange:NSMakeRange(0, 2)];
}
if (textMutiArr.count>=1 && [textMutiArr.lastObject isEqualToString:@""] && [textMutiArr.lastObject isEqualToString:textMutiArr[textMutiArr.count-2]]) {
[textMutiArr removeLastObject];
}
( 2 )获取字幕数组之后开始解析
NSMutableArray *textMutiArr = [self mutableArrayWithURL:url];//获取正常格式数组
NSMutableArray *data = [NSMutableArray array];
NSInteger number = textMutiArr.count;
SHCourseDetailSubtitlesModel *model;
for (NSInteger i = 0; i < number; i++) {
if ((i%4) == 0) {
model = [[SHCourseDetailSubtitlesModel alloc] init];
[data addObject:model];
model.index = textMutiArr[i];
}else if ((i%4) == 1){
NSString *time = textMutiArr[i];
NSArray *timeArr = [time componentsSeparatedByString:@"-->"];
model.starTime = [self timeIntervalWithString:timeArr[0]];
model.endTime = [self timeIntervalWithString:timeArr[1]];
}else if ((i%4) == 2){
model.content = textMutiArr[i];
}else{
model = nil;
}
}
self.subtitlesView.dataSource = data;//赋值
注:因为分割数组里面每四组数据是一套模型,所以数据模型放在for循环外,第一次进来分配空间加入数组,然后四个值都赋值之后置空销毁重新分配空间加入数组,如果小伙伴们不理解的话可以在评论区留言给我
( 3 )附上时间解析方法,比较简单,不想自己写代码的小伙伴可以直接复制
- (CGFloat)timeIntervalWithString:(NSString *)string
{
NSArray *timeArr = [string componentsSeparatedByString:@":"];
CGFloat hours = [timeArr[0] floatValue]*60.0*60.0;
CGFloat minute = [timeArr[1] floatValue]*60.0;
CGFloat seconds = [timeArr[2] floatValue];
return hours+minute+seconds;
}
第五步:设置定时器更新数据就可以了
( 1 )设置定时器(为了保证字幕显示精度,设置了300毫秒)
self.timer = [NSTimer timerWithTimeInterval:0.3 target:self selector:@selector(refreshSubtitles) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
注:设置定时器一定要记得退出页面操作时销毁定时器,销毁方法千万不要写在dealloc方法里面,因为当前页面有定时器的话dealloc方法不会调用,
[self.timer invalidate];
self.timer = nil;
( 2 )定时器回调更新数据(这里使用谓词查询)
- (void)refreshSubtitles//定时器回调
{
CMTime time = self.myPlayer.currentTime;//获取当前时间
CGFloat curentTime = CMTimeGetSeconds(time);//转成秒
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"starTime<=%f AND endTime>=%f",curentTime,curentTime]];
NSArray *arr = [self.subtitlesView.dataSource filteredArrayUsingPredicate:predicate];
if (arr.count>0) {//如当前时间段有字幕就显示
SHCourseDetailSubtitlesModel *mode = arr[0];//获取的字幕是否是当前显示的字幕,如是就返回无操作
if (self.subtitlesView.selectIndex == mode.index.integerValue-1) return;
self.subtitlesView.selectIndex = mode.index.integerValue-1;
}else{//反之就隐藏字幕视图
self.subtitlesView.hidden = YES;
}
}
代码里面都做了注释,如果不懂或者有误的可以留言给我,我们一起讨论,用for循环查询方法小伙伴们肯定都会,我就不在这里写给大家啦!
网友评论