|
@@ -0,0 +1,493 @@
|
|
|
+import { defineStore } from "pinia";
|
|
|
+import {
|
|
|
+ ref,
|
|
|
+ computed
|
|
|
+ // watch
|
|
|
+} from "vue";
|
|
|
+import {
|
|
|
+ ArtistTemp,
|
|
|
+ RecordingTemp,
|
|
|
+ ReleaseGroupTemp,
|
|
|
+ // YoutubeVideoTemp,
|
|
|
+ ReleaseTemp,
|
|
|
+ URLTemp,
|
|
|
+ WorkTemp
|
|
|
+ // YoutubeChannelTemp,
|
|
|
+ // RecordingTemp
|
|
|
+} from "@/types/artist";
|
|
|
+
|
|
|
+// type LinkedVideos = { [k: string]: string[] };
|
|
|
+// type YoutubeVideoMap = { [k: string]: YoutubeVideoTemp };
|
|
|
+// type HideYoutubeChannel = { [k: string]: boolean };
|
|
|
+
|
|
|
+const measureStart = name => {
|
|
|
+ performance.mark(`${name}-started`);
|
|
|
+ console.log(`[MEASURE] START: ${name}`);
|
|
|
+};
|
|
|
+
|
|
|
+const measureFinish = name => {
|
|
|
+ performance.mark(`${name}-finished`);
|
|
|
+ const measure = performance.measure(
|
|
|
+ `${name}-duration`,
|
|
|
+ `${name}-started`,
|
|
|
+ `${name}-finished`
|
|
|
+ );
|
|
|
+ console.log(`[MEASURE] FINISH: ${name} - ${measure.duration}ms`);
|
|
|
+};
|
|
|
+
|
|
|
+type URLSourceTemp = {
|
|
|
+ type: string;
|
|
|
+ id: string;
|
|
|
+ url: URLTemp;
|
|
|
+};
|
|
|
+
|
|
|
+export const useViewMBArtistStore = ({ modalUuid }: { modalUuid: string }) =>
|
|
|
+ defineStore(`viewMBArtist-${modalUuid}`, () => {
|
|
|
+ const artist = ref<ArtistTemp | Partial<ArtistTemp>>({});
|
|
|
+ const recordingsReleasesReleaseGroups = ref<ReleaseTemp[]>([]);
|
|
|
+
|
|
|
+ const releaseMap = ref<{ [releaseId: string]: ReleaseTemp }>();
|
|
|
+ const releaseGroupMap = ref<{
|
|
|
+ [releaseId: string]: ReleaseGroupTemp;
|
|
|
+ }>();
|
|
|
+ const recordingMap = ref<{ [releaseId: string]: RecordingTemp }>();
|
|
|
+ const workMap = ref<{ [workId: string]: WorkTemp }>();
|
|
|
+ const urlMap = ref<{ [urlId: string]: URLTemp }>();
|
|
|
+ const urlSourceMap = ref<{ [recordingId: string]: URLSourceTemp[] }>(
|
|
|
+ {}
|
|
|
+ );
|
|
|
+
|
|
|
+ const releaseIds = ref();
|
|
|
+ const releaseGroupIds = ref();
|
|
|
+ const recordingIds = ref();
|
|
|
+ const workIds = ref();
|
|
|
+ const urlIds = ref();
|
|
|
+
|
|
|
+ const recordingsLimit = ref<number>(1);
|
|
|
+
|
|
|
+ const setArtist = ({ name, musicbrainzIdentifier }) => {
|
|
|
+ measureStart("setArtist");
|
|
|
+ artist.value = {
|
|
|
+ name,
|
|
|
+ musicbrainzIdentifier
|
|
|
+ };
|
|
|
+ measureFinish("setArtist");
|
|
|
+ };
|
|
|
+ const setMusicBrainzRecordingsReleasesReleaseGroups = (
|
|
|
+ artistReleases: ReleaseTemp[],
|
|
|
+ trackArtistReleases: ReleaseTemp[],
|
|
|
+ recordings: RecordingTemp[]
|
|
|
+ ) => {
|
|
|
+ measureStart("setMusicBrainzRecordingsReleasesReleaseGroups");
|
|
|
+ // _recordingsReleasesReleaseGroups = _recordingsReleasesReleaseGroups.slice(0, 10);
|
|
|
+ console.log(
|
|
|
+ "albums.getMusicBrainzRecordingsReleasesReleaseGroups",
|
|
|
+ artistReleases,
|
|
|
+ trackArtistReleases
|
|
|
+ );
|
|
|
+ measureStart("setMusicBrainzRecordingsReleasesReleaseGroups 1");
|
|
|
+ recordingsReleasesReleaseGroups.value = [
|
|
|
+ ...artistReleases,
|
|
|
+ ...trackArtistReleases
|
|
|
+ ];
|
|
|
+
|
|
|
+ const _recordingMap = {};
|
|
|
+ const _releaseMap = {};
|
|
|
+ const _releaseGroupMap = {};
|
|
|
+ const _workMap = {};
|
|
|
+ const _urlMap = {};
|
|
|
+ const _urlSourceMap = {};
|
|
|
+
|
|
|
+ recordings.forEach(recording => {
|
|
|
+ _recordingMap[recording.id] = recording;
|
|
|
+ _urlSourceMap[recording.id] = [];
|
|
|
+
|
|
|
+ recording.relations.forEach(relation => {
|
|
|
+ if (relation["target-type"] === "work") {
|
|
|
+ const { work } = relation;
|
|
|
+ if (!_workMap[work.id]) _workMap[work.id] = work;
|
|
|
+ }
|
|
|
+ if (relation["target-type"] === "url") {
|
|
|
+ const { url } = relation;
|
|
|
+ if (!_urlMap[url.id]) _urlMap[url.id] = url;
|
|
|
+ _urlSourceMap[recording.id].push({
|
|
|
+ type: "Recording",
|
|
|
+ id: recording.id,
|
|
|
+ url
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ measureFinish("setMusicBrainzRecordingsReleasesReleaseGroups 1");
|
|
|
+
|
|
|
+ measureStart("setMusicBrainzRecordingsReleasesReleaseGroups 2");
|
|
|
+ recordingsReleasesReleaseGroups.value.forEach(release => {
|
|
|
+ const releaseGroup = release["release-group"];
|
|
|
+
|
|
|
+ if (!_releaseMap[release.id]) _releaseMap[release.id] = release;
|
|
|
+ if (!_releaseGroupMap[releaseGroup.id])
|
|
|
+ _releaseGroupMap[releaseGroup.id] = releaseGroup;
|
|
|
+
|
|
|
+ const urlSources = [];
|
|
|
+ release.relations.forEach(relation => {
|
|
|
+ if (relation["target-type"] !== "url") return;
|
|
|
+ const { url } = relation;
|
|
|
+ if (!_urlMap[url.id]) _urlMap[url.id] = url;
|
|
|
+ urlSources.push({
|
|
|
+ type: "Release",
|
|
|
+ id: release.id,
|
|
|
+ url
|
|
|
+ });
|
|
|
+ });
|
|
|
+ releaseGroup.relations.forEach(relation => {
|
|
|
+ if (relation["target-type"] !== "url") return;
|
|
|
+ const { url } = relation;
|
|
|
+ if (!_urlMap[url.id]) _urlMap[url.id] = url;
|
|
|
+ urlSources.push({
|
|
|
+ type: "Release group",
|
|
|
+ id: releaseGroup.id,
|
|
|
+ url
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ release.media.forEach(media => {
|
|
|
+ if (!media.tracks) return;
|
|
|
+ media.tracks.forEach(track => {
|
|
|
+ const { recording } = track;
|
|
|
+
|
|
|
+ if (!_recordingMap[recording.id]) return;
|
|
|
+
|
|
|
+ _urlSourceMap[recording.id] = [
|
|
|
+ ...urlSources,
|
|
|
+ ..._urlSourceMap[recording.id]
|
|
|
+ ];
|
|
|
+
|
|
|
+ // _urlSourceMap[recording.id] =
|
|
|
+ // console.log(`${recording.id}:`, urlMap);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ measureFinish("setMusicBrainzRecordingsReleasesReleaseGroups 2");
|
|
|
+
|
|
|
+ measureStart("setMusicBrainzRecordingsReleasesReleaseGroups 3");
|
|
|
+ recordingMap.value = _recordingMap;
|
|
|
+ releaseMap.value = _releaseMap;
|
|
|
+ releaseGroupMap.value = _releaseGroupMap;
|
|
|
+ workMap.value = _workMap;
|
|
|
+ urlMap.value = _urlMap;
|
|
|
+ urlSourceMap.value = _urlSourceMap;
|
|
|
+
|
|
|
+ releaseIds.value = Object.keys(releaseMap.value);
|
|
|
+ releaseGroupIds.value = Object.keys(releaseGroupMap.value);
|
|
|
+ recordingIds.value = Object.keys(recordingMap.value);
|
|
|
+ workIds.value = Object.keys(workMap.value);
|
|
|
+ urlIds.value = Object.keys(urlMap.value);
|
|
|
+ measureFinish("setMusicBrainzRecordingsReleasesReleaseGroups 3");
|
|
|
+
|
|
|
+ measureFinish("setMusicBrainzRecordingsReleasesReleaseGroups");
|
|
|
+ };
|
|
|
+
|
|
|
+ const releaseGroupIdsForRecordingIdMap = computed<{
|
|
|
+ [recordingId: string]: string[];
|
|
|
+ }>(() => {
|
|
|
+ measureStart("computed releaseGroupIdsForRecordingIdMap");
|
|
|
+ const map = {};
|
|
|
+ recordingIds.value.forEach(recordingId => {
|
|
|
+ map[recordingId] = [];
|
|
|
+ });
|
|
|
+ releaseIds.value.forEach(releaseId => {
|
|
|
+ const release = releaseMap.value[releaseId];
|
|
|
+ const releaseGroupId = release["release-group"].id;
|
|
|
+ release.media.forEach(media => {
|
|
|
+ if (!media.tracks) return;
|
|
|
+ media.tracks.forEach(track => {
|
|
|
+ const { recording } = track;
|
|
|
+ const recordingId = recording.id;
|
|
|
+ if (!recordingIds.value.includes(recordingId)) return;
|
|
|
+ if (!map[recordingId].includes(releaseGroupId))
|
|
|
+ map[recordingId].push(releaseGroupId);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ measureFinish("computed releaseGroupIdsForRecordingIdMap");
|
|
|
+ return map;
|
|
|
+ });
|
|
|
+ const releaseIdsForRecordingIdMap = computed<{
|
|
|
+ [recordingId: string]: string[];
|
|
|
+ }>(() => {
|
|
|
+ measureStart("computed releaseIdsForRecordingIdMap");
|
|
|
+ const map = {};
|
|
|
+ recordingIds.value.forEach(recordingId => {
|
|
|
+ map[recordingId] = [];
|
|
|
+ });
|
|
|
+ releaseIds.value.forEach(releaseId => {
|
|
|
+ const release = releaseMap.value[releaseId];
|
|
|
+ release.media.forEach(media => {
|
|
|
+ if (!media.tracks) return;
|
|
|
+ media.tracks.forEach(track => {
|
|
|
+ const { recording } = track;
|
|
|
+ const recordingId = recording.id;
|
|
|
+ if (!recordingIds.value.includes(recordingId)) return;
|
|
|
+ if (!map[recordingId].includes(releaseId))
|
|
|
+ map[recordingId].push(releaseId);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ recordingIds.value.forEach(recordingId => {
|
|
|
+ map[recordingId].sort((releaseIdA, releaseIdB) => {
|
|
|
+ const releaseA = releaseMap.value[releaseIdA];
|
|
|
+ const releaseB = releaseMap.value[releaseIdB];
|
|
|
+
|
|
|
+ const dateA = releaseA.date ?? "X";
|
|
|
+ const dateB = releaseB.date ?? "X";
|
|
|
+
|
|
|
+ return dateA.localeCompare(dateB);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ measureFinish("computed releaseIdsForRecordingIdMap");
|
|
|
+ return map;
|
|
|
+ });
|
|
|
+ const workIdsForRecordingIdMap = computed<{
|
|
|
+ [recordingId: string]: string[];
|
|
|
+ }>(() => {
|
|
|
+ measureStart("computed workIdsForRecordingIdMap");
|
|
|
+ const map = {};
|
|
|
+ recordingIds.value.forEach(recordingId => {
|
|
|
+ map[recordingId] = [];
|
|
|
+ const recording = recordingMap.value[recordingId];
|
|
|
+ // console.log(111222333, recording, recording.relations);
|
|
|
+ recording.relations.forEach(relation => {
|
|
|
+ if (relation["target-type"] !== "work") return;
|
|
|
+ const { work } = relation;
|
|
|
+ if (!map[recording.id].includes(work.id))
|
|
|
+ map[recording.id].push(work.id);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ // releaseIds.value.forEach(releaseId => {
|
|
|
+ // const release = releaseMap.value[releaseId];
|
|
|
+ // // const releaseGroupId = release["release-group"].id;
|
|
|
+ // release.media.forEach(media => {
|
|
|
+ // if (!media.tracks) return;
|
|
|
+ // media.tracks.forEach(track => {
|
|
|
+ // const { recording } = track;
|
|
|
+ // if (!recordingIds.value.includes(recording.id)) return;
|
|
|
+ // console.log(111222333, recording, recording.relations);
|
|
|
+ // recording.relations.forEach(relation => {
|
|
|
+ // if (relation["target-type"] !== "work") return;
|
|
|
+ // const { work } = relation;
|
|
|
+ // if (!map[recording.id].includes(work.id))
|
|
|
+ // map[recording.id].push(work.id);
|
|
|
+ // });
|
|
|
+ // });
|
|
|
+ // });
|
|
|
+ // });
|
|
|
+ measureFinish("computed workIdsForRecordingIdMap");
|
|
|
+ return map;
|
|
|
+ });
|
|
|
+ // const urlIdsForRecordingIdMap = computed<{
|
|
|
+ // [recordingId: string]: string[];
|
|
|
+ // }>(() => {
|
|
|
+ // measureStart("computed urlIdsForRecordingIdMap");
|
|
|
+ // const map = {};
|
|
|
+ // recordingIds.value.forEach(recordingId => {
|
|
|
+ // map[recordingId] = [];
|
|
|
+ // urlSourceMap[recordingId].forEach(urlSource => {
|
|
|
+
|
|
|
+ // })
|
|
|
+ // // const recording = recordingMap.value[recordingId];
|
|
|
+ // // recording.relations.forEach(relation => {
|
|
|
+ // // if (relation["target-type"] !== "url") return;
|
|
|
+ // // const { url } = relation;
|
|
|
+ // // if (!map[recording.id].includes(url.id))
|
|
|
+ // // map[recording.id].push(url.id);
|
|
|
+ // // });
|
|
|
+ // });
|
|
|
+ // // releaseIds.value.forEach(releaseId => {
|
|
|
+ // // const release = releaseMap.value[releaseId];
|
|
|
+ // // release.media.forEach(media => {
|
|
|
+ // // if (!media.tracks) return;
|
|
|
+ // // media.tracks.forEach(track => {
|
|
|
+ // // const { recording } = track;
|
|
|
+ // // if (!recordingIds.value.includes(recording.id)) return;
|
|
|
+ // // recording.relations.forEach(relation => {
|
|
|
+ // // if (relation["target-type"] !== "url") return;
|
|
|
+ // // const { url } = relation;
|
|
|
+ // // if (!map[recording.id].includes(url.id))
|
|
|
+ // // map[recording.id].push(url.id);
|
|
|
+ // // });
|
|
|
+ // // });
|
|
|
+ // // });
|
|
|
+ // // });
|
|
|
+ // measureFinish("computed workIdsForRecordingIdMap");
|
|
|
+ // return map;
|
|
|
+ // });
|
|
|
+ const releaseGroupTypeMapForRecordingMap = computed(() => {
|
|
|
+ measureStart("releaseGroupTypeMapForRecordingMap");
|
|
|
+ const map = {};
|
|
|
+ recordingIds.value.forEach(recordingId => {
|
|
|
+ const releaseGroupIds =
|
|
|
+ releaseGroupIdsForRecordingIdMap.value[recordingId];
|
|
|
+ const typeMap = {};
|
|
|
+ const typeKeys = [];
|
|
|
+ const typeNameMap = {};
|
|
|
+ releaseGroupIds.forEach(releaseGroupId => {
|
|
|
+ const releaseGroup = releaseGroupMap.value[releaseGroupId];
|
|
|
+ const typeIds = [
|
|
|
+ releaseGroup["primary-type-id"],
|
|
|
+ ...releaseGroup["secondary-type-ids"]
|
|
|
+ ];
|
|
|
+ const typeKey = `${typeIds.length}-${typeIds.join("-")}`;
|
|
|
+ if (!typeKeys.includes(typeKey)) {
|
|
|
+ typeKeys.push(typeKey);
|
|
|
+ typeMap[typeKey] = [];
|
|
|
+ typeNameMap[typeKey] = {
|
|
|
+ primaryType: releaseGroup["primary-type"] ?? "N/A",
|
|
|
+ secondaryTypes:
|
|
|
+ releaseGroup["secondary-types"].toSorted()
|
|
|
+ };
|
|
|
+ }
|
|
|
+ typeMap[typeKey].push(releaseGroupId);
|
|
|
+ });
|
|
|
+ typeKeys.sort((typeKeyA, typeKeyB) => {
|
|
|
+ const typeNameA = typeNameMap[typeKeyA];
|
|
|
+ const typeNameB = typeNameMap[typeKeyB];
|
|
|
+
|
|
|
+ const typesA = [
|
|
|
+ typeNameA.primaryType,
|
|
|
+ ...typeNameA.secondaryTypes
|
|
|
+ ];
|
|
|
+ const typesB = [
|
|
|
+ typeNameB.primaryType,
|
|
|
+ ...typeNameB.secondaryTypes
|
|
|
+ ];
|
|
|
+
|
|
|
+ const typesLength = typesA.length - typesB.length;
|
|
|
+ if (typesLength !== 0) return typesLength;
|
|
|
+
|
|
|
+ for (let i = 0; i < typesA.length; i += 1) {
|
|
|
+ const typeA = typesA[i].toLowerCase();
|
|
|
+ const typeB = typesB[i].toLowerCase();
|
|
|
+ const compareResult = typeA.localeCompare(typeB);
|
|
|
+ if (compareResult !== 0) return compareResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ });
|
|
|
+ typeKeys.forEach(typeKey => {
|
|
|
+ typeMap[typeKey].sort(
|
|
|
+ (releaseGroupIdA, releaseGroupIdB) => {
|
|
|
+ const releaseGroupA =
|
|
|
+ releaseGroupMap.value[releaseGroupIdA];
|
|
|
+ const releaseGroupB =
|
|
|
+ releaseGroupMap.value[releaseGroupIdB];
|
|
|
+
|
|
|
+ const dateA =
|
|
|
+ releaseGroupA["first-release-date"] ?? "X";
|
|
|
+ const dateB =
|
|
|
+ releaseGroupB["first-release-date"] ?? "X";
|
|
|
+
|
|
|
+ return dateA.localeCompare(dateB);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ });
|
|
|
+ map[recordingId] = {
|
|
|
+ typeMap,
|
|
|
+ typeKeys,
|
|
|
+ typeNameMap
|
|
|
+ };
|
|
|
+ });
|
|
|
+ measureFinish("releaseGroupTypeMapForRecordingMap");
|
|
|
+ return map;
|
|
|
+ });
|
|
|
+ const releaseIdsPerReleaseGroupMap = computed(() => {
|
|
|
+ measureStart("releaseIdsPerReleaseGroupMap");
|
|
|
+ const map = {};
|
|
|
+
|
|
|
+ releaseGroupIds.value.forEach(releaseGroupId => {
|
|
|
+ map[releaseGroupId] = [];
|
|
|
+ });
|
|
|
+ releaseIds.value.forEach(releaseId => {
|
|
|
+ const release = releaseMap.value[releaseId];
|
|
|
+ const releaseGroupId = release["release-group"].id;
|
|
|
+ map[releaseGroupId].push(releaseId);
|
|
|
+ });
|
|
|
+ releaseGroupIds.value.forEach(releaseGroupId => {
|
|
|
+ map[releaseGroupId].sort((releaseIdA, releaseIdB) => {
|
|
|
+ const releaseA = releaseMap.value[releaseIdA];
|
|
|
+ const releaseB = releaseMap.value[releaseIdB];
|
|
|
+
|
|
|
+ const dateA = releaseA.date ?? "X";
|
|
|
+ const dateB = releaseB.date ?? "X";
|
|
|
+
|
|
|
+ return dateA.localeCompare(dateB);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ measureFinish("releaseIdsPerReleaseGroupMap");
|
|
|
+ return map;
|
|
|
+ });
|
|
|
+
|
|
|
+ const filteredRecordingIds = computed(() => {
|
|
|
+ measureStart("computed filteredRecordingIds");
|
|
|
+ const sortedRecordingIds = recordingIds.value.toSorted(
|
|
|
+ (recordingIdA, recordingIdB) => {
|
|
|
+ const recordingA = recordingMap.value[recordingIdA];
|
|
|
+ const recordingB = recordingMap.value[recordingIdB];
|
|
|
+ const recordingDisambiguationA = recordingA.disambiguation
|
|
|
+ ? ` ${recordingA.disambiguation}`
|
|
|
+ : "";
|
|
|
+ const recordingDisambiguationB = recordingB.disambiguation
|
|
|
+ ? ` ${recordingB.disambiguation}`
|
|
|
+ : "";
|
|
|
+ const recordingTitleA = `${recordingA.title}${recordingDisambiguationA}`;
|
|
|
+ const recordingTitleB = `${recordingB.title}${recordingDisambiguationB}`;
|
|
|
+ return recordingTitleA.localeCompare(recordingTitleB);
|
|
|
+ }
|
|
|
+ );
|
|
|
+ const returnValue = sortedRecordingIds.slice(
|
|
|
+ 0,
|
|
|
+ recordingsLimit.value
|
|
|
+ );
|
|
|
+ measureFinish("computed filteredRecordingIds");
|
|
|
+ return returnValue;
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ artist,
|
|
|
+ recordingsReleasesReleaseGroups,
|
|
|
+ //
|
|
|
+ releaseMap,
|
|
|
+ releaseGroupMap,
|
|
|
+ recordingMap,
|
|
|
+ workMap,
|
|
|
+ urlMap,
|
|
|
+ //
|
|
|
+ releaseIds,
|
|
|
+ releaseGroupIds,
|
|
|
+ recordingIds,
|
|
|
+ workIds,
|
|
|
+ urlIds,
|
|
|
+ //
|
|
|
+ releaseIdsForRecordingIdMap,
|
|
|
+ releaseGroupIdsForRecordingIdMap,
|
|
|
+ workIdsForRecordingIdMap,
|
|
|
+ // urlIdsForRecordingIdMap,
|
|
|
+ //
|
|
|
+ recordingsLimit,
|
|
|
+ filteredRecordingIds,
|
|
|
+ //
|
|
|
+ releaseGroupTypeMapForRecordingMap,
|
|
|
+ releaseIdsPerReleaseGroupMap,
|
|
|
+ //
|
|
|
+ urlSourceMap,
|
|
|
+ // getters
|
|
|
+ // recordings,
|
|
|
+ // youtubeVideoMapAdjusted,
|
|
|
+ // filteredRecordings,
|
|
|
+ // filteredYoutubeVideoIds,
|
|
|
+ // filteredYoutubeVideosIdsLength,
|
|
|
+ // testRecordings,
|
|
|
+ // methods
|
|
|
+ setArtist,
|
|
|
+ setMusicBrainzRecordingsReleasesReleaseGroups
|
|
|
+ };
|
|
|
+ });
|