[mirotalksfu] - add YouTube share video

هذا الالتزام موجود في:
Miroslav Pejic
2021-10-03 17:11:19 +02:00
الأصل d9082c8ac0
التزام 447040110a
8 ملفات معدلة مع 159 إضافات و5 حذوفات

عرض الملف

@@ -20,6 +20,7 @@ Powered by `WebRTC` with [SFU](https://mediasoup.org) integrated server.
- Collaborative whiteboard for the teachers - Collaborative whiteboard for the teachers
- Select Microphone - Speaker and Video source - Select Microphone - Speaker and Video source
- Recording your Screen, Audio or Video - Recording your Screen, Audio or Video
- Share any YouTube video in real time to your participants
- Full Screen Mode on mouse click on the Video element - Full Screen Mode on mouse click on the Video element
- Supports [REST API](api/README.md) (Application Programming Interface) - Supports [REST API](api/README.md) (Application Programming Interface)

عرض الملف

@@ -139,6 +139,14 @@ access to use this app.
<button id="startScreenButton" class="hidden"><i class="fas fa-desktop"></i> Start screen</button> <button id="startScreenButton" class="hidden"><i class="fas fa-desktop"></i> Start screen</button>
<button id="stopScreenButton" class="hidden"><i class="fas fa-stop-circle"></i> Stop screen</button> <button id="stopScreenButton" class="hidden"><i class="fas fa-stop-circle"></i> Stop screen</button>
<button id="fileShareButton" class="hidden"><i class="fas fa-folder-open"></i> File Sharing</button> <button id="fileShareButton" class="hidden"><i class="fas fa-folder-open"></i> File Sharing</button>
<div class="dropdown">
<button id="youTubeShareButton" class="hidden"><i class="fab fa-youtube"></i> YouTube</button>
<div id="youTubeSettings" class="dropdown-content fadein">
<div id="youTubeOptions">
<button id="youTubeCloseBtn"><i class="fas fa-times"></i> Close Video</button>
</div>
</div>
</div>
<div class="dropdown"> <div class="dropdown">
<button id="whiteboardButton" class="hidden"> <button id="whiteboardButton" class="hidden">
<i class="fas fa-chalkboard-teacher"></i> Whiteboard <i class="fas fa-chalkboard-teacher"></i> Whiteboard

عرض الملف

@@ -611,6 +611,20 @@ progress {
min-width: 100%; min-width: 100%;
} }
/*--------------------------------------------------------------
# YouTube Video
--------------------------------------------------------------*/
#youTubeSettings {
display: 'none';
position: relative;
background: var(--body-bg);
}
#youTubeCloseBtn:hover {
color: red;
}
/*-------------------------------------------------------------- /*--------------------------------------------------------------
# Whiteboard # Whiteboard
--------------------------------------------------------------*/ --------------------------------------------------------------*/

ثنائية
public/images/youtube.png Normal file

ملف ثنائي غير معروض.

بعد

العرض:  |  الارتفاع:  |  الحجم: 2.4 KiB

عرض الملف

@@ -434,6 +434,7 @@ function roomIsReady() {
show(raiseHandButton); show(raiseHandButton);
if (isAudioAllowed) show(startAudioButton); if (isAudioAllowed) show(startAudioButton);
if (isVideoAllowed) show(startVideoButton); if (isVideoAllowed) show(startVideoButton);
show(youTubeShareButton);
show(fileShareButton); show(fileShareButton);
show(whiteboardButton); show(whiteboardButton);
show(participantsButton); show(participantsButton);
@@ -612,6 +613,12 @@ function handleButtons() {
fileShareButton.onclick = () => { fileShareButton.onclick = () => {
rc.selectFileToShare(); rc.selectFileToShare();
}; };
youTubeShareButton.onclick = () => {
rc.youTubeShareVideo();
};
youTubeCloseBtn.onclick = () => {
rc.closeYouTube(true);
};
sendAbortBtn.onclick = () => { sendAbortBtn.onclick = () => {
rc.abortFileTransfer(); rc.abortFileTransfer();
}; };

عرض الملف

@@ -18,6 +18,7 @@ const image = {
locked: '../images/locked.png', locked: '../images/locked.png',
mute: '../images/mute.png', mute: '../images/mute.png',
hide: '../images/hide.png', hide: '../images/hide.png',
youtube: '../images/youtube.png',
}; };
const mediaType = { const mediaType = {
@@ -458,6 +459,13 @@ class RoomClient {
}.bind(this), }.bind(this),
); );
this.socket.on(
'youTubeAction',
function (data) {
this.youTubeAction(data);
}.bind(this),
);
this.socket.on( this.socket.on(
'fileAbort', 'fileAbort',
function (data) { function (data) {
@@ -1857,6 +1865,117 @@ class RoomClient {
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
} }
// ####################################################
// YOUTUBE SHARE VIDEO
// ####################################################
youTubeShareVideo() {
rc.sound('open');
Swal.fire({
background: swalBackground,
position: 'center',
imageUrl: image.youtube,
title: 'Share YouTube Video',
text: 'Past YouTube video URL',
input: 'text',
showCancelButton: true,
confirmButtonText: `Share`,
showClass: {
popup: 'animate__animated animate__fadeInDown',
},
hideClass: {
popup: 'animate__animated animate__fadeOutUp',
},
}).then((result) => {
if (result.value) {
if (!this.thereIsParticipants()) {
userLog('info', 'No participants detected', 'top-end');
return;
}
// https://www.youtube.com/watch?v=RT6_Id5-7-s
let you_tube_url = this.getYoutubeEmbed(result.value);
if (you_tube_url) {
let data = {
peer_name: this.peer_name,
you_tube_url: you_tube_url,
action: 'open',
};
console.log('YouTube video URL: ', you_tube_url);
this.socket.emit('youTubeAction', data);
this.openYouTube(data);
} else {
this.userLog('error', 'Not valid YouTube URL', 'top-end');
}
}
});
}
getYoutubeEmbed(url) {
let regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
let match = url.match(regExp);
return match && match[7].length == 11 ? 'https://www.youtube.com/embed/' + match[7] + '?autoplay=1' : false;
}
youTubeAction(data) {
let action = data.action;
switch (action) {
case 'open':
this.userLog('info', `${peer_name} <i class="fab fa-youtube"></i> opened the YouTube video`, 'top-end');
this.openYouTube(data);
break;
case 'close':
this.userLog('info', `${peer_name} <i class="fab fa-youtube"></i> closed the YouTube video`, 'top-end');
this.closeYouTube();
break;
}
}
openYouTube(data) {
let d, iframe;
let peer_name = data.peer_name;
let you_tube_url = data.you_tube_url;
this.closeYouTube();
youTubeSettings.style.display = 'block';
d = document.createElement('div');
d.className = 'Camera';
d.id = '__youTube';
iframe = document.createElement('iframe');
iframe.setAttribute('id', '__youTubeIframe');
iframe.setAttribute('title', peer_name);
iframe.setAttribute('width', '100%');
iframe.setAttribute('height', '100%');
iframe.setAttribute('src', you_tube_url);
iframe.setAttribute(
'allow',
'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',
);
iframe.setAttribute('frameborder', '0');
iframe.setAttribute('allowfullscreen', true);
d.appendChild(iframe);
this.videoMediaContainer.appendChild(d);
resizeVideoMedia();
rc.sound('joined');
}
closeYouTube(emit = false) {
if (emit) {
let data = {
peer_name: this.peer_name,
action: 'close',
};
this.socket.emit('youTubeAction', data);
}
let youTubeDiv = this.getId('__youTube');
if (youTubeDiv) {
youTubeSettings.style.display = 'none';
youTubeDiv.parentNode.removeChild(youTubeDiv);
resizeVideoMedia();
rc.sound('left');
}
}
// #################################################### // ####################################################
// ROOM ACTION // ROOM ACTION
// #################################################### // ####################################################

عرض الملف

@@ -117,8 +117,8 @@
</h2> </h2>
<p class="section-paragraph mb-0"> <p class="section-paragraph mb-0">
MiroTalk with SFU integrated Server. We engineered a platform with maximum video MiroTalk with SFU integrated Server. We engineered a platform with maximum video
quality lowest latency that makes your calls crystal clear. Desktop and Mobile quality lowest latency that makes your calls crystal clear. Compatible with Desktop
compatible! and Mobile devices!
</p> </p>
</div> </div>
</div> </div>

عرض الملف

@@ -140,7 +140,7 @@ async function ngrokStart() {
tunnel: tunnel, tunnel: tunnel,
}); });
} catch (err) { } catch (err) {
console.error('Ngrok Start error: ', err); log.error('Ngrok Start error: ', err);
process.exit(1); process.exit(1);
} }
} }
@@ -192,7 +192,7 @@ async function createWorkers() {
rtcMaxPort: config.mediasoup.worker.rtcMaxPort, rtcMaxPort: config.mediasoup.worker.rtcMaxPort,
}); });
worker.on('died', () => { worker.on('died', () => {
console.error('Mediasoup worker died, exiting in 2 seconds... [pid:%d]', worker.pid); log.error('Mediasoup worker died, exiting in 2 seconds... [pid:%d]', worker.pid);
setTimeout(() => process.exit(1), 2000); setTimeout(() => process.exit(1), 2000);
}); });
workers.push(worker); workers.push(worker);
@@ -265,6 +265,11 @@ io.on('connection', (socket) => {
roomList.get(socket.room_id).broadCast(socket.id, 'fileAbort', data); roomList.get(socket.room_id).broadCast(socket.id, 'fileAbort', data);
}); });
socket.on('youTubeAction', (data) => {
log.debug('YouTube: ', data);
roomList.get(socket.room_id).broadCast(socket.id, 'youTubeAction', data);
});
socket.on('wbCanvasToJson', (data) => { socket.on('wbCanvasToJson', (data) => {
// let objLength = bytesToSize(Object.keys(data).length); // let objLength = bytesToSize(Object.keys(data).length);
// log.debug('Send Whiteboard canvas JSON', { length: objLength }); // log.debug('Send Whiteboard canvas JSON', { length: objLength });
@@ -328,7 +333,7 @@ io.on('connection', (socket) => {
const { params } = await roomList.get(socket.room_id).createWebRtcTransport(socket.id); const { params } = await roomList.get(socket.room_id).createWebRtcTransport(socket.id);
callback(params); callback(params);
} catch (err) { } catch (err) {
console.error('Create WebRtc Transport error: ', err); log.error('Create WebRtc Transport error: ', err);
callback({ callback({
error: err.message, error: err.message,
}); });