function doGet(e) { const callback = getCallback_(e); try { if (!callback) { throw new Error("Valid callback is required"); } const targetUrl = getTargetUrl_(e); if (!isAllowedUrl_(targetUrl)) { throw new Error("Only https://siatube.com is allowed"); } const response = UrlFetchApp.fetch(targetUrl, { method: "get", muteHttpExceptions: true, followRedirects: true, }); const statusCode = response.getResponseCode(); const responseText = response.getContentText(); if (statusCode < 200 || statusCode >= 300) { throw new Error("Request failed with status " + statusCode); } const data = JSON.parse(responseText); return createJsonpOutput_(callback, data); } catch (error) { const result = { ok: false, error: getErrorMessage_(error), }; if (callback) { return createJsonpOutput_(callback, result); } return ContentService .createTextOutput(JSON.stringify(result)) .setMimeType(ContentService.MimeType.JSON); } } function getTargetUrl_(e) { const targetUrl = e && e.parameter && e.parameter.url ? String(e.parameter.url) : ""; if (!targetUrl) { throw new Error("url is required"); } return targetUrl; } function getCallback_(e) { const callback = e && e.parameter && e.parameter.callback ? String(e.parameter.callback) : ""; if (!callback) { return ""; } const callbackPattern = /^[A-Za-z_$][0-9A-Za-z_$]*(?:\.[A-Za-z_$][0-9A-Za-z_$]*)*$/; return callbackPattern.test(callback) ? callback : ""; } function isAllowedUrl_(targetUrl) { return ( targetUrl === "https://siatube.com" || targetUrl.indexOf("https://siatube.com/") === 0 ); } function createJsonpOutput_(callback, data) { const json = JSON.stringify(data) .replace(/\u2028/g, "\\u2028") .replace(/\u2029/g, "\\u2029"); const jsonp = callback + "(" + json + ");"; return ContentService .createTextOutput(jsonp) .setMimeType(ContentService.MimeType.JAVASCRIPT); } function getErrorMessage_(error) { if (error && error.message) { return String(error.message); } return String(error); }