Changeset 3408984
- Timestamp:
- 12/03/2025 07:53:11 AM (4 months ago)
- Location:
- wpstream
- Files:
-
- 22 edited
- 1 copied
-
tags/4.9.4 (copied) (copied from wpstream/trunk)
-
tags/4.9.4/admin/js/wpstream-onboarding-page.js (modified) (2 diffs)
-
tags/4.9.4/includes/class-wpstream-player.php (modified) (3 diffs)
-
tags/4.9.4/public/class-wpstream-public.php (modified) (1 diff)
-
tags/4.9.4/public/css/broadcaster.css (modified) (3 diffs)
-
tags/4.9.4/public/css/wpstream_style.css (modified) (2 diffs)
-
tags/4.9.4/public/js/broadcaster.js (modified) (16 diffs)
-
tags/4.9.4/public/js/start_streaming.js (modified) (2 diffs)
-
tags/4.9.4/public/js/wpstream-player.js (modified) (1 diff)
-
tags/4.9.4/readme.txt (modified) (2 diffs)
-
tags/4.9.4/templates/broadcaster-template.php (modified) (2 diffs)
-
tags/4.9.4/wpstream.php (modified) (2 diffs)
-
trunk/admin/js/wpstream-onboarding-page.js (modified) (2 diffs)
-
trunk/includes/class-wpstream-player.php (modified) (3 diffs)
-
trunk/public/class-wpstream-public.php (modified) (1 diff)
-
trunk/public/css/broadcaster.css (modified) (3 diffs)
-
trunk/public/css/wpstream_style.css (modified) (2 diffs)
-
trunk/public/js/broadcaster.js (modified) (16 diffs)
-
trunk/public/js/start_streaming.js (modified) (2 diffs)
-
trunk/public/js/wpstream-player.js (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/templates/broadcaster-template.php (modified) (2 diffs)
-
trunk/wpstream.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
wpstream/tags/4.9.4/admin/js/wpstream-onboarding-page.js
r3394809 r3408984 8 8 */ 9 9 function wpstream_track_onboarding_step(action, step, element_type= 'button', element_name = '') { 10 console.log('Tracking onboarding step:', action, step, element_type, element_name); 10 11 fetch( wpstream_onboarding_page_vars.request_url + '/onboarding/index.php', { 11 12 method: 'POST', … … 30 31 31 32 window.addEventListener('DOMContentLoaded', async function() { 32 if ( jQuery('#wpstream_have_token').length >0 ) { 33 wpstream_track_onboarding_step('onboarding_loaded', 'wpstream_step_2'); 34 } else { 35 wpstream_track_onboarding_step('onboarding_loaded', 'login_step'); 33 // if it's the create channel page 34 if ( wpstream_onboarding_page_vars.current_page === 'post_edit' ) { 35 wpstream_track_onboarding_step('onboarding_loaded', 'create_channel_step'); 36 } 37 38 // if it's the WpStream -> Quick start page 39 if ( wpstream_onboarding_page_vars.current_page === 'onboarding' ) { 40 if (jQuery('#wpstream_have_token').length > 0) { 41 wpstream_track_onboarding_step('onboarding_loaded', 'wpstream_step_2'); 42 } else { 43 wpstream_track_onboarding_step('onboarding_loaded', 'register_step'); 44 } 36 45 } 37 46 }); -
wpstream/tags/4.9.4/includes/class-wpstream-player.php
r3404022 r3408984 479 479 $player_logo_horizontal_position = 'logo-' . explode( '-', $player_logo_position )[1]; 480 480 } 481 echo' 482 <video id="wpstream-video'.$now.'" '.$poster_data.' class="video-js vjs-default-skin vjs-fluid vjs-wpstream ' . esc_attr($has_trailer_class) . ' ' . $player_theme . ' ' . $player_logo_position_class . ' ' . $player_logo_horizontal_position . '" playsinline="true" '.$is_muted_str." ".$autoplay_str.'> 483 481 // echo' 482 // <div class="wpstream-video-container"> 483 // <div id="wpstream-pre-load-spinner" class="wpstream-pre-load-spinner"></div> 484 // <video id="wpstream-video'.$now.'" '.$poster_data.' class="video-js vjs-default-skin vjs-fluid vjs-wpstream ' . esc_attr($has_trailer_class) . ' ' . $player_theme . ' ' . $player_logo_position_class . ' ' . $player_logo_horizontal_position . '" playsinline="true" '.$is_muted_str." ".$autoplay_str.'> 485 // </video> 486 // </div>'; 487 echo '<div class="wpstream-pre-load-spinner"></div>'; 488 echo' 489 <video id="wpstream-video'.$now.'" '.$poster_data.' class="video-js vjs-default-skin vjs-fluid vjs-wpstream ' . esc_attr($has_trailer_class) . ' ' . $player_theme . ' ' . $player_logo_position_class . ' ' . $player_logo_horizontal_position . '" playsinline="true" '.$is_muted_str." ".$autoplay_str.'> 490 484 491 </video>'; 485 492 if ($video_trailer){ … … 975 982 unmuteTrailerButtonElementId: "wpstream_video_on_demand_unmute_trailer_btn_'.$now.'", 976 983 playVideoButtonElementId: "wpstream_video_on_demand_play_video_btn_'.$now.'", 977 //playerLogoSettings: {978 //image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '",979 //position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '",980 //opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ',981 //width: 100,982 //height: "auto",983 //padding: 10,984 //},984 playerLogoSettings: { 985 image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '", 986 position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '", 987 opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ', 988 width: 100, 989 height: "auto", 990 padding: 10, 991 }, 985 992 }); 986 993 }); … … 1002 1009 autoplay: '.var_export($autoplay, true).', 1003 1010 muted: '.var_export($muted, true).', 1004 //playerLogoSettings: {1005 //image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '",1006 //position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '",1007 //opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ',1008 //width: 100,1009 //height: "auto",1010 //padding: 10,1011 //}1011 playerLogoSettings: { 1012 image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '", 1013 position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '", 1014 opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ', 1015 width: 100, 1016 height: "auto", 1017 padding: 10, 1018 } 1012 1019 }); 1013 1020 }); -
wpstream/tags/4.9.4/public/class-wpstream-public.php
r3390939 r3408984 1719 1719 1720 1720 if ( false === $event_list_paid_posts ) { 1721 print ' transient paid expired ';1722 1721 $args = array( 1723 1722 'posts_per_page' => -1, -
wpstream/tags/4.9.4/public/css/broadcaster.css
r3362236 r3408984 81 81 left: 1.5em; 82 82 opacity: 90%; 83 z-index: 3; 83 84 } 84 85 … … 124 125 125 126 #localVideo { 126 width: 100%; 127 height: 100%; 127 position: relative; 128 z-index: 2; 129 width: 100%; 128 130 background-color: #EEEEEE; 129 131 } … … 300 302 } 301 303 304 .info-message, 305 .error-message { 306 position: relative; 307 padding: 1rem; 308 padding-right: 2.5rem; /* Make space for the close button */ 309 } 310 311 .error-message .dismiss-message { 312 position: absolute; 313 top: 50%; 314 right: 0.5rem; 315 transform: translateY(-50%); 316 background: none; 317 border: none; 318 font-size: 1.5rem; 319 line-height: 1; 320 color: inherit; 321 cursor: pointer; 322 opacity: 0.7; 323 padding: 0.5rem; 324 } 325 326 .error-message .dismiss-message:hover { 327 opacity: 1; 328 } 329 330 302 331 .success-message { 303 332 color: #00a32a; -
wpstream/tags/4.9.4/public/css/wpstream_style.css
r3402264 r3408984 84 84 top: 50%; 85 85 left: 50%; 86 width: 30px;87 height: 30px;86 width: 40px; 87 height: 40px; 88 88 margin: -25px 0 0 -25px; 89 89 opacity: 0.85; 90 border-radius: 25px;90 border-radius: 40px; 91 91 border: 6px solid rgba(43, 51, 63, 0.7); 92 92 border-top-color: white; 93 93 animation: wpstream-spinner-spin 1.1s linear infinite; 94 z-index: 1 000;94 z-index: 1; 95 95 } 96 96 … … 168 168 position:relative; 169 169 height: 30px; 170 position: relative;171 170 background: transparent; 172 171 margin-bottom: 15px; -
wpstream/tags/4.9.4/public/js/broadcaster.js
r3364177 r3408984 51 51 vga: { 52 52 width: { ideal: 640 }, 53 height: { ideal: 480 },53 height: { ideal: 360 }, 54 54 }, 55 55 hd: { 56 width: { ideal: 1280 },57 height: { ideal: 720 },56 width: { exact: 1280 }, 57 height: { exact: 720 }, 58 58 }, 59 59 fhd: { 60 width: { ideal: 1920 },61 height: { ideal: 1080 },60 width: { exact: 1920 }, 61 height: { exact: 1080 }, 62 62 }, 63 63 square: { 64 width: { ideal: 800 },65 height: { ideal: 600 },64 width: { exact: 800 }, 65 height: { exact: 600 }, 66 66 }, 67 67 default: { 68 width: { ideal: 1280 },69 height: { ideal: 720 },68 width: { min: 640, ideal: 1280, max: 1920 }, 69 height: { min: 360, ideal: 720, max: 1080 }, 70 70 }, 71 71 }; 72 72 73 73 const displayResolutions = { 74 vga: { width: 640, height: 480 },74 vga: { width: 640, height: 360 }, 75 75 hd: { width: 1280, height: 720 }, 76 76 fhd: { width: 1920, height: 1080 }, … … 89 89 console.log( 90 90 "Resolution: " + 91 videoElement.videoWidth +92 "x" +93 videoElement.videoHeight91 videoElement.videoWidth + 92 "x" + 93 videoElement.videoHeight 94 94 ); 95 95 … … 201 201 messageElement.textContent = message; 202 202 203 const dismissButton = document.createElement("button"); 204 dismissButton.className = 'dismiss-message'; 205 dismissButton.innerHTML = '×'; 206 dismissButton.addEventListener('click', function() { 207 messageElement.remove(); 208 }); 209 210 messageElement.appendChild(dismissButton); 211 203 212 messageContainer.innerHTML = ""; 204 213 messageContainer.appendChild(messageElement); … … 217 226 "connected", 218 227 "disconnected", 219 "connecting" 228 "connecting", 229 "reconnecting" 220 230 ); 221 231 … … 231 241 statusText.textContent = "Connecting..."; 232 242 liveIndicatorError.style.display = 'inline'; 233 liveIndicator Live.innerContent = 'Connecting';243 liveIndicatorError.innerText = 'Connecting...'; 234 244 break; 235 245 case "reconnecting": 236 246 statusIndicator.classList.add("connecting"); 237 statusText.textContent = "Reconnecting ...";247 statusText.textContent = "Reconnecting"; 238 248 liveIndicatorError.style.display = 'inline'; 239 liveIndicatorLive.innerContent = 'Reconnecting'; 249 liveIndicatorLive.style.display = 'none'; 250 liveIndicatorError.innerText = 'Connection lost. Reconnecting in 10 seconds...'; 240 251 break; 241 252 case "disconnected": … … 249 260 } 250 261 251 function createInput( shouldAutoStart = false ) {262 function createInput( shouldAutoStart = false, keepMessages = false ) { 252 263 if (streamingButton) { 253 264 streamingButton.disabled = true; … … 259 270 } 260 271 261 resetMessages(); 272 if ( !keepMessages ) { 273 resetMessages(); 274 } 275 276 if (localStream) { 277 localStream.getTracks().forEach((track) => track.stop()); 278 localStream = null; 279 } 262 280 263 281 input = OvenLiveKit.create({ 264 282 callbacks: { 265 283 error: function (error) { 266 let errorMessage = ""; 267 268 if (error.message) { 269 errorMessage = error.message; 270 } else if (error.name) { 271 errorMessage = error.name; 272 } else { 273 errorMessage = error.toString(); 284 let errorMessage = ''; 285 286 if (error.message) { 287 errorMessage = error.message; 288 } else if (error.name) { 289 errorMessage = error.name; 290 } else { 291 errorMessage = error.toString(); 292 } 293 294 if (error.name === "OverconstrainedError") { 295 showMessage( 296 "Your browser or camera does not support this frame size: " + videoResolutionSelect.value, 297 'error' 298 ); 299 videoResolutionSelect.value = 'default'; 300 createInput(shouldAutoStart, true); 301 return; 274 302 } 275 303 276 if (errorMessage === "OverconstrainedError") { 277 errorMessage = 278 "The input device does not support the specified resolution or frame rate."; 279 } 280 281 resetMessages(); 282 showMessage(errorMessage, "error"); 283 284 if ( shouldAutoStart) { 285 considerReconnect = false; 286 } 287 }, 288 connectionClosed: function (type, event) { 289 console.log("Connection closed:", type, event); 290 streamingStarted = false; 291 updateStatus("disconnected"); 292 293 if (streamingButton) { 294 streamingButton.classList.remove("hidden"); 295 streamingButton.disabled = false; 296 } 297 if (stopButton) { 298 stopButton.classList.add("hidden"); 299 } 304 resetMessages(); 305 showMessage(errorMessage, "error"); 306 307 if (shouldAutoStart) { 308 considerReconnect = false; 309 } 310 }, 311 connectionClosed: function (type, event) { 312 console.log("Connection closed:", type, event); 313 streamingStarted = false; 314 // updateStatus("disconnected"); 315 316 // if (streamingButton) { 317 // streamingButton.classList.remove("hidden"); 318 // streamingButton.disabled = false; 319 // } 320 // if (stopButton) { 321 // stopButton.classList.add("hidden"); 322 // } 300 323 301 324 if (considerReconnect && !pendingReconnect) { … … 307 330 } else { 308 331 console.log('connection closed, not reconnecting'); 309 updateInputState(false);332 // updateInputState(false); 310 333 } 311 334 }, … … 314 337 if ( state === 'connected' ) { 315 338 // showMessage("Broadcast started successfully"); 339 updateStatus('connected'); 316 340 } 317 341 318 if (state === "disconnected" && considerReconnect) { 319 streamingStarted = false; 320 updateStatus("disconnected"); 321 322 if (considerReconnect && !pendingReconnect) { 323 console.log('connection closed, attempting to reconnect from ice state change'); 324 // showMessage("Connection lost, attempting to reconnect...", "info"); 325 attemptReconnect(); 326 } else { 327 showMessage( 328 "Connection failed. Please check your network settings.", 329 "error" 330 ); 331 } 332 } 342 if (state === "disconnected" && considerReconnect) { 343 streamingStarted = false; 344 if (considerReconnect && !pendingReconnect) { 345 console.log( 346 "connection closed, attempting to reconnect from ice state change" 347 ); 348 updateStatus("reconnecting"); 349 attemptReconnect(); 350 } else { 351 showMessage( 352 "Connection failed. Please check your network settings.", 353 "error" 354 ); 355 } 356 } 357 }, 333 358 }, 334 }, 335 }); 336 337 input.attachMedia(videoElement); 338 339 if (videoSourceSelect.value) { 359 }); 360 361 input.attachMedia(videoElement); 362 363 if (videoSourceSelect.options.length > 0) { 340 364 if (videoSourceSelect.value === "displayCapture") { 341 365 input … … 445 469 function attemptReconnect() { 446 470 console.log("attemptReconnect()"); 471 updateStatus('reconnecting'); 447 472 448 473 if ( pendingReconnect ) { … … 451 476 } 452 477 453 considerReconnect = false; 454 pendingReconnect = true; 455 456 if ( input ) { 457 input.callbacks = { 458 error: function() {}, 459 connectionClosed: function () {}, 460 iceStateChange: function () {}, 461 }; 462 463 if( input.streamingMode === 'whip') { 464 input.stopStreaming(); 465 } else if ( input.streamingMode === 'webrtc' ) { 466 if( input.webSocket ) { 478 // Clean up existing connection before reconnecting 479 if (input) { 480 if (input.peerConnection || input.webSocket) { 481 // Force cleanup without triggering callbacks 482 if (input.peerConnection) { 483 input.peerConnection.close(); 484 input.peerConnection = null; 485 } 486 if (input.webSocket) { 467 487 input.webSocket.close(); 468 488 input.webSocket = null; 469 489 } 470 if( input.peerConnection ) {471 input.peerConnection.close();472 input.peerConnection = null;473 }474 } 475 }490 // Reset streaming mode 491 input.streamingMode = null; 492 } 493 } 494 495 pendingReconnect = true; 476 496 477 497 // Show a reconnecting state and allow user to cancel via Stop button 478 updateStatus("reconnecting"); 479 updateInputState(true); 480 498 // showMessage("Disconnected. Reconnecting in 5 seconds...", "info"); 499 // updateInputState(false); 500 501 pendingReconnect = true; 481 502 pendingReconnectTimeout = setTimeout(function () { 482 if (!considerReconnect && !pendingReconnect) { 483 return; // User cancelled or stopped 484 } 485 486 checkChannelStatus(wpstream_broadcaster_vars.channel_id) 487 .then(function(channelActive) { 488 if (channelActive) { 489 console.log("Channel is active, proceeding with reconnect..."); 490 // Reset flags before recreating 491 pendingReconnect = false; 492 pendingReconnectTimeout = null; 493 considerReconnect = true; 494 495 // Create new input and start streaming 496 createInput(true); 497 } else { 498 console.log("Channel is not active, cannot reconnect."); 499 pendingReconnect = false; 500 pendingReconnectTimeout = null; 501 showMessage('Channel is no longer active. Broadcasting stopped', 'error'); 502 resetStreamingUI(); 503 } 504 }) 505 .catch(function (error) { 506 console.error('Error during reconnect attempt:', error); 507 pendingReconnect = false; 508 pendingReconnectTimeout = null; 509 // Don't attempt another reconnect immediately to avoid loops 510 setTimeout(() => { 503 pendingReconnect = false; 504 pendingReconnectTimeout = null; 505 if (considerReconnect) { 506 checkChannelStatus(wpstream_broadcaster_vars.channel_id) 507 .then(function(channelActive) { 508 if (channelActive && considerReconnect) { 509 console.log("Channel is active, proceeding with reconnect..."); 510 updateStatus("connecting"); 511 // input.stopStreaming(); 512 setTimeout(function () { 513 createInput(true); 514 }, 5000); 515 } else { 516 console.log("Channel is not active, cannot reconnect."); 517 considerReconnect = false; 518 showMessage('Channel is no longer active. Broadcasting stopped'); 519 resetStreamingUI(); 520 } 521 }) 522 .catch(function (error) { 523 console.error('Error checking channel status'); 511 524 if (considerReconnect) { 525 console.error('Error during reconnect attempt:', error); 512 526 attemptReconnect(); 513 527 } 514 }, 5000); 515 }); 528 }); 529 530 // console.log('Reconnecting...'); 531 // createInput( true ); 532 // startStreaming(); 533 } 516 534 }, reconnectDelayMs); 517 535 } … … 539 557 }); 540 558 541 showMessage(enabled ? "Video enabled" : "Video disabled", "info");559 // showMessage(enabled ? "Video enabled" : "Video disabled", "info"); 542 560 } 543 561 } … … 714 732 const parsedResponse = JSON.parse(response); 715 733 if (parsedResponse.status === 'active') { 734 messageContainer.innerHTML = ""; 716 735 resolve(true); 717 736 } else { … … 727 746 error: function(xhr, status, error) { 728 747 console.error('Error checking channel status:', error); 748 resetStreamingUI(); 729 749 showMessage('Error checking channel status: ' + error, 'error'); 730 750 reject(false); … … 751 771 const parsedResponse = JSON.parse(response); 752 772 if (parsedResponse.available_data_mb > 0) { 773 messageContainer.innerHTML = ''; 753 774 resolve(true); 754 775 } else { … … 801 822 input.startStreaming(whipUrl, connectionConfig); 802 823 if ( input ) { 824 // TODO: check why input is sometimes null here 803 825 console.log('something was wrong' ); 804 826 } 805 updateStatus("connected");827 // updateStatus("connected"); 806 828 if ( isReconnect ) { 807 829 console.log('Reconnected successfully!'); -
wpstream/tags/4.9.4/public/js/start_streaming.js
r3402264 r3408984 759 759 var channelId = jQuery(this).closest('.event_list_unit').data('show-id'); 760 760 var whipUrl = ''; 761 var pendingPopup = window.open('', '_blank', 'location=yes,scrollbars=yes,status=yes'); 761 762 762 763 jQuery.ajax({ … … 776 777 // Open the new broadcaster in a new window 777 778 var broadcasterUrl = wpstream_start_streaming_vars.broadcaster_url + channelId; 778 window.open(broadcasterUrl, 'wpstream_broadcaster_' + channelId, 'fullscreen=yes'); 779 // window.open(broadcasterUrl, 'wpstream_broadcaster_' + channelId, 'fullscreen=yes'); 780 if (pendingPopup) { 781 pendingPopup.location.href = broadcasterUrl; 782 } else { 783 if (pendingPopup) { 784 pendingPopup.close(); 785 } 786 } 779 787 } 780 788 } else { -
wpstream/tags/4.9.4/public/js/wpstream-player.js
r3404022 r3408984 1475 1475 1476 1476 function removeSpinner( place ) { 1477 return; //disabled for now1478 const spinnerId = 'wpstream-pre-load-spinner';1479 const spinner = document.getElementById(spinnerId);1480 spinner.style.display = 'none';1481 } 1477 const playerSpinner = document.querySelectorAll('.wpstream-pre-load-spinner'); 1478 playerSpinner.forEach(spinner => { 1479 spinner.style.display = 'none'; 1480 }) 1481 } -
wpstream/tags/4.9.4/readme.txt
r3404022 r3408984 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.1 7 Stable tag: 4.9. 37 Stable tag: 4.9.4 8 8 License: GPL 9 9 License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html … … 136 136 == Changelog == 137 137 138 = 4.9.4 = 139 * Fix - Broadcaster reconnecting when losing connection 140 * Fix - Automatically select the right camera resolution when trying to use a non-supported resolution 141 * Fix - Broadcaster button on mobile devices 142 138 143 = 4.9.3 = 139 144 * Fix - Video not showing correctly when Hello WpStream theme is active -
wpstream/tags/4.9.4/templates/broadcaster-template.php
r3362236 r3408984 105 105 <span id="videoLiveIndicatorError" class="badge badge-pill badge-warning" style="display:none;"><?php esc_html_e('Connecting...', 'wpstream'); ?></span> 106 106 </div> 107 <video id="localVideo" autoplay muted playsinline></video> 107 <div class="video-wrapper"> 108 <div id="wpstream-pre-load-spinner" class="wpstream-pre-load-spinner"></div> 109 <video id="localVideo" autoplay muted playsinline></video> 110 </div> 108 111 </div> 109 112 … … 158 161 <option value="hd"><?php esc_html_e('1280x720', 'wpstream'); ?></option> 159 162 <option value="square"><?php esc_html_e('800x600', 'wpstream'); ?></option> 160 <option value="vga"><?php esc_html_e('640x 480', 'wpstream'); ?></option>163 <option value="vga"><?php esc_html_e('640x360', 'wpstream'); ?></option> 161 164 </select> 162 165 </div> -
wpstream/tags/4.9.4/wpstream.php
r3404022 r3408984 4 4 * Plugin URI: http://wpstream.net 5 5 * Description: WpStream is a platform that allows you to live stream, create Video-on-Demand, and offer Pay-Per-View videos. We provide an affordable and user-friendly way for businesses, non-profits, and public institutions to broadcast their content and monetize their work. 6 * Version: 4.9. 36 * Version: 4.9.4 7 7 * Author: wpstream 8 8 * Author URI: http://wpstream.net … … 15 15 die; 16 16 } 17 define('WPSTREAM_PLUGIN_VERSION', '4.9. 3');17 define('WPSTREAM_PLUGIN_VERSION', '4.9.4'); 18 18 define('WPSTREAM_CLUBLINK', 'wpstream.net'); 19 19 define('WPSTREAM_CLUBLINKSSL', 'https'); -
wpstream/trunk/admin/js/wpstream-onboarding-page.js
r3394809 r3408984 8 8 */ 9 9 function wpstream_track_onboarding_step(action, step, element_type= 'button', element_name = '') { 10 console.log('Tracking onboarding step:', action, step, element_type, element_name); 10 11 fetch( wpstream_onboarding_page_vars.request_url + '/onboarding/index.php', { 11 12 method: 'POST', … … 30 31 31 32 window.addEventListener('DOMContentLoaded', async function() { 32 if ( jQuery('#wpstream_have_token').length >0 ) { 33 wpstream_track_onboarding_step('onboarding_loaded', 'wpstream_step_2'); 34 } else { 35 wpstream_track_onboarding_step('onboarding_loaded', 'login_step'); 33 // if it's the create channel page 34 if ( wpstream_onboarding_page_vars.current_page === 'post_edit' ) { 35 wpstream_track_onboarding_step('onboarding_loaded', 'create_channel_step'); 36 } 37 38 // if it's the WpStream -> Quick start page 39 if ( wpstream_onboarding_page_vars.current_page === 'onboarding' ) { 40 if (jQuery('#wpstream_have_token').length > 0) { 41 wpstream_track_onboarding_step('onboarding_loaded', 'wpstream_step_2'); 42 } else { 43 wpstream_track_onboarding_step('onboarding_loaded', 'register_step'); 44 } 36 45 } 37 46 }); -
wpstream/trunk/includes/class-wpstream-player.php
r3404022 r3408984 479 479 $player_logo_horizontal_position = 'logo-' . explode( '-', $player_logo_position )[1]; 480 480 } 481 echo' 482 <video id="wpstream-video'.$now.'" '.$poster_data.' class="video-js vjs-default-skin vjs-fluid vjs-wpstream ' . esc_attr($has_trailer_class) . ' ' . $player_theme . ' ' . $player_logo_position_class . ' ' . $player_logo_horizontal_position . '" playsinline="true" '.$is_muted_str." ".$autoplay_str.'> 483 481 // echo' 482 // <div class="wpstream-video-container"> 483 // <div id="wpstream-pre-load-spinner" class="wpstream-pre-load-spinner"></div> 484 // <video id="wpstream-video'.$now.'" '.$poster_data.' class="video-js vjs-default-skin vjs-fluid vjs-wpstream ' . esc_attr($has_trailer_class) . ' ' . $player_theme . ' ' . $player_logo_position_class . ' ' . $player_logo_horizontal_position . '" playsinline="true" '.$is_muted_str." ".$autoplay_str.'> 485 // </video> 486 // </div>'; 487 echo '<div class="wpstream-pre-load-spinner"></div>'; 488 echo' 489 <video id="wpstream-video'.$now.'" '.$poster_data.' class="video-js vjs-default-skin vjs-fluid vjs-wpstream ' . esc_attr($has_trailer_class) . ' ' . $player_theme . ' ' . $player_logo_position_class . ' ' . $player_logo_horizontal_position . '" playsinline="true" '.$is_muted_str." ".$autoplay_str.'> 490 484 491 </video>'; 485 492 if ($video_trailer){ … … 975 982 unmuteTrailerButtonElementId: "wpstream_video_on_demand_unmute_trailer_btn_'.$now.'", 976 983 playVideoButtonElementId: "wpstream_video_on_demand_play_video_btn_'.$now.'", 977 //playerLogoSettings: {978 //image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '",979 //position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '",980 //opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ',981 //width: 100,982 //height: "auto",983 //padding: 10,984 //},984 playerLogoSettings: { 985 image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '", 986 position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '", 987 opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ', 988 width: 100, 989 height: "auto", 990 padding: 10, 991 }, 985 992 }); 986 993 }); … … 1002 1009 autoplay: '.var_export($autoplay, true).', 1003 1010 muted: '.var_export($muted, true).', 1004 //playerLogoSettings: {1005 //image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '",1006 //position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '",1007 //opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ',1008 //width: 100,1009 //height: "auto",1010 //padding: 10,1011 //}1011 playerLogoSettings: { 1012 image: "'. $this->wpstream_get_video_player_logo( $product_id ) . '", 1013 position: "' . esc_html( get_option('wpstream_player_logo_position','top-right') ) . '", 1014 opacity: ' . ( intval ( esc_html( get_option('wpstream_player_logo_opacity','100') ) ) / 100 ) . ', 1015 width: 100, 1016 height: "auto", 1017 padding: 10, 1018 } 1012 1019 }); 1013 1020 }); -
wpstream/trunk/public/class-wpstream-public.php
r3390939 r3408984 1719 1719 1720 1720 if ( false === $event_list_paid_posts ) { 1721 print ' transient paid expired ';1722 1721 $args = array( 1723 1722 'posts_per_page' => -1, -
wpstream/trunk/public/css/broadcaster.css
r3362236 r3408984 81 81 left: 1.5em; 82 82 opacity: 90%; 83 z-index: 3; 83 84 } 84 85 … … 124 125 125 126 #localVideo { 126 width: 100%; 127 height: 100%; 127 position: relative; 128 z-index: 2; 129 width: 100%; 128 130 background-color: #EEEEEE; 129 131 } … … 300 302 } 301 303 304 .info-message, 305 .error-message { 306 position: relative; 307 padding: 1rem; 308 padding-right: 2.5rem; /* Make space for the close button */ 309 } 310 311 .error-message .dismiss-message { 312 position: absolute; 313 top: 50%; 314 right: 0.5rem; 315 transform: translateY(-50%); 316 background: none; 317 border: none; 318 font-size: 1.5rem; 319 line-height: 1; 320 color: inherit; 321 cursor: pointer; 322 opacity: 0.7; 323 padding: 0.5rem; 324 } 325 326 .error-message .dismiss-message:hover { 327 opacity: 1; 328 } 329 330 302 331 .success-message { 303 332 color: #00a32a; -
wpstream/trunk/public/css/wpstream_style.css
r3402264 r3408984 84 84 top: 50%; 85 85 left: 50%; 86 width: 30px;87 height: 30px;86 width: 40px; 87 height: 40px; 88 88 margin: -25px 0 0 -25px; 89 89 opacity: 0.85; 90 border-radius: 25px;90 border-radius: 40px; 91 91 border: 6px solid rgba(43, 51, 63, 0.7); 92 92 border-top-color: white; 93 93 animation: wpstream-spinner-spin 1.1s linear infinite; 94 z-index: 1 000;94 z-index: 1; 95 95 } 96 96 … … 168 168 position:relative; 169 169 height: 30px; 170 position: relative;171 170 background: transparent; 172 171 margin-bottom: 15px; -
wpstream/trunk/public/js/broadcaster.js
r3364177 r3408984 51 51 vga: { 52 52 width: { ideal: 640 }, 53 height: { ideal: 480 },53 height: { ideal: 360 }, 54 54 }, 55 55 hd: { 56 width: { ideal: 1280 },57 height: { ideal: 720 },56 width: { exact: 1280 }, 57 height: { exact: 720 }, 58 58 }, 59 59 fhd: { 60 width: { ideal: 1920 },61 height: { ideal: 1080 },60 width: { exact: 1920 }, 61 height: { exact: 1080 }, 62 62 }, 63 63 square: { 64 width: { ideal: 800 },65 height: { ideal: 600 },64 width: { exact: 800 }, 65 height: { exact: 600 }, 66 66 }, 67 67 default: { 68 width: { ideal: 1280 },69 height: { ideal: 720 },68 width: { min: 640, ideal: 1280, max: 1920 }, 69 height: { min: 360, ideal: 720, max: 1080 }, 70 70 }, 71 71 }; 72 72 73 73 const displayResolutions = { 74 vga: { width: 640, height: 480 },74 vga: { width: 640, height: 360 }, 75 75 hd: { width: 1280, height: 720 }, 76 76 fhd: { width: 1920, height: 1080 }, … … 89 89 console.log( 90 90 "Resolution: " + 91 videoElement.videoWidth +92 "x" +93 videoElement.videoHeight91 videoElement.videoWidth + 92 "x" + 93 videoElement.videoHeight 94 94 ); 95 95 … … 201 201 messageElement.textContent = message; 202 202 203 const dismissButton = document.createElement("button"); 204 dismissButton.className = 'dismiss-message'; 205 dismissButton.innerHTML = '×'; 206 dismissButton.addEventListener('click', function() { 207 messageElement.remove(); 208 }); 209 210 messageElement.appendChild(dismissButton); 211 203 212 messageContainer.innerHTML = ""; 204 213 messageContainer.appendChild(messageElement); … … 217 226 "connected", 218 227 "disconnected", 219 "connecting" 228 "connecting", 229 "reconnecting" 220 230 ); 221 231 … … 231 241 statusText.textContent = "Connecting..."; 232 242 liveIndicatorError.style.display = 'inline'; 233 liveIndicator Live.innerContent = 'Connecting';243 liveIndicatorError.innerText = 'Connecting...'; 234 244 break; 235 245 case "reconnecting": 236 246 statusIndicator.classList.add("connecting"); 237 statusText.textContent = "Reconnecting ...";247 statusText.textContent = "Reconnecting"; 238 248 liveIndicatorError.style.display = 'inline'; 239 liveIndicatorLive.innerContent = 'Reconnecting'; 249 liveIndicatorLive.style.display = 'none'; 250 liveIndicatorError.innerText = 'Connection lost. Reconnecting in 10 seconds...'; 240 251 break; 241 252 case "disconnected": … … 249 260 } 250 261 251 function createInput( shouldAutoStart = false ) {262 function createInput( shouldAutoStart = false, keepMessages = false ) { 252 263 if (streamingButton) { 253 264 streamingButton.disabled = true; … … 259 270 } 260 271 261 resetMessages(); 272 if ( !keepMessages ) { 273 resetMessages(); 274 } 275 276 if (localStream) { 277 localStream.getTracks().forEach((track) => track.stop()); 278 localStream = null; 279 } 262 280 263 281 input = OvenLiveKit.create({ 264 282 callbacks: { 265 283 error: function (error) { 266 let errorMessage = ""; 267 268 if (error.message) { 269 errorMessage = error.message; 270 } else if (error.name) { 271 errorMessage = error.name; 272 } else { 273 errorMessage = error.toString(); 284 let errorMessage = ''; 285 286 if (error.message) { 287 errorMessage = error.message; 288 } else if (error.name) { 289 errorMessage = error.name; 290 } else { 291 errorMessage = error.toString(); 292 } 293 294 if (error.name === "OverconstrainedError") { 295 showMessage( 296 "Your browser or camera does not support this frame size: " + videoResolutionSelect.value, 297 'error' 298 ); 299 videoResolutionSelect.value = 'default'; 300 createInput(shouldAutoStart, true); 301 return; 274 302 } 275 303 276 if (errorMessage === "OverconstrainedError") { 277 errorMessage = 278 "The input device does not support the specified resolution or frame rate."; 279 } 280 281 resetMessages(); 282 showMessage(errorMessage, "error"); 283 284 if ( shouldAutoStart) { 285 considerReconnect = false; 286 } 287 }, 288 connectionClosed: function (type, event) { 289 console.log("Connection closed:", type, event); 290 streamingStarted = false; 291 updateStatus("disconnected"); 292 293 if (streamingButton) { 294 streamingButton.classList.remove("hidden"); 295 streamingButton.disabled = false; 296 } 297 if (stopButton) { 298 stopButton.classList.add("hidden"); 299 } 304 resetMessages(); 305 showMessage(errorMessage, "error"); 306 307 if (shouldAutoStart) { 308 considerReconnect = false; 309 } 310 }, 311 connectionClosed: function (type, event) { 312 console.log("Connection closed:", type, event); 313 streamingStarted = false; 314 // updateStatus("disconnected"); 315 316 // if (streamingButton) { 317 // streamingButton.classList.remove("hidden"); 318 // streamingButton.disabled = false; 319 // } 320 // if (stopButton) { 321 // stopButton.classList.add("hidden"); 322 // } 300 323 301 324 if (considerReconnect && !pendingReconnect) { … … 307 330 } else { 308 331 console.log('connection closed, not reconnecting'); 309 updateInputState(false);332 // updateInputState(false); 310 333 } 311 334 }, … … 314 337 if ( state === 'connected' ) { 315 338 // showMessage("Broadcast started successfully"); 339 updateStatus('connected'); 316 340 } 317 341 318 if (state === "disconnected" && considerReconnect) { 319 streamingStarted = false; 320 updateStatus("disconnected"); 321 322 if (considerReconnect && !pendingReconnect) { 323 console.log('connection closed, attempting to reconnect from ice state change'); 324 // showMessage("Connection lost, attempting to reconnect...", "info"); 325 attemptReconnect(); 326 } else { 327 showMessage( 328 "Connection failed. Please check your network settings.", 329 "error" 330 ); 331 } 332 } 342 if (state === "disconnected" && considerReconnect) { 343 streamingStarted = false; 344 if (considerReconnect && !pendingReconnect) { 345 console.log( 346 "connection closed, attempting to reconnect from ice state change" 347 ); 348 updateStatus("reconnecting"); 349 attemptReconnect(); 350 } else { 351 showMessage( 352 "Connection failed. Please check your network settings.", 353 "error" 354 ); 355 } 356 } 357 }, 333 358 }, 334 }, 335 }); 336 337 input.attachMedia(videoElement); 338 339 if (videoSourceSelect.value) { 359 }); 360 361 input.attachMedia(videoElement); 362 363 if (videoSourceSelect.options.length > 0) { 340 364 if (videoSourceSelect.value === "displayCapture") { 341 365 input … … 445 469 function attemptReconnect() { 446 470 console.log("attemptReconnect()"); 471 updateStatus('reconnecting'); 447 472 448 473 if ( pendingReconnect ) { … … 451 476 } 452 477 453 considerReconnect = false; 454 pendingReconnect = true; 455 456 if ( input ) { 457 input.callbacks = { 458 error: function() {}, 459 connectionClosed: function () {}, 460 iceStateChange: function () {}, 461 }; 462 463 if( input.streamingMode === 'whip') { 464 input.stopStreaming(); 465 } else if ( input.streamingMode === 'webrtc' ) { 466 if( input.webSocket ) { 478 // Clean up existing connection before reconnecting 479 if (input) { 480 if (input.peerConnection || input.webSocket) { 481 // Force cleanup without triggering callbacks 482 if (input.peerConnection) { 483 input.peerConnection.close(); 484 input.peerConnection = null; 485 } 486 if (input.webSocket) { 467 487 input.webSocket.close(); 468 488 input.webSocket = null; 469 489 } 470 if( input.peerConnection ) {471 input.peerConnection.close();472 input.peerConnection = null;473 }474 } 475 }490 // Reset streaming mode 491 input.streamingMode = null; 492 } 493 } 494 495 pendingReconnect = true; 476 496 477 497 // Show a reconnecting state and allow user to cancel via Stop button 478 updateStatus("reconnecting"); 479 updateInputState(true); 480 498 // showMessage("Disconnected. Reconnecting in 5 seconds...", "info"); 499 // updateInputState(false); 500 501 pendingReconnect = true; 481 502 pendingReconnectTimeout = setTimeout(function () { 482 if (!considerReconnect && !pendingReconnect) { 483 return; // User cancelled or stopped 484 } 485 486 checkChannelStatus(wpstream_broadcaster_vars.channel_id) 487 .then(function(channelActive) { 488 if (channelActive) { 489 console.log("Channel is active, proceeding with reconnect..."); 490 // Reset flags before recreating 491 pendingReconnect = false; 492 pendingReconnectTimeout = null; 493 considerReconnect = true; 494 495 // Create new input and start streaming 496 createInput(true); 497 } else { 498 console.log("Channel is not active, cannot reconnect."); 499 pendingReconnect = false; 500 pendingReconnectTimeout = null; 501 showMessage('Channel is no longer active. Broadcasting stopped', 'error'); 502 resetStreamingUI(); 503 } 504 }) 505 .catch(function (error) { 506 console.error('Error during reconnect attempt:', error); 507 pendingReconnect = false; 508 pendingReconnectTimeout = null; 509 // Don't attempt another reconnect immediately to avoid loops 510 setTimeout(() => { 503 pendingReconnect = false; 504 pendingReconnectTimeout = null; 505 if (considerReconnect) { 506 checkChannelStatus(wpstream_broadcaster_vars.channel_id) 507 .then(function(channelActive) { 508 if (channelActive && considerReconnect) { 509 console.log("Channel is active, proceeding with reconnect..."); 510 updateStatus("connecting"); 511 // input.stopStreaming(); 512 setTimeout(function () { 513 createInput(true); 514 }, 5000); 515 } else { 516 console.log("Channel is not active, cannot reconnect."); 517 considerReconnect = false; 518 showMessage('Channel is no longer active. Broadcasting stopped'); 519 resetStreamingUI(); 520 } 521 }) 522 .catch(function (error) { 523 console.error('Error checking channel status'); 511 524 if (considerReconnect) { 525 console.error('Error during reconnect attempt:', error); 512 526 attemptReconnect(); 513 527 } 514 }, 5000); 515 }); 528 }); 529 530 // console.log('Reconnecting...'); 531 // createInput( true ); 532 // startStreaming(); 533 } 516 534 }, reconnectDelayMs); 517 535 } … … 539 557 }); 540 558 541 showMessage(enabled ? "Video enabled" : "Video disabled", "info");559 // showMessage(enabled ? "Video enabled" : "Video disabled", "info"); 542 560 } 543 561 } … … 714 732 const parsedResponse = JSON.parse(response); 715 733 if (parsedResponse.status === 'active') { 734 messageContainer.innerHTML = ""; 716 735 resolve(true); 717 736 } else { … … 727 746 error: function(xhr, status, error) { 728 747 console.error('Error checking channel status:', error); 748 resetStreamingUI(); 729 749 showMessage('Error checking channel status: ' + error, 'error'); 730 750 reject(false); … … 751 771 const parsedResponse = JSON.parse(response); 752 772 if (parsedResponse.available_data_mb > 0) { 773 messageContainer.innerHTML = ''; 753 774 resolve(true); 754 775 } else { … … 801 822 input.startStreaming(whipUrl, connectionConfig); 802 823 if ( input ) { 824 // TODO: check why input is sometimes null here 803 825 console.log('something was wrong' ); 804 826 } 805 updateStatus("connected");827 // updateStatus("connected"); 806 828 if ( isReconnect ) { 807 829 console.log('Reconnected successfully!'); -
wpstream/trunk/public/js/start_streaming.js
r3402264 r3408984 759 759 var channelId = jQuery(this).closest('.event_list_unit').data('show-id'); 760 760 var whipUrl = ''; 761 var pendingPopup = window.open('', '_blank', 'location=yes,scrollbars=yes,status=yes'); 761 762 762 763 jQuery.ajax({ … … 776 777 // Open the new broadcaster in a new window 777 778 var broadcasterUrl = wpstream_start_streaming_vars.broadcaster_url + channelId; 778 window.open(broadcasterUrl, 'wpstream_broadcaster_' + channelId, 'fullscreen=yes'); 779 // window.open(broadcasterUrl, 'wpstream_broadcaster_' + channelId, 'fullscreen=yes'); 780 if (pendingPopup) { 781 pendingPopup.location.href = broadcasterUrl; 782 } else { 783 if (pendingPopup) { 784 pendingPopup.close(); 785 } 786 } 779 787 } 780 788 } else { -
wpstream/trunk/public/js/wpstream-player.js
r3404022 r3408984 1475 1475 1476 1476 function removeSpinner( place ) { 1477 return; //disabled for now1478 const spinnerId = 'wpstream-pre-load-spinner';1479 const spinner = document.getElementById(spinnerId);1480 spinner.style.display = 'none';1481 } 1477 const playerSpinner = document.querySelectorAll('.wpstream-pre-load-spinner'); 1478 playerSpinner.forEach(spinner => { 1479 spinner.style.display = 'none'; 1480 }) 1481 } -
wpstream/trunk/readme.txt
r3404022 r3408984 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.1 7 Stable tag: 4.9. 37 Stable tag: 4.9.4 8 8 License: GPL 9 9 License URI: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html … … 136 136 == Changelog == 137 137 138 = 4.9.4 = 139 * Fix - Broadcaster reconnecting when losing connection 140 * Fix - Automatically select the right camera resolution when trying to use a non-supported resolution 141 * Fix - Broadcaster button on mobile devices 142 138 143 = 4.9.3 = 139 144 * Fix - Video not showing correctly when Hello WpStream theme is active -
wpstream/trunk/templates/broadcaster-template.php
r3362236 r3408984 105 105 <span id="videoLiveIndicatorError" class="badge badge-pill badge-warning" style="display:none;"><?php esc_html_e('Connecting...', 'wpstream'); ?></span> 106 106 </div> 107 <video id="localVideo" autoplay muted playsinline></video> 107 <div class="video-wrapper"> 108 <div id="wpstream-pre-load-spinner" class="wpstream-pre-load-spinner"></div> 109 <video id="localVideo" autoplay muted playsinline></video> 110 </div> 108 111 </div> 109 112 … … 158 161 <option value="hd"><?php esc_html_e('1280x720', 'wpstream'); ?></option> 159 162 <option value="square"><?php esc_html_e('800x600', 'wpstream'); ?></option> 160 <option value="vga"><?php esc_html_e('640x 480', 'wpstream'); ?></option>163 <option value="vga"><?php esc_html_e('640x360', 'wpstream'); ?></option> 161 164 </select> 162 165 </div> -
wpstream/trunk/wpstream.php
r3404022 r3408984 4 4 * Plugin URI: http://wpstream.net 5 5 * Description: WpStream is a platform that allows you to live stream, create Video-on-Demand, and offer Pay-Per-View videos. We provide an affordable and user-friendly way for businesses, non-profits, and public institutions to broadcast their content and monetize their work. 6 * Version: 4.9. 36 * Version: 4.9.4 7 7 * Author: wpstream 8 8 * Author URI: http://wpstream.net … … 15 15 die; 16 16 } 17 define('WPSTREAM_PLUGIN_VERSION', '4.9. 3');17 define('WPSTREAM_PLUGIN_VERSION', '4.9.4'); 18 18 define('WPSTREAM_CLUBLINK', 'wpstream.net'); 19 19 define('WPSTREAM_CLUBLINKSSL', 'https');
Note: See TracChangeset
for help on using the changeset viewer.