mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-05 19:42:38 +02:00
Update
This commit is contained in:
parent
5d53819459
commit
01b32b7efd
14 changed files with 347 additions and 153 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -108,4 +108,5 @@ test*
|
||||||
CreatePlugin/plugins/
|
CreatePlugin/plugins/
|
||||||
vendor/james-heinrich/getid3/demos/
|
vendor/james-heinrich/getid3/demos/
|
||||||
AVideoStorage/
|
AVideoStorage/
|
||||||
plugin/VideoHLSOverlay/
|
plugin/VideoHLSOverlay/
|
||||||
|
plugin/Live/WebRTC/WebRTC2RTMP.json
|
||||||
|
|
Binary file not shown.
|
@ -61,6 +61,7 @@ function sendStreamToServer(stream) {
|
||||||
|
|
||||||
mediaRecorder.ondataavailable = (event) => {
|
mediaRecorder.ondataavailable = (event) => {
|
||||||
if (event.data.size > 0) {
|
if (event.data.size > 0) {
|
||||||
|
//console.log(`video-chunk`);
|
||||||
socket.emit('video-chunk', { rtmpURLEncrypted, chunk: event.data });
|
socket.emit('video-chunk', { rtmpURLEncrypted, chunk: event.data });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -87,6 +88,18 @@ function stopStreamToServer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function setIsWebcamServerConnected() {
|
||||||
|
console.log('Connection success');
|
||||||
|
// Custom logic to handle connection failure
|
||||||
|
$('body').removeClass('WebcamServerNotConnected').addClass('WebcamServerConnected');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIsWebcamServerNotConnected() {
|
||||||
|
console.log('Connection error');
|
||||||
|
$('body').removeClass('WebcamServerConnected').addClass('WebcamServerNotConnected');
|
||||||
|
setIsNotLive();
|
||||||
|
}
|
||||||
|
|
||||||
function setIsLive() {
|
function setIsLive() {
|
||||||
document.body.classList.remove('isNotLive');
|
document.body.classList.remove('isNotLive');
|
||||||
document.body.classList.add('isLive');
|
document.body.classList.add('isLive');
|
||||||
|
@ -199,6 +212,16 @@ async function startWebRTC({ videoDeviceId = null, audioDeviceId = null, useScre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleMediaSelector() {
|
||||||
|
if (!$('#mediaSelector').is(':visible')) {
|
||||||
|
$('#mediaSelector').fadeIn(); // Fade in #mediaSelector if not visible
|
||||||
|
$('#webrtcChat').hide(); // Hide #webrtcChat
|
||||||
|
} else {
|
||||||
|
$('#webrtcChat').show(); // Show #webrtcChat
|
||||||
|
$('#mediaSelector').fadeOut(); // Fade out #mediaSelector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener('orientationchange', () => {
|
window.addEventListener('orientationchange', () => {
|
||||||
console.log('Orientation changed.');
|
console.log('Orientation changed.');
|
||||||
if (isLive) {
|
if (isLive) {
|
||||||
|
|
|
@ -8,86 +8,93 @@ let isLive = false; // Track live status
|
||||||
|
|
||||||
// Handle connection errors
|
// Handle connection errors
|
||||||
socket.on('connect_error', (error) => {
|
socket.on('connect_error', (error) => {
|
||||||
$('body').removeClass('WebRTCReady');
|
setIsWebcamServerNotConnected();
|
||||||
console.error('Connection error:', error.message);
|
console.error('Connection error:', error.message);
|
||||||
// Custom logic to handle connection failure
|
//avideoToastError('Unable to connect to the webcam server. Please check your connection and try again.');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle connection errors
|
// Handle successful connection
|
||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
avideoToastSuccess('Webcam server is ready');
|
setIsWebcamServerConnected();
|
||||||
console.log('Connection success');
|
avideoToastSuccess('Successfully connected to the webcam server.');
|
||||||
// Custom logic to handle connection failure
|
|
||||||
$('body').addClass('WebRTCReady');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle disconnection
|
// Handle disconnection
|
||||||
socket.on('disconnect', (reason) => {
|
socket.on('disconnect', (reason) => {
|
||||||
avideoToastError('Webcam server disconnected');
|
setIsWebcamServerNotConnected();
|
||||||
|
avideoToastError(`Disconnected from the webcam server. Reason: ${reason}`);
|
||||||
console.log('Disconnected from the server:', reason);
|
console.log('Disconnected from the server:', reason);
|
||||||
$('body').removeClass('WebRTCReady');
|
|
||||||
if (reason === 'io server disconnect') {
|
if (reason === 'io server disconnect') {
|
||||||
// The server disconnected the client manually
|
|
||||||
socket.connect(); // Optionally reconnect
|
socket.connect(); // Optionally reconnect
|
||||||
|
avideoToastWarning('Reconnecting to the server...');
|
||||||
}
|
}
|
||||||
setIsNotLive();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle reconnection attempts if enabled
|
// Handle reconnection attempts
|
||||||
socket.on('reconnect_attempt', () => {
|
socket.on('reconnect_attempt', () => {
|
||||||
console.log('Attempting to reconnect...');
|
console.log('Attempting to reconnect...');
|
||||||
|
avideoToastInfo('Attempting to reconnect to the webcam server...');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle live-start
|
||||||
// Handle response
|
|
||||||
socket.on('live-start', ({ rtmpURL }) => {
|
socket.on('live-start', ({ rtmpURL }) => {
|
||||||
console.log('live-start', rtmpURL);
|
console.log('live-start', rtmpURL);
|
||||||
avideoToastSuccess('Live start');
|
avideoToastSuccess(`Live streaming started successfully.`);
|
||||||
setIsLive();
|
setIsLive();
|
||||||
requestNotifications();
|
requestNotifications();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle response
|
// Handle live-resumed
|
||||||
socket.on('live-resumed', ({ rtmpURL }) => {
|
socket.on('live-resumed', ({ rtmpURL }) => {
|
||||||
console.log('live-resumed', rtmpURL);
|
console.log('live-resumed', rtmpURL);
|
||||||
avideoToastSuccess('Live Resumed');
|
avideoToastSuccess(`Live streaming resumed.`);
|
||||||
setIsLive();
|
setIsLive();
|
||||||
requestNotifications();
|
requestNotifications();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle live-stopped
|
||||||
socket.on('live-stopped', ({ rtmpURL, message }) => {
|
socket.on('live-stopped', ({ rtmpURL, message }) => {
|
||||||
console.log('live-stopped', rtmpURL, message);
|
console.log('live-stopped', rtmpURL, message);
|
||||||
avideoToastWarning('Live stop');
|
avideoToastWarning(`Live streaming stopped. Reason: ${message}`);
|
||||||
setIsNotLive();
|
setIsNotLive();
|
||||||
requestNotifications();
|
requestNotifications();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle general errors
|
||||||
socket.on('error', ({ message }) => {
|
socket.on('error', ({ message }) => {
|
||||||
console.error(`Error: ${message}`);
|
console.error(`Error: ${message}`);
|
||||||
avideoToastError(message);
|
avideoToastError(`An error occurred: ${message}`);
|
||||||
requestNotifications();
|
requestNotifications();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle FFMPEG errors
|
||||||
socket.on('ffmpeg-error', ({ code }) => {
|
socket.on('ffmpeg-error', ({ code }) => {
|
||||||
console.error(`FFMPEG Error: ${code}`);
|
console.error(`FFMPEG Error: ${code}`);
|
||||||
//avideoToastError(message);
|
avideoToastError(`FFMPEG encountered an error. Error code: ${code}`);
|
||||||
requestNotifications();
|
requestNotifications();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle active connections
|
||||||
socket.on('connections', ({ current, max }) => {
|
socket.on('connections', ({ current, max }) => {
|
||||||
console.log(`Current number of active connections: ${current}/${max}`);
|
console.log(`Current number of active connections: ${current}/${max}`);
|
||||||
|
//avideoToastInfo(`Active connections: ${current}/${max}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle live-time
|
||||||
socket.on('live-time', ({ startTime, elapsedSeconds, remainingSeconds }) => {
|
socket.on('live-time', ({ startTime, elapsedSeconds, remainingSeconds }) => {
|
||||||
console.log(`Time remaining is: ${remainingSeconds} seconds `);
|
console.log(`Time remaining is: ${remainingSeconds} seconds`);
|
||||||
|
//avideoToastInfo(`Live stream time remaining: ${remainingSeconds} seconds.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle RTMP status
|
||||||
socket.on('rtmp-status', ({ rtmpURL, isRunning }) => {
|
socket.on('rtmp-status', ({ rtmpURL, isRunning }) => {
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
console.log(`This live is running with RTMP URL: ${rtmpURL}`);
|
console.log(`This live is running with RTMP URL: ${rtmpURL}`);
|
||||||
|
//avideoToastSuccess(`Live stream is running. RTMP URL: ${rtmpURL}`);
|
||||||
setIsLive();
|
setIsLive();
|
||||||
} else {
|
} else {
|
||||||
console.log(`This live is not running`);
|
console.log(`This live is not running`);
|
||||||
|
//avideoToastWarning('Live stream is not running.');
|
||||||
setIsNotLive();
|
setIsNotLive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +102,9 @@ socket.on('rtmp-status', ({ rtmpURL, isRunning }) => {
|
||||||
clearTimeout(liveStatusTimeout);
|
clearTimeout(liveStatusTimeout);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle stream-stopped
|
||||||
socket.on('stream-stopped', ({ rtmpURL, reason }) => {
|
socket.on('stream-stopped', ({ rtmpURL, reason }) => {
|
||||||
console.log(`Stream for ${rtmpURL} stopped: ${reason}`);
|
console.log(`Stream for ${rtmpURL} stopped: ${reason}`);
|
||||||
|
avideoToastWarning(`Stream stopped. Reason: ${reason}`);
|
||||||
requestNotifications();
|
requestNotifications();
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,4 +54,29 @@ function decrypt_data($ciphertextB64, $salt)
|
||||||
);
|
);
|
||||||
|
|
||||||
return $plaintext;
|
return $plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWebRTCInfo(){
|
||||||
|
global $global;
|
||||||
|
$file = "{$global['systemRootPath']}plugin/Live/WebRTC/WebRTC2RTMP.json";
|
||||||
|
if(!file_exists($file)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$content = file_get_contents("{$global['systemRootPath']}plugin/Live/WebRTC/WebRTC2RTMP.json");
|
||||||
|
if(empty($content)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$json = json_decode($content);
|
||||||
|
if(empty($json)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWebRTC2RTMPURL(){
|
||||||
|
$json = getWebRTCInfo();
|
||||||
|
if(empty($json)){
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return "https://{$json->domain}:{$json->serverPort}";
|
||||||
}
|
}
|
|
@ -19,12 +19,20 @@ if (empty($_REQUEST['avideoIframe'])) {
|
||||||
<?php
|
<?php
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<div id="webcamMediaControls" class="showWhenWebRTCIsReady">
|
<div id="webcamMediaControls" class="showWhenWebRTCIsConnected">
|
||||||
<?php
|
<?php
|
||||||
include __DIR__ . '/panel.medias.php';
|
include __DIR__ . '/panel.medias.php';
|
||||||
include __DIR__ . '/panel.buttons.php';
|
include __DIR__ . '/panel.buttons.php';
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="webcamMediaControlsMessage" class="alert alert-danger showWhenWebRTCIsNotConnected text-center">
|
||||||
|
<div class="fa-3x">
|
||||||
|
<i class="fa-solid fa-triangle-exclamation fa-fade"></i>
|
||||||
|
</div>
|
||||||
|
<strong>Error:</strong> Unable to connect to the Webcam server.<br>
|
||||||
|
<span>Please verify the server status and resolve any issues.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
startWebRTC();
|
startWebRTC();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<button type="button" id="startLive" class="btn btn-success oval-menu animate__animated animate__bounceIn" onclick="startWebcamLive(rtmpURLEncrypted);">
|
<button type="button" id="startLive" class="btn btn-success oval-menu animate__animated animate__bounceIn" onclick="startWebcamLive(rtmpURLEncrypted);">
|
||||||
<i class="fa fa-play"></i> Go Live
|
<i class="fa fa-play"></i> Go Live
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-default oval-menu animate__animated animate__bounceIn" onclick="$('#mediaSelector').fadeToggle()" style=" -webkit-animation-delay: .2s; animation-delay: .2s;">
|
<button type="button" class="btn btn-default oval-menu animate__animated animate__bounceIn" onclick="toggleMediaSelector();" style=" -webkit-animation-delay: .2s; animation-delay: .2s;">
|
||||||
<i class="fa-solid fa-ellipsis-vertical"></i>
|
<i class="fa-solid fa-ellipsis-vertical"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
include __DIR__ . '/video.php';
|
include __DIR__ . '/video.php';
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer showWhenWebRTCIsReady">
|
<div class="panel-footer showWhenWebRTCIsConnected">
|
||||||
<?php
|
<?php
|
||||||
include __DIR__ . '/panel.medias.php';
|
include __DIR__ . '/panel.medias.php';
|
||||||
include __DIR__ . '/panel.buttons.php';
|
include __DIR__ . '/panel.buttons.php';
|
||||||
|
|
|
@ -1,91 +1,135 @@
|
||||||
body{
|
body {
|
||||||
background-color: #000;;
|
background-color: #000;
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make the video cover the entire page */
|
/* Make the video cover the entire page */
|
||||||
video {
|
video {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: contain; /* Fill the container, even if it means cropping */
|
object-fit: contain;
|
||||||
|
/* Fill the container, even if it means cropping */
|
||||||
background: black;
|
background: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator{
|
.indicator {
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 30px;
|
top: 40px;
|
||||||
left: 30px;
|
left: 20px;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
border: 1px solid #DDD;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#offLineIndicator {
|
||||||
|
background: #FF000033;
|
||||||
|
color: #CCC;
|
||||||
|
border-color: #FAA;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Live indicator */
|
/* Live indicator */
|
||||||
|
#onLineIndicator {
|
||||||
|
background: #00000055;
|
||||||
|
color: #DDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Live indicator (Green) */
|
||||||
#liveIndicator {
|
#liveIndicator {
|
||||||
background: #FF0000AA;
|
background: #00FF00AA;
|
||||||
box-shadow: 0 0 5px #FF0000; /* Initial glow */
|
box-shadow: 0 0 5px #00FF00;
|
||||||
animation: glowPulse 1.5s infinite; /* Apply the glow animation */
|
/* Initial glow */
|
||||||
|
animation: greenGlowPulse 1.5s infinite;
|
||||||
|
/* Apply the glow animation */
|
||||||
|
border-color: 2px solid #55FF55;
|
||||||
}
|
}
|
||||||
|
|
||||||
#offLineIndicator{
|
/* Keyframes for green glowing pulse animation */
|
||||||
background: #CCCCCCAA;
|
@keyframes greenGlowPulse {
|
||||||
}
|
|
||||||
|
|
||||||
/* Keyframes for glowing pulse animation */
|
|
||||||
@keyframes glowPulse {
|
|
||||||
0% {
|
0% {
|
||||||
box-shadow: 0 0 5px #FF0000; /* Starting soft glow */
|
box-shadow: 0 0 5px #00FF00;
|
||||||
|
/* Starting soft glow */
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
box-shadow: 0 0 15px #FF0000; /* Intense glow */
|
box-shadow: 0 0 15px #00FF00;
|
||||||
|
/* Intense glow */
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
box-shadow: 0 0 5px #FF0000; /* Back to soft glow */
|
box-shadow: 0 0 5px #00FF00;
|
||||||
|
/* Back to soft glow */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.showWhenIsLive{
|
.showWhenIsLive {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.showWhenIsNotLive{
|
.showWhenIsNotLive {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.isLive .showWhenIsLive{
|
.isLive .showWhenIsLive {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.isLive .showWhenIsNotLive{
|
.isLive .showWhenIsNotLive {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.showWhenWebRTCIsReady{
|
.showWhenWebRTCIsConnected,
|
||||||
|
.showWhenWebRTCIsNotConnected {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.WebRTCReady .showWhenWebRTCIsReady{
|
.WebcamServerConnected .showWhenWebRTCIsConnected {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
#webcamMediaControls{
|
|
||||||
|
.WebcamServerNotConnected .showWhenWebRTCIsNotConnected {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#webcamMediaControls, #webcamMediaControlsMessage {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oval-menu {
|
.oval-menu {
|
||||||
height: 50px;
|
height: 30px;
|
||||||
min-width: 50px;
|
min-width: 30px;
|
||||||
border-radius: 25px;
|
border-radius: 15px;
|
||||||
box-shadow: 0 0 15px 1px black;
|
box-shadow: 0 0 15px 1px black;
|
||||||
font-size: 15px;
|
font-size: 12px;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.oval-menu i{
|
.oval-menu i {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transparent-iframe {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
/* Occupies full height minus 100px at the bottom */
|
||||||
|
border: none;
|
||||||
|
/* Removes the border */
|
||||||
|
background: transparent;
|
||||||
|
/* Ensures transparency if supported by the content */
|
||||||
|
z-index: 1;
|
||||||
|
/* Ensure proper stacking order */
|
||||||
|
pointer-events: auto;
|
||||||
|
/* Allows interaction with iframe content */
|
||||||
}
|
}
|
|
@ -1,22 +1,27 @@
|
||||||
<?php
|
<?php
|
||||||
require_once __DIR__.'/functions.php';
|
require_once __DIR__ . '/functions.php';
|
||||||
|
global $global;
|
||||||
// Use parse_url to extract components of the URL
|
$global['doNotLoadPlayer'] = 1;
|
||||||
$parsedUrl = parse_url($global['webSiteRootURL']);
|
$forceIndex = 'Webcam';
|
||||||
|
$rtmpURL = Live::getRTMPLink(User::getId(), $forceIndex);
|
||||||
// Get the domain (host) from the parsed URL
|
$key = Live::getKeyFromUser(User::getId());
|
||||||
$domain = $parsedUrl['host'] ?? null;
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<script class="doNotSepareteTag">
|
<script class="doNotSepareteTag">
|
||||||
// Send streamKey to the server when joining
|
// Send streamKey to the server when joining
|
||||||
var rtmpURLEncrypted = '<?php echo encrypt_data(Live::getRTMPLink(User::getId(), 'Webcam'), $global['saltV2']); ?>';
|
var rtmpURLEncrypted = '<?php echo encrypt_data($rtmpURL, $global['saltV2']); ?>';
|
||||||
var WebRTC2RTMPURL = 'https://<?php echo $domain; ?>:3000';
|
var WebRTC2RTMPURL = '<?php echo getWebRTC2RTMPURL(); ?>';
|
||||||
</script>
|
</script>
|
||||||
<link href="<?php echo getURL('plugin/Live/WebRTC/style.css'); ?>" rel="stylesheet" type="text/css" />
|
<link href="<?php echo getURL('plugin/Live/WebRTC/style.css'); ?>" rel="stylesheet" type="text/css" />
|
||||||
<div id="liveIndicator" class="showWhenIsLive indicator" style="display: none;">LIVE</div>
|
<div id="offLineIndicator" class="showWhenWebRTCIsNotConnected indicator" style="display: none;">
|
||||||
<div id="offLineIndicator" class="showWhenIsNotLive indicator" style="display: none;">OFFLINE</div>
|
<div>
|
||||||
|
<i class="fa-solid fa-wifi"></i>
|
||||||
|
<i class="fa-solid fa-slash" style="position: absolute;left: 4px;top: 3px;"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="onLineIndicator" class="showWhenWebRTCIsConnected showWhenIsNotLive indicator" style="display: none;"><i class="fa-solid fa-wifi"></i></div>
|
||||||
|
<div id="liveIndicator" class="showWhenIsLive indicator" style="display: none;"><i class="fa-solid fa-wifi"></i></div>
|
||||||
<video id="localVideo" autoplay muted playsinline></video>
|
<video id="localVideo" autoplay muted playsinline></video>
|
||||||
|
<iframe id="webrtcChat" class="transparent-iframe" src="<?php echo $global['webSiteRootURL']; ?>plugin/MobileYPT/index.php?key=<?php echo $key; ?>&live_index=<?php echo $forceIndex; ?>"></iframe>
|
||||||
<script src="<?php echo getURL('node_modules/socket.io-client/dist/socket.io.min.js'); ?>" type="text/javascript"></script>
|
<script src="<?php echo getURL('node_modules/socket.io-client/dist/socket.io.min.js'); ?>" type="text/javascript"></script>
|
||||||
<script src="<?php echo getURL('plugin/Live/WebRTC/api.js'); ?>" type="text/javascript"></script>
|
<script src="<?php echo getURL('plugin/Live/WebRTC/api.js'); ?>" type="text/javascript"></script>
|
||||||
<script src="<?php echo getURL('plugin/Live/WebRTC/events.js'); ?>" type="text/javascript"></script>
|
<script src="<?php echo getURL('plugin/Live/WebRTC/events.js'); ?>" type="text/javascript"></script>
|
|
@ -12,6 +12,9 @@ function isInLive(json) {
|
||||||
|
|
||||||
var prerollPosterAlreadyPlayed = false;
|
var prerollPosterAlreadyPlayed = false;
|
||||||
async function showImage(type, key) {
|
async function showImage(type, key) {
|
||||||
|
if (typeof player === 'undefined') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (typeof closeLiveImageRoll == 'function') {
|
if (typeof closeLiveImageRoll == 'function') {
|
||||||
closeLiveImageRoll();
|
closeLiveImageRoll();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,35 @@
|
||||||
function socketLiveONCallback(json) {
|
document.addEventListener('socketLiveONCallback', function(event) {
|
||||||
|
let json = event.detail;
|
||||||
|
if(json === null){
|
||||||
|
console.error('socketLiveONCallback socket EventListener error', event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log('socketLiveONCallback socket EventListener', json);
|
||||||
if (typeof json === 'string') {
|
if (typeof json === 'string') {
|
||||||
try {
|
try {
|
||||||
json = JSON.parse(json);
|
json = JSON.parse(json);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Invalid JSON string:", error);
|
console.error("Invalid JSON string:", error);
|
||||||
return null; // or return the original string if you prefer
|
return; // Exit the listener if JSON parsing fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(typeof json.key == 'undefined'){
|
||||||
|
if(typeof json.json !== 'undefined' && typeof json.json.key !== 'undefined' ){
|
||||||
|
json = json.json;
|
||||||
|
}else{
|
||||||
|
console.error("socketLiveONCallback Invalid JSON key not found:", json);
|
||||||
|
return; // Exit the listener if JSON parsing fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log('socketLiveONCallback live plugin', json);
|
console.log('socketLiveONCallback live plugin', json);
|
||||||
|
|
||||||
if (typeof processLiveStats == 'function') {
|
if (typeof processLiveStats == 'function') {
|
||||||
processLiveStats(json.stats);
|
processLiveStats(json.stats);
|
||||||
}
|
}
|
||||||
var selector = '.live_' + json.live_servers_id + "_" + json.key;
|
|
||||||
|
let selector = '.live_' + json.live_servers_id + "_" + json.key;
|
||||||
$(selector).slideDown();
|
$(selector).slideDown();
|
||||||
|
|
||||||
if (typeof onlineLabelOnline == 'function') {
|
if (typeof onlineLabelOnline == 'function') {
|
||||||
|
@ -23,38 +41,58 @@ function socketLiveONCallback(json) {
|
||||||
onlineLabelOnline(selector);
|
onlineLabelOnline(selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the chat if the history changes
|
let IframeClass = ".yptchat2IframeClass_" + json.key + "_" + json.live_servers_id;
|
||||||
var IframeClass = ".yptchat2IframeClass_" + json.key + "_" + json.live_servers_id;
|
|
||||||
if ($(IframeClass).length) {
|
if ($(IframeClass).length) {
|
||||||
var src = $(IframeClass).attr('src');
|
let src = $(IframeClass).attr('src');
|
||||||
if (src) {
|
if (src) {
|
||||||
avideoToast('Loading new chat');
|
avideoToast('Loading new chat');
|
||||||
var newSRC = addGetParam(src, 'live_transmitions_history_id', json.live_transmitions_history_id);
|
let newSRC = addGetParam(src, 'live_transmitions_history_id', json.live_transmitions_history_id);
|
||||||
$(IframeClass).attr('src', newSRC);
|
$(IframeClass).attr('src', newSRC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInLive(json)) {
|
if (isInLive(json)) {
|
||||||
playerPlay();
|
playerPlay();
|
||||||
showImage('prerollPoster', json.cleanKey);
|
showImage('prerollPoster', json.cleanKey);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
function socketLiveOFFCallback(json) {
|
|
||||||
|
document.addEventListener('socketLiveOFFCallback', function(event) {
|
||||||
|
let json = event.detail;
|
||||||
|
if(json === null){
|
||||||
|
console.error('socketLiveOFFCallback socket EventListener error', event);
|
||||||
|
console.trace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log('socketLiveOFFCallback socket EventListener', json);
|
||||||
|
|
||||||
if (typeof json === 'string') {
|
if (typeof json === 'string') {
|
||||||
try {
|
try {
|
||||||
json = JSON.parse(json);
|
json = JSON.parse(json);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Invalid JSON string:", error);
|
console.error("Invalid JSON string:", error);
|
||||||
return null; // or return the original string if you prefer
|
return; // Exit the listener if JSON parsing fails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(typeof json.key == 'undefined'){
|
||||||
|
if(typeof json.json !== 'undefined' && typeof json.json.key !== 'undefined' ){
|
||||||
|
json = json.json;
|
||||||
|
}else{
|
||||||
|
console.error("socketLiveOFFCallback Invalid JSON key not found:", json);
|
||||||
|
return; // Exit the listener if JSON parsing fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.log('socketLiveOFFCallback live socket', json);
|
console.log('socketLiveOFFCallback live socket', json);
|
||||||
var selector = '.live_' + json.live_servers_id + "_" + json.key;
|
|
||||||
|
let selector = '.live_' + json.live_servers_id + "_" + json.key;
|
||||||
selector += ', .liveVideo_live_' + json.live_servers_id + "_" + json.key;
|
selector += ', .liveVideo_live_' + json.live_servers_id + "_" + json.key;
|
||||||
selector += ', .live_' + json.key;
|
selector += ', .live_' + json.key;
|
||||||
////console.log('socketLiveOFFCallback 1', selector);
|
|
||||||
$(selector).slideUp("fast", function () {
|
$(selector).slideUp("fast", function () {
|
||||||
$(this).remove();
|
$(this).remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof onlineLabelOffline == 'function') {
|
if (typeof onlineLabelOffline == 'function') {
|
||||||
selector = '#liveViewStatusID_' + json.key + '_' + json.live_servers_id;
|
selector = '#liveViewStatusID_' + json.key + '_' + json.live_servers_id;
|
||||||
selector += ', .liveViewStatusClass_' + json.key + '_' + json.live_servers_id;
|
selector += ', .liveViewStatusClass_' + json.key + '_' + json.live_servers_id;
|
||||||
|
@ -63,8 +101,8 @@ function socketLiveOFFCallback(json) {
|
||||||
console.log('socketLiveOFFCallback', selector);
|
console.log('socketLiveOFFCallback', selector);
|
||||||
onlineLabelOffline(selector);
|
onlineLabelOffline(selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
//console.log('socketLiveOFFCallback processLiveStats');
|
|
||||||
if (typeof processLiveStats == 'function') {
|
if (typeof processLiveStats == 'function') {
|
||||||
processLiveStats(json.stats);
|
processLiveStats(json.stats);
|
||||||
}
|
}
|
||||||
|
@ -78,10 +116,12 @@ function socketLiveOFFCallback(json) {
|
||||||
if (isInLive(json)) {
|
if (isInLive(json)) {
|
||||||
showImage('postrollPoster', json.cleanKey);
|
showImage('postrollPoster', json.cleanKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof updateUserNotificationCount == 'function') {
|
if (typeof updateUserNotificationCount == 'function') {
|
||||||
updateUserNotificationCount();
|
updateUserNotificationCount();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
||||||
function redirectLive(json, countdown = 15) {
|
function redirectLive(json, countdown = 15) {
|
||||||
if (typeof json === 'string') {
|
if (typeof json === 'string') {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
global $global, $config;
|
global $global, $config;
|
||||||
$global['isIframe'] = 1;
|
$global['isIframe'] = 1;
|
||||||
|
$global['isNotAPlayer'] = 1;
|
||||||
// is online
|
// is online
|
||||||
// recorder
|
// recorder
|
||||||
// live users
|
// live users
|
||||||
|
@ -17,7 +18,7 @@ $global['skippPlugins'][] = 'TheaterButton';
|
||||||
//$global['doNotLoadPlayer'] = 1;
|
//$global['doNotLoadPlayer'] = 1;
|
||||||
$bodyClass = '';
|
$bodyClass = '';
|
||||||
$key = '';
|
$key = '';
|
||||||
$live_servers_id = '';
|
$live_servers_id = 0;
|
||||||
$live_index = '';
|
$live_index = '';
|
||||||
$users_id = User::getId();
|
$users_id = User::getId();
|
||||||
if (!empty($_REQUEST['logoff'])) {
|
if (!empty($_REQUEST['logoff'])) {
|
||||||
|
@ -28,12 +29,12 @@ User::loginFromRequestIfNotLogged();
|
||||||
if (User::isLogged()) {
|
if (User::isLogged()) {
|
||||||
if (!empty($_REQUEST['key'])) {
|
if (!empty($_REQUEST['key'])) {
|
||||||
$key = $_REQUEST['key'];
|
$key = $_REQUEST['key'];
|
||||||
$live_servers_id = @$_REQUEST['live_servers_id'];
|
$live_servers_id = intval(@$_REQUEST['live_servers_id']);
|
||||||
$live_index = @$_REQUEST['live_index'];
|
$live_index = @$_REQUEST['live_index'];
|
||||||
} else if (User::isLogged()) {
|
} else if (User::isLogged()) {
|
||||||
$lth = LiveTransmitionHistory::getLatestFromUser($users_id);
|
$lth = LiveTransmitionHistory::getLatestFromUser($users_id);
|
||||||
$key = $lth['key'];
|
$key = $lth['key'];
|
||||||
$live_servers_id = $lth['live_servers_id'];
|
$live_servers_id = intval($lth['live_servers_id']);
|
||||||
$live_index = @$lth['live_index'];
|
$live_index = @$lth['live_index'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,9 +60,11 @@ if (User::isLogged()) {
|
||||||
$chat->set_doNotAllowUsersSendMessagesToEachOther(1);
|
$chat->set_doNotAllowUsersSendMessagesToEachOther(1);
|
||||||
$chat->set_hideBubbleButtons(1);
|
$chat->set_hideBubbleButtons(1);
|
||||||
$iframeURL = $chat->getURL(true);
|
$iframeURL = $chat->getURL(true);
|
||||||
|
$iframeClass = "yptchat2IframeClass_{$key}-{$live_index}_{$live_servers_id}";
|
||||||
|
|
||||||
$html = '<iframe
|
$html = '<iframe
|
||||||
id="yptchat2Iframe"
|
id="yptchat2Iframe"
|
||||||
|
class="' . $iframeClass . '"
|
||||||
src="' . $iframeURL . '"
|
src="' . $iframeURL . '"
|
||||||
frameborder="0" scrolling="no" title="chat widget"
|
frameborder="0" scrolling="no" title="chat widget"
|
||||||
allowtransparency="true"
|
allowtransparency="true"
|
||||||
|
@ -97,7 +100,7 @@ if (User::isLogged()) {
|
||||||
//$html .= getIncludeFileContent($global['systemRootPath'] . 'plugin/Live/view/menuRight.php');
|
//$html .= getIncludeFileContent($global['systemRootPath'] . 'plugin/Live/view/menuRight.php');
|
||||||
//var_dump($lt);exit;
|
//var_dump($lt);exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AVideoPlugin::isEnabledByName('SendRecordedToEncoder')) {
|
if (AVideoPlugin::isEnabledByName('SendRecordedToEncoder')) {
|
||||||
$html .= '<!-- SendRecordedToEncoder start -->';
|
$html .= '<!-- SendRecordedToEncoder start -->';
|
||||||
$html .= getIncludeFileContent($global['systemRootPath'] . 'plugin/SendRecordedToEncoder/actionButtonLive.php');
|
$html .= getIncludeFileContent($global['systemRootPath'] . 'plugin/SendRecordedToEncoder/actionButtonLive.php');
|
||||||
|
@ -112,70 +115,89 @@ if (User::isLogged()) {
|
||||||
?>
|
?>
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="">
|
<html lang="">
|
||||||
<head>
|
|
||||||
|
<head>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
padding: 100px 0;
|
padding: 100px 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<?php
|
<?php
|
||||||
include $global['systemRootPath'] . 'view/include/head.php';
|
include $global['systemRootPath'] . 'view/include/head.php';
|
||||||
?>
|
?>
|
||||||
<style>
|
<style>
|
||||||
#accessibility-toolbar, footer, #socket_info_container{
|
#accessibility-toolbar,
|
||||||
display: none !important;
|
footer,
|
||||||
}
|
#socket_info_container {
|
||||||
body {
|
display: none !important;
|
||||||
padding: 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.liveUsersLabel{
|
body {
|
||||||
position: fixed;
|
padding: 0;
|
||||||
top: 10px !important;
|
}
|
||||||
}
|
|
||||||
.liveUsersLabel{
|
|
||||||
left: 20px !important;
|
|
||||||
}
|
|
||||||
#recorderToEncoderActionButtons{
|
|
||||||
position: absolute;
|
|
||||||
top: 40px;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.showWhenClosed, #closeRecorderButtons{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#recorderToEncoderActionButtons.closed .recordLiveControlsDiv,
|
|
||||||
#recorderToEncoderActionButtons.closed .hideWhenClosed{
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
#recorderToEncoderActionButtons.closed .showWhenClosed,
|
|
||||||
.isLiveOnline #closeRecorderButtons{
|
|
||||||
display: inline-block !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body style="background-color: transparent; <?php echo @$bodyClass; ?>">
|
.liveUsersLabel {
|
||||||
<?php
|
position: fixed;
|
||||||
echo $html;
|
top: 10px !important;
|
||||||
?>
|
}
|
||||||
<?php
|
|
||||||
include $global['systemRootPath'] . 'view/include/footer.php';
|
.liveUsersLabel {
|
||||||
?>
|
left: 20px !important;
|
||||||
<script>
|
}
|
||||||
function socketLiveONCallback(json) {
|
|
||||||
console.log('socketLiveONCallback MobileYPT', json);
|
#recorderToEncoderActionButtons {
|
||||||
if ((json.users_id == '<?php echo User::getId(); ?>' && json.live_transmitions_history_id) || (!empty(json.key) && json.key == '<?php echo @$_REQUEST['key']; ?>')) {
|
position: absolute;
|
||||||
modal.showPleaseWait();
|
top: 40px;
|
||||||
var url = addGetParam(window.location.href, 'live_transmitions_history_id', json.live_transmitions_history_id);
|
left: 0;
|
||||||
url = addGetParam(url, 'key', json.key);
|
width: 100%;
|
||||||
url = addGetParam(url, 'live_servers_id', json.live_servers_id);
|
}
|
||||||
url = addGetParam(url, 'live_schedule', json.live_schedule);
|
|
||||||
url = addGetParam(url, 'live_index', json.live_index);
|
.showWhenClosed,
|
||||||
document.location = url;
|
#closeRecorderButtons {
|
||||||
}
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#recorderToEncoderActionButtons.closed .recordLiveControlsDiv,
|
||||||
|
#recorderToEncoderActionButtons.closed .hideWhenClosed {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#recorderToEncoderActionButtons.closed .showWhenClosed,
|
||||||
|
.isLiveOnline #closeRecorderButtons {
|
||||||
|
display: inline-block !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="background-color: transparent; <?php echo @$bodyClass; ?>">
|
||||||
|
<?php
|
||||||
|
echo $html;
|
||||||
|
?>
|
||||||
|
<?php
|
||||||
|
include $global['systemRootPath'] . 'view/include/footer.php';
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('socketLiveONCallback', function(event) {
|
||||||
|
const json = event.detail; // Extract the JSON data from the event's detail property
|
||||||
|
console.log('socketLiveONCallback EventListener', json);
|
||||||
|
if(json == null){
|
||||||
|
console.trace();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
</script>
|
if (
|
||||||
</body>
|
(json.users_id == '<?php echo User::getId(); ?>' && json.live_transmitions_history_id) ||
|
||||||
|
(json.key && json.key == '<?php echo @$_REQUEST['key']; ?>')
|
||||||
|
) {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
let url = addGetParam(window.location.href, 'live_transmitions_history_id', json.live_transmitions_history_id);
|
||||||
|
url = addGetParam(url, 'key', json.key);
|
||||||
|
url = addGetParam(url, 'live_servers_id', json.live_servers_id);
|
||||||
|
url = addGetParam(url, 'live_schedule', json.live_schedule);
|
||||||
|
url = addGetParam(url, 'live_index', json.live_index);
|
||||||
|
document.location = url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
|
@ -41,17 +41,31 @@ function processSocketJson(json) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var myfunc;
|
var myfunc;
|
||||||
|
var _details = json;
|
||||||
|
if(typeof json.msg != 'undefined'){
|
||||||
|
_details = json.msg;
|
||||||
|
}
|
||||||
|
if(typeof _details === 'string'){
|
||||||
|
_details = JSON.parse(_details);
|
||||||
|
console.log('processSocketJson: details after', _details);
|
||||||
|
}
|
||||||
if (json.callback) {
|
if (json.callback) {
|
||||||
//console.log("processSocketJson json.callback ", json.resourceId, json.callback);
|
// Check if a function exists with the name in json.callback
|
||||||
var code = "if(typeof " + json.callback + " == 'function'){myfunc = " + json.callback + ";}else{myfunc = defaultCallback;}";
|
var code = "if (typeof " + json.callback + " == 'function') { myfunc = " + json.callback + "; } else { myfunc = defaultCallback; }";
|
||||||
console.log('processSocketJson: code=' + code);
|
console.log('processSocketJson: code=' + code, _details);
|
||||||
eval(code);
|
eval(code);
|
||||||
|
|
||||||
|
// Trigger the event with the same name as json.callback and pass the JSON object
|
||||||
|
const event = new CustomEvent(json.callback, { detail: _details }); // Pass the JSON as `detail`
|
||||||
|
document.dispatchEvent(event);
|
||||||
} else {
|
} else {
|
||||||
//console.log("processSocketJson: callback not found", json);
|
console.log("processSocketJson: callback not found", json);
|
||||||
myfunc = defaultCallback;
|
myfunc = defaultCallback;
|
||||||
}
|
}
|
||||||
//console.log("onmessage: callback ", myfunc, json.msg);
|
|
||||||
myfunc(json.msg);
|
// Call the function and pass the JSON object
|
||||||
|
myfunc(_details);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue