Changed out spliced ID's for dataset in admin panel. Removed auto-generated documentation from build step.
|
|
@ -20,8 +20,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
<% Object.keys(permList).forEach((key)=>{ %>
|
||||
<% if(key != "channelOverrides"){ %>
|
||||
<span class="admin-list-field-container">
|
||||
<label id="admin-perm-list-label-<%- key %>" class="admin-list-label admin-perm-list" for="admin-perm-list-rank-select-<%- key %>"><%- key %>: </label>
|
||||
<select id="admin-perm-list-rank-select-<%- key %>" name="admin-perm-list-rank-select-<%- key %>" class="admin-list-select admin-perm-list-rank-select">
|
||||
<label class="admin-list-label admin-perm-list" for="admin-perm-list-rank-select-<%- key %>"><%- key %>: </label>
|
||||
<select name="admin-perm-list-rank-select-<%- key %>" data-key="<%- key %>" class="admin-list-select admin-perm-list-rank-select">
|
||||
<%rankEnum.slice().reverse().forEach((rank)=>{ %>
|
||||
<option <%if(permList[key] == rank){%> selected <%}%> value="<%- rank %>"><%- rank %></option>
|
||||
<% }); %>
|
||||
|
|
@ -33,8 +33,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
<% Object.keys(permList.channelOverrides).forEach((key)=>{ %>
|
||||
<% if(key != "channelOverrides"){ %>
|
||||
<span class="admin-list-field-container">
|
||||
<label id="admin-chan-perm-list-label-<%- key %>" class="admin-list-label admin-chan-perm-list" for="admin-chan-perm-list-rank-select-<%- key %>"><%- key %>: </label>
|
||||
<select id="admin-chan-perm-list-rank-select-<%- key %>" name="admin-chan-perm-list-rank-select-<%- key %>" class="admin-list-select admin-chan-perm-list-rank-select">
|
||||
<label class="admin-list-label admin-chan-perm-list" for="admin-chan-perm-list-rank-select-<%- key %>"><%- key %>: </label>
|
||||
<select name="admin-chan-perm-list-rank-select-<%- key %>" data-key="<%- key %>" class="admin-list-select admin-chan-perm-list-rank-select">
|
||||
<%rankEnum.slice().reverse().forEach((rank)=>{ %>
|
||||
<option <%if(permList.channelOverrides[key] == rank){%> selected <%}%> value="<%- rank %>"><%- rank %></option>
|
||||
<% }); %>
|
||||
|
|
|
|||
|
|
@ -41,23 +41,23 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
</td>
|
||||
</tr>
|
||||
<% userList.forEach((curUser) => { %>
|
||||
<tr id="admin-user-list-entry-<%- curUser.user %>" class="admin-list-entry">
|
||||
<td id="admin-user-list-entry-img-<%- curUser.user %>" class="admin-list-entry-item">
|
||||
<tr id="admin-user-list-entry-<%- curUser.user %>" class="admin-list-entry" data-name="<%- curUser.user %>" >
|
||||
<td class="admin-list-entry-item">
|
||||
<a href="/profile/<%- curUser.user %>" class="admin-list-entry-item">
|
||||
<img id="admin-user-list-entry-img-<%- curUser.user %>" class="admin-list-entry-item" src="<%- curUser.img %>">
|
||||
<img class="admin-list-entry-item" src="<%- curUser.img %>">
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-id-<%- curUser.user %>" class="admin-list-entry-item not-first-col">
|
||||
<td class="admin-list-entry-item not-first-col">
|
||||
<a href="/profile/<%- curUser.user %>" class="admin-list-entry-item">
|
||||
<%- curUser.id %>
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-name-<%- curUser.user %>" class="admin-list-entry-item not-first-col">
|
||||
<a href="/profile/<%- curUser.user %>" class="admin-list-entry-item admin-user-list-name" id="admin-user-list-name-<%- curUser.user %>">
|
||||
<td class="admin-list-entry-item not-first-col">
|
||||
<a href="/profile/<%- curUser.user %>" class="admin-list-entry-item admin-user-list-name">
|
||||
<%- curUser.user %>
|
||||
</a>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-rank-<%- curUser.user %>" class="admin-list-entry-item not-first-col">
|
||||
<td class="admin-list-entry-item not-first-col">
|
||||
<% if(rankEnum.indexOf(curUser.rank) < rankEnum.indexOf(user.rank)){%>
|
||||
<select id="admin-user-list-rank-select-<%- curUser.user %>" class="admin-user-list-rank-select">
|
||||
<%rankEnum.slice().reverse().forEach((rank)=>{ %>
|
||||
|
|
@ -68,15 +68,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. %>
|
|||
<%- curUser.rank %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-email-<%- curUser.user %>" class="admin-list-entry-item not-first-col">
|
||||
<td class="admin-list-entry-item not-first-col">
|
||||
<%- curUser.email ? curUser.email : "N/A" %>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-date-<%- curUser.user %>" class="admin-list-entry-item not-first-col">
|
||||
<td class="admin-list-entry-item not-first-col">
|
||||
<%- curUser.date.toUTCString() %>
|
||||
</td>
|
||||
<td id="admin-user-list-entry-action-<%- curUser.user %>" class="admin-list-entry-item not-first-col">
|
||||
<td class="admin-list-entry-item not-first-col">
|
||||
<%# It's either this or add whitespce >:( %>
|
||||
<i class="bi-radioactive admin-user-list-icon admin-user-list-nuke-icon" id="admin-user-list-nuke-icon-<%- curUser.user %>" title="Nuke Account: <%- curUser.user %>"></i><i class="bi-fire admin-user-list-icon admin-user-list-ban-icon" id="admin-user-list-ban-icon-<%- curUser.user %>" title="Ban User: <%- curUser.user %>"></i><i class="bi-arrow-clockwise admin-user-list-icon admin-user-list-pw-reset-icon" id="admin-user-list-pw-reset-icon-<%- curUser.user %>" title="Generate Password Reset Link for <%- curUser.user %>"></i>
|
||||
<i class="bi-radioactive admin-user-list-icon admin-user-list-nuke-icon" title="Nuke Account: <%- curUser.user %>"></i><i class="bi-fire admin-user-list-icon admin-user-list-ban-icon" title="Ban User: <%- curUser.user %>"></i><i class="bi-arrow-clockwise admin-user-list-icon admin-user-list-pw-reset-icon" title="Generate Password Reset Link for <%- curUser.user %>"></i>
|
||||
</td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
|
|
|
|||
|
|
@ -1,884 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: addURLPopup</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: addURLPopup</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>addURLPopup<span class="signature">(event, playlist, location, client, doc)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class representing pop-up dialogue which adds media to a given playlist</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="addURLPopup"><span class="type-signature"></span>new addURLPopup<span class="signature">(event, playlist, location, client, doc)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a new Add URL Pop-up
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>playlist</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Playlist name</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>location</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Location of playlist, either Channel or User</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Parent Client Management Object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>doc</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Document</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Current owner documnet of the panel, so we know where to drop our pop-up</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line708">line 708</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management Object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line721">line 721</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="location"><span class="type-signature"></span>location<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Location of playlist, either Channel or User
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line731">line 731</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="playlist"><span class="type-signature"></span>playlist<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Playlist Name
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line726">line 726</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="popup"><span class="type-signature"></span>popup<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
canopyUXUtils.popup() object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line738">line 738</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="addToPlaylist"><span class="type-signature"></span>addToPlaylist<span class="signature">(event)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Handles sending request to add to a playlist to the server
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line764">line 764</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="asyncConstructor"><span class="type-signature"></span>asyncConstructor<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Continuation of object construction, called after child popup object construction
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line744">line 744</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="setupInput"><span class="type-signature"></span>setupInput<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Defines input-related Event Handlers
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line754">line 754</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,385 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: channel.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: channel.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 base code for the Canopy channel client.
|
||||
*/
|
||||
class channel{
|
||||
/**
|
||||
* Instantiates a new channel object
|
||||
*/
|
||||
constructor(){
|
||||
//Establish connetion to the server via socket.io
|
||||
this.connect();
|
||||
//Define socket listeners
|
||||
this.defineListeners();
|
||||
|
||||
/**
|
||||
* Returns true once the ytEmbed API has loaded in from google (eww)
|
||||
*/
|
||||
this.ytEmbedAPILoaded = false;
|
||||
|
||||
/**
|
||||
* Current connected channels name
|
||||
*/
|
||||
this.channelName = window.location.pathname.split('/c/')[1].split('/')[0];
|
||||
|
||||
/**
|
||||
* Child Video Player object
|
||||
*/
|
||||
this.player = new player(this);
|
||||
|
||||
/**
|
||||
* Child Chat Box Object
|
||||
*/
|
||||
this.chatBox = new chatBox(this);
|
||||
|
||||
/**
|
||||
* Child User List Object
|
||||
*/
|
||||
this.userList = new userList(this);
|
||||
|
||||
/**
|
||||
* Child Canopy Panel Object
|
||||
*/
|
||||
this.cPanel = new cPanel(this);
|
||||
|
||||
//Set defaults for any unset settings and run any required process steps for the current config
|
||||
this.setDefaults(false, true);
|
||||
|
||||
//Freak out any weirdos who take a peek in the dev console for shits n gigs
|
||||
console.log("👁️👄👁️ ℬℴ𝓊𝓃𝒿ℴ𝓊𝓇.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles initial client connection
|
||||
*/
|
||||
connect(){
|
||||
this.socket = io({
|
||||
extraHeaders: {
|
||||
//Include CSRF token
|
||||
'x-csrf-token': utils.ajax.getCSRFToken()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines network-related listeners
|
||||
*/
|
||||
defineListeners(){
|
||||
this.socket.on("connect", () => {
|
||||
document.title = `${this.channelName} - Connected`
|
||||
});
|
||||
|
||||
this.socket.on("kick", async (data) => {
|
||||
if(data.reason == "Invalid CSRF Token!"){
|
||||
//Reload the CSRF token
|
||||
await utils.ajax.reloadCSRFToken();
|
||||
|
||||
//Retry the connection
|
||||
this.connect();
|
||||
}else{
|
||||
new canopyUXUtils.popup(`You have been ${data.type} from the channel for the following reason:<br>${data.reason}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on("clientMetadata", this.handleClientInfo.bind(this));
|
||||
|
||||
this.socket.on("error", utils.ux.displayResponseError);
|
||||
|
||||
this.socket.on("queue", (data) => {
|
||||
this.queue = new Map(data.queue);
|
||||
});
|
||||
|
||||
this.socket.on("lock", (data) => {
|
||||
this.queueLock = data.locked;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles initial client-metadata ingestion from server upon connection
|
||||
* @param {Object} data - Data glob from server
|
||||
*/
|
||||
handleClientInfo(data){
|
||||
//Ingest user data
|
||||
this.user = data.user;
|
||||
|
||||
//Re-hydrate permission maps
|
||||
this.user.permMap.site = new Map(data.user.permMap.site);
|
||||
this.user.permMap.chan = new Map(data.user.permMap.chan);
|
||||
|
||||
//Tell the chatbox to handle client info
|
||||
//should it have its own event listener instead? Guess it's a stylistic choice :P
|
||||
this.chatBox.handleClientInfo(data);
|
||||
|
||||
//Store queue for use by the queue panel
|
||||
this.queue = new Map(data.queue);
|
||||
|
||||
//Store queue lock status
|
||||
this.queueLock = data.queueLock;
|
||||
|
||||
//For each chat held in the chat buffer
|
||||
for(let chat of data.chatBuffer){
|
||||
//Display the chat
|
||||
this.chatBox.displayChat(chat);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes and applies default config on any unset settings
|
||||
* @param {Boolean} force - Whether or not to forcefully reset already set settings
|
||||
* @param {Boolean} processConfig - Whether or not to run the Process Config function once complete
|
||||
*/
|
||||
setDefaults(force = false, processConfig = false){
|
||||
//Iterate through default config
|
||||
for(let [key, value] of channel.defaultConfig){
|
||||
//If the setting is unset or function was called forcefully
|
||||
if(force || localStorage.getItem(key) == null){
|
||||
//Set item from default map
|
||||
localStorage.setItem(key, value);
|
||||
}
|
||||
|
||||
//If we're running process steps for the config
|
||||
if(processConfig){
|
||||
//Process the current config value
|
||||
this.processConfig(key, localStorage.getItem(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run once every config change to ensure settings are properly set
|
||||
* @param {String} key - Setting to change
|
||||
* @param {*} value - Value to set setting to
|
||||
*/
|
||||
processConfig(key, value){
|
||||
//Unfortunately we can't scope constants to switch-cases so this is the best we got if we wanna re-use the name
|
||||
let nowPlaying;
|
||||
|
||||
//Switch/case by config key
|
||||
switch(key){
|
||||
case 'ytPlayerType':
|
||||
const embedScript = document.querySelector(".yt-embed-api");
|
||||
//If the user is running the embedded player and we don't have en embed script loaded
|
||||
if(value == 'embed' && embedScript == null){
|
||||
//Find our footer
|
||||
const footer = document.querySelector('footer');
|
||||
|
||||
//Create new script tag
|
||||
const ytEmbedAPI = document.createElement('script');
|
||||
//Link the iframe api from youtube
|
||||
ytEmbedAPI.src = "https://www.youtube.com/iframe_api";
|
||||
//set the iframe api script id
|
||||
ytEmbedAPI.classList.add('yt-embed-api');
|
||||
|
||||
//Append the script tag to the top of the footer to give everything else access
|
||||
footer.prepend(ytEmbedAPI);
|
||||
//If we're not using the embed player but the script is loaded
|
||||
}else if(embedScript != null){
|
||||
//Pull all scripts since the main one might have pulled others
|
||||
const scripts = document.querySelectorAll('script');
|
||||
|
||||
//Iterate through all script tags on the page
|
||||
for(let script of scripts){
|
||||
//If the script came from youtube
|
||||
if(script.src.match(/youtube\.com|youtu\.be/)){
|
||||
//Rip it out
|
||||
script.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//If the player or mediaHandler isn't loaded
|
||||
if(this.player == null || this.player.mediaHandler == null){
|
||||
//We're fuggin done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Get current video
|
||||
nowPlaying = this.player.mediaHandler.nowPlaying;
|
||||
|
||||
//If we're playing a youtube video
|
||||
if(nowPlaying != null && nowPlaying.type == 'yt'){
|
||||
//Restart the video
|
||||
this.player.hardReload();
|
||||
}
|
||||
|
||||
//Stop while we're ahead
|
||||
return;
|
||||
|
||||
case 'IACDN':
|
||||
//If the player or mediaHandler isn't loaded
|
||||
if(this.player == null || this.player.mediaHandler == null){
|
||||
//We're fuggin done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Get current video
|
||||
nowPlaying = this.player.mediaHandler.nowPlaying;
|
||||
|
||||
//If we're playing a video from Internet Archive
|
||||
if(nowPlaying != null && nowPlaying.type == 'ia'){
|
||||
//Hard reload the media, forcing media handler re-creation
|
||||
this.player.hardReload();
|
||||
}
|
||||
|
||||
return;
|
||||
case 'syncTolerance':
|
||||
//If the player isn't loaded
|
||||
if(this.player == null){
|
||||
//We're fuckin' done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Set syncronization tolerance
|
||||
this.player.syncTolerance = value;
|
||||
return;
|
||||
case 'liveSyncTolerance':
|
||||
//If the player isn't loaded
|
||||
if(this.player == null){
|
||||
//We're fuckin' done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Set syncronization tolerance
|
||||
this.player.streamSyncTolerance = value;
|
||||
return;
|
||||
case 'syncDelta':
|
||||
//If the player isn't loaded
|
||||
if(this.player == null){
|
||||
//We're fuckin' done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Set syncronization delta
|
||||
this.player.syncDelta = value;
|
||||
return;
|
||||
case 'chatWidthMin':
|
||||
//If the chat isn't loaded
|
||||
if(this.chatBox == null){
|
||||
//We're fuckin' done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Set Chat Box Width minimum while Locked to Aspect-Ratio
|
||||
this.chatBox.chatWidthMinimum = value / 100;
|
||||
return;
|
||||
case 'userlistHidden':
|
||||
//If the userlist class isn't loaded in yet
|
||||
if(this.userList == null){
|
||||
//We're fuckin' done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Pass value down to UI toggle, making sure to allow for string conversion
|
||||
this.userList.toggleUI(!(value == true || value == "true"));
|
||||
return;
|
||||
case 'cinemaMode':
|
||||
//If the userlist class isn't loaded in yet
|
||||
if(this.player == null){
|
||||
//We're fuckin' done here
|
||||
return;
|
||||
}
|
||||
|
||||
//Pass value down to UI toggle, making sure to allow for string conversion
|
||||
this.player.toggleCinemaMode(value == true || value == "true");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default channel config
|
||||
*/
|
||||
static defaultConfig = new Map([
|
||||
["ytPlayerType","raw"],
|
||||
["IACDN",""],
|
||||
["syncTolerance",0.4],
|
||||
["liveSyncTolerance", 2],
|
||||
["syncDelta", 6],
|
||||
["chatWidthMin", 20],
|
||||
["userlistHidden", false],
|
||||
["cinemaMode", false]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Youtube iframe-embed API entry point
|
||||
*/
|
||||
function onYouTubeIframeAPIReady(){
|
||||
//Set embed api to true
|
||||
client.ytEmbedAPILoaded = true;
|
||||
|
||||
//Get currently playing item
|
||||
const nowPlaying = client.player.mediaHandler.nowPlaying;
|
||||
|
||||
//If we're playing a youtube video and the official embeds are enabled
|
||||
if(nowPlaying.type == 'yt' && localStorage.getItem('ytPlayerType') == "embed"){
|
||||
//Restart the video now that the embed api has loaded
|
||||
client.player.start({media: nowPlaying});
|
||||
}
|
||||
}
|
||||
|
||||
const client = new channel();</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,676 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: chat.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: chat.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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-Width Minimum while sized to media Aspect-Ratio
|
||||
*/
|
||||
this.chatWidthMinimum = localStorage.getItem('chatWidthMin') / 100;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate Text into Chat Prompt
|
||||
* @param {String} text - Text to Concatenate
|
||||
*/
|
||||
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";
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 * this.chatWidthMinimum;
|
||||
|
||||
//Set width to target or 20vw depending on whether or not we've hit the width limit
|
||||
this.chatPanel.style.flexBasis = targetChatWidth > limit ? `${targetChatWidth}px` : `${this.chatWidthMinimum * 100}vw`;
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,680 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: chatPostprocessor.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: chatPostprocessor.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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");
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,799 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: clearPopup</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: clearPopup</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>clearPopup<span class="signature">(event, client, cb, doc)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class represneting pop-up dialogue for clearing queue between a range of two dates</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="clearPopup"><span class="type-signature"></span>new clearPopup<span class="signature">(event, client, cb, doc)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a new queue Clear Popup
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Parent Client Management Object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>cb</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Callback function, passed upon pop-up creation</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>doc</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Document</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Current owner documnet of the panel, so we know where to drop our pop-up</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1554">line 1554</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="cb"><span class="type-signature"></span>cb<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Callback function, passed upon pop-up creation
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1571">line 1571</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management Object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1566">line 1566</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="popup"><span class="type-signature"></span>popup<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
canopyUXUtils.popup() object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1578">line 1578</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="asyncConstructor"><span class="type-signature"></span>asyncConstructor<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Continuation of object construction, called after child popup object construction
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1584">line 1584</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="clear"><span class="type-signature"></span>clear<span class="signature">(event)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Handles sending request to clear playlist between two dates to the server
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1624">line 1624</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="setupInput"><span class="type-signature"></span>setupInput<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Defines input-related Event Handlers
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1614">line 1614</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,380 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: commandPreprocessor.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: commandPreprocessor.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 chat and command pre-processing logic
|
||||
*/
|
||||
class commandPreprocessor{
|
||||
/**
|
||||
* Instantiates a new commandPreprocessor object
|
||||
* @param {channel} client - Parent client Management Object
|
||||
*/
|
||||
constructor(client){
|
||||
/**
|
||||
* Parent Client Management object
|
||||
*/
|
||||
this.client = client;
|
||||
|
||||
/**
|
||||
* Child Command Processor object
|
||||
*/
|
||||
this.commandProcessor = new commandProcessor(client);
|
||||
|
||||
/**
|
||||
* Set of arrays containing site-wide, channel-wide, and user-specific emotes
|
||||
*/
|
||||
this.emotes = {
|
||||
site: [],
|
||||
chan: [],
|
||||
personal: []
|
||||
}
|
||||
|
||||
//define listeners
|
||||
this.defineListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines Network-Related Listeners
|
||||
*/
|
||||
defineListeners(){
|
||||
//When we receive site-wide emote list
|
||||
this.client.socket.on("siteEmotes", this.setSiteEmotes.bind(this));
|
||||
this.client.socket.on("chanEmotes", this.setChanEmotes.bind(this));
|
||||
this.client.socket.on("personalEmotes", this.setPersonalEmotes.bind(this));
|
||||
this.client.socket.on("usedTokes", this.setUsedTokes.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-Processes a single chat/command before sending it off to the server
|
||||
* @param {String} command - Chat/Command to pre-process
|
||||
*/
|
||||
preprocess(command){
|
||||
//Set command and sendFlag
|
||||
this.command = command;
|
||||
this.sendFlag = true;
|
||||
|
||||
//Attempt to process as local command
|
||||
this.processLocalCommand();
|
||||
|
||||
//If we made it through the local command processor
|
||||
if(this.sendFlag){
|
||||
//Set the message to the command
|
||||
this.message = command;
|
||||
//Process message emotes into links
|
||||
this.processEmotes();
|
||||
//Process unmarked links into marked links
|
||||
this.processLinks();
|
||||
//Send command off to server
|
||||
this.sendRemoteCommand();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes local commands, starting with '/'
|
||||
*/
|
||||
processLocalCommand(){
|
||||
//Create an empty array to hold the command
|
||||
this.commandArray = [];
|
||||
//Split string by words
|
||||
this.commandArray = this.command.split(/\b/g);//Split by word-borders
|
||||
this.argumentArray = this.command.match(/\b\w+\b/g);//Match by words surrounded by borders
|
||||
|
||||
//If this is a local command
|
||||
if(this.commandArray[0] == '/'){
|
||||
//If the command exists
|
||||
if(this.argumentArray != null && this.commandProcessor[this.argumentArray[0].toLowerCase()] != null){
|
||||
//Don't send it to the server
|
||||
this.sendFlag = false;
|
||||
|
||||
//Call the command with the argument array
|
||||
this.commandProcessor[this.argumentArray[0].toLowerCase()](this.argumentArray, this.commandArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes emotes refrences in loaded message into links to be further processed by processLinks()
|
||||
*/
|
||||
processEmotes(){
|
||||
//inject invisible whitespace in-between emotes to prevent from mushing links together
|
||||
this.message = this.message.replaceAll('][',']ㅤ[');
|
||||
|
||||
//For each list of emotes
|
||||
Object.keys(this.emotes).forEach((key) => {
|
||||
//For each emote in the current list
|
||||
this.emotes[key].forEach((emote) => {
|
||||
//Inject emote links into the message, pad with invisible whitespace to keep link from getting mushed
|
||||
this.message = this.message.replaceAll(`[${emote.name}]`, `ㅤ${emote.link}ㅤ`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes links into numbered file seperators, putting links into a dedicated array.
|
||||
*/
|
||||
processLinks(){
|
||||
//Strip out file seperators in-case the user is being a smart-ass
|
||||
this.message = this.message.replaceAll('␜','');
|
||||
//Split message by links
|
||||
var splitMessage = this.message.split(/(https?:\/\/[^\sㅤ]+)/g);
|
||||
//Create an empty array to hold links
|
||||
this.links = [];
|
||||
|
||||
splitMessage.forEach((chunk, chunkIndex) => {
|
||||
//For each chunk that is a link
|
||||
if(chunk.match(/(https?:\/\/[^\sㅤ]+)/g)){
|
||||
//I looked online for obscure characters that no one would use to prevent people from chatting embed placeholders
|
||||
//Then I found this fucker, turns out it's literally made for the job lmao (even if it was originally intended for paper/magnetic tape)
|
||||
//Replace link with indexed placeholder
|
||||
splitMessage[chunkIndex] = `␜${this.links.length}`
|
||||
|
||||
//push current chunk as link
|
||||
this.links.push(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
//Join the message back together
|
||||
this.message = splitMessage.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmits message/command off to server
|
||||
*/
|
||||
sendRemoteCommand(){
|
||||
this.client.socket.emit("chatMessage",{msg: this.message, links: this.links});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets site emotes
|
||||
* @param {Object} data - Emote data from server
|
||||
*/
|
||||
setSiteEmotes(data){
|
||||
this.emotes.site = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets channel emotes
|
||||
* @param {Object} data - Emote data from server
|
||||
*/
|
||||
setChanEmotes(data){
|
||||
this.emotes.chan = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets personal emotes
|
||||
* @param {Object} data - Emote data from server
|
||||
*/
|
||||
setPersonalEmotes(data){
|
||||
this.emotes.personal = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets used tokes
|
||||
* @param {Object} data - Used toke data from server
|
||||
*/
|
||||
setUsedTokes(data){
|
||||
this.usedTokes = data.tokes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches emote by link
|
||||
* @param {String} link - Link to fetch emote with
|
||||
* @returns {Object} found emote
|
||||
*/
|
||||
getEmoteByLink(link){
|
||||
//Create an empty variable to hold the found emote
|
||||
var foundEmote = null;
|
||||
|
||||
//For each list of emotes
|
||||
Object.keys(this.emotes).forEach((key) => {
|
||||
//For each emote in the current list
|
||||
this.emotes[key].forEach((emote) => {
|
||||
//if we found a match
|
||||
if(emote.link == link){
|
||||
//return the match
|
||||
foundEmote = emote;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return foundEmote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates flat list of emote names
|
||||
* @returns {Array} List of strings containing emote names
|
||||
*/
|
||||
getEmoteNames(){
|
||||
//Create an empty array to hold names
|
||||
let names = [];
|
||||
|
||||
//For every set of emotes
|
||||
for(let set of Object.keys(this.emotes)){
|
||||
//for every emote in the current set of emotes
|
||||
for(let emote of this.emotes[set]){
|
||||
//push the name of the emote to the name list
|
||||
names.push(emote.name);
|
||||
}
|
||||
}
|
||||
|
||||
//return our list of names
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates auto-complete dictionary from pre-written commands, emotes, and used tokes from servers for use with autocomplete
|
||||
* @returns {Object} Generated Dictionary object
|
||||
*/
|
||||
buildAutocompleteDictionary(){
|
||||
let dictionary = {
|
||||
tokes: {
|
||||
prefix: '!',
|
||||
postfix: '',
|
||||
cmds: [
|
||||
['toke', true]
|
||||
].concat(injectPerms(this.usedTokes))
|
||||
},
|
||||
//Make sure to add spaces at the end for commands that take arguments
|
||||
//Not necissary but definitely nice to have
|
||||
serverCMD: {
|
||||
prefix: '!',
|
||||
postfix: '',
|
||||
cmds: [
|
||||
["whisper ", true],
|
||||
["announce ", client.user.permMap.chan.get('announce')],
|
||||
["serverannounce ", client.user.permMap.site.get('announce')],
|
||||
["clear ", client.user.permMap.chan.get('clearChat')],
|
||||
["kick ", client.user.permMap.chan.get('kickUser')],
|
||||
]
|
||||
},
|
||||
localCMD:{
|
||||
prefix: '/',
|
||||
postfix: '',
|
||||
cmds: [
|
||||
["high ", true]
|
||||
]
|
||||
},
|
||||
usernames:{
|
||||
prefix: '',
|
||||
postfix: '',
|
||||
cmds: injectPerms(Array.from(client.userList.colorMap.keys()))
|
||||
},
|
||||
emotes:{
|
||||
prefix:'[',
|
||||
postfix:']',
|
||||
cmds: injectPerms(this.getEmoteNames())
|
||||
}
|
||||
};
|
||||
|
||||
//return our dictionary object
|
||||
return dictionary;
|
||||
|
||||
function injectPerms(cmds, perm = true){
|
||||
//Create empty array to hold cmds
|
||||
let cmdSet = [];
|
||||
|
||||
//For each cmd
|
||||
for(let cmd of cmds){
|
||||
//Add the cmd with its perm to the cmdset
|
||||
cmdSet.push([cmd, perm]);
|
||||
}
|
||||
|
||||
//return the cmd set
|
||||
return cmdSet;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class which contains logic for client-side commands
|
||||
*/
|
||||
class commandProcessor{
|
||||
/**
|
||||
* Instantiates a new Command Processor object
|
||||
* @param {channel} client - Parent client mgmt object
|
||||
*/
|
||||
constructor(client){
|
||||
/**
|
||||
* Parent Client Management object
|
||||
*/
|
||||
this.client = client
|
||||
}
|
||||
|
||||
/**
|
||||
* Method handling /high client command
|
||||
* @param {Array} argumentArray - Array of arguments passed down from Command Pre-Processor
|
||||
*/
|
||||
high(argumentArray){
|
||||
//If we have an argument
|
||||
if(argumentArray[1]){
|
||||
//Use it to set our high level
|
||||
//Technically this is less of a local command than it would be if it where telling the select to do this
|
||||
//but TTN used to treat this as a local command so fuck it
|
||||
this.client.socket.emit("setHighLevel", {highLevel: argumentArray[1]});
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,430 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: commandProcessor</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: commandProcessor</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>commandProcessor<span class="signature">(client)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class which contains logic for client-side commands</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="commandProcessor"><span class="type-signature"></span>new commandProcessor<span class="signature">(client)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a new Command Processor object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Parent client mgmt object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="commandPreprocessor.js.html">commandPreprocessor.js</a>, <a href="commandPreprocessor.js.html#line305">line 305</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="commandPreprocessor.js.html">commandPreprocessor.js</a>, <a href="commandPreprocessor.js.html#line314">line 314</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="high"><span class="type-signature"></span>high<span class="signature">(argumentArray)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Method handling /high client command
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>argumentArray</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Array</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Array of arguments passed down from Command Pre-Processor</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="commandPreprocessor.js.html">commandPreprocessor.js</a>, <a href="commandPreprocessor.js.html#line321">line 321</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,524 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: cpanel.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: cpanel.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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();
|
||||
}
|
||||
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,969 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: defaultTitlesPopup</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: defaultTitlesPopup</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>defaultTitlesPopup<span class="signature">(event, playlist, titles, location, client, doc)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class Representing popup dialogue for changing playlists defualt titles</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="defaultTitlesPopup"><span class="type-signature"></span>new defaultTitlesPopup<span class="signature">(event, playlist, titles, location, client, doc)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a new Default Titles Popup
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>playlist</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Playlist name</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>titles</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">List of titles, denoted by newlines</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>location</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Location of playlist, either Channel or User</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Parent Client Management Object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>doc</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Document</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Current owner documnet of the panel, so we know where to drop our pop-up</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line784">line 784</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management Object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line798">line 798</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="location"><span class="type-signature"></span>location<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Location of playlist, either Channel or User
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line808">line 808</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="playlist"><span class="type-signature"></span>playlist<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Playlist Name
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line803">line 803</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="popup"><span class="type-signature"></span>popup<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
canopyUXUtils.popup() object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line820">line 820</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="titles"><span class="type-signature"></span>titles<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Array of titles to set
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line813">line 813</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="asyncConstructor"><span class="type-signature"></span>asyncConstructor<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Continuation of object construction, called after child popup object construction
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line826">line 826</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="changeDefaultTitles"><span class="type-signature"></span>changeDefaultTitles<span class="signature">(event)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Handles sending request to change default titles of playlist to the server
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line847">line 847</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="setupInput"><span class="type-signature"></span>setupInput<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Defines input-related Event Handlers
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line837">line 837</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
|
@ -1,217 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Global</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Global</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2></h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="onYouTubeIframeAPIReady"><span class="type-signature"></span>onYouTubeIframeAPIReady<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Youtube iframe-embed API entry point
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="channel.js.html">channel.js</a>, <a href="channel.js.html#line321">line 321</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Home</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Home</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3> </h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article><h1>Canopy - 0.3-INDEV</h1>
|
||||
<p>Canopy - /ˈkæ.nə.pi/:</p>
|
||||
<ul>
|
||||
<li>The upper layer of foliage and branches of a forest, containing the majority of animal life.</li>
|
||||
</ul>
|
||||
<p>Canopy is a community chat & synced video embedding web application, intended to replace fore.st as the server software for ourfore.st.
|
||||
This new codebase intends to solve the following issues with the current CyTube based software:</p>
|
||||
<ul>
|
||||
<li>Unmaintained upstream codebase.</li>
|
||||
<li>Different goals.</li>
|
||||
<li>Different coding styles.</li>
|
||||
<li>Obsolete Technology and Dependencies.</li>
|
||||
<li>General Clunk</li>
|
||||
<li>Less Unique Community Identity</li>
|
||||
</ul>
|
||||
<p>Canopy intends to be a simple node/express.js app. It leverages yt-dlp and the internet archive REST api for metadata gathering. Persistant storage is handled by mongodb, as it's document based nature inherintly works well for cleanly storing large config documents for user/channel settings, and the low use of inter-collection references within the canopy software. All hardcore security functions like server-side input sanatization, session handling, CSRF mitigation, and password hashing are handled by industry-standard open source libraries such as validator/express-validator, express-sessions, csrf-sync, and bcrypt, however it IS hobbiest software, and it should be treated as such.</p>
|
||||
<p>The Canopy codebase does not, nor will it ever contain:</p>
|
||||
<ul>
|
||||
<li>Advertisements (targetted or otherwise)</li>
|
||||
<li>Proprietary Code</li>
|
||||
<li>Cryptocurrency/Blockchain integration</li>
|
||||
<li>'Analytics/Telemtry' spyware</li>
|
||||
<li>The use of video sources which require proprietary 'Digital <s>Rights Management</s> Ristricitons Malware' such as Widevine.</li>
|
||||
</ul>
|
||||
<p>Thirdparty media providers may or may not contain all of the above atrocities :P (though browser-side DRM extensions will never be required), always use an ad-blocker!</p>
|
||||
<p>Our current goal is to create a cleaner, more modern, purpose-built codebase that has feature-parity with the current version of fore.st, while writing improvements where possible. Once this is accomplished, and ourfore.st has been migrated, work will continue to re-create features from TTN, while also building completely new ones as well.</p>
|
||||
<h2>License</h2>
|
||||
<p>Canopy is written by the community, and provided under the GNU Affero General Public License v3 in order to prevent Canopy from being used in proprietary software or shitcoin scams.</p></article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,844 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: mediaHandler.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: mediaHandler.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 supposed to be 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,714 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: newPlaylistPopup</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: newPlaylistPopup</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>newPlaylistPopup<span class="signature">(event, client, doc)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class representing pop-up dialogue for creating a new playlist</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="newPlaylistPopup"><span class="type-signature"></span>new newPlaylistPopup<span class="signature">(event, client, doc)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a New Playlist Popup
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Parent Client Management Object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>doc</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Document</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Current owner documnet of the panel, so we know where to drop our pop-up</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line643">line 643</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management Object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line654">line 654</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="popup"><span class="type-signature"></span>popup<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
canopyUXUtils.popup() object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line661">line 661</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="asyncConstructor"><span class="type-signature"></span>asyncConstructor<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Continuation of object construction, called after child popup object construction
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line667">line 667</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="createPlaylist"><span class="type-signature"></span>createPlaylist<span class="signature">(event)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Sends request to create a playlist off to the server
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line689">line 689</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="setupInput"><span class="type-signature"></span>setupInput<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Defines input-related Event Handlers
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line679">line 679</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,918 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: panelObj</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: panelObj</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>panelObj<span class="signature">(client, name, pageURL, panelDocument)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Template Class for other Classes for Objects which represent a single Canopy Panel</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="panelObj"><span class="type-signature"></span>new panelObj<span class="signature">(client, name, pageURL, panelDocument)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a new Panel Object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
<th>Default</th>
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last">Parent client Management Object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>name</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
Placeholder Panel
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last">Panel Name</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>pageURL</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
/panel/placeholder
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last">Panel Default Page URL</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>panelDocument</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Document</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last">Panel Document</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line263">line 263</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line295">line 295</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="name"><span class="type-signature"></span>name<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Panel Name
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line275">line 275</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="ownerDoc"><span class="type-signature"></span>ownerDoc<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Current root document panel doc lives within
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line290">line 290</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="pageURL"><span class="type-signature"></span>pageURL<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Panel Default Page URL
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line280">line 280</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="panelDocument"><span class="type-signature"></span>panelDocument<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Panel Document
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line285">line 285</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="closer"><span class="type-signature"></span>closer<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Called upon panel close/exit
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line321">line 321</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="docSwitch"><span class="type-signature"></span>docSwitch<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Handles Document/Panel Changes
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line313">line 313</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="getPage"><span class="type-signature">(async) </span>getPage<span class="signature">()</span><span class="type-signature"> → {String}</span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Fetches panel page from the server
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="cpanel.js.html">cpanel.js</a>, <a href="cpanel.js.html#line302">line 302</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Returns:</h5>
|
||||
|
||||
|
||||
<div class="param-desc">
|
||||
Raw panel doc HTML
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
Type
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:58 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,362 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: panels/emotePanel.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: panels/emotePanel.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 representing Emote Panel UX
|
||||
* @extends panelObj
|
||||
*/
|
||||
class emotePanel extends panelObj{
|
||||
/**
|
||||
* Instantiates a new Panel Object
|
||||
* @param {channel} client - Parent client Management Object
|
||||
* @param {Document} panelDocument - Panel Document
|
||||
*/
|
||||
constructor(client, panelDocument){
|
||||
super(client, "Emote Palette", "/panel/emote", panelDocument);
|
||||
|
||||
this.client.socket.on("personalEmotes", this.renderEmoteLists.bind(this));
|
||||
}
|
||||
|
||||
closer(){
|
||||
this.client.socket.off("personalEmotes", this.renderEmoteLists.bind(this));
|
||||
}
|
||||
|
||||
docSwitch(){
|
||||
this.siteEmoteTitle = this.panelDocument.querySelector('#site-emotes-title');
|
||||
this.chanEmoteTitle = this.panelDocument.querySelector('#chan-emotes-title');
|
||||
this.personalEmoteTitle = this.panelDocument.querySelector('#personal-emotes-title');
|
||||
|
||||
this.siteEmoteToggle = this.panelDocument.querySelector('#site-emotes-toggle');
|
||||
this.chanEmoteToggle = this.panelDocument.querySelector('#chan-emotes-toggle');
|
||||
this.personalEmoteToggle = this.panelDocument.querySelector('#personal-emotes-toggle');
|
||||
|
||||
this.siteEmoteList = this.panelDocument.querySelector('#emote-panel-site-list');
|
||||
this.chanEmoteList = this.panelDocument.querySelector('#emote-panel-chan-list');
|
||||
this.personalEmoteSection = this.panelDocument.querySelector('#emote-panel-personal-section');
|
||||
this.personalEmoteList = this.panelDocument.querySelector('#emote-panel-personal-list');
|
||||
|
||||
this.searchPrompt = this.panelDocument.querySelector('#emote-panel-search-prompt');
|
||||
|
||||
this.personalEmoteLinkPrompt = this.panelDocument.querySelector('#new-emote-link-input');
|
||||
this.personalEmoteNamePrompt = this.panelDocument.querySelector('#new-emote-name-input');
|
||||
this.personalEmoteAddButton = this.panelDocument.querySelector('#new-emote-button');
|
||||
|
||||
this.setupInput();
|
||||
|
||||
this.renderEmoteLists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines input-related event handlers
|
||||
*/
|
||||
setupInput(){
|
||||
//Make sure to remove any event listeners in-case we moving an already instantiated panel
|
||||
this.siteEmoteToggle.removeEventListener("click", this.toggleSiteEmotes.bind(this));
|
||||
this.siteEmoteToggle.addEventListener("click", this.toggleSiteEmotes.bind(this));
|
||||
|
||||
this.chanEmoteToggle.removeEventListener("click", this.toggleChanEmotes.bind(this));
|
||||
this.chanEmoteToggle.addEventListener("click", this.toggleChanEmotes.bind(this));
|
||||
|
||||
this.personalEmoteToggle.removeEventListener("click", this.togglePersonalEmotes.bind(this));
|
||||
this.personalEmoteToggle.addEventListener("click", this.togglePersonalEmotes.bind(this));
|
||||
|
||||
this.siteEmoteTitle.removeEventListener("click", this.toggleSiteEmotes.bind(this));
|
||||
this.siteEmoteTitle.addEventListener("click", this.toggleSiteEmotes.bind(this));
|
||||
|
||||
this.chanEmoteTitle.removeEventListener("click", this.toggleChanEmotes.bind(this));
|
||||
this.chanEmoteTitle.addEventListener("click", this.toggleChanEmotes.bind(this));
|
||||
|
||||
this.personalEmoteTitle.removeEventListener("click", this.togglePersonalEmotes.bind(this));
|
||||
this.personalEmoteTitle.addEventListener("click", this.togglePersonalEmotes.bind(this));
|
||||
|
||||
this.searchPrompt.removeEventListener('keyup', this.renderEmoteLists.bind(this));
|
||||
this.searchPrompt.addEventListener('keyup', this.renderEmoteLists.bind(this));
|
||||
|
||||
this.personalEmoteAddButton.removeEventListener("click", this.addPersonalEmote.bind(this));
|
||||
this.personalEmoteAddButton.addEventListener("click", this.addPersonalEmote.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles Site emote display
|
||||
* @param {Event} event - Event passed down by event listener
|
||||
*/
|
||||
toggleSiteEmotes(event){
|
||||
this.toggleEmotes(this.siteEmoteToggle, this.siteEmoteList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles Channel emote display
|
||||
* @param {Event} event - Event passed down by event listener
|
||||
*/
|
||||
toggleChanEmotes(event){
|
||||
this.toggleEmotes(this.chanEmoteToggle, this.chanEmoteList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles Personal emote display
|
||||
* @param {Event} event - Event passed down by event listener
|
||||
*/
|
||||
togglePersonalEmotes(event){
|
||||
this.toggleEmotes(this.personalEmoteToggle, this.personalEmoteSection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles a specified emote list on or off
|
||||
* @param {Node} icon - Toggle Icon for given list
|
||||
* @param {Node} list - Emote list container to toggle
|
||||
*/
|
||||
toggleEmotes(icon, list){
|
||||
if(list.checkVisibility()){
|
||||
icon.classList.replace('bi-caret-down-fill','bi-caret-left-fill');
|
||||
list.style.display = 'none';
|
||||
}else{
|
||||
icon.classList.replace('bi-caret-left-fill', 'bi-caret-down-fill');
|
||||
list.style.display = 'grid';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates specified emote into chat prompt input
|
||||
* @param {String} emote - Emote to concat into chat
|
||||
*/
|
||||
useEmote(emote){
|
||||
//If we're using this from the active panel
|
||||
if(this.client.cPanel.activePanel == this){
|
||||
//Close it
|
||||
this.client.cPanel.hideActivePanel();
|
||||
}
|
||||
|
||||
//Add the emote to the chatbox prompt
|
||||
this.client.chatBox.catChat(`[${emote}]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests server to add emote to list of personal emotes
|
||||
* @param {Event} event - Event passed down by event listener
|
||||
*/
|
||||
addPersonalEmote(event){
|
||||
//Collect input
|
||||
const name = this.personalEmoteNamePrompt.value;
|
||||
const link = this.personalEmoteLinkPrompt.value;
|
||||
|
||||
//Empty out prompts
|
||||
this.personalEmoteNamePrompt.value = '';
|
||||
this.personalEmoteLinkPrompt.value = '';
|
||||
|
||||
//Send emote to server
|
||||
this.client.socket.emit("addPersonalEmote", {name, link});
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests server to remove emote from list of personal emotes
|
||||
* @param {String} name - Name of emote to delete
|
||||
*/
|
||||
deletePersonalEmote(name){
|
||||
//send out delete
|
||||
this.client.socket.emit('deletePersonalEmote', {name});
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders out emote list to panel document
|
||||
*/
|
||||
renderEmoteLists(){
|
||||
//if we've initialized the search prompt (wont happen yet first run)
|
||||
if(this.searchPrompt != null){
|
||||
//Get the search value
|
||||
var search = this.searchPrompt.value;
|
||||
}
|
||||
|
||||
//pull emote lists from the command preprocessor
|
||||
var siteEmotes = this.client.chatBox.commandPreprocessor.emotes.site;
|
||||
var chanEmotes = this.client.chatBox.commandPreprocessor.emotes.chan;
|
||||
var personalEmotes = this.client.chatBox.commandPreprocessor.emotes.personal;
|
||||
|
||||
//If we have a search bar and a search in the search bar
|
||||
if(search != null && search != ''){
|
||||
//filter emote lists using the filterQuery function
|
||||
siteEmotes = siteEmotes.filter(filterQuery);
|
||||
chanEmotes = chanEmotes.filter(filterQuery);
|
||||
personalEmotes = personalEmotes.filter(filterQuery);
|
||||
|
||||
function filterQuery(emote){
|
||||
//return true for anyany case-insensitive matches
|
||||
return (emote.name.toLowerCase().match(search.toLowerCase())) != null;
|
||||
}
|
||||
}
|
||||
|
||||
//render out the emote lists
|
||||
this.renderEmotes(siteEmotes, this.siteEmoteList);
|
||||
this.renderEmotes(chanEmotes, this.chanEmoteList);
|
||||
this.renderEmotes(personalEmotes, this.personalEmoteList, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders out emotes to emote lists
|
||||
* @param {Array} emoteList - list of emotes to render
|
||||
* @param {Node} container - Container to render emotes out to
|
||||
* @param {Boolean} personal - Denotes whether or not we're rendering personal emotes
|
||||
*/
|
||||
renderEmotes(emoteList, container, personal = false){
|
||||
//Clear out the container
|
||||
container.innerHTML = '';
|
||||
|
||||
//If we have two or less emotes
|
||||
if(emoteList.length <= 2){
|
||||
//Set the container display to flex
|
||||
container.style.display = 'flex';
|
||||
//otherwise
|
||||
}else{
|
||||
//Set the container display to grid
|
||||
container.style.display = 'grid';
|
||||
}
|
||||
|
||||
//For each emote
|
||||
emoteList.forEach((emote) => {
|
||||
//Create div to hold emote span
|
||||
const emoteDiv = document.createElement('div');
|
||||
emoteDiv.classList.add('emote-panel-list-emote');
|
||||
|
||||
const emoteSpan = document.createElement('span');
|
||||
emoteSpan.classList.add('emote-panel-list-emote');
|
||||
|
||||
//If we have a low emote count
|
||||
if(emoteList.length <= 2){
|
||||
//render them huuuuuge
|
||||
emoteDiv.classList.add('emote-panel-list-big-emote');
|
||||
emoteSpan.classList.add('emote-panel-list-big-emote');
|
||||
}
|
||||
|
||||
//If the emote is an image
|
||||
if(emote.type == 'image'){
|
||||
//Create image node
|
||||
var emoteMedia = document.createElement('img');
|
||||
//if emote is a video
|
||||
}else if(emote.type == 'video'){
|
||||
//create video node
|
||||
var emoteMedia = document.createElement('video');
|
||||
//Set video properties
|
||||
emoteMedia.autoplay = true;
|
||||
emoteMedia.muted = true;
|
||||
emoteMedia.controls = false;
|
||||
emoteMedia.loop = true;
|
||||
}
|
||||
|
||||
//set media link as source
|
||||
emoteMedia.src = emote.link;
|
||||
//Set media class
|
||||
emoteMedia.classList.add('emote-list-media');
|
||||
|
||||
//if we have a low emote count
|
||||
if(emoteList.length <= 2){
|
||||
//render them huuuuuge
|
||||
emoteMedia.classList.add('emote-list-big-media');
|
||||
}
|
||||
|
||||
|
||||
//Create paragraph tag
|
||||
const emoteTitle = document.createElement('p');
|
||||
//Set title class
|
||||
emoteTitle.classList.add('emote-list-title');
|
||||
//Set emote title
|
||||
emoteTitle.textContent = utils.unescapeEntities(`[${emote.name}]`);
|
||||
|
||||
//if we're rendering personal emotes
|
||||
if(personal){
|
||||
//create span to hold trash icon
|
||||
const trashSpan = document.createElement('span');
|
||||
trashSpan.classList.add('emote-list-trash-icon');
|
||||
|
||||
//Create trash icon
|
||||
const trashIcon = document.createElement('i');
|
||||
trashIcon.classList.add('emote-list-trash-icon', 'bi-trash-fill');
|
||||
trashIcon.id = `emote-list-trash-icon-${emote.name}`;
|
||||
|
||||
//add deletePersonalEmote event listener
|
||||
trashIcon.addEventListener('click', ()=>{this.deletePersonalEmote(emote.name)});
|
||||
|
||||
//Add trash icon to trash span
|
||||
trashSpan.appendChild(trashIcon);
|
||||
|
||||
//append trash span to emote div
|
||||
emoteDiv.appendChild(trashSpan);
|
||||
}
|
||||
|
||||
//Add the emote media to the emote span
|
||||
emoteSpan.appendChild(emoteMedia);
|
||||
//Add title paragraph node
|
||||
emoteSpan.appendChild(emoteTitle);
|
||||
|
||||
//Add useEmote event listener
|
||||
emoteSpan.addEventListener('click', ()=>{this.useEmote(emote.name)});
|
||||
|
||||
//Add emote span to the emote div
|
||||
emoteDiv.appendChild(emoteSpan);
|
||||
|
||||
//Append the mote span to the emote list
|
||||
container.appendChild(emoteDiv);
|
||||
})
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,992 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: panels/queuePanel/playlistManager.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: panels/queuePanel/playlistManager.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 representing Playlist Manager UX within the Queue Panel
|
||||
*/
|
||||
class playlistManager{
|
||||
|
||||
/**
|
||||
* Instantiates a new playlist manager
|
||||
* @param {channel} client - Parent Client Management Object
|
||||
* @param {Document} panelDocument - Panel Document
|
||||
* @param {queuePanel} queuePanel - Parent Queue Panel Object
|
||||
*/
|
||||
constructor(client, panelDocument, queuePanel){
|
||||
/**
|
||||
* Parent Client Management Object
|
||||
*/
|
||||
this.client = client;
|
||||
|
||||
/**
|
||||
* Panel Document
|
||||
*/
|
||||
this.panelDocument = panelDocument;
|
||||
|
||||
/**
|
||||
* Parent Queue Panel Object
|
||||
*/
|
||||
this.queuePanel = queuePanel;
|
||||
|
||||
/**
|
||||
* Map of which playlists are open and which are not, for better refresh handling
|
||||
*/
|
||||
this.openMap = {
|
||||
Channel: new Map(),
|
||||
User: new Map()
|
||||
};
|
||||
|
||||
//Define Listeners
|
||||
this.defineListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Network-Related Event Listeners
|
||||
*/
|
||||
defineListeners(){
|
||||
this.client.socket.on("chanPlaylists", this.renderChannelPlaylists.bind(this));
|
||||
this.client.socket.on("userPlaylists", this.renderUserPlaylists.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Up-stream Document/Panel Changes from the parent Queue Panel object
|
||||
*/
|
||||
docSwitch(){
|
||||
//Grab menus
|
||||
this.channelPlaylistDiv = this.panelDocument.querySelector("#queue-channel-playlist-div");
|
||||
this.userPlaylistDiv = this.panelDocument.querySelector("#queue-user-playlist-div");
|
||||
|
||||
//Grab controls
|
||||
this.createPlaylistSpan = this.panelDocument.querySelector('#queue-add-playlist-span');
|
||||
this.channelPlaylistLabel = this.panelDocument.querySelector('#queue-channel-playlist-span');
|
||||
this.channelPlaylistCaret = this.panelDocument.querySelector('#queue-channel-playlist-toggle');
|
||||
this.userPlaylistLabel = this.panelDocument.querySelector('#queue-user-playlist-span');
|
||||
this.userPlaylistCaret = this.panelDocument.querySelector('#queue-user-playlist-toggle');
|
||||
|
||||
//Force playlist re-render to fix controls
|
||||
this.client.socket.emit('getChannelPlaylists');
|
||||
this.client.socket.emit('getUserPlaylists');
|
||||
|
||||
//Setup Input
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Input-Related Event Listeners
|
||||
*/
|
||||
setupInput(){
|
||||
this.createPlaylistSpan.addEventListener('click', (event)=>{new newPlaylistPopup(event, this.client, this.queuePanel.ownerDoc)})
|
||||
this.channelPlaylistLabel.addEventListener('click', this.toggleChannelPlaylists.bind(this));
|
||||
this.userPlaylistLabel.addEventListener('click', this.toggleUserPlaylists.bind(this));
|
||||
}
|
||||
|
||||
/* queue control button functions */
|
||||
|
||||
/**
|
||||
* Toggle Channel Playlists
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
toggleChannelPlaylists(event){
|
||||
//If the div is hidden
|
||||
if(this.channelPlaylistDiv.style.display == 'none'){
|
||||
//Light up the button
|
||||
this.channelPlaylistLabel.classList.add('positive');
|
||||
//Flip the caret
|
||||
this.channelPlaylistCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
|
||||
//Show the div
|
||||
this.channelPlaylistDiv.style.display = '';
|
||||
}else{
|
||||
//Unlight the button
|
||||
this.channelPlaylistLabel.classList.remove('positive');
|
||||
//Flip the caret
|
||||
this.channelPlaylistCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
|
||||
//Hide the div
|
||||
this.channelPlaylistDiv.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle User Playlists
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
toggleUserPlaylists(event){
|
||||
//If the div is hidden
|
||||
if(this.userPlaylistDiv.style.display == 'none'){
|
||||
//Light up the button
|
||||
this.userPlaylistLabel.classList.add('positive');
|
||||
//Flip the caret
|
||||
this.userPlaylistCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
|
||||
//Show the div
|
||||
this.userPlaylistDiv.style.display = '';
|
||||
}else{
|
||||
//Unlight the button
|
||||
this.userPlaylistLabel.classList.remove('positive');
|
||||
//Flip the caret
|
||||
this.userPlaylistCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
|
||||
//Hide the div
|
||||
this.userPlaylistDiv.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks which playlists where open before a refresh and re-opens them
|
||||
* @param {String} location - Whether or not we're dealing with user or channel playlists
|
||||
*/
|
||||
checkOpenPlaylists(location){
|
||||
//If open map is a string, indicating we just renamed a playlist with it's media open
|
||||
if(typeof this.openMap[location] == 'string'){
|
||||
//Create new map to hold status with the new name of the renamed playlist already added
|
||||
this.openMap[location] = new Map([[this.openMap[location], true]]);
|
||||
}else{
|
||||
//Create new map to hold status
|
||||
this.openMap[location] = new Map();
|
||||
}
|
||||
|
||||
let mediaContainerDivs = [];
|
||||
|
||||
if(location == 'Channel'){
|
||||
mediaContainerDivs = this.channelPlaylistDiv.querySelectorAll('.queue-playlist-media-container-div')
|
||||
}else{
|
||||
mediaContainerDivs = this.userPlaylistDiv.querySelectorAll('.queue-playlist-media-container-div')
|
||||
}
|
||||
|
||||
//For each container Div rendered
|
||||
for(let containerDiv of mediaContainerDivs){
|
||||
//Set whether or not it's visible in the map
|
||||
this.openMap[location].set(containerDiv.dataset['playlist'], (containerDiv.style.display != 'none'));
|
||||
}
|
||||
}
|
||||
|
||||
//Main playlist rendering functions
|
||||
|
||||
/**
|
||||
* Renders Channel Playlist list
|
||||
* @param {Object} data - Data from server
|
||||
*/
|
||||
renderChannelPlaylists(data){
|
||||
//Check for open playlists
|
||||
this.checkOpenPlaylists('Channel');
|
||||
|
||||
//Clear channel playlist div
|
||||
this.channelPlaylistDiv.innerHTML = '';
|
||||
|
||||
//Append rendered playlists
|
||||
this.channelPlaylistDiv.append(...this.renderPlaylists(data, 'Channel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders User Playlist list
|
||||
* @param {Object} data - Data from server
|
||||
*/
|
||||
renderUserPlaylists(data){
|
||||
//Check for open playlists
|
||||
this.checkOpenPlaylists('User');
|
||||
|
||||
//Clear channel playlist div
|
||||
this.userPlaylistDiv.innerHTML = '';
|
||||
|
||||
//Append rendered playlists
|
||||
this.userPlaylistDiv.append(...this.renderPlaylists(data, 'User'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render set of playlists out to Playlist Management Menu
|
||||
* @param {Object} data - Data from server
|
||||
* @param {String} location - Location to load from, either Channel or User
|
||||
* @returns {Node} Rendered out playlist list
|
||||
*/
|
||||
renderPlaylists(data, location){
|
||||
const playlists = [];
|
||||
|
||||
//For every playlist sent down from the server
|
||||
for(let playlistIndex in data){
|
||||
//Get playlist from data
|
||||
const playlist = data[playlistIndex];
|
||||
|
||||
//Create a new playlist div
|
||||
const playlistDiv = document.createElement('div');
|
||||
//Set it's class
|
||||
playlistDiv.classList.add('queue-playlist-div');
|
||||
|
||||
//Create span to hold playlist entry line contents
|
||||
const playlistSpan = document.createElement('span');
|
||||
//Set classes
|
||||
playlistSpan.classList.add('queue-playlist-span');
|
||||
|
||||
//If this isn't our first rodeo
|
||||
if(playlistIndex != 0){
|
||||
//make note
|
||||
playlistSpan.classList.add('not-first');
|
||||
}
|
||||
|
||||
//assemble playlist entry line
|
||||
playlistSpan.append(
|
||||
this.renderLabels(playlist, location),
|
||||
this.renderControls(playlist, location)
|
||||
);
|
||||
|
||||
//assemble playlist div
|
||||
playlistDiv.append(
|
||||
playlistSpan,
|
||||
this.renderMedia(playlist, location),
|
||||
);
|
||||
|
||||
//add playlist div to playlists array
|
||||
playlists.push(playlistDiv);
|
||||
}
|
||||
|
||||
return playlists;
|
||||
}
|
||||
|
||||
//aux rendering functions
|
||||
/**
|
||||
* Renders Playlist labels
|
||||
* @param {Object} playlist - Playlist from server to render label for
|
||||
* @param {String} location - Location of playlist (Channel or User)
|
||||
* @returns {Node} Rendered out playlist label
|
||||
*/
|
||||
renderLabels(playlist, location){
|
||||
//Create playlist label span
|
||||
const playlistLabels = document.createElement('span');
|
||||
//Set it's class
|
||||
playlistLabels.classList.add('queue-playlist-labels-span');
|
||||
|
||||
//create playlist title span
|
||||
const playlistTitleSpan = document.createElement('span');
|
||||
//Set class
|
||||
playlistTitleSpan.classList.add('queue-playlist-title-span', 'interactive');
|
||||
|
||||
//Create playlist title caret
|
||||
const playlistTitleCaret = document.createElement('i');
|
||||
|
||||
//If this is supposed to be open
|
||||
if(this.openMap[location].get(playlist.name)){
|
||||
//Set class accordingly
|
||||
playlistTitleSpan.classList.add('positive');
|
||||
playlistTitleCaret.classList.add('bi-caret-down-fill');
|
||||
//otherwise
|
||||
}else{
|
||||
//Set class accordingly
|
||||
playlistTitleCaret.classList.add('bi-caret-right-fill');
|
||||
}
|
||||
|
||||
//Create playlist title label
|
||||
const playlistTitle = document.createElement('p');
|
||||
//Set it's class
|
||||
playlistTitle.classList.add('queue-playlist-title');
|
||||
//Unescape Sanatized Enteties and safely inject as plaintext
|
||||
playlistTitle.innerText = utils.unescapeEntities(playlist.name);
|
||||
|
||||
//Construct playlist title span
|
||||
playlistTitleSpan.appendChild(playlistTitleCaret);
|
||||
playlistTitleSpan.appendChild(playlistTitle);
|
||||
|
||||
//Create playlist count label
|
||||
const playlistCount = document.createElement('p');
|
||||
//Set it's class
|
||||
playlistCount.classList.add('queue-playlist-count');
|
||||
//List video count
|
||||
playlistCount.innerText = `Count: ${playlist.media.length}`;
|
||||
|
||||
//Append items to playlist labels span
|
||||
playlistLabels.appendChild(playlistTitleSpan);
|
||||
playlistLabels.appendChild(playlistCount);
|
||||
|
||||
//Define input listeners
|
||||
playlistTitleSpan.addEventListener('click', this.toggleMedia.bind(this));
|
||||
|
||||
return playlistLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders out Playlist Controls
|
||||
* @param {Object} playlist - Playlist from server to render label for
|
||||
* @param {String} location - Location of playlist (Channel or User)
|
||||
* @returns {Node} Rendered out playlist controls
|
||||
*/
|
||||
renderControls(playlist, location){
|
||||
//Create playlist control span
|
||||
const playlistControls = document.createElement('span');
|
||||
//Set it's class
|
||||
playlistControls.classList.add('queue-playlist-control-span');
|
||||
//Set dataset
|
||||
playlistControls.dataset['playlist'] = playlist.name;
|
||||
playlistControls.dataset['location'] = location;
|
||||
|
||||
//Create queue all button
|
||||
const playlistQueueRandomButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistQueueRandomButton.classList.add('queue-playlist-queue-random-button', 'queue-playlist-control');
|
||||
//Inject text content
|
||||
playlistQueueRandomButton.textContent = 'Random';
|
||||
//Set title
|
||||
playlistQueueRandomButton.title = 'Queue Random Item from Playlist';
|
||||
|
||||
//Create queue all button
|
||||
const playlistQueueAllButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistQueueAllButton.classList.add('queue-playlist-queue-all-button', 'queue-playlist-control', 'not-first');
|
||||
//Inject text content
|
||||
playlistQueueAllButton.textContent = 'All';
|
||||
//Set title
|
||||
playlistQueueAllButton.title = 'Queue Entire Playlist';
|
||||
|
||||
//Create add from URL button
|
||||
const playlistAddURLButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistAddURLButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'positive-button', 'not-first');
|
||||
//Set Tile
|
||||
playlistAddURLButton.title = 'Add To Playlist From URL'
|
||||
|
||||
//Create playlist icons (we're using two so we're putting them inside the button :P)
|
||||
const playlistAddIcon = document.createElement('i');
|
||||
const playlistLinkIcon = document.createElement('i');
|
||||
//set classes
|
||||
playlistAddIcon.classList.add('bi-plus-lg');
|
||||
playlistLinkIcon.classList.add('bi-link-45deg');
|
||||
|
||||
//Append icons to URL button
|
||||
playlistAddURLButton.appendChild(playlistAddIcon);
|
||||
playlistAddURLButton.appendChild(playlistLinkIcon);
|
||||
|
||||
//Create default titles button
|
||||
const playlistDefaultTitlesButton = document.createElement('button');
|
||||
//Set classes
|
||||
playlistDefaultTitlesButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-tags-fill', 'positive-button', 'not-first');
|
||||
//Set title
|
||||
playlistDefaultTitlesButton.title = 'Change Default Titles'
|
||||
//Set dataset
|
||||
playlistDefaultTitlesButton.dataset['titles'] = JSON.stringify(playlist.defaultTitles);
|
||||
|
||||
//Create rename button
|
||||
const playlistRenameButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistRenameButton.classList.add('queue-playlist-add-url-button', 'queue-playlist-control', 'bi-input-cursor-text', 'positive-button', 'not-first');
|
||||
//Set title
|
||||
playlistRenameButton.title = 'Rename Playlist'
|
||||
|
||||
//Create delete button
|
||||
const playlistDeleteButton = document.createElement('button');
|
||||
//Set it's classes
|
||||
playlistDeleteButton.classList.add('queue-playlist-delete-button', 'queue-playlist-control', 'danger-button', 'bi-trash-fill', 'not-first');
|
||||
//Set title
|
||||
playlistDeleteButton.title = 'Delete Playlist'
|
||||
|
||||
//Append items to playlist control span
|
||||
playlistControls.append(
|
||||
playlistQueueRandomButton,
|
||||
playlistQueueAllButton,
|
||||
playlistAddURLButton,
|
||||
playlistDefaultTitlesButton,
|
||||
playlistRenameButton,
|
||||
playlistDeleteButton
|
||||
);
|
||||
|
||||
//Define input event listeners
|
||||
playlistAddURLButton.addEventListener('click', this.addURL.bind(this));
|
||||
playlistDefaultTitlesButton.addEventListener('click', this.editDefaultTitles.bind(this));
|
||||
playlistRenameButton.addEventListener('click', this.renamePlaylist.bind(this));
|
||||
playlistQueueRandomButton.addEventListener('click', this.queueRandom.bind(this));
|
||||
playlistQueueAllButton.addEventListener('click', this.queueAll.bind(this));
|
||||
playlistDeleteButton.addEventListener('click', this.deletePlaylist.bind(this));
|
||||
|
||||
return playlistControls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders media object out for an entire playlist
|
||||
* @param {Object} playlist - Playlist from server to render label for
|
||||
* @param {String} location - Location of playlist (Channel or User)
|
||||
* @returns {Node} Rendered out playlist
|
||||
*/
|
||||
renderMedia(playlist, location){
|
||||
//Create media container div
|
||||
const mediaContainer = document.createElement('div');
|
||||
//Set classes
|
||||
mediaContainer.classList.add('queue-playlist-media-container-div');
|
||||
|
||||
//If the playlist wasn't set to open in the open map
|
||||
if(!this.openMap[location].get(playlist.name)){
|
||||
//Auto-hide media container
|
||||
mediaContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
//Set dataset
|
||||
mediaContainer.dataset['playlist'] = playlist.name;
|
||||
|
||||
for(let mediaIndex in playlist.media){
|
||||
//Grab media object from playlist
|
||||
const media = playlist.media[mediaIndex];
|
||||
|
||||
//Sanatize title text
|
||||
const title = utils.unescapeEntities(media.title);
|
||||
|
||||
//Create media div
|
||||
const mediaDiv = document.createElement('div');
|
||||
//Set class
|
||||
mediaDiv.classList.add('queue-playlist-media-div');
|
||||
//Inject title
|
||||
mediaDiv.title = title;
|
||||
|
||||
//If this isn't our first rodeo
|
||||
if(mediaIndex != 0){
|
||||
mediaDiv.classList.add('not-first');
|
||||
}
|
||||
|
||||
|
||||
//Create media title
|
||||
const mediaTitle = document.createElement('p');
|
||||
//Set class
|
||||
mediaTitle.classList.add('queue-playlist-media-title');
|
||||
//Inject text content
|
||||
mediaTitle.innerText = title;
|
||||
|
||||
//Append items to media div
|
||||
mediaDiv.append(
|
||||
mediaTitle,
|
||||
this.renderMediaControls(media, playlist, location)
|
||||
);
|
||||
|
||||
|
||||
//Append media div to media container
|
||||
mediaContainer.appendChild(mediaDiv);
|
||||
}
|
||||
|
||||
//return media container
|
||||
return mediaContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders controls out for a single media entry within a playlist
|
||||
* @param {Object} media - Media object from playlist to render controls for
|
||||
* @param {Object} playlist - Playlist from server to render label for
|
||||
* @param {String} location - Location of playlist (Channel or User)
|
||||
* @returns {Node} Rendered out playlist
|
||||
*/
|
||||
renderMediaControls(media, playlist, location){
|
||||
//Create media control span
|
||||
const mediaControlSpan = document.createElement('span');
|
||||
//Set it's class
|
||||
mediaControlSpan.classList.add('queue-playlist-media-control-span');
|
||||
//Set dataset
|
||||
mediaControlSpan.dataset['playlist'] = playlist.name;
|
||||
mediaControlSpan.dataset['uuid'] = media.uuid;
|
||||
mediaControlSpan.dataset['location'] = location;
|
||||
|
||||
//Create Queue Media icon
|
||||
const queueMediaIcon = document.createElement('i');
|
||||
//set class
|
||||
queueMediaIcon.classList.add('queue-playlist-control', 'queue-playlist-media-queue-icon', 'bi-play-circle');
|
||||
//Set title
|
||||
queueMediaIcon.title = (`Queue '${media.title}'`);
|
||||
|
||||
//Create delete media icon
|
||||
const deleteMediaIcon = document.createElement('i');
|
||||
//set class
|
||||
deleteMediaIcon.classList.add('queue-playlist-control', 'queue-playlist-media-delete-icon', 'danger-text', 'bi-trash-fill');
|
||||
//Set title
|
||||
deleteMediaIcon.title = `Delete '${media.title}' from playlist '${playlist.name}'`;
|
||||
|
||||
//Append items to media control span
|
||||
mediaControlSpan.appendChild(queueMediaIcon);
|
||||
mediaControlSpan.appendChild(deleteMediaIcon);
|
||||
|
||||
//Handle input event listeners
|
||||
queueMediaIcon.addEventListener('click', this.queueMedia.bind(this));
|
||||
deleteMediaIcon.addEventListener('click', this.deleteMedia.bind(this));
|
||||
|
||||
//Return media control span
|
||||
return mediaControlSpan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle Media List
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
toggleMedia(event){
|
||||
//Grab playlist title caret
|
||||
const playlistTitleCaret = event.target.querySelector('i');
|
||||
//I hope my mother doesn't see this next line, god I hate dot crawling...
|
||||
const mediaContainer = event.target.parentNode.parentNode.nextElementSibling;
|
||||
|
||||
//If the div is hidden
|
||||
if(mediaContainer.style.display == 'none'){
|
||||
//Light up the button
|
||||
event.target.classList.add('positive');
|
||||
//Flip the caret
|
||||
playlistTitleCaret.classList.replace('bi-caret-right-fill', 'bi-caret-down-fill');
|
||||
//Show the div
|
||||
mediaContainer.style.display = '';
|
||||
}else{
|
||||
//Unlight the button
|
||||
event.target.classList.remove('positive');
|
||||
//Flip the caret
|
||||
playlistTitleCaret.classList.replace('bi-caret-down-fill', 'bi-caret-right-fill');
|
||||
//Hide the div
|
||||
mediaContainer.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add URL to playlist
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
addURL(event){
|
||||
new addURLPopup(
|
||||
event,
|
||||
event.target.parentNode.dataset['playlist'],
|
||||
event.target.parentNode.dataset['location'],
|
||||
this.client,
|
||||
this.queuePanel.ownerDoc
|
||||
);
|
||||
}
|
||||
|
||||
//playlist control functions
|
||||
|
||||
/**
|
||||
* Sends request to server to edit default titles
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
editDefaultTitles(event){
|
||||
new defaultTitlesPopup(
|
||||
event,
|
||||
event.target.parentNode.dataset['playlist'],
|
||||
JSON.parse(event.target.dataset['titles']),
|
||||
event.target.parentNode.dataset['location'],
|
||||
this.client,
|
||||
this.queuePanel.ownerDoc
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to server to rename playlists
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
renamePlaylist(event){
|
||||
new renamePopup(
|
||||
event,
|
||||
event.target.parentNode.dataset['playlist'],
|
||||
this.client,
|
||||
this.queuePanel.ownerDoc,
|
||||
handleOpenedMedia.bind(this)
|
||||
);
|
||||
|
||||
function handleOpenedMedia(newName){
|
||||
//do an ugly dot crawl to get the media container div
|
||||
const mediaContainer = event.target.parentNode.parentNode.nextElementSibling;
|
||||
|
||||
//If the media container is visible
|
||||
if(mediaContainer.style.display != 'none'){
|
||||
//Set openMap to new name indicating the new playlist has it's media opened
|
||||
this.openMap[event.target.parentNode.dataset['location']] = newName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to server to queue all playlist items
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
queueAll(event){
|
||||
this.client.socket.emit(`queue${event.target.parentNode.dataset['location']}Playlist`, {playlist: event.target.parentNode.dataset['playlist']});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to server to queue a playlist item
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
queueMedia(event){
|
||||
this.client.socket.emit(`queueFrom${event.target.parentNode.dataset['location']}Playlist`,{playlist: event.target.parentNode.dataset['playlist'], uuid: event.target.parentNode.dataset['uuid']});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to server to queue a random playlist item
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
queueRandom(event){
|
||||
this.client.socket.emit(`queueRandomFrom${event.target.parentNode.dataset['location']}Playlist`,{playlist: event.target.parentNode.dataset['playlist']});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to server to delete a playlist
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
deletePlaylist(event){
|
||||
this.client.socket.emit(`delete${event.target.parentNode.dataset['location']}Playlist`, {playlist: event.target.parentNode.dataset['playlist']});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to server to delete a playlist item
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
deleteMedia(event ){
|
||||
this.client.socket.emit(`delete${event.target.parentNode.dataset['location']}PlaylistMedia`, {playlist: event.target.parentNode.dataset['playlist'], uuid: event.target.parentNode.dataset['uuid']});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing pop-up dialogue for creating a new playlist
|
||||
*/
|
||||
class newPlaylistPopup{
|
||||
/**
|
||||
* Instantiates a New Playlist Popup
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
* @param {channel} client - Parent Client Management Object
|
||||
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
|
||||
*/
|
||||
constructor(event, client, doc){
|
||||
/**
|
||||
* Parent Client Management Object
|
||||
*/
|
||||
this.client = client;
|
||||
|
||||
//Create media popup and call async constructor when done
|
||||
//unfortunately we cant call constructors asyncronously, and we cant call back to this from super, so we can't extend this as it stands :(
|
||||
/**
|
||||
* canopyUXUtils.popup() object
|
||||
*/
|
||||
this.popup = new canopyUXUtils.popup('/newPlaylist', true, this.asyncConstructor.bind(this), doc, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continuation of object construction, called after child popup object construction
|
||||
*/
|
||||
asyncConstructor(){
|
||||
this.name = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-name');
|
||||
this.defaultTitles = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-default-titles');
|
||||
this.location = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-location');
|
||||
this.saveButton = this.popup.contentDiv.querySelector('#queue-create-playlist-popup-save');
|
||||
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines input-related Event Handlers
|
||||
*/
|
||||
setupInput(){
|
||||
//Setup input
|
||||
this.saveButton.addEventListener('click', this.createPlaylist.bind(this));
|
||||
this.popup.popupDiv.addEventListener('keydown', this.createPlaylist.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to create a playlist off to the server
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
createPlaylist(event){
|
||||
//If we clicked or hit enter
|
||||
if(event.key == null || (event.key == "Enter" && this.defaultTitles !== this.popup.doc.activeElement)){
|
||||
|
||||
//Tell the server to create a new playlist
|
||||
this.client.socket.emit(`create${this.location.value}Playlist`, {
|
||||
playlist: this.name.value,
|
||||
defaultTitles: this.defaultTitles.value.split('\n')
|
||||
});
|
||||
|
||||
//Close the popup
|
||||
this.popup.closePopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing pop-up dialogue which adds media to a given playlist
|
||||
*/
|
||||
class addURLPopup{
|
||||
/**
|
||||
* Instantiates a new Add URL Pop-up
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
* @param {String} playlist - Playlist name
|
||||
* @param {String} location - Location of playlist, either Channel or User
|
||||
* @param {channel} client - Parent Client Management Object
|
||||
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
|
||||
*/
|
||||
constructor(event, playlist, location, client, doc){
|
||||
/**
|
||||
* Parent Client Management Object
|
||||
*/
|
||||
this.client = client;
|
||||
|
||||
/**
|
||||
* Playlist Name
|
||||
*/
|
||||
this.playlist = playlist
|
||||
|
||||
/**
|
||||
* Location of playlist, either Channel or User
|
||||
*/
|
||||
this.location = location;
|
||||
|
||||
//Create media popup and call async constructor when done
|
||||
//unfortunately we cant call constructors asyncronously, and we cant call back to this from super, so we can't extend this as it stands :(
|
||||
/**
|
||||
* canopyUXUtils.popup() object
|
||||
*/
|
||||
this.popup = new canopyUXUtils.popup('/addToPlaylist', true, this.asyncConstructor.bind(this), doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continuation of object construction, called after child popup object construction
|
||||
*/
|
||||
asyncConstructor(){
|
||||
this.urlPrompt = this.popup.contentDiv.querySelector('#playlist-add-media-popup-prompt');
|
||||
this.addButton = this.popup.contentDiv.querySelector('#playlist-add-media-popup-button');
|
||||
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines input-related Event Handlers
|
||||
*/
|
||||
setupInput(){
|
||||
//Setup input
|
||||
this.addButton.addEventListener('click', this.addToPlaylist.bind(this));
|
||||
this.popup.popupDiv.addEventListener('keydown', this.addToPlaylist.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sending request to add to a playlist to the server
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
addToPlaylist(event){
|
||||
//If we clicked or hit enter
|
||||
if(event.key == null || event.key == "Enter"){
|
||||
|
||||
//Tell the server to add url to the playlist
|
||||
this.client.socket.emit(`addTo${this.location}Playlist`, {
|
||||
//this.client.socket.emit(`addToChannelPlaylist`, {
|
||||
playlist: this.playlist,
|
||||
url: this.urlPrompt.value
|
||||
});
|
||||
|
||||
//Close the popup
|
||||
this.popup.closePopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Representing popup dialogue for changing playlists defualt titles
|
||||
*/
|
||||
class defaultTitlesPopup{
|
||||
/**
|
||||
* Instantiates a new Default Titles Popup
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
* @param {String} playlist - Playlist name
|
||||
* @param {String} titles - List of titles, denoted by newlines
|
||||
* @param {String} location - Location of playlist, either Channel or User
|
||||
* @param {channel} client - Parent Client Management Object
|
||||
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
|
||||
*/
|
||||
constructor(event, playlist, titles, location, client, doc){
|
||||
/**
|
||||
* Parent Client Management Object
|
||||
*/
|
||||
this.client = client;
|
||||
|
||||
/**
|
||||
* Playlist Name
|
||||
*/
|
||||
this.playlist = playlist
|
||||
|
||||
/**
|
||||
* Location of playlist, either Channel or User
|
||||
*/
|
||||
this.location = location;
|
||||
|
||||
/**
|
||||
* Array of titles to set
|
||||
*/
|
||||
this.titles = titles.join('\n');
|
||||
|
||||
//Create media popup and call async constructor when done
|
||||
//unfortunately we cant call constructors asyncronously, and we cant call back to this from super, so we can't extend this as it stands :(
|
||||
/**
|
||||
* canopyUXUtils.popup() object
|
||||
*/
|
||||
this.popup = new canopyUXUtils.popup('/playlistDefaultTitles', true, this.asyncConstructor.bind(this), doc, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continuation of object construction, called after child popup object construction
|
||||
*/
|
||||
asyncConstructor(){
|
||||
this.titlePrompt = this.popup.contentDiv.querySelector('#playlist-default-titles-popup-prompt');
|
||||
this.titleButton = this.popup.contentDiv.querySelector('#playlist-default-media-popup-button');
|
||||
|
||||
this.titlePrompt.textContent = utils.unescapeEntities(this.titles);
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines input-related Event Handlers
|
||||
*/
|
||||
setupInput(){
|
||||
//Setup input
|
||||
this.titleButton.addEventListener('click', this.changeDefaultTitles.bind(this));
|
||||
this.popup.popupDiv.addEventListener('keydown', this.changeDefaultTitles.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sending request to change default titles of playlist to the server
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
changeDefaultTitles(event){
|
||||
//If we clicked or hit enter while the prompt wasn't active
|
||||
if(event.key == null || (event.key == "Enter" && this.titlePrompt !== this.popup.doc.activeElement)){
|
||||
|
||||
//Tell the server to change the titles
|
||||
this.client.socket.emit(`changeDefaultTitles${this.location}Playlist`, {
|
||||
playlist: this.playlist,
|
||||
defaultTitles: this.titlePrompt.value.split('\n')
|
||||
});
|
||||
|
||||
//Close the popup
|
||||
this.popup.closePopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing pop-up dialogue to rename a playlist
|
||||
*/
|
||||
class renamePopup{
|
||||
/**
|
||||
* Instantiates a new Rename Pop-up
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
* @param {String} playlist - Playlist name
|
||||
* @param {channel} client - Parent Client Management Object
|
||||
* @param {Document} doc - Current owner documnet of the panel, so we know where to drop our pop-up
|
||||
* @param {Function} cb - Callback function, passed new name upon rename
|
||||
*/
|
||||
constructor(event, playlist, client, doc, cb){
|
||||
/**
|
||||
* Parent Client Management Object
|
||||
*/
|
||||
this.client = client;
|
||||
|
||||
/**
|
||||
* Playlist Name
|
||||
*/
|
||||
this.playlist = playlist
|
||||
|
||||
/**
|
||||
* Callback Function, passed new name upon rename
|
||||
*/
|
||||
this.cb = cb;
|
||||
|
||||
//Create media popup and call async constructor when done
|
||||
//unfortunately we cant call constructors asyncronously, and we cant call back to this from super, so we can't extend this as it stands :(
|
||||
/**
|
||||
* canopyUXUtils.popup() object
|
||||
*/
|
||||
this.popup = new canopyUXUtils.popup('/renamePlaylist', true, this.asyncConstructor.bind(this), doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continuation of object construction, called after child popup object construction
|
||||
*/
|
||||
asyncConstructor(){
|
||||
this.renamePrompt = this.popup.contentDiv.querySelector('#playlist-rename-popup-prompt');
|
||||
this.renameButton = this.popup.contentDiv.querySelector('#playlist-rename-popup-button');
|
||||
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines input-related Event Handlers
|
||||
*/
|
||||
setupInput(){
|
||||
//Setup input
|
||||
this.renameButton.addEventListener('click', this.renamePlaylist.bind(this));
|
||||
this.popup.popupDiv.addEventListener('keydown', this.renamePlaylist.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sending request to rename playlist to the server
|
||||
* @param {Event} event - Event passed down from Event Listener
|
||||
*/
|
||||
renamePlaylist(event){
|
||||
//If we clicked or hit enter while the prompt wasn't active
|
||||
if(event.key == null || event.key == "Enter"){
|
||||
|
||||
//Tell the server to change the titles
|
||||
this.client.socket.emit('renameChannelPlaylist', {
|
||||
playlist: this.playlist,
|
||||
name: this.renamePrompt.value
|
||||
});
|
||||
|
||||
//if CB is a function
|
||||
if(typeof this.cb == 'function'){
|
||||
//Hand it back the new name
|
||||
this.cb(this.renamePrompt.value);
|
||||
}
|
||||
|
||||
//Close the popup
|
||||
this.popup.closePopup();
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: panels/settingsPanel.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: panels/settingsPanel.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 representing the settings panel
|
||||
* @extends panelObj
|
||||
*/
|
||||
class settingsPanel extends panelObj{
|
||||
/**
|
||||
* Instantiates a new Panel Object
|
||||
* @param {channel} client - Parent client Management Object
|
||||
* @param {Document} panelDocument - Panel Document
|
||||
*/
|
||||
constructor(client, panelDocument){
|
||||
super(client, "Client Settings", "/panel/settings", panelDocument);
|
||||
}
|
||||
|
||||
closer(){
|
||||
}
|
||||
|
||||
docSwitch(){
|
||||
/**
|
||||
* Youtube Source Selector
|
||||
*/
|
||||
this.youtubeSource = this.panelDocument.querySelector("#settings-panel-youtube-source select");
|
||||
|
||||
/**
|
||||
* Internet Archive CDN Server Input
|
||||
*/
|
||||
this.iaCDN = this.panelDocument.querySelector("#settings-panel-ia-server input");
|
||||
|
||||
/**
|
||||
* Syncronization Tolerance Input
|
||||
*/
|
||||
this.syncTolerance = this.panelDocument.querySelector("#settings-panel-sync-tolerance input");
|
||||
|
||||
/**
|
||||
* Livestream Syncronization Tolerance Input
|
||||
*/
|
||||
this.liveSyncTolerance = this.panelDocument.querySelector("#settings-panel-live-sync-tolerance input");
|
||||
|
||||
/**
|
||||
* Syncronization Tolerance Delta
|
||||
*/
|
||||
this.syncDelta = this.panelDocument.querySelector("#settings-panel-sync-delta input");
|
||||
|
||||
/**
|
||||
* Chat Width Minimum while Size-Locked to Media Aspect Ratio
|
||||
*/
|
||||
this.chatWidthMinimum = this.panelDocument.querySelector("#settings-panel-min-chat-width input");
|
||||
|
||||
this.renderSettings();
|
||||
this.setupInput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines input-related event handlers
|
||||
*/
|
||||
setupInput(){
|
||||
this.youtubeSource.addEventListener('change', this.updateYoutubeSource.bind(this));
|
||||
this.iaCDN.addEventListener('keydown', this.updateIACDN.bind(this));
|
||||
this.syncTolerance.addEventListener('change', this.updateSyncTolerance.bind(this));
|
||||
this.liveSyncTolerance.addEventListener('change', this.updateLiveSyncTolerance.bind(this));
|
||||
this.syncDelta.addEventListener('change', this.updateSyncDelta.bind(this));
|
||||
this.chatWidthMinimum.addEventListener('change', this.updateChatWidthMinimum.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders actual user settings state into panel display
|
||||
*/
|
||||
renderSettings(){
|
||||
this.youtubeSource.value = localStorage.getItem("ytPlayerType");
|
||||
this.iaCDN.value = localStorage.getItem("IACDN");
|
||||
this.syncTolerance.value = localStorage.getItem("syncTolerance");
|
||||
this.liveSyncTolerance.value = localStorage.getItem("liveSyncTolerance");
|
||||
this.syncDelta.value = localStorage.getItem("syncDelta");
|
||||
this.chatWidthMinimum.value = localStorage.getItem("chatWidthMin");
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for Youtube Source selector
|
||||
*/
|
||||
updateYoutubeSource(){
|
||||
localStorage.setItem("ytPlayerType", this.youtubeSource.value);
|
||||
client.processConfig("ytPlayerType", this.youtubeSource.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for Internet Archive CDN Server input
|
||||
* @param {Event} event - Event handed down by event listener
|
||||
*/
|
||||
updateIACDN(event){
|
||||
//If we hit enter
|
||||
if(event.key == "Enter"){
|
||||
//If we have an invalid server string
|
||||
if(!(this.iaCDN.value.match(/^ia[0-9]{6}\...$/g) || this.iaCDN.value == "")){
|
||||
//reset back to what was set before
|
||||
this.iaCDN.value = localStorage.getItem('IACDN');
|
||||
|
||||
//BAIL!
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("IACDN", this.iaCDN.value);
|
||||
client.processConfig("IACDN", this.iaCDN.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Sync Tolerance Changes
|
||||
*/
|
||||
updateSyncTolerance(){
|
||||
//If sync tolerance was set to a negative number
|
||||
if(this.syncTolerance.value < 0){
|
||||
//Reset setting back to stored value
|
||||
this.syncTolerance.value = localStorage.getItem('syncTolerance');
|
||||
|
||||
//BAIL!
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("syncTolerance", this.syncTolerance.value);
|
||||
client.processConfig("syncTolerance", this.syncTolerance.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Live Sync Tolerance Changes
|
||||
*/
|
||||
updateLiveSyncTolerance(){
|
||||
//If sync tolerance was set to a negative number
|
||||
if(this.liveSyncTolerance.value < 0){
|
||||
//Reset setting back to stored value
|
||||
this.liveSyncTolerance.value = localStorage.getItem('liveSyncTolerance');
|
||||
|
||||
//BAIL!
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("liveSyncTolerance", this.liveSyncTolerance.value);
|
||||
client.processConfig("liveSyncTolerance", this.liveSyncTolerance.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Sync Delta Changes
|
||||
*/
|
||||
updateSyncDelta(){
|
||||
//If sync tolerance was set to a negative number
|
||||
if(this.syncDelta.value < 0){
|
||||
//Reset setting back to stored value
|
||||
this.syncDelta.value = localStorage.getItem('syncDelta');
|
||||
|
||||
//BAIL!
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("syncDelta", this.syncDelta.value);
|
||||
client.processConfig("syncDelta", this.syncDelta.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Chat Width minimum Changes
|
||||
*/
|
||||
updateChatWidthMinimum(){
|
||||
//If sync tolerance was set to a negative number
|
||||
if(this.chatWidthMinimum.value < 0 || this.chatWidthMinimum > 100){
|
||||
//Reset setting back to stored value
|
||||
this.syncDelta.value = localStorage.getItem('chatWidthMin');
|
||||
|
||||
//BAIL!
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem("chatWidthMin", this.chatWidthMinimum.value);
|
||||
client.processConfig("chatWidthMin", this.chatWidthMinimum.value);
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,518 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: player.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: player.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 = localStorage.getItem('syncTolerance');
|
||||
|
||||
/**
|
||||
* 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 = localStorage.getItem('liveSyncTolerance');
|
||||
|
||||
/**
|
||||
* Forced time to wait between sync checks, heavily decreases chance of seek-banging without reducing syncornization accuracy
|
||||
*/
|
||||
this.syncDelta = localStorage.getItem('syncDelta');
|
||||
|
||||
/**
|
||||
* 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'){
|
||||
//If we're running a source from IA
|
||||
if(data.media.type == 'ia'){
|
||||
//Replace specified CDN with generic URL, in-case of hard reload
|
||||
data.media.rawLink = data.media.rawLink.replace(/^https(.*)archive\.org(.*)items/g, "https://archive.org/download")
|
||||
|
||||
//If we have an IA source and a custom IA CDN Server set
|
||||
if(data.media.type == 'ia' && localStorage.getItem("IACDN") != ""){
|
||||
//Generate and set new link
|
||||
data.media.rawLink = data.media.rawLink.replace("https://archive.org/download", `https://${localStorage.getItem("IACDN")}.archive.org/0/items`);
|
||||
}
|
||||
}
|
||||
|
||||
//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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys and Re-Creates media handler
|
||||
*/
|
||||
hardReload(){
|
||||
if(this.mediaHandler != null){
|
||||
//Re-create data we'd get from server
|
||||
const data = {
|
||||
media: this.mediaHandler.nowPlaying,
|
||||
timestamp: this.mediaHandler.getTimestamp()
|
||||
}
|
||||
|
||||
//End current media handler
|
||||
this.end();
|
||||
|
||||
console.log(data);
|
||||
|
||||
//Restart from last media handlers
|
||||
this.start(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()){
|
||||
localStorage.setItem("cinemaMode", cinema);
|
||||
|
||||
if(cinema){
|
||||
this.navBar.style.display = "none";
|
||||
}else{
|
||||
this.navBar.style.display = "flex";
|
||||
}
|
||||
|
||||
//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();
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,884 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: renamePopup</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: renamePopup</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>renamePopup<span class="signature">(event, playlist, client, doc, cb)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class representing pop-up dialogue to rename a playlist</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="renamePopup"><span class="type-signature"></span>new renamePopup<span class="signature">(event, playlist, client, doc, cb)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a new Rename Pop-up
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>playlist</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Playlist name</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Parent Client Management Object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>doc</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Document</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Current owner documnet of the panel, so we know where to drop our pop-up</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>cb</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Callback function, passed new name upon rename</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line866">line 866</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="cb"><span class="type-signature"></span>cb<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Callback Function, passed new name upon rename
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line889">line 889</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management Object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line879">line 879</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="playlist"><span class="type-signature"></span>playlist<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Playlist Name
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line884">line 884</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="popup"><span class="type-signature"></span>popup<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
canopyUXUtils.popup() object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line896">line 896</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="asyncConstructor"><span class="type-signature"></span>asyncConstructor<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Continuation of object construction, called after child popup object construction
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line902">line 902</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="renamePlaylist"><span class="type-signature"></span>renamePlaylist<span class="signature">(event)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Handles sending request to rename playlist to the server
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line922">line 922</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="setupInput"><span class="type-signature"></span>setupInput<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Defines input-related Event Handlers
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_playlistManager.js.html">panels/queuePanel/playlistManager.js</a>, <a href="panels_queuePanel_playlistManager.js.html#line912">line 912</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:58 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,969 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: schedulePopup</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: schedulePopup</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>schedulePopup<span class="signature">(event, client, url, title, cb, doc)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class representing pop-up dialogue to schedule a piece of media</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="schedulePopup"><span class="type-signature"></span>new schedulePopup<span class="signature">(event, client, url, title, cb, doc)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a new schedule media Pop-up
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>client</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="channel.html">channel</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Parent Client Management Object</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>url</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">URL/link to media to queue</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>title</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Title of media to queue</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>cb</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Callback function, passed upon pop-up creation</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>doc</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Document</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Current owner documnet of the panel, so we know where to drop our pop-up</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1421">line 1421</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="cb"><span class="type-signature"></span>cb<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Callback function, passed upon pop-up creation
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1450">line 1450</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="client"><span class="type-signature"></span>client<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Parent Client Management Object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1435">line 1435</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="popup"><span class="type-signature"></span>popup<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
canopyUXUtils.popup() object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1457">line 1457</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="title"><span class="type-signature"></span>title<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Title of media to queue
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1445">line 1445</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="url"><span class="type-signature"></span>url<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
URL/Link to media to queue
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1440">line 1440</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="asyncConstructor"><span class="type-signature"></span>asyncConstructor<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Continuation of object construction, called after child popup object construction
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1463">line 1463</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="schedule"><span class="type-signature"></span>schedule<span class="signature">(event)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Handles sending request to schedule item to the queue
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>event</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Event</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Event passed down from Event Listener</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1498">line 1498</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="setupInput"><span class="type-signature"></span>setupInput<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Defines input-related Event Handlers
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="panels_queuePanel_queuePanel.js.html">panels/queuePanel/queuePanel.js</a>, <a href="panels_queuePanel_queuePanel.js.html#line1488">line 1488</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:58 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/*global document */
|
||||
(() => {
|
||||
const source = document.getElementsByClassName('prettyprint source linenums');
|
||||
let i = 0;
|
||||
let lineNumber = 0;
|
||||
let lineId;
|
||||
let lines;
|
||||
let totalLines;
|
||||
let anchorHash;
|
||||
|
||||
if (source && source[0]) {
|
||||
anchorHash = document.location.hash.substring(1);
|
||||
lines = source[0].getElementsByTagName('li');
|
||||
totalLines = lines.length;
|
||||
|
||||
for (; i < totalLines; i++) {
|
||||
lineNumber++;
|
||||
lineId = `line${lineNumber}`;
|
||||
lines[i].id = lineId;
|
||||
if (lineId === anchorHash) {
|
||||
lines[i].className += ' selected';
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
|
||||
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
|
||||
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
|
||||
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
|
||||
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
|
||||
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
|
||||
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
|
||||
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
|
||||
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
|
||||
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
|
||||
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
|
||||
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
|
||||
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
|
||||
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
|
||||
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
|
||||
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
|
||||
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
|
||||
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
|
||||
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
|
||||
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
|
||||
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
|
||||
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
|
||||
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
|
||||
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
|
||||
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
|
||||
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
|
||||
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
|
||||
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
|
||||
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
|
||||
|
|
@ -1,358 +0,0 @@
|
|||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
src: url('../fonts/OpenSans-Regular-webfont.eot');
|
||||
src:
|
||||
local('Open Sans'),
|
||||
local('OpenSans'),
|
||||
url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/OpenSans-Regular-webfont.woff') format('woff'),
|
||||
url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans Light';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
src: url('../fonts/OpenSans-Light-webfont.eot');
|
||||
src:
|
||||
local('Open Sans Light'),
|
||||
local('OpenSans Light'),
|
||||
url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/OpenSans-Light-webfont.woff') format('woff'),
|
||||
url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg');
|
||||
}
|
||||
|
||||
html
|
||||
{
|
||||
overflow: auto;
|
||||
background-color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
line-height: 1.5;
|
||||
color: #4d4e53;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
a, a:visited, a:active {
|
||||
color: #0095dd;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
header
|
||||
{
|
||||
display: block;
|
||||
padding: 0px 4px;
|
||||
}
|
||||
|
||||
tt, code, kbd, samp {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
}
|
||||
|
||||
.class-description {
|
||||
font-size: 130%;
|
||||
line-height: 140%;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.class-description:empty {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#main {
|
||||
float: left;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
article dl {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
article img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
section
|
||||
{
|
||||
display: block;
|
||||
background-color: #fff;
|
||||
padding: 12px 24px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.variation {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.signature-attributes {
|
||||
font-size: 60%;
|
||||
color: #aaa;
|
||||
font-style: italic;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
nav
|
||||
{
|
||||
display: block;
|
||||
float: right;
|
||||
margin-top: 28px;
|
||||
width: 30%;
|
||||
box-sizing: border-box;
|
||||
border-left: 1px solid #ccc;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif;
|
||||
font-size: 100%;
|
||||
line-height: 17px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
nav ul a, nav ul a:visited, nav ul a:active {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
line-height: 18px;
|
||||
color: #4D4E53;
|
||||
}
|
||||
|
||||
nav h3 {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
nav li {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
footer {
|
||||
display: block;
|
||||
padding: 6px;
|
||||
margin-top: 12px;
|
||||
font-style: italic;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-weight: 200;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
font-family: 'Open Sans Light', sans-serif;
|
||||
font-size: 48px;
|
||||
letter-spacing: -2px;
|
||||
margin: 12px 24px 20px;
|
||||
}
|
||||
|
||||
h2, h3.subsection-title
|
||||
{
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -1px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
font-size: 24px;
|
||||
letter-spacing: -0.5px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
h4
|
||||
{
|
||||
font-size: 18px;
|
||||
letter-spacing: -0.33px;
|
||||
margin-bottom: 12px;
|
||||
color: #4d4e53;
|
||||
}
|
||||
|
||||
h5, .container-overview .subsection-title
|
||||
{
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 8px 0 3px 0;
|
||||
}
|
||||
|
||||
h6
|
||||
{
|
||||
font-size: 100%;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 6px 0 3px 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-spacing: 0;
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td, th
|
||||
{
|
||||
border: 1px solid #ddd;
|
||||
margin: 0px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
padding: 4px 6px;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
thead tr
|
||||
{
|
||||
background-color: #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
th { border-right: 1px solid #aaa; }
|
||||
tr > th:last-child { border-right: 1px solid #ddd; }
|
||||
|
||||
.ancestors, .attribs { color: #999; }
|
||||
.ancestors a, .attribs a
|
||||
{
|
||||
color: #999 !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.clear
|
||||
{
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.important
|
||||
{
|
||||
font-weight: bold;
|
||||
color: #950B02;
|
||||
}
|
||||
|
||||
.yes-def {
|
||||
text-indent: -1000px;
|
||||
}
|
||||
|
||||
.type-signature {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.name, .signature {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
}
|
||||
|
||||
.details { margin-top: 14px; border-left: 2px solid #DDD; }
|
||||
.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; }
|
||||
.details dd { margin-left: 70px; }
|
||||
.details ul { margin: 0; }
|
||||
.details ul { list-style-type: none; }
|
||||
.details li { margin-left: 30px; padding-top: 6px; }
|
||||
.details pre.prettyprint { margin: 0 }
|
||||
.details .object-value { padding-top: 0; }
|
||||
|
||||
.description {
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.code-caption
|
||||
{
|
||||
font-style: italic;
|
||||
font-size: 107%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.source
|
||||
{
|
||||
border: 1px solid #ddd;
|
||||
width: 80%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.prettyprint.source {
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
.source code
|
||||
{
|
||||
font-size: 100%;
|
||||
line-height: 18px;
|
||||
display: block;
|
||||
padding: 4px 12px;
|
||||
margin: 0;
|
||||
background-color: #fff;
|
||||
color: #4D4E53;
|
||||
}
|
||||
|
||||
.prettyprint code span.line
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.prettyprint.linenums
|
||||
{
|
||||
padding-left: 70px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.prettyprint.linenums ol
|
||||
{
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.prettyprint.linenums li
|
||||
{
|
||||
border-left: 3px #ddd solid;
|
||||
}
|
||||
|
||||
.prettyprint.linenums li.selected,
|
||||
.prettyprint.linenums li.selected *
|
||||
{
|
||||
background-color: lightyellow;
|
||||
}
|
||||
|
||||
.prettyprint.linenums li *
|
||||
{
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.params .name, .props .name, .name code {
|
||||
color: #4D4E53;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.params td.description > p:first-child,
|
||||
.props td.description > p:first-child
|
||||
{
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.params td.description > p:last-child,
|
||||
.props td.description > p:last-child
|
||||
{
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #454545;
|
||||
}
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
/* JSDoc prettify.js theme */
|
||||
|
||||
/* plain text */
|
||||
.pln {
|
||||
color: #000000;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* string content */
|
||||
.str {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a keyword */
|
||||
.kwd {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a comment */
|
||||
.com {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* a type name */
|
||||
.typ {
|
||||
color: #000000;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a literal value */
|
||||
.lit {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* punctuation */
|
||||
.pun {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* lisp open bracket */
|
||||
.opn {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* lisp close bracket */
|
||||
.clo {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a markup tag name */
|
||||
.tag {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a markup attribute name */
|
||||
.atn {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a markup attribute value */
|
||||
.atv {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a declaration */
|
||||
.dec {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a variable name */
|
||||
.var {
|
||||
color: #000000;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a function name */
|
||||
.fun {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
/* Tomorrow Theme */
|
||||
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
|
||||
/* Pretty printing styles. Used with prettify.js. */
|
||||
/* SPAN elements with the classes below are added by prettyprint. */
|
||||
/* plain text */
|
||||
.pln {
|
||||
color: #4d4d4c; }
|
||||
|
||||
@media screen {
|
||||
/* string content */
|
||||
.str {
|
||||
color: #718c00; }
|
||||
|
||||
/* a keyword */
|
||||
.kwd {
|
||||
color: #8959a8; }
|
||||
|
||||
/* a comment */
|
||||
.com {
|
||||
color: #8e908c; }
|
||||
|
||||
/* a type name */
|
||||
.typ {
|
||||
color: #4271ae; }
|
||||
|
||||
/* a literal value */
|
||||
.lit {
|
||||
color: #f5871f; }
|
||||
|
||||
/* punctuation */
|
||||
.pun {
|
||||
color: #4d4d4c; }
|
||||
|
||||
/* lisp open bracket */
|
||||
.opn {
|
||||
color: #4d4d4c; }
|
||||
|
||||
/* lisp close bracket */
|
||||
.clo {
|
||||
color: #4d4d4c; }
|
||||
|
||||
/* a markup tag name */
|
||||
.tag {
|
||||
color: #c82829; }
|
||||
|
||||
/* a markup attribute name */
|
||||
.atn {
|
||||
color: #f5871f; }
|
||||
|
||||
/* a markup attribute value */
|
||||
.atv {
|
||||
color: #3e999f; }
|
||||
|
||||
/* a declaration */
|
||||
.dec {
|
||||
color: #f5871f; }
|
||||
|
||||
/* a variable name */
|
||||
.var {
|
||||
color: #c82829; }
|
||||
|
||||
/* a function name */
|
||||
.fun {
|
||||
color: #4271ae; } }
|
||||
/* Use higher contrast and text-weight for printable form. */
|
||||
@media print, projection {
|
||||
.str {
|
||||
color: #060; }
|
||||
|
||||
.kwd {
|
||||
color: #006;
|
||||
font-weight: bold; }
|
||||
|
||||
.com {
|
||||
color: #600;
|
||||
font-style: italic; }
|
||||
|
||||
.typ {
|
||||
color: #404;
|
||||
font-weight: bold; }
|
||||
|
||||
.lit {
|
||||
color: #044; }
|
||||
|
||||
.pun, .opn, .clo {
|
||||
color: #440; }
|
||||
|
||||
.tag {
|
||||
color: #006;
|
||||
font-weight: bold; }
|
||||
|
||||
.atn {
|
||||
color: #404; }
|
||||
|
||||
.atv {
|
||||
color: #060; } }
|
||||
/* Style */
|
||||
/*
|
||||
pre.prettyprint {
|
||||
background: white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px; }
|
||||
*/
|
||||
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0; }
|
||||
|
||||
/* IE indents via margin-left */
|
||||
li.L0,
|
||||
li.L1,
|
||||
li.L2,
|
||||
li.L3,
|
||||
li.L4,
|
||||
li.L5,
|
||||
li.L6,
|
||||
li.L7,
|
||||
li.L8,
|
||||
li.L9 {
|
||||
/* */ }
|
||||
|
||||
/* Alternate shading for lines */
|
||||
li.L1,
|
||||
li.L3,
|
||||
li.L5,
|
||||
li.L7,
|
||||
li.L9 {
|
||||
/* */ }
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: userlist.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: userlist.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 logic behind userlist UX
|
||||
*/
|
||||
class userList{
|
||||
/**
|
||||
* Instantiates a new userList object
|
||||
* @param {channel} client - Parent client mgmt object
|
||||
*/
|
||||
constructor(client){
|
||||
/**
|
||||
* Parent Client Management object
|
||||
*/
|
||||
this.client = client
|
||||
|
||||
/**
|
||||
* Click Dragger object for handling userlist resizes
|
||||
*/
|
||||
this.clickDragger = new canopyUXUtils.clickDragger("#chat-panel-users-drag-handle", "#chat-panel-users-div", true, this.client.chatBox.clickDragger);
|
||||
|
||||
/**
|
||||
* Userlist color array (Maps to css classes)
|
||||
*/
|
||||
this.userColors = [
|
||||
"userlist-color0",
|
||||
"userlist-color1",
|
||||
"userlist-color2",
|
||||
"userlist-color3",
|
||||
"userlist-color4",
|
||||
"userlist-color5",
|
||||
"userlist-color6"];
|
||||
|
||||
/**
|
||||
* Map of usernames to assigned username color
|
||||
*/
|
||||
this.colorMap = new Map();
|
||||
|
||||
/**
|
||||
* users div
|
||||
*/
|
||||
this.userDiv = document.querySelector("#chat-panel-users-div");
|
||||
|
||||
/**
|
||||
* userlist div
|
||||
*/
|
||||
this.userList = document.querySelector("#chat-panel-users-list-div");
|
||||
|
||||
/**
|
||||
* user count label
|
||||
*/
|
||||
this.userCount = document.querySelector("#chat-panel-user-count");
|
||||
|
||||
/**
|
||||
* userlist toggle button
|
||||
*/
|
||||
this.toggleIcon = document.querySelector("#chat-panel-users-toggle");
|
||||
|
||||
//Call setup functions
|
||||
this.setupInput();
|
||||
this.defineListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines input-related event listeners
|
||||
*/
|
||||
setupInput(){
|
||||
this.toggleIcon.addEventListener("click", ()=>{this.toggleUI()});
|
||||
this.userCount.addEventListener("click", ()=>{this.toggleUI()});
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines network-related event listeners
|
||||
*/
|
||||
defineListeners(){
|
||||
this.client.socket.on('userList', (data) => {
|
||||
this.updateList(data);
|
||||
});
|
||||
|
||||
this.client.socket.on("disconnect", () => {
|
||||
this.updateList([]);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates UX after user list change
|
||||
* @param {Array} list - Userlist data from server
|
||||
*/
|
||||
updateList(list){
|
||||
//Clear list and set user count
|
||||
this.userCount.textContent = list.length == 1 ? '1 User' : `${list.length} Users`;
|
||||
this.userList.innerHTML = null;
|
||||
|
||||
//create a new map
|
||||
var newMap = new Map();
|
||||
|
||||
//for each user
|
||||
list.forEach((user) => {
|
||||
//randomly pick a color
|
||||
var color = this.userColors[Math.floor(Math.random()*this.userColors.length)]
|
||||
|
||||
//if this user was in the previous colormap
|
||||
if(this.colorMap.get(user.user) != null){
|
||||
//Override with previous color
|
||||
color = this.colorMap.get(user.user);
|
||||
}
|
||||
|
||||
newMap.set(user.user, color);
|
||||
this.renderUser(user, color);
|
||||
});
|
||||
|
||||
this.colorMap = newMap;
|
||||
|
||||
//Make sure we're not cutting the ux off
|
||||
this.clickDragger.fixCutoff();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders out a single username to the userlist
|
||||
* @param {String} user - Username to render
|
||||
* @param {String} flair - Flair to render as
|
||||
*/
|
||||
renderUser(user, flair){
|
||||
|
||||
//Create user span
|
||||
var userSpan = document.createElement('span');
|
||||
userSpan.classList.add('chat-panel-users', 'user-entry');
|
||||
|
||||
//Create high-level label
|
||||
var highLevel = document.createElement('p');
|
||||
highLevel.classList.add("user-list-high-level","high-level");
|
||||
highLevel.textContent = `${user.highLevel}`;
|
||||
|
||||
//Create nameplate
|
||||
var userEntry = document.createElement('p');
|
||||
userEntry.innerText = user.user;
|
||||
userEntry.id = `user-entry-${user.user}`;
|
||||
|
||||
//Override color with flair
|
||||
if(user.flair != "classic"){
|
||||
flair = `flair-${user.flair}`;
|
||||
}
|
||||
//Add classes to classList
|
||||
userEntry.classList.add("chat-panel-users","user-entry",flair);
|
||||
|
||||
//Add high-level username to nameplate
|
||||
userSpan.appendChild(highLevel);
|
||||
userSpan.appendChild(userEntry);
|
||||
|
||||
//Setup profile tooltip
|
||||
userSpan.addEventListener('mouseenter',(event)=>{utils.ux.displayTooltip(event, `profile?user=${user.user}`, true, null, true);});
|
||||
|
||||
//Setup profile context menu
|
||||
userSpan.addEventListener('click', renderContextMenu.bind(this));
|
||||
userSpan.addEventListener('contextmenu', renderContextMenu.bind(this));
|
||||
|
||||
this.userList.appendChild(userSpan);
|
||||
|
||||
function renderContextMenu(event){
|
||||
//Setup menu map
|
||||
let menuMap = new Map([
|
||||
["Profile", ()=>{this.client.cPanel.setActivePanel(new panelObj(this.client, `${user.user}`, `/panel/profile?user=${user.user}`))}],
|
||||
["Mention", ()=>{this.client.chatBox.catChat(`${user.user} `)}],
|
||||
["Toke With", ()=>{this.client.chatBox.tokeWith(user.user)}],
|
||||
]);
|
||||
|
||||
if(user.user != "Tokebot" && user.user != this.client.user.user){
|
||||
if(this.client.user.permMap.chan.get("kickUser")){
|
||||
menuMap.set("Kick", ()=>{this.client.chatBox.commandPreprocessor.preprocess(`!kick ${user.user}`)});
|
||||
}
|
||||
|
||||
if(this.client.user.permMap.chan.get("banUser")){
|
||||
menuMap.set("Channel Ban", ()=>{new chanBanUserPopup(this.client.channelName, user.user);});
|
||||
}
|
||||
|
||||
if(this.client.user.permMap.site.get("banUser")){
|
||||
menuMap.set("Site Ban", ()=>{new banUserPopup(user.user);});
|
||||
}
|
||||
}
|
||||
|
||||
//Display the menu
|
||||
utils.ux.displayContextMenu(event, user.user, menuMap);
|
||||
}
|
||||
}
|
||||
|
||||
toggleUI(show = !this.userDiv.checkVisibility()){
|
||||
localStorage.setItem("userlistHidden", !show);
|
||||
|
||||
if(show){
|
||||
this.userDiv.style.display = "flex";
|
||||
this.toggleIcon.classList.replace("bi-caret-left-fill","bi-caret-down-fill");
|
||||
this.clickDragger.fixCutoff();
|
||||
}else{
|
||||
this.userDiv.style.display = "none";
|
||||
this.toggleIcon.classList.replace("bi-caret-down-fill","bi-caret-left-fill");
|
||||
}
|
||||
}
|
||||
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:57 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/activeChannel.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/activeChannel.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
//local imports
|
||||
const connectedUser = require('./connectedUser');
|
||||
const chatBuffer = require('./chatBuffer');
|
||||
const queue = require('./media/queue');
|
||||
const channelModel = require('../../schemas/channel/channelSchema');
|
||||
const playlistHandler = require('./media/playlistHandler')
|
||||
|
||||
/**
|
||||
* Class representing a single active channel
|
||||
*/
|
||||
class activeChannel{
|
||||
|
||||
/**
|
||||
* Instantiates an activeChannel object
|
||||
* @param {channelManager} server - Parent Server Object
|
||||
* @param {Mongoose.Document} chanDB - chanDB to rehydrate buffer from
|
||||
*/
|
||||
constructor(server, chanDB){
|
||||
/**
|
||||
* Parent Server Object
|
||||
*/
|
||||
this.server = server;
|
||||
|
||||
/**
|
||||
* Current Channel Name
|
||||
*/
|
||||
this.name = chanDB.name;
|
||||
|
||||
/**
|
||||
* List of channel-wide toke commands
|
||||
*/
|
||||
this.tokeCommands = chanDB.tokeCommands;
|
||||
|
||||
/**
|
||||
* List of connected users
|
||||
*/
|
||||
this.userList = new Map();
|
||||
|
||||
/**
|
||||
* Child Queue Object
|
||||
*/
|
||||
this.queue = new queue(server, chanDB, this);
|
||||
|
||||
/**
|
||||
* Child Playlist Handler Object
|
||||
*/
|
||||
this.playlistHandler = new playlistHandler(server, this);
|
||||
|
||||
/**
|
||||
* Child Chat Buffer Object
|
||||
*/
|
||||
this.chatBuffer = new chatBuffer(server, chanDB, this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles server-side initialization for new connections to the channel
|
||||
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
|
||||
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
*/
|
||||
async handleConnection(userDB, chanDB, socket){
|
||||
//get current user object from the userlist
|
||||
var userObj = this.userList.get(userDB.user);
|
||||
//get channel rank for current user
|
||||
const chanRank = await chanDB.getChannelRankByUserDoc(userDB);
|
||||
|
||||
//If user is already connected
|
||||
if(userObj){
|
||||
//Add this socket on to the userobject
|
||||
userObj.sockets.push(socket.id);
|
||||
//If the user is joining the channel
|
||||
}else{
|
||||
//Grab flair
|
||||
await userDB.populate('flair');
|
||||
//Set user object
|
||||
userObj = new connectedUser(userDB, chanRank, this, socket);
|
||||
}
|
||||
|
||||
//Set user entry in userlist
|
||||
this.userList.set(userDB.user, userObj);
|
||||
|
||||
//if everything looks good, admit the connection to the channel
|
||||
socket.join(socket.chan);
|
||||
|
||||
//Define per-channel event listeners
|
||||
this.queue.defineListeners(socket);
|
||||
this.playlistHandler.defineListeners(socket);
|
||||
|
||||
//Hand off the connection initiation to it's user object
|
||||
await userObj.handleConnection(userDB, chanDB, socket)
|
||||
|
||||
//Send out the userlist
|
||||
this.broadcastUserList(socket.chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles server-side initialization for disconnecting from the channel
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
*/
|
||||
handleDisconnect(socket){
|
||||
//If we have more than one active connection
|
||||
if(this.userList.get(socket.user.user).sockets.length > 1){
|
||||
//temporarily store userObj
|
||||
var userObj = this.userList.get(socket.user.user);
|
||||
|
||||
//Filter out disconnecting socket from socket list, and set as current socket list for user
|
||||
userObj.sockets = userObj.sockets.filter((id) => {
|
||||
return id != socket.id;
|
||||
});
|
||||
|
||||
//Update the userlist
|
||||
this.userList.set(socket.user.user, userObj);
|
||||
}else{
|
||||
//If this is the last connection for this user, remove them from the userlist
|
||||
this.userList.delete(socket.user.user);
|
||||
}
|
||||
|
||||
//and send out the filtered list
|
||||
this.broadcastUserList(socket.chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts user list to all users
|
||||
*/
|
||||
broadcastUserList(){
|
||||
//Create a userlist object with the tokebot user pre-loaded
|
||||
var userList = [{
|
||||
user: "Tokebot",
|
||||
flair: "classic",
|
||||
highLevel: "∞",
|
||||
}];
|
||||
|
||||
this.userList.forEach((userObj, user) => {
|
||||
userList.push({
|
||||
user: user,
|
||||
flair: userObj.flair,
|
||||
highLevel: userObj.highLevel
|
||||
});
|
||||
});
|
||||
|
||||
this.server.io.in(this.name).emit("userList", userList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts channel emote list to connected users
|
||||
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
|
||||
*/
|
||||
async broadcastChanEmotes(chanDB){
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
chanDB = await channelModel.findOne({name: this.name});
|
||||
}
|
||||
|
||||
//Get emote list from channel document
|
||||
const emoteList = chanDB.getEmotes();
|
||||
|
||||
//Broadcast that sumbitch
|
||||
this.server.io.in(this.name).emit('chanEmotes', emoteList);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = activeChannel;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,361 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/channelManager.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/channelManager.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
//Config
|
||||
const config = require('../../../config.json');
|
||||
|
||||
//Local Imports
|
||||
const channelModel = require('../../schemas/channel/channelSchema');
|
||||
const emoteModel = require('../../schemas/emoteSchema');
|
||||
const {userModel} = require('../../schemas/user/userSchema');
|
||||
const userBanModel = require('../../schemas/user/userBanSchema');
|
||||
const loggerUtils = require('../../utils/loggerUtils');
|
||||
const csrfUtils = require('../../utils/csrfUtils');
|
||||
const activeChannel = require('./activeChannel');
|
||||
const chatHandler = require('./chatHandler');
|
||||
|
||||
/**
|
||||
* Class containing global server-side channel connection management logic
|
||||
*/
|
||||
class channelManager{
|
||||
/**
|
||||
* Instantiates object containing global server-side channel conection management logic
|
||||
* @param {Server} io - Socket.io server instanced passed down from server.js
|
||||
*/
|
||||
constructor(io){
|
||||
/**
|
||||
* Socket.io server instance passed down from server.js
|
||||
*/
|
||||
this.io = io;
|
||||
|
||||
/**
|
||||
* Map containing all active channels running on the server
|
||||
*/
|
||||
this.activeChannels = new Map;
|
||||
|
||||
/**
|
||||
* Global Chat Handler Object
|
||||
*/
|
||||
this.chatHandler = new chatHandler(this);
|
||||
|
||||
//Handle connections from socket.io
|
||||
io.on("connection", this.handleConnection.bind(this) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles global server-side initialization for new connections to any channel
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
*/
|
||||
async handleConnection(socket){
|
||||
try{
|
||||
//ensure unbanned ip and valid CSRF token
|
||||
if(!(await this.validateSocket(socket))){
|
||||
socket.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
//Prevent logged out connections and authenticate socket
|
||||
if(socket.request.session.user != null){
|
||||
//Authenticate socket
|
||||
const userDB = await this.authSocket(socket);
|
||||
|
||||
//Get the active channel based on the socket
|
||||
var {activeChan, chanDB} = await this.getActiveChan(socket);
|
||||
|
||||
//Check for chan ban
|
||||
const ban = await chanDB.checkBanByUserDoc(userDB);
|
||||
if(ban != null){
|
||||
//Toss out banned user's
|
||||
if(ban.expirationDays < 0){
|
||||
socket.emit("kick", {type: "kicked", reason: "You have been permanently banned from this channel!"});
|
||||
}else{
|
||||
socket.emit("kick", {type: "kicked", reason: `You have been temporarily banned from this channel, and will be unbanned in ${ban.getDaysUntilExpiration()} day(s)!`});
|
||||
}
|
||||
socket.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
//Define listeners for inter-channel classes
|
||||
this.defineListeners(socket);
|
||||
this.chatHandler.defineListeners(socket);
|
||||
|
||||
//Hand off the connection to it's given active channel object
|
||||
//Lil' hacky to pass chanDB like that, but why double up on DB calls?
|
||||
activeChan.handleConnection(userDB, chanDB, socket);
|
||||
}else{
|
||||
//Toss out anon's
|
||||
socket.emit("kick", {type: "disconnected", reason: "You must log-in to join this channel!"});
|
||||
socket.disconnect();
|
||||
return;
|
||||
}
|
||||
}catch(err){
|
||||
//Flip a table if something fucks up
|
||||
return loggerUtils.socketCriticalExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Global server-side validation logic for new connections to any channel
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
* @returns {Boolean} true on success
|
||||
*/
|
||||
async validateSocket(socket){
|
||||
//If we're proxied use passthrough IP
|
||||
const ip = config.proxied ? socket.handshake.headers['x-forwarded-for'] : socket.handshake.address;
|
||||
|
||||
//Look for ban by IP
|
||||
const ipBanDB = await userBanModel.checkBanByIP(ip);
|
||||
|
||||
//If this ip is randy bobandy
|
||||
if(ipBanDB != null){
|
||||
//Make the number a little prettier despite the lack of precision since we're not doing calculations here :P
|
||||
const expiration = ipBanDB.getDaysUntilExpiration() < 1 ? 0 : ipBanDB.getDaysUntilExpiration();
|
||||
|
||||
//If the ban is permanent
|
||||
if(ipBanDB.permanent){
|
||||
//tell it to fuck off
|
||||
socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been permanently banned. Your cleartext IP has been saved to the database. Any associated accounts will be nuked in ${expiration} day(s).`});
|
||||
//Otherwise
|
||||
}else{
|
||||
//tell it to fuck off
|
||||
socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been temporarily banned. Your cleartext IP has been saved to the database until the ban expires in ${expiration} day(s).`});
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//Check for Cross-Site Request Forgery
|
||||
if(!csrfUtils.isRequestValid(socket.request)){
|
||||
socket.emit("kick", {type: "disconnected", reason: "Invalid CSRF Token!"});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global server-side authorization logic for new connections to any channel
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
* @returns {Mongoose.Document} - Authorized User Document upon success
|
||||
*/
|
||||
async authSocket(socket){
|
||||
//Find the user in the Database since the session won't store enough data to fulfill our needs :P
|
||||
const userDB = await userModel.findOne({user: socket.request.session.user.user});
|
||||
|
||||
if(userDB == null){
|
||||
throw loggerUtils.exceptionSmith("User not found!", "unauthorized");
|
||||
}
|
||||
|
||||
//Set socket user and channel values
|
||||
socket.user = {
|
||||
id: userDB.id,
|
||||
user: userDB.user,
|
||||
};
|
||||
|
||||
return userDB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets active channel from a given socket
|
||||
* @param {Socket} socket - Socket to check
|
||||
* @returns {Object} Object containing users active channel name and channel document object
|
||||
*/
|
||||
async getActiveChan(socket){
|
||||
socket.chan = socket.handshake.headers.referer.split('/c/')[1].split('/')[0];
|
||||
const chanDB = (await channelModel.findOne({name: socket.chan}));
|
||||
|
||||
//Check if channel exists
|
||||
if(chanDB == null){
|
||||
throw loggerUtils.exceptionSmith("Channel not found", "validation");
|
||||
}
|
||||
|
||||
//Check if current channel is active
|
||||
var activeChan = this.activeChannels.get(socket.chan);
|
||||
|
||||
if(!activeChan){
|
||||
//If not, make it so
|
||||
activeChan = new activeChannel(this, chanDB);
|
||||
this.activeChannels.set(socket.chan, activeChan);
|
||||
}
|
||||
|
||||
//Return whatever the active channel is (new or old)
|
||||
return {activeChan, chanDB};
|
||||
}
|
||||
|
||||
/**
|
||||
* Define Global Server-Side socket event listeners
|
||||
* @param {Socket} socket - Socket to check
|
||||
*/
|
||||
defineListeners(socket){
|
||||
//Socket Listeners
|
||||
socket.conn.on("close", (reason) => {this.handleDisconnect(socket, reason)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Global server-side logic for handling disconncted sockets
|
||||
* @param {Socket} socket - Socket to check
|
||||
* @param {String} reason - Reason for disconnection
|
||||
*/
|
||||
handleDisconnect(socket, reason){
|
||||
var activeChan = this.activeChannels.get(socket.chan);
|
||||
activeChan.handleDisconnect(socket, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls user information by socket
|
||||
* @param {Socket} socket - Socket to check
|
||||
* @return returns related user info
|
||||
*/
|
||||
getSocketInfo(socket){
|
||||
const channel = this.activeChannels.get(socket.chan);
|
||||
return channel.userList.get(socket.user.user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pulls user information by socket
|
||||
* @param {Socket} socket - Socket to check
|
||||
* @return returns related user info
|
||||
*/
|
||||
getConnectedChannels(socket){
|
||||
//Create a list to hold connected channels
|
||||
var chanList = [];
|
||||
|
||||
//For each channel
|
||||
this.activeChannels.forEach((channel) => {
|
||||
//Check and see if the user is connected
|
||||
const foundUser = channel.userList.get(socket.user.user);
|
||||
|
||||
//If we found a user and this channel hasn't been added to the list
|
||||
if(foundUser){
|
||||
chanList.push(channel);
|
||||
}
|
||||
});
|
||||
|
||||
//return the channels this user is connected to
|
||||
return chanList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through connections by a given username, and runs them through a given callback function/method
|
||||
* @param {String} user - Username to crawl connections against
|
||||
* @param {Function} cb - Callback function to run active connections of a given user against
|
||||
*/
|
||||
crawlConnections(user, cb){
|
||||
//For each channel
|
||||
this.activeChannels.forEach((channel) => {
|
||||
//Check and see if the user is connected
|
||||
const foundUser = channel.userList.get(user);
|
||||
|
||||
//If we found a user and this channel hasn't been added to the list
|
||||
if(foundUser){
|
||||
cb(foundUser);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through connections by a given username, and runs them through a given callback function/method
|
||||
* @param {String} user - Username to crawl connections against
|
||||
* @param {Function} cb - Callback function to run active connections of a given user against
|
||||
*/
|
||||
getConnections(user){
|
||||
//Create a list to store our connections
|
||||
var connections = [];
|
||||
|
||||
//crawl through connections
|
||||
//this.crawlConnections(user,(foundUser)=>{connections.push(foundUser)});
|
||||
this.crawlConnections(user,(foundUser)=>{connections.push(foundUser)});
|
||||
|
||||
//return connects
|
||||
return connections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks a user from all channels by username
|
||||
* @param {String} user - Username to kick from the server
|
||||
* @param {String} reason - Reason for kick
|
||||
*/
|
||||
kickConnections(user, reason){
|
||||
//crawl through connections and kick user
|
||||
this.crawlConnections(user,(foundUser)=>{foundUser.disconnect(reason)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast global emote list
|
||||
*/
|
||||
async broadcastSiteEmotes(){
|
||||
//Get emote list from DB
|
||||
const emoteList = await emoteModel.getEmotes();
|
||||
|
||||
//Broadcast that sumbitch
|
||||
this.io.sockets.emit('siteEmotes', emoteList);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = channelManager;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/chat.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/chat.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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 representing a single chat message
|
||||
*/
|
||||
class chat{
|
||||
/**
|
||||
* Instantiates a chat message object
|
||||
* @param {connectedUser} user - User who sent the message
|
||||
* @param {String} flair - Flair ID String for the flair used to send the message
|
||||
* @param {Number} highLevel - Number representing current high level
|
||||
* @param {String} msg - Contents of the message, with links replaced with numbered file-seperator markers
|
||||
* @param {String} type - Message Type Identifier, used for client-side processing.
|
||||
* @param {Array} links - Array of URLs/Links included in the message.
|
||||
*/
|
||||
constructor(user, flair, highLevel, msg, type, links){
|
||||
/**
|
||||
* User who sent the message
|
||||
*/
|
||||
this.user = user;
|
||||
|
||||
/**
|
||||
* Flair ID String for the flair used to send the message
|
||||
*/
|
||||
this.flair = flair;
|
||||
|
||||
/**
|
||||
* Number representing current high level
|
||||
*/
|
||||
this.highLevel = highLevel;
|
||||
|
||||
/**
|
||||
* COntents of the message, with links replaced with numbered file-seperator marks
|
||||
*/
|
||||
this.msg = msg;
|
||||
|
||||
/**
|
||||
* Message Type Identifier, used for client-side processing.
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* Array of URLs/Links included in the message.
|
||||
*/
|
||||
this.links = links;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = chat;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/chatBuffer.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/chatBuffer.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
const config = require('../../../config.json');
|
||||
const channelModel = require('../../schemas/channel/channelSchema');
|
||||
|
||||
/**
|
||||
* Class representing a stored chat buffer
|
||||
*/
|
||||
class chatBuffer{
|
||||
/**
|
||||
* Instantiates a new chat buffer for a given channel
|
||||
* @param {channelManager} server - Parent Server Object
|
||||
* @param {Mongoose.Document} chanDB - chanDB to rehydrate buffer from
|
||||
* @param {activeChannel} channel - Parent Channel Object
|
||||
*/
|
||||
constructor(server, chanDB, channel){
|
||||
/**
|
||||
* Parent Server Object
|
||||
*/
|
||||
this.server = server;
|
||||
|
||||
/**
|
||||
* Parent CHannel Object
|
||||
*/
|
||||
this.channel = channel;
|
||||
|
||||
//If we have no chanDB.chatBuffer
|
||||
if(chanDB == null || chanDB.chatBuffer == null){
|
||||
/**
|
||||
* RAM-Based buffer containing array of previous chats
|
||||
*/
|
||||
this.buffer = [];
|
||||
//Otherwise
|
||||
}else{
|
||||
/**
|
||||
* RAM-Based buffer containing array of previous chats
|
||||
*/
|
||||
this.buffer = chanDB.chatBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inactivity Timer, goes off after x seconds of chat inactivity
|
||||
*/
|
||||
this.inactivityTimer = null;
|
||||
|
||||
/**
|
||||
* Inactivity Timer Delay
|
||||
*/
|
||||
this.inactivityDelay = 10;
|
||||
|
||||
/**
|
||||
* Goes off after x minutes of solid chatroom activity (no inactivityTimer call in x minutes)
|
||||
*/
|
||||
this.busyTimer = null;
|
||||
|
||||
/**
|
||||
* Busy Timer Delay
|
||||
*/
|
||||
this.busyDelay = 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a given chat to the chat buffer in RAM and sets any appropriate timers for DB transactions
|
||||
* @param {chat} chat - Chat object to commit to buffer
|
||||
*/
|
||||
push(chat){
|
||||
//push chat into RAM buffer
|
||||
this.buffer.push(chat);
|
||||
|
||||
//clear existing inactivity timer
|
||||
clearTimeout(this.inactivityTimer);
|
||||
|
||||
//reset inactivity timer
|
||||
this.inactivityTimer = setTimeout(this.handleInactivity.bind(this), 1000 * this.inactivityDelay);
|
||||
|
||||
//If busy timer is unset
|
||||
if(this.busyTimer == null){
|
||||
this.busyTimer = setTimeout(this.handleBusyRoom.bind(this), 1000 * 60 * this.busyDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the oldest item from the chat buffer
|
||||
*
|
||||
* Was originally created in-case we needed to trigger timing functions
|
||||
*
|
||||
* Left here since it seems like good form anywho, since this would be a private, or at least protected member in another language
|
||||
*/
|
||||
shift(){
|
||||
this.buffer.shift();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after 10 seconds of chat room inactivity
|
||||
*/
|
||||
handleInactivity(){
|
||||
this.saveDB(`${this.inactivityDelay} seconds of inactivity.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after 5 minutes of solid activity
|
||||
*/
|
||||
handleBusyRoom(){
|
||||
this.saveDB(`${this.busyDelay} minutes of activity.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves RAM-Based buffer to Channel Document in DB
|
||||
* @param {String} reason - Reason for DB save, formatted as 'x minutes/seconds of in/activity', used for logging purposes
|
||||
* @param {Mongoose.Document} chanDB - Channel Doc to work with, can be left empty for method to auto-find through channel name.
|
||||
*/
|
||||
async saveDB(reason, chanDB){
|
||||
//clear existing timers
|
||||
clearTimeout(this.inactivityTimer);
|
||||
clearTimeout(this.busyTimer);
|
||||
this.inactivityTimer = null;
|
||||
this.busyTimer = null;
|
||||
|
||||
//if the server is in screamy boi mode
|
||||
if(config.verbose){
|
||||
//This should eventually be replaced by a per-channel logging feature that provides access to chan admins via web front-end
|
||||
console.log(`Saving chat buffer to channel ${this.channel.name} after ${reason}.`);
|
||||
}
|
||||
|
||||
|
||||
//If we wheren't handed a channel
|
||||
if(chanDB == null){
|
||||
//Now that everything is clean, we can take our time with the DB :P
|
||||
chanDB = await channelModel.findOne({name:this.channel.name});
|
||||
}
|
||||
|
||||
//If we couldn't find the channel
|
||||
if(chanDB == null){
|
||||
//FUCK
|
||||
throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while saving chat buffer!`, "chat");
|
||||
}
|
||||
|
||||
//Set chan doc buffer to RAM buffer
|
||||
chanDB.chatBuffer = this.buffer;
|
||||
|
||||
//save chan doc to DB.
|
||||
await chanDB.save();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = chatBuffer;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,393 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/chatHandler.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/chatHandler.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
//NPM imports
|
||||
const validator = require('validator')
|
||||
|
||||
//local imports
|
||||
const commandPreprocessor = require('./commandPreprocessor');
|
||||
const loggerUtils = require('../../utils/loggerUtils');
|
||||
const linkUtils = require('../../utils/linkUtils');
|
||||
const emoteValidator = require('../../validators/emoteValidator');
|
||||
const chat = require('./chat');
|
||||
const {userModel} = require('../../schemas/user/userSchema');
|
||||
|
||||
/**
|
||||
* Class containing global server-side chat relay logic
|
||||
*/
|
||||
class chatHandler{
|
||||
/**
|
||||
* Instantiates a chatHandler object
|
||||
* @param {channelManager} server - Parent Server Object
|
||||
*/
|
||||
constructor(server){
|
||||
/**
|
||||
* Parent Server Object
|
||||
*/
|
||||
this.server = server;
|
||||
|
||||
/**
|
||||
* Child Command Pre-Processor Object
|
||||
*/
|
||||
this.commandPreprocessor = new commandPreprocessor(server, this)
|
||||
|
||||
/**
|
||||
* Max chat buffer message count
|
||||
*/
|
||||
this.chatBufferSize = 50;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines global server-side chat relay event listeners
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
*/
|
||||
defineListeners(socket){
|
||||
socket.on("chatMessage", (data) => {this.handleChat(socket, data)});
|
||||
socket.on("setFlair", (data) => {this.setFlair(socket, data)});
|
||||
socket.on("setHighLevel", (data) => {this.setHighLevel(socket, data)});
|
||||
socket.on("addPersonalEmote", (data) => {this.addPersonalEmote(socket, data)});
|
||||
socket.on("deletePersonalEmote", (data) => {this.deletePersonalEmote(socket, data)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming chat messages from client connections
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {Object} data - Event payload
|
||||
*/
|
||||
handleChat(socket, data){
|
||||
this.commandPreprocessor.preprocess(socket, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming client request to change flair
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {Object} data - Event payload
|
||||
*/
|
||||
async setFlair(socket, data){
|
||||
var userDB = await userModel.findOne({user: socket.user.user});
|
||||
|
||||
if(userDB){
|
||||
try{
|
||||
//We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries
|
||||
const flairDB = await userDB.setFlair(data.flair);
|
||||
|
||||
//Crawl through users active connections
|
||||
this.server.crawlConnections(socket.user.user, (conn)=>{
|
||||
//Update flair
|
||||
conn.updateFlair(flairDB.name);
|
||||
});
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming client request to change high level
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {Object} data - Event payload
|
||||
*/
|
||||
async setHighLevel(socket, data){
|
||||
var userDB = await userModel.findOne({user: socket.user.user});
|
||||
|
||||
if(userDB){
|
||||
try{
|
||||
//Floor input to an integer and set high level
|
||||
userDB.highLevel = Math.floor(data.highLevel);
|
||||
//Save user DB Document
|
||||
await userDB.save();
|
||||
|
||||
//GetConnects across all channels
|
||||
const connections = this.server.getConnections(socket.user.user);
|
||||
|
||||
//For each connection
|
||||
connections.forEach((conn) => {
|
||||
conn.updateHighLevel(userDB.highLevel);
|
||||
});
|
||||
}catch(err){
|
||||
return loggerUtils.socketExceptionHandler(socket, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming client request to add a personal emote
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {Object} data - Event payload
|
||||
*/
|
||||
async addPersonalEmote(socket, data){
|
||||
//Sanatize and Validate input
|
||||
const name = emoteValidator.manualName(data.name);
|
||||
const link = emoteValidator.manualLink(data.link);
|
||||
|
||||
//If we received good input
|
||||
if(link && name){
|
||||
//Generate marked link object
|
||||
var emote = await linkUtils.markLink(link);
|
||||
|
||||
//If the link we have is an image or video
|
||||
if(emote.type == 'image' || emote.type == 'video'){
|
||||
//Get user document from DB
|
||||
const userDB = await userModel.findOne({user: socket.user.user})
|
||||
|
||||
//if we have a user in the DB
|
||||
if(userDB != null){
|
||||
//Convert marked link into emote object with 1 ez step for only $19.95
|
||||
emote.name = name;
|
||||
|
||||
//add emote to user document emotes list
|
||||
userDB.emotes.push(emote);
|
||||
|
||||
//Save user doc
|
||||
await userDB.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming client request to delete a personal emote
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {Object} data - Event payload
|
||||
*/
|
||||
async deletePersonalEmote(socket, data){
|
||||
//Get user doc from DB based on socket
|
||||
const userDB = await userModel.findOne({user: socket.user.user});
|
||||
|
||||
//if we found a user
|
||||
if(userDB != null){
|
||||
await userDB.deleteEmote(data.name);
|
||||
}
|
||||
}
|
||||
|
||||
//Base chat functions
|
||||
/**
|
||||
* Creates a new chatObject and relays the resulting message to the given channel
|
||||
* @param {String} user - Originating user
|
||||
* @param {String} flair - Flair ID to mark chat with
|
||||
* @param {Number} highLevel - High Level to mark chat with
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {String} type - Message Type, used for client-side chat post-processing.
|
||||
* @param {String} chan - Channel to broadcast message within
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayChat(user, flair, highLevel, msg, type = 'chat', chan, links){
|
||||
this.relayChatObject(chan, new chat(user, flair, highLevel, msg, type, links));
|
||||
}
|
||||
|
||||
/**
|
||||
* Relays an existing chat object to a channel
|
||||
* @param {String} chan - Channel to broadcast message within
|
||||
* @param {chat} chat - Chat Object representing the message to broadcast to the given channel
|
||||
*/
|
||||
relayChatObject(chan, chat){
|
||||
//Send out chat
|
||||
this.server.io.in(chan).emit("chatMessage", chat);
|
||||
|
||||
const channel = this.server.activeChannels.get(chan);
|
||||
|
||||
//If chat buffer length is over mandated size
|
||||
if(channel.chatBuffer.buffer.length >= this.chatBufferSize){
|
||||
//Take out oldest chat
|
||||
channel.chatBuffer.shift();
|
||||
}
|
||||
|
||||
//Add buffer to chat
|
||||
channel.chatBuffer.push(chat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chatObject and relays the resulting message to the given socket
|
||||
* @param {Socket} socket - Socket we're sending a message to (sounds menacing, huh?)
|
||||
* @param {String} user - Originating user
|
||||
* @param {String} flair - Flair ID to mark chat with
|
||||
* @param {Number} highLevel - High Level to mark chat with
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {String} type - Message Type, used for client-side chat post-processing.
|
||||
* @param {String} chan - Channel to broadcast message within
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayPrivateChat(socket, user, flair, highLevel, msg, type, links){
|
||||
this.relayPrivateChatObject(socket , new chat(user, flair, highLevel, msg, type, links));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming client request to delete a personal emote
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {Object} data - Event payload
|
||||
*/
|
||||
relayPrivateChatObject(socket, chat){
|
||||
socket.emit("chatMessage", chat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new chatObject and relays the resulting message to the entire server
|
||||
* @param {String} user - Originating user
|
||||
* @param {String} flair - Flair ID to mark chat with
|
||||
* @param {Number} highLevel - High Level to mark chat with
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {String} type - Message Type, used for client-side chat post-processing.
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayGlobalChat(user, flair, highLevel, msg, type = 'chat', links){
|
||||
this.relayGlobalChatObject(new chat(user, flair, highLevel, msg, type, links));
|
||||
}
|
||||
|
||||
/**
|
||||
* Relays an existing chat object to the entire server
|
||||
* @param {chat} chat - Chat Object representing the message to broadcast throughout the server
|
||||
*/
|
||||
relayGlobalChatObject(chat){
|
||||
this.server.io.emit("chatMessage", chat);
|
||||
}
|
||||
|
||||
//User Chat Functions
|
||||
/**
|
||||
* Relays a chat message from a user to the rest of the channel based on socket
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {String} type - Message Type, used for client-side chat post-processing.
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayUserChat(socket, msg, type, links){
|
||||
const user = this.server.getSocketInfo(socket);
|
||||
this.relayChat(user.user, user.flair, user.highLevel, msg, type, socket.chan, links);
|
||||
}
|
||||
|
||||
//Toke Chat Functions
|
||||
/**
|
||||
* Broadcasts toke callout to the server
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayTokeCallout(msg, links){
|
||||
this.relayGlobalChat("Tokebot", "", '∞', msg, "toke", links);
|
||||
}
|
||||
/**
|
||||
* Broadcasts toke callout to the server
|
||||
* @param {Socket} socket - Socket we're sending the whisper to
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayTokeWhisper(socket, msg, links){
|
||||
this.relayPrivateChat(socket, "Tokebot", "", '∞', msg, "tokewhisper", links);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts toke whisper to the server
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayGlobalTokeWhisper(msg, links){
|
||||
this.relayGlobalChat("Tokebot", "", '∞', msg, "tokewhisper", links);
|
||||
}
|
||||
|
||||
//Announcement Functions
|
||||
/**
|
||||
* Broadcasts announcement to the server
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayServerAnnouncement(msg, links){
|
||||
this.relayGlobalChat("Server", "", '∞', msg, "announcement", links);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts announcement to a given channel
|
||||
* @param {String} msg - Message Text Content
|
||||
* @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
|
||||
*/
|
||||
relayChannelAnnouncement(chan, msg, links){
|
||||
const activeChan = this.server.activeChannels.get(chan);
|
||||
|
||||
//If channel isn't null
|
||||
if(activeChan != null){
|
||||
this.relayChat("Channel", "", '∞', msg, "announcement", chan, links);
|
||||
}
|
||||
}
|
||||
|
||||
//Misc Functions
|
||||
/**
|
||||
* Clears chat for a given channel, targets specified user or entire channel if none found/specified.
|
||||
* @param {String} user - User chats to clear
|
||||
* @param {String} chan - Channel to broadcast message within
|
||||
*/
|
||||
clearChat(chan, user){
|
||||
const activeChan = this.server.activeChannels.get(chan);
|
||||
|
||||
//If channel isn't null
|
||||
if(activeChan != null){
|
||||
const target = activeChan.userList.get(user);
|
||||
|
||||
//If no user was entered OR the user was found
|
||||
if(user == null || target != null){
|
||||
this.server.io.in(chan).emit("clearChat", {user});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = chatHandler;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,497 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/commandPreprocessor.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/commandPreprocessor.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
//NPM Imports
|
||||
const validator = require('validator');//No express here, so regular validator it is!
|
||||
|
||||
//Local Imports
|
||||
const tokebot = require('./tokebot');
|
||||
const linkUtils = require('../../utils/linkUtils');
|
||||
const permissionModel = require('../../schemas/permissionSchema');
|
||||
const channelModel = require('../../schemas/channel/channelSchema');
|
||||
|
||||
/**
|
||||
* Class containing global server-side chat/command pre-processing logic
|
||||
*/
|
||||
class commandPreprocessor{
|
||||
/**
|
||||
* Instantiates a commandPreprocessor object
|
||||
* @param {channelManager} server - Parent Server Object
|
||||
* @param {chatHandler} chatHandler - Parent Chat Handler Object
|
||||
*/
|
||||
constructor(server, chatHandler){
|
||||
/**
|
||||
* Parent Server Object
|
||||
*/
|
||||
this.server = server;
|
||||
|
||||
/**
|
||||
* Parent Chat Handler Object
|
||||
*/
|
||||
this.chatHandler = chatHandler;
|
||||
|
||||
/**
|
||||
* Child Command Processor Object
|
||||
*/
|
||||
this.commandProcessor = new commandProcessor(server, chatHandler);
|
||||
|
||||
/**
|
||||
* Child Tokebot Object
|
||||
*/
|
||||
this.tokebot = new tokebot(server, chatHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly
|
||||
* @param {Socket} socket - Socket we're receiving the request from
|
||||
* @param {Object} data - Event payload
|
||||
*/
|
||||
async preprocess(socket, data){
|
||||
//Set command object
|
||||
const commandObj = {
|
||||
socket,
|
||||
sendFlag: true,
|
||||
rawData: data,
|
||||
chatType: 'chat'
|
||||
}
|
||||
|
||||
//If we don't pass sanatization/validation turn this car around
|
||||
if(!this.sanatizeCommand(commandObj)){
|
||||
return;
|
||||
}
|
||||
|
||||
//split the command
|
||||
this.splitCommand(commandObj);
|
||||
|
||||
//Process the command
|
||||
await this.processServerCommand(commandObj);
|
||||
|
||||
//If we're going to relay this command as a message, continue on to chat processing
|
||||
if(commandObj.sendFlag){
|
||||
//Prep the message
|
||||
await this.prepMessage(commandObj);
|
||||
|
||||
//Send the chat
|
||||
this.sendChat(commandObj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanatizes and Validates a single user chat message/command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} false if Command/Message is too long to send
|
||||
*/
|
||||
sanatizeCommand(commandObj){
|
||||
//Trim and Sanatize for XSS
|
||||
commandObj.command = validator.trim(validator.escape(commandObj.rawData.msg));
|
||||
|
||||
//Return whether or not the shit was long enough
|
||||
return (validator.isLength(commandObj.rawData.msg, {min: 1, max: 255}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders
|
||||
* These arrays are used to handle further command/chat processing
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
*/
|
||||
splitCommand(commandObj){
|
||||
//Split string by words
|
||||
commandObj.commandArray = commandObj.command.split(/\b/g);//Split by word-borders
|
||||
commandObj.argumentArray = commandObj.command.match(/\b\w+\b/g);//Match by words surrounded by borders
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the server's Command Processor object to process the chat/command request.
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
*/
|
||||
async processServerCommand(commandObj){
|
||||
//If the raw message starts with '!' (skip commands that start with whitespace so people can send example commands in chat)
|
||||
if(commandObj.rawData.msg[0] == '!'){
|
||||
//if it isn't just an exclimation point, and we have a real command
|
||||
if(commandObj.argumentArray != null){
|
||||
//If the command processor knows what to do with whatever the fuck the user sent us
|
||||
if(this.commandProcessor[commandObj.argumentArray[0].toLowerCase()] != null){
|
||||
//Process the command and use the return value to set the sendflag (true if command valid)
|
||||
commandObj.sendFlag = await this.commandProcessor[commandObj.argumentArray[0].toLowerCase()](commandObj, this);
|
||||
}else{
|
||||
//Process as toke command if we didnt get a match from the standard server-side command processor
|
||||
commandObj.sendFlag = await this.tokebot.tokeProcessor(commandObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through links in message and marks them by link type for later use by client-side post-processing
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
*/
|
||||
async markLinks(commandObj){
|
||||
//Setup the links array
|
||||
commandObj.links = [];
|
||||
|
||||
//For each link sent from the client
|
||||
//this.rawData.links.forEach((link) => {
|
||||
for (const link of commandObj.rawData.links){
|
||||
//Add a marked link object to our links array
|
||||
commandObj.links.push(await linkUtils.markLink(link));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-creates message string from processed Command Array
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
*/
|
||||
async prepMessage(commandObj){
|
||||
//Create message from commandArray
|
||||
commandObj.message = commandObj.commandArray.join('').trimStart();
|
||||
//Validate links and mark them by embed type
|
||||
await this.markLinks(commandObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relays chat to channel via parent Chat Handler object
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
*/
|
||||
sendChat(commandObj){
|
||||
//FUCKIN' SEND IT!
|
||||
this.chatHandler.relayUserChat(commandObj.socket, commandObj.message, commandObj.chatType, commandObj.links);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing global server-side chat/command processing logic
|
||||
*/
|
||||
class commandProcessor{
|
||||
/**
|
||||
* Instantiates a commandProcessor object
|
||||
* @param {channelManager} server - Parent Server Object
|
||||
* @param {chatHandler} chatHandler - Parent Chat Handler Object
|
||||
*/
|
||||
constructor(server, chatHandler){
|
||||
this.server = server;
|
||||
this.chatHandler = chatHandler;
|
||||
}
|
||||
|
||||
//Command keywords get run through .toLowerCase(), so we should use lowercase method names for command methods
|
||||
/**
|
||||
* Command Processor method to handle the '!whisper' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag
|
||||
*/
|
||||
whisper(commandObj){
|
||||
//splice out our command
|
||||
commandObj.commandArray.splice(0,2);
|
||||
|
||||
//Mark out the current message as a whisper
|
||||
commandObj.chatType = 'whisper';
|
||||
|
||||
//Make sure to throw the send flag
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!spoiler' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag
|
||||
*/
|
||||
spoiler(commandObj){
|
||||
//splice out our command
|
||||
commandObj.commandArray.splice(0,2);
|
||||
|
||||
//Mark out the current message as a spoiler
|
||||
commandObj.chatType = 'spoiler';
|
||||
|
||||
//Make sure to throw the send flag
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!strikethrough' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag
|
||||
*/
|
||||
strikethrough(commandObj){
|
||||
//splice out our command
|
||||
commandObj.commandArray.splice(0,2);
|
||||
|
||||
//Mark out the current message as a spoiler
|
||||
commandObj.chatType = 'strikethrough';
|
||||
|
||||
//Make sure to throw the send flag
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!bold' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag
|
||||
*/
|
||||
bold(commandObj){
|
||||
//splice out our command
|
||||
commandObj.commandArray.splice(0,2);
|
||||
|
||||
//Mark out the current message as a spoiler
|
||||
commandObj.chatType = 'bold';
|
||||
|
||||
//Make sure to throw the send flag
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!italics' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag
|
||||
*/
|
||||
italics(commandObj){
|
||||
//splice out our command
|
||||
commandObj.commandArray.splice(0,2);
|
||||
|
||||
//Mark out the current message as a spoiler
|
||||
commandObj.chatType = 'italics';
|
||||
|
||||
//Make sure to throw the send flag
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!announce' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
|
||||
*/
|
||||
async announce(commandObj, preprocessor){
|
||||
//Get the current channel from the database
|
||||
const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
|
||||
|
||||
//Check if the user has permission, and publicly shame them if they don't (lmao)
|
||||
if(chanDB != null && await chanDB.permCheck(commandObj.socket.user, 'announce')){
|
||||
//splice out our command
|
||||
commandObj.commandArray.splice(0,2);
|
||||
|
||||
//Prep the message using pre-processor functions chat-handling
|
||||
await preprocessor.prepMessage(commandObj);
|
||||
|
||||
//send it
|
||||
this.chatHandler.relayChannelAnnouncement(commandObj.socket.chan, commandObj.message, commandObj.links);
|
||||
|
||||
//throw send flag
|
||||
return false;
|
||||
}
|
||||
|
||||
//throw send flag
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!serverannounce' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
|
||||
*/
|
||||
async serverannounce(commandObj, preprocessor){
|
||||
//Check if the user has permission, and publicly shame them if they don't (lmao)
|
||||
if(await permissionModel.permCheck(commandObj.socket.user, 'announce')){
|
||||
//splice out our command
|
||||
commandObj.commandArray.splice(0,2);
|
||||
|
||||
//Prep the message using pre-processor functions for chat-handling
|
||||
await preprocessor.prepMessage(commandObj);
|
||||
|
||||
//send it
|
||||
this.chatHandler.relayServerAnnouncement(commandObj.message, commandObj.links);
|
||||
|
||||
//disble send flag
|
||||
return false;
|
||||
}
|
||||
|
||||
//throw send flag
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!resettoke' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
|
||||
*/
|
||||
async resettoke(commandObj, preprocessor){
|
||||
//Check if the user has permission, and publicly shame them if they don't (lmao)
|
||||
if(await permissionModel.permCheck(commandObj.socket.user, 'resetToke')){
|
||||
//Acknowledge command
|
||||
this.chatHandler.relayTokeWhisper(commandObj.socket, 'Toke cooldown reset.');
|
||||
|
||||
//Tell tokebot to reset the toke
|
||||
preprocessor.tokebot.resetToke();
|
||||
|
||||
//disable send flag
|
||||
return false;
|
||||
}
|
||||
|
||||
//throw send flag
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!clear' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
|
||||
*/
|
||||
async clear(commandObj){
|
||||
//Get the current channel from the database
|
||||
const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
|
||||
|
||||
//Check if the user has permission, and publicly shame them if they don't (lmao)
|
||||
if(await chanDB.permCheck(commandObj.socket.user, 'clearChat')){
|
||||
//Send off the command
|
||||
this.chatHandler.clearChat(commandObj.socket.chan, commandObj.argumentArray[1]);
|
||||
//disable send flag
|
||||
return false;
|
||||
}
|
||||
|
||||
//throw send flag
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command Processor method to handle the '!kick' command
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request
|
||||
* @returns {Boolean} True to enable send flag on un-authorized call to shame the user
|
||||
*/
|
||||
async kick(commandObj){
|
||||
//Get the current channel from the database
|
||||
const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
|
||||
|
||||
//Check if the user has permission, and publicly shame them if they don't (lmao)
|
||||
if(await chanDB.permCheck(commandObj.socket.user, 'kickUser')){
|
||||
//Get username from argument array
|
||||
const username = commandObj.argumentArray[1];
|
||||
|
||||
//Get channel
|
||||
const channel = this.server.activeChannels.get(commandObj.socket.chan);
|
||||
|
||||
//get initiator and target user objects
|
||||
const initiator = channel.userList.get(commandObj.socket.user.user);
|
||||
const target = channel.userList.get(username);
|
||||
|
||||
//get initiator and target override abilities
|
||||
const override = await permissionModel.overrideCheck(commandObj.socket.user, 'kickUser');
|
||||
const targetOverride = await permissionModel.overrideCheck(target, 'kickUser');
|
||||
|
||||
//If there is no user
|
||||
if(target == null){
|
||||
//silently drop the command
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//If the user is capable of overriding this permission based on site permissions
|
||||
if(override || targetOverride){
|
||||
//If the site rank is equal
|
||||
if(permissionModel.rankToNum(initiator.rank) == permissionModel.rankToNum(target.rank)){
|
||||
//compare chan rank
|
||||
if(permissionModel.rankToNum(initiator.chanRank) <= permissionModel.rankToNum(target.chanRank)){
|
||||
//shame the person running it
|
||||
return true;
|
||||
}
|
||||
//otherwise
|
||||
}else{
|
||||
//compare site rank
|
||||
if(permissionModel.rankToNum(initiator.rank) <= permissionModel.rankToNum(target.rank)){
|
||||
//shame the person running it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//If the target has a higher chan rank than the initiator
|
||||
if(permissionModel.rankToNum(initiator.chanRank) <= permissionModel.rankToNum(target.chanRank)){
|
||||
//shame the person running it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Splice out kick
|
||||
commandObj.commandArray.splice(0,4)
|
||||
|
||||
//Get collect reason
|
||||
var reason = commandObj.commandArray.join('');
|
||||
|
||||
//If no reason was given
|
||||
if(reason == ''){
|
||||
//Fill in a generic reason
|
||||
reason = "You have been kicked from the channel!";
|
||||
}
|
||||
|
||||
//Kick the user
|
||||
target.disconnect(reason);
|
||||
|
||||
//throw send flag
|
||||
return false;
|
||||
}
|
||||
|
||||
//throw send flag
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = commandPreprocessor;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/connectedUser.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/connectedUser.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
//local imports
|
||||
const config = require('../../../config.json');
|
||||
const channelModel = require('../../schemas/channel/channelSchema');
|
||||
const permissionModel = require('../../schemas/permissionSchema');
|
||||
const flairModel = require('../../schemas/flairSchema');
|
||||
const emoteModel = require('../../schemas/emoteSchema');
|
||||
const { userModel } = require('../../schemas/user/userSchema');
|
||||
|
||||
/**
|
||||
* Class representing a single user connected to a channel
|
||||
*/
|
||||
class connectedUser{
|
||||
/**
|
||||
* Instantiates a connectedUser object
|
||||
* @param {Mongoose.Document} userDB - User document to re-hydrate user from
|
||||
* @param {PemissionModel.chanRank} chanRank - Enum representing user channel rank
|
||||
* @param {String} - Channel the user is connecting to
|
||||
* @param {Socket} socket - Socket associated with the users connection
|
||||
*/
|
||||
constructor(userDB, chanRank, channel, socket){
|
||||
/**
|
||||
* User ID Number
|
||||
*/
|
||||
this.id = userDB.id;
|
||||
|
||||
/**
|
||||
* User Name
|
||||
*/
|
||||
this.user = userDB.user;
|
||||
|
||||
/**
|
||||
* User Rank
|
||||
*/
|
||||
this.rank = userDB.rank;
|
||||
|
||||
/**
|
||||
* User High-Level
|
||||
*/
|
||||
this.highLevel = userDB.highLevel;
|
||||
|
||||
//Check to make sure users flair entry from DB is good
|
||||
if(userDB.flair != null){
|
||||
//Set flair from DB
|
||||
/**
|
||||
* User Flair
|
||||
*/
|
||||
this.flair = userDB.flair.name;
|
||||
//Otherwise
|
||||
}else{
|
||||
//Gracefully default to classic
|
||||
/**
|
||||
* User Flair
|
||||
*/
|
||||
this.flair = 'classic';
|
||||
}
|
||||
|
||||
/**
|
||||
* User Channel-Rank
|
||||
*/
|
||||
this.chanRank = chanRank;
|
||||
|
||||
/**
|
||||
* Connected Channel
|
||||
*/
|
||||
this.channel = channel;
|
||||
|
||||
/**
|
||||
* List of active sockets to current channel
|
||||
*/
|
||||
this.sockets = [socket.id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles server-side initialization for new connections from a specific user
|
||||
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
|
||||
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
|
||||
* @param {Socket} socket - Requesting Socket
|
||||
*/
|
||||
async handleConnection(userDB, chanDB, socket){
|
||||
//send metadata to client
|
||||
this.sendClientMetadata();
|
||||
|
||||
//Send out emotes
|
||||
this.sendSiteEmotes();
|
||||
this.sendChanEmotes(chanDB);
|
||||
this.sendPersonalEmotes(userDB);
|
||||
|
||||
//Send out used tokes
|
||||
this.sendUsedTokes(userDB);
|
||||
|
||||
//Send out the currently playing item
|
||||
this.channel.queue.sendMedia(socket);
|
||||
|
||||
//If we're proxied
|
||||
if(config.proxied){
|
||||
//Tattoo hashed IP address from reverse proxy to user account for seven days
|
||||
await userDB.tattooIPRecord(socket.handshake.headers['x-forwarded-for']);
|
||||
}else{
|
||||
//Tattoo hashed IP address to user account for seven days
|
||||
await userDB.tattooIPRecord(socket.handshake.address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through all known connections for a given user, running them through a supplied callback function
|
||||
* @param {Function} cb - Callback to call against found sockets for a given user
|
||||
*/
|
||||
socketCrawl(cb){
|
||||
//Crawl through user's sockets (lol)
|
||||
this.sockets.forEach((sockid) => {
|
||||
//get socket based on ID
|
||||
const socket = this.channel.server.io.sockets.sockets.get(sockid);
|
||||
//Callback with socket
|
||||
cb(socket);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emits an event to all known sockets for a given user
|
||||
*
|
||||
* My brain keeps going back to using dynamic per-user namespaces for this
|
||||
* but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces
|
||||
* and using per-user channels for this, but what of gold or mod-only features? or games?
|
||||
* No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms).
|
||||
* at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it.
|
||||
* Having to crawl through these sockets is that. Because the other ways seem more gross somehow.
|
||||
* @param {String} eventName - Event name to emit to client sockets
|
||||
* @param {Object} data - Data to emit to client sockets
|
||||
*/
|
||||
emit(eventName, data){
|
||||
this.socketCrawl((socket)=>{
|
||||
//Ensure our socket is initialized
|
||||
if(socket != null){
|
||||
socket.emit(eventName, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects all sockets for a given user
|
||||
* @param {String} reason - Reason for being disconnected
|
||||
* @param {String} type - Disconnection Type
|
||||
*/
|
||||
disconnect(reason, type = "Disconnected"){
|
||||
this.emit("kick",{type, reason});
|
||||
this.socketCrawl((socket)=>{socket.disconnect()});
|
||||
}
|
||||
|
||||
//This is the big first push upon connection
|
||||
//It should only fire once, so things that only need to be sent once can be slapped into here
|
||||
/**
|
||||
* Sends glut of required initial metadata to the client upon a new connection
|
||||
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
|
||||
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
|
||||
*/
|
||||
async sendClientMetadata(userDB, chanDB){
|
||||
//Get flairList from DB and setup flairList array
|
||||
const flairListDB = await flairModel.find({});
|
||||
var flairList = [];
|
||||
|
||||
//if we wherent handed a user document
|
||||
if(userDB == null){
|
||||
//Pull it based on user name
|
||||
userDB = await userModel.findOne({user: this.user});
|
||||
}
|
||||
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
chanDB = await channelModel.findOne({name: this.channel.name});
|
||||
}
|
||||
|
||||
//If our perm map is un-initiated
|
||||
//can't set this in constructor easily since it's asyncornous
|
||||
//need to wait for it to complete before sending this off, but shouldnt re-do the wait for later connections
|
||||
if(this.permMap == null){
|
||||
//Grab perm map
|
||||
this.permMap = await chanDB.getPermMapByUserDoc(userDB);
|
||||
}
|
||||
|
||||
//Setup our userObj
|
||||
const userObj = {
|
||||
id: this.id,
|
||||
user: this.user,
|
||||
rank: this.rank,
|
||||
chanRank: this.chanRank,
|
||||
highLevel: this.highLevel,
|
||||
permMap: {
|
||||
site: Array.from(this.permMap.site),
|
||||
chan: Array.from(this.permMap.chan),
|
||||
},
|
||||
flair: this.flair,
|
||||
}
|
||||
|
||||
//For each flair listed in the Database
|
||||
flairListDB.forEach((flair)=>{
|
||||
//Check if the user has permission to use the current flair
|
||||
if(permissionModel.rankToNum(flair.rank) <= permissionModel.rankToNum(this.rank)){
|
||||
//If so push a light version of the flair object into our final flair list
|
||||
flairList.push({
|
||||
name: flair.name,
|
||||
displayName: flair.displayName
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//Get schedule as a temporary array
|
||||
const queue = await this.channel.queue.prepQueue(chanDB);
|
||||
|
||||
//Get schedule lock status
|
||||
const queueLock = this.channel.queue.locked;
|
||||
|
||||
//Get chat buffer
|
||||
const chatBuffer = this.channel.chatBuffer.buffer;
|
||||
|
||||
//Send off the metadata to our user's clients
|
||||
this.emit("clientMetadata", {user: userObj, flairList, queue, queueLock, chatBuffer});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send copy of site emotes to the user
|
||||
*/
|
||||
async sendSiteEmotes(){
|
||||
//Get emote list from DB
|
||||
const emoteList = await emoteModel.getEmotes();
|
||||
|
||||
//Send it off to the user
|
||||
this.emit('siteEmotes', emoteList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send copy of channel emotes to the user
|
||||
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
|
||||
*/
|
||||
async sendChanEmotes(chanDB){
|
||||
//if we wherent handed a channel document
|
||||
if(chanDB == null){
|
||||
//Pull it based on channel name
|
||||
chanDB = await channelModel.findOne({name: this.channel.name});
|
||||
}
|
||||
|
||||
//Pull emotes from channel
|
||||
const emoteList = chanDB.getEmotes();
|
||||
|
||||
//Send it off to the user
|
||||
this.emit('chanEmotes', emoteList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send copy of channel emotes to the user
|
||||
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
|
||||
*/
|
||||
async sendPersonalEmotes(userDB){
|
||||
//if we wherent handed a user document
|
||||
if(userDB == null){
|
||||
//Pull it based on user name
|
||||
userDB = await userModel.findOne({user: this.user});
|
||||
}
|
||||
|
||||
//Pull emotes from channel
|
||||
const emoteList = userDB.getEmotes();
|
||||
|
||||
//Send it off to the user
|
||||
this.emit('personalEmotes', emoteList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send copy of channel emotes to the user
|
||||
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
|
||||
*/
|
||||
async sendUsedTokes(userDB){
|
||||
//if we wherent handed a user document
|
||||
if(userDB == null){
|
||||
//Pull it based on user name
|
||||
userDB = await userModel.findOne({user: this.user});
|
||||
}
|
||||
|
||||
//Create array of used toks from toke map and send it out to the user
|
||||
this.emit('usedTokes',{
|
||||
tokes: Array.from(userDB.tokes.keys())
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flair for a given user and broadcast update to clients
|
||||
* @param {String} flair - Flair string to update user's flair to
|
||||
*/
|
||||
updateFlair(flair){
|
||||
this.flair = flair;
|
||||
|
||||
this.channel.broadcastUserList();
|
||||
this.sendClientMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set high level for a given user and broadcast update to clients
|
||||
* @param {Number} highLevel - Number to update user's high-level to
|
||||
*/
|
||||
updateHighLevel(highLevel){
|
||||
this.highLevel = highLevel;
|
||||
|
||||
//TODO: show high-level in userlist
|
||||
this.channel.broadcastUserList();
|
||||
this.sendClientMetadata();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connectedUser;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,119 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/media/media.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/media/media.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
/**
|
||||
* Object representing a piece of media
|
||||
*/
|
||||
class media{
|
||||
/**
|
||||
* Creates a new media object from scraped information
|
||||
* @param {String} title - Chosen title of media
|
||||
* @param {String} fileName - Original filename/title of media provided by source
|
||||
* @param {String} url - Original URL to file
|
||||
* @param {String} id - Video ID from source (IE: youtube watch code/archive.org file path)
|
||||
* @param {String} type - Original video source
|
||||
* @param {Number} duration - Length of media in seconds
|
||||
* @param {String} rawLink - URL to raw file copy of media, not applicable to all sources
|
||||
*/
|
||||
constructor(title, fileName, url, id, type, duration, rawLink = url){
|
||||
/**
|
||||
* Chosen title of media
|
||||
*/
|
||||
this.title = title;
|
||||
|
||||
/**
|
||||
* Original filename/title of media provided by source
|
||||
*/
|
||||
this.fileName = fileName
|
||||
|
||||
/**
|
||||
* Original URL to file
|
||||
*/
|
||||
this.url = url;
|
||||
|
||||
/**
|
||||
* Video ID from source (IE: youtube watch code/archive.org file path)
|
||||
*/
|
||||
this.id = id;
|
||||
|
||||
/**
|
||||
* Original video source
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* Length of media in seconds
|
||||
*/
|
||||
this.duration = duration;
|
||||
|
||||
/**
|
||||
* URL to raw file copy of media, not applicable to all sources
|
||||
*/
|
||||
this.rawLink = rawLink;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = media;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/media/queuedMedia.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/media/queuedMedia.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
//Local Imports
|
||||
const media = require('./media');
|
||||
|
||||
/**
|
||||
* Class extending media which represents a queued piece of media
|
||||
* @extends media
|
||||
*/
|
||||
class queuedMedia extends media{
|
||||
/**
|
||||
* Creates a new queued media object
|
||||
* @param {Number} startTime - JS Epoch representing start time
|
||||
* @param {Number} startTimeStamp - Media start time stamp in seconds (relative to duration)
|
||||
* @param {Number} earlyEnd - Media end timestamp in seconds (relative to duration)
|
||||
* @param {String} uuid - Media object's unique identifier
|
||||
*/
|
||||
constructor(title, fileName, url, id, type, duration, rawLink, startTime, startTimeStamp = 0, earlyEnd, uuid){
|
||||
//Call derived constructor
|
||||
super(title, fileName, url, id, type, duration, rawLink);
|
||||
|
||||
/**
|
||||
* JS Epoch (millis) representing start time
|
||||
*/
|
||||
this.startTime = startTime;
|
||||
|
||||
/**
|
||||
* Media start time stamp in seconds (relative to duration)
|
||||
*/
|
||||
this.startTimeStamp = startTimeStamp;
|
||||
|
||||
/**
|
||||
* Media ent timestamp in seconds (relative to duration)
|
||||
*/
|
||||
this.earlyEnd = earlyEnd;
|
||||
|
||||
/**
|
||||
* Media status type
|
||||
*/
|
||||
this.status = 'queued';
|
||||
|
||||
//If we have a null uuid (can't use default argument because of 'this')
|
||||
if(uuid == null){
|
||||
//Generate id unique to this specific entry of this specific file within this specific channel's queue
|
||||
//That way even if we have six copies of the same video queued, we can still uniquely idenitify each instance
|
||||
this.genUUID();
|
||||
}else{
|
||||
/**
|
||||
* Media object's unique identifier
|
||||
*/
|
||||
this.uuid = uuid;
|
||||
}
|
||||
}
|
||||
|
||||
//statics
|
||||
/**
|
||||
* Creates a queuedMedia object from a media object
|
||||
* @param {media} media - Media object to queue
|
||||
* @param {Number} startTime - Start time formatted as a JS Epoch
|
||||
* @param {Number} startTimeStamp - Start time stamp in seconds
|
||||
* @returns {queuedMedia} queuedMedia object created from given media object
|
||||
*/
|
||||
static fromMedia(media, startTime, startTimeStamp){
|
||||
//Create and return queuedMedia object from given media object and arguments
|
||||
return new this(
|
||||
media.title,
|
||||
media.fileName,
|
||||
media.url,
|
||||
media.id,
|
||||
media.type,
|
||||
media.duration,
|
||||
media.rawLink,
|
||||
startTime,
|
||||
startTimeStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts array of media objects into array of queuedMedia objects
|
||||
* @param {Array} mediaList - Array of media objects to queue
|
||||
* @param {Number} start - Start time formatted as JS Epoch
|
||||
* @returns Array of converted queued media objects
|
||||
*/
|
||||
static fromMediaArray(mediaList, start){
|
||||
//Queued Media List
|
||||
const queuedMediaList = [];
|
||||
//Start Time Offset
|
||||
let startOffset = 0;
|
||||
|
||||
for(let media of mediaList){
|
||||
//Convert mediaObj to queuedMedia and push to the back of the list
|
||||
queuedMediaList.push(this.fromMedia(media, start + startOffset, 0));
|
||||
|
||||
//Set start offset to end of the current item
|
||||
startOffset += (media.duration * 1000) + 5;
|
||||
}
|
||||
|
||||
return queuedMediaList;
|
||||
}
|
||||
|
||||
//methods
|
||||
/**
|
||||
* Generates new unique identifier for queued media
|
||||
*/
|
||||
genUUID(){
|
||||
this.uuid = crypto.randomUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the end time of a given queuedMedia object
|
||||
* @param {boolean} fullTime - Overrides early ends
|
||||
* @returns end time of given queuedMedia object
|
||||
*/
|
||||
getEndTime(fullTime = false){
|
||||
//If we have an early ending
|
||||
if(this.earlyEnd == null || fullTime){
|
||||
//Calculate our ending
|
||||
return this.startTime + ((this.duration - this.startTimeStamp) * 1000);
|
||||
}else{
|
||||
//Return our early end
|
||||
return this.startTime + (this.earlyEnd * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = queuedMedia;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,308 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: app/channel/tokebot.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: app/channel/tokebot.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/*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/>.*/
|
||||
|
||||
//Local Imports
|
||||
const tokeCommandModel = require('../../schemas/tokebot/tokeCommandSchema');
|
||||
const {userModel} = require('../../schemas/user/userSchema');
|
||||
const statSchema = require('../../schemas/statSchema');
|
||||
|
||||
|
||||
/**
|
||||
* Class containing global server-side tokebot logic
|
||||
*/
|
||||
class tokebot{
|
||||
/**
|
||||
* Instantiates a tokebot object
|
||||
* @param {channelManager} server - Parent Server Object
|
||||
* @param {chatHandler} chatHandler - Parent Chat Handler Object
|
||||
*/
|
||||
constructor(server, chatHandler){
|
||||
/**
|
||||
* Parent Server Object
|
||||
*/
|
||||
this.server = server;
|
||||
|
||||
/**
|
||||
* Parent Chat Handler
|
||||
*/
|
||||
this.chatHandler = chatHandler;
|
||||
|
||||
/**
|
||||
* Toke Timer
|
||||
*/
|
||||
this.tokeTimer = null;
|
||||
|
||||
/**
|
||||
* Cooldown Timer
|
||||
*/
|
||||
this.cooldownTimer = null;
|
||||
|
||||
/**
|
||||
* Toke time
|
||||
*/
|
||||
this.tokeTime = 60;
|
||||
|
||||
/**
|
||||
* Cooldown Time
|
||||
*/
|
||||
this.cooldownTime = 120;
|
||||
|
||||
/**
|
||||
* Toke Counter
|
||||
*/
|
||||
this.tokeCounter = 0;
|
||||
|
||||
/**
|
||||
* Cooldown Counter
|
||||
*/
|
||||
this.cooldownCounter = 0;
|
||||
|
||||
/**
|
||||
* List of current tokers
|
||||
*/
|
||||
this.tokers = new Map();
|
||||
|
||||
//Load in toke commands from the DB
|
||||
this.refreshCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads toke commands from DB into RAM-based toke command store
|
||||
*/
|
||||
async refreshCommands(){
|
||||
//Pull Command Strings from DB
|
||||
this.tokeCommands = await tokeCommandModel.getCommandStrings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes toke commands from Command Pre-Processor
|
||||
* @param {Object} commandObj - Object representing a single given command/chat request, passed down from the Command Pre-Processor
|
||||
* @returns {Boolean} True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat)
|
||||
*/
|
||||
tokeProcessor(commandObj){
|
||||
//Check for site-wide toke commands
|
||||
if(this.tokeCommands.indexOf(commandObj.argumentArray[0].toLowerCase()) != -1){
|
||||
//Seems lame to set a bool in an if statement but this would've made a really ugly turinary
|
||||
var foundToke = true;
|
||||
}else if(commandObj.argumentArray[0].toLowerCase() == 'r'){
|
||||
//Find the users active channel
|
||||
const activeChan = this.server.activeChannels.get(commandObj.socket.chan);
|
||||
|
||||
//Combile site-wide and channel tokes into one list
|
||||
const tokeList = this.tokeCommands.concat(activeChan.tokeCommands);
|
||||
|
||||
//Pick a random number between 0 and one less than the number of tokes
|
||||
const foundIndex = Math.round(Math.random() * (tokeList.length - 1));
|
||||
|
||||
//Set override command argument 0 w/ the found toke
|
||||
commandObj.argumentArray[0] = tokeList[foundIndex];
|
||||
|
||||
//throw toke flag
|
||||
var foundToke = true;
|
||||
}else{
|
||||
//Find the users active channel
|
||||
const activeChan = this.server.activeChannels.get(commandObj.socket.chan);
|
||||
|
||||
//Check if they're using a channel-only toke
|
||||
//This should be safe to do without a null check but someone prove me wrong lmao
|
||||
var foundToke = (activeChan.tokeCommands.indexOf(commandObj.argumentArray[0].toLowerCase()) != -1);
|
||||
}
|
||||
|
||||
|
||||
//If we found a toke
|
||||
if(foundToke){
|
||||
//If there is no active toke or cooldown (new toke)
|
||||
if(this.tokeTimer == null && this.cooldownTimer == null){
|
||||
//Call-out toke start
|
||||
this.chatHandler.relayTokeCallout(`A group toke has been started by ${commandObj.socket.user.user} from #${commandObj.socket.chan}! We'll be taking a toke in 60 seconds - join in by posting !${commandObj.argumentArray[0]}`);
|
||||
//Set a full minute on our toke timer
|
||||
this.tokeCounter = this.tokeTime;
|
||||
|
||||
//Add the toking user to the tokers map
|
||||
this.tokers.set(commandObj.socket.user.user, commandObj.argumentArray[0].toLowerCase());
|
||||
|
||||
//kick-off the count-down
|
||||
this.tokeTimer = setTimeout(this.countdown.bind(this), 1000)
|
||||
//If the tokeTimer is popping but the cooldownTimer has fucked off (a toke is in progress)
|
||||
}else if(this.cooldownTimer == null){
|
||||
//look for user in tokers map
|
||||
const foundToker = this.tokers.get(commandObj.socket.user.user);
|
||||
|
||||
//if the user has not yet joined the toke
|
||||
if(foundToker == null){
|
||||
//Call-out toke join
|
||||
this.chatHandler.relayTokeCallout(`${commandObj.socket.user.user} has joined the toke from #${commandObj.socket.chan}! Post !${commandObj.argumentArray[0]} to take part!`);
|
||||
|
||||
//Add the toking user to the tokers map
|
||||
this.tokers.set(commandObj.socket.user.user, commandObj.argumentArray[0].toLowerCase());
|
||||
//If the user is already in the toke
|
||||
}else{
|
||||
//Tell them to fuck off
|
||||
this.chatHandler.relayTokeWhisper(commandObj.socket, "You're already taking part in this toke!");
|
||||
}
|
||||
|
||||
//Otherwise (there isn't a toke timer, but there is a cooldown timer. AKA: we're in cooldown)
|
||||
}else{
|
||||
//if the cooldownTimer exists (we're cooling down the toke)
|
||||
this.chatHandler.relayTokeWhisper(commandObj.socket, `Please wait ${this.cooldownCounter} seconds before starting a new group toke.`);
|
||||
}
|
||||
|
||||
//Toke command found, and there isn't any extra text, don't send as chat (re-create fore.st tokebot behaviour)
|
||||
return (commandObj.command != `!${commandObj.argumentArray[0]}` && commandObj.command != '!r');
|
||||
}else{
|
||||
//No toke found, send it down the line, because shaming the user is funny
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called each second during the toke. Handles decrementing the timer variable, and countdown end logic.
|
||||
*/
|
||||
countdown(){
|
||||
//If we're in the last three seconds
|
||||
if(this.tokeCounter <= 3 && this.tokeCounter > 0){
|
||||
//Callout the last three seconds
|
||||
this.chatHandler.relayTokeCallout(`${this.tokeCounter}...`);
|
||||
//if the toke is over
|
||||
}else if(this.tokeCounter < 0){
|
||||
//if we had multiple tokers
|
||||
if(this.tokers.size > 1){
|
||||
//call out the toke
|
||||
this.chatHandler.relayTokeCallout(`Take a toke ${Array.from(this.tokers.keys()).join(', ')}! ${this.tokers.size} tokers!`);
|
||||
//if we only had one toker
|
||||
}else{
|
||||
//call out the solo toke
|
||||
this.chatHandler.relayTokeCallout(`Take a toke ${Array.from(this.tokers.keys())[0]}.`);
|
||||
}
|
||||
|
||||
//Asynchronously tattoo the toke into the users documents within the database so that tokebot doesn't have to wait or worry about DB transactions
|
||||
userModel.tattooToke(this.tokers);
|
||||
//Do the same for the global stat schema
|
||||
statSchema.tattooToke(this.tokers);
|
||||
|
||||
//Set the toke cooldown
|
||||
this.cooldownCounter = this.cooldownTime;
|
||||
this.cooldownTimer = setTimeout(this.cooldown.bind(this), 1000);
|
||||
|
||||
//Empty out the tokers array
|
||||
this.tokers = new Map;
|
||||
|
||||
//Null out our timer
|
||||
this.tokeTimer = null;
|
||||
|
||||
//return the function before it can continue
|
||||
return;
|
||||
}
|
||||
|
||||
//Decrement toke time
|
||||
this.tokeCounter--;
|
||||
//try again in another second
|
||||
this.tokeTimer = setTimeout(this.countdown.bind(this), 1000)
|
||||
}
|
||||
|
||||
/**
|
||||
* This method seems to be a vestage from a bygone era. We should remove it after documenting shit.
|
||||
* I would now, but I don't want to break shit in a comment-only commit.
|
||||
*/
|
||||
async asyncFinisher(){
|
||||
//Grab a copy of the tokers map before it gets cleared out
|
||||
const tokers = this.tokers;
|
||||
|
||||
//we need to wait for this so we don't send used tokes pre-maturely
|
||||
await userModel.tattooToke(tokers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs every second for 60 seconds after a toke
|
||||
*/
|
||||
cooldown(){
|
||||
//If the cooldown timer isn't over
|
||||
if(this.cooldownCounter > 0){
|
||||
//Decrement toke time
|
||||
this.cooldownCounter--;
|
||||
//try again in another second
|
||||
this.cooldownTimer = setTimeout(this.cooldown.bind(this), 1000);
|
||||
//If the cooldown is over
|
||||
}else{
|
||||
//Null out the cooldown timer
|
||||
this.cooldownTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets toke cooldowns early upon authorized request
|
||||
*/
|
||||
resetToke(){
|
||||
//Set cooldown to 0
|
||||
this.cooldownCounter = 0;
|
||||
|
||||
//Null out the timer
|
||||
this.cooldownTimer = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = tokebot;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,714 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: chat</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: chat</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>chat<span class="signature">(user, flair, highLevel, msg, type, links)</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Class representing a single chat message</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="chat"><span class="type-signature"></span>new chat<span class="signature">(user, flair, highLevel, msg, type, links)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Instantiates a chat message object
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>user</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="connectedUser.html">connectedUser</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">User who sent the message</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>flair</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Flair ID String for the flair used to send the message</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>highLevel</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Number</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Number representing current high level</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>msg</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Contents of the message, with links replaced with numbered file-seperator markers</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>type</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">String</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Message Type Identifier, used for client-side processing.</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>links</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Array</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">Array of URLs/Links included in the message.</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="app_channel_chat.js.html">app/channel/chat.js</a>, <a href="app_channel_chat.js.html#line20">line 20</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="flair"><span class="type-signature"></span>flair<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Flair ID String for the flair used to send the message
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="app_channel_chat.js.html">app/channel/chat.js</a>, <a href="app_channel_chat.js.html#line39">line 39</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="highLevel"><span class="type-signature"></span>highLevel<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Number representing current high level
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="app_channel_chat.js.html">app/channel/chat.js</a>, <a href="app_channel_chat.js.html#line44">line 44</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="links"><span class="type-signature"></span>links<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Array of URLs/Links included in the message.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="app_channel_chat.js.html">app/channel/chat.js</a>, <a href="app_channel_chat.js.html#line59">line 59</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="msg"><span class="type-signature"></span>msg<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
COntents of the message, with links replaced with numbered file-seperator marks
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="app_channel_chat.js.html">app/channel/chat.js</a>, <a href="app_channel_chat.js.html#line49">line 49</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="type"><span class="type-signature"></span>type<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Message Type Identifier, used for client-side processing.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="app_channel_chat.js.html">app/channel/chat.js</a>, <a href="app_channel_chat.js.html#line54">line 54</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="user"><span class="type-signature"></span>user<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
User who sent the message
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="app_channel_chat.js.html">app/channel/chat.js</a>, <a href="app_channel_chat.js.html#line34">line 34</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="activeChannel.html">activeChannel</a></li><li><a href="channelManager.html">channelManager</a></li><li><a href="chat.html">chat</a></li><li><a href="chatBuffer.html">chatBuffer</a></li><li><a href="chatHandler.html">chatHandler</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="connectedUser.html">connectedUser</a></li><li><a href="media.html">media</a></li><li><a href="playlistHandler.html">playlistHandler</a></li><li><a href="queue.html">queue</a></li><li><a href="queuedMedia.html">queuedMedia</a></li><li><a href="tokebot.html">tokebot</a></li></ul><h3>Global</h3><ul><li><a href="global.html#authenticateSession">authenticateSession</a></li><li><a href="global.html#cache">cache</a></li><li><a href="global.html#channelBanSchema">channelBanSchema</a></li><li><a href="global.html#channelPermissionSchema">channelPermissionSchema</a></li><li><a href="global.html#channelSchema">channelSchema</a></li><li><a href="global.html#chatSchema">chatSchema</a></li><li><a href="global.html#comparePassword">comparePassword</a></li><li><a href="global.html#consoleWarn">consoleWarn</a></li><li><a href="global.html#daysToExpire">daysToExpire</a></li><li><a href="global.html#dumpError">dumpError</a></li><li><a href="global.html#emailChangeSchema">emailChangeSchema</a></li><li><a href="global.html#emoteSchema">emoteSchema</a></li><li><a href="global.html#errorHandler">errorHandler</a></li><li><a href="global.html#errorMiddleware">errorMiddleware</a></li><li><a href="global.html#escapeRegex">escapeRegex</a></li><li><a href="global.html#exceptionHandler">exceptionHandler</a></li><li><a href="global.html#exceptionSmith">exceptionSmith</a></li><li><a href="global.html#failedAttempts">failedAttempts</a></li><li><a href="global.html#fetchMetadata">fetchMetadata</a></li><li><a href="global.html#fetchVideoMetadata">fetchVideoMetadata</a></li><li><a href="global.html#fetchYoutubeMetadata">fetchYoutubeMetadata</a></li><li><a href="global.html#fetchYoutubePlaylistMetadata">fetchYoutubePlaylistMetadata</a></li><li><a href="global.html#flairSchema">flairSchema</a></li><li><a href="global.html#genCaptcha">genCaptcha</a></li><li><a href="global.html#getLoginAttempts">getLoginAttempts</a></li><li><a href="global.html#getMediaType">getMediaType</a></li><li><a href="global.html#hashIP">hashIP</a></li><li><a href="global.html#hashPassword">hashPassword</a></li><li><a href="global.html#kickoff">kickoff</a></li><li><a href="global.html#killSession">killSession</a></li><li><a href="global.html#lifetime">lifetime</a></li><li><a href="global.html#localExceptionHandler">localExceptionHandler</a></li><li><a href="global.html#mailem">mailem</a></li><li><a href="global.html#markLink">markLink</a></li><li><a href="global.html#maxAttempts">maxAttempts</a></li><li><a href="global.html#mediaSchema">mediaSchema</a></li><li><a href="global.html#passwordResetSchema">passwordResetSchema</a></li><li><a href="global.html#permissionSchema">permissionSchema</a></li><li><a href="global.html#playlistMediaProperties">playlistMediaProperties</a></li><li><a href="global.html#playlistSchema">playlistSchema</a></li><li><a href="global.html#processExpiredAttempts">processExpiredAttempts</a></li><li><a href="global.html#queuedProperties">queuedProperties</a></li><li><a href="global.html#rankEnum">rankEnum</a></li><li><a href="global.html#refreshRawLink">refreshRawLink</a></li><li><a href="global.html#schedule">schedule</a></li><li><a href="global.html#securityCheck">securityCheck</a></li><li><a href="global.html#sendAddressVerification">sendAddressVerification</a></li><li><a href="global.html#socketCriticalExceptionHandler">socketCriticalExceptionHandler</a></li><li><a href="global.html#socketErrorHandler">socketErrorHandler</a></li><li><a href="global.html#socketExceptionHandler">socketExceptionHandler</a></li><li><a href="global.html#spent">spent</a></li><li><a href="global.html#statSchema">statSchema</a></li><li><a href="global.html#throttleAttempts">throttleAttempts</a></li><li><a href="global.html#tokeCommandSchema">tokeCommandSchema</a></li><li><a href="global.html#transporter">transporter</a></li><li><a href="global.html#typeEnum">typeEnum</a></li><li><a href="global.html#userBanSchema">userBanSchema</a></li><li><a href="global.html#userSchema">userSchema</a></li><li><a href="global.html#verify">verify</a></li><li><a href="global.html#yankMedia">yankMedia</a></li><li><a href="global.html#ytdlpFetch">ytdlpFetch</a></li></ul>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 19:07:56 GMT-0400 (Eastern Daylight Time)
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 114 KiB |