Browse Source

Major refactor and simplification of stations and songs

theflametrooper 8 years ago
parent
commit
e7fbeed0ba

+ 1 - 2
backend/app.js

@@ -51,8 +51,7 @@ function setupExpress() {
 	global.db = {
 	global.db = {
 		user: require('./schemas/user')(mongoose),
 		user: require('./schemas/user')(mongoose),
 		station: require('./schemas/station')(mongoose),
 		station: require('./schemas/station')(mongoose),
-		song: require('./schemas/song')(mongoose),
-		queueSong: require('./schemas/queueSong')(mongoose)
+		song: require('./schemas/song')(mongoose)
 	};
 	};
 
 
 	const mongoStore = new MongoStore({'mongooseConnection': MongoDB});
 	const mongoStore = new MongoStore({'mongooseConnection': MongoDB});

+ 119 - 108
backend/logic/coreHandler.js

@@ -19,41 +19,64 @@ const global   = require('./global'),
 
 
 var eventEmitter = new events.EventEmitter();
 var eventEmitter = new events.EventEmitter();
 
 
-const station = new stations.Station("edm", {
+const edmStation = new stations.Station("edm", {
+	"genres": ["edm"],
 	playlist: [
 	playlist: [
 		{
 		{
-			startedAt: Date.now(),
 			id: "dQw4w9WgXcQ",
 			id: "dQw4w9WgXcQ",
 			title: "Never gonna give you up",
 			title: "Never gonna give you up",
 			artists: ["Rick Astley"],
 			artists: ["Rick Astley"],
 			duration: 20,
 			duration: 20,
-			skipDuration: 0,
-			image: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
+			thumbnail: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
 			likes: 0,
 			likes: 0,
-			dislikes: 1,
-			genres: ["pop", "edm"]
+			dislikes: 1
 		},
 		},
 		{
 		{
-			startedAt: Date.now(),
 			id: "GxBSyx85Kp8",
 			id: "GxBSyx85Kp8",
 			title: "Yeah!",
 			title: "Yeah!",
 			artists: ["Usher"],
 			artists: ["Usher"],
 			duration: 20,
 			duration: 20,
-			skipDuration: 0,
-			image: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
+			thumbnail: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
 			likes: 0,
 			likes: 0,
-			dislikes: 1,
-			genres: ["pop", "edm"]
+			dislikes: 1
 		}
 		}
 	],
 	],
-	currentSongIndex: 1,
+	currentSongIndex: 0,
 	paused: false,
 	paused: false,
-	locked: false,
 	displayName: "EDM",
 	displayName: "EDM",
 	description: "EDM Music"
 	description: "EDM Music"
 });
 });
 
 
-stations.addStation(station);
+const popStation = new stations.Station("pop", {
+	"genres": ["pop"],
+	playlist: [
+		{
+			id: "HXeYRs_zR6w",
+			title: "Nobody But Me",
+			artists: ["Michael Bublé"],
+			duration: 12,
+			thumbnail: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
+			likes: 0,
+			dislikes: 1
+		},
+		{
+			id: "CR4YE7htLgI",
+			title: "Someday ",
+			artists: ["Michael Bublé", "Meghan Trainor"],
+			duration: 30,
+			thumbnail: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
+			likes: 0,
+			dislikes: 1
+		}
+	],
+	currentSongIndex: 0,
+	paused: false,
+	displayName: "Pop",
+	description: "Pop Music"
+});
+
+stations.addStation(edmStation);
+stations.addStation(popStation);
 
 
 module.exports = {
 module.exports = {
 
 
@@ -131,106 +154,95 @@ module.exports = {
 	},
 	},
 
 
 	'/stations': cb => {
 	'/stations': cb => {
-		cb(stations.getStations().map(function (result) {
+		cb(stations.getStations().map(station => {
 			return {
 			return {
-				id: result.getId(),
-				displayName: result.getDisplayName(),
-				description: result.getDescription(),
-				users: result.getUsers()
+				id: station.id,
+				playlist: station.playlist,
+				displayName: station.displayName,
+				description: station.description,
+				currentSongIndex: station.currentSongIndex
 			}
 			}
 		}));
 		}));
 	},
 	},
 
 
-	'/station/:id/join': (stationId, socketId, cb) => {
-
-		const station = stations.getStation(stationId);
-
-		if (station) {
-
-			var response = station.handleUserJoin(socketId);
-
-			return cb(response);
-		}
-		else {
-			return cb({ status: 'error', message: 'Room with that ID does not exists' });
-		}
-	},
-
-	'/station/:id/skip': (stationId, socketId, cb) => {
-
-		const station = stations.getStation(stationId);
-
-		if (station) {
-
-			var response = station.handleUserJoin(socketId);
-
-			return cb(response);
-		}
-		else {
-			return cb({ status: 'error', message: 'Room with that ID does not exists' });
-		}
-	},
+	'/youtube/getVideo/:query': (query, cb) => {
+		const params = [
+			'part=snippet',
+			`q=${encodeURIComponent(query)}`,
+			`key=${config.get('apis.youtube.key')}`,
+			'type=video',
+			'maxResults=15'
+		].join('&');
+		// function params(type, id) {
+		// 	if (type == "search") {
+		// 		return [
+		// 			'part=snippet',
+		// 			`q=${encodeURIComponent(query)}`,
+		// 			`key=${config.get('apis.youtube.key')}`,
+		// 			'type=video',
+		// 			'maxResults=15'
+		// 		].join('&');
+		// 	} else if (type == "video") {
+		// 		return [
+		// 			'part=snippet,contentDetails,statistics,status',
+		// 			`id=${encodeURIComponent(id)}`,
+		// 			`key=${config.get('apis.youtube.key')}`
+		// 		].join('&');
+		// 	}
+		// }
+
+		// let finalResults = [];
 
 
-	'/youtube/getVideos/:query': (query, cb) => {
-		cb({
-			type: "query",
-			items: [
-				{
-					id: "39fk3490krf9",
-					title: "Test Title",
-					channel: "Test Channel",
-					duration: 200,
-					image: "https://i.ytimg.com/vi/lwg5yAuanPg/hqdefault.jpg?custom=true&w=196&h=110&stc=true&jpg444=true&jpgq=90&sp=68&sigh=DWOZl_nkv78qzj8WHPY1-53iQfA"
-				},
-				{
-					id: "49iug05it",
-					title: "Test Title 222",
-					channel: "Test Channel 222",
-					duration: 100,
-					image: "https://i.ytimg.com/vi/QJwIsBoe3Lg/hqdefault.jpg?custom=true&w=196&h=110&stc=true&jpg444=true&jpgq=90&sp=68&sigh=8L20nlTyPf7xuIB8DTeBQFWW2Xw"
-				}
-			]
+		request(`https://www.googleapis.com/youtube/v3/search?${params}`, (err, res, body) => {
+			cb(body);
+			// for (let i = 0; i < results.items.length; i++) {
+			// 	request(`https://www.googleapis.com/youtube/v3/videos?${
+			// 		params("video", results.items[i].id.videoId)
+			// 	}`, (err, res, body) => {
+			// 		finalResults.push(JSON.parse(body));
+			// 	});
+			// }
+			// setTimeout(() => {
+			// 	return cb(finalResults);
+			// }, 500);
 		});
 		});
 	},
 	},
 
 
-	'/songs/queue/addSongs/:songs': (songs, user, cb) => {
-		if (user !== null && user !== undefined && user.logged_in) {
-			if (Array.isArray(songs)) {
-				if (songs.length > 0) {
-					let failed = 0;
-					let success = 0;
-					songs.forEach(function (song) {
-						if (typeof song === "object" && song !== null) {
-							let obj = {};
-							obj.title = song.title;
-							obj._id = song.id;
-							obj.artists = [];
-							obj.image = "test";
-							obj.duration = 0;
-							obj.genres = ["edm"];
-							//TODO Get data from Wikipedia and Spotify
-							obj.requestedBy = user._id;
-							console.log(user._id);
-							console.log(user);
-							obj.requestedAt = Date.now();
-							let queueSong = new global.db.queueSong(obj);
-							queueSong.save(function(err) {
-								console.log(err);
-								if (err) failed++;
-								else success++;
-							});
-						} else {
-							failed++;
-						}
-					});
-					cb({success, failed});
-				} else {
-					cb({err: "No songs supplied."});
-				}
+	'/songs/queue/add/:song': (song, user, cb) => {
+		if (user.logged_in) {
+				// if (songs.length > 0) {
+				// 	let failed = 0;
+				// 	let success = 0;
+				// 	songs.forEach(function (song) {
+				// 		if (typeof song === "object" && song !== null) {
+				// 			let obj = {};
+				// 			obj.title = song.title;
+				// 			obj._id = song.id;
+				// 			obj.artists = [];
+				// 			obj.image = "test";
+				// 			obj.duration = 0;
+				// 			obj.genres = ["edm"];
+				// 			//TODO Get data from Wikipedia and Spotify
+				// 			obj.requestedBy = user._id;
+				// 			console.log(user._id);
+				// 			console.log(user);
+				// 			obj.requestedAt = Date.now();
+				// 			let queueSong = new global.db.queueSong(obj);
+				// 			queueSong.save(function(err) {
+				// 				console.log(err);
+				// 				if (err) failed++;
+				// 				else success++;
+				// 			});
+				// 		} else {
+				// 			failed++;
+				// 		}
+				// 	});
+				// 	cb({success, failed});
+				// } else {
+				// 	cb({err: "No songs supplied."});
+				// }
+				console.log(song);
 			} else {
 			} else {
-				cb({err: "Not supplied an array."});
-			}
-		} else {
 			cb({err: "Not logged in."});
 			cb({err: "Not logged in."});
 		}
 		}
 	},
 	},
@@ -272,7 +284,7 @@ module.exports = {
 		}
 		}
 	},
 	},
 
 
-	/*'/stations/search/:query': (query, cb) => {
+	'/stations/search/:query': (query, cb) => {
 
 
 		const params = [
 		const params = [
 			'part=snippet',
 			'part=snippet',
@@ -285,8 +297,7 @@ module.exports = {
 		request(`https://www.googleapis.com/youtube/v3/search?${params}`, (err, res, body) => {
 		request(`https://www.googleapis.com/youtube/v3/search?${params}`, (err, res, body) => {
 			if (err) {
 			if (err) {
 				return cb({ status: 'error', message: 'Failed to make request' });
 				return cb({ status: 'error', message: 'Failed to make request' });
-			}
-			else {
+			} else {
 				try {
 				try {
 					return cb({ status: 'success', body: JSON.parse(body) });
 					return cb({ status: 'success', body: JSON.parse(body) });
 				}
 				}
@@ -295,7 +306,7 @@ module.exports = {
 				}
 				}
 			}
 			}
 		});
 		});
-	},*/
+	},
 
 
 	'/song/:id/toggleLike': (songId, userId, cb) => {
 	'/song/:id/toggleLike': (songId, userId, cb) => {
 
 

+ 2 - 2
backend/logic/expressHandler.js

@@ -21,9 +21,9 @@ module.exports = (core, app) => {
 		});
 		});
 	});
 	});
 
 
-	app.get('/stations', (req, res) => {
+	app.post('/stations', (req, res) => {
 		core['/stations'](result => {
 		core['/stations'](result => {
-			res.send(JSON.stringify(result));
+			res.send(result);
 		});
 		});
 	});
 	});
 
 

+ 40 - 0
backend/logic/global.js

@@ -53,6 +53,45 @@ function getRandomNumber(min, max) {
 	return Math.floor(Math.random() * (max - min + 1)) + min;
 	return Math.floor(Math.random() * (max - min + 1)) + min;
 }
 }
 
 
+
+function convertTime(duration) {
+	let a = duration.match(/\d+/g);
+
+    if (duration.indexOf('M') >= 0 && duration.indexOf('H') == -1 && duration.indexOf('S') == -1) {
+        a = [0, a[0], 0];
+    }
+
+    if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1) {
+        a = [a[0], 0, a[1]];
+    }
+    if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1 && duration.indexOf('S') == -1) {
+        a = [a[0], 0, 0];
+    }
+
+    duration = 0;
+
+    if (a.length == 3) {
+        duration = duration + parseInt(a[0]) * 3600;
+        duration = duration + parseInt(a[1]) * 60;
+        duration = duration + parseInt(a[2]);
+    }
+
+    if (a.length == 2) {
+        duration = duration + parseInt(a[0]) * 60;
+        duration = duration + parseInt(a[1]);
+    }
+
+    if (a.length == 1) {
+        duration = duration + parseInt(a[0]);
+    }
+
+    let hours = Math.floor(duration / 3600);
+    let minutes = Math.floor(duration % 3600 / 60);
+    let seconds = Math.floor(duration % 3600 % 60);
+
+    return ((hours > 0 ? hours + ":" + (minutes) : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
+}
+
 module.exports = {
 module.exports = {
 	io: null, // Socket.io
 	io: null, // Socket.io
 	db: null, // Database
 	db: null, // Database
@@ -60,6 +99,7 @@ module.exports = {
 		return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
 		return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
 	},
 	},
 	getRandomNumber,
 	getRandomNumber,
+	convertTime,
 	generateRandomString: len => {
 	generateRandomString: len => {
 		let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split("");
 		let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split("");
 		let result = [];
 		let result = [];

+ 5 - 17
backend/logic/socketHandler.js

@@ -10,12 +10,6 @@ module.exports = (core, io) => {
 			console.log('User has disconnected');
 			console.log('User has disconnected');
 		});
 		});
 
 
-		socket.on('/stations', cb => {
-			core['/stations'](result => {
-				cb(result);
-			});
-		});
-
 		/*socket.on('/station/:id/join', (id, cb) => {
 		/*socket.on('/station/:id/join', (id, cb) => {
 			console.log("JOINED!!!");
 			console.log("JOINED!!!");
 			core['/station/:id/join'](id, socket.id, result => {
 			core['/station/:id/join'](id, socket.id, result => {
@@ -24,14 +18,14 @@ module.exports = (core, io) => {
 			});
 			});
 		});*/
 		});*/
 
 
-		socket.on('/youtube/getVideos/:query', (query, cb) => {
-			core['/youtube/getVideos/:query'](query, result => {
-				cb(result);
+		socket.on('/youtube/getVideo/:query', (query, cb) => {
+			core['/youtube/getVideo/:query'](query, result => {
+				cb(JSON.parse(result));
 			});
 			});
 		});
 		});
 
 
-		socket.on('/songs/queue/addSongs/:songs', (songs, cb) => {
-			core['/songs/queue/addSongs/:songs'](songs, _user, result => {
+		socket.on('/songs/queue/add/:song', (song, cb) => {
+			core['/songs/queue/add/:song'](song, _user, result => {
 				cb(result);
 				cb(result);
 			});
 			});
 		});
 		});
@@ -48,12 +42,6 @@ module.exports = (core, io) => {
 			});
 			});
 		});
 		});
 
 
-		/*socket.on('/stations/search/:query', (query, cb) => {
-			core['/stations/search/:query'](query, result => {
-				cb(result);
-			});
-		});*/
-
 		// this lets the client socket know that they can start making request
 		// this lets the client socket know that they can start making request
 		socket.emit('ready', socket.request.user.logged_in);
 		socket.emit('ready', socket.request.user.logged_in);
 	});
 	});

+ 43 - 103
backend/logic/stations.js

@@ -10,76 +10,61 @@ module.exports = {
 			this.nsp = io.of(id);
 			this.nsp = io.of(id);
 			let local = this;
 			let local = this;
 			this.nsp.on('connection', (socket, cb) => {
 			this.nsp.on('connection', (socket, cb) => {
-				console.log('someone connected');
-				socket.on("pause", function() {
-					local.pause();
-				});
-				socket.on("unpause", function() {
-					local.unPause();
-				});
-				socket.on("skipSong", function() {
-					local.skipSong();
-				});
+				// socket.on("pause", () => {
+				// 	local.pause();
+				// });
+
+				// socket.on("unpause", () => {
+				// 	local.unPause();
+				// });
 
 
 				socket.emit("connected", {
 				socket.emit("connected", {
-					displayName: this.getDisplayName(),
-					users: this.getUsers().length,
-					currentSong: this.getCurrentSong(),
-					timePaused: this.getTimePaused(),
-					paused: this.isPaused(),
+					currentSong: this.currentSong,
+					paused: this.paused,
+					timePaused: this.timePaused,
 					currentTime: Date.now()
 					currentTime: Date.now()
 				});
 				});
 			});
 			});
-			this.id = id;
 
 
+			this.id = id;
 			this.playlist = data.playlist;
 			this.playlist = data.playlist;
 			this.currentSongIndex = data.currentSongIndex;
 			this.currentSongIndex = data.currentSongIndex;
-			this.currentSong = this.playlist[this.currentSongIndex];
 			this.paused = data.paused;
 			this.paused = data.paused;
-			this.locked = data.locked;
-			this.skipVotes = 0;
-			this.users = [];
 			this.displayName = data.displayName;
 			this.displayName = data.displayName;
 			this.description = data.description;
 			this.description = data.description;
+
 			this.timePaused = 0;
 			this.timePaused = 0;
 			this.timer = undefined;
 			this.timer = undefined;
-			this.skipSong();
+			this.currentSong = this.playlist[this.currentSongIndex];
+
+			this.nextSong();
 		}
 		}
 
 
-		skipSong() {
+		nextSong() {
 			if (this.playlist.length > 0) {
 			if (this.playlist.length > 0) {
 				if (this.timer !== undefined) this.timer.pause();
 				if (this.timer !== undefined) this.timer.pause();
 
 
-				if (this.currentSongIndex + 1 < this.playlist.length) this.currentSongIndex++;
-				else this.currentSongIndex = 0;
+				if (this.currentSongIndex + 1 < this.playlist.length) {
+					this.currentSongIndex++;
+				}
+				else {
+					this.currentSongIndex = 0;
+				}
 
 
-				this.skipVotes = 0;
 				this.currentSong = this.playlist[this.currentSongIndex];
 				this.currentSong = this.playlist[this.currentSongIndex];
 
 
-				var self = this;
+				let self = this;
 				this.timer = new global.Timer(() => {
 				this.timer = new global.Timer(() => {
-					self.skipSong();
+					self.nextSong();
 				}, this.currentSong.duration, this.paused);
 				}, this.currentSong.duration, this.paused);
+
 				this.timePaused = 0;
 				this.timePaused = 0;
 				this.currentSong.startedAt = Date.now();
 				this.currentSong.startedAt = Date.now();
-				this.nsp.emit("skippedSong", this.currentSong);
+				this.nsp.emit("nextSong", this.currentSong);
 			}
 			}
 		}
 		}
 
 
-		toggleVoteSkip(userId) {
-			if (this.skipVotes.indexOf(userId) === -1) this.skipVotes.push(userId);
-			else this.skipVotes = this.skipVotes.splice(this.skipVotes.indexOf(userId), 1);
-
-			// TODO: Calculate if enough people voted to skip
-			this.nsp.emit("voteSkip", this.skipVotes);
-		}
-
-		retrievePlaylist() {
-			// TODO: get the Playlist for this station using db
-		}
-
 		pause() {
 		pause() {
-			console.log("PAUSE");
 			if (!this.paused) {
 			if (!this.paused) {
 				this.paused = true;
 				this.paused = true;
 				this.timer.pause();
 				this.timer.pause();
@@ -88,7 +73,6 @@ module.exports = {
 		}
 		}
 
 
 		unPause() {
 		unPause() {
-			console.log("UNPAUSE");
 			if (this.paused) {
 			if (this.paused) {
 				this.paused = false;
 				this.paused = false;
 				this.timer.resume();
 				this.timer.resume();
@@ -97,31 +81,13 @@ module.exports = {
 			}
 			}
 		}
 		}
 
 
-		isPaused() {
-			return this.paused;
-		}
-
-		getCurrentSong() {
-			return this.currentSong;
-		}
-
-		lock() {
-			if (!this.locked) {
-				this.locked = true;
-				this.nsp.emit("lock");
-			}
-		}
-
-		unlock() {
-			if (this.locked) {
-				this.locked = false;
-				this.nsp.emit("unlocked");
-			}
-		}
+		// isPaused() {
+		// 	return this.paused;
+		// }
 
 
-		isLocked() {
-			return this.locked;
-		}
+		// getCurrentSong() {
+		// 	return this.currentSong;
+		// }
 
 
 		updateDisplayName(newDisplayName) {
 		updateDisplayName(newDisplayName) {
 			// TODO: Update db
 			// TODO: Update db
@@ -135,49 +101,23 @@ module.exports = {
 			this.nsp.emit("updateDescription", newDescription);
 			this.nsp.emit("updateDescription", newDescription);
 		}
 		}
 
 
-		getId() {
-			return this.id;
-		}
-
-		getDisplayName() {
-			return this.displayName;
-		}
-
-		getDescription() {
-			return this.description;
-		}
-
-		addUser(user) {
-			this.users.add(user);
-			this.nsp.emit("updateUsers", this.users);
-		}
-
-		removeUser(user) {
-			this.users.splice(this.users.indexOf(user), 1);
-			this.nsp.emit("updateUsers", this.users);
-		}
-
-		getUsers() {
-			return this.users;
-		}
-
 		getTimePaused() {
 		getTimePaused() {
-			console.log(this.timePaused, "        ", this.timer.getTimePaused());
 			return this.timePaused + this.timer.getTimePaused();
 			return this.timePaused + this.timer.getTimePaused();
 		}
 		}
 	},
 	},
-	addStation: station => {
+	addStation: (station) => {
 		stations.push(station);
 		stations.push(station);
 	},
 	},
-	getStation: id => {
-		let result;
-		stations.forEach(function(station) {
-			if (station.getId() === id) {
-				result = station;
-			}
-		});
-		return result;
-	},
+	// getStation: id => {
+	// 	let result;
+	// 	stations.forEach(function(station) {
+	// 		if (station.getId() === id) {
+	// 			result = station;
+	// 		}
+	// 	});
+	// 	return result;
+	// },
+	// Returns stations list when POSTing to '/stations'
 	getStations: () => {
 	getStations: () => {
 		return stations;
 		return stations;
 	}
 	}

+ 16 - 73
backend/schema.json

@@ -1,41 +1,21 @@
 [
 [
   // Station
   // Station
   {
   {
-    "_id": "edm",
-    "type": "official",
+    "id": "edm",
     "displayName": "EDM",
     "displayName": "EDM",
     "description": "EDM Music",
     "description": "EDM Music",
-    "privacy": "private",
-    "paused": true,
-    "currentSong": {
-      "startedAt": 1472926465,
-      "id": "dQw4w9WgXcQ",
-      "title": "Never Gonna Give You Up",
-      "artists": ["Rick Astley"],
-      "duration": 254.21,
-      "skipDuration": 0.0,
-      "image": "https://upload.wikimedia.org/wikipedia/en/3/34/RickAstleyNeverGonnaGiveYouUp7InchSingleCover.jpg",
-      "likes": 4,
-      "dislikes": 100,
-      "genres": ["edm"]
-    },
-    "timePaused": 0,
-    "playlist": "playlistId",
-    "genres": ["edm"],
-    "whitelist": ["UserId"],
-    "partyMode": true,
-    "queueLocked": true,
-    "owner": "UserId"
-  },
-  // Queue Item
-  {
-    "id": "dQw4w9WgXcQ",
-    "title": "Never Gonna Give You Up",
-    "artists": ["Rick Astley"],
-    "duration": 254.21,
-    "skipDuration": 0.0,
-    "image": "https://upload.wikimedia.org/wikipedia/en/3/34/RickAstleyNeverGonnaGiveYouUp7InchSingleCover.jpg",
-    "genres": ["edm"]
+    "paused": false,
+    "playlist": [
+		{
+			"id": "dQw4w9WgXcQ",
+			"title": "Never Gonna Give You Up",
+			"artists": ["Rick Astley"],
+			"duration": 254.21,
+			"thumbnail": "https://upload.wikimedia.org/wikipedia/en/3/34/RickAstleyNeverGonnaGiveYouUp7InchSingleCover.jpg"
+		}
+	],
+	"currentSongIndex": 1,
+	"genres": ["edm"]
   },
   },
   // Song Item
   // Song Item
   {
   {
@@ -43,35 +23,9 @@
     "title": "Never Gonna Give You Up",
     "title": "Never Gonna Give You Up",
     "artists": ["Rick Astley"],
     "artists": ["Rick Astley"],
     "duration": 254.21,
     "duration": 254.21,
-    "skipDuration": 0.0,
-    "image": "https://upload.wikimedia.org/wikipedia/en/3/34/RickAstleyNeverGonnaGiveYouUp7InchSingleCover.jpg",
-    "genres": ["edm"],
-    "likes": 13,
-    "dislikes": 1
-  },
-  // Playlist
-  {
-    "id": "defaultRethinkId",
-    "songs": [
-      "dQw4w9WgXcQ"
-    ],
-    "genres": ["edm"]
-  },
-  // Private Playlist
-  {
-    "id": "defaultRethinkId",
-    "name": "nostalgia",
-    "displayName": "Nostalgia",
-    "owner": "UserId",
-    "songs": [
-      "dQw4w9WgXcQ", //If a song is in the Song table,
-      {//If a song is not in the Song table
-        "id": "dQw4w9WgXcQ",
-        "title": "Rick Astley - Never gonna give you up",
-        "duration": 254.21
-      }
-    ]
+    "thumbnail": "https://upload.wikimedia.org/wikipedia/en/3/34/RickAstleyNeverGonnaGiveYouUp7InchSingleCover.jpg"
   },
   },
+
   // User
   // User
   {
   {
     "id": "kF9u3jf9eu3nf84rh47gf7474gf",
     "id": "kF9u3jf9eu3nf84rh47gf7474gf",
@@ -98,19 +52,8 @@
       "bannedAt": 1472926465,
       "bannedAt": 1472926465,
       "bannedUntil": 1472926466
       "bannedUntil": 1472926466
     },
     },
-    "mute": {
-      "muted": true,
-      "reason": "Spamming",
-      "mutedAt": 1472926465,
-      "mutedUntil": 1472926466
-    },
-    "2fa": {
-      "enabled": true
-      //Token and such
-    },
     "statistics": {
     "statistics": {
-      "songsRequested": 34,
-      "songsAccepted": 23
+      "songsRequested": 34
     },
     },
     "createdAt": 1472926465
     "createdAt": 1472926465
   }
   }

+ 0 - 18
backend/schemas/queueSong.js

@@ -1,18 +0,0 @@
-module.exports = mongoose => {
-
-	const Schema = mongoose.Schema;
-
-	const queueSongSchema = new Schema({
-		_id: { type: String, length: 11, index: true, unique: true, required: true },
-		title: { type: String, required: true },
-		artists: [{ type: String, min: 1 }],
-		duration: { type: Number, required: true },
-		skipDuration: { type: Number, required: true, default: 0 },
-		image: { type: String, required: true, default: "" },
-		genres: [{ type: String }],
-		requestedBy: { type: String, required: true },
-		requestedAt: { type: Date, required: true },
-	});
-
-	return mongoose.model('queueSong', queueSongSchema);
-};

+ 2 - 21
backend/schemas/song.js

@@ -3,30 +3,11 @@ module.exports = mongoose => {
 	const Schema = mongoose.Schema;
 	const Schema = mongoose.Schema;
 
 
 	const songSchema = new Schema({
 	const songSchema = new Schema({
-		_id: { type: String, length: 11, index: true, unique: true, required: true },
+		id: { type: String, length: 11, index: true, unique: true, required: true },
 		title: { type: String, required: true },
 		title: { type: String, required: true },
 		artists: [{ type: String, min: 1 }],
 		artists: [{ type: String, min: 1 }],
 		duration: { type: Number, required: true },
 		duration: { type: Number, required: true },
-		skipDuration: { type: Number, required: true },
-		image: { type: String, required: true },
-		likes: { type: Number, required: true },
-		dislikes: { type: Number, required: true },
-		genres: [{ type: String }],
-		acceptedBy: { type: String, required: true },
-		acceptedAt: { type: Date, required: true },
-		requestedBy: { type: String, required: true },
-		requestedAt: { type: Date, required: true },
-		reports: [{
-			reportedBy: { type: String, required: true },
-			reportedAt: { type: Date, required: true },
-			reason: [{
-				type: { type: String, enum: ["title", "artist", "image", "duration", "video"], required: true },
-				message: { type: String, default: "" }
-			}],
-			resolved: { type: Boolean, required: true, default: false },
-			resolvedBy: { type: String },
-			resolvedAt: { type: String }
-		}]
+		thumbnail: { type: String, required: true }
 	});
 	});
 
 
 	return songSchema;
 	return songSchema;

+ 6 - 15
backend/schemas/station.js

@@ -3,31 +3,22 @@ module.exports = mongoose => {
 	const Schema = mongoose.Schema;
 	const Schema = mongoose.Schema;
 
 
 	const stationSchema = new Schema({
 	const stationSchema = new Schema({
-		_id: { type: String, lowercase: true, max: 16, min: 2, index: true, unique: true, required: true },
+		id: { type: String, lowercase: true, max: 16, min: 2, index: true, unique: true, required: true },
 		type: { type: String, enum: ["official", "community"], required: true},
 		type: { type: String, enum: ["official", "community"], required: true},
 		displayName: { type: String, min: 2, max: 32, required: true },
 		displayName: { type: String, min: 2, max: 32, required: true },
 		description: { type: String, min: 2, max: 128, required: true },
 		description: { type: String, min: 2, max: 128, required: true },
-		privacy: { type: String, enum: ["public", "unlisted", "private"], default: "public", required: true },
 		paused: { type: Boolean, default: false, required: true },
 		paused: { type: Boolean, default: false, required: true },
 		currentSong: {
 		currentSong: {
-			startedAt: { type: Number, required: true },
-			id: { type: String, length: 11, required: true },
+			id: { type: String, length: 11, index: true, unique: true, required: true },
 			title: { type: String, required: true },
 			title: { type: String, required: true },
 			artists: [{ type: String, min: 1 }],
 			artists: [{ type: String, min: 1 }],
 			duration: { type: Number, required: true },
 			duration: { type: Number, required: true },
-			skipDuration: { type: Number, required: true },
-			image: { type: String, required: true },
-			likes: { type: Number, required: true },
-			dislikes: { type: Number, required: true },
-			genres: [{ type: String }]
+			thumbnail: { type: String, required: true }
 		},
 		},
+		currentSongIndex: { type: Number, default: 0, required: true },
 		timePaused: { type: Number, default: 0, required: true },
 		timePaused: { type: Number, default: 0, required: true },
-		playlist: { type: String, required: true },
-		genres: [{ type: String }],
-		whitelist: [{ type: String }],
-		partyMode: { type: Boolean, default: false, required: true },
-		queueLocked: { type: Boolean, default: false, required: true },
-		owner: { type: String }
+		playlist: { type: Object, required: true },
+		genres: [{ type: String }]
 	});
 	});
 
 
 	return mongoose.model('station', stationSchema);
 	return mongoose.model('station', stationSchema);

+ 5 - 21
backend/schemas/user.js

@@ -3,43 +3,27 @@ module.exports = mongoose => {
     const Schema = mongoose.Schema;
     const Schema = mongoose.Schema;
 
 
     const userSchema = new Schema({
     const userSchema = new Schema({
-        username: String,
+        username: { type: String, required: true },
         email: {
         email: {
-            verified: { type: Boolean, default: false },
+            verified: { type: Boolean, default: false, required: true },
             verificationToken: String,
             verificationToken: String,
             address: String
             address: String
         },
         },
         services: {
         services: {
             password: {
             password: {
                 password: String
                 password: String
-            },
-            github: {
-                id: String
-            },
-            discord: {
-                id: String
             }
             }
         },
         },
         ban: {
         ban: {
-            banned: { type: Boolean, default: false },
+            banned: { type: Boolean, default: false, required: true },
             reason: String,
             reason: String,
             bannedAt: Date,
             bannedAt: Date,
             bannedUntil: Date
             bannedUntil: Date
         },
         },
-        mute: {
-            muted: { type: Boolean, default: false },
-            reason: String,
-            mutedAt: Date,
-            mutedUntil: Date
-        },
         statistics: {
         statistics: {
-            songsRequested: { type: Number, default: 0 },
-            songsAccepted: { type: Number, default: 0 }
+            songsRequested: { type: Number, default: 0 }
         },
         },
-        createdAt: { type: Date, default: Date.now() },
-		friends: [],
-		likes: [],
-		dislikes: []
+        createdAt: { type: Date, default: Date.now() }
     });
     });
 
 
     return mongoose.model('user', userSchema);
     return mongoose.model('user', userSchema);

+ 19 - 68
frontend/App.vue

@@ -1,7 +1,4 @@
 <template>
 <template>
-	<div id="toasts">
-		<span v-for="toast in toasts" v-bind:class="toast.class">{{toast.text}}</span>
-	</div>
 	<div>
 	<div>
 		<router-view></router-view>
 		<router-view></router-view>
 	</div>
 	</div>
@@ -30,30 +27,7 @@
 				likes: [],
 				likes: [],
 				dislikes: [],
 				dislikes: [],
 				loggedIn: true,
 				loggedIn: true,
-				groups: [
-					{
-						id: "lu08gw56571r4497wrk9",
-						name: "Official Rooms",
-						rooms: [
-							{ id: "73qvw65746acvo8yqfr", thumbnail: "https://lh6.googleusercontent.com/-ghASz3s6yL4/AAAAAAAAAAI/AAAAAAAAALc/tFblPp2myu0/s0-c-k-no-ns/photo.jpg", name: "Country", description: "Johnny Cash - I Walk The Line", users: 10 },
-							{ id: "enxcysmhn1k7ld56ogvi", thumbnail: "http://66.media.tumblr.com/1734069af425e491fae7deae0a19869f/tumblr_o0i0xmIYrF1v421f2o1_1280.jpg", name: "Pop", description: "Sia - Cheap Thrills", users: 14 },
-							{ id: "kqa99gbva7lij05dn29", thumbnail: "http://www.youredm.com/wp-content/uploads/2014/09/taking-you-higher.jpg", name: "Chill", description: "MrSuicideSheep - Taking you higher", users: 13 },
-							{ id: "w19hu791iiub6wmjf9a4i", thumbnail: "http://edmsauce.wpengine.netdna-cdn.com/wp-content/uploads/2012/12/Deadmau5-album-title-goes-here.jpg", name: "EDM", description: "Deadmau5 - There Might Be Coffee", users: 13 }
-						]
-					},
-					{
-						id: "g2b8v03xaedj8ht1emi",
-						name: "Trending Rooms",
-						rooms: [
-							{ id: "73qvw65746acvo8yqfr", thumbnail: "https://lh6.googleusercontent.com/-ghASz3s6yL4/AAAAAAAAAAI/AAAAAAAAALc/tFblPp2myu0/s0-c-k-no-ns/photo.jpg", name: "Country", description: "Johnny Cash - I Walk The Line", users: 10 },
-							{ id: "enxcysmhn1k7ld56ogvi", thumbnail: "http://66.media.tumblr.com/1734069af425e491fae7deae0a19869f/tumblr_o0i0xmIYrF1v421f2o1_1280.jpg", name: "Pop", description: "Sia - Cheap Thrills", users: 14 },
-							{ id: "kqa99gbva7lij05dn29", thumbnail: "http://www.youredm.com/wp-content/uploads/2014/09/taking-you-higher.jpg", name: "Chill", description: "MrSuicideSheep - Taking you higher", users: 13 },
-							{ id: "w19hu791iiub6wmjf9a4i", thumbnail: "http://edmsauce.wpengine.netdna-cdn.com/wp-content/uploads/2012/12/Deadmau5-album-title-goes-here.jpg", name: "EDM", description: "Deadmau5 - There Might Be Coffee", users: 13 }
-						]
-					}
-				],
-				toastCount: 0,
-				toasts: []
+				stations: []
 			}
 			}
 		},
 		},
 		methods: {
 		methods: {
@@ -67,54 +41,29 @@
 						location.reload();
 						location.reload();
 					}
 					}
 				});
 				});
-			},
-			toast(text, duration) {
-				let local = this;
-				let id = local.toastCount++;
-
-				this.toasts.push({id: id, text: text, class: "toast toast-add"});
-				if (duration > 250) {
-					setTimeout(function() {
-						local.toasts = local.toasts.map(function(toast) {
-							if (toast.id === id) {
-								toast.class = "toast";
-							}
-							return toast;
-						});
-					}, 250);
-				}
-
-				setTimeout(function() {
-					local.toasts = local.toasts.map(function(toast) {
-						if (toast.id === id) {
-							toast.class = "toast toast-remove";
-						}
-						return toast;
-					});
-					setTimeout(function() {
-						local.toasts = local.toasts.filter(function(toast) {
-							return toast.id !== id;
-						});
-					}, 250);
-				}, duration);
 			}
 			}
 		},
 		},
-		ready: function () {
+		ready: function() {
 			let local = this;
 			let local = this;
 			local.socket = io();
 			local.socket = io();
 			local.socket.on("ready", status => {
 			local.socket.on("ready", status => {
 				local.loggedIn = status;
 				local.loggedIn = status;
-				local.socket.emit("/user/ratings", result => {
-					if (!result.err) {
-						local.likes = result.likes;
-						local.dislikes = result.dislikes;
-					}
-				});
+			});
+
+			$.ajax({
+				method: "POST",
+				url: "/stations",
+				contentType: "application/json; charset=utf-8",
+				success: stations => {
+					if (stations) this.stations = stations;
+				},
+				error: err => {
+					if (err) console.log(err);
+				}
 			});
 			});
 		},
 		},
 		events: {
 		events: {
-			'register': function() {
-				console.log('registered');
+			'register': () => {
 				$.ajax({
 				$.ajax({
 					method: "POST",
 					method: "POST",
 					url: "/users/register",
 					url: "/users/register",
@@ -139,8 +88,7 @@
 					}
 					}
 				});
 				});
 			},
 			},
-			'login': function() {
-				console.log('login');
+			'login': () => {
 				$.ajax({
 				$.ajax({
 					method: "POST",
 					method: "POST",
 					url: "/users/login",
 					url: "/users/login",
@@ -162,6 +110,9 @@
 
 
 					}
 					}
 				});
 				});
+			},
+			'joinStation': id => {
+
 			}
 			}
 		}
 		}
 	}
 	}

+ 1 - 0
frontend/build/index.html

@@ -11,6 +11,7 @@
 	<!-- Bootstrap -->
 	<!-- Bootstrap -->
 	<link rel="stylesheet" href="./vendor/bootstrap.min.css">
 	<link rel="stylesheet" href="./vendor/bootstrap.min.css">
 	<link rel="stylesheet" href="./index.css">
 	<link rel="stylesheet" href="./index.css">
+	<script src="https://www.youtube.com/iframe_api"></script>
 	<script src="./vendor/jquery.min.js"></script>
 	<script src="./vendor/jquery.min.js"></script>
 	<script src="./vendor/bootstrap.min.js"></script>
 	<script src="./vendor/bootstrap.min.js"></script>
 	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.0/moment.min.js"></script>
 	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.0/moment.min.js"></script>

+ 12 - 1
frontend/components/StationHeader.vue

@@ -15,7 +15,7 @@
 					<li class="pull-left"><a href="#" data-toggle="modal" data-target="#queue"><i class="material-icons left">playlist_add</i></a></li>
 					<li class="pull-left"><a href="#" data-toggle="modal" data-target="#queue"><i class="material-icons left">playlist_add</i></a></li>
 					<li class="pull-left"><a href="#"><i class="material-icons left">flag</i></a></li>
 					<li class="pull-left"><a href="#"><i class="material-icons left">flag</i></a></li>
 					<li class="pull-left"><a href="#"><i class="material-icons left">skip_next</i></a></li>
 					<li class="pull-left"><a href="#"><i class="material-icons left">skip_next</i></a></li>
-					<li class="pull-center"><a href="#">Station Name</a></li>
+					<li class="pull-center"><a href="#">{{title}}</a></li>
 					<li class="pull-right"><a href="#"><i class="material-icons">queue_music</i></a></li>
 					<li class="pull-right"><a href="#"><i class="material-icons">queue_music</i></a></li>
 					<li class="pull-right"><a href="#"><i class="material-icons">chat</i></a></li>
 					<li class="pull-right"><a href="#"><i class="material-icons">chat</i></a></li>
 					<li class="pull-right"><a href="#"><i class="material-icons">people</i></a></li>
 					<li class="pull-right"><a href="#"><i class="material-icons">people</i></a></li>
@@ -25,6 +25,16 @@
 	</nav>
 	</nav>
 </template>
 </template>
 
 
+<script>
+	export default {
+		data() {
+			return {
+				title: this.$route.params.id
+			}
+		}
+	}
+</script>
+
 <style lang="sass" scoped>
 <style lang="sass" scoped>
 	.navbar-default {
 	.navbar-default {
 		background-color: #0091ea;
 		background-color: #0091ea;
@@ -45,6 +55,7 @@
 
 
 			li.pull-center a {
 			li.pull-center a {
 				line-height: 64px;
 				line-height: 64px;
+				text-transform: capitalize;
 			}
 			}
 
 
 			li.pull-right, li.pull-left {
 			li.pull-right, li.pull-left {

+ 33 - 36
frontend/components/pages/Home.vue

@@ -30,9 +30,6 @@
 					<div class="modal-body">
 					<div class="modal-body">
 						<input class="form-control" type="text" placeholder="Email..." v-model="$parent.login.email"/>
 						<input class="form-control" type="text" placeholder="Email..." v-model="$parent.login.email"/>
 						<input class="form-control" type="password" placeholder="Password..." v-model="$parent.login.password"/>
 						<input class="form-control" type="password" placeholder="Password..." v-model="$parent.login.password"/>
-						<hr />
-						<a class="btn btn-block btn-default btn-github" href="/users/github"><i class="fa fa-github"></i> Login with GitHub</a>
-						<a class="btn btn-block btn-default btn-discord" href="/users/discord">Login with Discord</a>
 					</div>
 					</div>
 					<div class="modal-footer">
 					<div class="modal-footer">
 						<button type="button" class="btn btn-primary" data-dismiss="modal" @click="this.$dispatch('login');">Submit</button>
 						<button type="button" class="btn btn-primary" data-dismiss="modal" @click="this.$dispatch('login');">Submit</button>
@@ -40,18 +37,18 @@
 				</div>
 				</div>
 			</div>
 			</div>
 		</div>
 		</div>
-		<div class="group" v-for="group in $parent.groups">
-			<div class="group-title">{{group.name}}</div>
-			<div class="group-rooms">
-				<div class="rooms-room" v-for="room in group.rooms" v-link="{ path: '/station' }">
-					<img class="room-image" :src="room.thumbnail" />
-					<div class="room-info">
-						<div class="room-grid-left">
-							<h3>{{ room.name }}</h3>
-							<p>{{ room.description }}</p>
+		<div class="group">
+			<!--<div class="group-title">{{group.name}}</div>-->
+			<div class="group-stations">
+				<div class="stations-station" v-for="station in $parent.stations" v-link="{ path: '/station/' + station.id }">
+					<img class="station-image" :src="station.playlist[station.currentSongIndex].thumbnail" />
+					<div class="station-info">
+						<div class="station-grid-left">
+							<h3>{{ station.displayName }}</h3>
+							<p>{{ station.description }}</p>
 						</div>
 						</div>
-						<div class="room-grid-right">
-							<div>{{ room.users }}&nbsp;&nbsp;<i class="fa fa-user" aria-hidden="true"></i></div>
+						<div class="station-grid-right">
+							<!--<div>{{ station.users }}&nbsp;&nbsp;<i class="fa fa-user" aria-hidden="true"></i></div>-->
 						</div>
 						</div>
 					</div>
 					</div>
 				</div>
 				</div>
@@ -104,28 +101,28 @@
 		}
 		}
 	}
 	}
 
 
-		.g-recaptcha {
-			display: flex;
-			justify-content: center;
-			margin-top: 10px;
+	.g-recaptcha {
+		display: flex;
+		justify-content: center;
+		margin-top: 10px;
 	}
 	}
 
 
-		.group {
-			width: 100%;
-			height: 448px;
-			margin: 64px 0 64px 0;
+	.group {
+		width: 100%;
+		height: 448px;
+		margin: 64px 0 64px 0;
 
 
-			.group-title {
-				float: left;
-				clear: none;
-				width: 100%;
-				height: 64px;
-				line-height: 48px;
-				text-align: center;
-				font-size: 48px;
+		.group-title {
+			float: left;
+			clear: none;
+			width: 100%;
+			height: 64px;
+			line-height: 48px;
+			text-align: center;
+			font-size: 48px;
 		}
 		}
 
 
-		.group-rooms {
+		.group-stations {
 			white-space: nowrap;
 			white-space: nowrap;
 			text-align: center;
 			text-align: center;
 			overflow: hidden;
 			overflow: hidden;
@@ -134,7 +131,7 @@
 			width: 100%;
 			width: 100%;
 			height: 400px;
 			height: 400px;
 
 
-			.rooms-room {
+			.stations-station {
 				position: relative;
 				position: relative;
 				top: 16px;
 				top: 16px;
 				display: inline-block;
 				display: inline-block;
@@ -145,18 +142,18 @@
 				box-shadow: 0 1px 6px 2px rgba(0, 0, 0, 0.25);
 				box-shadow: 0 1px 6px 2px rgba(0, 0, 0, 0.25);
 				cursor: pointer;
 				cursor: pointer;
 
 
-				.room-info {
+				.station-info {
 					display: flex;
 					display: flex;
 					flex-direction: row;
 					flex-direction: row;
 					align-items: center;
 					align-items: center;
 				}
 				}
 
 
-				.room-image {
+				.station-image {
 					width: 100%;
 					width: 100%;
 					height: 256px;
 					height: 256px;
 				}
 				}
 
 
-				.room-grid-left {
+				.station-grid-left {
 					display: flex;
 					display: flex;
 					flex-direction: column;
 					flex-direction: column;
 					width: 75%;
 					width: 75%;
@@ -170,7 +167,7 @@
 					}
 					}
 				}
 				}
 
 
-				.room-grid-right {
+				.station-grid-right {
 					display: flex;
 					display: flex;
 					flex-direction: column;
 					flex-direction: column;
 					width: 25%;
 					width: 25%;

+ 74 - 199
frontend/components/pages/Station.vue

@@ -5,17 +5,16 @@
 			<div class="col-md-8 col-md-push-2 col-sm-10 col-sm-push-1 col-xs-12 video-col">
 			<div class="col-md-8 col-md-push-2 col-sm-10 col-sm-push-1 col-xs-12 video-col">
 				<div class="video-container">
 				<div class="video-container">
 					<div id="player"></div>
 					<div id="player"></div>
-					<!--iframe id="player" frameborder="0" allowfullscreen="1" title="YouTube video player" width="480" height="270" src="https://www.youtube.com/embed/xo1VInw-SKc?controls=0&amp;iv_load_policy=3&amp;rel=0&amp;showinfo=0&amp;enablejsapi=1&amp;origin=https%3A%2F%2Fmusare.com&amp;widgetid=1" kwframeid="1"></iframe-->
 				</div>
 				</div>
 			</div>
 			</div>
 			<div class="col-md-8 col-md-push-2 col-sm-10 col-sm-push-1 col-xs-12">
 			<div class="col-md-8 col-md-push-2 col-sm-10 col-sm-push-1 col-xs-12">
 				<div class="row">
 				<div class="row">
-					<button v-if="paused" @click="unpauseStation()">Unpause</button>
-					<button v-if="!paused" @click="pauseStation()">Pause</button>
+					<!--<button v-if="paused" @click="unpauseStation()">Unpause</button>-->
+					<!--<button v-if="!paused" @click="pauseStation()">Pause</button>-->
 					<div class="col-md-8 col-sm-12 col-sm-12">
 					<div class="col-md-8 col-sm-12 col-sm-12">
-						<h4 id="time-display">{{timeElapsed}} / {{songDuration}}</h4>
-						<h3>{{title}}</h3>
-						<h4 class="thin" style="margin-left: 0">{{artists}}</h4>
+						<h4 id="time-display">{{timeElapsed}} / {{currentSong.duration}}</h4>
+						<h3>{{currentSong.title}}</h3>
+						<h4 class="thin" style="margin-left: 0">{{currentSong.artists}}</h4>
 						<div class="row">
 						<div class="row">
 							<form style="margin-top: 12px; margin-bottom: 0;" action="#" class="col-md-4 col-lg-4 col-xs-4 col-sm-4">
 							<form style="margin-top: 12px; margin-bottom: 0;" action="#" class="col-md-4 col-lg-4 col-xs-4 col-sm-4">
 								<p style="margin-top: 0; position: relative;">
 								<p style="margin-top: 0; position: relative;">
@@ -24,8 +23,8 @@
 							</form>
 							</form>
 							<div class="col-xs-8 col-sm-5 col-md-5" style="float: right;">
 							<div class="col-xs-8 col-sm-5 col-md-5" style="float: right;">
 								<ul id="ratings">
 								<ul id="ratings">
-									<li id="like" class="right"><span class="flow-text">{{likes}} </span> <i id="thumbs_up" class="material-icons grey-text" @click="toggleLike()">thumb_up</i></li>
-									<li style="margin-right: 10px;" id="dislike" class="right"><span class="flow-text">{{dislikes}} </span><i id="thumbs_down" class="material-icons grey-text" @click="toggleDislike()">thumb_down</i></li>
+									<li id="like" class="right"><span class="flow-text">{{currentSong.likes}} </span> <i id="thumbs_up" class="material-icons grey-text">thumb_up</i></li>
+									<li style="margin-right: 10px;" id="dislike" class="right"><span class="flow-text">{{currentSong.dislikes}} </span><i id="thumbs_down" class="material-icons grey-text">thumb_down</i></li>
 								</ul>
 								</ul>
 							</div>
 							</div>
 						</div>
 						</div>
@@ -33,7 +32,7 @@
 							<div class="seeker-bar light-blue" style="width: 60.9869%;"></div>
 							<div class="seeker-bar light-blue" style="width: 60.9869%;"></div>
 						</div>
 						</div>
 					</div>
 					</div>
-					<img alt="Not loading" class="img-responsive col-md-4 col-xs-12 col-sm-12" onerror="this.src='../assets/notes.png'" id="song-image" style="margin-top: 10px !important" v-bind:src="image" />
+					<img class="img-responsive col-md-4 col-xs-12 col-sm-12" id="song-thumbnail" style="margin-top: 10px !important" :src="currentSong.thumbnail" alt="Song Thumbnail" />
 				</div>
 				</div>
 			</div>
 			</div>
 		</div>
 		</div>
@@ -44,32 +43,31 @@
 			<div class="modal-content">
 			<div class="modal-content">
 				<div class="modal-header">
 				<div class="modal-header">
 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
 					<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-					<h5 class="modal-title">Add to Musare</h5>
+					<h5 class="modal-title">Add to Station</h5>
 				</div>
 				</div>
 				<div class="modal-body">
 				<div class="modal-body">
-					<input class="form-control" type="text" placeholder="YouTube Query / Video ID / Video link / Playlist link" v-model="queueQuery"/>
-					<button type="button" class="btn btn-primary" @click="submitQueueQuery()">Search</button>
-					<button type="button" class="btn btn-error" @click="clearQueueQuery()" v-if="queueQueryActive">Clear List</button>
-					<div v-if="queueQueryActive">
-						<h2>Queue Results</h2>
-						<div v-for="item in queueQueryResults">
-							<h5>{{item.title}}</h5>
-							<button @click='addItemToItems(item.id)'>Add</button>
-							<br>
+					<div class="form-group">
+						<div class="input-group">
+							<input class="form-control" type="text" placeholder="YouTube Query" v-model="queryInput"/>
+							<a type="button" class="input-group-btn btn btn-primary btn-search" @click="submitQuery()">Search</a>
 						</div>
 						</div>
 					</div>
 					</div>
-					<hr>
-					<div class="row">
-						<h2>Items to add</h2>
-						<div v-for="item in queueItems">
-							<h5>{{item.title}}</h5>
-							<br>
+					<div>
+						<div v-for="result in queryResults">
+							<div class="media">
+								<div class="media-left">
+									<a href={{result.url}}>
+										<img class="media-object" :src="result.thumbnail" />
+									</a>
+								</div>
+								<div class="media-body">
+									<h4 class="media-heading">{{result.title}}</h4>
+									<button class="btn btn-success" @click='addSongToQueue(result)'>Add</button>
+								</div>
+							</div>
 						</div>
 						</div>
 					</div>
 					</div>
 				</div>
 				</div>
-				<div class="modal-footer">
-					<button type="button" class="btn btn-primary left" data-dismiss="modal" @click="addItemsToQueue()">Add items to queue</button>
-				</div>
 			</div>
 			</div>
 		</div>
 		</div>
 	</div>
 	</div>
@@ -83,36 +81,27 @@
 		data() {
 		data() {
 			return {
 			return {
 				playerReady: false,
 				playerReady: false,
-				currentSong: undefined,
+				currentSong: {},
 				player: undefined,
 				player: undefined,
 				timePaused: 0,
 				timePaused: 0,
 				paused: false,
 				paused: false,
-				songDuration: "0:00",
 				timeElapsed: "0:00",
 				timeElapsed: "0:00",
-				artists: "",
-				title: "",
-				image: "",
-				likes: 0,
-				dislikes: 0,
 				interval: 0,
 				interval: 0,
-				queueQuery: "",
-				queueQueryActive: false,
-				queueQueryResults: [],
-				queueItems: []
+				queryInput: "",
+				queryResults: [],
+				queue: []
 			}
 			}
 		},
 		},
 		methods: {
 		methods: {
 			youtubeReady: function() {
 			youtubeReady: function() {
 				let local = this;
 				let local = this;
-				console.log("YT Ready!!!");
 				local.player = new YT.Player("player", {
 				local.player = new YT.Player("player", {
 					height: 270,
 					height: 270,
 					width: 480,
 					width: 480,
 					videoId: local.currentSong.id,
 					videoId: local.currentSong.id,
 					playerVars: {controls: 1, iv_load_policy: 3, rel: 0, showinfo: 0},
 					playerVars: {controls: 1, iv_load_policy: 3, rel: 0, showinfo: 0},
 					events: {
 					events: {
-						'onReady': function (event) {
-							console.log("Ready!!!");
+						'onReady': function(event) {
 							local.playerReady = true;
 							local.playerReady = true;
 							let volume = parseInt(localStorage.getItem("volume"));
 							let volume = parseInt(localStorage.getItem("volume"));
 							volume = (typeof volume === "number") ? volume : 20;
 							volume = (typeof volume === "number") ? volume : 20;
@@ -122,7 +111,7 @@
 							}
 							}
 							local.playVideo();
 							local.playVideo();
 						},
 						},
-						'onStateChange': function (event) {
+						'onStateChange': function(event) {
 							if (event.data === 1 && local.videoLoading === true) {
 							if (event.data === 1 && local.videoLoading === true) {
 								local.videoLoading = false;
 								local.videoLoading = false;
 								local.player.seekTo(local.getTimeElapsed() / 1000, true);
 								local.player.seekTo(local.getTimeElapsed() / 1000, true);
@@ -134,32 +123,12 @@
 					}
 					}
 				});
 				});
 			},
 			},
-			startSong: function(song) {
-				let local = this;
-				if (local.playerReady) {
-
-				}
-			},
 			getTimeElapsed: function() {
 			getTimeElapsed: function() {
 				let local = this;
 				let local = this;
 				if (local.currentSong !== undefined) {
 				if (local.currentSong !== undefined) {
 					return Date.now() - local.currentSong.startedAt - local.timePaused;
 					return Date.now() - local.currentSong.startedAt - local.timePaused;
-				}
-				return 0;
-			},
-			pauseVideo: function() {
-				let local = this;
-				local.paused = true;
-				if (local.playerReady) {
-					local.player.pauseVideo();
-				}
-			},
-			unpauseVideo: function() {
-				let local = this;
-				local.paused = false;
-				if (local.playerReady) {
-					local.player.seekTo(local.getTimeElapsed() / 1000);
-					local.player.playVideo();
+				} else {
+					return 0;
 				}
 				}
 			},
 			},
 			playVideo: function() {
 			playVideo: function() {
@@ -167,13 +136,11 @@
 				if (local.playerReady) {
 				if (local.playerReady) {
 					local.videoLoading = true;
 					local.videoLoading = true;
 					local.player.loadVideoById(local.currentSong.id);
 					local.player.loadVideoById(local.currentSong.id);
-					var d = moment.duration(parseInt(local.currentSong.duration), 'seconds');
-					local.songDuration = d.minutes() + ":" + ("0" + d.seconds()).slice(-2);
-					local.artists = local.currentSong.artists.join(", ");
-					local.title = local.currentSong.title;
-					local.image = local.currentSong.image;
-					local.likes = local.currentSong.likes;
-					local.dislikes = local.currentSong.dislikes;
+
+					const d = moment.duration(parseInt(local.currentSong.duration), 'seconds');
+					local.currentSong.songDuration = d.minutes() + ":" + ("0" + d.seconds()).slice(-2);
+
+					local.currentSong.artists = local.currentSong.artists.join(", ");
 
 
 					if (local.interval !== 0) {
 					if (local.interval !== 0) {
 						clearInterval(local.interval);
 						clearInterval(local.interval);
@@ -194,9 +161,9 @@
 			calculateTimeElapsed: function() {
 			calculateTimeElapsed: function() {
 				let local = this;
 				let local = this;
 				let currentTime = Date.now();
 				let currentTime = Date.now();
-				if (local.timePausedCurrentTime !== undefined && local.paused) {
-					local.timePaused += (Date.now() - local.timePausedCurrentTime);
-					local.timePausedCurrentTime = undefined;
+				if (local.currentTime !== undefined && local.paused) {
+					local.timePaused += (Date.now() - local.currentTime);
+					local.currentTime = undefined;
 				}
 				}
 				let duration = (Date.now() - local.currentSong.startedAt - local.timePaused) / 1000;
 				let duration = (Date.now() - local.currentSong.startedAt - local.timePaused) / 1000;
 				let songDuration = local.currentSong.duration;
 				let songDuration = local.currentSong.duration;
@@ -204,7 +171,6 @@
 					local.player.pauseVideo();
 					local.player.pauseVideo();
 				}
 				}
 				let d = moment.duration(duration, 'seconds');
 				let d = moment.duration(duration, 'seconds');
-				console.log(duration, "    ", local.timePaused);
 				if ((!local.paused || local.timeElapsed === "0:00") && duration <= songDuration) {
 				if ((!local.paused || local.timeElapsed === "0:00") && duration <= songDuration) {
 					local.timeElapsed = d.minutes() + ":" + ("0" + d.seconds()).slice(-2);
 					local.timeElapsed = d.minutes() + ":" + ("0" + d.seconds()).slice(-2);
 				}
 				}
@@ -221,161 +187,66 @@
 				}
 				}
 			},
 			},
 			unpauseStation: function() {
 			unpauseStation: function() {
-				console.log("UNPAUSE1");
 				let local = this;
 				let local = this;
-				local.stationSocket.emit("unpause");
+				local.paused = false;
+				if (local.playerReady) {
+					local.player.seekTo(local.getTimeElapsed() / 1000);
+					local.player.playVideo();
+				}
 			},
 			},
 			pauseStation: function() {
 			pauseStation: function() {
-				console.log("PAUSE1");
 				let local = this;
 				let local = this;
-				local.stationSocket.emit("pause");
-			},
-			toggleLike: function() {
-				/*let local = this;
-				local.stationSocket.emit("toggleLike");//TODO Add code here to see if this was a success or not*/
-			},
-			toggleDislike: function() {
-				/*let local = this;
-				local.stationSocket.emit("toggleDislike");//TODO Add code here to see if this was a success or not*/
-			},
-			addItemToItems: function(id) {
-				let local = this;
-				let ids = local.queueItems.map(function(item) {
-					return item.id;
-				});
-				let item;
-				local.queueQueryResults.forEach(function(result) {
-					if (result.id === id) {
-						console.log(result);
-						item = result;
-					}
-				});
-				if (ids.indexOf(id) === -1) {
-					console.log(item, 222);
-					local.queueItems.push(item);
-					local.queueQuery = "";
-					local.queueQueryActive = false;
-					local.queueQueryResults = [];
-				} else {
-					//TODO Error
+				local.paused = true;
+				if (local.playerReady) {
+					local.player.pauseVideo();
 				}
 				}
 			},
 			},
-			addItemsToQueue: function() {
+			addSongToQueue: function(song) {
 				let local = this;
 				let local = this;
-				let items = local.queueItems;
-				local.socket.emit("/songs/queue/addSongs/:songs", items, function(data) {
+				local.socket.emit("/songs/queue/add/:song", song, function(data) {
 					console.log(data);
 					console.log(data);
-					if (!data.err) {
-						local.queueItems = [];
-						$('#queue').modal('hide');
-					}
 				});
 				});
 			},
 			},
-			submitQueueQuery: function() {
+			submitQuery: function() {
 				let local = this;
 				let local = this;
-				let query = local.queueQuery;
-				local.socket.emit("/youtube/getVideos/:query", query, function(data) {
-					if (!data.err) {
-						/*queueQueryActive:
-						 queueQueryResults:*/
-						if (data.type === "playlist") {
-							let added = 0;
-							let duplicate = 0;
-							let items = [];
-							let ids = local.queueItems.map(function(item) {
-								return item.id;
-							});
-
-							data.items.forEach(function(item) {
-								if (ids.indexOf(item.id) === -1) {
-									items.push(item);
-									added++;
-								} else {
-									duplicate++;
-								}
-							});
-
-							//TODO Give result
-							local.queueItems = local.queueItems.concat(items);
-						} else if (data.type === "video") {
-							let ids = local.queueItems.map(function(item) {
-								return item.id;
-							});
-
-							if (data.item !== undefined) {
-								if (ids.indexOf(data.item.id)) {
-									local.queueItems.push(data.item);
-								}
-							}
-
-							//TODO Give result
-						} else {
-							local.queueQueryResults = [];
-							data.items.forEach(function(item) {
-								local.queueQueryResults.push(item);
-							});
-							//TODO Give result
-							local.queueQueryActive = true;
-						}
+				local.socket.emit("/youtube/getVideo/:query", local.queryInput, function(data) {
+					local.queryResults = [];
+					for (let i = 0; i < data.items.length; i++) {
+						local.queryResults.push({
+							id: data.items[i].id.videoId,
+							url: `https://www.youtube.com/watch?v=${this.id}`,
+							title: data.items[i].snippet.title,
+							thumbnail: data.items[i].snippet.thumbnails.default.url
+						});
 					}
 					}
 				});
 				});
 			}
 			}
 		},
 		},
 		ready: function() {
 		ready: function() {
 			let local = this;
 			let local = this;
-			window.onYouTubeIframeAPIReady = function() {
-				console.log("API READY?");
-				local.youtubeReady();
-			};
+
+			local.interval = 0;
 
 
 			local.socket = this.$parent.socket;
 			local.socket = this.$parent.socket;
-			local.stationSocket = io.connect('http://dev.musare.com/edm');
+			local.stationSocket = io.connect(`http://dev.musare.com/${local.$route.params.id}`);
 			local.stationSocket.on("connected", function(data) {
 			local.stationSocket.on("connected", function(data) {
-				console.log("JOINED!?");
 				local.currentSong = data.currentSong;
 				local.currentSong = data.currentSong;
 				local.paused = data.paused;
 				local.paused = data.paused;
 				local.timePaused = data.timePaused;
 				local.timePaused = data.timePaused;
-				local.timePausedCurrentTime  = data.currentTime;
-				let tag = document.createElement('script');
-
-				tag.src = "https://www.youtube.com/iframe_api";
-				let firstScriptTag = document.getElementsByTagName('script')[0];
-				firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+				local.currentTime  = data.currentTime;
 			});
 			});
-			local.stationSocket.on("skippedSong", function(currentSong) {
-				console.log("SKIPPED SONG");
+
+			local.youtubeReady();
+
+			local.stationSocket.on("nextSong", function(currentSong) {
 				local.currentSong = currentSong;
 				local.currentSong = currentSong;
 				local.timePaused = 0;
 				local.timePaused = 0;
 				local.playVideo();
 				local.playVideo();
 			});
 			});
-			local.stationSocket.on("pause", function() {
-				console.log("PAUSE");
-				local.pauseVideo();
-			});
-			local.stationSocket.on("unpause", function(timePaused) {
-				console.log("UNPAUSE");
-				local.timePaused = timePaused;
-				local.unpauseVideo();
-			});
-
 
 
 			let volume = parseInt(localStorage.getItem("volume"));
 			let volume = parseInt(localStorage.getItem("volume"));
 			volume = (typeof volume === "number") ? volume : 20;
 			volume = (typeof volume === "number") ? volume : 20;
 			$("#volumeSlider").val(volume);
 			$("#volumeSlider").val(volume);
-
-			// TODO: Remove this
-			/*local.socket.emit("/station/:id/join", "edm", function(data) {
-				console.log("JOINED!?");
-				local.currentSong = data.data.currentSong;
-				local.paused = data.data.paused;
-				local.timePaused = data.data.timePaused;
-				local.timePausedCurrentTime  = data.data.currentTime;
-				let tag = document.createElement('script');
-
-				tag.src = "https://www.youtube.com/iframe_api";
-				let firstScriptTag = document.getElementsByTagName('script')[0];
-				firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
-			});*/
 		},
 		},
 		components: { StationHeader, MainFooter }
 		components: { StationHeader, MainFooter }
 	}
 	}
@@ -630,4 +501,8 @@
 	.white {
 	.white {
 		background-color: #FFFFFF !important;
 		background-color: #FFFFFF !important;
 	}
 	}
+
+	.btn-search {
+		font-size: 14px;
+	}
 </style>
 </style>

+ 1 - 1
frontend/main.js

@@ -12,7 +12,7 @@ router.map({
 	'/': {
 	'/': {
 		component: Home
 		component: Home
 	},
 	},
-	'/station': {
+	'/station/:id': {
 		component: Station
 		component: Station
 	},
 	},
 	'/admin/queue': {
 	'/admin/queue': {