easyproctor 0.0.7 → 0.0.11
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.
- package/README.md +64 -0
- package/esm/index.js +200 -14
- package/index.d.ts +4 -1
- package/index.js +203 -32
- package/modules/database.d.ts +6 -0
- package/modules/recorder.d.ts +1 -0
- package/modules/startCameraCapture.d.ts +1 -1
- package/modules/startScreenCapture.d.ts +1 -1
- package/package.json +9 -5
- package/test.js +252 -0
- package/unpkg/easyproctor.min.js +1 -1
package/README.md
CHANGED
|
@@ -32,6 +32,70 @@ Via CDN: A função "useProctoring" é injetada para ser utilizada globalmente
|
|
|
32
32
|
</script>
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
## Exemplo completo
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<!DOCTYPE html>
|
|
39
|
+
<html lang="en">
|
|
40
|
+
|
|
41
|
+
<head>
|
|
42
|
+
<meta charset="UTF-8">
|
|
43
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
44
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
45
|
+
<title>Document</title>
|
|
46
|
+
<script src="https://cdn.jsdelivr.net/npm/easyproctor/unpkg/easyproctor.min.js"></script>
|
|
47
|
+
<script>
|
|
48
|
+
|
|
49
|
+
const { start, pause, resume, finish, download } = useProctoring("125-125125-12512512-1251");
|
|
50
|
+
|
|
51
|
+
async function startExam() {
|
|
52
|
+
try {
|
|
53
|
+
await start();
|
|
54
|
+
console.log("EXAME INICIADO");
|
|
55
|
+
} catch (error) {
|
|
56
|
+
alert(error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function pauseExam() {
|
|
61
|
+
try {
|
|
62
|
+
await pause();
|
|
63
|
+
console.log("EXAME PAUSADO");
|
|
64
|
+
} catch (error) {
|
|
65
|
+
alert(error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function resumeExam() {
|
|
70
|
+
try {
|
|
71
|
+
await resume();
|
|
72
|
+
console.log("EXAME REINICIADO");
|
|
73
|
+
} catch (error) {
|
|
74
|
+
alert(error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function finishExam() {
|
|
79
|
+
const [cameraFile, screenFile] = await finish();
|
|
80
|
+
download(cameraFile);
|
|
81
|
+
download(screenFile);
|
|
82
|
+
console.log("EXAME FINALIZADO");
|
|
83
|
+
}
|
|
84
|
+
</script>
|
|
85
|
+
</head>
|
|
86
|
+
|
|
87
|
+
<body>
|
|
88
|
+
<div style="height: 100vh; display: flex; align-items: center; justify-content: center;">
|
|
89
|
+
<button onclick="startExam()">Iniciar</button>
|
|
90
|
+
<button onclick="pauseExam()">Pausar</button>
|
|
91
|
+
<button onclick="resumeExam()">Continuar</button>
|
|
92
|
+
<button onclick="finishExam()">Finalizar</button>
|
|
93
|
+
</div>
|
|
94
|
+
</body>
|
|
95
|
+
|
|
96
|
+
</html>
|
|
97
|
+
```
|
|
98
|
+
|
|
35
99
|
## API
|
|
36
100
|
```javascript
|
|
37
101
|
const {
|
package/esm/index.js
CHANGED
|
@@ -1,24 +1,210 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// src/modules/database.ts
|
|
2
|
+
var databaseName = "EasyProctorPlugin";
|
|
3
|
+
var databaseVersion = 1;
|
|
4
|
+
function initializeDatabase(table) {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const request = indexedDB.open(databaseName, databaseVersion);
|
|
7
|
+
request.onupgradeneeded = () => {
|
|
8
|
+
request.result.createObjectStore("cameraBuffers", { keyPath: "id", autoIncrement: true });
|
|
9
|
+
request.result.createObjectStore("screenBuffers", { keyPath: "id", autoIncrement: true });
|
|
10
|
+
};
|
|
11
|
+
request.onerror = (e) => {
|
|
12
|
+
console.log(e);
|
|
13
|
+
reject("N\xE3o foi poss\xEDvel inicializar a biblioteca, por favor, entre em contato com o suporte e informe o erro acima");
|
|
14
|
+
};
|
|
15
|
+
request.onsuccess = () => {
|
|
16
|
+
const db = request.result;
|
|
17
|
+
const tableRef = db.transaction(table, "readwrite");
|
|
18
|
+
const store = tableRef.objectStore(table);
|
|
19
|
+
resolve(store);
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async function insertBuffer(table, buffer) {
|
|
24
|
+
const store = await initializeDatabase(table);
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const request = store.add({ data: buffer });
|
|
27
|
+
request.onsuccess = () => resolve();
|
|
28
|
+
request.onerror = (e) => reject(e);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async function getBuffers(table) {
|
|
32
|
+
const store = await initializeDatabase(table);
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
const request = store.getAll();
|
|
35
|
+
request.onsuccess = () => {
|
|
36
|
+
const data = request.result;
|
|
37
|
+
const blobs = data.reduce((acc, el) => [...acc, ...el.data], []);
|
|
38
|
+
resolve(blobs);
|
|
39
|
+
};
|
|
40
|
+
request.onerror = (e) => reject(e);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function clearBuffers(table) {
|
|
44
|
+
const store = await initializeDatabase(table);
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const request = store.clear();
|
|
47
|
+
request.onsuccess = () => resolve();
|
|
48
|
+
request.onerror = (e) => reject(e);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/modules/recorder.ts
|
|
53
|
+
function recorder(stream, buffer) {
|
|
54
|
+
let resolvePromise;
|
|
55
|
+
const options = {
|
|
56
|
+
mimeType: "video/webm; codecs=vp9",
|
|
57
|
+
videoBitsPerSecond: 128e3,
|
|
58
|
+
audioBitsPerSecond: 64 * 1e3
|
|
59
|
+
};
|
|
60
|
+
const mediaRecorder = new MediaRecorder(stream, options);
|
|
61
|
+
mediaRecorder.ondataavailable = (e) => {
|
|
62
|
+
if (e.data.size > 0) {
|
|
63
|
+
buffer.push(e.data);
|
|
64
|
+
}
|
|
65
|
+
resolvePromise && resolvePromise();
|
|
5
66
|
};
|
|
6
|
-
|
|
67
|
+
mediaRecorder.start();
|
|
68
|
+
function stopRecording() {
|
|
7
69
|
return new Promise((resolve) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
70
|
+
resolvePromise = resolve;
|
|
71
|
+
mediaRecorder.stop();
|
|
72
|
+
stream.getTracks().forEach((el) => {
|
|
73
|
+
el.stop();
|
|
74
|
+
});
|
|
11
75
|
});
|
|
76
|
+
}
|
|
77
|
+
return stopRecording;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/modules/startCameraCapture.ts
|
|
81
|
+
async function startCameraCapture(buffer) {
|
|
82
|
+
const constraints = {
|
|
83
|
+
audio: true,
|
|
84
|
+
video: {
|
|
85
|
+
width: { max: 1280, ideal: 640 },
|
|
86
|
+
height: { max: 720, ideal: 480 },
|
|
87
|
+
frameRate: 15
|
|
88
|
+
}
|
|
12
89
|
};
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
90
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
91
|
+
const stopRecording = recorder(stream, buffer);
|
|
92
|
+
return stopRecording;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/modules/startScreenCapture.ts
|
|
96
|
+
async function startScreenCapture(buffer) {
|
|
97
|
+
const displayMediaStreamConstraints = {
|
|
98
|
+
video: {
|
|
99
|
+
cursor: "always"
|
|
100
|
+
},
|
|
101
|
+
audio: false
|
|
18
102
|
};
|
|
103
|
+
const stream = await navigator.mediaDevices.getDisplayMedia(displayMediaStreamConstraints);
|
|
104
|
+
const stopRecording = recorder(stream, buffer);
|
|
105
|
+
return stopRecording;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/index.ts
|
|
109
|
+
function useProctoring(key) {
|
|
110
|
+
if (!navigator.mediaDevices.getDisplayMedia) {
|
|
111
|
+
throw "Voc\xEA est\xE1 utilizando uma vers\xE3o muito antiga do navegador, por favor, atualize a vers\xE3o";
|
|
112
|
+
}
|
|
113
|
+
if (!window.indexedDB) {
|
|
114
|
+
throw "Voc\xEA est\xE1 usando uma vers\xE3o muito antiga do navegador, n\xE3o \xE9 poss\xEDvel relizar a requisi\xE7\xE3o";
|
|
115
|
+
}
|
|
116
|
+
function download(file) {
|
|
117
|
+
const url = URL.createObjectURL(file);
|
|
118
|
+
const a = document.createElement("a");
|
|
119
|
+
document.body.appendChild(a);
|
|
120
|
+
a.style.display = "none";
|
|
121
|
+
a.href = url;
|
|
122
|
+
a.download = file.name;
|
|
123
|
+
a.click();
|
|
124
|
+
window.URL.revokeObjectURL(url);
|
|
125
|
+
}
|
|
126
|
+
let cameraBuffer = [];
|
|
127
|
+
let screenBuffer = [];
|
|
128
|
+
let cancelCallback = null;
|
|
129
|
+
async function _startCapture() {
|
|
130
|
+
if (!document.body) {
|
|
131
|
+
throw "A execu\xE7\xE3o do script deve ser feita por algum elemento dentro do <body> da p\xE1gina html";
|
|
132
|
+
}
|
|
133
|
+
if (cancelCallback != null) {
|
|
134
|
+
throw "Uma grava\xE7\xE3o ja est\xE1 em andamento";
|
|
135
|
+
}
|
|
136
|
+
let cancelCameraCapture = null;
|
|
137
|
+
let cancelScreenCapture = null;
|
|
138
|
+
try {
|
|
139
|
+
cancelScreenCapture = await startScreenCapture(screenBuffer);
|
|
140
|
+
cancelCameraCapture = await startCameraCapture(cameraBuffer);
|
|
141
|
+
cancelCallback = async function() {
|
|
142
|
+
await Promise.all([cancelCameraCapture(), cancelScreenCapture()]);
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
cancelCallback = null;
|
|
146
|
+
cancelScreenCapture && await cancelScreenCapture();
|
|
147
|
+
cancelCameraCapture && await cancelCameraCapture();
|
|
148
|
+
cameraBuffer = [];
|
|
149
|
+
screenBuffer = [];
|
|
150
|
+
throw "N\xE3o foi poss\xEDvel iniciar a captura, por favor, verifique as permiss\xF5es de camera e microfone";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function start(options = { override: false }) {
|
|
154
|
+
const { override } = options;
|
|
155
|
+
if (override) {
|
|
156
|
+
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
157
|
+
} else {
|
|
158
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
159
|
+
if (storedCameraBuffers.length > 0 || storedScreenBuffers.length > 0) {
|
|
160
|
+
throw "Existe uma grava\xE7\xE3o iniciada, por favor, execute o m\xE9todo resume() para retomar, ou utilize o parametro start({ override: true }) para limpar os dados";
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
await _startCapture();
|
|
164
|
+
}
|
|
165
|
+
async function finish() {
|
|
166
|
+
if (cancelCallback) {
|
|
167
|
+
await cancelCallback();
|
|
168
|
+
}
|
|
169
|
+
const time = new Date().toISOString();
|
|
170
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
171
|
+
const finalCameraBuffer = [...storedCameraBuffers, ...cameraBuffer];
|
|
172
|
+
const finalScreenBuffer = [...storedScreenBuffers, ...screenBuffer];
|
|
173
|
+
if (finalCameraBuffer.length == 0 || finalScreenBuffer.length == 0) {
|
|
174
|
+
throw "N\xE3o existe nenhuma grava\xE7\xE3o iniciada";
|
|
175
|
+
}
|
|
176
|
+
const cameraFile = new File(finalCameraBuffer, `${time}-camera.webm`, { type: "video/webm" });
|
|
177
|
+
const screenFile = new File(finalScreenBuffer, `${time}-screen.webm`, { type: "video/webm" });
|
|
178
|
+
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
179
|
+
cameraBuffer = [];
|
|
180
|
+
screenBuffer = [];
|
|
181
|
+
cancelCallback = null;
|
|
182
|
+
return [cameraFile, screenFile];
|
|
183
|
+
}
|
|
184
|
+
async function pause() {
|
|
185
|
+
if (!cancelCallback) {
|
|
186
|
+
throw "O evento de grava\xE7\xE3o n\xE3o foi iniciado";
|
|
187
|
+
}
|
|
188
|
+
await cancelCallback();
|
|
189
|
+
if (cameraBuffer.length == 0 || screenBuffer.length == 0) {
|
|
190
|
+
throw "N\xE3o foram registrado dados, o tempo de grava\xE7\xE3o pode ter sido muito curto";
|
|
191
|
+
}
|
|
192
|
+
await Promise.all([insertBuffer("cameraBuffers", cameraBuffer), insertBuffer("screenBuffers", screenBuffer)]);
|
|
193
|
+
cameraBuffer = [];
|
|
194
|
+
screenBuffer = [];
|
|
195
|
+
cancelCallback = null;
|
|
196
|
+
}
|
|
197
|
+
async function resume() {
|
|
198
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
199
|
+
if (storedCameraBuffers.length == 0 || storedScreenBuffers.length == 0) {
|
|
200
|
+
throw "N\xE3o existe nenhuma grava\xE7\xE3o pausada";
|
|
201
|
+
}
|
|
202
|
+
await _startCapture();
|
|
203
|
+
}
|
|
19
204
|
const onLostFocus = (cb) => {
|
|
205
|
+
cb();
|
|
20
206
|
};
|
|
21
|
-
return { start, finish, pause, resume, onLostFocus };
|
|
207
|
+
return { start, finish, pause, resume, onLostFocus, download };
|
|
22
208
|
}
|
|
23
209
|
if (typeof window !== "undefined") {
|
|
24
210
|
window.useProctoring = useProctoring;
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export declare function useProctoring(key: string): {
|
|
2
|
-
start: (
|
|
2
|
+
start: (options?: {
|
|
3
|
+
override: boolean;
|
|
4
|
+
}) => Promise<void>;
|
|
3
5
|
finish: () => Promise<[File, File]>;
|
|
4
6
|
pause: () => Promise<void>;
|
|
5
7
|
resume: () => Promise<void>;
|
|
6
8
|
onLostFocus: (cb: () => void) => void;
|
|
9
|
+
download: (file: File) => void;
|
|
7
10
|
};
|
package/index.js
CHANGED
|
@@ -1,56 +1,227 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
2
|
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
|
6
3
|
var __export = (target, all) => {
|
|
4
|
+
__markAsModule(target);
|
|
7
5
|
for (var name in all)
|
|
8
6
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
7
|
};
|
|
10
|
-
var __reExport = (target, module2, copyDefault, desc) => {
|
|
11
|
-
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(module2))
|
|
13
|
-
if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default"))
|
|
14
|
-
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return target;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = /* @__PURE__ */ ((cache) => {
|
|
19
|
-
return (module2, temp) => {
|
|
20
|
-
return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp);
|
|
21
|
-
};
|
|
22
|
-
})(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
|
|
23
8
|
|
|
24
9
|
// src/index.ts
|
|
25
|
-
|
|
26
|
-
__export(src_exports, {
|
|
10
|
+
__export(exports, {
|
|
27
11
|
useProctoring: () => useProctoring
|
|
28
12
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
13
|
+
|
|
14
|
+
// src/modules/database.ts
|
|
15
|
+
var databaseName = "EasyProctorPlugin";
|
|
16
|
+
var databaseVersion = 1;
|
|
17
|
+
function initializeDatabase(table) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const request = indexedDB.open(databaseName, databaseVersion);
|
|
20
|
+
request.onupgradeneeded = () => {
|
|
21
|
+
request.result.createObjectStore("cameraBuffers", { keyPath: "id", autoIncrement: true });
|
|
22
|
+
request.result.createObjectStore("screenBuffers", { keyPath: "id", autoIncrement: true });
|
|
23
|
+
};
|
|
24
|
+
request.onerror = (e) => {
|
|
25
|
+
console.log(e);
|
|
26
|
+
reject("N\xE3o foi poss\xEDvel inicializar a biblioteca, por favor, entre em contato com o suporte e informe o erro acima");
|
|
27
|
+
};
|
|
28
|
+
request.onsuccess = () => {
|
|
29
|
+
const db = request.result;
|
|
30
|
+
const tableRef = db.transaction(table, "readwrite");
|
|
31
|
+
const store = tableRef.objectStore(table);
|
|
32
|
+
resolve(store);
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async function insertBuffer(table, buffer) {
|
|
37
|
+
const store = await initializeDatabase(table);
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const request = store.add({ data: buffer });
|
|
40
|
+
request.onsuccess = () => resolve();
|
|
41
|
+
request.onerror = (e) => reject(e);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async function getBuffers(table) {
|
|
45
|
+
const store = await initializeDatabase(table);
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const request = store.getAll();
|
|
48
|
+
request.onsuccess = () => {
|
|
49
|
+
const data = request.result;
|
|
50
|
+
const blobs = data.reduce((acc, el) => [...acc, ...el.data], []);
|
|
51
|
+
resolve(blobs);
|
|
52
|
+
};
|
|
53
|
+
request.onerror = (e) => reject(e);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async function clearBuffers(table) {
|
|
57
|
+
const store = await initializeDatabase(table);
|
|
58
|
+
return new Promise((resolve, reject) => {
|
|
59
|
+
const request = store.clear();
|
|
60
|
+
request.onsuccess = () => resolve();
|
|
61
|
+
request.onerror = (e) => reject(e);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/modules/recorder.ts
|
|
66
|
+
function recorder(stream, buffer) {
|
|
67
|
+
let resolvePromise;
|
|
68
|
+
const options = {
|
|
69
|
+
mimeType: "video/webm; codecs=vp9",
|
|
70
|
+
videoBitsPerSecond: 128e3,
|
|
71
|
+
audioBitsPerSecond: 64 * 1e3
|
|
32
72
|
};
|
|
33
|
-
const
|
|
73
|
+
const mediaRecorder = new MediaRecorder(stream, options);
|
|
74
|
+
mediaRecorder.ondataavailable = (e) => {
|
|
75
|
+
if (e.data.size > 0) {
|
|
76
|
+
buffer.push(e.data);
|
|
77
|
+
}
|
|
78
|
+
resolvePromise && resolvePromise();
|
|
79
|
+
};
|
|
80
|
+
mediaRecorder.start();
|
|
81
|
+
function stopRecording() {
|
|
34
82
|
return new Promise((resolve) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
83
|
+
resolvePromise = resolve;
|
|
84
|
+
mediaRecorder.stop();
|
|
85
|
+
stream.getTracks().forEach((el) => {
|
|
86
|
+
el.stop();
|
|
87
|
+
});
|
|
38
88
|
});
|
|
89
|
+
}
|
|
90
|
+
return stopRecording;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/modules/startCameraCapture.ts
|
|
94
|
+
async function startCameraCapture(buffer) {
|
|
95
|
+
const constraints = {
|
|
96
|
+
audio: true,
|
|
97
|
+
video: {
|
|
98
|
+
width: { max: 1280, ideal: 640 },
|
|
99
|
+
height: { max: 720, ideal: 480 },
|
|
100
|
+
frameRate: 15
|
|
101
|
+
}
|
|
39
102
|
};
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
103
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
104
|
+
const stopRecording = recorder(stream, buffer);
|
|
105
|
+
return stopRecording;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/modules/startScreenCapture.ts
|
|
109
|
+
async function startScreenCapture(buffer) {
|
|
110
|
+
const displayMediaStreamConstraints = {
|
|
111
|
+
video: {
|
|
112
|
+
cursor: "always"
|
|
113
|
+
},
|
|
114
|
+
audio: false
|
|
45
115
|
};
|
|
116
|
+
const stream = await navigator.mediaDevices.getDisplayMedia(displayMediaStreamConstraints);
|
|
117
|
+
const stopRecording = recorder(stream, buffer);
|
|
118
|
+
return stopRecording;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/index.ts
|
|
122
|
+
function useProctoring(key) {
|
|
123
|
+
if (!navigator.mediaDevices.getDisplayMedia) {
|
|
124
|
+
throw "Voc\xEA est\xE1 utilizando uma vers\xE3o muito antiga do navegador, por favor, atualize a vers\xE3o";
|
|
125
|
+
}
|
|
126
|
+
if (!window.indexedDB) {
|
|
127
|
+
throw "Voc\xEA est\xE1 usando uma vers\xE3o muito antiga do navegador, n\xE3o \xE9 poss\xEDvel relizar a requisi\xE7\xE3o";
|
|
128
|
+
}
|
|
129
|
+
function download(file) {
|
|
130
|
+
const url = URL.createObjectURL(file);
|
|
131
|
+
const a = document.createElement("a");
|
|
132
|
+
document.body.appendChild(a);
|
|
133
|
+
a.style.display = "none";
|
|
134
|
+
a.href = url;
|
|
135
|
+
a.download = file.name;
|
|
136
|
+
a.click();
|
|
137
|
+
window.URL.revokeObjectURL(url);
|
|
138
|
+
}
|
|
139
|
+
let cameraBuffer = [];
|
|
140
|
+
let screenBuffer = [];
|
|
141
|
+
let cancelCallback = null;
|
|
142
|
+
async function _startCapture() {
|
|
143
|
+
if (!document.body) {
|
|
144
|
+
throw "A execu\xE7\xE3o do script deve ser feita por algum elemento dentro do <body> da p\xE1gina html";
|
|
145
|
+
}
|
|
146
|
+
if (cancelCallback != null) {
|
|
147
|
+
throw "Uma grava\xE7\xE3o ja est\xE1 em andamento";
|
|
148
|
+
}
|
|
149
|
+
let cancelCameraCapture = null;
|
|
150
|
+
let cancelScreenCapture = null;
|
|
151
|
+
try {
|
|
152
|
+
cancelScreenCapture = await startScreenCapture(screenBuffer);
|
|
153
|
+
cancelCameraCapture = await startCameraCapture(cameraBuffer);
|
|
154
|
+
cancelCallback = async function() {
|
|
155
|
+
await Promise.all([cancelCameraCapture(), cancelScreenCapture()]);
|
|
156
|
+
};
|
|
157
|
+
} catch (error) {
|
|
158
|
+
cancelCallback = null;
|
|
159
|
+
cancelScreenCapture && await cancelScreenCapture();
|
|
160
|
+
cancelCameraCapture && await cancelCameraCapture();
|
|
161
|
+
cameraBuffer = [];
|
|
162
|
+
screenBuffer = [];
|
|
163
|
+
throw "N\xE3o foi poss\xEDvel iniciar a captura, por favor, verifique as permiss\xF5es de camera e microfone";
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function start(options = { override: false }) {
|
|
167
|
+
const { override } = options;
|
|
168
|
+
if (override) {
|
|
169
|
+
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
170
|
+
} else {
|
|
171
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
172
|
+
if (storedCameraBuffers.length > 0 || storedScreenBuffers.length > 0) {
|
|
173
|
+
throw "Existe uma grava\xE7\xE3o iniciada, por favor, execute o m\xE9todo resume() para retomar, ou utilize o parametro start({ override: true }) para limpar os dados";
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
await _startCapture();
|
|
177
|
+
}
|
|
178
|
+
async function finish() {
|
|
179
|
+
if (cancelCallback) {
|
|
180
|
+
await cancelCallback();
|
|
181
|
+
}
|
|
182
|
+
const time = new Date().toISOString();
|
|
183
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
184
|
+
const finalCameraBuffer = [...storedCameraBuffers, ...cameraBuffer];
|
|
185
|
+
const finalScreenBuffer = [...storedScreenBuffers, ...screenBuffer];
|
|
186
|
+
if (finalCameraBuffer.length == 0 || finalScreenBuffer.length == 0) {
|
|
187
|
+
throw "N\xE3o existe nenhuma grava\xE7\xE3o iniciada";
|
|
188
|
+
}
|
|
189
|
+
const cameraFile = new File(finalCameraBuffer, `${time}-camera.webm`, { type: "video/webm" });
|
|
190
|
+
const screenFile = new File(finalScreenBuffer, `${time}-screen.webm`, { type: "video/webm" });
|
|
191
|
+
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
192
|
+
cameraBuffer = [];
|
|
193
|
+
screenBuffer = [];
|
|
194
|
+
cancelCallback = null;
|
|
195
|
+
return [cameraFile, screenFile];
|
|
196
|
+
}
|
|
197
|
+
async function pause() {
|
|
198
|
+
if (!cancelCallback) {
|
|
199
|
+
throw "O evento de grava\xE7\xE3o n\xE3o foi iniciado";
|
|
200
|
+
}
|
|
201
|
+
await cancelCallback();
|
|
202
|
+
if (cameraBuffer.length == 0 || screenBuffer.length == 0) {
|
|
203
|
+
throw "N\xE3o foram registrado dados, o tempo de grava\xE7\xE3o pode ter sido muito curto";
|
|
204
|
+
}
|
|
205
|
+
await Promise.all([insertBuffer("cameraBuffers", cameraBuffer), insertBuffer("screenBuffers", screenBuffer)]);
|
|
206
|
+
cameraBuffer = [];
|
|
207
|
+
screenBuffer = [];
|
|
208
|
+
cancelCallback = null;
|
|
209
|
+
}
|
|
210
|
+
async function resume() {
|
|
211
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
212
|
+
if (storedCameraBuffers.length == 0 || storedScreenBuffers.length == 0) {
|
|
213
|
+
throw "N\xE3o existe nenhuma grava\xE7\xE3o pausada";
|
|
214
|
+
}
|
|
215
|
+
await _startCapture();
|
|
216
|
+
}
|
|
46
217
|
const onLostFocus = (cb) => {
|
|
218
|
+
cb();
|
|
47
219
|
};
|
|
48
|
-
return { start, finish, pause, resume, onLostFocus };
|
|
220
|
+
return { start, finish, pause, resume, onLostFocus, download };
|
|
49
221
|
}
|
|
50
222
|
if (typeof window !== "undefined") {
|
|
51
223
|
window.useProctoring = useProctoring;
|
|
52
224
|
}
|
|
53
|
-
module.exports = __toCommonJS(src_exports);
|
|
54
225
|
// Annotate the CommonJS export names for ESM import in node:
|
|
55
226
|
0 && (module.exports = {
|
|
56
227
|
useProctoring
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare type Tables = "cameraBuffers" | "screenBuffers";
|
|
2
|
+
export declare function initializeDatabase(table: string): Promise<IDBObjectStore>;
|
|
3
|
+
export declare function insertBuffer(table: Tables, buffer: Blob[]): Promise<void>;
|
|
4
|
+
export declare function getBuffers(table: Tables): Promise<Blob[]>;
|
|
5
|
+
export declare function clearBuffers(table: Tables): Promise<void>;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function recorder(stream: MediaStream, buffer: Blob[]): () => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default function startCameraCapture(): void
|
|
1
|
+
export default function startCameraCapture(buffer: Blob[]): Promise<() => Promise<void>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default function startScreenCapture(): Promise<void
|
|
1
|
+
export default function startScreenCapture(buffer: Blob[]): Promise<() => Promise<void>>;
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "easyproctor",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "Modulo web de gravação do EasyProctor",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./esm/index.js",
|
|
7
7
|
"unpkg": "./unpkg/easyproctor.min.js",
|
|
8
8
|
"types": "./index.d.ts",
|
|
9
|
-
"keywords": [
|
|
9
|
+
"keywords": [
|
|
10
|
+
"proctoring"
|
|
11
|
+
],
|
|
10
12
|
"homepage": "https://github.com/Igor4505/render-function#readme",
|
|
11
13
|
"repository": {
|
|
12
14
|
"type": "git",
|
|
@@ -19,10 +21,12 @@
|
|
|
19
21
|
"author": "Igor Dantas",
|
|
20
22
|
"license": "ISC",
|
|
21
23
|
"devDependencies": {
|
|
22
|
-
"@
|
|
23
|
-
"@typescript-eslint/
|
|
24
|
+
"@types/dom-mediacapture-record": "^1.0.11",
|
|
25
|
+
"@typescript-eslint/eslint-plugin": "^5.8.0",
|
|
26
|
+
"@typescript-eslint/parser": "^5.8.0",
|
|
24
27
|
"esbuild": "^0.13.13",
|
|
28
|
+
"esbuild-serve": "^1.0.1",
|
|
25
29
|
"eslint": "^8.2.0",
|
|
26
|
-
"typescript": "^
|
|
30
|
+
"typescript": "^4.5.4"
|
|
27
31
|
}
|
|
28
32
|
}
|
package/test.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
// src/modules/database.ts
|
|
3
|
+
var databaseName = "EasyProctorPlugin";
|
|
4
|
+
var databaseVersion = 1;
|
|
5
|
+
function initializeDatabase(table) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const request = indexedDB.open(databaseName, databaseVersion);
|
|
8
|
+
request.onupgradeneeded = () => {
|
|
9
|
+
request.result.createObjectStore("cameraBuffers", {keyPath: "id", autoIncrement: true});
|
|
10
|
+
request.result.createObjectStore("screenBuffers", {keyPath: "id", autoIncrement: true});
|
|
11
|
+
};
|
|
12
|
+
request.onerror = (e) => {
|
|
13
|
+
console.log(e);
|
|
14
|
+
reject("N\xE3o foi poss\xEDvel inicializar a biblioteca, por favor, entre em contato com o suporte e informe o erro acima");
|
|
15
|
+
};
|
|
16
|
+
request.onsuccess = () => {
|
|
17
|
+
const db = request.result;
|
|
18
|
+
const tableRef = db.transaction(table, "readwrite");
|
|
19
|
+
const store = tableRef.objectStore(table);
|
|
20
|
+
resolve(store);
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async function insertBuffer(table, buffer) {
|
|
25
|
+
const store = await initializeDatabase(table);
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const request = store.add({data: buffer});
|
|
28
|
+
request.onsuccess = () => resolve();
|
|
29
|
+
request.onerror = (e) => reject(e);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
async function getBuffers(table) {
|
|
33
|
+
const store = await initializeDatabase(table);
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
const request = store.getAll();
|
|
36
|
+
request.onsuccess = () => {
|
|
37
|
+
const data = request.result;
|
|
38
|
+
const blobs = data.reduce((acc, el) => [...acc, ...el.data], []);
|
|
39
|
+
resolve(blobs);
|
|
40
|
+
};
|
|
41
|
+
request.onerror = (e) => reject(e);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async function clearBuffers(table) {
|
|
45
|
+
const store = await initializeDatabase(table);
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const request = store.clear();
|
|
48
|
+
request.onsuccess = () => resolve();
|
|
49
|
+
request.onerror = (e) => reject(e);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/modules/recorder.ts
|
|
54
|
+
function recorder(stream, buffer) {
|
|
55
|
+
let resolvePromise;
|
|
56
|
+
const options = {
|
|
57
|
+
mimeType: "video/webm; codecs=vp9",
|
|
58
|
+
videoBitsPerSecond: 128e3,
|
|
59
|
+
audioBitsPerSecond: 64 * 1e3
|
|
60
|
+
};
|
|
61
|
+
const mediaRecorder = new MediaRecorder(stream, options);
|
|
62
|
+
mediaRecorder.ondataavailable = (e) => {
|
|
63
|
+
if (e.data.size > 0) {
|
|
64
|
+
buffer.push(e.data);
|
|
65
|
+
}
|
|
66
|
+
resolvePromise && resolvePromise();
|
|
67
|
+
};
|
|
68
|
+
mediaRecorder.start();
|
|
69
|
+
function stopRecording() {
|
|
70
|
+
return new Promise((resolve) => {
|
|
71
|
+
resolvePromise = resolve;
|
|
72
|
+
mediaRecorder.stop();
|
|
73
|
+
stream.getTracks().forEach((el) => {
|
|
74
|
+
el.stop();
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return stopRecording;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/modules/startCameraCapture.ts
|
|
82
|
+
async function startCameraCapture(buffer) {
|
|
83
|
+
const constraints = {
|
|
84
|
+
audio: true,
|
|
85
|
+
video: {
|
|
86
|
+
width: {max: 1280, ideal: 640},
|
|
87
|
+
height: {max: 720, ideal: 480},
|
|
88
|
+
frameRate: 15
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
92
|
+
const stopRecording = recorder(stream, buffer);
|
|
93
|
+
return stopRecording;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/modules/startScreenCapture.ts
|
|
97
|
+
async function startScreenCapture(buffer) {
|
|
98
|
+
const displayMediaStreamConstraints = {
|
|
99
|
+
video: {
|
|
100
|
+
cursor: "always"
|
|
101
|
+
},
|
|
102
|
+
audio: false
|
|
103
|
+
};
|
|
104
|
+
const stream = await navigator.mediaDevices.getDisplayMedia(displayMediaStreamConstraints);
|
|
105
|
+
const stopRecording = recorder(stream, buffer);
|
|
106
|
+
return stopRecording;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/index.ts
|
|
110
|
+
function useProctoring(key) {
|
|
111
|
+
if (!navigator.mediaDevices.getDisplayMedia) {
|
|
112
|
+
throw "Voc\xEA est\xE1 utilizando uma vers\xE3o muito antiga do navegador, por favor, atualize a vers\xE3o";
|
|
113
|
+
}
|
|
114
|
+
if (!window.indexedDB) {
|
|
115
|
+
throw "Voc\xEA est\xE1 usando uma vers\xE3o muito antiga do navegador, n\xE3o \xE9 poss\xEDvel relizar a requisi\xE7\xE3o";
|
|
116
|
+
}
|
|
117
|
+
function download(file) {
|
|
118
|
+
const url = URL.createObjectURL(file);
|
|
119
|
+
const a = document.createElement("a");
|
|
120
|
+
document.body.appendChild(a);
|
|
121
|
+
a.style.display = "none";
|
|
122
|
+
a.href = url;
|
|
123
|
+
a.download = file.name;
|
|
124
|
+
a.click();
|
|
125
|
+
window.URL.revokeObjectURL(url);
|
|
126
|
+
}
|
|
127
|
+
let cameraBuffer = [];
|
|
128
|
+
let screenBuffer = [];
|
|
129
|
+
let cancelCallback = null;
|
|
130
|
+
async function _startCapture() {
|
|
131
|
+
if (!document.body) {
|
|
132
|
+
throw "A execu\xE7\xE3o do script deve ser feita por algum elemento dentro do <body> da p\xE1gina html";
|
|
133
|
+
}
|
|
134
|
+
if (cancelCallback != null) {
|
|
135
|
+
throw "Uma grava\xE7\xE3o ja est\xE1 em andamento";
|
|
136
|
+
}
|
|
137
|
+
let cancelCameraCapture = null;
|
|
138
|
+
let cancelScreenCapture = null;
|
|
139
|
+
try {
|
|
140
|
+
cancelScreenCapture = await startScreenCapture(screenBuffer);
|
|
141
|
+
cancelCameraCapture = await startCameraCapture(cameraBuffer);
|
|
142
|
+
cancelCallback = async function() {
|
|
143
|
+
await Promise.all([cancelCameraCapture(), cancelScreenCapture()]);
|
|
144
|
+
};
|
|
145
|
+
} catch (error) {
|
|
146
|
+
cancelCallback = null;
|
|
147
|
+
cancelScreenCapture && await cancelScreenCapture();
|
|
148
|
+
cancelCameraCapture && await cancelCameraCapture();
|
|
149
|
+
cameraBuffer = [];
|
|
150
|
+
screenBuffer = [];
|
|
151
|
+
throw "N\xE3o foi poss\xEDvel iniciar a captura, por favor, verifique as permiss\xF5es de camera e microfone";
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function start2(options = {override: false}) {
|
|
155
|
+
const {override} = options;
|
|
156
|
+
if (override) {
|
|
157
|
+
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
158
|
+
} else {
|
|
159
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
160
|
+
if (storedCameraBuffers.length > 0 || storedScreenBuffers.length > 0) {
|
|
161
|
+
throw "Existe uma grava\xE7\xE3o iniciada, por favor, execute o m\xE9todo resume() para retomar, ou utilize o parametro start({ override: true }) para limpar os dados";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
await _startCapture();
|
|
165
|
+
}
|
|
166
|
+
async function finish2() {
|
|
167
|
+
if (cancelCallback) {
|
|
168
|
+
await cancelCallback();
|
|
169
|
+
}
|
|
170
|
+
const time = new Date().toISOString();
|
|
171
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
172
|
+
const finalCameraBuffer = [...storedCameraBuffers, ...cameraBuffer];
|
|
173
|
+
const finalScreenBuffer = [...storedScreenBuffers, ...screenBuffer];
|
|
174
|
+
if (finalCameraBuffer.length == 0 || finalScreenBuffer.length == 0) {
|
|
175
|
+
throw "N\xE3o existe nenhuma grava\xE7\xE3o iniciada";
|
|
176
|
+
}
|
|
177
|
+
const cameraFile = new File(finalCameraBuffer, `${time}-camera.webm`, {type: "video/webm"});
|
|
178
|
+
const screenFile = new File(finalScreenBuffer, `${time}-screen.webm`, {type: "video/webm"});
|
|
179
|
+
await Promise.all([clearBuffers("cameraBuffers"), clearBuffers("screenBuffers")]);
|
|
180
|
+
cameraBuffer = [];
|
|
181
|
+
screenBuffer = [];
|
|
182
|
+
cancelCallback = null;
|
|
183
|
+
return [cameraFile, screenFile];
|
|
184
|
+
}
|
|
185
|
+
async function pause2() {
|
|
186
|
+
if (!cancelCallback) {
|
|
187
|
+
throw "O evento de grava\xE7\xE3o n\xE3o foi iniciado";
|
|
188
|
+
}
|
|
189
|
+
await cancelCallback();
|
|
190
|
+
if (cameraBuffer.length == 0 || screenBuffer.length == 0) {
|
|
191
|
+
throw "N\xE3o foram registrado dados, o tempo de grava\xE7\xE3o pode ter sido muito curto";
|
|
192
|
+
}
|
|
193
|
+
await Promise.all([insertBuffer("cameraBuffers", cameraBuffer), insertBuffer("screenBuffers", screenBuffer)]);
|
|
194
|
+
cameraBuffer = [];
|
|
195
|
+
screenBuffer = [];
|
|
196
|
+
cancelCallback = null;
|
|
197
|
+
}
|
|
198
|
+
async function resume2() {
|
|
199
|
+
const [storedCameraBuffers, storedScreenBuffers] = await Promise.all([getBuffers("cameraBuffers"), getBuffers("screenBuffers")]);
|
|
200
|
+
if (storedCameraBuffers.length == 0 || storedScreenBuffers.length == 0) {
|
|
201
|
+
throw "N\xE3o existe nenhuma grava\xE7\xE3o pausada";
|
|
202
|
+
}
|
|
203
|
+
await _startCapture();
|
|
204
|
+
}
|
|
205
|
+
const onLostFocus = (cb) => {
|
|
206
|
+
cb();
|
|
207
|
+
};
|
|
208
|
+
return {start: start2, finish: finish2, pause: pause2, resume: resume2, onLostFocus, download};
|
|
209
|
+
}
|
|
210
|
+
if (typeof window !== "undefined") {
|
|
211
|
+
window.useProctoring = useProctoring;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/test.ts
|
|
215
|
+
var {start, pause, resume, finish} = useProctoring("125-125125-12512512-1251");
|
|
216
|
+
async function startExam() {
|
|
217
|
+
try {
|
|
218
|
+
await start();
|
|
219
|
+
console.log("EXAME INICIADO");
|
|
220
|
+
} catch (error) {
|
|
221
|
+
alert(error);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async function pauseExam() {
|
|
225
|
+
try {
|
|
226
|
+
await pause();
|
|
227
|
+
console.log("EXAME PAUSADO");
|
|
228
|
+
} catch (error) {
|
|
229
|
+
alert(error);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function resumeExam() {
|
|
233
|
+
try {
|
|
234
|
+
await resume();
|
|
235
|
+
console.log("EXAME REINICIADO");
|
|
236
|
+
} catch (error) {
|
|
237
|
+
alert(error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async function finishExam() {
|
|
241
|
+
try {
|
|
242
|
+
await finish();
|
|
243
|
+
console.log("EXAME FINALIZADO");
|
|
244
|
+
} catch (error) {
|
|
245
|
+
alert(error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
window.startExam = startExam;
|
|
249
|
+
window.pauseExam = pauseExam;
|
|
250
|
+
window.resumeExam = resumeExam;
|
|
251
|
+
window.finishExam = finishExam;
|
|
252
|
+
})();
|
package/unpkg/easyproctor.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{function
|
|
1
|
+
(()=>{var S="EasyProctorPlugin",x=1;function v(o){return new Promise((s,a)=>{let r=indexedDB.open(S,x);r.onupgradeneeded=()=>{r.result.createObjectStore("cameraBuffers",{keyPath:"id",autoIncrement:!0}),r.result.createObjectStore("screenBuffers",{keyPath:"id",autoIncrement:!0})},r.onerror=e=>{console.log(e),a("N\xE3o foi poss\xEDvel inicializar a biblioteca, por favor, entre em contato com o suporte e informe o erro acima")},r.onsuccess=()=>{let c=r.result.transaction(o,"readwrite").objectStore(o);s(c)}})}async function g(o,s){let a=await v(o);return new Promise((r,e)=>{let n=a.add({data:s});n.onsuccess=()=>r(),n.onerror=c=>e(c)})}async function d(o){let s=await v(o);return new Promise((a,r)=>{let e=s.getAll();e.onsuccess=()=>{let c=e.result.reduce((l,w)=>[...l,...w.data],[]);a(c)},e.onerror=n=>r(n)})}async function f(o){let s=await v(o);return new Promise((a,r)=>{let e=s.clear();e.onsuccess=()=>a(),e.onerror=n=>r(n)})}function m(o,s){let a,r={mimeType:"video/webm; codecs=vp9",videoBitsPerSecond:128e3,audioBitsPerSecond:64*1e3},e=new MediaRecorder(o,r);e.ondataavailable=c=>{c.data.size>0&&s.push(c.data),a&&a()},e.start();function n(){return new Promise(c=>{a=c,e.stop(),o.getTracks().forEach(l=>{l.stop()})})}return n}async function B(o){let s={audio:!0,video:{width:{max:1280,ideal:640},height:{max:720,ideal:480},frameRate:15}},a=await navigator.mediaDevices.getUserMedia(s);return m(a,o)}async function b(o){let s={video:{cursor:"always"},audio:!1},a=await navigator.mediaDevices.getDisplayMedia(s);return m(a,o)}function R(o){if(!navigator.mediaDevices.getDisplayMedia)throw"Voc\xEA est\xE1 utilizando uma vers\xE3o muito antiga do navegador, por favor, atualize a vers\xE3o";if(!window.indexedDB)throw"Voc\xEA est\xE1 usando uma vers\xE3o muito antiga do navegador, n\xE3o \xE9 poss\xEDvel relizar a requisi\xE7\xE3o";function s(t){let i=URL.createObjectURL(t),u=document.createElement("a");document.body.appendChild(u),u.style.display="none",u.href=i,u.download=t.name,u.click(),window.URL.revokeObjectURL(i)}let a=[],r=[],e=null;async function n(){if(!document.body)throw"A execu\xE7\xE3o do script deve ser feita por algum elemento dentro do <body> da p\xE1gina html";if(e!=null)throw"Uma grava\xE7\xE3o ja est\xE1 em andamento";let t=null,i=null;try{i=await b(r),t=await B(a),e=async function(){await Promise.all([t(),i()])}}catch{throw e=null,i&&await i(),t&&await t(),a=[],r=[],"N\xE3o foi poss\xEDvel iniciar a captura, por favor, verifique as permiss\xF5es de camera e microfone"}}async function c(t={override:!1}){let{override:i}=t;if(i)await Promise.all([f("cameraBuffers"),f("screenBuffers")]);else{let[u,p]=await Promise.all([d("cameraBuffers"),d("screenBuffers")]);if(u.length>0||p.length>0)throw"Existe uma grava\xE7\xE3o iniciada, por favor, execute o m\xE9todo resume() para retomar, ou utilize o parametro start({ override: true }) para limpar os dados"}await n()}async function l(){e&&await e();let t=new Date().toISOString(),[i,u]=await Promise.all([d("cameraBuffers"),d("screenBuffers")]),p=[...i,...a],y=[...u,...r];if(p.length==0||y.length==0)throw"N\xE3o existe nenhuma grava\xE7\xE3o iniciada";let P=new File(p,`${t}-camera.webm`,{type:"video/webm"}),C=new File(y,`${t}-screen.webm`,{type:"video/webm"});return await Promise.all([f("cameraBuffers"),f("screenBuffers")]),a=[],r=[],e=null,[P,C]}async function w(){if(!e)throw"O evento de grava\xE7\xE3o n\xE3o foi iniciado";if(await e(),a.length==0||r.length==0)throw"N\xE3o foram registrado dados, o tempo de grava\xE7\xE3o pode ter sido muito curto";await Promise.all([g("cameraBuffers",a),g("screenBuffers",r)]),a=[],r=[],e=null}async function h(){let[t,i]=await Promise.all([d("cameraBuffers"),d("screenBuffers")]);if(t.length==0||i.length==0)throw"N\xE3o existe nenhuma grava\xE7\xE3o pausada";await n()}return{start:c,finish:l,pause:w,resume:h,onLostFocus:t=>{t()},download:s}}typeof window!="undefined"&&(window.useProctoring=R);})();
|