Refactor soundtrack metadata types to use RomFileAudioMetaSchema for improved consistency

This commit is contained in:
zurdi
2026-05-28 09:38:28 +00:00
parent 6274f83716
commit fb10a51bb8
4 changed files with 47 additions and 54 deletions

View File

@@ -4,11 +4,12 @@ import type { Emitter } from "mitt";
import { storeToRefs } from "pinia";
import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import type {
RomFileAudioMetaSchema,
SoundtrackTrackMetaSchema,
} from "@/__generated__";
import VolumeControl from "@/components/common/VolumeControl.vue";
import romApi, {
type SoundtrackAudioMeta,
type SoundtrackTrackMeta,
} from "@/services/api/rom";
import romApi from "@/services/api/rom";
import type { DetailedRom } from "@/stores/roms";
import useSoundtrackPlayer, {
type PlayerMeta,
@@ -74,7 +75,7 @@ const folderCoverUrl = computed(() => {
return cover ? fileUrl(cover.id, cover.file_name) : null;
});
const tracksMeta = ref<Map<number, SoundtrackAudioMeta>>(new Map());
const tracksMeta = ref<Map<number, RomFileAudioMetaSchema>>(new Map());
const isLoadingMeta = ref(false);
let metaAbort: AbortController | null = null;
@@ -88,13 +89,13 @@ const activeTrack = computed(() =>
tracks.value.find((t) => t.id === activeTrackId.value),
);
const activeMeta = computed<SoundtrackAudioMeta | undefined>(() =>
const activeMeta = computed<RomFileAudioMetaSchema | undefined>(() =>
activeTrackId.value != null
? tracksMeta.value.get(activeTrackId.value)
: undefined,
);
function coverUrlForMeta(m: SoundtrackAudioMeta | undefined): string | null {
function coverUrlForMeta(m: RomFileAudioMetaSchema | undefined): string | null {
if (m?.cover_path) return `${FRONTEND_RESOURCES_PATH}/${m.cover_path}`;
return null;
}
@@ -151,8 +152,8 @@ async function loadAllMetadata() {
romId: props.rom.id,
signal: metaAbort.signal,
});
const next = new Map<number, SoundtrackAudioMeta>();
for (const row of data as SoundtrackTrackMeta[]) {
const next = new Map<number, RomFileAudioMetaSchema>();
for (const row of data as SoundtrackTrackMetaSchema[]) {
if (row.audio_meta) next.set(row.file_id, row.audio_meta);
}
tracksMeta.value = next;
@@ -171,7 +172,7 @@ async function loadAllMetadata() {
}
}
function toPlayerMeta(m: SoundtrackAudioMeta | undefined): PlayerMeta {
function toPlayerMeta(m: RomFileAudioMetaSchema | undefined): PlayerMeta {
return {
title: m?.title ?? undefined,
artist: m?.artist ?? undefined,
@@ -243,7 +244,7 @@ function onDelete(fileId: number) {
emit("delete-track", fileId);
}
function chips(meta: SoundtrackAudioMeta | undefined) {
function chips(meta: RomFileAudioMetaSchema | undefined) {
if (!meta) return [];
const items: { icon: string; label: string }[] = [];
if (meta.album) items.push({ icon: "mdi-album", label: meta.album });

View File

@@ -10,6 +10,7 @@ import type {
RomUserSchema,
SearchRomSchema,
SimpleRomSchema,
SoundtrackTrackMetaSchema,
UserNoteSchema,
RomFiltersDict,
} from "@/__generated__";
@@ -635,26 +636,6 @@ async function removeSoundtrack({
return api.delete(`/roms/${romId}/soundtracks/${fileId}`);
}
export interface SoundtrackAudioMeta {
title: string | null;
artist: string | null;
album: string | null;
year: string | null;
genre: string | null;
track: string | null;
disc: string | null;
duration_seconds: number | null;
has_embedded_cover: boolean;
cover_path: string | null;
}
export interface SoundtrackTrackMeta {
file_id: number;
file_name: string;
file_size_bytes: number;
audio_meta: SoundtrackAudioMeta | null;
}
async function getSoundtrackMetadata({
romId,
signal,
@@ -662,9 +643,12 @@ async function getSoundtrackMetadata({
romId: number;
signal?: AbortSignal;
}) {
return api.get<SoundtrackTrackMeta[]>(`/roms/${romId}/soundtracks/metadata`, {
signal,
});
return api.get<SoundtrackTrackMetaSchema[]>(
`/roms/${romId}/soundtracks/metadata`,
{
signal,
},
);
}
async function uploadManualFiles({

View File

@@ -2,6 +2,7 @@ import { useLocalStorage } from "@vueuse/core";
import { throttle } from "lodash";
import { defineStore } from "pinia";
import { computed, ref, shallowRef } from "vue";
import type { RomFileAudioMetaSchema } from "@/__generated__";
const volumeStorage = useLocalStorage<number>("soundtrack.volume", 1);
const mutedStorage = useLocalStorage<boolean>("soundtrack.muted", false);
@@ -13,18 +14,24 @@ export interface PlayerTrack {
url: string;
}
export interface PlayerMeta {
title?: string;
artist?: string;
album?: string;
year?: string;
genre?: string;
track?: string;
disc?: string;
// Audio-tag fields are sourced from the generated schema; the rest (duration in
// seconds + resolved cover URLs) are UI-specific to the player.
type AudioTagKey =
| "title"
| "artist"
| "album"
| "year"
| "genre"
| "track"
| "disc";
export type PlayerMeta = {
[K in AudioTagKey]?: NonNullable<RomFileAudioMetaSchema[K]>;
} & {
duration?: number;
coverUrl?: string;
folderCoverUrl?: string;
}
};
const useSoundtrackPlayer = defineStore("soundtrackPlayer", () => {
const track = ref<PlayerTrack | null>(null);

View File

@@ -21,10 +21,11 @@ import {
watch,
} from "vue";
import { useI18n } from "vue-i18n";
import romApi, {
type SoundtrackAudioMeta,
type SoundtrackTrackMeta,
} from "@/services/api/rom";
import type {
RomFileAudioMetaSchema,
SoundtrackTrackMetaSchema,
} from "@/__generated__";
import romApi from "@/services/api/rom";
import type { DetailedRom } from "@/stores/roms";
import useSoundtrackPlayer, {
type PlayerMeta,
@@ -101,16 +102,16 @@ const folderCoverUrl = computed(() => {
});
// ---------- Metadata fetch ----------
const tracksMeta = ref<Map<number, SoundtrackAudioMeta>>(new Map());
const tracksMeta = ref<Map<number, RomFileAudioMetaSchema>>(new Map());
const isLoadingMeta = ref(false);
let metaAbort: AbortController | null = null;
function coverUrlForMeta(m: SoundtrackAudioMeta | undefined): string | null {
function coverUrlForMeta(m: RomFileAudioMetaSchema | undefined): string | null {
if (m?.cover_path) return `${FRONTEND_RESOURCES_PATH}/${m.cover_path}`;
return null;
}
function toPlayerMeta(m: SoundtrackAudioMeta | undefined): PlayerMeta {
function toPlayerMeta(m: RomFileAudioMetaSchema | undefined): PlayerMeta {
return {
title: m?.title ?? undefined,
artist: m?.artist ?? undefined,
@@ -149,8 +150,8 @@ async function loadAllMetadata() {
romId: props.rom.id,
signal: metaAbort.signal,
});
const next = new Map<number, SoundtrackAudioMeta>();
for (const row of data as SoundtrackTrackMeta[]) {
const next = new Map<number, RomFileAudioMetaSchema>();
for (const row of data as SoundtrackTrackMetaSchema[]) {
if (row.audio_meta) next.set(row.file_id, row.audio_meta);
}
tracksMeta.value = next;
@@ -192,7 +193,7 @@ const activeTrack = computed(() =>
tracks.value.find((t) => t.id === activeTrackId.value),
);
const activeMeta = computed<SoundtrackAudioMeta | undefined>(() =>
const activeMeta = computed<RomFileAudioMetaSchema | undefined>(() =>
activeTrackId.value != null
? tracksMeta.value.get(activeTrackId.value)
: undefined,
@@ -236,7 +237,7 @@ function trackDurationFor(fileId: number): number | undefined {
// Chips shown in the now-playing header.
type ChipItem = { icon: string; label: string; color?: string };
function headerChips(meta: SoundtrackAudioMeta | undefined): ChipItem[] {
function headerChips(meta: RomFileAudioMetaSchema | undefined): ChipItem[] {
if (!meta) return [];
const items: ChipItem[] = [];
if (meta.album) items.push({ icon: "mdi-album", label: meta.album });