import path from 'node:path' import { files as backgroundFiles } from '@aklive2d/background' import config from '@aklive2d/config' import { githubDownload } from '@aklive2d/downloader' import { envParser, file } from '@aklive2d/libs' import type { AudioDataTable, DisplayMetaTable, MusicDataItem, MusicFileMapping, MusicFiles, MusicItem, MusicMapping, MusicTable, } from './types.ts' const AUTO_UPDATE_FOLDER = path.resolve( import.meta.dirname, config.dir_name.auto_update ) export const DATA_DIR = path.resolve(import.meta.dirname, config.dir_name.data) const MUSIC_TABLE_JSON = path.join( AUTO_UPDATE_FOLDER, config.module.music.music_table_json ) const download = async () => { const display_meta_table_json = path.resolve( AUTO_UPDATE_FOLDER, config.module.music.display_meta_table_json ) const audio_data_json = path.resolve( AUTO_UPDATE_FOLDER, config.module.music.audio_data_json ) const metaTable: DisplayMetaTable = await githubDownload( `https://api.github.com/repos/Kengxxiao/ArknightsGameData/commits?path=zh_CN/gamedata/excel/display_meta_table.json`, `https://raw.githubusercontent.com/Kengxxiao/ArknightsGameData/master/zh_CN/gamedata/excel/display_meta_table.json`, display_meta_table_json ) const audioDataTable: AudioDataTable = await githubDownload( `https://api.github.com/repos/Kengxxiao/ArknightsGameData/commits?path=zh_CN/gamedata/excel/audio_data.json`, `https://raw.githubusercontent.com/Kengxxiao/ArknightsGameData/master/zh_CN/gamedata/excel/audio_data.json`, audio_data_json ) return { metaTable, audioDataTable, } } const generateMapping = () => { const { mode } = envParser.parse({ mode: { type: 'string', short: 'm', }, }) if (mode === 'update') { return } const musicFolder = DATA_DIR const musicTableContent = file.readSync(MUSIC_TABLE_JSON) const musicTable: MusicTable = musicTableContent ? JSON.parse(musicTableContent) : null const musicFileMapping: MusicFileMapping = {} const musicFiles: MusicFiles = [] if (!musicTable) throw new Error('Music table not found') for (const item of musicTable) { const key = `${item.id}.png` musicFileMapping[key] = {} as MusicItem if (item.intro) { const filename = `${item.intro.split('/').pop()}.ogg` musicFileMapping[key].intro = filename musicFiles.push({ filename, source: musicFolder, }) } else { musicFileMapping[key].intro = null } if (item.loop) { const filename = `${item.loop.split('/').pop()}.ogg` musicFileMapping[key].loop = filename musicFiles.push({ filename, source: musicFolder, }) } else { musicFileMapping[key].loop = null } } for (const e of musicFiles) { const musicPath = path.join(e.source, e.filename) if (!file.exists(musicPath)) { throw new Error( `Music file ${e.filename} is not found in music folder.` ) } } for (const e of Object.keys(musicFileMapping)) { if (!backgroundFiles.includes(e)) { throw new Error( `Background file ${e} is not found in background folder.` ) } } for (const background of backgroundFiles) { if (!musicFileMapping[background]) { const alternativeMatch = background.replace( /_(form)(.*)(\.png)$/, '$3' ) if (musicFileMapping[alternativeMatch]) { musicFileMapping[background] = structuredClone( musicFileMapping[alternativeMatch] ) } else { throw new Error( `Music mapping for background file ${background} is not found in music mapping.` ) } } } return { musicFiles, musicFileMapping, } } export const mapping: MusicMapping = generateMapping() export const update = async () => { const { metaTable, audioDataTable } = await download() const musicTable = audioDataTable.musics const musicBank = audioDataTable.bgmBanks const musicBankAlias = audioDataTable.bankAlias const musicData: MusicDataItem[] = metaTable.homeBackgroundData.homeBgDataList.reduce((acc, cur) => { if (cur.multiFormList.length > 1) // TODO: support multiple backgrounds console.warn(`${cur.bgId} has multiple musicIds`, cur.multiFormList) acc.push({ id: cur.bgId, musicId: cur.multiFormList[0].bgMusicId, }) return acc }, [] as MusicDataItem[]) const list = [] for (const item of musicData) { const bankItem = musicTable.find((el) => item.musicId === el.id) if (typeof bankItem === 'undefined') console.warn(`No music found for id ${item.musicId}`) let bankName = bankItem!.bank if (typeof musicBankAlias[bankName] !== 'undefined') { bankName = musicBankAlias[bankName] } const obj = musicBank.find((el) => bankName === el.name) if (typeof obj === 'undefined') console.warn(`No bank found for name ${bankName}`) list.push({ id: item.id, intro: obj!.intro, loop: obj!.loop, }) } list.push({ id: 'operator_bg', intro: 'm_sys_void_intro', loop: 'm_sys_void_loop', }) file.writeSync(JSON.stringify(list, null), MUSIC_TABLE_JSON) }