2
0
Эх сурвалжийг харах

Worked on party mode logic.

KrisVos130 8 жил өмнө
parent
commit
ee2293f2bf

+ 11 - 1
app/client/scripts/helpers.js

@@ -556,10 +556,20 @@ Template.room.helpers({
 });
 
 Template.communityStation.helpers({
+    noCurrentSong: function() {
+        return Session.get("noCurrentSong");
+    },
+    noCurrentSongHidden: function() {
+        if (Session.get("noCurrentSong")) {
+            return "hidden";
+        } else {
+            return "";
+        }
+    },
     partyModeChecked: function() {
         var name = Session.get("CommunityStationName");
         var room = CommunityStations.findOne({name: name});
-        if (room.partyModeEnabled === true) {
+        if (room !== undefined && room.partyModeEnabled === true) {
             return "checked";
         } else {
             return "";

+ 17 - 10
app/client/scripts/onCreated.js

@@ -431,11 +431,11 @@ Template.communityStation.onCreated(function () {
         $("#time-elapsed").text("0:00");
         $("#vote-skip").attr("disabled", false);
         if (currentSong !== undefined) {
-            if (YTPlayer !== undefined && YTPlayer.stopVideo !== undefined) YTPlayer.stopVideo();
+            if (YTPlayer !== undefined && YTPlayer.stopVideo !== undefined && YTPlayer.getPlayerState() === YT.PlayerState.PLAYING) YTPlayer.stopVideo();
 
             var volume = localStorage.getItem("volume") || 20;
-            $("#volume_slider").val(volume);
 
+            $("#volume_slider").val(volume);
             $("#player").show();
             function loadVideo() {
                 if (!Session.get("YTLoaded")) {
@@ -469,7 +469,7 @@ Template.communityStation.onCreated(function () {
                                     },
                                     'onStateChange': function (event) {
                                         if (Session.get("YTLoaded")) {
-                                            if (event.data == YT.PlayerState.PAUSED && Session.get("state") === "playing") {
+                                            if (event.data == YT.PlayerState.PAUSED && Session.get("state") === "playing" && !Session.get("noCurrentSong")) {
                                                 event.target.seekTo(getTimeElapsed() / 1000);
                                                 event.target.playVideo();
                                             }
@@ -521,7 +521,7 @@ Template.communityStation.onCreated(function () {
                         }
                     } else {
                         Session.set("state", "playing");
-                        if (YTPlayer !== undefined && YTPlayer.getPlayerState !== undefined && YTPlayer.getPlayerState() !== 1) {
+                        if (YTPlayer !== undefined && YTPlayer.getPlayerState !== undefined && YTPlayer.getPlayerState() !== 1 && !Session.get("noCurrentSong")) {
                             YTPlayer.playVideo();
                         }
                     }
@@ -531,14 +531,21 @@ Template.communityStation.onCreated(function () {
                     Session.set("previousSong", currentSong);
                     currentSongR = room.currentSong;
 
-                    currentSong = room.currentSong.song;
-                    currentSong.started = room.currentSong.started;
-                    Session.set("currentSong", currentSong);
-                    Meteor.clearTimeout(Session.get("loadVideoTimeout"));
-                    startSong();
+                    if (!_.isEqual(currentSongR, {})) {
+                        Session.set("noCurrentSong", false);
+                        currentSong = room.currentSong.song;
+                        currentSong.started = room.currentSong.started;
+                        Session.set("currentSong", currentSong);
+                        Meteor.clearTimeout(Session.get("loadVideoTimeout"));
+                        startSong();
+                    } else {
+                        if (YTPlayer !== undefined && YTPlayer.stopVideo !== undefined && YTPlayer.getPlayerState() === YT.PlayerState.PLAYING) YTPlayer.stopVideo();
+                        document.title = "Musare";
+                        Session.set("noCurrentSong", true);
+                    }
                 }
 
-                if (currentSong !== undefined) {
+                if (currentSong !== undefined && !Session.get("noCurrentSong")) {
                     if (room !== undefined) {
                         var duration = (Date.now() - currentSong.started - room.timePaused) / 1000;
                         var song_duration = currentSong.duration;

+ 5 - 0
app/client/stylesheets/app.css

@@ -491,3 +491,8 @@ input[type=range]::-moz-range-thumb {
 input[type=range]::-ms-thumb {
   background: rgb(3, 169, 244);
 }
+
+.hidden {
+    display: none;
+    height: 0;
+}

+ 82 - 44
app/client/templates/communityStation.html

@@ -3,28 +3,48 @@
         <nav>
             <div class="nav-wrapper light-blue accent-4">
                 <ul class="left hide-on-med-and-down">
-                    <li><a style="margin-left: 0px; padding-left: 20px; padding-right: 20px;" href="/" class="brand-logo">Musare</a></li>
+                    <li><a style="margin-left: 0px; padding-left: 20px; padding-right: 20px;" href="/"
+                           class="brand-logo">Musare</a></li>
                     <!--li><a id="vote-skip" class="tooltipped" data-position="bottom" data-delay="50" data-tooltip="Vote to skip this song"><i class="material-icons left">skip_next</i>{{votes}}</a></li-->
                     {{#if isCommunityStationOwner name}}
                         {{#if playing}}
-                            <li style="margin-left: 144px;"><a id="pause" data-position="bottom" data-delay="50" data-tooltip="Pause this room" data-activates="chat-slide-out" class="tooltipped"><i class="material-icons">pause</i></a></li>
+                            <li style="margin-left: 144px;"><a id="pause" data-position="bottom" data-delay="50"
+                                                               data-tooltip="Pause this room"
+                                                               data-activates="chat-slide-out" class="tooltipped"><i
+                                    class="material-icons">pause</i></a></li>
                         {{else}}
-                            <li style="margin-left: 144px;"><a id="play" data-position="bottom" data-delay="50" data-tooltip="Play this room" data-activates="chat-slide-out" class="tooltipped"><i class="material-icons">play_arrow</i></a></li>
+                            <li style="margin-left: 144px;"><a id="play" data-position="bottom" data-delay="50"
+                                                               data-tooltip="Play this room"
+                                                               data-activates="chat-slide-out" class="tooltipped"><i
+                                    class="material-icons">play_arrow</i></a></li>
                         {{/if}}
-                        <li><a id="skip" data-position="bottom" data-delay="50" data-tooltip="Skip this song" data-activates="chat-slide-out" class="tooltipped"><i class="material-icons">skip_next</i></a></li>
-                        <li><a id="edit_room" href="#edit_room_modal" data-position="bottom" data-delay="50" data-tooltip="Edit this room" data-activates="chat-slide-out" class="tooltipped"><i class="material-icons">settings</i></a></li>
+                        <li><a id="skip" data-position="bottom" data-delay="50" data-tooltip="Skip this song"
+                               data-activates="chat-slide-out" class="tooltipped"><i
+                                class="material-icons">skip_next</i></a></li>
+                        <li><a id="edit_room" href="#edit_room_modal" data-position="bottom" data-delay="50"
+                               data-tooltip="Edit this room" data-activates="chat-slide-out" class="tooltipped"><i
+                                class="material-icons">settings</i></a></li>
                     {{/if}}
                 </ul>
-                <span class="brand-logo center">{{communityStationDisplayName}} <small>(by {{communityStationOwnerName}})</small></span>
+                <span class="brand-logo center">{{communityStationDisplayName}}
+                    <small>(by {{communityStationOwnerName}})</small></span>
                 <ul class="right hide-on-med-and-down">
                     <!--li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Playlist" id="playlist-slideout" data-activates="playlist-slide-out" class="tooltipped header-collapse"><i class="material-icons">queue_music</i></a></li-->
                     {{#if isLoggedIn}}
-                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Chat" id="chat-slideout" data-activates="chat-slide-out" class="tooltipped header-collapse"><i class="material-icons">chat</i></a></li>
+                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Chat" id="chat-slideout"
+                               data-activates="chat-slide-out" class="tooltipped header-collapse"><i
+                                class="material-icons">chat</i></a></li>
                     {{/if}}
                     {{#if isCommunityStationOwner name}}
-                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Users" id="users-slideout" data-activates="users-slide-out" class="tooltipped header-collapse"><i class="material-icons">people</i></a></li>
-                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Allowed" id="allowed-slideout" data-activates="allowed-slide-out" class="tooltipped header-collapse"><i class="material-icons">assignment</i></a></li>
-                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Playlists" id="playlists-slideout" data-activates="playlists-slide-out" class="tooltipped header-collapse"><i class="material-icons">library_music</i></a></li>
+                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Users" id="users-slideout"
+                               data-activates="users-slide-out" class="tooltipped header-collapse"><i
+                                class="material-icons">people</i></a></li>
+                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Allowed"
+                               id="allowed-slideout" data-activates="allowed-slide-out"
+                               class="tooltipped header-collapse"><i class="material-icons">assignment</i></a></li>
+                        <li><a href="#" data-position="bottom" data-delay="50" data-tooltip="Playlists"
+                               id="playlists-slideout" data-activates="playlists-slide-out"
+                               class="tooltipped header-collapse"><i class="material-icons">library_music</i></a></li>
                     {{/if}}
                 </ul>
             </div>
@@ -33,25 +53,28 @@
     {{> alerts}}
     <main id="room-content">
         <div class="container room-container">
-            <div class="row">
+            {{#if noCurrentSong}}
+                No current song. Please add a song to the queue!
+            {{/if}}
+            <div class="row {{noCurrentSongHidden}}">
                 <div class="col s12 m10 l8 offset-l2 offset-m1" id="media-container">
                     <div class="video-container">
                         <div id="player"></div>
                     </div>
                 </div>
                 <div class="col s12 m10 l8 offset-l2 offset-m1">
-                  <h4 id="time-display"><span id="time-elapsed"></span> / <span id="time-total"></span></h4>
-                  <h3>{{{title}}}</h3>
-                  <div class="row">
-                      <form action="#" class="left col s4 m4 l4">
-                          <p class="range-field" style="margin-top: 0">
-                              <input type="range" id="volume_slider" min="0" max="100"/>
-                          </p>
-                      </form>
-                  </div>
-                  <div class="seeker-bar-container white" id="preview-progress">
-                      <div class="seeker-bar light-blue" style="width: 0%"></div>
-                  </div>
+                    <h4 id="time-display"><span id="time-elapsed"></span> / <span id="time-total"></span></h4>
+                    <h3>{{{title}}}</h3>
+                    <div class="row">
+                        <form action="#" class="left col s4 m4 l4">
+                            <p class="range-field" style="margin-top: 0">
+                                <input type="range" id="volume_slider" min="0" max="100"/>
+                            </p>
+                        </form>
+                    </div>
+                    <div class="seeker-bar-container white" id="preview-progress">
+                        <div class="seeker-bar light-blue" style="width: 0%"></div>
+                    </div>
                 </div>
             </div>
         </div>
@@ -64,7 +87,9 @@
                 {{#emojione}}
                     <li class="chat-message" style="line-height: 30px">
                         <span title="{{time}}" style="float: right; margin-top: 15px">{{rtime time}}</span>
-                        <a style="text-decoration: none; font-size: 0.9em; height: 0.9em; font-weight: 500" href="/u/{{this.username}}" target="_blank"><span class="rank-{{this.rawrank}}">{{this.rank}}</span>{{this.username}}</a>
+                        <a style="text-decoration: none; font-size: 0.9em; height: 0.9em; font-weight: 500"
+                           href="/u/{{this.username}}" target="_blank"><span
+                                class="rank-{{this.rawrank}}">{{this.rank}}</span>{{this.username}}</a>
                         <p style="clear: both; line-height: 1.2em; margin-left: 13px; margin-bottom: 0; font-size: 1.2em">{{{this.message}}}</p>
                     </li>
                 {{/emojione}}
@@ -104,9 +129,11 @@
         </ul>
 
         {{#if currentUser}}
-            <a class="btn btn-block musare white-text waves-effect waves-light" href="#" id="logout" style="position: fixed; bottom: 0; width: 342px;">Logout</a>
+            <a class="btn btn-block musare white-text waves-effect waves-light" href="#" id="logout"
+               style="position: fixed; bottom: 0; width: 342px;">Logout</a>
         {{else}}
-            <a class="btn btn-block musare white-text waves-effect waves-light" href="/login" style="position: fixed; bottom: 0; width: 342px;">Login / Register</a>
+            <a class="btn btn-block musare white-text waves-effect waves-light" href="/login"
+               style="position: fixed; bottom: 0; width: 342px;">Login / Register</a>
         {{/if}}
     </div>
 
@@ -127,15 +154,15 @@
             {{/each}}
         </ul>
         {{#if isCommunityStationOwner name}}
-        <div>
-            <div class="row" id="chat-input-div">
-                <div class="input-field col s12">
-                    <input id="add-allowed" type="text">
-                    <label for="add-allowed">Add user</label>
+            <div>
+                <div class="row" id="chat-input-div">
+                    <div class="input-field col s12">
+                        <input id="add-allowed" type="text">
+                        <label for="add-allowed">Add user</label>
+                    </div>
                 </div>
+                <a id="add-allowed-submit" class="waves-effect waves-light btn">Add</a>
             </div>
-            <a id="add-allowed-submit" class="waves-effect waves-light btn">Add</a>
-        </div>
         {{/if}}
     </div>
 
@@ -151,7 +178,8 @@
                                 {{#if isPlaylistSelected name this.name}}
                                     <i class="material-icons" style="line-height: 64px;">check_circle</i>
                                 {{else}}
-                                    <i class="material-icons" data-playlist={{this.name}} style="line-height: 64px;" title="Select playlist">panorama_fish_eye</i>
+                                    <i class="material-icons" data-playlist={{this.name}} style="line-height: 64px;"
+                                    title="Select playlist">panorama_fish_eye</i>
                                 {{/if}}
                             {{/if}}
                         </a>
@@ -160,7 +188,8 @@
             {{/each}}
         </ul>
         <div>
-            <a id="add-playlist-modal-button" class="waves-effect waves-light btn" href="#create_playlist_modal">Create Playlist</a>
+            <a id="add-playlist-modal-button" class="waves-effect waves-light btn" href="#create_playlist_modal">Create
+                Playlist</a>
         </div>
     </div>
 
@@ -204,16 +233,21 @@
                 {{#each song in editingPlaylist.songs}}
                     <li class="collection-item">
                         <a href="https://youtube.com/watch?v={{song.id}}" target="_blank">{{song.title}}</a>
-                        <a href="#" class="secondary-content playlistSongRemove" data-id={{song.id}}><i class="material-icons" data-id={{song.id}}>delete</i></a>
+                        <a href="#" class="secondary-content playlistSongRemove" data-id={{song.id}}><i
+                                class="material-icons" data-id={{song.id}}>delete</i></a>
                         {{#if hasMoreThanOne editingPlaylist.songs}}
                             {{#if isFirst song editingPlaylist.songs}}
-                                <a href="#" class="secondary-content playlistSongDown" data-id={{song.id}}><i class="material-icons" data-id={{song.id}}>keyboard_arrow_down</i></a>
+                                <a href="#" class="secondary-content playlistSongDown" data-id={{song.id}}><i
+                                        class="material-icons" data-id={{song.id}}>keyboard_arrow_down</i></a>
                             {{else}}
                                 {{#if isLast song editingPlaylist.songs}}
-                                    <a href="#" class="secondary-content playlistSongUp" data-id={{song.id}}><i class="material-icons" data-id={{song.id}}>keyboard_arrow_up</i></a>
+                                    <a href="#" class="secondary-content playlistSongUp" data-id={{song.id}}><i
+                                            class="material-icons" data-id={{song.id}}>keyboard_arrow_up</i></a>
                                 {{else}}
-                                    <a href="#" class="secondary-content playlistSongDown" data-id={{song.id}}><i class="material-icons" data-id={{song.id}}>keyboard_arrow_down</i></a>
-                                    <a href="#" class="secondary-content playlistSongUp" data-id={{song.id}}><i class="material-icons" data-id={{song.id}}>keyboard_arrow_up</i></a>
+                                    <a href="#" class="secondary-content playlistSongDown" data-id={{song.id}}><i
+                                            class="material-icons" data-id={{song.id}}>keyboard_arrow_down</i></a>
+                                    <a href="#" class="secondary-content playlistSongUp" data-id={{song.id}}><i
+                                            class="material-icons" data-id={{song.id}}>keyboard_arrow_up</i></a>
                                 {{/if}}
                             {{/if}}
                         {{/if}}
@@ -231,12 +265,15 @@
                         <ul class="collection light-blue-text">
                             {{#each result in singleVideoResults}}
                                 <li class="collection-item avatar youtube-search-result-li">
-                                    <img src="{{result.image}}" onerror="this.src='/notes.png'" alt="" class="video-import-thumbnail">
+                                    <img src="{{result.image}}" onerror="this.src='/notes.png'" alt=""
+                                         class="video-import-thumbnail">
                                     <span class="title video-import-text">{{result.title}}</span>
                                     <p class="video-import-text">{{result.artist}} <br>
-                                        <a href="https://youtube.com/watch?v={{result.id}}" target="_blank">View Video In YouTube</a>
+                                        <a href="https://youtube.com/watch?v={{result.id}}" target="_blank">View Video
+                                            In YouTube</a>
                                     </p>
-                                    <a href="#" class="secondary-content addSong" data-result="{{result.id}}"><i class="material-icons" data-result="{{result.id}}">add</i></a>
+                                    <a href="#" class="secondary-content addSong" data-result="{{result.id}}"><i
+                                            class="material-icons" data-result="{{result.id}}">add</i></a>
                                 </li>
                             {{/each}}
                         </ul>
@@ -249,7 +286,8 @@
                 <label for="rename-playlist-name">Rename playlist name</label>
             </div>
             <div class="input-field">
-                <input id="rename-playlist-display-name" type="text" class="validate" value={{editingPlaylist.displayName}}>
+                <input id="rename-playlist-display-name" type="text" class="validate"
+                       value={{editingPlaylist.displayName}}>
                 <label for="rename-playlist-display-name">Rename playlist display name</label>
             </div>
             <button class="btn waves-effect waves-light musare" id="rename-playlist-button">Rename playlist</button>

+ 25 - 1
app/lib/schemas.js

@@ -288,7 +288,8 @@ Schemas.CommunityStation = new SimpleSchema({
     currentSong: {
         type: Object,
         defaultValue: {song: {id: "60ItHLz5WEA", duration: 213, title: "Alan Walker - Faded"}, started: 0},
-        label: "Current Song Object"
+        label: "Current Song Object",
+        blackbox: true
     },
     "currentSong.song": {
         type: Schemas.UserSong,
@@ -298,6 +299,11 @@ Schemas.CommunityStation = new SimpleSchema({
         type: Number,
         label: "Current Song Start Date"
     },
+    "currentSong.requestedBy": {
+        type: String,
+        label: "Current Song requested by",
+        optional: true
+    },
     timePaused: {
         type: Number,
         defaultValue: 0,
@@ -367,6 +373,24 @@ Schemas.CommunityStation = new SimpleSchema({
         type: Boolean,
         label: "Party mode",
         defaultValue: false
+    },
+    queue: {
+        type: Array,
+        label: "Community station queue",
+        defaultValue: []
+    },
+    "queue.$": {
+        type: new SimpleSchema({
+            song: {
+                type: Schemas.UserSong,
+                label: "Queue song object"
+            },
+            requestedBy: {
+                type: String,
+                label: "User id of person who added song to queue"
+            }
+        }),
+        label: "Queue song"
     }
 });
 

+ 171 - 53
app/server/server.js

@@ -124,6 +124,7 @@ function getStation(type, cb) {
             return;
         }
     });
+    //TODO Return error
 }
 
 function getCommunityStation(name, cb) {
@@ -133,6 +134,7 @@ function getCommunityStation(name, cb) {
             return;
         }
     });
+    //TODO Return error
 }
 
 function createRoom(display, tag, private, desc) {
@@ -407,6 +409,11 @@ function CommunityStation(name) {
         }
         return undefined;
     });
+
+    this.isPartyModeEnabled = function() {
+        return CommunityStations.findOne({name: name}).partyModeEnabled;
+    };
+
     var self = this;
     var startedAt = Date.now();
     var _room = CommunityStations.findOne({name: name});
@@ -429,38 +436,87 @@ function CommunityStation(name) {
     if (song === undefined) {
         song = {id: "60ItHLz5WEA", duration: 213, title: "Alan Walker - Faded"};
     }
-    var res = CommunityStations.update({name: name}, {
-        $set: {
-            currentSong: {song: song, started: startedAt},
-            users: 0
-        }
-    });
+    if (this.isPartyModeEnabled()) {
+        var res = CommunityStations.update({name: name}, {
+            $set: {
+                users: 0
+            }
+        });
+    } else {
+        var res = CommunityStations.update({name: name}, {
+            $set: {
+                currentSong: {song: song, started: startedAt},
+                users: 0
+            }
+        });
+    }
+
+    var queue = _room.queue;
 
     this.skipSong = function () {
         self.voted = [];
         voteNum = 0;
         CommunityStations.update({name: name}, {$set: {votes: 0}});
-        playlist = PrivatePlaylists.findOne({name: _room.playlist, owner: _room.owner});
-        if (playlist === undefined) {
-            playlist = default_private_playlist;
-        }
-        if (playlist !== undefined && playlist.songs.length === 0) {
-            CommunityStations.update({name: name}, {$unset: {"playlist": 1}});
-            playlist = default_private_playlist;
-        }
-        songs = playlist.songs;
-        songs.forEach(function (id, index) {
-            if (id === currentId) {
-                currentSong = index;
+        //TODO Party mode
+
+        if (this.isPartyModeEnabled()) {
+            var queue = CommunityStations.findOne({name: name}).queue;
+            if (queue.length > 0) {
+                CommunityStations.update({name: name}, {$pop: {queue: -1}});
+                queue.shift();
+
+                if (queue.length > 0) {
+                    CommunityStations.update({name: name}, {
+                        $set: {
+                            currentSong: {
+                                song: queue[0].song,
+                                requestedBy: queue[0].requestedBy,
+                                started: startedAt
+                            }
+                        }
+                    });
+
+                    CommunityStations.update({name: name}, {$set: {timePaused: 0}});
+                    this.songTimer();
+                } else {
+                    CommunityStations.update({name: name}, {
+                        $set: {
+                            currentSong: {},
+                            timePaused: 0
+                        }
+                    });
+                }
             }
-        });
-        if (currentSong < (songs.length - 1)) {
-            currentSong++;
-        } else currentSong = 0;
-        currentId = songs[currentSong];
-        CommunityStations.update({name: name}, {$set: {timePaused: 0}});
-        this.songTimer();
-        CommunityStations.update({name: name}, {$set: {currentSong: {song: songs[currentSong], started: startedAt}}});
+        } else {
+            playlist = PrivatePlaylists.findOne({name: _room.playlist, owner: _room.owner});
+            if (playlist === undefined) {
+                playlist = default_private_playlist;
+            }
+            if (playlist !== undefined && playlist.songs.length === 0) {
+                CommunityStations.update({name: name}, {$unset: {"playlist": 1}});
+                playlist = default_private_playlist;
+            }
+            songs = playlist.songs;
+            songs.forEach(function (id, index) {
+                if (id === currentId) {
+                    currentSong = index;
+                }
+            });
+            if (currentSong < (songs.length - 1)) {
+                currentSong++;
+            } else currentSong = 0;
+            currentId = songs[currentSong];
+            CommunityStations.update({name: name}, {$set: {timePaused: 0}});
+            this.songTimer();
+            CommunityStations.update({name: name}, {
+                $set: {
+                    currentSong: {
+                        song: songs[currentSong],
+                        started: startedAt
+                    }
+                }
+            });
+        }
     };
 
     CommunityStations.update({name: name}, {$set: {timePaused: 0}});
@@ -476,9 +532,15 @@ function CommunityStation(name) {
                 timer.pause();
             }
             timerInitialised = true;
-            timer = new Timer(function () {
-                self.skipSong();
-            }, songs[currentSong].duration * 1000);
+            if (this.isPartyModeEnabled()) {
+                timer = new Timer(function () {
+                    self.skipSong();
+                }, queue[0].song.duration * 1000);
+            } else {
+                timer = new Timer(function () {
+                    self.skipSong();
+                }, songs[currentSong].duration * 1000);
+            }
         }
     };
 
@@ -486,7 +548,9 @@ function CommunityStation(name) {
 
     this.pauseRoom = function () {
         if (state !== "paused") {
-            timer.pause();
+            if (timer !== undefined) {
+                timer.pause();
+            }
             CommunityStations.update({name: name}, {$set: {state: "paused"}});
             state = "paused";
         }
@@ -494,12 +558,24 @@ function CommunityStation(name) {
     this.resumeRoom = function () {
         if (state !== "playing") {
             if (!timerInitialised) {
-                timer = new Timer(function () {
-                    self.skipSong();
-                }, songs[currentSong] * 1000);
+                if (this.isPartyModeEnabled()) {
+                    if (queue.length > 0) {
+                        timer = new Timer(function () {
+                            self.skipSong();
+                        }, queue[0].song.duration * 1000);
+                    }
+                } else {
+                    timer = new Timer(function () {
+                        self.skipSong();
+                    }, songs[currentSong].duration * 1000);
+                }
+            }
+            if (timer !== undefined) {
+                timer.resume();
+                CommunityStations.update({name: name}, {$set: {state: "playing", timePaused: timer.timeWhenPaused()}});
+            } else {
+                CommunityStations.update({name: name}, {$set: {state: "playing"}});
             }
-            timer.resume();
-            CommunityStations.update({name: name}, {$set: {state: "playing", timePaused: timer.timeWhenPaused()}});
             state = "playing";
         }
     };
@@ -546,6 +622,51 @@ function CommunityStation(name) {
         }
     };
 
+    this.setPartyMode = function(partyMode) {
+        partyMode = (typeof partyMode === "boolean") ? partyMode : false;
+        CommunityStations.update({name: name}, {
+            $set: {
+                partyModeEnabled: partyMode,
+                currentSong: {}
+            }
+        });
+    };
+
+    this.addSongToQueue = function(id, userId) {
+        var duplicate = false;
+        queue = CommunityStations.findOne({name: name}).queue;
+        queue.forEach(function(song) {
+            if (song.song.id === id) {
+                duplicate = true;
+            }
+        });
+        if (!duplicate) {
+            var data = getSongDataYT(id);
+            if (data !== 0) {
+                data.id = id;
+                CommunityStations.update({name: name}, {$push: {queue: {requestedBy: userId, song: data}}});
+                queue = CommunityStations.findOne({name: name}).queue;
+                if (queue.length === 1) {
+                    CommunityStations.update({name: name}, {
+                        $set: {
+                            timePaused: 0,
+                            currentSong: {
+                                song: queue[0].song,
+                                requestedBy: queue[0].requestedBy,
+                                started: Date.now()
+                            }
+                        }
+                    });
+                    this.songTimer();
+                }
+            } else {
+                throw new Meteor.Error(500, "Invalid song id.");
+            }
+        } else {
+            throw new Meteor.Error(500, "This song is already in the queue.");
+        }
+    };
+
     this.skipSong();
     this.voted = [];
 }
@@ -818,19 +939,6 @@ Meteor.publish("chat", function () {
 
 Meteor.publish("userProfiles", function (username) {
     username = username.toLowerCase();
-    console.log(username);
-    console.log(Meteor.users.find({"profile.usernameL": username}, {
-        fields: {
-        "profile.username": 1,
-        "profile.usernameL": 1,
-        "profile.rank": 1,
-        createdAt: 1,
-        "profile.liked": 1,
-        "profile.disliked": 1,
-        "profile.settings": 1,
-        "profile.realname": 1
-        }
-    }).fetch());
     var settings = Meteor.users.findOne({"profile.usernameL": username}, {fields: {"profile.settings": 1}});
     if (settings !== undefined && settings.profile.settings) {
         settings = settings.profile.settings;
@@ -965,12 +1073,25 @@ Meteor.updatedMethods({
     },
     setCommunityStationPartyMode: function(roomName, partyMode) {
         if ((isAdmin() || isCommunityStationOwner(roomName)) && !isBanned()) {
-            partyMode = (typeof partyMode === "boolean") ? partyMode : false;
-            CommunityStations.update({name: roomName}, {$set: {partyModeEnabled: partyMode}});
+            getCommunityStation(roomName, function(room) {
+                if (room !== 0) {
+                    room.setPartyMode(partyMode);
+                } else {
+                    throw new Meteor.Error(500, "Room not found.");
+                }
+            });
         } else {
             throw new Meteor.Error(403, "Invalid permissions.");
         }
     },
+    addSongToCommunityStationQueue: {
+        code: function(name, id) {
+            getCommunityStation(name, function(station) {
+                station.addSongToQueue(id, Meteor.userId());
+            });
+        },
+        requirements: ["login"]
+    },
     addVideoToPrivatePlaylist: {
         code: function(name, id) {
             var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name});
@@ -1028,11 +1149,8 @@ Meteor.updatedMethods({
                         song = currentSong;
                     }
                 });
-                console.log(song);
                 if (song !== undefined) {
                     var index = songs.indexOf(song);
-                    console.log(index);
-                    console.log(songs.length - 1);
                     if (index > 0 && songs.length > 1) {
                         PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$pull: {songs: song}});
                         PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$push: {

+ 1 - 0
app/server/updateDatabase.js

@@ -1,3 +1,4 @@
 Meteor.startup(function() {
     CommunityStations.update({partyModeEnabled: {$exists: false}}, {$set: {partyModeEnabled: false}});
+    CommunityStations.update({queue: {$exists: false}}, {$set: {queue: []}});
 });