alice-asset-manager
v1.2.0
Published
Node.js API for managing images and sounds in Alice skill
Downloads
12
Readme
alice-asset-manager
Node.js API для загрузки изображений и звуков в навык Алисы.
Позволяет:
- загружать/удалять изображения и звуки
- в режиме синхронизации загружать только измененные файлы и удалять неиспользуемые файлы с сервера
- просматривать загруженные изображения/звуки на реальном устройстве через встроенный навык
Содержание
Установка
npm i alice-asset-manager --save-dev
Изображения
new ImageManager()
Создает инстанс менеджера изображений.
Параметры:
/**
* @param {string} token OAuth-токен
* @param {string} skillId идентификатор навыка
*/
Как получить token
и skillId
- описано в документации.
Пример:
const { ImageManager } = require('alice-asset-manager');
const imageManager = new ImageManager({
token: 'TOKEN',
skillId: 'SKILL_ID',
});
.getQuota()
Получить данные о занятом месте.
await imageManager.getQuota();
/*
{
total: 104857600,
used: 379850
}
*/
.upload()
Загрузить изображение из файла.
Параметры:
/**
* @param {string} filePath путь до файла
* @returns {Promise}
*/
Пример:
await imageManager.upload('images/test.jpg');
/*
{
id: '213044/aef2a365f198b4435611',
size: 8596,
createdAt: '2019-12-09T06:05:35.035Z',
url: 'https://avatars.mds.yandex.net/get-dialogs-skill-card/213044/aef2a365f198b4435611/orig'
}
*/
.getItems()
Получить список всех изображений на сервере.
await imageManager.getItems();
/*
[
{
id: '213044/aef2a365f198b4435611',
origUrl: null,
size: 8596,
createdAt: '2019-12-09T06:05:35.035Z',
url: 'https://avatars.mds.yandex.net/get-dialogs-skill-card/213044/aef2a365f198b4435611/orig'
}
...
]
*/
.getItem()
Получить данные об отдельном изображении.
Параметры:
/**
* @param {string} imageId
* @returns {Promise}
*/
Пример:
await imageManager.getItem('213044/aef2a365f198b4435611');
/*
{
id: '213044/aef2a365f198b4435611',
origUrl: null,
size: 8596,
createdAt: '2019-12-09T06:05:35.035Z',
url: 'https://avatars.mds.yandex.net/get-dialogs-skill-card/213044/aef2a365f198b4435611/orig'
}
*/
.getUrl()
Получить ссылку на изображение.
Параметры:
/**
* @param {string} imageId
* @returns {string}
*/
Пример:
imageManager.getUrl('213044/aef2a365f198b4435611');
/*
'https://avatars.mds.yandex.net/get-dialogs-skill-card/213044/aef2a365f198b4435611/orig'
*/
.delete()
Удалить изображение с сервера.
Параметры:
/**
* @param {string} imageId
* @returns {Promise}
*/
Пример:
await imageManager.delete('213044/aef2a365f198b4435611');
.uploadChanged()
Загрузить новые и измененные изображения на сервер.
Параметры:
/**
* @param {string} pattern путь/паттерн до папки с изображениями
* @param {string} dbFile путь до файла с данными о загрузках
* @param {function} [getLocalId] функция вычисления localId по имени файла
* @param {function} [transform] функция обработки файлов (buffer, filepath) => buffer
* @param {boolean} [dryRun=false] запуск без фактической загрузки файлов
* @returns {Promise}
*/
Как это работает:
При каждом вызове uploadChanged()
сохраняет результаты загрузки во вспомогательный файл
и при последующих вызовах использует сохраненную информацию, чтобы определить файлы для загрузки.
Чтобы избежать повторной загрузки файла при переименовании,
для каждого файла вычисляется localId
- уникальный идентификатор,
который должен сохраняться при переименовании.
По умолчанию localId
ищется в квадратных скобках []
в имени файла:
image[foo].png -> foo
Пример:
В папке images
лежат два изображения my_image_1[alice].png
и my_image_2[bob].png
.
Их localId
следующие:
my_image_1[alice].png -> alice
my_image_2[bob].png -> bob
Запускаем первую зарузку - на сервер загрузятся оба файла:
await imageManager.uploadChanged({
pattern: 'images/*.png', // путь/паттерн до папки с изображениями
dbFile: 'images.json', // путь до файла с данными о загрузках (изначально файла нет)
});
/*
uploaded: 'images/my_image_1[alice].png', 'images/my_image_2[bob].png'
skipped: 0
*/
В images.json
запишется примерно следующее:
{
"ids": {
"alice": "213044/aef2a365f198b4435611",
"bob": "834732/sdg3s44fjh234524j2h4"
},
"meta": {
"alice": {
"file": "images/my_image_1[alice].png",
"url": "https://avatars.mds.yandex.net/get-dialogs-skill-card/213044/aef2a365f198b4435611/orig",
"mtimeMs": 1576249136829.0754
},
"bob": {
"file": "images/my_image_2[bob].png",
"url": "https://avatars.mds.yandex.net/get-dialogs-skill-card/834732/sdg3s44fjh234524j2h4/orig",
"mtimeMs": 1576249136830.0842
}
}
}
Файл images.json
удобно использовать в коде вашего навыка, вставляя изображения по их localId
.
Главный плюс в том, что при изменении изображения и получении нового image_id
на сервере,
в коде навыка ничего менять не нужно - новый image_id
подтянется по localId
автоматически:
const images = require('./images.json').ids;
// ...
response.card.image_id = images.alice;
Если повторно вызвать uploadChanged()
ничего не меняя, то загрузок не произойдет,
т.к. файлы не изменились и уже загружены на сервер:
await imageManager.uploadChanged({
pattern: 'images/*.png',
dbFile: 'images.json',
});
/*
uploaded: 0
skipped: 'images/my_image_1[alice].png', 'images/my_image_2[bob].png'
*/
Если изменить в фоторедакторе один из файлов (например my_image_1[alice].png
),
то при вызове uploadChanged()
загрузится только этот измененный файл:
await imageManager.uploadChanged({
pattern: 'images/*.png',
dbFile: 'images.json',
});
/*
uploaded: 'images/my_image_1[alice].png'
skipped: 'images/my_image_2[bob].png'
*/
Информация в images.json
также обновится - туда запишется новый image_id
для my_image_1[alice].png
.
Использование в коде навыка останется прежним:
const images = require('./images.json').ids;
// ...
response.card.image_id = images.alice;
Для обработки загружаемых файлов (например изменения размеров изображений) можно использовать параметр transform
.
Вот готовый пример кода для подгона изображений под размер 776х344
с использованием библиотеки Jimp:
await imageManager.uploadChanged({
pattern: 'images/*.png',
dbFile: 'images.json',
transform: async buffer => {
const image = await Jimp.read(buffer);
return image
.normalize()
.background(0xFFFFFFFF)
.contain(776, 344)
.quality(75)
.getBufferAsync(Jimp.AUTO);
}
});
.deleteUnused()
Удалить неиспользуемые изображения с сервера.
Параметры:
/**
* @param {string} dbFile путь до файла с данными о загрузках, созданный методом uploadChanged()
* @param {boolean} [dryRun=false] запуск без фактического удаления изображений
* @returns {Promise}
*/
Работает только в связке с .uploadChanged()
.
При частых изменениях файлов и многократных вызовах .uploadChanged()
на сервере накапливаются неиспользуемые изображения.
Их нужно периодически удалять, чтобы освободить место.
Метод .deleteUnused()
сравнивает то, что записано в dbFile
с тем что лежит на сервере, и удаляет с сервера лишнее.
Пример:
В навыке используются два изображения my_image_1[alice].png
и my_image_2[bob].png
.
Они были загружены на сервер через .uploadChanged()
и информация сохранена в dbFile: 'images.json'
.
В новой версии навыка файл my_image_1[alice].png
не используется и был удален.
После вызова .uploadChanged()
в images.json
останется только запись про второй файл images/my_image_2[bob].png
:
{
"ids": {
"bob": "834732/sdg3s44fjh234524j2h4"
},
"meta": {
"bob": {
"file": "images/my_image_2[bob].png",
"url": "https://avatars.mds.yandex.net/get-dialogs-skill-card/834732/sdg3s44fjh234524j2h4/orig",
"mtimeMs": 1576249136830.0842
}
}
}
Но на сервере все еще лежат два файла.
Это нужно для того, чтобы текущая версия навыка продолжала нормально работать.
Когда новая версия навыка выкатится, запись про my_image_1[alice].png
можно удалить с сервера:
await imageManager.deleteUnused({
dbFile: 'images.json',
});
/*
{
deleted: [ '213044/aef2a365f198b4435611' ],
used: [ 'images/my_image_2[bob].png' ]
}
*/
Чтобы предварительно посмотреть, какие изображения будут удалены с сервера - можно вызвать метод
с параметром dryRun: true
:
await imageManager.deleteUnused({
dbFile: 'images.json',
dryRun: true
});
/*
{
deleted: [ '213044/aef2a365f198b4435611' ],
used: [ 'images/my_image_2[bob].png' ]
}
*/
.createViewServer()
Создает HTTP-сервер для просмотра загруженных изображений через навык.
Параметры:
/**
* @param {string} [dbFile] путь до файла с данными о загрузках, созданный методом uploadChanged()
*/
Создаваемый HTTP-сервер позволяет быстро посмотреть загруженные изображения на экране смартфона.
Пример:
const server = imageManager.createViewServer();
server.listen(3000);
Когда сервер запустился на 3000
порту, можно используя любой прокси-навык
(например alice-dev.vitalets.xyz) проверить все изображения на смартфоне.
Изображения в навыке отсортированы по дате загрузки, поэтому в первую очередь будут показаны недавно измененные файлы.
Чтобы рядом с изображениями дополнительно выводилось имя файла и localId, нужно указать в параметрах dbFile
:
const server = imageManager.createViewServer({
dbFile: 'images.json'
});
server.listen(3000);
Чтобы сервер автоматически перезапускался при изменениях images.json
можно использовать nodemon:
nodemon ./image-server.js --watch ./images.json
Звуки
new SoundManager()
Создает инстанс менеджера звуков.
Параметры:
/**
* @param {string} token OAuth-токен
* @param {string} skillId идентификатор навыка
*/
Как получить token
и skillId
- описано в документации.
Пример:
const { SoundManager } = require('alice-asset-manager');
const soundManager = new SoundManager({
token: 'TOKEN',
skillId: 'SKILL_ID',
});
.getQuota()
Получить данные о занятом месте.
await soundManager.getQuota();
/*
{
total: 104857600,
used: 379850
}
*/
.upload()
Загрузить звук из файла.
Параметры:
/**
* @param {string} filePath путь до файла
* @returns {Promise}
*/
Пример:
await soundManager.upload('images/test.mp3');
/*
{
id: 'c72463ae-01b5-48a1-a7f2-e657e4594166',
skillId: 'SKILL_ID',
size: null,
originalName: 'test.mp3',
createdAt: '2019-12-09T06:13:49.595Z',
isProcessed: false,
error: null,
url: 'https://yastatic.net/s3/dialogs/dialogs-upload/sounds/opus/SKILL_ID/c72463ae-01b5-48a1-a7f2-e657e4594166.opus'
}
*/
.getItems()
Получить список всех звуков на сервере.
await soundManager.getItems();
/*
[
{
id: 'c72463ae-01b5-48a1-a7f2-e657e4594166',
skillId: 'SKILL_ID',
size: 24915,
originalName: 'test.mp3',
createdAt: '2019-12-09T06:19:48.317Z',
isProcessed: true,
error: null,
url: 'https://yastatic.net/s3/dialogs/dialogs-upload/sounds/opus/SKILL_ID/c72463ae-01b5-48a1-a7f2-e657e4594166.opus'
}
...
]
*/
.getItem()
Получить данные об отдельном звуке на сервере.
Параметры:
/**
* @param {string} soundId
* @returns {Promise}
*/
Пример:
await soundManager.getItem('c72463ae-01b5-48a1-a7f2-e657e4594166');
/*
{
id: 'c72463ae-01b5-48a1-a7f2-e657e4594166',
skillId: 'SKILL_ID',
size: 24915,
originalName: 'test.mp3',
createdAt: '2019-12-09T06:19:48.317Z',
isProcessed: true,
error: null,
url: 'https://yastatic.net/s3/dialogs/dialogs-upload/sounds/opus/SKILL_ID/c72463ae-01b5-48a1-a7f2-e657e4594166.opus'
}
*/
.getUrl()
Получить ссылку на звук.
Параметры:
/**
* @param {string} soundId
* @returns {string}
*/
Пример:
soundManager.getUrl('c72463ae-01b5-48a1-a7f2-e657e4594166');
/*
'https://yastatic.net/s3/dialogs/dialogs-upload/sounds/opus/SKILL_ID/c72463ae-01b5-48a1-a7f2-e657e4594166.opus'
*/
.getTts()
Получить tts для вставки звука в ответ навыка.
Параметры:
/**
* @param {string} soundId
* @returns {string}
*/
Пример:
soundManager.getTts('c72463ae-01b5-48a1-a7f2-e657e4594166');
/*
'<speaker audio="dialogs-upload/SKILL_ID/c72463ae-01b5-48a1-a7f2-e657e4594166.opus">'
*/
.delete()
Удалить звук с сервера.
Параметры:
/**
* @param {string} soundId
* @returns {Promise}
*/
Пример:
await soundManager.delete('213044/aef2a365f198b4435611');
.uploadChanged()
Загрузить новые и измененные звуки на сервер.
Параметры:
/**
* @param {string} pattern путь/паттерн до папки со звуками
* @param {string} dbFile путь до файла с данными о загрузках
* @param {function} [getLocalId] функция вычисления localId по имени файла
* @param {boolean} [dryRun=false] запуск без зфактической загрузки файлов
* @returns {Promise}
*/
Все работает аналогично методу .uploadChanged() для изображений.
.deleteUnused()
Удалить неиспользуемые звуки с сервера.
Параметры:
/**
* @param {string} dbFile путь до файла с данными о загрузках, созданный методом uploadChanged()
* @param {boolean} [dryRun=false] запуск без фактического удаления звуков
* @returns {Promise}
*/
Все работает аналогично методу .deleteUnused() для изображений.
.createViewServer()
Создает HTTP-сервер для прослушивания загруженных звуков через навык.
Параметры:
/**
* @param {string} [dbFile] путь до файла с данными о загрузках, созданный методом uploadChanged()
*/
Все работает аналогично методу .createViewServer() для изображений.
Лицензия
MIT @ Vitaliy Potapov