Преглед на файлове

refactor: Converted editSong and editSongs stores from VueX to Pinia

Kristian Vos преди 2 години
родител
ревизия
c5bc29b61e

+ 9 - 13
frontend/src/components/modals/EditSong/Tabs/Discogs.vue

@@ -1,8 +1,11 @@
 <script setup lang="ts">
-import { ref, computed, onMounted } from "vue";
+import { ref, onMounted } from "vue";
+import { storeToRefs } from "pinia";
 import Toast from "toasters";
-import { useModalState, useModalActions } from "@/vuex_helpers";
 import keyboardShortcuts from "@/keyboardShortcuts";
+
+import { useEditSongStore } from "@/stores/editSong";
+
 import { useWebsocketsStore } from "@/stores/websockets";
 
 const props = defineProps({
@@ -14,20 +17,13 @@ const props = defineProps({
 	bulk: { type: Boolean, default: false }
 });
 
+const editSongStore = useEditSongStore(props);
+
 const { socket } = useWebsocketsStore();
 
-const modalState = useModalState(props.modalModulePath, {
-	modalUuid: props.modalUuid
-});
-const song = computed(() => modalState.song);
+const { song } = storeToRefs(editSongStore);
 
-const { selectDiscogsInfo } = useModalActions(
-	props.modalModulePath,
-	["selectDiscogsInfo"],
-	{
-		modalUuid: props.modalUuid
-	}
-);
+const { selectDiscogsInfo } = editSongStore;
 
 const discogs = ref({
 	apiResults: [],

+ 14 - 19
frontend/src/components/modals/EditSong/Tabs/Reports.vue

@@ -1,20 +1,25 @@
 <script setup lang="ts">
 import { defineAsyncComponent, ref, computed, onMounted } from "vue";
+import { storeToRefs } from "pinia";
 import Toast from "toasters";
+
+import { useEditSongStore } from "@/stores/editSong";
+
 import { useWebsocketsStore } from "@/stores/websockets";
-import { useModalState, useModalActions } from "@/vuex_helpers";
 
 const ReportInfoItem = defineAsyncComponent(
 	() => import("@/components/ReportInfoItem.vue")
 );
 
-const { socket } = useWebsocketsStore();
-
 const props = defineProps({
 	modalUuid: { type: String, default: "" },
 	modalModulePath: { type: String, default: "modals/editSong/MODAL_UUID" }
 });
 
+const editSongStore = useEditSongStore(props);
+
+const { socket } = useWebsocketsStore();
+
 const tab = ref("sort-by-report");
 const icons = ref({
 	duration: "timer",
@@ -26,15 +31,12 @@ const icons = ref({
 });
 const tabs = ref({});
 
-const { reports } = useModalState("MODAL_MODULE_PATH", {
-	modalUuid: props.modalUuid,
-	modalModulePath: props.modalModulePath
-});
+const { reports } = storeToRefs(editSongStore);
 
 const sortedByCategory = computed(() => {
 	const categories = {};
 
-	reports.forEach(report =>
+	reports.value.forEach(report =>
 		report.issues.forEach(issue => {
 			if (categories[issue.category])
 				categories[issue.category].push({
@@ -54,14 +56,7 @@ const sortedByCategory = computed(() => {
 // const closeModal = payload =>
 // 	store.dispatch("modalVisibility/closeModal", payload);
 
-const { resolveReport } = useModalActions(
-	"MODAL_MODULE_PATH",
-	["resolveReport"],
-	{
-		modalUuid: props.modalUuid,
-		modalModulePath: props.modalModulePath
-	}
-);
+const { resolveReport } = editSongStore;
 
 const showTab = _tab => {
 	tabs.value[`${_tab}-tab`].scrollIntoView({ block: "nearest" });
@@ -81,7 +76,7 @@ const toggleIssue = (reportId, issueId) => {
 onMounted(() => {
 	socket.on(
 		"event:admin.report.created",
-		res => reports.unshift(res.data.report),
+		res => reports.value.unshift(res.data.report),
 		{ modalUuid: props.modalUuid }
 	);
 
@@ -94,9 +89,9 @@ onMounted(() => {
 	socket.on(
 		"event:admin.report.issue.toggled",
 		res => {
-			reports.forEach((report, index) => {
+			reports.value.forEach((report, index) => {
 				if (report._id === res.data.reportId) {
-					const issue = reports[index].issues.find(
+					const issue = reports.value[index].issues.find(
 						issue => issue._id.toString() === res.data.issueId
 					);
 

+ 7 - 6
frontend/src/components/modals/EditSong/Tabs/Songs.vue

@@ -1,7 +1,9 @@
 <script setup lang="ts">
 import { defineAsyncComponent, ref, onMounted } from "vue";
 
-import { useModalState } from "@/vuex_helpers";
+import { storeToRefs } from "pinia";
+
+import { useEditSongStore } from "@/stores/editSong";
 
 import useSearchMusare from "@/composables/useSearchMusare";
 
@@ -16,10 +18,9 @@ const props = defineProps({
 
 const sitename = ref("Musare");
 
-const { song } = useModalState("MODAL_MODULE_PATH", {
-	modalUuid: props.modalUuid,
-	modalModulePath: props.modalModulePath
-});
+const editSongStore = useEditSongStore(props);
+
+const { song } = storeToRefs(editSongStore);
 
 const {
 	musareSearch,
@@ -31,7 +32,7 @@ const {
 onMounted(async () => {
 	sitename.value = await lofig.get("siteSettings.sitename");
 
-	musareSearch.value.query = song.title;
+	musareSearch.value.query = song.value.title;
 	searchForMusareSongs(1, false);
 });
 </script>

+ 7 - 13
frontend/src/components/modals/EditSong/Tabs/Youtube.vue

@@ -1,5 +1,7 @@
 <script setup lang="ts">
-import { useModalState, useModalActions } from "@/vuex_helpers";
+import { storeToRefs } from "pinia";
+
+import { useEditSongStore } from "@/stores/editSong";
 
 import useSearchYoutube from "@/composables/useSearchYoutube";
 
@@ -10,19 +12,11 @@ const props = defineProps({
 	modalModulePath: { type: String, default: "modals/editSong/MODAL_UUID" }
 });
 
-const { song, newSong } = useModalState("MODAL_MODULE_PATH", {
-	modalUuid: props.modalUuid,
-	modalModulePath: props.modalModulePath
-});
+const editSongStore = useEditSongStore(props);
 
-const { updateYoutubeId, updateTitle, updateThumbnail } = useModalActions(
-	"MODAL_MODULE_PATH",
-	["updateYoutubeId", "updateTitle", "updateThumbnail"],
-	{
-		modalUuid: props.modalUuid,
-		modalModulePath: props.modalModulePath
-	}
-);
+const { song, newSong } = storeToRefs(editSongStore);
+
+const { updateYoutubeId, updateTitle, updateThumbnail } = editSongStore;
 
 const { youtubeSearch, searchForSongs, loadMoreSongs } = useSearchYoutube();
 

+ 18 - 50
frontend/src/components/modals/EditSong/index.vue

@@ -1,5 +1,6 @@
 <script setup lang="ts">
 import { useStore } from "vuex";
+import { storeToRefs } from "pinia";
 import {
 	defineAsyncComponent,
 	ref,
@@ -9,12 +10,13 @@ import {
 	onBeforeUnmount
 } from "vue";
 import Toast from "toasters";
-import { useModalState, useModalActions } from "@/vuex_helpers";
 import aw from "@/aw";
 import ws from "@/ws";
 import validation from "@/validation";
 import keyboardShortcuts from "@/keyboardShortcuts";
+
 import { useWebsocketsStore } from "@/stores/websockets";
+import { useEditSongStore } from "@/stores/editSong";
 
 const FloatingBox = defineAsyncComponent(
 	() => import("@/components/FloatingBox.vue")
@@ -51,23 +53,22 @@ const emit = defineEmits([
 ]);
 
 const store = useStore();
-
+const editSongStore = useEditSongStore(props);
 const { socket } = useWebsocketsStore();
 
 const modals = computed(() => store.state.modalVisibility.modals);
 const activeModals = computed(() => store.state.modalVisibility.activeModals);
 
-const modalState = useModalState(props.modalModulePath, {
-	modalUuid: props.modalUuid
-});
-const tab = computed(() => modalState.tab);
-const video = computed(() => modalState.video);
-const song = computed(() => modalState.song);
-const youtubeId = computed(() => modalState.youtubeId);
-const prefillData = computed(() => modalState.prefillData);
-const originalSong = computed(() => modalState.originalSong);
-const reports = computed(() => modalState.reports);
-const newSong = computed(() => modalState.newSong);
+const {
+	tab,
+	video,
+	song,
+	youtubeId,
+	prefillData,
+	originalSong,
+	reports,
+	newSong
+} = storeToRefs(editSongStore);
 
 const songDataLoaded = ref(false);
 const songDeleted = ref(false);
@@ -159,24 +160,7 @@ const {
 	updateSongField,
 	updateReports,
 	setPlaybackRate
-} = useModalActions(
-	props.modalModulePath,
-	[
-		"stopVideo",
-		"hardStopVideo",
-		"loadVideoById",
-		"pauseVideo",
-		"setSong",
-		"resetSong",
-		"updateOriginalSong",
-		"updateSongField",
-		"updateReports",
-		"setPlaybackRate"
-	],
-	{
-		modalUuid: props.modalUuid
-	}
-);
+} = editSongStore;
 
 const openModal = payload =>
 	store.dispatch("modalVisibility/openModal", payload);
@@ -189,13 +173,7 @@ const closeCurrentModal = () => {
 const showTab = payload => {
 	if (tabs.value[`${payload}-tab`])
 		tabs.value[`${payload}-tab`].scrollIntoView({ block: "nearest" });
-	store.dispatch(
-		`${props.modalModulePath.replace(
-			"MODAL_UUID",
-			props.modalUuid
-		)}/showTab`,
-		payload
-	);
+	editSongStore.showTab(payload);
 };
 
 const onThumbnailLoad = () => {
@@ -268,7 +246,6 @@ const loadSong = _youtubeId => {
 
 const drawCanvas = () => {
 	if (!songDataLoaded.value || !canvasElement.value) return;
-	console.log(555, canvasElement.value);
 	const ctx = canvasElement.value.getContext("2d");
 
 	const videoDuration = Number(youtubeVideoDuration.value);
@@ -1275,17 +1252,8 @@ onBeforeUnmount(() => {
 		keyboardShortcuts.unregisterShortcut(shortcutName);
 	});
 
-	if (!props.bulk) {
-		// Delete the VueX module that was created for this modal, after all other cleanup tasks are performed
-		store.unregisterModule(["modals", "editSong", props.modalUuid]);
-	} else {
-		store.unregisterModule([
-			"modals",
-			"editSongs",
-			props.modalUuid,
-			"editSong"
-		]);
-	}
+	// Delete the Pinia store that was created for this modal, after all other cleanup tasks are performed
+	editSongStore.$dispose();
 });
 </script>
 

+ 21 - 27
frontend/src/components/modals/EditSongs.vue

@@ -1,17 +1,19 @@
 <script setup lang="ts">
 import { useStore } from "vuex";
+import { storeToRefs } from "pinia";
 import {
 	defineAsyncComponent,
 	ref,
 	computed,
-	onBeforeMount,
 	onMounted,
 	onBeforeUnmount,
 	onUnmounted
 } from "vue";
 import Toast from "toasters";
-import { useModalState, useModalActions } from "@/vuex_helpers";
-import editSongStore from "@/store/modules/modals/editSong";
+
+import { useEditSongStore } from "@/stores/editSong";
+import { useEditSongsStore } from "@/stores/editSongs";
+
 import { useWebsocketsStore } from "@/stores/websockets";
 
 const EditSongModal = defineAsyncComponent(
@@ -27,22 +29,14 @@ const props = defineProps({
 
 const store = useStore();
 
+const editSongStore = useEditSongStore(props);
+const editSongsStore = useEditSongsStore(props);
+
 const { socket } = useWebsocketsStore();
 
-const { youtubeIds, songPrefillData } = useModalState(
-	"modals/editSongs/MODAL_UUID",
-	{
-		modalUuid: props.modalUuid
-	}
-);
+const { youtubeIds, songPrefillData } = storeToRefs(editSongsStore);
 
-const { editSong } = useModalActions(
-	"modals/editSongs/MODAL_UUID/editSong",
-	["editSong"],
-	{
-		modalUuid: props.modalUuid
-	}
-);
+const { editSong } = editSongStore;
 
 const openModal = payload =>
 	store.dispatch("modalVisibility/openModal", payload);
@@ -85,7 +79,7 @@ const currentSongFlagged = computed(
 const pickSong = song => {
 	editSong({
 		youtubeId: song.youtubeId,
-		prefill: songPrefillData[song.youtubeId]
+		prefill: songPrefillData.value[song.youtubeId]
 	});
 	currentSong.value = song;
 	if (
@@ -209,20 +203,20 @@ const onClose = () => {
 	else closeCurrentModal();
 };
 
-onBeforeMount(() => {
-	console.log("EDITSONGS BEFOREMOUNT");
-	store.registerModule(
-		["modals", "editSongs", props.modalUuid, "editSong"],
-		editSongStore
-	);
-});
+// onBeforeMount(() => {
+// 	console.log("EDITSONGS BEFOREMOUNT");
+//  store.registerModule(
+//  	["modals", "editSongs", props.modalUuid, "editSong"],
+//  	editSongStore
+//  );
+// });
 
 onMounted(async () => {
 	console.log("EDITSONGS MOUNTED");
 
 	socket.dispatch("apis.joinRoom", "edit-songs");
 
-	socket.dispatch("songs.getSongsFromYoutubeIds", youtubeIds, res => {
+	socket.dispatch("songs.getSongsFromYoutubeIds", youtubeIds.value, res => {
 		if (res.data.songs.length === 0) {
 			closeCurrentModal();
 			new Toast("You can't edit 0 songs.");
@@ -298,8 +292,8 @@ onBeforeUnmount(() => {
 
 onUnmounted(() => {
 	console.log("EDITSONGS UNMOUNTED");
-	// Delete the VueX module that was created for this modal, after all other cleanup tasks are performed
-	store.unregisterModule(["modals", "editSongs", props.modalUuid]);
+	// Delete the Pinia store that was created for this modal, after all other cleanup tasks are performed
+	editSongsStore.$dispose();
 });
 </script>
 

+ 0 - 2
frontend/src/store/index.ts

@@ -13,8 +13,6 @@ export default createStore({
 		modals: {
 			namespaced: true,
 			modules: {
-				editSong: emptyModule,
-				editSongs: emptyModule,
 				importAlbum: emptyModule,
 				editPlaylist: emptyModule,
 				manageStation: emptyModule,

+ 9 - 5
frontend/src/store/modules/modalVisibility.ts

@@ -13,19 +13,19 @@ import viewApiRequest from "./modals/viewApiRequest";
 import viewPunishment from "./modals/viewPunishment";
 import importAlbum from "./modals/importAlbum";
 import confirm from "./modals/confirm";
-import editSongs from "./modals/editSongs";
-import editSong from "./modals/editSong";
 import viewYoutubeVideo from "./modals/viewYoutubeVideo";
 import removeAccount from "./modals/removeAccount";
 
 import { useEditUserStore } from "@/stores/editUser";
+import { useEditSongStore } from "@/stores/editSong";
+import { useEditSongsStore } from "@/stores/editSongs";
 
 const state = {
 	modals: {},
 	activeModals: []
 };
 
-const piniaStores = ["editUser"];
+const piniaStores = ["editUser", "editSong", "editSongs"];
 
 const modalModules = {
 	whatIsNew,
@@ -40,8 +40,6 @@ const modalModules = {
 	viewPunishment,
 	importAlbum,
 	confirm,
-	editSongs,
-	editSong,
 	viewYoutubeVideo,
 	removeAccount
 };
@@ -108,6 +106,12 @@ const mutations = {
 				case "editUser":
 					store = useEditUserStore({ modalUuid: uuid });
 					break;
+				case "editSong":
+					store = useEditSongStore({ modalUuid: uuid });
+					break;
+				case "editSongs":
+					store = useEditSongsStore({ modalUuid: uuid });
+					break;
 				default:
 					break;
 			}

+ 0 - 163
frontend/src/store/modules/modals/editSong.ts

@@ -1,163 +0,0 @@
-/* eslint no-param-reassign: 0 */
-
-export default {
-	namespaced: true,
-	state: {
-		video: {
-			player: null,
-			paused: true,
-			playerReady: false,
-			autoPlayed: false,
-			currentTime: 0,
-			playbackRate: 1
-		},
-		youtubeId: null,
-		song: {},
-		originalSong: {},
-		reports: [],
-		tab: "discogs",
-		newSong: false
-	},
-	getters: {},
-	actions: {
-		init: ({ commit }, { song }) => commit("editSong", song),
-		showTab: ({ commit }, tab) => commit("showTab", tab),
-		editSong: ({ commit }, song) => commit("editSong", song),
-		setSong: ({ commit }, song) => commit("setSong", song),
-		updateOriginalSong: ({ commit }, song) =>
-			commit("updateOriginalSong", song),
-		resetSong: ({ commit }, youtubeId) => commit("resetSong", youtubeId),
-		stopVideo: ({ commit }) => commit("stopVideo"),
-		hardStopVideo: ({ commit }) => commit("hardStopVideo"),
-		loadVideoById: ({ commit }, id, skipDuration) =>
-			commit("loadVideoById", id, skipDuration),
-		pauseVideo: ({ commit }, status) => commit("pauseVideo", status),
-		getCurrentTime: ({ commit, state }, fixedVal) =>
-			new Promise(resolve => {
-				commit("getCurrentTime", fixedVal);
-				resolve(state.video.currentTime);
-			}),
-		updateSongField: ({ commit }, data) => commit("updateSongField", data),
-		selectDiscogsInfo: ({ commit }, discogsInfo) =>
-			commit("selectDiscogsInfo", discogsInfo),
-		updateReports: ({ commit }, reports) =>
-			commit("updateReports", reports),
-		resolveReport: ({ commit }, reportId) =>
-			commit("resolveReport", reportId),
-		updateYoutubeId: ({ commit }, youtubeId) => {
-			commit("updateYoutubeId", youtubeId);
-			commit("loadVideoById", youtubeId, 0);
-		},
-		updateTitle: ({ commit }, title) => commit("updateTitle", title),
-		updateThumbnail: ({ commit }, thumbnail) =>
-			commit("updateThumbnail", thumbnail),
-		setPlaybackRate: ({ commit }, rate) => commit("setPlaybackRate", rate)
-	},
-	mutations: {
-		showTab(state, tab) {
-			state.tab = tab;
-		},
-		editSong(state, song) {
-			state.newSong = !!song.newSong || !song._id;
-			state.youtubeId = song.youtubeId || null;
-			state.prefillData = song.prefill ? song.prefill : {};
-		},
-		setSong(state, song) {
-			if (song.discogs === undefined) song.discogs = null;
-			state.originalSong = JSON.parse(JSON.stringify(song));
-			state.song = JSON.parse(JSON.stringify(song));
-			state.newSong = !song._id;
-			state.youtubeId = song.youtubeId;
-		},
-		updateOriginalSong(state, song) {
-			state.originalSong = JSON.parse(JSON.stringify(song));
-		},
-		resetSong(state, youtubeId) {
-			if (state.youtubeId === youtubeId) state.youtubeId = "";
-			if (state.song && state.song.youtubeId === youtubeId)
-				state.song = {};
-			if (
-				state.originalSong &&
-				state.originalSong.youtubeId === youtubeId
-			)
-				state.originalSong = {};
-		},
-		stopVideo(state) {
-			if (state.video.player && state.video.player.pauseVideo) {
-				state.video.player.pauseVideo();
-				state.video.player.seekTo(0);
-			}
-		},
-		hardStopVideo(state) {
-			if (state.video.player && state.video.player.stopVideo) {
-				state.video.player.stopVideo();
-			}
-		},
-		loadVideoById(state, id, skipDuration) {
-			state.song.duration = -1;
-			state.video.player.loadVideoById(id, skipDuration);
-		},
-		pauseVideo(state, status) {
-			if (
-				(state.video.player && state.video.player.pauseVideo) ||
-				state.video.playVideo
-			) {
-				if (status) state.video.player.pauseVideo();
-				else state.video.player.playVideo();
-			}
-			state.video.paused = status;
-		},
-		getCurrentTime(state, fixedVal) {
-			if (!state.playerReady) state.video.currentTime = 0;
-			else {
-				Promise.resolve(state.video.player.getCurrentTime()).then(
-					time => {
-						if (fixedVal)
-							Promise.resolve(time.toFixed(fixedVal)).then(
-								fixedTime => {
-									state.video.currentTime = fixedTime;
-								}
-							);
-						else state.video.currentTime = time;
-					}
-				);
-			}
-		},
-		updateSongField(state, data) {
-			state.song[data.field] = data.value;
-		},
-		selectDiscogsInfo(state, discogsInfo) {
-			state.song.discogs = discogsInfo;
-		},
-		updateReports(state, reports) {
-			state.reports = reports;
-		},
-		resolveReport(state, reportId) {
-			state.reports = state.reports.filter(
-				report => report._id !== reportId
-			);
-		},
-		updateYoutubeId(state, youtubeId) {
-			state.song.youtubeId = youtubeId;
-		},
-		updateTitle(state, title) {
-			state.song.title = title;
-		},
-		updateThumbnail(state, thumbnail) {
-			state.song.thumbnail = thumbnail;
-		},
-		setPlaybackRate(state, rate) {
-			if (rate) {
-				state.video.playbackRate = rate;
-				state.video.player.setPlaybackRate(rate);
-			} else if (
-				state.video.player.getPlaybackRate() !== undefined &&
-				state.video.playbackRate !==
-					state.video.player.getPlaybackRate()
-			) {
-				state.video.player.setPlaybackRate(state.video.playbackRate);
-				state.video.playbackRate = state.video.player.getPlaybackRate();
-			}
-		}
-	}
-};

+ 0 - 29
frontend/src/store/modules/modals/editSongs.ts

@@ -1,29 +0,0 @@
-/* eslint no-param-reassign: 0 */
-
-export default {
-	namespaced: true,
-	state: {
-		youtubeIds: [],
-		songPrefillData: {}
-	},
-	getters: {},
-	actions: {
-		init: ({ commit }, data) => commit("init", data)
-		// resetSongs: ({ commit }) => commit("resetSongs")
-	},
-	mutations: {
-		init(state, { songs }) {
-			state.youtubeIds = songs.map(song => song.youtubeId);
-			state.songPrefillData = Object.fromEntries(
-				songs.map(song => [
-					song.youtubeId,
-					song.prefill ? song.prefill : {}
-				])
-			);
-		}
-		// resetSongs(state) {
-		// 	state.youtubeIds = [];
-		// 	state.songPrefillData = {};
-		// }
-	}
-};

+ 145 - 0
frontend/src/stores/editSong.ts

@@ -0,0 +1,145 @@
+/* eslint no-param-reassign: 0 */
+
+import { defineStore } from "pinia";
+
+// TODO fix/decide eslint rule properly
+// eslint-disable-next-line
+export const useEditSongStore = props => {
+	const { modalUuid } = props;
+	return defineStore(`editSong-${modalUuid}`, {
+		state: () => ({
+			video: {
+				player: null,
+				paused: true,
+				playerReady: false,
+				autoPlayed: false,
+				currentTime: 0,
+				playbackRate: 1
+			},
+			youtubeId: null,
+			song: {},
+			originalSong: {},
+			reports: [],
+			tab: "discogs",
+			newSong: false,
+			prefillData: {}
+		}),
+		actions: {
+			init({ song }) {
+				this.editSong(song);
+			},
+			showTab(tab) {
+				this.tab = tab;
+			},
+			editSong(song) {
+				this.newSong = !!song.newSong || !song._id;
+				this.youtubeId = song.youtubeId || null;
+				this.prefillData = song.prefill ? song.prefill : {};
+			},
+			setSong(song) {
+				if (song.discogs === undefined) song.discogs = null;
+				this.originalSong = JSON.parse(JSON.stringify(song));
+				this.song = JSON.parse(JSON.stringify(song));
+				this.newSong = !song._id;
+				this.youtubeId = song.youtubeId;
+			},
+			updateOriginalSong(song) {
+				this.originalSong = JSON.parse(JSON.stringify(song));
+			},
+			resetSong(youtubeId) {
+				if (this.youtubeId === youtubeId) this.youtubeId = "";
+				if (this.song && this.song.youtubeId === youtubeId)
+					this.song = {};
+				if (
+					this.originalSong &&
+					this.originalSong.youtubeId === youtubeId
+				)
+					this.originalSong = {};
+			},
+			stopVideo() {
+				if (this.video.player && this.video.player.pauseVideo) {
+					this.video.player.pauseVideo();
+					this.video.player.seekTo(0);
+				}
+			},
+			hardStopVideo() {
+				if (this.video.player && this.video.player.stopVideo) {
+					this.video.player.stopVideo();
+				}
+			},
+			loadVideoById(id, skipDuration) {
+				this.song.duration = -1;
+				this.video.player.loadVideoById(id, skipDuration);
+			},
+			pauseVideo(status) {
+				if (
+					(this.video.player && this.video.player.pauseVideo) ||
+					this.video.playVideo
+				) {
+					if (status) this.video.player.pauseVideo();
+					else this.video.player.playVideo();
+				}
+				this.video.paused = status;
+			},
+			updateSongField(data) {
+				this.song[data.field] = data.value;
+			},
+			selectDiscogsInfo(discogsInfo) {
+				this.song.discogs = discogsInfo;
+			},
+			updateReports(reports) {
+				this.reports = reports;
+			},
+			resolveReport(reportId) {
+				this.reports = this.reports.filter(
+					report => report._id !== reportId
+				);
+			},
+			updateYoutubeId(youtubeId) {
+				this.song.youtubeId = youtubeId;
+				this.loadVideoById(youtubeId, 0);
+			},
+			updateTitle(title) {
+				this.song.title = title;
+			},
+			updateThumbnail(thumbnail) {
+				this.song.thumbnail = thumbnail;
+			},
+			setPlaybackRate(rate) {
+				if (rate) {
+					this.video.playbackRate = rate;
+					this.video.player.setPlaybackRate(rate);
+				} else if (
+					this.video.player.getPlaybackRate() !== undefined &&
+					this.video.playbackRate !==
+						this.video.player.getPlaybackRate()
+				) {
+					this.video.player.setPlaybackRate(this.video.playbackRate);
+					this.video.playbackRate =
+						this.video.player.getPlaybackRate();
+				}
+			},
+
+			getCurrentTime(fixedVal) {
+				// new Promise(resolve => {
+				// 	commit("getCurrentTime", fixedVal);
+				// 	resolve(this.video.currentTime);
+				// }),
+				// 	if (!this.playerReady) this.video.currentTime = 0;
+				// else {
+				// 	Promise.resolve(this.video.player.getCurrentTime()).then(
+				// 		time => {
+				// 			if (fixedVal)
+				// 				Promise.resolve(time.toFixed(fixedVal)).then(
+				// 					fixedTime => {
+				// 						this.video.currentTime = fixedTime;
+				// 					}
+				// 				);
+				// 			else this.video.currentTime = time;
+				// 		}
+				// 	);
+				// }
+			}
+		}
+	})();
+};

+ 30 - 0
frontend/src/stores/editSongs.ts

@@ -0,0 +1,30 @@
+/* eslint no-param-reassign: 0 */
+
+import { defineStore } from "pinia";
+
+// TODO fix/decide eslint rule properly
+// eslint-disable-next-line
+export const useEditSongsStore = props => {
+	const { modalUuid } = props;
+	return defineStore(`editSongs-${modalUuid}`, {
+		state: () => ({
+			youtubeIds: [],
+			songPrefillData: {}
+		}),
+		actions: {
+			init({ songs }) {
+				this.youtubeIds = songs.map(song => song.youtubeId);
+				this.songPrefillData = Object.fromEntries(
+					songs.map(song => [
+						song.youtubeId,
+						song.prefill ? song.prefill : {}
+					])
+				);
+			}
+			// 	resetSongs(state) {
+			// 	this.youtubeIds = [];
+			// 	this.songPrefillData = {};
+			// }
+		}
+	})();
+};