浏览代码

EditSong modal on stations for current and queued songs

Owen Diffey 4 年之前
父节点
当前提交
020ac58a23

+ 1 - 0
backend/logic/db/schemas/station.js

@@ -7,6 +7,7 @@ export default {
 	description: { type: String, minlength: 2, maxlength: 128, required: true },
 	paused: { type: Boolean, default: false, required: true },
 	currentSong: {
+		_id: { type: String },
 		songId: { type: String },
 		title: { type: String },
 		artists: [{ type: String }],

+ 2 - 0
backend/logic/stations.js

@@ -610,6 +610,7 @@ class _StationsModule extends CoreClass {
 							const { song } = response;
 							if (song) {
 								const newSong = {
+									_id: song._id,
 									songId: song.songId,
 									title: song.title,
 									artists: song.artists,
@@ -851,6 +852,7 @@ class _StationsModule extends CoreClass {
 							};
 						} else {
 							$set.currentSong = {
+								_id: song._id,
 								songId: song.songId,
 								title: song.title,
 								artists: song.artists,

+ 102 - 97
frontend/src/components/modals/EditSong.vue

@@ -5,7 +5,7 @@
 				<div class="left-section">
 					<div class="top-section">
 						<div class="player-section">
-							<div id="player"></div>
+							<div id="editSongPlayer"></div>
 							<canvas
 								id="durationCanvas"
 								height="20"
@@ -481,7 +481,7 @@
 				</button>
 				<button
 					class="button is-danger"
-					@click="closeModal({ sector: 'admin', modal: 'editSong' })"
+					@click="closeModal({ sector: sector, modal: 'editSong' })"
 				>
 					<span>&nbsp;Close</span>
 				</button>
@@ -520,7 +520,8 @@ export default {
 	components: { Modal, FloatingBox },
 	props: {
 		songId: { type: String, default: null },
-		songType: { type: String, default: null }
+		songType: { type: String, default: null },
+		sector: { type: String, default: "admin" }
 	},
 	data() {
 		return {
@@ -593,10 +594,10 @@ export default {
 	},
 	watch: {
 		/* eslint-disable */
-		"song.duration": function() {
+		"song.duration": function () {
 			this.drawCanvas();
 		},
-		"song.skipDuration": function() {
+		"song.skipDuration": function () {
 			this.drawCanvas();
 		}
 		/* eslint-enable */
@@ -655,110 +656,114 @@ export default {
 							if (this.video.paused === false) this.drawCanvas();
 						}, 200);
 
-						this.video.player = new window.YT.Player("player", {
-							height: 298,
-							width: 530,
-							videoId: this.song.songId,
-							host: "https://www.youtube-nocookie.com",
-							playerVars: {
-								controls: 0,
-								iv_load_policy: 3,
-								rel: 0,
-								showinfo: 0,
-								autoplay: 1
-							},
-							startSeconds: this.song.skipDuration,
-							events: {
-								onReady: () => {
-									let volume = parseInt(
-										localStorage.getItem("volume")
-									);
-									volume =
-										typeof volume === "number"
-											? volume
-											: 20;
-									console.log(
-										`Seekto: ${this.song.skipDuration}`
-									);
-									this.video.player.seekTo(
-										this.song.skipDuration
-									);
-									this.video.player.setVolume(volume);
-									if (volume > 0) this.video.player.unMute();
-									this.youtubeVideoDuration = this.video.player
-										.getDuration()
-										.toFixed(3);
-									this.youtubeVideoNote = "(~)";
-									this.playerReady = true;
-
-									this.drawCanvas();
+						this.video.player = new window.YT.Player(
+							"editSongPlayer",
+							{
+								height: 298,
+								width: 530,
+								videoId: this.song.songId,
+								host: "https://www.youtube-nocookie.com",
+								playerVars: {
+									controls: 0,
+									iv_load_policy: 3,
+									rel: 0,
+									showinfo: 0,
+									autoplay: 1
 								},
-								onStateChange: event => {
-									this.drawCanvas();
-
-									if (event.data === 1) {
-										if (!this.video.autoPlayed) {
-											this.video.autoPlayed = true;
-											return this.video.player.stopVideo();
-										}
-
-										this.video.paused = false;
-										let youtubeDuration = this.video.player.getDuration();
-										this.youtubeVideoDuration = youtubeDuration.toFixed(
-											3
+								startSeconds: this.song.skipDuration,
+								events: {
+									onReady: () => {
+										let volume = parseInt(
+											localStorage.getItem("volume")
 										);
-										this.youtubeVideoNote = "";
-
-										if (this.song.duration === -1)
-											this.song.duration = youtubeDuration;
-
-										youtubeDuration -= this.song
-											.skipDuration;
-										if (
-											this.song.duration >
-											youtubeDuration + 1
-										) {
-											this.video.player.stopVideo();
-											this.video.paused = true;
-											return new Toast({
-												content:
-													"Video can't play. Specified duration is bigger than the YouTube song duration.",
-												timeout: 4000
-											});
-										}
-										if (this.song.duration <= 0) {
-											this.video.player.stopVideo();
-											this.video.paused = true;
-											return new Toast({
-												content:
-													"Video can't play. Specified duration has to be more than 0 seconds.",
-												timeout: 4000
-											});
-										}
-
-										if (
-											this.video.player.getCurrentTime() <
+										volume =
+											typeof volume === "number"
+												? volume
+												: 20;
+										console.log(
+											`Seekto: ${this.song.skipDuration}`
+										);
+										this.video.player.seekTo(
 											this.song.skipDuration
-										) {
-											return this.video.player.seekTo(
-												this.song.skipDuration
+										);
+										this.video.player.setVolume(volume);
+										if (volume > 0)
+											this.video.player.unMute();
+										this.youtubeVideoDuration = this.video.player
+											.getDuration()
+											.toFixed(3);
+										this.youtubeVideoNote = "(~)";
+										this.playerReady = true;
+
+										this.drawCanvas();
+									},
+									onStateChange: event => {
+										this.drawCanvas();
+
+										if (event.data === 1) {
+											if (!this.video.autoPlayed) {
+												this.video.autoPlayed = true;
+												return this.video.player.stopVideo();
+											}
+
+											this.video.paused = false;
+											let youtubeDuration = this.video.player.getDuration();
+											this.youtubeVideoDuration = youtubeDuration.toFixed(
+												3
 											);
+											this.youtubeVideoNote = "";
+
+											if (this.song.duration === -1)
+												this.song.duration = youtubeDuration;
+
+											youtubeDuration -= this.song
+												.skipDuration;
+											if (
+												this.song.duration >
+												youtubeDuration + 1
+											) {
+												this.video.player.stopVideo();
+												this.video.paused = true;
+												return new Toast({
+													content:
+														"Video can't play. Specified duration is bigger than the YouTube song duration.",
+													timeout: 4000
+												});
+											}
+											if (this.song.duration <= 0) {
+												this.video.player.stopVideo();
+												this.video.paused = true;
+												return new Toast({
+													content:
+														"Video can't play. Specified duration has to be more than 0 seconds.",
+													timeout: 4000
+												});
+											}
+
+											if (
+												this.video.player.getCurrentTime() <
+												this.song.skipDuration
+											) {
+												return this.video.player.seekTo(
+													this.song.skipDuration
+												);
+											}
+										} else if (event.data === 2) {
+											this.video.paused = true;
 										}
-									} else if (event.data === 2) {
-										this.video.paused = true;
-									}
 
-									return false;
+										return false;
+									}
 								}
 							}
-						});
+						);
 					} else {
 						new Toast({
 							content: "Song with that ID not found",
 							timeout: 3000
 						});
 						this.closeModal({
-							sector: "admin",
+							sector: this.sector,
 							modal: "editSong"
 						});
 					}
@@ -863,7 +868,7 @@ export default {
 			preventDefault: true,
 			handler: () => {
 				this.closeModal({
-					sector: "admin",
+					sector: this.sector,
 					modal: "editSong"
 				});
 				setTimeout(() => {
@@ -1079,7 +1084,7 @@ export default {
 					}
 					if (close)
 						this.closeModal({
-							sector: "admin",
+							sector: this.sector,
 							modal: "editSong"
 						});
 				}

+ 8 - 0
frontend/src/pages/Station/components/CurrentlyPlaying.vue

@@ -71,6 +71,14 @@
 				>
 					<div class="icon"></div>
 				</a>
+				<button
+					class="button is-primary"
+					id="editsong-icon"
+					v-if="$parent.isAdminOnly() && !currentSong.simpleSong"
+					@click="$parent.editSong(currentSong)"
+				>
+					<i class="material-icons icon-with-button">edit</i>Edit
+				</button>
 			</div>
 		</div>
 	</div>

+ 69 - 11
frontend/src/pages/Station/components/Sidebar/Queue/QueueItem.vue

@@ -48,21 +48,48 @@
 			<p id="song-duration">
 				{{ utils.formatTime(song.duration) }}
 			</p>
-			<i
-				v-if="
-					station.type === 'community' &&
-						($parent.isOwnerOnly() || $parent.isAdminOnly())
-				"
-				class="material-icons"
-				id="remove-queue-item"
-				@click="$parent.removeFromQueue(song.songId)"
-				>delete_forever</i
-			>
+			<div id="queue-item-buttons">
+				<i
+					v-if="
+						$parent.loggedIn &&
+							!song.simpleSong &&
+							song.likes !== -1 &&
+							song.dislikes !== -1
+					"
+					class="material-icons"
+					id="report-queue-item"
+					@click="openModal({ sector: 'station', modal: 'report' })"
+					>flag</i
+				>
+				<i
+					v-if="
+						$parent.isAdminOnly() &&
+							!song.simpleSong &&
+							song.likes !== -1 &&
+							song.dislikes !== -1
+					"
+					class="material-icons"
+					id="edit-queue-item"
+					@click="$parent.$parent.$parent.editSong(song)"
+					>edit</i
+				>
+				<i
+					v-if="
+						station.type === 'community' &&
+							($parent.isOwnerOnly() || $parent.isAdminOnly())
+					"
+					class="material-icons"
+					id="remove-queue-item"
+					@click="$parent.removeFromQueue(song.songId)"
+					>delete_forever</i
+				>
+			</div>
 		</div>
 	</div>
 </template>
 
 <script>
+import { mapActions } from "vuex";
 import { formatDistance, parseISO } from "date-fns";
 
 import UserIdToUsername from "../../../../../components/common/UserIdToUsername.vue";
@@ -88,6 +115,7 @@ export default {
 		};
 	},
 	methods: {
+		...mapActions("modals", ["openModal"]),
 		formatDistance,
 		parseISO
 	}
@@ -111,6 +139,14 @@ export default {
 		display: flex;
 		align-items: center;
 	}
+	#duration-and-actions {
+		margin-left: 5px;
+	}
+	#queue-item-buttons {
+		display: flex;
+		flex-direction: column;
+		margin-left: 10px;
+	}
 
 	#thumbnail {
 		width: 60px;
@@ -146,9 +182,31 @@ export default {
 		font-size: 20px;
 	}
 
+	#report-queue-item {
+		cursor: pointer;
+		color: $yellow;
+		&:hover,
+		&:focus {
+			color: darken($yellow, 5%);
+		}
+	}
+
+	#edit-queue-item {
+		cursor: pointer;
+		color: $musare-blue;
+		&:hover,
+		&:focus {
+			color: darken($musare-blue, 5%);
+		}
+	}
+
 	#remove-queue-item {
 		cursor: pointer;
-		margin-left: 10px;
+		color: $red;
+		&:hover,
+		&:focus {
+			color: darken($red, 5%);
+		}
 	}
 }
 </style>

+ 42 - 7
frontend/src/pages/Station/index.vue

@@ -90,7 +90,10 @@
 
 				<div class="player-container quadrant" v-show="!noSong">
 					<div id="video-container">
-						<div id="player" style="width: 100%; height: 100%" />
+						<div
+							id="stationPlayer"
+							style="width: 100%; height: 100%"
+						/>
 						<div class="player-cannot-autoplay" v-if="!canAutoplay">
 							<p>
 								Please click anywhere on the screen for the
@@ -299,6 +302,13 @@
 
 		<main-footer v-if="exists" />
 
+		<edit-song
+			v-if="modals.editSong"
+			:song-id="editingSongId"
+			song-type="songs"
+			sector="station"
+		/>
+
 		<floating-box id="player-debug-box" ref="playerDebugBox">
 			<template #body>
 				<span><b>YouTube id</b>: {{ currentSong.songId }}</span>
@@ -380,7 +390,8 @@ export default {
 		FloatingBox,
 		CurrentlyPlaying,
 		StationSidebar,
-		AddToPlaylistDropdown
+		AddToPlaylistDropdown,
+		EditSong: () => import("../../components/modals/EditSong.vue")
 	},
 	data() {
 		return {
@@ -406,7 +417,8 @@ export default {
 			seeking: false,
 			playbackRate: 1,
 			volumeSliderValue: 0,
-			showPlaylistDropdown: false
+			showPlaylistDropdown: false,
+			editingSongId: ""
 		};
 	},
 	computed: {
@@ -487,8 +499,14 @@ export default {
 								if (
 									this.autoSkipDisliked &&
 									song.disliked === true
-								)
+								) {
 									this.voteSkipStation();
+									new Toast({
+										content:
+											"Automatically voted to skip disliked song.",
+										timeout: 4000
+									});
+								}
 							}
 						}
 					);
@@ -708,7 +726,7 @@ export default {
 		},
 		youtubeReady() {
 			if (!this.player) {
-				this.player = new window.YT.Player("player", {
+				this.player = new window.YT.Player("stationPlayer", {
 					height: 270,
 					width: 480,
 					videoId: this.currentSong.songId,
@@ -743,7 +761,19 @@ export default {
 						},
 						onError: err => {
 							console.log("iframe error", err);
-							if (this.loggedIn) this.voteSkipStation();
+							if (this.loggedIn) {
+								new Toast({
+									content:
+										"Error with YouTube Embed, voted to skip the current song.",
+									timeout: 8000
+								});
+								this.voteSkipStation();
+							} else {
+								new Toast({
+									content: "Error with YouTube Embed",
+									timeout: 8000
+								});
+							}
 						},
 						onStateChange: event => {
 							if (
@@ -1432,6 +1462,10 @@ export default {
 				}
 			);
 		},
+		editSong(song) {
+			this.editingSongId = song._id;
+			this.openModal({ sector: "station", modal: "editSong" });
+		},
 		...mapActions("modals", ["openModal"]),
 		...mapActions("station", [
 			"joinStation",
@@ -1445,7 +1479,8 @@ export default {
 			"updateNoSong",
 			"editStation",
 			"updateIfStationIsFavorited"
-		])
+		]),
+		...mapActions("editSongModal", ["stopVideo"])
 	}
 };
 </script>