diff --git a/gitadora@asphyxia/data/mdb/.gitignore b/gitadora@asphyxia/data/mdb/.gitignore index 33a0b3f..7a7be89 100644 --- a/gitadora@asphyxia/data/mdb/.gitignore +++ b/gitadora@asphyxia/data/mdb/.gitignore @@ -6,4 +6,5 @@ ex.json mt.json nt.json hv.json -custom.xml \ No newline at end of file +custom.xml +custom.json \ No newline at end of file diff --git a/gitadora@asphyxia/data/mdb/index.ts b/gitadora@asphyxia/data/mdb/index.ts index d78e877..5b4d1f9 100644 --- a/gitadora@asphyxia/data/mdb/index.ts +++ b/gitadora@asphyxia/data/mdb/index.ts @@ -21,6 +21,9 @@ export enum DATAVersion { MATTIX = "mt" } +const allowedFormats = ['.json', '.xml', '.b64'] +const mdbFolder = "data/mdb/" + type processRawDataHandler = (path: string) => Promise const logger = new Logger("mdb") @@ -32,30 +35,41 @@ export async function readXML(path: string) { return json } -export async function readJSON(path: string) { - logger.debugInfo(`Loading MDB data from ${path}.`) - const str = await IO.ReadFile(path, 'utf-8'); - const json = JSON.parse(str) - return json -} +export async function readMDBFile(path: string, processHandler?: processRawDataHandler): Promise { -export async function readJSONOrXML(jsonPath: string, xmlPath: string, processHandler: processRawDataHandler): Promise { - if (!IO.Exists(jsonPath)) { - logger.debugInfo(`Loading MDB data from ${xmlPath}.`) - const data = await processHandler(xmlPath) - await IO.WriteFile(jsonPath, JSON.stringify(data)) - return data - } else { - logger.debugInfo(`Loading MDB data from ${jsonPath}.`) - const json = JSON.parse(await IO.ReadFile(jsonPath, 'utf-8')) - return json + if (!IO.Exists(path)) { + throw "Unable to find MDB file at " + path } -} -export async function readB64JSON(b64path: string) { - logger.debugInfo(`Loading MDB data from ${b64path}.`) - const buff = await IO.ReadFile(b64path, 'utf-8'); - return JSON.parse(Buffer.from(buff, 'base64').toString('utf-8')); + logger.debugInfo(`Loading MDB data from ${path}.`) + + let result : CommonMusicData; + const fileType = path.substring(path.lastIndexOf('.')).toLowerCase() + + switch (fileType) { + case '.json': + const str = await IO.ReadFile(path, 'utf-8'); + result = JSON.parse(str) + break; + case '.xml': + processHandler ?? defaultProcessRawXmlData + result = await processHandler(path) + // Uncomment to save the loaded XML file as JSON. + // await IO.WriteFile(path.replace(".xml", ".json"), JSON.stringify(data)) + break; + case '.b64': + const buff = await IO.ReadFile(path, 'utf-8'); + const json = Buffer.from(buff, 'base64').toString('utf-8') + // Uncomment to save the decoded base64 file as JSON. + // await IO.WriteFile(path.replace(".b64",".json"), json) + result = JSON.parse(json) + break; + default: + throw `Invalid MDB file type: ${fileType}. Only .json, .xml, .b64 are supported.` + } + + logger.debugInfo(`Loaded ${result.music.length} songs from MDB file.`) + return result } export function gameVerToDataVer(ver: string): DATAVersion { @@ -72,18 +86,47 @@ export function gameVerToDataVer(ver: string): DATAVersion { } } -export async function processDataBuilder(gameVer: string, processHandler?: processRawDataHandler) { - const ver = gameVerToDataVer(gameVer) - const base = `data/mdb/${ver}` - if (IO.Exists(`${base}.b64`)) { - return await readB64JSON(`${base}.b64`); +/** + * Attempts to find a .json, .xml, or .b64 file (in that order) matching the given name in the specified folder. + * @param fileNameWithoutExtension - The name of the file to find (without the extension). + * @param path - The path to the folder to search. If left null, the default MDB folder ('data/mdb' in the plugin folder) will be used. + * @returns - The path of the first matching file found, or null if no file was found. + */ +export function findMDBFile(fileNameWithoutExtension: string, path: string = null): string { + + path = path ?? mdbFolder + if (!IO.Exists(path)) { + throw `Path does not exist: ${path}` } - const { music } = await readJSONOrXML(`${base}.json`, `${base}.xml`, processHandler ?? defaultProcessRawData) - // await IO.WriteFile(`${base}.b64`, Buffer.from(JSON.stringify({music})).toString("base64")) - return { music }; + + if (!path.endsWith("/")) { + path += "/" + } + + for (const ext of allowedFormats) { + const filePath = path + fileNameWithoutExtension + ext + if (IO.Exists(filePath)) { + return filePath + } + } + + return null } -export async function defaultProcessRawData(path: string): Promise { +export async function loadSongsForGameVersion(gameVer: string, processHandler?: processRawDataHandler) { + const ver = gameVerToDataVer(gameVer) + + let mdbFile = findMDBFile(ver, mdbFolder) + + if (mdbFile == null) { + throw `No valid MDB files were found in the data/mdb subfolder. Ensure that this folder contains at least one of the following: ${ver}.json, ${ver}.xml or ${ver}.b64` + } + + const music = await readMDBFile(mdbFile, processHandler ?? defaultProcessRawXmlData) + return music +} + +export async function defaultProcessRawXmlData(path: string): Promise { const data = await readXML(path) const mdb = $(data).elements("mdb.mdb_data"); const music: any[] = []; diff --git a/gitadora@asphyxia/handlers/MusicList.ts b/gitadora@asphyxia/handlers/MusicList.ts index 10841b1..18fafd7 100644 --- a/gitadora@asphyxia/handlers/MusicList.ts +++ b/gitadora@asphyxia/handlers/MusicList.ts @@ -1,6 +1,5 @@ import { getVersion } from "../utils"; -import { defaultProcessRawData, processDataBuilder } from "../data/mdb" -import { CommonMusicDataField, readJSONOrXML, readXML } from "../data/mdb"; +import { CommonMusicDataField, findMDBFile, readMDBFile, loadSongsForGameVersion } from "../data/mdb"; import Logger from "../utils/logger" const logger = new Logger("MusicList") @@ -10,7 +9,9 @@ export const playableMusic: EPR = async (info, data, send) => { let music: CommonMusicDataField[] = []; try { if (U.GetConfig("enable_custom_mdb")) { - music = (await defaultProcessRawData('data/mdb/custom.xml')).music + let customMdb = findMDBFile("custom") + + music = (await readMDBFile(customMdb)).music } } catch (e) { logger.warn("Read Custom MDB failed. Using default MDB as a fallback.") @@ -19,7 +20,7 @@ export const playableMusic: EPR = async (info, data, send) => { } if (music.length == 0) { - music = _.get(await processDataBuilder(version), 'music', []); + music = (await loadSongsForGameVersion(version)).music } await send.object({