[mirotalksfu] - add HtmlInjector
هذا الالتزام موجود في:
95
app/src/HtmlInjector.js
Normal file
95
app/src/HtmlInjector.js
Normal file
@@ -0,0 +1,95 @@
|
||||
const fs = require('fs');
|
||||
|
||||
const Logger = require('./Logger');
|
||||
|
||||
const log = new Logger('HtmlInjection');
|
||||
|
||||
class HtmlInjector {
|
||||
constructor(filesPath, config) {
|
||||
this.filesPath = filesPath; // Array of file paths to cache
|
||||
this.cache = {}; // Object to store cached files
|
||||
this.config = config; // Configuration containing metadata (OG, title, etc.)
|
||||
this.injectData = this.getInjectData(); // Initialize dynamic injection data
|
||||
this.preloadPages(filesPath); // Preload pages at startup
|
||||
this.watchFiles(filesPath); // Watch files for changes
|
||||
log.info('filesPath cached', this.filesPath);
|
||||
}
|
||||
|
||||
// Function to get dynamic data for injection (e.g., OG data, title, etc.)
|
||||
getInjectData() {
|
||||
return {
|
||||
OG_TYPE: this.config.og?.type || 'app-webrtc',
|
||||
OG_SITE_NAME: this.config.og?.siteName || 'MiroTalk SFU',
|
||||
OG_TITLE: this.config.og?.title || 'Click the link to make a call.',
|
||||
OG_DESCRIPTION:
|
||||
this.config.og?.description ||
|
||||
'MiroTalk SFU calling provides real-time video calls, messaging and screen sharing.',
|
||||
OG_IMAGE: this.config.og?.image || 'https://sfu.mirotalk.com/images/mirotalksfu.png',
|
||||
OG_URL: this.config.og?.url || 'https://sfu.mirotalk.com',
|
||||
// Add more data here as needed with fallbacks
|
||||
};
|
||||
}
|
||||
|
||||
// Function to load a file into the cache
|
||||
loadFileToCache(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
this.cache[filePath] = content; // Store the content in cache
|
||||
} catch (err) {
|
||||
log.error(`Error reading file: ${filePath}`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to preload pages into the cache
|
||||
preloadPages(filePaths) {
|
||||
filePaths.forEach((filePath) => this.loadFileToCache(filePath));
|
||||
}
|
||||
|
||||
// Function to watch a file for changes and reload the cache
|
||||
watchFileForChanges(filePath) {
|
||||
fs.watch(filePath, (eventType) => {
|
||||
if (eventType === 'change') {
|
||||
log.debug(`File changed: ${filePath}`);
|
||||
this.loadFileToCache(filePath);
|
||||
log.debug(`Reload the file ${filePath} into cache`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to watch all files for changes
|
||||
watchFiles(filePaths) {
|
||||
filePaths.forEach((filePath) => this.watchFileForChanges(filePath));
|
||||
}
|
||||
|
||||
// Function to inject dynamic data (e.g., OG, TITLE, etc.) into a given file
|
||||
injectHtml(filePath, res) {
|
||||
// return res.send(this.cache[filePath]);
|
||||
|
||||
if (!this.cache[filePath]) {
|
||||
log.error(`File not cached: ${filePath}`);
|
||||
if (!res.headersSent) {
|
||||
return res.status(500).send('Server Error');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Replace placeholders with dynamic data (OG, TITLE, etc.)
|
||||
const modifiedHTML = this.cache[filePath].replace(
|
||||
/{{(OG_[A-Z_]+)}}/g,
|
||||
(_, key) => this.injectData[key] || '',
|
||||
);
|
||||
|
||||
if (!res.headersSent) {
|
||||
res.send(modifiedHTML);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error injecting HTML data:', error);
|
||||
if (!res.headersSent) {
|
||||
res.status(500).send('Server Error');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HtmlInjector;
|
||||
@@ -55,7 +55,7 @@ dev dependencies: {
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.7.17
|
||||
* @version 1.7.18
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -81,6 +81,7 @@ const Peer = require('./Peer');
|
||||
const ServerApi = require('./ServerApi');
|
||||
const Logger = require('./Logger');
|
||||
const Validator = require('./Validator');
|
||||
const HtmlInjector = require('./HtmlInjector');
|
||||
const log = new Logger('Server');
|
||||
const yaml = require('js-yaml');
|
||||
const swaggerUi = require('swagger-ui-express');
|
||||
@@ -237,6 +238,7 @@ if (serverRecordingEnabled) {
|
||||
|
||||
// html views
|
||||
const views = {
|
||||
html: path.join(__dirname, '../../public/views'),
|
||||
about: path.join(__dirname, '../../', 'public/views/about.html'),
|
||||
landing: path.join(__dirname, '../../', 'public/views/landing.html'),
|
||||
login: path.join(__dirname, '../../', 'public/views/login.html'),
|
||||
@@ -249,6 +251,10 @@ const views = {
|
||||
whoAreYou: path.join(__dirname, '../../', 'public/views/whoAreYou.html'),
|
||||
};
|
||||
|
||||
const filesPath = [views.landing, views.newRoom, views.room, views.login];
|
||||
|
||||
const htmlInjector = new HtmlInjector(filesPath, config.ui.brand);
|
||||
|
||||
const authHost = new Host(); // Authenticated IP by Login
|
||||
|
||||
const roomList = new Map(); // All Rooms
|
||||
@@ -457,20 +463,19 @@ function startServer() {
|
||||
});
|
||||
|
||||
// main page
|
||||
app.get(['/'], OIDCAuth, (req, res) => {
|
||||
app.get('/', OIDCAuth, (req, res) => {
|
||||
//log.debug('/ - hostCfg ----->', hostCfg);
|
||||
|
||||
if (!OIDC.enabled && hostCfg.protected) {
|
||||
const ip = getIP(req);
|
||||
if (allowedIP(ip)) {
|
||||
res.sendFile(views.landing);
|
||||
htmlInjector.injectHtml(views.landing, res);
|
||||
hostCfg.authenticated = true;
|
||||
} else {
|
||||
hostCfg.authenticated = false;
|
||||
res.redirect('/login');
|
||||
}
|
||||
} else {
|
||||
res.sendFile(views.landing);
|
||||
return htmlInjector.injectHtml(views.landing, res);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -483,7 +488,7 @@ function startServer() {
|
||||
});
|
||||
|
||||
// set new room name and join
|
||||
app.get(['/newroom'], OIDCAuth, (req, res) => {
|
||||
app.get('/newroom', OIDCAuth, (req, res) => {
|
||||
//log.info('/newroom - hostCfg ----->', hostCfg);
|
||||
|
||||
if (!OIDC.enabled && hostCfg.protected) {
|
||||
@@ -496,12 +501,12 @@ function startServer() {
|
||||
res.redirect('/login');
|
||||
}
|
||||
} else {
|
||||
res.sendFile(views.newRoom);
|
||||
htmlInjector.injectHtml(views.newRoom, res);
|
||||
}
|
||||
});
|
||||
|
||||
// Check if room active (exists)
|
||||
app.post(['/isRoomActive'], (req, res) => {
|
||||
app.post('/isRoomActive', (req, res) => {
|
||||
const { roomId } = checkXSS(req.body);
|
||||
|
||||
if (roomId && (hostCfg.protected || hostCfg.user_auth)) {
|
||||
@@ -571,8 +576,8 @@ function startServer() {
|
||||
} catch (err) {
|
||||
log.error('Direct Join JWT error', { error: err.message, token: token });
|
||||
return hostCfg.protected || hostCfg.user_auth
|
||||
? res.sendFile(views.login)
|
||||
: res.sendFile(views.landing);
|
||||
? htmlInjector.injectHtml(views.login, res)
|
||||
: htmlInjector.injectHtml(views.landing, res);
|
||||
}
|
||||
} else {
|
||||
const allowRoomAccess = isAllowedRoomAccess('/join/params', req, hostCfg, roomList, room);
|
||||
@@ -601,9 +606,9 @@ function startServer() {
|
||||
}
|
||||
|
||||
if (room && (hostCfg.authenticated || isPeerValid)) {
|
||||
return res.sendFile(views.room);
|
||||
return htmlInjector.injectHtml(views.room, res);
|
||||
} else {
|
||||
return res.sendFile(views.login);
|
||||
return htmlInjector.injectHtml(views.login, res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,7 +637,7 @@ function startServer() {
|
||||
if (!OIDC.enabled && hostCfg.protected && hostCfg.users_from_db) {
|
||||
const roomExists = await roomExistsForUser(roomId);
|
||||
log.debug('/join/:roomId exists from API endpoint', roomExists);
|
||||
return roomExists ? res.sendFile(views.room) : res.redirect('/login');
|
||||
return roomExists ? htmlInjector.injectHtml(views.room, res) : res.redirect('/login');
|
||||
}
|
||||
// 2. Protect room access with configuration check
|
||||
if (!OIDC.enabled && hostCfg.protected && !hostCfg.users_from_db) {
|
||||
@@ -640,9 +645,9 @@ function startServer() {
|
||||
(user) => user.allowed_rooms && (user.allowed_rooms.includes(roomId) || roomList.has(roomId)),
|
||||
);
|
||||
log.debug('/join/:roomId exists from config allowed rooms', roomExists);
|
||||
return roomExists ? res.sendFile(views.room) : res.redirect('/whoAreYou/' + roomId);
|
||||
return roomExists ? htmlInjector.injectHtml(views.room, res) : res.redirect('/whoAreYou/' + roomId);
|
||||
}
|
||||
res.sendFile(views.room);
|
||||
htmlInjector.injectHtml(views.room, res);
|
||||
} else {
|
||||
// Who are you?
|
||||
!OIDC.enabled && hostCfg.protected ? res.redirect('/whoAreYou/' + roomId) : res.redirect('/');
|
||||
@@ -655,42 +660,42 @@ function startServer() {
|
||||
});
|
||||
|
||||
// if not allow video/audio
|
||||
app.get(['/permission'], (req, res) => {
|
||||
app.get('/permission', (req, res) => {
|
||||
res.sendFile(views.permission);
|
||||
});
|
||||
|
||||
// privacy policy
|
||||
app.get(['/privacy'], (req, res) => {
|
||||
app.get('/privacy', (req, res) => {
|
||||
res.sendFile(views.privacy);
|
||||
});
|
||||
|
||||
// mirotalk about
|
||||
app.get(['/about'], (req, res) => {
|
||||
app.get('/about', (req, res) => {
|
||||
res.sendFile(views.about);
|
||||
});
|
||||
|
||||
// Get stats endpoint
|
||||
app.get(['/stats'], (req, res) => {
|
||||
app.get('/stats', (req, res) => {
|
||||
const stats = config.stats ? config.stats : defaultStats;
|
||||
// log.debug('Send stats', stats);
|
||||
res.send(stats);
|
||||
});
|
||||
|
||||
// handle who are you: Presenter or Guest
|
||||
app.get(['/whoAreYou/:roomId'], (req, res) => {
|
||||
app.get('/whoAreYou/:roomId', (req, res) => {
|
||||
res.sendFile(views.whoAreYou);
|
||||
});
|
||||
|
||||
// handle login if user_auth enabled
|
||||
app.get(['/login'], (req, res) => {
|
||||
app.get('/login', (req, res) => {
|
||||
if (hostCfg.protected || hostCfg.user_auth) {
|
||||
return res.sendFile(views.login);
|
||||
return htmlInjector.injectHtml(views.login, res);
|
||||
}
|
||||
res.redirect('/');
|
||||
});
|
||||
|
||||
// handle logged on host protected
|
||||
app.get(['/logged'], (req, res) => {
|
||||
app.get('/logged', (req, res) => {
|
||||
const ip = getIP(req);
|
||||
if (allowedIP(ip)) {
|
||||
res.redirect('/');
|
||||
@@ -706,7 +711,7 @@ function startServer() {
|
||||
// ####################################################
|
||||
|
||||
// handle login on host protected
|
||||
app.post(['/login'], async (req, res) => {
|
||||
app.post('/login', async (req, res) => {
|
||||
const ip = getIP(req);
|
||||
log.debug(`Request login to host from: ${ip}`, req.body);
|
||||
|
||||
@@ -753,7 +758,7 @@ function startServer() {
|
||||
// KEEP RECORDING ON SERVER DIR
|
||||
// ####################################################
|
||||
|
||||
app.post(['/recSync'], (req, res) => {
|
||||
app.post('/recSync', (req, res) => {
|
||||
// Store recording...
|
||||
if (serverRecordingEnabled) {
|
||||
//
|
||||
@@ -940,7 +945,7 @@ function startServer() {
|
||||
// REST API
|
||||
// ####################################################
|
||||
|
||||
app.get([restApi.basePath + '/stats'], (req, res) => {
|
||||
app.get(restApi.basePath + '/stats', (req, res) => {
|
||||
try {
|
||||
// Check if endpoint allowed
|
||||
if (restApi.allowed && !restApi.allowed.stats) {
|
||||
@@ -985,7 +990,7 @@ function startServer() {
|
||||
});
|
||||
|
||||
// request meetings list
|
||||
app.get([restApi.basePath + '/meetings'], (req, res) => {
|
||||
app.get(restApi.basePath + '/meetings', (req, res) => {
|
||||
// Check if endpoint allowed
|
||||
if (restApi.allowed && !restApi.allowed.meetings) {
|
||||
return res.status(403).json({
|
||||
@@ -1014,7 +1019,7 @@ function startServer() {
|
||||
});
|
||||
|
||||
// request meeting room endpoint
|
||||
app.post([restApi.basePath + '/meeting'], (req, res) => {
|
||||
app.post(restApi.basePath + '/meeting', (req, res) => {
|
||||
// Check if endpoint allowed
|
||||
if (restApi.allowed && !restApi.allowed.meeting) {
|
||||
return res.status(403).json({
|
||||
@@ -1043,7 +1048,7 @@ function startServer() {
|
||||
});
|
||||
|
||||
// request join room endpoint
|
||||
app.post([restApi.basePath + '/join'], (req, res) => {
|
||||
app.post(restApi.basePath + '/join', (req, res) => {
|
||||
// Check if endpoint allowed
|
||||
if (restApi.allowed && !restApi.allowed.join) {
|
||||
return res.status(403).json({
|
||||
@@ -1072,7 +1077,7 @@ function startServer() {
|
||||
});
|
||||
|
||||
// request token endpoint
|
||||
app.post([restApi.basePath + '/token'], (req, res) => {
|
||||
app.post(restApi.basePath + '/token', (req, res) => {
|
||||
// Check if endpoint allowed
|
||||
if (restApi.allowed && !restApi.allowed.token) {
|
||||
return res.status(403).json({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalksfu",
|
||||
"version": "1.7.17",
|
||||
"version": "1.7.18",
|
||||
"description": "WebRTC SFU browser-based video calls",
|
||||
"main": "Server.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.7.17
|
||||
* @version 1.7.18
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -4905,7 +4905,7 @@ function showAbout() {
|
||||
imageUrl: image.about,
|
||||
customClass: { image: 'img-about' },
|
||||
position: 'center',
|
||||
title: 'WebRTC SFU v1.7.17',
|
||||
title: 'WebRTC SFU v1.7.18',
|
||||
html: `
|
||||
<br />
|
||||
<div id="about">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.7.17
|
||||
* @version 1.7.18
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -24,19 +24,6 @@
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600" />
|
||||
|
||||
@@ -24,19 +24,6 @@
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600" />
|
||||
|
||||
@@ -28,16 +28,12 @@
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
<meta property="og:type" content="{{OG_TYPE}}" />
|
||||
<meta property="og:site_name" content="{{OG_SITE_NAME}}" />
|
||||
<meta property="og:title" content="{{OG_TITLE}}" />
|
||||
<meta property="og:description" content="{{OG_DESCRIPTION}}" />
|
||||
<meta property="og:image" content="{{OG_IMAGE}}" />
|
||||
<meta property="og:url" content="{{OG_URL}}" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
<link rel="stylesheet" href="../css/Root.css" />
|
||||
|
||||
@@ -27,19 +27,6 @@
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<link rel="stylesheet" href="../css/Root.css" />
|
||||
|
||||
@@ -24,19 +24,6 @@
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600" />
|
||||
|
||||
@@ -26,16 +26,12 @@
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
<meta property="og:type" content="{{OG_TYPE}}" />
|
||||
<meta property="og:site_name" content="{{OG_SITE_NAME}}" />
|
||||
<meta property="og:title" content="{{OG_TITLE}}" />
|
||||
<meta property="og:description" content="{{OG_DESCRIPTION}}" />
|
||||
<meta property="og:image" content="{{OG_IMAGE}}" />
|
||||
<meta property="og:url" content="{{OG_URL}}" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
|
||||
@@ -26,16 +26,12 @@
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
<meta property="og:type" content="{{OG_TYPE}}" />
|
||||
<meta property="og:site_name" content="{{OG_SITE_NAME}}" />
|
||||
<meta property="og:title" content="{{OG_TITLE}}" />
|
||||
<meta property="og:description" content="{{OG_DESCRIPTION}}" />
|
||||
<meta property="og:image" content="{{OG_IMAGE}}" />
|
||||
<meta property="og:url" content="{{OG_URL}}" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
|
||||
@@ -26,16 +26,12 @@
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
<meta property="og:type" content="{{OG_TYPE}}" />
|
||||
<meta property="og:site_name" content="{{OG_SITE_NAME}}" />
|
||||
<meta property="og:title" content="{{OG_TITLE}}" />
|
||||
<meta property="og:description" content="{{OG_DESCRIPTION}}" />
|
||||
<meta property="og:image" content="{{OG_IMAGE}}" />
|
||||
<meta property="og:url" content="{{OG_URL}}" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
|
||||
|
||||
@@ -24,19 +24,6 @@
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600" />
|
||||
|
||||
@@ -24,19 +24,6 @@
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600" />
|
||||
|
||||
@@ -24,19 +24,6 @@
|
||||
content="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"
|
||||
/>
|
||||
|
||||
<!-- https://ogp.me -->
|
||||
|
||||
<meta id="ogType" property="og:type" content="app-webrtc" />
|
||||
<meta id="ogSiteName" property="og:site_name" content="MiroTalk SFU" />
|
||||
<meta id="ogTitle" property="og:title" content="Click the link to make a call." />
|
||||
<meta
|
||||
id="ogDescription"
|
||||
property="og:description"
|
||||
content="MiroTalk SFU calling provides real-time video calls, messaging and screen sharing."
|
||||
/>
|
||||
<meta id="ogImage" property="og:image" content="https://sfu.mirotalk.com/images/mirotalksfu.png" />
|
||||
<meta id="ogUrl" property="og:url" content="https://sfu.mirotalk.com" />
|
||||
|
||||
<!-- StyleSheet -->
|
||||
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,600" />
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم