Browse Source

Improved private playlists. Added searching, moving songs, renaming and a better UI.

KrisVos130 9 years ago
parent
commit
875ad0a1fe

+ 75 - 7
app/client/scripts/events.js

@@ -1623,6 +1623,23 @@ Template.room.events({
 });
 
 Template.communityStation.events({
+    "click #search-song": function () {
+        var songs = [];
+        Session.set("songResults", songs);
+        $.ajax({
+            type: "GET",
+            url: "https://www.googleapis.com/youtube/v3/search?part=snippet&q=" + $("#song-input").val() + "&key=AIzaSyAgBdacEWrHCHVPPM4k-AFM7uXg-Q__YXY&type=video&maxResults=15",
+            applicationType: "application/json",
+            contentType: "json",
+            success: function (data) {
+                for (var i in data.items) {
+                    var item = data.items[i];
+                    songs.push({title: item.snippet.title, artist: item.snippet.channelTitle, id: item.id.videoId, image: item.snippet.thumbnails.medium.url});
+                }
+                Session.set("songResults", songs);
+            }
+        })
+    },
     "click #logout": function() {
         Meteor.logout();
     },
@@ -1829,11 +1846,16 @@ Template.communityStation.events({
             }
         });
     },
-    "click .edit-playlist-button": function(e) {
-        if ($(e.target).hasClass("edit-playlist-button")) {
-            Session.set("editingPlaylistName", $(e.target).data("playlist"), function(err) {
+    "click #rename-playlist-button": function(e) {
+        var newName = $("#rename-playlist-name").val();
+        var newDisplayName = $("#rename-playlist-display-name").val();
+
+        var playlist = PrivatePlaylists.findOne({owner: Meteor.userId(), name: Session.get("editingPlaylistName")});
+        var currentName = playlist.name;
+        var currentDisplayName = playlist.displayName;
+        if (newName !== currentName) {
+            Meteor.call("renamePrivatePlaylistName", Session.get("editingPlaylistName"), newName, function (err) {
                 if (err) {
-                    console.log(err);
                     var $toastContent = $('<span><strong>Playlist name not changed.</strong> ' + err.reason + '</span>');
                     Materialize.toast($toastContent, 2000);
                 } else {
@@ -1842,9 +1864,20 @@ Template.communityStation.events({
                 }
             });
         }
+        if (newDisplayName !== currentDisplayName) {
+            Meteor.call("renamePrivatePlaylistDisplayName", Session.get("editingPlaylistName"), newDisplayName, function (err) {
+                if (err) {
+                    var $toastContent = $('<span><strong>Playlist display name not changed.</strong> ' + err.reason + '</span>');
+                    Materialize.toast($toastContent, 2000);
+                } else {
+                    var $toastContent = $('<span><strong>Playlist display name changed.</strong></span>');
+                    Materialize.toast($toastContent, 2000);
+                }
+            });
+        }
     },
-    "click #add_playlist_video_submit": function() {
-        var id = $("#add_playlist_video").val();
+    "click .addSong": function(e) {
+        var id = $(e.target).attr("data-result");
         var pp = Session.get("editingPlaylistName");
         Meteor.call("addVideoToPrivatePlaylist", pp, id, function(err) {
             if (err) {
@@ -1858,8 +1891,11 @@ Template.communityStation.events({
         });
         $("#add_playlist_video").val("");
     },
-    "click .remove_playlist_button": function(e) {
+    "click .playlistSongRemove": function(e) {
         var id = $(e.target).data("id");
+        if (id === undefined) {
+            id = $(e.target).parent().data("id");
+        }
         Meteor.call("removeVideoFromPrivatePlaylist", Session.get("editingPlaylistName"), id, function(err) {
             if (err) {
                 console.log(err);
@@ -1871,6 +1907,38 @@ Template.communityStation.events({
             }
         });
     },
+    "click .playlistSongDown": function(e) {
+        var id = $(e.target).attr("data-id");
+        if (id === undefined) {
+            id = $(e.target).parent().attr("data-id");
+        }
+        Meteor.call("moveVideoToBottomOfPrivatePlaylist", Session.get("editingPlaylistName"), id, function(err, res) {
+            if (err) {
+                console.log(err);
+                var $toastContent = $('<span><strong>Video not moved.</strong> ' + err.reason + '</span>');
+                Materialize.toast($toastContent, 2000);
+            } else if (res) {
+                var $toastContent = $('<span><strong>Video moved.</strong></span>');
+                Materialize.toast($toastContent, 2000);
+            }
+        });
+    },
+    "click .playlistSongUp": function(e) {
+        var id = $(e.target).data("id");
+        if (id === undefined) {
+            id = $(e.target).parent().data("id");
+        }
+        Meteor.call("moveVideoToTopOfPrivatePlaylist", Session.get("editingPlaylistName"), id, function(err, res) {
+            if (err) {
+                console.log(err);
+                var $toastContent = $('<span><strong>Video not moved.</strong> ' + err.reason + '</span>');
+                Materialize.toast($toastContent, 2000);
+            } else if (res) {
+                var $toastContent = $('<span><strong>Video moved.</strong></span>');
+                Materialize.toast($toastContent, 2000);
+            }
+        });
+    },
     "click #delete_playlist": function() {
         Meteor.call("deletePrivatePlaylist", Session.get("editingPlaylistName"), function(err) {
             if (err) {

+ 32 - 0
app/client/scripts/helpers.js

@@ -556,6 +556,38 @@ Template.room.helpers({
 });
 
 Template.communityStation.helpers({
+    singleVideoResults: function() {
+        return Session.get("songResults");
+    },
+    singleVideoResultsActive: function() {
+        var songs = Session.get("songResults");
+        if (songs !== undefined && songs.length > 0) {
+            return true;
+        } else {
+            return false;
+        }
+    },
+    hasMoreThanOne: function(array) {
+        if (array.length > 1) {
+            return true;
+        } else {
+            return false;
+        }
+    },
+    isFirst: function(object, array) {
+        if (_.isEqual(array[0], object) && array.length > 1) {
+            return true;
+        } else {
+            return false;
+        }
+    },
+    isLast: function(object, array) {
+        if (_.isEqual(array[array.length - 1], object) && array.length > 1) {
+            return true;
+        } else {
+            return false;
+        }
+    },
     communityStationOwnerName: function() {
         var room = CommunityStations.findOne({name: Session.get("CommunityStationName")});
         if (room !== undefined) {

+ 55 - 8
app/client/templates/communityStation.html

@@ -18,7 +18,9 @@
                 <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-->
-                    <!--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 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>
+                    {{/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>
@@ -194,19 +196,64 @@
     <div id="edit_playlist_modal" class="modal">
         <div class="modal-content">
             <h4>Editing: {{editingPlaylist.name}}</h4>
-            {{#each song in editingPlaylist.songs}}
-                <a href="https://youtube.com/watch?v={{song.id}}" target="_blank">{{song.title}}</a> <span class="red-text remove_playlist_button" data-id={{song.id}} style="cursor: pointer">remove</span><br>
-            {{/each}}
+            <ul class="collection">
+                {{#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>
+                        {{#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>
+                            {{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>
+                                {{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>
+                                {{/if}}
+                            {{/if}}
+                        {{/if}}
+                    </li>
+                {{/each}}
+            </ul>
+            <div class="input-field">
+                <input id="song-input" type="text" class="validate">
+                <label for="search_for_song">Search for song to add</label>
+            </div>
+            <a class="waves-effect waves-light btn" id="search-song"><i class="material-icons left">search</i>Search</a>
+            {{#if singleVideoResultsActive}}
+                <div id="single-video-results">
+                    <div style="overflow: auto; height: 400px; margin-top: 1rem;">
+                        <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">
+                                    <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>
+                                    </p>
+                                    <a href="#" class="secondary-content addSong" data-result="{{result.id}}"><i class="material-icons" data-result="{{result.id}}">add</i></a>
+                                </li>
+                            {{/each}}
+                        </ul>
+                    </div>
+                </div>
+            {{/if}}
+            <br>
+            <div class="input-field">
+                <input id="rename-playlist-name" type="text" class="validate" value={{editingPlaylist.name}}>
+                <label for="rename-playlist-name">Rename playlist name</label>
+            </div>
             <div class="input-field">
-                <input id="add_playlist_video" type="text">
-                <label for="add_playlist_video">Video ID</label>
+                <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" id="add_playlist_video_submit">Add video</button>
-            <button class="btn waves-effect waves-light right red" id="delete_playlist">Delete playlist</button>
+            <button class="btn waves-effect waves-light musare" id="rename-playlist-button">Rename playlist</button>
         </div>
         <div class="divider"></div>
         <div class="modal-footer">
             <a class="modal-action modal-close waves-effect btn">Close</a>
+            <button class="btn waves-effect waves-light left red" id="delete_playlist">Delete playlist</button>
         </div>
     </div>
     <!-- Create Playlist Modal -->

+ 94 - 1
app/server/server.js

@@ -974,7 +974,6 @@ Meteor.updatedMethods({
                     }
                 });
                 if (!copy) {
-                    console.log(getSongDataYT(id));
                     var data = getSongDataYT(id);
                     data.id = id;
                     PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$push: {songs: data}});
@@ -1010,6 +1009,70 @@ Meteor.updatedMethods({
         },
         requirements: ["login"]
     },
+    moveVideoToTopOfPrivatePlaylist: {
+        code: function(name, id) {
+            var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name});
+            if (pl !== undefined) {
+                var songs = pl.songs;
+                var song;
+                songs.forEach(function(currentSong) {
+                    if (id === currentSong.id) {
+                        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: {
+                            songs: {
+                                $each: [song],
+                                $position: 0
+                            }
+                        }});
+                        return true;
+                    } else {
+                        return false;
+                    }
+                } else {
+                    throw new Meteor.Error(404, "Song not found.");
+                }
+            } else {
+                throw new Meteor.Error(404, "Playlist not found.");
+            }
+        },
+        requirements: ["login"]
+    },
+    moveVideoToBottomOfPrivatePlaylist: {
+        code: function(name, id) {
+            var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name});
+            if (pl !== undefined) {
+                var songs = pl.songs;
+                var song;
+                songs.forEach(function(currentSong) {
+                    if (id === currentSong.id) {
+                        song = currentSong;
+                    }
+                });
+                if (song !== undefined) {
+                    var index = songs.indexOf(song);
+                    if (index < (songs.length - 1) && index !== -1) {
+                        PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$pull: {songs: song}});
+                        PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$push: {songs: song}});
+                        return true;
+                    }
+                } else {
+                    throw new Meteor.Error(404, "Song not found.");
+                }
+            } else {
+                throw new Meteor.Error(404, "Playlist not found.");
+            }
+        },
+        requirements: ["login"]
+    },
     deletePrivatePlaylist: {
         code: function(name) {
             var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name});
@@ -1022,6 +1085,36 @@ Meteor.updatedMethods({
         },
         requirements: ["login"]
     },
+    renamePrivatePlaylistDisplayName: {
+        code: function(name, newDisplayName) {
+            var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name});
+            if (pl !== undefined) {
+                if (PrivatePlaylists.findOne({owner: Meteor.userId(), displayName: newDisplayName}) === undefined) {
+                    PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$set: {displayName: newDisplayName}});
+                } else {
+                    throw new Meteor.Error(500, "A playlist with that display name already exists.");
+                }
+            } else {
+                throw new Meteor.Error(404, "Playlist not found.");
+            }
+        },
+        requirements: ["login"]
+    },
+    renamePrivatePlaylistName: {
+        code: function(name, newName) {
+            var pl = PrivatePlaylists.findOne({owner: Meteor.userId(), name: name});
+            if (pl !== undefined) {
+                if (PrivatePlaylists.findOne({owner: Meteor.userId(), name: newName}) === undefined) {
+                    PrivatePlaylists.update({owner: Meteor.userId(), name: name}, {$set: {name: newName}});
+                } else {
+                    throw new Meteor.Error(500, "A playlist with that name already exists.");
+                }
+            } else {
+                throw new Meteor.Error(404, "Playlist not found.");
+            }
+        },
+        requirements: ["login"]
+    },
     activateAlert: {
         code: function(id) {
             Alerts.update(id, {$set: {active: true}});