import {drive} from '@googleapis/drive'; import {Readable} from 'form-data'; import {GaxiosError, GaxiosPromise} from 'gaxios'; import {FetchError, Response as FetchResponse, Headers} from 'node-fetch'; const SPREADSHEETS_MIMETYPE = 'application/vnd.google-apps.spreadsheet', XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; export async function downloadFromGDrive(url: string) { const fileId = fileIdFromUrl(url); const googleDrive = drive("v3"); const key = process.env.GOOGLE_API_KEY; if (!key) { throw new Error("Can't download file from Google Drive. Api key is not configured"); } if (!fileId) { throw new Error(`Can't download from ${url}. Url is not valid`); } const fileRes = await googleDrive.files.get({ key, fileId }); if (fileRes.data.mimeType === SPREADSHEETS_MIMETYPE) { return await asFetchResponse(googleDrive.files.export( { key, fileId, alt: 'media', mimeType: XLSX_MIMETYPE }, { responseType: 'stream' } )); } else { return await asFetchResponse(googleDrive.files.get( { key, fileId, alt: 'media' }, { responseType: 'stream' } )); } } async function asFetchResponse(req: GaxiosPromise) { try { const res = await req; return new FetchResponse(res.data, { headers: new Headers(res.headers), status: res.status, statusText: res.statusText }); } catch (err) { const error: GaxiosError = err; if (!error.response) { // Fetch throws exception on network error. // https://github.com/node-fetch/node-fetch/blob/master/docs/ERROR-HANDLING.md throw new FetchError(error.message, "system", error.code || "unknown"); } else { // Fetch returns failure response on http error const resInit = error.response ? { status: error.response.status, headers: new Headers(error.response.headers), statusText: error.response.statusText } : undefined; return new FetchResponse(error.response.data, resInit); } } } export function isDriveUrl(url: string) { return !!fileIdFromUrl(url); } function fileIdFromUrl(url: string) { if (!url) { return null; } const match = /^https:\/\/(docs|drive).google.com\/(spreadsheets|file)\/d\/([^/]*)/i.exec(url); return match ? match[3] : null; }