Merge pull request #1001 from kiwix/magnet

This commit is contained in:
Matthieu Gautier 2023-10-09 18:16:39 +02:00 committed by GitHub
commit 4425cd2122
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 2 deletions

View File

@ -197,6 +197,58 @@
} }
} }
function makeURLSearchString(params, keysToURIEncode) {
let output = '';
for (const [key, value] of params.entries()) {
let finalValue = (keysToURIEncode.indexOf(key) >= 0) ? encodeURIComponent(value) : value;
output += `&${key}=${finalValue}`;
}
return output;
}
/* 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 = [];
const metalink = await fetch(`${zimUrl}.meta4`).then(response => {
return response.ok ? response.text() : '';
}).catch((_error) => '');
if (metalink) {
try {
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 parse 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
return 'magnet:?' + makeURLSearchString(params, ['ws', 'as', 'dn', 'xs', 'tr']);
}
async function getMagnetLink(downloadLink) { async function getMagnetLink(downloadLink) {
const magnetUrl = downloadLink + '.magnet'; const magnetUrl = downloadLink + '.magnet';
const controller = new AbortController(); const controller = new AbortController();
@ -204,6 +256,9 @@
const magnetLink = await fetch(magnetUrl, { signal: controller.signal }).then(response => { const magnetLink = await fetch(magnetUrl, { signal: controller.signal }).then(response => {
return response.ok ? response.text() : ''; return response.ok ? response.text() : '';
}).catch((_error) => ''); }).catch((_error) => '');
if (magnetLink) {
return await getFixedMirrorbrainMagnet(magnetLink);
}
return magnetLink; return magnetLink;
} }

View File

@ -63,7 +63,7 @@ const ResourceCollection resources200Compressible{
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.css" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.css" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/index.css?cacheid=e4d76d16" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/index.css?cacheid=e4d76d16" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.js" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/index.js" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/index.js?cacheid=e1b1ae55" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/index.js?cacheid=ce19da2a" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/iso6391To3.js" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/iso6391To3.js" },
{ STATIC_CONTENT, "/ROOT%23%3F/skin/iso6391To3.js?cacheid=ecde2bb3" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/iso6391To3.js?cacheid=ecde2bb3" },
{ DYNAMIC_CONTENT, "/ROOT%23%3F/skin/isotope.pkgd.min.js" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/isotope.pkgd.min.js" },
@ -288,7 +288,7 @@ R"EXPECTEDRESULT( href="/ROOT%23%3F/skin/index.css?cacheid=e4d76d16"
<script type="text/javascript" src="/ROOT%23%3F/skin/languages.js?cacheid=648526e1" defer></script> <script type="text/javascript" src="/ROOT%23%3F/skin/languages.js?cacheid=648526e1" defer></script>
<script src="/ROOT%23%3F/skin/isotope.pkgd.min.js?cacheid=2e48d392" defer></script> <script src="/ROOT%23%3F/skin/isotope.pkgd.min.js?cacheid=2e48d392" defer></script>
<script src="/ROOT%23%3F/skin/iso6391To3.js?cacheid=ecde2bb3"></script> <script src="/ROOT%23%3F/skin/iso6391To3.js?cacheid=ecde2bb3"></script>
<script type="text/javascript" src="/ROOT%23%3F/skin/index.js?cacheid=e1b1ae55" defer></script> <script type="text/javascript" src="/ROOT%23%3F/skin/index.js?cacheid=ce19da2a" defer></script>
<img src="/ROOT%23%3F/skin/feed.svg?cacheid=055b333f" <img src="/ROOT%23%3F/skin/feed.svg?cacheid=055b333f"
<img src="/ROOT%23%3F/skin/langSelector.svg?cacheid=00b59961" <img src="/ROOT%23%3F/skin/langSelector.svg?cacheid=00b59961"
)EXPECTEDRESULT" )EXPECTEDRESULT"