Youtube videos now refresh metadata 10 seconds before playback starts.

This commit is contained in:
rainbow napkin 2025-05-06 21:13:54 -04:00
parent a71f1d6cc0
commit 60cd21d938
4 changed files with 62 additions and 5 deletions

View file

@ -42,6 +42,8 @@ module.exports = class{
this.syncTimer = null; this.syncTimer = null;
//Create variable to hold next playing item timer //Create variable to hold next playing item timer
this.nextTimer = null; this.nextTimer = null;
//Create vairable to hold pre-switch timer
this.preSwitchTimer = null;
//Create variable to hold currently playing media object //Create variable to hold currently playing media object
this.nowPlaying = null; this.nowPlaying = null;
@ -97,12 +99,12 @@ module.exports = class{
//Set title //Set title
const title = validator.escape(validator.trim(data.title)); const title = validator.escape(validator.trim(data.title));
//set start
let start = this.getStart(data.start);
//Pull media list //Pull media list
const mediaList = await yanker.yankMedia(url, title); const mediaList = await yanker.yankMedia(url, title);
//set start
let start = this.getStart(data.start);
//If we didn't find any media //If we didn't find any media
if(mediaList == null || mediaList.length <= 0){ if(mediaList == null || mediaList.length <= 0){
//Bitch, moan, complain... //Bitch, moan, complain...
@ -286,6 +288,7 @@ module.exports = class{
//Clear out any stale timers to prevent ghost queueing //Clear out any stale timers to prevent ghost queueing
clearTimeout(this.nextTimer); clearTimeout(this.nextTimer);
clearTimeout(this.preSwitchTimer);
//If we have a current item and it isn't currently playing //If we have a current item and it isn't currently playing
if(currentItem != null && (this.nowPlaying == null || currentItem.uuid != this.nowPlaying.uuid)){ if(currentItem != null && (this.nowPlaying == null || currentItem.uuid != this.nowPlaying.uuid)){
@ -293,8 +296,23 @@ module.exports = class{
this.start(currentItem, Math.round((new Date().getTime() - currentItem.startTime) / 1000) + currentItem.startTimeStamp, volatile); this.start(currentItem, Math.round((new Date().getTime() - currentItem.startTime) / 1000) + currentItem.startTimeStamp, volatile);
//If we have a next item //If we have a next item
}else if(nextItem != null){ }else if(nextItem != null){
//Get current time as epoch
const now = new Date().getTime();
//Calculate the amount of time in ms that the next item will start in //Calculate the amount of time in ms that the next item will start in
const startsIn = nextItem.startTime - new Date().getTime(); const startsIn = nextItem.startTime - now;
//Delay between pre-switch function call and start of media
//This should be enough time to do things like pre-fetch updated raw links from youtube
const preSwitchDelta = 10 * 1000;
//Calculate when the pre-switch timer would be called
const preSwitchTime = nextItem.startTime - preSwitchDelta;
//Calculate how long the pre-switch timer will be called in
const preSwitchIn = preSwitchTime - now;
//If we have enough time to call the pre-switch timer
if(preSwitchIn > preSwitchDelta){
//Set the pre-switch timer
this.preSwitchTimer = setTimeout(()=>{this.preSwitch(nextItem)}, preSwitchIn);
}
//Set the next timer //Set the next timer
this.nextTimer = setTimeout(()=>{this.start(nextItem, nextItem.startTimeStamp, volatile)}, startsIn); this.nextTimer = setTimeout(()=>{this.start(nextItem, nextItem.startTimeStamp, volatile)}, startsIn);
@ -655,6 +673,17 @@ module.exports = class{
return true; return true;
} }
async preSwitch(mediaObj){
//Check if media needs a new raw link and update if it does
if(await yanker.refreshRawLink(mediaObj)){
//If the fetch took so god damned long we've already started the video (isn't 10 seconds enough?)
if(this.nowPlaying != null && this.nowPlaying.uuid == mediaObj.uuid){
//Tell the clients to update the raw file for the current item fore.st-style, as it probably got sent out with a stale link
this.server.io.in(this.channel.name).emit("updateCurrentRawFile", {file: mediaObj.rawLink});
}
}
}
async start(mediaObj, timestamp = mediaObj.startTimeStamp, volatile = false){ async start(mediaObj, timestamp = mediaObj.startTimeStamp, volatile = false){
//If something is already playing //If something is already playing
if(this.nowPlaying != null){ if(this.nowPlaying != null){

View file

@ -54,7 +54,7 @@ queuedProperties.methods.rehydrate = function(){
this.type, this.type,
this.duration, this.duration,
//We don't save raw links that are stored seperate from the standard URL as they tend to expire. //We don't save raw links that are stored seperate from the standard URL as they tend to expire.
null, undefined,
this.startTime, this.startTime,
this.startTimeStamp, this.startTimeStamp,
this.earlyEnd, this.earlyEnd,

View file

@ -38,6 +38,22 @@ module.exports.yankMedia = async function(url, title){
} }
} }
module.exports.refreshRawLink = async function(mediaObj){
switch(mediaObj.type){
case 'yt':
//Re-fetch media metadata
metadata = await ytdlpUtil.fetchYoutubeVideoMetadata(mediaObj.id);
//Refresh media rawlink from metadata
mediaObj.rawLink = metadata[0].rawLink;
//return media object
return mediaObj;
}
//Return null to tell the calling function there is no refresh required for this media type
return null;
}
//I'd be lying if this didn't take at least some inspiration/regex patterns from extractQueryParam() in cytube/forest's browser-side 'util.js' //I'd be lying if this didn't take at least some inspiration/regex patterns from extractQueryParam() in cytube/forest's browser-side 'util.js'
//Still this has some improvements like url pre-checks and the fact that it's handled serverside, recuing possibility of bad requests. //Still this has some improvements like url pre-checks and the fact that it's handled serverside, recuing possibility of bad requests.
//Some of the regex expressions for certain services have also been improved, such as youtube, and the fore.st-unique archive.org //Some of the regex expressions for certain services have also been improved, such as youtube, and the fore.st-unique archive.org

View file

@ -71,6 +71,7 @@ class player{
this.client.socket.on("start", this.start.bind(this)); this.client.socket.on("start", this.start.bind(this));
this.client.socket.on("sync", this.sync.bind(this)); this.client.socket.on("sync", this.sync.bind(this));
this.client.socket.on("end", this.end.bind(this)); this.client.socket.on("end", this.end.bind(this));
this.client.socket.on("updateCurrentRawFile", this.updateCurrentRawFile.bind(this));
} }
start(data){ start(data){
@ -144,6 +145,17 @@ class player{
this.lockSync(); this.lockSync();
} }
updateCurrentRawFile(data){
//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});
}
lockSync(){ lockSync(){
//Enable syncing //Enable syncing
this.syncLock = true; this.syncLock = true;