all
This commit is contained in:
183
Video/MiroTalk SFU/public/js/Brand.js
Normal file
183
Video/MiroTalk SFU/public/js/Brand.js
Normal file
@ -0,0 +1,183 @@
|
||||
'use strict';
|
||||
|
||||
const brandDataKey = 'brandData';
|
||||
const brandData = window.sessionStorage.getItem(brandDataKey);
|
||||
|
||||
const title = document.getElementById('title');
|
||||
const icon = document.getElementById('icon');
|
||||
const appleTouchIcon = document.getElementById('appleTouchIcon');
|
||||
|
||||
const description = document.getElementById('description');
|
||||
const keywords = document.getElementById('keywords');
|
||||
|
||||
const ogType = document.getElementById('ogType');
|
||||
const ogSiteName = document.getElementById('ogSiteName');
|
||||
const ogTitle = document.getElementById('ogTitle');
|
||||
const ogDescription = document.getElementById('ogDescription');
|
||||
const ogImage = document.getElementById('ogImage');
|
||||
|
||||
const appTitle = document.getElementById('appTitle');
|
||||
const appDescription = document.getElementById('appDescription');
|
||||
|
||||
const features = document.getElementById('features');
|
||||
const teams = document.getElementById('teams');
|
||||
const tryEasier = document.getElementById('tryEasier');
|
||||
const poweredBy = document.getElementById('poweredBy');
|
||||
const sponsors = document.getElementById('sponsors');
|
||||
const advertisers = document.getElementById('advertisers');
|
||||
const footer = document.getElementById('footer');
|
||||
//...
|
||||
|
||||
// app/src/config.js - ui.brand
|
||||
let BRAND = {
|
||||
app: {
|
||||
name: 'MiroTalk SFU',
|
||||
title: 'MiroTalk SFU<br />Free browser based Real-time video calls.<br />Simple, Secure, Fast.',
|
||||
description:
|
||||
'Start your next video call with a single click. No download, plug-in, or login is required. Just get straight to talking, messaging, and sharing your screen.',
|
||||
},
|
||||
site: {
|
||||
title: 'MiroTalk SFU, Free Video Calls, Messaging and Screen Sharing',
|
||||
icon: '../images/logo.svg',
|
||||
appleTouchIcon: '../images/logo.svg',
|
||||
},
|
||||
meta: {
|
||||
description:
|
||||
'MiroTalk SFU powered by WebRTC and mediasoup, Real-time Simple Secure Fast video calls, messaging and screen sharing capabilities in the browser.',
|
||||
keywords:
|
||||
'webrtc, miro, mediasoup, mediasoup-client, self hosted, voip, sip, real-time communications, chat, messaging, meet, webrtc stun, webrtc turn, webrtc p2p, webrtc sfu, video meeting, video chat, video conference, multi video chat, multi video conference, peer to peer, p2p, sfu, rtc, alternative to, zoom, microsoft teams, google meet, jitsi, meeting',
|
||||
},
|
||||
og: {
|
||||
type: 'app-webrtc',
|
||||
siteName: 'MiroTalk SFU',
|
||||
title: 'Click the link to make a call.',
|
||||
description: 'MiroTalk SFU calling provides real-time video calls, messaging and screen sharing.',
|
||||
image: 'https://sfu.mirotalk.com/images/mirotalksfu.png',
|
||||
},
|
||||
html: {
|
||||
features: true,
|
||||
teams: true,
|
||||
tryEasier: true,
|
||||
poweredBy: true,
|
||||
sponsors: true,
|
||||
advertisers: true,
|
||||
footer: true,
|
||||
},
|
||||
//...
|
||||
};
|
||||
|
||||
async function initialize() {
|
||||
await getBrand();
|
||||
|
||||
customizeSite();
|
||||
|
||||
customizeMetaTags();
|
||||
|
||||
customizeOpenGraph();
|
||||
|
||||
customizeApp();
|
||||
|
||||
checkBrand();
|
||||
}
|
||||
|
||||
async function getBrand() {
|
||||
if (brandData) {
|
||||
setBrand(JSON.parse(brandData));
|
||||
} else {
|
||||
try {
|
||||
const response = await fetch('/brand', { timeout: 5000 });
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
const serverBrand = data.message;
|
||||
if (serverBrand) {
|
||||
setBrand(serverBrand);
|
||||
console.log('FETCH BRAND SETTINGS', {
|
||||
serverBrand: serverBrand,
|
||||
clientBrand: BRAND,
|
||||
});
|
||||
window.sessionStorage.setItem(brandDataKey, JSON.stringify(serverBrand));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('FETCH GET BRAND ERROR', error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// BRAND configurations
|
||||
function setBrand(data) {
|
||||
BRAND = data;
|
||||
console.log('Set Brand done');
|
||||
}
|
||||
|
||||
// BRAND check
|
||||
function checkBrand() {
|
||||
!BRAND.html.features && elementDisplay(features, false);
|
||||
!BRAND.html.teams && elementDisplay(teams, false);
|
||||
!BRAND.html.tryEasier && elementDisplay(tryEasier, false);
|
||||
!BRAND.html.poweredBy && elementDisplay(poweredBy, false);
|
||||
!BRAND.html.sponsors && elementDisplay(sponsors, false);
|
||||
!BRAND.html.advertisers && elementDisplay(advertisers, false);
|
||||
!BRAND.html.footer && elementDisplay(footer, false);
|
||||
}
|
||||
|
||||
// ELEMENT display mode
|
||||
function elementDisplay(element, display, mode = 'block') {
|
||||
if (!element) return;
|
||||
element.style.display = display ? mode : 'none';
|
||||
}
|
||||
|
||||
// APP customize
|
||||
function customizeApp() {
|
||||
if (appTitle) {
|
||||
appTitle.innerHTML = BRAND.app.title;
|
||||
}
|
||||
if (appDescription) {
|
||||
appDescription.textContent = BRAND.app.description;
|
||||
}
|
||||
}
|
||||
|
||||
// SITE metadata
|
||||
function customizeSite() {
|
||||
if (title) {
|
||||
title.textContent = BRAND.site.title;
|
||||
}
|
||||
if (icon) {
|
||||
icon.href = BRAND.site.icon;
|
||||
}
|
||||
if (appleTouchIcon) {
|
||||
appleTouchIcon.href = BRAND.site.appleTouchIcon;
|
||||
}
|
||||
}
|
||||
|
||||
// SEO metadata
|
||||
function customizeMetaTags() {
|
||||
if (description) {
|
||||
description.content = BRAND.meta.description;
|
||||
}
|
||||
if (keywords) {
|
||||
keywords.content = BRAND.meta.keywords;
|
||||
}
|
||||
}
|
||||
|
||||
// SOCIAL MEDIA SHARING metadata
|
||||
function customizeOpenGraph() {
|
||||
if (ogType) {
|
||||
ogType.content = BRAND.og.type;
|
||||
}
|
||||
if (ogSiteName) {
|
||||
ogSiteName.content = BRAND.og.siteName;
|
||||
}
|
||||
if (ogTitle) {
|
||||
ogTitle.content = BRAND.og.title;
|
||||
}
|
||||
if (ogDescription) {
|
||||
ogDescription.content = BRAND.og.description;
|
||||
}
|
||||
if (ogImage) {
|
||||
ogImage.content = BRAND.og.image;
|
||||
}
|
||||
}
|
||||
|
||||
initialize();
|
83
Video/MiroTalk SFU/public/js/Helpers.js
Normal file
83
Video/MiroTalk SFU/public/js/Helpers.js
Normal file
@ -0,0 +1,83 @@
|
||||
'use strict';
|
||||
|
||||
class MixedAudioRecorder {
|
||||
constructor(useGainNode = true) {
|
||||
this.useGainNode = useGainNode;
|
||||
this.gainNode = null;
|
||||
this.audioSources = [];
|
||||
this.audioDestination = null;
|
||||
this.audioContext = this.createAudioContext();
|
||||
}
|
||||
|
||||
createAudioContext() {
|
||||
if (window.AudioContext) {
|
||||
return new AudioContext();
|
||||
} else if (window.webkitAudioContext) {
|
||||
return new webkitAudioContext();
|
||||
} else if (window.mozAudioContext) {
|
||||
return new mozAudioContext();
|
||||
} else {
|
||||
throw new Error('Web Audio API is not supported in this browser');
|
||||
}
|
||||
}
|
||||
|
||||
getMixedAudioStream(audioStreams) {
|
||||
this.audioSources = [];
|
||||
|
||||
if (this.useGainNode) {
|
||||
this.gainNode = this.audioContext.createGain();
|
||||
this.gainNode.connect(this.audioContext.destination);
|
||||
this.gainNode.gain.value = 0;
|
||||
}
|
||||
|
||||
audioStreams.forEach((stream) => {
|
||||
if (!stream || !stream.getTracks().filter((t) => t.kind === 'audio').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Mixed audio tracks to add on MediaStreamAudioDestinationNode --->', stream.getTracks());
|
||||
|
||||
let audioSource = this.audioContext.createMediaStreamSource(stream);
|
||||
|
||||
if (this.useGainNode) {
|
||||
audioSource.connect(this.gainNode);
|
||||
}
|
||||
this.audioSources.push(audioSource);
|
||||
});
|
||||
|
||||
this.audioDestination = this.audioContext.createMediaStreamDestination();
|
||||
this.audioSources.forEach((audioSource) => {
|
||||
audioSource.connect(this.audioDestination);
|
||||
});
|
||||
|
||||
return this.audioDestination.stream;
|
||||
}
|
||||
|
||||
stopMixedAudioStream() {
|
||||
if (this.useGainNode) {
|
||||
this.gainNode.disconnect();
|
||||
this.gainNode = null;
|
||||
}
|
||||
if (this.audioSources.length) {
|
||||
this.audioSources.forEach((source) => {
|
||||
source.disconnect();
|
||||
});
|
||||
this.audioSources = [];
|
||||
}
|
||||
if (this.audioDestination) {
|
||||
this.audioDestination.disconnect();
|
||||
this.audioDestination = null;
|
||||
}
|
||||
if (this.audioContext) {
|
||||
this.audioContext.close();
|
||||
this.audioContext = null;
|
||||
}
|
||||
console.log('Stop Mixed Audio Stream');
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
// const audioRecorder = new MixedAudioRecorder();
|
||||
// To start recording, call audioRecorder.getMixedAudioStream(audioStreams);
|
||||
// To stop recording, call audioRecorder.stopMixedAudioStream();
|
||||
// Credits: https://github.com/muaz-khan/MultiStreamsMixer
|
163
Video/MiroTalk SFU/public/js/LocalStorage.js
Normal file
163
Video/MiroTalk SFU/public/js/LocalStorage.js
Normal file
@ -0,0 +1,163 @@
|
||||
'use-strict';
|
||||
|
||||
class LocalStorage {
|
||||
constructor() {
|
||||
this.MEDIA_TYPE = {
|
||||
audio: 'audio',
|
||||
video: 'video',
|
||||
audioVideo: 'audioVideo',
|
||||
speaker: 'speaker',
|
||||
};
|
||||
|
||||
this.INIT_CONFIG = {
|
||||
audio: true,
|
||||
video: true,
|
||||
audioVideo: true,
|
||||
};
|
||||
|
||||
this.SFU_SETTINGS = {
|
||||
share_on_join: true, // popup message on join
|
||||
show_chat_on_msg: true, // show chat on new message
|
||||
transcript_persistent_mode: false, // Prevent stop transcript in case of no-speech
|
||||
transcript_show_on_msg: true, // show transcript on new message
|
||||
speech_in_msg: false, // speech incoming message
|
||||
moderator_audio_start_muted: false, // Everyone starts muted in the room
|
||||
moderator_video_start_hidden: false, // Everyone starts hidden in the room
|
||||
moderator_audio_cant_unmute: false, // Everyone can't unmute themselves
|
||||
moderator_video_cant_unhide: false, // Everyone can't unhide themselves
|
||||
moderator_screen_cant_share: false, // Everyone can't share screen
|
||||
moderator_chat_cant_privately: false, // Everyone can't chat privately, only Public chat allowed
|
||||
moderator_chat_cant_chatgpt: false, // Everyone can't chat with ChatGPT
|
||||
moderator_disconnect_all_on_leave: false, // Disconnect all participants on leave room
|
||||
mic_auto_gain_control: false,
|
||||
mic_echo_cancellations: true,
|
||||
mic_noise_suppression: true,
|
||||
mic_sample_rate: 0, // 0: 48000 Hz 1: 44100 Hz
|
||||
mic_sample_size: 0, // 0: 16 bits 1: 32 bits
|
||||
mic_channel_count: 0, // 0: 1(mono) 1: 2 (stereo)
|
||||
mic_latency: 50, // ms
|
||||
mic_volume: 100, // %
|
||||
video_fps: 0, // default 1280x768 30fps
|
||||
screen_fps: 3, // default 5fps
|
||||
broadcasting: false, // default false (one to many a/v streaming)
|
||||
lobby: false, // default false
|
||||
pitch_bar: true, // volume indicator
|
||||
sounds: true, // room notify sounds
|
||||
host_ony_recording: false, // presenter
|
||||
rec_prioritize_h264: false, // Prioritize h.264 with AAC or h.264 with Opus codecs over VP8 with Opus or VP9 with Opus codecs
|
||||
rec_server: false, // The recording will be stored on the server rather than locally
|
||||
video_obj_fit: 2, // cover
|
||||
video_controls: 0, // off
|
||||
theme: 0, // dark
|
||||
theme_color: '#000000', // custom theme color
|
||||
theme_custom: false, // keep custom theme
|
||||
buttons_bar: 0, // vertical
|
||||
pin_grid: 0, // vertical
|
||||
};
|
||||
|
||||
this.DEVICES_COUNT = {
|
||||
audio: 0,
|
||||
speaker: 0,
|
||||
video: 0,
|
||||
};
|
||||
|
||||
this.LOCAL_STORAGE_DEVICES = {
|
||||
audio: {
|
||||
count: 0,
|
||||
index: 0,
|
||||
select: null,
|
||||
},
|
||||
speaker: {
|
||||
count: 0,
|
||||
index: 0,
|
||||
select: null,
|
||||
},
|
||||
video: {
|
||||
count: 0,
|
||||
index: 0,
|
||||
select: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// SET LOCAL STORAGE
|
||||
// ####################################################
|
||||
|
||||
setItemLocalStorage(key, value) {
|
||||
localStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
setObjectLocalStorage(name, object) {
|
||||
localStorage.setItem(name, JSON.stringify(object));
|
||||
}
|
||||
|
||||
setSettings(settings) {
|
||||
this.SFU_SETTINGS = settings;
|
||||
this.setObjectLocalStorage('SFU_SETTINGS', this.SFU_SETTINGS);
|
||||
}
|
||||
|
||||
setInitConfig(type, status) {
|
||||
switch (type) {
|
||||
case this.MEDIA_TYPE.audio:
|
||||
this.INIT_CONFIG.audio = status;
|
||||
break;
|
||||
case this.MEDIA_TYPE.video:
|
||||
this.INIT_CONFIG.video = status;
|
||||
break;
|
||||
case this.MEDIA_TYPE.audioVideo:
|
||||
this.INIT_CONFIG.audioVideo = status;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.setObjectLocalStorage('INIT_CONFIG', this.INIT_CONFIG);
|
||||
}
|
||||
|
||||
setLocalStorageDevices(type, index, select) {
|
||||
switch (type) {
|
||||
case this.MEDIA_TYPE.audio:
|
||||
this.LOCAL_STORAGE_DEVICES.audio.count = this.DEVICES_COUNT.audio;
|
||||
this.LOCAL_STORAGE_DEVICES.audio.index = index;
|
||||
this.LOCAL_STORAGE_DEVICES.audio.select = select;
|
||||
break;
|
||||
case this.MEDIA_TYPE.video:
|
||||
this.LOCAL_STORAGE_DEVICES.video.count = this.DEVICES_COUNT.video;
|
||||
this.LOCAL_STORAGE_DEVICES.video.index = index;
|
||||
this.LOCAL_STORAGE_DEVICES.video.select = select;
|
||||
break;
|
||||
case this.MEDIA_TYPE.speaker:
|
||||
this.LOCAL_STORAGE_DEVICES.speaker.count = this.DEVICES_COUNT.speaker;
|
||||
this.LOCAL_STORAGE_DEVICES.speaker.index = index;
|
||||
this.LOCAL_STORAGE_DEVICES.speaker.select = select;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.setObjectLocalStorage('LOCAL_STORAGE_DEVICES', this.LOCAL_STORAGE_DEVICES);
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// GET LOCAL STORAGE
|
||||
// ####################################################
|
||||
|
||||
getLocalStorageSettings() {
|
||||
return this.getObjectLocalStorage('SFU_SETTINGS');
|
||||
}
|
||||
|
||||
getLocalStorageInitConfig() {
|
||||
return this.getObjectLocalStorage('INIT_CONFIG');
|
||||
}
|
||||
|
||||
getLocalStorageDevices() {
|
||||
return this.getObjectLocalStorage('LOCAL_STORAGE_DEVICES');
|
||||
}
|
||||
|
||||
getItemLocalStorage(key) {
|
||||
localStorage.getItem(key);
|
||||
}
|
||||
|
||||
getObjectLocalStorage(name) {
|
||||
return JSON.parse(localStorage.getItem(name));
|
||||
}
|
||||
}
|
3910
Video/MiroTalk SFU/public/js/Room.js
Normal file
3910
Video/MiroTalk SFU/public/js/Room.js
Normal file
File diff suppressed because it is too large
Load Diff
6695
Video/MiroTalk SFU/public/js/RoomClient.js
Normal file
6695
Video/MiroTalk SFU/public/js/RoomClient.js
Normal file
File diff suppressed because it is too large
Load Diff
242
Video/MiroTalk SFU/public/js/Rules.js
Normal file
242
Video/MiroTalk SFU/public/js/Rules.js
Normal file
@ -0,0 +1,242 @@
|
||||
'use-strict';
|
||||
|
||||
let isPresenter = false;
|
||||
|
||||
// ####################################################
|
||||
// SHOW HIDE DESIRED BUTTONS BY RULES
|
||||
// ####################################################
|
||||
|
||||
const isRulesActive = true;
|
||||
|
||||
/**
|
||||
* WARNING!
|
||||
* This will be replaced by the ui.buttons specified in the server configuration file located at app/src/config.js.
|
||||
* Ensure that any changes made here are also reflected in the configuration file to maintain synchronization.
|
||||
*/
|
||||
let BUTTONS = {
|
||||
main: {
|
||||
shareButton: true, // for quest, presenter default true
|
||||
hideMeButton: true,
|
||||
startAudioButton: true,
|
||||
startVideoButton: true,
|
||||
startScreenButton: true,
|
||||
swapCameraButton: true,
|
||||
chatButton: true,
|
||||
raiseHandButton: true,
|
||||
transcriptionButton: true,
|
||||
whiteboardButton: true,
|
||||
emojiRoomButton: true,
|
||||
settingsButton: true,
|
||||
aboutButton: true, // Please keep me always visible, thank you!
|
||||
exitButton: true,
|
||||
},
|
||||
settings: {
|
||||
fileSharing: true,
|
||||
lockRoomButton: true, // presenter
|
||||
unlockRoomButton: true, // presenter
|
||||
broadcastingButton: true, // presenter
|
||||
lobbyButton: true, // presenter
|
||||
sendEmailInvitation: true, // presenter
|
||||
micOptionsButton: true, // presenter
|
||||
tabModerator: true, // presenter
|
||||
tabRecording: true,
|
||||
host_only_recording: true, // presenter
|
||||
pushToTalk: true,
|
||||
},
|
||||
producerVideo: {
|
||||
videoPictureInPicture: true,
|
||||
fullScreenButton: true,
|
||||
snapShotButton: true,
|
||||
muteAudioButton: true,
|
||||
videoPrivacyButton: true,
|
||||
},
|
||||
consumerVideo: {
|
||||
videoPictureInPicture: true,
|
||||
fullScreenButton: true,
|
||||
snapShotButton: true,
|
||||
sendMessageButton: true,
|
||||
sendFileButton: true,
|
||||
sendVideoButton: true,
|
||||
muteVideoButton: true,
|
||||
muteAudioButton: true,
|
||||
audioVolumeInput: true, // Disabled for mobile
|
||||
geolocationButton: true, // Presenter
|
||||
banButton: true, // presenter
|
||||
ejectButton: true, // presenter
|
||||
},
|
||||
videoOff: {
|
||||
sendMessageButton: true,
|
||||
sendFileButton: true,
|
||||
sendVideoButton: true,
|
||||
muteAudioButton: true,
|
||||
audioVolumeInput: true, // Disabled for mobile
|
||||
geolocationButton: true, // Presenter
|
||||
banButton: true, // presenter
|
||||
ejectButton: true, // presenter
|
||||
},
|
||||
chat: {
|
||||
chatPinButton: true,
|
||||
chatMaxButton: true,
|
||||
chatSaveButton: true,
|
||||
chatEmojiButton: true,
|
||||
chatMarkdownButton: true,
|
||||
chatSpeechStartButton: true,
|
||||
chatGPT: true,
|
||||
},
|
||||
participantsList: {
|
||||
saveInfoButton: true, // presenter
|
||||
sendFileAllButton: true, // presenter
|
||||
ejectAllButton: true, // presenter
|
||||
sendFileButton: false, // presenter & guests
|
||||
geoLocationButton: true, // presenter
|
||||
banButton: true, // presenter
|
||||
ejectButton: true, // presenter
|
||||
},
|
||||
whiteboard: {
|
||||
whiteboardLockButton: true, // presenter
|
||||
},
|
||||
//...
|
||||
};
|
||||
|
||||
function handleRules(isPresenter) {
|
||||
console.log('07.1 ----> IsPresenter: ' + isPresenter);
|
||||
if (!isRulesActive) return;
|
||||
if (!isPresenter) {
|
||||
// ##################################
|
||||
// GUEST
|
||||
// ##################################
|
||||
//BUTTONS.main.shareButton = false;
|
||||
BUTTONS.participantsList.saveInfoButton = false;
|
||||
BUTTONS.settings.lockRoomButton = false;
|
||||
BUTTONS.settings.unlockRoomButton = false;
|
||||
BUTTONS.settings.broadcastingButton = false;
|
||||
BUTTONS.settings.lobbyButton = false;
|
||||
BUTTONS.settings.sendEmailInvitation = false;
|
||||
BUTTONS.settings.micOptionsButton = false;
|
||||
BUTTONS.settings.tabModerator = false;
|
||||
BUTTONS.videoOff.muteAudioButton = false;
|
||||
BUTTONS.videoOff.geolocationButton = false;
|
||||
BUTTONS.videoOff.banButton = false;
|
||||
BUTTONS.videoOff.ejectButton = false;
|
||||
BUTTONS.consumerVideo.geolocationButton = false;
|
||||
BUTTONS.consumerVideo.banButton = false;
|
||||
BUTTONS.consumerVideo.ejectButton = false;
|
||||
//BUTTONS.consumerVideo.muteAudioButton = false;
|
||||
//BUTTONS.consumerVideo.muteVideoButton = false;
|
||||
BUTTONS.whiteboard.whiteboardLockButton = false;
|
||||
//...
|
||||
} else {
|
||||
// ##################################
|
||||
// PRESENTER
|
||||
// ##################################
|
||||
BUTTONS.main.shareButton = true;
|
||||
BUTTONS.settings.lockRoomButton = BUTTONS.settings.lockRoomButton && !isRoomLocked;
|
||||
BUTTONS.settings.unlockRoomButton = BUTTONS.settings.lockRoomButton && isRoomLocked;
|
||||
BUTTONS.settings.sendEmailInvitation = true;
|
||||
//...
|
||||
|
||||
// ##################################
|
||||
// Auto detected rules for presenter
|
||||
// ##################################
|
||||
|
||||
// Room broadcasting
|
||||
isBroadcastingEnabled = localStorageSettings.broadcasting;
|
||||
switchBroadcasting.checked = isBroadcastingEnabled;
|
||||
rc.roomAction('broadcasting', true, false);
|
||||
if (isBroadcastingEnabled) rc.toggleRoomBroadcasting();
|
||||
// Room lobby
|
||||
isLobbyEnabled = localStorageSettings.lobby;
|
||||
switchLobby.checked = isLobbyEnabled;
|
||||
rc.roomAction(isLobbyEnabled ? 'lobbyOn' : 'lobbyOff', true, false);
|
||||
// Room host-only-recording
|
||||
hostOnlyRecording = localStorageSettings.host_only_recording;
|
||||
switchHostOnlyRecording.checked = hostOnlyRecording;
|
||||
rc.roomAction(hostOnlyRecording ? 'hostOnlyRecordingOn' : 'hostOnlyRecordingOff', true, false);
|
||||
// Room moderator
|
||||
switchEveryoneMute.checked = localStorageSettings.moderator_audio_start_muted;
|
||||
switchEveryoneHidden.checked = localStorageSettings.moderator_video_start_hidden;
|
||||
switchEveryoneCantUnmute.checked = localStorageSettings.moderator_audio_cant_unmute;
|
||||
switchEveryoneCantUnhide.checked = localStorageSettings.moderator_video_cant_unhide;
|
||||
switchEveryoneCantShareScreen.checked = localStorageSettings.moderator_screen_cant_share;
|
||||
switchEveryoneCantChatPrivately.checked = localStorageSettings.moderator_chat_cant_privately;
|
||||
switchEveryoneCantChatChatGPT.checked = localStorageSettings.moderator_chat_cant_chatgpt;
|
||||
switchDisconnectAllOnLeave.checked = localStorageSettings.moderator_disconnect_all_on_leave;
|
||||
|
||||
// Update moderator settings...
|
||||
const moderatorData = {
|
||||
audio_start_muted: switchEveryoneMute.checked,
|
||||
video_start_hidden: switchEveryoneHidden.checked,
|
||||
audio_cant_unmute: switchEveryoneCantUnmute.checked,
|
||||
video_cant_unhide: switchEveryoneCantUnhide.checked,
|
||||
screen_cant_share: switchEveryoneCantShareScreen.checked,
|
||||
chat_cant_privately: switchEveryoneCantChatPrivately.checked,
|
||||
chat_cant_chatgpt: switchEveryoneCantChatChatGPT.checked,
|
||||
};
|
||||
rc.updateRoomModeratorALL(moderatorData);
|
||||
}
|
||||
// main. settings...
|
||||
BUTTONS.main.shareButton ? show(shareButton) : hide(shareButton);
|
||||
BUTTONS.settings.lockRoomButton ? show(lockRoomButton) : hide(lockRoomButton);
|
||||
BUTTONS.settings.unlockRoomButton ? show(unlockRoomButton) : hide(unlockRoomButton);
|
||||
BUTTONS.settings.broadcastingButton ? show(broadcastingButton) : hide(broadcastingButton);
|
||||
BUTTONS.settings.lobbyButton ? show(lobbyButton) : hide(lobbyButton);
|
||||
BUTTONS.settings.sendEmailInvitation ? show(sendEmailInvitation) : hide(sendEmailInvitation);
|
||||
!BUTTONS.settings.micOptionsButton && hide(micOptionsButton);
|
||||
!BUTTONS.settings.tabModerator && hide(tabModeratorBtn);
|
||||
BUTTONS.participantsList.saveInfoButton ? show(participantsSaveBtn) : hide(participantsSaveBtn);
|
||||
BUTTONS.whiteboard.whiteboardLockButton
|
||||
? elemDisplay('whiteboardLockButton', true)
|
||||
: elemDisplay('whiteboardLockButton', false, 'flex');
|
||||
//...
|
||||
}
|
||||
|
||||
function handleRulesBroadcasting() {
|
||||
console.log('07.2 ----> handleRulesBroadcasting');
|
||||
BUTTONS.main.shareButton = false;
|
||||
BUTTONS.main.hideMeButton = false;
|
||||
BUTTONS.main.startAudioButton = false;
|
||||
BUTTONS.main.startVideoButton = false;
|
||||
BUTTONS.main.startScreenButton = false;
|
||||
BUTTONS.main.swapCameraButton = false;
|
||||
//BUTTONS.main.raiseHandButton = false;
|
||||
BUTTONS.main.whiteboardButton = false;
|
||||
//BUTTONS.main.emojiRoomButton = false,
|
||||
BUTTONS.main.transcriptionButton = false;
|
||||
BUTTONS.main.settingsButton = false;
|
||||
BUTTONS.participantsList.saveInfoButton = false;
|
||||
BUTTONS.settings.lockRoomButton = false;
|
||||
BUTTONS.settings.unlockRoomButton = false;
|
||||
BUTTONS.settings.lobbyButton = false;
|
||||
BUTTONS.videoOff.muteAudioButton = false;
|
||||
BUTTONS.videoOff.geolocationButton = false;
|
||||
BUTTONS.videoOff.banButton = false;
|
||||
BUTTONS.videoOff.ejectButton = false;
|
||||
BUTTONS.consumerVideo.sendMessageButton = false;
|
||||
BUTTONS.consumerVideo.sendFileButton = false;
|
||||
BUTTONS.consumerVideo.sendVideoButton = false;
|
||||
BUTTONS.consumerVideo.geolocationButton = false;
|
||||
BUTTONS.consumerVideo.banButton = false;
|
||||
BUTTONS.consumerVideo.ejectButton = false;
|
||||
BUTTONS.consumerVideo.muteAudioButton = false;
|
||||
BUTTONS.consumerVideo.muteVideoButton = false;
|
||||
BUTTONS.whiteboard.whiteboardLockButton = false;
|
||||
//...
|
||||
elemDisplay('shareButton', false);
|
||||
elemDisplay('hideMeButton', false);
|
||||
elemDisplay('startAudioButton', false);
|
||||
elemDisplay('stopAudioButton', false);
|
||||
elemDisplay('startVideoButton', false);
|
||||
elemDisplay('stopVideoButton', false);
|
||||
elemDisplay('startScreenButton', false);
|
||||
elemDisplay('stopScreenButton', false);
|
||||
elemDisplay('swapCameraButton', false);
|
||||
//elemDisplay('raiseHandButton', false);
|
||||
elemDisplay('whiteboardButton', false);
|
||||
//elemDisplay('emojiRoomButton', false);
|
||||
elemDisplay('transcriptionButton', false);
|
||||
elemDisplay('lockRoomButton', false);
|
||||
elemDisplay('unlockRoomButton', false);
|
||||
elemDisplay('lobbyButton', false);
|
||||
elemDisplay('settingsButton', false);
|
||||
//...
|
||||
}
|
50
Video/MiroTalk SFU/public/js/Snow.js
Normal file
50
Video/MiroTalk SFU/public/js/Snow.js
Normal file
@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
// https://codepen.io/tutsplus/pen/BaVqjvg
|
||||
|
||||
const snowContainer = document.getElementById('snow-container');
|
||||
|
||||
const snowContent = ['❄', '❅', '❆'];
|
||||
|
||||
const random = (num) => {
|
||||
return Math.floor(Math.random() * num);
|
||||
};
|
||||
|
||||
const getRandomStyles = () => {
|
||||
const top = random(100);
|
||||
const left = random(100);
|
||||
const dur = random(10) + 10;
|
||||
const size = random(25) + 25;
|
||||
return `
|
||||
top: -${top}%;
|
||||
left: ${left}%;
|
||||
font-size: ${size}px;
|
||||
animation-duration: ${dur}s;
|
||||
`;
|
||||
};
|
||||
|
||||
const createSnow = (num) => {
|
||||
for (let i = num; i > 0; i--) {
|
||||
let snow = document.createElement('div');
|
||||
snow.className = 'snow';
|
||||
snow.style.cssText = getRandomStyles();
|
||||
snow.innerHTML = snowContent[random(3)];
|
||||
snowContainer.append(snow);
|
||||
}
|
||||
};
|
||||
|
||||
const removeSnow = () => {
|
||||
snowContainer.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
snowContainer.remove();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
createSnow(30);
|
||||
setTimeout(removeSnow, 1000 * 60);
|
||||
});
|
||||
|
||||
window.addEventListener('click', () => {
|
||||
removeSnow();
|
||||
});
|
354
Video/MiroTalk SFU/public/js/SpeechRec.js
Normal file
354
Video/MiroTalk SFU/public/js/SpeechRec.js
Normal file
@ -0,0 +1,354 @@
|
||||
'use strict';
|
||||
|
||||
let isWebkitSpeechRecognitionSupported = false;
|
||||
let recognition;
|
||||
let isVoiceCommandsEnabled = true;
|
||||
let browserLanguage = navigator.language || navigator.userLanguage;
|
||||
let isVoiceCommandSupported = browserLanguage.includes('en-');
|
||||
|
||||
const speechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||||
|
||||
/**
|
||||
* Enable real-time voice recognition in the chat, allowing you to execute commands using your voice.
|
||||
* Note: Currently, it supports only the English language.
|
||||
* TODO make it multi languages...
|
||||
*/
|
||||
const commands = {
|
||||
shareRoom: 'room',
|
||||
hideMe: 'hide me',
|
||||
showMe: 'show me',
|
||||
newRoom: 'new room',
|
||||
leaveRoom: 'exit the room',
|
||||
audioOn: 'start the audio',
|
||||
audioOff: 'stop the audio',
|
||||
videoOn: 'start the video',
|
||||
videoOff: 'stop the video',
|
||||
screenOn: 'start the screen',
|
||||
screenOff: 'stop the screen',
|
||||
chatOn: 'open the chat',
|
||||
chatSend: 'send',
|
||||
chatOff: 'close the chat',
|
||||
toggleTr: 'toggle transcription',
|
||||
whiteboardOn: 'open the whiteboard',
|
||||
whiteboardOff: 'close the whiteboard',
|
||||
recordingOn: 'start the recording',
|
||||
recordingPause: 'pause the recording',
|
||||
recordingResume: 'resume the recording',
|
||||
recordingOff: 'stop the recording',
|
||||
settingsOn: 'open the settings',
|
||||
settingsOff: 'close the settings',
|
||||
participantsOn: 'show the participants',
|
||||
participantsOff: 'hide the participants',
|
||||
participantsVideoOff: 'stop the participants video',
|
||||
participantsAudioOff: 'stop the participants audio',
|
||||
participantsKickOut: 'kick out the participants',
|
||||
fileShareOn: 'open a file',
|
||||
fileShareOff: 'close a file',
|
||||
videoShareOn: 'share the video',
|
||||
videoShareOff: 'close the video',
|
||||
swapCamera: 'swap the camera',
|
||||
raiseHand: 'raise the hand',
|
||||
lowerHand: 'lower the hand',
|
||||
roomLock: 'lock the room',
|
||||
roomUnlock: 'unlock the room',
|
||||
about: 'show the about',
|
||||
email: 'open email',
|
||||
google: 'open google',
|
||||
googleTr: 'open google translate',
|
||||
youtube: 'open youtube',
|
||||
facebook: 'open facebook',
|
||||
linkedin: 'open linkedin',
|
||||
twitter: 'open twitter',
|
||||
tiktok: 'open tiktok',
|
||||
github: 'open github',
|
||||
survey: 'open survey',
|
||||
stopRecognition: 'stop the voice recognition',
|
||||
};
|
||||
|
||||
const browser = {
|
||||
newroom: '/newroom',
|
||||
email: 'mailto:?subject=&body=',
|
||||
google: 'https://www.google.com',
|
||||
googleTr: 'https://translate.google.com/',
|
||||
youtube: 'https://www.youtube.com',
|
||||
facebook: 'https://www.facebook.com',
|
||||
linkedin: 'https://www.linkedin.com',
|
||||
twitter: 'https://www.twitter.com',
|
||||
tiktok: 'https://www.tiktok.com',
|
||||
github: 'https://github.com/miroslavpejic85',
|
||||
};
|
||||
|
||||
if (speechRecognition) {
|
||||
recognition = new speechRecognition();
|
||||
|
||||
recognition.maxAlternatives = 1;
|
||||
recognition.continuous = true;
|
||||
recognition.lang = browserLanguage;
|
||||
|
||||
console.log('Speech recognition', recognition);
|
||||
|
||||
recognition.onstart = function () {
|
||||
console.log('Speech recognition started');
|
||||
hide(chatSpeechStartButton);
|
||||
show(chatSpeechStopButton);
|
||||
setColor(chatSpeechStopButton, 'lime');
|
||||
userLog('info', 'Speech recognition started', 'top-end');
|
||||
};
|
||||
|
||||
recognition.onresult = (e) => {
|
||||
let current = e.resultIndex;
|
||||
let transcript = e.results[current][0].transcript;
|
||||
if (transcript) {
|
||||
if (transcript.trim().toLowerCase() != commands.chatSend) {
|
||||
chatMessage.value = transcript;
|
||||
}
|
||||
if (isVoiceCommandsEnabled && isVoiceCommandSupported) {
|
||||
execVoiceCommands(transcript);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
recognition.onerror = function (event) {
|
||||
console.error('Speech recognition error', event.error);
|
||||
userLog('error', `Speech recognition error ${event.error}`, 'top-end', 6000);
|
||||
};
|
||||
|
||||
recognition.onend = function () {
|
||||
console.log('Speech recognition stopped');
|
||||
show(chatSpeechStartButton);
|
||||
hide(chatSpeechStopButton);
|
||||
setColor(chatSpeechStopButton, 'white');
|
||||
userLog('info', 'Speech recognition stopped', 'top-end');
|
||||
};
|
||||
|
||||
isWebkitSpeechRecognitionSupported = true;
|
||||
console.info('Browser supports webkitSpeechRecognition');
|
||||
} else {
|
||||
console.warn('This browser not supports webkitSpeechRecognition');
|
||||
}
|
||||
|
||||
function startSpeech() {
|
||||
recognition.lang = browserLanguage;
|
||||
recognition.start();
|
||||
}
|
||||
|
||||
function stopSpeech() {
|
||||
recognition.stop();
|
||||
}
|
||||
|
||||
function execVoiceCommands(transcript) {
|
||||
switch (transcript.trim().toLowerCase()) {
|
||||
case commands.shareRoom:
|
||||
printCommand(commands.shareRoom);
|
||||
shareButton.click();
|
||||
break;
|
||||
case commands.hideMe:
|
||||
printCommand(commands.hideMe);
|
||||
hideMeButton.click();
|
||||
break;
|
||||
case commands.showMe:
|
||||
printCommand(commands.showMe);
|
||||
hideMeButton.click();
|
||||
break;
|
||||
case commands.newRoom:
|
||||
printCommand(commands.newRoom);
|
||||
openURL(browser.newroom);
|
||||
break;
|
||||
case commands.leaveRoom:
|
||||
printCommand(commands.leaveRoom);
|
||||
exitButton.click();
|
||||
break;
|
||||
case commands.audioOn:
|
||||
printCommand(commands.audioOn);
|
||||
startAudioButton.click();
|
||||
break;
|
||||
case commands.audioOff:
|
||||
printCommand(commands.audioOff);
|
||||
stopAudioButton.click();
|
||||
break;
|
||||
case commands.videoOn:
|
||||
printCommand(commands.videoOn);
|
||||
startVideoButton.click();
|
||||
break;
|
||||
case commands.videoOff:
|
||||
printCommand(commands.videoOff);
|
||||
stopVideoButton.click();
|
||||
break;
|
||||
case commands.screenOn:
|
||||
printCommand(commands.screenOn);
|
||||
startScreenButton.click();
|
||||
break;
|
||||
case commands.screenOff:
|
||||
printCommand(commands.screenOff);
|
||||
stopScreenButton.click();
|
||||
break;
|
||||
case commands.chatOn:
|
||||
printCommand(commands.chatOn);
|
||||
chatButton.click();
|
||||
break;
|
||||
case commands.chatSend:
|
||||
printCommand(commands.chatSend);
|
||||
chatSendButton.click();
|
||||
break;
|
||||
case commands.chatOff:
|
||||
printCommand(commands.chatOff);
|
||||
chatCloseButton.click();
|
||||
break;
|
||||
case commands.toggleTr:
|
||||
transcriptionButton.click();
|
||||
break;
|
||||
case commands.whiteboardOn:
|
||||
printCommand(commands.whiteboardOn);
|
||||
whiteboardButton.click();
|
||||
break;
|
||||
case commands.whiteboardOff:
|
||||
printCommand(commands.whiteboardOff);
|
||||
whiteboardCloseBtn.click();
|
||||
break;
|
||||
case commands.recordingOn:
|
||||
printCommand(commands.recordingOn);
|
||||
startRecButton.click();
|
||||
break;
|
||||
case commands.recordingPause:
|
||||
printCommand(commands.recordingPause);
|
||||
pauseRecButton.click();
|
||||
break;
|
||||
case commands.recordingResume:
|
||||
printCommand(commands.recordingResume);
|
||||
recordingResume.click();
|
||||
break;
|
||||
case commands.recordingOff:
|
||||
printCommand(commands.recordingOff);
|
||||
stopRecButton.click();
|
||||
break;
|
||||
case commands.settingsOn:
|
||||
printCommand(commands.settingsOn);
|
||||
settingsButton.click();
|
||||
break;
|
||||
case commands.settingsOff:
|
||||
printCommand(commands.settingsOff);
|
||||
mySettingsCloseBtn.click();
|
||||
break;
|
||||
case commands.participantsOn:
|
||||
printCommand(commands.participantsOn);
|
||||
chatButton.click();
|
||||
break;
|
||||
case commands.participantsOff:
|
||||
printCommand(commands.participantsOff);
|
||||
chatCloseButton.click();
|
||||
break;
|
||||
case commands.participantsVideoOff:
|
||||
printCommand(commands.participantsVideoOff);
|
||||
rc.peerAction('me', socket.id, 'hide', true, true);
|
||||
break;
|
||||
case commands.participantsAudioOff:
|
||||
printCommand(commands.participantsAudioOff);
|
||||
rc.peerAction('me', socket.id, 'mute', true, true);
|
||||
break;
|
||||
case commands.participantsKickOut:
|
||||
printCommand(commands.participantsKickOut);
|
||||
rc.peerAction('me', socket.id, 'eject', true, true);
|
||||
break;
|
||||
case commands.fileShareOn:
|
||||
printCommand(commands.fileShareOn);
|
||||
fileShareButton.click();
|
||||
break;
|
||||
case commands.fileShareOff:
|
||||
printCommand(commands.fileShareOff);
|
||||
sendAbortBtn.click();
|
||||
break;
|
||||
case commands.videoShareOn:
|
||||
printCommand(commands.videoShareOn);
|
||||
videoShareButton.click();
|
||||
break;
|
||||
case commands.videoShareOff:
|
||||
printCommand(commands.videoShareOff);
|
||||
videoCloseBtn.click();
|
||||
break;
|
||||
case commands.swapCamera:
|
||||
printCommand(commands.swapCamera);
|
||||
swapCameraButton.click();
|
||||
break;
|
||||
case commands.raiseHand:
|
||||
printCommand(commands.raiseHand);
|
||||
raiseHandButton.click();
|
||||
break;
|
||||
case commands.lowerHand:
|
||||
printCommand(commands.lowerHand);
|
||||
lowerHandButton.click();
|
||||
break;
|
||||
case commands.roomLock:
|
||||
printCommand(commands.roomLock);
|
||||
lockRoomButton.click();
|
||||
break;
|
||||
case commands.roomUnlock:
|
||||
printCommand(commands.roomUnlock);
|
||||
unlockRoomButton.click();
|
||||
break;
|
||||
case commands.about:
|
||||
printCommand(commands.about);
|
||||
aboutButton.click();
|
||||
break;
|
||||
case commands.email:
|
||||
printCommand(commands.email);
|
||||
openURL(browser.email, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.google:
|
||||
printCommand(commands.google);
|
||||
openURL(browser.google, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.googleTr:
|
||||
printCommand(commands.googleTr);
|
||||
openURL(browser.googleTr, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.youtube:
|
||||
printCommand(commands.youtube);
|
||||
openURL(browser.youtube, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.facebook:
|
||||
printCommand(commands.facebook);
|
||||
openURL(browser.facebook, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.linkedin:
|
||||
printCommand(commands.linkedin);
|
||||
openURL(browser.linkedin, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.twitter:
|
||||
printCommand(commands.twitter);
|
||||
openURL(browser.twitter, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.tiktok:
|
||||
printCommand(commands.tiktok);
|
||||
openURL(browser.tiktok, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.github:
|
||||
printCommand(commands.github);
|
||||
openURL(browser.github, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.survey:
|
||||
printCommand(commands.survey);
|
||||
survey.enabled && openURL(survey.url, true);
|
||||
sound('open');
|
||||
break;
|
||||
case commands.stopRecognition:
|
||||
printCommand(commands.stopRecognition);
|
||||
chatSpeechStopButton.click();
|
||||
break;
|
||||
// ...
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function printCommand(command) {
|
||||
console.log('Detected', { command: command });
|
||||
}
|
429
Video/MiroTalk SFU/public/js/Transcription.js
Normal file
429
Video/MiroTalk SFU/public/js/Transcription.js
Normal file
@ -0,0 +1,429 @@
|
||||
'use strict';
|
||||
|
||||
class Transcription {
|
||||
constructor() {
|
||||
this.languages = [
|
||||
['Afrikaans', ['af-ZA']],
|
||||
['Bahasa Indonesia', ['id-ID']],
|
||||
['Bahasa Melayu', ['ms-MY']],
|
||||
['Català', ['ca-ES']],
|
||||
['Čeština', ['cs-CZ']],
|
||||
['Deutsch', ['de-DE']],
|
||||
[
|
||||
'English',
|
||||
['en-AU', 'Australia'],
|
||||
['en-CA', 'Canada'],
|
||||
['en-IN', 'India'],
|
||||
['en-NZ', 'New Zealand'],
|
||||
['en-ZA', 'South Africa'],
|
||||
['en-GB', 'United Kingdom'],
|
||||
['en-US', 'United States'],
|
||||
],
|
||||
[
|
||||
'Español',
|
||||
['es-AR', 'Argentina'],
|
||||
['es-BO', 'Bolivia'],
|
||||
['es-CL', 'Chile'],
|
||||
['es-CO', 'Colombia'],
|
||||
['es-CR', 'Costa Rica'],
|
||||
['es-EC', 'Ecuador'],
|
||||
['es-SV', 'El Salvador'],
|
||||
['es-ES', 'España'],
|
||||
['es-US', 'Estados Unidos'],
|
||||
['es-GT', 'Guatemala'],
|
||||
['es-HN', 'Honduras'],
|
||||
['es-MX', 'México'],
|
||||
['es-NI', 'Nicaragua'],
|
||||
['es-PA', 'Panamá'],
|
||||
['es-PY', 'Paraguay'],
|
||||
['es-PE', 'Perú'],
|
||||
['es-PR', 'Puerto Rico'],
|
||||
['es-DO', 'República Dominicana'],
|
||||
['es-UY', 'Uruguay'],
|
||||
['es-VE', 'Venezuela'],
|
||||
],
|
||||
['Euskara', ['eu-ES']],
|
||||
['Français', ['fr-FR']],
|
||||
['Galego', ['gl-ES']],
|
||||
['Hrvatski', ['hr_HR']],
|
||||
['IsiZulu', ['zu-ZA']],
|
||||
['Íslenska', ['is-IS']],
|
||||
['Italiano', ['it-IT', 'Italia'], ['it-CH', 'Svizzera']],
|
||||
['Magyar', ['hu-HU']],
|
||||
['Nederlands', ['nl-NL']],
|
||||
['Norsk bokmål', ['nb-NO']],
|
||||
['Polski', ['pl-PL']],
|
||||
['Português', ['pt-BR', 'Brasil'], ['pt-PT', 'Portugal']],
|
||||
['Română', ['ro-RO']],
|
||||
['Slovenčina', ['sk-SK']],
|
||||
['Suomi', ['fi-FI']],
|
||||
['Svenska', ['sv-SE']],
|
||||
['Türkçe', ['tr-TR']],
|
||||
['български', ['bg-BG']],
|
||||
['Pусский', ['ru-RU']],
|
||||
['Српски', ['sr-RS']],
|
||||
['한국어', ['ko-KR']],
|
||||
[
|
||||
'中文',
|
||||
['cmn-Hans-CN', '普通话 (中国大陆)'],
|
||||
['cmn-Hans-HK', '普通话 (香港)'],
|
||||
['cmn-Hant-TW', '中文 (台灣)'],
|
||||
['yue-Hant-HK', '粵語 (香港)'],
|
||||
],
|
||||
['日本語', ['ja-JP']],
|
||||
['Lingua latīna', ['la']],
|
||||
];
|
||||
this.speechTranscription = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||||
this.isTranscriptionSupported = false;
|
||||
this.transcriptionRunning = false;
|
||||
this.transcription;
|
||||
this.transcripts = [];
|
||||
this.isBgTransparent = false;
|
||||
this.isPinned = false;
|
||||
this.isHidden = true;
|
||||
this.isPersistentMode = false;
|
||||
this.isPersistent = false;
|
||||
this.showOnMessage = true;
|
||||
}
|
||||
|
||||
isSupported() {
|
||||
return Boolean(this.speechTranscription);
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.isSupported()) {
|
||||
this.handleLanguages();
|
||||
|
||||
this.transcription = new this.speechTranscription();
|
||||
this.transcription.maxAlternatives = 1;
|
||||
this.transcription.continuous = true;
|
||||
this.transcription.lang = transcriptionDialect.value;
|
||||
|
||||
this.transcription.onstart = function () {
|
||||
console.log('Transcription started');
|
||||
hide(transcriptionSpeechStart);
|
||||
show(transcriptionSpeechStop);
|
||||
setColor(transcriptionSpeechStatus, 'lime');
|
||||
!transcription.isPersistentMode
|
||||
? userLog('info', 'Transcription started', 'top-end')
|
||||
: (transcription.isPersistent = true);
|
||||
};
|
||||
|
||||
this.transcription.onresult = (e) => {
|
||||
const current = e.resultIndex;
|
||||
const transcript = e.results[current][0].transcript;
|
||||
const transcriptionData = {
|
||||
type: 'transcript',
|
||||
room_id: room_id,
|
||||
peer_name: peer_name,
|
||||
text_data: transcript,
|
||||
time_stamp: new Date(),
|
||||
broadcast: true,
|
||||
};
|
||||
if (transcript) {
|
||||
this.sendTranscript(transcriptionData);
|
||||
this.handleTranscript(transcriptionData);
|
||||
}
|
||||
};
|
||||
|
||||
this.transcription.onaudiostart = () => {
|
||||
console.log('Transcription start to capture your voice');
|
||||
};
|
||||
|
||||
this.transcription.onaudioend = () => {
|
||||
console.log('Transcription stop to capture your voice');
|
||||
};
|
||||
|
||||
this.transcription.onerror = function (event) {
|
||||
console.error('Transcription error', event.error);
|
||||
if (!transcription.isPersistent || !transcription.isPersistentMode)
|
||||
userLog('error', `Transcription error ${event.error}`, 'top-end', 6000);
|
||||
};
|
||||
|
||||
this.transcription.onend = function () {
|
||||
console.log('Transcription stopped');
|
||||
hide(transcriptionSpeechStop);
|
||||
show(transcriptionSpeechStart);
|
||||
setColor(transcriptionSpeechStatus, 'white');
|
||||
// Prevent stopping in the absence of speech...
|
||||
if (
|
||||
transcription.isPersistentMode &&
|
||||
transcription.isPersistent &&
|
||||
transcription.transcriptionRunning
|
||||
) {
|
||||
setTimeout(() => {
|
||||
transcription.start();
|
||||
}, 2000);
|
||||
} else {
|
||||
transcription.isPersistent = false;
|
||||
userLog('info', 'Transcription stopped', 'top-end');
|
||||
}
|
||||
};
|
||||
|
||||
this.isTranscriptionSupported = true;
|
||||
console.info('This Browser support Transcription');
|
||||
} else {
|
||||
console.warn(
|
||||
'This browser not support Transcription, check out supported browsers: https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API#browser_compatibility',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sendTranscript(transcriptionData) {
|
||||
if (rc.thereAreParticipants()) {
|
||||
//console.log('TRANSCRIPTION SEND', transcriptionData);
|
||||
rc.emitCmd(transcriptionData);
|
||||
}
|
||||
}
|
||||
|
||||
handleTranscript(transcriptionData) {
|
||||
console.log('TRANSCRIPTION TEXT', transcriptionData.text_data);
|
||||
|
||||
transcriptionData.text_data = filterXSS(transcriptionData.text_data);
|
||||
transcriptionData.peer_name = filterXSS(transcriptionData.peer_name);
|
||||
|
||||
const { peer_name, text_data } = transcriptionData;
|
||||
const time_stamp = rc.getTimeNow();
|
||||
const avatar_image = rc.isValidEmail(peer_name) ? rc.genGravatar(peer_name) : rc.genAvatarSvg(peer_name, 32);
|
||||
|
||||
if (this.isHidden) {
|
||||
if (this.showOnMessage) {
|
||||
this.toggle();
|
||||
} else {
|
||||
this.handleTranscriptionPopup(transcriptionData);
|
||||
}
|
||||
}
|
||||
|
||||
const msgHTML = `
|
||||
<div class="msg-transcription left-msg-transcription">
|
||||
<img class="msg-transcription-img" src="${avatar_image}" />
|
||||
<div class="msg-transcription-bubble">
|
||||
<div class="msg-transcription-info">
|
||||
<div class="msg-transcription-info-name">${peer_name} : ${time_stamp}</div>
|
||||
</div>
|
||||
<div class="msg-transcription-text">${text_data}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
transcriptionChat.insertAdjacentHTML('beforeend', msgHTML);
|
||||
transcriptionChat.scrollTop += 500;
|
||||
|
||||
this.transcripts.push({
|
||||
time: time_stamp,
|
||||
name: peer_name,
|
||||
caption: text_data,
|
||||
});
|
||||
rc.sound('transcript');
|
||||
}
|
||||
|
||||
handleTranscriptionPopup(transcriptionData, duration = 5000) {
|
||||
const transcriptionDisplay = document.createElement('div');
|
||||
transcriptionDisplay.className = 'animate__animated animate__fadeInUp';
|
||||
transcriptionDisplay.style.padding = '10px';
|
||||
transcriptionDisplay.style.fontSize = '1rem';
|
||||
transcriptionDisplay.style.color = '#FFF';
|
||||
transcriptionDisplay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
|
||||
transcriptionDisplay.style.borderRadius = '10px';
|
||||
transcriptionDisplay.innerText = `${transcriptionData.peer_name}: ${transcriptionData.text_data}`;
|
||||
transcriptionPopup.appendChild(transcriptionDisplay);
|
||||
setTimeout(() => {
|
||||
transcriptionDisplay.remove();
|
||||
}, duration);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (this.isHidden) {
|
||||
this.center();
|
||||
transcriptionRoom.style.display = 'block';
|
||||
rc.sound('open');
|
||||
} else {
|
||||
transcriptionRoom.style.display = 'none';
|
||||
}
|
||||
this.isHidden = !this.isHidden;
|
||||
if (this.isPinned) this.unpinned();
|
||||
resizeTranscriptionRoom();
|
||||
}
|
||||
|
||||
toggleBg() {
|
||||
this.isBgTransparent = !this.isBgTransparent;
|
||||
this.isBgTransparent
|
||||
? document.documentElement.style.setProperty('--transcription-bg', 'rgba(0, 0, 0, 0.100)')
|
||||
: setTheme();
|
||||
}
|
||||
|
||||
maximize() {
|
||||
hide(transcriptionMaxBtn);
|
||||
show(transcriptionMinBtn);
|
||||
this.center();
|
||||
document.documentElement.style.setProperty('--transcription-width', '100%');
|
||||
document.documentElement.style.setProperty('--transcription-height', '100%');
|
||||
}
|
||||
|
||||
minimize() {
|
||||
hide(transcriptionMinBtn);
|
||||
show(transcriptionMaxBtn);
|
||||
if (this.isPinned) {
|
||||
this.pinned();
|
||||
} else {
|
||||
this.center();
|
||||
document.documentElement.style.setProperty('--transcription-width', '420px');
|
||||
document.documentElement.style.setProperty('--transcription-height', '680px');
|
||||
}
|
||||
}
|
||||
|
||||
center() {
|
||||
transcriptionRoom.style.position = 'fixed';
|
||||
transcriptionRoom.style.transform = 'translate(-50%, -50%)';
|
||||
transcriptionRoom.style.top = '50%';
|
||||
transcriptionRoom.style.left = '50%';
|
||||
}
|
||||
|
||||
togglePinUnpin() {
|
||||
if (rc.isChatPinned) {
|
||||
return userLog('info', 'Please unpin the chat that appears to be currently pinned', 'top-end');
|
||||
}
|
||||
this.isPinned ? this.unpinned() : this.pinned();
|
||||
rc.sound('click');
|
||||
}
|
||||
|
||||
isPin() {
|
||||
return this.isPinned;
|
||||
}
|
||||
|
||||
pinned() {
|
||||
if (!rc.isVideoPinned) {
|
||||
rc.videoMediaContainer.style.top = 0;
|
||||
rc.videoMediaContainer.style.width = '75%';
|
||||
rc.videoMediaContainer.style.height = '100%';
|
||||
}
|
||||
this.pin();
|
||||
this.isPinned = true;
|
||||
setColor(transcriptionTogglePinBtn, 'lime');
|
||||
resizeVideoMedia();
|
||||
transcriptionRoom.style.resize = 'none';
|
||||
if (!rc.isMobileDevice) rc.makeUnDraggable(transcriptionRoom, transcriptionHeader);
|
||||
}
|
||||
|
||||
pin() {
|
||||
transcriptionRoom.style.position = 'absolute';
|
||||
transcriptionRoom.style.top = 0;
|
||||
transcriptionRoom.style.right = 0;
|
||||
transcriptionRoom.style.left = null;
|
||||
transcriptionRoom.style.transform = null;
|
||||
document.documentElement.style.setProperty('--transcription-width', '25%');
|
||||
document.documentElement.style.setProperty('--transcription-height', '100%');
|
||||
}
|
||||
|
||||
unpinned() {
|
||||
if (!rc.isVideoPinned) {
|
||||
rc.videoMediaContainer.style.top = 0;
|
||||
rc.videoMediaContainer.style.right = null;
|
||||
rc.videoMediaContainer.style.width = '100%';
|
||||
rc.videoMediaContainer.style.height = '100%';
|
||||
}
|
||||
document.documentElement.style.setProperty('--transcription-width', '420px');
|
||||
document.documentElement.style.setProperty('--transcription-height', '680px');
|
||||
hide(transcriptionMinBtn);
|
||||
show(transcriptionMaxBtn);
|
||||
this.center();
|
||||
this.isPinned = false;
|
||||
setColor(transcriptionTogglePinBtn, 'white');
|
||||
resizeVideoMedia();
|
||||
resizeTranscriptionRoom();
|
||||
transcriptionRoom.style.resize = 'both';
|
||||
if (!rc.isMobileDevice) rc.makeDraggable(transcriptionRoom, transcriptionHeader);
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.transcripts.length != 0) {
|
||||
const a = document.createElement('a');
|
||||
a.href = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(this.transcripts, null, 1));
|
||||
a.download = getDataTimeString() + room_id + '-TRANSCRIPTIONS.txt';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
rc.sound('download');
|
||||
} else {
|
||||
userLog('info', "There isn't transcriptions to save", 'top-end');
|
||||
}
|
||||
}
|
||||
|
||||
delete() {
|
||||
if (this.transcripts.length != 0) {
|
||||
Swal.fire({
|
||||
background: swalBackground,
|
||||
position: 'center',
|
||||
title: 'Clean up all transcripts?',
|
||||
imageUrl: image.delete,
|
||||
showDenyButton: true,
|
||||
confirmButtonText: `Yes`,
|
||||
denyButtonText: `No`,
|
||||
showClass: { popup: 'animate__animated animate__fadeInDown' },
|
||||
hideClass: { popup: 'animate__animated animate__fadeOutUp' },
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
let captions = transcriptionChat.firstChild;
|
||||
while (captions) {
|
||||
transcriptionChat.removeChild(captions);
|
||||
captions = transcriptionChat.firstChild;
|
||||
}
|
||||
this.transcripts = [];
|
||||
rc.sound('delete');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
userLog('info', "There isn't transcriptions to delete", 'top-end');
|
||||
}
|
||||
}
|
||||
|
||||
updateCountry() {
|
||||
for (let i = transcriptionDialect.options.length - 1; i >= 0; i--) {
|
||||
transcriptionDialect.remove(i);
|
||||
}
|
||||
let list = this.languages[transcriptionLanguage.selectedIndex];
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
transcriptionDialect.options.add(new Option(list[i][1], list[i][0]));
|
||||
}
|
||||
transcriptionDialect.style.visibility = list[1].length == 1 ? 'hidden' : 'visible';
|
||||
}
|
||||
|
||||
handleLanguages() {
|
||||
for (let i = 0; i < this.languages.length; i++) {
|
||||
transcriptionLanguage.options[i] = new Option(this.languages[i][0], i);
|
||||
}
|
||||
|
||||
transcriptionLanguage.selectedIndex = 6;
|
||||
this.updateCountry();
|
||||
|
||||
transcriptionDialect.selectedIndex = 6;
|
||||
transcriptionLanguage.onchange = () => {
|
||||
this.updateCountry();
|
||||
};
|
||||
}
|
||||
|
||||
start() {
|
||||
try {
|
||||
this.transcriptionRunning = true;
|
||||
this.transcription.lang = transcriptionDialect.value;
|
||||
this.selectDisabled(true);
|
||||
this.transcription.start();
|
||||
} catch (error) {
|
||||
this.transcriptionRunning = false;
|
||||
userLog('error', `Transcription start error ${error.message}`, 'top-end', 6000);
|
||||
console.error('Transcription start error', error);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.transcriptionRunning = false;
|
||||
this.isPersistent = false;
|
||||
this.selectDisabled(false);
|
||||
this.transcription.stop();
|
||||
}
|
||||
|
||||
selectDisabled(disabled = false) {
|
||||
transcriptionLanguage.disabled = disabled;
|
||||
transcriptionDialect.disabled = disabled;
|
||||
transcriptPersistentMode.disabled = disabled;
|
||||
}
|
||||
}
|
39
Video/MiroTalk SFU/public/js/Umami.js
Normal file
39
Video/MiroTalk SFU/public/js/Umami.js
Normal file
@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
|
||||
console.log('STATS', window.location);
|
||||
|
||||
const statsDataKey = 'statsData';
|
||||
const statsData = window.sessionStorage.getItem(statsDataKey);
|
||||
|
||||
const apiUrl = window.location.origin + '/stats';
|
||||
|
||||
if (statsData) {
|
||||
setStats(JSON.parse(statsData));
|
||||
} else {
|
||||
fetch(apiUrl, { timeout: 5000 })
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
setStats(data);
|
||||
window.sessionStorage.setItem(statsDataKey, JSON.stringify(data));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Stats fetch error', error);
|
||||
});
|
||||
}
|
||||
|
||||
function setStats(data) {
|
||||
console.log('STATS', data);
|
||||
const { enabled, src, id } = data;
|
||||
if (enabled) {
|
||||
const script = document.createElement('script');
|
||||
script.setAttribute('async', '');
|
||||
script.setAttribute('src', src);
|
||||
script.setAttribute('data-website-id', id);
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
}
|
218
Video/MiroTalk SFU/public/js/VideoGrid.js
Normal file
218
Video/MiroTalk SFU/public/js/VideoGrid.js
Normal file
@ -0,0 +1,218 @@
|
||||
'use strict';
|
||||
|
||||
// ####################################################
|
||||
// RESPONSIVE PARTICIPANTS VIEW
|
||||
// ####################################################
|
||||
|
||||
let customRatio = true;
|
||||
|
||||
// aspect 0 1 2 3 4
|
||||
let ratios = ['0:0', '4:3', '16:9', '1:1', '1:2'];
|
||||
let aspect = 2;
|
||||
|
||||
let ratio = getAspectRatio();
|
||||
|
||||
function getAspectRatio() {
|
||||
customRatio = aspect == 0 ? true : false;
|
||||
var ratio = ratios[aspect].split(':');
|
||||
return ratio[1] / ratio[0];
|
||||
}
|
||||
|
||||
function setAspectRatio(i) {
|
||||
aspect = i;
|
||||
ratio = getAspectRatio();
|
||||
resizeVideoMedia();
|
||||
}
|
||||
|
||||
function Area(Increment, Count, Width, Height, Margin = 10) {
|
||||
ratio = customRatio ? 0.75 : ratio;
|
||||
let i = 0;
|
||||
let w = 0;
|
||||
let h = Increment * ratio + Margin * 2;
|
||||
while (i < Count) {
|
||||
if (w + Increment > Width) {
|
||||
w = 0;
|
||||
h = h + Increment * ratio + Margin * 2;
|
||||
}
|
||||
w = w + Increment + Margin * 2;
|
||||
i++;
|
||||
}
|
||||
if (h > Height) return false;
|
||||
else return Increment;
|
||||
}
|
||||
|
||||
function resizeVideoMedia() {
|
||||
let Margin = 5;
|
||||
let videoMediaContainer = document.getElementById('videoMediaContainer');
|
||||
let Cameras = document.getElementsByClassName('Camera');
|
||||
let Width = videoMediaContainer.offsetWidth - Margin * 2;
|
||||
let Height = videoMediaContainer.offsetHeight - Margin * 2;
|
||||
let max = 0;
|
||||
let optional = isHideMeActive && videoMediaContainer.childElementCount <= 2 ? 1 : 0;
|
||||
let isOneVideoElement = videoMediaContainer.childElementCount - optional == 1 ? true : false;
|
||||
|
||||
// console.log('videoMediaContainer.childElementCount', {
|
||||
// isOneVideoElement: isOneVideoElement,
|
||||
// children: videoMediaContainer.childElementCount,
|
||||
// optional: optional,
|
||||
// });
|
||||
|
||||
// full screen mode
|
||||
let bigWidth = Width * 4;
|
||||
if (isOneVideoElement) {
|
||||
Width = Width - bigWidth;
|
||||
}
|
||||
|
||||
resetZoom();
|
||||
|
||||
// loop (i recommend you optimize this)
|
||||
let i = 1;
|
||||
while (i < 5000) {
|
||||
let w = Area(i, Cameras.length, Width, Height, Margin);
|
||||
if (w === false) {
|
||||
max = i - 1;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
max = max - Margin * 2;
|
||||
setWidth(Cameras, max, bigWidth, Margin, Height, isOneVideoElement);
|
||||
document.documentElement.style.setProperty('--vmi-wh', max / 3 + 'px');
|
||||
}
|
||||
|
||||
function resetZoom() {
|
||||
const videoElements = document.querySelectorAll('video');
|
||||
videoElements.forEach((video) => {
|
||||
video.style.transform = '';
|
||||
video.style.transformOrigin = 'center';
|
||||
});
|
||||
}
|
||||
|
||||
function setWidth(Cameras, width, bigWidth, margin, maxHeight, isOneVideoElement) {
|
||||
ratio = customRatio ? 0.68 : ratio;
|
||||
for (let s = 0; s < Cameras.length; s++) {
|
||||
Cameras[s].style.width = width + 'px';
|
||||
Cameras[s].style.margin = margin + 'px';
|
||||
Cameras[s].style.height = width * ratio + 'px';
|
||||
if (isOneVideoElement) {
|
||||
Cameras[s].style.width = bigWidth + 'px';
|
||||
Cameras[s].style.height = bigWidth * ratio + 'px';
|
||||
let camHeigh = Cameras[s].style.height.substring(0, Cameras[s].style.height.length - 2);
|
||||
if (camHeigh >= maxHeight) Cameras[s].style.height = maxHeight - 2 + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// BREAKPOINTS
|
||||
// ####################################################
|
||||
|
||||
const MOBILE_BREAKPOINT = 500;
|
||||
const TABLET_BREAKPOINT = 580;
|
||||
const DESKTOP_BREAKPOINT = 730;
|
||||
const CUSTOM_BREAKPOINT = 680;
|
||||
|
||||
// ####################################################
|
||||
// RESPONSIVE MAIN BUTTONS
|
||||
// ####################################################
|
||||
|
||||
const mainButtonsBar = document.querySelectorAll('#control button');
|
||||
const mainButtonsIcon = document.querySelectorAll('#control button i');
|
||||
|
||||
function resizeMainButtons() {
|
||||
const windowWidth = window.innerWidth;
|
||||
const windowHeight = window.innerHeight;
|
||||
const isButtonsBarVertical = BtnsBarPosition.selectedIndex === 0;
|
||||
//console.log('Window size', { width: windowWidth, height: windowWidth});
|
||||
if (isButtonsBarVertical) {
|
||||
// Main buttons vertical align
|
||||
if (windowHeight <= MOBILE_BREAKPOINT) {
|
||||
setStyles(mainButtonsBar, '0.7rem', '4px', mainButtonsIcon, '0.8rem', '40px');
|
||||
} else if (windowHeight <= TABLET_BREAKPOINT) {
|
||||
setStyles(mainButtonsBar, '0.9rem', '4px', mainButtonsIcon, '1rem', '45px');
|
||||
} else if (windowHeight <= DESKTOP_BREAKPOINT) {
|
||||
setStyles(mainButtonsBar, '1rem', '5px', mainButtonsIcon, '1.1rem', '50px');
|
||||
} else {
|
||||
// > DESKTOP_BREAKPOINT
|
||||
setStyles(mainButtonsBar, '1rem', '10px', mainButtonsIcon, '1.2rem', '60px');
|
||||
}
|
||||
} else {
|
||||
// Main buttons horizontal align
|
||||
if (windowWidth <= MOBILE_BREAKPOINT) {
|
||||
setStyles(mainButtonsBar, '0.7rem', '4px', mainButtonsIcon, '0.8rem');
|
||||
} else if (windowWidth <= TABLET_BREAKPOINT) {
|
||||
setStyles(mainButtonsBar, '0.9rem', '4px', mainButtonsIcon, '1rem');
|
||||
} else if (windowWidth <= DESKTOP_BREAKPOINT) {
|
||||
setStyles(mainButtonsBar, '1rem', '5px', mainButtonsIcon, '1.1rem');
|
||||
} else {
|
||||
// > DESKTOP_BREAKPOINT
|
||||
setStyles(mainButtonsBar, '1rem', '10px', mainButtonsIcon, '1.2rem');
|
||||
}
|
||||
}
|
||||
//
|
||||
function setStyles(elements, fontSize, padding, icons, fontSizeIcon, bWidth = null) {
|
||||
if (bWidth) document.documentElement.style.setProperty('--btns-width', bWidth);
|
||||
|
||||
elements.forEach(function (element) {
|
||||
element.style.fontSize = fontSize;
|
||||
element.style.padding = padding;
|
||||
});
|
||||
icons.forEach(function (icon) {
|
||||
icon.style.fontSize = fontSizeIcon;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// RESPONSIVE CHAT
|
||||
// ####################################################
|
||||
|
||||
function resizeChatRoom() {
|
||||
if (!rc || rc.isMobileDevice || !rc.isChatOpen || rc.isChatPinned) return;
|
||||
|
||||
const windowWidth = window.innerWidth;
|
||||
const windowHeight = window.innerHeight;
|
||||
|
||||
windowWidth <= DESKTOP_BREAKPOINT || windowHeight <= DESKTOP_BREAKPOINT ? rc.chatMaximize() : rc.chatMinimize();
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// RESPONSIVE TRANSCRIPTION
|
||||
// ####################################################
|
||||
|
||||
function resizeTranscriptionRoom() {
|
||||
if (
|
||||
DetectRTC.isMobileDevice ||
|
||||
!Boolean(transcription.speechTranscription) ||
|
||||
transcription.isHidden ||
|
||||
transcription.isPinned
|
||||
)
|
||||
return;
|
||||
|
||||
const windowWidth = window.innerWidth;
|
||||
const windowHeight = window.innerHeight;
|
||||
|
||||
windowWidth <= CUSTOM_BREAKPOINT || windowHeight <= CUSTOM_BREAKPOINT
|
||||
? transcription.maximize()
|
||||
: transcription.minimize();
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
// WINDOW LOAD/RESIZE EVENT
|
||||
// ####################################################
|
||||
|
||||
window.addEventListener(
|
||||
'load',
|
||||
function (event) {
|
||||
resizeVideoMedia();
|
||||
resizeMainButtons();
|
||||
window.onresize = function () {
|
||||
resizeVideoMedia();
|
||||
resizeMainButtons();
|
||||
resizeChatRoom();
|
||||
resizeTranscriptionRoom();
|
||||
};
|
||||
},
|
||||
false,
|
||||
);
|
419
Video/MiroTalk SFU/public/js/landing.js
Normal file
419
Video/MiroTalk SFU/public/js/landing.js
Normal file
@ -0,0 +1,419 @@
|
||||
!(function () {
|
||||
window;
|
||||
const e = document.documentElement;
|
||||
if ((e.classList.remove('no-js'), e.classList.add('js'), document.body.classList.contains('has-animations'))) {
|
||||
(window.sr = ScrollReveal()).reveal('.feature, .pricing-table-inner', {
|
||||
duration: 600,
|
||||
distance: '20px',
|
||||
easing: 'cubic-bezier(0.5, -0.01, 0, 1.005)',
|
||||
origin: 'bottom',
|
||||
interval: 100,
|
||||
}),
|
||||
e.classList.add('anime-ready'),
|
||||
anime
|
||||
.timeline({ targets: '.hero-figure-box-05' })
|
||||
.add({
|
||||
duration: 400,
|
||||
easing: 'easeInOutExpo',
|
||||
scaleX: [0.05, 0.05],
|
||||
scaleY: [0, 1],
|
||||
perspective: '500px',
|
||||
delay: anime.random(0, 400),
|
||||
})
|
||||
.add({ duration: 400, easing: 'easeInOutExpo', scaleX: 1 })
|
||||
.add({
|
||||
duration: 800,
|
||||
rotateY: '-15deg',
|
||||
rotateX: '8deg',
|
||||
rotateZ: '-1deg',
|
||||
}),
|
||||
anime
|
||||
.timeline({ targets: '.hero-figure-box-06, .hero-figure-box-07' })
|
||||
.add({
|
||||
duration: 400,
|
||||
easing: 'easeInOutExpo',
|
||||
scaleX: [0.05, 0.05],
|
||||
scaleY: [0, 1],
|
||||
perspective: '500px',
|
||||
delay: anime.random(0, 400),
|
||||
})
|
||||
.add({ duration: 400, easing: 'easeInOutExpo', scaleX: 1 })
|
||||
.add({ duration: 800, rotateZ: '20deg' }),
|
||||
anime({
|
||||
targets:
|
||||
'.hero-figure-box-01, .hero-figure-box-02, .hero-figure-box-03, .hero-figure-box-04, .hero-figure-box-08, .hero-figure-box-09, .hero-figure-box-10',
|
||||
duration: anime.random(600, 800),
|
||||
delay: anime.random(600, 800),
|
||||
rotate: [
|
||||
anime.random(-360, 360),
|
||||
function (e) {
|
||||
return e.getAttribute('data-rotation');
|
||||
},
|
||||
],
|
||||
scale: [0.7, 1],
|
||||
opacity: [0, 1],
|
||||
easing: 'easeInOutExpo',
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
const e = document.querySelectorAll('[class*=reveal-]');
|
||||
let t = window.innerHeight;
|
||||
|
||||
function n(e, t) {
|
||||
let n = 0;
|
||||
return function () {
|
||||
let i = new Date().getTime();
|
||||
if (!(i - n < e)) return (n = i), t.apply(void 0, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
function i() {
|
||||
let n;
|
||||
for (let i = 0; i < e.length; i++) {
|
||||
let s = e[i],
|
||||
a = s.getAttribute('data-reveal-delay'),
|
||||
l = s.getAttribute('data-reveal-offset') ? s.getAttribute('data-reveal-offset') : '200',
|
||||
c = s.getAttribute('data-reveal-container') ? s.closest(s.getAttribute('data-reveal-container')) : s;
|
||||
(n = l),
|
||||
c.getBoundingClientRect().top <= t - n &&
|
||||
!s.classList.contains('is-revealed') &&
|
||||
(a && 0 !== a
|
||||
? setTimeout(function () {
|
||||
s.classList.add('is-revealed');
|
||||
}, a)
|
||||
: s.classList.add('is-revealed'));
|
||||
}
|
||||
!(function () {
|
||||
if (e.length > document.querySelectorAll('[class*=reveal-].is-revealed').length) return;
|
||||
window.removeEventListener('load', i),
|
||||
window.removeEventListener('scroll', s),
|
||||
window.removeEventListener('resize', a);
|
||||
})();
|
||||
}
|
||||
|
||||
function s() {
|
||||
n(30, i());
|
||||
}
|
||||
|
||||
function a() {
|
||||
(t = window.innerHeight), n(30, i());
|
||||
}
|
||||
|
||||
e.length > 0 &&
|
||||
document.body.classList.contains('has-animations') &&
|
||||
(window.addEventListener('load', i),
|
||||
window.addEventListener('scroll', s),
|
||||
window.addEventListener('resize', a));
|
||||
})();
|
||||
|
||||
!(function () {
|
||||
'use strict';
|
||||
const e = document.getElementsByClassName('accordion-header');
|
||||
|
||||
function t(e, t) {
|
||||
e.classList.add('is-active'), (t.style.maxHeight = t.scrollHeight + 'px');
|
||||
}
|
||||
|
||||
function n(e, t) {
|
||||
e.classList.remove('is-active'), (t.style.maxHeight = null);
|
||||
}
|
||||
|
||||
if (e.length > 0)
|
||||
for (let i = 0; i < e.length; i++) {
|
||||
const s = e[i],
|
||||
a = s.parentNode,
|
||||
l = s.nextElementSibling;
|
||||
a.classList.contains('is-active') && t(a, l),
|
||||
s.addEventListener('click', function () {
|
||||
a.classList.contains('is-active') ? n(a, l) : t(a, l);
|
||||
});
|
||||
}
|
||||
})(),
|
||||
(function () {
|
||||
'use strict';
|
||||
let e = {
|
||||
touchStartX: 0,
|
||||
touchEndX: 0,
|
||||
minSwipePixels: 30,
|
||||
detectionZone: void 0,
|
||||
swipeCallback: function () {},
|
||||
init: function (t, n) {
|
||||
(e.swipeCallback = n),
|
||||
t.addEventListener(
|
||||
'touchstart',
|
||||
function (t) {
|
||||
e.touchStartX = t.changedTouches[0].screenX;
|
||||
},
|
||||
!1,
|
||||
),
|
||||
t.addEventListener(
|
||||
'touchend',
|
||||
function (t) {
|
||||
(e.touchEndX = t.changedTouches[0].screenX), e.handleSwipeGesture();
|
||||
},
|
||||
!1,
|
||||
);
|
||||
},
|
||||
handleSwipeGesture: function () {
|
||||
let t, n;
|
||||
e.touchEndX <= e.touchStartX && ((n = e.touchStartX - e.touchEndX), (t = 'left')),
|
||||
e.touchEndX >= e.touchStartX && ((n = e.touchEndX - e.touchStartX), (t = 'right')),
|
||||
n > e.minSwipePixels && 'undefined' !== t && e.swipe(t, n);
|
||||
},
|
||||
swipe: function (t, n) {
|
||||
let i = {};
|
||||
(i.direction = t), (i.movedPixels = n), e.swipeCallback(i);
|
||||
},
|
||||
};
|
||||
const t = document.getElementsByClassName('carousel-items');
|
||||
|
||||
function n(e, t) {
|
||||
void 0 === t && (t = 'next');
|
||||
let n = e.getElementsByClassName('carousel-item is-active')[0],
|
||||
i = 'next' === t ? n.nextElementSibling : n.previousElementSibling,
|
||||
s = n.getAttribute('data-carousel'),
|
||||
a = e.parentNode.getElementsByClassName('carousel-bullet')[s],
|
||||
l = 'next' === t ? a.nextElementSibling : a.previousElementSibling;
|
||||
n.classList.remove('is-active'),
|
||||
a.classList.remove('is-active'),
|
||||
i
|
||||
? (i.classList.add('is-active'), l.classList.add('is-active'))
|
||||
: 'next' === t
|
||||
? (e.firstElementChild.classList.add('is-active'),
|
||||
e.parentNode
|
||||
.getElementsByClassName('carousel-bullets')[0]
|
||||
.firstElementChild.classList.add('is-active'))
|
||||
: (e.lastElementChild.classList.add('is-active'),
|
||||
e.parentNode
|
||||
.getElementsByClassName('carousel-bullets')[0]
|
||||
.lastElementChild.classList.add('is-active'));
|
||||
}
|
||||
|
||||
function i(e, t) {
|
||||
let n,
|
||||
i = 0;
|
||||
for (let e = 0; e < t.length; e++)
|
||||
(t[0].parentNode.style.minHeight = i + 'px'),
|
||||
t[e].classList.add('is-loading'),
|
||||
(n = t[e].offsetHeight),
|
||||
t[e].classList.remove('is-loading'),
|
||||
n > i && (i = n);
|
||||
t[0].parentNode.style.minHeight = i + 'px';
|
||||
}
|
||||
|
||||
function s(e) {
|
||||
e && clearInterval(e);
|
||||
}
|
||||
|
||||
if (t.length > 0)
|
||||
for (let a = 0; a < t.length; a++) {
|
||||
let l = t[a],
|
||||
c = l.getElementsByClassName('carousel-item'),
|
||||
o = 0,
|
||||
r = l.getAttribute('data-autorotate');
|
||||
const d = document.createElement('div');
|
||||
(d.className = 'carousel-bullets'), l.parentNode.insertBefore(d, l.nextSibling);
|
||||
for (let e = 0; e < c.length; e++) {
|
||||
c[e].setAttribute('data-carousel', e), c[e].classList.contains('is-active') && (o = e);
|
||||
let t = document.createElement('button');
|
||||
(t.className = 'carousel-bullet'),
|
||||
t.setAttribute('data-bullet', e),
|
||||
l.parentNode.getElementsByClassName('carousel-bullets')[0].appendChild(t);
|
||||
}
|
||||
c[o].classList.add('is-active');
|
||||
let u = l.parentNode.getElementsByClassName('carousel-bullet');
|
||||
u[o].classList.add('is-active'),
|
||||
i(0, c),
|
||||
window.addEventListener('resize', function () {
|
||||
i(0, c);
|
||||
});
|
||||
let m = !1;
|
||||
r &&
|
||||
(m = setInterval(function () {
|
||||
n(l, 'next');
|
||||
}, r));
|
||||
for (let e = 0; e < u.length; e++) {
|
||||
let t = u[e];
|
||||
t.addEventListener('click', function (e) {
|
||||
if ((e.preventDefault(), t.classList.contains('is-active'))) return;
|
||||
for (let e = 0; e < u.length; e++) u[e].classList.remove('is-active');
|
||||
for (let e = 0; e < c.length; e++) c[e].classList.remove('is-active');
|
||||
let n = this.getAttribute('data-bullet');
|
||||
c[n].classList.add('is-active'), this.classList.add('is-active'), s(m);
|
||||
});
|
||||
}
|
||||
e.init(l, function (e) {
|
||||
'left' === e.direction ? n(l, 'next') : 'right' === e.direction && n(l, 'prev'), s(m);
|
||||
});
|
||||
}
|
||||
})(),
|
||||
(function () {
|
||||
'use strict';
|
||||
document.documentElement.classList.remove('no-js'),
|
||||
document.documentElement.classList.add('js'),
|
||||
window.addEventListener('load', function () {
|
||||
document.body.classList.add('is-loaded');
|
||||
});
|
||||
})(),
|
||||
(function () {
|
||||
'use strict';
|
||||
const e = document.getElementById('header-nav-toggle'),
|
||||
t = document.getElementById('header-nav');
|
||||
e &&
|
||||
(e.addEventListener('click', function () {
|
||||
document.body.classList.toggle('off-nav-is-active'),
|
||||
t.classList.toggle('is-active'),
|
||||
t.style.maxHeight ? (t.style.maxHeight = null) : (t.style.maxHeight = t.scrollHeight + 'px'),
|
||||
'true' === this.getAttribute('aria-expanded')
|
||||
? this.setAttribute('aria-expanded', 'false')
|
||||
: this.setAttribute('aria-expanded', 'true');
|
||||
}),
|
||||
document.addEventListener('click', function (n) {
|
||||
n.target === t ||
|
||||
n.target === e ||
|
||||
t.contains(n.target) ||
|
||||
(document.body.classList.remove('off-nav-is-active'),
|
||||
t.classList.remove('is-active'),
|
||||
(t.style.maxHeight = null),
|
||||
e.setAttribute('aria-expanded', 'false'));
|
||||
}));
|
||||
})(),
|
||||
(function () {
|
||||
'use strict';
|
||||
const e = document.getElementsByClassName('modal'),
|
||||
t = document.getElementsByClassName('modal-trigger');
|
||||
|
||||
function n() {
|
||||
document.body.classList.remove('modal-is-active');
|
||||
for (let t = 0; t < e.length; t++) e[t].classList.remove('is-active');
|
||||
}
|
||||
|
||||
if (e.length > 0 && t.length > 0)
|
||||
for (let e = 0; e < t.length; e++) {
|
||||
let n = t[e],
|
||||
i = document.getElementById(n.getAttribute('aria-controls'));
|
||||
i &&
|
||||
(n.hasAttribute('data-video') &&
|
||||
(null !== i.querySelector('iframe')
|
||||
? i.querySelector('iframe').setAttribute('src', n.getAttribute('data-video'))
|
||||
: null !== i.querySelector('video') &&
|
||||
i.querySelector('video').setAttribute('src', n.getAttribute('data-video'))),
|
||||
n.addEventListener('click', function (e) {
|
||||
let t;
|
||||
e.preventDefault(),
|
||||
n.hasAttribute('aria-controls') &&
|
||||
(t = i) &&
|
||||
(document.body.classList.add('modal-is-active'), t.classList.add('is-active'));
|
||||
}));
|
||||
}
|
||||
document.addEventListener('click', function (e) {
|
||||
(e.target.classList.contains('modal') || e.target.classList.contains('modal-close-trigger')) &&
|
||||
(e.preventDefault(), n());
|
||||
}),
|
||||
document.addEventListener('keydown', function (e) {
|
||||
27 === (e || window.event).keyCode && n();
|
||||
});
|
||||
})(),
|
||||
(function () {
|
||||
'use strict';
|
||||
const e = document.getElementById('pricing-toggle');
|
||||
|
||||
function t() {
|
||||
const t = document.getElementsByClassName('pricing-switchable');
|
||||
if (e.checked) for (let e = 0; e < t.length; e++) t[e].innerHTML = t[e].getAttribute('data-pricing-yearly');
|
||||
else for (let e = 0; e < t.length; e++) t[e].innerHTML = t[e].getAttribute('data-pricing-monthly');
|
||||
}
|
||||
|
||||
e && (window.addEventListener('load', t), e.addEventListener('change', t));
|
||||
})(),
|
||||
(function () {
|
||||
'use strict';
|
||||
const e = document.querySelectorAll('[class*=reveal-]');
|
||||
let t = window.innerHeight;
|
||||
|
||||
function n(e, t) {
|
||||
let n = 0;
|
||||
return function () {
|
||||
let i = new Date().getTime();
|
||||
if (!(i - n < e)) return (n = i), t.apply(void 0, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
function i() {
|
||||
let n;
|
||||
for (let i = 0; i < e.length; i++) {
|
||||
let s = e[i],
|
||||
a = s.getAttribute('data-reveal-delay'),
|
||||
l = s.getAttribute('data-reveal-offset') ? s.getAttribute('data-reveal-offset') : '200',
|
||||
c = s.getAttribute('data-reveal-container')
|
||||
? s.closest(s.getAttribute('data-reveal-container'))
|
||||
: s;
|
||||
(n = l),
|
||||
c.getBoundingClientRect().top <= t - n &&
|
||||
!s.classList.contains('is-revealed') &&
|
||||
(a && 0 !== a
|
||||
? setTimeout(function () {
|
||||
s.classList.add('is-revealed');
|
||||
}, a)
|
||||
: s.classList.add('is-revealed'));
|
||||
}
|
||||
!(function () {
|
||||
if (e.length > document.querySelectorAll('[class*=reveal-].is-revealed').length) return;
|
||||
window.removeEventListener('load', i),
|
||||
window.removeEventListener('scroll', s),
|
||||
window.removeEventListener('resize', a);
|
||||
})();
|
||||
}
|
||||
|
||||
function s() {
|
||||
n(30, i());
|
||||
}
|
||||
|
||||
function a() {
|
||||
(t = window.innerHeight), n(30, i());
|
||||
}
|
||||
|
||||
e.length > 0 &&
|
||||
document.body.classList.contains('has-animations') &&
|
||||
(window.addEventListener('load', i),
|
||||
window.addEventListener('scroll', s),
|
||||
window.addEventListener('resize', a));
|
||||
})(),
|
||||
(function () {
|
||||
'use strict';
|
||||
const e = document.getElementsByClassName('smooth-scroll'),
|
||||
t = (e, n, i, s, a) => {
|
||||
const l = n - e;
|
||||
let c = l / i;
|
||||
const o = (function (e) {
|
||||
return e < 0.5 ? 2 * e * e : (4 - 2 * e) * e - 1;
|
||||
})((c = Math.min(c, 1)));
|
||||
window.scroll(0, a + s * o),
|
||||
l < i &&
|
||||
window.requestAnimationFrame((n) => {
|
||||
const l = n || new Date().getTime();
|
||||
t(e, l, i, s, a);
|
||||
});
|
||||
};
|
||||
if (e.length > 0)
|
||||
for (let n = 0; n < e.length; n++) {
|
||||
e[n].addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const n = e.target.closest('.smooth-scroll'),
|
||||
i = n.href.split('#')[1],
|
||||
s = document.getElementById(i),
|
||||
a = n.getAttribute('data-duration') || 1e3;
|
||||
s &&
|
||||
window.requestAnimationFrame((e) => {
|
||||
const n = e || new Date().getTime(),
|
||||
i = n,
|
||||
l = window.pageYOffset,
|
||||
c = s.getBoundingClientRect().top;
|
||||
t(i, n, a, c, l);
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
155
Video/MiroTalk SFU/public/js/newRoom.js
Normal file
155
Video/MiroTalk SFU/public/js/newRoom.js
Normal file
@ -0,0 +1,155 @@
|
||||
'use strict';
|
||||
|
||||
const adjectives = [
|
||||
'small',
|
||||
'big',
|
||||
'large',
|
||||
'smelly',
|
||||
'new',
|
||||
'happy',
|
||||
'shiny',
|
||||
'old',
|
||||
'clean',
|
||||
'nice',
|
||||
'bad',
|
||||
'cool',
|
||||
'hot',
|
||||
'cold',
|
||||
'warm',
|
||||
'hungry',
|
||||
'slow',
|
||||
'fast',
|
||||
'red',
|
||||
'white',
|
||||
'black',
|
||||
'blue',
|
||||
'green',
|
||||
'basic',
|
||||
'strong',
|
||||
'cute',
|
||||
'poor',
|
||||
'nice',
|
||||
'huge',
|
||||
'rare',
|
||||
'lucky',
|
||||
'weak',
|
||||
'tall',
|
||||
'short',
|
||||
'tiny',
|
||||
'great',
|
||||
'long',
|
||||
'single',
|
||||
'rich',
|
||||
'young',
|
||||
'dirty',
|
||||
'fresh',
|
||||
'brown',
|
||||
'dark',
|
||||
'crazy',
|
||||
'sad',
|
||||
'loud',
|
||||
'brave',
|
||||
'calm',
|
||||
'silly',
|
||||
'smart',
|
||||
];
|
||||
|
||||
const nouns = [
|
||||
'dog',
|
||||
'bat',
|
||||
'wrench',
|
||||
'apple',
|
||||
'pear',
|
||||
'ghost',
|
||||
'cat',
|
||||
'wolf',
|
||||
'squid',
|
||||
'goat',
|
||||
'snail',
|
||||
'hat',
|
||||
'sock',
|
||||
'plum',
|
||||
'bear',
|
||||
'snake',
|
||||
'turtle',
|
||||
'horse',
|
||||
'spoon',
|
||||
'fork',
|
||||
'spider',
|
||||
'tree',
|
||||
'chair',
|
||||
'table',
|
||||
'couch',
|
||||
'towel',
|
||||
'panda',
|
||||
'bread',
|
||||
'grape',
|
||||
'cake',
|
||||
'brick',
|
||||
'rat',
|
||||
'mouse',
|
||||
'bird',
|
||||
'oven',
|
||||
'phone',
|
||||
'photo',
|
||||
'frog',
|
||||
'bear',
|
||||
'camel',
|
||||
'sheep',
|
||||
'shark',
|
||||
'tiger',
|
||||
'zebra',
|
||||
'duck',
|
||||
'eagle',
|
||||
'fish',
|
||||
'kitten',
|
||||
'lobster',
|
||||
'monkey',
|
||||
'owl',
|
||||
'puppy',
|
||||
'pig',
|
||||
'rabbit',
|
||||
'fox',
|
||||
'whale',
|
||||
'beaver',
|
||||
'gorilla',
|
||||
'lizard',
|
||||
'parrot',
|
||||
'sloth',
|
||||
'swan',
|
||||
];
|
||||
|
||||
function getRandomNumber(length) {
|
||||
let result = '';
|
||||
let characters = '0123456789';
|
||||
let charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
let adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
|
||||
let noun = nouns[Math.floor(Math.random() * nouns.length)];
|
||||
let num = getRandomNumber(5);
|
||||
noun = noun.charAt(0).toUpperCase() + noun.substring(1);
|
||||
adjective = adjective.charAt(0).toUpperCase() + adjective.substring(1);
|
||||
document.getElementById('roomName').value = '';
|
||||
|
||||
// ####################################################
|
||||
// TYPING EFFECT
|
||||
// ####################################################
|
||||
|
||||
let i = 0;
|
||||
let txt = num + adjective + noun;
|
||||
let speed = 100;
|
||||
|
||||
function typeWriter() {
|
||||
if (i < txt.length) {
|
||||
document.getElementById('roomName').value += txt.charAt(i);
|
||||
i++;
|
||||
setTimeout(typeWriter, speed);
|
||||
}
|
||||
}
|
||||
|
||||
typeWriter();
|
Reference in New Issue
Block a user