import { LitElement, html, css } from "lit"; import { wrapCss } from "./misc"; import fabGoogleDrive from "@fortawesome/fontawesome-free/svgs/brands/google-drive.svg"; // =========================================================================== class GDrive extends LitElement { constructor() { super(); this.state = "trypublic"; this.sourceUrl = ""; this.scriptLoaded = false; this.error = false; } static get properties() { return { state: { type: String }, sourceUrl: { type: String }, error: { type: Boolean }, reauth: { type: Boolean }, }; } updated(changedProperties) { if (changedProperties.has("sourceUrl")) { this.error = false; this.state = "trypublic"; this.tryPublicAccess().then((result) => { if (!result) { this.state = "tryauto"; this.requestUpdate(); } }); } } async tryPublicAccess() { try { const sourceUrl = this.sourceUrl; const fileId = sourceUrl.slice("googledrive://".length); // eslint-disable-next-line no-undef const publicCheckUrl = `${__HELPER_PROXY__}/g/${fileId}`; let resp = null; try { resp = await fetch(publicCheckUrl); } catch (e) { return false; } const json = await resp.json(); if (!json.url || !json.name || !json.size) { return false; } // only allow for small downloads that will not result in partial download if (json.size > 15000000) { return false; } const publicUrl = json.url; try { const abort = new AbortController(); const signal = abort.signal; resp = await fetch(publicUrl, { signal }); abort.abort(); if (resp.status != 200) { return false; } } catch (e) { return false; } const name = json.name; const extra = { publicUrl }; const size = Number(json.size); this.dispatchEvent( new CustomEvent("load-ready", { detail: { name, extra, size, sourceUrl }, }), ); return true; } catch (e) { return false; } } onLoad() { this.scriptLoaded = true; this.gauth("none", (response) => { if (response.error) { if (this.state !== "implicitonly") { this.state = "trymanual"; } } else { this.authed(response); } }); } onClickAuth() { this.gauth("select_account", (response) => { if (!response.error) { this.authed(response); } }); } async authed(response) { const sourceUrl = this.sourceUrl; const fileId = sourceUrl.slice("googledrive://".length); const metadataUrl = `https://www.googleapis.com/drive/v3/files/${fileId}`; const authToken = response.access_token; const headers = { Authorization: `Bearer ${authToken}` }; const resp = await fetch( metadataUrl + "?fields=name,size&supportsAllDrives=true", { headers }, ); if (resp.status === 404 || resp.status == 403) { if (this.state !== "implicitonly") { this.state = "trymanual"; } this.error = true; return; } this.error = false; const metadata = await resp.json(); const name = metadata.name; const size = Number(metadata.size); this.dispatchEvent( new CustomEvent("load-ready", { detail: { sourceUrl, headers, size, name }, }), ); } static get styles() { return wrapCss(css``); } render() { return html` ${this.script()} ${this.state !== "trymanual" ? html`

Connecting to Google Drive...

` : html` ${this.error ? html`

${this.reauth ? "Some resources are loaded on demand from Google Drive, which requires reauthorization." : "Could not access this file with the current Google Drive account."}

If you have multiple Google Drive accounts, be sure to select the correct one.


` : ""} `}`; } script() { if (this.state === "trypublic" || this.scriptLoaded) { return html``; } const script = document.createElement("script"); script.onload = () => this.onLoad(); script.src = "https://apis.google.com/js/platform.js"; return script; } gauth(prompt, callback) { self.gapi.load("auth2", () => { self.gapi.auth2.authorize( { // eslint-disable-next-line no-undef client_id: __GDRIVE_CLIENT_ID__, scope: "https://www.googleapis.com/auth/drive.file", response_type: "token", prompt, }, callback, ); }); } } customElements.define("wr-gdrive", GDrive); export { GDrive };