diff --git a/modules/jukebox.js b/modules/jukebox.js index 95f8373..29f4652 100644 --- a/modules/jukebox.js +++ b/modules/jukebox.js @@ -1,18 +1,36 @@ // Websocket Server const WebSocketServer = require('ws').Server; +const fe = require('path'); // list of currently connected clients (users) var clients = { }; -// TODO: Any code in here will be limitted in functionality +// Any code in here will be limitted in functionality var guests = { }; +const allowedCommands = [ + 'next', + 'previous', + 'playPause', + 'addSong', + 'getPlaylist', + 'removeSong', +]; + +const guestCommands = [ + 'addSong', + 'getPlaylist' +]; + + exports.setup = function(mstream, server, program){ const wss = new WebSocketServer({ server: server }); // This callback function is called every time someone // tries to connect to the WebSocket server + // TODO: Add authentication step with jwt if necessary + // TODO: https://gist.github.com/jfromaniello/8418116 wss.on('connection', function(connection) { // accept connection - you should check 'request.origin' to make sure that @@ -32,7 +50,6 @@ exports.setup = function(mstream, server, program){ } - // Add code to clients object clients[code] = connection; // Connect guest code to standard code @@ -42,16 +59,15 @@ exports.setup = function(mstream, server, program){ // Send Code connection.send(JSON.stringify( { code: code, guestCode: guestcode} )); - // user sent some message connection.on('message', function(message) { // Send client code back connection.send(JSON.stringify( { code: code, guestCode: guestcode} )); }); + // user disconnected connection.on('close', function(connection) { - // Remove client from array delete guests[guestcode]; delete clients[code]; @@ -84,16 +100,16 @@ exports.setup = function(mstream, server, program){ // TODO: Get Album Art calls - mstream.post( '/push-to-client', function(req, res){ + + // Send codes to client + mstream.post( '/jukebox/push-to-client', function(req, res){ // Get client id const json = JSON.parse(req.body.json); - - // Check if client ID exists var clientCode = json.code; const command = json.command; - // + // Check that code exists if(!(clientCode in clients) && !(clientCode in guests)){ res.status(500).json({ error: 'Client code not found' }); return; @@ -116,4 +132,24 @@ exports.setup = function(mstream, server, program){ res.json({ status: 'done' }); }); + + +mstream.get('/jukebox/does-code-exist', function(req, res){ + // Get client id + const json = JSON.parse(req.body.json); + const clientCode = json.code; + + var status; + + // Check that code exists + if(!(clientCode in clients) && !(clientCode in guests)){ + re.json({ status: false }); + + return; + } + + var guestStatus = (clientCode in guests); + res.json({ status: true, guestStatus: guestStatus }); +}); + } diff --git a/mstream.js b/mstream.js index dab5e35..566094c 100755 --- a/mstream.js +++ b/mstream.js @@ -336,7 +336,7 @@ mstream.post('/dirparser', function (req, res) { var extension = getFileType(files[i]); if (fileTypesArray.indexOf(extension) > -1 && masterFileTypesArray.indexOf(extension) > -1) { filesArray.push({ - type:extension, + type:extension, // TODO: Should this be changed name:files[i] }); } @@ -430,7 +430,9 @@ mstream.post( '/get-album-art', function(req, res){ // JukeBox const jukebox = require('./modules/jukebox.js'); jukebox.setup(mstream, server, program); - +mstream.all('/remote', function (req, res) { + res.sendFile( fe.join('public', 'remote.html'), { root: __dirname }); +}); //////////////////////////////////////////////////////////////////////////// diff --git a/public/css/remote.css b/public/css/remote.css new file mode 100644 index 0000000..2c8452b --- /dev/null +++ b/public/css/remote.css @@ -0,0 +1,81 @@ +body, html { + height: 100%; } + +body{ + background: url(../img/struckaxiom.png) top left repeat; +} + + +.header{ + margin: 0; + padding: 0; + background-color: #333; + height:25px; +} + +.mstream-image{ + height:100%; + background-color: white; + border-radius: 0 0 3px 3px; + box-shadow: 0 0 5px #8D8D8D; +} + +.logo-box{ + overflow-y: visible; + width: 1px; + height: 140%; + margin-left: 35px; + z-index: 99; +} + +.browser-header{ + height: 48px; + background-color: white; + font-family: "Open Sans", "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; + + background-color: #F5F5F5; + border-bottom: 1px solid #b4b4b4; +} + +.browser-header-text{ + font-size: 20px; + font-weight: 500; + padding-top:16px; + padding-left: 10px; +} + +.browser-container{ + height:calc(100% - 80px); + background-color: rgba(250,250,250, .50); + font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; +} + +#browser{ + list-style: none; + padding: 0; + overflow-y: scroll; + height: calc(100% - 40px); +} + +.browser-tools{ + height:0px; +} + +.browser-item{ + height:auto; + border-bottom:solid 1px #b4b4b4; + + cursor: pointer; + width: 100%; + background: white; + color: #252525; + font-size: 10pt; + text-shadow: 0 1px white; + font-weight: 300; + overflow: hidden; + padding: 0 !important; +} + +.browser-item:hover{ + background-color: #F5F5F5; +} diff --git a/public/css/shared.css b/public/css/shared.css index 9c212f9..9602d1c 100644 --- a/public/css/shared.css +++ b/public/css/shared.css @@ -74,147 +74,3 @@ body{ .playlist-item:hover{ background-color: #F5F5F5; } - - -.mstream-player{ - position:absolute; - bottom:0; - width:100%; - height: 50px; - overflow: hidden; - box-shadow: 0px -2px 3px rgba(50, 50, 50, 0.75); -} - -.previous-button{ - position:relative; - height: 100%; - width:50px; - background-color: #333333; - float:left; - overflow:hidden; - box-shadow: 5px 0 8px -2px rgba(31, 73, 125, 0.8), -5px 0 8px -2px rgba(31, 73, 125, 0.8); - cursor:pointer; -} -.play-pause-button{ - height: 100%; - width:50px; - background-color: rgb(102, 132, 178); - float:left; - overflow:hidden; - cursor:pointer; -} -.next-border{ - height: 100%; - padding: 8px; -} -.previous-border{ - height: 100%; - padding: 8px; -} -.play-pause-border{ - border-left: 5px solid rgb(102, 132, 178); - border-top: 5px solid rgb(102, 132, 178); - height: 100%; - padding: 3px; -} -.next-button{ - height: 100%; - width:50px; - background-color: #333333; - float:left; - position: relative; - overflow:hidden; - box-shadow: 5px 0 8px -2px rgba(31, 73, 125, 0.8), -5px 0 8px -2px rgba(31, 73, 125, 0.8); - cursor:pointer; -} -.progress-bar{ - height: 100%; - width: calc(100% - 152px); - background-color: rgba(51,51,51,.15); - float:left; - overflow-x: hidden; - border-right: 2px solid rgba(51,51,51,.15); - cursor: crosshair; -} - - -.removeSong{ - width: 29px !important; - height: 33px; - background-color: rgba(255,0,0, .7); - float: right; - - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 3px 10px 0 rgba(0, 0, 0, 0.19); - - text-align: center; - font-size: 28px; - text-shadow: 0 1px darkred; - padding-bottom: 5px; - font-family: "Arial Black", Gadget, sans-serif; - opacity: 0.9; -} - -.removeSong:hover{ - opacity: 1; - background-color: rgba(255,0,0, .85); -} -.song-area{ - display: block; - width: calc(100% - 49px); - float: left; - padding-top: 12px; - padding-bottom: 10px; - padding-left: 12px; - -} - -.titlebar{ - height: 50%; - width:calc(100% - 190px); - background-color: rgba(255, 255, 255,0.7); - position: absolute; - margin-top: 10px; - border-radius: 5px; - box-shadow: 3px 3px 3px #888888; - margin-left: 20px; - - overflow-y: hidden; - white-space: nowrap; /* This is the secret to make text scroll left-to-right*/ -} -.pbar{ - background-color: rgb(102, 132, 178); - height: 100%; -} - -.playing{ - background-color: #E6EBFA !important; -} - - -.title-text{ - width: calc(100% - 100px); - float:left; - - font-family: '8BITWONDERNominal'; - font-weight: normal; - font-style: normal; - - margin-top: 3px; - margin-left: 2px; - - padding-bottom: 17px; /* This pushes the scr */ - overflow-x: scroll; - overflow-y: hidden; - height: 100%; -} - -.duration-text{ - float: right; - width: 90px; - font-family: '8BITWONDERNominal'; - font-weight: normal; - font-style: normal; - margin-top: 3px; - text-align: right; - margin-right: 5px; -} diff --git a/public/js/mstream.api.js b/public/js/mstream.api.js index 434b74a..24aa43f 100644 --- a/public/js/mstream.api.js +++ b/public/js/mstream.api.js @@ -1,8 +1,11 @@ var MSTREAMAPI = (function () { let mstreamModule = {}; - mstreamModule.listOfServers = []; + + + // TODO: Server Configs + mstreamModule.listOfServers = []; mstreamModule.currentServer = { host:"", username:"", @@ -13,49 +16,75 @@ var MSTREAMAPI = (function () { + mstreamModule.currentProperties = { + currentList: false + // Can be anything in the title array + } + var currentListTypes = [ + 'filebrowser', + 'albums', + 'artists', + 'search', + 'playlists' + ]; - var dataList = []; - + mstreamModule.dataList = []; + // TODO: Modify prototype functions for dataList to verify all items // dataItem = { // type: '', // data:'', - // //} + function clearAndSetDataList(type){ + if(!(type in currentListTypes) || type !== false){ + // TODO: Throw Error + } + + mstreamModule.currentProperties.currentList = type; + + while(mstreamModule.dataList.length > 0){ + mstreamModule.dataList.pop(); + } + } + + mstreamModule.manuallyClearData = function(){ + clearAndSetDataList(false); + } - var fileExplorerArray = { - // This goes by the following pattern - // path-segemnt: scroll pos - // music: 70 - // folder: 20 - // ACDC: 0 - // Greatest Hits: 0 - }; - function getDirectoryContents(filepath){ + // TODO: TURN THIS INTO MAP + var fileExplorerArray = [ + {name:'/', position:0} + ]; + + function getDirectoryContents(){ // Construct the directory string var directoryString = ""; for (var i = 0; i < fileExplorerArray.length; i++) { - directoryString += fileExplorerArray[i] + "/"; + // Ignore root directory + if(fileExplorerArray[i].name !== '/'){ + directoryString += fileExplorerArray[i].name + "/"; + } } // If the scraper option is checked, then tell dirparer to use getID3 - $.post('dirparser', {dir: directoryString, filetypes: filetypes}, function(response) { - clearDatalist(); + $.post('dirparser', {dir: directoryString, filetypes: '["flac", "mp3", "ogg", "wav"]'}, function(response) { + clearAndSetDataList('filebrowser'); - var parsedResponse = $.parseJSON(dir); + var parsedResponse = $.parseJSON(response); var path = parsedResponse.path; $.each(parsedResponse.contents, function() { - dataList.push( + mstreamModule.dataList.push( { - type: this.type, + type: (this.type === 'directory' ? "directory" : "file"), path: path + this.name, + name: this.name, artist: false, // TODO: title: false // TODO: } @@ -67,6 +96,50 @@ var MSTREAMAPI = (function () { + mstreamModule.getCurrentDirectoryContents = function(){ + getDirectoryContents(); + } + + mstreamModule.goToNextDirectory = function(folder, currentScrollPosition = 0){ + if(currentScrollPosition != 0 ){ + // TODO: Save Scroll Position + } + + fileExplorerArray.push({name:folder, position:0}); + getDirectoryContents(); + + } + + mstreamModule.goBackDirectory = function(){ + // Make sure it's not the root directory + // TODO: TEST THAT THIS ALL WORKS + if(dataList[dataList.length-1].name === '/'){ + return false; + } + + fileExplorerArray.pop(); + getDirectoryContents(); + + // TODO: Return Current Scroll Position + } + + mstreamModule.getCurrentScrollPosition = function(){ + return dataList[dataList.length-1].position; + } + + // TODO: + mstreamModule.goToExactDirectory = function(directory){ + // Clear Out fileExplorerArray + // loop and pop + + // Setup new fileExplorerArray + // splice + // loop + + getDirectoryContents(); + } + + // TODO Move this to a secondary module that's initiated when it's assured the MSTREAM module is looded @@ -130,13 +203,13 @@ var MSTREAMAPI = (function () { }); request.done(function( msg ) { - clearDatalist(); + clearAndSetDataList('playlists'); var parsedResponse = $.parseJSON(msg); //parse through the json array and make an array of corresponding divs var playlists = []; $.each(parsedResponse, function() { - dataList.push( + mstreamModule.dataList.push( { type: 'playlist', name: this.name @@ -151,12 +224,7 @@ var MSTREAMAPI = (function () { } - // TODO: Can thie be cahnged to a reset of the variable - function clearDatalist(){ - while(dataList.length > 0){ - dataList.pop(); - } - } + diff --git a/public/js/mstream.js b/public/js/mstream.js index a65070e..6add071 100755 --- a/public/js/mstream.js +++ b/public/js/mstream.js @@ -367,7 +367,7 @@ $(document).ready(function(){ } // Load up the file explorer - $('.get_file_explorer').on('click', loadFileExplorer); + // $('.get_file_explorer').on('click', loadFileExplorer); // when you click on a directory, go to that directory $("#filelist").on('click', 'div.dirz', function() { diff --git a/public/remote.html b/public/remote.html new file mode 100644 index 0000000..784b340 --- /dev/null +++ b/public/remote.html @@ -0,0 +1,362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +
+ + + + + +
+
+ + +
+ + + +
Login Failed
+
+ +

+
+
+ + + + +
+
+ +
+
+ + + + +
+ +
+
{{titleText}}
+
+
+
+
+
+
+ + +
+
+ + +
+
+
+
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + diff --git a/public/shared.html b/public/shared.html index bbcb1c4..b25841c 100644 --- a/public/shared.html +++ b/public/shared.html @@ -1,6 +1,8 @@ + + @@ -37,7 +39,7 @@ // } - + MSTREAM.addSong('/Darn Coyotes - See You in Hell- I Guess/Darn Coyotes - See You in Hell, I Guess - 02 We Oughtta Make Like Antelope and Split.mp3'); MSTREAM.addSong('/Darn Coyotes - See You in Hell- I Guess/Darn Coyotes - See You in Hell, I Guess - 06 We Are Not the Friends You Are Looking For.mp3'); MSTREAM.addSong('/TV Torso - Clear Lake Strangler (1)/TV Torso - Clear Lake Strangler - 02 Prismatic Ideation.flac');