소스 검색

feat(Playlists): functionality to deselect private playlists from queue

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan 4 년 전
부모
커밋
3a0f38fe04

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

@@ -100,6 +100,16 @@ CacheModule.runJob("SUB", {
 	}
 });
 
+CacheModule.runJob("SUB", {
+	channel: "privatePlaylist.deselected",
+	cb: data => {
+		IOModule.runJob("EMIT_TO_ROOM", {
+			room: `station.${data.stationId}`,
+			args: ["event:privatePlaylist.deselected"]
+		});
+	}
+});
+
 CacheModule.runJob("SUB", {
 	channel: "station.pause",
 	cb: stationId => {
@@ -2207,6 +2217,96 @@ export default {
 		);
 	}),
 
+	/**
+	 * Deselects the private playlist selected in a station
+	 *
+	 * @param session
+	 * @param stationId - the station id
+	 * @param cb
+	 */
+	deselectPrivatePlaylist: isOwnerRequired(async function deselectPrivatePlaylist(session, stationId, 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.type !== "community") return next("Station is not a community station.");
+					if (!station.privatePlaylist) return next("No private playlist is currently selected.");
+
+					return stationModel.updateOne(
+						{ _id: stationId },
+						{
+							$set: {
+								privatePlaylist: null,
+								currentSongIndex: 0
+							}
+						},
+						{ runValidators: true },
+						next
+					);
+				},
+
+				(res, next) => {
+					StationsModule.runJob("UPDATE_STATION", { stationId }, this)
+						.then(station => {
+							next(null, station);
+						})
+						.catch(next);
+				}
+			],
+			async (err, station) => {
+				if (err) {
+					err = await UtilsModule.runJob("GET_ERROR", { error: err }, this);
+					this.log(
+						"ERROR",
+						"STATIONS_DESELECT_PRIVATE_PLAYLIST",
+						`Deselecting private playlist for station "${stationId}" failed. "${err}"`
+					);
+					return cb({ status: "failure", message: err });
+				}
+
+				this.log(
+					"SUCCESS",
+					"STATIONS_DESELECT_PRIVATE_PLAYLIST",
+					`Deselected private playlist for station "${stationId}" successfully.`
+				);
+
+				NotificationsModule.runJob("UNSCHEDULE", {
+					name: `stations.nextSong?id${stationId}`
+				});
+
+				if (!station.partyMode) StationsModule.runJob("SKIP_STATION", { stationId });
+
+				CacheModule.runJob("PUB", {
+					channel: "privatePlaylist.deselected",
+					value: {
+						stationId
+					}
+				});
+
+				return cb({
+					status: "success",
+					message: "Successfully deselected playlist."
+				});
+			}
+		);
+	}),
+
 	favoriteStation: isLoginRequired(async function favoriteStation(session, stationId, cb) {
 		const userModel = await DBModule.runJob("GET_MODEL", { modelName: "user" }, this);
 		async.waterfall(

+ 26 - 7
frontend/src/components/modals/EditStation.vue

@@ -185,14 +185,10 @@
 								:key="index"
 							>
 								<div slot="actions">
-									<!-- <a
+									<a
 										class="button is-danger"
 										href="#"
-										@click="
-											togglePlaylistSelection(
-												playlist._id
-											)
-										"
+										@click="deselectPlaylist()"
 										v-if="isPlaylistSelected(playlist._id)"
 									>
 										<i
@@ -200,11 +196,12 @@
 											>stop</i
 										>
 										Stop playing
-									</a> -->
+									</a>
 									<a
 										class="button is-success"
 										href="#"
 										@click="selectPlaylist(playlist._id)"
+										v-else
 										><i
 											class="material-icons icon-with-button"
 											>play_arrow</i
@@ -577,6 +574,20 @@ export default {
 				}
 			);
 		},
+		deselectPlaylist() {
+			this.socket.emit(
+				"stations.deselectPrivatePlaylist",
+				this.station._id,
+				res => {
+					if (res.status === "failure")
+						return new Toast({
+							content: res.message,
+							timeout: 8000
+						});
+					return new Toast({ content: res.message, timeout: 4000 });
+				}
+			);
+		},
 		update() {
 			if (this.station.name !== this.editing.name) this.updateName();
 			if (this.station.displayName !== this.editing.displayName)
@@ -1263,6 +1274,14 @@ export default {
 
 #playlists {
 	overflow: auto;
+
+	.playlist:not(:last-of-type) {
+		margin-bottom: 10px;
+	}
+
+	.button {
+		width: 148px;
+	}
 }
 
 .modal-card {

+ 25 - 0
frontend/src/pages/Station/components/Sidebar/MyPlaylists.vue

@@ -15,6 +15,17 @@
 						>
 							<i class="material-icons">play_arrow</i>
 						</button>
+						<button
+							v-if="
+								station.type === 'community' &&
+									!isNotSelected(playlist._id) &&
+									!station.partyMode
+							"
+							class="button is-danger"
+							@click="deselectPlaylist()"
+						>
+							<i class="material-icons">stop</i>
+						</button>
 						<button
 							class="button is-primary"
 							@click="edit(playlist._id)"
@@ -128,6 +139,20 @@ export default {
 				}
 			);
 		},
+		deselectPlaylist() {
+			this.socket.emit(
+				"stations.deselectPrivatePlaylist",
+				this.station._id,
+				res => {
+					if (res.status === "failure")
+						return new Toast({
+							content: res.message,
+							timeout: 8000
+						});
+					return new Toast({ content: res.message, timeout: 4000 });
+				}
+			);
+		},
 		isNotSelected(id) {
 			// TODO Also change this once it changes for a station
 			if (this.station && this.station.privatePlaylist === id)

+ 6 - 0
frontend/src/pages/Station/index.vue

@@ -586,6 +586,12 @@ export default {
 				}
 			});
 
+			this.socket.on("event:privatePlaylist.deselected", () => {
+				if (this.station.type === "community") {
+					this.station.privatePlaylist = null;
+				}
+			});
+
 			this.socket.on("event:partyMode.updated", partyMode => {
 				if (this.station.type === "community") {
 					this.station.partyMode = partyMode;