|
@@ -0,0 +1,896 @@
|
|
|
+<script setup lang="ts">
|
|
|
+/* eslint vue/no-unused-vars: 1 */
|
|
|
+/* eslint @typescript-eslint/no-unused-vars: 1 */
|
|
|
+
|
|
|
+import Toast from "toasters";
|
|
|
+import {
|
|
|
+ defineAsyncComponent,
|
|
|
+ ref,
|
|
|
+ reactive,
|
|
|
+ computed,
|
|
|
+ onMounted,
|
|
|
+ watch
|
|
|
+} from "vue";
|
|
|
+import { GenericResponse } from "@musare_types/actions/GenericActions";
|
|
|
+import VueJsonPretty from "vue-json-pretty";
|
|
|
+import { storeToRefs } from "pinia";
|
|
|
+import { useForm } from "@/composables/useForm";
|
|
|
+import { useWebsocketsStore } from "@/stores/websockets";
|
|
|
+import { useModalsStore } from "@/stores/modals";
|
|
|
+import { useLongJobsStore } from "@/stores/longJobs";
|
|
|
+import { useImportArtistStore } from "@/stores/importArtist";
|
|
|
+import "vue-json-pretty/lib/styles.css";
|
|
|
+import utils from "@/utils";
|
|
|
+// import { TempDraggableList } from "vue-draggable-list";
|
|
|
+const TempDraggableList = defineAsyncComponent(
|
|
|
+ () => import("@/components/TempDraggableList.vue")
|
|
|
+);
|
|
|
+const TempYoutubeChannelCard = defineAsyncComponent(
|
|
|
+ () => import("@/components/TempYoutubeChannelCard.vue")
|
|
|
+);
|
|
|
+const TempYoutubeVideoCard = defineAsyncComponent(
|
|
|
+ () => import("@/components/TempYoutubeVideoCard.vue")
|
|
|
+);
|
|
|
+
|
|
|
+const Modal = defineAsyncComponent(() => import("@/components/Modal.vue"));
|
|
|
+const SaveButton = defineAsyncComponent(
|
|
|
+ () => import("@/components/SaveButton.vue")
|
|
|
+);
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ modalUuid: { type: String, required: true },
|
|
|
+ artistId: { type: String, default: null }
|
|
|
+});
|
|
|
+
|
|
|
+const importArtistStore = useImportArtistStore({
|
|
|
+ modalUuid: props.modalUuid
|
|
|
+})();
|
|
|
+const {
|
|
|
+ artist,
|
|
|
+ youtubeChannels,
|
|
|
+ hideYoutubeChannel,
|
|
|
+ youtubeVideoMap,
|
|
|
+ youtubeVideoIds,
|
|
|
+ linkedVideos,
|
|
|
+ recordingsReleasesReleaseGroups,
|
|
|
+ filterYoutubeVideos,
|
|
|
+ recordingFilters,
|
|
|
+ recordingSort,
|
|
|
+ youtubeVideosSort,
|
|
|
+ youtubeVideoTitleChanges,
|
|
|
+ youtubeVideoFilters,
|
|
|
+ hideYoutubeInfo,
|
|
|
+ hideMusicbrainzInfo,
|
|
|
+ youtubeChannelIds,
|
|
|
+ // getters
|
|
|
+ recordings,
|
|
|
+ youtubeVideoMapAdjusted,
|
|
|
+ filteredRecordings,
|
|
|
+ filteredYoutubeVideoIds,
|
|
|
+ filteredYoutubeVideosIdsLength
|
|
|
+} = storeToRefs(importArtistStore);
|
|
|
+const {
|
|
|
+ setArtist,
|
|
|
+ setYoutubeChannels,
|
|
|
+ setYoutubeVideos,
|
|
|
+ setMusicBrainzRecordingsReleasesReleaseGroups,
|
|
|
+ linkVideos
|
|
|
+} = importArtistStore;
|
|
|
+
|
|
|
+const { socket } = useWebsocketsStore();
|
|
|
+
|
|
|
+const { closeCurrentModal } = useModalsStore();
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ socket.onConnect(() => {
|
|
|
+ if (props.artistId) {
|
|
|
+ socket.dispatch(`artists.getArtistFromId`, props.artistId, res => {
|
|
|
+ // res: GetArtistResponse
|
|
|
+ if (res.status === "success") {
|
|
|
+ setArtist(res.data.artist);
|
|
|
+
|
|
|
+ socket.dispatch(
|
|
|
+ `youtube.getChannelsById`,
|
|
|
+ youtubeChannelIds.value,
|
|
|
+ res => {
|
|
|
+ // TODO handle fail
|
|
|
+ const { data } = res;
|
|
|
+
|
|
|
+ setYoutubeChannels(data);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ socket.dispatch(
|
|
|
+ `youtube.getVideosForChannelIds`,
|
|
|
+ youtubeChannelIds.value,
|
|
|
+ res => {
|
|
|
+ console.log(333222111, res);
|
|
|
+
|
|
|
+ const { data } = res;
|
|
|
+
|
|
|
+ setYoutubeVideos(data);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ socket.dispatch(
|
|
|
+ `albums.getMusicBrainzRecordingsReleasesReleaseGroups`,
|
|
|
+ artist.value.musicbrainzIdentifier,
|
|
|
+ res => {
|
|
|
+ const { data } = res;
|
|
|
+
|
|
|
+ setMusicBrainzRecordingsReleasesReleaseGroups(
|
|
|
+ data.releases
|
|
|
+ );
|
|
|
+ }
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ new Toast("Artist with that ID not found.");
|
|
|
+ closeCurrentModal();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+const drag = ref(false);
|
|
|
+
|
|
|
+const repositionYoutubeVideo = () => {
|
|
|
+ console.log("Reposition youtube video");
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <modal
|
|
|
+ class="import-artist-mb-modal"
|
|
|
+ title="Import Artist MB"
|
|
|
+ :size="'wide'"
|
|
|
+ :split="true"
|
|
|
+ >
|
|
|
+ <template #body>
|
|
|
+ <div class="columns flex flex-row w-full">
|
|
|
+ <div class="column-left flex flex-column">
|
|
|
+ <div class="card artist-info-card flex flex-row">
|
|
|
+ <img src="/assets/notes.png" alt="Temp" />
|
|
|
+ <div>
|
|
|
+ <p>{{ artist.name }}</p>
|
|
|
+ <p>
|
|
|
+ MB:
|
|
|
+ <a
|
|
|
+ :href="`https://musicbrainz.org/artist/${artist.musicbrainzIdentifier}`"
|
|
|
+ >{{ artist.musicbrainzIdentifier }}</a
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="card recordings-card flex flex-column">
|
|
|
+ <div
|
|
|
+ class="flex flex-row"
|
|
|
+ style="justify-content: space-between"
|
|
|
+ >
|
|
|
+ <p class="card-title">Recordings to display</p>
|
|
|
+ <button class="button temp-button">
|
|
|
+ <i class="material-icons">filter_alt</i>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Filter
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="hideNullLength"
|
|
|
+ id="hideNullLength"
|
|
|
+ v-model="recordingFilters.hideNullLength"
|
|
|
+ />
|
|
|
+ <label for="hideNullLength"
|
|
|
+ >Hide null length</label
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="hidePartOf"
|
|
|
+ id="hidePartOf"
|
|
|
+ v-model="recordingFilters.hidePartOf"
|
|
|
+ />
|
|
|
+ <label for="hidePartOf">Hide part of</label>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Sort
|
|
|
+ <div>
|
|
|
+ <select
|
|
|
+ name="recordingSort"
|
|
|
+ id="recordingSort"
|
|
|
+ v-model="recordingSort"
|
|
|
+ >
|
|
|
+ <option value="title">Title</option>
|
|
|
+ <option value="length">Length</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Hide info
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="hideMusicbrainzInfo"
|
|
|
+ id="hideMusicbrainzInfo"
|
|
|
+ v-model="hideMusicbrainzInfo"
|
|
|
+ />
|
|
|
+ <label for="hideMusicbrainzInfo"
|
|
|
+ >Hide MusicBrainz info</label
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="flex flex-column recordings">
|
|
|
+ <div
|
|
|
+ v-for="recording in filteredRecordings"
|
|
|
+ :key="recording.id"
|
|
|
+ class="recording flex flex-row"
|
|
|
+ :class="recording.hide ? 'recording-hide' : ''"
|
|
|
+ >
|
|
|
+ <p>
|
|
|
+ <span>{{ recording.title }}</span>
|
|
|
+ <span v-if="recording.disambiguation"
|
|
|
+ >({{ recording.disambiguation }})</span
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <span>{{
|
|
|
+ utils.formatTime(recording.length / 1000)
|
|
|
+ }}</span>
|
|
|
+ <div class="icons">
|
|
|
+ <tippy
|
|
|
+ theme="info"
|
|
|
+ v-if="!hideMusicbrainzInfo"
|
|
|
+ >
|
|
|
+ <i class="material-icons">info</i>
|
|
|
+
|
|
|
+ <template #content>
|
|
|
+ <div>
|
|
|
+ <ul>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ Title:
|
|
|
+ {{
|
|
|
+ recording.title
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ Video:
|
|
|
+ {{
|
|
|
+ recording.video
|
|
|
+ ? "true"
|
|
|
+ : "false"
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ ID:
|
|
|
+ {{ recording.id }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ Length:
|
|
|
+ {{
|
|
|
+ recording.length
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li
|
|
|
+ v-if="
|
|
|
+ recording.disambiguation
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <p>
|
|
|
+ Disambiguation:
|
|
|
+ {{
|
|
|
+ recording.disambiguation
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </tippy>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="column-center flex flex-column">
|
|
|
+ <div class="card linking-card flex flex-column">
|
|
|
+ <div
|
|
|
+ class="flex flex-row"
|
|
|
+ style="justify-content: space-between"
|
|
|
+ >
|
|
|
+ <p class="card-title">Linking</p>
|
|
|
+ <div class="button-icons flex flex-row">
|
|
|
+ <i class="material-icons">settings</i>
|
|
|
+ <i class="material-icons">lock_open</i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <button
|
|
|
+ class="button is-primary"
|
|
|
+ @click="linkVideos"
|
|
|
+ >
|
|
|
+ Link
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="recordings flex flex-column">
|
|
|
+ <div
|
|
|
+ class="recording flex flex-column"
|
|
|
+ v-for="recording in filteredRecordings"
|
|
|
+ :key="recording.id"
|
|
|
+ v-show="!recording.hide"
|
|
|
+ >
|
|
|
+ <div class="flex flex-row">
|
|
|
+ <p>
|
|
|
+ {{ recording.title }}
|
|
|
+ <span v-if="recording.disambiguation"
|
|
|
+ >({{
|
|
|
+ recording.disambiguation
|
|
|
+ }})</span
|
|
|
+ >
|
|
|
+ </p>
|
|
|
+ <span>{{
|
|
|
+ utils.formatTime(
|
|
|
+ recording.length / 1000
|
|
|
+ )
|
|
|
+ }}</span>
|
|
|
+ <div class="button-icons flex flex-row">
|
|
|
+ <tippy
|
|
|
+ theme="info"
|
|
|
+ v-if="!hideMusicbrainzInfo"
|
|
|
+ >
|
|
|
+ <i class="material-icons">info</i>
|
|
|
+
|
|
|
+ <template #content>
|
|
|
+ <div>
|
|
|
+ <ul>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ Title:
|
|
|
+ {{
|
|
|
+ recording.title
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ Video:
|
|
|
+ {{
|
|
|
+ recording.video
|
|
|
+ ? "true"
|
|
|
+ : "false"
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ ID:
|
|
|
+ {{
|
|
|
+ recording.id
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <p>
|
|
|
+ Length:
|
|
|
+ {{
|
|
|
+ recording.length
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ <li
|
|
|
+ v-if="
|
|
|
+ recording.disambiguation
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <p>
|
|
|
+ Disambiguation:
|
|
|
+ {{
|
|
|
+ recording.disambiguation
|
|
|
+ }}
|
|
|
+ </p>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </tippy>
|
|
|
+ <button class="button temp-button">
|
|
|
+ <i class="material-icons"
|
|
|
+ >lock_open</i
|
|
|
+ >
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="youtube-videos flex flex-column">
|
|
|
+ <!-- <div class="youtube-video no-youtube-video" v-if="!linkedVideos[recording.id] || linkedVideos[recording.id].length === 0">
|
|
|
+ <p>No videos linked</p>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <temp-draggable-list
|
|
|
+ v-if="linkedVideos[recording.id]"
|
|
|
+ v-model:list="
|
|
|
+ linkedVideos[recording.id]
|
|
|
+ "
|
|
|
+ @start="drag = true"
|
|
|
+ @end="drag = false"
|
|
|
+ @update="repositionYoutubeVideo"
|
|
|
+ group="mb-youtube-videos"
|
|
|
+ :unique="true"
|
|
|
+ debug-name="linked-videos"
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ #item="{
|
|
|
+ element: youtubeVideoId,
|
|
|
+ index
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <temp-youtube-video-card
|
|
|
+ :youtube-video="
|
|
|
+ youtubeVideoMapAdjusted[
|
|
|
+ youtubeVideoId
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ :hide-youtube-info="
|
|
|
+ hideYoutubeInfo
|
|
|
+ "
|
|
|
+ :key="youtubeVideoId"
|
|
|
+ ></temp-youtube-video-card>
|
|
|
+ </template>
|
|
|
+ <template #empty-list-placeholder>
|
|
|
+ <div
|
|
|
+ class="youtube-video no-youtube-video"
|
|
|
+ >
|
|
|
+ <p>No videos linked</p>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </temp-draggable-list>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="column-right flex flex-column">
|
|
|
+ <div class="card youtube-channels-card">
|
|
|
+ <p class="card-title">
|
|
|
+ YouTube channels / playlists card
|
|
|
+ </p>
|
|
|
+ <div class="youtube-channels flex flex-column">
|
|
|
+ <temp-youtube-channel-card
|
|
|
+ v-for="youtubeChannel in youtubeChannels"
|
|
|
+ :youtube-channel="youtubeChannel"
|
|
|
+ :key="youtubeChannel.channelId"
|
|
|
+ >
|
|
|
+ </temp-youtube-channel-card>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="card youtube-videos-card">
|
|
|
+ <p class="card-title">
|
|
|
+ YouTube videos card ({{
|
|
|
+ filteredYoutubeVideosIdsLength
|
|
|
+ }}
|
|
|
+ / {{ youtubeVideoIds.length }})
|
|
|
+ </p>
|
|
|
+ <div>
|
|
|
+ Filter
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="teaser"
|
|
|
+ v-model="youtubeVideoFilters.teaser"
|
|
|
+ />
|
|
|
+ <label for="teaser">Teaser</label>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="under45"
|
|
|
+ v-model="youtubeVideoFilters.under45"
|
|
|
+ />
|
|
|
+ <label for="under45">Under 45s</label>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="live"
|
|
|
+ v-model="youtubeVideoFilters.live"
|
|
|
+ />
|
|
|
+ <label for="live">Live</label>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="tour"
|
|
|
+ v-model="youtubeVideoFilters.tour"
|
|
|
+ />
|
|
|
+ <label for="tour">Tour</label>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Name
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="artistDash"
|
|
|
+ v-model="
|
|
|
+ youtubeVideoTitleChanges.artistDash
|
|
|
+ "
|
|
|
+ />
|
|
|
+ <label for="artistDash">artistDash</label>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="parantheses"
|
|
|
+ v-model="
|
|
|
+ youtubeVideoTitleChanges.parantheses
|
|
|
+ "
|
|
|
+ />
|
|
|
+ <label for="parantheses">parantheses</label>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="brackets"
|
|
|
+ v-model="youtubeVideoTitleChanges.brackets"
|
|
|
+ />
|
|
|
+ <label for="brackets">brackets</label>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="commonPhrases"
|
|
|
+ v-model="
|
|
|
+ youtubeVideoTitleChanges.commonPhrases
|
|
|
+ "
|
|
|
+ />
|
|
|
+ <label for="commonPhrases"
|
|
|
+ >common phrases (official mv, official
|
|
|
+ audio, official video)</label
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Sort
|
|
|
+ <div>
|
|
|
+ <select
|
|
|
+ name="youtubeVideosSort"
|
|
|
+ id="youtubeVideosSort"
|
|
|
+ v-model="youtubeVideosSort"
|
|
|
+ >
|
|
|
+ <option value="title">Title</option>
|
|
|
+ <option value="length">Length</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Hide info
|
|
|
+ <div>
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ name="hideYoutubeInfo"
|
|
|
+ id="hideYoutubeInfo"
|
|
|
+ v-model="hideYoutubeInfo"
|
|
|
+ />
|
|
|
+ <label for="hideYoutubeInfo"
|
|
|
+ >Hide YouTube info</label
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Hide YouTube channels
|
|
|
+ <div
|
|
|
+ v-for="youtubeChannel in youtubeChannels"
|
|
|
+ :key="youtubeChannel.rawData.id"
|
|
|
+ >
|
|
|
+ <input
|
|
|
+ type="checkbox"
|
|
|
+ :name="youtubeChannel.rawData.id"
|
|
|
+ :id="youtubeChannel.rawData.id"
|
|
|
+ v-model="
|
|
|
+ hideYoutubeChannel[
|
|
|
+ youtubeChannel.rawData.id
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ />
|
|
|
+ <label :for="youtubeChannel.rawData.id"
|
|
|
+ >Hide {{ youtubeChannel.title }}</label
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ Filter
|
|
|
+ <input type="text" v-model="filterYoutubeVideos" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="flex flex-column youtube-videos">
|
|
|
+ <temp-draggable-list
|
|
|
+ v-if="filteredYoutubeVideoIds.length > 0"
|
|
|
+ v-model:list="filteredYoutubeVideoIds"
|
|
|
+ @start="drag = true"
|
|
|
+ @end="drag = false"
|
|
|
+ @update="repositionYoutubeVideo"
|
|
|
+ :read-only="true"
|
|
|
+ group="mb-youtube-videos"
|
|
|
+ debug-name="youtube-videos"
|
|
|
+ >
|
|
|
+ <template
|
|
|
+ #item="{ element: youtubeVideoId, index }"
|
|
|
+ >
|
|
|
+ <temp-youtube-video-card
|
|
|
+ :youtube-video="
|
|
|
+ youtubeVideoMapAdjusted[
|
|
|
+ youtubeVideoId
|
|
|
+ ]
|
|
|
+ "
|
|
|
+ :hide-youtube-info="hideYoutubeInfo"
|
|
|
+ :key="youtubeVideoId"
|
|
|
+ ></temp-youtube-video-card>
|
|
|
+ </template>
|
|
|
+ </temp-draggable-list>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template #footer>
|
|
|
+ <div>
|
|
|
+ <!-- <save-button
|
|
|
+ v-if="!importMode"
|
|
|
+ :default-message="`${createArtist ? 'Create' : 'Update'} Artist`"
|
|
|
+ @clicked="saveArtist()"
|
|
|
+ />
|
|
|
+ <save-button
|
|
|
+ v-if="!importMode"
|
|
|
+ :default-message="`${createArtist ? 'Create' : 'Update'} and close`"
|
|
|
+ @clicked="saveArtist(true)"
|
|
|
+ />
|
|
|
+ <button
|
|
|
+ v-if="!createArtist"
|
|
|
+ class="button is-primary"
|
|
|
+ @click="toggleImportMode()"
|
|
|
+ >
|
|
|
+ <span v-if="importMode">Edit Mode</span>
|
|
|
+ <span v-else>Import Mode</span>
|
|
|
+ </button> -->
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </modal>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="less">
|
|
|
+// .night-mode {
|
|
|
+// .edit-artist-modal {
|
|
|
+// .vjs-tree-node.is-highlight,
|
|
|
+// .vjs-tree-node:hover {
|
|
|
+// background: black;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+.import-artist-mb-modal {
|
|
|
+ .modal-card {
|
|
|
+ width: 100% !important;
|
|
|
+ // height: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.flex {
|
|
|
+ display: flex;
|
|
|
+}
|
|
|
+
|
|
|
+.flex-column {
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.flex-row {
|
|
|
+ flex-direction: row;
|
|
|
+}
|
|
|
+
|
|
|
+.w-full {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.card {
|
|
|
+ background-color: var(--dark-grey-3);
|
|
|
+ border-radius: @border-radius;
|
|
|
+}
|
|
|
+
|
|
|
+.columns {
|
|
|
+ gap: 16px;
|
|
|
+ max-height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.column-left,
|
|
|
+.column-right {
|
|
|
+ width: 25%;
|
|
|
+ max-height: 100%;
|
|
|
+ overflow: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.column-center {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.column-left,
|
|
|
+.column-center,
|
|
|
+.column-right {
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.artist-info-card {
|
|
|
+ padding: 8px;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ // Temp
|
|
|
+ img {
|
|
|
+ aspect-ratio: 1/1;
|
|
|
+ max-width: 100px;
|
|
|
+ }
|
|
|
+
|
|
|
+ p:first-of-type {
|
|
|
+ font-size: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ p:last-of-type {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.card-title {
|
|
|
+ font-size: 20px;
|
|
|
+ line-height: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.recordings-card {
|
|
|
+ padding: 8px;
|
|
|
+ height: 100%;
|
|
|
+ gap: 16px;
|
|
|
+ // font-size: 20px;
|
|
|
+
|
|
|
+ .recordings {
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .recording {
|
|
|
+ background-color: var(--dark-grey-2);
|
|
|
+ border-radius: @border-radius;
|
|
|
+ padding: 8px;
|
|
|
+ font-size: 16px;
|
|
|
+ gap: 8px;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ > p {
|
|
|
+ flex: 1;
|
|
|
+ line-height: 24px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ // gap: 4px;
|
|
|
+
|
|
|
+ span:nth-child(2) {
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .icons {
|
|
|
+ height: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.recording-hide {
|
|
|
+ opacity: 0.5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.linking-card {
|
|
|
+ padding: 8px;
|
|
|
+ height: 100%;
|
|
|
+ gap: 16px;
|
|
|
+
|
|
|
+ > div > p {
|
|
|
+ // font-size: 20px;
|
|
|
+ // line-height: 24px;
|
|
|
+
|
|
|
+ .button-icons {
|
|
|
+ gap: 8px;
|
|
|
+ padding: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .recordings {
|
|
|
+ gap: 8px;
|
|
|
+ overflow: auto;
|
|
|
+ max-height: 100%;
|
|
|
+
|
|
|
+ .recording {
|
|
|
+ background-color: var(--dark-grey-2);
|
|
|
+ border-radius: @border-radius;
|
|
|
+ padding: 8px;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ > div:first-child {
|
|
|
+ gap: 8px;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ p {
|
|
|
+ font-size: 16px;
|
|
|
+ line-height: 20px;
|
|
|
+ flex: 1;
|
|
|
+
|
|
|
+ span {
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ > span {
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .button-icons {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .youtube-videos {
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .youtube-video {
|
|
|
+ background-color: var(--dark-grey);
|
|
|
+ border-radius: @border-radius;
|
|
|
+ gap: 8px;
|
|
|
+ min-width: 350px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .no-youtube-video {
|
|
|
+ padding: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.youtube-channels-card {
|
|
|
+ padding: 8px;
|
|
|
+
|
|
|
+ .youtube-channels {
|
|
|
+ gap: 8px;
|
|
|
+ margin-top: 16px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.youtube-videos-card {
|
|
|
+ padding: 8px;
|
|
|
+
|
|
|
+ .youtube-videos {
|
|
|
+ gap: 8px;
|
|
|
+ margin-top: 16px;
|
|
|
+
|
|
|
+ .youtube-video {
|
|
|
+ background-color: var(--dark-grey);
|
|
|
+ border-radius: @border-radius;
|
|
|
+ gap: 8px;
|
|
|
+ min-width: 350px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.temp-button {
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ background: none;
|
|
|
+ color: white;
|
|
|
+ outline: none;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+</style>
|