[JavaScript, Google API] Google документы станут полновесными с 1 июня. Пишем скрипт для обхода этого ограничения
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Предыстория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="https://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
===========
Похожие новости:
- [Веб-дизайн, Разработка веб-сайтов, HTML] Самая серьёзная проблема HTML? Разработчики, разработчики, разработчики (перевод)
- [Разработка веб-сайтов, JavaScript, API] Наиболее полное руководство по практическому использованию Web Speech API
- [Веб-дизайн, Habr, JavaScript, Программирование, HTML] Косяк колхозной простоты в коде веб-сайта Хабра
- [Системное администрирование, *nix, Сетевые технологии, DevOps] Сеть контейнеров — это не сложно (перевод)
- [JavaScript, Программирование, Node.JS] RESTful backend приложение. Базовый шаблон
- [Разработка веб-сайтов, JavaScript, Angular, TypeScript] RxJS Challenge: Неделя 1
- [Разработка веб-сайтов, JavaScript, ReactJS] 5 приемов по разделению «бандла» и «ленивой» загрузке компонентов в React (перевод)
- [JavaScript, Разработка мобильных приложений, Swift, ReactJS] Как Лёня с React на Swift переезжал
- [Разработка веб-сайтов, JavaScript, Программирование, GitHub, Игры и игровые приставки] Разработчик сделал Doom Captcha — теперь можно проходить тест на робота играя
- [CSS, HTML, Usability, Accessibility] HTML и CSS ошибки, ухудшающие UX
Теги для поиска: #_javascript, #_google_api, #_google_apps_script, #_google_docs, #_javascript, #_tutorial, #_html, #_javascript, #_google_api
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:35
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
ПредысторияGoogle изменяет политику хранения данных с 1 июня 2021 года. Вкратце: документы и фото теперь станут полновесными и будут учитываться в общей квоте 15Гб. К тому же, при неактивности аккаунта более двух лет, Google может удалить ваши данные.Я часто работаю с Google документами, и при активном использовании дисковая квота закончится довольно быстро. Но есть и хорошая новость: документы, созданные до 1 июня 2021 года так и останутся невесомыми, поэтому вы не получите превышение квоты в одночасье.У меня сразу возникла мысль сделать документов "в запас". Ниже я расскажу, как это можно осуществить, не тратя много времени и сил.Пишем скрипт, создающий документыСкрипт буду писать с помощью Google Apps Script. Создаём новую таблицу Google, заходим в редактор скриптов (Инструменты - Редактор скриптов).Создаём три файла
function onOpen(e) { // Выполняется при открытии таблицы
SpreadsheetApp.getUi() // Получаем интерфейс пользователя .createMenu('Меню') // Создаём меню .addItem('Создать документы', 'main') // Создаём команду меню .addToUi(); // Добавляем меню в интерфейс } function main() { // Меню - Создать документы
// Создаём HTML документ из шаблона let template = HtmlService.createTemplateFromFile(`index`); // Показываем модальное окно с HTML SpreadsheetApp.getUi() .showModelessDialog(template.evaluate(),`Создаю документы...`); } <!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="https://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>
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; }; 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)); }; Модальное окно для визуализации прогрессаОграничения скрипта
=========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:35
Часовой пояс: UTC + 5