Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

alice-asset-manager

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

alice-asset-manager - npm Package Compare versions

Comparing version 1.0.1 to 1.1.0

5

package.json
{
"name": "alice-asset-manager",
"version": "1.0.1",
"version": "1.1.0",
"description": "Node.js API for managing images and sounds in Alice skill",

@@ -24,3 +24,3 @@ "author": {

"test": "mocha test/setup.js test/specs/*.js --timeout=6000",
"test:d": "npm run test -- --bail",
"test:d": "DEBUG=alice-asset-manager npm run test -- --bail",
"toc": "markdown-toc README.md -i",

@@ -41,2 +41,3 @@ "release": "npm run lint && npm test && npm version $VER && npm publish && git push --follow-tags --no-verify",

"dependencies": {
"debug": "^4.1.1",
"form-data": "^3.0.0",

@@ -43,0 +44,0 @@ "glob": "^7.1.6",

41

README.md

@@ -197,3 +197,4 @@ # alice-asset-manager

* @param {function} [getLocalId] функция вычисления localId по имени файла
* @param {boolean} [dryRun=false] запуск без зфактической загрузки файлов
* @param {function} [transform] функция обработки файлов (buffer, filepath) => buffer
* @param {boolean} [dryRun=false] запуск без фактической загрузки файлов
* @returns {Promise}

@@ -233,6 +234,4 @@ */

/*
{
uploaded: [ 'images/my_image_1[alice].png', 'images/my_image_2[bob].png' ],
skipped: []
}
uploaded: 'images/my_image_1[alice].png', 'images/my_image_2[bob].png'
skipped: 0
*/

@@ -265,3 +264,3 @@ ```

Главный плюс в том, что при изменении изображения и получении нового `image_id` на сервере,
в коде навыка ничего менять не нужно - новый `image_id` подтянется автоматически:
в коде навыка ничего менять не нужно - новый `image_id` подтянется по `localId` автоматически:
```js

@@ -281,6 +280,4 @@ const images = require('./images.json').ids;

/*
{
uploaded: [],
skipped: [ 'images/my_image_1[alice].png', 'images/my_image_2[bob].png' ]
}
uploaded: 0
skipped: 'images/my_image_1[alice].png', 'images/my_image_2[bob].png'
*/

@@ -297,6 +294,4 @@ ```

/*
{
uploaded: [ 'images/my_image_1[alice].png' ],
skipped: [ 'images/my_image_2[bob].png' ]
}
uploaded: 'images/my_image_1[alice].png'
skipped: 'images/my_image_2[bob].png'
*/

@@ -312,2 +307,20 @@ ```

Для обработки загружаемых файлов (например изменения размеров изображений) можно использовать параметр `transform`.
Вот готовый пример кода для подгона изображений под размер `776х344` с использованием библиотеки [Jimp](https://github.com/oliver-moran/jimp):
```js
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()

@@ -314,0 +327,0 @@ Удалить неиспользуемые изображения с сервера.

@@ -1,5 +0,4 @@

const fs = require('fs-extra');
const path = require('path');
const fetch = require('node-fetch');
const FormData = require('form-data');
const debug = require('debug')('alice-asset-manager');
const {throwIf} = require('throw-utils');

@@ -44,6 +43,12 @@ const {stringify} = require('./utils');

async upload(filePath) {
/**
* Uploads buffer.
*
* @param {Buffer|Stream} buffer
* @param {string} filename
* @returns {Promise}
*/
async uploadBuffer(buffer, filename) {
const formData = new FormData();
const filename = path.basename(filePath);
formData.append('file', fs.createReadStream(filePath), {filename});
formData.append('file', buffer, { filename });
return this._request(this._restUrl, {

@@ -69,15 +74,23 @@ method: 'post',

const fullUrl = `${BASE_URL}${url}`;
options.headers = Object.assign({
Authorization: `OAuth ${this._token}`,
timeout: this._timeout,
}, options.headers);
options = this._buildOptions(options);
debug(options.method, fullUrl);
const response = await fetch(fullUrl, options);
if (response.ok) {
return response.json();
const json = await response.json();
debug(response.status, json);
return json;
} else {
const text = await response.text();
const method = (options.method || 'get').toUpperCase();
throw new Error(`${response.status} ${text} ${method} ${url}`);
throw new Error(`${response.status} ${text} ${options.method} ${url}`);
}
}
_buildOptions(options) {
options.method = (options.method || 'GET').toUpperCase();
options.headers = Object.assign({
Authorization: `OAuth ${this._token}`,
timeout: this._timeout,
}, options.headers);
return options;
}
};
/**
* Image manager.
*/
const fs = require('fs-extra');
const path = require('path');
const BaseManager = require('./base-manager');

@@ -63,3 +65,16 @@ const SmartUploader = require('./smart-uploader');

async upload(filePath) {
const { image } = await super.upload(filePath);
const buffer = fs.createReadStream(filePath);
const filename = path.basename(filePath);
return this.uploadBuffer(buffer, filename);
}
/**
* Загрузить изображение из буфера.
*
* @param {Buffer|Stream} buffer данные
* @param {string} filename имя файла
* @returns {Promise}
*/
async uploadBuffer(buffer, filename) {
const { image } = await super.uploadBuffer(buffer, filename);
return {

@@ -97,8 +112,9 @@ ...image,

* @param {function} [getLocalId] функция вычисления localId по имени файла
* @param {function} [transform] функция обработки файлов (buffer, filepath) => buffer
* @param {boolean} [dryRun=false] запуск без фактической загрузки файлов
* @returns {Promise}
* @returns {Promise<Array>}
*/
async uploadChanged({pattern, dbFile, dryRun, getLocalId}) {
async uploadChanged({ pattern, dbFile, getLocalId, transform, dryRun }) {
const uploader = new SmartUploader(this);
return uploader.uploadChanged({pattern, dbFile, dryRun, getLocalId});
return uploader.uploadChanged({ pattern, dbFile, getLocalId, transform, dryRun });
}

@@ -105,0 +121,0 @@

@@ -10,6 +10,9 @@ /**

// By default extract localId as '[local_id]' at the end of filename
const getLocalIdDefault = file => {
const matches = path.basename(file).match(/\[(.+?)\]/);
return matches && matches[1];
const defaults = {
// By default extract localId as '[local_id]' at the end of filename
getLocalId: file => {
const matches = path.basename(file).match(/\[(.+?)\]/);
return matches && matches[1];
},
transform: (buffer, filePath) => buffer, // eslint-disable-line no-unused-vars
};

@@ -36,3 +39,3 @@

async uploadChanged({pattern, dbFile, dryRun, getLocalId}) {
async uploadChanged({ pattern, dbFile, getLocalId, transform, dryRun }) {
const files = this._getFiles(pattern);

@@ -43,10 +46,5 @@ this._createLocalItems(files, getLocalId);

this._markLocalItemsForUpload();
if (!dryRun) {
await this._upload();
this._saveDbFile();
}
return {
uploaded: this._localItems.filter(item => item.upload).map(item => item.file),
skipped: this._localItems.filter(item => !item.upload).map(item => item.file),
};
await this._upload({ transform, dryRun });
this._saveDbFile({ dryRun });
return this._localItems;
}

@@ -85,4 +83,8 @@

// загружаем файл, если он не был загружен или изменилась дата модификации или его нет на сервере
if (!id || mtimeMs !== localItem.mtimeMs || !this._hasRemoteItem(id)) {
localItem.upload = true;
if (!id) {
localItem.upload = 'new';
} else if (mtimeMs !== localItem.mtimeMs) {
localItem.upload = 'changed';
} else if (!this._hasRemoteItem(id)) {
localItem.upload = 'deleted_on_server';
} else {

@@ -99,3 +101,3 @@ localItem.id = id;

_createLocalItems(files, getLocalId) {
getLocalId = getLocalId || getLocalIdDefault;
getLocalId = getLocalId || defaults.getLocalId;
this._localItems = files.map(file => {

@@ -114,10 +116,13 @@ const localId = stringify(getLocalId(file));

async _upload() {
const tasks = this._localItems
.filter(localItem => localItem.upload)
.map(async localItem => {
const { id } = await this._manager.upload(localItem.file);
async _upload({ transform, dryRun }) {
transform = transform || defaults.transform;
const localItemToUpload = this._localItems.filter(localItem => localItem.upload);
for (const localItem of localItemToUpload) {
const buffer = await fs.readFile(localItem.file);
const transformedBuffer = await transform(buffer, localItem.file);
if (!dryRun) {
const {id} = await this._manager.uploadBuffer(transformedBuffer, localItem.file);
localItem.id = id;
});
await Promise.all(tasks);
}
}
}

@@ -156,10 +161,19 @@

_saveDbFile() {
_saveDbFile({ dryRun }) {
const newDbFileData = this._buildDbFileData();
if (!dryRun) {
fs.outputJsonSync(this._dbFile, newDbFileData, {spaces: 2});
}
}
_buildDbFileData() {
const newDbFileData = {};
// сортируем по localId, чтобы удобнее было смотреть в dbFile
this._localItems.sort((a, b) => a.localId.localeCompare(b.localId));
// записываем id-шники в отдельное свойство ids для удобного доступа
newDbFileData.ids = {};
this._localItems.forEach(({localId, id}) => newDbFileData.ids[localId] = id);
// для звуков записываем еще поле tts, так удобнее использовать их в коде навыка
// для звуков записываем еще поле tts, так удобнее использовать их в коде навыка
if (this._manager.getTts) {

@@ -169,3 +183,4 @@ newDbFileData.tts = {};

}
// имя файла и дату моюицикации пишем в поле meta
// имя файла и дату модификации пишем в поле meta
newDbFileData.meta = {};

@@ -176,3 +191,4 @@ this._localItems.forEach(({file, localId, mtimeMs, id}) => {

});
fs.outputJsonSync(this._dbFile, newDbFileData, {spaces: 2});
return newDbFileData;
}

@@ -179,0 +195,0 @@

/**
* Sound manager.
*/
const fs = require('fs-extra');
const path = require('path');
const BaseManager = require('./base-manager');

@@ -68,3 +70,16 @@ const SmartUploader = require('./smart-uploader');

async upload(filePath) {
const { sound } = await super.upload(filePath);
const buffer = fs.createReadStream(filePath);
const filename = path.basename(filePath);
return this.uploadBuffer(buffer, filename);
}
/**
* Загрузить звук из буфера.
*
* @param {Buffer|Stream} buffer данные
* @param {string} filename имя файла
* @returns {Promise}
*/
async uploadBuffer(buffer, filename) {
const { sound } = await super.uploadBuffer(buffer, filename);
return {

@@ -113,8 +128,9 @@ ...sound,

* @param {function} [getLocalId] функция вычисления localId по имени файла
* @param {function} [transform] функция обработки файлов (buffer, filepath) => buffer
* @param {boolean} [dryRun=false] запуск без фактической загрузки файлов
* @returns {Promise}
* @returns {Promise<Array>}
*/
async uploadChanged({pattern, dbFile, dryRun, getLocalId}) {
async uploadChanged({ pattern, dbFile, getLocalId, transform, dryRun }) {
const uploader = new SmartUploader(this);
return uploader.uploadChanged({pattern, dbFile, dryRun, getLocalId});
return uploader.uploadChanged({ pattern, dbFile, getLocalId, transform, dryRun });
}

@@ -121,0 +137,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc