Browse Source

Added play mode to station

Kristian Vos 4 years ago
parent
commit
0494b2ddf1

+ 79 - 0
backend/logic/actions/stations.js

@@ -752,6 +752,7 @@ export default {
 						privacy: station.privacy,
 						locked: station.locked,
 						partyMode: station.partyMode,
+						playMode: station.playMode,
 						owner: station.owner,
 						// privatePlaylist: station.privatePlaylist,
 						includedPlaylists: station.includedPlaylists,
@@ -878,6 +879,7 @@ export default {
 						privacy: station.privacy,
 						locked: station.locked,
 						partyMode: station.partyMode,
+						playMode: station.playMode,
 						owner: station.owner,
 						// privatePlaylist: station.privatePlaylist,
 						// genres: station.genres,
@@ -2029,6 +2031,83 @@ export default {
 		);
 	}),
 
+	/**
+	 * Updates a station's play mode
+	 *
+	 * @param session
+	 * @param stationId - the station id
+	 * @param newPlayMode - the new station play mode
+	 * @param cb
+	 */
+	updatePlayMode: isOwnerRequired(async function updatePartyMode(session, stationId, newPlayMode, cb) {
+		const stationModel = await DBModule.runJob("GET_MODEL", { modelName: "station" }, this);
+
+		async.waterfall(
+			[
+				next => {
+					StationsModule.runJob("GET_STATION", { stationId }, this)
+						.then(station => {
+							next(null, station);
+						})
+						.catch(next);
+				},
+
+				(station, next) => {
+					if (!station) return next("Station not found.");
+					if (station.newPlayMode === newPlayMode) return next(`The play mode was already ${newPlayMode}`);
+					return stationModel.updateOne(
+						{ _id: stationId },
+						{ $set: { playMode: newPlayMode, queue: [] } },
+						{ runValidators: true },
+						next
+					);
+				},
+
+				(res, next) => {
+					CacheModule.runJob("PUB", {
+						channel: "station.queueUpdate",
+						value: stationId
+					})
+						.then()
+						.catch();
+					StationsModule.runJob("UPDATE_STATION", { stationId }, this)
+						.then(station => {
+							next(null, station);
+						})
+						.catch(next);
+				}
+			],
+			async err => {
+				if (err) {
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
+						"ERROR",
+						"STATIONS_UPDATE_PLAY_MODE",
+						`Updating station "${stationId}" play mode to "${newPlayMode}" failed. "${err}"`
+					);
+					return cb({ status: "failure", message: err });
+				}
+				this.log(
+					"SUCCESS",
+					"STATIONS_UPDATE_PLAY_MODE",
+					`Updated station "${stationId}" play mode to "${newPlayMode}" successfully.`
+				);
+				CacheModule.runJob("PUB", {
+					channel: "station.newPlayMode",
+					value: {
+						stationId,
+						playMode: newPlayMode
+					}
+				});
+				StationsModule.runJob("SKIP_STATION", { stationId });
+				return cb({
+					status: "success",
+					message: "Successfully updated the play mode."
+				});
+			}
+		);
+	}),
+
 	/**
 	 * Updates a station's theme
 	 *

+ 45 - 23
backend/logic/stations.js

@@ -479,51 +479,73 @@ class _StationsModule extends CoreClass {
 					},
 
 					(playlist, next) => {
-						UtilsModule.runJob("SHUFFLE", { array: playlist.songs }, this)
-							.then(response => {
-								next(null, response.array);
-							})
-							.catch(next);
-					},
-
-					(playlistSongs, next) => {
 						StationsModule.runJob("GET_STATION", { stationId }, this)
 							.then(station => {
-								next(null, playlistSongs, station);
+								next(null, playlist, station);
 							})
 							.catch(next);
 					},
 
-					(playlistSongs, station, next) => {
+					(playlist, station, next) => {
+						if (station.playMode === "random") {
+							UtilsModule.runJob("SHUFFLE", { array: playlist.songs }, this)
+								.then(response => {
+									next(null, response.array, station);
+								})
+								.catch(console.log);
+						} else next(null, playlist.songs, station);
+					},
+
+					(_playlistSongs, station, next) => {
+						let playlistSongs = JSON.parse(JSON.stringify(_playlistSongs));
+						if (station.playMode === "sequential") {
+							if (station.currentSongIndex <= playlistSongs.length) {
+								const songsToAddToEnd = playlistSongs.splice(0, station.currentSongIndex);
+								playlistSongs = [...playlistSongs, ...songsToAddToEnd];
+							}
+						}
+
 						const songsStillNeeded = 50 - station.queue.length;
 						const currentSongs = station.queue;
 						const currentSongIds = station.queue.map(song => song.songId);
 						const songsToAdd = [];
+						let lastSongAdded = null;
 
 						playlistSongs
-							.map(song => song._doc)
+							// .map(song => song._doc)
 							.every(song => {
+								console.log(11, song, playlistSongs);
 								if (
 									songsToAdd.length < songsStillNeeded &&
 									currentSongIds.indexOf(song.songId) === -1
 								) {
+									lastSongAdded = song;
 									songsToAdd.push(song);
 									return true;
 								}
 								if (songsToAdd.length >= songsStillNeeded) return false;
 								return true;
 							});
+
+						let { currentSongIndex } = station;
+						if (station.playMode === "sequential") {
+							const indexOfLastSong = _playlistSongs
+								.map(song => song.songId)
+								.indexOf(lastSongAdded.songId);
+							if (indexOfLastSong !== -1) currentSongIndex = indexOfLastSong;
+						}
+
 						const newPlaylist = [...currentSongs, ...songsToAdd].map(song => {
 							if (!song._id) song._id = null;
 							return song;
 						});
-						next(null, newPlaylist);
+						next(null, newPlaylist, currentSongIndex);
 					},
 
-					(newPlaylist, next) => {
+					(newPlaylist, currentSongIndex, next) => {
 						StationsModule.stationModel.updateOne(
 							{ _id: stationId },
-							{ $set: { queue: newPlaylist } },
+							{ $set: { queue: newPlaylist, currentSongIndex } },
 							{ runValidators: true },
 							err => {
 								if (err) next(err);
@@ -714,11 +736,11 @@ class _StationsModule extends CoreClass {
 						if (!station) return next("Station not found.");
 
 						if (station.type === "community" && station.partyMode && station.queue.length === 0)
-							return next(null, null, -11, station); // Community station with party mode enabled and no songs in the queue
+							return next(null, null, station); // Community station with party mode enabled and no songs in the queue
 
 						if (station.type === "community" && station.partyMode && station.queue.length > 0) {
 							// Community station with party mode enabled and songs in the queue
-							if (station.paused) return next(null, null, -19, station);
+							if (station.paused) return next(null, null, station);
 
 							StationsModule.runJob("GET_NEXT_STATION_SONG", { stationId: station._id }, this)
 								.then(response => {
@@ -731,7 +753,7 @@ class _StationsModule extends CoreClass {
 									});
 								})
 								.catch(err => {
-									if (err === "No songs available.") next(null, null, 0, station);
+									if (err === "No songs available.") next(null, null, station);
 									else next(err);
 								});
 
@@ -765,11 +787,11 @@ class _StationsModule extends CoreClass {
 												{ stationId: station._id },
 												this
 											).then(() => {
-												next(null, response.song, 0, station);
+												next(null, response.song, station);
 											});
 										})
 										.catch(err => {
-											if (err === "No songs available.") next(null, null, 0, station);
+											if (err === "No songs available.") next(null, null, station);
 											else next(err);
 										});
 								})
@@ -849,19 +871,19 @@ class _StationsModule extends CoreClass {
 												this
 											)
 												.then(() => {
-													next(null, response.song, 0, station);
+													next(null, response.song, station);
 												})
 												.catch(next);
 										})
 										.catch(err => {
-											if (err === "No songs available.") next(null, null, 0, station);
+											if (err === "No songs available.") next(null, null, station);
 											else next(err);
 										});
 								})
 								.catch(next);
 						}
 					},
-					(song, currentSongIndex, station, next) => {
+					(song, station, next) => {
 						const $set = {};
 
 						if (song === null) $set.currentSong = null;
@@ -890,7 +912,7 @@ class _StationsModule extends CoreClass {
 							};
 						}
 
-						if (currentSongIndex >= 0) $set.currentSongIndex = currentSongIndex;
+						// if (currentSongIndex >= 0) $set.currentSongIndex = currentSongIndex;
 						$set.startedAt = Date.now();
 						$set.timePaused = 0;
 						if (station.paused) $set.pausedAt = Date.now();

+ 85 - 1
frontend/src/components/modals/EditStation.vue

@@ -229,7 +229,7 @@
 					</div>
 					<!--  Buttons changing the mode of the station -->
 					<div v-if="station.type === 'community'">
-						<label class="label">Mode</label>
+						<label class="label">Play Mode</label>
 						<div
 							@mouseenter="modeDropdownActive = true"
 							@mouseleave="modeDropdownActive = false"
@@ -279,6 +279,60 @@
 							</transition>
 						</div>
 					</div>
+					<div>
+						<label class="label">Play Mode</label>
+						<div
+							@mouseenter="playModeDropdownActive = true"
+							@mouseleave="playModeDropdownActive = false"
+							class="button-wrapper"
+						>
+							<button
+								class="blue"
+								@click="
+									station.playMode === 'random'
+										? updatePlayModeLocal('sequential')
+										: updatePlayModeLocal('random')
+								"
+							>
+								<i class="material-icons">{{
+									station.playMode
+										? "playlist_play"
+										: "playlist_play"
+								}}</i>
+								{{
+									station.playMode === "random"
+										? "Random"
+										: "Sequential"
+								}}
+							</button>
+							<transition name="slide-down">
+								<button
+									class="blue"
+									v-if="
+										playModeDropdownActive &&
+											station.playMode === 'sequential'
+									"
+									@click="updatePlayModeLocal('random')"
+								>
+									<i class="material-icons">playlist_play</i>
+									Random
+								</button>
+							</transition>
+							<transition name="slide-down">
+								<button
+									class="blue"
+									v-if="
+										playModeDropdownActive &&
+											station.playMode === 'random'
+									"
+									@click="updatePlayModeLocal('sequential')"
+								>
+									<i class="material-icons">playlist_play</i>
+									Sequential
+								</button>
+							</transition>
+						</div>
+					</div>
 					<div
 						v-if="
 							station.type === 'community' &&
@@ -449,6 +503,7 @@ export default {
 			blacklistGenreAutosuggestItems: [],
 			privacyDropdownActive: false,
 			modeDropdownActive: false,
+			playModeDropdownActive: false,
 			queueLockDropdownActive: false,
 			themeDropdownActive: false,
 			genres: [
@@ -596,6 +651,9 @@ export default {
 			const partyModeChanged =
 				this.originalStation.type === "community" &&
 				this.originalStation.partyMode !== this.station.partyMode;
+			const playModeChanged =
+				this.originalStation.type === "community" &&
+				this.originalStation.playMode !== this.station.playMode;
 			const queueLockChanged =
 				this.originalStation.type === "community" &&
 				this.station.partyMode &&
@@ -614,6 +672,7 @@ export default {
 			if (descriptionChanged) this.updateDescription();
 			if (privacyChanged) this.updatePrivacy();
 			if (partyModeChanged) this.updatePartyMode();
+			if (playModeChanged) this.updatePlayMode();
 			if (queueLockChanged) this.updateQueueLock();
 			if (genresChanged) this.updateGenres();
 			if (blacklistedGenresChanged) this.updateBlacklistedGenres();
@@ -625,6 +684,7 @@ export default {
 				!descriptionChanged &&
 				!privacyChanged &&
 				!partyModeChanged &&
+				!playModeChanged &&
 				!queueLockChanged &&
 				!genresChanged &&
 				!blacklistedGenresChanged &&
@@ -839,6 +899,30 @@ export default {
 				}
 			);
 		},
+		updatePlayModeLocal(playMode) {
+			if (this.station.playMode === playMode) return;
+			this.station.playMode = playMode;
+			this.playModeDropdownActive = false;
+		},
+		updatePlayMode() {
+			this.$refs.saveButton.status = "disabled";
+
+			this.socket.dispatch(
+				"stations.updatePlayMode",
+				this.station._id,
+				this.station.playMode,
+				res => {
+					new Toast({ content: res.message, timeout: 8000 });
+
+					if (res.status === "success") {
+						this.originalStation.playMode = this.station.playMode;
+						return this.$refs.saveButton.handleSuccessfulSave();
+					}
+
+					return this.$refs.saveButton.handleFailedSave();
+				}
+			);
+		},
 		updateQueueLockLocal(locked) {
 			if (this.station.locked === locked) return;
 			this.station.locked = locked;