瀏覽代碼

refactor: worked more on EditSongs/bulk edit song queue

Kristian Vos 3 年之前
父節點
當前提交
b4ff49eb71

+ 66 - 9
frontend/src/components/modals/EditSong/index.vue

@@ -436,6 +436,7 @@
 				</div>
 			</template>
 			<template #footer>
+				<slot name="footer-actions" :song="song" />
 				<div>
 					<save-button
 						ref="saveButton"
@@ -560,8 +561,10 @@ export default {
 	props: {
 		songId: { type: String, default: null },
 		discogsAlbum: { type: Object, default: null },
-		sector: { type: String, default: "admin" }
+		sector: { type: String, default: "admin" },
+		bulk: { type: Boolean, default: false }
 	},
+	emits: ["error", "savedSuccess", "savedError"],
 	data() {
 		return {
 			songDataLoaded: false,
@@ -879,10 +882,26 @@ export default {
 					this.video.player.stopVideo();
 					this.drawCanvas();
 				}
-				if (this.playerReady) {
-					this.youtubeVideoCurrentTime = this.video.player
-						.getCurrentTime()
-						?.toFixed(3);
+				if (
+					this.playerReady &&
+					this.video.player.getVideoData()?.video_id ===
+						this.song.youtubeId
+				) {
+					const currentTime = this.video.player.getCurrentTime();
+
+					if (currentTime !== undefined)
+						this.youtubeVideoCurrentTime = currentTime.toFixed(3);
+
+					if (this.youtubeVideoDuration === "0.000") {
+						const duration = this.video.player.getDuration();
+
+						if (duration !== undefined) {
+							this.youtubeVideoDuration = duration.toFixed(3);
+							this.youtubeVideoNote = "(~)";
+
+							this.drawCanvas();
+						}
+					}
 				}
 
 				if (this.video.paused === false) this.drawCanvas();
@@ -911,10 +930,10 @@ export default {
 							this.video.player.setVolume(volume);
 							if (volume > 0) this.video.player.unMute();
 
-							const duration = this.video.player.getDuration();
+							// const duration = this.video.player.getDuration();
 
-							this.youtubeVideoDuration = duration.toFixed(3);
-							this.youtubeVideoNote = "(~)";
+							// this.youtubeVideoDuration = duration.toFixed(3);
+							// this.youtubeVideoNote = "(~)";
 							this.playerReady = true;
 
 							if (this.song && this.song._id)
@@ -1033,10 +1052,14 @@ export default {
 			this.songDataLoaded = false;
 			if (this.video.player && this.video.player.stopVideo)
 				this.video.player.stopVideo();
+			this.resetSong();
+			this.youtubeVideoCurrentTime = "0.000";
+			this.youtubeVideoDuration = "0.000";
 			this.socket.dispatch(
 				"apis.leaveRoom",
 				`edit-song.${this.song._id}`
 			);
+			this.saveButtonRef.status = "default";
 		},
 		loadSong(songId) {
 			console.log(`LOAD SONG ${songId}`);
@@ -1070,11 +1093,24 @@ export default {
 						// console.log(this.video.player);
 						// console.log(this.video.player.loadVideoById);
 
-						if (this.video.player && this.video.player.cueVideoById)
+						if (
+							this.video.player &&
+							this.video.player.cueVideoById
+						) {
 							this.video.player.cueVideoById(
 								this.song.youtubeId,
 								this.song.skipDuration
 							);
+
+							// const duration = this.video.player.getDuration();
+
+							// if (duration !== undefined) {
+							// 	this.youtubeVideoDuration = duration.toFixed(3);
+							// 	this.youtubeVideoNote = "(~)";
+
+							// 	this.drawCanvas();
+							// }
+						}
 					} else {
 						new Toast("Song with that ID not found");
 						// this.closeModal("editSong");
@@ -1102,6 +1138,8 @@ export default {
 		save(songToCopy, verify, close) {
 			const song = JSON.parse(JSON.stringify(songToCopy));
 
+			this.$emit("saving", song._id);
+
 			let saveButtonRef = this.$refs.saveButton;
 			if (close && !verify) saveButtonRef = this.$refs.saveAndCloseButton;
 			else if (close && verify)
@@ -1109,16 +1147,19 @@ export default {
 
 			if (!this.youtubeError && this.youtubeVideoDuration === "0.000") {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast("The video appears to not be working.");
 			}
 
 			if (!song.title) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast("Please fill in all fields");
 			}
 
 			if (!song.thumbnail) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast("Please fill in all fields");
 			}
 
@@ -1150,6 +1191,7 @@ export default {
 				this.originalSong.youtubeId !== song.youtubeId
 			) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(
 					"You're not allowed to change the YouTube id while the player is not working"
 				);
@@ -1163,6 +1205,7 @@ export default {
 					this.originalSong.duration !== song.duration)
 			) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(
 					"Duration can't be higher than the length of the video"
 				);
@@ -1171,6 +1214,7 @@ export default {
 			// Title
 			if (!validation.isLength(song.title, 1, 100)) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(
 					"Title must have between 1 and 100 characters."
 				);
@@ -1179,6 +1223,7 @@ export default {
 			// Artists
 			if (song.artists.length < 1 || song.artists.length > 10) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(
 					"Invalid artists. You must have at least 1 artist and a maximum of 10 artists."
 				);
@@ -1201,6 +1246,7 @@ export default {
 
 			if (error) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(error);
 			}
 
@@ -1225,6 +1271,7 @@ export default {
 
 			if (error) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(error);
 			}
 
@@ -1244,18 +1291,21 @@ export default {
 
 			if (error) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(error);
 			}
 
 			// Thumbnail
 			if (!validation.isLength(song.thumbnail, 1, 256)) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast(
 					"Thumbnail must have between 8 and 256 characters."
 				);
 			}
 			if (this.useHTTPS && song.thumbnail.indexOf("https://") !== 0) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast('Thumbnail must start with "https://".');
 			}
 
@@ -1265,6 +1315,7 @@ export default {
 				song.thumbnail.indexOf("https://") !== 0
 			) {
 				saveButtonRef.handleFailedSave();
+				this.$emit("savedError", song._id);
 				return new Toast('Thumbnail must start with "http://".');
 			}
 
@@ -1277,6 +1328,11 @@ export default {
 					saveButtonRef.handleSuccessfulSave();
 				else saveButtonRef.handleFailedSave();
 
+				if (res.status === "success")
+					this.$emit("savedSuccess", song._id);
+				else if (res.status === "error")
+					this.$emit("savedError", song._id);
+
 				if (verify) this.verify(this.song._id);
 				if (close) this.closeModal("editSong");
 			});
@@ -1574,6 +1630,7 @@ export default {
 			"pauseVideo",
 			"getCurrentTime",
 			"editSong",
+			"resetSong",
 			"updateSongField",
 			"updateReports"
 		]),

+ 93 - 16
frontend/src/components/modals/EditSongs.vue

@@ -1,5 +1,13 @@
 <template>
-	<edit-song v-if="currentSong" :song-id="currentSong._id" v-show="!closed">
+	<edit-song
+		:song-id="currentSong._id"
+		:bulk="true"
+		v-if="currentSong"
+		v-show="!closed"
+		@savedSuccess="onSavedSuccess"
+		@savedError="onSavedError"
+		@saving="onSaving"
+	>
 		<template #sidebar>
 			<div class="sidebar">
 				<header class="sidebar-head">
@@ -11,13 +19,13 @@
 				<section class="sidebar-body">
 					<div
 						class="item"
-						v-for="{ status, song } in items"
+						v-for="{ status, flagged, song } in items"
 						:key="song._id"
 					>
 						<i
-							class="material-icons item-icon todo-icon"
-							v-if="status === 'todo'"
-							>cancel</i
+							class="material-icons item-icon editing-icon"
+							v-if="currentSong._id === song._id"
+							>edit</i
 						>
 						<i
 							class="material-icons item-icon error-icon"
@@ -25,19 +33,24 @@
 							>error</i
 						>
 						<i
-							class="material-icons item-icon done-icon"
-							v-else-if="status === 'done'"
-							>check_circle</i
+							class="material-icons item-icon saving-icon"
+							v-else-if="status === 'saving'"
+							>pending<!--or we can use change_circle--></i
 						>
 						<i
 							class="material-icons item-icon flag-icon"
-							v-else-if="status === 'flag'"
+							v-else-if="flagged"
 							>flag_circle</i
 						>
 						<i
-							class="material-icons item-icon editing-icon"
-							v-else-if="status === 'editing'"
-							>edit</i
+							class="material-icons item-icon done-icon"
+							v-else-if="status === 'done'"
+							>check_circle</i
+						>
+						<i
+							class="material-icons item-icon todo-icon"
+							v-else-if="status === 'todo'"
+							>cancel</i
 						>
 						<song-item
 							:song="song"
@@ -65,6 +78,16 @@
 				</footer>
 			</div>
 		</template>
+		<template #footer-actions="slotProps">
+			<div>
+				<button class="button is-primary" @click="editNextSong()">
+					Next
+				</button>
+				<button class="button is-primary" @click="flagSong()">
+					Flag
+				</button>
+			</div>
+		</template>
 	</edit-song>
 </template>
 
@@ -99,6 +122,11 @@ export default {
 		};
 	},
 	computed: {
+		editingItemIndex() {
+			return this.items.findIndex(
+				item => item.song._id === this.currentSong._id
+			);
+		},
 		...mapGetters({
 			socket: "websockets/getSocket"
 		})
@@ -106,20 +134,65 @@ export default {
 	async mounted() {
 		this.songIds.forEach(songId => {
 			this.socket.dispatch("songs.getSongFromSongId", songId, res => {
-				this.items.push({ status: "todo", song: res.data.song });
+				this.items.push({
+					status: "todo",
+					flagged: false,
+					song: res.data.song
+				});
 			});
 		});
 	},
 	methods: {
 		pickSong(song) {
 			this.currentSong = song;
-			this.items[
-				this.items.findIndex(item => item.song._id === song._id)
-			].status = "editing";
+			// this.items[
+			// 	this.items.findIndex(item => item.song._id === song._id)
+			// ].status = "editing";
 		},
 		closeEditSongs() {
 			this.closed = true;
 		},
+		editNextSong() {
+			const currentlyEditingSongIndex = this.editingItemIndex;
+			let newEditingSongIndex = -1;
+
+			for (
+				let i = currentlyEditingSongIndex + 1;
+				i < this.items.length;
+				i += 1
+			) {
+				if (this.items[i].status !== "done") {
+					newEditingSongIndex = i;
+					break;
+				}
+			}
+
+			if (newEditingSongIndex > -1)
+				this.pickSong(this.items[newEditingSongIndex].song);
+			// else edit no song
+		},
+		flagSong() {
+			if (this.editingItemIndex > -1)
+				this.items[this.editingItemIndex].flagged = true;
+		},
+		onSavedSuccess(songId) {
+			const itemIndex = this.items.findIndex(
+				item => item.song._id === songId
+			);
+			if (itemIndex > -1) this.items[itemIndex].status = "done";
+		},
+		onSavedError(songId) {
+			const itemIndex = this.items.findIndex(
+				item => item.song._id === songId
+			);
+			if (itemIndex > -1) this.items[itemIndex].status = "error";
+		},
+		onSaving(songId) {
+			const itemIndex = this.items.findIndex(
+				item => item.song._id === songId
+			);
+			if (itemIndex > -1) this.items[itemIndex].status = "saving";
+		},
 		...mapActions("modals/editSong", ["editSong"])
 	}
 };
@@ -198,6 +271,10 @@ export default {
 				color: var(--red);
 			}
 
+			.saving-icon {
+				color: var(--primary-color);
+			}
+
 			.todo-icon {
 				color: var(--primary-color);
 			}

+ 5 - 0
frontend/src/store/modules/modals/editSong.js

@@ -19,6 +19,7 @@ export default {
 	actions: {
 		showTab: ({ commit }, tab) => commit("showTab", tab),
 		editSong: ({ commit }, song) => commit("editSong", song),
+		unloadSong: ({ commit }) => commit("unloadSong"),
 		stopVideo: ({ commit }) => commit("stopVideo"),
 		loadVideoById: ({ commit }, id, skipDuration) =>
 			commit("loadVideoById", id, skipDuration),
@@ -49,6 +50,10 @@ export default {
 			state.originalSong = JSON.parse(JSON.stringify(song));
 			state.song = { ...song };
 		},
+		unloadSong(state) {
+			state.originalSong = {};
+			state.song = {};
+		},
 		stopVideo(state) {
 			state.video.player.stopVideo();
 		},