@midscene/visualizer 1.0.1-beta-20251029093754.0 → 1.0.1-beta-20251103074550.0
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.
|
@@ -6,7 +6,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
|
|
|
6
6
|
import "./index.css";
|
|
7
7
|
import { mouseLoading, mousePointer } from "../../utils/index.mjs";
|
|
8
8
|
import { CaretRightOutlined, DownloadOutlined, ExportOutlined, LoadingOutlined } from "@ant-design/icons";
|
|
9
|
-
import { Dropdown, Spin, Switch, Tooltip } from "antd";
|
|
9
|
+
import { Dropdown, Spin, Switch, Tooltip, message } from "antd";
|
|
10
10
|
import global_perspective from "../../icons/global-perspective.mjs";
|
|
11
11
|
import player_setting from "../../icons/player-setting.mjs";
|
|
12
12
|
import show_marker from "../../icons/show-marker.mjs";
|
|
@@ -83,17 +83,32 @@ class RecordingSession {
|
|
|
83
83
|
mediaRecorder.ondataavailable = (event)=>{
|
|
84
84
|
if (event.data.size > 0) this.chunks.push(event.data);
|
|
85
85
|
};
|
|
86
|
+
mediaRecorder.onerror = (event)=>{
|
|
87
|
+
console.error('MediaRecorder error:', event);
|
|
88
|
+
message.error('Video recording failed. Please try again.');
|
|
89
|
+
this.recording = false;
|
|
90
|
+
this.mediaRecorder = null;
|
|
91
|
+
};
|
|
86
92
|
this.mediaRecorder = mediaRecorder;
|
|
87
93
|
this.recording = true;
|
|
88
94
|
return this.mediaRecorder.start();
|
|
89
95
|
}
|
|
90
96
|
stop() {
|
|
91
|
-
var _this_mediaRecorder;
|
|
92
97
|
if (!this.recording || !this.mediaRecorder) return void console.warn('not recording');
|
|
93
98
|
this.mediaRecorder.onstop = ()=>{
|
|
99
|
+
if (0 === this.chunks.length) {
|
|
100
|
+
console.error('No video data captured');
|
|
101
|
+
message.error('Video export failed: No data captured.');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
94
104
|
const blob = new Blob(this.chunks, {
|
|
95
105
|
type: 'video/webm'
|
|
96
106
|
});
|
|
107
|
+
if (0 === blob.size) {
|
|
108
|
+
console.error('Video blob is empty');
|
|
109
|
+
message.error('Video export failed: Empty file.');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
97
112
|
const url = URL.createObjectURL(blob);
|
|
98
113
|
const a = document.createElement('a');
|
|
99
114
|
a.href = url;
|
|
@@ -101,7 +116,7 @@ class RecordingSession {
|
|
|
101
116
|
a.click();
|
|
102
117
|
URL.revokeObjectURL(url);
|
|
103
118
|
};
|
|
104
|
-
|
|
119
|
+
this.mediaRecorder.stop();
|
|
105
120
|
this.recording = false;
|
|
106
121
|
this.mediaRecorder = null;
|
|
107
122
|
}
|
|
@@ -453,9 +468,15 @@ function Player(props) {
|
|
|
453
468
|
};
|
|
454
469
|
const [isRecording, setIsRecording] = useState(false);
|
|
455
470
|
const recorderSessionRef = useRef(null);
|
|
456
|
-
const
|
|
471
|
+
const cancelAnimationRef = useRef(null);
|
|
472
|
+
const handleExport = async ()=>{
|
|
457
473
|
if (recorderSessionRef.current) return void console.warn('recorderSession exists');
|
|
458
474
|
if (!app.canvas) return void console.warn('canvas is not initialized');
|
|
475
|
+
if (cancelAnimationRef.current) {
|
|
476
|
+
cancelAnimationRef.current();
|
|
477
|
+
cancelAnimationRef.current = null;
|
|
478
|
+
await new Promise((resolve)=>setTimeout(resolve, 100));
|
|
479
|
+
}
|
|
459
480
|
recorderSessionRef.current = new RecordingSession(app.canvas);
|
|
460
481
|
setIsRecording(true);
|
|
461
482
|
triggerReplay();
|
|
@@ -467,6 +488,7 @@ function Player(props) {
|
|
|
467
488
|
if (!scripts) throw new Error("scripts is required");
|
|
468
489
|
const { frame, cancel, timeout } = frameKit();
|
|
469
490
|
cancelFn = cancel;
|
|
491
|
+
cancelAnimationRef.current = cancel;
|
|
470
492
|
const allImages = scripts.filter((item)=>!!item.img).map((item)=>item.img);
|
|
471
493
|
await Promise.all([
|
|
472
494
|
...allImages,
|
|
@@ -535,9 +557,20 @@ function Player(props) {
|
|
|
535
557
|
}
|
|
536
558
|
})().catch((e)=>{
|
|
537
559
|
console.error('player error', e);
|
|
560
|
+
if (recorderSessionRef.current) {
|
|
561
|
+
try {
|
|
562
|
+
recorderSessionRef.current.stop();
|
|
563
|
+
} catch (stopError) {
|
|
564
|
+
console.error('Error stopping recorder:', stopError);
|
|
565
|
+
}
|
|
566
|
+
recorderSessionRef.current = null;
|
|
567
|
+
}
|
|
568
|
+
setIsRecording(false);
|
|
569
|
+
message.error('Failed to export video. Please try again.');
|
|
538
570
|
}));
|
|
539
571
|
return ()=>{
|
|
540
572
|
null == cancelFn || cancelFn();
|
|
573
|
+
cancelAnimationRef.current = null;
|
|
541
574
|
};
|
|
542
575
|
};
|
|
543
576
|
useEffect(()=>{
|
|
@@ -123,17 +123,32 @@ class RecordingSession {
|
|
|
123
123
|
mediaRecorder.ondataavailable = (event)=>{
|
|
124
124
|
if (event.data.size > 0) this.chunks.push(event.data);
|
|
125
125
|
};
|
|
126
|
+
mediaRecorder.onerror = (event)=>{
|
|
127
|
+
console.error('MediaRecorder error:', event);
|
|
128
|
+
external_antd_namespaceObject.message.error('Video recording failed. Please try again.');
|
|
129
|
+
this.recording = false;
|
|
130
|
+
this.mediaRecorder = null;
|
|
131
|
+
};
|
|
126
132
|
this.mediaRecorder = mediaRecorder;
|
|
127
133
|
this.recording = true;
|
|
128
134
|
return this.mediaRecorder.start();
|
|
129
135
|
}
|
|
130
136
|
stop() {
|
|
131
|
-
var _this_mediaRecorder;
|
|
132
137
|
if (!this.recording || !this.mediaRecorder) return void console.warn('not recording');
|
|
133
138
|
this.mediaRecorder.onstop = ()=>{
|
|
139
|
+
if (0 === this.chunks.length) {
|
|
140
|
+
console.error('No video data captured');
|
|
141
|
+
external_antd_namespaceObject.message.error('Video export failed: No data captured.');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
134
144
|
const blob = new Blob(this.chunks, {
|
|
135
145
|
type: 'video/webm'
|
|
136
146
|
});
|
|
147
|
+
if (0 === blob.size) {
|
|
148
|
+
console.error('Video blob is empty');
|
|
149
|
+
external_antd_namespaceObject.message.error('Video export failed: Empty file.');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
137
152
|
const url = URL.createObjectURL(blob);
|
|
138
153
|
const a = document.createElement('a');
|
|
139
154
|
a.href = url;
|
|
@@ -141,7 +156,7 @@ class RecordingSession {
|
|
|
141
156
|
a.click();
|
|
142
157
|
URL.revokeObjectURL(url);
|
|
143
158
|
};
|
|
144
|
-
|
|
159
|
+
this.mediaRecorder.stop();
|
|
145
160
|
this.recording = false;
|
|
146
161
|
this.mediaRecorder = null;
|
|
147
162
|
}
|
|
@@ -493,9 +508,15 @@ function Player(props) {
|
|
|
493
508
|
};
|
|
494
509
|
const [isRecording, setIsRecording] = (0, external_react_namespaceObject.useState)(false);
|
|
495
510
|
const recorderSessionRef = (0, external_react_namespaceObject.useRef)(null);
|
|
496
|
-
const
|
|
511
|
+
const cancelAnimationRef = (0, external_react_namespaceObject.useRef)(null);
|
|
512
|
+
const handleExport = async ()=>{
|
|
497
513
|
if (recorderSessionRef.current) return void console.warn('recorderSession exists');
|
|
498
514
|
if (!app.canvas) return void console.warn('canvas is not initialized');
|
|
515
|
+
if (cancelAnimationRef.current) {
|
|
516
|
+
cancelAnimationRef.current();
|
|
517
|
+
cancelAnimationRef.current = null;
|
|
518
|
+
await new Promise((resolve)=>setTimeout(resolve, 100));
|
|
519
|
+
}
|
|
499
520
|
recorderSessionRef.current = new RecordingSession(app.canvas);
|
|
500
521
|
setIsRecording(true);
|
|
501
522
|
triggerReplay();
|
|
@@ -507,6 +528,7 @@ function Player(props) {
|
|
|
507
528
|
if (!scripts) throw new Error("scripts is required");
|
|
508
529
|
const { frame, cancel, timeout } = frameKit();
|
|
509
530
|
cancelFn = cancel;
|
|
531
|
+
cancelAnimationRef.current = cancel;
|
|
510
532
|
const allImages = scripts.filter((item)=>!!item.img).map((item)=>item.img);
|
|
511
533
|
await Promise.all([
|
|
512
534
|
...allImages,
|
|
@@ -575,9 +597,20 @@ function Player(props) {
|
|
|
575
597
|
}
|
|
576
598
|
})().catch((e)=>{
|
|
577
599
|
console.error('player error', e);
|
|
600
|
+
if (recorderSessionRef.current) {
|
|
601
|
+
try {
|
|
602
|
+
recorderSessionRef.current.stop();
|
|
603
|
+
} catch (stopError) {
|
|
604
|
+
console.error('Error stopping recorder:', stopError);
|
|
605
|
+
}
|
|
606
|
+
recorderSessionRef.current = null;
|
|
607
|
+
}
|
|
608
|
+
setIsRecording(false);
|
|
609
|
+
external_antd_namespaceObject.message.error('Failed to export video. Please try again.');
|
|
578
610
|
}));
|
|
579
611
|
return ()=>{
|
|
580
612
|
null == cancelFn || cancelFn();
|
|
613
|
+
cancelAnimationRef.current = null;
|
|
581
614
|
};
|
|
582
615
|
};
|
|
583
616
|
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
@@ -8,7 +8,7 @@ export declare function usePlaygroundState(playgroundSDK: PlaygroundSDKLike | nu
|
|
|
8
8
|
setLoading: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
9
9
|
infoList: InfoListItem[];
|
|
10
10
|
setInfoList: import("react").Dispatch<import("react").SetStateAction<InfoListItem[]>>;
|
|
11
|
-
actionSpace: DeviceAction<unknown>[];
|
|
11
|
+
actionSpace: DeviceAction<unknown, any>[];
|
|
12
12
|
actionSpaceLoading: boolean;
|
|
13
13
|
uiContextPreview: UIContext | undefined;
|
|
14
14
|
setUiContextPreview: import("react").Dispatch<import("react").SetStateAction<UIContext | undefined>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midscene/visualizer",
|
|
3
|
-
"version": "1.0.1-beta-
|
|
3
|
+
"version": "1.0.1-beta-20251103074550.0",
|
|
4
4
|
"repository": "https://github.com/web-infra-dev/midscene",
|
|
5
5
|
"homepage": "https://midscenejs.com/",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"antd": "^5.21.6",
|
|
61
61
|
"buffer": "6.0.3",
|
|
62
62
|
"dayjs": "^1.11.11",
|
|
63
|
-
"@midscene/core": "1.0.1-beta-
|
|
64
|
-
"@midscene/
|
|
65
|
-
"@midscene/
|
|
66
|
-
"@midscene/
|
|
63
|
+
"@midscene/core": "1.0.1-beta-20251103074550.0",
|
|
64
|
+
"@midscene/playground": "1.0.1-beta-20251103074550.0",
|
|
65
|
+
"@midscene/shared": "1.0.1-beta-20251103074550.0",
|
|
66
|
+
"@midscene/web": "1.0.1-beta-20251103074550.0"
|
|
67
67
|
},
|
|
68
68
|
"license": "MIT",
|
|
69
69
|
"scripts": {
|