Русский
Русский
English
Статистика
Реклама

Google документы станут полновесными с 1 июня. Пишем скрипт для обхода этого ограничения

Предыстория

Google изменяет политику хранения данных с 1 июня 2021 года. Вкратце: документы и фото теперь станут полновесными и будут учитываться в общей квоте 15Гб. К тому же, при неактивности аккаунта более двух лет, Google может удалить ваши данные.

Я часто работаю с Google документами, и при активном использовании дисковая квота закончится довольно быстро. Но есть и хорошая новость: документы, созданные до 1 июня 2021 года так и останутся невесомыми, поэтому вы не получите превышение квоты в одночасье.

У меня сразу возникла мысль сделать документов "в запас". Ниже я расскажу, как это можно осуществить, не тратя много времени и сил.

Пишем скрипт, создающий документы

Скрипт буду писать с помощью Google Apps Script.

Создаём новую таблицу Google, заходим в редактор скриптов (Инструменты - Редактор скриптов).

Создаём три файла

  • main.gs - основной код для создания файлов

  • menu.gs - код для создания пользовательского меню при открытии таблицы

  • index.html - шаблон страницы для отображения информации

Сначала в файле menu.gs создаём функцию onOpen(). Это простой триггер, который выполняется при открытии таблицы. Его задача - создать пользовательское меню, из которого можно запустить функцию.

function onOpen(e) { // Выполняется при открытии таблицы  SpreadsheetApp.getUi() // Получаем интерфейс пользователя      .createMenu('Меню')// Создаём меню      .addItem('Создать документы', 'main') // Создаём команду меню      .addToUi();// Добавляем меню в интерфейс}

В файле main.gs создадим функцию main(), которая и будет запускаться с кнопки в меню.

function main() { // Меню - Создать документы  // Создаём HTML документ из шаблона  let template = HtmlService.createTemplateFromFile(`index`);  // Показываем модальное окно с HTML   SpreadsheetApp.getUi()    .showModelessDialog(template.evaluate(),`Создаю документы...`);}

Пора разобраться с index.html. это обычный HTML файл, который отобразится в модальном окне. там можно использовать стили, скрипты и т.п.

index.html
<!doctype html><html lang="en">  <head>    <!-- Required meta tags -->    <meta charset="utf-8">    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">    <!-- Bootstrap CSS -->    <link rel="stylesheet" href="http://personeltest.ru/aways/maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">    <script>      let timer = function(){ // Обслуживает таймер        // Получаем текущее время        let now = (new Date()).getTime();                // Задаём режим обновления таймера - 1 раз в секунду        setInterval(function(){          // Получаем прошедшее время. now будет доступно из-за замыкания.          let time = (new Date()).getTime() - now;          // Вычисляем минуты          let minutes = Math.floor(time/60000);          // И секунды          let seconds = Math.floor(time%60000/1000);          // Обновляем данные в поле lifeTime          updateData("lifeTime", `${minutes<10?"0"+minutes:minutes}:${seconds<10?"0"+seconds:seconds}`);        },1000);      };            updateData = function(id, value){ // Обновляет информацию в одном элементе по id        let element = document.getElementById(id);        if (element) {          element.innerHTML = value;        };      };            refreshData = function(){ // Обновляем все данные        google.script.run.withSuccessHandler(function(data){        updateData("createTables", data.createTables); // Таблиц создано:        updateData("createDocs", data.createDocs);// Документов создано:        updateData("createForms", data.createForms);// Форм создано        updateData("createSlides", data.createSlides);// Презентаций создано        updateData("log", data.log);// Лог      }).getData(); // Получаем данные     };      setTimeout(setInterval(refreshData, 2000),1000); // Данные обновляем раз в 2 секунды      timer();// Запуск таймера      google.script.run.doMagic();// Запуск функции для создания документов    </script>  </head>  <body>    <div class=".container bg-dark text-white text-center">      <div class="row">        <div class="col">          Таблиц        </div>                <div class="col">          Документов        </div>                <div class="col">          Форм        </div>                <div class="col">          Презентаций        </div>      </div>      <div class="row">        <div class="col" id="createTables">          0        </div>        <div class="col" id="createDocs">          0        </div>                <div class="col" id="createForms">          0        </div>                <div class="col" id="createSlides">          0        </div>      </div>    </div>         <div class=".container bg-dark text-white">      <div class="row">        <div class="col text-right" id="label_lifeTime">          Время работы:          </div>                <div class="col  text-left" id="lifeTime">          00:00        </div>              </div>    </div>    <div bg-dark text-white id="label_log">Лог: </div>    <ul class="list-group" id="log">    </ul>  </body></html>

В ней подключаем стили, создаём скрипт, в котором три функции:

  • updateData(id, value) - ищет на странице элемент по id и обновляет содержимое

  • refreshData() - обновляет все данные на странице, кроме таймера

  • timer() - обслуживает таймер

Для создания документов в файле main.gs создаём универсальную функцию.

function create()
const FILES_TO_CREATE = 50;function create(filesToCreate = FILES_TO_CREATE, folderId, prefix="file_", app, key) {  // Получаем словарь ключ-значение для текущего скрипта.  let props = PropertiesService.getScriptProperties();  // Получаем значение для ключа data. Преобразуем в объект  let data = JSON.parse(props.getProperty(`data`));  try{    // Получаем директорию по id    let folder = DriveApp.getFolderById(folderId);    for(var i=0; i<filesToCreate; i++){ // Создаём filesToCreate документов      // Создаём документ, получаем его id      let ssId = app.create(`${prefix}${(new Date()).getTime()}`).getId();      // Получаем файл по его id      let ss = DriveApp.getFileById(ssId);      // Копируем файл в папку      folder.addFile(ss);      // Удаляем файл из корневой папки      DriveApp.getRootFolder().removeFile(ss);      // Увеличиваем счётчик созданных файлов      data[key]=1+data[key];      // Сохраняем новые данные      props.setProperty(`data`, JSON.stringify(data));    };  }catch(err){    // В случае ошибки - пишем её в лог    logToHtml(`Error: ${err}`, LOG_TYPES.danger);  };  // Возвращаем из функции количество созданных файлов  return +i;};

И конкретные реализации - для таблиц, документов, форм и презентаций.

Обёртки для функции create()
function createSheets(key) {  // Получаем id папки для таблиц  let folderId =  PropertiesService.getScriptProperties().getProperty(`sheetsFolder`);  // Создаём нужное количество таблиц  let count = create(FILES_TO_CREATE, folderId, `sheet_`, SpreadsheetApp, key);  // Сохраняем в лог  logToHtml(`${count} sheets were created`, LOG_TYPES.success);}function createDocs(key) {  let folderId =  PropertiesService.getScriptProperties().getProperty(`docsFolder`);  let count = create(FILES_TO_CREATE, folderId, `doc_`, DocumentApp, key);  logToHtml(`${count} docs were created`, LOG_TYPES.success);}function createForms(key) {  let folderId =  PropertiesService.getScriptProperties().getProperty(`formsFolder`);  let count = create(FILES_TO_CREATE, folderId, `form_`, FormApp, key);  logToHtml(`${count} forms were created`, LOG_TYPES.success);}function createSlides(key) {  let folderId =  PropertiesService.getScriptProperties().getProperty(`slidesFolder`);  let count = create(FILES_TO_CREATE, folderId, `slide_`, SlidesApp, key);  logToHtml(`${count} slides were created`, LOG_TYPES.success);}

Далее делаем функцию для создания папок.

function createFolders(){  // Получаем словарь ключ-значение для текущего скрипта  let props = PropertiesService.getScriptProperties();  // Задаём структуру папок  let folders = [    {key:`rootFolder`,   name:`Прозапас`                         },    {key:`sheetsFolder`, name:`Sheets`, parentFolder:`rootFolder`},    {key:`docsFolder`,   name:`Docs`,   parentFolder:`rootFolder`},    {key:`formsFolder`,  name:`Forms`,  parentFolder:`rootFolder`},    {key:`slidesFolder`, name:`Slides`, parentFolder:`rootFolder`},    ];  // Проходим по структуре и создаём папки    folders.forEach(folder=>{      if (!props.getProperty(folder.key)){ // Если папка ещё не создана        // Если есть параметр rootFolder, то используем его, иначе выбираем корневую папку        let parentFolder = folder.parentFolder?DriveApp.getFolderById(props.getProperty(folder.parentFolder)):DriveApp.getRootFolder();        // Создаём папку        let folderId = parentFolder.createFolder(folder.name).getId();        // Сохраняем информацию о ней        props.setProperty(folder.key, folderId);      };    });}

И функцию для создания всех типов документов:

Основная функция, которая запускает создание папок и документов
function doMagic(){  let props = PropertiesService.getScriptProperties();  // Структура данных  let data = {    createTables:0,     createDocs:0,     createForms:0,     createSlides:0,     startTime:new Date(),    log:``,  };  // Сохраняем данные в словарь скрипта  props.setProperty(`data`, JSON.stringify(data));    try{    createFolders(); // Создаём папки    createSheets(`createTables`);// Создаём таблицы    createDocs(`createDocs`);// Создаём документы    createForms(`createForms`);// Создаём формы    createSlides(`createSlides`);// Создаём презентации        // Сообщаем, что всё готово    SpreadsheetApp.getUi().alert(`Готово!`);  }catch(err){    // При ошибке сообщаем об этом    SpreadsheetApp.getUi().alert(`Ошибка! ${err}`);  };};

Остаётся создать функцию для получения данных - так модальное окно может получить актуальные данные для отображения.

function getData(){ // Получает данные из словаря  // Получаем словарь ключ-значение  let props = PropertiesService.getScriptProperties();  // Получаем нужные данные и преобразуем в объект  let data = JSON.parse(props.getProperty(`data`));  return data; //Возвращаем данные};

И функция для записи строки в лог:

const LOG_TYPES = { // Типы сообщений. Взято из bootstrap  primary:   "primary",  secondary: "secondary",  success:   "success",  danger:    "danger",  warning:   "warning",  info:      "info",  };function logToHtml(log, type = LOG_TYPES.primary){  // Получаем данные  let data = getData();  // Добавляем li тег (лог отображается в виде списка) с данными  data.log+=`<li class="list-group-item text-${type}">${log}</li>\n`;  // Сохраняем данные  let props = PropertiesService.getScriptProperties();  props.setProperty(`data`, JSON.stringify(data));};

Что получилось

Остаётся только запустить скрипт из меню. При первом запуске Google запросит права - это нормально. После этого откроется окно, в котором можно наблюдать за прогрессом.

Модальное окно для визуализации прогрессаМодальное окно для визуализации прогресса

Ограничения скрипта

  • Время жизни скрипта ограничено 6 минутами. За это время он успеет создать несколько сотен документов. Можно обойти это ограничение, закинув все функции непосредственно в HTML код модального окна и обращаться к диску по API, но об этом в следующий раз

  • Есть ограничение на количество ежедневно созданных документов. Рано или поздно будет появляться ошибка Exception: Служба была вызвана слишком много раз за день: docs create. Тогда скрипт можно запустить на следующий день


TL;DR

Всё вышеописанное я собрал в таблицу, которую можно скопировать себе(Файл - Создать копию), запустить(Меню - Создать файлы) и получить к себе на диск несколько сотен файлов. При необходимости процедуру повторить.

Спасибо за внимание. Буду рад получить фидбэк по коду. Удачи!

Источник: habr.com
К списку статей
Опубликовано: 27.05.2021 18:04:31
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Javascript

Google api

Google apps script

Google docs

Tutorial

Html

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru