museria 0.2.49 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.eslintrc +10 -2
  2. package/.github/workflows/build.yml +3 -3
  3. package/.github/workflows/publish.yml +3 -3
  4. package/README.md +55 -59
  5. package/bin/actions.js +28 -28
  6. package/bin/index.js +4 -4
  7. package/bin/runner.js +1 -1
  8. package/bin/utils.js +6 -2
  9. package/dist/client/museria.client.js +7 -7
  10. package/dist/face/45a265d0f07b31cde85f.ttf +0 -0
  11. package/dist/face/6205fd00fb1b573e9f0f.ttf +0 -0
  12. package/dist/face/8d3cabfc66809162fb4d.woff2 +0 -0
  13. package/dist/face/fb8184add5a3101ad0a3.woff2 +0 -0
  14. package/dist/face/museria.face.js +33 -13
  15. package/dist/face/style.css +13 -11
  16. package/package.json +41 -40
  17. package/src/browser/client/index.js +2 -1
  18. package/src/browser/face/client.js +2 -1
  19. package/src/browser/face/controllers/app/app.html +77 -69
  20. package/src/browser/face/controllers/app/app.js +14 -7
  21. package/src/browser/face/controllers/app/app.scss +2 -22
  22. package/src/browser/face/index.js +3 -3
  23. package/src/browser/face/styles/main.scss +91 -11
  24. package/src/browser/face/styles/vars.scss +0 -1
  25. package/src/client.js +73 -74
  26. package/src/collection/transports/music/index.js +20 -18
  27. package/src/db/transports/database/index.js +7 -5
  28. package/src/db/transports/loki/index.js +30 -25
  29. package/src/errors.js +2 -1
  30. package/src/index.js +8 -6
  31. package/src/node.js +312 -323
  32. package/src/schema.js +27 -29
  33. package/src/server/transports/express/api/butler/controllers.js +7 -10
  34. package/src/server/transports/express/api/butler/routes.js +5 -5
  35. package/src/server/transports/express/api/master/controllers.js +7 -10
  36. package/src/server/transports/express/api/master/routes.js +5 -5
  37. package/src/server/transports/express/api/node/controllers.js +52 -61
  38. package/src/server/transports/express/api/node/routes.js +10 -10
  39. package/src/server/transports/express/api/routes.js +1 -1
  40. package/src/server/transports/express/api/slave/controllers.js +7 -10
  41. package/src/server/transports/express/api/slave/routes.js +6 -6
  42. package/src/server/transports/express/client/controllers.js +40 -61
  43. package/src/server/transports/express/client/routes.js +33 -39
  44. package/src/server/transports/express/controllers.js +10 -21
  45. package/src/server/transports/express/index.js +23 -20
  46. package/src/server/transports/express/midds.js +67 -67
  47. package/src/server/transports/express/routes.js +12 -12
  48. package/src/utils.js +175 -184
  49. package/test/client.js +311 -305
  50. package/test/db/database.js +32 -28
  51. package/test/db/loki.js +78 -74
  52. package/test/group.js +161 -156
  53. package/test/index.js +20 -10
  54. package/test/node.js +461 -460
  55. package/test/routes.js +404 -399
  56. package/test/server/express.js +35 -31
  57. package/test/services.js +25 -18
  58. package/test/tools.js +8 -6
  59. package/test/utils.js +236 -234
  60. package/webpack.client.js +9 -7
  61. package/webpack.face.js +8 -6
  62. package/dist/face/fa-brands-400.eot +0 -0
  63. package/dist/face/fa-brands-400.svg +0 -3717
  64. package/dist/face/fa-brands-400.ttf +0 -0
  65. package/dist/face/fa-brands-400.woff +0 -0
  66. package/dist/face/fa-brands-400.woff2 +0 -0
  67. package/dist/face/fa-solid-900.eot +0 -0
  68. package/dist/face/fa-solid-900.svg +0 -5034
  69. package/dist/face/fa-solid-900.ttf +0 -0
  70. package/dist/face/fa-solid-900.woff +0 -0
  71. package/dist/face/fa-solid-900.woff2 +0 -0
  72. /package/dist/face/{open-sans.ttf → 17e98b9e5586529b13cc.ttf} +0 -0
  73. /package/dist/face/{proxima-nova.ttf → 326601dfabd91e3f016c.ttf} +0 -0
  74. /package/dist/face/{logo.svg → ee9c6af64aa224827cec.svg} +0 -0
package/src/node.js CHANGED
@@ -1,36 +1,42 @@
1
- const _ = require('lodash');
2
- const fs = require('fs');
3
- const path = require('path');
4
- const sharp = require('sharp');
5
- const fse = require('fs-extra');
6
- const qs = require('querystring');
7
- const SplayTree = require('splaytree');
8
- const DatabaseLokiMuseria = require('./db/transports/loki')();
9
- const ServerExpressMuseria = require('./server/transports/express')();
10
- const MusicCollection = require('./collection/transports/music')();
11
- const ApprovalCaptcha = require('spreadable/src/approval/transports/captcha')();
12
- const NodeMetastocle = require('metastocle/src/node')();
13
- const NodeStoracle = require('storacle/src/node')(NodeMetastocle);
14
- const schema = require('./schema');
15
- const utils = require('./utils');
16
- const errors = require('./errors');
17
- const pack = require('../package.json');
18
-
19
- module.exports = (Parent) => {
1
+ import { merge, omit, random, assign } from "lodash-es";
2
+ import path from "path";
3
+ import sharp from "sharp";
4
+ import fse from "fs-extra";
5
+ import qs from "querystring";
6
+ import SplayTree from "splaytree";
7
+ import databaseLokiMuseria from "./db/transports/loki/index.js";
8
+ import serverExpressMuseria from "./server/transports/express/index.js";
9
+ import musicCollection from "./collection/transports/music/index.js";
10
+ import approvalCaptcha from "spreadable/src/approval/transports/captcha/index.js";
11
+ import nodeMetastocle from "metastocle/src/node.js";
12
+ import nodeStoracle from "storacle/src/node.js";
13
+ import schema from "./schema.js";
14
+ import utils from "./utils.js";
15
+ import errors from "./errors.js";
16
+ import pack from "../package.json" with { type: "json" }
17
+
18
+ const DatabaseLokiMuseria = databaseLokiMuseria();
19
+ const ServerExpressMuseria = serverExpressMuseria();
20
+ const MusicCollection = musicCollection();
21
+ const ApprovalCaptcha = approvalCaptcha();
22
+ const NodeMetastocle = nodeMetastocle();
23
+ const NodeStoracle = nodeStoracle(NodeMetastocle);
24
+
25
+ export default (Parent) => {
20
26
  /**
21
27
  * Class to manage the node
22
28
  */
23
29
  return class NodeMuseria extends (Parent || NodeStoracle) {
24
- static get version () { return pack.version }
25
- static get codename () { return pack.name }
26
- static get DatabaseTransport () { return DatabaseLokiMuseria }
27
- static get ServerTransport () { return ServerExpressMuseria }
30
+ static get version() { return pack.version; }
31
+ static get codename() { return pack.name; }
32
+ static get DatabaseTransport() { return DatabaseLokiMuseria; }
33
+ static get ServerTransport() { return ServerExpressMuseria; }
28
34
 
29
35
  /**
30
36
  * @see NodeStoracle
31
37
  */
32
38
  constructor(options = {}) {
33
- options = _.merge({
39
+ options = merge({
34
40
  request: {
35
41
  fileStoringNodeTimeout: '10m'
36
42
  },
@@ -42,7 +48,7 @@ module.exports = (Parent) => {
42
48
  queue: true,
43
49
  loki: {
44
50
  unique: ['title', 'fileHash'],
45
- },
51
+ },
46
52
  limitationOrder: ['priority', '$accessedAt'],
47
53
  duplicationKey: 'fileHash',
48
54
  schema: schema.getMusicCollection()
@@ -74,14 +80,13 @@ module.exports = (Parent) => {
74
80
  mimeWhitelist: [
75
81
  'audio/mp3',
76
82
  'audio/mpeg',
77
- 'audio/mpeg3'
83
+ 'audio/mpeg3'
78
84
  ]
79
85
  },
80
86
  task: {
81
87
  cleanUpMusicInterval: '1m'
82
88
  }
83
89
  }, options);
84
-
85
90
  super(options);
86
91
  this.__addingFiles = {};
87
92
  }
@@ -90,51 +95,51 @@ module.exports = (Parent) => {
90
95
  * @see NodeStoracle.prototype.initBeforeSync
91
96
  */
92
97
  async initBeforeSync() {
93
- await super.initBeforeSync.apply(this, arguments);
98
+ await super.initBeforeSync.apply(this, arguments);
94
99
  await this.normalizeSongTitles();
95
100
  await this.cleanUpMusic();
96
- }
101
+ }
97
102
 
98
103
  /**
99
104
  * @see NodeStoracle.prototype.prepareServices
100
105
  */
101
106
  async prepareServices() {
102
107
  await super.prepareServices.apply(this, arguments);
103
- await this.addApproval('addSong', new ApprovalCaptcha({ period: this.options.request.fileStoringNodeTimeout }));
108
+ await this.addApproval('addSong', new ApprovalCaptcha({ period: this.options.request.fileStoringNodeTimeout }));
104
109
  await this.addCollection('music', new MusicCollection(this.options.collections.music));
105
110
  }
106
111
 
107
112
  /**
108
113
  * Prepare the task service
109
- *
114
+ *
110
115
  * @async
111
116
  */
112
- async prepareTask() {
117
+ async prepareTask() {
113
118
  await super.prepareTask.apply(this, arguments);
114
-
115
- if(!this.task) {
119
+
120
+ if (!this.task) {
116
121
  return;
117
122
  }
118
123
 
119
- if(this.options.task.cleanUpMusicInterval) {
124
+ if (this.options.task.cleanUpMusicInterval) {
120
125
  await this.task.add('cleanUpMusic', this.options.task.cleanUpMusicInterval, () => this.cleanUpMusic());
121
126
  }
122
127
  }
123
128
 
124
- /**
129
+ /**
125
130
  * Normalize the song titles
126
- *
131
+ *
127
132
  * @async
128
133
  */
129
134
  async normalizeSongTitles() {
130
135
  const docs = await this.db.getDocuments('music');
131
136
  const titles = {};
132
-
133
- for(let i = 0; i < docs.length; i++) {
137
+
138
+ for (let i = 0; i < docs.length; i++) {
134
139
  const doc = docs[i];
135
140
  const title = utils.beautifySongTitle(doc.title);
136
-
137
- if(titles[title] && titles[title] != doc.$loki) {
141
+
142
+ if (titles[title] && titles[title] != doc.$loki) {
138
143
  await this.db.deleteDocument(doc);
139
144
  continue;
140
145
  }
@@ -145,43 +150,38 @@ module.exports = (Parent) => {
145
150
  }
146
151
  }
147
152
 
148
- /**
153
+ /**
149
154
  * Clean up the music
150
- *
155
+ *
151
156
  * @async
152
157
  */
153
158
  async cleanUpMusic() {
154
159
  const docs = await this.db.getDocuments('music');
155
160
  const hashes = {};
156
161
 
157
- for(let i = 0; i < docs.length; i++) {
162
+ for (let i = 0; i < docs.length; i++) {
158
163
  const doc = docs[i];
159
164
 
160
- if(
161
- !doc.fileHash ||
165
+ if (!doc.fileHash ||
162
166
  typeof doc.fileHash != 'string' ||
163
- (
164
- !this.isFileAdding(doc.fileHash) &&
167
+ (!this.isFileAdding(doc.fileHash) &&
165
168
  !await this.hasFile(doc.fileHash) &&
166
- await this.db.getMusicByFileHash(doc.fileHash)
167
- )
168
- ) {
169
+ await this.db.getMusicByFileHash(doc.fileHash))) {
169
170
  await this.db.deleteDocument(doc);
170
171
  continue;
171
172
  }
172
173
 
173
174
  hashes[doc.fileHash] = true;
174
175
  }
175
-
176
- await this.iterateFiles(async filePath => {
176
+ await this.iterateFiles(async (filePath) => {
177
177
  try {
178
178
  const hash = path.basename(filePath);
179
-
180
- if(!hashes[hash] && !this.isFileAdding(hash) && !await this.db.getMusicByFileHash(hash)) {
179
+
180
+ if (!hashes[hash] && !this.isFileAdding(hash) && !await this.db.getMusicByFileHash(hash)) {
181
181
  await this.removeFileFromStorage(hash);
182
182
  }
183
183
  }
184
- catch(err) {
184
+ catch (err) {
185
185
  this.logger.warn(err.stack);
186
186
  }
187
187
  });
@@ -190,17 +190,17 @@ module.exports = (Parent) => {
190
190
  /**
191
191
  * @see NodeStoracle.prototype.calculateStorageInfo
192
192
  */
193
- async calculateStorageInfo() {
194
- let limit = this.options.collections.music.limit;
195
- await super.calculateStorageInfo.apply(this, arguments);
196
-
197
- if(limit != 'auto') {
193
+ async calculateStorageInfo() {
194
+ let limit = this.options.collections.music.limit;
195
+ await super.calculateStorageInfo.apply(this, arguments);
196
+
197
+ if (limit != 'auto') {
198
198
  return;
199
199
  }
200
-
200
+
201
201
  const filesTotalSize = await this.db.getData('filesTotalSize');
202
202
  const filesCount = await this.db.getData('filesCount');
203
- const avgSize = filesTotalSize && filesCount? filesTotalSize / filesCount: this.fileMaxSize;
203
+ const avgSize = filesTotalSize && filesCount ? filesTotalSize / filesCount : this.fileMaxSize;
204
204
  limit = Math.floor(this.storageDataSize / avgSize) - 1;
205
205
  limit < 1 && (limit = 1);
206
206
  const collection = await this.getCollection('music');
@@ -210,59 +210,59 @@ module.exports = (Parent) => {
210
210
  /**
211
211
  * @see NodeStoracle.prototype.getStatusInfo
212
212
  */
213
- async getStatusInfo(pretty = false) {
213
+ async getStatusInfo(pretty = false) {
214
214
  const collection = await this.getCollection('music');
215
- return _.merge(await super.getStatusInfo(pretty), { collectionLimit: collection.limit });
215
+ return merge(await super.getStatusInfo(pretty), { collectionLimit: collection.limit });
216
216
  }
217
217
 
218
218
  /**
219
219
  * @see NodeStoracle.prototype.getStorageCleaningUpTree
220
220
  */
221
- async getStorageCleaningUpTree() {
221
+ async getStorageCleaningUpTree() {
222
222
  const docs = await this.db.getDocuments('music');
223
223
  const hashes = {};
224
-
225
- for(let i = 0; i < docs.length; i++) {
224
+
225
+ for (let i = 0; i < docs.length; i++) {
226
226
  const doc = docs[i];
227
-
228
- if(!doc.fileHash || typeof doc.fileHash != 'string') {
227
+
228
+ if (!doc.fileHash || typeof doc.fileHash != 'string') {
229
229
  continue;
230
230
  }
231
231
 
232
232
  hashes[doc.fileHash] = doc;
233
233
  }
234
-
234
+
235
235
  const tree = new SplayTree((a, b) => {
236
- if(a.priority == b.priority) {
236
+ if (a.priority == b.priority) {
237
237
  return a.accessedAt - b.accessedAt;
238
238
  }
239
-
239
+
240
240
  return a.priority - b.priority;
241
241
  });
242
242
  await this.iterateFiles(async (filePath, stat) => {
243
243
  const hash = path.basename(filePath);
244
244
  const doc = hashes[hash] || await this.db.getMusicByFileHash(hash);
245
245
 
246
- if(!this.isFileAdding(hash)) {
247
- const accessedAt = doc? doc.$accessedAt: 0;
248
- const priority = doc? doc.priority: -1;
246
+ if (!this.isFileAdding(hash)) {
247
+ const accessedAt = doc ? doc.$accessedAt : 0;
248
+ const priority = doc ? doc.priority : -1;
249
249
  tree.insert({ accessedAt, priority }, { size: stat.size, path: filePath });
250
- }
250
+ }
251
251
  });
252
252
  return tree;
253
253
  }
254
-
254
+
255
255
  /**
256
256
  * Add the song
257
- *
257
+ *
258
258
  * @async
259
- * @param {string|Buffer|fs.ReadStream} file
259
+ * @param {string|Buffer|fse.ReadStream} file
260
260
  * @param {object} [options]
261
261
  * @returns {string}
262
262
  */
263
263
  async addSong(file, options = {}) {
264
264
  const destroyFileStream = () => utils.isFileReadStream(file) && file.destroy();
265
-
265
+
266
266
  try {
267
267
  options = Object.assign({
268
268
  priority: 0,
@@ -271,52 +271,48 @@ module.exports = (Parent) => {
271
271
  this.songPriorityTest(options);
272
272
  file = await this.prepareSongFileBeforeAddition(file);
273
273
  const timer = this.createRequestTimer(options.timeout);
274
- const collection = await this.getCollection('music');
274
+ const collection = await this.getCollection('music');
275
275
  const tags = await utils.getSongTags(file);
276
- this.songTitleTest(tags.fullTitle);
276
+ this.songTitleTest(tags.fullTitle);
277
277
  const fileInfo = await utils.getFileInfo(file);
278
278
  const info = { collection: 'music', pkValue: tags.fullTitle, fileInfo };
279
279
  const masterRequestTimeout = await this.getRequestMasterTimeout();
280
-
281
- if(typeof file == 'string') {
282
- file = fs.createReadStream(file);
280
+
281
+ if (typeof file == 'string') {
282
+ file = fse.createReadStream(file);
283
283
  }
284
284
 
285
285
  const results = await this.requestNetwork('get-document-addition-info', {
286
286
  body: { info },
287
- timeout: timer(
288
- [masterRequestTimeout, this.options.request.fileStoringNodeTimeout],
289
- { min: masterRequestTimeout, grabFree: true }
290
- ),
291
- responseSchema: schema.getDocumentAdditionInfoMasterResponse({
287
+ timeout: timer([masterRequestTimeout, this.options.request.fileStoringNodeTimeout], { min: masterRequestTimeout, grabFree: true }),
288
+ responseSchema: schema.getDocumentAdditionInfoMasterResponse({
292
289
  networkOptimum: await this.getNetworkOptimum(),
293
290
  schema: collection.schema
294
291
  })
295
292
  });
296
-
297
293
  const limit = await this.getDocumentDuplicatesCount(info);
298
294
  const filterOptions = Object.assign(await this.getDocumentAdditionInfoFilterOptions(info), { limit });
299
295
  const candidates = await this.filterCandidatesMatrix(results.map(r => r.candidates), filterOptions);
300
-
301
- if(!candidates.length) {
296
+
297
+ if (!candidates.length) {
302
298
  throw new errors.WorkError('Not found a suitable server to store the song', 'ERR_MUSERIA_NOT_FOUND_STORAGE');
303
299
  }
304
300
 
305
301
  const suspicious = candidates.filter(c => !c.existenceInfo)[0];
306
302
  suspicious && await this.db.addBehaviorCandidate('addSong', suspicious.address);
307
- const servers = candidates.map(c => c.address);
303
+ const servers = candidates.map(c => c.address);
308
304
  const dupOptions = Object.assign({}, options, { timeout: timer() });
309
- const dupInfo = Object.assign({ title: tags.fullTitle }, fileInfo);
305
+ const dupInfo = Object.assign({ title: tags.fullTitle }, fileInfo);
310
306
  const result = await this.duplicateSong(servers, file, dupInfo, dupOptions);
311
307
 
312
- if(!result) {
308
+ if (!result) {
313
309
  throw new errors.WorkError('Not found an available server to store the file', 'ERR_MUSERIA_NOT_FOUND_STORAGE');
314
310
  }
315
311
 
316
312
  destroyFileStream();
317
- return _.omit(result, ['address']);
313
+ return omit(result, ['address']);
318
314
  }
319
- catch(err) {
315
+ catch (err) {
320
316
  destroyFileStream();
321
317
  throw err;
322
318
  }
@@ -324,36 +320,36 @@ module.exports = (Parent) => {
324
320
 
325
321
  /**
326
322
  * Prepare the song file before the addition
327
- *
323
+ *
328
324
  * @async
329
- * @param {string|Buffer|fs.ReadStream} file
330
- * @returns {string|Buffer|fs.ReadStream}
325
+ * @param {string|Buffer|fse.ReadStream} file
326
+ * @returns {string|Buffer|fse.ReadStream}
331
327
  */
332
328
  async prepareSongFileBeforeAddition(file) {
333
329
  const tags = await utils.getSongTags(file);
334
330
  let changed = false;
335
-
336
- if(this.options.music.prepareTitle) {
331
+
332
+ if (this.options.music.prepareTitle) {
337
333
  this.songTitleTest(tags.fullTitle);
338
- tags.fullTitle = await this.prepareSongTitle(tags.fullTitle);
334
+ tags.fullTitle = await this.prepareSongTitle(tags.fullTitle);
339
335
  changed = true;
340
336
  }
341
337
 
342
- if(tags.APIC && this.options.music.prepareCover) {
338
+ if (tags.APIC && this.options.music.prepareCover) {
343
339
  tags.APIC = await this.prepareSongCover(tags.APIC);
344
340
  changed = true;
345
341
  }
346
342
 
347
- if(!changed) {
343
+ if (!changed) {
348
344
  return file;
349
345
  }
350
-
346
+
351
347
  return await utils.setSongTags(file, tags);
352
348
  }
353
349
 
354
350
  /**
355
351
  * Prepare the song cover
356
- *
352
+ *
357
353
  * @async
358
354
  * @param {Buffer} buffer
359
355
  * @returns {Buffer}
@@ -367,51 +363,51 @@ module.exports = (Parent) => {
367
363
  let width = metadata.width;
368
364
  let height = metadata.height;
369
365
 
370
- if(minSize && (width < minSize || height < minSize )) {
366
+ if (minSize && (width < minSize || height < minSize)) {
371
367
  throw new errors.WorkError(`Minimum size of a cover width or height is ${minSize}px`, 'ERR_MUSERIA_COVER_MIN_SIZE');
372
- }
368
+ }
373
369
 
374
- let dev;
370
+ let dev;
375
371
  let maxDev;
376
-
377
- if(width > maxSize) {
372
+
373
+ if (width > maxSize) {
378
374
  maxDev = height / maxSize;
379
375
  dev = width / maxSize;
380
376
  }
381
377
  else {
382
378
  maxDev = width / maxSize;
383
- dev = height / maxSize;
379
+ dev = height / maxSize;
384
380
  }
385
381
 
386
382
  dev > maxDev && (dev = maxDev);
387
383
  width = Math.floor(width / dev);
388
- height = Math.floor(height / dev);
389
- const size = width > height? height: width;
384
+ height = Math.floor(height / dev);
385
+ const size = width > height ? height : width;
390
386
  let buff = await image
391
387
  .jpeg({ quality: this.options.music.coverQuality })
392
388
  .resize(width, height)
393
- .extract({
389
+ .extract({
394
390
  left: Math.floor((width - size) / 2),
395
391
  top: Math.floor((height - size) / 2),
396
392
  width: size,
397
393
  height: size
398
394
  })
399
395
  .toBuffer();
400
-
401
- if(buff.byteLength > metadata.size) {
396
+
397
+ if (buff.byteLength > metadata.size) {
402
398
  buff = buffer;
403
- }
404
-
405
- if(buff.byteLength > maxFileSize) {
399
+ }
400
+
401
+ if (buff.byteLength > maxFileSize) {
406
402
  throw new errors.WorkError(`Maximum size of a cover file is ${maxFileSize} byte(s)`, 'ERR_MUSERIA_COVER_MAX_FILE_SIZE');
407
- }
403
+ }
408
404
 
409
405
  return buff;
410
406
  }
411
407
 
412
408
  /**
413
409
  * Prepare the song title
414
- *
410
+ *
415
411
  * @async
416
412
  * @param {string} title
417
413
  * @returns {string}
@@ -419,23 +415,23 @@ module.exports = (Parent) => {
419
415
  async prepareSongTitle(title) {
420
416
  return utils.beautifySongTitle(title);
421
417
  }
422
-
418
+
423
419
  /**
424
- * Get the song info
425
- *
420
+ * Get the song info
421
+ *
426
422
  * @async
427
423
  * @param {string} title
428
424
  * @param {object} [options]
429
425
  * @returns {object[]}
430
426
  */
431
- async getSongInfo(title, options = {}) {
427
+ async getSongInfo(title, options = {}) {
432
428
  title = utils.prepareComparisonSongTitle(title);
433
429
  const collection = await this.getCollection('music');
434
- const actions = utils.prepareDocumentGettingActions({
430
+ const actions = utils.prepareDocumentGettingActions({
435
431
  offset: 0,
436
432
  limit: 0,
437
433
  removeDuplicates: false,
438
- filter: {
434
+ filter: {
439
435
  compTitle: {
440
436
  $mus: {
441
437
  value: title,
@@ -445,13 +441,13 @@ module.exports = (Parent) => {
445
441
  }
446
442
  },
447
443
  sort: this.getFindingSongsSort()
448
- });
444
+ });
449
445
  await collection.actionsGettingTest(actions);
450
446
  const results = await this.requestNetwork('get-documents', {
451
447
  body: { actions, collection: 'music' },
452
448
  timeout: options.timeout,
453
449
  responseSchema: schema.getDocumentsMasterResponse({ schema: collection.schema })
454
- });
450
+ });
455
451
  results.forEach((result) => {
456
452
  result.documents.forEach(doc => {
457
453
  doc.main = 1;
@@ -459,51 +455,51 @@ module.exports = (Parent) => {
459
455
  doc.intScore = parseInt(doc.score * 100);
460
456
  doc.random = Math.random();
461
457
  });
462
- })
458
+ });
463
459
  const result = await this.handleDocumentsGettingForClient(collection, results, actions);
464
- const documents = result.documents.map(doc => _.omit(doc, ['main', 'address', 'random', 'intScore', 'compTitle']));
460
+ const documents = result.documents.map(doc => omit(doc, ['main', 'address', 'random', 'intScore', 'compTitle']));
465
461
  return documents;
466
462
  }
467
463
 
468
464
  /**
469
465
  * Find songs
470
- *
466
+ *
471
467
  * @async
472
468
  * @param {string} str
473
469
  * @param {object} [options]
474
470
  * @returns {object[]}
475
471
  */
476
- async findSongs(str, options = {}) {
472
+ async findSongs(str, options = {}) {
477
473
  const title = utils.prepareComparisonSongTitle(str);
478
474
  str = utils.prepareSongFindingString(str);
479
-
480
- if(str.length < this.options.music.findingStringMinLength) {
481
- const msg = `You have to pass at least "${ this.options.music.findingStringMinLength }" symbol(s)`;
475
+
476
+ if (str.length < this.options.music.findingStringMinLength) {
477
+ const msg = `You have to pass at least "${this.options.music.findingStringMinLength}" symbol(s)`;
482
478
  throw new errors.WorkError(msg, 'ERR_MUSERIA_FINDING_SONGS_STRING_LENGTH');
483
479
  }
484
-
485
- if(!str) {
480
+
481
+ if (!str) {
486
482
  return [];
487
483
  }
488
-
484
+
489
485
  const collection = await this.getCollection('music');
490
- let limit = options.limit === undefined? this.options.music.findingLimit: options.limit;
486
+ let limit = options.limit === undefined ? this.options.music.findingLimit : options.limit;
491
487
  limit > this.options.music.findingLimit && (limit = this.options.music.findingLimit);
492
- limit < 0 && (limit = 0);
493
- const actions = utils.prepareDocumentGettingActions({
488
+ limit < 0 && (limit = 0);
489
+ const actions = utils.prepareDocumentGettingActions({
494
490
  offset: 0,
495
491
  limit,
496
492
  removeDuplicates: true,
497
- filter: {
493
+ filter: {
498
494
  compTitle: {
499
495
  $or: [
500
496
  { $milk: str },
501
- {
497
+ {
502
498
  $mus: {
503
499
  value: title,
504
500
  similarity: this.options.music.similarity,
505
501
  beautify: false
506
- }
502
+ }
507
503
  }
508
504
  ]
509
505
  }
@@ -514,83 +510,82 @@ module.exports = (Parent) => {
514
510
  body: { actions, collection: 'music' },
515
511
  timeout: options.timeout,
516
512
  responseSchema: schema.getDocumentsMasterResponse({ schema: collection.schema })
517
- });
518
-
513
+ });
519
514
  const titles = {};
520
- let documents = results.reduce((p, c) => p.concat(c.documents), []);
515
+ let documents = results.reduce((p, c) => p.concat(c.documents), []);
521
516
  documents = this.uniqDocuments(collection, documents);
522
517
  documents.forEach((doc) => {
523
518
  doc.main = 0;
524
519
  doc.score = utils.getStringSimilarity(str, doc.compTitle, { ignoreOrder: true });
525
520
  doc.intScore = parseInt(doc.score * 100);
526
521
  doc.random = Math.random();
527
- titles[doc.title]? titles[doc.title].push(doc): titles[doc.title] = [doc];
522
+ titles[doc.title] ? titles[doc.title].push(doc) : titles[doc.title] = [doc];
528
523
  });
529
-
530
- for(let key in titles) {
524
+
525
+ for (let key in titles) {
531
526
  const docs = titles[key];
532
- docs[_.random(0, docs.length - 1)].main = 1;
527
+ docs[random(0, docs.length - 1)].main = 1;
533
528
  }
534
529
 
535
530
  actions.removeDuplicates = false;
536
531
  const result = await this.handleDocumentsGettingForClient(collection, [{ documents }], actions);
537
- documents = result.documents.map(doc => _.omit(doc, ['main', 'address', 'random', 'intScore', 'compTitle']));
532
+ documents = result.documents.map(doc => omit(doc, ['main', 'address', 'random', 'intScore', 'compTitle']));
538
533
  return documents;
539
534
  }
540
535
 
541
536
  /**
542
537
  * Find the artist songs
543
- *
538
+ *
544
539
  * @async
545
540
  * @param {string} artist
546
541
  * @param {object} [options]
547
542
  * @returns {object[]}
548
543
  */
549
- async findArtistSongs(artist, options = {}) {
550
- if(!artist || typeof artist != 'string') {
551
- return [];
552
- }
553
-
554
- artist = utils.prepareSongFindingString(artist);
555
- const collection = await this.getCollection('music');
556
- const actions = utils.prepareDocumentGettingActions({
557
- offset: 0,
558
- limit: 0,
559
- removeDuplicates: true,
560
- filter: {
561
- compTitle: {
562
- $art: artist
563
- }
564
- },
565
- sort: this.getFindingSongsSort()
566
- });
567
- const results = await this.requestNetwork('get-documents', {
568
- body: { actions, collection: 'music' },
569
- timeout: options.timeout,
570
- responseSchema: schema.getDocumentsMasterResponse({ schema: collection.schema })
571
- });
572
- const titles = {};
573
- let documents = results.reduce((p, c) => p.concat(c.documents), []);
574
- documents = this.uniqDocuments(collection, documents);
575
- documents.forEach((doc) => {
576
- doc.main = 0;
577
- titles[doc.title]? titles[doc.title].push(doc): titles[doc.title] = [doc];
578
- });
579
-
580
- for(let key in titles) {
581
- const docs = titles[key];
582
- docs[_.random(0, docs.length - 1)].main = 1;
583
- }
544
+ async findArtistSongs(artist, options = {}) {
545
+ if (!artist || typeof artist != 'string') {
546
+ return [];
547
+ }
548
+
549
+ artist = utils.prepareSongFindingString(artist);
550
+ const collection = await this.getCollection('music');
551
+ const actions = utils.prepareDocumentGettingActions({
552
+ offset: 0,
553
+ limit: 0,
554
+ removeDuplicates: true,
555
+ filter: {
556
+ compTitle: {
557
+ $art: artist
558
+ }
559
+ },
560
+ sort: this.getFindingSongsSort()
561
+ });
562
+ const results = await this.requestNetwork('get-documents', {
563
+ body: { actions, collection: 'music' },
564
+ timeout: options.timeout,
565
+ responseSchema: schema.getDocumentsMasterResponse({ schema: collection.schema })
566
+ });
567
+ const titles = {};
568
+ let documents = results.reduce((p, c) => p.concat(c.documents), []);
569
+ documents = this.uniqDocuments(collection, documents);
570
+ documents.forEach((doc) => {
571
+ doc.main = 0;
572
+ titles[doc.title] ? titles[doc.title].push(doc) : titles[doc.title] = [doc];
573
+ });
584
574
 
585
- actions.removeDuplicates = false;
586
- const result = await this.handleDocumentsGettingForClient(collection, [{ documents }], actions);
587
- documents = result.documents.map(doc => _.omit(doc, ['main', 'address']));
588
- return documents;
575
+ for (let key in titles) {
576
+ const docs = titles[key];
577
+ docs[random(0, docs.length - 1)].main = 1;
589
578
  }
590
579
 
580
+ actions.removeDuplicates = false;
581
+ const result = await this.handleDocumentsGettingForClient(collection, [{ documents }], actions);
582
+ documents = result.documents.map(doc => omit(doc, ['main', 'address']));
583
+ return documents;
584
+ }
585
+
591
586
  /**
592
587
  * Get the song link
593
- *
588
+ *
594
589
  * @async
595
590
  * @param {string} title
596
591
  * @param {string} type
@@ -598,53 +593,52 @@ module.exports = (Parent) => {
598
593
  * @returns {string}
599
594
  */
600
595
  async getSongLink(title, type, options = {}) {
601
- if(type != 'audio' && type != 'cover') {
596
+ if (type != 'audio' && type != 'cover') {
602
597
  throw new errors.WorkError(`Link type must be "audio" or "cover", not "${type}"`, 'ERR_MUSERIA_SONG_LINK_TYPE');
603
598
  }
604
599
 
605
600
  this.songTitleTest(title);
606
- options = _.merge({
601
+ options = merge({
607
602
  cache: true
608
603
  }, options);
609
- title = utils.beautifySongTitle(title);
610
-
611
- LOOKING_FOR_CACHE: if(this.cacheFile && options.cache) {
604
+ title = utils.beautifySongTitle(title);
605
+
606
+ LOOKING_FOR_CACHE: if (this.cacheFile && options.cache) {
612
607
  const cache = await this.cacheFile.get(title);
613
-
614
- if(!cache) {
608
+ if (!cache) {
615
609
  break LOOKING_FOR_CACHE;
616
610
  }
617
611
 
618
612
  const link = cache.value[`${type}Link`];
619
-
620
- if(await this.checkCacheLink(link)) {
613
+
614
+ if (await this.checkCacheLink(link)) {
621
615
  return link;
622
616
  }
623
617
 
624
- const obj = _.merge({}, cache.value, { [`${type}Link`]: '' });
618
+ const obj = merge({}, cache.value, { [`${type}Link`]: '' });
625
619
 
626
- if(!obj.audioLink && !obj.coverLink) {
620
+ if (!obj.audioLink && !obj.coverLink) {
627
621
  await this.cacheFile.remove(title);
628
622
  break LOOKING_FOR_CACHE;
629
623
  }
630
624
 
631
625
  await this.cacheFile.set(title, obj);
632
- }
626
+ }
633
627
 
634
- const info = (await this.getSongInfo(title, options)).filter(c => c[`${type}Link`]);
628
+ const info = (await this.getSongInfo(title, options)).filter(c => c[`${type}Link`]);
635
629
  const selected = info[0];
636
-
637
- if(options.cache && selected) {
630
+
631
+ if (options.cache && selected) {
638
632
  await this.updateSongCache(title, selected);
639
633
  selected.title != title && await this.updateSongCache(selected.title, selected);
640
634
  }
641
-
642
- return selected? selected[`${type}Link`]: '';
635
+
636
+ return selected ? selected[`${type}Link`] : '';
643
637
  }
644
638
 
645
639
  /**
646
640
  * Get the song audio link
647
- *
641
+ *
648
642
  * @see NodeMuseria.prototype.getSongAudioLink
649
643
  */
650
644
  async getSongAudioLink(title, options = {}) {
@@ -653,7 +647,7 @@ module.exports = (Parent) => {
653
647
 
654
648
  /**
655
649
  * Get the song cover link
656
- *
650
+ *
657
651
  * @see NodeMuseria.prototype.getSongCoverLink
658
652
  */
659
653
  async getSongCoverLink(title, options = {}) {
@@ -662,22 +656,22 @@ module.exports = (Parent) => {
662
656
 
663
657
  /**
664
658
  * Get the song info filter options
665
- *
659
+ *
666
660
  * @async
667
661
  * @returns {object}
668
662
  */
669
663
  async getSongInfoFilterOptions() {
670
664
  return {
671
665
  fnFilter: c => (
672
- utils.isValidSongAudioLink(c.audioLink) &&
666
+ utils.isValidSongAudioLink(c.audioLink) &&
673
667
  (!c.coverLink || utils.isValidSongCoverLink(c.coverLink))
674
668
  )
675
- }
669
+ };
676
670
  }
677
671
 
678
672
  /**
679
673
  * Remove the song
680
- *
674
+ *
681
675
  * @async
682
676
  * @param {string} title
683
677
  * @param {object} [options]
@@ -695,28 +689,28 @@ module.exports = (Parent) => {
695
689
 
696
690
  /**
697
691
  * Update the song cache
698
- *
692
+ *
699
693
  * @async
700
694
  * @param {string} title
701
695
  * @param {object} value
702
696
  * @param {string} value.audioLink
703
697
  * @param {string} [value.coverLink]
704
698
  */
705
- async updateSongCache(title, value) {
706
- if(!this.cacheFile) {
699
+ async updateSongCache(title, value) {
700
+ if (!this.cacheFile) {
707
701
  return;
708
702
  }
709
-
710
- const cache = await this.cacheFile.get(title);
711
- let obj = { audioLink: value.audioLink, coverLink: value.coverLink };
703
+
704
+ const cache = await this.cacheFile.get(title);
705
+ let obj = { audioLink: value.audioLink, coverLink: value.coverLink };
712
706
  !utils.isValidSongAudioLink(obj.audioLink) && delete obj.audioLink;
713
707
  !utils.isValidSongCoverLink(obj.coverLink) && delete obj.coverLink;
714
- obj = _.merge(cache? cache.value: {}, obj);
708
+ obj = merge(cache ? cache.value : {}, obj);
715
709
 
716
- if(!Object.keys(obj).length) {
710
+ if (!Object.keys(obj).length) {
717
711
  return;
718
712
  }
719
-
713
+
720
714
  await this.cacheFile.set(title, obj);
721
715
  }
722
716
 
@@ -725,30 +719,29 @@ module.exports = (Parent) => {
725
719
  */
726
720
  async duplicateSong(servers, file, info, options = {}) {
727
721
  const query = qs.stringify({ title: info.title });
728
- options = _.assign({}, {
722
+ options = assign({}, {
729
723
  cache: true,
730
- action: `add-song?${ query }`,
731
- formData: {
732
- exported: options.exported? '1': '',
733
- controlled: options.controlled? '1': '',
734
- priority: String(options.priority || 0),
735
- approvalInfo: options.approvalInfo? JSON.stringify(options.approvalInfo): ''
724
+ action: `add-song?${query}`,
725
+ formData: {
726
+ exported: options.exported ? '1' : '',
727
+ controlled: options.controlled ? '1' : '',
728
+ priority: String(options.priority || 0),
729
+ approvalInfo: options.approvalInfo ? JSON.stringify(options.approvalInfo) : ''
736
730
  },
737
731
  responseSchema: schema.getSongAdditionResponse()
738
732
  }, options);
739
-
740
- const result = await super.duplicateFile(servers, file, info, _.omit(options, ['priority']));
733
+ const result = await super.duplicateFile(servers, file, info, omit(options, ['priority']));
741
734
  result && options.cache && await this.updateSongCache(result.title, result);
742
735
  return result;
743
736
  }
744
737
 
745
738
  /**
746
739
  * Export all songs to another server
747
- *
740
+ *
748
741
  * @see NodeStoracle.prototype.exportFiles
749
742
  */
750
- async exportSongs(address, options = {}) {
751
- options = _.merge({
743
+ async exportSongs(address, options = {}) {
744
+ options = merge({
752
745
  strict: false
753
746
  }, options);
754
747
  let success = 0;
@@ -760,56 +753,55 @@ module.exports = (Parent) => {
760
753
  });
761
754
  const docs = await this.db.getDocuments('music');
762
755
  const hashes = {};
763
-
764
- for(let i = 0; i < docs.length; i++) {
756
+
757
+ for (let i = 0; i < docs.length; i++) {
765
758
  const doc = docs[i];
766
-
767
- if(!doc.fileHash || typeof doc.fileHash != 'string') {
759
+
760
+ if (!doc.fileHash || typeof doc.fileHash != 'string') {
768
761
  continue;
769
762
  }
770
-
771
763
  hashes[doc.fileHash] = doc;
772
764
  }
773
-
765
+
774
766
  await this.iterateFiles(async (filePath) => {
775
767
  const fileInfo = await utils.getFileInfo(filePath);
776
768
  const doc = hashes[fileInfo.hash];
777
769
 
778
- if(!doc) {
770
+ if (!doc) {
779
771
  return;
780
772
  }
781
773
 
782
774
  const info = Object.assign({ title: doc.title }, fileInfo);
783
775
  let file;
784
-
776
+
785
777
  try {
786
- file = fs.createReadStream(filePath);
787
- await this.duplicateSong([address], file, info, {
778
+ file = fse.createReadStream(filePath);
779
+ await this.duplicateSong([address], file, info, {
788
780
  exported: true,
789
781
  priority: doc.priority,
790
- timeout: timer()
782
+ timeout: timer()
791
783
  });
792
784
  success++;
793
785
  file.destroy();
794
786
  this.logger.info(`Song "${doc.title}" has been exported`);
795
787
  }
796
- catch(err) {
797
- file.destroy();
798
-
799
- if(options.strict) {
788
+ catch (err) {
789
+ file.destroy();
790
+
791
+ if (options.strict) {
800
792
  throw err;
801
793
  }
802
-
794
+
803
795
  fail++;
804
796
  this.logger.warn(err.stack);
805
797
  this.logger.info(`Song "${doc.title}" has been failed`);
806
798
  }
807
799
  });
808
800
 
809
- if(!success && !fail) {
801
+ if (!success && !fail) {
810
802
  this.logger.info(`There haven't been songs to export`);
811
803
  }
812
- else if(!fail) {
804
+ else if (!fail) {
813
805
  this.logger.info(`${success} song(s) have been exported`);
814
806
  }
815
807
  else {
@@ -821,7 +813,7 @@ module.exports = (Parent) => {
821
813
  * @see NodeMetastocle.prototype.getDocumentAdditionInfoFilterOptions
822
814
  */
823
815
  async getDocumentAdditionInfoFilterOptions() {
824
- return _.merge(await super.getDocumentAdditionInfoFilterOptions.apply(this, arguments), {
816
+ return merge(await super.getDocumentAdditionInfoFilterOptions.apply(this, arguments), {
825
817
  uniq: 'address',
826
818
  fnCompare: await this.createSongAdditionComparisonFunction(),
827
819
  fnFilter: c => c.isAvailable
@@ -832,10 +824,9 @@ module.exports = (Parent) => {
832
824
  * @see NodeMetastocle.prototype.getDocumentExistenceInfo
833
825
  */
834
826
  async getDocumentExistenceInfo(info) {
835
- if(info.collection == 'music') {
827
+ if (info.collection == 'music') {
836
828
  return await this.db.getMusicByPk(info.pkValue);
837
- }
838
-
829
+ }
839
830
  return await super.getDocumentExistenceInfo.apply(this, arguments);
840
831
  }
841
832
 
@@ -843,51 +834,50 @@ module.exports = (Parent) => {
843
834
  * @see NodeMetastocle.prototype.documentAvailabilityTest
844
835
  */
845
836
  async documentAvailabilityTest(info = {}) {
846
- if(info.collection == 'music') {
837
+ if (info.collection == 'music') {
847
838
  await this.fileAvailabilityTest(info.fileInfo);
848
839
  const existent = await this.db.getMusicByPk(info.pkValue);
849
-
850
- if(existent) {
840
+
841
+ if (existent) {
851
842
  return;
852
843
  }
853
844
  }
854
-
845
+
855
846
  return await super.documentAvailabilityTest.apply(this, arguments);
856
847
  }
857
848
 
858
849
  /**
859
850
  * Create a document addition comparison function
860
- *
851
+ *
861
852
  * @async
862
853
  * @returns {function}
863
854
  */
864
855
  async createSongAdditionComparisonFunction() {
865
856
  const obj = await this.prepareCandidateSuscpicionInfo('addSong');
866
857
  const fn = await this.createDocumentAdditionComparisonFunction();
867
-
868
858
  return (a, b) => {
869
- if(a.existenceInfo && !b.existenceInfo) {
859
+ if (a.existenceInfo && !b.existenceInfo) {
870
860
  return -1;
871
861
  }
872
862
 
873
- if(!a.existenceInfo && b.existenceInfo) {
863
+ if (!a.existenceInfo && b.existenceInfo) {
874
864
  return 1;
875
865
  }
876
866
 
877
867
  const suspicionLevelA = obj[a.address] || 0;
878
868
  const suspicionLevelB = obj[b.address] || 0;
879
869
 
880
- if(suspicionLevelA != suspicionLevelB) {
870
+ if (suspicionLevelA != suspicionLevelB) {
881
871
  return suspicionLevelA - suspicionLevelB;
882
872
  }
883
873
 
884
874
  return fn(a, b);
885
- }
875
+ };
886
876
  }
887
877
 
888
878
  /**
889
879
  * Create the song audio link
890
- *
880
+ *
891
881
  * @async
892
882
  * @param {object} document
893
883
  * @param {object} document.fileHash
@@ -901,7 +891,7 @@ module.exports = (Parent) => {
901
891
 
902
892
  /**
903
893
  * Create the song cover link
904
- *
894
+ *
905
895
  * @async
906
896
  * @param {object} document
907
897
  * @param {object} document.fileHash
@@ -913,27 +903,27 @@ module.exports = (Parent) => {
913
903
  const hash = document.fileHash;
914
904
  const filePath = this.getFilePath(hash);
915
905
  tags = tags || await utils.getSongTags(filePath);
916
-
917
- if(!tags.APIC) {
906
+
907
+ if (!tags.APIC) {
918
908
  return '';
919
909
  }
920
910
 
921
911
  const buff = await this.getSongCoverHeadersBuffer(tags.APIC);
922
912
  const info = await utils.getFileInfo(buff, { hash: false });
923
913
  const code = utils.encodeSongTitle(document.title);
924
- return `${this.getRequestProtocol()}://${this.address}/cover/${code}${info.ext? '.' + info.ext: ''}?f=${hash}`;
914
+ return `${this.getRequestProtocol()}://${this.address}/cover/${code}${info.ext ? '.' + info.ext : ''}?f=${hash}`;
925
915
  }
926
916
 
927
917
  /**
928
918
  * @see NodeStoracle.prototype.removeFileFromStorage
929
- *
919
+ *
930
920
  * @param [options]
931
921
  */
932
922
  async removeFileFromStorage(hash, options = {}) {
933
923
  await super.removeFileFromStorage.apply(this, arguments);
934
924
  !options.ignoreDocument && await this.db.removeMusicByFileHash(hash);
935
- }
936
-
925
+ }
926
+
937
927
  /**
938
928
  * @see NodeStoracle.prototype.emptyStorage
939
929
  */
@@ -944,7 +934,7 @@ module.exports = (Parent) => {
944
934
 
945
935
  /**
946
936
  * Check the song relevance
947
- *
937
+ *
948
938
  * @async
949
939
  * @param {string} filePathSource
950
940
  * @param {string} filePathTarget
@@ -953,32 +943,32 @@ module.exports = (Parent) => {
953
943
  async checkSongRelevance(filePathSource, filePathTarget) {
954
944
  const hashSource = path.basename(filePathSource);
955
945
  const hashTarget = path.basename(filePathTarget);
956
-
957
- if(!this.hasFile(hashSource)) {
946
+
947
+ if (!this.hasFile(hashSource)) {
958
948
  return false;
959
949
  }
960
950
 
961
- if(!await fse.pathExists(filePathTarget)) {
951
+ if (!await fse.pathExists(filePathTarget)) {
962
952
  return true;
963
953
  }
964
954
 
965
- if(hashSource == hashTarget) {
955
+ if (hashSource == hashTarget) {
966
956
  return true;
967
957
  }
968
958
 
969
959
  let time = this.options.music.relevanceTime;
970
-
971
- if(time <= 0) {
960
+
961
+ if (time <= 0) {
972
962
  return false;
973
963
  }
974
964
 
975
965
  let mdSource;
976
966
  let mdTarget;
977
-
967
+
978
968
  try {
979
969
  mdSource = await utils.getSongMetadata(filePathSource);
980
970
  }
981
- catch(err) {
971
+ catch (err) {
982
972
  this.logger.warn(err.stack);
983
973
  return false;
984
974
  }
@@ -986,13 +976,13 @@ module.exports = (Parent) => {
986
976
  try {
987
977
  mdTarget = await utils.getSongMetadata(filePathTarget);
988
978
  }
989
- catch(err) {
979
+ catch (err) {
990
980
  this.logger.warn(err.stack);
991
981
  return true;
992
982
  }
993
-
983
+
994
984
  const criterias = 2;
995
- const step = Math.round(time / criterias);
985
+ const step = Math.round(time / criterias);
996
986
  mdTarget.duration > mdSource.duration && (time -= step);
997
987
  mdTarget.sampleRate > mdSource.sampleRate && (time -= step / 2);
998
988
  mdTarget.bitrate > mdSource.bitrate && (time -= step / 2);
@@ -1011,17 +1001,17 @@ module.exports = (Parent) => {
1011
1001
  let res;
1012
1002
  let isError = false;
1013
1003
  this.__addingFiles[hash] = true;
1014
-
1004
+
1015
1005
  try {
1016
1006
  res = await fn();
1017
1007
  }
1018
- catch(err) {
1008
+ catch (err) {
1019
1009
  isError = true;
1020
1010
  }
1021
1011
 
1022
1012
  delete this.__addingFiles[hash];
1023
-
1024
- if(isError) {
1013
+
1014
+ if (isError) {
1025
1015
  throw res;
1026
1016
  }
1027
1017
 
@@ -1030,16 +1020,16 @@ module.exports = (Parent) => {
1030
1020
 
1031
1021
  /**
1032
1022
  * Get the song audio file headers buffer
1033
- *
1023
+ *
1034
1024
  * @see NodeMuseria.prototype.getSongHeadersBuffer
1035
1025
  */
1036
1026
  async getSongAudioHeadersBuffer(content) {
1037
1027
  return this.getSongHeadersBuffer(content, this.options.music.audioHeadersMaxSize);
1038
1028
  }
1039
-
1029
+
1040
1030
  /**
1041
1031
  * Get the song cover file headers buffer
1042
- *
1032
+ *
1043
1033
  * @see NodeMuseria.prototype.getSongHeadersBuffer
1044
1034
  */
1045
1035
  async getSongCoverHeadersBuffer(content) {
@@ -1048,17 +1038,17 @@ module.exports = (Parent) => {
1048
1038
 
1049
1039
  /**
1050
1040
  * Get the song file headers buffer
1051
- *
1041
+ *
1052
1042
  * @async
1053
- * @param {string|Buffer} content
1054
- * @param {number} limit
1043
+ * @param {string|Buffer} content
1044
+ * @param {number} limit
1055
1045
  * @returns {Buffer}
1056
1046
  */
1057
1047
  async getSongHeadersBuffer(content, limit) {
1058
- if(typeof content == 'string') {
1048
+ if (typeof content == 'string') {
1059
1049
  return new Promise((resolve, reject) => {
1060
1050
  const chunks = [];
1061
- fs.createReadStream(content, { start: 0, end: limit })
1051
+ fse.createReadStream(content, { start: 0, end: limit })
1062
1052
  .on('error', reject)
1063
1053
  .on('data', data => chunks.push(data))
1064
1054
  .on('end', () => resolve(Buffer.concat(chunks)));
@@ -1067,20 +1057,19 @@ module.exports = (Parent) => {
1067
1057
 
1068
1058
  return content.slice(0, limit);
1069
1059
  }
1070
-
1071
1060
  /**
1072
1061
  * Get finding songs sort
1073
- *
1062
+ *
1074
1063
  * @returns {array}
1075
1064
  */
1076
1065
  getFindingSongsSort() {
1077
- return [['main', 'desc'],['intScore', 'desc'], ['priority', 'desc'], ['random', 'asc']];
1066
+ return [['main', 'desc'], ['intScore', 'desc'], ['priority', 'desc'], ['random', 'asc']];
1078
1067
  }
1079
1068
 
1080
1069
  /**
1081
1070
  * Check the file is adding
1082
- *
1083
- * @param {string} hash
1071
+ *
1072
+ * @param {string} hash
1084
1073
  * @returns {boolean}
1085
1074
  */
1086
1075
  isFileAdding(hash) {
@@ -1089,42 +1078,42 @@ module.exports = (Parent) => {
1089
1078
 
1090
1079
  /**
1091
1080
  * Test the song title
1092
- *
1093
- * @param {string} title
1081
+ *
1082
+ * @param {string} title
1094
1083
  */
1095
1084
  songTitleTest(title) {
1096
- if(!utils.isSongTitle(title)) {
1085
+ if (!utils.isSongTitle(title)) {
1097
1086
  throw new errors.WorkError(`Wrong song title "${title}"`, 'ERR_MUSERIA_SONG_WRONG_TITLE');
1098
1087
  }
1099
1088
  }
1100
1089
 
1101
1090
  /**
1102
1091
  * Test the song title
1103
- *
1104
- * @param {object} info
1092
+ *
1093
+ * @param {object} info
1105
1094
  * @param {number} info.priority
1106
1095
  * @param {boolean} info.controlled
1107
1096
  * @param {boolean} [info.exported]
1108
1097
  */
1109
1098
  songPriorityTest({ priority, controlled, exported }) {
1110
- if(!utils.isValidSongPriority(priority)) {
1099
+ if (!utils.isValidSongPriority(priority)) {
1111
1100
  const msg = 'Song priority must be an integer from -1 to 1';
1112
1101
  throw new errors.WorkError(msg, 'ERR_MUSERIA_SONG_WRONG_PRIORITY');
1113
1102
  }
1114
1103
 
1115
- if(priority > 0 && !controlled && !exported) {
1104
+ if (priority > 0 && !controlled && !exported) {
1116
1105
  const msg = 'Priority 1 is possible only if "controlled" is true';
1117
1106
  throw new errors.WorkError(msg, 'ERR_MUSERIA_SONG_WRONG_PRIORITY_CONTROLLED');
1118
1107
  }
1119
1108
  }
1120
1109
 
1121
- /**
1110
+ /**
1122
1111
  * @see NodeStoracle.prototype.calculateTempFileMinSize
1123
1112
  */
1124
1113
  calculateTempFileMinSize(size) {
1125
1114
  return size * 2 + this.fileMaxSize;
1126
1115
  }
1127
-
1116
+
1128
1117
  /**
1129
1118
  * Prepare the options
1130
1119
  */
@@ -1133,7 +1122,7 @@ module.exports = (Parent) => {
1133
1122
  this.options.music.relevanceTime = utils.getMs(this.options.music.relevanceTime);
1134
1123
  this.options.music.audioHeadersMaxSize = utils.getBytes(this.options.music.audioHeadersMaxSize);
1135
1124
  this.options.music.coverHeadersMaxSize = utils.getBytes(this.options.music.coverHeadersMaxSize);
1136
- this.options.music.coverMaxFileSize = utils.getBytes(this.options.music.coverMaxFileSize);
1125
+ this.options.music.coverMaxFileSize = utils.getBytes(this.options.music.coverMaxFileSize);
1137
1126
  }
1138
- }
1139
- };
1127
+ };
1128
+ };