Continued work on channel-wide playlists.
This commit is contained in:
parent
72a89ae5ff
commit
70a68d9336
|
|
@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
||||||
const validator = require('validator');
|
const validator = require('validator');
|
||||||
|
|
||||||
//Local imports
|
//Local imports
|
||||||
|
const queuedMedia = require('./queuedMedia');
|
||||||
const loggerUtils = require('../../../utils/loggerUtils');
|
const loggerUtils = require('../../../utils/loggerUtils');
|
||||||
const yanker = require('../../../utils/media/yanker');
|
const yanker = require('../../../utils/media/yanker');
|
||||||
const channelModel = require('../../../schemas/channel/channelSchema');
|
const channelModel = require('../../../schemas/channel/channelSchema');
|
||||||
|
|
@ -35,8 +36,10 @@ module.exports = class{
|
||||||
socket.on("getChannelPlaylists", () => {this.getChannelPlaylists(socket)});
|
socket.on("getChannelPlaylists", () => {this.getChannelPlaylists(socket)});
|
||||||
socket.on("createChannelPlaylist", (data) => {this.createChannelPlaylist(socket, data)});
|
socket.on("createChannelPlaylist", (data) => {this.createChannelPlaylist(socket, data)});
|
||||||
socket.on("addToChannelPlaylist", (data) => {this.addToChannelPlaylist(socket, data)});
|
socket.on("addToChannelPlaylist", (data) => {this.addToChannelPlaylist(socket, data)});
|
||||||
|
socket.on("queueChannelPlaylist", (data) => {this.queueChannelPlaylist(socket, data)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--- USER-FACING PLAYLIST FUNCTIONS ---
|
||||||
async getChannelPlaylists(socket, chanDB){
|
async getChannelPlaylists(socket, chanDB){
|
||||||
//if we wherent handed a channel document
|
//if we wherent handed a channel document
|
||||||
if(chanDB == null){
|
if(chanDB == null){
|
||||||
|
|
@ -84,4 +87,30 @@ module.exports = class{
|
||||||
//Return playlists from channel doc
|
//Return playlists from channel doc
|
||||||
socket.emit('chanPlaylists', chanDB.getPlaylists());
|
socket.emit('chanPlaylists', chanDB.getPlaylists());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async queueChannelPlaylist(socket, data, 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 a valid start time from input, or make one up if we can't
|
||||||
|
let start = this.channel.queue.getStart(data.start);
|
||||||
|
|
||||||
|
//Grab playlist from the DB
|
||||||
|
let playlist = chanDB.getPlaylistByName(data.playlist);
|
||||||
|
|
||||||
|
//Create an empty array to hold our media list
|
||||||
|
const mediaList = [];
|
||||||
|
|
||||||
|
//Iterate through playlist media
|
||||||
|
for(let item of playlist.media){
|
||||||
|
//Rehydrate playlist item and push it into the media list
|
||||||
|
mediaList.push(item.rehydrate());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert array of standard media objects to queued media objects, and push to schedule
|
||||||
|
this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray(mediaList, start), socket, chanDB);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,11 +56,12 @@ module.exports = class{
|
||||||
socket.on("queue", (data) => {this.queueURL(socket, data)});
|
socket.on("queue", (data) => {this.queueURL(socket, data)});
|
||||||
socket.on("stop", (data) => {this.stopMedia(socket)});
|
socket.on("stop", (data) => {this.stopMedia(socket)});
|
||||||
socket.on("delete", (data) => {this.deleteMedia(socket, data)});
|
socket.on("delete", (data) => {this.deleteMedia(socket, data)});
|
||||||
socket.on("move", (data) => {this.moveMedia(socket, data)});
|
|
||||||
socket.on("clear", (data) => {this.deleteRange(socket, data)});
|
socket.on("clear", (data) => {this.deleteRange(socket, data)});
|
||||||
socket.on("lock", (data) => {this.toggleLock(socket)});
|
socket.on("move", (data) => {this.moveMedia(socket, data)});
|
||||||
|
socket.on("lock", () => {this.toggleLock(socket)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--- USER FACING QUEUEING FUNCTIONS ---
|
||||||
async queueURL(socket, data){
|
async queueURL(socket, data){
|
||||||
//Get the current channel from the database
|
//Get the current channel from the database
|
||||||
const chanDB = await channelModel.findOne({name: socket.chan});
|
const chanDB = await channelModel.findOne({name: socket.chan});
|
||||||
|
|
@ -68,7 +69,7 @@ module.exports = class{
|
||||||
if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
|
if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
|
||||||
try{
|
try{
|
||||||
//Set url
|
//Set url
|
||||||
var url = data.url;
|
let url = data.url;
|
||||||
|
|
||||||
//If we where given a bad URL
|
//If we where given a bad URL
|
||||||
if(!validator.isURL(url)){
|
if(!validator.isURL(url)){
|
||||||
|
|
@ -94,14 +95,9 @@ 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
|
|
||||||
var start = data.start;
|
|
||||||
|
|
||||||
//If start time isn't an integer after the current epoch
|
//set start
|
||||||
if(start != null &&!validator.isInt(String(start), (new Date().getTime()))){
|
let start = this.getStart(data.start);
|
||||||
//Null out time to tell the later parts of the function to start it now
|
|
||||||
start = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Pull media list
|
//Pull media list
|
||||||
const mediaList = await yanker.yankMedia(url, title);
|
const mediaList = await yanker.yankMedia(url, title);
|
||||||
|
|
@ -114,8 +110,56 @@ module.exports = class{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Queue the first media object given
|
//Convert media list
|
||||||
this.queueMedia(mediaList[0], start, socket);
|
let queuedMediaList = queuedMedia.fromMediaArray(mediaList, start);
|
||||||
|
|
||||||
|
//schedule the media
|
||||||
|
this.scheduleMedia(queuedMediaList, socket);
|
||||||
|
}catch(err){
|
||||||
|
return loggerUtils.socketExceptionHandler(socket, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopMedia(socket){
|
||||||
|
//If we're not currently playing anything
|
||||||
|
if(this.nowPlaying == null){
|
||||||
|
//If an originating socket was provided for this request
|
||||||
|
if(socket != null){
|
||||||
|
//Yell at the user for being an asshole
|
||||||
|
loggerUtils.socketErrorHandler(socket, "No media playing!", "queue");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ignore it
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Stop playing
|
||||||
|
const stoppedMedia = this.nowPlaying;
|
||||||
|
|
||||||
|
//Get difference between current time and start time and set as early end
|
||||||
|
stoppedMedia.earlyEnd = (new Date().getTime() - stoppedMedia.startTime) / 1000;
|
||||||
|
|
||||||
|
//End the media
|
||||||
|
this.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteMedia(socket, data){
|
||||||
|
//Get the current channel from the database
|
||||||
|
const chanDB = await channelModel.findOne({name: socket.chan});
|
||||||
|
|
||||||
|
if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
|
||||||
|
try{
|
||||||
|
//If we don't have a valid UUID
|
||||||
|
if(!validator.isUUID(data.uuid)){
|
||||||
|
//Bitch, moan, complain...
|
||||||
|
loggerUtils.socketErrorHandler(socket, "Bad UUID!", "queue");
|
||||||
|
//and ignore it!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove media by UUID
|
||||||
|
await this.removeMedia(data.uuid, socket);
|
||||||
}catch(err){
|
}catch(err){
|
||||||
return loggerUtils.socketExceptionHandler(socket, err);
|
return loggerUtils.socketExceptionHandler(socket, err);
|
||||||
}
|
}
|
||||||
|
|
@ -150,28 +194,6 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteMedia(socket, data){
|
|
||||||
//Get the current channel from the database
|
|
||||||
const chanDB = await channelModel.findOne({name: socket.chan});
|
|
||||||
|
|
||||||
if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
|
|
||||||
try{
|
|
||||||
//If we don't have a valid UUID
|
|
||||||
if(!validator.isUUID(data.uuid)){
|
|
||||||
//Bitch, moan, complain...
|
|
||||||
loggerUtils.socketErrorHandler(socket, "Bad UUID!", "queue");
|
|
||||||
//and ignore it!
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Remove media by UUID
|
|
||||||
await this.removeMedia(data.uuid, socket);
|
|
||||||
}catch(err){
|
|
||||||
return loggerUtils.socketExceptionHandler(socket, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async moveMedia(socket, data){
|
async moveMedia(socket, data){
|
||||||
//Get the current channel from the database
|
//Get the current channel from the database
|
||||||
const chanDB = await channelModel.findOne({name: socket.chan});
|
const chanDB = await channelModel.findOne({name: socket.chan});
|
||||||
|
|
@ -214,36 +236,33 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Default start time to now + half a second to give everyone time to process shit
|
//--- INTERNAL USE ONLY QUEUEING FUNCTIONS ---
|
||||||
queueMedia(inputMedia, start, socket){
|
getStart(start){
|
||||||
//If we have an invalid time
|
//Pull current time
|
||||||
if(start == null || start < (new Date).getTime()){
|
const now = new Date().getTime();
|
||||||
|
|
||||||
|
//If start time is null, or it isn't a valid integer after the current epoch
|
||||||
|
if(start == null || !validator.isInt(String(start), {min: now})){
|
||||||
//Get last item from schedule
|
//Get last item from schedule
|
||||||
const lastItem = (Array.from(this.schedule)[this.schedule.size - 1]);
|
const lastItem = (Array.from(this.schedule)[this.schedule.size - 1]);
|
||||||
|
|
||||||
const now = new Date().getTime()
|
|
||||||
|
|
||||||
//if we have a last item
|
//if we have a last item
|
||||||
if(lastItem != null){
|
if(lastItem != null){
|
||||||
//If the last item has ended
|
//If the last item has ended
|
||||||
if(lastItem[1].getEndTime() < now){
|
if(lastItem[1].getEndTime() < now){
|
||||||
start = now + 5;
|
//Throw it on in five ms
|
||||||
//If it hasn't started yet
|
return now;
|
||||||
|
//If it hasn't ended yet
|
||||||
}else{
|
}else{
|
||||||
//Throw it on five ms after the last item
|
//Throw it on five ms after the last item
|
||||||
start = lastItem[1].getEndTime() + 5;
|
return lastItem[1].getEndTime() + 5;
|
||||||
}
|
}
|
||||||
|
//If we don't have a last item
|
||||||
}else{
|
}else{
|
||||||
//Throw it on five ms after the last item
|
//Throw it on in five ms
|
||||||
start = now + 5;
|
return now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create a new media queued object, set start time to now
|
|
||||||
const mediaObj = queuedMedia.fromMedia(inputMedia, start, 0);
|
|
||||||
|
|
||||||
//schedule the media
|
|
||||||
this.scheduleMedia(mediaObj, socket);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshNextTimer(volatile = false){
|
refreshNextTimer(volatile = false){
|
||||||
|
|
@ -305,7 +324,7 @@ module.exports = class{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async rescheduleMedia(uuid, start = new Date().getTime() + 5, socket){
|
async rescheduleMedia(uuid, start = new Date().getTime(), socket){
|
||||||
//Find our media, don't remove it yet since we want to do some more testing first
|
//Find our media, don't remove it yet since we want to do some more testing first
|
||||||
const media = this.getItemByUUID(uuid);
|
const media = this.getItemByUUID(uuid);
|
||||||
|
|
||||||
|
|
@ -355,7 +374,7 @@ module.exports = class{
|
||||||
|
|
||||||
//Attempt to schedule media at given time
|
//Attempt to schedule media at given time
|
||||||
//Otherwise, if it returns false for fuckup
|
//Otherwise, if it returns false for fuckup
|
||||||
if(!(await this.scheduleMedia(media, socket))){
|
if(!(await this.scheduleMedia([media], socket))){
|
||||||
//Reset start time
|
//Reset start time
|
||||||
media.startTime = oldStart;
|
media.startTime = oldStart;
|
||||||
|
|
||||||
|
|
@ -363,7 +382,7 @@ module.exports = class{
|
||||||
media.startTimeStamp = 0;
|
media.startTimeStamp = 0;
|
||||||
|
|
||||||
//Schedule in old slot
|
//Schedule in old slot
|
||||||
this.scheduleMedia(media, socket, null, true);
|
this.scheduleMedia([media], socket, null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,30 +493,7 @@ module.exports = class{
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
stopMedia(socket){
|
async scheduleMedia(media, socket, chanDB, force = false, volatile = false, startVolatile = false){
|
||||||
//If we're not currently playing anything
|
|
||||||
if(this.nowPlaying == null){
|
|
||||||
//If an originating socket was provided for this request
|
|
||||||
if(socket != null){
|
|
||||||
//Yell at the user for being an asshole
|
|
||||||
loggerUtils.socketErrorHandler(socket, "No media playing!", "queue");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Ignore it
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Stop playing
|
|
||||||
const stoppedMedia = this.nowPlaying;
|
|
||||||
|
|
||||||
//Get difference between current time and start time and set as early end
|
|
||||||
stoppedMedia.earlyEnd = (new Date().getTime() - stoppedMedia.startTime) / 1000;
|
|
||||||
|
|
||||||
//End the media
|
|
||||||
this.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
async scheduleMedia(mediaObj, socket, chanDB, force = false, volatile = false, startVolatile = false){
|
|
||||||
/* This is a fun method and I think it deserves it's own little explination...
|
/* This is a fun method and I think it deserves it's own little explination...
|
||||||
Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option
|
Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option
|
||||||
I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass.
|
I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass.
|
||||||
|
|
@ -512,7 +508,7 @@ module.exports = class{
|
||||||
since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about.
|
since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about.
|
||||||
Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely.
|
Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely.
|
||||||
This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider
|
This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider
|
||||||
that, no matter what, re-ordering the schedule map would've required us to iterate through and convert it to an array and back anyways...
|
that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways...
|
||||||
|
|
||||||
|
|
||||||
Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds.
|
Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds.
|
||||||
|
|
@ -526,6 +522,8 @@ module.exports = class{
|
||||||
https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it
|
https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
let mediaObj = media[0];
|
||||||
|
|
||||||
//If someone is trying to schedule something that starts and ends in the past
|
//If someone is trying to schedule something that starts and ends in the past
|
||||||
if((mediaObj.getEndTime() < new Date().getTime()) && !force){
|
if((mediaObj.getEndTime() < new Date().getTime()) && !force){
|
||||||
//If an originating socket was provided for this request
|
//If an originating socket was provided for this request
|
||||||
|
|
@ -539,9 +537,16 @@ module.exports = class{
|
||||||
//If the item has already started
|
//If the item has already started
|
||||||
if((mediaObj.startTime < new Date().getTime()) && !force){
|
if((mediaObj.startTime < new Date().getTime()) && !force){
|
||||||
//Set time stamp to existing timestamp plus the difference between the orginal start-date and now
|
//Set time stamp to existing timestamp plus the difference between the orginal start-date and now
|
||||||
mediaObj.startTimeStamp = mediaObj.startTimeStamp + ((new Date().getTime() - mediaObj.startTime) / 1000)
|
const calculatedTimeStamp = mediaObj.startTimeStamp + ((new Date().getTime() - mediaObj.startTime) / 1000)
|
||||||
//Start the item now
|
|
||||||
mediaObj.startTime = new Date().getTime() + 5;
|
//If the calculated time stamp is more than negligible, and therefore not simply caused by serverside processing time
|
||||||
|
if(calculatedTimeStamp > 5){
|
||||||
|
//Set the media timestamp
|
||||||
|
mediaObj.startTimeStamp = calculatedTimeStamp;
|
||||||
|
|
||||||
|
//Start the item now
|
||||||
|
mediaObj.startTime = new Date().getTime();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//If there's already something queued right now
|
//If there's already something queued right now
|
||||||
|
|
@ -935,7 +940,7 @@ module.exports = class{
|
||||||
//If the media hasn't ended yet
|
//If the media hasn't ended yet
|
||||||
if(wasPlaying.getEndTime() > now){
|
if(wasPlaying.getEndTime() > now){
|
||||||
//Re-Schedule it in RAM
|
//Re-Schedule it in RAM
|
||||||
await this.scheduleMedia(wasPlaying, null, chanDB, true, true, true);
|
await this.scheduleMedia([wasPlaying], null, chanDB, true, true, true);
|
||||||
//Otherwise, if it has
|
//Otherwise, if it has
|
||||||
}else{
|
}else{
|
||||||
//Null out nowPlaying
|
//Null out nowPlaying
|
||||||
|
|
@ -961,7 +966,7 @@ module.exports = class{
|
||||||
|
|
||||||
|
|
||||||
//Re-Schedule it in RAM
|
//Re-Schedule it in RAM
|
||||||
await this.scheduleMedia(mediaObj, null, chanDB, true, true, false);
|
await this.scheduleMedia([mediaObj], null, chanDB, true, true, false);
|
||||||
}else{
|
}else{
|
||||||
//If the media should be playing now
|
//If the media should be playing now
|
||||||
if(mediaObj.getEndTime() > now){
|
if(mediaObj.getEndTime() > now){
|
||||||
|
|
@ -969,7 +974,7 @@ module.exports = class{
|
||||||
chanDB.media.nowPlaying = record;
|
chanDB.media.nowPlaying = record;
|
||||||
|
|
||||||
//Re-Schedule it in RAM
|
//Re-Schedule it in RAM
|
||||||
await this.scheduleMedia(mediaObj, null, chanDB, true, true, true);
|
await this.scheduleMedia([mediaObj], null, chanDB, true, true, true);
|
||||||
//If it's been ended
|
//If it's been ended
|
||||||
}else{
|
}else{
|
||||||
//Archive ended media
|
//Archive ended media
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,23 @@ module.exports = class extends media{
|
||||||
startTimeStamp);
|
startTimeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
//methods
|
||||||
genUUID(){
|
genUUID(){
|
||||||
this.uuid = crypto.randomUUID();
|
this.uuid = crypto.randomUUID();
|
||||||
|
|
|
||||||
|
|
@ -605,13 +605,16 @@ channelSchema.methods.addToPlaylist = async function(name, media){
|
||||||
//If the playlist name matches
|
//If the playlist name matches
|
||||||
if(playlist.name == name){
|
if(playlist.name == name){
|
||||||
//Push the given media into the found playlist
|
//Push the given media into the found playlist
|
||||||
//this.media.playlists[listIndex].push(media);
|
|
||||||
|
|
||||||
//Make note of the found index
|
//Make note of the found index
|
||||||
foundIndex = listIndex
|
foundIndex = listIndex
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Set media status schema discriminator
|
||||||
|
media.status = 'saved';
|
||||||
|
|
||||||
|
//Add the media to the playlist
|
||||||
this.media.playlists[foundIndex].media.push(media);
|
this.media.playlists[foundIndex].media.push(media);
|
||||||
|
|
||||||
//Save the changes made to the chan doc
|
//Save the changes made to the chan doc
|
||||||
|
|
|
||||||
|
|
@ -48,4 +48,5 @@ const mediaSchema = new mongoose.Schema({
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
module.exports = mediaSchema;
|
module.exports = mediaSchema;
|
||||||
|
|
@ -25,7 +25,8 @@ const playlistMediaProperties = new mongoose.Schema({
|
||||||
uuid: {
|
uuid: {
|
||||||
type: mongoose.SchemaTypes.UUID,
|
type: mongoose.SchemaTypes.UUID,
|
||||||
required:true,
|
required:true,
|
||||||
unique: true
|
unique: true,
|
||||||
|
default: crypto.randomUUID()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ const {mongoose} = require('mongoose');
|
||||||
//Local Imports
|
//Local Imports
|
||||||
const playlistMediaSchema = require('./playlistMediaSchema');
|
const playlistMediaSchema = require('./playlistMediaSchema');
|
||||||
|
|
||||||
module.exports = new mongoose.Schema({
|
const playlistSchema = new mongoose.Schema({
|
||||||
name: {
|
name: {
|
||||||
type: mongoose.SchemaTypes.String,
|
type: mongoose.SchemaTypes.String,
|
||||||
required: true,
|
required: true,
|
||||||
|
|
@ -32,3 +32,9 @@ module.exports = new mongoose.Schema({
|
||||||
default: []
|
default: []
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
playlistSchema.methods.test = function(){
|
||||||
|
console.log(this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = playlistSchema;
|
||||||
Loading…
Reference in a new issue