From 07931db95f24139048f63c1b928519ab6742a3ef Mon Sep 17 00:00:00 2001 From: renaud gaudin Date: Mon, 2 Oct 2023 13:02:23 +0000 Subject: [PATCH] Issue #938: added hack for mirrobrain magnet URIs --- static/skin/index.js | 50 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/static/skin/index.js b/static/skin/index.js index b93253aaa..fbdc788e9 100644 --- a/static/skin/index.js +++ b/static/skin/index.js @@ -197,6 +197,53 @@ } } + /* hack for library.kiwix.org magnet links (created by MirrorBrain) + See https://github.com/kiwix/container-images/issues/242 */ + async function getFixedMirrorbrainMagnet(magnetLink) { + // parse as query parameters + const params = new URLSearchParams( + magnetLink.replaceAll('&', '&').replace(/^magnet:/, '')); + + const zimUrl = params.get('as'); // as= is fallback URL + // download metalink to build list of mirrored URLs + let mirrorUrls = []; + try { + const metalink = await fetch(`${zimUrl}.meta4`).then(response => { + return response.ok ? response.text() : ''; + }).catch((_error) => ''); + if (metalink) { + const parser = new DOMParser(); + const doc = parser.parseFromString(metalink, "application/xml"); + doc.querySelectorAll("url").forEach((node) => { + if (node.hasAttribute("priority")) { // ensures its a mirror link + mirrorUrls.push(node.innerHTML); + } + }); + } + } catch (err) { + // not a big deal, magnet will only contain primary URL + console.debug(`Failed to retrieve mirror links for ${zimUrl}`); + } + + // set webseed (ws=) URL to primary download URL (redirects to mirror) + params.set('ws', zimUrl); + // if we got metalink mirror URLs, append them all + if (mirrorUrls) { + mirrorUrls.forEach((url) => { + params.append('ws', url); + }); + } + + params.set('xs', `${zimUrl}.torrent`); // adding xs= to point to torrent URL + + magnetLink = 'magnet:?'; + // we don't want params.ToString()'s urlencoding + for (const [key, value] of params.entries()) { + magnetLink += `&${key}=${value}`; + } + return magnetLink; + } + async function getMagnetLink(downloadLink) { const magnetUrl = downloadLink + '.magnet'; const controller = new AbortController(); @@ -204,6 +251,9 @@ const magnetLink = await fetch(magnetUrl, { signal: controller.signal }).then(response => { return response.ok ? response.text() : ''; }).catch((_error) => ''); + if (magnetLink) { + return await getFixedMirrorbrainMagnet(magnetLink); + } return magnetLink; }