Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 2x 5x 5x 1x 4x 4x 1x 4x 2x 11x 11x 6x 4x 2x 2x 2x 2x 2x 2x 1x 1x | import { unzipDiscImage } from "./archive.js";
// Always https, whatever the page was loaded over: the mirror redirects plain
// http, so following the page's protocol would cost a redirect on every request
// when developing over http, and Electron reports "file:" anyway.
const mirrorBase = "https://bbc.xania.org/archive/sth";
async function _fetchManifest(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Network response was not ok (${response.status})`);
}
const data = await response.json();
if (!Array.isArray(data?.files)) {
throw new Error("Invalid manifest: missing files array");
}
return data.files.map((f) => f.path).sort();
}
// Each path component is encoded individually so slashes survive but special
// characters in filenames (e.g. brackets in "Daxis[droids]-demo.zip") don't
// produce a malformed URL.
function encodePath(path) {
return path.split("/").map(encodeURIComponent).join("/");
}
export class StairwayToHell {
/** @param {{tapes?: boolean}} [what] the tape images rather than the disc images */
constructor({ tapes = false } = {}) {
this._baseUrl = `${mirrorBase}/${tapes ? "tape" : "disk"}images/`;
this._catalog = [];
}
/** @returns {Promise<string[]>} every path in the archive, fetched the first time it is asked for */
async catalogue() {
if (this._catalog.length === 0) this._catalog = await _fetchManifest(this._baseUrl + "manifest.json");
return this._catalog;
}
async fetch(file) {
const url = this._baseUrl + encodePath(file);
console.log("Loading ZIP from " + url);
const response = await fetch(url);
Iif (!response.ok) throw new Error(`Unable to load ${url}, http code ${response.status}`);
try {
return await unzipDiscImage(new Uint8Array(await response.arrayBuffer()));
} catch (error) {
console.error("Failed to fetch file:", error);
throw error;
}
}
}
|