@bscotch/stitch
Version:
Stitch: The GameMaker Studio 2 Asset Pipeline Development Kit.
118 lines • 4.26 kB
JavaScript
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