美文网首页
M3U8文件的下载总结

M3U8文件的下载总结

作者: ViolinCover | 来源:发表于2020-03-22 18:29 被阅读0次

一、简述

    最近的项目有个m3u8文件的下载需求,m3u8文件和其他文件有个根本的区别是它只是一个地址的集合文件,我们如果需要下载m3u8文件的话需要将它列表里面所有的文件都一一下载下来,然后还要生成一个播放的排列文件,最后开始播放。

二、难点

1、多文件下载。

2、播放文件的生成。

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

三、相关代码详解

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;

//设置本地视频下载状态为已下载

+ (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.创建主文件夹

    [self creatDir:DownloadFile];

    //创建子文件夹

    NSString *file = [DownloadFile stringByAppendingPathComponent:name];

    [self creatDir:file];

    //2.通过 M3U8 URL 进行初始化

    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.创建主文件夹

    [self creatDir:DownloadFile];

    //创建子文件夹

    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];

        }

    }

    //清除临时缓存内的播放器

    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];

    //循环删除本地下载文件

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

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

        [self creatDir:DownloadFile];

        //创建子文件夹

        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];

    }];

    //最后删除视频数组里面的数据

    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];

}

/**

创建文件夹

@param dirPath 文件夹名称

@return 创建成功或失败

*/

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

    if ([[NSFileManager defaultManager] fileExistsAtPath:dirPath]) {//判断dirPath路径文件夹是否已存在,此处dirPath为需要新建的文件夹的绝对路径

        NSLog(@"沙盒目录已经存在%@",dirPath);

        return NO;

    }else {

        [[NSFileManager defaultManager] createDirectoryAtPath:dirPath withIntermediateDirectories:YES attributes:nil error:nil];//创建文件夹

        NSLog(@"创建成功%@",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;

}

//设置本地视频下载状态为已下载

+ (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:@"已经在后台下载了!"];

        });

        return;

    }

    //4.判断本地有无下载

    if ([BYM3U3DownLoadManger checkDownloadHaveVideoWith:videoId]) {

        asyncMainBlock(^{

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

        });

        return;

    }

    [downloader start];

    downloader.downloadTSSuccessExeBlock = ^(NSString *event) {

        NSLog(@"这里是每一个TS下载完成的回调方法:%@", event);

    };

    downloader.downloadStartExeBlock = ^(void) {

        NSLog(@"这里是开始下载的回调方法");

    };

    //下载影片信息存储在本地

    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:@"已开始后台下载,请到下载列表查看"];

    });

}

其他的就是下载进度的一些展示了,播放的方法在这里

//开始播放

                [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'

后面的以后再说吧。

相关文章

网友评论

      本文标题:M3U8文件的下载总结

      本文链接:https://www.haomeiwen.com/subject/ogvomxtx.html