Skip to content

Instantly share code, notes, and snippets.

@arilotter
Created March 8, 2022 22:10
Show Gist options
  • Save arilotter/3a0a8147b89352b02b082eecbef0c4f2 to your computer and use it in GitHub Desktop.
Save arilotter/3a0a8147b89352b02b082eecbef0c4f2 to your computer and use it in GitHub Desktop.
How Skyweaver's asset manifests are parsed! :)
export interface AssetsManifestTree {
radix: number
dicts: {
dirs: string[]
exts: string[]
segments: string[]
filenames: string[]
}
encoded: { [dirext: string]: { [filename: string]: string } }
}
/**
* Used to pull down an asset's real URL from a manifest.
* # Example
* ```ts
* const prefix = 'https://assets.skyweaver.net';
* const ASSETS_MANIFEST_VERSION_HASH = "57595abd04045637d2bfee8b22dc8f40";
* const assetsURL = `${prefix}/asset-manifests/assets-manifest.webapp.tree.${ASSETS_MANIFEST_VERSION_HASH}.json`;
* const manifest: AssetsManifestTree = await fetch(assetsURL).then(r => r.json() as any);
* const hasher = new AssetHashManifest(prefix, manifest);
* const realPath = hasher.getFullUrl('webapp/cards/full-cards/6x/4021.png')
* console.log(realPath) // https://assets.skyweaver.net/I511NUzw/webapp/cards/full-cards/6x/4021.png
* ```
*/
export default class AssetHashManifest {
private _hashFinder: (path: string) => string
constructor(private _prefix: string, data: AssetsManifestTree) {
this._hashFinder = this._makeCompressedHashFinder(data)
}
getFullUrl(url: string) {
return `${this._prefix}/${this._hashFinder(url)}/${url}`
}
private _makeCompressedHashFinder(data: AssetsManifestTree) {
const { radix, dicts, encoded } = data
const { dirs, exts, segments, filenames } = dicts
const radixEncode = (intCode: number) => intCode.toString(radix)
const splitPath = (path: string) => {
const dirOffset = path.lastIndexOf('/')
const extOffset = path.indexOf('.')
const dir = path.substring(0, dirOffset).replace(/^\//, '')
const ext = path.substring(extOffset + 1)
const filename = path.substring(dirOffset + 1, extOffset)
return [dir, filename, ext]
}
const getKey = (collection: string[], item: string) => {
return radixEncode(collection.indexOf(item))
}
return (path: string) => {
const [dir, filename, ext] = splitPath(path)
const encodedDir = getKey(dirs, dir)
const encodedExt = getKey(exts, ext)
const encodedFilename = getKey(
filenames,
filename
.split('-')
.map(x => getKey(segments, x))
.join('-')
)
const root = encoded[`${encodedDir}/${encodedExt}`]
if (root && root[encodedFilename]) {
return root[encodedFilename][0]
} else {
console.error(
`Could not find asset in tree for ${path}: ${encodedDir}/${encodedExt}: ${encodedFilename}`
)
return 'hash-not-found'
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment