@cc-component/cc-ex-component 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,395 @@
1
+ import { VideoPlayer, Node, sys, Sprite, UITransform, Size, view, assetManager, SpriteFrame, AssetManager, Asset } from 'cc';
2
+ import { _decorator } from 'cc';
3
+ import { BaseVideo, InitParam, IVideoData, IVideoParam } from './IVideo';
4
+ import { VideoPlayWeb } from './VideoPlayWeb';
5
+ import { VideoPlayWX } from './VideoPlayWX';
6
+ import { WECHAT } from 'cc/env';
7
+ import { VideoPlayTT } from './VideoPlayTT';
8
+ const { ccclass, property } = _decorator;
9
+
10
+
11
+
12
+ export class VideoManager {
13
+ Debug: boolean = false;
14
+ static _instance: VideoManager = null!;
15
+ public static get instance(): VideoManager {
16
+ if (!VideoManager._instance) {
17
+ VideoManager._instance = new VideoManager();
18
+ }
19
+ return VideoManager._instance;
20
+ }
21
+
22
+ isPlaying: boolean;
23
+ isloop: boolean;
24
+ baseVideo: BaseVideo;
25
+ // 添加一个标志位用于控制是否停止播放
26
+ private stopRequested: boolean = false;
27
+
28
+ /** 封面图 */
29
+ cover: Sprite;
30
+ isError: boolean = false;
31
+
32
+
33
+ currentIndex = 0;
34
+ currentList: IVideoData[] = [];
35
+ node: Node;
36
+ taskId = 'mainVideoList';
37
+ param: IVideoParam = {
38
+ isLoop: false,
39
+ isLocal: false,
40
+ isPlayTime: false,
41
+ isTargetSize: false
42
+ };
43
+ paramPlay: IVideoParam = {
44
+ isLoop: false,
45
+ isPlayTime: true,
46
+ isTargetSize: false
47
+ };
48
+ paramInit: InitParam;
49
+ cur_name = "";
50
+ get isLoop() {
51
+ if (this.paramPlay.isLoop === undefined || this.paramPlay.isLoop === null) {
52
+ return true
53
+ }
54
+ return this.paramPlay.isLoop
55
+ }
56
+ get isPlayTime() {
57
+ if (this.param.isPlayTime === undefined || this.param.isPlayTime === null) {
58
+ return false
59
+ }
60
+ return this.param.isPlayTime
61
+ }
62
+ get isMinGame() {
63
+ if (WECHAT) {
64
+ return true;
65
+ }
66
+ return false;
67
+ }
68
+ remote_url = ""
69
+ initVideo(param: InitParam) {
70
+ this.paramInit = param;
71
+ this.node = param.node;
72
+ this.cover = param.cover.getComponent(Sprite);
73
+ this.cover.node.active = false;
74
+ this.node.addChild(this.cover.node);
75
+ switch (sys.platform) {
76
+ case sys.Platform.ANDROID:
77
+ this.baseVideo = this.node.addComponent(VideoPlayWeb);
78
+ break;
79
+ case sys.Platform.WECHAT_GAME:
80
+ this.baseVideo = this.node.addComponent(VideoPlayWX);
81
+ break;
82
+ case sys.Platform.BYTEDANCE_MINI_GAME:
83
+ this.baseVideo = this.node.addComponent(VideoPlayTT);
84
+ break;
85
+ default:
86
+ this.baseVideo = this.node.addComponent(VideoPlayWeb);
87
+ break;
88
+ }
89
+ this.baseVideo.initVideo({ bundle: this.paramInit.bundle, dir: param.dir });
90
+ this.baseVideo.onTimeUpdate = async (data: { position: number, duration: number }) => {
91
+ if (this.currentList.length <= 0) {
92
+ return
93
+ }
94
+ const currentName = this.currentList[this.currentIndex]
95
+ //console.log("时间:", !this.baseVideo.getisPause(),data.position , currentName.end);
96
+ if (this.isLoop) {
97
+ if (data.position >= currentName.end_time && !this.baseVideo.getisPause()) {
98
+ if (VideoManager.instance.Debug)
99
+ console.log("播放结束:", currentName, !this.baseVideo.getisPause);
100
+ await this.pause();
101
+ this.currentIndex++;
102
+ if (this.currentIndex === this.currentList.length) {
103
+ this.currentIndex = 0;
104
+ }
105
+ this.playVideoTime(this.currentList[this.currentIndex])
106
+ }
107
+
108
+ } else {
109
+ if (data.position >= currentName.end_time && !this.baseVideo.getisPause()) {
110
+ if (VideoManager.instance.Debug)
111
+ console.log("播放结束:", currentName, !this.baseVideo.getisPause);
112
+ await this.pause();
113
+ this.paramPlay?.onFinish?.()
114
+ }
115
+ }
116
+
117
+ };
118
+ this.baseVideo.onError = (err) => {
119
+ this.isError = true;
120
+ console.error("视频报错了", err)
121
+ };
122
+
123
+ this.baseVideo.onVideoEnd = () => {
124
+ if (VideoManager.instance.Debug)
125
+ console.warn("视频播放完成")
126
+ const taskId = 'mainVideoList';
127
+ if (this.playTasks.has(taskId)) {
128
+ const task = this.playTasks.get(taskId);
129
+ if (task && task.finishPlayResolve) {
130
+ task.finishPlayResolve();
131
+ // 调用后清空引用
132
+ // task.finishPlayResolve = null;
133
+ }
134
+ }
135
+ if (this.paramPlay?.onFinish) {
136
+ this.paramPlay.onFinish();
137
+ if (this.paramPlay.isLoop)
138
+ this.paramPlay.onFinish = undefined;
139
+ }
140
+ };
141
+ this.baseVideo.onRead = () => {
142
+ if (VideoManager.instance.Debug)
143
+ console.log("视频准备好了")
144
+ this.cover.node.active = false
145
+ if (this.param.isLocal) {
146
+ //this.play()
147
+ //console.log("开始播放")
148
+ this.param?.onRead?.()
149
+ }
150
+ else if (this.param.isPlayTime) {
151
+ this.pause()
152
+ this.param?.onRead?.()
153
+ }
154
+ else {
155
+ this.pause()
156
+ this.param?.onRead?.()
157
+ }
158
+ };
159
+
160
+ this.autoSize()
161
+
162
+ }
163
+ // 在类中添加属性(您已经添加了)
164
+ coount = 0
165
+ // 修改 playTasks 的类型定义,增加 finishPlayResolve 字段
166
+ private playTasks: Map<string, { count: number, stop: () => void, finishPlayResolve: (() => void) | null }> = new Map();
167
+
168
+ // 在 playVideoList 方法中更新存储逻辑
169
+ loadVideo(name: string, param: IVideoParam): void {
170
+ name = param.isLocal ? name : `${this.remote_url}${name}.mp4`
171
+ if (VideoManager.instance.Debug)
172
+ console.log("加载视频:", name);
173
+ this.param = param;
174
+ this.cover.spriteFrame = assetManager.getBundle(this.paramInit.bundle)?.get(`${this.paramInit.cover_dir}/${param.coverImage}/spriteFrame`)
175
+ this.cover.node.active = this.cur_name === name ? false : true;
176
+ this.seek(0)
177
+ this.baseVideo.loadVideo(name, param)
178
+ this.cur_name = name;
179
+ }
180
+
181
+ private play(): void {
182
+ this.baseVideo.play()
183
+ }
184
+
185
+ setSize(param: { x: number, y: number, width: number, height: number }) {
186
+ this.baseVideo.setSize(param)
187
+ }
188
+ // 节点位置适配
189
+ autoSize() {
190
+ this.baseVideo.autoSize()
191
+ }
192
+
193
+
194
+ async pause() {
195
+ await this.baseVideo.pause()
196
+ }
197
+ stop(): void {
198
+ }
199
+ resume(): void {
200
+ }
201
+ seek(time: number): void {
202
+ this.baseVideo.seek(time)
203
+ }
204
+
205
+ /**播放单个视频 */
206
+ playVideo(param?: IVideoParam): void {
207
+ this.paramPlay = param
208
+ this.baseVideo.play(param?.isLoop)
209
+ }
210
+
211
+ playVideoOne(name: string, param: IVideoParam) {
212
+ // if (VideoManager.instance.Debug)
213
+ // console.log('加载视频', name)
214
+ const isloop = false
215
+ param.onRead = () => {
216
+ console.warn('当前播放', name)
217
+ this.playVideo(param)
218
+ }
219
+ this.loadVideo(name, param)
220
+ }
221
+
222
+ private playVideoTime(name: IVideoData): void {
223
+ if (VideoManager.instance.Debug)
224
+ console.warn('当前播放', name.start_time, name.end_time)
225
+
226
+ this.baseVideo.seek(name.start_time)
227
+ this.baseVideo.play()
228
+ }
229
+
230
+ //#region 新方案
231
+ async playVideoList(list: IVideoData[], param: IVideoParam) {
232
+ this.paramPlay = param
233
+
234
+
235
+ // 如果存在正在播放的任务,先停止它
236
+ const taskId = this.taskId
237
+ this.stopTask(taskId)
238
+ //新任务延迟1帧
239
+ setTimeout(async () => {
240
+ this.currentList = list;
241
+ this.currentIndex = 0
242
+ if (VideoManager.instance.Debug)
243
+ console.log("当前播放列表", JSON.stringify(list))
244
+ this.coount++;
245
+ // 重置状态
246
+ this.stopRequested = false;
247
+ this.isError = false;
248
+ // 创建停止函数
249
+ let isStopped = false;
250
+ const stopFunction = () => {
251
+ isStopped = true;
252
+ this.stopRequested = true;
253
+ if (this.baseVideo) {
254
+ //this.baseVideo.pause();
255
+ }
256
+ };
257
+ if (VideoManager.instance.Debug)
258
+ console.log("开始任务", this.coount)
259
+ // 将停止函数和 finishPlayResolve 存储到Map中
260
+ this.playTasks.set(taskId, { count: this.coount, stop: stopFunction, finishPlayResolve: null });
261
+ const oldTask = this.playTasks.get(taskId);
262
+ // 调用原始的播放逻辑
263
+ await this._playVideoList(list, param, taskId);
264
+ // 清理任务
265
+ if (VideoManager.instance.Debug)
266
+ console.log('任务已结束', oldTask?.count);
267
+ if (!param.isLoop)
268
+ param.onFinish?.()
269
+ //this.playTasks.delete(taskId);
270
+ });
271
+ }
272
+
273
+ stopTask(taskId: string) {
274
+ if (this.playTasks.has(taskId)) {
275
+ let oldTask: any = this.playTasks.get(taskId);
276
+ if (oldTask) {
277
+ // 调用之前存储的 finishPlayResolve 来中断等待
278
+ if (oldTask.finishPlayResolve) {
279
+ oldTask.finishPlayResolve();
280
+ }
281
+ oldTask.stop();
282
+ }
283
+ this.playTasks.delete(taskId);
284
+ }
285
+
286
+ }
287
+ // 在 _playVideoList 方法中更新 finishPlayResolve 的存储
288
+ async _playVideoList(list: IVideoData[], param: IVideoParam, taskId: string) {
289
+ // this.cover.node.active = true
290
+ for (let index = 0; index < list.length; index++) {
291
+ // 检查是否需要停止
292
+ if (this.stopRequested) {
293
+ if (VideoManager.instance.Debug)
294
+ console.log("播放被停止");
295
+ break;
296
+ }
297
+ if (this.isError) { break; }
298
+ const name = list[index];
299
+ if (this.isPlayTime) {
300
+ this.playVideoTime(name)
301
+ } else {
302
+ this.playVideoOne(name.name, param)
303
+ }
304
+
305
+ // 更新 playTasks 中的 finishPlayResolve
306
+ await new Promise<void>((resolve, reject) => {
307
+ // 更新Map中的 finishPlayResolve 引用
308
+ if (this.playTasks.has(taskId)) {
309
+ const task = this.playTasks.get(taskId);
310
+ if (task) {
311
+ task.finishPlayResolve = resolve;
312
+ }
313
+ }
314
+ })
315
+
316
+ if (this.isError) { break; }
317
+ if (VideoManager.instance.Debug)
318
+ console.warn('停止', this.stopRequested)
319
+ if (this.stopRequested) {
320
+ break;
321
+ }
322
+ }
323
+ if (VideoManager.instance.Debug)
324
+ console.log('播放结束')
325
+ if (param.isLoop) {
326
+ // 同样检查停止请求
327
+ if (!this.stopRequested) {
328
+ this._playVideoList(list, param, taskId)
329
+ }
330
+ }
331
+ }
332
+
333
+
334
+ // 增加停止播放列表的方法
335
+ public stopVideoList() {
336
+ this.stopRequested = true;
337
+ this.stopTask(this.taskId)
338
+ this.baseVideo.destroyVideo()
339
+ }
340
+
341
+ async loadBundle(bundleName) {
342
+ let bundle = assetManager.getBundle(bundleName);
343
+ if (!bundle) {
344
+ bundle = await new Promise<AssetManager.Bundle>(resolve => {
345
+ assetManager.loadBundle(bundleName, (err, bundle) => {
346
+ if (err) {
347
+
348
+ console.error("没有bundle", bundleName, err)
349
+ return
350
+ } else {
351
+ resolve(bundle)
352
+ }
353
+ });
354
+ })
355
+ }
356
+ }
357
+ // 在 VideoManager 类中添加以下方法
358
+ /**加载视频 */
359
+ preLoadVideo(bundleName: string, dirs: string[], pro: (pro: number) => void) {
360
+ return new Promise<void>(async (resolve, reject) => {
361
+ let bundle = assetManager.getBundle(bundleName);
362
+ if (!bundle) {
363
+ bundle = await new Promise<AssetManager.Bundle>(resolve => {
364
+ assetManager.loadBundle(bundleName, (err, bundle) => {
365
+ if (err) {
366
+ reject(err);
367
+ } else {
368
+ resolve(bundle)
369
+ }
370
+ });
371
+ })
372
+ }
373
+ let pro_num = 0
374
+
375
+ for (let index = 0; index < dirs.length; index++) {
376
+ const dir = dirs[index];
377
+ await new Promise<void>(resolve => {
378
+ bundle.loadDir(dir, (fin, total) => {
379
+ const value = fin / total * 100;
380
+ pro?.(Math.floor(value));
381
+ }, (err, assets) => {
382
+ resolve()
383
+ })
384
+ })
385
+ // let pro_add = (index + 1) / dirs.length
386
+ // pro_num = pro_add * 100
387
+ // pro?.(index);
388
+ }
389
+ resolve()
390
+ })
391
+ }
392
+ }
393
+
394
+
395
+
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.24",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "a987e3ef-276e-48bf-ac02-62b00f26afc6",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
@@ -0,0 +1,114 @@
1
+ import { _decorator, assetManager, Component, Node, randomRangeInt } from 'cc';
2
+ import { VideoManager } from './VideoManager';
3
+ import { InitParam, IVideoData, IVideoParam } from './IVideo';
4
+ import { BYTEDANCE, WECHAT } from 'cc/env';
5
+ const { ccclass, property } = _decorator;
6
+
7
+
8
+ export class VideoModule {
9
+ static _instance: VideoModule = null;
10
+ static get instance(): VideoModule {
11
+ if (!this._instance) {
12
+ this._instance = new VideoModule();
13
+ }
14
+ return this._instance;
15
+ }
16
+
17
+ get isMinGame() {
18
+ if (WECHAT || BYTEDANCE) {
19
+ return true
20
+ }
21
+ return false;
22
+ }
23
+ /**视频地址 */
24
+ remote_url = "https://hcy-cdn-domestic.wyx.cn/online/comeback/";
25
+ static async initVideo(param: InitParam) {
26
+ // if (BYTEDANCE) {
27
+ // param.bg.active = true;
28
+ // this.remote_url += "video_dy/"
29
+ // }
30
+ // else if (WECHAT) {
31
+ // param.bg.active = false;
32
+ // this.remote_url += "video_dy/"
33
+ // }
34
+ // else {
35
+ // param.bg.active = false;
36
+ // this.remote_url += "video/"
37
+ // await VideoManager.instance.loadBundle(param.bundle)
38
+ // }
39
+ VideoManager.instance.remote_url = param.remote_url
40
+ VideoManager.instance.initVideo(param)
41
+ console.log("视频初始化完成")
42
+ }
43
+
44
+ static Debug(enabled: boolean) { VideoManager.instance.Debug = enabled }
45
+ /**视频设置到指定大小 */
46
+ static SetSize(param: { x: number, y: number, width: number, height: number }) { VideoManager.instance.setSize(param) }
47
+ /**节点位置适配-自动适配 */
48
+ static AutoSize() { VideoManager.instance.autoSize() }
49
+ /**暂停 */
50
+ static async Pause() { return await VideoManager.instance.pause() }
51
+ /**继续 */
52
+ static async Resume() { return await VideoManager.instance.resume() }
53
+ /**停止视频 */
54
+ static StopVideoTask() { VideoManager.instance.stopVideoList() }
55
+
56
+ /**提前加载视频 */
57
+ static LoadVideo(url: string, param: IVideoParam) {
58
+ VideoManager.instance.stopVideoList()
59
+ param.isLocal = !url.includes("http")
60
+ VideoManager.instance.loadVideo(url, param)
61
+ }
62
+
63
+ /**播放单个视频 */
64
+ static PlayVideo(video: IVideoData, param: IVideoParam) {
65
+ VideoManager.instance.stopVideoList()
66
+ param.isLocal = !video.name.includes("http")
67
+ param.onRead = () => { VideoManager.instance.playVideo(param) }
68
+ VideoManager.instance.loadVideo(video.name, param)
69
+ }
70
+
71
+ /** 播放多个视频*/
72
+ static PlayVideoMore(video_list: IVideoData[], param: IVideoParam) {
73
+ const url = video_list[0].name
74
+ param.isLocal = !url.includes("http")
75
+ if (param.isPlayTime) {
76
+ param.onRead = () => {
77
+ VideoManager.instance.playVideoList(video_list, param)
78
+ }
79
+ VideoManager.instance.loadVideo(url, param)
80
+ } else {
81
+ VideoManager.instance.playVideoList(video_list, param)
82
+ }
83
+ }
84
+
85
+
86
+
87
+ //#region 本地视频
88
+ /**播放单个视频 -本地视频 */
89
+ // public play(url: string, param: IVideoParam) {
90
+ // VideoManager.instance.loadVideo(url, {
91
+ // isLoop: param.isLoop, isFullNot: param.isFullNot, isLocal: param.isLocal, isPlayTime: param.isPlayTime, coverImage: param.coverImage, onRead: () => {
92
+ // VideoManager.instance.playVideo({
93
+ // isLoop: param.isLoop,
94
+ // finish: param.onRead
95
+ // })
96
+ // }
97
+ // })
98
+ // }
99
+
100
+
101
+ // //#region 网络视频
102
+ // /**播放单个视频 --- */
103
+ // public playRemote(url: string, param: { isloop: boolean, coverImage: string, finish: Function }) {
104
+ // VideoManager.instance.loadVideo(url, {
105
+ // isLoop: param.isloop, isLocal: false, isPlayTime: false, coverImage: param.coverImage, onRead: () => {
106
+ // VideoManager.instance.playVideo({
107
+ // isLoop: param.isloop,
108
+ // finish: param.finish
109
+ // })
110
+ // }
111
+ // })
112
+ // }
113
+ }
114
+ window.VideoModule = VideoModule;
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.24",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "4f113e31-c657-4961-b12c-754c5d4bdb56",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }