import 'dart:async'; import 'dart:ui'; import 'package:flutter/services.dart'; import 'callback_dispatcher.dart'; typedef CallbackHandle? _GetCallbackHandle(Function callback); typedef SelectNotificationCallback = Future Function(); class M3u8Downloader { static const MethodChannel _channel = const MethodChannel( 'm3u8_downloader', JSONMethodCodec()); static _GetCallbackHandle _getCallbackHandle = (Function callback) => PluginUtilities.getCallbackHandle(callback); static SelectNotificationCallback? _onSelectNotification; static bool _initialized = false; static bool get isInitialized { return _initialized; } /// 初始化下载器 /// 在使用之前必须调用 /// /// - [onSelect] 点击通知的回调 static Future initialize({ SelectNotificationCallback? onSelect }) async { assert(!_initialized, 'M3u8Downloader.initialize() must be called only once!'); final CallbackHandle? handle = _getCallbackHandle(callbackDispatcher); if (handle == null) { return false; } if (onSelect != null) { _onSelectNotification = onSelect; } _channel.setMethodCallHandler((MethodCall call) { switch (call.method) { case 'selectNotification': if (_onSelectNotification == null) { return Future.value(false); } return _onSelectNotification!(); default: return Future.error('method not defined'); } }); final bool? r = await _channel.invokeMethod('initialize', { "handle": handle.toRawHandle(), }) ?? false; _initialized = r ?? false; return _initialized; } /// 下载配置 /// /// - [saveDir] 文件保存位置 /// - [showNotification] 是否显示通知 /// - [convertMp4] 是否转成mp4 /// - [connTimeout] 网络连接超时时间 /// - [readTimeout] 文件读取超时时间 /// - [threadCount] 同时下载的线程数 /// - [debugMode] 调试模式 static Future config({ String? saveDir, bool showNotification = true, bool convertMp4 = false, int? connTimeout, int? readTimeout, int? threadCount, bool? debugMode = true, Function? progressCallback, Function? successCallback, Function? errorCallback, }) async { Map params = { "saveDir": saveDir, "showNotification": showNotification, "convertMp4": convertMp4, "connTimeout": connTimeout, "readTimeout": readTimeout, "threadCount": threadCount, "debugMode": debugMode, }; if (progressCallback != null) { final CallbackHandle? handle = _getCallbackHandle(progressCallback); if (handle != null) { params["progressCallback"] = handle.toRawHandle(); } } if (successCallback != null) { final CallbackHandle? handle = _getCallbackHandle(successCallback); if (handle != null) { params["successCallback"] = handle.toRawHandle(); } } if (errorCallback != null) { final CallbackHandle? handle = _getCallbackHandle(errorCallback); if (handle != null) { params["errorCallback"] = handle.toRawHandle(); } } final bool? r = await _channel.invokeMethod('config', params); return r ?? false; } /// 下载文件 /// /// - [url] 下载链接地址 /// - [name] 下载文件名(通知标题) /// - [progressCallback] 下载进度回调 /// - [successCallback] 下载成功回调 /// - [errorCallback] 下载失败回调 static Future download({ required String url, required String name, Function? progressCallback, Function? successCallback, Function? errorCallback }) async { assert(url.isNotEmpty && name.isNotEmpty); assert(_initialized, 'M3u8Downloader.initialize() must be called first!'); Map params = { "url": url, "name": name, }; if (progressCallback != null) { final CallbackHandle? handle = _getCallbackHandle(progressCallback); if (handle != null) { params["progressCallback"] = handle.toRawHandle(); } } if (successCallback != null) { final CallbackHandle? handle = _getCallbackHandle(successCallback); if (handle != null) { params["successCallback"] = handle.toRawHandle(); } } if (errorCallback != null) { final CallbackHandle? handle = _getCallbackHandle(errorCallback); if (handle != null) { params["errorCallback"] = handle.toRawHandle(); } } return await _channel.invokeMethod("download", params); } /// 查询任务 /// /// - [url] 下载链接地址 static Future searchInfo(String url,{ Function? progressCallback, Function? successCallback, Function? errorCallback,}) async { assert(url.isNotEmpty); assert(_initialized, 'M3u8Downloader.initialize() must be called first!'); Map params = { "url": url, }; if (progressCallback != null) { final CallbackHandle? handle = _getCallbackHandle(progressCallback); if (handle != null) { params["progressCallback"] = handle.toRawHandle(); } } if (successCallback != null) { final CallbackHandle? handle = _getCallbackHandle(successCallback); if (handle != null) { params["successCallback"] = handle.toRawHandle(); } } if (errorCallback != null) { final CallbackHandle? handle = _getCallbackHandle(errorCallback); if (handle != null) { params["errorCallback"] = handle.toRawHandle(); } } return await _channel.invokeMethod("searchInfo", params) ?? null; } /// 暂停下载 /// /// - [url] 暂停指定的链接地址 static dynamic pause(String url) async { assert(_initialized, 'M3u8Downloader.initialize() must be called first!'); return await _channel.invokeMethod("pause", { "url": url }); } static void pauseAll() async { assert(_initialized, 'M3u8Downloader.initialize() must be called first!'); await _channel.invokeMethod("pauseAll", {}); } /// 删除下载 /// /// - [url] 下载链接地址 static Future delete(String url) async { assert(url.isNotEmpty); assert(_initialized, 'M3u8Downloader.initialize() must be called first!'); return await _channel.invokeMethod("delete", { "url": url }) ?? false; } static Future deleteAll() async { assert(_initialized, 'M3u8Downloader.initialize() must be called first!'); return await _channel.invokeMethod("deleteAll",{}) ?? false; } /// 下载状态 static Future isRunning() async { assert(_initialized, 'M3u8Downloader.initialize() must be called first!'); bool isRunning = await _channel.invokeMethod("isRunning"); return isRunning; } /// 通过URL获取保存的路径 /// - [url] 请求的URL /// baseDir - 基础文件保存路径 /// m3u8 - m3u8文件地址 /// mp4 - mp4存储位置 static Future getSavePath(String url) async { return await _channel.invokeMethod("getSavePath", { "url": url}); } }