M3U8文件的下載總結(jié)

一、簡述

? ? 最近的項(xiàng)目有個m3u8文件的下載需求,m3u8文件和其他文件有個根本的區(qū)別是它只是一個地址的集合文件,我們?nèi)绻枰螺dm3u8文件的話需要將它列表里面所有的文件都一一下載下來,然后還要生成一個播放的排列文件,最后開始播放。

二、難點(diǎn)

1、多文件下載。

2、播放文件的生成。

3、緩存的存取周期管理。

三、相關(guān)代碼詳解

1、為了方便,我們先寫一個下載的管理類 BYM3U3DownLoadManger

//返回下載類對象

+ (AriaM3U8Downloader *)plistGetDownloadWith:(NSString *)name dowloadUrl:(NSString *)url;

//刪除下載,單集

+ (void)plistDeleteDwonloadWith:(NSString *)name type:(NSString *)poType;

//刪除下載,傳入電視劇videoID,刪除該電視劇下所有劇集

+ (void)plistDeleteAllTVDownloadWith:(NSString *)videoId;

//添加視頻下載信息

+ (void)addVideoDownloadDataWith:(NSDictionary *)dict;

+ (NSArray *)getAllVideoDownloadData;

//檢查下本地有無下載信息

+ (BOOL)checkDownloadHaveVideoWith:(NSString *)videoId;

//設(shè)置本地視頻下載狀態(tài)為已下載

+ (void)setDownloadVideoCompleteWith:(NSString *)videoId;

//傳入字典,返回下載類對象

+ (AriaM3U8Downloader *)plistGetDownloadWith:(NSString *)name dowloadUrl:(NSString *)url {

? ? //先判斷臨時緩存里面有沒有

? ? __block AriaM3U8Downloader *cashDownload = [AriaM3U8Downloader new];

? ? __block BOOL isInList = NO;

? ? NSArray *cashDownloadList = [BYDownloadHelper sharedDownloadMark].downAriaM3U8Arr;

? ? [cashDownloadList enumerateObjectsUsingBlock:^(BYCashDownloadModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? NSString *cashName = obj.fileName;

? ? ? ? if ([cashName isEqualToString:name]) {

? ? ? ? ? ? cashDownload = obj.downModel;

? ? ? ? ? ? isInList = YES;

? ? ? ? ? ? *stop = YES;

? ? ? ? }

? ? }];

? ? if (isInList) {

? ? ? ? return cashDownload;

? ? }



? ? //1.創(chuàng)建主文件夾

? ? [self creatDir:DownloadFile];

? ? //創(chuàng)建子文件夾

? ? NSString *file = [DownloadFile stringByAppendingPathComponent:name];

? ? [self creatDir:file];

? ? //2.通過 M3U8 URL 進(jìn)行初始化

? ? AriaM3U8Downloader *downloader = [[AriaM3U8Downloader alloc] initWithURLString:url outputPath:file tag:[name integerValue]];

? ? if (downloader) {

? ? ? ? //添加到臨時緩存里面去

? ? ? ? BYCashDownloadModel *downModel = [BYCashDownloadModel new];

? ? ? ? downModel.fileName = name;

? ? ? ? downModel.downModel = downloader;

? ? ? ? [[BYDownloadHelper sharedDownloadMark] addNewModelWith:downModel];

? ? }


? ? return downloader;

}

//傳入字典,刪除本地下載文件夾

+ (void)plistDeleteDwonloadWith:(NSString *)name type:(NSString *)poType {

? ? //1.創(chuàng)建主文件夾

? ? [self creatDir:DownloadFile];

? ? //創(chuàng)建子文件夾

? ? NSString *file = [DownloadFile stringByAppendingPathComponent:name];

? ? [self creatDir:file];

? ? NSFileManager *fileManager = [NSFileManager defaultManager];

? ? if ([[NSFileManager defaultManager] fileExistsAtPath:file]) {

? ? ? ? [fileManager removeItemAtPath:file error:nil];

? ? ? ? NSLog(@"緩存清理成功");

? ? }


? ? //清除本地存儲的視頻信息

? ? if ([poType isEqualToString:@"1"]) {//電影

? ? ? ? NSArray *videoDownloadList = [kUserDefaults archivedForKey:KVideoDownloadList];

? ? ? ? NSMutableArray *newMuarr = [[NSMutableArray alloc] initWithArray:videoDownloadList];

? ? ? ? [videoDownloadList enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? ? ? if ([[obj objectOrNilForKey:@"videoId"] isEqualToString:name]) {

? ? ? ? ? ? ? ? [newMuarr removeObject:obj];

? ? ? ? ? ? ? ? *stop = YES;

? ? ? ? ? ? }

? ? ? ? }];

? ? ? ? [kUserDefaults setArchived:newMuarr forKey:KVideoDownloadList];

? ? ? ? [kUserDefaults synchronize];

? ? } else {

? ? ? ? NSArray *videoTVDownloadList = [kUserDefaults archivedForKey:KVideoTVDownloadList];

? ? ? ? NSMutableArray *newMuarr = [[NSMutableArray alloc] initWithArray:videoTVDownloadList];

? ? ? ? __block NSString *espVideoId;

? ? ? ? [videoTVDownloadList enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? ? ? espVideoId = [obj objectOrNilForKey:@"videoId"];

? ? ? ? ? ? if ([[obj objectOrNilForKey:@"videoEpisodeId"] isEqualToString:name]) {

? ? ? ? ? ? ? ? [newMuarr removeObject:obj];

? ? ? ? ? ? ? ? *stop = YES;

? ? ? ? ? ? }

? ? ? ? }];

? ? ? ? [kUserDefaults setArchived:newMuarr forKey:KVideoTVDownloadList];

? ? ? ? [kUserDefaults synchronize];



? ? ? ? //判斷下該視頻下還有無劇集在本地,沒有的話直接把劇集頁刪了

? ? ? ? if (![self checkDownloadHaveOtherTVVideoWith:espVideoId]) {

? ? ? ? ? ? NSArray *videoDownloadList = [kUserDefaults archivedForKey:KVideoDownloadList];

? ? ? ? ? ? NSMutableArray *asdMuArr = [[NSMutableArray alloc] initWithArray:videoDownloadList];

? ? ? ? ? ? [videoDownloadList enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? ? ? ? ? if ([[obj objectOrNilForKey:@"videoId"] isEqualToString:espVideoId]) {

? ? ? ? ? ? ? ? ? ? [asdMuArr removeObject:obj];

? ? ? ? ? ? ? ? ? ? *stop = YES;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }];

? ? ? ? ? ? [kUserDefaults setArchived:asdMuArr forKey:KVideoDownloadList];

? ? ? ? ? ? [kUserDefaults synchronize];

? ? ? ? }

? ? }


? ? //清除臨時緩存內(nèi)的播放器

? ? NSArray *cashDownloadList = [BYDownloadHelper sharedDownloadMark].downAriaM3U8Arr;

? ? __block BYCashDownloadModel *deleteModel = [BYCashDownloadModel new];

? ? [cashDownloadList enumerateObjectsUsingBlock:^(BYCashDownloadModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? NSString *cashName = obj.fileName;

? ? ? ? if ([cashName isEqualToString:name]) {

? ? ? ? ? ? deleteModel = obj;

? ? ? ? ? ? [deleteModel.downModel stop];//停止下載

? ? ? ? ? ? *stop = YES;

? ? ? ? }

? ? }];

? ? [[BYDownloadHelper sharedDownloadMark] deleteModelWith:deleteModel];


}

//刪除下載,傳入電視劇videoID,刪除該電視劇下所有劇集

+ (void)plistDeleteAllTVDownloadWith:(NSString *)videoId {

? ? NSArray *videoTVDownloadList = [kUserDefaults archivedForKey:KVideoTVDownloadList];

? ? NSMutableArray *newMuarr = [[NSMutableArray alloc] initWithArray:videoTVDownloadList];

? ? NSMutableArray *deleteLisst = [[NSMutableArray alloc] init];

? ? [videoTVDownloadList enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? if ([[obj objectOrNilForKey:@"videoId"] isEqualToString:videoId]) {

? ? ? ? ? ? [deleteLisst addObject:obj];

? ? ? ? ? ? [newMuarr removeObject:obj];

? ? ? ? ? ? *stop = YES;

? ? ? ? }

? ? }];

? ? [kUserDefaults setArchived:newMuarr forKey:KVideoTVDownloadList];

? ? [kUserDefaults synchronize];


? ? //循環(huán)刪除本地下載文件

? ? [deleteLisst enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? NSString *fileName = [obj objectOrNilForKey:@"videoEpisodeId"];

? ? ? ? [self creatDir:DownloadFile];

? ? ? ? //創(chuàng)建子文件夾

? ? ? ? NSString *file = [DownloadFile stringByAppendingPathComponent:fileName];

? ? ? ? [self creatDir:file];

? ? ? ? NSFileManager *fileManager = [NSFileManager defaultManager];

? ? ? ? if ([[NSFileManager defaultManager] fileExistsAtPath:file]) {

? ? ? ? ? ? [fileManager removeItemAtPath:file error:nil];

? ? ? ? ? ? NSLog(@"緩存清理成功");

? ? ? ? }


? ? ? ? //刪除臨時緩存的播放器

? ? ? ? NSArray *cashDownloadList = [BYDownloadHelper sharedDownloadMark].downAriaM3U8Arr;

? ? ? ? __block BYCashDownloadModel *deleteModel = [BYCashDownloadModel new];

? ? ? ? [cashDownloadList enumerateObjectsUsingBlock:^(BYCashDownloadModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? ? ? NSString *cashName = obj.fileName;

? ? ? ? ? ? if ([cashName isEqualToString:fileName]) {

? ? ? ? ? ? ? ? deleteModel = obj;

? ? ? ? ? ? ? ? [deleteModel.downModel stop];//停止下載

? ? ? ? ? ? ? ? *stop = YES;

? ? ? ? ? ? }

? ? ? ? }];

? ? ? ? [[BYDownloadHelper sharedDownloadMark] deleteModelWith:deleteModel];

? ? }];


? ? //最后刪除視頻數(shù)組里面的數(shù)據(jù)

? ? NSArray *videoDownloadList = [kUserDefaults archivedForKey:KVideoDownloadList];

? ? NSMutableArray *newMuarrList = [[NSMutableArray alloc] initWithArray:videoDownloadList];

? ? [videoDownloadList enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? if ([[obj objectOrNilForKey:@"videoId"] isEqualToString:videoId]) {

? ? ? ? ? ? [newMuarrList removeObject:obj];

? ? ? ? ? ? *stop = YES;

? ? ? ? }

? ? }];

? ? [kUserDefaults setArchived:newMuarrList forKey:KVideoDownloadList];

? ? [kUserDefaults synchronize];

}

/**

創(chuàng)建文件夾

@param dirPath 文件夾名稱

@return 創(chuàng)建成功或失敗

*/

+ (BOOL)creatDir:(NSString *)dirPath {

? ? if ([[NSFileManager defaultManager] fileExistsAtPath:dirPath]) {//判斷dirPath路徑文件夾是否已存在,此處dirPath為需要新建的文件夾的絕對路徑

? ? ? ? NSLog(@"沙盒目錄已經(jīng)存在%@",dirPath);

? ? ? ? return NO;

? ? }else {

? ? ? ? [[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];//創(chuàng)建文件夾

? ? ? ? NSLog(@"創(chuàng)建成功%@",dirPath);

? ? ? ? return YES;

? ? }

}

//視頻下載信息

+ (void)addVideoDownloadDataWith:(NSDictionary *)dict {

? ? NSArray *videoDownloadList = [kUserDefaults archivedForKey:KVideoDownloadList];

? ? NSMutableArray *newMuarr = [[NSMutableArray alloc] initWithArray:videoDownloadList];

? ? [newMuarr addObject:dict];

? ? [kUserDefaults setArchived:newMuarr forKey:KVideoDownloadList];

? ? [kUserDefaults synchronize];

}

+ (NSArray *)getAllVideoDownloadData {

? ? return [kUserDefaults archivedForKey:KVideoDownloadList];

}

+ (BOOL)checkDownloadHaveVideoWith:(NSString *)videoId {

? ? __block BOOL isHave = NO;

? ? NSArray *allDataArr = [kUserDefaults archivedForKey:KVideoDownloadList];

? ? [allDataArr enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? if ([[obj objectOrNilForKey:@"videoId"] isEqualToString:videoId]) {

? ? ? ? ? ? isHave = YES;

? ? ? ? ? ? *stop = YES;

? ? ? ? }

? ? }];

? ? return isHave;

}

//設(shè)置本地視頻下載狀態(tài)為已下載

+ (void)setDownloadVideoCompleteWith:(NSString *)videoId {

? ? NSArray *allDataArr = [kUserDefaults archivedForKey:KVideoDownloadList];

? ? NSMutableArray *allDataMuArr = [[NSMutableArray alloc] initWithArray:allDataArr];

? ? [allDataArr enumerateObjectsUsingBlock:^(NSDictionary *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? if ([[obj objectOrNilForKey:@"videoId"] isEqualToString:videoId]) {

? ? ? ? ? ? NSMutableDictionary *muDict = [[NSMutableDictionary alloc] initWithDictionary:obj];

? ? ? ? ? ? [muDict setObject:@(1) forKey:@"videoComplete"];

? ? ? ? ? ? [allDataMuArr replaceObjectAtIndex:idx withObject:muDict];

? ? ? ? ? ? *stop = YES;

? ? ? ? }

? ? }];

? ? [kUserDefaults setArchived:allDataMuArr forKey:KVideoDownloadList];

? ? [kUserDefaults synchronize];

}

2、模型

@interface BYCashDownloadModel : NSObject

@property (nonatomic, copy) NSString *fileName;? ? ? ? ? ? ? ? ? ? //文件名

@property (nonatomic, strong) AriaM3U8Downloader *downModel;? ? ? ? //下載器對象

@end

//下載單例

@interface BYDownloadHelper : NSObject

+ (instancetype)sharedDownloadMark;

@property (nonatomic, strong) NSArray<BYCashDownloadModel *> *downAriaM3U8Arr;? ? ? ? //下載器

- (void)addNewModelWith:(BYCashDownloadModel *)model;

- (void)deleteModelWith:(BYCashDownloadModel *)model;

- (NSString *)nameWithModel:(AriaM3U8Downloader *)download;

@end

+ (instancetype)sharedDownloadMark{

? ? static dispatch_once_t onceToken;

? ? dispatch_once(&onceToken, ^{

? ? ? ? _showWaterMark = [[super allocWithZone:NULL] init];

? ? });


? ? return _showWaterMark;

}

+ (id)allocWithZone:(struct _NSZone *)zone {

? ? return [BYDownloadHelper sharedDownloadMark];

}


- (id)copyWithZone:(struct _NSZone *)zone {

? ? return [BYDownloadHelper sharedDownloadMark];

}

- (void)addNewModelWith:(BYCashDownloadModel *)model {

? ? NSMutableArray *dataMuArr = [[NSMutableArray alloc] initWithArray:self.downAriaM3U8Arr];

? ? [dataMuArr addObject:model];

? ? self.downAriaM3U8Arr = [dataMuArr copy];

}

- (void)deleteModelWith:(BYCashDownloadModel *)model {

? ? NSMutableArray *dataMuArr = [[NSMutableArray alloc] initWithArray:self.downAriaM3U8Arr];

? ? [dataMuArr removeObject:model];

? ? self.downAriaM3U8Arr = [dataMuArr copy];

}

- (NSString *)nameWithModel:(AriaM3U8Downloader *)download {

? ? NSMutableArray *dataMuArr = [[NSMutableArray alloc] initWithArray:self.downAriaM3U8Arr];

? ? __block NSString *strName;

? ? [dataMuArr enumerateObjectsUsingBlock:^(BYCashDownloadModel *? _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

? ? ? ? if (obj.downModel == download) {

? ? ? ? ? ? strName = obj.fileName;

? ? ? ? ? ? *stop = YES;

? ? ? ? }

? ? }];

? ? return strName;

}

3、開始下載

NSArray *defaultList = [[self.allUrlPlayDatArr firstObject] objectOrNilForKey:@"defaultList"];

? ? ? ? BYMovieDownLoadView *downLoadView = [[BYMovieDownLoadView alloc] initWithAlertWithArr:defaultList];

? ? ? ? [downLoadView showAlert];

? ? ? ? downLoadView.clickDownloadBlock = ^(NSDictionary * _Nonnull dict) {

? ? ? ? ? ? asyncGlobalBlock(^{

? ? ? ? ? ? ? ? [self startDownloadVideoWith:dict];

? ? ? ? ? ? });

? ? ? ? };

//電影下載

- (void)startDownloadVideoWith:(NSDictionary *)dict {

? ? NSString *url = [dict objectOrNilForKey:@"value"];

? ? NSString *videoId = self.post_id;

? ? AriaM3U8Downloader *downloader = [BYM3U3DownLoadManger plistGetDownloadWith:videoId dowloadUrl:url];

? ? //3.開始下載

? ? if (downloader.downloadStatus == AriaDownloadStatusIsDownloading) {

? ? ? ? asyncMainBlock(^{

? ? ? ? ? ? [kKeyWindow makeToast:@"已經(jīng)在后臺下載了!"];

? ? ? ? });


? ? ? ? return;

? ? }

? ? //4.判斷本地有無下載

? ? if ([BYM3U3DownLoadManger checkDownloadHaveVideoWith:videoId]) {

? ? ? ? asyncMainBlock(^{

? ? ? ? ? ? [kKeyWindow makeToast:@"本地已存在下載文件!"];

? ? ? ? });

? ? ? ? return;

? ? }




? ? [downloader start];

? ? downloader.downloadTSSuccessExeBlock = ^(NSString *event) {

? ? ? ? NSLog(@"這里是每一個TS下載完成的回調(diào)方法:%@", event);

? ? };

? ? downloader.downloadStartExeBlock = ^(void) {

? ? ? ? NSLog(@"這里是開始下載的回調(diào)方法");

? ? };


? ? //下載影片信息存儲在本地

? ? NSDictionary *videoDict = @{@"videoId": self.post_id,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @"displayInfo": [self.dataDict objectOrNilForKey:@"displayInfo"],

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @"videoTitle": [self.dataDict objectOrNilForKey:@"videoTitle"],

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @"imgUrl": [self.dataDict objectOrNilForKey:@"videoBigImg"],

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @"videoDownloadUrl": url,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @"videoType": self.post_Type,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @"videoComplete":@(0)

? ? };

? ? [BYM3U3DownLoadManger addVideoDownloadDataWith:videoDict];

? ? asyncMainBlock(^{

? ? ? ? [kKeyWindow makeToast:@"已開始后臺下載,請到下載列表查看"];

? ? });

}

其他的就是下載進(jìn)度的一些展示了,播放的方法在這里

//開始播放

? ? ? ? ? ? ? ? [AriaM3U8LocalServer.shared startWithPath:DownloadFile port:8080 bonjourName:@"AriaM3U8LocalServer"];

//? ? ? ? ? ? ? ? [playdownloader createLocalM3U8FileWithTSCount:-1];

? ? ? ? ? ? ? ? NSString *localServer = [AriaM3U8LocalServer.shared getLocalServerURLString];

? ? ? ? ? ? ? ? if ( localServer == nil ) {

? ? ? ? ? ? ? ? ? ? NSLog(@"獲取Local Server失敗...");

? ? ? ? ? ? ? ? ? ? [self.view makeToast:@"播放失敗"];

? ? ? ? ? ? ? ? ? ? return;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? NSString *indexM3U8 = [NSString stringWithFormat:@"%@/%@/index.m3u8", localServer,[dict objectOrNilForKey:@"videoId"]];

? ? ? ? ? ? ? ? NSURL *indexURL = [NSURL URLWithString:indexM3U8];

? ? ? ? ? ? ? ? NSLog(@"%@", indexURL);

? ? ? ? ? ? ? ? [self startPlayWith:indexURL];

3、用到的Pod工具

swift 下載

pod 'AriaM3U8Downloader', :git => 'https://github.com/moxcomic/AriaM3U8Downloader.git'

pod 'AriaM3U8Downloader/LocalServer', :git => 'https://github.com/moxcomic/AriaM3U8Downloader.git'

后面的以后再說吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容