museria 0.2.49 → 0.3.2
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.
- package/.eslintrc +10 -2
- package/.github/workflows/build.yml +3 -3
- package/.github/workflows/publish.yml +3 -3
- package/README.md +55 -59
- package/bin/actions.js +28 -28
- package/bin/index.js +4 -4
- package/bin/runner.js +1 -1
- package/bin/utils.js +6 -2
- package/dist/client/museria.client.js +7 -7
- package/dist/face/45a265d0f07b31cde85f.ttf +0 -0
- package/dist/face/6205fd00fb1b573e9f0f.ttf +0 -0
- package/dist/face/8d3cabfc66809162fb4d.woff2 +0 -0
- package/dist/face/fb8184add5a3101ad0a3.woff2 +0 -0
- package/dist/face/museria.face.js +33 -13
- package/dist/face/style.css +13 -11
- package/package.json +41 -40
- package/src/browser/client/index.js +2 -1
- package/src/browser/face/client.js +2 -1
- package/src/browser/face/controllers/app/app.html +77 -69
- package/src/browser/face/controllers/app/app.js +14 -7
- package/src/browser/face/controllers/app/app.scss +2 -22
- package/src/browser/face/index.js +3 -3
- package/src/browser/face/styles/main.scss +91 -11
- package/src/browser/face/styles/vars.scss +0 -1
- package/src/client.js +73 -74
- package/src/collection/transports/music/index.js +20 -18
- package/src/db/transports/database/index.js +7 -5
- package/src/db/transports/loki/index.js +30 -25
- package/src/errors.js +2 -1
- package/src/index.js +8 -6
- package/src/node.js +312 -323
- package/src/schema.js +27 -29
- package/src/server/transports/express/api/butler/controllers.js +7 -10
- package/src/server/transports/express/api/butler/routes.js +5 -5
- package/src/server/transports/express/api/master/controllers.js +7 -10
- package/src/server/transports/express/api/master/routes.js +5 -5
- package/src/server/transports/express/api/node/controllers.js +52 -61
- package/src/server/transports/express/api/node/routes.js +10 -10
- package/src/server/transports/express/api/routes.js +1 -1
- package/src/server/transports/express/api/slave/controllers.js +7 -10
- package/src/server/transports/express/api/slave/routes.js +6 -6
- package/src/server/transports/express/client/controllers.js +40 -61
- package/src/server/transports/express/client/routes.js +33 -39
- package/src/server/transports/express/controllers.js +10 -21
- package/src/server/transports/express/index.js +23 -20
- package/src/server/transports/express/midds.js +67 -67
- package/src/server/transports/express/routes.js +12 -12
- package/src/utils.js +175 -184
- package/test/client.js +311 -305
- package/test/db/database.js +32 -28
- package/test/db/loki.js +78 -74
- package/test/group.js +161 -156
- package/test/index.js +20 -10
- package/test/node.js +461 -460
- package/test/routes.js +404 -399
- package/test/server/express.js +35 -31
- package/test/services.js +25 -18
- package/test/tools.js +8 -6
- package/test/utils.js +236 -234
- package/webpack.client.js +9 -7
- package/webpack.face.js +8 -6
- package/dist/face/fa-brands-400.eot +0 -0
- package/dist/face/fa-brands-400.svg +0 -3717
- package/dist/face/fa-brands-400.ttf +0 -0
- package/dist/face/fa-brands-400.woff +0 -0
- package/dist/face/fa-brands-400.woff2 +0 -0
- package/dist/face/fa-solid-900.eot +0 -0
- package/dist/face/fa-solid-900.svg +0 -5034
- package/dist/face/fa-solid-900.ttf +0 -0
- package/dist/face/fa-solid-900.woff +0 -0
- package/dist/face/fa-solid-900.woff2 +0 -0
- /package/dist/face/{open-sans.ttf → 17e98b9e5586529b13cc.ttf} +0 -0
- /package/dist/face/{proxima-nova.ttf → 326601dfabd91e3f016c.ttf} +0 -0
- /package/dist/face/{logo.svg → ee9c6af64aa224827cec.svg} +0 -0
package/test/node.js
CHANGED
@@ -1,471 +1,472 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
describe('
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
1
|
+
import { assert } from "chai";
|
2
|
+
import sharp from "sharp";
|
3
|
+
import path from "path";
|
4
|
+
import url from "url";
|
5
|
+
import node from "../src/node.js";
|
6
|
+
import utils from "../src/utils.js";
|
7
|
+
import tools from "./tools.js";
|
8
|
+
|
9
|
+
const Node = node();
|
10
|
+
|
11
|
+
export default function () {
|
12
|
+
describe('Node', () => {
|
13
|
+
let node;
|
14
|
+
|
15
|
+
describe('instance creation', () => {
|
16
|
+
it('should create an instance', async () => {
|
17
|
+
const options = await tools.createNodeOptions();
|
18
|
+
assert.doesNotThrow(() => node = new Node(options));
|
19
|
+
});
|
20
|
+
});
|
21
|
+
|
22
|
+
describe('.init()', () => {
|
23
|
+
it('should not throw an exception', async () => {
|
24
|
+
await node.init();
|
25
|
+
});
|
26
|
+
});
|
27
|
+
|
28
|
+
describe('.addSong()', () => {
|
29
|
+
it('should throw an error because of a wrong title', async () => {
|
30
|
+
try {
|
31
|
+
await node.addSong(path.join(tools.tmpPath, 'audio.mp3'));
|
32
|
+
throw new Error('Fail');
|
33
|
+
}
|
34
|
+
catch (err) {
|
35
|
+
assert.isOk(err.message.match('Wrong song title'));
|
36
|
+
}
|
37
|
+
});
|
38
|
+
|
39
|
+
it('should throw a confirmation error', async () => {
|
40
|
+
const file = path.join(tools.tmpPath, 'audio.mp3');
|
41
|
+
const title = 'artist - title';
|
42
|
+
await utils.setSongTags(file, { fullTitle: title });
|
43
|
+
|
44
|
+
try {
|
45
|
+
await node.addSong(file, { priority: 1, controlled: true });
|
46
|
+
throw new Error('Fail');
|
47
|
+
}
|
48
|
+
catch (err) {
|
49
|
+
assert.isOk(err.message.match('requires confirmation'));
|
50
|
+
}
|
51
|
+
});
|
52
|
+
|
53
|
+
it('should add the song', async () => {
|
54
|
+
const file = path.join(tools.tmpPath, 'audio.mp3');
|
55
|
+
const title = 'artist - title';
|
56
|
+
await utils.setSongTags(file, { fullTitle: title, TIT3: 'x' });
|
57
|
+
const result = await node.addSong(file);
|
58
|
+
const doc = await node.db.getMusicByPk(result.title);
|
59
|
+
assert.equal(utils.beautifySongTitle(title), result.title, 'check the title');
|
60
|
+
assert.equal(utils.prepareComparisonSongTitle(title), doc.compTitle, 'check the compTitle');
|
61
|
+
assert.equal(result.tags.TIT3, 'x', 'check the tags');
|
62
|
+
assert.isNotNull(doc, 'check the database');
|
63
|
+
assert.isTrue(await node.hasFile(doc.fileHash), 'check the file');
|
64
|
+
assert.isTrue(utils.isValidSongAudioLink(result.audioLink), 'check the audio link');
|
65
|
+
assert.isTrue(result.coverLink == '', 'check the cover link');
|
66
|
+
});
|
67
|
+
|
68
|
+
it('should not replace the current song with the similar one', async () => {
|
69
|
+
let file = path.join(tools.tmpPath, 'audio.mp3');
|
70
|
+
const title = 'artists - title';
|
71
|
+
file = await utils.setSongTags(file, { fullTitle: title, TIT3: 'y', TALB: 'z' });
|
72
|
+
const result = await node.addSong(file);
|
73
|
+
const docs = await node.db.getDocuments('music');
|
74
|
+
assert.lengthOf(docs, 1, 'check the docs');
|
75
|
+
assert.notEqual(utils.beautifySongTitle(title), result.title, 'check the title');
|
76
|
+
assert.isOk(result.tags.TIT3 == 'x' && result.tags.TALB == 'z', 'check the tags');
|
77
|
+
assert.isFalse(await node.hasFile(await utils.getFileHash(file)), 'check the file');
|
78
|
+
});
|
79
|
+
|
80
|
+
it('should replace the current song with the similar one', async () => {
|
81
|
+
const rel = node.options.music.relevanceTime;
|
82
|
+
node.options.music.relevanceTime = 1;
|
83
|
+
let file = path.join(tools.tmpPath, 'audio.mp3');
|
84
|
+
const title = 'artist - title';
|
85
|
+
file = await utils.setSongTags(file, { fullTitle: title, TIT3: 'y' });
|
86
|
+
const oldDoc = Object.assign({}, await node.db.getMusicByPk(title));
|
87
|
+
const result = await node.addSong(file);
|
88
|
+
const newDoc = await node.db.getMusicByPk(title);
|
89
|
+
const docs = await node.db.getDocuments('music');
|
90
|
+
const tags = utils.createSongTags(result.tags);
|
91
|
+
assert.lengthOf(docs, 1, 'check the docs');
|
92
|
+
assert.equal(utils.beautifySongTitle(title), tags.fullTitle, 'check the title');
|
93
|
+
assert.equal(result.tags.TIT3, 'y', 'check the tags');
|
94
|
+
assert.isTrue(await node.hasFile(newDoc.fileHash), 'check the new file');
|
95
|
+
assert.isFalse(await node.hasFile(oldDoc.fileHash), 'check the old file');
|
96
|
+
node.options.music.relevanceTime = rel;
|
97
|
+
});
|
98
|
+
|
99
|
+
it('should add the song with a cover', async () => {
|
100
|
+
const file = path.join(tools.tmpPath, 'audio.mp3');
|
101
|
+
const title = 'new - song';
|
102
|
+
await utils.setSongTags(file, { fullTitle: title, APIC: path.join(tools.tmpPath, 'cover.jpg') });
|
103
|
+
const result = await node.addSong(file);
|
104
|
+
const doc = await node.db.getMusicByPk(result.title);
|
105
|
+
const docs = await node.db.getDocuments('music');
|
106
|
+
assert.equal(utils.beautifySongTitle(title), result.title, 'check the title');
|
107
|
+
assert.isNotNull(doc, 'check the doc');
|
108
|
+
assert.lengthOf(docs, 2, 'check the database');
|
109
|
+
assert.isTrue(utils.isValidSongCoverLink(result.coverLink), 'check the audio link');
|
110
|
+
});
|
111
|
+
});
|
112
|
+
|
113
|
+
describe('.getSongInfo()', () => {
|
114
|
+
it('should return an empty array with a wrong title', async () => {
|
115
|
+
const title = 'unexistent';
|
116
|
+
const result = await node.getSongInfo(title);
|
117
|
+
assert.lengthOf(result, 0);
|
118
|
+
});
|
119
|
+
|
120
|
+
it('should return an empty array with a right title', async () => {
|
121
|
+
const title = 'unexistent - unexistent';
|
122
|
+
const result = await node.getSongInfo(title);
|
123
|
+
assert.lengthOf(result, 0);
|
124
|
+
});
|
125
|
+
|
126
|
+
it('should return the appropriate song', async () => {
|
127
|
+
const title = 'news - song';
|
128
|
+
const similarity = node.options.music.similarity;
|
129
|
+
const result = await node.getSongInfo(title);
|
130
|
+
const doc = await node.db.getMusicByPk(title);
|
131
|
+
const tags = utils.createSongTags(result[0].tags);
|
132
|
+
assert.lengthOf(result, 1, 'check the array');
|
133
|
+
assert.isTrue(utils.getSongSimilarity(doc.title, result[0].title) >= similarity, 'check the title');
|
134
|
+
assert.equal(tags.fullTitle, doc.title, 'check the tags');
|
135
|
+
assert.isTrue(utils.isValidSongAudioLink(result[0].audioLink), 'check the audio link');
|
136
|
+
assert.isTrue(utils.isValidSongCoverLink(result[0].coverLink), 'check the cover link');
|
137
|
+
});
|
138
|
+
});
|
139
|
+
|
140
|
+
describe('.getSongAudioLink()', () => {
|
141
|
+
it('should throw an error', async () => {
|
142
|
+
try {
|
143
|
+
await node.getSongAudioLink('unexistent song');
|
144
|
+
throw new Error('Fail');
|
145
|
+
}
|
146
|
+
catch (err) {
|
147
|
+
assert.isOk(err.message.match('Wrong song title'));
|
148
|
+
}
|
149
|
+
});
|
150
|
+
|
151
|
+
it('should return an empty string', async () => {
|
152
|
+
const result = await node.getSongAudioLink('unexistent - unexistent');
|
153
|
+
assert.equal(result, '');
|
154
|
+
});
|
155
|
+
|
156
|
+
it('should return the appropriate song link', async () => {
|
157
|
+
const result = await node.getSongAudioLink('new - song');
|
158
|
+
assert.isTrue(utils.isValidSongAudioLink(result));
|
159
|
+
});
|
160
|
+
});
|
161
|
+
|
162
|
+
describe('.getSongCoverLink()', () => {
|
163
|
+
it('should throw an error', async () => {
|
164
|
+
try {
|
165
|
+
await node.getSongCoverLink('unexistent song');
|
166
|
+
throw new Error('Fail');
|
167
|
+
}
|
168
|
+
catch (err) {
|
169
|
+
assert.isOk(err.message.match('Wrong song title'));
|
170
|
+
}
|
171
|
+
});
|
172
|
+
|
173
|
+
it('should return an empty string', async () => {
|
174
|
+
const result = await node.getSongCoverLink('unexistent - unexistent');
|
175
|
+
assert.equal(result, '');
|
176
|
+
});
|
177
|
+
|
178
|
+
it('should return the appropriate song link', async () => {
|
179
|
+
const result = await node.getSongCoverLink('new - song');
|
180
|
+
assert.isTrue(utils.isValidSongCoverLink(result));
|
181
|
+
});
|
182
|
+
});
|
183
|
+
|
184
|
+
describe('.removeSong()', () => {
|
185
|
+
it('should remove the song', async () => {
|
186
|
+
const title = 'artists - title';
|
187
|
+
const doc = await node.db.getMusicByPk(title);
|
188
|
+
const res = await node.removeSong(title);
|
189
|
+
assert.equal(res.removed, 1, 'check the result');
|
190
|
+
assert.isNull(await node.db.getMusicByPk(title), 'check the database');
|
191
|
+
assert.isFalse(await node.hasFile(doc.fileHash), 'check the file');
|
192
|
+
});
|
193
|
+
});
|
194
|
+
|
195
|
+
describe('.updateSongCache()', () => {
|
196
|
+
let title;
|
197
|
+
|
198
|
+
before(async () => {
|
199
|
+
title = 'new - song';
|
200
|
+
});
|
201
|
+
|
202
|
+
it('should not add the cache because of a wrong link', async () => {
|
203
|
+
const value = {
|
204
|
+
audioLink: 'wrong'
|
205
|
+
};
|
206
|
+
await node.updateSongCache(title, value);
|
207
|
+
assert.isNull(await node.cacheFile.get(title));
|
208
|
+
});
|
209
|
+
|
210
|
+
it('should add the cache partially', async () => {
|
211
|
+
const doc = await node.db.getMusicByPk(title);
|
212
|
+
const info = url.parse(await node.createSongAudioLink(doc));
|
213
|
+
const audioLink = url.format(Object.assign(info, { host: 'example.com:80' }));
|
214
|
+
const value = {
|
215
|
+
audioLink,
|
216
|
+
coverLink: 'wrong'
|
217
|
+
};
|
218
|
+
await node.updateSongCache(title, value);
|
219
|
+
const cache = (await node.cacheFile.get(title)).value;
|
220
|
+
assert.equal(audioLink, cache.audioLink, 'check the audio');
|
221
|
+
assert.isNotOk(cache.coverLink, 'check the cover');
|
222
|
+
});
|
223
|
+
|
224
|
+
it('should add the cache completely', async () => {
|
225
|
+
const doc = await node.db.getMusicByPk(title);
|
226
|
+
let info = url.parse(await node.createSongAudioLink(doc));
|
227
|
+
const audioLink = url.format(Object.assign(info, { host: 'example.com:80' }));
|
228
|
+
info = url.parse(await node.createSongCoverLink(doc));
|
229
|
+
const coverLink = url.format(Object.assign(info, { host: 'example.com:80' }));
|
230
|
+
const value = {
|
231
|
+
audioLink,
|
232
|
+
coverLink,
|
233
|
+
userless: true
|
234
|
+
};
|
235
|
+
await node.updateSongCache(title, value);
|
236
|
+
const cache = (await node.cacheFile.get(title)).value;
|
237
|
+
assert.equal(audioLink, cache.audioLink, 'check the audio');
|
238
|
+
assert.equal(coverLink, cache.coverLink, 'check the cover');
|
239
|
+
assert.isUndefined(cache.userless, 'check the wrong proprty');
|
240
|
+
});
|
241
|
+
});
|
242
|
+
|
243
|
+
describe('.createSongAudioLink()', () => {
|
244
|
+
it('should create a right audio link', async () => {
|
245
|
+
const doc = await node.db.getMusicByPk('new - song');
|
246
|
+
const code = utils.encodeSongTitle(doc.title);
|
247
|
+
const hash = doc.fileHash;
|
248
|
+
assert.equal(await node.createSongAudioLink(doc), `http://${node.address}/audio/${code}.mp3?f=${hash}`);
|
249
|
+
});
|
250
|
+
});
|
251
|
+
|
252
|
+
describe('.createSongCoverLink()', () => {
|
253
|
+
it('should create a right cover link', async () => {
|
254
|
+
const doc = await node.db.getMusicByPk('new - song');
|
255
|
+
const hash = doc.fileHash;
|
256
|
+
const code = utils.encodeSongTitle(doc.title);
|
257
|
+
assert.equal(await node.createSongCoverLink(doc), `http://${node.address}/cover/${code}.jpeg?f=${hash}`);
|
258
|
+
});
|
259
|
+
});
|
260
|
+
|
261
|
+
describe('.checkSongRelevance()', () => {
|
262
|
+
let title;
|
263
|
+
before(() => {
|
264
|
+
title = 'new - song';
|
265
|
+
});
|
266
|
+
it('should return true', async () => {
|
267
|
+
const doc = await node.db.getMusicByPk(title);
|
268
|
+
const filePath = node.getFilePath(doc.fileHash);
|
269
|
+
assert.isTrue(await node.checkSongRelevance(filePath, filePath));
|
270
|
+
});
|
271
|
+
});
|
272
|
+
|
273
|
+
describe('.removeFileFromStorage()', () => {
|
274
|
+
let title;
|
40
275
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
node.options.music.relevanceTime = rel;
|
94
|
-
});
|
95
|
-
|
96
|
-
it('should add the song with a cover', async () => {
|
97
|
-
const file = path.join(tools.tmpPath, 'audio.mp3');
|
98
|
-
const title = 'new - song';
|
99
|
-
await utils.setSongTags(file, { fullTitle: title, APIC: path.join(tools.tmpPath, 'cover.jpg') });
|
100
|
-
const result = await node.addSong(file);
|
101
|
-
const doc = await node.db.getMusicByPk(result.title);
|
102
|
-
const docs = await node.db.getDocuments('music');
|
103
|
-
assert.equal(utils.beautifySongTitle(title), result.title, 'check the title');
|
104
|
-
assert.isNotNull(doc, 'check the doc');
|
105
|
-
assert.lengthOf(docs, 2, 'check the database');
|
106
|
-
assert.isTrue(utils.isValidSongCoverLink(result.coverLink), 'check the audio link');
|
107
|
-
});
|
108
|
-
});
|
109
|
-
|
110
|
-
describe('.getSongInfo()', () => {
|
111
|
-
it('should return an empty array with a wrong title', async () => {
|
112
|
-
const title = 'unexistent';
|
113
|
-
const result = await node.getSongInfo(title);
|
114
|
-
assert.lengthOf(result, 0);
|
115
|
-
});
|
116
|
-
|
117
|
-
it('should return an empty array with a right title', async () => {
|
118
|
-
const title = 'unexistent - unexistent';
|
119
|
-
const result = await node.getSongInfo(title);
|
120
|
-
assert.lengthOf(result, 0);
|
121
|
-
});
|
122
|
-
|
123
|
-
it('should return the appropriate song', async () => {
|
124
|
-
const title = 'news - song';
|
125
|
-
const similarity = node.options.music.similarity;
|
126
|
-
const result = await node.getSongInfo(title);
|
127
|
-
const doc = await node.db.getMusicByPk(title);
|
128
|
-
const tags = utils.createSongTags(result[0].tags);
|
129
|
-
assert.lengthOf(result, 1, 'check the array');
|
130
|
-
assert.isTrue(utils.getSongSimilarity(doc.title, result[0].title) >= similarity, 'check the title');
|
131
|
-
assert.equal(tags.fullTitle, doc.title, 'check the tags');
|
132
|
-
assert.isTrue(utils.isValidSongAudioLink(result[0].audioLink), 'check the audio link');
|
133
|
-
assert.isTrue(utils.isValidSongCoverLink(result[0].coverLink), 'check the cover link');
|
134
|
-
});
|
135
|
-
});
|
136
|
-
|
137
|
-
describe('.getSongAudioLink()', () => {
|
138
|
-
it('should throw an error', async () => {
|
139
|
-
try {
|
140
|
-
await node.getSongAudioLink('unexistent song');
|
141
|
-
throw new Error('Fail');
|
142
|
-
}
|
143
|
-
catch (err) {
|
144
|
-
assert.isOk(err.message.match('Wrong song title'));
|
145
|
-
}
|
146
|
-
});
|
147
|
-
|
148
|
-
it('should return an empty string', async () => {
|
149
|
-
const result = await node.getSongAudioLink('unexistent - unexistent');
|
150
|
-
assert.equal(result, '');
|
151
|
-
});
|
152
|
-
|
153
|
-
it('should return the appropriate song link', async () => {
|
154
|
-
const result = await node.getSongAudioLink('new - song');
|
155
|
-
assert.isTrue(utils.isValidSongAudioLink(result));
|
156
|
-
});
|
157
|
-
});
|
158
|
-
|
159
|
-
describe('.getSongCoverLink()', () => {
|
160
|
-
it('should throw an error', async () => {
|
161
|
-
try {
|
162
|
-
await node.getSongCoverLink('unexistent song');
|
163
|
-
throw new Error('Fail');
|
164
|
-
}
|
165
|
-
catch (err) {
|
166
|
-
assert.isOk(err.message.match('Wrong song title'));
|
167
|
-
}
|
168
|
-
});
|
169
|
-
|
170
|
-
it('should return an empty string', async () => {
|
171
|
-
const result = await node.getSongCoverLink('unexistent - unexistent');
|
172
|
-
assert.equal(result, '');
|
173
|
-
});
|
174
|
-
|
175
|
-
it('should return the appropriate song link', async () => {
|
176
|
-
const result = await node.getSongCoverLink('new - song');
|
177
|
-
assert.isTrue(utils.isValidSongCoverLink(result));
|
178
|
-
});
|
179
|
-
});
|
180
|
-
|
181
|
-
describe('.removeSong()', () => {
|
182
|
-
it('should remove the song', async () => {
|
183
|
-
const title = 'artists - title';
|
184
|
-
const doc = await node.db.getMusicByPk(title)
|
185
|
-
const res = await node.removeSong(title);
|
186
|
-
assert.equal(res.removed, 1, 'check the result');
|
187
|
-
assert.isNull(await node.db.getMusicByPk(title), 'check the database');
|
188
|
-
assert.isFalse(await node.hasFile(doc.fileHash), 'check the file');
|
189
|
-
});
|
190
|
-
});
|
191
|
-
|
192
|
-
describe('.updateSongCache()', () => {
|
193
|
-
let title;
|
194
|
-
|
195
|
-
before(async () => {
|
196
|
-
title = 'new - song';
|
197
|
-
});
|
198
|
-
|
199
|
-
it('should not add the cache because of a wrong link', async () => {
|
200
|
-
const value = {
|
201
|
-
audioLink: 'wrong'
|
202
|
-
};
|
203
|
-
await node.updateSongCache(title, value);
|
204
|
-
assert.isNull(await node.cacheFile.get(title));
|
205
|
-
});
|
206
|
-
|
207
|
-
it('should add the cache partially', async () => {
|
208
|
-
const doc = await node.db.getMusicByPk(title);
|
209
|
-
const info = url.parse(await node.createSongAudioLink(doc));
|
210
|
-
const audioLink = url.format(Object.assign(info, { host: 'example.com:80' }));
|
211
|
-
const value = {
|
212
|
-
audioLink,
|
213
|
-
coverLink: 'wrong'
|
214
|
-
};
|
215
|
-
await node.updateSongCache(title, value);
|
216
|
-
const cache = (await node.cacheFile.get(title)).value;
|
217
|
-
assert.equal(audioLink, cache.audioLink, 'check the audio');
|
218
|
-
assert.isNotOk(cache.coverLink, 'check the cover');
|
219
|
-
});
|
220
|
-
|
221
|
-
it('should add the cache completely', async () => {
|
222
|
-
const doc = await node.db.getMusicByPk(title);
|
223
|
-
let info = url.parse(await node.createSongAudioLink(doc));
|
224
|
-
const audioLink = url.format(Object.assign(info, { host: 'example.com:80' }));
|
225
|
-
info = url.parse(await node.createSongCoverLink(doc));
|
226
|
-
const coverLink = url.format(Object.assign(info, { host: 'example.com:80' }));
|
227
|
-
const value = {
|
228
|
-
audioLink,
|
229
|
-
coverLink,
|
230
|
-
userless: true
|
231
|
-
};
|
232
|
-
await node.updateSongCache(title, value);
|
233
|
-
const cache = (await node.cacheFile.get(title)).value;
|
234
|
-
assert.equal(audioLink, cache.audioLink, 'check the audio');
|
235
|
-
assert.equal(coverLink, cache.coverLink, 'check the cover');
|
236
|
-
assert.isUndefined(cache.userless, 'check the wrong proprty');
|
237
|
-
});
|
238
|
-
});
|
239
|
-
|
240
|
-
describe('.createSongAudioLink()', () => {
|
241
|
-
it('should create a right audio link', async () => {
|
242
|
-
const doc = await node.db.getMusicByPk('new - song');
|
243
|
-
const code = utils.encodeSongTitle(doc.title);
|
244
|
-
const hash = doc.fileHash;
|
245
|
-
assert.equal(await node.createSongAudioLink(doc), `http://${node.address}/audio/${code}.mp3?f=${hash}`);
|
246
|
-
});
|
247
|
-
});
|
248
|
-
|
249
|
-
describe('.createSongCoverLink()', () => {
|
250
|
-
it('should create a right cover link', async () => {
|
251
|
-
const doc = await node.db.getMusicByPk('new - song');
|
252
|
-
const hash = doc.fileHash;
|
253
|
-
const code = utils.encodeSongTitle(doc.title);
|
254
|
-
assert.equal(await node.createSongCoverLink(doc), `http://${node.address}/cover/${code}.jpeg?f=${hash}`);
|
255
|
-
});
|
256
|
-
});
|
257
|
-
|
258
|
-
describe('.checkSongRelevance()', () => {
|
259
|
-
let title;
|
260
|
-
|
261
|
-
before(() => {
|
262
|
-
title = 'new - song';
|
263
|
-
});
|
264
|
-
|
265
|
-
it('should return true', async () => {
|
266
|
-
const doc = await node.db.getMusicByPk(title);
|
267
|
-
const filePath = node.getFilePath(doc.fileHash);
|
268
|
-
assert.isTrue(await node.checkSongRelevance(filePath, filePath));
|
269
|
-
});
|
270
|
-
});
|
271
|
-
|
272
|
-
describe('.removeFileFromStorage()', () => {
|
273
|
-
let title;
|
274
|
-
|
275
|
-
before(() => {
|
276
|
-
title = 'new - song';
|
277
|
-
});
|
278
|
-
|
279
|
-
it('should remove the file and the document', async () => {
|
280
|
-
const doc = await node.db.getMusicByPk(title);
|
281
|
-
await node.removeFileFromStorage(doc.fileHash);
|
282
|
-
assert.isNull(await node.db.getMusicByPk(title), 'check the database');
|
283
|
-
assert.isFalse(await node.hasFile(doc.fileHash), 'check the file');
|
284
|
-
});
|
285
|
-
|
286
|
-
it('should remove the file and the document', async () => {
|
287
|
-
await node.addSong(path.join(tools.tmpPath, 'audio.mp3'));
|
288
|
-
const doc = await node.db.getMusicByPk(title);
|
289
|
-
assert.isObject(doc, 'check the database before');
|
290
|
-
await node.removeFileFromStorage(doc.fileHash, { ignoreDocument: true });
|
291
|
-
assert.isObject(await node.db.getMusicByPk(title));
|
292
|
-
assert.isFalse(await node.hasFile(doc.fileHash));
|
293
|
-
});
|
294
|
-
});
|
295
|
-
|
296
|
-
describe('.prepareSongCover', () => {
|
297
|
-
it('should throw an error because of minimum width', async () => {
|
298
|
-
try {
|
299
|
-
const image = sharp(path.join(tools.tmpPath, 'cover.jpg'));
|
300
|
-
const metadata = await image.metadata();
|
301
|
-
image.resize(node.options.music.coverMinSize - 1, metadata.height);
|
302
|
-
await node.prepareSongCover(await image.toBuffer());
|
303
|
-
throw new Error('Fail');
|
304
|
-
}
|
305
|
-
catch (err) {
|
306
|
-
assert.isOk(err.message.match('Minimum size'));
|
307
|
-
}
|
308
|
-
});
|
309
|
-
|
310
|
-
it('should throw an error because of minimum height', async () => {
|
311
|
-
try {
|
312
|
-
const image = sharp(path.join(tools.tmpPath, 'cover.jpg'));
|
276
|
+
before(() => {
|
277
|
+
title = 'new - song';
|
278
|
+
});
|
279
|
+
|
280
|
+
it('should remove the file and the document', async () => {
|
281
|
+
const doc = await node.db.getMusicByPk(title);
|
282
|
+
await node.removeFileFromStorage(doc.fileHash);
|
283
|
+
assert.isNull(await node.db.getMusicByPk(title), 'check the database');
|
284
|
+
assert.isFalse(await node.hasFile(doc.fileHash), 'check the file');
|
285
|
+
});
|
286
|
+
|
287
|
+
it('should remove the file and the document', async () => {
|
288
|
+
await node.addSong(path.join(tools.tmpPath, 'audio.mp3'));
|
289
|
+
const doc = await node.db.getMusicByPk(title);
|
290
|
+
assert.isObject(doc, 'check the database before');
|
291
|
+
await node.removeFileFromStorage(doc.fileHash, { ignoreDocument: true });
|
292
|
+
assert.isObject(await node.db.getMusicByPk(title));
|
293
|
+
assert.isFalse(await node.hasFile(doc.fileHash));
|
294
|
+
});
|
295
|
+
});
|
296
|
+
|
297
|
+
describe('.prepareSongCover', () => {
|
298
|
+
it('should throw an error because of minimum width', async () => {
|
299
|
+
try {
|
300
|
+
const image = sharp(path.join(tools.tmpPath, 'cover.jpg'));
|
301
|
+
const metadata = await image.metadata();
|
302
|
+
image.resize(node.options.music.coverMinSize - 1, metadata.height);
|
303
|
+
await node.prepareSongCover(await image.toBuffer());
|
304
|
+
throw new Error('Fail');
|
305
|
+
}
|
306
|
+
catch (err) {
|
307
|
+
assert.isOk(err.message.match('Minimum size'));
|
308
|
+
}
|
309
|
+
});
|
310
|
+
|
311
|
+
it('should throw an error because of minimum height', async () => {
|
312
|
+
try {
|
313
|
+
const image = sharp(path.join(tools.tmpPath, 'cover.jpg'));
|
314
|
+
const metadata = await image.metadata();
|
315
|
+
image.resize(metadata.width, node.options.music.coverMinSize - 1);
|
316
|
+
await node.prepareSongCover(await image.toBuffer());
|
317
|
+
throw new Error('Fail');
|
318
|
+
}
|
319
|
+
catch (err) {
|
320
|
+
assert.isOk(err.message.match('Minimum size'));
|
321
|
+
}
|
322
|
+
});
|
323
|
+
|
324
|
+
it('should prepare and resize the image', async () => {
|
325
|
+
const maxSize = node.options.music.coverMaxSize;
|
326
|
+
const buffer = await node.prepareSongCover(path.join(tools.tmpPath, 'cover.jpg'));
|
327
|
+
const image = sharp(buffer);
|
313
328
|
const metadata = await image.metadata();
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
}
|
318
|
-
catch (err) {
|
319
|
-
assert.isOk(err.message.match('Minimum size'));
|
320
|
-
}
|
329
|
+
assert.instanceOf(buffer, Buffer);
|
330
|
+
assert.isTrue(metadata.width <= maxSize && metadata.height <= maxSize);
|
331
|
+
});
|
321
332
|
});
|
322
333
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
assert.isTrue(metadata.width <= maxSize && metadata.height <= maxSize);
|
334
|
+
describe('.prepareSongTitle()', () => {
|
335
|
+
it('should return beautified title', async () => {
|
336
|
+
const title = 'artist - song ft. artist2';
|
337
|
+
const res = await node.prepareSongTitle(title);
|
338
|
+
assert.equal(res, utils.beautifySongTitle(title));
|
339
|
+
});
|
330
340
|
});
|
331
|
-
});
|
332
341
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
assert.equal(res, utils.beautifySongTitle(title));
|
338
|
-
});
|
339
|
-
});
|
340
|
-
|
341
|
-
describe('.cleanUpMusic()', () => {
|
342
|
-
it('should remove wrong documents', async () => {
|
343
|
-
const title = 'test - test';
|
344
|
-
await node.db.addMusicDocument({ title });
|
345
|
-
await node.cleanUpMusic();
|
346
|
-
assert.isNull(await node.db.getDocumentByPk('music', title))
|
347
|
-
});
|
348
|
-
|
349
|
-
it('should not remove wrong files', async () => {
|
350
|
-
const filePath = await utils.setSongTags(path.join(tools.tmpPath, 'audio.mp3'), { fullTitle: 'another - song' });
|
351
|
-
const hash = await utils.getFileHash(filePath);
|
352
|
-
await node.withAddingFile(hash, async () => {
|
353
|
-
await node.addFileToStorage(filePath, hash, { copy: true });
|
342
|
+
describe('.cleanUpMusic()', () => {
|
343
|
+
it('should remove wrong documents', async () => {
|
344
|
+
const title = 'test - test';
|
345
|
+
await node.db.addMusicDocument({ title });
|
354
346
|
await node.cleanUpMusic();
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
347
|
+
assert.isNull(await node.db.getDocumentByPk('music', title));
|
348
|
+
});
|
349
|
+
|
350
|
+
it('should not remove wrong files', async () => {
|
351
|
+
const filePath = await utils.setSongTags(path.join(tools.tmpPath, 'audio.mp3'), { fullTitle: 'another - song' });
|
352
|
+
const hash = await utils.getFileHash(filePath);
|
353
|
+
await node.withAddingFile(hash, async () => {
|
354
|
+
await node.addFileToStorage(filePath, hash, { copy: true });
|
355
|
+
await node.cleanUpMusic();
|
356
|
+
});
|
357
|
+
assert.isTrue(await node.hasFile(hash));
|
358
|
+
});
|
359
|
+
|
360
|
+
it('should remove wrong files', async () => {
|
361
|
+
const hash = await utils.getFileHash(path.join(tools.tmpPath, 'audio.mp3'));
|
362
|
+
await node.cleanUpMusic();
|
363
|
+
assert.isFalse(await node.hasFile(hash));
|
364
|
+
});
|
365
|
+
});
|
366
|
+
|
367
|
+
describe('.normalizeSongTitles()', () => {
|
368
|
+
it('should beautify song titles', async () => {
|
369
|
+
const title = 'ARTIST - test';
|
370
|
+
await node.db.addMusicDocument({ title });
|
371
|
+
await node.normalizeSongTitles();
|
372
|
+
const beauty = utils.beautifySongTitle(title);
|
373
|
+
const docs = await node.db.getDocuments('music');
|
374
|
+
assert.notEqual(title, beauty, 'check the title');
|
375
|
+
assert.equal(docs[docs.length - 1].compTitle, utils.prepareComparisonSongTitle(beauty), 'check the doc');
|
376
|
+
});
|
377
|
+
});
|
378
|
+
|
379
|
+
describe('.getStorageCleaningUpTree()', () => {
|
380
|
+
it('should get right order of priority', async () => {
|
381
|
+
for (let i = 0; i < 3; i++) {
|
382
|
+
const title = `artist${Math.random()} - title${Math.random()}`;
|
383
|
+
const filePath = await utils.setSongTags(path.join(tools.tmpPath, 'audio.mp3'), { fullTitle: title });
|
384
|
+
const hash = await utils.getFileHash(filePath);
|
385
|
+
await node.db.addMusicDocument({ title, priority: 1 - i, fileHash: hash });
|
386
|
+
await node.addFileToStorage(filePath, hash, { copy: true });
|
387
|
+
}
|
388
|
+
|
389
|
+
const delay = node.__songSyncDelay;
|
390
|
+
node.__songSyncDelay = 0;
|
391
|
+
const tree = await node.getStorageCleaningUpTree();
|
392
|
+
const keys = tree.keys();
|
393
|
+
assert.isTrue(keys[0].priority == -1 && keys[1].priority == 0 && keys[2].priority == 1);
|
394
|
+
node.__songSyncDelay = delay;
|
395
|
+
});
|
396
|
+
});
|
397
|
+
|
398
|
+
describe('.exportSongs()', () => {
|
399
|
+
let importNode;
|
400
|
+
|
401
|
+
before(async () => {
|
402
|
+
importNode = new Node(await tools.createNodeOptions());
|
403
|
+
await importNode.init();
|
404
|
+
});
|
405
|
+
|
406
|
+
after(async () => {
|
407
|
+
await importNode.deinit();
|
408
|
+
});
|
409
|
+
|
410
|
+
it('should export the song', async () => {
|
411
|
+
importNode.options.network.trustlist = [node.address];
|
412
|
+
const title = 'export - song';
|
413
|
+
const filePath = path.join(tools.tmpPath, 'audio.mp3');
|
414
|
+
const file = await utils.setSongTags(filePath, { fullTitle: title });
|
415
|
+
await node.addSong(file);
|
416
|
+
await node.db.updateMusicDocument(Object.assign(await node.db.getMusicByPk(title), { priority: 1 }));
|
417
|
+
await node.exportSongs(importNode.address);
|
418
|
+
const doc = await importNode.db.getMusicByPk(title);
|
419
|
+
assert.isNotNull(doc, 'check the database');
|
420
|
+
assert.isTrue(await importNode.hasFile(doc.fileHash), 'check the file');
|
421
|
+
});
|
422
|
+
});
|
423
|
+
|
424
|
+
describe('.songTitleTest()', () => {
|
425
|
+
it('should throw an error', () => {
|
426
|
+
try {
|
427
|
+
node.songTitleTest('wrong song title');
|
428
|
+
throw new Error('Fail');
|
429
|
+
}
|
430
|
+
catch (err) {
|
431
|
+
assert.isOk(err.message.match('Wrong song'));
|
432
|
+
}
|
433
|
+
});
|
434
|
+
|
435
|
+
it('should not throw an error', async () => {
|
436
|
+
node.songTitleTest('artist - title');
|
437
|
+
});
|
438
|
+
});
|
439
|
+
|
440
|
+
describe('.uniqDocuments()', () => {
|
441
|
+
it('should remove the duplicates', async () => {
|
442
|
+
const arr = [
|
443
|
+
{ fileHash: 'a' },
|
444
|
+
{ fileHash: 'a' },
|
445
|
+
{ fileHash: 'b' },
|
446
|
+
{ fileHash: 'b' },
|
447
|
+
{ fileHash: 'c' }
|
448
|
+
];
|
449
|
+
const collection = await node.getCollection('music');
|
450
|
+
assert.lengthOf(await node.uniqDocuments(collection, arr), 3);
|
451
|
+
});
|
452
|
+
});
|
453
|
+
|
454
|
+
describe('.deinit()', () => {
|
455
|
+
it('should not throw an exception', async () => {
|
456
|
+
await node.deinit();
|
457
|
+
});
|
458
|
+
});
|
459
|
+
|
460
|
+
describe('reinitialization', () => {
|
461
|
+
it('should not throw an exception', async () => {
|
462
|
+
await node.init();
|
463
|
+
});
|
375
464
|
});
|
376
|
-
});
|
377
|
-
|
378
|
-
describe('.getStorageCleaningUpTree()', () => {
|
379
|
-
it('should get right order of priority', async () => {
|
380
|
-
for(let i = 0; i < 3; i++) {
|
381
|
-
const title = `artist${ Math.random() } - title${ Math.random() }`;
|
382
|
-
const filePath = await utils.setSongTags(path.join(tools.tmpPath, 'audio.mp3'), { fullTitle: title });
|
383
|
-
const hash = await utils.getFileHash(filePath);
|
384
|
-
await node.db.addMusicDocument({ title, priority: 1 - i, fileHash: hash });
|
385
|
-
await node.addFileToStorage(filePath, hash, { copy: true });
|
386
|
-
}
|
387
465
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
assert.isTrue(keys[0].priority == -1 && keys[1].priority == 0 && keys[2].priority == 1);
|
393
|
-
node.__songSyncDelay = delay;
|
394
|
-
});
|
395
|
-
});
|
396
|
-
|
397
|
-
describe('.exportSongs()', () => {
|
398
|
-
let importNode;
|
399
|
-
|
400
|
-
before(async () => {
|
401
|
-
importNode = new Node(await tools.createNodeOptions());
|
402
|
-
await importNode.init();
|
403
|
-
});
|
404
|
-
|
405
|
-
after(async () => {
|
406
|
-
await importNode.deinit();
|
407
|
-
});
|
408
|
-
|
409
|
-
it('should export the song', async () => {
|
410
|
-
importNode.options.network.trustlist = [node.address];
|
411
|
-
const title = 'export - song';
|
412
|
-
const filePath = path.join(tools.tmpPath, 'audio.mp3');
|
413
|
-
const file = await utils.setSongTags(filePath, { fullTitle: title });
|
414
|
-
await node.addSong(file);
|
415
|
-
await node.db.updateMusicDocument(Object.assign(await node.db.getMusicByPk(title), { priority: 1 }));
|
416
|
-
await node.exportSongs(importNode.address);
|
417
|
-
const doc = await importNode.db.getMusicByPk(title);
|
418
|
-
assert.isNotNull(doc, 'check the database');
|
419
|
-
assert.isTrue(await importNode.hasFile(doc.fileHash), 'check the file');
|
420
|
-
});
|
421
|
-
});
|
422
|
-
|
423
|
-
describe('.songTitleTest()', () => {
|
424
|
-
it('should throw an error', () => {
|
425
|
-
try {
|
426
|
-
node.songTitleTest('wrong song title');
|
427
|
-
throw new Error('Fail');
|
428
|
-
}
|
429
|
-
catch (err) {
|
430
|
-
assert.isOk(err.message.match('Wrong song'));
|
431
|
-
}
|
432
|
-
});
|
433
|
-
|
434
|
-
it('should not throw an error', async () => {
|
435
|
-
node.songTitleTest('artist - title');
|
436
|
-
});
|
437
|
-
});
|
438
|
-
|
439
|
-
describe('.uniqDocuments()', () => {
|
440
|
-
it('should remove the duplicates', async () => {
|
441
|
-
const arr = [
|
442
|
-
{ fileHash: 'a' },
|
443
|
-
{ fileHash: 'a' },
|
444
|
-
{ fileHash: 'b' },
|
445
|
-
{ fileHash: 'b' },
|
446
|
-
{ fileHash: 'c' }
|
447
|
-
];
|
448
|
-
|
449
|
-
const collection = await node.getCollection('music');
|
450
|
-
assert.lengthOf(await node.uniqDocuments(collection, arr), 3);
|
451
|
-
});
|
452
|
-
});
|
453
|
-
|
454
|
-
describe('.deinit()', () => {
|
455
|
-
it('should not throw an exception', async () => {
|
456
|
-
await node.deinit();
|
457
|
-
});
|
458
|
-
});
|
459
|
-
|
460
|
-
describe('reinitialization', () => {
|
461
|
-
it('should not throw an exception', async () => {
|
462
|
-
await node.init();
|
463
|
-
});
|
464
|
-
});
|
465
|
-
|
466
|
-
describe('.destroy()', () => {
|
467
|
-
it('should not throw an exception', async () => {
|
468
|
-
await node.destroy();
|
466
|
+
describe('.destroy()', () => {
|
467
|
+
it('should not throw an exception', async () => {
|
468
|
+
await node.destroy();
|
469
|
+
});
|
469
470
|
});
|
470
471
|
});
|
471
|
-
}
|
472
|
+
}
|