Files
2026-09-15 15:44:13 +07:00

238 lines
7.0 KiB
Dart

import 'dart:async';
import 'dart:ui';
import 'package:flutter/services.dart';
import 'callback_dispatcher.dart';
typedef CallbackHandle? _GetCallbackHandle(Function callback);
typedef SelectNotificationCallback = Future<dynamic> 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<bool> 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<bool?>('initialize', {
"handle": handle.toRawHandle(),
}) ?? false;
_initialized = r ?? false;
return _initialized;
}
/// 下载配置
///
/// - [saveDir] 文件保存位置
/// - [showNotification] 是否显示通知
/// - [convertMp4] 是否转成mp4
/// - [connTimeout] 网络连接超时时间
/// - [readTimeout] 文件读取超时时间
/// - [threadCount] 同时下载的线程数
/// - [debugMode] 调试模式
static Future<bool> 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<String, dynamic> 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<bool>('config', params);
return r ?? false;
}
/// 下载文件
///
/// - [url] 下载链接地址
/// - [name] 下载文件名(通知标题)
/// - [progressCallback] 下载进度回调
/// - [successCallback] 下载成功回调
/// - [errorCallback] 下载失败回调
static Future<dynamic> 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<String, dynamic> 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<dynamic> searchInfo(String url,{
Function? progressCallback,
Function? successCallback,
Function? errorCallback,}) async {
assert(url.isNotEmpty);
assert(_initialized, 'M3u8Downloader.initialize() must be called first!');
Map<String, dynamic> 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<bool> 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<bool> deleteAll() async {
assert(_initialized, 'M3u8Downloader.initialize() must be called first!');
return await _channel.invokeMethod("deleteAll",{}) ?? false;
}
/// 下载状态
static Future<bool> 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<dynamic> getSavePath(String url) async {
return await _channel.invokeMethod("getSavePath", { "url": url});
}
}