1function loadVideo(videoEl, src) { 2 const isHls = getQueryStringValue('isHls'); 3 4 if (isHls) { 5 if (src.endsWith('.m3u8')) { 6 const config = { 7 maxBufferLength: 30, 8 debug: true, 9 autoStartLoad: true 10 }; 11 let hls = new Hls(config); 12 hls.attachMedia(videoEl); 13 14 hls.on(Hls.Events.MEDIA_ATTACHED, function () { 15 hls.loadSource(src); 16 }); 17 } else if (src.endsWith('.mpd')) { 18 let dashPlayer = dashjs.MediaPlayer().create(); 19 dashPlayer.initialize(videoEl, src, false); 20 // dashPlayer.on('playbackPlaying', function () { 21 // console.log("videoEl.currentTime playing: ", videoEl.currentTime); 22 // }); 23 } 24 } else { 25 videoEl.setAttribute('src', src); 26 } 27} 28 29export async function loadPlayer() { 30 const firebaseDb = firebase.database(); 31 const previewVideoLink = getQueryStringValue('previewVideoLink'); 32 const roomId = getQueryStringValue('roomId'); 33 let isSelfHost = /selfhost/.test(roomId); 34 let invitedSelfHost = isSelfHost && getQueryStringValue('notAuth') === 'true'; 35 let isWorld = getQueryStringValue('type') === 'world'; 36 let isKaraoke = getQueryStringValue('isKaraoke') === 'true'; 37 let staticVideoLink = previewVideoLink ? previewVideoLink : getQueryStringValue('staticVideoLink'); 38 let isPreview = !!previewVideoLink; 39 const isSimpleMenu = getQueryStringValue('isSimpleMenu') === 'true'; 40 let videoPosListener, hostVideoPos = {}, isPlaying = false; 41 const oculusRightControl = document.querySelector('#oculus-right'); 42 43 window.Sentry?.setTag("isVideoMode", !!staticVideoLink); 44 45 if (previewVideoLink) { 46 try { 47 console.log("=== has preview video, so checking which video is playing ===") 48 const snapshot = await firebaseDb.ref(`opentok/rooms/${roomId}/videoPos`).get(); 49 50 if (snapshot.exists()) { 51 const val = snapshot.val(); 52 if (val && isPreview !== val.isPreview) { 53 isPreview = val.isPreview; 54 staticVideoLink = getQueryStringValue(isPreview ? 'previewVideoLink' : 'staticVideoLink'); 55 console.log("isPreview: ", isPreview); 56 console.log("videoLink: ", staticVideoLink); 57 console.log("=== check completed ==="); 58 } 59 } 60 } catch (err) { 61 console.error(err); 62 } 63 } 64 65 // Encode S3 URL to avoid special char in filename 66 let staticVideoLinkBaseHost = staticVideoLink.substring(0, staticVideoLink.lastIndexOf("/") + 1); 67 let staticVideoLinkFilename = staticVideoLink.substring(staticVideoLink.lastIndexOf("/") + 1, staticVideoLink.length); 68 staticVideoLink = staticVideoLinkBaseHost + encodeURIComponent(staticVideoLinkFilename); 69 console.log("Encoded staticVideoLink: ", staticVideoLink); 70 71 if (staticVideoLink) { 72 let subtitlePc = document.getElementById('subtitle-pc'); 73 let subtitleTxtAframe = document.getElementById('subtitle-message-content'); 74 let subtitleTxtAframeBoard = document.getElementById('subtitle-message-board'); 75 let subtitleTxtAframeWrapper = document.getElementById('subtitle-message-board-wrapper'); 76 77 console.log("is2dVideo: ", is2dVideo); 78 const videoEl = createVideoPlayer(staticVideoLink, is2dVideo); 79 const videoControlButtonEl = document.getElementById('videoControlButton'); 80 81 if (isKaraoke){ 82 videoEl.volume = 0.2; 83 } 84 85 const soundBtn = document.getElementById('soundBtn'); 86 const soundBtnAframe = document.getElementById('soundButton'); 87 88 // let soundMuted = true; 89 let soundMuted = false; 90 if(!isChatbotDisabled && !isMsAIWorld) { 91 soundMuted = switchSoundMode(videoEl, 'html5', soundMuted, soundBtn, soundBtnAframe); 92 } else if (!isSimpleMenu && (!isKaraoke || !hasVrMusicQuery)) { 93 soundBtn.style.display = 'block'; 94 soundBtn.addEventListener('click', function () { 95 soundMuted = switchSoundMode(videoEl, 'html5', soundMuted, soundBtn, soundBtnAframe); 96 }, false); 97 } else { 98 soundBtn.style.display = 'none'; 99 soundMuted = switchSoundMode(videoEl, 'html5', soundMuted, soundBtn, soundBtnAframe); 100 soundBtnAframe.setAttribute('material', {visible: false}); 101 } 102 103 let pausePressed = false;
104 105 oculusRightControl.addEventListener('triggerdown', evt => { 106 if (oculusIntersected === 'sound-control' && !isKaraoke) { 107 soundMuted = switchSoundMode(videoEl, 'html5', soundMuted, soundBtn, soundBtnAframe); 108 } 109 110 if (oculusIntersected === 'play-video-control') { 111 if (videoControlButtonEl.getAttribute('src') === "#playButtonImg") { 112 videoEl.play(); 113 } else { 114 pausePressed = true; 115 videoEl.pause(); 116 } 117 } 118 }); 119 120 // Left controller not in use 121 /*const oculusLeftControl = document.querySelector('#oculus-left'); 122 123 oculusLeftControl.removeEventListener('triggerdown', function () { 124 console.log("remove event from oculus left control"); 125 }); 126 127 oculusLeftControl.addEventListener('triggerdown', evt => { 128 if (oculusIntersected === 'sound-control') { 129 soundMuted = switchSoundMode(videoEl, 'html5', soundMuted, soundBtn, soundBtnAframe); 130 } 131 if (oculusIntersected === 'play-video-control') { 132 if (videoControlButtonEl.getAttribute('src') === "#playButtonImg") { 133 videoEl.play(); 134 } else { 135 videoEl.pause(); 136 } 137 } 138 });*/ 139 console.log("isHost: ", isHost); 140 const videoSlider = document.getElementById('videoSlider'); 141 const videoSliderValue = document.getElementById('video-slider-value'); 142 const bufferedAmount = document.getElementById('buffered-amount'); 143 const progressAmount = document.getElementById('progress-amount'); 144 const videoBufferedEl = document.getElementById('buffered-el'); 145 const videoProgressEl = document.getElementById('progress-el'); 146 const playControlBtn = document.getElementById('playBtn'); 147 148 let playPromise = null; 149 let isSeeked = false; 150 151 if (sampleVideo && !isFullSampleVideo) { 152 videoEl.addEventListener("timeupdate", function(){ 153 if (videoEl.currentTime >= 90) { 154 pausePressed = true; 155 videoEl.pause(); 156 isPlaying = false; 157 } 158 159 if (videoEl.currentTime >= 91) { 160 setTimeout(() => { 161 videoEl.currentTime = 0; 162 }, 250); // to avoid flickering 163 } 164 }); 165 } 166 167 if (isHost || (sampleVideo && !isFullSampleVideo)) { 168 videoEl.addEventListener('progress', function() { 169 if (videoEl.buffered.length > 0) { 170 const bufferedEnd = videoEl.buffered.end(videoEl.buffered.length - 1); 171 const duration = videoEl.duration; 172 if (duration > 0 && bufferedAmount) { 173 bufferedAmount.style.width = ((bufferedEnd / duration)*100) + "%"; 174 } 175 } 176 }); 177 178 if (videoControlButtonEl) { 179 if(isChatbotDisabled || isMsAIWorld) 180 videoControlButtonEl.setAttribute('visible', true); 181 videoControlButtonEl.setAttribute('src', '#playButtonImg'); 182 } 183 if (videoSlider) { 184 videoSlider.style.display = 'block'; 185 videoSlider.oninput = function() { 186 let currentPosition = (this.value / 1000) * videoEl.duration; 187 videoSliderValue.innerHTML = new Date(currentPosition * 1000).toISOString().substr(11, 8); 188 videoEl.currentTime = currentPosition; 189 isSeeked = true; 190 } 191 } 192 if (videoSliderValue) { 193 videoSliderValue.style.display = 'block'; 194 } 195 if (videoBufferedEl) { 196 videoBufferedEl.style.display = 'block'; 197 } 198 if (videoProgressEl) { 199 videoProgressEl.style.display = 'block'; 200 } 201 if (playControlBtn) { 202 playControlBtn.style.display = 'block'; 203 204 playControlBtn.addEventListener("click", function() { 205 console.log("Clicked play/pause button, current isPlaying: ", isPlaying); 206 if (isPlaying == false) { 207 requestDeviceOrientationListener(); 208 playPromise = videoEl.play(); 209 if (!!playPromise) { 210 playPromise.then(_ => { 211 isPlaying = true 212 // playControlBtn.setAttribute('src', '../../img/pause.png'); 213 }).catch(error => { 214 console.log("Unable to set isPlaying value with error: ", error); 215 }); 216 } 217 } else { 218 if (!!playPromise) {
219 playPromise.then(_ => { 220 pausePressed = true; 221 videoEl.pause(); 222 isPlaying = false; 223 // playControlBtn.setAttribute('src', '../../img/play-black.png'); 224 }).catch(error => { 225 console.log("Unable to pause with error: ", error); 226 }); 227 } 228 } 229 }); 230 } 231 232 videoEl.onseeked = async function(event) { 233 console.log('Video seeked to: ', videoEl.currentTime); 234 if (isSeeked && meId) { 235 hostVideoPos["host"] = meId; 236 hostVideoPos["isPlaying"] = !videoEl.paused; 237 hostVideoPos["currentTime"] = videoEl.currentTime; 238 hostVideoPos["isPreview"] = isPreview; 239 hostVideoPos["last_synced_at"] = new Date(); 240 241 console.log("=== syncing video position (seeked) ==="); 242 console.log("sync data: ", hostVideoPos); 243 await firebaseDb.ref(`opentok/rooms/${roomId}/videoPos`).update(hostVideoPos); 244 isSeeked = false; 245 console.log("=== video sync completed ==="); 246 } 247 }; 248 videoEl.onplay = async function () { 249 console.log("on play: ", videoEl.currentTime); 250 251 if (sampleVideo && !isFullSampleVideo && videoEl.currentTime >= 90) { 252 videoEl.currentTime = 0; 253 } 254 255 if (meId) { 256 hostVideoPos["host"] = meId; 257 hostVideoPos["isPlaying"] = true; 258 hostVideoPos["currentTime"] = videoEl.currentTime; 259 hostVideoPos["isPreview"] = isPreview; 260 hostVideoPos["last_synced_at"] = new Date(); 261 262 console.log("=== syncing video position (played) ==="); 263 console.log("sync data: ", hostVideoPos); 264 await firebaseDb.ref(`opentok/rooms/${roomId}/videoPos`).update(hostVideoPos); 265 } 266 if (videoControlButtonEl) { 267 videoControlButtonEl.setAttribute('src', '#pauseButtonImg'); 268 } 269 if (playControlBtn) { 270 playControlBtn.setAttribute('src', '../../img/pause.png'); 271 } 272 console.log("=== video sync completed ==="); 273 } 274 videoEl.onpause = async function () { 275 if (pausePressed && meId) { 276 console.log("on pause: ", videoEl.currentTime); 277 hostVideoPos["host"] = meId; 278 hostVideoPos["isPlaying"] = false; 279 hostVideoPos["currentTime"] = videoEl.currentTime; 280 hostVideoPos["isPreview"] = isPreview; 281 hostVideoPos["last_synced_at"] = new Date(); 282 283 console.log("=== syncing video position (paused) ==="); 284 console.log("sync data: ", hostVideoPos); 285 await firebaseDb.ref(`opentok/rooms/${roomId}/videoPos`).update(hostVideoPos); 286 pausePressed = false; 287 console.log("=== video sync completed ==="); 288 } 289 290 // isPlaying = false; 291 if (videoControlButtonEl) { 292 videoControlButtonEl.setAttribute('src', '#playButtonImg'); 293 } 294 if (playControlBtn) { 295 playControlBtn.setAttribute('src', '../../img/play-black.png'); 296 } 297 } 298 if (!is2dVideo) document.getElementById("html-control-panel").prepend(videoEl); 299 } else { 300 // If is guest user 301 if (!is2dVideo) document.getElementById("html-control-panel").appendChild(videoEl); 302 if (videoControlButtonEl) { 303 videoControlButtonEl.remove(); 304 } 305 } 306 307 videoEl.onended = async function() { 308 isPlaying = false; 309 310 if (isPreview) { 311 const nextVideoLink = getQueryStringValue('staticVideoLink'); 312 313 if (nextVideoLink) { 314 isPreview = false; 315 staticVideoLink = nextVideoLink; 316 loadVideo(videoEl, staticVideoLink); 317 videoEl.play(); 318 isPlaying = true; 319 } 320 } else { 321 if (isHost) { 322 if (meId) { 323 hostVideoPos["host"] = meId; 324 hostVideoPos["isPlaying"] = false; 325 hostVideoPos["currentTime"] = videoEl.currentTime; 326 hostVideoPos["last_synced_at"] = new Date(); 327 328 console.log("=== syncing video position (ended) ==="); 329 console.log("sync data: ", hostVideoPos); 330 await firebaseDb.ref(`opentok/rooms/${roomId}/videoPos`).update(hostVideoPos); 331 console.log("=== video sync completed ===") 332 } 333 334 if ((isSelfHost || isWorld) && !window.hasEvaluation) {
335 window.openModal('#evaluation-modal'); 336 } 337 } else if (!isKaraoke && !isTherapy && !invitedSelfHost && !window.hasEvaluation) { 338 window.openModal('#evaluation-modal'); 339 } 340 } 341 } 342 343 loadVideo(videoEl, staticVideoLink); 344 345 // const videoSphereEl = document.querySelector("a-videosphere"); 346 // videoSphereEl.setAttribute('src', '#staticVideo'); 347 348 videoEl.onloadedmetadata = async function() { 349 if (!videoPosListener) { 350 videoPosListener = function(snapshot) { 351 const val = snapshot.val(); 352 if (!val || val.host === meId) return; 353 354 console.log("[Sync Video Position] data: ", val); 355 356 if (isPreview !== val.isPreview) { 357 isPreview = val.isPreview; 358 staticVideoLink = getQueryStringValue(isPreview ? 'previewVideoLink' : 'staticVideoLink'); 359 loadVideo(videoEl, staticVideoLink); 360 if (val.isPlaying) { 361 videoEl.play(); 362 } 363 console.log("[Sync Video Position] video switched"); 364 return; 365 } 366 367 let hostCurrentTime = val.currentTime || 0; 368 if (val.isPlaying) { 369 const diff = (new Date() - new Date(val.last_synced_at)) / 1000 + hostCurrentTime; 370 videoEl.currentTime = diff % videoEl.duration; 371 console.debug(`[Sync Video Position] Set video postion = ${videoEl.currentTime}`); 372 playPromise = videoEl.play(); 373 isPlaying = true; 374 console.debug('[Sync Video Position] Video position was synced'); 375 } else { 376 videoEl.currentTime = hostCurrentTime; 377 if (playPromise !== undefined && playPromise !== null) { 378 playPromise.then(_ => { 379 videoEl.pause(); 380 isPlaying = false; 381 }) 382 .catch(error => { 383 console.error("Unable to pause with error: ", error); 384 }); 385 } 386 } 387 }; 388 389 firebaseDb.ref(`opentok/rooms/${roomId}/videoPos`).on('value', videoPosListener); 390 } 391 } 392 videoEl.ontimeupdate = function () { 393 if ((srtSubtitleEnabled && srtSubtitleModeValue && srtSubtitleModeValue === 'on')) { 394 let subtitle = getSubtitleByTime(subtitles, videoEl.currentTime*1000); 395 console.log("subtitle: ", subtitle); 396 397 let userColor = '#FFFFFF'; 398 399 if (subtitleTxtAframe.childElementCount > 0) { 400 subtitleTxtAframe.removeChild(subtitleTxtAframe.childNodes[0]); 401 } else { 402 subtitleTxtAframeWrapper.object3D.visible = false; 403 subtitlePc.innerHTML = ""; 404 subtitleTxtAframe.innerHTML = ""; 405 } 406 if (subtitlePc.childElementCount > 0) { 407 subtitlePc.removeChild(subtitlePc.childNodes[0]); 408 } else { 409 subtitlePc.style.display = 'none'; 410 } 411 412 // Only show subtitle elements when there is subtitle text 413 if (subtitle.length > 0) { 414 subtitlePc.insertAdjacentHTML('beforeend', '<div style="color:white;"><span style="font-weight:bolder;font-style:italic;color: ' + userColor + ';"> </span>' + subtitle + '</div>'); 415 subtitleTxtAframe.insertAdjacentHTML('beforeend', '<div style="color:white;"><span style="font-weight:bolder;font-style:italic;color: ' + userColor + ';"> </span>' + subtitle + '</div>'); 416 417 if (subtitleTxtAframe.childElementCount > 0 && window.isEnterVR) { 418 subtitleTxtAframeWrapper.object3D.visible = true; 419 } 420 421 if (subtitlePc.childElementCount > 0 && !window.isEnterVR) { 422 subtitlePc.style.display = 'block'; 423 } 424 } else { 425 subtitlePc.style.display = 'none'; 426 subtitleTxtAframeWrapper.object3D.visible = false; 427 } 428 } 429 430 const time = new Date(videoEl.currentTime * 1000).toISOString().substr(11, 8) 431 const elapsedTimer = document.getElementById('elapsed-timer'); 432 elapsedTimer.innerHTML = time; 433 434 videoSliderValue.innerHTML = time; 435 if (videoSlider) { 436 videoSlider.value = (videoEl.currentTime/videoEl.duration)*1000; 437 } 438 439 const aframeElapsedTimer = document.getElementById('aframe-elapsed-timer'); 440 aframeElapsedTimer.setAttribute('value', time); 441 442 // console.log("duration: ", videoEl.duration); 443 var duration = videoEl.duration; 444 if (duration > 0 && progressAmount) { 445 progressAmount.style.width = ((videoEl.currentTime / duration)*100) + "%"; 446 } 447 } 448 } 449}; 450 451function createVideoPlayer(src, is2d) { 452 let videoEl = document.createElement('video'); 453 videoEl.setAttribute('id', 'staticVideo'); 454 videoEl.setAttribute('preload', 'auto'); 455 videoEl.setAttribute('src', src); 456 videoEl.setAttribute('crossorigin', 'anonymous'); 457 videoEl.setAttribute('playsinline', ''); 458 // videoEl.setAttribute('muted', ''); 459 // videoEl.muted = true; 460 461 if (is2d) { 462 videoEl.addEventListener('loadeddata', (evt) => { 463 let player2dEl = document.createElement('a-video'); 464 player2dEl.setAttribute('id', 'youtube-player'); 465 player2dEl.setAttribute('position', {x:0, y:5, z:-20}); 466 player2dEl.setAttribute('width', 40); 467 player2dEl.setAttribute('height', 23); 468 player2dEl.setAttribute('src', '#staticVideo'); 469 document.querySelector('a-scene').appendChild(player2dEl); 470 player2dEl.addEventListener('loaded', () => { 471 evt.target.play(); 472 }); 473 }); 474 475 document.querySelector('a-assets').appendChild(videoEl); 476 } else {
477 const videoSphereEl = document.querySelector("a-videosphere"); 478 videoSphereEl.setAttribute('src', '#staticVideo'); 479 } 480 481 return videoEl; 482} 483 484function requestDeviceOrientationListener() { 485 // request for access to device orientation sensor 486 if (typeof DeviceOrientationEvent.requestPermission === 'function') { 487 DeviceOrientationEvent.requestPermission().then((state) => { 488 if (state !== 'granted') { 489 return; 490 } 491 const el = document.querySelector('#aframe-view a-scene'); 492 if (el) { 493 el.emit('deviceorientationpermissiongranted'); 494 } 495 }).catch(console.error); 496 } 497}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.