diff --git a/src/app/channel/activeChannel.js b/src/app/channel/activeChannel.js
index 18d059e..a465b06 100644
--- a/src/app/channel/activeChannel.js
+++ b/src/app/channel/activeChannel.js
@@ -106,7 +106,8 @@ class activeChannel{
"Greetings, %UNAME%.",
"Sup, %UNAME%.",
"I AM THE GOD OF HELLFIRE, AND I BRING YOU: %UNAME%!",
- "A wild %UNAME% has appeared!"
+ "A wild %UNAME% has appeared!",
+ "OH MY FUCKING GOD HOLY SHIT IT'S %UNAME%!!!",
],
leave: [
"%UNAME% left.",
@@ -134,7 +135,6 @@ class activeChannel{
"That'll do, %UNAME%."
]
}
-
}
@@ -150,6 +150,8 @@ class activeChannel{
var userObj = this.userList.get(userDB.user);
//get channel rank for current user
const chanRank = await chanDB.getChannelRankByUserDoc(userDB);
+ //Keep track of whether or not user has connected to this channel on another tab/device yet
+ let first = false;
//If user is already connected
if(userObj){
@@ -161,6 +163,8 @@ class activeChannel{
await userDB.populate('flair');
//Set user object
userObj = new connectedUser(userDB, chanRank, this, socket);
+ //Throw first flag
+ first = true;
}
//Set user entry in userlist
@@ -175,7 +179,7 @@ class activeChannel{
this.webRTCHandler.defineListeners(socket);
//Hand off the connection initiation to it's user object
- const activeUser = await userObj.handleConnection(userDB, chanDB, socket)
+ const activeUser = await userObj.handleConnection(userDB, chanDB, socket, first)
//Send out the userlist
this.broadcastUserList(socket.chan);
@@ -267,7 +271,7 @@ class activeChannel{
const activeList = leaving ? this.userAnnouncements.leave : this.userAnnouncements.join;
//Randomly yoink the applicable message
const msg = activeList[Math.floor(Math.random() * activeList.length)];
-
+ //Replace %UNAME% placeholder with users name and broadcast the welcome wagon
this.server.chatHandler.relayChat(user, "", 0, msg.replace("%UNAME%", user), "serverwhisper", this.name, []);
}
}
diff --git a/src/app/channel/connectedUser.js b/src/app/channel/connectedUser.js
index b70e63a..d0b09ae 100644
--- a/src/app/channel/connectedUser.js
+++ b/src/app/channel/connectedUser.js
@@ -96,11 +96,12 @@ class connectedUser{
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
* @param {Socket} socket - Requesting Socket
+ * @param {Boolean} first - thrown true if this is the socket for this user on this channel
* @returns {activeUser} active user object generated by the new connection
*/
- async handleConnection(userDB, chanDB, socket){
+ async handleConnection(userDB, chanDB, socket, first){
//send metadata to client
- this.sendClientMetadata();
+ this.sendClientMetadata(undefined, undefined, first);
//Send out emotes
this.sendSiteEmotes();
@@ -122,7 +123,6 @@ class connectedUser{
await userDB.tattooIPRecord(socket.handshake.address);
}
-
//Return active user object for use by activeChannel and channelManager objects
return this;
}
@@ -179,8 +179,9 @@ class connectedUser{
* Sends glut of required initial metadata to the client upon a new connection
* @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
* @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+ * @param {Boolean} welcome - Whether or not to throw welcome wagon, ensures we dont welcome before the metadata is sent
*/
- async sendClientMetadata(userDB, chanDB){
+ async sendClientMetadata(userDB, chanDB, welcome){
//Get flairList from DB and setup flairList array
const flairListDB = await flairModel.find({});
var flairList = [];
@@ -238,8 +239,11 @@ class connectedUser{
//Send off the metadata to our user's clients
this.emit("clientMetadata", {user: userObj, flairList, queueLock, chatBuffer, streamType: chanDB.settings.streamType});
- //Broadcast the welcome wagon
- this.channel.welcomeWagon(userDB.user);
+ //If we where told to welcome the user
+ if(welcome){
+ //Broadcast the welcome wagon
+ this.channel.welcomeWagon(userDB.user);
+ }
}
/**
diff --git a/src/app/channel/media/queue.js b/src/app/channel/media/queue.js
index f74b0f0..b6871f2 100644
--- a/src/app/channel/media/queue.js
+++ b/src/app/channel/media/queue.js
@@ -518,30 +518,7 @@ class queue{
*/
async getArchive(socket, data){
try{
- //If we get an invalid start date
- if(typeof data.startDate != "number" || data.startDate < 0){
- //Bitch, moan, an' complain!
- loggerUtils.socketErrorHandler(socket, "Invalid Start Date!", "validation");
- //Yeetus-Deletus bitch
- return;
- }
- //If we get an invalid start date
- if(typeof data.endDate != "number" || data.endDate < 0){
- //Bitch, moan, an' complain!
- loggerUtils.socketErrorHandler(socket, "Invalid End Date!", "validation");
- //Yeetus-Deletus bitch
- return;
- }
-
- //If our startDate isn't before our endDate
- if(data.startDate >= data.endDate){
- //Bitch, moan, an' complain!
- loggerUtils.socketErrorHandler(socket, "Invalid Date Range!", "validation");
- //Yeetus-Deletus bitch
- return;
- }
-
//Get the current channel from the database
const chanDB = await channelModel.findOne({name: socket.chan});
@@ -551,12 +528,86 @@ class queue{
return;
}
- //Create new date objects to represent range of data requested
- const startDate = new Date(data.startDate);
- const endDate = new Date(data.endDate);
+ let startDate = undefined;
+ let endDate = undefined;
+ let title = undefined;
+ let url = undefined
- //Grab archives from given range, and send them back to the requesting socket
- socket.emit("archive", {archive: await this.prepArchive(startDate, endDate)});
+ //If we where supplied with a start date
+ if(data.startDate != null){
+ //If we get an invalid start date
+ if((typeof data.startDate != "number" || data.startDate < 0)){
+ //Bitch, moan, an' complain!
+ loggerUtils.socketErrorHandler(socket, "Invalid Start Date!", "validation");
+ //Yeetus-Deletus bitch
+ return;
+ }
+
+
+ //Store validated start date as new date object
+ startDate = new Date(data.startDate);
+ }
+
+ if(data.endDate != null){
+ //If we get an invalid start date
+ if((typeof data.endDate != "number" || data.endDate < 0)){
+ //Bitch, moan, an' complain!
+ loggerUtils.socketErrorHandler(socket, "Invalid End Date!", "validation");
+ //Yeetus-Deletus bitch
+ return;
+ }
+
+ //If our startDate isn't before our endDate
+ if(data.startDate != null && data.startDate >= data.endDate){
+ //Bitch, moan, an' complain!
+ loggerUtils.socketErrorHandler(socket, "Invalid Date Range!", "validation");
+ //Yeetus-Deletus bitch
+ return;
+ }
+
+ //Store validated endDate as new date object
+ endDate = new Date(data.endDate);
+ }
+
+
+ //If we have a valid title
+ if(data.title != null && data.title != ''){
+ //If the title is too long
+ if(!validator.isLength(data.title, {max:30})){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, "Title too long!", "validation");
+ //and ignore it!
+ return;
+ }
+
+ //Sanatize, trim, and keep the title
+ title = validator.escape(validator.trim(data.title));
+ }
+
+ //If we were given a URL
+ if(data.url != null && data.url != ''){
+ //Set URL
+ url = data.url;
+
+ //If we were given a bad URL
+ if(!validator.isURL(url,{require_valid_protocol: true})){
+ //Attempt to fix the situation by encoding it
+ url = encodeURI(url);
+
+ //If it's still bad
+ if(!validator.isURL(url,{require_valid_protocol: true})){
+ //Bitch, moan, complain...
+ loggerUtils.socketErrorHandler(socket, "Bad URL!", "validation");
+ //and ignore it!
+ return;
+ }
+ }
+ }
+
+
+
+ //Grab archives from given range, and send them back to the requesting socket, providing result as search result if search was requested
+ socket.emit(data.search ? "archiveSearch" : "archive", {archive: await this.prepArchive(startDate, endDate, title, url)});
}catch(err){
return loggerUtils.socketExceptionHandler(socket, err);
}
@@ -1903,12 +1954,20 @@ class queue{
}
}
- async prepArchive(startDate, endDate = new Date()){
+ /**
+ * Preps archive for network transmission to clients
+ * @param {Date} startDate - Start date to pass to archive query
+ * @param {Date} endDate - end date to pass to archive query
+ * @param {String} title - title to search through archive for
+ * @param {String} url - URL to pass to archive query
+ * @returns Array of archived media objects prepped for network transmission.
+ */
+ async prepArchive(startDate, endDate = new Date(), title, url){
//Define array to hold prepped archive objects
const preppedArchive = [];
//Get archive since yesterday
- const archive = await this.queryArchive(startDate, endDate);
+ const archive = await this.queryArchive(startDate, endDate, url);
//Iterate through the channel archive backwards to save time
for(let mediaIndex = archive.length - 1; mediaIndex >= 0; mediaIndex--){
@@ -1921,8 +1980,11 @@ class queue{
media.earlyEnd = null;
}
- //Add it to the temporary preppd archive array as if it where part of the actual schedule map
- preppedArchive.unshift([media.startTime, media]);
+ //If requested title is unspecified or was found in the in the media's title
+ if((title == null || title == '') || media.title.includes(title)){
+ //Add it to the temporary preppd archive array as if it where part of the actual schedule map
+ preppedArchive.unshift([media.startTime, media]);
+ }
}
return preppedArchive;
@@ -2062,21 +2124,28 @@ class queue{
* Get Channel Archive
* @param {Date} startDate - Start of range to grab from
* @param {Date} endDate - End of range to grab from
+ * @param {String} url - URL to search for
*/
- async queryArchive(startDate, endDate = new Date()){
+ async queryArchive(startDate, endDate = new Date(), url){
+ //Define object to contain our DB query
+ const dbQuery = {
+ channel: this.channel._id
+ };
+
//If we provided a start date
if(startDate != null){
- //Return archived media after start date
- return await archivedMediaModel.find({
- channel:this.channel._id,
- //Prevent mongoose from attempting to sanatize and invalidate our query object, plus I think we can trust an epoch that came from server-side :)
- startTime: mongoose.trusted({$gt: startDate.getTime(), $lt: endDate.getTime()})
- });
- //Otherwise
- }else{
- //return all archived media
- return await archivedMediaModel.find({channel:this.channel._id});
+ //Specify start/end datetime, this one needs to be unsantized for it to werk, I figure its taking in numbers returned by a server-side function, this is fine
+ dbQuery.startTime = mongoose.trusted({$gt: startDate.getTime(), $lt: endDate.getTime()});
}
+
+ //Do I really need to re-type this shit for the url?
+ if(url != null && url != ''){
+ //Search for exact URL matches
+ dbQuery.url = {$eq: url};
+ }
+
+ //return archived media based on resulting query
+ return await archivedMediaModel.find(dbQuery);
}
}
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