1 | const NodeID3 = require('../index.js')
|
2 | const jsmediatags = require("jsmediatags")
|
3 | const assert = require('assert')
|
4 | const chai = require('chai')
|
5 | const expect = chai.expect
|
6 | const iconv = require('iconv-lite')
|
7 | const fs = require('fs')
|
8 | const ID3Util = require('../src/ID3Util')
|
9 |
|
10 | describe('NodeID3', function () {
|
11 | describe('#create()', function () {
|
12 | it('empty tags', function () {
|
13 | assert.strictEqual(NodeID3.create({}).compare(Buffer.from([0x49, 0x44, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])), 0)
|
14 | })
|
15 | it('text frames', function () {
|
16 | let tags = {
|
17 | TIT2: "abcdeÜ看板かんばん",
|
18 | album: "nasÖÄkdnasd",
|
19 | notfound: "notfound",
|
20 | year: 1990
|
21 | }
|
22 | let buffer = NodeID3.create(tags)
|
23 | let titleSize = 10 + 1 + iconv.encode(tags.TIT2, 'utf16').length
|
24 | let albumSize = 10 + 1 + iconv.encode(tags.album, 'utf16').length
|
25 | let yearSize = 10 + 1 + iconv.encode(tags.year, 'utf16').length
|
26 | assert.strictEqual(buffer.length,
|
27 | 10 +
|
28 | titleSize +
|
29 | albumSize +
|
30 | yearSize
|
31 | )
|
32 |
|
33 | assert.ok(buffer.includes(
|
34 | Buffer.concat([
|
35 | Buffer.from([0x49, 0x44, 0x33, 0x03, 0x00, 0x00]),
|
36 | Buffer.from(ID3Util.encodeSize(titleSize + albumSize + yearSize))
|
37 | ])
|
38 | ))
|
39 |
|
40 |
|
41 | assert.ok(buffer.includes(
|
42 | Buffer.concat([
|
43 | Buffer.from([0x54, 0x49, 0x54, 0x32]),
|
44 | sizeToBuffer(titleSize - 10),
|
45 | Buffer.from([0x00, 0x00]),
|
46 | Buffer.from([0x01]),
|
47 | iconv.encode(tags.TIT2, 'utf16')
|
48 | ])
|
49 | ))
|
50 |
|
51 | assert.ok(buffer.includes(
|
52 | Buffer.concat([
|
53 | Buffer.from([0x54, 0x41, 0x4C, 0x42]),
|
54 | sizeToBuffer(albumSize - 10),
|
55 | Buffer.from([0x00, 0x00]),
|
56 | Buffer.from([0x01]),
|
57 | iconv.encode(tags.album, 'utf16')
|
58 | ])
|
59 | ))
|
60 | assert.ok(buffer.includes(
|
61 | Buffer.concat([
|
62 | Buffer.from([0x54, 0x59, 0x45, 0x52]),
|
63 | sizeToBuffer(yearSize - 10),
|
64 | Buffer.from([0x00, 0x00]),
|
65 | Buffer.from([0x01]),
|
66 | iconv.encode(tags.year, 'utf16')
|
67 | ])
|
68 | ))
|
69 | })
|
70 |
|
71 | it('user defined text frames', function() {
|
72 | let tags = {
|
73 | userDefinedText: {
|
74 | description: "abc",
|
75 | value: "defg"
|
76 | }
|
77 | }
|
78 | let buffer = NodeID3.create(tags).slice(10)
|
79 | let descEncoded = iconv.encode(tags.userDefinedText.description + "\0", "UTF-16")
|
80 | let valueEncoded = iconv.encode(tags.userDefinedText.value, "UTF-16")
|
81 |
|
82 | assert.strictEqual(Buffer.compare(
|
83 | buffer,
|
84 | Buffer.concat([
|
85 | Buffer.from([0x54, 0x58, 0x58, 0x58]),
|
86 | sizeToBuffer(1 + descEncoded.length + valueEncoded.length),
|
87 | Buffer.from([0x00, 0x00]),
|
88 | Buffer.from([0x01]),
|
89 | descEncoded,
|
90 | valueEncoded
|
91 | ])
|
92 | ), 0)
|
93 |
|
94 | tags = {
|
95 | userDefinedText: [{
|
96 | description: "abc",
|
97 | value: "defg"
|
98 | }, {
|
99 | description: "hij",
|
100 | value: "klmn"
|
101 | }]
|
102 | }
|
103 | buffer = NodeID3.create(tags).slice(10)
|
104 | let desc1Encoded = iconv.encode(tags.userDefinedText[0].description + "\0", "UTF-16")
|
105 | let value1Encoded = iconv.encode(tags.userDefinedText[0].value, "UTF-16")
|
106 | let desc2Encoded = iconv.encode(tags.userDefinedText[1].description + "\0", "UTF-16")
|
107 | let value2Encoded = iconv.encode(tags.userDefinedText[1].value, "UTF-16")
|
108 |
|
109 | assert.strictEqual(Buffer.compare(
|
110 | buffer,
|
111 | Buffer.concat([
|
112 | Buffer.from([0x54, 0x58, 0x58, 0x58]),
|
113 | sizeToBuffer(1 + desc1Encoded.length + value1Encoded.length),
|
114 | Buffer.from([0x00, 0x00]),
|
115 | Buffer.from([0x01]),
|
116 | desc1Encoded,
|
117 | value1Encoded,
|
118 | Buffer.from([0x54, 0x58, 0x58, 0x58]),
|
119 | sizeToBuffer(1 + desc2Encoded.length + value2Encoded.length),
|
120 | Buffer.from([0x00, 0x00]),
|
121 | Buffer.from([0x01]),
|
122 | desc2Encoded,
|
123 | value2Encoded
|
124 | ])
|
125 | ), 0)
|
126 | })
|
127 |
|
128 | it('create APIC frame', function() {
|
129 | let tags = {
|
130 | image: {
|
131 | description: "asdf",
|
132 | imageBuffer: Buffer.from('5B307836312C20307836322C20307836332C20307836345D', 'hex'),
|
133 | mime: "image/jpeg",
|
134 | type: {id: 3, name: "front cover"}
|
135 | }
|
136 | }
|
137 |
|
138 | assert.strictEqual(Buffer.compare(
|
139 | NodeID3.create(tags),
|
140 | Buffer.from('4944330300000000003B4150494300000031000001696D6167652F6A7065670003FFFE610073006400660000005B307836312C20307836322C20307836332C20307836345D', 'hex')
|
141 | ), 0)
|
142 |
|
143 | assert.strictEqual(Buffer.compare(
|
144 | NodeID3.create({
|
145 | image: __dirname + '/smallimg'
|
146 | }),
|
147 | NodeID3.create({
|
148 | image: {
|
149 | imageBuffer: fs.readFileSync(__dirname + '/smallimg')
|
150 | }
|
151 | })
|
152 | ), 0)
|
153 |
|
154 | assert.strictEqual(Buffer.compare(
|
155 | NodeID3.create({
|
156 | image: fs.readFileSync(__dirname + '/smallimg')
|
157 | }),
|
158 | NodeID3.create({
|
159 | image: {
|
160 | imageBuffer: fs.readFileSync(__dirname + '/smallimg')
|
161 | }
|
162 | })
|
163 | ), 0)
|
164 | })
|
165 |
|
166 | it('create USLT frame', function() {
|
167 | let tags = {
|
168 | unsynchronisedLyrics: {
|
169 | language: "deu",
|
170 | shortText: "Haiwsää#",
|
171 | text: "askdh ashd olahs elowz dlouaish dkajh"
|
172 | }
|
173 | }
|
174 |
|
175 | assert.strictEqual(Buffer.compare(
|
176 | NodeID3.create(tags),
|
177 | Buffer.from('4944330300000000006E55534C5400000064000001646575FFFE48006100690077007300E400E40023000000FFFE610073006B00640068002000610073006800640020006F006C00610068007300200065006C006F0077007A00200064006C006F0075006100690073006800200064006B0061006A006800', 'hex')
|
178 | ), 0)
|
179 | })
|
180 |
|
181 | it('create COMM frame', function() {
|
182 | const tags = {
|
183 | comment: {
|
184 | language: "deu",
|
185 | shortText: "Haiwsää#",
|
186 | text: "askdh ashd olahs elowz dlouaish dkajh"
|
187 | }
|
188 | }
|
189 | let frameBuf = Buffer.from('4944330300000000006E434F4D4D00000064000001646575FFFE48006100690077007300E400E40023000000FFFE610073006B00640068002000610073006800640020006F006C00610068007300200065006C006F0077007A00200064006C006F0075006100690073006800200064006B0061006A006800', 'hex')
|
190 |
|
191 | assert.strictEqual(Buffer.compare(
|
192 | NodeID3.create(tags),
|
193 | frameBuf
|
194 | ), 0)
|
195 | })
|
196 |
|
197 | it('create POPM frame', function() {
|
198 | let frameBuf = Buffer.from('49443303000000000020504F504D0000001600006D61696C406578616D706C652E636F6D00C00000000C', 'hex')
|
199 | const tags = {
|
200 | popularimeter: {
|
201 | email: "mail@example.com",
|
202 | rating: 192,
|
203 | counter: 12
|
204 | }
|
205 | }
|
206 |
|
207 | assert.strictEqual(Buffer.compare(
|
208 | NodeID3.create(tags),
|
209 | frameBuf
|
210 | ), 0)
|
211 | })
|
212 |
|
213 | it('create PRIV frame', function() {
|
214 | let frameBuf = Buffer.from('4944330300000000003250524956000000140000416243006173646F61687764696F686177646177505249560000000A000041624353535300010205', 'hex')
|
215 | const tags = { PRIV: [{
|
216 | ownerIdentifier: "AbC",
|
217 | data: Buffer.from("asdoahwdiohawdaw")
|
218 | }, {
|
219 | ownerIdentifier: "AbCSSS",
|
220 | data: Buffer.from([0x01, 0x02, 0x05])
|
221 | }]
|
222 | }
|
223 |
|
224 | assert.deepStrictEqual(
|
225 | NodeID3.create(tags),
|
226 | frameBuf
|
227 | )
|
228 | })
|
229 |
|
230 | it('create CHAP frame', function() {
|
231 | let frameBuf = Buffer.from('494433030000000000534348415000000049000048657921000000138800001F400000007B000001C8544954320000000F000001FFFE6100620063006400650066005450453100000011000001FFFE61006B0073006800640061007300', 'hex')
|
232 | const tags = { CHAP: [{
|
233 | elementID: "Hey!",
|
234 | startTimeMs: 5000,
|
235 | endTimeMs: 8000,
|
236 | startOffsetBytes: 123,
|
237 | endOffsetBytes: 456,
|
238 | tags: {
|
239 | title: "abcdef",
|
240 | artist: "akshdas"
|
241 | }
|
242 | }]}
|
243 |
|
244 | assert.deepStrictEqual(
|
245 | NodeID3.create(tags),
|
246 | frameBuf
|
247 | )
|
248 | })
|
249 |
|
250 | it('create WXXX frame', function() {
|
251 | const frameBuf = Buffer.from('4944330300000000002c5758585800000022000001fffe61006200630064002300000068747470733a2f2f6578616d706c652e636f6d', 'hex')
|
252 | const tags = {
|
253 | userDefinedUrl: [{
|
254 | description: 'abcd#',
|
255 | url: 'https://example.com'
|
256 | }]
|
257 | }
|
258 |
|
259 | assert.deepStrictEqual(
|
260 | NodeID3.create(tags),
|
261 | frameBuf
|
262 | )
|
263 | })
|
264 |
|
265 | it('create URL frame', function() {
|
266 | const frameBuf = Buffer.from('4944330300000000003b57434f4d00000013000068747470733a2f2f6578616d706c652e636f6d574f414600000014000068747470733a2f2f6578616d706c65322e636f6d', 'hex')
|
267 | const tags = {
|
268 | commercialUrl: ['https://example.com'],
|
269 | fileUrl: 'https://example2.com'
|
270 | }
|
271 |
|
272 | assert.deepStrictEqual(
|
273 | NodeID3.create(tags),
|
274 | frameBuf
|
275 | )
|
276 | })
|
277 | })
|
278 |
|
279 | describe('#write()', function() {
|
280 | it('sync not existing filepath', function() {
|
281 | assert.throws(NodeID3.write.bind({}, './hopefullydoesnotexist.mp3'), Error)
|
282 | })
|
283 | it('async not existing filepath', function() {
|
284 | NodeID3.write({}, './hopefullydoesnotexist.mp3', function(err) {
|
285 | if(!(err instanceof Error)) {
|
286 | assert.fail("No error thrown on non-existing filepath")
|
287 | }
|
288 | })
|
289 | })
|
290 |
|
291 | let buffer = Buffer.from([0x02, 0x06, 0x12, 0x22])
|
292 | let tags = {title: "abc"}
|
293 | let filepath = './testfile.mp3'
|
294 |
|
295 | it('sync write file without id3 tag', function() {
|
296 | fs.writeFileSync(filepath, buffer, 'binary')
|
297 | NodeID3.write(tags, filepath)
|
298 | let newFileBuffer = fs.readFileSync(filepath)
|
299 | fs.unlinkSync(filepath)
|
300 | assert.strictEqual(Buffer.compare(
|
301 | newFileBuffer,
|
302 | Buffer.concat([NodeID3.create(tags), buffer])
|
303 | ), 0)
|
304 | })
|
305 | it('async write file without id3 tag', function(done) {
|
306 | fs.writeFileSync(filepath, buffer, 'binary')
|
307 | NodeID3.write(tags, filepath, function() {
|
308 | let newFileBuffer = fs.readFileSync(filepath)
|
309 | fs.unlinkSync(filepath)
|
310 | if(Buffer.compare(
|
311 | newFileBuffer,
|
312 | Buffer.concat([NodeID3.create(tags), buffer])
|
313 | ) === 0) {
|
314 | done()
|
315 | } else {
|
316 | done(new Error("buffer not the same"))
|
317 | }
|
318 | })
|
319 | })
|
320 |
|
321 | let bufferWithTag = Buffer.concat([NodeID3.create(tags), buffer])
|
322 | tags = {album: "ix123"}
|
323 |
|
324 | it('sync write file with id3 tag', function() {
|
325 | fs.writeFileSync(filepath, bufferWithTag, 'binary')
|
326 | NodeID3.write(tags, filepath)
|
327 | let newFileBuffer = fs.readFileSync(filepath)
|
328 | fs.unlinkSync(filepath)
|
329 | assert.strictEqual(Buffer.compare(
|
330 | newFileBuffer,
|
331 | Buffer.concat([NodeID3.create(tags), buffer])
|
332 | ), 0)
|
333 | })
|
334 | it('async write file with id3 tag', function(done) {
|
335 | fs.writeFileSync(filepath, bufferWithTag, 'binary')
|
336 | NodeID3.write(tags, filepath, function() {
|
337 | let newFileBuffer = fs.readFileSync(filepath)
|
338 | fs.unlinkSync(filepath)
|
339 | if(Buffer.compare(
|
340 | newFileBuffer,
|
341 | Buffer.concat([NodeID3.create(tags), buffer])
|
342 | ) === 0) {
|
343 | done()
|
344 | } else {
|
345 | done(new Error("file written incorrectly"))
|
346 | }
|
347 | })
|
348 | })
|
349 | })
|
350 |
|
351 | describe('#read()', function() {
|
352 | it('read empty id3 tag', function() {
|
353 | let frame = NodeID3.create({})
|
354 | assert.deepStrictEqual(
|
355 | NodeID3.read(frame),
|
356 | {raw: {}}
|
357 | )
|
358 | })
|
359 |
|
360 | it('read text frames id3 tag', function() {
|
361 | let frame = NodeID3.create({ title: "asdfghjÄÖP", album: "naBGZwssg" })
|
362 | assert.deepStrictEqual(
|
363 | NodeID3.read(frame),
|
364 | { title: "asdfghjÄÖP", album: "naBGZwssg", raw: { TIT2: "asdfghjÄÖP", TALB: "naBGZwssg" }}
|
365 | )
|
366 | })
|
367 |
|
368 | it('read tag with broken frame', function() {
|
369 | let frame = NodeID3.create({ title: "asdfghjÄÖP", album: "naBGZwssg" })
|
370 | frame[10] = 0x99
|
371 | assert.deepStrictEqual(
|
372 | NodeID3.read(frame),
|
373 | { album: "naBGZwssg", raw: { TALB: "naBGZwssg" }}
|
374 | )
|
375 | })
|
376 |
|
377 | |
378 |
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 |
|
385 |
|
386 | it('read tag with bigger size', function() {
|
387 | let frame = NodeID3.create({ title: "asdfghjÄÖP", album: "naBGZwssg" })
|
388 | frame[9] += 100
|
389 | assert.deepStrictEqual(
|
390 | NodeID3.read(frame),
|
391 | { title: "asdfghjÄÖP", album: "naBGZwssg", raw: { TIT2: "asdfghjÄÖP", TALB: "naBGZwssg" }}
|
392 | )
|
393 | })
|
394 |
|
395 | it('read tag with smaller size', function() {
|
396 | let frame = NodeID3.create({ title: "asdfghjÄÖP", album: "naBGZwssg" })
|
397 | frame[9] -= 25
|
398 | assert.deepStrictEqual(
|
399 | NodeID3.read(frame),
|
400 | { title: "asdfghjÄÖP", raw: { TIT2: "asdfghjÄÖP" }}
|
401 | )
|
402 | })
|
403 |
|
404 | it('read TXXX frame', function() {
|
405 | let tags = { userDefinedText: {description: "abc", value: "deg"} }
|
406 | let frame = NodeID3.create(tags)
|
407 | assert.deepStrictEqual(
|
408 | NodeID3.read(frame),
|
409 | {
|
410 | userDefinedText: [tags.userDefinedText],
|
411 | raw: {
|
412 | TXXX: [tags.userDefinedText]
|
413 | }
|
414 | }
|
415 | )
|
416 | })
|
417 |
|
418 | it('read TXXX array frame', function() {
|
419 | let tags = { userDefinedText: [{description: "abc", value: "deg"}, {description: "abcd", value: "efgh"}] }
|
420 | let frame = NodeID3.create(tags)
|
421 | assert.deepStrictEqual(
|
422 | NodeID3.read(frame),
|
423 | {
|
424 | userDefinedText: tags.userDefinedText,
|
425 | raw: {
|
426 | TXXX: tags.userDefinedText
|
427 | }
|
428 | }
|
429 | )
|
430 | })
|
431 |
|
432 | it('read APIC frame', function() {
|
433 | let withAll = Buffer.from("4944330300000000101C4150494300000016000000696D6167652F6A7065670003617364660061626364", "hex")
|
434 | let noDesc = Buffer.from("494433030000000000264150494300000012000000696D6167652F6A70656700030061626364", "hex")
|
435 | let obj = {
|
436 | description: "asdf",
|
437 | imageBuffer: Buffer.from([0x61, 0x62, 0x63, 0x64]),
|
438 | mime: "jpeg",
|
439 | type: { id: 3, name: "front cover" }
|
440 | }
|
441 |
|
442 | assert.deepStrictEqual(
|
443 | NodeID3.read(withAll).image,
|
444 | obj
|
445 | )
|
446 |
|
447 | obj.description = undefined
|
448 | assert.deepStrictEqual(
|
449 | NodeID3.read(noDesc).image,
|
450 | obj
|
451 | )
|
452 | })
|
453 |
|
454 | it('read USLT frame', function() {
|
455 | let frameBuf = Buffer.from('4944330300000000006E55534C5400000064000001646575FFFE48006100690077007300E400E40023000000FFFE610073006B00640068002000610073006800640020006F006C00610068007300200065006C006F0077007A00200064006C006F0075006100690073006800200064006B0061006A006800', 'hex')
|
456 | const unsynchronisedLyrics = {
|
457 | language: "deu",
|
458 | shortText: "Haiwsää#",
|
459 | text: "askdh ashd olahs elowz dlouaish dkajh"
|
460 | }
|
461 |
|
462 | assert.deepStrictEqual(
|
463 | NodeID3.read(frameBuf).unsynchronisedLyrics,
|
464 | unsynchronisedLyrics
|
465 | )
|
466 | })
|
467 |
|
468 | it('read COMM frame', function() {
|
469 | let frameBuf = Buffer.from('4944330300000000006E434F4D4D00000064000001646575FFFE48006100690077007300E400E40023000000FFFE610073006B00640068002000610073006800640020006F006C00610068007300200065006C006F0077007A00200064006C006F0075006100690073006800200064006B0061006A006800', 'hex')
|
470 | const comment = {
|
471 | language: "deu",
|
472 | shortText: "Haiwsää#",
|
473 | text: "askdh ashd olahs elowz dlouaish dkajh"
|
474 | }
|
475 |
|
476 | assert.deepStrictEqual(
|
477 | NodeID3.read(frameBuf).comment,
|
478 | comment
|
479 | )
|
480 | })
|
481 |
|
482 | it('read POPM frame', function() {
|
483 | let frameBuf = Buffer.from('49443303000000000020504F504D0000001600006D61696C406578616D706C652E636F6D00C00000000C', 'hex')
|
484 | const popularimeter = {
|
485 | email: "mail@example.com",
|
486 | rating: 192,
|
487 | counter: 12
|
488 | }
|
489 |
|
490 | assert.deepStrictEqual(
|
491 | NodeID3.read(frameBuf).popularimeter,
|
492 | popularimeter
|
493 | )
|
494 | })
|
495 |
|
496 | it('read PRIV frame', function() {
|
497 | let frameBuf = Buffer.from('4944330300000000003250524956000000140000416243006173646F61687764696F686177646177505249560000000A000041624353535300010205', 'hex')
|
498 | const priv = [{
|
499 | ownerIdentifier: "AbC",
|
500 | data: Buffer.from("asdoahwdiohawdaw")
|
501 | }, {
|
502 | ownerIdentifier: "AbCSSS",
|
503 | data: Buffer.from([0x01, 0x02, 0x05])
|
504 | }]
|
505 |
|
506 | assert.deepStrictEqual(
|
507 | NodeID3.read(frameBuf).private,
|
508 | priv
|
509 | )
|
510 | })
|
511 |
|
512 | it('read CHAP frame', function() {
|
513 | let frameBuf = Buffer.from('494433030000000000534348415000000049000048657921000000138800001F400000007B000001C8544954320000000F000001FFFE6100620063006400650066005450453100000011000001FFFE61006B0073006800640061007300', 'hex')
|
514 | const chap = [{
|
515 | elementID: "Hey!",
|
516 | startTimeMs: 5000,
|
517 | endTimeMs: 8000,
|
518 | startOffsetBytes: 123,
|
519 | endOffsetBytes: 456,
|
520 | tags: {
|
521 | title: "abcdef",
|
522 | artist: "akshdas",
|
523 | raw: {
|
524 | TIT2: "abcdef",
|
525 | TPE1: "akshdas"
|
526 | }
|
527 | }
|
528 | }]
|
529 |
|
530 | assert.deepStrictEqual(
|
531 | NodeID3.read(frameBuf).chapter,
|
532 | chap
|
533 | )
|
534 | })
|
535 |
|
536 | it('read WXXX frame', function() {
|
537 | const frameBuf = Buffer.from('4944330300000000002c5758585800000022000001fffe61006200630064002300000068747470733a2f2f6578616d706c652e636f6d', 'hex')
|
538 | const userDefinedUrl = [{
|
539 | description: 'abcd#',
|
540 | url: 'https://example.com'
|
541 | }]
|
542 |
|
543 | assert.deepStrictEqual(
|
544 | NodeID3.read(frameBuf).userDefinedUrl,
|
545 | userDefinedUrl
|
546 | )
|
547 | })
|
548 |
|
549 | it('read URL frame', function() {
|
550 | const frameBuf = Buffer.from('4944330300000000003d57434f4d0000001400000068747470733a2f2f6578616d706c652e636f6d574f41460000001500000068747470733a2f2f6578616d706c65322e636f6d', 'hex')
|
551 | const commercialUrl = ['https://example.com']
|
552 | const fileUrl = 'https://example2.com'
|
553 |
|
554 | assert.deepStrictEqual(
|
555 | NodeID3.read(frameBuf).commercialUrl,
|
556 | commercialUrl
|
557 | )
|
558 | assert.deepStrictEqual(
|
559 | NodeID3.read(frameBuf).fileUrl,
|
560 | fileUrl
|
561 | )
|
562 | })
|
563 |
|
564 | it('read exclude', function() {
|
565 | let tags = {
|
566 | TIT2: "abcdeÜ看板かんばん",
|
567 | album: "nasÖÄkdnasd",
|
568 | year: "1990"
|
569 | }
|
570 |
|
571 | const buffer = NodeID3.create(tags)
|
572 | let read = NodeID3.read(buffer, { exclude: ['TIT2'] })
|
573 | delete read.raw
|
574 | delete tags.TIT2
|
575 | assert.deepStrictEqual(
|
576 | read,
|
577 | tags
|
578 | )
|
579 | })
|
580 |
|
581 | it('read include', function() {
|
582 | let tags = {
|
583 | title: "abcdeÜ看板かんばん",
|
584 | album: "nasÖÄkdnasd",
|
585 | year: "1990"
|
586 | }
|
587 |
|
588 | const buffer = NodeID3.create(tags)
|
589 | let read = NodeID3.read(buffer, { include: ['TALB', 'TIT2'] })
|
590 | delete read.raw
|
591 | delete tags.year
|
592 | assert.deepStrictEqual(
|
593 | read,
|
594 | tags
|
595 | )
|
596 | })
|
597 |
|
598 | it('onlyRaw', function() {
|
599 | let tags = {
|
600 | TIT2: "abcdeÜ看板かんばん",
|
601 | TALB: "nasÖÄkdnasd"
|
602 | }
|
603 |
|
604 | const buffer = NodeID3.create(tags)
|
605 | let read = NodeID3.read(buffer, { onlyRaw: true })
|
606 | assert.deepStrictEqual(
|
607 | read,
|
608 | tags
|
609 | )
|
610 | })
|
611 |
|
612 | it('noRaw', function() {
|
613 | let tags = {
|
614 | title: "abcdeÜ看板かんばん",
|
615 | album: "nasÖÄkdnasd"
|
616 | }
|
617 |
|
618 | const buffer = NodeID3.create(tags)
|
619 | let read = NodeID3.read(buffer, { noRaw: true })
|
620 | assert.deepStrictEqual(
|
621 | read,
|
622 | tags
|
623 | )
|
624 | })
|
625 | })
|
626 | })
|
627 |
|
628 | describe('ID3 helper functions', function () {
|
629 | describe('#removeTagsFromBuffer()', function () {
|
630 | it('no tags in buffer', function () {
|
631 | let emptyBuffer = Buffer.from([0x12, 0x04, 0x05, 0x01, 0x76, 0x27, 0x76, 0x27, 0x76, 0x27, 0x76, 0x27])
|
632 | assert.strictEqual(Buffer.compare(
|
633 | emptyBuffer,
|
634 | NodeID3.removeTagsFromBuffer(emptyBuffer)
|
635 | ), 0)
|
636 | })
|
637 |
|
638 | it('tags at start', function () {
|
639 | let buffer = Buffer.from([0x22, 0x73, 0x72])
|
640 | let bufferWithID3 = Buffer.concat([
|
641 | NodeID3.create({title: "abc"}),
|
642 | buffer
|
643 | ])
|
644 | assert.strictEqual(Buffer.compare(
|
645 | NodeID3.removeTagsFromBuffer(bufferWithID3),
|
646 | buffer
|
647 | ), 0)
|
648 | })
|
649 |
|
650 | it('tags in middle/end', function () {
|
651 | let buffer = Buffer.from([0x22, 0x73, 0x72])
|
652 | let bufferWithID3 = Buffer.concat([
|
653 | buffer,
|
654 | NodeID3.create({title: "abc"}),
|
655 | buffer
|
656 | ])
|
657 | assert.strictEqual(Buffer.compare(
|
658 | NodeID3.removeTagsFromBuffer(bufferWithID3),
|
659 | Buffer.concat([buffer, buffer])
|
660 | ), 0)
|
661 | })
|
662 | })
|
663 | })
|
664 |
|
665 | const nodeTagsFull = {
|
666 | title: 'abc',
|
667 | album: '人物asfjas as das \\',
|
668 | comment: {
|
669 | language: 'en3',
|
670 | shortText: 'asd物f',
|
671 | text: 1337
|
672 | },
|
673 | unsynchronisedLyrics: {
|
674 | language: 'e33',
|
675 | text: 'asd物f asd物f asd物f'
|
676 | },
|
677 | userDefinedText: [
|
678 | {
|
679 | description: "txxx name物",
|
680 | value: "TXXX value text"
|
681 | }, {
|
682 | description: "txxx name 2",
|
683 | value: "TXXX value text 2"
|
684 | }
|
685 | ],
|
686 | image: {
|
687 | mime: "jpeg",
|
688 | description: 'asd物f asd物f asd物f',
|
689 | imageBuffer: Buffer.from([0x02, 0x27, 0x17, 0x99])
|
690 | },
|
691 | popularimeter: {
|
692 | email: 'test@example.com',
|
693 | rating: 192,
|
694 | counter: 12
|
695 | },
|
696 | private: [{
|
697 | ownerIdentifier: "AbC",
|
698 | data: "asdoahwdiohawdaw"
|
699 | }, {
|
700 | ownerIdentifier: "AbCSSS",
|
701 | data: Buffer.from([0x01, 0x02, 0x05])
|
702 | }],
|
703 | chapter: [{
|
704 | elementID: "Hey!",
|
705 | startTimeMs: 5000,
|
706 | endTimeMs: 8000,
|
707 | startOffsetBytes: 123,
|
708 | endOffsetBytes: 456,
|
709 | tags: {
|
710 | title: "abcdef",
|
711 | artist: "akshdas"
|
712 | }
|
713 | }],
|
714 | tableOfContents: [{
|
715 | elementID: "toc1",
|
716 | isOrdered: false,
|
717 | elements: ['chap1'],
|
718 | tags: {
|
719 | title: "abcdef"
|
720 | }
|
721 | }],
|
722 | commercialUrl: ["commercialurl.com"],
|
723 | userDefinedUrl: [{
|
724 | description: "URL description物",
|
725 | url: "https://example.com/"
|
726 | }]
|
727 | }
|
728 |
|
729 | const nodeTagsMissingValues = {
|
730 | comment: {
|
731 | language: 'en3',
|
732 | text: 1337
|
733 | },
|
734 | userDefinedText: [
|
735 | {
|
736 | value: "TXXX value text"
|
737 | }, {
|
738 | value: "TXXX value text 2"
|
739 | }
|
740 | ],
|
741 | image: {
|
742 | mime: "jpeg",
|
743 | imageBuffer: Buffer.from([0x02, 0x27, 0x17, 0x99])
|
744 | },
|
745 | popularimeter: {
|
746 | email: 'test@example.com',
|
747 | counter: 12
|
748 | },
|
749 | private: [{
|
750 | data: "asdoahwdiohawdaw"
|
751 | }, {
|
752 | data: Buffer.from([0x01, 0x02, 0x05])
|
753 | }],
|
754 | chapter: [{
|
755 | elementID: "Hey!",
|
756 | startTimeMs: 5000,
|
757 | endTimeMs: 8000
|
758 | }],
|
759 | tableOfContents: [{
|
760 | elementID: "toc1",
|
761 | elements: ['chap1']
|
762 | }],
|
763 | }
|
764 |
|
765 | describe('Cross tests jsmediatags', function() {
|
766 | it('write full', function() {
|
767 | jsmediatags.read(NodeID3.create(nodeTagsFull), {
|
768 | onSuccess: (tag) => {
|
769 | const tags = tag.tags
|
770 | assert.strictEqual(tags.TIT2.data, nodeTagsFull.title)
|
771 | assert.strictEqual(tags.TALB.data, nodeTagsFull.album)
|
772 | assert.deepStrictEqual({ language: tags.COMM.data.language, shortText: tags.COMM.data.short_description, text: parseInt(tags.COMM.data.text) }, nodeTagsFull.comment)
|
773 | assert.deepStrictEqual({ language: tags.USLT.data.language, text: tags.USLT.data.lyrics }, nodeTagsFull.unsynchronisedLyrics)
|
774 | expect(tags.TXXX.map((t) => {
|
775 | return {
|
776 | description: t.data.user_description,
|
777 | value: t.data.data
|
778 | }
|
779 | })).to.have.deep.members(nodeTagsFull.userDefinedText)
|
780 | assert.deepStrictEqual({
|
781 | mime: tags.APIC.data.format,
|
782 | description: tags.APIC.data.description,
|
783 | imageBuffer: Buffer.from(tags.APIC.data.data)
|
784 | }, nodeTagsFull.image)
|
785 |
|
786 |
|
787 | assert.deepStrictEqual({
|
788 | elementID: nodeTagsFull.chapter[0].elementID,
|
789 | startTimeMs: tags.CHAP.data.startTime,
|
790 | endTimeMs: tags.CHAP.data.endTime,
|
791 | startOffsetBytes: tags.CHAP.data.startOffset,
|
792 | endOffsetBytes: tags.CHAP.data.endOffset,
|
793 | tags: {
|
794 | title: tags.CHAP.data.subFrames.TIT2.data,
|
795 | artist: tags.CHAP.data.subFrames.TPE1.data
|
796 | }
|
797 | }, nodeTagsFull.chapter[0])
|
798 | assert.deepStrictEqual({
|
799 | elementID:nodeTagsFull.tableOfContents[0].elementID,
|
800 | isOrdered: false,
|
801 | elements: tags.CTOC.data.childElementIds,
|
802 | tags: {
|
803 | title: tags.CTOC.data.subFrames.TIT2.data
|
804 | }
|
805 | }, nodeTagsFull.tableOfContents[0])
|
806 | assert.strictEqual(tags.WCOM.data, nodeTagsFull.commercialUrl[0])
|
807 | assert.deepStrictEqual({
|
808 | description: tags.WXXX.data.user_description,
|
809 | url: nodeTagsFull.userDefinedUrl[0].url
|
810 | }, nodeTagsFull.userDefinedUrl[0])
|
811 | },
|
812 | onError: function(error) {
|
813 | throw error
|
814 | }
|
815 | })
|
816 | })
|
817 |
|
818 | it('write with missing values', function() {
|
819 | jsmediatags.read(NodeID3.create(nodeTagsMissingValues), {
|
820 | onSuccess: (tag) => {
|
821 | const tags = tag.tags
|
822 | assert.deepStrictEqual({ language: tags.COMM.data.language, text: parseInt(tags.COMM.data.text) }, nodeTagsMissingValues.comment)
|
823 | assert.strictEqual(tags.COMM.data.short_description, '')
|
824 | expect(tags.TXXX.map((t) => {
|
825 | return {
|
826 | value: t.data.data
|
827 | }
|
828 | })).to.have.deep.members(nodeTagsMissingValues.userDefinedText)
|
829 | tags.TXXX.forEach((t) => {
|
830 | assert.strictEqual(t.data.user_description, '')
|
831 | })
|
832 | assert.deepStrictEqual({
|
833 | mime: tags.APIC.data.format,
|
834 | imageBuffer: Buffer.from(tags.APIC.data.data)
|
835 | }, nodeTagsMissingValues.image)
|
836 | assert.strictEqual(tags.APIC.data.description, '')
|
837 |
|
838 |
|
839 | assert.deepStrictEqual({
|
840 | elementID: nodeTagsMissingValues.chapter[0].elementID,
|
841 | startTimeMs: tags.CHAP.data.startTime,
|
842 | endTimeMs: tags.CHAP.data.endTime
|
843 | }, nodeTagsMissingValues.chapter[0])
|
844 | assert.deepStrictEqual(tags.CHAP.data.subFrames, {})
|
845 | assert.strictEqual(tags.CHAP.data.startOffset, 0xFFFFFFFF)
|
846 | assert.strictEqual(tags.CHAP.data.endOffset, 0xFFFFFFFF)
|
847 | assert.deepStrictEqual({
|
848 | elementID: nodeTagsMissingValues.tableOfContents[0].elementID,
|
849 | elements: tags.CTOC.data.childElementIds,
|
850 | }, nodeTagsMissingValues.tableOfContents[0])
|
851 | assert.deepStrictEqual(tags.CTOC.data.subFrames, {})
|
852 | assert.strictEqual(tags.CTOC.data.ordered, false)
|
853 | },
|
854 | onError: function(error) {
|
855 | throw error
|
856 | }
|
857 | })
|
858 | })
|
859 |
|
860 | it('read from full self-created tags', function() {
|
861 | const tagsBuffer = NodeID3.create(nodeTagsFull)
|
862 | let read = NodeID3.read(tagsBuffer)
|
863 |
|
864 | delete read.raw
|
865 | delete read.chapter[0].tags.raw
|
866 | delete read.tableOfContents[0].tags.raw
|
867 | read.comment.text = parseInt(read.comment.text)
|
868 | delete read.image.type
|
869 | read.private[0].data = read.private[0].data.toString()
|
870 | if(read.unsynchronisedLyrics.shortText === undefined) delete read.unsynchronisedLyrics.shortText
|
871 | assert.deepStrictEqual(nodeTagsFull, read)
|
872 | })
|
873 |
|
874 | it('read from missing values self-created tags', function() {
|
875 | const tagsBuffer = NodeID3.create(nodeTagsMissingValues)
|
876 | let read = NodeID3.read(tagsBuffer)
|
877 |
|
878 | delete read.raw
|
879 | assert.deepStrictEqual(read.chapter[0].tags.raw, {})
|
880 | delete read.chapter[0].tags
|
881 | read.comment.text = parseInt(read.comment.text)
|
882 | if(read.comment.shortText === undefined) delete read.comment.shortText
|
883 | if(read.image.description === undefined) delete read.image.description
|
884 | delete read.image.type
|
885 | assert.strictEqual(read.popularimeter.rating, 0)
|
886 | delete read.popularimeter.rating
|
887 | read.private[0].data = read.private[0].data.toString()
|
888 | if(read.private[0].ownerIdentifier === undefined) delete read.private[0].ownerIdentifier
|
889 | if(read.private[1].ownerIdentifier === undefined) delete read.private[1].ownerIdentifier
|
890 | assert.strictEqual(read.tableOfContents[0].isOrdered, false)
|
891 | assert.deepStrictEqual(read.tableOfContents[0].tags.raw, {})
|
892 | delete read.tableOfContents[0].tags
|
893 | delete read.tableOfContents[0].isOrdered
|
894 | if(read.userDefinedText[0].description === undefined) delete read.userDefinedText[0].description
|
895 | if(read.userDefinedText[1].description === undefined) delete read.userDefinedText[1].description
|
896 | assert.deepStrictEqual(nodeTagsMissingValues, read)
|
897 | })
|
898 | })
|
899 |
|
900 | function sizeToBuffer(totalSize) {
|
901 | let buffer = Buffer.alloc(4)
|
902 | buffer.writeUInt32BE(totalSize)
|
903 | return buffer
|
904 | }
|