Files
aklive2d/packages/music/index.ts
2025-10-12 22:01:35 +08:00

182 lines
5.8 KiB
TypeScript

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)
}