Browse Source

Added basic functionality for station page.

KrisVos130 8 years ago
parent
commit
276739359b

+ 40 - 3
backend/logic/coreHandler.js

@@ -19,6 +19,42 @@ const global   = require('./global'),
 
 var eventEmitter = new events.EventEmitter();
 
+const station = new stations.Station("edm", {
+	playlist: [
+		{
+			startedAt: Date.now(),
+			id: "dQw4w9WgXcQ",
+			title: "Never gonna give you up",
+			artists: ["Rick Astley"],
+			duration: 20,
+			skipDuration: 0,
+			image: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
+			likes: 0,
+			dislikes: 1,
+			genres: ["pop", "edm"]
+		},
+		{
+			startedAt: Date.now(),
+			id: "GxBSyx85Kp8",
+			title: "Yeah!",
+			artists: ["Usher"],
+			duration: 20,
+			skipDuration: 0,
+			image: "https://yt3.ggpht.com/-CGlBu6kDEi8/AAAAAAAAAAI/AAAAAAAAAAA/Pi679mvyyyU/s88-c-k-no-mo-rj-c0xffffff/photo.jpg",
+			likes: 0,
+			dislikes: 1,
+			genres: ["pop", "edm"]
+		}
+	],
+	currentSongIndex: 1,
+	paused: false,
+	locked: false,
+	displayName: "EDM",
+	description: "EDM Music"
+});
+
+stations.addStation(station);
+
 module.exports = {
 
 	// module functions
@@ -119,19 +155,20 @@ module.exports = {
 
 			user.stationId = id;
 
-			this.emit('station-joined', {
+			/*io.sockets.emit('station-joined', {
 				user: {
 					id: user.id,
 					username: user.username
 				}
-			});
+			});*/
 
 			return cb({
 				status: 'joined',
 				data: {
 					displayName: station.getDisplayName(),
 					users: station.getUsers(),
-					currentSong: station.getCurrentSong()
+					currentSong: station.getCurrentSong(),
+					timePaused: 0
 				}
 			});
 		}

+ 7 - 6
backend/logic/global.js

@@ -3,14 +3,15 @@
 class Timer {
 	constructor(callback, delay, paused) {
 		this.callback = callback;
-		this.delay = delay;
-		this.paused = paused;
-
-		this.timerId = delay;
-		this.start = delay;
-		this.remaining = delay;
+		this.timerId = undefined;
+		this.start = undefined;
+		this.remaining = delay * 1000;
 		this.timeWhenPaused = 0;
 		this.timePaused = Date.now();
+
+		if (!paused) {
+			this.resume();
+		}
 	}
 
 	pause() {

+ 1 - 1
backend/logic/socketHandler.js

@@ -30,7 +30,7 @@ module.exports = (core, io) => {
 		});
 
 		socket.on('/stations/join/:id', (id, cb) => {
-			core['/stations/join/:id'](id, result => {
+			core['/stations/join/:id'](id, socket.request.user, result => {
 				cb(result);
 			});
 		});

+ 128 - 109
backend/logic/stations.js

@@ -1,138 +1,157 @@
 'use strict';
 
 const global = require('./global');
-let io = global.io;
-
-module.exports = class Station {
-	constructor(id, data) {
-		this.nsp = io.of('/' + id);
-		this.nsp.on('connection', socket => {
-			console.info('someone connected');
-		});
-		this.id = id;
-		this.data = data;
-
-		this.playlist = data.playlist;
-		this.currentSong = this.playlist[0];
-		this.currentSongIndex = data.currentSongIndex;
-		this.paused = data.paused;
-		this.locked = data.locked;
-		this.skipVotes = data.skipVotes;
-		this.users = data.users;
-		this.displayName = data.displayName;
-		this.description = data.description;
-		this.timer = undefined;
-	}
-
-	skipSong() {
-		if (this.playlist.length > 0) {
-			if (this.timer !== undefined) this.timer.pause();
-
-			if (this.currentSongIndex+1 < this.playlist.length) this.currentSongIndex++;
-			else this.currentSongIndex = 0;
-
-			this.skipVotes = 0;
+const io = global.io;
+let stations = [];
+
+module.exports = {
+	Station: class Station {
+		constructor(id, data) {
+			this.nsp = io.of(id);
+			this.nsp.on('connection', socket => {
+				console.log('someone connected');
+			});
+			this.id = id;
+
+			this.playlist = data.playlist;
+			this.currentSongIndex = data.currentSongIndex;
 			this.currentSong = this.playlist[this.currentSongIndex];
+			this.paused = data.paused;
+			this.locked = data.locked;
+			this.skipVotes = 0;
+			this.users = [];
+			this.displayName = data.displayName;
+			this.description = data.description;
+			this.timer = undefined;
+			this.skipSong();
+		}
 
-			this.timer = new global.Timer(() => {
-				console.log("Skip!");
-				self.skipSong();
-			}, this.currentSong.duration, this.paused);
-
-			nsp.emit("skippedSong", this.currentSong);
+		skipSong() {
+			if (this.playlist.length > 0) {
+				console.log("SKIPP");
+				if (this.timer !== undefined) this.timer.pause();
+
+				if (this.currentSongIndex + 1 < this.playlist.length) this.currentSongIndex++;
+				else this.currentSongIndex = 0;
+
+				this.skipVotes = 0;
+				this.currentSong = this.playlist[this.currentSongIndex];
+
+				var self = this;
+				this.timer = new global.Timer(() => {
+					console.log("Skip!");
+					self.skipSong();
+				}, this.currentSong.duration, this.paused);
+				this.currentSong.startedAt = Date.now();
+				this.nsp.emit("skippedSong", 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);
+		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
-		nsp.emit("voteSkip", this.skipVotes);
-	}
+			// TODO: Calculate if enough people voted to skip
+			this.nsp.emit("voteSkip", this.skipVotes);
+		}
 
-	retrievePlaylist() {
-		// TODO: get the Playlist for this station using db
-	}
+		retrievePlaylist() {
+			// TODO: get the Playlist for this station using db
+		}
 
-	pause() {
-		if (!this.paused) {
-			this.paused = true;
-			this.timer.pause();
-			nsp.emit("pause");
+		pause() {
+			if (!this.paused) {
+				this.paused = true;
+				this.timer.pause();
+				this.snp.emit("pause");
+			}
 		}
-	}
 
-	unPause() {
-		if (this.paused) {
-			this.paused = false;
-			this.timer.resume();
-			nsp.emit("unpause");
+		unPause() {
+			if (this.paused) {
+				this.paused = false;
+				this.timer.resume();
+				this.snp.emit("unpause");
+			}
 		}
-	}
 
-	isPaused() {
-		return this.paused;
-	}
+		isPaused() {
+			return this.paused;
+		}
 
-	getCurrentSong() {
-		return this.currentSong;
-	}
+		getCurrentSong() {
+			return this.currentSong;
+		}
 
-	lock() {
-		if (!this.locked) {
-			this.locked = true;
-			nsp.emit("lock");
+		lock() {
+			if (!this.locked) {
+				this.locked = true;
+				this.snp.emit("lock");
+			}
 		}
-	}
 
-	unlock() {
-		if (this.locked) {
-			this.locked = false;
-			nsp.emit("unlocked");
+		unlock() {
+			if (this.locked) {
+				this.locked = false;
+				this.snp.emit("unlocked");
+			}
 		}
-	}
 
-	isLocked() {
-		return this.locked;
-	}
+		isLocked() {
+			return this.locked;
+		}
 
-	updateDisplayName(newDisplayName) {
-		// TODO: Update db
-		this.displayName = newDisplayName;
-		nsp.emit("updateDisplayName", newDisplayName);
-	}
+		updateDisplayName(newDisplayName) {
+			// TODO: Update db
+			this.displayName = newDisplayName;
+			this.snp.emit("updateDisplayName", newDisplayName);
+		}
 
-	updateDescription(newDescription) {
-		// TODO: Update db
-		this.description = newDescription;
-		nsp.emit("updateDescription", newDescription);
-	}
+		updateDescription(newDescription) {
+			// TODO: Update db
+			this.description = newDescription;
+			this.snp.emit("updateDescription", newDescription);
+		}
 
-	getId() {
-		return this.id;
-	}
+		getId() {
+			return this.id;
+		}
 
-	getDisplayName() {
-		return this.displayName;
-	}
+		getDisplayName() {
+			return this.displayName;
+		}
 
-	getDescription() {
-		return this.description;
-	}
+		getDescription() {
+			return this.description;
+		}
 
-	addUser(user) {
-		this.users.add(user);
-		nsp.emit("updateUsers", this.users);
-	}
+		addUser(user) {
+			this.users.add(user);
+			this.snp.emit("updateUsers", this.users);
+		}
 
-	removeUser(user) {
-		this.users.splice(this.users.indexOf(user), 1);
-		nsp.emit("updateUsers", this.users);
-	}
+		removeUser(user) {
+			this.users.splice(this.users.indexOf(user), 1);
+			this.snp.emit("updateUsers", this.users);
+		}
 
-	getUsers() {
-		return this.users;
+		getUsers() {
+			return this.users;
+		}
+	},
+	addStation: station => {
+		stations.push(station);
+	},
+	getStation: id => {
+		let result;
+		stations.forEach(function(station) {
+			if (station.getId() === id) {
+				result = station;
+			}
+		});
+		return result;
+	},
+	getStations: () => {
+		return stations;
 	}
-
-}
+};

+ 1 - 1
backend/schemas/station.js

@@ -7,7 +7,7 @@ module.exports = mongoose => {
 		type: { type: String, enum: ["official", "community"], required: true},
 		displayName: { type: String, min: 2, max: 32, required: true },
 		description: { type: String, min: 2, max: 128, required: true },
-		privacy: { type: String, enum: ["public", "unlisted", "private"], required: true },
+		privacy: { type: String, enum: ["public", "unlisted", "private"], default: "public", required: true },
 		paused: { type: Boolean, default: false, required: true },
 		currentSong: {
 			startedAt: { type: Number, required: true },

+ 2 - 1
frontend/build/index.html

@@ -6,12 +6,13 @@
 	<title>Musare</title>
 	<link rel="shortcut icon" type="image/x-icon" href="https://musare.com/favicon.ico" />
 	<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" type="text/css">
-	<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css">
+	<link href="https://fonts.googleapis.com/css?family=Roboto:100,400" rel="stylesheet">
 	<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
 	<!-- Bootstrap -->
 	<link rel="stylesheet" href="./vendor/bootstrap.min.css">
 	<script src="./vendor/jquery.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/socket.io/1.4.8/socket.io.min.js"></script>
 	<script src='https://www.google.com/recaptcha/api.js'></script>
 </head>

+ 2 - 2
frontend/components/MainHeader.vue

@@ -15,8 +15,8 @@
 					<li><a href="#">The Project</a></li>
 					<li><a href="#">Donate</a></li>
 					<li v-if="$parent.loggedIn"><a href="#" @click="$parent.logout()">Logout</a></li>
-					<li><a href="#" data-toggle="modal" data-target="#register">Register</a></li>
-					<li><a href="#" data-toggle="modal" data-target="#login">Login</a></li>
+					<li v-if="!$parent.loggedIn"><a href="#" data-toggle="modal" data-target="#register">Register</a></li>
+					<li v-if="!$parent.loggedIn"><a href="#" data-toggle="modal" data-target="#login">Login</a></li>
 				</ul>
 			</div>
 		</div>

+ 144 - 6
frontend/components/StationBody.Vue

@@ -1,18 +1,18 @@
 <template>
 	<div class="station">
 		<div class="row">
-			<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 video-col">
 				<div class="video-container">
-					<!--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 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 class="col-md-8 col-md-push-2 col-sm-10 col-sm-push-1 col-xs-12">
 				<div class="row">
 					<div class="col-md-8 col-sm-12 col-sm-12">
-						<h4 id="time-display"><span id="time-elapsed">2:58</span> / <span id="time-total">3:19</span></h4>
-						<h3>Stitches</h3>
-						<h4 class="thin" style="margin-left: 0">Shawn Mendes</h4>
+						<h4 id="time-display">{{timeElapsed}} / {{songDuration}}</h4>
+						<h3>{{title}}</h3>
+						<h4 class="thin" style="margin-left: 0">{{artists}}</h4>
 						<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">
 								<p style="margin-top: 0; position: relative;">
@@ -37,6 +37,139 @@
 	</div>
 </template>
 
+<script>
+	export default {
+		data() {
+			return {
+				playerReady: false,
+				currentSong: undefined,
+				player: undefined,
+				timePaused: 0,
+				paused: false,
+				songDuration: "0:00",
+				timeElapsed: "0:00",
+				artists: "",
+				title: "",
+				interval: 0
+			}
+		},
+		methods: {
+			youtubeReady: function() {
+				var local = this;
+				local.player = new YT.Player("player", {
+					height: 270,
+					width: 480,
+					videoId: local.currentSong.id,
+					playerVars: {controls: 1, iv_load_policy: 3, rel: 0, showinfo: 0},
+					events: {
+						'onReady': function (event) {
+							local.playerReady = true;
+							if (!local.paused) {
+								local.playVideo();
+							}
+						},
+						'onStateChange': function (event) {
+							if (event.data === 1 && local.videoLoading === true) {
+								local.videoLoading = false;
+								local.player.seekTo(local.getTimeElapsed() / 1000, true);
+							}
+						}
+					}
+				});
+			},
+			startSong: function(song) {
+				var local = this;
+				if (local.playerReady) {
+
+				}
+			},
+			getTimeElapsed: function() {
+				var local = this;
+				if (local.currentSong !== undefined) {
+					return Date.now() - local.currentSong.startedAt - local.timePaused;
+				}
+				return 0;
+			},
+			pauseVideo: function() {
+				var local = this;
+				local.paused = true;
+				if (local.playerReady) {
+					local.player.pauseVideo();
+				}
+			},
+			unpauseVideo: function() {
+				var local = this;
+				local.paused = false;
+				if (local.playerReady) {
+					local.player.seekTo(local.getTimeElapsed() / 1000);
+					local.player.playVideo();
+				}
+			},
+			playVideo: function() {
+				var local = this;
+				if (local.playerReady) {
+					local.videoLoading = true;
+					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;
+
+					if (local.interval !== 0) {
+						clearInterval(local.interval);
+					}
+
+					local.interval = setInterval(function () {
+						local.resizeSeekerbar();
+						local.calculateTimeElapsed();
+					}, 500);
+				}
+			},
+			resizeSeekerbar: function() {
+				var local = this;
+				if (!local.paused) {
+					$(".seeker-bar").width(((local.getTimeElapsed() / 1000) / local.currentSong.duration * 100) + "%");
+				}
+			},
+			calculateTimeElapsed: function() {
+				var local = this;
+				var duration = (Date.now() - local.currentSong.startedAt - local.timePaused) / 1000;
+				var songDuration = local.currentSong.duration;
+				if (songDuration <= duration) {
+					local.player.pauseVideo();
+				}
+				var d = moment.duration(duration, 'seconds');
+				if (!local.paused) {
+					this.timeElapsed = d.minutes() + ":" + ("0" + d.seconds()).slice(-2);
+				}
+			}
+		},
+		ready: function() {
+			var local = this;
+			window.onYouTubeIframeAPIReady = function() {
+				local.youtubeReady();
+			};
+
+			var socket = this.$parent.socket;
+			local.stationSocket = io.connect('http://dev.musare.com/edm');
+			local.stationSocket.on("skippedSong", function(currentSong) {
+				local.currentSong = currentSong;
+				local.playVideo();
+			});
+
+			//TODO Remove this
+			socket.emit("/stations/join/:id", "edm", function(data) {
+				local.currentSong = data.data.currentSong;
+				var tag = document.createElement('script');
+
+				tag.src = "https://www.youtube.com/iframe_api";
+				var firstScriptTag = document.getElementsByTagName('script')[0];
+				firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+			});
+		}
+	}
+</script>
+
 <style lang="sass">
 	.station {
 		flex: 1 0 auto;
@@ -157,6 +290,10 @@
 				height: 100%;
 			}
 		}
+		.video-col {
+			padding-right: 0.75rem;
+			padding-left: 0.75rem;
+		}
 	}
 
 	.room-title {
@@ -204,6 +341,7 @@
 		left: 0;
 		bottom: 0;
 		position: absolute;
+		margin-top: 20px;
 	}
 
 	ul {