Comparing version 0.1.16 to 0.1.17
@@ -286,3 +286,52 @@ declare module "node-id3" { | ||
data: string | ||
}] | ||
}], | ||
chapter?: Array<{ | ||
elementID: string, | ||
endTimeMs: number, | ||
startTimeMs: number, | ||
tags?: { | ||
image?: Tags["image"], | ||
title?: string, | ||
}, | ||
}>, | ||
/** | ||
* The 'Commercial information' frame is a URL pointing at a webpage with information such as where the album can be bought. There may be more than one "WCOM" frame in a tag, but not with the same content. | ||
*/ | ||
commercialUrl?: Array<string>, | ||
/** | ||
* The 'Copyright/Legal information' frame is a URL pointing at a webpage where the terms of use and ownership of the file is described. | ||
*/ | ||
copyrightUrl?: string, | ||
/** | ||
* The 'Official audio file webpage' frame is a URL pointing at a file specific webpage. | ||
*/ | ||
fileUrl?: string, | ||
/** | ||
* The 'Official artist/performer webpage' frame is a URL pointing at the artists official webpage. There may be more than one "WOAR" frame in a tag if the audio contains more than one performer, but not with the same content. | ||
*/ | ||
artistUrl?: Array<string>, | ||
/** | ||
* The 'Official audio source webpage' frame is a URL pointing at the official webpage for the source of the audio file, e.g. a movie. | ||
*/ | ||
audioSourceUrl?: string, | ||
/** | ||
* The 'Official internet radio station homepage' contains a URL pointing at the homepage of the internet radio station. | ||
*/ | ||
radioStationUrl?: string, | ||
/** | ||
* The 'Payment' frame is a URL pointing at a webpage that will handle the process of paying for this file. | ||
*/ | ||
paymentUrl?: string, | ||
/** | ||
* The 'Publishers official webpage' frame is a URL pointing at the official wepage for the publisher. | ||
*/ | ||
publisherUrl?: string, | ||
/** | ||
* The 'User-defined URL link' frame is intended for URL links concerning the audiofile in a similar way to the other "W"-frames. There may be more than one "WXXX" frame in each tag, but only one with the same description. | ||
*/ | ||
userDefinedUrl?: Array<{ | ||
description: string, | ||
url: string | ||
}> | ||
} | ||
@@ -289,0 +338,0 @@ export function write(tags: Tags, filebuffer: Buffer): Buffer |
249
index.js
@@ -139,2 +139,9 @@ const fs = require('fs') | ||
multiple: true | ||
}, | ||
userDefinedUrl: { | ||
create: "createUserDefinedUrl", | ||
read: "readUserDefinedUrl", | ||
name: "WXXX", | ||
multiple: true, | ||
updateCompareKey: "description" | ||
} | ||
@@ -152,2 +159,74 @@ } | ||
/* | ||
** List of URL frames. | ||
** name => Frame ID | ||
** multiple => Whether multiple of this frame can exist | ||
** hasDescription => Whether this frame may include a description | ||
*/ | ||
const WFrames = { | ||
commercialUrl: { | ||
name: "WCOM", | ||
multiple: true | ||
}, | ||
copyrightUrl: { | ||
name: "WCOP" | ||
}, | ||
fileUrl: { | ||
name: "WOAF" | ||
}, | ||
artistUrl: { | ||
name: "WOAR", | ||
multiple: true | ||
}, | ||
audioSourceUrl: { | ||
name: "WOAS" | ||
}, | ||
radioStationUrl: { | ||
name: "WORS" | ||
}, | ||
paymentUrl: { | ||
name: "WPAY" | ||
}, | ||
publisherUrl: { | ||
name: "WPUB" | ||
} | ||
} | ||
/* | ||
4.3.1 WAF Official audio file webpage | ||
4.3.1 WAR Official artist/performer webpage | ||
4.3.1 WAS Official audio source webpage | ||
4.3.1 WCM Commercial information | ||
4.3.1 WCP Copyright/Legal information | ||
4.3.1 WPB Publishers official webpage | ||
4.3.2 WXX User defined URL link frame | ||
*/ | ||
const WFrames220 = { | ||
commercialUrl: { | ||
name: "WCM", | ||
multiple: true | ||
}, | ||
copyrightUrl: { | ||
name: "WCP" | ||
}, | ||
fileUrl: { | ||
name: "WAF" | ||
}, | ||
artistUrl: { | ||
name: "WAR", | ||
multiple: true | ||
}, | ||
audioSourceUrl: { | ||
name: "WAS" | ||
}, | ||
publisherUrl: { | ||
name: "WPB" | ||
}, | ||
userDefinedUrl: { | ||
name: "WXX", | ||
multiple: true, | ||
hasDescription: true | ||
} | ||
} | ||
/* | ||
** Officially available types of the picture frame | ||
@@ -273,2 +352,14 @@ */ | ||
frame = this.createTextFrame(specName, tags[tag]) | ||
} else if (WFrames[tag] || Object.keys(WFrames).map(i => WFrames[i]).map(x => x.name).indexOf(tag) !== -1) { | ||
let specName = WFrames[tag] ? WFrames[tag].name : tag | ||
let multiple = WFrames[Object.keys(WFrames)[Object.keys(WFrames).map(i => WFrames[i]).map(x => x.name).indexOf(specName)]].multiple | ||
if(multiple && tags[tag] instanceof Array && tags[tag].length > 0) { | ||
frame = Buffer.alloc(0); | ||
// deduplicate array | ||
for(var url of [...new Set(tags[tag])]) { | ||
frame = Buffer.concat([frame, this.createUrlFrame(specName, url)]) | ||
} | ||
} else { | ||
frame = this.createUrlFrame(specName, tags[tag]) | ||
} | ||
} else if (SFrames[tag]) { // Check if Alias of special frame | ||
@@ -339,2 +430,6 @@ let createFrameFunction = SFrames[tag].create | ||
// if js name passed (WF) | ||
} else if(WFrames[tagKey]) { | ||
rawTags[WFrames[tagKey].name] = tags[tagKey] | ||
// if js name passed (SF) | ||
@@ -348,2 +443,6 @@ } else if(SFrames[tagKey]) { | ||
// if raw name passed (WF) | ||
} else if(Object.keys(WFrames).map(i => WFrames[i]).map(x => x.name).indexOf(tagKey) !== -1) { | ||
rawTags[tagKey] = tags[tagKey] | ||
// if raw name passed (SF) | ||
@@ -360,3 +459,3 @@ } else if(Object.keys(SFrames).map(i => SFrames[i]).map(x => x.name).indexOf(tagKey) !== -1) { | ||
if(SFrames[SRawToNameMap[tag]] && SFrames[SRawToNameMap[tag]].multiple && currentTags[tag] && rawTags[tag]) { | ||
cCompare = {} | ||
const cCompare = {} | ||
currentTags[tag].forEach((cTag, index) => { | ||
@@ -389,3 +488,3 @@ cCompare[cTag[SFrames[SRawToNameMap[tag]].updateCompareKey]] = index | ||
if(SFrames[SRawToNameMap[tag]] && SFrames[SRawToNameMap[tag]].multiple && currentTags[tag] && rawTags[tag]) { | ||
cCompare = {} | ||
const cCompare = {} | ||
currentTags[tag].forEach((cTag, index) => { | ||
@@ -493,2 +592,22 @@ cCompare[cTag[SFrames[SRawToNameMap[tag]].updateCompareKey]] = index | ||
}) | ||
} else if (frame.name[0] === "W" && frame.name !== "WXXX") { | ||
let versionFrames = WFrames | ||
if(ID3Version == 2) { | ||
versionFrames = WFramesV220 | ||
} | ||
Object.keys(versionFrames).map(function(key) { | ||
if(versionFrames[key].name === frame.name) { | ||
// URL fields contain no encoding byte and are always ISO-8859-1 as per spec | ||
let decoded = iconv.decode(frame.body, "ISO-8859-1").replace(/\0/g, "") | ||
if(versionFrames[key].multiple) { | ||
if(!tags[key]) tags[key] = [] | ||
if(!tags.raw[frame.name]) tags.raw[frame.name] = [] | ||
tags.raw[frame.name].push(decoded) | ||
tags[key].push(decoded) | ||
} else { | ||
tags.raw[frame.name] = decoded | ||
tags[key] = decoded | ||
} | ||
} | ||
}) | ||
} else { | ||
@@ -690,2 +809,25 @@ let versionFrames = SFrames | ||
/* | ||
** Create URL frame | ||
** specName => string (ID) | ||
** text => string (body) | ||
*/ | ||
NodeID3.prototype.createUrlFrame = function(specName, text) { | ||
if(!specName || !text) { | ||
return null | ||
} | ||
let encoded = iconv.encode(text, "ISO-8859-1") | ||
let buffer = Buffer.alloc(10) | ||
buffer.fill(0) | ||
buffer.write(specName, 0) // ID of the specified frame | ||
buffer.writeUInt32BE((encoded).length + 1, 4) // Size of frame (string length + encoding byte) | ||
let encBuffer = Buffer.alloc(1) // Encoding (URLs are always ISO-8859-1) | ||
encBuffer.fill(0) // ISO-8859-1 | ||
var contentBuffer = Buffer.from(encoded, 'binary') // Text -> Binary encoding for ISO-8859-1 | ||
return Buffer.concat([buffer, encBuffer, contentBuffer]) | ||
} | ||
/* | ||
** data => string || buffer | ||
@@ -994,3 +1136,3 @@ */ | ||
NodeID3.prototype.createUserDefinedText = function(userDefinedText, recursiveBuffer) { | ||
udt = userDefinedText || {} | ||
let udt = userDefinedText || {} | ||
if(udt instanceof Array && udt.length > 0) { | ||
@@ -1192,12 +1334,12 @@ if(!recursiveBuffer) { | ||
/* | ||
** chapter => object|array { | ||
** startTimeMs: number, | ||
** endTimeMs: number, | ||
** startOffsetBytes: number, | ||
** endOffsetBytes: number, | ||
** tags: object | ||
** } | ||
**/ | ||
NodeID3.prototype.createChapterFrame = function(chapter) { | ||
/** | ||
* @typedef {Object} Chapter | ||
* @property {string} elementID | ||
* @property {number} startTimeMs | ||
* @property {number} endTimeMs | ||
* @property {number} [startOffsetBytes] | ||
* @property {number} [endOffsetBytes] | ||
* @property {object} [tags] | ||
*/ | ||
NodeID3.prototype.createChapterFrame = function (/** @type Chapter[] | Chapter */chapter) { | ||
if(chapter instanceof Array && chapter.length > 0) { | ||
@@ -1218,3 +1360,3 @@ let frames = [] | ||
NodeID3.prototype.createChapterFrameHelper = function(chapter, id) { | ||
if(!chapter || !chapter.elementID || !chapter.startTimeMs || !chapter.endTimeMs) { | ||
if(!chapter || !chapter.elementID || typeof chapter.startTimeMs === "undefined" || !chapter.endTimeMs) { | ||
return null | ||
@@ -1228,12 +1370,12 @@ } | ||
let startTimeBuffer = Buffer.alloc(4) | ||
startTimeBuffer.writeUInt32BE(chapter.startTimeMs) | ||
startTimeBuffer.writeUInt32BE(chapter.startTimeMs, 0) | ||
let endTimeBuffer = Buffer.alloc(4) | ||
endTimeBuffer.writeUInt32BE(chapter.endTimeMs) | ||
endTimeBuffer.writeUInt32BE(chapter.endTimeMs, 0) | ||
let startOffsetBytesBuffer = Buffer.alloc(4, 0xFF) | ||
if(chapter.startOffsetBytes) { | ||
startOffsetBytesBuffer.writeUInt32BE(chapter.startOffsetBytes) | ||
startOffsetBytesBuffer.writeUInt32BE(chapter.startOffsetBytes, 0) | ||
} | ||
let endOffsetBytesBuffer = Buffer.alloc(4, 0xFF) | ||
if(chapter.endOffsetBytes) { | ||
endOffsetBytesBuffer.writeUInt32BE(chapter.endOffsetBytes) | ||
endOffsetBytesBuffer.writeUInt32BE(chapter.endOffsetBytes, 0) | ||
} | ||
@@ -1245,3 +1387,3 @@ | ||
} | ||
framesBuffer = frames ? Buffer.concat(frames) : Buffer.alloc(0) | ||
const framesBuffer = frames ? Buffer.concat(frames) : Buffer.alloc(0) | ||
@@ -1270,6 +1412,6 @@ header.writeUInt32BE(elementIDBuffer.length + 16 + framesBuffer.length, 4) | ||
tags.endTimeMs = frame.readUInt32BE(endOfElementIDString + 5) | ||
if(frame.readUInt32BE(endOfElementIDString + 9) != Buffer.alloc(4, 0xff).readUInt32BE()) { | ||
if(frame.readUInt32BE(endOfElementIDString + 9) != Buffer.alloc(4, 0xff).readUInt32BE(0)) { | ||
tags.startOffsetBytes = frame.readUInt32BE(endOfElementIDString + 9) | ||
} | ||
if(frame.readUInt32BE(endOfElementIDString + 13) != Buffer.alloc(4, 0xff).readUInt32BE()) { | ||
if(frame.readUInt32BE(endOfElementIDString + 13) != Buffer.alloc(4, 0xff).readUInt32BE(0)) { | ||
tags.endOffsetBytes = frame.readUInt32BE(endOfElementIDString + 13) | ||
@@ -1284,2 +1426,67 @@ } | ||
return tags | ||
} | ||
NodeID3.prototype.createUserDefinedUrl = function(userDefinedUrl, recursiveBuffer) { | ||
let udu = userDefinedUrl || {} | ||
if(udu instanceof Array && udu.length > 0) { | ||
if(!recursiveBuffer) { | ||
// Don't alter passed array value! | ||
userDefinedUrl = userDefinedUrl.slice(0) | ||
} | ||
udu = userDefinedUrl.pop() | ||
} | ||
if(udu && udu.description) { | ||
// Create frame header | ||
let buffer = Buffer.alloc(10) | ||
buffer.fill(0) | ||
buffer.write("WXXX", 0) // Write header ID | ||
let encodingBuffer = this.createTextEncoding(0x01) | ||
let descriptorBuffer = this.createContentDescriptor(udu.description, 0x01, true) | ||
let urlBuffer = this.createText(udu.url, 0x00, false) | ||
buffer.writeUInt32BE(encodingBuffer.length + descriptorBuffer.length + urlBuffer.length, 4) | ||
if(!recursiveBuffer) { | ||
recursiveBuffer = Buffer.concat([buffer, encodingBuffer, descriptorBuffer, urlBuffer]) | ||
} else { | ||
recursiveBuffer = Buffer.concat([recursiveBuffer, buffer, encodingBuffer, descriptorBuffer, urlBuffer]) | ||
} | ||
} | ||
if(userDefinedUrl instanceof Array && userDefinedUrl.length > 0) { | ||
return this.createUserDefinedUrl(userDefinedUrl, recursiveBuffer) | ||
} else { | ||
return recursiveBuffer | ||
} | ||
} | ||
NodeID3.prototype.readUserDefinedUrl = function(frame) { | ||
let tags = {} | ||
if(!frame) { | ||
return tags | ||
} | ||
if(frame[0] == 0x00) { | ||
tags = { | ||
description: iconv.decode(frame, "ISO-8859-1").substring(1, frame.indexOf(0x00, 1)).replace(/\0/g, ""), | ||
url: iconv.decode(frame, "ISO-8859-1").substring(frame.indexOf(0x00, 1) + 1).replace(/\0/g, "") | ||
} | ||
} else if(frame[0] == 0x01) { | ||
let descriptorEscape = 0 | ||
while(frame[descriptorEscape] !== undefined && frame[descriptorEscape] !== 0x00 || frame[descriptorEscape + 1] !== 0x00 || frame[descriptorEscape + 2] === 0x00) { | ||
descriptorEscape++ | ||
} | ||
if(frame[descriptorEscape] === undefined) { | ||
return tags | ||
} | ||
let description = frame.slice(1, descriptorEscape) | ||
let value = frame.slice(descriptorEscape + 2) | ||
tags = { | ||
description: iconv.decode(description, "utf16").replace(/\0/g, ""), | ||
url: iconv.decode(value, "ISO-8859-1").replace(/\0/g, "") | ||
} | ||
} | ||
return tags | ||
} |
{ | ||
"name": "node-id3", | ||
"version": "0.1.16", | ||
"version": "0.1.17", | ||
"description": "Pure JavaScript ID3 Tag writer/reader", | ||
@@ -35,4 +35,4 @@ "author": "Jan Metzger <jan.metzger@gmx.net>", | ||
"dependencies": { | ||
"iconv-lite": "^0.4.15" | ||
"iconv-lite": "0.5.1" | ||
} | ||
} |
@@ -174,2 +174,14 @@ # node-id3 | ||
}] | ||
commercialUrl: ["commercialurl.com"], // array or single string | ||
copyrightUrl: "example.com", | ||
fileUrl: "example.com", | ||
artistUrl: ["example.com"], // array or single string | ||
audioSourceUrl: "example.com", | ||
radioStationUrl: "example.com", | ||
paymentUrl: "example.com", | ||
publisherUrl: "example.com", | ||
userDefinedUrl: [{ | ||
description: "URL description" | ||
url: "https://example.com/" | ||
}] // array or single object | ||
``` | ||
@@ -225,2 +237,11 @@ | ||
chapter "CHAP" | ||
commercialUrl "WCOM" | ||
copyrightUrl "WCOP" | ||
fileUrl "WOAF" | ||
artistUrl "WOAR" | ||
audioSourceUrl "WOAS" | ||
radioStationUrl "WORS" | ||
paymentUrl "WPAY" | ||
publisherUrl "WPUB" | ||
userDefinedUrl "WXXX" | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
77883
1775
245
+ Addediconv-lite@0.5.1(transitive)
- Removediconv-lite@0.4.24(transitive)
Updatediconv-lite@0.5.1