Zazama /
node-id3
| 1 | const fs = require('fs')
|
||
| 2 | const ID3Definitions = require("./src/ID3Definitions")
|
||
| 3 | const ID3Frames = require('./src/ID3Frames')
|
||
| 4 | const ID3Util = require('./src/ID3Util')
|
||
| 5 | const zlib = require('zlib')
|
||
| 6 | |||
| 7 | /* |
||
| 8 | ** Used specification: http://id3.org/id3v2.3.0 |
||
| 9 | */ |
||
| 10 | |||
| 11 | /** |
||
| 12 | * Write passed tags to a file/buffer |
||
| 13 | * @param tags - Object containing tags to be written |
||
| 14 | * @param filebuffer - Can contain a filepath string or buffer |
||
| 15 | * @param fn - (optional) Function for async version |
||
| 16 | * @returns {boolean|Buffer|Error}
|
||
| 17 | */ |
||
| 18 | module.exports.write = function(tags, filebuffer, fn) {
|
||
| 19 | let completeTag = this.create(tags) |
||
| 20 | if(filebuffer instanceof Buffer) {
|
||
| 21 | filebuffer = this.removeTagsFromBuffer(filebuffer) || filebuffer |
||
| 22 | let completeBuffer = Buffer.concat([completeTag, filebuffer]) |
||
| 23 | if(fn && typeof fn === 'function') {
|
||
| 24 | fn(null, completeBuffer) |
||
| 25 | return undefined |
||
| 26 | } else {
|
||
| 27 | return completeBuffer |
||
| 28 | } |
||
| 29 | } |
||
| 30 | |||
| 31 | if(fn && typeof fn === 'function') {
|
||
| 32 | try {
|
||
| 33 | fs.readFile(filebuffer, function(err, data) {
|
||
| 34 | if(err) {
|
||
| 35 | fn(err) |
||
| 36 | return |
||
| 37 | } |
||
| 38 | data = this.removeTagsFromBuffer(data) || data |
||
| 39 | let rewriteFile = Buffer.concat([completeTag, data]) |
||
| 40 | fs.writeFile(filebuffer, rewriteFile, 'binary', (err) => {
|
||
| 41 | fn(err) |
||
| 42 | }) |
||
| 43 | }.bind(this)) |
||
| 44 | } catch(err) {
|
||
| 45 | fn(err) |
||
| 46 | } |
||
| 47 | } else {
|
||
| 48 | try {
|
||
| 49 | let data = fs.readFileSync(filebuffer) |
||
| 50 | data = this.removeTagsFromBuffer(data) || data |
||
| 51 | let rewriteFile = Buffer.concat([completeTag, data]) |
||
| 52 | fs.writeFileSync(filebuffer, rewriteFile, 'binary') |
||
| 53 | return true |
||
| 54 | } catch(err) {
|
||
| 55 | return err |
||
| 56 | } |
||
| 57 | } |
||
| 58 | } |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Creates a buffer containing the ID3 Tag |
||
| 62 | * @param tags - Object containing tags to be written |
||
| 63 | * @param fn fn - (optional) Function for async version |
||
| 64 | * @returns {Buffer}
|
||
| 65 | */ |
||
| 66 | module.exports.create = function(tags, fn) {
|
||
| 67 | let frames = [] |
||
| 68 | |||
| 69 | // Create & push a header for the ID3-Frame |
||
| 70 | const header = Buffer.alloc(10) |
||
| 71 | header.fill(0) |
||
| 72 | header.write("ID3", 0) //File identifier
|
||
| 73 | header.writeUInt16BE(0x0300, 3) //Version 2.3.0 -- 03 00 |
||
| 74 | header.writeUInt16BE(0x0000, 5) //Flags 00 |
||
| 75 | |||
| 76 | //Last 4 bytes are used for header size, but have to be inserted later, because at this point, its size is not clear. |
||
| 77 | frames.push(header) |
||
| 78 | |||
| 79 | frames = frames.concat(this.createBuffersFromTags(tags)) |
||
| 80 | |||
| 81 | // Calculate frame size of ID3 body to insert into header |
||
| 82 | |||
| 83 | let totalSize = 0 |
||
| 84 | frames.forEach((frame) => {
|
||
| 85 | totalSize += frame.length |
||
| 86 | }) |
||
| 87 | |||
| 88 | // Don't count ID3 header itself |
||
| 89 | totalSize -= 10 |
||
| 90 | // ID3 header size uses only 7 bits of a byte, bit shift is needed |
||
| 91 | let size = ID3Util.encodeSize(totalSize) |
||
| 92 | |||
| 93 | // Write bytes to ID3 frame header, which is the first frame |
||
| 94 | frames[0].writeUInt8(size[0], 6) |
||
| 95 | frames[0].writeUInt8(size[1], 7) |
||
| 96 | frames[0].writeUInt8(size[2], 8) |
||
| 97 | frames[0].writeUInt8(size[3], 9) |
||
| 98 | |||
| 99 | if(fn && typeof fn === 'function') {
|
||
| 100 | fn(Buffer.concat(frames)) |
||
| 101 | } else {
|
||
| 102 | return Buffer.concat(frames) |
||
| 103 | } |
||
| 104 | } |
||
| 105 | |||
| 106 | /** |
||
| 107 | * Returns array of buffers created by tags specified in the tags argument |
||
| 108 | * @param tags - Object containing tags to be written |
||
| 109 | * @returns {Array}
|
||
| 110 | */ |
||
| 111 | module.exports.createBuffersFromTags = function(tags) {
|
||
| 112 | let frames = [] |
||
| 113 | if(!tags) {
|
||
| 114 | return frames |
||
| 115 | } |
||
| 116 | const rawObject = Object.keys(tags).reduce((acc, val) => {
|
||
| 117 | if(ID3Definitions.FRAME_IDENTIFIERS.v3[val] !== undefined) {
|
||
| 118 | acc[ID3Definitions.FRAME_IDENTIFIERS.v3[val]] = tags[val] |
||
| 119 | } else {
|
||
| 120 | acc[val] = tags[val] |
||
| 121 | } |
||
| 122 | return acc |
||
| 123 | }, {})
|
||
| 124 | |||
| 125 | Object.keys(rawObject).forEach((specName) => {
|
||
| 126 | let frame |
||
| 127 | // Check if invalid specName |
||
| 128 | if(specName.length !== 4) {
|
||
| 129 | return |
||
| 130 | } |
||
| 131 | if(ID3Frames[specName] !== undefined) {
|
||
| 132 | frame = ID3Frames[specName].create(rawObject[specName], 3, this) |
||
| 133 | } else if(specName.startsWith('T')) {
|
||
| 134 | frame = ID3Frames.GENERIC_TEXT.create(specName, rawObject[specName], 3) |
||
| 135 | } else if(specName.startsWith('W')) {
|
||
| 136 | if(ID3Util.getSpecOptions(specName, 3).multiple && rawObject[specName] instanceof Array && rawObject[specName].length > 0) {
|
||
| 137 | frame = Buffer.alloc(0) |
||
| 138 | // deduplicate array |
||
| 139 | for(let url of [...new Set(rawObject[specName])]) {
|
||
| 140 | frame = Buffer.concat([frame, ID3Frames.GENERIC_URL.create(specName, url, 3)]) |
||
| 141 | } |
||
| 142 | } else {
|
||
| 143 | frame = ID3Frames.GENERIC_URL.create(specName, rawObject[specName], 3) |
||
| 144 | } |
||
| 145 | } |
||
| 146 | |||
| 147 | if (frame && frame instanceof Buffer) {
|
||
| 148 | frames.push(frame) |
||
| 149 | } |
||
| 150 | }) |
||
| 151 | |||
| 152 | return frames |
||
| 153 | } |
||
| 154 | |||
| 155 | /** |
||
| 156 | * Read ID3-Tags from passed buffer/filepath |
||
| 157 | * @param filebuffer - Can contain a filepath string or buffer |
||
| 158 | * @param options - (optional) Object containing options |
||
| 159 | * @param fn - (optional) Function for async version |
||
| 160 | * @returns {boolean}
|
||
| 161 | */ |
||
| 162 | module.exports.read = function(filebuffer, options, fn) {
|
||
| 163 | if(!options || typeof options === 'function') {
|
||
| 164 | fn = fn || options |
||
| 165 | options = {}
|
||
| 166 | } |
||
| 167 | if(!fn || typeof fn !== 'function') {
|
||
| 168 | if(typeof filebuffer === "string" || filebuffer instanceof String) {
|
||
| 169 | filebuffer = fs.readFileSync(filebuffer) |
||
| 170 | } |
||
| 171 | return this.getTagsFromBuffer(filebuffer, options) |
||
| 172 | } else {
|
||
| 173 | if(typeof filebuffer === "string" || filebuffer instanceof String) {
|
||
| 174 | fs.readFile(filebuffer, function(err, data) {
|
||
| 175 | if(err) {
|
||
| 176 | fn(err, null) |
||
| 177 | } else {
|
||
| 178 | fn(null, this.getTagsFromBuffer(data, options)) |
||
| 179 | } |
||
| 180 | }.bind(this)) |
||
| 181 | } else {
|
||
| 182 | fn(null, this.getTagsFromBuffer(filebuffer, options)) |
||
| 183 | } |
||
| 184 | } |
||
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * Update ID3-Tags from passed buffer/filepath |
||
| 189 | * @param tags - Object containing tags to be written |
||
| 190 | * @param filebuffer - Can contain a filepath string or buffer |
||
| 191 | * @param options - (optional) Object containing options |
||
| 192 | * @param fn - (optional) Function for async version |
||
| 193 | * @returns {boolean|Buffer|Error}
|
||
| 194 | */ |
||
| 195 | module.exports.update = function(tags, filebuffer, options, fn) {
|
||
| 196 | if(!options || typeof options === 'function') {
|
||
| 197 | fn = fn || options |
||
| 198 | options = {}
|
||
| 199 | } |
||
| 200 | |||
| 201 | const rawTags = Object.keys(tags).reduce((acc, val) => {
|
||
| 202 | if(ID3Definitions.FRAME_IDENTIFIERS.v3[val] !== undefined) {
|
||
| 203 | acc[ID3Definitions.FRAME_IDENTIFIERS.v3[val]] = tags[val] |
||
| 204 | } else {
|
||
| 205 | acc[val] = tags[val] |
||
| 206 | } |
||
| 207 | return acc |
||
| 208 | }, {})
|
||
| 209 | |||
| 210 | const updateFn = (currentTags) => {
|
||
| 211 | currentTags = currentTags.raw || {}
|
||
| 212 | Object.keys(rawTags).map((specName) => {
|
||
| 213 | const options = ID3Util.getSpecOptions(specName, 3) |
||
| 214 | const cCompare = {}
|
||
| 215 | if(options.multiple && currentTags[specName] && rawTags[specName]) {
|
||
| 216 | if(options.updateCompareKey) {
|
||
| 217 | currentTags[specName].forEach((cTag, index) => {
|
||
| 218 | cCompare[cTag[options.updateCompareKey]] = index |
||
| 219 | }) |
||
| 220 | |||
| 221 | } |
||
| 222 | if (!(rawTags[specName] instanceof Array)) {
|
||
| 223 | rawTags[specName] = [rawTags[specName]] |
||
| 224 | } |
||
| 225 | rawTags[specName].forEach((rTag) => {
|
||
| 226 | const comparison = cCompare[rTag[options.updateCompareKey]] |
||
| 227 | if (comparison !== undefined) {
|
||
| 228 | currentTags[specName][comparison] = rTag |
||
| 229 | } else {
|
||
| 230 | currentTags[specName].push(rTag) |
||
| 231 | } |
||
| 232 | }) |
||
| 233 | } else {
|
||
| 234 | currentTags[specName] = rawTags[specName] |
||
| 235 | } |
||
| 236 | }) |
||
| 237 | |||
| 238 | return currentTags |
||
| 239 | } |
||
| 240 | |||
| 241 | if(!fn || typeof fn !== 'function') {
|
||
| 242 | return this.write(updateFn(this.read(filebuffer, options)), filebuffer) |
||
| 243 | } |
||
| 244 | |||
| 245 | this.write(updateFn(this.read(filebuffer, options)), filebuffer, fn) |
||
| 246 | } |
||
| 247 | |||
| 248 | module.exports.getTagsFromBuffer = function(filebuffer, options) {
|
||
| 249 | let framePosition = ID3Util.getFramePosition(filebuffer) |
||
| 250 | if(framePosition === -1) {
|
||
| 251 | return this.getTagsFromFrames([], 3, options) |
||
| 252 | } |
||
| 253 | const frameSize = ID3Util.decodeSize(filebuffer.slice(framePosition + 6, framePosition + 10)) + 10 |
||
| 254 | let ID3Frame = Buffer.alloc(frameSize + 1) |
||
| 255 | filebuffer.copy(ID3Frame, 0, framePosition) |
||
| 256 | //ID3 version e.g. 3 if ID3v2.3.0 |
||
| 257 | let ID3Version = ID3Frame[3] |
||
| 258 | const tagFlags = ID3Util.parseTagHeaderFlags(ID3Frame) |
||
| 259 | let extendedHeaderOffset = 0 |
||
| 260 | if(tagFlags.extendedHeader) {
|
||
| 261 | if(ID3Version === 3) {
|
||
| 262 | extendedHeaderOffset = 4 + filebuffer.readUInt32BE(10) |
||
| 263 | } else if(ID3Version === 4) {
|
||
| 264 | extendedHeaderOffset = ID3Util.decodeSize(filebuffer.slice(10, 14)) |
||
| 265 | } |
||
| 266 | } |
||
| 267 | let ID3FrameBody = Buffer.alloc(frameSize - 10 - extendedHeaderOffset) |
||
| 268 | filebuffer.copy(ID3FrameBody, 0, framePosition + 10 + extendedHeaderOffset) |
||
| 269 | |||
| 270 | let frames = this.getFramesFromID3Body(ID3FrameBody, ID3Version, options) |
||
| 271 | |||
| 272 | return this.getTagsFromFrames(frames, ID3Version, options) |
||
| 273 | } |
||
| 274 | |||
| 275 | module.exports.getFramesFromID3Body = function(ID3FrameBody, ID3Version, options = {}) {
|
||
| 276 | let currentPosition = 0 |
||
| 277 | let frames = [] |
||
| 278 | if(!ID3FrameBody || !(ID3FrameBody instanceof Buffer)) {
|
||
| 279 | return frames |
||
| 280 | } |
||
| 281 | |||
| 282 | let identifierSize = 4 |
||
| 283 | let textframeHeaderSize = 10 |
||
| 284 | if(ID3Version === 2) {
|
||
| 285 | identifierSize = 3 |
||
| 286 | textframeHeaderSize = 6 |
||
| 287 | } |
||
| 288 | |||
| 289 | while(currentPosition < ID3FrameBody.length && ID3FrameBody[currentPosition] !== 0x00) {
|
||
| 290 | let bodyFrameHeader = Buffer.alloc(textframeHeaderSize) |
||
| 291 | ID3FrameBody.copy(bodyFrameHeader, 0, currentPosition) |
||
| 292 | |||
| 293 | let decodeSize = false |
||
| 294 | if(ID3Version === 4) {
|
||
| 295 | decodeSize = true |
||
| 296 | } |
||
| 297 | let bodyFrameSize = ID3Util.getFrameSize(bodyFrameHeader, decodeSize, ID3Version) |
||
| 298 | if(bodyFrameSize + 10 > (ID3FrameBody.length - currentPosition)) {
|
||
| 299 | break |
||
| 300 | } |
||
| 301 | const specName = bodyFrameHeader.toString('utf8', 0, identifierSize)
|
||
| 302 | if(options.exclude instanceof Array && options.exclude.includes(specName) || options.include instanceof Array && !options.include.includes(specName)) {
|
||
| 303 | currentPosition += bodyFrameSize + textframeHeaderSize |
||
| 304 | continue |
||
| 305 | } |
||
| 306 | const frameHeaderFlags = ID3Util.parseFrameHeaderFlags(bodyFrameHeader, ID3Version) |
||
| 307 | let bodyFrameBuffer = Buffer.alloc(bodyFrameSize) |
||
| 308 | ID3FrameBody.copy(bodyFrameBuffer, 0, currentPosition + textframeHeaderSize + (frameHeaderFlags.dataLengthIndicator ? 4 : 0)) |
||
| 309 | // Size of sub frame + its header |
||
| 310 | currentPosition += bodyFrameSize + textframeHeaderSize |
||
| 311 | frames.push({
|
||
| 312 | name: specName, |
||
| 313 | flags: frameHeaderFlags, |
||
| 314 | body: frameHeaderFlags.unsynchronisation ? ID3Util.processUnsynchronisedBuffer(bodyFrameBuffer) : bodyFrameBuffer |
||
| 315 | }) |
||
| 316 | } |
||
| 317 | |||
| 318 | return frames |
||
| 319 | } |
||
| 320 | |||
| 321 | module.exports.getTagsFromFrames = function(frames, ID3Version, options = {}) {
|
||
| 322 | let tags = { }
|
||
| 323 | let raw = { }
|
||
| 324 | |||
| 325 | frames.forEach((frame) => {
|
||
| 326 | const specName = ID3Version === 2 ? ID3Definitions.FRAME_IDENTIFIERS.v3[ID3Definitions.FRAME_INTERNAL_IDENTIFIERS.v2[frame.name]] : frame.name |
||
| 327 | const identifier = ID3Version === 2 ? ID3Definitions.FRAME_INTERNAL_IDENTIFIERS.v2[frame.name] : ID3Definitions.FRAME_INTERNAL_IDENTIFIERS.v3[frame.name] |
||
| 328 | |||
| 329 | if(!specName || !identifier || frame.flags.encryption) {
|
||
| 330 | return |
||
| 331 | } |
||
| 332 | |||
| 333 | if(frame.flags.compression) {
|
||
| 334 | if(frame.body.length < 5) {
|
||
| 335 | return |
||
| 336 | } |
||
| 337 | const inflatedSize = frame.body.readInt32BE() |
||
| 338 | /* |
||
| 339 | * ID3 spec defines that compression is stored in ZLIB format, but doesn't specify if header is present or not. |
||
| 340 | * ZLIB has a 2-byte header. |
||
| 341 | * 1. try if header + body decompression |
||
| 342 | * 2. else try if header is not stored (assume that all content is deflated "body") |
||
| 343 | * 3. else try if inflation works if the header is omitted (implementation dependent) |
||
| 344 | * */ |
||
| 345 | try {
|
||
| 346 | frame.body = zlib.inflateSync(frame.body.slice(4)) |
||
| 347 | } catch (e) {
|
||
| 348 | try {
|
||
| 349 | frame.body = zlib.inflateRawSync(frame.body.slice(4)) |
||
| 350 | } catch (e) {
|
||
| 351 | try {
|
||
| 352 | frame.body = zlib.inflateRawSync(frame.body.slice(6)) |
||
| 353 | } catch (e) {
|
||
| 354 | return |
||
| 355 | } |
||
| 356 | } |
||
| 357 | } |
||
| 358 | if(frame.body.length !== inflatedSize) {
|
||
| 359 | return |
||
| 360 | } |
||
| 361 | } |
||
| 362 | |||
| 363 | let decoded |
||
| 364 | if(ID3Frames[specName]) {
|
||
| 365 | decoded = ID3Frames[specName].read(frame.body, ID3Version, this) |
||
| 366 | } else if(specName.startsWith('T')) {
|
||
| 367 | decoded = ID3Frames.GENERIC_TEXT.read(frame.body, ID3Version) |
||
| 368 | } else if(specName.startsWith('W')) {
|
||
| 369 | decoded = ID3Frames.GENERIC_URL.read(frame.body, ID3Version) |
||
| 370 | } |
||
| 371 | |||
| 372 | if(decoded) {
|
||
| 373 | if(ID3Util.getSpecOptions(specName, ID3Version).multiple) {
|
||
| 374 | if(!options.onlyRaw) {
|
||
| 375 | if(!tags[identifier]) {
|
||
| 376 | tags[identifier] = [] |
||
| 377 | } |
||
| 378 | tags[identifier].push(decoded) |
||
| 379 | } |
||
| 380 | if(!options.noRaw) {
|
||
| 381 | if(!raw[specName]) {
|
||
| 382 | raw[specName] = [] |
||
| 383 | } |
||
| 384 | raw[specName].push(decoded) |
||
| 385 | } |
||
| 386 | } else {
|
||
| 387 | if(!options.onlyRaw) {
|
||
| 388 | tags[identifier] = decoded |
||
| 389 | } |
||
| 390 | if(!options.noRaw) {
|
||
| 391 | raw[specName] = decoded |
||
| 392 | } |
||
| 393 | } |
||
| 394 | } |
||
| 395 | }) |
||
| 396 | |||
| 397 | if(options.onlyRaw) {
|
||
| 398 | return raw |
||
| 399 | } |
||
| 400 | if(options.noRaw) {
|
||
| 401 | return tags |
||
| 402 | } |
||
| 403 | |||
| 404 | tags.raw = raw |
||
| 405 | return tags |
||
| 406 | } |
||
| 407 | |||
| 408 | /** |
||
| 409 | * Checks and removes already written ID3-Frames from a buffer |
||
| 410 | * @param data - Buffer |
||
| 411 | * @returns {boolean|Buffer}
|
||
| 412 | */ |
||
| 413 | module.exports.removeTagsFromBuffer = function(data) {
|
||
| 414 | let framePosition = ID3Util.getFramePosition(data) |
||
| 415 | |||
| 416 | if (framePosition === -1) {
|
||
| 417 | return data |
||
| 418 | } |
||
| 419 | |||
| 420 | let hSize = Buffer.from([data[framePosition + 6], data[framePosition + 7], data[framePosition + 8], data[framePosition + 9]]) |
||
| 421 | |||
| 422 | if ((hSize[0] | hSize[1] | hSize[2] | hSize[3]) & 0x80) {
|
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 423 | // Invalid tag size (msb not 0) |
||
| 424 | return false |
||
| 425 | } |
||
| 426 | |||
| 427 | if (data.length >= framePosition + 10) {
|
||
| 428 | const size = ID3Util.decodeSize(data.slice(framePosition + 6, framePosition + 10)) |
||
| 429 | return Buffer.concat([data.slice(0, framePosition), data.slice(framePosition + size + 10)]) |
||
| 430 | } |
||
| 431 | |||
| 432 | return data |
||
| 433 | } |
||
| 434 | |||
| 435 | /** |
||
| 436 | * Checks and removes already written ID3-Frames from a file |
||
| 437 | * @param filepath - Filepath to file |
||
| 438 | * @param fn - (optional) Function for async usage |
||
| 439 | * @returns {boolean|Error}
|
||
| 440 | */ |
||
| 441 | module.exports.removeTags = function(filepath, fn) {
|
||
| 442 | if(!fn || typeof fn !== 'function') {
|
||
| 443 | let data |
||
| 444 | try {
|
||
| 445 | data = fs.readFileSync(filepath) |
||
| 446 | } catch(e) {
|
||
| 447 | return e |
||
| 448 | } |
||
| 449 | |||
| 450 | let newData = this.removeTagsFromBuffer(data) |
||
| 451 | if(!newData) {
|
||
| 452 | return false |
||
| 453 | } |
||
| 454 | |||
| 455 | try {
|
||
| 456 | fs.writeFileSync(filepath, newData, 'binary') |
||
| 457 | } catch(e) {
|
||
| 458 | return e |
||
| 459 | } |
||
| 460 | |||
| 461 | return true |
||
| 462 | } |
||
| 463 | |||
| 464 | fs.readFile(filepath, function(err, data) {
|
||
| 465 | if(err) {
|
||
| 466 | fn(err) |
||
| 467 | } |
||
| 468 | |||
| 469 | let newData = this.removeTagsFromBuffer(data) |
||
| 470 | if(!newData) {
|
||
| 471 | fn(err) |
||
| 472 | return |
||
| 473 | } |
||
| 474 | |||
| 475 | fs.writeFile(filepath, newData, 'binary', function(err) {
|
||
| 476 | if(err) {
|
||
| 477 | fn(err) |
||
| 478 | } else {
|
||
| 479 | fn(false) |
||
| 480 | } |
||
| 481 | }) |
||
| 482 | }.bind(this)) |
||
| 483 | } |
||
| 484 | |||
| 485 | module.exports.Promise = {
|
||
| 486 | write: (tags, file) => {
|
||
| 487 | return new Promise((resolve, reject) => {
|
||
| 488 | this.write(tags, file, (err, ret) => {
|
||
| 489 | if(err) {
|
||
| 490 | reject(err) |
||
| 491 | } else {
|
||
| 492 | resolve(ret) |
||
| 493 | } |
||
| 494 | }) |
||
| 495 | }) |
||
| 496 | }, |
||
| 497 | update: (tags, file) => {
|
||
| 498 | return new Promise((resolve, reject) => {
|
||
| 499 | this.update(tags, file, (err, ret) => {
|
||
| 500 | if(err) {
|
||
| 501 | reject(err) |
||
| 502 | } else {
|
||
| 503 | resolve(ret) |
||
| 504 | } |
||
| 505 | }) |
||
| 506 | }) |
||
| 507 | }, |
||
| 508 | create: (tags) => {
|
||
| 509 | return new Promise((resolve) => {
|
||
| 510 | this.create(tags, (buffer) => {
|
||
| 511 | resolve(buffer) |
||
| 512 | }) |
||
| 513 | }) |
||
| 514 | }, |
||
| 515 | read: (file, options) => {
|
||
| 516 | return new Promise((resolve, reject) => {
|
||
| 517 | this.read(file, options, (err, ret) => {
|
||
| 518 | if(err) {
|
||
| 519 | reject(err) |
||
| 520 | } else {
|
||
| 521 | resolve(ret) |
||
| 522 | } |
||
| 523 | }) |
||
| 524 | }) |
||
| 525 | }, |
||
| 526 | removeTags: (filepath) => {
|
||
| 527 | return new Promise((resolve, reject) => {
|
||
| 528 | this.removeTags(filepath, (err) => {
|
||
| 529 | if(err) {
|
||
| 530 | reject(err) |
||
| 531 | } else {
|
||
| 532 | resolve() |
||
| 533 | } |
||
| 534 | }) |
||
| 535 | }) |
||
| 536 | } |
||
| 537 | } |
||
| 538 |