From c0f219276f4c8f43e5879ca3d251ebdf8f98a27f Mon Sep 17 00:00:00 2001 From: rainbow napkin Date: Thu, 4 Sep 2025 20:11:23 -0400 Subject: [PATCH] JSDoc for www/js/channel/*.js complete. Just need to hadnle ww/js/channel/panels. --- www/doc/client/cPanel.html | 2611 +++++++++ www/doc/client/channel.html | 6 +- www/doc/client/channel.js.html | 6 +- www/doc/client/chat.js.html | 671 +++ www/doc/client/chatBox.html | 4659 +++++++++++++++++ www/doc/client/chatPostprocessor.html | 1803 +++++++ www/doc/client/chatPostprocessor.js.html | 680 +++ www/doc/client/commandPreprocessor.html | 8 +- www/doc/client/commandPreprocessor.js.html | 10 +- www/doc/client/commandProcessor.html | 6 +- www/doc/client/cpanel.js.html | 524 ++ www/doc/client/global.html | 4 +- www/doc/client/hlsBase.html | 2928 +++++++++++ www/doc/client/hlsLiveStreamHandler.html | 2905 ++++++++++ www/doc/client/index.html | 4 +- www/doc/client/mediaHandler.html | 2710 ++++++++++ www/doc/client/mediaHandler.js.html | 844 +++ www/doc/client/nullHandler.html | 2882 ++++++++++ www/doc/client/panelObj.html | 918 ++++ www/doc/client/player.html | 3383 ++++++++++++ www/doc/client/player.js.html | 483 ++ www/doc/client/poppedPanel.html | 1451 +++++ www/doc/client/rawFileBase.html | 2923 +++++++++++ www/doc/client/rawFileHandler.html | 2905 ++++++++++ www/doc/client/userList.html | 6 +- www/doc/client/userlist.js.html | 6 +- www/doc/client/youtubeEmbedHandler.html | 2900 ++++++++++ www/doc/server/activeChannel.html | 2 +- .../server/app_channel_activeChannel.js.html | 2 +- .../server/app_channel_channelManager.js.html | 2 +- www/doc/server/app_channel_chat.js.html | 2 +- www/doc/server/app_channel_chatBuffer.js.html | 2 +- .../server/app_channel_chatHandler.js.html | 2 +- .../app_channel_commandPreprocessor.js.html | 2 +- .../server/app_channel_connectedUser.js.html | 2 +- .../server/app_channel_media_media.js.html | 2 +- .../app_channel_media_playlistHandler.js.html | 2 +- .../server/app_channel_media_queue.js.html | 2 +- .../app_channel_media_queuedMedia.js.html | 2 +- www/doc/server/app_channel_tokebot.js.html | 2 +- www/doc/server/channelManager.html | 2 +- www/doc/server/chat.html | 2 +- www/doc/server/chatBuffer.html | 2 +- www/doc/server/chatHandler.html | 2 +- www/doc/server/commandPreprocessor.html | 2 +- www/doc/server/commandProcessor.html | 2 +- www/doc/server/connectedUser.html | 2 +- www/doc/server/global.html | 2 +- www/doc/server/index.html | 2 +- www/doc/server/media.html | 2 +- www/doc/server/playlistHandler.html | 2 +- www/doc/server/queue.html | 2 +- www/doc/server/queuedMedia.html | 2 +- .../schemas_channel_channelBanSchema.js.html | 2 +- ...as_channel_channelPermissionSchema.js.html | 2 +- .../schemas_channel_channelSchema.js.html | 2 +- .../server/schemas_channel_chatSchema.js.html | 2 +- .../schemas_channel_media_mediaSchema.js.html | 2 +- ..._channel_media_playlistMediaSchema.js.html | 2 +- ...hemas_channel_media_playlistSchema.js.html | 2 +- ...as_channel_media_queuedMediaSchema.js.html | 2 +- www/doc/server/schemas_emoteSchema.js.html | 2 +- www/doc/server/schemas_flairSchema.js.html | 2 +- .../server/schemas_permissionSchema.js.html | 2 +- www/doc/server/schemas_statSchema.js.html | 2 +- .../schemas_tokebot_tokeCommandSchema.js.html | 2 +- .../schemas_user_emailChangeSchema.js.html | 2 +- .../schemas_user_passwordResetSchema.js.html | 2 +- .../server/schemas_user_userBanSchema.js.html | 2 +- .../server/schemas_user_userSchema.js.html | 2 +- www/doc/server/tokebot.html | 2 +- www/doc/server/utils_altchaUtils.js.html | 2 +- www/doc/server/utils_configCheck.js.html | 2 +- www/doc/server/utils_hashUtils.js.html | 2 +- www/doc/server/utils_linkUtils.js.html | 2 +- www/doc/server/utils_loggerUtils.js.html | 2 +- www/doc/server/utils_mailUtils.js.html | 2 +- .../utils_media_internetArchiveUtils.js.html | 2 +- www/doc/server/utils_media_yanker.js.html | 2 +- www/doc/server/utils_media_ytdlpUtils.js.html | 2 +- www/doc/server/utils_regexUtils.js.html | 2 +- www/doc/server/utils_scheduler.js.html | 2 +- www/doc/server/utils_sessionUtils.js.html | 2 +- www/js/channel/channel.js | 2 +- www/js/channel/chat.js | 152 +- www/js/channel/chatPostprocessor.js | 67 +- www/js/channel/commandPreprocessor.js | 4 +- www/js/channel/cpanel.js | 4 +- www/js/channel/mediaHandler.js | 176 +- www/js/channel/player.js | 2 +- www/js/channel/userlist.js | 2 +- 91 files changed, 38653 insertions(+), 104 deletions(-) create mode 100644 www/doc/client/cPanel.html create mode 100644 www/doc/client/chat.js.html create mode 100644 www/doc/client/chatBox.html create mode 100644 www/doc/client/chatPostprocessor.html create mode 100644 www/doc/client/chatPostprocessor.js.html create mode 100644 www/doc/client/cpanel.js.html create mode 100644 www/doc/client/hlsBase.html create mode 100644 www/doc/client/hlsLiveStreamHandler.html create mode 100644 www/doc/client/mediaHandler.html create mode 100644 www/doc/client/mediaHandler.js.html create mode 100644 www/doc/client/nullHandler.html create mode 100644 www/doc/client/panelObj.html create mode 100644 www/doc/client/player.html create mode 100644 www/doc/client/player.js.html create mode 100644 www/doc/client/poppedPanel.html create mode 100644 www/doc/client/rawFileBase.html create mode 100644 www/doc/client/rawFileHandler.html create mode 100644 www/doc/client/youtubeEmbedHandler.html diff --git a/www/doc/client/cPanel.html b/www/doc/client/cPanel.html new file mode 100644 index 0000000..582e49c --- /dev/null +++ b/www/doc/client/cPanel.html @@ -0,0 +1,2611 @@ + + + + + JSDoc: Class: cPanel + + + + + + + + + + +
+ +

Class: cPanel

+ + + + + + +
+ +
+ +

cPanel(client)

+ +
Class containing code for managing the Canopy Panel UX
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new cPanel(client)

+ + + + + + +
+ Instantiates a new Canopy Panel Management object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent client Management Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

activePanel

+ + + + +
+ Active Panel Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

activePanelCloseIcon

+ + + + +
+ Active Panel Close Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

activePanelDiv

+ + + + +
+ Active Panel Container +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

activePanelDoc

+ + + + +
+ Active Title Document Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

activePanelDragger

+ + + + +
+ Click-Dragger object for re-sizable active panel +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

activePanelPinIcon

+ + + + +
+ Active Panel Pin Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

activePanelPopoutIcon

+ + + + +
+ Active Panel Pop-Out Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

activePanelTitle

+ + + + +
+ Active Panel Title +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

client

+ + + + +
+ Parent Client Management object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanel

+ + + + +
+ Pinned Panel Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelCloseIcon

+ + + + +
+ Pinned Panel Close Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelDiv

+ + + + +
+ Pinned Panel Contianer +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelDoc

+ + + + +
+ Pinned Panel Document Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelDragger

+ + + + +
+ Click-Dragger object for re-sizable pinned panel +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelPopoutIcon

+ + + + +
+ Pinned Panel Pop-Out Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelTitle

+ + + + +
+ Pinned Panel Title +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelUnpinIcon

+ + + + +
+ Pinned Panel Un-Pin Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

poppedPanels

+ + + + +
+ Popped Panel Objects +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

hideActivePanel(event, keepAlive)

+ + + + + + +
+ Hides active panel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
event + + +Event + + + + + + Event passed down from Input Handler
keepAlive + + +Boolean + + + + + + false + + Prevents closing panel if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

hidePinnedPanel(event, keepAlive)

+ + + + + + +
+ Hides pinned panel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
event + + +Event + + + + + + Passed down input event
keepAlive + + +Boolean + + + + + + false + + Prevents panel.closer() from running if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pinPanel()

+ + + + + + +
+ Pins active panel +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

popActivePanel()

+ + + + + + +
+ Pop's out active panel +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

popPanel(panel, panelBody)

+ + + + + + +
+ Pops a new pop-out panel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
panel + + +panelObj + + + + panelObj to apply to the panel
panelBody + + +String + + + + Raw HTML to inject into panel body, injects panel default if left to null
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

popPinnedPanel()

+ + + + + + +
+ Pops pinned panel +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setActivePanel(panel, panelBody)

+ + + + + + +
+ Sets Active Panel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
panel + + +panelObj + + + + Panel Object to set as active
panelBody + + +String + + + + innerHTML of Panel, pulls from panelObj.getPage() if empty
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setPinnedPanel(panel, panelBody)

+ + + + + + +
+ Sets pinned panel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
panel + + +panelObj + + + + Panel Object to apply to panel
panelBody + + +String + + + + Raw HTML to inject into panel body, defaults to panel page if null
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setupInput()

+ + + + + + +
+ Defines input-related event listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

unpinPanel()

+ + + + + + +
+ Sets pinned panel to active +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/channel.html b/www/doc/client/channel.html index ca741ff..d5f9a33 100644 --- a/www/doc/client/channel.html +++ b/www/doc/client/channel.html @@ -30,7 +30,7 @@

channel()

-
Class for object containing base code for the Canopy channel client.
+
Class containing base code for the Canopy channel client.
@@ -1248,13 +1248,13 @@
diff --git a/www/doc/client/channel.js.html b/www/doc/client/channel.js.html index 995b6e5..eb8ae9d 100644 --- a/www/doc/client/channel.js.html +++ b/www/doc/client/channel.js.html @@ -43,7 +43,7 @@ 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 for object containing base code for the Canopy channel client. + * Class containing base code for the Canopy channel client. */ class channel{ /** @@ -283,13 +283,13 @@ const client = new channel();
diff --git a/www/doc/client/chat.js.html b/www/doc/client/chat.js.html new file mode 100644 index 0000000..cf1f5f0 --- /dev/null +++ b/www/doc/client/chat.js.html @@ -0,0 +1,671 @@ + + + + + JSDoc: Source: chat.js + + + + + + + + + + +
+ +

Source: chat.js

+ + + + + + +
+
+
/*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 which represents Canopy Chat Box UI
+ */
+class chatBox{
+    /**
+     * Instantiates a new Chat Box object
+     * @param {channel} client - Parent client Management Object
+     */
+    constructor(client){
+        /**
+         * Parent Client Management Object
+         */
+        this.client = client
+
+        /**
+         * Whether or not chat-size should be locked to current media aspect ratio
+         */
+        this.aspectLock = true;
+
+        /**
+         * Whether or not the chat box should auto-scroll on new chat
+         */
+        this.autoScroll = true;
+
+        /**
+         * Chat Buffer Scroll Top on last scroll
+         */
+        this.lastPos = 0;
+
+        /**
+         * Height of Chat Buffer on last scroll
+         */
+        this.lastHeight = 0;
+
+        /**
+         * Width of Chat Buffer on last scroll
+         */
+        this.lastWidth = 0;
+
+        /**
+         * Click-Dragger Object for handling dynamic chat/video split re-sizing
+         */
+        this.clickDragger = new canopyUXUtils.clickDragger("#chat-panel-drag-handle", "#chat-panel-div");
+        
+        /**
+         * Command Pre-Processor Object
+         */
+        this.commandPreprocessor = new commandPreprocessor(client);
+
+        /**
+         * Chat Post-Processor Object
+         */
+        this.chatPostprocessor = new chatPostprocessor(client);
+
+        //Element Nodes
+        /**
+         * Chat Panel Container Div
+         */
+        this.chatPanel = document.querySelector("#chat-panel-div");
+
+        /**
+         * High Level Selector
+         */
+        this.highSelect = document.querySelector("#chat-panel-high-level-select");
+
+        /**
+         * Flair Selector
+         */
+        this.flairSelect = document.querySelector("#chat-panel-flair-select");
+
+        /**
+         * Chat Buffer Div
+         */
+        this.chatBuffer = document.querySelector("#chat-panel-buffer-div");
+
+        /**
+         * Chat Prompt
+         */
+        this.chatPrompt = document.querySelector("#chat-panel-prompt");
+
+        /**
+         * Auto-Complete Placeholder
+         */
+        this.autocompletePlaceholder = document.querySelector("#chat-panel-prompt-autocomplete-filler");
+
+        /**
+         * Auto-Complete Display
+         */
+        this.autocompleteDisplay = document.querySelector("#chat-panel-prompt-autocomplete-display");
+
+        /**
+         * Settings Panel Icon
+         */
+        this.settingsIcon = document.querySelector("#chat-panel-settings-icon");
+
+        /**
+         * Admin Panel Icon
+         */
+        this.adminIcon = document.querySelector("#chat-panel-admin-icon");
+
+        /**
+         * Emote Icon
+         */
+        this.emoteIcon = document.querySelector("#chat-panel-emote-icon");
+
+        /**
+         * Send Chat/Command Button
+         */
+        this.sendButton = document.querySelector("#chat-panel-send-button");
+
+        /**
+         * Aspect Lock Icon
+         * Seems weird to stick this in here, but the split is dictated by chat width :P
+         */
+        this.aspectLockIcon = document.querySelector("#media-panel-aspect-lock-icon");
+
+        /**
+         * Hide Chat Icon
+         */
+        this.hideChatIcon = document.querySelector("#chat-panel-div-hide");
+
+        /**
+         * Show Chat Icon
+         */
+        this.showChatIcon = document.querySelector("#media-panel-show-chat-icon");
+
+        //Setup functions
+        this.setupInput();
+        this.defineListeners();
+        this.sizeToAspect();
+    }
+
+    /**
+     * Defines input-related event listeners
+     */
+    setupInput(){
+        //Chat bar
+        this.chatPrompt.addEventListener("keydown", this.send.bind(this));
+        this.chatPrompt.addEventListener("keydown", this.tabComplete.bind(this));
+        this.chatPrompt.addEventListener("input", this.displayAutocomplete.bind(this));
+        this.autocompleteDisplay.addEventListener("click", this.tabComplete.bind(this));
+        this.sendButton.addEventListener("click", this.send.bind(this));
+        this.settingsIcon.addEventListener("click", ()=>{this.client.cPanel.setActivePanel(new settingsPanel(client))});
+        this.adminIcon.addEventListener("click", ()=>{this.client.cPanel.setActivePanel(new queuePanel(client))});
+        this.emoteIcon.addEventListener("click", ()=>{this.client.cPanel.setActivePanel(new emotePanel(client))});
+
+        //Header icons
+        this.aspectLockIcon.addEventListener("click", this.lockAspect.bind(this));
+        this.showChatIcon.addEventListener("click", ()=>{this.toggleUI()});
+        this.hideChatIcon.addEventListener("click", ()=>{this.toggleUI()});
+        this.highSelect.addEventListener("change", this.setHighLevel.bind(this));
+        this.flairSelect.addEventListener("change", this.setFlair.bind(this));
+
+        //Clickdragger/Resize
+        this.clickDragger.handle.addEventListener("mousedown", this.unlockAspect.bind(this));
+        this.clickDragger.handle.addEventListener("clickdrag", this.handleAutoScroll.bind(this));
+        window.addEventListener("resize", this.resizeAspect.bind(this));
+
+        //chatbuffer
+        this.chatBuffer.addEventListener('scroll', this.scrollHandler.bind(this));
+    }
+
+    /**
+     * Defines network-related event listners
+     */
+    defineListeners(){
+        this.client.socket.on("chatMessage", this.displayChat.bind(this));
+        this.client.socket.on("clearChat", this.clearChat.bind(this));
+    }
+
+    /**
+     * Clears chat on command from server
+     * @param {Object} data - Data from server
+     */
+    clearChat(data){
+        //If we where passed a user to check
+        if(data.user != null){
+            var clearedChats = document.querySelectorAll(`.chat-entry-${data.user}`);
+        }else{
+            var clearedChats = document.querySelectorAll('.chat-entry');
+        }
+
+        //For each chat found
+        clearedChats.forEach((chat) => {
+            //fuckin' nukem!
+            chat.remove();
+        });
+    }
+
+    /**
+     * Receives, Post-Processes, and Displays chat messages from server
+     * @param {Object} data De-hydrated chat object from server
+     */
+    displayChat(data){
+        //Create chat-entry span
+        var chatEntry = document.createElement('span');
+        chatEntry.classList.add("chat-panel-buffer","chat-entry",`chat-entry-${data.user}`);
+
+        //Create high-level label
+        var highLevel = document.createElement('p');
+        highLevel.classList.add("chat-panel-buffer","chat-entry-high-level","high-level");
+        highLevel.textContent = utils.unescapeEntities(`${data.highLevel}`);
+        chatEntry.appendChild(highLevel);
+
+        //If we're not using classic flair
+        if(data.flair != "classic"){
+            //Use flair
+            var flair = `flair-${data.flair}`;
+        //Otherwise
+        }else{
+            //Pull user's assigned color from the color map
+            var flair =  this.client.userList.colorMap.get(data.user);
+        }
+
+        //Create username label
+        var userLabel = document.createElement('p');
+        userLabel.classList.add("chat-panel-buffer", "chat-entry-username", );
+        
+        //Create color span
+        var flairSpan = document.createElement('span');
+        flairSpan.classList.add("chat-entry-flair-span", flair);
+        flairSpan.innerHTML = data.user;
+
+        //Inject flair span into user label before the colon
+        userLabel.innerHTML = `${flairSpan.outerHTML}: `;
+
+        //Append user label
+        chatEntry.appendChild(userLabel);
+
+        //Create chat body
+        var chatBody = document.createElement('p');
+        chatBody.classList.add("chat-panel-buffer","chat-entry-body");
+        chatEntry.appendChild(chatBody);
+
+        //Append the post-processed chat-body to the chat buffer
+        this.chatBuffer.appendChild(this.chatPostprocessor.postprocess(chatEntry, data));
+
+        //Set size to aspect on launch
+        this.resizeAspect();
+    }
+
+    /**
+     * Concatinate Text into Chat Prompt
+     * @param {String} text - Text to Concatinate
+     */
+    catChat(text){
+        this.chatPrompt.value += text;
+        this.displayAutocomplete();
+    }
+
+    /**
+     * Calls a toke command out with a specified user
+     * @param {String} user - User to toke with
+     */
+    tokeWith(user){
+        this.commandPreprocessor.preprocess(user == this.client.user.user ? "!toke up fuckers" : `!toke up ${user}`);
+    }
+
+    /**
+     * Pre-processes and sends text from chat prompt to server
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    send(event){
+        if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){
+            this.commandPreprocessor.preprocess(this.chatPrompt.value);
+            //Clear our prompt and autocomplete nodes
+            this.chatPrompt.value = "";
+            this.autocompletePlaceholder.innerHTML = '';
+            this.autocompleteDisplay.innerHTML = '';
+        }
+    }
+
+    /**
+     * Displays auto-complete text against current prompt input
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    displayAutocomplete(event){
+        //Find current match
+        const match = this.checkAutocomplete();
+
+        //Set placeholder to space out the autocomplete display
+        //Use text content because it's unescaped, and while this only effects local users, it'll keep someone from noticing and whinging about it
+        this.autocompletePlaceholder.textContent = this.chatPrompt.value;
+        //Set the autocomplete display
+        this.autocompleteDisplay.textContent = match.match.replace(match.word, '');
+    }
+
+    /**
+     * Called upon tab-complete
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    tabComplete(event){
+        //If we hit tab or this isn't a keyboard event
+        if(event.key == "Tab" || event.key == null){
+            //Prevent default action
+            event.preventDefault();
+
+            //return focus to the chat prompt
+            this.chatPrompt.focus();
+
+            //Grab autocompletion match
+            const match = this.checkAutocomplete();
+
+            //If we have a match
+            if(match.match != ''){
+                //Autocomplete the current word
+                this.chatPrompt.value += match.match.replace(match.word, '');
+
+                //Clear out the autocomplete display
+                this.autocompleteDisplay.innerHTML = '';
+            }
+        }
+    }
+
+    /**
+     * Checks string input against auto-complete dictionary to generate the best guess as to what the user is typing
+     * @param {String} input - Current input from Chat Prompt
+     * @returns {Object} Object containing word we where handed and the match we found
+     */
+    checkAutocomplete(input = this.chatPrompt.value){
+        //Rebuild this fucker every time because it really doesn't take that much compute power and emotes/used tokes change
+        //Worst case we could store it persistantly and update as needed but I think that might be much
+        const dictionary = this.commandPreprocessor.buildAutocompleteDictionary();       
+
+        //Split our input by whitespace
+        const splitInput = input.split(/\s/g);
+        //Get the current word we're working on
+        const word = splitInput[splitInput.length - 1];
+        let matches = [];
+
+
+        //Run through dictionary sets
+        for(let set of Object.keys(dictionary)){
+            //Go through the current definitions of the current dictionary set
+            //I went with a for loop instead of a filter beacuse I wanted to pull the processed definition with pre/postfix
+            //and also directly push it into a shared array :P
+            for(let cmd of dictionary[set].cmds){
+
+                //Append the proper prefix/postfix to the current command
+                const definition = (`${dictionary[set].prefix}${cmd[0]}${dictionary[set].postfix}`);
+
+                //if definition starts with the current word and the command is enabled
+                if((word == '' ? false : definition.indexOf(word) == 0) && cmd[1]){
+                    //Add definition to match list
+                    matches.push(definition);
+                }
+            }
+        }
+
+        //If we found jack shit
+        if(matches.length == 0){
+            //Return jack shit
+            return {
+                match: '',
+                word
+            };
+        //If we got something
+        }else{
+            //return our top match
+            return {
+                match: matches[0],
+                word
+            };
+
+        }
+    }
+
+    /**
+     * Handles initial client meta-data dump from server upon connection
+     * @param {Object} data - Data dump from server
+     */
+    handleClientInfo(data){
+        this.updateFlairSelect(data.flairList, data.user.flair);
+        this.updateHighSelect(data.user.highLevel);
+    }
+
+    /**
+     * Sets user high-level
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    setHighLevel(event){
+        const highLevel = event.target.value;
+
+        this.client.socket.emit("setHighLevel", {highLevel});
+    }
+
+    /**
+     * Sets user flair
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    setFlair(event){
+        const flair = event.target.value;
+
+        this.client.socket.emit("setFlair", {flair});
+    }
+
+    /**
+     * Handles High-Level updates from the server
+     * @param {Number} highLevel - High Level to Set
+     */
+    updateHighSelect(highLevel){
+        this.highSelect.value = highLevel;
+    }
+
+    /**
+     * Handles flair updates from the server
+     * @param {Array} fliarList - List of flairs to put into flair select
+     * @param {String} fliar - Flair to set
+     */
+    updateFlairSelect(flairList, flair){
+        //clear current flair select
+        this.flairSelect.innerHTML = "";
+
+        //For each flair in flairlist
+        flairList.forEach((flair) => {
+            //Create an option
+            var flairOption = document.createElement('option');
+            //Set the name and innerHTML
+            flairOption.value = flair.name;
+            flairOption.textContent = utils.unescapeEntities(flair.displayName);
+
+            //Append it to the select
+            this.flairSelect.appendChild(flairOption);
+        });
+
+        //Set the selected flair in the UI
+        this.flairSelect.value = flair;
+        //Re-style the UI, do this in two seperate steps in-case we're running for the first time and have nothing to replace.
+        this.flairSelect.className = this.flairSelect.className.replace(/flair-\S*/, "");
+        this.flairSelect.classList.add(`flair-${flair}`);
+    }
+
+    /**
+     * Locks chat-size to aspect ratio of media
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    lockAspect(event){
+        //prevent the user from breaking shit :P
+        if(this.chatPanel.style.display != "none"){
+            this.aspectLock = true;
+            this.aspectLockIcon.style.display = "none";
+            this.sizeToAspect();
+        }
+    }
+
+    /**
+     * Un-locks chat-size to aspect ratio of media
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    unlockAspect(event){
+        //Disable aspect lock
+        this.aspectLock = false;
+
+        //Show aspect lock icon
+        this.aspectLockIcon.style.display = "inline";
+    }
+
+L    /**
+     * Re-sizes chat back to aspect ratio on window re-size when chat box is aspect locked
+     * Also prevents horizontal scroll-bars from chat/window resizing
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    resizeAspect(event){
+        const playerHidden = this.client.player.playerDiv.style.display == "none";
+
+        //If the aspect is locked and the player is hidden
+        if(this.aspectLock && !playerHidden){
+            this.sizeToAspect();
+        //Otherwise
+        }else{
+            //Fix the clickDragger on userlist
+            this.client.userList.clickDragger.fixCutoff();
+        }
+
+        //Autoscroll chat in-case we fucked it up
+        this.handleAutoScroll();
+    }
+
+L    /**
+     * Re-sizes chat box relative to media aspect ratio
+     */
+    sizeToAspect(){
+        if(this.chatPanel.style.display != "none"){
+            var targetVidWidth = this.client.player.getRatio() * this.chatPanel.getBoundingClientRect().height;
+            const targetChatWidth = window.innerWidth - targetVidWidth;
+            //This should be changeable in settings later on, for now it defaults to 20%
+            const limit = window.innerWidth * .2;
+
+            //Set width to target or 20vh depending on whether or not we've hit the width limit
+            this.chatPanel.style.flexBasis = targetChatWidth > limit ? `${targetChatWidth}px` : '20vh';
+
+            //Fix busted layout
+            var pageBreak = document.body.scrollWidth - document.body.getBoundingClientRect().width;
+            this.chatPanel.style.flexBasis = `${this.chatPanel.getBoundingClientRect().width + pageBreak}px`;
+            //This sometimes gets called before userList ahs been initiated :p
+            if(this.client.userList != null){
+                this.client.userList.clickDragger.fixCutoff();
+            }
+        }
+    } 
+
+    /**
+     * Toggles Chat Box UX
+     * @param {Boolean} show - Whether or not to show Chat Box UX
+     */
+    toggleUI(show = !this.chatPanel.checkVisibility()){
+        if(show){
+            this.chatPanel.style.display = "flex";
+            this.showChatIcon.style.display = "none";
+            this.client.player.hideVideoIcon.style.display = "flex";
+            this.client.userList.clickDragger.fixCutoff();
+        }else{
+            this.chatPanel.style.display = "none";
+            this.showChatIcon.style.display = "flex";
+            this.client.player.hideVideoIcon.style.display = "none";
+        }
+    }
+
+    /**
+     * Handles Video Toggling
+     * @param {Boolean} show - Whether or not the video is currently being hidden
+     */
+    handleVideoToggle(show){
+        //If we're enabling the video
+        if(show){
+            //Show hide chat icon
+            this.hideChatIcon.style.display = "flex";
+
+            //Re-enable the click dragger
+            this.clickDragger.enabled = true;
+
+            //Lock the chat to aspect ratio of the video, to make sure the chat width isn't breaking shit
+            this.lockAspect();
+        //If we're disabling the video
+        }else{
+            //Hide hide hide hide hide hide chat icon
+            this.hideChatIcon.style.display = "none";
+
+            //Need to clear the width from the split, or else it doesn't display properly
+            this.chatPanel.style.flexBasis = "100%";
+
+            //Disable the click dragger
+            this.clickDragger.enabled = false;
+        }
+    }
+
+    /**
+     * Handles scrolling within the chat buffer
+     * @param {Event} event - Event passed down from Event Handler
+     */
+    scrollHandler(event){
+        //If we're just starting out
+        if(this.lastPos == 0){
+            //Set last pos for the first time
+            this.lastPos = this.chatBuffer.scrollTop;
+        }
+
+        //Calculate scroll delta
+        const deltaY = this.chatBuffer.scrollTop - this.lastPos;
+
+        //Grab visible bounding rect so we don't have to do it again (can't use offset because someone might zoom in :P)
+        const bufferRect = this.chatBuffer.getBoundingClientRect();
+        const bufferHeight = Math.round(bufferRect.height);
+        const bufferWidth = Math.round(bufferRect.width);
+
+        if(this.lastHeight == 0){
+            this.lastHeight = bufferHeight;
+        }
+
+        if(this.lastWidth == 0){
+            this.lastWidth = bufferWidth;
+        }
+
+        //If we're scrolling up
+        if(deltaY < 0){
+            //If we have room to scroll, and we didn't resize
+            if(this.chatBuffer.scrollHeight > bufferHeight && (this.lastWidth == bufferWidth && this.lastHeight == bufferHeight)){
+                //Disable auto scrolling
+                this.autoScroll = false;
+            }else{
+                this.handleAutoScroll();
+            }
+        //Otherwise if the difference between the chat buffers scroll height and offset height is equal to the scroll top
+        //(Because it is scrolled all the way down)
+        }else if((this.chatBuffer.scrollHeight - bufferHeight) == this.chatBuffer.scrollTop){
+            this.autoScroll = true;
+        }
+
+        //Set last post/size for next the run
+        this.lastPos = this.chatBuffer.scrollTop;
+        this.lastHeight = bufferHeight;
+        this.lastWidth = bufferWidth;
+    }
+
+    /**
+     * Auto-scrolls chat buffer when new chats are entered.
+     */
+    handleAutoScroll(){
+        //If autoscroll is enabled
+        if(this.autoScroll){
+            //Set chatBuffer scrollTop to the difference between scrollHeight and buffer height (scroll to the bottom)
+            this.chatBuffer.scrollTop = this.chatBuffer.scrollHeight - Math.round(this.chatBuffer.getBoundingClientRect().height);
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/client/chatBox.html b/www/doc/client/chatBox.html new file mode 100644 index 0000000..255128e --- /dev/null +++ b/www/doc/client/chatBox.html @@ -0,0 +1,4659 @@ + + + + + JSDoc: Class: chatBox + + + + + + + + + + +
+ +

Class: chatBox

+ + + + + + +
+ +
+ +

chatBox(client)

+ +
Class which represents Canopy Chat Box UI
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new chatBox(client)

+ + + + + + +
+ Instantiates a new Chat Box object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent client Management Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

adminIcon

+ + + + +
+ Admin Panel Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

aspectLock

+ + + + +
+ Whether or not chat-size should be locked to current media aspect ratio +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

aspectLockIcon

+ + + + +
+ Aspect Lock Icon +Seems weird to stick this in here, but the split is dictated by chat width :P +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

autoScroll

+ + + + +
+ Whether or not the chat box should auto-scroll on new chat +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

autocompleteDisplay

+ + + + +
+ Auto-Complete Display +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

autocompletePlaceholder

+ + + + +
+ Auto-Complete Placeholder +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

chatBuffer

+ + + + +
+ Chat Buffer Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

chatPanel

+ + + + +
+ Chat Panel Container Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

chatPostprocessor

+ + + + +
+ Chat Post-Processor Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

chatPrompt

+ + + + +
+ Chat Prompt +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

clickDragger

+ + + + +
+ Click-Dragger Object for handling dynamic chat/video split re-sizing +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

commandPreprocessor

+ + + + +
+ Command Pre-Processor Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

emoteIcon

+ + + + +
+ Emote Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

flairSelect

+ + + + +
+ Flair Selector +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hideChatIcon

+ + + + +
+ Hide Chat Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

highSelect

+ + + + +
+ High Level Selector +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

lastHeight

+ + + + +
+ Height of Chat Buffer on last scroll +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

lastPos

+ + + + +
+ Chat Buffer Scroll Top on last scroll +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

lastWidth

+ + + + +
+ Width of Chat Buffer on last scroll +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

sendButton

+ + + + +
+ Send Chat/Command Button +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

settingsIcon

+ + + + +
+ Settings Panel Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

showChatIcon

+ + + + +
+ Show Chat Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

catChat(text)

+ + + + + + +
+ Concatinate Text into Chat Prompt +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
text + + +String + + + + Text to Concatinate
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

checkAutocomplete(input) → {Object}

+ + + + + + +
+ Checks string input against auto-complete dictionary to generate the best guess as to what the user is typing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
input + + +String + + + + Current input from Chat Prompt
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing word we where handed and the match we found +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

clearChat(data)

+ + + + + + +
+ Clears chat on command from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners()

+ + + + + + +
+ Defines network-related event listners +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

displayAutocomplete(event)

+ + + + + + +
+ Displays auto-complete text against current prompt input +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

displayChat(data)

+ + + + + + +
+ Receives, Post-Processes, and Displays chat messages from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + De-hydrated chat object from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleAutoScroll()

+ + + + + + +
+ Auto-scrolls chat buffer when new chats are entered. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleClientInfo(data)

+ + + + + + +
+ Handles initial client meta-data dump from server upon connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data dump from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleVideoToggle(show)

+ + + + + + +
+ Handles Video Toggling +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
show + + +Boolean + + + + Whether or not the video is currently being hidden
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

lockAspect(event)

+ + + + + + +
+ Locks chat-size to aspect ratio of media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resizeAspect(event)

+ + + + + + +
+ Re-sizes chat back to aspect ratio on window re-size when chat box is aspect locked +Also prevents horizontal scroll-bars from chat/window resizing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

scrollHandler(event)

+ + + + + + +
+ Handles scrolling within the chat buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

send(event)

+ + + + + + +
+ Pre-processes and sends text from chat prompt to server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setFlair(event)

+ + + + + + +
+ Sets user flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setHighLevel(event)

+ + + + + + +
+ Sets user high-level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setupInput()

+ + + + + + +
+ Defines input-related event listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sizeToAspect()

+ + + + + + +
+ Re-sizes chat box relative to media aspect ratio +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tabComplete(event)

+ + + + + + +
+ Called upon tab-complete +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

toggleUI(show)

+ + + + + + +
+ Toggles Chat Box UX +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
show + + +Boolean + + + + Whether or not to show Chat Box UX
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeWith(user)

+ + + + + + +
+ Calls a toke command out with a specified user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User to toke with
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

unlockAspect(event)

+ + + + + + +
+ Un-locks chat-size to aspect ratio of media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down from Event Handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateFlairSelect(fliarList, fliar)

+ + + + + + +
+ Handles flair updates from the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fliarList + + +Array + + + + List of flairs to put into flair select
fliar + + +String + + + + Flair to set
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighSelect(highLevel)

+ + + + + + +
+ Handles High-Level updates from the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + High Level to Set
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/chatPostprocessor.html b/www/doc/client/chatPostprocessor.html new file mode 100644 index 0000000..4673ea7 --- /dev/null +++ b/www/doc/client/chatPostprocessor.html @@ -0,0 +1,1803 @@ + + + + + JSDoc: Class: chatPostprocessor + + + + + + + + + + +
+ +

Class: chatPostprocessor

+ + + + + + +
+ +
+ +

chatPostprocessor(client)

+ +
Class contianing client-side message post-processing code
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new chatPostprocessor(client)

+ + + + + + +
+ Instantiates a new Chat Post-Processor object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent client Management Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

addWhitespace()

+ + + + + + +
+ Injects invisible whitespace in long-ass words to prevent fucking up the chat buffer size +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChatType()

+ + + + + + +
+ Marks chat nodes in-case of non-standard chat types +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

injectBody()

+ + + + + + +
+ Injects word objects into chat-entry as proper DOM Nodes +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

postprocess(chatEntry, rawData) → {Node}

+ + + + + + +
+ Post-Processes a single message from the server and returns a presntable DOM Node +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chatEntry + + +Node + + + + Chat entry generated by initial chatBox method
rawData + + +Object + + + + Raw data from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Post-Processed Chat Entry +
+ + + +
+
+ Type +
+
+ +Node + + +
+
+ + + + + + + + + + + + + +

processBold()

+ + + + + + +
+ Processes in-line Bold/Strong text +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

processChannelNames()

+ + + + + + +
+ Processes clickable channel names in chat +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

processCommandExamples()

+ + + + + + +
+ Processes clickable command examples in chat +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

processFilter(delimiter, cb) → {Array}

+ + + + + + +
+ Searches for text in-between a specific delimiter and runs a given callback against it + +Internal command used by several text filters to prevent code re-writes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
delimiter + + +String + + + + delimiter to search string by
cb + + +function + + + + Callback function to run against found strings
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - list of found instances of filter +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

processItalics()

+ + + + + + +
+ Processes in-line Italics +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Processes clickable links and embedded media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

processQoute()

+ + + + + + +
+ Processes qouted text in chat +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

processSpoilers()

+ + + + + + +
+ Processes in-line spoilers +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

processStrikethrough()

+ + + + + + +
+ Processes in-line Strike-through +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

processUsernames()

+ + + + + + +
+ Processes clickable username callouts in chat +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitMessage()

+ + + + + + +
+ Splits message into an array of Word Objects for further processing +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/chatPostprocessor.js.html b/www/doc/client/chatPostprocessor.js.html new file mode 100644 index 0000000..ae4b63c --- /dev/null +++ b/www/doc/client/chatPostprocessor.js.html @@ -0,0 +1,680 @@ + + + + + JSDoc: Source: chatPostprocessor.js + + + + + + + + + + +
+ +

Source: chatPostprocessor.js

+ + + + + + +
+
+
/*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 contianing client-side message post-processing code
+ */
+class chatPostprocessor{
+    /**
+     * Instantiates a new Chat Post-Processor object
+     * @param {channel} client - Parent client Management Object
+     */
+    constructor(client){
+        /**
+         * Parent Client Management Object
+         */
+        this.client = client;
+    }
+
+    /**
+     * Post-Processes a single message from the server and returns a presntable DOM Node
+     * @param {Node} chatEntry - Chat entry generated by initial chatBox method
+     * @param {Object} rawData - Raw data from server
+     * @returns {Node} Post-Processed Chat Entry
+     */
+    postprocess(chatEntry, rawData){
+        //Create empty array to hold filter spans
+        this.filterSpans = [];
+        //Set raw message data
+        this.rawData = rawData;
+        //Set current chat nodes
+        this.chatEntry = chatEntry;
+        this.chatBody = this.chatEntry.querySelector(".chat-entry-body");
+
+        //Split the chat message into an array of objects representing each word/chunk
+        this.splitMessage();
+
+        //Process Qoutes
+        this.processQoute();
+
+        //Re-Hydrate and Inject links and embedded media into un-processed placeholders
+        this.processLinks();
+
+        //Inject clickable command examples
+        this.processCommandExamples();
+
+        //Inject clickable channel names
+        this.processChannelNames();
+
+        //Inject clickable usernames
+        this.processUsernames();
+
+        //Detect inline spoilers
+        this.processSpoilers();
+
+        //Detect inline strikethrough
+        this.processStrikethrough();
+
+        //Detect inline bold text
+        this.processBold();
+
+        //Detect inline italics
+        this.processItalics();
+
+        //Inject whitespace into long ass-words
+        this.addWhitespace();
+
+        //Handle non-standard chat types
+        this.handleChatType();
+                
+        //Inject the pre-processed chat hyper-text into the chatEntry node
+        this.injectBody();
+
+        //Return the pre-processed node
+        return this.chatEntry;
+    }
+
+    /**
+     * Splits message into an array of Word Objects for further processing
+     */
+    splitMessage(){
+        //Create an empty array to hold the body
+        this.messageArray = [];
+
+        //Unescape any sanatized char codes as we use .textContent for double-safety, and to prevent splitting of char codes
+        //Split string by word-boundries on words and non-word boundries around whitespace, with negative lookaheads to exclude file seperators so we don't split link placeholders, and dashes so we dont split usernames and other things
+        //Also split by any invisble whitespace as a crutch to handle mushed links/emotes
+        //If we can one day figure out how to split non-repeating special chars instead of special chars with whitespace, that would be perf, unfortunately my brain hasn't rotted enough to understand regex like that just yet.
+        const splitString = utils.unescapeEntities(this.rawData.msg).split(/(?<!-)(?<!␜)(?=\w)\b|(?!-)(?<=\w)\b|(?=\s)\B|(?<=\s)\B|ㅤ/g);
+
+        //for each word in the splitstring
+        splitString.forEach((string) => {
+            //create a word object
+            const wordObj = {
+                string: string,
+                filterClasses: [],
+                type: "word"
+            }
+
+            //Add it to our body array
+            this.messageArray.push(wordObj);
+        });
+    }
+
+    /**
+     * Injects word objects into chat-entry as proper DOM Nodes
+     */
+    injectBody(){
+        //Create an empty array to hold the objects to inject
+        const injectionArray = [];
+
+        //For each word object
+        this.messageArray.forEach((wordObj) => {
+            if(wordObj.type == 'word'){
+                //Create span node
+                const span = document.createElement('span');
+
+                //Set span filter classes
+                span.classList.add(...wordObj.filterClasses);
+
+                //Set span text
+                span.textContent = wordObj.string;
+                
+                //Inject node into array
+                injectionArray.push(span);
+            }else if(wordObj.type == 'link'){
+                //Create a link node from our link
+                const link = document.createElement('a');
+                link.classList.add('chat-link', ...wordObj.filterClasses);
+                link.href = wordObj.link;
+                link.target = "_blank";
+                //Use textContent to be safe since links can't be escaped serverside
+                link.textContent = wordObj.link;
+
+                //Append node to chatBody
+                combineNode(wordObj, link);
+            }else if(wordObj.type == 'deadLink'){
+                //Create a text span node from our link
+                const badLink = document.createElement('a');
+                badLink.classList.add('chat-dead-link', 'danger-link', ...wordObj.filterClasses);
+                badLink.href = wordObj.link;
+                badLink.target = "_blank";
+                //Use textContent to be safe since links can't be escaped serverside
+                badLink.textContent = wordObj.link;
+
+                //Append node to chatBody
+                combineNode(wordObj, badLink);
+            }else if(wordObj.type == 'malformedLink'){
+                //Create a text span node from our link
+                const malformedLink = document.createElement('span');
+                malformedLink.classList.add('chat-malformed-link', ...wordObj.filterClasses);
+                //Use textContent to be safe since links can't be escaped (this is why we don't just add it using injectString)
+                //arguably we could sanatize malformed links serverside since they're never actually used as links
+                malformedLink.textContent = wordObj.link;
+
+                //Append node to chatBody
+                combineNode(wordObj, malformedLink);
+            }else if(wordObj.type == 'image'){
+                //Create an img node from our link
+                const img = document.createElement('img');
+                img.classList.add('chat-img', ...wordObj.filterClasses);
+                img.src = wordObj.link;
+
+                //Look for an emote by link since emotes are tx'd as bare links
+                const emote = this.client.chatBox.commandPreprocessor.getEmoteByLink(wordObj.link);
+
+                //If this is a known emote
+                if(emote != null){
+                    //Set the hover text to the emote's name
+                    img.title = `[${emote.name}]`;
+                }
+
+                //Append node to chatBody
+                combineNode(wordObj, img);
+            }else if(wordObj.type == 'video'){
+                //Create a video node from our link
+                const vid = document.createElement('video');
+                vid.classList.add('chat-video', ...wordObj.filterClasses);
+                vid.src = wordObj.link;
+                vid.controls = false;
+                vid.autoplay = true;
+                vid.loop = true;
+                vid.muted = true;
+
+                //Look for an emote by link since emotes are tx'd as bare links
+                const emote = this.client.chatBox.commandPreprocessor.getEmoteByLink(wordObj.link);
+
+                //If this is a known emote
+                if(emote != null){
+                    //Set the hover text to the emote's name
+                    vid.title = `[${emote.name}]`;
+                }
+
+                combineNode(wordObj, vid);
+            }else if(wordObj.type == 'command'){
+                //Create link node
+                const link = document.createElement('a');
+                //Set class
+                link.classList.add('chat-link', ...wordObj.filterClasses);
+                //Set href and inner text
+                link.href = "javascript:";
+                link.textContent = wordObj.command;
+
+                //Add chatbox functionality
+                link.addEventListener('click', () => {this.client.chatBox.commandPreprocessor.preprocess(wordObj.command)});
+
+                //We don't have to worry about injecting this into whitespace since there shouldn't be any here.
+                injectionArray.push(link);
+            }else if(wordObj.type == "username"){
+                //Create link node
+                const link = document.createElement('a');
+                //set class
+                link.classList.add(wordObj.color, ...wordObj.filterClasses);
+                //Set href and inner text
+                link.href = "javascript:";
+                link.textContent = wordObj.string;
+
+                //add chatbox functionality
+                link.addEventListener('click', () => {this.client.chatBox.chatPrompt.value += `${wordObj.string} `});
+
+                //We don't have to worry about injecting this into whitespace since there shouldn't be any here.
+                injectionArray.push(link);
+            }else if(wordObj.type == "channel"){
+                //Create link node
+                const link = document.createElement('a');
+                //set class
+                link.classList.add('chat-link', ...wordObj.filterClasses);
+                //Set href and inner text
+                link.href = `/c/${wordObj.chan}`;
+                link.target = "_blank"
+                link.textContent = wordObj.string;
+
+                //We don't have to worry about injecting this into whitespace since there shouldn't be any here.
+                injectionArray.push(link);
+            }else{
+                console.warn("Unknown chat postprocessor word type:");
+                console.warn(wordObj);
+            }
+
+        });
+
+        //For each item found in the injection array
+        for(let itemIndex in injectionArray){
+            const item = injectionArray[itemIndex];
+
+            //Currently this doesnt support multiple overlapping span-type filters
+            //not a huge deal since we only have once (spoiler)
+            //All others can be applied per-node without any usability side effects
+            const curFilter = this.filterSpans.filter(filterFilters)[0];
+            let appendBody = this.chatBody;
+
+            //If we have a filter span
+            if(curFilter != null){
+                //If we're beggining the array
+                if(itemIndex == curFilter.index[0]){
+                    //Create the span
+                    appendBody = document.createElement('span');
+                    //Label it for what it is
+                    appendBody.classList.add(curFilter.class);
+                    //Add it to the chat body
+                    this.chatBody.appendChild(appendBody);
+                //Otherwise
+                }else{
+                    //Use the existing span
+                    appendBody = (this.chatBody.children[this.chatBody.children.length - 1]);
+                }
+            }
+
+            //Append the node to our chat body
+            appendBody.appendChild(item);
+
+            function filterFilters(filter){
+                //If the index is within the filter span
+                return filter.index[0] <= itemIndex && filter.index[1] >= itemIndex;
+            }
+        }
+
+        //Like string.replace except it actually injects the node so we can keep things like event handlers
+        function combineNode(wordObj, node, placeholder = '␜'){
+            //Split string by the placeholder so we can keep surrounding whitespace
+            const splitWord = wordObj.string.split(placeholder, 2);
+
+            //Create combined node
+            const combinedSpan = document.createElement('span');
+
+            //Add the first part of the text
+            combinedSpan.textContent = splitWord[0];
+
+            //Add in the requestd node
+            combinedSpan.appendChild(node);
+
+            //Finish it off with the last bit of text
+            combinedSpan.insertAdjacentText('beforeend', splitWord[1]);
+
+            //Add to injection array as three nested items to keep arrays lined up
+            injectionArray.push(combinedSpan);
+        } 
+    }
+
+    /**
+     * Processes qouted text in chat
+     */
+    processQoute(){
+        //If the message starts off with '>'
+        if(this.messageArray[0].string[0] == '>'){
+            this.chatBody.classList.add("qoute");
+        }
+    }
+
+    /**
+     * Processes clickable command examples in chat
+     */
+    processCommandExamples(){
+        //for each word object in the body
+        this.messageArray.forEach((wordObj, wordIndex) => {
+            //if the word object hasn't been pre-processed elsewhere
+            if(wordObj.type == "word"){
+                //Get last char of current word
+                const lastChar = wordObj.string[wordObj.string.length - 1];
+
+                //if the last char is !
+                if(lastChar == '!' || lastChar == '/'){
+                    //get next word
+                    const nextWord = this.messageArray[wordIndex + 1];
+                    //if we have another word
+                    if(nextWord != null){
+                        const command = lastChar + nextWord.string;
+                        //Take out the command marker
+                        this.messageArray[wordIndex].string = wordObj.string.slice(0,-1);
+
+                        const commandObj = {
+                            type: "command",
+                            string: nextWord.string,
+                            filterClasses: [],
+                            command: command
+                        }
+
+                        this.messageArray[wordIndex + 1] = commandObj;
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Processes clickable channel names in chat
+     */
+    processChannelNames(){
+        //for each word object in the body
+        this.messageArray.forEach((wordObj, wordIndex) => {
+            //if the word object hasn't been pre-processed elsewhere
+            if(wordObj.type == "word"){
+                //Get last char of current word with slashes pounds
+                const lastChar = wordObj.string[wordObj.string.length - 1];
+                const secondLastChar = wordObj.string[wordObj.string.length - 2];
+
+                //if the last char is # and the second to last char isn't & or # (avoid spoilers)
+                if(lastChar == '#' && secondLastChar != '#'){
+                    //get next word
+                    const nextWord = this.messageArray[wordIndex + 1];
+                    //if we have another word
+                    if(nextWord != null){
+                        //Take out the chan marker
+                        this.messageArray[wordIndex].string = wordObj.string.slice(0,-1);
+
+                        const commandObj = {
+                            type: "channel",
+                            string: lastChar + nextWord.string,
+                            filterClasses: [],
+                            chan: nextWord.string
+                        }
+
+                        this.messageArray[wordIndex + 1] = commandObj;
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Processes clickable username callouts in chat
+     */
+    processUsernames(){
+        //for each word object in the body
+        this.messageArray.forEach((wordObj, wordIndex) => {
+            //if the word object hasn't been pre-processed elsewhere
+            if(wordObj.type == "word"){
+                //Check for user and get their color
+                const color = this.client.userList.colorMap.get(wordObj.string);
+
+                //If the current word is the username of a connected user
+                if(color != null){
+                    //Mark it as so
+                    this.messageArray[wordIndex].type = "username";
+                    //Store their color
+                    this.messageArray[wordIndex].color = color;
+                }
+            }
+        });
+    }
+
+    /**
+     * Injects invisible whitespace in long-ass words to prevent fucking up the chat buffer size
+     */
+    addWhitespace(){
+        //for each word object in the body
+        this.messageArray.forEach((wordObj, wordIndex) => {
+            //if the word object hasn't been pre-processed elsewhere
+            if(wordObj.type == "word"){
+                //Create an empty array to hold our word
+                var wordArray = [];
+                //For each character in the string of the current word object
+                this.messageArray[wordIndex].string.split("").forEach((char, charIndex) => {
+                    //push the current character to the wordArray
+                    wordArray.push(char);
+                    //After eight characters
+                    if(charIndex > 8){
+                        //Push an invisible line-break character between every character
+                        wordArray.push("ㅤ");
+                    }
+
+                });
+
+                //Join the wordArray into a single string, and use it to set the current wordObject's string
+                this.messageArray[wordIndex].string = wordArray.join("");
+            }
+        });
+    }
+
+    /**
+     * Searches for text in-between a specific delimiter and runs a given callback against it
+     * 
+     * Internal command used by several text filters to prevent code re-writes
+     * @param {String} delimiter - delimiter to search string by
+     * @param {Function} cb - Callback function to run against found strings
+     * @returns {Array} - list of found instances of filter
+     */
+    processFilter(delimiter, cb){
+        //Create empty array to hold spoilers (keep this seperate at first for internal function use)
+        const foundFilters = [];
+        //Spoiler detection stage
+        //For each word object in the message array
+        main: for(let wordIndex = 0; wordIndex < this.messageArray.length; wordIndex++){
+            //Get the current word object
+            const wordObj = this.messageArray[wordIndex];
+            
+            //If its a regular word and contains '##'
+            if(wordObj.type == 'word' && wordObj.string.match(utils.escapeRegex(delimiter))){
+
+                //Crawl through detected spoilers
+                for(let spoiler of foundFilters){
+                    //If the current word object is part of a detected spoiler
+                    if(wordIndex == spoiler[0] || wordIndex == spoiler[1]){
+                        //ignore it and continue on to the next word object
+                        continue main;
+                    }
+                }
+
+                //Crawl throw word objects after the current one
+                for(let endIndex = (wordIndex + 1); endIndex < this.messageArray.length; endIndex++){
+                    //Get the current end object
+                    const endObj = this.messageArray[endIndex];
+
+                    //If its a regular word and contains '##'
+                    if(endObj.type == 'word' && endObj.string.match(utils.escapeRegex(delimiter))){                   
+                        //Setup the found filter array
+                        const foundFilter = [wordIndex, endIndex];
+
+                        //Scrape out delimiters
+                        wordObj.string = wordObj.string.replaceAll(delimiter,'');
+                        endObj.string = endObj.string.replaceAll(delimiter,'');
+
+                        //Add it to the list of detected filters
+                        foundFilters.push(foundFilter);
+
+                        //Run the filter callback
+                        cb(foundFilter)
+
+                        //Break the nested end-detection loop
+                        break;
+                    }
+                }
+            }
+        }
+
+        return foundFilters;
+    }
+
+    /**
+     * Processes in-line spoilers
+     */
+    processSpoilers(){
+        //Process spoilers using '##' delimiter
+        this.processFilter('##', (foundSpoiler)=>{
+            //For each found spoiler add it to the list of found filter spans
+            this.filterSpans.push({class: "spoiler", index: [foundSpoiler[0] + 1, foundSpoiler[1] - 1], delimiters: [foundSpoiler[0], foundSpoiler[1]]});
+        });
+    }
+
+    /**
+     * Processes in-line Strike-through
+     */
+    processStrikethrough(){
+        //Process strikethrough's using '~~' delimiter
+        this.processFilter('~~', (foundStrikethrough)=>{
+            for(let wordIndex = foundStrikethrough[0]; wordIndex < foundStrikethrough[1]; wordIndex++){
+                this.messageArray[wordIndex].filterClasses.push("strikethrough");
+            }
+        })
+    }
+
+    /**
+     * Processes in-line Bold/Strong text
+     */
+    processBold(){
+        //Process strong text using '*' delimiter
+        this.processFilter('**', (foundStrikethrough)=>{
+            for(let wordIndex = foundStrikethrough[0]; wordIndex < foundStrikethrough[1]; wordIndex++){
+                this.messageArray[wordIndex].filterClasses.push("bold");
+            }
+        })
+    }
+
+    /**
+     * Processes in-line Italics
+     */
+    processItalics(){
+        //Process italics using '__' delimiter
+        this.processFilter('*', (foundStrikethrough)=>{
+            for(let wordIndex = foundStrikethrough[0]; wordIndex < foundStrikethrough[1]; wordIndex++){
+                this.messageArray[wordIndex].filterClasses.push("italics");
+            }
+        })
+    }
+
+    /**
+     * Processes clickable links and embedded media
+     */
+    processLinks(){
+        //If we don't have links
+        if(this.rawData.links == null){
+            //Don't bother
+            return;
+        }
+
+        //For every link received in this message
+        this.rawData.links.forEach((link, linkIndex) => {
+            //For every word obj in the message array
+            this.messageArray.forEach((wordObj, wordIndex) => {
+                //Check current wordobj for link (placeholder may contain whitespace with it)
+                if(wordObj.string.match(`␜${linkIndex}`)){
+                    //Set current word object in the body array to the new link object
+                    this.messageArray[wordIndex] = {
+                        //Don't want to use a numbered placeholder to make this easier during body injection
+                        //but we also don't want to clobber any surrounding whitespace
+                        string: wordObj.string.replace(`␜${linkIndex}`, '␜'),
+                        link: link.link,
+                        type: link.type,
+                        filterClasses: []
+                    }
+                }
+            })
+        });
+    }
+
+    /**
+     * Marks chat nodes in-case of non-standard chat types
+     */
+    handleChatType(){
+        if(this.rawData.type == "whisper"){
+            //add whisper class
+            this.chatBody.classList.add('whisper');
+        }else if(this.rawData.type == "announcement"){
+            //Squash the high-level
+            this.chatEntry.querySelector('.high-level').remove();
+
+            //Get the username and make it into an announcement title (little hacky but this *IS* postprocessing)
+            const userNode = this.chatEntry.querySelector('.chat-entry-username');
+            userNode.textContent = `${userNode.textContent.slice(0,-2)} Announcement`;
+
+            //Add/remove relevant classes
+            userNode.classList.remove('chat-entry-username');
+            userNode.classList.add('announcement-title');
+            this.chatBody.classList.add('announcement-body');
+            this.chatEntry.classList.add('announcement');
+        }else if(this.rawData.type == "toke"){
+            //Squash the high-level
+            this.chatEntry.querySelector('.high-level').remove();
+
+            //remove the username
+            this.chatEntry.querySelector('.chat-entry-username').remove();
+
+            //Add toke/tokewhisper class
+            this.chatBody.classList.add("toke");
+        }else if(this.rawData.type == "tokewhisper"){
+            //Squash the high-level
+            this.chatEntry.querySelector('.high-level').remove();
+
+            //remove the username
+            this.chatEntry.querySelector('.chat-entry-username').remove();
+
+            //Add toke/tokewhisper class
+            this.chatBody.classList.add("tokewhisper","serverwhisper");
+        }else if(this.rawData.type == "spoiler"){
+            //Set whole-body spoiler
+            this.chatBody.classList.add("spoiler");
+        }else if(this.rawData.type == "strikethrough"){
+            //Set whole-body spoiler
+            this.chatBody.classList.add("strikethrough");
+        }else if(this.rawData.type == "bold"){
+            //Set whole-body spoiler
+            this.chatBody.classList.add("bold");
+        }else if(this.rawData.type == "italics"){
+            //Set whole-body spoiler
+            this.chatBody.classList.add("italics");
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/client/commandPreprocessor.html b/www/doc/client/commandPreprocessor.html index 21290cc..99d9d3f 100644 --- a/www/doc/client/commandPreprocessor.html +++ b/www/doc/client/commandPreprocessor.html @@ -30,7 +30,7 @@

commandPreprocessor(client)

-
Class for object containing chat and command pre-processing logic
+
Class containing chat and command pre-processing logic
@@ -105,7 +105,7 @@ - Parent client mgmt object + Parent client Management Object @@ -1906,13 +1906,13 @@
diff --git a/www/doc/client/commandPreprocessor.js.html b/www/doc/client/commandPreprocessor.js.html index d2220c7..9e6a44c 100644 --- a/www/doc/client/commandPreprocessor.js.html +++ b/www/doc/client/commandPreprocessor.js.html @@ -43,12 +43,12 @@ 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 for object containing chat and command pre-processing logic + * Class containing chat and command pre-processing logic */ class commandPreprocessor{ /** * Instantiates a new commandPreprocessor object - * @param {channel} client - Parent client mgmt object + * @param {channel} client - Parent client Management Object */ constructor(client){ /** @@ -328,7 +328,7 @@ class commandPreprocessor{ } /** - * Class for Object which contains logic for client-side commands + * Class which contains logic for client-side commands */ class commandProcessor{ /** @@ -365,13 +365,13 @@ class commandProcessor{
diff --git a/www/doc/client/commandProcessor.html b/www/doc/client/commandProcessor.html index d4960e4..e8bf2a6 100644 --- a/www/doc/client/commandProcessor.html +++ b/www/doc/client/commandProcessor.html @@ -30,7 +30,7 @@

commandProcessor(client)

-
Class for Object which contains logic for client-side commands
+
Class which contains logic for client-side commands
@@ -415,13 +415,13 @@
diff --git a/www/doc/client/cpanel.js.html b/www/doc/client/cpanel.js.html new file mode 100644 index 0000000..8056e0a --- /dev/null +++ b/www/doc/client/cpanel.js.html @@ -0,0 +1,524 @@ + + + + + JSDoc: Source: cpanel.js + + + + + + + + + + +
+ +

Source: cpanel.js

+ + + + + + +
+
+
/*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 containing code for managing the Canopy Panel UX
+ */
+class cPanel{
+    /**
+     * Instantiates a new Canopy Panel Management object
+     * @param {channel} client - Parent client Management Object
+     */
+    constructor(client){
+        /**
+         * Parent Client Management object
+         */
+        this.client = client;
+
+        /**
+         * Active Panel Object
+         */
+        this.activePanel = null;
+
+        /**
+         * Pinned Panel Object
+         */
+        this.pinnedPanel = null;
+
+        /**
+         * Popped Panel Objects
+         */
+        this.poppedPanels = [];
+
+        /**
+         * Click-Dragger object for re-sizable active panel
+         */
+        this.activePanelDragger = new canopyUXUtils.clickDragger("#cpanel-active-drag-handle", "#cpanel-active-div", false, null, false);
+
+        /**
+         * Click-Dragger object for re-sizable pinned panel
+         */
+        this.pinnedPanelDragger = new canopyUXUtils.clickDragger("#cpanel-pinned-drag-handle", "#cpanel-pinned-div", false, this.client.chatBox.clickDragger);
+
+        //Element Nodes
+        //Active Panel
+        /**
+         * Active Panel Container
+         */
+        this.activePanelDiv = document.querySelector("#cpanel-active-div");
+
+        /**
+         * Active Panel Title
+         */
+        this.activePanelTitle = document.querySelector("#cpanel-active-title");
+
+        /**
+         * Active Title Document Div
+         */
+        this.activePanelDoc = document.querySelector("#cpanel-active-doc");
+
+        /**
+         * Active Panel Pin Icon
+         */
+        this.activePanelPinIcon = document.querySelector("#cpanel-active-pin-icon");
+
+        /**
+         * Active Panel Pop-Out Icon
+         */
+        this.activePanelPopoutIcon = document.querySelector("#cpanel-active-popout-icon");
+
+        /**
+         * Active Panel Close Icon
+         */
+        this.activePanelCloseIcon = document.querySelector("#cpanel-active-close-icon");
+
+        //Pinned Panel
+        /**
+         * Pinned Panel Contianer
+         */
+        this.pinnedPanelDiv = document.querySelector("#cpanel-pinned-div");
+
+        /**
+         * Pinned Panel Title
+         */
+        this.pinnedPanelTitle = document.querySelector("#cpanel-pinned-title");
+
+        /**
+         * Pinned Panel Document Div
+         */
+        this.pinnedPanelDoc = document.querySelector("#cpanel-pinned-doc");
+
+        /**
+         * Pinned Panel Un-Pin Icon
+         */
+        this.pinnedPanelUnpinIcon = document.querySelector("#cpanel-pinned-unpin-icon");
+
+        /**
+         * Pinned Panel Pop-Out Icon
+         */
+        this.pinnedPanelPopoutIcon = document.querySelector("#cpanel-pinned-popout-icon");
+
+        /**
+         * Pinned Panel Close Icon
+         */
+        this.pinnedPanelCloseIcon = document.querySelector("#cpanel-pinned-close-icon");
+
+        this.setupInput();
+    }
+
+    /**
+     * Defines input-related event listeners
+     */
+    setupInput(){
+        this.activePanelCloseIcon.addEventListener("click", this.hideActivePanel.bind(this));
+        this.activePanelPinIcon.addEventListener("click", this.pinPanel.bind(this));
+        this.activePanelPopoutIcon.addEventListener("click", this.popActivePanel.bind(this));
+        this.pinnedPanelCloseIcon.addEventListener("click", this.hidePinnedPanel.bind(this));
+        this.pinnedPanelUnpinIcon.addEventListener("click", this.unpinPanel.bind(this));
+        this.pinnedPanelPopoutIcon.addEventListener("click", this.popPinnedPanel.bind(this));
+    }
+
+    /**
+     * Sets Active Panel
+     * @param {panelObj} panel - Panel Object to set as active
+     * @param {String} panelBody - innerHTML of Panel, pulls from panelObj.getPage() if empty
+     */
+    async setActivePanel(panel, panelBody){
+        //Set active panel
+        this.activePanel = panel;
+
+        //Grab panel hypertext content and load it into div
+        this.activePanelDoc.innerHTML = (panelBody == null || panelBody == "") ? await this.activePanel.getPage() : panelBody;
+          
+
+        //Display panel
+        this.activePanelDiv.style.display = "flex";
+        this.activePanelTitle.textContent = this.activePanel.name;
+
+        //Call panel initialization function
+        this.activePanel.panelDocument = this.activePanelDoc;
+        this.activePanel.docSwitch();
+    }
+
+    /**
+     * Hides active panel
+     * @param {Event} event - Event passed down from Input Handler
+     * @param {Boolean} keepAlive - Prevents closing panel if true
+     */
+    hideActivePanel(event, keepAlive = false){
+        if(!keepAlive){
+            this.activePanel.closer();
+        }
+
+        //Hide the panel
+        this.activePanelDiv.style.display = "none";
+        //Clear out the panel
+        this.activePanelDoc.innerHTML = '';
+        //Set active panel to null
+        this.activePanel = null;
+    }
+
+    /**
+     * Pins active panel
+     */
+    pinPanel(){
+        this.setPinnedPanel(this.activePanel, this.activePanelDoc.innerHTML);
+        this.hideActivePanel(null, true);
+    }
+
+    /**
+     * Pop's out active panel
+     */
+    popActivePanel(){
+        this.popPanel(this.activePanel, this.activePanelDoc.innerHTML);
+        this.hideActivePanel(null, true);
+    }
+
+    /**
+     * Sets pinned panel
+     * @param {panelObj} panel - Panel Object to apply to panel
+     * @param {String} panelBody - Raw HTML to inject into panel body, defaults to panel page if null
+     */
+    async setPinnedPanel(panel, panelBody){
+        //Set pinned panel
+        this.pinnedPanel = panel;
+
+        //Set Title
+        this.pinnedPanelTitle.textContent = this.pinnedPanel.name;
+
+        //Grab panel hypertext content and load it into div
+        this.pinnedPanelDoc.innerHTML = (panelBody == null || panelBody == "") ? await this.pinnedPanel.getPage() : panelBody;
+
+        //Display panel
+        this.pinnedPanelDiv.style.display = "flex";
+
+        //Call panel initialization function
+        this.pinnedPanel.panelDocument = this.pinnedPanelDoc;
+        this.pinnedPanel.docSwitch();
+
+        //Resize to window/content
+        this.pinnedPanelDragger.fixCutoff();
+    }
+
+    /**
+     * Hides pinned panel
+     * @param {Event} event - Passed down input event
+     * @param {Boolean} keepAlive - Prevents panel.closer() from running if true
+     */
+    hidePinnedPanel(event, keepAlive = false){
+        this.pinnedPanelDiv.style.display = "none";
+
+        if(!keepAlive){
+            this.pinnedPanel.closer();
+        }
+
+        this.pinnedPanel = null;
+    }
+
+    /**
+     * Sets pinned panel to active
+     */
+    unpinPanel(){
+        this.setActivePanel(this.pinnedPanel, this.pinnedPanelDoc.innerHTML);
+        this.hidePinnedPanel(null, true);
+    }
+
+    /**
+     * Pops pinned panel
+     */
+    popPinnedPanel(){
+        this.popPanel(this.pinnedPanel, this.pinnedPanelDoc.innerHTML);
+        this.hidePinnedPanel(null, true);
+    }
+
+    /**
+     * Pops a new pop-out panel
+     * @param {panelObj} panel - panelObj to apply to the panel
+     * @param {String} panelBody - Raw HTML to inject into panel body, injects panel default if left to null
+     */
+    popPanel(panel, panelBody){
+        var newPanel = new poppedPanel(panel, panelBody, this)
+
+        this.poppedPanels.push(newPanel);
+    }
+
+}
+
+/**
+ * Template Class for other Classes for Objects which represent a single Canopy Panel
+ */
+class panelObj{
+    /**
+     * Instantiates a new Panel Object
+     * @param {channel} client - Parent client Management Object
+     * @param {String} name - Panel Name
+     * @param {String} pageURL - Panel Default Page URL
+     * @param {Document} panelDocument - Panel Document
+     */
+    constructor(client, name = "Placeholder Panel", pageURL = "/panel/placeholder", panelDocument = window.document){
+        /**
+         * Panel Name
+         */
+        this.name = name;
+
+        /**
+         * Panel Default Page URL
+         */
+        this.pageURL = pageURL;
+
+        /**
+         * Panel Document
+         */
+        this.panelDocument = panelDocument;
+
+        /**
+         * Current root document panel doc lives within
+         */
+        this.ownerDoc = this.panelDocument.ownerDocument == null ? this.panelDocument : this.panelDocument.ownerDocument; 
+
+        /**
+         * Parent Client Management object
+         */
+        this.client = client;
+    }
+
+    /**
+     * Fetches panel page from the server
+     * @returns {String} Raw panel doc HTML
+     */
+    async getPage(){
+        var response = await fetch(this.pageURL,{
+            method: "GET",
+        });
+
+        return await response.text();
+    }
+
+    /**
+     * Handles Document/Panel Changes
+     */
+    docSwitch(){
+        //Set owner doc
+        this.ownerDoc = this.panelDocument.ownerDocument == null ? this.panelDocument : this.panelDocument.ownerDocument; 
+    }
+
+    /**
+     * Called upon panel close/exit
+     */
+    closer(){
+    }
+}
+
+/**
+ * Class which represents a single instance of a popped-out panel
+ */
+class poppedPanel{
+    /**
+     * Instantiates a new Popped Panel Object
+     * @param {panelObj} panel - Panel Object to apply to Popped Panel
+     * @param {String} panelBody - Raw HTML to inject into panel body, defaults to panel page if null
+     * @param {cPanel} cPanel - Parent Canopy Panel Management Object
+     */
+    constructor(panel, panelBody, cPanel){
+        /**
+         * Panel Object to apply to Popped Panel
+         */
+        this.panel = panel;
+
+        /**
+         * Raw HTML to inject into panel body, defaults to panel page if null
+         */
+        this.panelBody = panelBody;
+
+        /**
+         * Browser Window taken up by the Popped Panel
+         */
+        this.window = null;
+
+        /**
+         * Popped Panel Container Div
+         */
+        this.pinnedPanelDiv = null;
+
+        /**
+         * Popped Panel Title
+         */
+        this.pinnedPanelTitle = null;
+
+        /**
+         * Popped Panel Document Div
+         */
+        this.pinnedPanelDoc = null;
+
+        /**
+         * Popped Panel Close Icon
+         */
+        this.pinnedPanelCloseIcon = null;
+
+        /**
+         * Parent Canopy Panel Management Object
+         */
+        this.cPanel = cPanel;
+
+        /**
+         * Disables this.panel.closer() calls from this.closer()
+         */
+        this.keepAlive = false;
+
+        //Continue constructor asynchrnously
+        this.asyncConstructor();
+    }
+
+    /**
+     * Continuation of constructor method for asynchronous function calls
+     */
+    async asyncConstructor(){
+        //Set panel body properly
+        this.panelBody = (this.panelBody == null || this.panelBody == "") ? await this.panel.getPage() : this.panelBody;
+
+        //Pop the panel
+        this.popContainer();
+    }
+
+    /**
+     * Pops/Opens container window upon start
+     */
+    popContainer(){
+        //Set Window Object
+        this.window = window.open("/panel/popoutContainer","",`menubar=no,height=850,width=600`);
+        this.window.addEventListener("load", this.fillContainer.bind(this)); 
+    }
+
+    /**
+     * Fills container window with Popped Panel container elements
+     */
+    fillContainer(){
+        //Set Element Nodes
+        this.panelDiv = this.window.document.querySelector("#cpanel-div");
+        this.panelTitle = this.window.document.querySelector("#cpanel-title");
+        this.panelDoc = this.window.document.querySelector("#cpanel-doc");
+        this.panelPopinIcon = this.window.document.querySelector("#cpanel-popin-icon");
+        this.panelPinIcon = this.window.document.querySelector("#cpanel-pin-icon");
+
+        //Set Window Title
+        this.window.document.title = this.window.document.title.replace("NULL_POPOUT", `${this.panel.name} (${client.channelName})`);
+
+        //Set Panel Content
+        this.panelTitle.innerText = this.panel.name;
+        this.panelDoc.innerHTML = this.panelBody;
+
+        //Set panel object document and call the related function
+        this.panel.panelDocument = this.window.document;
+        this.panel.docSwitch();
+
+        this.setupInput();
+    }
+
+    /**
+     * Defines default input-related popped-panel Event Listeners
+     */
+    setupInput(){
+        this.panelPopinIcon.addEventListener("click", this.unpop.bind(this));
+        this.panelPinIcon.addEventListener("click", this.pin.bind(this));
+        this.window.addEventListener("unload", this.closer.bind(this));
+    }
+
+    /**
+     * Called upon close/exit of panel
+     */
+    closer(){
+        if(!this.keepAlive){
+            this.panel.closer();
+        }
+
+        this.cPanel.poppedPanels.splice(this.cPanel.poppedPanels.indexOf(this),1);
+    }
+
+    /**
+     * Un-pops panel into active-panel slot
+     */
+    unpop(){
+        //Set active panel
+        this.cPanel.setActivePanel(this.panel, this.panelDoc.innerHTML);
+
+        this.keepAlive = true;
+
+        //Close the popped window
+        this.window.close();
+    }
+
+    /**
+     * Pins panel next to chat
+     */
+    pin(){
+        this.cPanel.setPinnedPanel(this.panel, this.panelDoc.innerHTML);
+
+        this.keepAlive = true;
+
+        this.window.close();
+    }
+
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/client/global.html b/www/doc/client/global.html index d122a61..281baf5 100644 --- a/www/doc/client/global.html +++ b/www/doc/client/global.html @@ -202,13 +202,13 @@
diff --git a/www/doc/client/hlsBase.html b/www/doc/client/hlsBase.html new file mode 100644 index 0000000..570794e --- /dev/null +++ b/www/doc/client/hlsBase.html @@ -0,0 +1,2928 @@ + + + + + JSDoc: Class: hlsBase + + + + + + + + + + +
+ +

Class: hlsBase

+ + + + + + +
+ +
+ +

hlsBase(client, player, media, type)

+ +
Base HLS Media handler for handling all HLS related media
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new hlsBase(client, player, media, type)

+ + + + + + +
+ Instantiates a new HLS Base object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent Client Management Object
player + + +player + + + + Parent Canopy Player Object
media + + +Object + + + + De-hydrated media object from server
type + + +String + + + + Media Handler Source Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player

+ + + + +
+ Parent Canopy Player Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

type

+ + + + +
+ Media Handler Source Type +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

buildPlayer()

+ + + + + + +
+ Builds video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners()

+ + + + + + +
+ Defines input-related event listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

destroyPlayer()

+ + + + + + +
+ Destroys video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles media end +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates Aspect Ratio of media +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Aspect Ratio as Floating Point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getTimestamp() → {Number}

+ + + + + + +
+ Gets current timestamp from video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Timestamp in seconds +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

ingestMedia(media) → {Boolean}

+ + + + + + +
+ Ingests media object from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from the server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True upon success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

onBuffer(event)

+ + + + + + +
+ Called on media buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onMetadataLoad(event)

+ + + + + + +
+ Called once all video metadata has properly been fetched +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onPause(event)

+ + + + + + +
+ Called on media pause +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onSeek(event)

+ + + + + + +
+ Called on media seek +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onVolumeChange(event)

+ + + + + + +
+ Called on media volume change +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pause()

+ + + + + + +
+ Pauses video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

play()

+ + + + + + +
+ Plays video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads media player +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setPlayerLock(lock)

+ + + + + + +
+ Toggles player control lockout +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
lock + + +Boolean + + + + Whether or not to lock-out user control of video
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setVideoTitle(title)

+ + + + + + +
+ Sets player title +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Title to set
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start()

+ + + + + + +
+ Starts video playback +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

startMedia(media)

+ + + + + + +
+ Ingests media nd starts playback +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(timestamp)

+ + + + + + +
+ Syncronizes timestamp based on timestamp received from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
timestamp + + +Number + + + + Current video timestamp in seconds
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/hlsLiveStreamHandler.html b/www/doc/client/hlsLiveStreamHandler.html new file mode 100644 index 0000000..be4378b --- /dev/null +++ b/www/doc/client/hlsLiveStreamHandler.html @@ -0,0 +1,2905 @@ + + + + + JSDoc: Class: hlsLiveStreamHandler + + + + + + + + + + +
+ +

Class: hlsLiveStreamHandler

+ + + + + + +
+ +
+ +

hlsLiveStreamHandler(client, player, media)

+ +
HLS Livestream Handler
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new hlsLiveStreamHandler(client, player, media)

+ + + + + + +
+ Instantiates a new HLS Live Stream Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent Client Management Object
player + + +player + + + + Parent Canopy Player Object
media + + +Object + + + + De-hydrated media object from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player

+ + + + +
+ Parent Canopy Player Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

type

+ + + + +
+ Media Handler Source Type +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

buildPlayer()

+ + + + + + +
+ Builds video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners()

+ + + + + + +
+ Defines input-related event listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

destroyPlayer()

+ + + + + + +
+ Destroys video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles media end +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates Aspect Ratio of media +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Aspect Ratio as Floating Point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getTimestamp() → {Number}

+ + + + + + +
+ Gets current timestamp from video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Timestamp in seconds +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

ingestMedia(media) → {Boolean}

+ + + + + + +
+ Ingests media object from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from the server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True upon success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

onBuffer(event)

+ + + + + + +
+ Called on media buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onMetadataLoad(event)

+ + + + + + +
+ Called once all video metadata has properly been fetched +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onPause(event)

+ + + + + + +
+ Called on media pause +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onSeek(event)

+ + + + + + +
+ Called on media seek +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onVolumeChange(event)

+ + + + + + +
+ Called on media volume change +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pause()

+ + + + + + +
+ Pauses video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

play()

+ + + + + + +
+ Plays video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads media player +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setPlayerLock(lock)

+ + + + + + +
+ Toggles player control lockout +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
lock + + +Boolean + + + + Whether or not to lock-out user control of video
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setVideoTitle(title)

+ + + + + + +
+ Sets player title +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Title to set
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start()

+ + + + + + +
+ Starts video playback +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

startMedia(media)

+ + + + + + +
+ Ingests media nd starts playback +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(timestamp)

+ + + + + + +
+ Syncronizes timestamp based on timestamp received from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
timestamp + + +Number + + + + Current video timestamp in seconds
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/index.html b/www/doc/client/index.html index c5f5bb4..eefcca4 100644 --- a/www/doc/client/index.html +++ b/www/doc/client/index.html @@ -81,13 +81,13 @@ This new codebase intends to solve the following issues with the current CyTube
diff --git a/www/doc/client/mediaHandler.html b/www/doc/client/mediaHandler.html new file mode 100644 index 0000000..64a1729 --- /dev/null +++ b/www/doc/client/mediaHandler.html @@ -0,0 +1,2710 @@ + + + + + JSDoc: Class: mediaHandler + + + + + + + + + + +
+ +

Class: mediaHandler

+ + + + + + +
+ +
+ +

mediaHandler(client, player, media, type)

+ + +
+ +
+
+ + + + + + +

new mediaHandler(client, player, media, type)

+ + + + + + +
+ Instantiates a new Media Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent Client Management Object
player + + +player + + + + Parent Canopy Player Object
media + + +Object + + + + De-hydrated media object from server
type + + +String + + + + Media Handler Source Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player

+ + + + +
+ Parent Canopy Player Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

type

+ + + + +
+ Media Handler Source Type +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

buildPlayer()

+ + + + + + +
+ Builds video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

destroyPlayer()

+ + + + + + +
+ Destroys video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles media end +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates Aspect Ratio of media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Aspect Ratio as Floating Point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getTimestamp() → {Number}

+ + + + + + +
+ Gets current timestamp from video +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Timestamp in seconds +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

ingestMedia(media) → {Boolean}

+ + + + + + +
+ Ingests media object from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True upon success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

onBuffer(event)

+ + + + + + +
+ Called on media buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onMetadataLoad(event)

+ + + + + + +
+ Called once all video metadata has properly been fetched +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onPause(event)

+ + + + + + +
+ Called on media pause +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onSeek(event)

+ + + + + + +
+ Called on media seek +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onVolumeChange(event)

+ + + + + + +
+ Called on media volume change +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pause()

+ + + + + + +
+ Pauses video +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

play()

+ + + + + + +
+ Plays video +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads media player +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setPlayerLock(lock)

+ + + + + + +
+ Toggles player control lockout +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
lock + + +Boolean + + + + Whether or not to lock-out user control of video
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setVideoTitle(title)

+ + + + + + +
+ Sets player title +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Title to set
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start()

+ + + + + + +
+ Starts video playback +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

startMedia(media)

+ + + + + + +
+ Ingests media nd starts playback +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(timestamp)

+ + + + + + +
+ Syncronizes timestamp based on timestamp received from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
timestamp + + +Number + + + + Current video timestamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/mediaHandler.js.html b/www/doc/client/mediaHandler.js.html new file mode 100644 index 0000000..d1d7982 --- /dev/null +++ b/www/doc/client/mediaHandler.js.html @@ -0,0 +1,844 @@ + + + + + JSDoc: Source: mediaHandler.js + + + + + + + + + + +
+ +

Source: mediaHandler.js

+ + + + + + +
+
+
/*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/>.*/
+
+/*
+ * Base class for all Canopy Media Handlers
+ *
+ * This is little more than a interface class
+ */
+class mediaHandler{ 
+    /**
+     * Instantiates a new Media Handler object
+     * @param {channel} client - Parent Client Management Object
+     * @param {player} player  - Parent Canopy Player Object
+     * @param {Object} media - De-hydrated media object from server
+     * @param {String} type - Media Handler Source Type
+     */
+    constructor(client, player, media, type){
+        /**
+         * Parent Client Management Object
+         */
+        this.client = client;
+
+        /**
+         * Parent Canopy Player Object
+         */
+        this.player = player;
+
+        /**
+         * Media Handler Source Type
+         */
+        this.type = type
+
+        /*
+         * Denotes wether a seek call was made by the syncing function
+         */
+        this.selfAct = false;
+
+        /*
+         * Contains the last received time stamp
+         */
+        this.lastTimestamp = 0;
+
+        //Ingest media object from server
+        this.startMedia(media);
+    }
+
+    /**
+     * Ingests media nd starts playback
+     * @param {Object} media - Media object from server
+     */
+    startMedia(media){
+        //If we properly ingested the media
+        if(this.ingestMedia(media)){
+            //Build the video player
+            this.buildPlayer();
+
+            //Call the start function
+            this.start();
+        }
+    }
+
+    /**
+     * Builds video player element
+     */
+    buildPlayer(){
+        //Reset player lock
+        this.lock = false;
+    }
+
+    /**
+     * Destroys video player element
+     */
+    destroyPlayer(){
+        //Null out video property
+        this.video = null;
+    }
+
+    /**
+     * Ingests media object from server
+     * @param {Object} media - Media object from the server
+     * @returns {Boolean} True upon success
+     */
+    ingestMedia(media){
+        //Set now playing
+        this.nowPlaying = media;
+        
+        //return true to signify success
+        return true;
+    }
+
+    /**
+     * Starts video playback
+     */
+    start(){
+        this.setVideoTitle(this.nowPlaying.title);
+    }
+
+    /**
+     * Syncronizes timestamp based on timestamp received from server
+     * @param {Number} timestamp - Current video timestamp in seconds
+     */
+    sync(timestamp = this.lastTimestamp){
+        //Skip sync calls that won't seek so we don't pointlessly throw selfAct
+        if(timestamp != this.video.currentTime){
+            //Set self act flag
+            this.selfAct = true;
+        }
+    }
+
+    /**
+     * Reloads media player
+     */
+    reload(){
+        //Get current timestamp
+        const timestamp = this.video.currentTime;
+
+        //Throw self act flag to make sure we don't un-sync the player
+        this.selfAct = true;
+    }
+
+    /**
+     * Handles media end
+     */
+    end(){
+        //Null out current media
+        this.nowPlaying = null;
+
+        //Throw self act to prevent unlock on video end
+        this.selfAct = true;
+
+        //Destroy the player
+        this.destroyPlayer();
+    }
+
+    /**
+     * Plays video
+     */
+    play(){
+    }
+
+    /**
+     * Pauses video
+     */
+    pause(){
+    }
+
+    /**
+     * Toggles player control lockout
+     * @param {Boolean} lock - Whether or not to lock-out user control of video
+     */
+    setPlayerLock(lock){
+        //set lock property
+        this.lock = lock;
+    }
+
+    /**
+     * Calculates Aspect Ratio of media
+     * @returns {Number} Media Aspect Ratio as Floating Point number
+     */
+    getRatio(){
+        return 4/3;
+    } 
+
+    /**
+     * Gets current timestamp from video
+     * @returns {Number} Media Timestamp in seconds
+     */
+    getTimestamp(){
+        return 0;
+    }
+
+    /**
+     * Sets player title
+     * @param {String} title - Title to set
+     */
+    setVideoTitle(title){
+        this.player.title.textContent = `Currently Playing: ${title}`;
+    }
+
+    /**
+     * Called once all video metadata has properly been fetched
+     * @param {Event} event - Event passed down by event handler
+     */
+    onMetadataLoad(event){
+        //Resize aspect (if locked), since the video doesn't properly report it's resolution until it's been loaded
+        this.client.chatBox.resizeAspect();
+    }
+
+    /**
+     * Called on media pause
+     * @param {Event} event - Event passed down by event handler
+     */
+    onPause(event){
+        //If the video was paused out-side of code
+        if(!this.selfAct){
+            this.player.unlockSync();
+        }
+
+        this.selfAct = false;
+    }
+
+    /**
+     * Called on media volume change
+     * @param {Event} event - Event passed down by event handler
+     */
+    onVolumeChange(event){
+    }
+
+    /**
+     * Called on media seek
+     * @param {Event} event - Event passed down by event handler
+     */
+    onSeek(event){
+        //If the video was seeked out-side of code
+        if(!this.selfAct){
+            this.player.unlockSync();
+        }
+
+        //reset self act flag
+        this.selfAct = false;
+    }
+
+    /**
+     * Called on media buffer
+     * @param {Event} event - Event passed down by event handler
+     */
+    onBuffer(){
+        this.selfAct = true;
+    }
+}
+
+/**
+ * Class containing basic building blocks for anything that touches a <video> tag
+ * @extends mediaHandler
+ */
+class rawFileBase extends mediaHandler{
+    /**
+     * Instantiates a new rawFileBase object
+     * @param {channel} client - Parent Client Management Object
+     * @param {player} player  - Parent Canopy Player Object
+     * @param {Object} media - De-hydrated media object from server
+     * @param {String} type - Media Handler Source Type
+     */
+    constructor(client, player, media, type){
+        super(client, player, media, type);
+    }
+
+    /**
+     * Defines input-related event listeners
+     */
+    defineListeners(){
+        //Resize to aspect on metadata load
+        this.video.addEventListener('loadedmetadata', this.onMetadataLoad.bind(this));
+        this.video.addEventListener('volumechange', this.onVolumeChange.bind(this));
+    }
+
+    buildPlayer(){
+        //Create player
+        this.video = document.createElement('video');
+
+        //Enable controls
+        this.video.controls = true;
+
+        //Append it to page
+        this.player.videoContainer.appendChild(this.video);
+
+        //Run derived method
+        super.buildPlayer();
+    }
+
+    destroyPlayer(){
+        //Stops playback
+        this.video.pause();
+        //Remove player from page
+        this.video.remove();
+        //Run derived method
+        super.destroyPlayer();
+    }
+
+    reload(){
+        //Call derived method
+        super.reload();
+
+        //Load video from source
+        this.video.load();
+
+        //Set it back to the proper time
+        this.video.currentTime = this.lastTimestamp;
+
+        //Play the video
+        this.video.play();
+    }
+
+    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;
+
+            //Run derived method
+            super.setPlayerLock(lock);
+    }
+
+    getRatio(){
+        return this.video.videoWidth / this.video.videoHeight;
+    } 
+
+    onVolumeChange(event){
+        //Pull volume from video
+        this.player.volume = this.video.volume;
+    }
+}
+
+/** 
+ * Off air static 'player'
+ * @extends rawFileBase
+ */
+class nullHandler extends rawFileBase{
+    /**
+     * Instantiates a new Null Handler object
+     * @param {channel} client - Parent Client Management Object
+     * @param {player} player  - Parent Canopy Player Object
+     */
+    constructor(client, player){
+        //Call derived constructor
+        super(client, player, {}, null);
+
+        this.defineListeners();
+    }
+
+    defineListeners(){
+        //Run derived method
+        super.defineListeners();
+
+        //Disable right clicking
+        this.video.addEventListener('contextmenu', (e)=>{e.preventDefault()});
+    }
+
+    start(){
+        //call derived start function
+        super.start();        
+
+        //Lock the player
+        this.setPlayerLock(true);
+
+        //Set the static placeholder
+        this.video.src = '/video/static.webm';
+
+        //play the placeholder video
+        this.video.play();
+    }
+
+    setVideoTitle(title){
+        this.player.title.textContent = `Channel Off Air`;
+    }
+}
+
+/**
+ * Basic building blocks needed for proper time-synchronized raw-file playback
+ * @extends rawFileBase
+ */
+class rawFileHandler extends rawFileBase{
+    /**
+     * Instantiates a new Null Handler object
+     * @param {channel} client - Parent Client Management Object
+     * @param {player} player  - Parent Canopy Player Object
+     * @param {Object} media - De-hydrated media object from server
+     */
+    constructor(client, player, media){
+        //Call derived constructor
+        super(client, player, media, 'raw');
+
+        //Define listeners
+        this.defineListeners();
+    }
+
+    defineListeners(){
+        //Run derived method
+        super.defineListeners();
+
+        this.video.addEventListener('pause', this.onPause.bind(this));
+        this.video.addEventListener('seeked', this.onSeek.bind(this));
+        this.video.addEventListener('waiting', this.onBuffer.bind(this));
+    }
+
+    start(){
+        //Call derived start
+        super.start();
+
+        //Set video
+        this.video.src = this.nowPlaying.rawLink;
+
+        //Set video volume
+        this.video.volume = this.player.volume;
+
+        //Unlock player
+        this.setPlayerLock(false);
+
+        //play video
+        this.video.play();
+    }
+
+    play(){
+        this.video.play();
+    }
+
+    pause(){
+        this.video.pause();
+    }
+
+    sync(timestamp = this.lastTimestamp){
+        //Call derived sync
+        super.sync(timestamp);
+
+        //Skip sync calls that won't seek so we don't pointlessly throw selfAct
+        if(timestamp != this.video.currentTime){
+            //Set current video time based on timestamp received from server
+            this.video.currentTime = timestamp;
+        }
+    }
+
+    getTimestamp(){
+        //Return current timestamp
+        return this.video.currentTime;
+    }
+}
+
+/**
+ * Handles Youtube playback via the official YT embed (gross)
+ * @extends mediaHandler
+ */
+class youtubeEmbedHandler extends mediaHandler{
+    /**
+     * Instantiates a new  Youtube Embed Handler object
+     * @param {channel} client - Parent Client Management Object
+     * @param {player} player  - Parent Canopy Player Object
+     * @param {Object} media - De-hydrated media object from server
+     */
+    constructor(client, player, media){
+        //Call derived constructor
+        super(client, player, media, 'ytEmbed');
+
+        //Set flag to notify functions when the player is actually ready
+        this.ready = false;
+
+        //Create property to hold video iframe for easy access
+        this.iframe = null;
+    }
+
+    //custom start media function since we want the youtube player to call the start function once it's ready
+    startMedia(media){
+        //If we properly ingested the media
+        if(this.ingestMedia(media)){
+            //Build the video player
+            this.buildPlayer();
+        }
+    }
+
+    buildPlayer(){
+        //If the embed API hasn't loaded
+        if(!this.client.ytEmbedAPILoaded){
+            //Complain and stop
+            return console.warn("youtubeEmbedHandler.buildPlayer() Called before YT Iframe API Loaded, waiting on refresh to rebuild...");
+        }
+
+        //Create temp div for yt api to replace
+        const tempDiv = document.createElement('div');
+        //Name the div
+        tempDiv.id = "youtube-embed-player"
+        //Append it to the video container
+        this.player.videoContainer.appendChild(tempDiv);
+
+        //Create a new youtube player using the official YT iframe-embed api
+        this.video = new YT.Player('youtube-embed-player', {
+            //Inject video id
+            videoId: this.nowPlaying.id,
+            events: {
+                'onReady': this.start.bind(this),
+                'onStateChange': this.onStateChange.bind(this)
+            }
+        }); 
+
+        //Call derived function
+        super.buildPlayer();
+    }
+
+    start(){
+        //Call derived start function
+        super.start();
+
+        //Set volume based on player volume
+        this.video.setVolume(this.player.volume * 100);
+
+        //Kick the video off
+        this.video.playVideo();
+
+        //Pull iframe
+        this.iframe = this.video.getIframe()
+
+        //Throw the ready flag
+        this.ready = true;
+    }
+
+    destroyPlayer(){
+        //If we've had enough time to create a player frame
+        if(this.ready){
+            //Pull volume from player before destroying since google didn't give us a volume change event like a bunch of dicks
+            this.player.volume = (this.video.getVolume() / 100);
+
+            //Use the embed api's built in destroy function
+            this.video.destroy();
+        }
+
+        //Check the f̶r̶i̶d̶g̶e video container for leftovers
+        const leftovers = this.player.videoContainer.querySelector("#youtube-embed-player");
+
+        //If we have any leftovers
+        if(leftovers != null){
+            //Nukem like last nights chicken
+            leftovers.remove();
+        }
+
+        //Call derived destroy function
+        super.destroyPlayer();
+    }
+
+    sync(timestamp = this.lastTimestamp){
+        //If we're not ready
+        if(!this.ready){
+            //Kick off a timer to wait it out and try again l8r
+            setTimeout(this.sync.bind(this), 100);
+
+            //If it failed, tell randy to fuck off
+            return;
+        }
+
+        //Seek to timestamp, allow buffering
+        this.video.seekTo(timestamp, true);
+    }
+
+    reload(){
+        //if we're ready
+        if(this.ready){
+            //re-load the video by id
+            this.video.loadVideoById(this.nowPlaying.id);
+        }
+    }
+
+    play(){
+        //If we're ready
+        if(this.ready){
+            //play the video
+            this.video.playVideo();
+        }
+    }
+
+    pause(){
+        //If we're ready
+        if(this.ready){
+            //pause the video
+            this.video.pauseVideo();
+        }
+    }
+
+    getRatio(){
+        //TODO: Implement a type-specific metadata property object in the media class to hold type-sepecifc meta-data
+        //Alternatively we could fill in resolution information from the raw link 
+        //However keeping embedded functionality dependant on raw-links seems like bad practice
+    }
+
+    getTimestamp(){
+        //If we're ready
+        if(this.ready){
+            //Return the timestamp
+            return this.video.getCurrentTime();
+        }
+        
+        //If we fall through, simply report that the video hasn't gone anywhere yet
+        return 0;
+    }
+
+    setVideoTitle(){
+        //Clear out the player title so that youtube's baked in title can do it's thing.
+        //This will be replaced once we complete the full player control and remove the defualt youtube UI
+        this.player.title.textContent = "";
+    }
+
+    /**
+     * Generic handler for state changes since google is a dick
+     */
+    onStateChange(event){
+        switch(event.data){
+            //video unstarted
+            case -1:
+                return;
+            //video ended
+            case 0:
+                return;
+            //video playing
+            case 1:
+                return;
+            //video paused
+            case 2:
+                super.onPause(event);
+                return;
+            //video buffering
+            case 3:
+                //There is no good way to tell slow connections apart from user seeking
+                //This will be easier to implement once we get custom player controls up
+                //super.onSeek(event);
+                return;
+            //video queued
+            case 5:
+                return;
+            //bad status code
+            default:
+                return;
+        }
+    }
+
+    setPlayerLock(lock){
+        super.setPlayerLock(lock);
+
+        if(this.ready){
+            this.iframe.style.pointerEvents = (lock ? "none" : "");
+        }
+    }
+}
+
+/**
+ * Base HLS Media handler for handling all HLS related media
+ * @extends rawFileBase
+ */
+class hlsBase extends rawFileBase{
+    /**
+     * Instantiates a new HLS Base object
+     * @param {channel} client - Parent Client Management Object
+     * @param {player} player - Parent Canopy Player Object
+     * @param {Object} media - De-hydrated media object from server
+     * @param {String} type - Media Handler Source Type
+     */
+    constructor(client, player, media, type){
+        //Call derived constructor
+        super(client, player, media, type);
+    }
+
+    buildPlayer(){
+        //Call derived buildPlayer function
+        super.buildPlayer();
+
+        //Instantiate HLS object
+        this.hls = new Hls();
+
+        //Load HLS Stream
+        this.hls.loadSource(this.nowPlaying.url);
+
+        //Attatch hls object to video element
+        this.hls.attachMedia(this.video);
+
+        //Bind onMetadataLoad to MANIFEST_PARSED
+        this.hls.on(Hls.Events.MANIFEST_PARSED, this.onMetadataLoad.bind(this));
+    }
+
+    end(){
+        //Stop hls.js from loading any more of the stream
+        this.hls.stopLoad();
+
+        //Call derived method
+        super.end();
+    }
+
+    onMetadataLoad(){
+        //Call derived method
+        super.onMetadataLoad();
+    }
+
+    start(){
+        //Call derived method
+        super.start();
+
+        //Start the video
+        this.video.play();
+    }
+}
+
+/**
+ * HLS Livestream Handler
+ * @extends hlsBase
+ */
+class hlsLiveStreamHandler extends hlsBase{
+    /**
+     * Instantiates a new HLS Live Stream Handler object
+     * @param {channel} client - Parent Client Management Object
+     * @param {player} player - Parent Canopy Player Object
+     * @param {Object} media - De-hydrated media object from server
+     */
+    constructor(client, player, media){
+        //Call derived constructor
+        super(client, player, media, "livehls");
+
+        //Create variable to determine if we need to resync after next seek
+        this.reSync = false;
+
+        this.video.addEventListener('pause', this.onPause.bind(this));
+        this.video.addEventListener('seeked', this.onSeek.bind(this));
+        this.video.addEventListener('waiting', this.onBuffer.bind(this));
+    }
+
+    sync(){
+        //Kick the video back on if it was paused
+        this.video.play();
+
+        //Pull video duration
+        const duration = this.video.duration;
+
+        //Ignore bad timestamps
+        if(duration > 0){
+            //Seek to the end to sync up w/ the livestream
+            this.video.currentTime = duration;
+        }
+    }
+
+    setVideoTitle(title){
+        //Add title as text content for security :P
+        this.player.title.textContent = `: ${title}`;
+
+        //Create glow span
+        const glowSpan = document.createElement('span');
+        //Fill glow span content
+        glowSpan.textContent = "🔴LIVE";
+        //Set glowspan class
+        glowSpan.classList.add('critical-danger-text');
+
+        //Inject glowspan into title in a way that allows it to be easily replaced
+        this.player.title.prepend(glowSpan);
+    }
+
+    onBuffer(event){
+        //Call derived function
+        super.onBuffer(event);
+
+
+        //If we're synced by the end of buffering
+        if(this.player.syncLock){
+            //Throw flag to manually sync since this works entirely differently from literally every other fucking media source
+            this.reSync = true;
+        }
+    }
+
+    onSeek(event){
+        //Call derived method
+        super.onSeek(event);
+
+        //If we stopped playing the video
+        if(this.video == null){
+            //Don't worry about it
+            return;
+        }
+
+        //Calculate distance to end of stream
+        const difference = this.video.duration - this.video.currentTime;
+
+        //If we where buffering under sync lock
+        if(this.reSync){
+            //Set reSync to false
+            this.reSync = false;
+
+            //If the difference is bigger than streamSyncTolerance
+            if(difference > this.player.streamSyncTolerance){
+                //Sync manually since we have no timestamp, and therefore the player won't do it for us
+                this.sync();
+            }
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/client/nullHandler.html b/www/doc/client/nullHandler.html new file mode 100644 index 0000000..6f54084 --- /dev/null +++ b/www/doc/client/nullHandler.html @@ -0,0 +1,2882 @@ + + + + + JSDoc: Class: nullHandler + + + + + + + + + + +
+ +

Class: nullHandler

+ + + + + + +
+ +
+ +

nullHandler(client, player)

+ +
Off air static 'player'
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new nullHandler(client, player)

+ + + + + + +
+ Instantiates a new Null Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent Client Management Object
player + + +player + + + + Parent Canopy Player Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player

+ + + + +
+ Parent Canopy Player Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

type

+ + + + +
+ Media Handler Source Type +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

buildPlayer()

+ + + + + + +
+ Builds video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners()

+ + + + + + +
+ Defines input-related event listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

destroyPlayer()

+ + + + + + +
+ Destroys video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles media end +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates Aspect Ratio of media +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Aspect Ratio as Floating Point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getTimestamp() → {Number}

+ + + + + + +
+ Gets current timestamp from video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Timestamp in seconds +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

ingestMedia(media) → {Boolean}

+ + + + + + +
+ Ingests media object from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from the server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True upon success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

onBuffer(event)

+ + + + + + +
+ Called on media buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onMetadataLoad(event)

+ + + + + + +
+ Called once all video metadata has properly been fetched +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onPause(event)

+ + + + + + +
+ Called on media pause +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onSeek(event)

+ + + + + + +
+ Called on media seek +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onVolumeChange(event)

+ + + + + + +
+ Called on media volume change +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pause()

+ + + + + + +
+ Pauses video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

play()

+ + + + + + +
+ Plays video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads media player +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setPlayerLock(lock)

+ + + + + + +
+ Toggles player control lockout +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
lock + + +Boolean + + + + Whether or not to lock-out user control of video
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setVideoTitle(title)

+ + + + + + +
+ Sets player title +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Title to set
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start()

+ + + + + + +
+ Starts video playback +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

startMedia(media)

+ + + + + + +
+ Ingests media nd starts playback +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(timestamp)

+ + + + + + +
+ Syncronizes timestamp based on timestamp received from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
timestamp + + +Number + + + + Current video timestamp in seconds
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/panelObj.html b/www/doc/client/panelObj.html new file mode 100644 index 0000000..114225a --- /dev/null +++ b/www/doc/client/panelObj.html @@ -0,0 +1,918 @@ + + + + + JSDoc: Class: panelObj + + + + + + + + + + +
+ +

Class: panelObj

+ + + + + + +
+ +
+ +

panelObj(client, name, pageURL, panelDocument)

+ +
Template Class for other Classes for Objects which represent a single Canopy Panel
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new panelObj(client, name, pageURL, panelDocument)

+ + + + + + +
+ Instantiates a new Panel Object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
client + + +channel + + + + + + Parent client Management Object
name + + +String + + + + + + Placeholder Panel + + Panel Name
pageURL + + +String + + + + + + /panel/placeholder + + Panel Default Page URL
panelDocument + + +Document + + + + + + Panel Document
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

name

+ + + + +
+ Panel Name +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

ownerDoc

+ + + + +
+ Current root document panel doc lives within +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pageURL

+ + + + +
+ Panel Default Page URL +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

panelDocument

+ + + + +
+ Panel Document +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

closer()

+ + + + + + +
+ Called upon panel close/exit +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

docSwitch()

+ + + + + + +
+ Handles Document/Panel Changes +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getPage() → {String}

+ + + + + + +
+ Fetches panel page from the server +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Raw panel doc HTML +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/player.html b/www/doc/client/player.html new file mode 100644 index 0000000..e96c2d9 --- /dev/null +++ b/www/doc/client/player.html @@ -0,0 +1,3383 @@ + + + + + JSDoc: Class: player + + + + + + + + + + +
+ +

Class: player

+ + + + + + +
+ +
+ +

player(client)

+ +
Class which represents Canopy Player UX
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new player(client)

+ + + + + + +
+ Instantiates a new Canopy Player object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent client Management Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

cinemaModeIcon

+ + + + +
+ Player Cinema-Mode Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

client

+ + + + +
+ Parent CLient Management Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

flipXIcon

+ + + + +
+ Player Flip Video X Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

flipYIcon

+ + + + +
+ Player Filp Video Y Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hideVideoIcon

+ + + + +
+ Player Hide Video Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Page Nav-Par +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

onUI

+ + + + +
+ Whether or not the mouse cursor is floating over player UX +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

playerDiv

+ + + + +
+ Top-Level Player Container Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

reloadIcon

+ + + + +
+ Player Media Reload Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

showVideoIcon

+ + + + +
+ Player Show Video Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

streamSyncTolerance

+ + + + +
+ Tolerance in livestream delay before corrective seek to live. + +Might seem weird to keep this here instead of the HLS handler, but remember we may want to support other livestream services in the future... +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

syncDelta

+ + + + +
+ Forced time to wait between sync checks, heavily decreases chance of seek-banging without reducing syncornization accuracy +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

syncIcon

+ + + + +
+ Player Syncronization Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

syncLock

+ + + + +
+ Whether or not player scrub is locked to sync signal from the server +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

syncTolerance

+ + + + +
+ Tolerance between timestamp from server and actual media before corrective seek for pre-recorded media +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

title

+ + + + +
+ Player Title Label +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

uiBar

+ + + + +
+ Auto-Hiding Player UI +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

uiTimer

+ + + + +
+ Player UX Stow-Away timer +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

videoContainer

+ + + + +
+ Player Element Container Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

volume

+ + + + +
+ Current Player Volume +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

defineListeners()

+ + + + + + +
+ Define Network-Related Event Listeners for the player +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles End-Media Commands from the Server +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

flipX()

+ + + + + + +
+ Flips the video horizontally +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

flipY()

+ + + + + + +
+ Flips the video vertically +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates ratio of current media object +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Current media aspect ratio as a single floating point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

lockSync()

+ + + + + + +
+ Locks player seek to synced timestamp from the server +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

popUI(event)

+ + + + + + +
+ Displays UI after player-related input +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed through by event handler
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads the media player +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setOnUI(onUI)

+ + + + + + +
+ Informs the class when the user's mouse curosr enters and leaves the UI area +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
onUI + + +Boolean + + + + Whether or not onUI should be toggled true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setupInput()

+ + + + + + +
+ Defines Input-Related Event Listeners for the player +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start(data)

+ + + + + + +
+ Handles command from server to start media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Media Metadata from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(data)

+ + + + + + +
+ Handles synchronization command from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Syncrhonization Data from Server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

toggleCinemaMode(cinema)

+ + + + + + +
+ Toggles Cinema Mode on or off +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cinema + + +Boolean + + + + Whether or not to enter Cinema Mode. Defaults to toggle if left unspecified
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

toggleUI(show)

+ + + + + + +
+ Toggles UI-Bar on or off +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
show + + +Boolean + + + + Whether or not to show the UI-Bar. Defaults to toggle if left unspecified.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

toggleVideo(show)

+ + + + + + +
+ Toggles video on or off +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
show + + +Boolean + + + + Whether or not to show the video player. Defaults to toggle if left unspecified
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

unlockSync()

+ + + + + + +
+ Un-locks player seek to synced timestamp from the server +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateCurrentRawFile(data)

+ + + + + + +
+ Handles Raw-File Metadata Updates from the Server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Updadated Raw-File link from Server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/player.js.html b/www/doc/client/player.js.html new file mode 100644 index 0000000..25a1ace --- /dev/null +++ b/www/doc/client/player.js.html @@ -0,0 +1,483 @@ + + + + + JSDoc: Source: player.js + + + + + + + + + + +
+ +

Source: player.js

+ + + + + + +
+
+
/*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 which represents Canopy Player UX
+ */
+class player{
+    /**
+     * Instantiates a new Canopy Player object
+     * @param {channel} client - Parent client Management Object
+     */
+    constructor (client){
+        /**
+         * Parent CLient Management Object
+         */
+        this.client = client;
+
+        /**
+         * Whether or not the mouse cursor is floating over player UX
+         */
+        this.onUI = false;
+
+        /**
+         * Whether or not player scrub is locked to sync signal from the server
+         */
+        this.syncLock = true;
+        
+        /**
+         * Player UX Stow-Away timer
+         */
+        this.uiTimer = setTimeout(this.toggleUI.bind(this), 1500, false);
+
+        //elements
+        /**
+         * Top-Level Player Container Div
+         */
+        this.playerDiv = document.querySelector("#media-panel-div");
+
+        /**
+         * Player Element Container Div
+         */
+        this.videoContainer = document.querySelector("#media-panel-video-container")
+
+        /**
+         * Page Nav-Par
+         */
+        this.navBar = document.querySelector("#navbar");
+
+        /**
+         * Auto-Hiding Player UI
+         */
+        this.uiBar = document.querySelector("#media-panel-head-div");
+
+        /**
+         * Player Title Label
+         */
+        this.title = document.querySelector("#media-panel-title-paragraph");
+
+        /**
+         * Player Show Video Icon
+         */
+        this.showVideoIcon = document.querySelector("#chat-panel-show-video-icon");
+
+        /**
+         * Player Hide Video Icon
+         */
+        this.hideVideoIcon = document.querySelector("#media-panel-div-toggle-icon");
+
+        /**
+         * Player Syncronization Icon
+         */
+        this.syncIcon = document.querySelector("#media-panel-sync-icon");
+
+        /**
+         * Player Cinema-Mode Icon
+         */
+        this.cinemaModeIcon = document.querySelector("#media-panel-cinema-mode-icon");
+
+        /**
+         * Player Filp Video Y Icon
+         */
+        this.flipYIcon = document.querySelector("#media-panel-flip-vertical-icon")
+
+        /**
+         * Player Flip Video X Icon
+         */
+        this.flipXIcon = document.querySelector("#media-panel-flip-horizontal-icon")
+
+        /**
+         * Player Media Reload Icon
+         */
+        this.reloadIcon = document.querySelector("#media-panel-reload-icon");
+
+        /**
+         * Tolerance between timestamp from server and actual media before corrective seek for pre-recorded media
+         */
+        this.syncTolerance = 0.4;
+
+        /**
+         * Tolerance in livestream delay before corrective seek to live.
+         * 
+         * Might seem weird to keep this here instead of the HLS handler, but remember we may want to support other livestream services in the future...
+         */
+        this.streamSyncTolerance = 2;
+
+        /**
+         * Forced time to wait between sync checks, heavily decreases chance of seek-banging without reducing syncornization accuracy
+         */
+        this.syncDelta = 6;
+
+        /**
+         * Current Player Volume
+         */
+        this.volume = 1;
+
+        //run setup functions
+        this.setupInput();
+        this.defineListeners();
+    }
+
+    /**
+     * Defines Input-Related Event Listeners for the player
+     */
+    setupInput(){
+        //UIBar Movement Detection
+        this.playerDiv.addEventListener("mousemove", this.popUI.bind(this));
+        this.uiBar.addEventListener("mouseenter", ()=>{this.setOnUI(true)});
+        this.uiBar.addEventListener("mouseleave", ()=>{this.setOnUI(false)});
+
+        //UIBar/header icons
+        //Don't bind these, they want an argument that isn't an event :P
+        this.showVideoIcon.addEventListener("click", ()=>{this.toggleVideo()});
+        this.hideVideoIcon.addEventListener("click", ()=>{this.toggleVideo()});
+        this.syncIcon.addEventListener("click", this.lockSync.bind(this));
+        this.cinemaModeIcon.addEventListener("click", ()=>{this.toggleCinemaMode()});
+        this.flipYIcon.addEventListener('click', this.flipY.bind(this));
+        this.flipXIcon.addEventListener('click', this.flipX.bind(this));
+        this.reloadIcon.addEventListener("click", this.reload.bind(this));
+    }
+
+    /**
+     * Define Network-Related Event Listeners for the player
+     */
+    defineListeners(){
+        this.client.socket.on("start", this.start.bind(this));
+        this.client.socket.on("sync", this.sync.bind(this));
+        this.client.socket.on("end", this.end.bind(this));
+        this.client.socket.on("updateCurrentRawFile", this.updateCurrentRawFile.bind(this));
+    }
+
+    /**
+     * Handles command from server to start media
+     * @param {Object} data - Media Metadata from server
+     */
+    start(data){
+        //If we have an active media handler
+        if(this.mediaHandler != null){
+            //End the media handler
+            this.mediaHandler.end();
+        }
+
+        //Ignore null media
+        if(data.media == null){
+            //Set null handler
+            this.mediaHandler = new nullHandler(client, this);
+        //Otherwise
+        }else{
+            //If we have a youtube video and the official embedded iframe player is selected
+            if(data.media.type == 'yt' && localStorage.getItem("ytPlayerType") == 'embed'){
+                //Create a new yt handler for it
+                this.mediaHandler = new youtubeEmbedHandler(this.client, this, data.media);
+                //Sync to time stamp
+                this.mediaHandler.sync(data.timestamp);
+            //If we have an HLS Livestream
+            }else if(data.media.type == "livehls"){
+                //Create a new HLS Livestream Handler for it
+                this.mediaHandler = new hlsLiveStreamHandler(this.client, this, data.media);
+            }else if(data.media.type == 'dm'){
+                this.mediaHandler = new hlsDailymotionHandler(this.client, this, data.media);
+            //Otherwise, if we have a raw-file compatible source
+            }else if(data.media.type == 'ia' || data.media.type == 'raw' || data.media.type == 'yt' || data.media.type == 'dm'){
+                //Create a new raw file handler for it
+                this.mediaHandler = new rawFileHandler(client, this, data.media);
+                //Sync to time stamp
+                this.mediaHandler.sync(data.timestamp);   
+            }else{
+                this.mediaHandler = new nullHandler(client, this);
+            }
+        }
+
+        //Lock synchronization since everyone starts at 0, and update the UI
+        this.lockSync();
+
+        //Re-size to aspect since video may now be a different size
+        this.client.chatBox.resizeAspect();
+
+        //Sync off of starter time stamp
+        this.mediaHandler.sync(data.timestamp);
+    }
+
+    /**
+     * Handles synchronization command from server
+     * @param {Object} data - Syncrhonization Data from Server
+     */
+    sync(data){
+        if(this.mediaHandler != null){
+            //Get timestamp
+            const timestamp = data.timestamp;
+            //Get difference between server and local timestamp
+            const difference = Math.abs(timestamp - this.mediaHandler.getTimestamp());
+
+            //Check if timestamp evenly devides into sync delta, effectively only checking for sync every X seconds
+            //Check if the difference between timestamps is larger than the sync tolerance
+            //Lastly, check to make sure we have sync lock
+            if(timestamp % this.syncDelta == 0 && difference > this.syncTolerance && this.syncLock){
+                //If we need to sync, then sync the video!
+                this.mediaHandler.sync(timestamp);
+            }
+
+            //Collect last timestamp
+            this.mediaHandler.lastTimestamp = timestamp;
+        }
+    }
+
+    /**
+     * Reloads the media player
+     */
+    reload(){
+        if(this.mediaHandler != null){
+            this.mediaHandler.reload();
+        }
+    }
+
+    /**
+     * Handles End-Media Commands from the Server
+     */
+    end(){
+        //Call the media handler finisher
+        this.mediaHandler.end();
+
+        //Replace it with a null handler
+        this.mediaHandler = new nullHandler(client, this);
+
+        //Re-lock sync since we're probably gonna start new media soon anywho, and we need to update the UI anywho
+        this.lockSync();
+    }
+
+    /**
+     * Handles Raw-File Metadata Updates from the Server
+     * @param {Object} data - Updadated Raw-File link from Server
+     */
+    updateCurrentRawFile(data){
+        //typecheck the media handler to see if we really need to do any of this shit, if not...
+        if(this.mediaHandler.type == 'ytEmbed'){
+            //Ignore it
+            return;
+        }
+
+        //Grab current item from media handler
+        const currentItem = this.mediaHandler.nowPlaying;
+
+        //Update raw link
+        currentItem.rawLink = data.file;
+
+        //Re-start the item
+        this.start({media: currentItem});
+    }
+
+    /**
+     * Locks player seek to synced timestamp from the server
+     */
+    lockSync(){
+        //Enable syncing
+        this.syncLock = true;
+
+        if(this.mediaHandler != null && this.mediaHandler.type != null){
+            //Light up the sync icon to show that we're actively synchronized
+            this.syncIcon.classList.add('positive');
+
+            //Sync to last timestamp
+            this.mediaHandler.sync();
+
+            //Play
+            this.mediaHandler.play();
+        }else{
+            //Unlight the sync icon since there is nothing to sync
+            this.syncIcon.classList.remove('positive');
+        }
+    }
+
+    /**
+     * Un-locks player seek to synced timestamp from the server
+     */
+    unlockSync(){
+        //Unlight the sync icon since we're no longer actively synced
+        this.syncIcon.classList.remove('positive');
+
+        //Disable syncing
+        this.syncLock = false;
+    }
+
+    /**
+     * Flips the video horizontally
+     */
+    flipX(){
+        //I'm lazy
+        const transform = this.videoContainer.style.transform;
+
+        //If we we're specifically set to un-mirrored
+        if(transform.match("scaleX(1)")){
+            //mirror it
+            this.videoContainer.style.transfrom = transform.replace('scaleX(1)', 'scaleX(-1)');
+        //If we're currently mirrored
+        }else if(transform.match("scaleX(-1)")){
+            //Un-mirror
+            this.videoContainer.style.transfrom = transform.replace('scaleX(-1)', 'scaleX(1)');
+        //Otherwise, if it's untouched
+        }else{
+            //Mirror it
+            this.videoContainer.style.transform += 'scaleX(-1)';
+        }
+    }
+
+    /**
+     * Flips the video vertically
+     */
+    flipY(){
+        //I'm lazy
+        const transform = this.videoContainer.style.transform;
+
+        //If we we're specifically set to un-mirrored
+        if(transform.match("scaleY(1)")){
+            //mirror it
+            this.videoContainer.style.transfrom = transform.replace('scaleY(1)', 'scaleY(-1)');
+        //If we're currently mirrored
+        }else if(transform.match("scaleY(-1)")){
+            //Un-mirror
+            this.videoContainer.style.transfrom = transform.replace('scaleY(-1)', 'scaleY(1)');
+        //Otherwise, if it's untouched
+        }else{
+            //Mirror it
+            this.videoContainer.style.transform += 'scaleY(-1)';
+        }
+    }
+
+    /**
+     * Displays UI after player-related input
+     * @param {Event} event - Event passed through by event handler
+     */
+    popUI(event){
+        this.toggleUI(true);
+        clearTimeout(this.uiTimer);
+        if(!this.onUI){
+            this.uiTimer = setTimeout(this.toggleUI.bind(this), 1500, false);
+        }
+    }
+
+    /**
+     * Toggles UI-Bar on or off
+     * @param {Boolean} show - Whether or not to show the UI-Bar. Defaults to toggle if left unspecified.
+     */
+    toggleUI(show = this.uiBar.style.display == "none"){
+        this.uiBar.style.display = show ? "flex" : "none";
+    }
+
+    /**
+     * Toggles video on or off
+     * @param {Boolean} show - Whether or not to show the video player. Defaults to toggle if left unspecified
+     */
+    toggleVideo(show = !this.playerDiv.checkVisibility()){
+        if(show){
+            this.playerDiv.style.display = "flex";
+            this.showVideoIcon.style.display = "none";
+        }else{
+            this.playerDiv.style.display = "none";
+            this.showVideoIcon.style.display = "flex";
+        }
+
+        //Tell chatbox to handle this shit
+        this.client.chatBox.handleVideoToggle(show);
+    }
+
+    /**
+     * Toggles Cinema Mode on or off
+     * @param {Boolean} cinema - Whether or not to enter Cinema Mode. Defaults to toggle if left unspecified
+     */
+    toggleCinemaMode(cinema = !this.navBar.checkVisibility()){
+        if(cinema){
+            this.navBar.style.display = "flex";
+        }else{
+            this.navBar.style.display = "none";
+        }
+
+        //Resize the video if we're aspect locked
+        this.client.chatBox.resizeAspect();
+    }
+
+    /**
+     * Informs the class when the user's mouse curosr enters and leaves the UI area
+     * @param {Boolean} onUI - Whether or not onUI should be toggled true
+     */
+    setOnUI(onUI){
+        this.onUI = onUI;
+        this.popUI();
+    }
+
+    /**
+     * Calculates ratio of current media object
+     * @returns {Number} Current media aspect ratio as a single floating point number
+     */
+    getRatio(){
+        //If we have no media handler
+        if(this.mediaHandler == null){
+            //Return a 4/3 aspect to get a decent chat size
+            return 4/3;
+        }else{
+            return this.mediaHandler.getRatio();
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/client/poppedPanel.html b/www/doc/client/poppedPanel.html new file mode 100644 index 0000000..b9f77ad --- /dev/null +++ b/www/doc/client/poppedPanel.html @@ -0,0 +1,1451 @@ + + + + + JSDoc: Class: poppedPanel + + + + + + + + + + +
+ +

Class: poppedPanel

+ + + + + + +
+ +
+ +

poppedPanel(panel, panelBody, cPanel)

+ +
Class which represents a single instance of a popped-out panel
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new poppedPanel(panel, panelBody, cPanel)

+ + + + + + +
+ Instantiates a new Popped Panel Object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
panel + + +panelObj + + + + Panel Object to apply to Popped Panel
panelBody + + +String + + + + Raw HTML to inject into panel body, defaults to panel page if null
cPanel + + +cPanel + + + + Parent Canopy Panel Management Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

cPanel

+ + + + +
+ Parent Canopy Panel Management Object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

keepAlive

+ + + + +
+ Disables this.panel.closer() calls from this.closer() +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

panel

+ + + + +
+ Panel Object to apply to Popped Panel +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

panelBody

+ + + + +
+ Raw HTML to inject into panel body, defaults to panel page if null +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelCloseIcon

+ + + + +
+ Popped Panel Close Icon +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelDiv

+ + + + +
+ Popped Panel Container Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelDoc

+ + + + +
+ Popped Panel Document Div +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

pinnedPanelTitle

+ + + + +
+ Popped Panel Title +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

window

+ + + + +
+ Browser Window taken up by the Popped Panel +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(async) asyncConstructor()

+ + + + + + +
+ Continuation of constructor method for asynchronous function calls +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

closer()

+ + + + + + +
+ Called upon close/exit of panel +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fillContainer()

+ + + + + + +
+ Fills container window with Popped Panel container elements +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pin()

+ + + + + + +
+ Pins panel next to chat +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

popContainer()

+ + + + + + +
+ Pops/Opens container window upon start +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setupInput()

+ + + + + + +
+ Defines default input-related popped-panel Event Listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

unpop()

+ + + + + + +
+ Un-pops panel into active-panel slot +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/rawFileBase.html b/www/doc/client/rawFileBase.html new file mode 100644 index 0000000..ab77579 --- /dev/null +++ b/www/doc/client/rawFileBase.html @@ -0,0 +1,2923 @@ + + + + + JSDoc: Class: rawFileBase + + + + + + + + + + +
+ +

Class: rawFileBase

+ + + + + + +
+ +
+ +

rawFileBase(client, player, media, type)

+ +
Class containing basic building blocks for anything that touches a
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new rawFileBase(client, player, media, type)

+ + + + + + +
+ Instantiates a new rawFileBase object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent Client Management Object
player + + +player + + + + Parent Canopy Player Object
media + + +Object + + + + De-hydrated media object from server
type + + +String + + + + Media Handler Source Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player

+ + + + +
+ Parent Canopy Player Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

type

+ + + + +
+ Media Handler Source Type +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

buildPlayer()

+ + + + + + +
+ Builds video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners()

+ + + + + + +
+ Defines input-related event listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

destroyPlayer()

+ + + + + + +
+ Destroys video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles media end +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates Aspect Ratio of media +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Aspect Ratio as Floating Point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getTimestamp() → {Number}

+ + + + + + +
+ Gets current timestamp from video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Timestamp in seconds +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

ingestMedia(media) → {Boolean}

+ + + + + + +
+ Ingests media object from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from the server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True upon success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

onBuffer(event)

+ + + + + + +
+ Called on media buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onMetadataLoad(event)

+ + + + + + +
+ Called once all video metadata has properly been fetched +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onPause(event)

+ + + + + + +
+ Called on media pause +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onSeek(event)

+ + + + + + +
+ Called on media seek +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onVolumeChange(event)

+ + + + + + +
+ Called on media volume change +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pause()

+ + + + + + +
+ Pauses video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

play()

+ + + + + + +
+ Plays video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads media player +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setPlayerLock(lock)

+ + + + + + +
+ Toggles player control lockout +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
lock + + +Boolean + + + + Whether or not to lock-out user control of video
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setVideoTitle(title)

+ + + + + + +
+ Sets player title +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Title to set
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start()

+ + + + + + +
+ Starts video playback +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

startMedia(media)

+ + + + + + +
+ Ingests media nd starts playback +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(timestamp)

+ + + + + + +
+ Syncronizes timestamp based on timestamp received from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
timestamp + + +Number + + + + Current video timestamp in seconds
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/rawFileHandler.html b/www/doc/client/rawFileHandler.html new file mode 100644 index 0000000..64939ea --- /dev/null +++ b/www/doc/client/rawFileHandler.html @@ -0,0 +1,2905 @@ + + + + + JSDoc: Class: rawFileHandler + + + + + + + + + + +
+ +

Class: rawFileHandler

+ + + + + + +
+ +
+ +

rawFileHandler(client, player, media)

+ +
Basic building blocks needed for proper time-synchronized raw-file playback
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new rawFileHandler(client, player, media)

+ + + + + + +
+ Instantiates a new Null Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent Client Management Object
player + + +player + + + + Parent Canopy Player Object
media + + +Object + + + + De-hydrated media object from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player

+ + + + +
+ Parent Canopy Player Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

type

+ + + + +
+ Media Handler Source Type +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

buildPlayer()

+ + + + + + +
+ Builds video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners()

+ + + + + + +
+ Defines input-related event listeners +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

destroyPlayer()

+ + + + + + +
+ Destroys video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles media end +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates Aspect Ratio of media +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Aspect Ratio as Floating Point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getTimestamp() → {Number}

+ + + + + + +
+ Gets current timestamp from video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Timestamp in seconds +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

ingestMedia(media) → {Boolean}

+ + + + + + +
+ Ingests media object from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from the server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True upon success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

onBuffer(event)

+ + + + + + +
+ Called on media buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onMetadataLoad(event)

+ + + + + + +
+ Called once all video metadata has properly been fetched +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onPause(event)

+ + + + + + +
+ Called on media pause +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onSeek(event)

+ + + + + + +
+ Called on media seek +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onVolumeChange(event)

+ + + + + + +
+ Called on media volume change +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pause()

+ + + + + + +
+ Pauses video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

play()

+ + + + + + +
+ Plays video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads media player +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setPlayerLock(lock)

+ + + + + + +
+ Toggles player control lockout +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
lock + + +Boolean + + + + Whether or not to lock-out user control of video
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setVideoTitle(title)

+ + + + + + +
+ Sets player title +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Title to set
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start()

+ + + + + + +
+ Starts video playback +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

startMedia(media)

+ + + + + + +
+ Ingests media nd starts playback +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(timestamp)

+ + + + + + +
+ Syncronizes timestamp based on timestamp received from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
timestamp + + +Number + + + + Current video timestamp in seconds
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/client/userList.html b/www/doc/client/userList.html index 74f27cc..8c2accc 100644 --- a/www/doc/client/userList.html +++ b/www/doc/client/userList.html @@ -30,7 +30,7 @@

userList(client)

-
Class for object containing logic behind userlist UX
+
Class containing logic behind userlist UX
@@ -1185,13 +1185,13 @@
diff --git a/www/doc/client/userlist.js.html b/www/doc/client/userlist.js.html index b1677df..d93908b 100644 --- a/www/doc/client/userlist.js.html +++ b/www/doc/client/userlist.js.html @@ -43,7 +43,7 @@ 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 for object containing logic behind userlist UX + * Class containing logic behind userlist UX */ class userList{ /** @@ -246,13 +246,13 @@ class userList{
diff --git a/www/doc/client/youtubeEmbedHandler.html b/www/doc/client/youtubeEmbedHandler.html new file mode 100644 index 0000000..cd60f4b --- /dev/null +++ b/www/doc/client/youtubeEmbedHandler.html @@ -0,0 +1,2900 @@ + + + + + JSDoc: Class: youtubeEmbedHandler + + + + + + + + + + +
+ +

Class: youtubeEmbedHandler

+ + + + + + +
+ +
+ +

youtubeEmbedHandler(client, player, media)

+ +
Handles Youtube playback via the official YT embed (gross)
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new youtubeEmbedHandler(client, player, media)

+ + + + + + +
+ Instantiates a new Youtube Embed Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
client + + +channel + + + + Parent Client Management Object
player + + +player + + + + Parent Canopy Player Object
media + + +Object + + + + De-hydrated media object from server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + + + + + + + + + + + + + + + + + +

Members

+ + + +

client

+ + + + +
+ Parent Client Management Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

player

+ + + + +
+ Parent Canopy Player Object +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

type

+ + + + +
+ Media Handler Source Type +
+ + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

buildPlayer()

+ + + + + + +
+ Builds video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

destroyPlayer()

+ + + + + + +
+ Destroys video player element +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

end()

+ + + + + + +
+ Handles media end +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getRatio() → {Number}

+ + + + + + +
+ Calculates Aspect Ratio of media +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Aspect Ratio as Floating Point number +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getTimestamp() → {Number}

+ + + + + + +
+ Gets current timestamp from video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media Timestamp in seconds +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

ingestMedia(media) → {Boolean}

+ + + + + + +
+ Ingests media object from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from the server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True upon success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

onBuffer(event)

+ + + + + + +
+ Called on media buffer +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onMetadataLoad(event)

+ + + + + + +
+ Called once all video metadata has properly been fetched +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onPause(event)

+ + + + + + +
+ Called on media pause +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onSeek(event)

+ + + + + + +
+ Called on media seek +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onStateChange()

+ + + + + + +
+ Generic handler for state changes since google is a dick +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

onVolumeChange(event)

+ + + + + + +
+ Called on media volume change +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
event + + +Event + + + + Event passed down by event handler
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

pause()

+ + + + + + +
+ Pauses video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

play()

+ + + + + + +
+ Plays video +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

reload()

+ + + + + + +
+ Reloads media player +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setPlayerLock(lock)

+ + + + + + +
+ Toggles player control lockout +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
lock + + +Boolean + + + + Whether or not to lock-out user control of video
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

setVideoTitle(title)

+ + + + + + +
+ Sets player title +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Title to set
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

start()

+ + + + + + +
+ Starts video playback +
+ + + + + + + + + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

startMedia(media)

+ + + + + + +
+ Ingests media nd starts playback +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +Object + + + + Media object from server
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync(timestamp)

+ + + + + + +
+ Syncronizes timestamp based on timestamp received from server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
timestamp + + +Number + + + + Current video timestamp in seconds
+ + + + + + +
+ + + + + + + + +
Overrides:
+
+ + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/server/activeChannel.html b/www/doc/server/activeChannel.html index 6e0f755..2504c7e 100644 --- a/www/doc/server/activeChannel.html +++ b/www/doc/server/activeChannel.html @@ -786,7 +786,7 @@
diff --git a/www/doc/server/app_channel_activeChannel.js.html b/www/doc/server/app_channel_activeChannel.js.html index fbc5fbc..348ddf8 100644 --- a/www/doc/server/app_channel_activeChannel.js.html +++ b/www/doc/server/app_channel_activeChannel.js.html @@ -196,7 +196,7 @@ module.exports = activeChannel;
diff --git a/www/doc/server/app_channel_channelManager.js.html b/www/doc/server/app_channel_channelManager.js.html index 51e0812..ced5aee 100644 --- a/www/doc/server/app_channel_channelManager.js.html +++ b/www/doc/server/app_channel_channelManager.js.html @@ -347,7 +347,7 @@ module.exports = channelManager;
diff --git a/www/doc/server/app_channel_chat.js.html b/www/doc/server/app_channel_chat.js.html index d013229..e1e4fa2 100644 --- a/www/doc/server/app_channel_chat.js.html +++ b/www/doc/server/app_channel_chat.js.html @@ -81,7 +81,7 @@ module.exports = chat;
diff --git a/www/doc/server/app_channel_chatBuffer.js.html b/www/doc/server/app_channel_chatBuffer.js.html index 11947f7..3c09baf 100644 --- a/www/doc/server/app_channel_chatBuffer.js.html +++ b/www/doc/server/app_channel_chatBuffer.js.html @@ -178,7 +178,7 @@ module.exports = chatBuffer;
diff --git a/www/doc/server/app_channel_chatHandler.js.html b/www/doc/server/app_channel_chatHandler.js.html index c7ffc23..44b3036 100644 --- a/www/doc/server/app_channel_chatHandler.js.html +++ b/www/doc/server/app_channel_chatHandler.js.html @@ -376,7 +376,7 @@ module.exports = chatHandler;
diff --git a/www/doc/server/app_channel_commandPreprocessor.js.html b/www/doc/server/app_channel_commandPreprocessor.js.html index f2411c6..6514a1e 100644 --- a/www/doc/server/app_channel_commandPreprocessor.js.html +++ b/www/doc/server/app_channel_commandPreprocessor.js.html @@ -473,7 +473,7 @@ module.exports = commandPreprocessor;
diff --git a/www/doc/server/app_channel_connectedUser.js.html b/www/doc/server/app_channel_connectedUser.js.html index 63bc23e..a520193 100644 --- a/www/doc/server/app_channel_connectedUser.js.html +++ b/www/doc/server/app_channel_connectedUser.js.html @@ -334,7 +334,7 @@ module.exports = connectedUser;
diff --git a/www/doc/server/app_channel_media_media.js.html b/www/doc/server/app_channel_media_media.js.html index 1f4249a..f4553bb 100644 --- a/www/doc/server/app_channel_media_media.js.html +++ b/www/doc/server/app_channel_media_media.js.html @@ -83,7 +83,7 @@ module.exports = media;
diff --git a/www/doc/server/app_channel_media_playlistHandler.js.html b/www/doc/server/app_channel_media_playlistHandler.js.html index 02d6a5c..0fbd48f 100644 --- a/www/doc/server/app_channel_media_playlistHandler.js.html +++ b/www/doc/server/app_channel_media_playlistHandler.js.html @@ -1180,7 +1180,7 @@ module.exports = playlistHandler;
diff --git a/www/doc/server/app_channel_media_queue.js.html b/www/doc/server/app_channel_media_queue.js.html index 7ffd44f..61488cf 100644 --- a/www/doc/server/app_channel_media_queue.js.html +++ b/www/doc/server/app_channel_media_queue.js.html @@ -1795,7 +1795,7 @@ module.exports = queue;
diff --git a/www/doc/server/app_channel_media_queuedMedia.js.html b/www/doc/server/app_channel_media_queuedMedia.js.html index 6bf4702..186edec 100644 --- a/www/doc/server/app_channel_media_queuedMedia.js.html +++ b/www/doc/server/app_channel_media_queuedMedia.js.html @@ -165,7 +165,7 @@ module.exports = queuedMedia;
diff --git a/www/doc/server/app_channel_tokebot.js.html b/www/doc/server/app_channel_tokebot.js.html index 14732da..730b904 100644 --- a/www/doc/server/app_channel_tokebot.js.html +++ b/www/doc/server/app_channel_tokebot.js.html @@ -273,7 +273,7 @@ module.exports = tokebot;
diff --git a/www/doc/server/channelManager.html b/www/doc/server/channelManager.html index 5e1c56b..f4a7404 100644 --- a/www/doc/server/channelManager.html +++ b/www/doc/server/channelManager.html @@ -1991,7 +1991,7 @@
diff --git a/www/doc/server/chat.html b/www/doc/server/chat.html index 890fa38..421f210 100644 --- a/www/doc/server/chat.html +++ b/www/doc/server/chat.html @@ -329,7 +329,7 @@
diff --git a/www/doc/server/chatBuffer.html b/www/doc/server/chatBuffer.html index 6df7d3c..1c88a99 100644 --- a/www/doc/server/chatBuffer.html +++ b/www/doc/server/chatBuffer.html @@ -829,7 +829,7 @@ Left here since it seems like good form anywho, since this would be a private, o
diff --git a/www/doc/server/chatHandler.html b/www/doc/server/chatHandler.html index 72a56ca..8a2b548 100644 --- a/www/doc/server/chatHandler.html +++ b/www/doc/server/chatHandler.html @@ -3686,7 +3686,7 @@
diff --git a/www/doc/server/commandPreprocessor.html b/www/doc/server/commandPreprocessor.html index 5d60fbd..191b74c 100644 --- a/www/doc/server/commandPreprocessor.html +++ b/www/doc/server/commandPreprocessor.html @@ -1246,7 +1246,7 @@ These arrays are used to handle further command/chat processing
diff --git a/www/doc/server/commandProcessor.html b/www/doc/server/commandProcessor.html index 698151b..c54ee7b 100644 --- a/www/doc/server/commandProcessor.html +++ b/www/doc/server/commandProcessor.html @@ -1831,7 +1831,7 @@
diff --git a/www/doc/server/connectedUser.html b/www/doc/server/connectedUser.html index 8e48e2f..0bc268c 100644 --- a/www/doc/server/connectedUser.html +++ b/www/doc/server/connectedUser.html @@ -1879,7 +1879,7 @@ Having to crawl through these sockets is that. Because the other ways seem more
diff --git a/www/doc/server/global.html b/www/doc/server/global.html index 9bc98d7..8c21ffa 100644 --- a/www/doc/server/global.html +++ b/www/doc/server/global.html @@ -7377,7 +7377,7 @@ Warns server admin against unsafe config options.
diff --git a/www/doc/server/index.html b/www/doc/server/index.html index 91b924e..a5fac30 100644 --- a/www/doc/server/index.html +++ b/www/doc/server/index.html @@ -87,7 +87,7 @@ This new codebase intends to solve the following issues with the current CyTube
diff --git a/www/doc/server/media.html b/www/doc/server/media.html index 05f1463..33b9fa0 100644 --- a/www/doc/server/media.html +++ b/www/doc/server/media.html @@ -352,7 +352,7 @@
diff --git a/www/doc/server/playlistHandler.html b/www/doc/server/playlistHandler.html index b507305..98c99a5 100644 --- a/www/doc/server/playlistHandler.html +++ b/www/doc/server/playlistHandler.html @@ -5108,7 +5108,7 @@
diff --git a/www/doc/server/queue.html b/www/doc/server/queue.html index 0dcfeda..7813882 100644 --- a/www/doc/server/queue.html +++ b/www/doc/server/queue.html @@ -5805,7 +5805,7 @@ Called auto-magically by the Synchronization Timer
diff --git a/www/doc/server/queuedMedia.html b/www/doc/server/queuedMedia.html index 6dae2ba..90c33bb 100644 --- a/www/doc/server/queuedMedia.html +++ b/www/doc/server/queuedMedia.html @@ -936,7 +936,7 @@
diff --git a/www/doc/server/schemas_channel_channelBanSchema.js.html b/www/doc/server/schemas_channel_channelBanSchema.js.html index f75fc05..dd2b77b 100644 --- a/www/doc/server/schemas_channel_channelBanSchema.js.html +++ b/www/doc/server/schemas_channel_channelBanSchema.js.html @@ -101,7 +101,7 @@ module.exports = channelBanSchema;
diff --git a/www/doc/server/schemas_channel_channelPermissionSchema.js.html b/www/doc/server/schemas_channel_channelPermissionSchema.js.html index 60a8dfb..750b88c 100644 --- a/www/doc/server/schemas_channel_channelPermissionSchema.js.html +++ b/www/doc/server/schemas_channel_channelPermissionSchema.js.html @@ -169,7 +169,7 @@ module.exports = channelPermissionSchema;
diff --git a/www/doc/server/schemas_channel_channelSchema.js.html b/www/doc/server/schemas_channel_channelSchema.js.html index 143bfc4..f392729 100644 --- a/www/doc/server/schemas_channel_channelSchema.js.html +++ b/www/doc/server/schemas_channel_channelSchema.js.html @@ -934,7 +934,7 @@ module.exports = mongoose.model("channel", channelSchema);
diff --git a/www/doc/server/schemas_channel_chatSchema.js.html b/www/doc/server/schemas_channel_chatSchema.js.html index f2ecd6a..c1ed22f 100644 --- a/www/doc/server/schemas_channel_chatSchema.js.html +++ b/www/doc/server/schemas_channel_chatSchema.js.html @@ -96,7 +96,7 @@ module.exports = chatSchema;
diff --git a/www/doc/server/schemas_channel_media_mediaSchema.js.html b/www/doc/server/schemas_channel_media_mediaSchema.js.html index 79f37b8..81a1f2c 100644 --- a/www/doc/server/schemas_channel_media_mediaSchema.js.html +++ b/www/doc/server/schemas_channel_media_mediaSchema.js.html @@ -96,7 +96,7 @@ module.exports = mediaSchema;
diff --git a/www/doc/server/schemas_channel_media_playlistMediaSchema.js.html b/www/doc/server/schemas_channel_media_playlistMediaSchema.js.html index f5e8950..e0e0de1 100644 --- a/www/doc/server/schemas_channel_media_playlistMediaSchema.js.html +++ b/www/doc/server/schemas_channel_media_playlistMediaSchema.js.html @@ -124,7 +124,7 @@ module.exports = mediaSchema.discriminator('saved', playlistMediaProperties); diff --git a/www/doc/server/schemas_channel_media_playlistSchema.js.html b/www/doc/server/schemas_channel_media_playlistSchema.js.html index 3bb51f6..e369231 100644 --- a/www/doc/server/schemas_channel_media_playlistSchema.js.html +++ b/www/doc/server/schemas_channel_media_playlistSchema.js.html @@ -174,7 +174,7 @@ module.exports = playlistSchema;
diff --git a/www/doc/server/schemas_channel_media_queuedMediaSchema.js.html b/www/doc/server/schemas_channel_media_queuedMediaSchema.js.html index b1f0ac2..a7152ba 100644 --- a/www/doc/server/schemas_channel_media_queuedMediaSchema.js.html +++ b/www/doc/server/schemas_channel_media_queuedMediaSchema.js.html @@ -113,7 +113,7 @@ module.exports = mediaSchema.discriminator('queued', queuedProperties); diff --git a/www/doc/server/schemas_emoteSchema.js.html b/www/doc/server/schemas_emoteSchema.js.html index d08a919..c943ef9 100644 --- a/www/doc/server/schemas_emoteSchema.js.html +++ b/www/doc/server/schemas_emoteSchema.js.html @@ -164,7 +164,7 @@ module.exports = mongoose.model("emote", emoteSchema);
diff --git a/www/doc/server/schemas_flairSchema.js.html b/www/doc/server/schemas_flairSchema.js.html index 657647f..89a923b 100644 --- a/www/doc/server/schemas_flairSchema.js.html +++ b/www/doc/server/schemas_flairSchema.js.html @@ -118,7 +118,7 @@ module.exports = mongoose.model("flair", flairSchema);
diff --git a/www/doc/server/schemas_permissionSchema.js.html b/www/doc/server/schemas_permissionSchema.js.html index 8f40f49..15ef881 100644 --- a/www/doc/server/schemas_permissionSchema.js.html +++ b/www/doc/server/schemas_permissionSchema.js.html @@ -356,7 +356,7 @@ module.exports = mongoose.model("permissions", permissionSchema);
diff --git a/www/doc/server/schemas_statSchema.js.html b/www/doc/server/schemas_statSchema.js.html index c61fbf9..d3bac04 100644 --- a/www/doc/server/schemas_statSchema.js.html +++ b/www/doc/server/schemas_statSchema.js.html @@ -240,7 +240,7 @@ module.exports = mongoose.model("statistics", statSchema);
diff --git a/www/doc/server/schemas_tokebot_tokeCommandSchema.js.html b/www/doc/server/schemas_tokebot_tokeCommandSchema.js.html index 4c5a68e..53b32c0 100644 --- a/www/doc/server/schemas_tokebot_tokeCommandSchema.js.html +++ b/www/doc/server/schemas_tokebot_tokeCommandSchema.js.html @@ -160,7 +160,7 @@ module.exports = mongoose.model("tokeCommand", tokeCommandSchema);
diff --git a/www/doc/server/schemas_user_emailChangeSchema.js.html b/www/doc/server/schemas_user_emailChangeSchema.js.html index 9a392c1..5d491e4 100644 --- a/www/doc/server/schemas_user_emailChangeSchema.js.html +++ b/www/doc/server/schemas_user_emailChangeSchema.js.html @@ -222,7 +222,7 @@ module.exports = mongoose.model("emailChange", emailChangeSchema);
diff --git a/www/doc/server/schemas_user_passwordResetSchema.js.html b/www/doc/server/schemas_user_passwordResetSchema.js.html index 16be6b7..38156eb 100644 --- a/www/doc/server/schemas_user_passwordResetSchema.js.html +++ b/www/doc/server/schemas_user_passwordResetSchema.js.html @@ -198,7 +198,7 @@ module.exports = mongoose.model("passwordReset", passwordResetSchema);
diff --git a/www/doc/server/schemas_user_userBanSchema.js.html b/www/doc/server/schemas_user_userBanSchema.js.html index 6f532e3..4c2954d 100644 --- a/www/doc/server/schemas_user_userBanSchema.js.html +++ b/www/doc/server/schemas_user_userBanSchema.js.html @@ -521,7 +521,7 @@ module.exports = mongoose.model("userBan", userBanSchema);
diff --git a/www/doc/server/schemas_user_userSchema.js.html b/www/doc/server/schemas_user_userSchema.js.html index 10ee9d0..385a7f4 100644 --- a/www/doc/server/schemas_user_userSchema.js.html +++ b/www/doc/server/schemas_user_userSchema.js.html @@ -888,7 +888,7 @@ module.exports.userModel = mongoose.model("user", userSchema);
diff --git a/www/doc/server/tokebot.html b/www/doc/server/tokebot.html index 5e3f64b..39cedd1 100644 --- a/www/doc/server/tokebot.html +++ b/www/doc/server/tokebot.html @@ -841,7 +841,7 @@ I would now, but I don't want to break shit in a comment-only commit.
diff --git a/www/doc/server/utils_altchaUtils.js.html b/www/doc/server/utils_altchaUtils.js.html index 3230072..9b888ce 100644 --- a/www/doc/server/utils_altchaUtils.js.html +++ b/www/doc/server/utils_altchaUtils.js.html @@ -118,7 +118,7 @@ module.exports.verify = async function(payload, uniqueSecret = ''){
diff --git a/www/doc/server/utils_configCheck.js.html b/www/doc/server/utils_configCheck.js.html index f230ed1..408a772 100644 --- a/www/doc/server/utils_configCheck.js.html +++ b/www/doc/server/utils_configCheck.js.html @@ -108,7 +108,7 @@ module.exports.securityCheck = function(){
diff --git a/www/doc/server/utils_hashUtils.js.html b/www/doc/server/utils_hashUtils.js.html index 4ccb566..af4d8ba 100644 --- a/www/doc/server/utils_hashUtils.js.html +++ b/www/doc/server/utils_hashUtils.js.html @@ -103,7 +103,7 @@ module.exports.hashIP = function(ip){
diff --git a/www/doc/server/utils_linkUtils.js.html b/www/doc/server/utils_linkUtils.js.html index 53c42b2..4bee12a 100644 --- a/www/doc/server/utils_linkUtils.js.html +++ b/www/doc/server/utils_linkUtils.js.html @@ -146,7 +146,7 @@ module.exports.markLink = async function(link){
diff --git a/www/doc/server/utils_loggerUtils.js.html b/www/doc/server/utils_loggerUtils.js.html index 53e51ab..20cafd3 100644 --- a/www/doc/server/utils_loggerUtils.js.html +++ b/www/doc/server/utils_loggerUtils.js.html @@ -207,7 +207,7 @@ module.exports.errorMiddleware = function(err, req, res, next){
diff --git a/www/doc/server/utils_mailUtils.js.html b/www/doc/server/utils_mailUtils.js.html index 067fd69..f9ff380 100644 --- a/www/doc/server/utils_mailUtils.js.html +++ b/www/doc/server/utils_mailUtils.js.html @@ -140,7 +140,7 @@ module.exports.sendAddressVerification = async function(requestDB, userDB, newEm
diff --git a/www/doc/server/utils_media_internetArchiveUtils.js.html b/www/doc/server/utils_media_internetArchiveUtils.js.html index da6f930..60d0abe 100644 --- a/www/doc/server/utils_media_internetArchiveUtils.js.html +++ b/www/doc/server/utils_media_internetArchiveUtils.js.html @@ -154,7 +154,7 @@ module.exports.fetchMetadata = async function(fullID, title){
diff --git a/www/doc/server/utils_media_yanker.js.html b/www/doc/server/utils_media_yanker.js.html index 63610fd..9381dc7 100644 --- a/www/doc/server/utils_media_yanker.js.html +++ b/www/doc/server/utils_media_yanker.js.html @@ -193,7 +193,7 @@ module.exports.getMediaType = async function(url){
diff --git a/www/doc/server/utils_media_ytdlpUtils.js.html b/www/doc/server/utils_media_ytdlpUtils.js.html index 66c0dae..400a92b 100644 --- a/www/doc/server/utils_media_ytdlpUtils.js.html +++ b/www/doc/server/utils_media_ytdlpUtils.js.html @@ -186,7 +186,7 @@ async function ytdlpFetch(link, format = 'b'){
diff --git a/www/doc/server/utils_regexUtils.js.html b/www/doc/server/utils_regexUtils.js.html index fd9f1a1..b1e7099 100644 --- a/www/doc/server/utils_regexUtils.js.html +++ b/www/doc/server/utils_regexUtils.js.html @@ -69,7 +69,7 @@ module.exports.escapeRegex = function(string){
diff --git a/www/doc/server/utils_scheduler.js.html b/www/doc/server/utils_scheduler.js.html index 500ce72..e067e4f 100644 --- a/www/doc/server/utils_scheduler.js.html +++ b/www/doc/server/utils_scheduler.js.html @@ -105,7 +105,7 @@ module.exports.kickoff = function(){
diff --git a/www/doc/server/utils_sessionUtils.js.html b/www/doc/server/utils_sessionUtils.js.html index c2ca71d..c4b04a3 100644 --- a/www/doc/server/utils_sessionUtils.js.html +++ b/www/doc/server/utils_sessionUtils.js.html @@ -236,7 +236,7 @@ module.exports.maxAttempts = maxAttempts;
diff --git a/www/js/channel/channel.js b/www/js/channel/channel.js index 3a9d511..49f9dc9 100644 --- a/www/js/channel/channel.js +++ b/www/js/channel/channel.js @@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ /** - * Class for object containing base code for the Canopy channel client. + * Class containing base code for the Canopy channel client. */ class channel{ /** diff --git a/www/js/channel/chat.js b/www/js/channel/chat.js index 81624fd..0f2eae4 100644 --- a/www/js/channel/chat.js +++ b/www/js/channel/chat.js @@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ /** - * Class for Object which represents Canopy Chat Box UI + * Class which represents Canopy Chat Box UI */ class chatBox{ /** @@ -24,7 +24,7 @@ class chatBox{ */ constructor(client){ /** - * Parent CLient Management Object + * Parent Client Management Object */ this.client = client @@ -69,20 +69,75 @@ class chatBox{ this.chatPostprocessor = new chatPostprocessor(client); //Element Nodes + /** + * Chat Panel Container Div + */ this.chatPanel = document.querySelector("#chat-panel-div"); + + /** + * High Level Selector + */ this.highSelect = document.querySelector("#chat-panel-high-level-select"); + + /** + * Flair Selector + */ this.flairSelect = document.querySelector("#chat-panel-flair-select"); + + /** + * Chat Buffer Div + */ this.chatBuffer = document.querySelector("#chat-panel-buffer-div"); + + /** + * Chat Prompt + */ this.chatPrompt = document.querySelector("#chat-panel-prompt"); + + /** + * Auto-Complete Placeholder + */ this.autocompletePlaceholder = document.querySelector("#chat-panel-prompt-autocomplete-filler"); + + /** + * Auto-Complete Display + */ this.autocompleteDisplay = document.querySelector("#chat-panel-prompt-autocomplete-display"); + + /** + * Settings Panel Icon + */ this.settingsIcon = document.querySelector("#chat-panel-settings-icon"); + + /** + * Admin Panel Icon + */ this.adminIcon = document.querySelector("#chat-panel-admin-icon"); + + /** + * Emote Icon + */ this.emoteIcon = document.querySelector("#chat-panel-emote-icon"); + + /** + * Send Chat/Command Button + */ this.sendButton = document.querySelector("#chat-panel-send-button"); - //Seems weird to stick this in here, but the split is dictated by chat width :P + + /** + * Aspect Lock Icon + * Seems weird to stick this in here, but the split is dictated by chat width :P + */ this.aspectLockIcon = document.querySelector("#media-panel-aspect-lock-icon"); + + /** + * Hide Chat Icon + */ this.hideChatIcon = document.querySelector("#chat-panel-div-hide"); + + /** + * Show Chat Icon + */ this.showChatIcon = document.querySelector("#media-panel-show-chat-icon"); //Setup functions @@ -91,6 +146,9 @@ class chatBox{ this.sizeToAspect(); } + /** + * Defines input-related event listeners + */ setupInput(){ //Chat bar this.chatPrompt.addEventListener("keydown", this.send.bind(this)); @@ -118,11 +176,18 @@ class chatBox{ this.chatBuffer.addEventListener('scroll', this.scrollHandler.bind(this)); } + /** + * Defines network-related event listners + */ defineListeners(){ this.client.socket.on("chatMessage", this.displayChat.bind(this)); this.client.socket.on("clearChat", this.clearChat.bind(this)); } + /** + * Clears chat on command from server + * @param {Object} data - Data from server + */ clearChat(data){ //If we where passed a user to check if(data.user != null){ @@ -138,6 +203,10 @@ class chatBox{ }); } + /** + * Receives, Post-Processes, and Displays chat messages from server + * @param {Object} data De-hydrated chat object from server + */ displayChat(data){ //Create chat-entry span var chatEntry = document.createElement('span'); @@ -186,15 +255,27 @@ class chatBox{ this.resizeAspect(); } + /** + * Concatinate Text into Chat Prompt + * @param {String} text - Text to Concatinate + */ catChat(text){ this.chatPrompt.value += text; this.displayAutocomplete(); } + /** + * Calls a toke command out with a specified user + * @param {String} user - User to toke with + */ tokeWith(user){ this.commandPreprocessor.preprocess(user == this.client.user.user ? "!toke up fuckers" : `!toke up ${user}`); } + /** + * Pre-processes and sends text from chat prompt to server + * @param {Event} event - Event passed down from Event Handler + */ send(event){ if((!event || !event.key || event.key == "Enter") && this.chatPrompt.value){ this.commandPreprocessor.preprocess(this.chatPrompt.value); @@ -205,6 +286,10 @@ class chatBox{ } } + /** + * Displays auto-complete text against current prompt input + * @param {Event} event - Event passed down from Event Handler + */ displayAutocomplete(event){ //Find current match const match = this.checkAutocomplete(); @@ -216,6 +301,10 @@ class chatBox{ this.autocompleteDisplay.textContent = match.match.replace(match.word, ''); } + /** + * Called upon tab-complete + * @param {Event} event - Event passed down from Event Handler + */ tabComplete(event){ //If we hit tab or this isn't a keyboard event if(event.key == "Tab" || event.key == null){ @@ -239,6 +328,11 @@ class chatBox{ } } + /** + * Checks string input against auto-complete dictionary to generate the best guess as to what the user is typing + * @param {String} input - Current input from Chat Prompt + * @returns {Object} Object containing word we where handed and the match we found + */ checkAutocomplete(input = this.chatPrompt.value){ //Rebuild this fucker every time because it really doesn't take that much compute power and emotes/used tokes change //Worst case we could store it persistantly and update as needed but I think that might be much @@ -287,27 +381,48 @@ class chatBox{ } } + /** + * Handles initial client meta-data dump from server upon connection + * @param {Object} data - Data dump from server + */ handleClientInfo(data){ this.updateFlairSelect(data.flairList, data.user.flair); this.updateHighSelect(data.user.highLevel); } + /** + * Sets user high-level + * @param {Event} event - Event passed down from Event Handler + */ setHighLevel(event){ const highLevel = event.target.value; this.client.socket.emit("setHighLevel", {highLevel}); } + /** + * Sets user flair + * @param {Event} event - Event passed down from Event Handler + */ setFlair(event){ const flair = event.target.value; this.client.socket.emit("setFlair", {flair}); } + /** + * Handles High-Level updates from the server + * @param {Number} highLevel - High Level to Set + */ updateHighSelect(highLevel){ this.highSelect.value = highLevel; } + /** + * Handles flair updates from the server + * @param {Array} fliarList - List of flairs to put into flair select + * @param {String} fliar - Flair to set + */ updateFlairSelect(flairList, flair){ //clear current flair select this.flairSelect.innerHTML = ""; @@ -331,6 +446,10 @@ class chatBox{ this.flairSelect.classList.add(`flair-${flair}`); } + /** + * Locks chat-size to aspect ratio of media + * @param {Event} event - Event passed down from Event Handler + */ lockAspect(event){ //prevent the user from breaking shit :P if(this.chatPanel.style.display != "none"){ @@ -340,6 +459,10 @@ class chatBox{ } } + /** + * Un-locks chat-size to aspect ratio of media + * @param {Event} event - Event passed down from Event Handler + */ unlockAspect(event){ //Disable aspect lock this.aspectLock = false; @@ -348,6 +471,11 @@ class chatBox{ this.aspectLockIcon.style.display = "inline"; } +L /** + * Re-sizes chat back to aspect ratio on window re-size when chat box is aspect locked + * Also prevents horizontal scroll-bars from chat/window resizing + * @param {Event} event - Event passed down from Event Handler + */ resizeAspect(event){ const playerHidden = this.client.player.playerDiv.style.display == "none"; @@ -364,6 +492,9 @@ class chatBox{ this.handleAutoScroll(); } +L /** + * Re-sizes chat box relative to media aspect ratio + */ sizeToAspect(){ if(this.chatPanel.style.display != "none"){ var targetVidWidth = this.client.player.getRatio() * this.chatPanel.getBoundingClientRect().height; @@ -384,6 +515,10 @@ class chatBox{ } } + /** + * Toggles Chat Box UX + * @param {Boolean} show - Whether or not to show Chat Box UX + */ toggleUI(show = !this.chatPanel.checkVisibility()){ if(show){ this.chatPanel.style.display = "flex"; @@ -397,6 +532,10 @@ class chatBox{ } } + /** + * Handles Video Toggling + * @param {Boolean} show - Whether or not the video is currently being hidden + */ handleVideoToggle(show){ //If we're enabling the video if(show){ @@ -421,6 +560,10 @@ class chatBox{ } } + /** + * Handles scrolling within the chat buffer + * @param {Event} event - Event passed down from Event Handler + */ scrollHandler(event){ //If we're just starting out if(this.lastPos == 0){ @@ -465,6 +608,9 @@ class chatBox{ this.lastWidth = bufferWidth; } + /** + * Auto-scrolls chat buffer when new chats are entered. + */ handleAutoScroll(){ //If autoscroll is enabled if(this.autoScroll){ diff --git a/www/js/channel/chatPostprocessor.js b/www/js/channel/chatPostprocessor.js index 4b8759d..6bc03c0 100644 --- a/www/js/channel/chatPostprocessor.js +++ b/www/js/channel/chatPostprocessor.js @@ -13,11 +13,28 @@ 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 .*/ + +/** + * Class contianing client-side message post-processing code + */ class chatPostprocessor{ + /** + * Instantiates a new Chat Post-Processor object + * @param {channel} client - Parent client Management Object + */ constructor(client){ + /** + * Parent Client Management Object + */ this.client = client; } + /** + * Post-Processes a single message from the server and returns a presntable DOM Node + * @param {Node} chatEntry - Chat entry generated by initial chatBox method + * @param {Object} rawData - Raw data from server + * @returns {Node} Post-Processed Chat Entry + */ postprocess(chatEntry, rawData){ //Create empty array to hold filter spans this.filterSpans = []; @@ -30,6 +47,7 @@ class chatPostprocessor{ //Split the chat message into an array of objects representing each word/chunk this.splitMessage(); + //Process Qoutes this.processQoute(); //Re-Hydrate and Inject links and embedded media into un-processed placeholders @@ -62,13 +80,16 @@ class chatPostprocessor{ //Handle non-standard chat types this.handleChatType(); - //Inject the pre-processed chat into the chatEntry node + //Inject the pre-processed chat hyper-text into the chatEntry node this.injectBody(); //Return the pre-processed node return this.chatEntry; } + /** + * Splits message into an array of Word Objects for further processing + */ splitMessage(){ //Create an empty array to hold the body this.messageArray = []; @@ -93,6 +114,9 @@ class chatPostprocessor{ }); } + /** + * Injects word objects into chat-entry as proper DOM Nodes + */ injectBody(){ //Create an empty array to hold the objects to inject const injectionArray = []; @@ -285,6 +309,9 @@ class chatPostprocessor{ } } + /** + * Processes qouted text in chat + */ processQoute(){ //If the message starts off with '>' if(this.messageArray[0].string[0] == '>'){ @@ -292,6 +319,9 @@ class chatPostprocessor{ } } + /** + * Processes clickable command examples in chat + */ processCommandExamples(){ //for each word object in the body this.messageArray.forEach((wordObj, wordIndex) => { @@ -324,6 +354,9 @@ class chatPostprocessor{ }); } + /** + * Processes clickable channel names in chat + */ processChannelNames(){ //for each word object in the body this.messageArray.forEach((wordObj, wordIndex) => { @@ -356,6 +389,9 @@ class chatPostprocessor{ }); } + /** + * Processes clickable username callouts in chat + */ processUsernames(){ //for each word object in the body this.messageArray.forEach((wordObj, wordIndex) => { @@ -375,6 +411,9 @@ class chatPostprocessor{ }); } + /** + * Injects invisible whitespace in long-ass words to prevent fucking up the chat buffer size + */ addWhitespace(){ //for each word object in the body this.messageArray.forEach((wordObj, wordIndex) => { @@ -400,6 +439,14 @@ class chatPostprocessor{ }); } + /** + * Searches for text in-between a specific delimiter and runs a given callback against it + * + * Internal command used by several text filters to prevent code re-writes + * @param {String} delimiter - delimiter to search string by + * @param {Function} cb - Callback function to run against found strings + * @returns {Array} - list of found instances of filter + */ processFilter(delimiter, cb){ //Create empty array to hold spoilers (keep this seperate at first for internal function use) const foundFilters = []; @@ -451,6 +498,9 @@ class chatPostprocessor{ return foundFilters; } + /** + * Processes in-line spoilers + */ processSpoilers(){ //Process spoilers using '##' delimiter this.processFilter('##', (foundSpoiler)=>{ @@ -459,6 +509,9 @@ class chatPostprocessor{ }); } + /** + * Processes in-line Strike-through + */ processStrikethrough(){ //Process strikethrough's using '~~' delimiter this.processFilter('~~', (foundStrikethrough)=>{ @@ -468,6 +521,9 @@ class chatPostprocessor{ }) } + /** + * Processes in-line Bold/Strong text + */ processBold(){ //Process strong text using '*' delimiter this.processFilter('**', (foundStrikethrough)=>{ @@ -477,6 +533,9 @@ class chatPostprocessor{ }) } + /** + * Processes in-line Italics + */ processItalics(){ //Process italics using '__' delimiter this.processFilter('*', (foundStrikethrough)=>{ @@ -486,6 +545,9 @@ class chatPostprocessor{ }) } + /** + * Processes clickable links and embedded media + */ processLinks(){ //If we don't have links if(this.rawData.links == null){ @@ -513,6 +575,9 @@ class chatPostprocessor{ }); } + /** + * Marks chat nodes in-case of non-standard chat types + */ handleChatType(){ if(this.rawData.type == "whisper"){ //add whisper class diff --git a/www/js/channel/commandPreprocessor.js b/www/js/channel/commandPreprocessor.js index 6486cc9..ddfb9f6 100644 --- a/www/js/channel/commandPreprocessor.js +++ b/www/js/channel/commandPreprocessor.js @@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ /** - * Class for object containing chat and command pre-processing logic + * Class containing chat and command pre-processing logic */ class commandPreprocessor{ /** @@ -300,7 +300,7 @@ class commandPreprocessor{ } /** - * Class for Object which contains logic for client-side commands + * Class which contains logic for client-side commands */ class commandProcessor{ /** diff --git a/www/js/channel/cpanel.js b/www/js/channel/cpanel.js index 53c2f44..3a180a0 100644 --- a/www/js/channel/cpanel.js +++ b/www/js/channel/cpanel.js @@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see .*/ /** - * Class for Object containing code for managing the Canopy Panel UX + * Class containing code for managing the Canopy Panel UX */ class cPanel{ /** @@ -323,7 +323,7 @@ class panelObj{ } /** - * Class for Objects which represent a single instance of a popped-out panel + * Class which represents a single instance of a popped-out panel */ class poppedPanel{ /** diff --git a/www/js/channel/mediaHandler.js b/www/js/channel/mediaHandler.js index 5432ebd..0fde0d1 100644 --- a/www/js/channel/mediaHandler.js +++ b/www/js/channel/mediaHandler.js @@ -14,26 +14,53 @@ 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 .*/ -//This is little more than a interface class +/* + * Base class for all Canopy Media Handlers + * + * This is little more than a interface class + */ class mediaHandler{ + /** + * Instantiates a new Media Handler object + * @param {channel} client - Parent Client Management Object + * @param {player} player - Parent Canopy Player Object + * @param {Object} media - De-hydrated media object from server + * @param {String} type - Media Handler Source Type + */ constructor(client, player, media, type){ - //Get parents + /** + * Parent Client Management Object + */ this.client = client; + + /** + * Parent Canopy Player Object + */ this.player = player; - //Set handler type + /** + * Media Handler Source Type + */ this.type = type - //Denotes wether a seek call was made by the syncing function + /* + * Denotes wether a seek call was made by the syncing function + */ this.selfAct = false; - //Set last received timestamp to 0 + /* + * Contains the last received time stamp + */ this.lastTimestamp = 0; //Ingest media object from server this.startMedia(media); } + /** + * Ingests media nd starts playback + * @param {Object} media - Media object from server + */ startMedia(media){ //If we properly ingested the media if(this.ingestMedia(media)){ @@ -45,16 +72,27 @@ class mediaHandler{ } } + /** + * Builds video player element + */ buildPlayer(){ //Reset player lock this.lock = false; } + /** + * Destroys video player element + */ destroyPlayer(){ //Null out video property this.video = null; } + /** + * Ingests media object from server + * @param {Object} media - Media object from the server + * @returns {Boolean} True upon success + */ ingestMedia(media){ //Set now playing this.nowPlaying = media; @@ -63,10 +101,17 @@ class mediaHandler{ return true; } + /** + * Starts video playback + */ start(){ this.setVideoTitle(this.nowPlaying.title); } + /** + * Syncronizes timestamp based on timestamp received from server + * @param {Number} timestamp - Current video timestamp in seconds + */ sync(timestamp = this.lastTimestamp){ //Skip sync calls that won't seek so we don't pointlessly throw selfAct if(timestamp != this.video.currentTime){ @@ -75,6 +120,9 @@ class mediaHandler{ } } + /** + * Reloads media player + */ reload(){ //Get current timestamp const timestamp = this.video.currentTime; @@ -83,6 +131,9 @@ class mediaHandler{ this.selfAct = true; } + /** + * Handles media end + */ end(){ //Null out current media this.nowPlaying = null; @@ -94,32 +145,64 @@ class mediaHandler{ this.destroyPlayer(); } + /** + * Plays video + */ play(){ } + /** + * Pauses video + */ pause(){ } + /** + * Toggles player control lockout + * @param {Boolean} lock - Whether or not to lock-out user control of video + */ setPlayerLock(lock){ //set lock property this.lock = lock; } + /** + * Calculates Aspect Ratio of media + * @returns {Number} Media Aspect Ratio as Floating Point number + */ getRatio(){ + return 4/3; } + /** + * Gets current timestamp from video + * @returns {Number} Media Timestamp in seconds + */ getTimestamp(){ + return 0; } + /** + * Sets player title + * @param {String} title - Title to set + */ setVideoTitle(title){ this.player.title.textContent = `Currently Playing: ${title}`; } + /** + * Called once all video metadata has properly been fetched + * @param {Event} event - Event passed down by event handler + */ onMetadataLoad(event){ //Resize aspect (if locked), since the video doesn't properly report it's resolution until it's been loaded this.client.chatBox.resizeAspect(); } + /** + * Called on media pause + * @param {Event} event - Event passed down by event handler + */ onPause(event){ //If the video was paused out-side of code if(!this.selfAct){ @@ -129,9 +212,17 @@ class mediaHandler{ this.selfAct = false; } + /** + * Called on media volume change + * @param {Event} event - Event passed down by event handler + */ onVolumeChange(event){ } + /** + * Called on media seek + * @param {Event} event - Event passed down by event handler + */ onSeek(event){ //If the video was seeked out-side of code if(!this.selfAct){ @@ -142,17 +233,34 @@ class mediaHandler{ this.selfAct = false; } + /** + * Called on media buffer + * @param {Event} event - Event passed down by event handler + */ onBuffer(){ this.selfAct = true; } } -//Basic building blocks for anything that touches a