Source: app/channel/media/queuedMedia.js

/*Canopy - The next generation of stoner streaming software
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.*/

//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;