Started work on queueEntries for active livestreams.

This commit is contained in:
rainbow napkin 2025-05-15 08:36:04 -04:00
parent a927b31919
commit afa57e8080
4 changed files with 227 additions and 79 deletions

View file

@ -101,7 +101,7 @@ class queuePanel extends panelObj{
closer(){
//Clear any remaining timers
clearTimeout(this.timeMarkerTimer);
clearTimeout(this.renderIntervalTimer);
//Clear timetips
this.killTimetips();
}
@ -382,7 +382,7 @@ class queuePanel extends panelObj{
}
//Set scale label text to humie readable time scale
this.scaleLabel.innerHTML = `Time Scale:<br>${this.humieFriendlyDuration(this.scale)}`
this.scaleLabel.innerHTML = `Time Scale:<br>${utils.ux.humieFriendlyDuration(this.scale)}`
//Clear any previous rescale timer
clearTimeout(this.rescaleTimer);
@ -403,64 +403,7 @@ class queuePanel extends panelObj{
this.autoscroll = false;
//Unlight the indicator
this.scrollLockButton.classList.remove('positive-button');
}
humieFriendlyDuration(seconds){
//If we have an invalid duration
if(seconds <= 0){
//bitch, moan, and complain!
return('Invalid input duration');
}
//Create an empty array to hold the time strings
const timeStrings = [];
//Pull hours from time
const hours = Math.floor(seconds / 3600);
//Remove recorded hours
seconds -= hours * 3600;
//Pull minutes from time
const minutes = Math.floor(seconds / 60);
//Remove recorded minutes
seconds -= minutes * 60;
//If we have an hour
if(hours == 1){
//Add the string
timeStrings.push('1 Hour');
//If we have hours
}else if(hours > 0){
//Add the string
timeStrings.push(`${hours} Hours`);
}
//If we have a minute
if(minutes == 1){
//Add the string
timeStrings.push('1 Minute');
//If we have minutes
}else if(minutes > 0){
//Add the string
timeStrings.push(`${minutes} Minutes`);
}
//Add the 'and ' if we need it
const secondsPrefix = timeStrings.length > 0 ? 'and ' : '';
//If we have a second
if(seconds == 1){
//Add the string
timeStrings.push(`${secondsPrefix}1 Second`);
//If we have more than a second
}else if(seconds > 1){
//Add the string
timeStrings.push(`${secondsPrefix}${seconds} Seconds`);
}
//Join the time strings together
return timeStrings.join(', ');
}
}
resizeRender(event){
const date = new Date();
@ -490,7 +433,7 @@ class queuePanel extends panelObj{
}
//Clear any marker timers
clearTimeout(this.timeMarkerTimer);
clearTimeout(this.renderIntervalTimer);
//If we have an existing time marker
if(this.timeMarker != null){
@ -501,7 +444,6 @@ class queuePanel extends panelObj{
}
async fullRender(date = new Date()){
//Clear the queue
this.clearQueue();
@ -524,9 +466,12 @@ class queuePanel extends panelObj{
await utils.ux.awaitNextFrame();
}
//render the time marker
//render the time marker w/ force scroll
this.renderTimeMarker(date, true);
//Kick off render interval
this.renderInterval(date);
//render out the queue
this.renderQueue(date);
}
@ -575,7 +520,7 @@ class queuePanel extends panelObj{
//Place item beginning at dawn
entryDiv.style.top = `${this.offsetByDate(dawn)}px`;
//Run apply the rest of the styling rules
//Apply style rules for items that starrted yesterday
entryDiv.classList.add('started-yesterday');
}
@ -620,14 +565,14 @@ class queuePanel extends panelObj{
`Title: ${entry[1].title}`,
`File Name: ${entry[1].fileName}`,
`Source: ${entry[1].type}`,
`Duration: ${entry[1].duration}`,
`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 = string;
component.textContent = utils.unescapeEntities(string);
//Append it to the tooltip div
tooltipDiv.append(component);
}
@ -690,6 +635,9 @@ class queuePanel extends panelObj{
//Append entry
this.queueContainer.append(entryDiv);
}
//Render out any playing livestreams
this.renderLiveStream(date);
}
function clickEntry(event){
@ -888,6 +836,18 @@ class queuePanel extends panelObj{
}
}
renderInterval(date = new Date()){
this.renderTimeMarker(date);
this.renderLiveStream(date);
//Clear update timer
clearTimeout(this.renderIntervalTimer);
//Set timer to update marker every second
this.renderIntervalTimer = setTimeout(this.renderInterval.bind(this), 1000);
}
renderTimeMarker(date = new Date(), forceScroll = false){
//Calculate marker position by date
const markerPosition = Math.round(this.offsetByDate(date));
@ -895,7 +855,7 @@ class queuePanel extends panelObj{
//If markers are null
if(markerPosition == null){
//Try again in a second since the user probably just popped the panel or something :P
(smackTimer.bind(this))();
return;
}
//If we're not looking at today
@ -940,16 +900,6 @@ class queuePanel extends panelObj{
behavior: scrollBehavior
});
}
//Set the timer to run the function again
(smackTimer.bind(this))();
function smackTimer(){
//Clear update timer
clearTimeout(this.timeMarkerTimer);
//Set timer to update marker every second
this.timeMarkerTimer = setTimeout(this.renderTimeMarker.bind(this), 1000);
}
}
renderQueueScale(inputDate = new Date()){
@ -1015,6 +965,135 @@ class queuePanel extends panelObj{
}
}
renderLiveStream(date = new Date()){
//Grab all live queue entries
const staleEntry = this.queueContainer.querySelector('.queue-entry.live');
//If we're not livestreaming
if(client.player.mediaHandler.type != "livehls"){
//If we have a stale entry
if(staleEntry != null){
//Remove stale entry since we're no longer streaming
staleEntry.remove();
}
//Fuck off and die
return;
}
//Grab currently playing media
const nowPlaying = client.player.mediaHandler.nowPlaying;
//If we don't have a good stale entry to re-use
if(staleEntry == null || staleEntry.dataset.uuid != nowPlaying.uuid){
//If it wasn't null but just old
if(staleEntry != null){
//Nukem
staleEntry.remove();
}
//Create entry div
const entryDiv = document.createElement('div');
entryDiv.classList.add('queue-entry', 'live');
//Iterate through nowPlaying's properties
for(let key of Object.keys(nowPlaying)){
//Add them to the entry div's dataset
entryDiv.dataset[key] = nowPlaying[key];
}
//Convert start epoch to JS date object
const started = new Date(nowPlaying.startTime);
//If this started today
if(utils.isSameDate(this.day, started)){
//Set entryDiv top-border location based on start time
entryDiv.style.top = `${this.offsetByDate(started)}px`
}else{
//Get dawn
const dawn = new Date();
dawn.setHours(0,0,0,0)
//Place item at the beginning of dawn
entryDiv.style.top = `${this.offsetByDate(dawn)}px`;
//Apply rest of the styling rules for items that started yestarday
entryDiv.classList.add('started-yesterday')
}
//Create entry title
const entryTitle = document.createElement('p');
entryTitle.textContent = utils.unescapeEntities(nowPlaying.title);
//Set entry div bottom-border location based on current time
entryDiv.style.bottom = `${this.offsetByDate(date, true)}px`
//Assembly entryDiv
entryDiv.appendChild(entryTitle);
//Setup media tooltip
entryDiv.addEventListener('mouseenter',(event)=>{
//Construct tooltip on mouseover to re-calculate duration for live media
const tooltipDiv = buildTooltip();
//Display tooltip
utils.ux.displayTooltip(event, tooltipDiv, false, null, true, this.ownerDoc);
});
//Append entry div to queue container
this.queueContainer.appendChild(entryDiv);
}else{
//Update existing entry
staleEntry.style.bottom = `${this.offsetByDate(date, true)}px`
}
//Keep tooltip date seperate so it re-calculates live duration properly
function buildTooltip(date = new Date()){
//Tooltip generation
//tooltip div
const tooltipDiv = document.createElement('div');
tooltipDiv.classList.add('media-tooltip');
//tooltip components
const tooltipStrings = [
`Title: ${nowPlaying.title}`,
`File Name: ${nowPlaying.fileName}`,
`Source: HLS Livestream (${nowPlaying.url})`,
`Duration: ${utils.ux.humieFriendlyDuration((date.getTime() - nowPlaying.startTime) / 1000)}`,
`Start Time: ${new Date(nowPlaying.startTime).toLocaleString()}`,
];
//For each string in the tooltip
for(const string of tooltipStrings){
//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);
}
//Create End Date
const source = document.createElement('p');
const liveSpan = document.createElement('span');
//Fill end date label
source.textContent = "End Time: "
liveSpan.textContent = 'LIVE'
//Set class
liveSpan.classList.add('critical-danger-text');
//Assemble end date
source.appendChild(liveSpan);
tooltipDiv.appendChild(source);
return tooltipDiv;
}
}
offsetByDate(date = new Date(), bottomOffset = false){
//Pull start of day epoch from given date, make sure to use a new date object so we don't fuck up any date objects passed to us
const dayEpoch = new Date(date).setHours(0,0,0,0);