Compare commits

...

13 Commits

12 changed files with 150 additions and 67 deletions

View File

@ -142,7 +142,7 @@ class Stat {
Stat.fromJson(Map<String, dynamic> json) { Stat.fromJson(Map<String, dynamic> json) {
view = json["play"]; view = json["play"];
danmaku = json['comment']; danmaku = json['video_review'];
} }
} }

View File

@ -34,6 +34,7 @@ class PlayUrlModel {
String? seekParam; String? seekParam;
String? seekType; String? seekType;
Dash? dash; Dash? dash;
List<Durl>? durl;
List<FormatItem>? supportFormats; List<FormatItem>? supportFormats;
// String? highFormat; // String? highFormat;
int? lastPlayTime; int? lastPlayTime;
@ -52,7 +53,8 @@ class PlayUrlModel {
videoCodecid = json['video_codecid']; videoCodecid = json['video_codecid'];
seekParam = json['seek_param']; seekParam = json['seek_param'];
seekType = json['seek_type']; seekType = json['seek_type'];
dash = Dash.fromJson(json['dash']); dash = json['dash'] != null ? Dash.fromJson(json['dash']) : null;
durl = json['durl']?.map<Durl>((e) => Durl.fromJson(e)).toList();
supportFormats = json['support_formats'] != null supportFormats = json['support_formats'] != null
? json['support_formats'] ? json['support_formats']
.map<FormatItem>((e) => FormatItem.fromJson(e)) .map<FormatItem>((e) => FormatItem.fromJson(e))
@ -250,3 +252,30 @@ class Flac {
audio = json['audio'] != null ? AudioItem.fromJson(json['audio']) : null; audio = json['audio'] != null ? AudioItem.fromJson(json['audio']) : null;
} }
} }
class Durl {
Durl({
this.order,
this.length,
this.size,
this.ahead,
this.vhead,
this.url,
});
int? order;
int? length;
int? size;
String? ahead;
String? vhead;
String? url;
Durl.fromJson(Map<String, dynamic> json) {
order = json['order'];
length = json['length'];
size = json['size'];
ahead = json['ahead'];
vhead = json['vhead'];
url = json['url'];
}
}

View File

@ -218,14 +218,12 @@ class BangumiIntroController extends GetxController {
addIds: addMediaIdsNew.join(','), addIds: addMediaIdsNew.join(','),
delIds: delMediaIdsNew.join(',')); delIds: delMediaIdsNew.join(','));
if (result['status']) { if (result['status']) {
if (result['data']['prompt']) { addMediaIdsNew = [];
addMediaIdsNew = []; delMediaIdsNew = [];
delMediaIdsNew = []; // 重新获取收藏状态
Get.back(); queryHasFavVideo();
// 重新获取收藏状态 SmartDialog.showToast('✅ 操作成功');
queryHasFavVideo(); Get.back();
SmartDialog.showToast('✅ 操作成功');
}
} }
} }

View File

@ -60,16 +60,14 @@ class FavDetailController extends GetxController {
var result = await VideoHttp.favVideo( var result = await VideoHttp.favVideo(
aid: id, addIds: '', delIds: mediaId.toString()); aid: id, addIds: '', delIds: mediaId.toString());
if (result['status']) { if (result['status']) {
if (result['data']['prompt']) { List dataList = favList;
List dataList = favList; for (var i in dataList) {
for (var i in dataList) { if (i.id == id) {
if (i.id == id) { dataList.remove(i);
dataList.remove(i); break;
break;
}
} }
SmartDialog.showToast('取消收藏');
} }
SmartDialog.showToast('取消收藏');
} }
} }

View File

@ -29,6 +29,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
mediaId = Get.parameters['mediaId']!;
_futureBuilderFuture = _favDetailController.queryUserFavFolderDetail(); _futureBuilderFuture = _favDetailController.queryUserFavFolderDetail();
mediaId = Get.parameters['mediaId']!; mediaId = Get.parameters['mediaId']!;
titleStreamC = StreamController<bool>(); titleStreamC = StreamController<bool>();

View File

@ -80,16 +80,14 @@ class FavSearchController extends GetxController {
var result = await VideoHttp.favVideo( var result = await VideoHttp.favVideo(
aid: id, addIds: '', delIds: mediaId.toString()); aid: id, addIds: '', delIds: mediaId.toString());
if (result['status']) { if (result['status']) {
if (result['data']['prompt']) { List dataList = favList;
List dataList = favList; for (var i in dataList) {
for (var i in dataList) { if (i.id == id) {
if (i.id == id) { dataList.remove(i);
dataList.remove(i); break;
break;
}
} }
SmartDialog.showToast('取消收藏');
} }
SmartDialog.showToast('取消收藏');
} }
} }
} }

View File

@ -4,6 +4,8 @@ import 'package:pilipala/http/live.dart';
import 'package:pilipala/models/live/room_info.dart'; import 'package:pilipala/models/live/room_info.dart';
import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/plugin/pl_player/index.dart';
import '../../models/live/room_info_h5.dart'; import '../../models/live/room_info_h5.dart';
import '../../utils/storage.dart';
import '../../utils/video_utils.dart';
class LiveRoomController extends GetxController { class LiveRoomController extends GetxController {
String cover = ''; String cover = '';
@ -16,6 +18,7 @@ class LiveRoomController extends GetxController {
PlPlayerController plPlayerController = PlPlayerController plPlayerController =
PlPlayerController.getInstance(videoType: 'live'); PlPlayerController.getInstance(videoType: 'live');
Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs; Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs;
late bool enableCDN;
@override @override
void onInit() { void onInit() {
@ -31,6 +34,8 @@ class LiveRoomController extends GetxController {
cover = liveItem.cover; cover = liveItem.cover;
} }
} }
// CDN优化
enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true);
} }
playerInit(source) async { playerInit(source) async {
@ -57,9 +62,11 @@ class LiveRoomController extends GetxController {
List<CodecItem> codec = List<CodecItem> codec =
res['data'].playurlInfo.playurl.stream.first.format.first.codec; res['data'].playurlInfo.playurl.stream.first.format.first.codec;
CodecItem item = codec.first; CodecItem item = codec.first;
String videoUrl = (item.urlInfo?.first.host)! + String videoUrl = enableCDN
item.baseUrl! + ? VideoUtils.getCdnUrl(item)
item.urlInfo!.first.extra!; : (item.urlInfo?.first.host)! +
item.baseUrl! +
item.urlInfo!.first.extra!;
await playerInit(videoUrl); await playerInit(videoUrl);
return res; return res;
} }

View File

@ -90,6 +90,8 @@ class VideoDetailController extends GetxController
late String cacheDecode; late String cacheDecode;
late int cacheAudioQa; late int cacheAudioQa;
PersistentBottomSheetController? replyReplyBottomSheetCtr;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -140,7 +142,7 @@ class VideoDetailController extends GetxController
} }
showReplyReplyPanel() { showReplyReplyPanel() {
PersistentBottomSheetController? ctr = replyReplyBottomSheetCtr =
scaffoldKey.currentState?.showBottomSheet((BuildContext context) { scaffoldKey.currentState?.showBottomSheet((BuildContext context) {
return VideoReplyReplyPanel( return VideoReplyReplyPanel(
oid: oid.value, oid: oid.value,
@ -153,7 +155,7 @@ class VideoDetailController extends GetxController
source: 'videoDetail', source: 'videoDetail',
); );
}); });
ctr?.closed.then((value) { replyReplyBottomSheetCtr?.closed.then((value) {
fRpid = 0; fRpid = 0;
}); });
} }
@ -229,9 +231,11 @@ class VideoDetailController extends GetxController
seekTo: seekToTime ?? defaultST, seekTo: seekToTime ?? defaultST,
duration: duration ?? Duration(milliseconds: data.timeLength ?? 0), duration: duration ?? Duration(milliseconds: data.timeLength ?? 0),
// 宽>高 水平 否则 垂直 // 宽>高 水平 否则 垂直
direction: (firstVideo.width! - firstVideo.height!) > 0 direction: firstVideo.width != null && firstVideo.height != null
? 'horizontal' ? ((firstVideo.width! - firstVideo.height!) > 0
: 'vertical', ? 'horizontal'
: 'vertical')
: null,
bvid: bvid, bvid: bvid,
cid: cid.value, cid: cid.value,
enableHeart: enableHeart, enableHeart: enableHeart,
@ -248,6 +252,21 @@ class VideoDetailController extends GetxController
var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid); var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid);
if (result['status']) { if (result['status']) {
data = result['data']; data = result['data'];
if (data.acceptDesc!.isNotEmpty && data.acceptDesc!.contains('试看')) {
SmartDialog.showToast(
'该视频为专属视频,仅提供试看',
displayTime: const Duration(seconds: 3),
);
videoUrl = data.durl!.first.url!;
audioUrl = '';
defaultST = Duration.zero;
firstVideo = VideoItem();
if (autoPlay.value) {
await playerInit();
isShowCover.value = false;
}
return result;
}
final List<VideoItem> allVideosList = data.dash!.video!; final List<VideoItem> allVideosList = data.dash!.video!;
try { try {
// 当前可播放的最高质量视频 // 当前可播放的最高质量视频
@ -355,4 +374,11 @@ class VideoDetailController extends GetxController
} }
return result; return result;
} }
// mob端全屏状态关闭二级回复
hiddenReplyReplyPanel() {
replyReplyBottomSheetCtr != null
? replyReplyBottomSheetCtr!.close()
: print('replyReplyBottomSheetCtr is null');
}
} }

View File

@ -305,11 +305,9 @@ class VideoIntroController extends GetxController {
delIds: favStatus == 1 ? '$defaultFolderId' : '', delIds: favStatus == 1 ? '$defaultFolderId' : '',
); );
if (result['status']) { if (result['status']) {
if (result['data']['prompt']) { // 重新获取收藏状态
// 重新获取收藏状态 await queryHasFavVideo();
await queryHasFavVideo(); SmartDialog.showToast('✅ 操作成功');
SmartDialog.showToast('✅ 操作成功');
}
} else { } else {
SmartDialog.showToast(result['msg']); SmartDialog.showToast(result['msg']);
} }
@ -334,14 +332,12 @@ class VideoIntroController extends GetxController {
delIds: delMediaIdsNew.join(',')); delIds: delMediaIdsNew.join(','));
SmartDialog.dismiss(); SmartDialog.dismiss();
if (result['status']) { if (result['status']) {
if (result['data']['prompt']) { addMediaIdsNew = [];
addMediaIdsNew = []; delMediaIdsNew = [];
delMediaIdsNew = []; Get.back();
Get.back(); // 重新获取收藏状态
// 重新获取收藏状态 await queryHasFavVideo();
await queryHasFavVideo(); SmartDialog.showToast('✅ 操作成功');
SmartDialog.showToast('✅ 操作成功');
}
} else { } else {
SmartDialog.showToast(result['msg']); SmartDialog.showToast(result['msg']);
} }
@ -482,7 +478,7 @@ class VideoIntroController extends GetxController {
final ReleatedController releatedCtr = final ReleatedController releatedCtr =
Get.find<ReleatedController>(tag: heroTag); Get.find<ReleatedController>(tag: heroTag);
videoDetailCtr.bvid = bvid; videoDetailCtr.bvid = bvid;
videoDetailCtr.oid.value = aid; videoDetailCtr.oid.value = aid ?? IdUtils.bv2av(bvid);
videoDetailCtr.cid.value = cid; videoDetailCtr.cid.value = cid;
videoDetailCtr.danmakuCid.value = cid; videoDetailCtr.danmakuCid.value = cid;
videoDetailCtr.queryVideoUrl(); videoDetailCtr.queryVideoUrl();

View File

@ -12,6 +12,7 @@ import 'package:pilipala/pages/preview/index.dart';
import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/index.dart';
import 'package:pilipala/pages/video/detail/reply_new/index.dart'; import 'package:pilipala/pages/video/detail/reply_new/index.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/id_utils.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/url_utils.dart'; import 'package:pilipala/utils/url_utils.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
@ -620,26 +621,34 @@ InlineSpan buildContent(
..onTap = () async { ..onTap = () async {
final String title = content.jumpUrl[matchStr]['title']; final String title = content.jumpUrl[matchStr]['title'];
if (appUrlSchema == '') { if (appUrlSchema == '') {
final String redirectUrl = if (matchStr.startsWith('BV')) {
await UrlUtils.parseRedirectUrl(matchStr);
final String pathSegment = Uri.parse(redirectUrl).path;
final String lastPathSegment =
pathSegment.split('/').last;
if (lastPathSegment.startsWith('BV')) {
UrlUtils.matchUrlPush( UrlUtils.matchUrlPush(
lastPathSegment, matchStr,
title, title,
redirectUrl, '',
); );
} else { } else {
Get.toNamed( final String redirectUrl =
'/webview', await UrlUtils.parseRedirectUrl(matchStr);
parameters: { final String pathSegment = Uri.parse(redirectUrl).path;
'url': redirectUrl, final String lastPathSegment =
'type': 'url', pathSegment.split('/').last;
'pageTitle': title if (lastPathSegment.startsWith('BV')) {
}, UrlUtils.matchUrlPush(
); lastPathSegment,
title,
redirectUrl,
);
} else {
Get.toNamed(
'/webview',
parameters: {
'url': redirectUrl,
'type': 'url',
'pageTitle': title
},
);
}
} }
} else { } else {
if (appUrlSchema.startsWith('bilibili://search')) { if (appUrlSchema.startsWith('bilibili://search')) {

View File

@ -92,6 +92,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
videoSourceInit(); videoSourceInit();
appbarStreamListen(); appbarStreamListen();
lifecycleListener(); lifecycleListener();
fullScreenStatusListener();
} }
// 获取视频资源,初始化播放器 // 获取视频资源,初始化播放器
@ -188,6 +189,14 @@ class _VideoDetailPageState extends State<VideoDetailPage>
); );
} }
void fullScreenStatusListener() {
plPlayerController?.isFullScreen.listen((bool isFullScreen) {
if (isFullScreen) {
videoDetailController.hiddenReplyReplyPanel();
}
});
}
@override @override
void dispose() { void dispose() {
shutdownTimerService.handleWaitingFinished(); shutdownTimerService.handleWaitingFinished();
@ -225,7 +234,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
@override @override
// 返回当前页面时 // 返回当前页面时
void didPopNext() async { void didPopNext() async {
setState(() => isShowing = true); if (plPlayerController != null &&
plPlayerController!.videoPlayerController != null) {
setState(() => isShowing = true);
}
videoDetailController.isFirstTime = false; videoDetailController.isFirstTime = false;
final bool autoplay = autoPlayEnable; final bool autoplay = autoPlayEnable;
videoDetailController.playerInit(autoplay: autoplay); videoDetailController.playerInit(autoplay: autoplay);

View File

@ -1,5 +1,7 @@
import 'package:pilipala/models/video/play/url.dart'; import 'package:pilipala/models/video/play/url.dart';
import '../models/live/room_info.dart';
class VideoUtils { class VideoUtils {
static String getCdnUrl(dynamic item) { static String getCdnUrl(dynamic item) {
var backupUrl = ""; var backupUrl = "";
@ -12,13 +14,20 @@ class VideoUtils {
} else if (item is AudioItem) { } else if (item is AudioItem) {
backupUrl = item.backupUrl ?? ""; backupUrl = item.backupUrl ?? "";
videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? ""); videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? "");
} else if (item is CodecItem) {
backupUrl = (item.urlInfo?.first.host)! +
item.baseUrl! +
item.urlInfo!.first.extra!;
videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? "");
} else { } else {
return ""; return "";
} }
/// issues #70 /// issues #70
if (videoUrl.contains(".mcdn.bilivideo") || if (videoUrl.contains(".mcdn.bilivideo")) {
videoUrl.contains("/upgcxcode/")) { videoUrl =
'https://proxy-tf-all-ws.bilivideo.com/?url=${Uri.encodeComponent(videoUrl)}';
} else if (videoUrl.contains("/upgcxcode/")) {
//CDN列表 //CDN列表
var cdnList = { var cdnList = {
'ali': 'upos-sz-mirrorali.bilivideo.com', 'ali': 'upos-sz-mirrorali.bilivideo.com',