diff --git a/src/views/partial/panels/queue.ejs b/src/views/partial/panels/queue.ejs
index 4c07713..753501f 100644
--- a/src/views/partial/panels/queue.ejs
+++ b/src/views/partial/panels/queue.ejs
@@ -50,6 +50,14 @@ along with this program. If not, see . %>
+
+
+ <%# Probably not the cleanest way to do this but fuggit %>
+
+
+
+
+
diff --git a/www/css/panel/queue.css b/www/css/panel/queue.css
index c2785ec..07b7af8 100644
--- a/www/css/panel/queue.css
+++ b/www/css/panel/queue.css
@@ -144,6 +144,26 @@ div.dragging-queue-entry{
margin: 0.15em 0.3em;
}
+/* Search Results */
+.queue-search-prompts-result-entry-div{
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ text-wrap: nowrap;
+ margin: 0 0.15em;
+ padding: 0 0.15em;
+ font-size: 0.8em
+}
+
+.queue-search-prompts-result-entry-div p{
+ margin: 0;
+ user-select: none;
+}
+
+.queue-search-prompts-result-entry-control-div i{
+ margin: 0 0.15em;
+}
+
/* playlist manager */
.queue-playlist-label-span{
display: flex;
diff --git a/www/css/theme/movie-night.css b/www/css/theme/movie-night.css
index 5e4d372..4caf154 100644
--- a/www/css/theme/movie-night.css
+++ b/www/css/theme/movie-night.css
@@ -708,8 +708,9 @@ div.archived p{
}
-.queue-playlist-media-container-div{
+.queue-playlist-media-container-div, #queue-search-prompts-result-div:not(:empty){
background-color: var(--bg1-alt0);
+ color: var(--accent1);
border-block: var(--accent1) solid 1px;
}
@@ -726,7 +727,7 @@ div.archived p{
color: var(--accent1);
}
-.queue-playlist-media-div.not-first{
+.queue-playlist-media-div.not-first, .queue-search-prompts-result-entry-div.not-first{
border-top: var(--bg1) solid 1px;
}
diff --git a/www/css/theme/the-network-classic.css b/www/css/theme/the-network-classic.css
index 5b4ba10..1ccbee5 100644
--- a/www/css/theme/the-network-classic.css
+++ b/www/css/theme/the-network-classic.css
@@ -907,8 +907,9 @@ div.archived p{
}
-.queue-playlist-media-container-div{
+.queue-playlist-media-container-div, #queue-search-prompts-result-div:not(:empty){
background-color: var(--bg1-alt0);
+ color: var(--accent1);
border-block: var(--accent1) solid 1px;
}
@@ -925,7 +926,7 @@ div.archived p{
color: var(--accent1);
}
-.queue-playlist-media-div.not-first{
+.queue-playlist-media-div.not-first, .queue-search-prompts-result-entry-div.not-first{
border-top: var(--bg1) solid 1px;
}
diff --git a/www/js/channel/channel.js b/www/js/channel/channel.js
index 010c343..0782a38 100644
--- a/www/js/channel/channel.js
+++ b/www/js/channel/channel.js
@@ -194,6 +194,30 @@ class channel{
}
}
+ /**
+ * searches through local un-archived queue for matching titles/urls
+ * @param {String} title - Title of media to search for
+ * @param {String} url - URL of media to search fo4
+ */
+ searchQueue(title, url){
+ //Create array to hold results of the search
+ const results = [];
+
+ //Run through the local queue
+ for(const rawEntry of this.queue.entries()){
+ //Quick syntatic sugar XP
+ const entry = rawEntry[1];
+ //If the entry title includes our title search string, or the URL is an exact match
+ if(((title != null && entry.title.includes(title)) || (url != null && entry.url == url)) && entry.status != "archived"){
+ //Plop that fucker down
+ results.push(entry);
+ }
+ }
+
+ //Return all found entries
+ return results;
+ }
+
/**
* Processes and applies default config on any unset settings
* @param {Boolean} force - Whether or not to forcefully reset already set settings
diff --git a/www/js/channel/panels/queuePanel/queuePanel.js b/www/js/channel/panels/queuePanel/queuePanel.js
index 50a9dee..05b1c21 100644
--- a/www/js/channel/panels/queuePanel/queuePanel.js
+++ b/www/js/channel/panels/queuePanel/queuePanel.js
@@ -88,6 +88,7 @@ class queuePanel extends panelObj{
//Get main control buttons
this.addMediaButton = this.panelDocument.querySelector('#queue-add-media');
this.goLiveButton = this.panelDocument.querySelector('#queue-go-live');
+ this.searchButton = this.panelDocument.querySelector('#queue-search-media');
this.scrollLockButton = this.panelDocument.querySelector('#queue-scroll-lock');
this.queueDateButton = this.panelDocument.querySelector('#queue-date');
this.playlistMenuButton = this.panelDocument.querySelector("#queue-playlists");
@@ -97,6 +98,7 @@ class queuePanel extends panelObj{
//Get control divs
this.addMediaDiv = this.panelDocument.querySelector('#queue-media-prompts');
this.goLiveDiv = this.panelDocument.querySelector('#queue-live-prompts');
+ this.searchDiv = this.panelDocument.querySelector('#queue-search-prompts');
this.queueDateDiv = this.panelDocument.querySelector('#queue-control-date');
this.playlistDiv = this.panelDocument.querySelector('#queue-playlist-prompts');
@@ -110,6 +112,10 @@ class queuePanel extends panelObj{
this.goLiveNamePrompt = this.panelDocument.querySelector("#queue-live-prompts-name-input");
this.goLiveOverwriteButton = this.panelDocument.querySelector("#queue-live-prompts-overwrite-button");
this.goLivePushbackButton = this.panelDocument.querySelector("#queue-live-prompts-pushback-button");
+ //Search
+ this.searchPrompt = this.panelDocument.querySelector('#queue-search-prompts-search-input');
+ this.searchPromptButton = this.panelDocument.querySelector('#queue-search-prompts-search-button');
+ this.searchResultDiv = this.panelDocument.querySelector('#queue-search-prompts-result-div')
//Date Queue date
this.queueDateDecrement = this.panelDocument.querySelector('#queue-control-date-decrement');
this.queueDateIncrement = this.panelDocument.querySelector('#queue-control-date-increment');
@@ -163,6 +169,7 @@ class queuePanel extends panelObj{
//control bar controls
this.addMediaButton.addEventListener('click', this.toggleAddMedia.bind(this));
this.goLiveButton.addEventListener('click', this.toggleGoLive.bind(this));
+ this.searchButton.addEventListener('click', this.toggleSearch.bind(this));
this.scrollLockButton.addEventListener('click', this.lockScroll.bind(this));
this.queueDateButton.addEventListener('click', this.toggleDateControl.bind(this));
this.playlistMenuButton.addEventListener('click', this.togglePlaylistDiv.bind(this));
@@ -274,6 +281,90 @@ class queuePanel extends panelObj{
}
}
+ /**
+ * Toggles add media UX
+ * @param {Event} event - Event passed down from Event Listener
+ */
+ toggleSearch(event){
+ //If the div is hidden
+ if(this.searchDiv.style.display == 'none'){
+ //Light up the button
+ this.searchButton.classList.add('positive-button');
+ //Show the div
+ this.searchDiv.style.display = '';
+ }else{
+ //Unlight the button
+ this.searchButton.classList.remove('positive-button');
+ //Hide the div
+ this.searchDiv.style.display = 'none';
+ }
+ }
+
+ search(event){
+ //Grab query
+ const query = this.searchPrompt.value;
+
+ //If we're searching by URL
+ if(utils.isURL(query)){
+ //Render local items matching provided URL
+ this.renderResults(client.searchQueue(undefined, query));
+ }else{
+ //Render local items matching title
+ this.renderResults(client.searchQueue(query));
+ }
+ }
+
+ renderResults(results){
+ //Keep track of whether or not we're on the first entry
+ let notFirst = false;
+
+ for(const entry of results){
+ //Create entry div
+ const entryDiv = document.createElement('div');
+ entryDiv.classList.add('queue-search-prompts-result-entry-div');
+
+ if(notFirst){
+ entryDiv.classList.add('not-first');
+ }
+
+ //Create and append entryTitle
+ const entryTitle = document.createElement('p');
+ entryTitle.textContent = utils.unescapeEntities(entry.title);
+
+ //Setup media tooltip
+ entryTitle.addEventListener('mouseenter',(event)=>{
+ //Display tooltip
+ utils.ux.displayTooltip(event, this.renderMediaTooltip(entry), false, null, true, this.ownerDoc);
+ });
+
+ //Append entry title
+ entryDiv.appendChild(entryTitle);
+
+ //Create a div to hold result controls
+ const controlDiv = document.createElement('div');
+ controlDiv.classList.add('queue-search-prompts-result-entry-control-div');
+
+ //Create go to entry button
+ const goToEntry = document.createElement('i');
+ goToEntry.classList.add('bi-arrow-return-left')
+ controlDiv.appendChild(goToEntry);
+
+ //Create queue entry button
+ const queueEntry = document.createElement('i');
+ queueEntry.classList.add('bi-play-circle')
+ controlDiv.appendChild(queueEntry);
+
+ //Append control div to entry div
+ entryDiv.appendChild(controlDiv);
+
+ //Add result to the result container
+ this.searchResultDiv.appendChild(entryDiv);
+
+ //Throw not first flag for future entries
+ notFirst = true;
+ }
+ }
+
/**
* Toggles Go-Live UX
* @param {Event} event - Event passed down from Event Listener
@@ -766,26 +857,7 @@ class queuePanel extends panelObj{
//Tooltip generation
//tooltip div
- const tooltipDiv = document.createElement('div');
- tooltipDiv.classList.add('media-tooltip');
-
- //tooltip components
- //For each string
- for(let string of [
- `Title: ${entry[1].title}`,
- `File Name: ${entry[1].fileName}`,
- `Source: ${entry[1].type}`,
- `Duration: ${utils.ux.humieFriendlyDuration(entry[1].duration)}`,
- `Start Time: ${new Date(entry[1].startTime).toLocaleString()}${entry[1].startTimeStamp == 0 ? '' : ' (Started Late)'}`,
- `End Time: ${new Date(this.getMediaEnd(entry[1])).toLocaleString()}${entry[1].earlyEnd == null ? '' : ' (Ended Early)'}`
- ]){
- //Create a 'p' node
- const component = document.createElement('p');
- //Fill it with the string
- component.textContent = utils.unescapeEntities(string);
- //Append it to the tooltip div
- tooltipDiv.append(component);
- }
+ const tooltipDiv = this.renderMediaTooltip(entry[1]);
//Setup media tooltip
entryDiv.addEventListener('mouseenter',(event)=>{
@@ -1042,6 +1114,38 @@ class queuePanel extends panelObj{
}
+ /**
+ * Ingests a media object and returns a working tooltip ready to be placed into DOM
+ * @param {Object} media - Media object to render tooltip for
+ * @returns DOMNode containing tooltip div
+ */
+ renderMediaTooltip(media){
+ //Create tooltip div
+ const tooltipDiv = document.createElement('div');
+ tooltipDiv.classList.add('media-tooltip');
+
+ //tooltip components
+ //For each string
+ for(let string of [
+ `Title: ${media.title}`,
+ `File Name: ${media.fileName}`,
+ `Source: ${media.type}`,
+ `Duration: ${utils.ux.humieFriendlyDuration(media.duration)}`,
+ `Start Time: ${new Date(media.startTime).toLocaleString()}${media.startTimeStamp == 0 ? '' : ' (Started Late)'}`,
+ `End Time: ${new Date(this.getMediaEnd(media)).toLocaleString()}${media.earlyEnd == null ? '' : ' (Ended Early)'}`
+ ]){
+ //Create a 'p' node
+ const component = document.createElement('p');
+ //Fill it with the string
+ component.textContent = utils.unescapeEntities(string);
+ //Append it to the tooltip div
+ tooltipDiv.append(component);
+ }
+
+ //Return tooltip
+ return tooltipDiv;
+ }
+
/**
* Kills off hung tooltips
* @param {Event} event - Event passed down from Event Listener
diff --git a/www/js/utils.js b/www/js/utils.js
index dda6c03..bdfa514 100644
--- a/www/js/utils.js
+++ b/www/js/utils.js
@@ -43,6 +43,20 @@ class canopyUtils{
dateWithinRange(min, max, input){
return min.getTime() < input.getTime() && max.getTime() > input.getTime();
}
+
+ isURL(url){
+ //attempt to makem a url
+ try{
+ new URL(url);
+ //if it dont work
+ }catch{
+ //FUCK
+ return false;
+ }
+
+ //if it do, return true XP
+ return true;
+ }
}