Skip to content

Commit

Permalink
Merge branch 'feature-playerSubtitle'
Browse files Browse the repository at this point in the history
  • Loading branch information
guozhigq committed Mar 24, 2024
2 parents 7e7bb1f + 955d8f5 commit 9faa625
Show file tree
Hide file tree
Showing 11 changed files with 460 additions and 2 deletions.
3 changes: 3 additions & 0 deletions lib/http/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,9 @@ class Api {
/// 激活buvid3
static const activateBuvidApi = '/x/internal/gaia-gateway/ExClimbWuzhi';

/// 获取字幕配置
static const getSubtitleConfig = '/x/player/v2';

/// 我的订阅
static const userSubFolder = '/x/v3/fav/folder/collected/list';

Expand Down
29 changes: 29 additions & 0 deletions lib/http/video.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import '../models/model_rec_video_item.dart';
import '../models/user/fav_folder.dart';
import '../models/video/ai.dart';
import '../models/video/play/url.dart';
import '../models/video/subTitile/result.dart';
import '../models/video_detail_res.dart';
import '../utils/recommend_filter.dart';
import '../utils/storage.dart';
import '../utils/subtitle.dart';
import '../utils/wbi_sign.dart';
import 'api.dart';
import 'init.dart';
Expand Down Expand Up @@ -476,6 +478,25 @@ class VideoHttp {
}
}

static Future getSubtitle({int? cid, String? bvid}) async {
var res = await Request().get(Api.getSubtitleConfig, data: {
'cid': cid,
'bvid': bvid,
});
try {
if (res.data['code'] == 0) {
return {
'status': true,
'data': SubTitlteModel.fromJson(res.data['data']),
};
} else {
return {'status': false, 'data': [], 'msg': res.data['msg']};
}
} catch (err) {
print(err);
}
}

// 视频排行
static Future getRankVideoList(int rid) async {
try {
Expand All @@ -498,4 +519,12 @@ class VideoHttp {
return {'status': false, 'data': [], 'msg': err};
}
}

// 获取字幕内容
static Future<Map<String, dynamic>> getSubtitleContent(url) async {
var res = await Request().get('https:$url');
final String content = SubTitleUtils.convertToWebVTT(res.data['body']);
final List body = res.data['body'];
return {'content': content, 'body': body};
}
}
47 changes: 47 additions & 0 deletions lib/models/common/subtitle_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
enum SubtitleType {
// 中文(中国)
zhCN,
// 中文(自动翻译)
aizh,
// 英语(自动生成)
aien,
}

extension SubtitleTypeExtension on SubtitleType {
String get description {
switch (this) {
case SubtitleType.zhCN:
return '中文(中国)';
case SubtitleType.aizh:
return '中文(自动翻译)';
case SubtitleType.aien:
return '英语(自动生成)';
}
}
}

extension SubtitleIdExtension on SubtitleType {
String get id {
switch (this) {
case SubtitleType.zhCN:
return 'zh-CN';
case SubtitleType.aizh:
return 'ai-zh';
case SubtitleType.aien:
return 'ai-en';
}
}
}

extension SubtitleCodeExtension on SubtitleType {
int get code {
switch (this) {
case SubtitleType.zhCN:
return 1;
case SubtitleType.aizh:
return 2;
case SubtitleType.aien:
return 3;
}
}
}
20 changes: 20 additions & 0 deletions lib/models/video/subTitile/content.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class SubTitileContentModel {
double? from;
double? to;
int? location;
String? content;

SubTitileContentModel({
this.from,
this.to,
this.location,
this.content,
});

SubTitileContentModel.fromJson(Map<String, dynamic> json) {
from = json['from'];
to = json['to'];
location = json['location'];
content = json['content'];
}
}
89 changes: 89 additions & 0 deletions lib/models/video/subTitile/result.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import 'package:get/get.dart';
import '../../common/subtitle_type.dart';

class SubTitlteModel {
SubTitlteModel({
this.aid,
this.bvid,
this.cid,
this.loginMid,
this.loginMidHash,
this.isOwner,
this.name,
this.subtitles,
});

int? aid;
String? bvid;
int? cid;
int? loginMid;
String? loginMidHash;
bool? isOwner;
String? name;
List<SubTitlteItemModel>? subtitles;

factory SubTitlteModel.fromJson(Map<String, dynamic> json) => SubTitlteModel(
aid: json["aid"],
bvid: json["bvid"],
cid: json["cid"],
loginMid: json["login_mid"],
loginMidHash: json["login_mid_hash"],
isOwner: json["is_owner"],
name: json["name"],
subtitles: json["subtitle"] != null
? json["subtitle"]["subtitles"]
.map<SubTitlteItemModel>((x) => SubTitlteItemModel.fromJson(x))
.toList()
: [],
);
}

class SubTitlteItemModel {
SubTitlteItemModel({
this.id,
this.lan,
this.lanDoc,
this.isLock,
this.subtitleUrl,
this.type,
this.aiType,
this.aiStatus,
this.title,
this.code,
this.content,
this.body,
});

int? id;
String? lan;
String? lanDoc;
bool? isLock;
String? subtitleUrl;
int? type;
int? aiType;
int? aiStatus;
String? title;
int? code;
String? content;
List? body;

factory SubTitlteItemModel.fromJson(Map<String, dynamic> json) =>
SubTitlteItemModel(
id: json["id"],
lan: json["lan"].replaceAll('-', ''),
lanDoc: json["lan_doc"],
isLock: json["is_lock"],
subtitleUrl: json["subtitle_url"],
type: json["type"],
aiType: json["ai_type"],
aiStatus: json["ai_status"],
title: json["lan_doc"],
code: SubtitleType.values
.firstWhereOrNull(
(element) => element.id.toString() == json["lan"])
?.index ??
-1,
content: '',
body: [],
);
}
46 changes: 46 additions & 0 deletions lib/pages/video/detail/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import 'package:pilipala/utils/utils.dart';
import 'package:pilipala/utils/video_utils.dart';
import 'package:screen_brightness/screen_brightness.dart';

import '../../../models/video/subTitile/content.dart';
import '../../../http/danmaku.dart';
import '../../../utils/id_utils.dart';
import 'widgets/header_control.dart';
Expand Down Expand Up @@ -93,7 +94,10 @@ class VideoDetailController extends GetxController
late int cacheAudioQa;

PersistentBottomSheetController? replyReplyBottomSheetCtr;
RxList<SubTitileContentModel> subtitleContents =
<SubTitileContentModel>[].obs;
late bool enableRelatedVideo;
List subtitles = [];

@override
void onInit() {
Expand Down Expand Up @@ -145,6 +149,7 @@ class VideoDetailController extends GetxController
cacheAudioQa = setting.get(SettingBoxKey.defaultAudioQa,
defaultValue: AudioQuality.hiRes.code);
oid.value = IdUtils.bv2av(Get.parameters['bvid']!);
getSubtitle();
}

showReplyReplyPanel() {
Expand Down Expand Up @@ -251,6 +256,8 @@ class VideoDetailController extends GetxController

/// 开启自动全屏时,在player初始化完成后立即传入headerControl
plPlayerController.headerControl = headerControl;

plPlayerController.subtitles.value = subtitles;
}

// 视频链接
Expand Down Expand Up @@ -388,6 +395,45 @@ class VideoDetailController extends GetxController
: print('replyReplyBottomSheetCtr is null');
}

// 获取字幕配置
Future getSubtitle() async {
var result = await VideoHttp.getSubtitle(bvid: bvid, cid: cid.value);
if (result['status']) {
if (result['data'].subtitles.isNotEmpty) {
subtitles = result['data'].subtitles;
if (subtitles.isNotEmpty) {
for (var i in subtitles) {
final Map<String, dynamic> res = await VideoHttp.getSubtitleContent(
i.subtitleUrl,
);
i.content = res['content'];
i.body = res['body'];
}
}
}
return result['data'];
}
}

// 获取字幕内容
// Future getSubtitleContent(String url) async {
// var res = await Request().get('https:$url');
// subtitleContents.value = res.data['body'].map<SubTitileContentModel>((e) {
// return SubTitileContentModel.fromJson(e);
// }).toList();
// setSubtitleContent();
// }

setSubtitleContent() {
plPlayerController.subtitleContent.value = '';
plPlayerController.subtitles.value = subtitles;
}

clearSubtitleContent() {
plPlayerController.subtitleContent.value = '';
plPlayerController.subtitles.value = [];
}

/// 发送弹幕
void showShootDanmakuSheet() {
final TextEditingController textController = TextEditingController();
Expand Down
6 changes: 5 additions & 1 deletion lib/pages/video/detail/view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
videoIntroController.isPaused = true;
plPlayerController!.removeStatusLister(playerListener);
plPlayerController!.pause();
vdCtr.clearSubtitleContent();
}
setState(() => isShowing = false);
super.didPushNext();
Expand All @@ -222,7 +223,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
void didPopNext() async {
if (plPlayerController != null &&
plPlayerController!.videoPlayerController != null) {
setState(() => isShowing = true);
setState(() {
vdCtr.setSubtitleContent();
isShowing = true;
});
}
vdCtr.isFirstTime = false;
final bool autoplay = autoPlayEnable;
Expand Down
Loading

0 comments on commit 9faa625

Please sign in to comment.