-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.mjs
65 lines (50 loc) · 2.41 KB
/
index.mjs
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
54
55
56
57
58
59
60
61
62
63
64
65
/**
* @module gdrive-downloader
* @fileoverview The library for getting a download link to the public Google Drive files.
*/
const HTTP_STATUS_CONFIRMATION_NEEDED = 200;
const HTTP_STATUS_PROCEED_TO_DOWNLOAD = 303;
const fileIDRegex = /\/d\/(.+?)\//; //basically anything starting after the "/d/" until the next slash.
/**
* @param {string} fileID
*/
const downloadLinkMaker = (fileID) => `https://drive.google.com/uc?id=${fileID}&export=download`; //normally the download link is made with "/u/0/uc" but by using "/uc" we save a redirect.
const confirmDownloadPageLinkRegex = /action="(.+?)"/;
/**
* Gets the "continue anyway" link when the virus scan "fails". See {@link confirmDownloadPageLinkRegex the link extractor}.
* @param {string} confirmationPageContents
*/
const extractRealDownloadLink = confirmationPageContents => decodeURI(confirmDownloadPageLinkRegex.exec(confirmationPageContents)?.[1] ?? "");
/**
* Tries to get the file id from the file url. See {@link fileIDRegex the file id extractor}.
* @param {string} fileLink
*/
export function fileIDExtractor(fileLink) { return fileIDRegex.exec(fileLink)?.[1] ?? ""; }
/**
* Tries to get a download link to the {@link fileLink file}.
* @param {string} fileLink Make sure the file is accessible for anyone with a link.
*
* Well, because we are the "anyone" since we are "not logged in".
*/
export default async function getFileDownloadLinkFromFileLink(fileLink) {
return getDownloadLinkFromID(fileIDExtractor(fileLink));
}
/**
* @param {string} fileID
*/
export async function getDownloadLinkFromID(fileID) {
if (typeof fileID !== "string" || fileID.length === 0)
return "";
const downloadStartLink = downloadLinkMaker(fileID);
//redirect:manual allows us to stop on any redirects -- that's useful because we want to grab the link and not download the files immediately.
const startingResponse = await fetch(downloadStartLink, { redirect: "manual" });
switch (startingResponse.status) {
case HTTP_STATUS_CONFIRMATION_NEEDED:
return extractRealDownloadLink((await startingResponse.text()));
case HTTP_STATUS_PROCEED_TO_DOWNLOAD:
return startingResponse.headers.get("Location") ?? "";
default:
console.log(`Getting download link for file with id "${fileID}" failed with status code ${startingResponse.status}. Please make sure the file is public.`);
return ""
}
}