Browse Source

feat: worked on EditSongs/bulk edit song queue (WIP)

Kristian Vos 3 years ago
parent
commit
f2f94b8e1c

+ 1 - 0
frontend/src/components/Modal.vue

@@ -1,6 +1,7 @@
 <template>
 	<div class="modal is-active">
 		<div class="modal-background" @click="closeCurrentModal()" />
+		<slot name="sidebar" />
 		<div
 			:class="{
 				'modal-card': true,

+ 9 - 2
frontend/src/components/SongItem.vue

@@ -5,7 +5,7 @@
 		v-if="song"
 	>
 		<div class="thumbnail-and-info">
-			<song-thumbnail :song="song" />
+			<song-thumbnail :song="song" v-if="thumbnail" />
 			<div class="song-info">
 				<h6 v-if="header">{{ header }}</h6>
 				<div class="song-title">
@@ -184,6 +184,10 @@ export default {
 			type: Boolean,
 			default: true
 		},
+		thumbnail: {
+			type: Boolean,
+			default: true
+		},
 		disabledActions: {
 			type: Array,
 			default: () => []
@@ -299,6 +303,8 @@ export default {
 }
 
 .song-item {
+	min-height: 65px;
+
 	&:not(:last-of-type) {
 		margin-bottom: 10px;
 	}
@@ -326,13 +332,14 @@ export default {
 		width: 65px;
 		height: 65px;
 		margin: -7.5px;
+		margin-right: calc(20px - 7.5px);
 	}
 
 	.song-info {
 		display: flex;
 		flex-direction: column;
 		justify-content: center;
-		margin-left: 20px;
+		// margin-left: 20px;
 		min-width: 0;
 
 		*:not(i) {

+ 204 - 186
frontend/src/components/modals/EditSong/index.vue

@@ -6,8 +6,17 @@
 			:size="'wide'"
 			:split="true"
 		>
+			<template #sidebar>
+				<slot name="sidebar" />
+			</template>
 			<template #body>
-				<div class="left-section">
+				<div v-if="!songId">
+					<h1>No song has been selected</h1>
+				</div>
+				<div v-if="songId && !songDataLoaded">
+					<h1>Song hasn't loaded yet</h1>
+				</div>
+				<div class="left-section" v-show="songDataLoaded">
 					<div class="top-section">
 						<div class="player-section">
 							<div id="editSongPlayer" />
@@ -597,7 +606,6 @@ export default {
 		)
 	},
 	props: {
-		youtubeId: { type: String, default: null },
 		songId: { type: String, default: null },
 		discogsAlbum: { type: Object, default: null },
 		sector: { type: String, default: "admin" }
@@ -693,8 +701,13 @@ export default {
 		},
 		"song.skipDuration": function () {
 			this.drawCanvas();
-		}
+		},
 		/* eslint-enable */
+		songId: function (songId) {
+			console.log("NEW SONG ID", songId);
+			this.unloadSong();
+			this.loadSong(songId);
+		}
 	},
 	async mounted() {
 		this.activityWatchVideoDataInterval = setInterval(() => {
@@ -897,12 +910,14 @@ export default {
 		*/
 	},
 	beforeUnmount() {
-		this.video.player.stopVideo();
+		this.unloadSong();
+
+		// this.video.player.stopVideo();
 		this.playerReady = false;
 		clearInterval(this.interval);
 		clearInterval(this.activityWatchVideoDataInterval);
 
-		this.socket.dispatch("apis.leaveRoom", `edit-song.${this.song._id}`);
+		// this.socket.dispatch("apis.leaveRoom", `edit-song.${this.song._id}`);
 
 		const shortcutNames = [
 			"editSong.pauseResume",
@@ -927,24 +942,191 @@ export default {
 	},
 	methods: {
 		init() {
+			if (this.songId) this.loadSong(this.songId);
+
+			this.interval = setInterval(() => {
+				if (
+					this.song.duration !== -1 &&
+					this.video.paused === false &&
+					this.playerReady &&
+					(this.video.player.getCurrentTime() -
+						this.song.skipDuration >
+						this.song.duration ||
+						(this.video.player.getCurrentTime() > 0 &&
+							this.video.player.getCurrentTime() >=
+								this.video.player.getDuration()))
+				) {
+					this.video.paused = true;
+					this.video.player.stopVideo();
+					this.drawCanvas();
+				}
+				if (this.playerReady) {
+					this.youtubeVideoCurrentTime = this.video.player
+						.getCurrentTime()
+						?.toFixed(3);
+				}
+
+				if (this.video.paused === false) this.drawCanvas();
+			}, 200);
+
+			if (window.YT && window.YT.Player) {
+				this.video.player = new window.YT.Player("editSongPlayer", {
+					height: 298,
+					width: 530,
+					videoId: null,
+					host: "https://www.youtube-nocookie.com",
+					playerVars: {
+						controls: 0,
+						iv_load_policy: 3,
+						rel: 0,
+						showinfo: 0,
+						autoplay: 0
+					},
+					startSeconds: this.song.skipDuration,
+					events: {
+						onReady: () => {
+							let volume = parseInt(
+								localStorage.getItem("volume")
+							);
+							volume = typeof volume === "number" ? volume : 20;
+							this.video.player.setVolume(volume);
+							if (volume > 0) this.video.player.unMute();
+
+							const duration = this.video.player.getDuration();
+
+							this.youtubeVideoDuration = duration.toFixed(3);
+							this.youtubeVideoNote = "(~)";
+							this.playerReady = true;
+
+							if (this.song && this.song._id)
+								this.video.player.cueVideoById(
+									this.song.youtubeId,
+									this.song.skipDuration
+								);
+
+							this.drawCanvas();
+						},
+						onStateChange: event => {
+							this.drawCanvas();
+
+							let skipToLast10SecsPressed = false;
+							if (
+								event.data === 1 &&
+								this.skipToLast10SecsPressed
+							) {
+								this.skipToLast10SecsPressed = false;
+								skipToLast10SecsPressed = true;
+							}
+
+							if (event.data === 1 && !skipToLast10SecsPressed) {
+								this.video.paused = false;
+								let youtubeDuration =
+									this.video.player.getDuration();
+								const newYoutubeVideoDuration =
+									youtubeDuration.toFixed(3);
+
+								const songDurationNumber = Number(
+									this.song.duration
+								);
+								const songDurationNumber2 =
+									Number(this.song.duration) + 1;
+								const songDurationNumber3 =
+									Number(this.song.duration) - 1;
+								const fixedSongDuration =
+									songDurationNumber.toFixed(3);
+								const fixedSongDuration2 =
+									songDurationNumber2.toFixed(3);
+								const fixedSongDuration3 =
+									songDurationNumber3.toFixed(3);
+
+								if (
+									this.youtubeVideoDuration !==
+										newYoutubeVideoDuration &&
+									(fixedSongDuration ===
+										this.youtubeVideoDuration ||
+										fixedSongDuration2 ===
+											this.youtubeVideoDuration ||
+										fixedSongDuration3 ===
+											this.youtubeVideoDuration)
+								)
+									this.song.duration =
+										newYoutubeVideoDuration;
+
+								this.youtubeVideoDuration =
+									newYoutubeVideoDuration;
+								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(
+										"Video can't play. Specified duration is bigger than the YouTube song duration."
+									);
+								}
+								if (this.song.duration <= 0) {
+									this.video.player.stopVideo();
+									this.video.paused = true;
+									return new Toast(
+										"Video can't play. Specified duration has to be more than 0 seconds."
+									);
+								}
+
+								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;
+							}
+
+							return false;
+						}
+					}
+				});
+			} else {
+				this.youtubeError = true;
+				this.youtubeErrorMessage = "Player could not be loaded.";
+			}
+		},
+		unloadSong() {
+			this.songDataLoaded = false;
+			if (this.video.player && this.video.player.stopVideo)
+				this.video.player.stopVideo();
+			this.socket.dispatch(
+				"apis.leaveRoom",
+				`edit-song.${this.song._id}`
+			);
+		},
+		loadSong(songId) {
+			console.log(`LOAD SONG ${songId}`);
 			this.socket.dispatch(
 				`songs.getSongFromSongId`,
-				this.song._id,
+				songId, // Was this.song._id
 				res => {
 					if (res.status === "success") {
 						let { song } = res.data;
 
-						if (this.song.prefill)
-							song = Object.assign(song, this.song.prefill);
+						// if (this.song.prefill)
+						// 	song = Object.assign(song, this.song.prefill);
 
-						if (this.song.discogs)
-							song = {
-								...song,
-								discogs: this.song.discogs
-							};
+						// if (this.song.discogs)
+						// 	song = {
+						// 		...song,
+						// 		discogs: this.song.discogs
+						// 	};
 
 						this.editSong(song);
 
+						console.log(321);
+
 						this.songDataLoaded = true;
 
 						this.socket.dispatch(
@@ -952,183 +1134,17 @@ export default {
 							`edit-song.${this.song._id}`
 						);
 
-						this.interval = setInterval(() => {
-							if (
-								this.song.duration !== -1 &&
-								this.video.paused === false &&
-								this.playerReady &&
-								(this.video.player.getCurrentTime() -
-									this.song.skipDuration >
-									this.song.duration ||
-									(this.video.player.getCurrentTime() > 0 &&
-										this.video.player.getCurrentTime() >=
-											this.video.player.getDuration()))
-							) {
-								this.video.paused = true;
-								this.video.player.stopVideo();
-								this.drawCanvas();
-							}
-							if (this.playerReady) {
-								this.youtubeVideoCurrentTime = this.video.player
-									.getCurrentTime()
-									.toFixed(3);
-							}
+						// console.log(this.video.player);
+						// console.log(this.video.player.loadVideoById);
 
-							if (this.video.paused === false) this.drawCanvas();
-						}, 200);
-
-						if (window.YT && window.YT.Player) {
-							this.video.player = new window.YT.Player(
-								"editSongPlayer",
-								{
-									height: 298,
-									width: 530,
-									videoId: this.song.youtubeId,
-									host: "https://www.youtube-nocookie.com",
-									playerVars: {
-										controls: 0,
-										iv_load_policy: 3,
-										rel: 0,
-										showinfo: 0,
-										autoplay: 0
-									},
-									startSeconds: this.song.skipDuration,
-									events: {
-										onReady: () => {
-											let volume = parseInt(
-												localStorage.getItem("volume")
-											);
-											volume =
-												typeof volume === "number"
-													? volume
-													: 20;
-											this.video.player.setVolume(volume);
-											if (volume > 0)
-												this.video.player.unMute();
-
-											const duration =
-												this.video.player.getDuration();
-
-											this.youtubeVideoDuration =
-												duration.toFixed(3);
-											this.youtubeVideoNote = "(~)";
-											this.playerReady = true;
-
-											this.drawCanvas();
-										},
-										onStateChange: event => {
-											this.drawCanvas();
-
-											let skipToLast10SecsPressed = false;
-											if (
-												event.data === 1 &&
-												this.skipToLast10SecsPressed
-											) {
-												this.skipToLast10SecsPressed = false;
-												skipToLast10SecsPressed = true;
-											}
-
-											if (
-												event.data === 1 &&
-												!skipToLast10SecsPressed
-											) {
-												this.video.paused = false;
-												let youtubeDuration =
-													this.video.player.getDuration();
-												const newYoutubeVideoDuration =
-													youtubeDuration.toFixed(3);
-
-												const songDurationNumber =
-													Number(this.song.duration);
-												const songDurationNumber2 =
-													Number(this.song.duration) +
-													1;
-												const songDurationNumber3 =
-													Number(this.song.duration) -
-													1;
-												const fixedSongDuration =
-													songDurationNumber.toFixed(
-														3
-													);
-												const fixedSongDuration2 =
-													songDurationNumber2.toFixed(
-														3
-													);
-												const fixedSongDuration3 =
-													songDurationNumber3.toFixed(
-														3
-													);
-
-												if (
-													this
-														.youtubeVideoDuration !==
-														newYoutubeVideoDuration &&
-													(fixedSongDuration ===
-														this
-															.youtubeVideoDuration ||
-														fixedSongDuration2 ===
-															this
-																.youtubeVideoDuration ||
-														fixedSongDuration3 ===
-															this
-																.youtubeVideoDuration)
-												)
-													this.song.duration =
-														newYoutubeVideoDuration;
-
-												this.youtubeVideoDuration =
-													newYoutubeVideoDuration;
-												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(
-														"Video can't play. Specified duration is bigger than the YouTube song duration."
-													);
-												}
-												if (this.song.duration <= 0) {
-													this.video.player.stopVideo();
-													this.video.paused = true;
-													return new Toast(
-														"Video can't play. Specified duration has to be more than 0 seconds."
-													);
-												}
-
-												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;
-											}
-
-											return false;
-										}
-									}
-								}
+						if (this.video.player && this.video.player.cueVideoById)
+							this.video.player.cueVideoById(
+								this.song.youtubeId,
+								this.song.skipDuration
 							);
-						} else {
-							this.youtubeError = true;
-							this.youtubeErrorMessage =
-								"Player could not be loaded.";
-						}
 					} else {
 						new Toast("Song with that ID not found");
-						this.closeModal("editSong");
+						// this.closeModal("editSong");
 					}
 				}
 			);
@@ -1519,6 +1535,8 @@ export default {
 				this.song.tags.splice(this.song.tags.indexOf(value), 1);
 		},
 		drawCanvas() {
+			if (!this.songDataLoaded) return;
+			console.log(111, this.songDataLoaded);
 			const canvasElement = this.$refs.durationCanvas;
 			const ctx = canvasElement.getContext("2d");
 

+ 244 - 0
frontend/src/components/modals/EditSongs.vue

@@ -0,0 +1,244 @@
+<template>
+	<edit-song v-if="currentSong" :song-id="currentSong._id" v-show="!closed">
+		<template #sidebar>
+			<div class="sidebar">
+				<header class="sidebar-head">
+					<h2 class="sidebar-title is-marginless">Edit Queue</h2>
+					<!-- <span class="delete material-icons" @click="closeCurrentModal()"
+						>highlight_off</span
+					> -->
+				</header>
+				<section class="sidebar-body">
+					<div
+						class="item"
+						v-for="{ status, song } in items"
+						:key="song._id"
+					>
+						<i
+							class="material-icons item-icon todo-icon"
+							v-if="status === 'todo'"
+							>cancel</i
+						>
+						<i
+							class="material-icons item-icon error-icon"
+							v-else-if="status === 'error'"
+							>error</i
+						>
+						<i
+							class="material-icons item-icon done-icon"
+							v-else-if="status === 'done'"
+							>check_circle</i
+						>
+						<i
+							class="material-icons item-icon flag-icon"
+							v-else-if="status === 'flag'"
+							>flag_circle</i
+						>
+						<i
+							class="material-icons item-icon editing-icon"
+							v-else-if="status === 'editing'"
+							>edit</i
+						>
+						<song-item
+							:song="song"
+							:thumbnail="false"
+							:duration="false"
+							:disabled-actions="['report']"
+						>
+							<template #actions>
+								<i
+									class="material-icons edit-icon"
+									content="Edit Song"
+									v-tippy
+									@click="pickSong(song)"
+								>
+									edit
+								</i>
+							</template>
+						</song-item>
+					</div>
+				</section>
+				<footer class="sidebar-foot">
+					<button @click="closeEditSongs()" class="button is-primary">
+						Close
+					</button>
+				</footer>
+			</div>
+		</template>
+	</edit-song>
+</template>
+
+<script>
+// eslint-disable-next-line no-unused-vars
+import { mapState, mapActions, mapGetters } from "vuex";
+import { defineAsyncComponent } from "vue";
+
+import SongItem from "@/components/SongItem.vue";
+
+export default {
+	components: {
+		EditSong: defineAsyncComponent(() =>
+			import("@/components/modals/EditSong")
+		),
+		SongItem
+	},
+	props: {},
+	data() {
+		return {
+			songIds: [
+				"58c8513977eadd0bfc3afced",
+				"58c8513977eadd0bfc3afcf3",
+				"58c8513977eadd0bfc3afd0c",
+				"58c8513977eadd0bfc3afd19",
+				"61a208911a62abe1765ed027",
+				"61a63326e32fe2f3c76fad61"
+			],
+			items: [],
+			currentSong: {},
+			closed: false
+		};
+	},
+	computed: {
+		...mapGetters({
+			socket: "websockets/getSocket"
+		})
+	},
+	async mounted() {
+		this.songIds.forEach(songId => {
+			this.socket.dispatch("songs.getSongFromSongId", songId, res => {
+				this.items.push({ status: "todo", song: res.data.song });
+			});
+		});
+	},
+	methods: {
+		pickSong(song) {
+			this.currentSong = song;
+			this.items[
+				this.items.findIndex(item => item.song._id === song._id)
+			].status = "editing";
+		},
+		closeEditSongs() {
+			this.closed = true;
+		},
+		...mapActions("modals/editSong", ["editSong"])
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+.sidebar {
+	width: 350px;
+	z-index: 2000;
+	display: flex;
+	flex-direction: column;
+	position: relative;
+	height: 100%;
+	max-height: calc(100vh - 40px);
+	overflow: auto;
+	margin-right: 8px;
+	// padding: 10px;
+	border-radius: 5px;
+
+	.sidebar-head,
+	.sidebar-foot {
+		display: flex;
+		flex-shrink: 0;
+		position: relative;
+		justify-content: flex-start;
+		align-items: center;
+		padding: 20px;
+		background-color: var(--light-grey);
+	}
+
+	.sidebar-head {
+		border-bottom: 1px solid var(--light-grey-2);
+		border-radius: 5px 5px 0 0;
+
+		.sidebar-title {
+			display: flex;
+			flex: 1;
+			margin: 0;
+			font-size: 26px;
+			font-weight: 600;
+		}
+
+		// .delete.material-icons {
+		// 	font-size: 28px;
+		// 	cursor: pointer;
+		// 	user-select: none;
+		// 	-webkit-user-drag: none;
+		// 	&:hover,
+		// 	&:focus {
+		// 		filter: brightness(90%);
+		// 	}
+		// }
+	}
+
+	.sidebar-body {
+		background-color: var(--white);
+		display: flex;
+		flex-direction: column;
+		row-gap: 8px;
+		flex: 1;
+		overflow: auto;
+		padding: 10px;
+
+		.item {
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+			column-gap: 8px;
+
+			.item-icon {
+				font-size: 32px;
+				line-height: 32px;
+			}
+
+			.error-icon {
+				color: var(--red);
+			}
+
+			.todo-icon {
+				color: var(--primary-color);
+			}
+
+			.done-icon {
+				color: var(--green);
+			}
+
+			.flag-icon {
+				color: var(--orange);
+			}
+
+			.editing-icon {
+				color: var(--primary-color);
+			}
+		}
+	}
+
+	.sidebar-foot {
+		border-top: 1px solid var(--light-grey-2);
+		border-radius: 0 0 5px 5px;
+		overflow: initial;
+		column-gap: 16px;
+
+		// & > div {
+		// 	display: flex;
+		// 	flex-grow: 1;
+		// 	column-gap: 16px;
+		// }
+
+		// .right {
+		// 	display: flex;
+		// 	margin-left: auto;
+		// 	margin-right: 0;
+		// 	justify-content: flex-end;
+		// 	column-gap: 16px;
+		// }
+
+		// &.blank {
+		// 	padding: 10px;
+		// }
+	}
+}
+</style>

+ 4 - 0
frontend/src/pages/Admin/tabs/Songs.vue

@@ -275,6 +275,7 @@
 		</div>
 		<import-album v-if="modals.importAlbum" />
 		<edit-song v-if="modals.editSong" song-type="songs" :key="song._id" />
+		<edit-songs />
 		<report v-if="modals.report" />
 		<request-song v-if="modals.requestSong" />
 		<confirm v-if="modals.confirm" @confirmed="handleConfirmed()" />
@@ -297,6 +298,9 @@ export default {
 		EditSong: defineAsyncComponent(() =>
 			import("@/components/modals/EditSong")
 		),
+		EditSongs: defineAsyncComponent(() =>
+			import("@/components/modals/EditSongs")
+		),
 		Report: defineAsyncComponent(() =>
 			import("@/components/modals/Report.vue")
 		),