Created
March 8, 2022 22:10
-
-
Save arilotter/3a0a8147b89352b02b082eecbef0c4f2 to your computer and use it in GitHub Desktop.
How Skyweaver's asset manifests are parsed! :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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