初始化
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:m3u8_downloader/m3u8_downloader.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
import 'video_player_page.dart';
|
||||
|
||||
void main() => runApp(MyApp());
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
@override
|
||||
_MyAppState createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
ReceivePort _port = ReceivePort();
|
||||
String? _downloadingUrl;
|
||||
|
||||
//
|
||||
//http://m3u8.afhklsdd.com/d1af20263f1b11cc685ba52e842f6659.m3u8
|
||||
// 未加密的url地址(喜羊羊与灰太狼之决战次时代)
|
||||
//String url1 = "http://m3u8.afhklsdd.com/2eb056a7a1fc2774aa536421939d73a49652eac7.m3u8"; //"https://cdn.605-zy.com/20210713/MiJecHrZ/index.m3u8";
|
||||
// 加密的url地址(火影忍者疾风传)
|
||||
//String url2 = "https://v3.dious.cc/20201116/SVGYv7Lo/index.m3u8";
|
||||
String url2 =
|
||||
"http://163.53.216.122:9898/api/media/m3u8/sp/ah/a9/nk/pr/441c94f4f57b4b1a9058217eaf3663d3.m3u8?Authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJwdWJsaWMiLCJleHAiOjE2OTQzNDIzMTEsImlzc3VlciI6ImNvbS5idXR0ZXJmbHkiLCJzdWIiOiJhc2lnbiIsInVzZXJJZCI6OTk4MzMxMn0.u98UciEaat-JYiSx5GueWtYMM8gt61TSBy43maBdCvI"; // "http://m3u8.afhklsdd.com/7266e82a230a18ef457fe82b6c853fad.m3u8";
|
||||
|
||||
//"http://m3u8.afhklsdd.com/7266e82a230a18ef457fe82b6c853fad.m3u8";
|
||||
//"https://m3u8.afhklsdd.com/fd1ff0da268f722901030204c0c1edbf.m3u8";//"http://m3u8.afhklsdd.com/d1af20263f1b11cc685ba52e842f6659.m3u8";
|
||||
dynamic taskInfo;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
initAsync();
|
||||
});
|
||||
}
|
||||
|
||||
dynamic progress;
|
||||
|
||||
void initAsync() async {
|
||||
String saveDir = await _findSavePath();
|
||||
print(saveDir);
|
||||
bool result = await M3u8Downloader.initialize(onSelect: () async {
|
||||
print('下载成功点击');
|
||||
return null;
|
||||
});
|
||||
print("initialize====$result");
|
||||
await M3u8Downloader.config(
|
||||
saveDir: saveDir,
|
||||
threadCount: 5,
|
||||
convertMp4: true,
|
||||
debugMode: true,
|
||||
progressCallback: progressCallback,
|
||||
successCallback: successCallback,
|
||||
errorCallback: errorCallback,
|
||||
);
|
||||
// 注册监听器
|
||||
IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
|
||||
_port.listen((dynamic data) {
|
||||
// 监听数据请求
|
||||
print(data);
|
||||
progress = data;
|
||||
setState(() {});
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> _checkPermission() async {
|
||||
var status = await Permission.storage.status;
|
||||
if (!status.isGranted) {
|
||||
status = await Permission.storage.request();
|
||||
}
|
||||
return status.isGranted;
|
||||
}
|
||||
|
||||
Future<String> _findSavePath() async {
|
||||
var directory = await getExternalStorageDirectory(); //getApplicationSupportDirectory();
|
||||
String saveDir = "/sdcard/vPlayDownload"; //directory!.path + '/vPlayDownload';
|
||||
Directory root = Directory(saveDir);
|
||||
if (!root.existsSync()) {
|
||||
await root.create();
|
||||
}
|
||||
print(saveDir);
|
||||
return saveDir;
|
||||
}
|
||||
|
||||
static progressCallback(dynamic args) {
|
||||
//print("progressCallback====$args");
|
||||
final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port');
|
||||
if (send != null) {
|
||||
args["status"] = 1;
|
||||
send.send(args);
|
||||
}
|
||||
}
|
||||
|
||||
static successCallback(dynamic args) {
|
||||
print("successCallback====$args");
|
||||
final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port');
|
||||
if (send != null) {
|
||||
send.send({"status": 2, "url": args["url"], "filePath": args["filePath"], "dir": args["dir"]});
|
||||
}
|
||||
}
|
||||
|
||||
static errorCallback(dynamic args) {
|
||||
print("errorCallback====$args");
|
||||
final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port');
|
||||
if (send != null) {
|
||||
send.send({"status": 3, "url": args["url"]});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
useInheritedMediaQuery: true,
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Plugin example app'),
|
||||
),
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
ElevatedButton(
|
||||
child: Text("${_downloadingUrl == url2 ? '暂停' : '下载'}已加密m3u8"),
|
||||
onPressed: () {
|
||||
if (_downloadingUrl == url2) {
|
||||
// 暂停
|
||||
setState(() {
|
||||
_downloadingUrl = null;
|
||||
});
|
||||
M3u8Downloader.pause(url2);
|
||||
return;
|
||||
}
|
||||
// 下载
|
||||
_checkPermission().then((hasGranted) async {
|
||||
if (hasGranted) {
|
||||
await M3u8Downloader.config(
|
||||
convertMp4: true,
|
||||
);
|
||||
setState(() {
|
||||
_downloadingUrl = url2;
|
||||
});
|
||||
final result = await M3u8Downloader.download(
|
||||
url: url2,
|
||||
name: "下载已加密m3u8",
|
||||
);
|
||||
print("=========download:$result");
|
||||
if (result != null) {
|
||||
setState(() {
|
||||
_downloadingUrl = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Text("打开已下载的已加密的文件"),
|
||||
onPressed: () async {
|
||||
final result = await M3u8Downloader.download(
|
||||
url: url2,
|
||||
name: "下载已加密m3u8",
|
||||
progressCallback: progressCallback,
|
||||
successCallback: successCallback,
|
||||
errorCallback: errorCallback);
|
||||
print("=========download:$result");
|
||||
if (result != null) {
|
||||
setState(() {
|
||||
_downloadingUrl = null;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Text("清空下载"),
|
||||
onPressed: () async {
|
||||
await M3u8Downloader.delete(url2);
|
||||
print("清理完成");
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Text(taskInfo?.toString() ?? "查询"),
|
||||
onPressed: () async {
|
||||
taskInfo = await M3u8Downloader.searchInfo(url2);
|
||||
print("=======taskInfo:");
|
||||
print(taskInfo);
|
||||
print("=======taskInfo:");
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
Container(
|
||||
child: Text(progress?.toString() ?? "progress"),
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Text("movie"),
|
||||
onPressed: () {
|
||||
print("Navigator push:${context}");
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => VideoM38UPlayerPage(),
|
||||
),
|
||||
);
|
||||
// Navigator.of(context).push(MaterialPageRoute(builder: (context){
|
||||
// print("Navigator push VideoPlayerPage");
|
||||
// return VideoPlayerPage();
|
||||
// }));
|
||||
},
|
||||
),
|
||||
Container(
|
||||
height: 300,
|
||||
width: 400,
|
||||
child: VideoM38UPlayerPage(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:m3u8_downloader/m3u8_downloader.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
//视频播放器封装需要使用动态类
|
||||
class VideoM38UPlayerPage extends StatefulWidget {
|
||||
@override
|
||||
_VideoPlayerPageState createState() => _VideoPlayerPageState();
|
||||
}
|
||||
|
||||
//继承VideoApp类
|
||||
class _VideoPlayerPageState extends State<VideoM38UPlayerPage> {
|
||||
|
||||
//定义一个VideoPlayerController
|
||||
VideoPlayerController? _controller;
|
||||
|
||||
//重写类方法initState(),初始化界面
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
print("_VideoPlayerPageState init");
|
||||
//设置视频参数 (..)是级联的意思
|
||||
// initController();
|
||||
}
|
||||
|
||||
|
||||
void initController() {
|
||||
String url = "http://163.53.216.122:9898/api/media/m3u8/sp/ah/a9/nk/pr/441c94f4f57b4b1a9058217eaf3663d3.m3u8?Authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJwdWJsaWMiLCJleHAiOjE2OTQzNDIzMTEsImlzc3VlciI6ImNvbS5idXR0ZXJmbHkiLCJzdWIiOiJhc2lnbiIsInVzZXJJZCI6OTk4MzMxMn0.u98UciEaat-JYiSx5GueWtYMM8gt61TSBy43maBdCvI"; //"""https://m3u8.afhklsdd.com/5678954c76ece8b4345ae437e7344367e22e2G1o.m3u8";
|
||||
M3u8Downloader.searchInfo(url).then((result) {
|
||||
if (result is Map) {
|
||||
Map fileInfoMap = result;
|
||||
String? filePath = fileInfoMap["localPath"];
|
||||
// filePath = filePath?.replaceAll("local.m3u8", "remote.m3u8");
|
||||
print(filePath);
|
||||
if (filePath?.isNotEmpty == true) {
|
||||
|
||||
_controller = VideoPlayerController.file(File(filePath!))
|
||||
..initialize().then((value) {
|
||||
setState(() {
|
||||
if (_controller == null) {
|
||||
_controller?.addListener(() {setState(() {
|
||||
|
||||
});});
|
||||
print("_controller success local path");
|
||||
_controller?.play();
|
||||
}
|
||||
});
|
||||
});
|
||||
}else {
|
||||
_controller = VideoPlayerController.network(url)..initialize().then((value) {
|
||||
setState(() {
|
||||
if (_controller == null) {
|
||||
_controller?.addListener(() {setState(() {
|
||||
|
||||
});});
|
||||
print("_controller success");
|
||||
_controller?.play();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: Text("back"),
|
||||
),
|
||||
body: Center(
|
||||
child: (_controller?.value.isInitialized ?? false)
|
||||
? AspectRatio(
|
||||
aspectRatio: _controller!.value.aspectRatio,
|
||||
child: VideoPlayer(_controller!),
|
||||
)
|
||||
: Container(
|
||||
child: Text("没有要播放的视频"),
|
||||
),
|
||||
),
|
||||
|
||||
//右下角图标按钮onPressed中需要调用setState方法,用于刷新界面
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
if (_controller != null) {
|
||||
_controller!.value.isPlaying
|
||||
? _controller!.pause() : _controller!.play();
|
||||
}else{
|
||||
initController();
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Icon(
|
||||
(_controller?.value.isPlaying ?? false)? Icons.pause : Icons.play_arrow,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//dispose():程序中是用来关闭一个GUI页面的
|
||||
//视频播放完需要把页面关闭
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_controller?.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user