mirror of
				https://github.com/KevinMidboe/zoff.git
				synced 2025-10-29 18:00:23 +00:00 
			
		
		
		
	REST-endpoints and readme
This commit is contained in:
		
							
								
								
									
										219
									
								
								server/README.md
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								server/README.md
									
									
									
									
									
								
							| @@ -2,57 +2,197 @@ | ||||
|  | ||||
| Under ``` /server/apps/ ```, there are two files, ``` admin.js ``` and ``` client.js ```.``` admin.js ``` are for the adminpanel, and ``` client.js ``` are for zoff itself. | ||||
|  | ||||
| ## REST | ||||
|  | ||||
| Add song | ||||
|  | ||||
| ``` | ||||
| POST /api/list/:channel_name/:video_id | ||||
|     { | ||||
|         "title": TITLE, | ||||
|         "duration": END_TIME - START_TIME, | ||||
|         "end_time": END_TIME, | ||||
|         "start_time": START_TIME, | ||||
|         "adminpass": PASSWORD, | ||||
|         "userpass": USER_PASSWORD | ||||
|     } | ||||
|  | ||||
| Returns 403 for bad authentication | ||||
| Returns 409 if the song exists | ||||
| Returns 200 and the added song object if successful | ||||
| ``` | ||||
|  | ||||
| Delete song | ||||
| ``` | ||||
| DELETE /api/list/:channel_name/:video_id | ||||
|     { | ||||
|         "adminpass": PASSWORD, | ||||
|         "userpass": USER_PASSWORD | ||||
|     } | ||||
|  | ||||
| Returns 403 for bad authentication | ||||
| Returns 404 if the song doesnt exist | ||||
| Returns 200 if successful | ||||
| ``` | ||||
|  | ||||
| Vote on song | ||||
| ``` | ||||
| PUT /api/list/:channel_name/:video_id | ||||
|     { | ||||
|         "adminpass": PASSWORD, | ||||
|         "userpass": USER_PASSWORD | ||||
|     } | ||||
|  | ||||
| Returns 403 for bad authentication | ||||
| Returns 404 if the song doesnt exist | ||||
| Returns 409 if you've already voted on that song | ||||
| Returns 200 and the added song object if successful | ||||
| ``` | ||||
|  | ||||
| Change channel configurations | ||||
| ``` | ||||
| PUT /api/conf/:channel_name | ||||
|     { | ||||
|         "userpass": USER_PASSWORD, | ||||
|         "adminpass": PASSWORD, | ||||
|         "voting": BOOLEAN, | ||||
|         "addsongs": BOOLEAN, | ||||
|         "longsongs": BOOLEAN, | ||||
|         "frontpage": BOOLEAN (if you want to set userpassword, this MUST be false for it to work), | ||||
|         "allvideos": BOOLEAN, | ||||
|         "removeplay": BOOLEAN, | ||||
|         "skipping": BOOLEAN, | ||||
|         "shuffling": BOOLEAN, | ||||
|         "userpass_changed": BOOLEAN (this must be true if you want to keep the userpassword you're sending) | ||||
|     } | ||||
|  | ||||
| Returns 403 for bad authentication | ||||
| Returns 404 if the list doesn't exist | ||||
| Returns 200 and the newly added configuration if successful | ||||
| ``` | ||||
|  | ||||
| Still to come: SKIP and SHUFFLE RESTApi calls.. | ||||
|  | ||||
|  | ||||
| ## Events | ||||
|  | ||||
| ### To server | ||||
| ``` | ||||
| //  Tells the server the song is clientside | ||||
| 'end', {id: video_id, channel: channel_name, pass: channel_pass} | ||||
| //  Tells the server the song is over | ||||
| 'end', { | ||||
|     id: video_id, | ||||
|     channel: channel_name, | ||||
|     pass: channel_pass | ||||
| } | ||||
|  | ||||
| // Asks server where in the song it should be | ||||
| 'pos', {channel: channel_name, pass: channel_pass} | ||||
| 'pos', { | ||||
|     channel: channel_name, | ||||
|     pass: channel_pass | ||||
| } | ||||
|  | ||||
| // Tells the server the client wants the list | ||||
| 'list', {channel: channel_name, pass: channel_pass, version: system_version (now 3)} | ||||
| 'list', { | ||||
|     channel: channel_name, | ||||
|     pass: channel_pass, | ||||
|     version: system_version (now 3) | ||||
| } | ||||
|  | ||||
| // Sends info about a song the client wants to add | ||||
| 'add', {id: VIDEO_ID, title: VIDEO_TITLE, adminpass: sha256(PASSWORD), duration: VIDEO_DURATION, list: channel_name, playlist: true_if_importing_playlist, num: current_number_of_sending_songs, total: total_number_of_sending_songs, pass: channel_pass} | ||||
| 'add', { | ||||
|     id: VIDEO_ID, | ||||
|     title: VIDEO_TITLE, | ||||
|     adminpass: AES-CBC-Pkcs7 with Base64 IV(PASSWORD), | ||||
|     duration: VIDEO_DURATION, | ||||
|     list: channel_name, | ||||
|     playlist: true_if_importing_playlist, | ||||
|     num: current_number_of_sending_songs, | ||||
|     total: total_number_of_sending_songs, | ||||
|     pass: channel_pass | ||||
| } | ||||
|  | ||||
| // Tells the server to disconnect the user from the current channel, is used for remote controlling on the host side | ||||
| 'change_channel', {channel: channel_name} | ||||
| 'change_channel', { | ||||
|     channel: channel_name | ||||
| } | ||||
|  | ||||
| // Sends chat text to all chat | ||||
| 'all,chat', {channel: channel_name, data: input} | ||||
| 'all,chat', { | ||||
|     channel: channel_name, | ||||
|     data: input | ||||
| } | ||||
|  | ||||
| // Sends chat text to channelchat | ||||
| 'chat',{channel: channel_name, data: input, pass: channel_pass} | ||||
| 'chat',{ | ||||
|     channel: channel_name, | ||||
|     data: input, | ||||
|     pass: channel_pass | ||||
| } | ||||
|  | ||||
| // Sends info about song the user wants to vote on. If VOTE_TYPE is del, its deleting the song, if its pos, its just voting | ||||
| 'vote', {channel: CHANNEL_NAME, id: VIDEO_ID, type: VOTE_TYPE, adminpass: PASSWORD} | ||||
| 'vote', { | ||||
|     channel: CHANNEL_NAME, | ||||
|     id: VIDEO_ID, | ||||
|     type: VOTE_TYPE, | ||||
|     adminpass: AES-CBC-Pkcs7 with Base64 IV(PASSWORD) | ||||
| } | ||||
|  | ||||
| // Sends skip message to server | ||||
| 'skip', {pass: adminpass, id:video_id, channel: chan, userpass: channel_pass} | ||||
| 'skip', { | ||||
|     pass: AES-CBC-Pkcs7 with Base64 IV(PASSWORD), | ||||
|     id:video_id, | ||||
|     channel: chan, | ||||
|     userpass: channel_pass | ||||
| } | ||||
|  | ||||
| // Sends password for instant log in to server | ||||
| 'password', {password: PASSWORD, channel: CHANNEL_NAME, oldpass: old_pass_if_changing_password} | ||||
| 'password', { | ||||
|     password: PASSWORD, | ||||
|     channel: CHANNEL_NAME, | ||||
|     oldpass: old_pass_if_changing_password | ||||
| } | ||||
|  | ||||
| // Sends message to the host channel for play | ||||
| 'id', {id: CHANNEL_ID, type: "play", value: "mock"} | ||||
| 'id', { | ||||
|     id: CHANNEL_ID, | ||||
|     type: "play", | ||||
|     value: "mock" | ||||
| } | ||||
|  | ||||
| // Sends message to the host channel for pause | ||||
| 'id', {id: CHANNEL_ID, type: "pause", value: "mock"} | ||||
| 'id', { | ||||
|     id: CHANNEL_ID, | ||||
|     type: "pause", | ||||
|     value: "mock" | ||||
| } | ||||
|  | ||||
| // Sends message to the host channel for skip | ||||
| 'id', {id: CHANNEL_ID, type: "skip", value: "mock"} | ||||
| 'id', { | ||||
|     id: CHANNEL_ID, | ||||
|     type: "skip", | ||||
|     value: "mock" | ||||
| } | ||||
|  | ||||
| // Sends message to the host channel to change volume | ||||
| 'id', {id: CHANNEL_ID, type: "volume", value: VALUE} | ||||
| 'id', { | ||||
|     id: CHANNEL_ID, | ||||
|     type: "volume", | ||||
|     value: VALUE | ||||
| } | ||||
|  | ||||
| // Sends message to the host channel to change channel | ||||
| 'id', {id: CHANNEL_ID, type: "channel", value: NEW_CHANNEL_NAME} | ||||
| 'id', { | ||||
|     id: CHANNEL_ID, | ||||
|     type: "channel", | ||||
|     value: NEW_CHANNEL_NAME | ||||
| } | ||||
|  | ||||
| // Sends a video that triggered an error | ||||
| 'error_video', {channel: CHANNE_NAME, id: VIDEO_ID, title: VIDEO_TITLE} | ||||
| 'error_video', { | ||||
|     channel: CHANNE_NAME, | ||||
|     id: VIDEO_ID, | ||||
|     title: VIDEO_TITLE | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### From server | ||||
| @@ -60,36 +200,65 @@ Under ``` /server/apps/ ```, there are two files, ``` admin.js ``` and ``` clien | ||||
| // Receives a string from server for what type of toast to be triggered | ||||
| 'toast', STRING   | ||||
|  | ||||
| // Receives the password for the channel if the user sent the right in the first place | ||||
| 'pw', STRING    | ||||
| // Receives a boolean if the password was correct | ||||
| 'pw', BOOLEAN    | ||||
|  | ||||
| // Receives configuration array from server | ||||
| 'conf', [ARRAY] | ||||
|  | ||||
| // Receives chat message from allchat | ||||
| 'chat.all', {from: name, msg: message, channel: channel, icon: icon_src} | ||||
| 'chat.all', { | ||||
|     from: name, | ||||
|     msg: message, | ||||
|     channel: channel, | ||||
|     icon: icon_src | ||||
| } | ||||
|  | ||||
| // Receives chat-history for all and for current channel | ||||
| 'chat_history', { | ||||
|     all: BOOLEAN (if true, it is for all-chat), | ||||
|     data: CHAT_HISTORY | ||||
| } | ||||
|  | ||||
| // Receives chat message from channelchat | ||||
| 'chat', {from: name, msg: message, icon: icon_src} | ||||
| 'chat', { | ||||
|     from: name, | ||||
|     msg: message, | ||||
|     icon: icon_src | ||||
| } | ||||
|  | ||||
| // Receives the ID of the current client, used for remote listening | ||||
| 'id', STRING     | ||||
|  | ||||
| // Receives the messages sent on CHANNEL_ID above | ||||
| id, {type: STRING, value: VALUE} | ||||
| id, { | ||||
|     type: STRING, | ||||
|     value: VALUE | ||||
| } | ||||
|  | ||||
| // Receives updates from channel. type is one of the following: list, added, deleted, vote, song_change, changed_values (see further down for better explanation here) | ||||
| 'channel', {type: TYPE, value: value, time: time_of_occurence} | ||||
| 'channel', { | ||||
|     type: TYPE, | ||||
|     value: value, | ||||
|     time: time_of_occurence | ||||
| } | ||||
|  | ||||
| // Receives message from the server that its ready to send the playlist and info | ||||
| 'get_list' | ||||
|  | ||||
| // Receives array of now playing song. Is triggered on song-change | ||||
| 'np', {np: NOW_PLAYING, conf: CONFIGURATION, time: SERVER_TIME} | ||||
| 'np', { | ||||
|     np: NOW_PLAYING, | ||||
|     conf: CONFIGURATION, | ||||
|     time: SERVER_TIME | ||||
| } | ||||
|  | ||||
| // Receives number of viewers on the current channel | ||||
| 'viewers', VALUE     | ||||
|  | ||||
| // Receives a newly updated video, that was checked for errors (song_generated contains .id which is the current id of the video, and a .new_id for the new video to change the video to) | ||||
| 'channel', {type: "changed_values", value: song_generated} | ||||
| 'channel', { | ||||
|     type: "changed_values", | ||||
|     value: song_generated | ||||
| } | ||||
| ``` | ||||
|   | ||||
| @@ -10,12 +10,14 @@ function frontpage_lists(msg, socket) { | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function update_frontpage(coll, id, title) { | ||||
| function update_frontpage(coll, id, title, callback) { | ||||
|     db.collection("frontpage_lists").update({_id: coll}, {$set: { | ||||
|         id: id, | ||||
|         title: title, | ||||
|         accessed: Functions.get_time()} | ||||
|     },{upsert: true}, function(err, returnDocs){}); | ||||
|     },{upsert: true}, function(err, returnDocs){ | ||||
|         if(typeof(callback) == "function") callback(); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| module.exports.frontpage_lists = frontpage_lists; | ||||
|   | ||||
| @@ -74,6 +74,7 @@ function list(msg, guid, coll, offline, socket) { | ||||
|  | ||||
| function skip(list, guid, coll, offline, socket) { | ||||
|     var socketid = socket.zoff_id; | ||||
|  | ||||
|     if(list !== undefined && list !== null && list !== "") | ||||
|     { | ||||
|  | ||||
| @@ -81,7 +82,11 @@ function skip(list, guid, coll, offline, socket) { | ||||
|             socket.emit("update_required"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if(typeof(list.pass) != "string" || typeof(list.id) != "string" || | ||||
|             typeof(list.channel) != "string" || typeof(list.userpass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|         db.collection(coll + "_settings").find(function(err, docs){ | ||||
|             if(docs.length > 0 && (docs[0].userpass == undefined || docs[0].userpass == "" || (list.hasOwnProperty('userpass') && docs[0].userpass == Functions.decrypt_string(socketid, list.userpass)))) { | ||||
|  | ||||
| @@ -401,6 +406,7 @@ function end(obj, coll, guid, offline, socket) { | ||||
|         return; | ||||
|     } | ||||
|     id = obj.id; | ||||
|  | ||||
|     if(id !== undefined && id !== null && id !== "") { | ||||
|  | ||||
|         if(coll == "" || coll == undefined || coll == null) { | ||||
| @@ -408,6 +414,12 @@ function end(obj, coll, guid, offline, socket) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if(typeof(obj.id) != "string" || typeof(obj.channel) != "string" || | ||||
|             typeof(obj.pass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|         db.collection(coll + "_settings").find(function(err, docs){ | ||||
|             if(docs.length > 0 && (docs[0].userpass == undefined || docs[0].userpass == "" || (obj.hasOwnProperty('pass') && docs[0].userpass == Functions.decrypt_string(socketid, obj.pass)))) { | ||||
|  | ||||
| @@ -491,7 +503,7 @@ function sendColor(coll, socket, id) { | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function getNextSong(coll) { | ||||
| function getNextSong(coll, callback) { | ||||
|     db.collection(coll).aggregate([{ | ||||
|         $match:{ | ||||
|             views:{ | ||||
| @@ -514,6 +526,7 @@ function getNextSong(coll) { | ||||
|         if(doc.length == 1) { | ||||
|             io.to(coll).emit("next_song", {videoId: doc[0].id, title: doc[0].title}); | ||||
|         } | ||||
|         if(typeof(callback) == "function") callback(); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -27,6 +27,17 @@ function add_function(arr, coll, guid, offline, socket) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         if(typeof(arr.id) != "string" || typeof(arr.start) != "number" || | ||||
|             typeof(arr.end) != "number" || typeof(arr.title) != "string" || | ||||
|             typeof(arr.list) != "string" || typeof(arr.duration) != "number" || | ||||
|             typeof(arr.playlist) != "boolean" || typeof(arr.num) != "number" || | ||||
|             typeof(arr.total) != "number" || typeof(arr.pass) != "string" || | ||||
|             typeof(arr.adminpass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|         db.collection(coll + "_settings").find(function(err, docs){ | ||||
|             if(docs.length > 0 && (docs[0].userpass == undefined || docs[0].userpass == "" || (arr.hasOwnProperty('pass') && docs[0].userpass == Functions.decrypt_string(socketid, arr.pass)))) { | ||||
|  | ||||
| @@ -179,6 +190,13 @@ function voteUndecided(msg, coll, guid, offline, socket) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if(typeof(msg.channel) != "string" || typeof(msg.id) != "string" || | ||||
|             typeof(msg.type) != "string" || typeof(msg.adminpass) != "string" || | ||||
|             typeof(msg.pass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|         db.collection(coll + "_settings").find(function(err, docs){ | ||||
|             if(docs.length > 0 && (docs[0].userpass == undefined || docs[0].userpass == "" || (msg.hasOwnProperty('pass') && docs[0].userpass == Functions.decrypt_string(socketid, msg.pass)))) { | ||||
|  | ||||
| @@ -218,6 +236,12 @@ function shuffle(msg, coll, guid, offline, socket) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if(typeof(msg.adminpass) != "string" || typeof(msg.channel) != "string" || | ||||
|             typeof(msg.pass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|         Functions.check_inlist(coll, guid, socket, offline); | ||||
|         var hash; | ||||
|         if(msg.adminpass === "") hash = msg.adminpass; | ||||
| @@ -290,6 +314,11 @@ function delete_all(msg, coll, guid, offline, socket) { | ||||
|         var hash = Functions.hash_pass(Functions.decrypt_string(socketid, msg.adminpass)); | ||||
|         var hash_userpass = Functions.decrypt_string(socketid, msg.pass); | ||||
|  | ||||
|         if(typeof(msg.channel) != "string" || typeof(msg.adminpass) != "string" || | ||||
|             typeof(msg.pass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|         db.collection(coll + "_settings").find(function(err, conf) { | ||||
|             if(conf.length == 1 && conf) { | ||||
|                 conf = conf[0]; | ||||
|   | ||||
| @@ -21,7 +21,6 @@ function password(inp, coll, guid, offline, socket) { | ||||
|  | ||||
|         uncrypted = pw; | ||||
|         pw = Functions.decrypt_string(socket.zoff_id, pw); | ||||
|  | ||||
|         Functions.check_inlist(coll, guid, socket, offline); | ||||
|  | ||||
|         if(inp.oldpass) | ||||
| @@ -44,6 +43,7 @@ function password(inp, coll, guid, offline, socket) { | ||||
|                     }); | ||||
|                 }else | ||||
|                 socket.emit("toast", "wrongpass"); | ||||
|                 socket.emit("pw", false); | ||||
|             } | ||||
|         }); | ||||
|     } else { | ||||
| @@ -94,6 +94,15 @@ function conf_function(params, coll, guid, offline, socket) { | ||||
|         var skipping = params.skipping; | ||||
|         var shuffling = params.shuffling; | ||||
|         var userpass = Functions.decrypt_string(socket.zoff_id, params.userpass); | ||||
|         if(typeof(userpass) != "string" || typeof(adminpass) != "string" || | ||||
|             typeof(voting) != "boolean" || typeof(addsongs) != "boolean" || | ||||
|             typeof(longsongs) != "boolean" || typeof(frontpage) != "boolean" || | ||||
|             typeof(allvideos) != "boolean" || typeof(removeplay) != "boolean" || | ||||
|             typeof(skipping) != "boolean" || typeof(shuffling) != "boolean" || | ||||
|             typeof(params.userpass_changed) != "boolean") { | ||||
|                 socket.emit("toast", "wrongpass"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|         if((!params.userpass_changed && frontpage) || (params.userpass_changed && userpass == "")) { | ||||
|             userpass = ""; | ||||
|   | ||||
| @@ -1,5 +1,10 @@ | ||||
| function thumbnail(msg, coll, guid, offline, socket) { | ||||
|     if(msg.thumbnail && msg.channel && msg.adminpass && msg.thumbnail.indexOf("i.imgur.com") > -1){ | ||||
|         if(typeof(msg.channel) != "string" || typeof(msg.thumbnail) != "string" || | ||||
|             typeof(msg.adminpass) != "string" || typeof(msg.pass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|         msg.thumbnail = msg.thumbnail.replace(/^https?\:\/\//i, ""); | ||||
|         if(msg.thumbnail.substring(0,2) != "//") msg.thumbnail = "//" + msg.thumbnail; | ||||
|         var channel = msg.channel.toLowerCase(); | ||||
| @@ -23,6 +28,11 @@ function thumbnail(msg, coll, guid, offline, socket) { | ||||
|  | ||||
| function description(msg, coll, guid, offline, socket) { | ||||
|     if(msg.description && msg.channel && msg.adminpass && msg.description.length < 100){ | ||||
|         if(typeof(msg.channel) != "string" || typeof(msg.description) != "string" || | ||||
|             typeof(msg.adminpass) != "string" || typeof(msg.pass) != "string") { | ||||
|                 socket.emit("toast", "update_required"); | ||||
|                 return; | ||||
|             } | ||||
|         var channel = msg.channel.toLowerCase(); | ||||
|         var hash = Functions.hash_pass(Functions.decrypt_string(socket.zoff_id, msg.adminpass)); | ||||
|         db.collection(channel + "_settings").update({views: {$exists: true}}, function(err, docs){ | ||||
|   | ||||
| @@ -19,6 +19,332 @@ router.route('/api/generate_name').get(function(req, res) { | ||||
|     Functions.generate_channel_name(res); | ||||
| }); | ||||
|  | ||||
| router.route('/api/list/:channel_name/:video_id').delete(function(req, res) { | ||||
|     res.header("Access-Control-Allow-Origin", "*"); | ||||
|     res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); | ||||
|     if(!req.body.hasOwnProperty('adminpass') || !req.body.hasOwnProperty('userpass') || | ||||
|         !req.params.hasOwnProperty('channel_name') || !req.params.hasOwnProperty('video_id')) { | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|     try { | ||||
|         var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; | ||||
|         var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]); | ||||
|         var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex")); | ||||
|         req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex"); | ||||
|         var userpass = req.body.userpass; | ||||
|         var channel_name = cleanChannelName(req.params.channel_name); | ||||
|         var video_id = req.params.video_id; | ||||
|         if(typeof(userpass) != "string" || typeof(adminpass) != "string") { | ||||
|                 throw "Wrong format"; | ||||
|             } | ||||
|     } catch(e) { | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     validateLogin(adminpass, userpass, channel_name, "delete", res, function(exists) { | ||||
|         if(!exists) { | ||||
|             res.sendStatus(404); | ||||
|             return; | ||||
|         } | ||||
|         db.collection(channel_name).find({id:video_id, now_playing: false}, function(err, docs){ | ||||
|             if(docs.length == 0) { | ||||
|                 res.sendStatus(404); | ||||
|                 return; | ||||
|             } | ||||
|             dont_increment = true; | ||||
|             if(docs[0]){ | ||||
|                 if(docs[0].type == "suggested"){ | ||||
|                     dont_increment = false; | ||||
|                 } | ||||
|                 db.collection(channel_name).remove({id:video_id}, function(err, docs){ | ||||
|                     io.to(channel_name).emit("channel", {type:"deleted", value: video_id}); | ||||
|                     if(dont_increment) { | ||||
|                         db.collection("frontpage_lists").update({_id: channel_name, count: {$gt: 0}}, {$inc: {count: -1}, $set:{accessed: Functions.get_time()}}, {upsert: true}, function(err, docs){ | ||||
|                             res.sendStatus(200); | ||||
|                             return; | ||||
|                         }); | ||||
|                     } else { | ||||
|                         res.sendStatus(200); | ||||
|                         return; | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| function cleanChannelName(channel_name) { | ||||
|     var coll = emojiStrip(channel_name).toLowerCase(); | ||||
|     coll = coll.replace("_", ""); | ||||
|     coll = encodeURIComponent(coll).replace(/\W/g, ''); | ||||
|     coll = filter.clean(coll); | ||||
|     return coll; | ||||
| } | ||||
|  | ||||
| function validateLogin(adminpass, userpass, channel_name, type, res, callback) { | ||||
|     db.collection(channel_name + "_settings").find({views: {$exists: true}}, function(err, conf) { | ||||
|         var exists = false; | ||||
|         if(conf.length > 0 && ((conf[0].userpass == undefined || conf[0].userpass == "" || conf[0].userpass == userpass))) { | ||||
|             exists = true; | ||||
|         } else if(conf.length > 0) { | ||||
|             res.sendStatus(403); | ||||
|             return; | ||||
|         } | ||||
|         if( | ||||
|             (type == "add" && ((conf[0].addsongs && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) || !conf[0].addsongs)) || | ||||
|             (type == "delete" && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) || | ||||
|             (type == "vote" && ((conf[0].vote && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) || !conf[0].vote)) || | ||||
|             (type == "config" && (conf[0].adminpass == "" || conf[0].adminpass == undefined || conf[0].adminpass == adminpass)) | ||||
|         ) { | ||||
|             callback(exists); | ||||
|         } else { | ||||
|             res.sendStatus(403); | ||||
|             return; | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| router.route('/api/conf/:channel_name').put(function(req, res) { | ||||
|     res.header("Access-Control-Allow-Origin", "*"); | ||||
|     res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); | ||||
|     if(!req.body.hasOwnProperty('adminpass') || !req.body.hasOwnProperty('userpass') || | ||||
|         !req.params.hasOwnProperty('channel_name') || !req.body.hasOwnProperty('voting') || | ||||
|         !req.body.hasOwnProperty('addsongs') || !req.body.hasOwnProperty('longsongs') || | ||||
|         !req.body.hasOwnProperty('frontpage') || !req.body.hasOwnProperty('allvideos') || | ||||
|         !req.body.hasOwnProperty('skipping') || !req.body.hasOwnProperty('shuffling') || | ||||
|         !req.body.hasOwnProperty('userpass_changed')) { | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|     try { | ||||
|         var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; | ||||
|         var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]); | ||||
|         var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex")); | ||||
|         req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex"); | ||||
|         var userpass = req.body.userpass; | ||||
|         var voting = req.body.voting; | ||||
|         var addsongs = req.body.addsongs; | ||||
|         var longsongs = req.body.longsongs; | ||||
|         var frontpage = req.body.frontpage; | ||||
|         var allvideos = req.body.allvideos; | ||||
|         var removeplay = req.body.removeplay; | ||||
|         var skipping = req.body.skipping; | ||||
|         var shuffling = req.body.shuffling; | ||||
|         var userpass_changed = req.body.userpass_changed; | ||||
|         var channel_name = cleanChannelName(req.params.channel_name); | ||||
|         if(typeof(userpass) != "string" || typeof(adminpass) != "string" || | ||||
|             typeof(voting) != "boolean" || typeof(addsongs) != "boolean" || | ||||
|             typeof(longsongs) != "boolean" || typeof(frontpage) != "boolean" || | ||||
|             typeof(allvideos) != "boolean" || typeof(removeplay) != "boolean" || | ||||
|             typeof(skipping) != "boolean" || typeof(shuffling) != "boolean" || | ||||
|             typeof(userpass_changed) != "boolean") { | ||||
|                 throw "Wrong format"; | ||||
|             } | ||||
|     } catch(e) { | ||||
|         res.send(e); | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     validateLogin(adminpass, userpass, channel_name, "config", res, function(exists) { | ||||
|         if(!exists) { | ||||
|             res.sendStatus(404); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if((!userpass_changed && frontpage) || (userpass_changed && userpass == "")) { | ||||
|             userpass = ""; | ||||
|         } else if(userpass_changed && userpass != "") { | ||||
|             frontpage = false; | ||||
|         } | ||||
|         var description = ""; | ||||
|  | ||||
|         var obj = { | ||||
|             addsongs:addsongs, | ||||
|             allvideos:allvideos, | ||||
|             frontpage:frontpage, | ||||
|             skip:skipping, | ||||
|             vote:voting, | ||||
|             removeplay:removeplay, | ||||
|             shuffle:shuffling, | ||||
|             longsongs:longsongs, | ||||
|             adminpass:adminpass, | ||||
|             desc: description, | ||||
|         }; | ||||
|         if(userpass_changed) { | ||||
|             obj["userpass"] = userpass; | ||||
|         } else if (frontpage) { | ||||
|             obj["userpass"] = ""; | ||||
|         } | ||||
|         db.collection(channel_name + "_settings").update({views:{$exists:true}}, { | ||||
|             $set:obj | ||||
|         }, function(err, docs){ | ||||
|  | ||||
|             if(obj.adminpass !== "") obj.adminpass = true; | ||||
|             if(obj.hasOwnProperty("userpass") && obj.userpass != "") obj.userpass = true; | ||||
|             else obj.userpass = false; | ||||
|             io.to(channel_name).emit("conf", [obj]); | ||||
|  | ||||
|             db.collection("frontpage_lists").update({_id: channel_name}, {$set:{ | ||||
|                 frontpage:frontpage, accessed: Functions.get_time()} | ||||
|             }, | ||||
|             {upsert:true}, function(err, docs){ | ||||
|                 res.header({'Content-Type': 'application/json'}); | ||||
|                 res.status(200).send(JSON.stringify(obj)); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| }) | ||||
|  | ||||
| router.route('/api/list/:channel_name/:video_id').put(function(req,res) { | ||||
|     res.header("Access-Control-Allow-Origin", "*"); | ||||
|     res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); | ||||
|     if(!req.body.hasOwnProperty('adminpass') || !req.body.hasOwnProperty('userpass') || | ||||
|         !req.params.hasOwnProperty('channel_name') || !req.params.hasOwnProperty('video_id')) { | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|     try { | ||||
|         var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; | ||||
|         var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]); | ||||
|         var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex")); | ||||
|         req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex"); | ||||
|         var userpass = req.body.userpass; | ||||
|         var channel_name = cleanChannelName(req.params.channel_name); | ||||
|         var video_id = req.params.video_id; | ||||
|         if(typeof(userpass) != "string" || typeof(adminpass) != "string") { | ||||
|                 throw "Wrong format"; | ||||
|             } | ||||
|     } catch(e) { | ||||
|         res.send(e); | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     validateLogin(adminpass, userpass, channel_name, "vote", res, function(exists) { | ||||
|         if(!exists) { | ||||
|             res.sendStatus(404); | ||||
|             return; | ||||
|         } | ||||
|         db.collection(channel_name).find({id: video_id, now_playing: false}, function(err, song) { | ||||
|             if(song.length == 0) { | ||||
|                 res.sendStatus(404); | ||||
|                 return; | ||||
|             } else if(song[0].guids.indexOf(guid) > -1) { | ||||
|                 res.sendStatus(409); | ||||
|                 return; | ||||
|             } else { | ||||
|                 song[0].votes += 1; | ||||
|                 song[0].guids.push(guid); | ||||
|                 db.collection(channel_name).update({id: video_id}, {$inc:{votes:1}, $set:{added:Functions.get_time()}, $push :{guids: guid}}, function(err, success) { | ||||
|                     io.to(channel_name).emit("channel", {type: "vote", value: video_id, time: Functions.get_time()}); | ||||
|                     List.getNextSong(channel_name, function() { | ||||
|                         res.header({'Content-Type': 'application/json'}); | ||||
|                         res.status(200).send(JSON.stringify(song[0])); | ||||
|                         return; | ||||
|                     }); | ||||
|                 }); | ||||
|             } | ||||
|         }) | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| router.route('/api/list/:channel_name/:video_id').post(function(req,res) { | ||||
|     res.header("Access-Control-Allow-Origin", "*"); | ||||
|     res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); | ||||
|     if(!req.body.hasOwnProperty('adminpass') || !req.body.hasOwnProperty('userpass') || | ||||
|         !req.params.hasOwnProperty('channel_name') || !req.params.hasOwnProperty('video_id') || | ||||
|         !req.body.hasOwnProperty('duration') || !req.body.hasOwnProperty('start_time') || | ||||
|         !req.body.hasOwnProperty('end_time') || !req.body.hasOwnProperty('title')) { | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|     try { | ||||
|         var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; | ||||
|         var guid = Functions.hash_pass(req.get('User-Agent') + ip + req.headers["accept-language"]); | ||||
|         var adminpass = req.body.adminpass == "" ? "" : Functions.hash_pass(crypto.createHash('sha256').update(req.body.adminpass, 'utf8').digest("hex")); | ||||
|         req.body.userpass = crypto.createHash('sha256').update(req.body.userpass, 'utf8').digest("hex"); | ||||
|         var userpass = req.body.userpass; | ||||
|         var channel_name = cleanChannelName(req.params.channel_name); | ||||
|         var video_id = req.params.video_id; | ||||
|         var duration = parseInt(req.body.duration); | ||||
|         var start_time = parseInt(req.body.start_time); | ||||
|         var end_time = parseInt(req.body.end_time); | ||||
|         if(duration != end_time - start_time) duration = end_time - start_time; | ||||
|         var title = req.body.title; | ||||
|         if(typeof(userpass) != "string" || typeof(adminpass) != "string" || | ||||
|             typeof(title) != "string") { | ||||
|                 throw "Wrong format"; | ||||
|             } | ||||
|     } catch(e) { | ||||
|         res.send(e); | ||||
|         res.sendStatus(400); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     validateLogin(adminpass, userpass, channel_name, "add", res, function(exists) { | ||||
|         db.collection(channel_name).find({id: video_id}, function(err, result) { | ||||
|             if(result.length == 0) { | ||||
|                 db.collection(channel_name).find({now_playing: true}, function(err, now_playing) { | ||||
|                     var set_np = false; | ||||
|                     if(now_playing.length == 0) { | ||||
|                         set_np = true; | ||||
|                     } | ||||
|                     var new_song = {"added": Functions.get_time(),"guids":[guid],"id":video_id,"now_playing":set_np,"title":title,"votes":1, "duration":duration, "start": parseInt(start_time), "end": parseInt(end_time)}; | ||||
|                     db.collection("frontpage_lists").find({"_id": channel_name}, function(err, count) { | ||||
|                         var create_frontpage_lists = false; | ||||
|                         if(count.length == 0) { | ||||
|                             create_frontpage_lists = true; | ||||
|                         } | ||||
|                         if(!exists) { | ||||
|                             var configs = {"addsongs":false, "adminpass":"", "allvideos":true, "frontpage":true, "longsongs":false, "removeplay": false, "shuffle": true, "skip": false, "skips": [], "startTime":Functions.get_time(), "views": [], "vote": false, "desc": ""}; | ||||
|                             db.collection(channel_name + "_settings").insert(configs, function(err, docs){ | ||||
|                                 io.to(channel_name).emit("conf", configs); | ||||
|                             }); | ||||
|                         } | ||||
|                         db.collection(channel_name).insert(new_song, function(err, success) { | ||||
|                             if(create_frontpage_lists) { | ||||
|                                 db.collection("frontpage_lists").insert({"_id": channel_name, "count" : 1, "frontpage": true, "accessed": Functions.get_time(), "viewers": 1}, function(err, docs) { | ||||
|                                     io.to(channel_name).emit("conf", configs); | ||||
|                                     io.to(channel_name).emit("channel", {type: "added", value: new_song}); | ||||
|                                     List.getNextSong(channel_name, function() { | ||||
|                                         res.header({'Content-Type': 'application/json'}); | ||||
|                                         res.status(200).send(JSON.stringify(new_song)); | ||||
|                                         return; | ||||
|                                     }); | ||||
|                                 }); | ||||
|                             } else if(set_np) { | ||||
|                                 Frontpage.update_frontpage(channel_name, video_id, title, function() { | ||||
|                                     io.to(channel_name).emit("np", new_song); | ||||
|                                     List.getNextSong(channel_name, function() { | ||||
|                                         res.header({'Content-Type': 'application/json'}); | ||||
|                                         res.status(200).send(JSON.stringify(new_song)); | ||||
|                                         return; | ||||
|                                     }); | ||||
|                                 }); | ||||
|                             } else { | ||||
|                                 db.collection("frontpage_lists").update({"_id": channel_name}, {$inc: {count: 1}}, function(err, docs) { | ||||
|                                     io.to(channel_name).emit("channel", {type: "added", value: new_song}); | ||||
|                                     List.getNextSong(channel_name, function() { | ||||
|                                         res.header({'Content-Type': 'application/json'}); | ||||
|                                         res.status(200).send(JSON.stringify(new_song)); | ||||
|                                         return; | ||||
|                                     }); | ||||
|                                 }); | ||||
|                             } | ||||
|                         }); | ||||
|                     }) | ||||
|                 }) | ||||
|             } else { | ||||
|                 res.sendStatus(409); | ||||
|                 return; | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| router.route('/api/list/:channel_name').get(function(req, res) { | ||||
|     res.header("Access-Control-Allow-Origin", "*"); | ||||
|     res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user