import yaml from 'yaml' import type { Song } from '~/types/song' import type { ChapterSongLink, BookConfig } from '~/types/book' let _configCache: BookConfig | null = null async function loadConfig(): Promise { if (_configCache) return _configCache const raw = await import('~/data/librodrome.config.yml?raw').then(m => m.default) const parsed = yaml.parse(raw) _configCache = { title: parsed.book.title, author: parsed.book.author, description: parsed.book.description, coverImage: parsed.book.coverImage, chapters: [], songs: parsed.songs as Song[], chapterSongs: parsed.chapterSongs as ChapterSongLink[], defaultPlaylistOrder: parsed.defaultPlaylistOrder as string[], } return _configCache } export function useBookData() { const config = ref(null) const isLoaded = ref(false) async function init() { if (isLoaded.value) return config.value = await loadConfig() isLoaded.value = true } function getSongs(): Song[] { return config.value?.songs ?? [] } function getSongById(id: string): Song | undefined { return config.value?.songs.find(s => s.id === id) } function getChapterSongs(chapterSlug: string): Song[] { if (!config.value) return [] const links = config.value.chapterSongs.filter(cs => cs.chapterSlug === chapterSlug) return links .map(link => config.value!.songs.find(s => s.id === link.songId)) .filter((s): s is Song => !!s) } function getPrimarySong(chapterSlug: string): Song | undefined { if (!config.value) return undefined const link = config.value.chapterSongs.find( cs => cs.chapterSlug === chapterSlug && cs.primary, ) if (!link) return undefined return config.value.songs.find(s => s.id === link.songId) } function getChapterSongLinks(chapterSlug: string): ChapterSongLink[] { return config.value?.chapterSongs.filter(cs => cs.chapterSlug === chapterSlug) ?? [] } function getPlaylistOrder(): Song[] { if (!config.value) return [] return config.value.defaultPlaylistOrder .map(id => config.value!.songs.find(s => s.id === id)) .filter((s): s is Song => !!s) } function getBookMeta() { if (!config.value) return null return { title: config.value.title, author: config.value.author, description: config.value.description, coverImage: config.value.coverImage, } } return { config, isLoaded, init, getSongs, getSongById, getChapterSongs, getPrimarySong, getChapterSongLinks, getPlaylistOrder, getBookMeta, } }