UNPKG

@bscotch/stitch

Version:

Stitch: The GameMaker Studio 2 Asset Pipeline Development Kit.

118 lines 4.26 kB
import { parseFile } from 'music-metadata'; import { fileChecksum } from './assetSource.lib.js'; import { audioFileSchema, deletedAssetSchema, isDeletedAsset, } from './assetSource.types.js'; export class AssetSourceFile { options; constructor(options) { this.options = options; } get path() { return this.options.path; } async isDeleted() { return !(await this.options.path.exists()); } /** * If the file does not exist, returns `undefined`. Else * returns its checksum. */ async computeChecksum() { if (await this.isDeleted()) { return; } // Calculating the actual checksum is slow, so we only want to do it // if we're double-checking because modified-by-date is not reliable. return await fileChecksum(this.options.path); } // /** // * If the file has been updated/added, returns the new checksum. // * If the file has been deleted, returns an empty string `''`. // * If the file has not been deleted or updated, returns `undefined`. // */ // async checksumIfUpdated(): Promise<string | undefined> { // const currentChecksum = await this.computeChecksum(); // const oldChecksum = this.options.meta // ? isDeletedAsset(this.options.meta) // ? undefined // : this.options.meta.checksum // : undefined; // if (currentChecksum === oldChecksum) { // return; // } // if (oldChecksum && !currentChecksum) { // return ''; // } // return currentChecksum; // } async refresh() { const exists = await this.options.path.exists(); const updatedAt = (exists && (await this.options.path.stat()).mtime) || undefined; const partialUpdated = { id: this.options.meta?.id, path: this.options.path.relative, version: (this.options.meta?.version ?? -1) + 1, updatedAt: updatedAt?.toISOString(), importable: false, }; if (this.options.meta && isDeletedAsset(this.options.meta) && !exists) { // Then we have a deleted asset that is still deleted return this; } else if (this.options.meta && !exists) { // Then we have a recently-deleted asset this.options.meta = deletedAssetSchema.parse({ ...partialUpdated, deleted: true, }); } else if (this.options.meta && !isDeletedAsset(this.options.meta) && exists && this.options.meta.updatedAt == partialUpdated.updatedAt) { // Then we have an unchanged asset. Mkake sure we have a checksum. this.options.meta.checksum ||= await this.computeChecksum(); } else { // Then something has changed const props = {}; for (const key of Object.keys(this.options.props || {})) { const value = this.options.props[key](this); props[key] = value instanceof Promise ? await value : value; } this.options.meta = this.options.metaSchema.parse({ ...partialUpdated, ...props, checksum: await this.computeChecksum(), }); } return this; } toJSON() { return { ...this.options.meta }; } } export class AssetSourceFileAudio extends AssetSourceFile { constructor(path, meta) { super({ path, metaSchema: audioFileSchema, meta, props: { duration: async (asset) => { try { const metadata = await parseFile(asset.path.absolute); return metadata.format.duration; } catch (err) { console.error('WARNING: Could not parse audio file', asset.path.absolute, err?.message); return 0; } }, }, }); } static from(path, meta) { return new AssetSourceFileAudio(path, meta); } } //# sourceMappingURL=AssetSourceFile.js.map