canopy/www/js/channel/mediaHandler.js

216 lines
5.1 KiB
JavaScript

/*Canopy - The next generation of stoner streaming software
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
class mediaHandler{
constructor(client, player, media){
//Get parents
this.client = client;
this.player = player;
this.lastTimestamp = 0;
//Ingest media object from server
this.startMedia(media);
}
startMedia(media){
//If we properly ingested the media
if(this.ingestMedia(media)){
//Build the video player
this.buildPlayer();
//Call the start function
this.start();
}
}
buildPlayer(){
//Create player
this.video = document.createElement('video');
//Append it to page
this.player.videoContainer.appendChild(this.video);
//Reset player lock
this.lock = false;
}
destroyPlayer(){
//Remove player from page
this.video.remove();
//Null out video property
this.video = null;
}
ingestMedia(media){
//Set now playing
this.nowPlaying = media;
//return true to signify success
return true;
}
start(){
}
sync(timestamp = this.lastTimestamp){
}
reload(){
//Get current timestamp
const timestamp = this.video.currentTime;
//Load video from source
this.video.load();
//Set it back to the proper time
this.video.currentTime = timestamp;
//Play the video
this.video.play();
}
end(){
this.nowPlaying = null;
this.destroyPlayer();
}
play(){
}
pause(){
}
setPlayerLock(lock){
//toggle controls
this.video.controls = !lock;
//Only toggle mute if we're locking, or if we're unlocking after being locked
//If this is ran twice without locking we don't want to surprise unmute on the user
if(lock || this.lock){
//toggle mute
this.video.muted = lock;
}
//toggle looping
this.video.loop = lock;
//set lock property
this.lock = lock;
}
getRatio(){
return this.video.videoWidth / this.video.videoHeight;
}
getTimestamp(){
}
setVideoTitle(title){
this.player.title.textContent = `Currently Playing: ${title}`;
}
}
class nullHandler extends mediaHandler{
constructor(client, player){
//Call derived constructor
super(client, player, {});
}
start(){
//Lock the player
this.setPlayerLock(true);
//Set the static placeholder
this.video.src = '/video/static.webm';
//Set video title manually
this.player.title.textContent = 'Channel Off Air';
//play the placeholder video
this.video.play();
}
}
class rawFileHandler extends mediaHandler{
constructor(client, player, media){
//Call derived constructor
super(client, player, media);
//Since this media type has no way to tell between the user and code seek events, we need a flag to mark them
this.selfSeek = false;
//Define listeners
this.defineListeners();
}
defineListeners(){
this.video.addEventListener('pause', this.onPause.bind(this));
this.video.addEventListener('seeking', this.onSeek.bind(this));
}
start(){
//Set video
this.video.src = this.nowPlaying.id;
//Set video title
this.setVideoTitle(this.nowPlaying.title);
//Unlock player
this.setPlayerLock(false);
//play video
this.video.play();
}
play(){
this.video.play();
}
pause(){
this.video.pause();
}
sync(timestamp = this.lastTimestamp){
//Set self seek flag
this.selfSeek = true;
//Set current video time based on timestamp received from server
this.video.currentTime = timestamp;
}
reload(){
//Throw self seek flag to make sure we don't un-sync the player
this.selfSeek = true;
//Call derived reload function
super.reload();
}
onPause(event){
this.player.unlockSync();
}
onSeek(event){
//If the video was seeked out-side of code
if(!this.selfSeek){
this.player.unlockSync();
}
//reset self seek flag
this.selfSeek = false;
}
getTimestamp(){
//Return current timestamp
return this.video.currentTime;
}
}