mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-07-25 01:35:33 +02:00
.devcontainer
.github
.vscode
build
client
images
server
controllers
controllers2
db
finders
libs
archiver
async
bcryptjs
busboy
commandLineArgs
css
dateAndTime
expressFileupload
expressRateLimit
fastSort
fluentFfmpeg
fsExtra
imageType
isexe
jsonwebtoken
jwa
jws
lodash.once
ms
nodeCron
nodeFfprobe
nodeStreamZip
readChunk
recursiveReaddirAsync
requestIp
rss
sanitizeHtml
streamsearch
uaParser
universalify
watcher
which
xml
LICENSE
escapeForXML.js
index.js
managers
models
objects
providers
routers
routes
scanner
utils
Auth.js
Database.js
Logger.js
Server.js
SocketAuthority.js
Watcher.js
.dockerignore
.gitattributes
.gitignore
Dockerfile
LICENSE
docker-compose.yml
docker-template.xml
index.js
package-lock.json
package.json
prod.js
readme.md
286 lines
6.1 KiB
JavaScript
286 lines
6.1 KiB
JavaScript
// node-xml
|
|
// SOURCE: https://github.com/dylang/node-xml
|
|
// LICENSE: https://github.com/dylang/node-xml/blob/master/LICENSE
|
|
|
|
var escapeForXML = require('./escapeForXML');
|
|
var Stream = require('stream').Stream;
|
|
|
|
var DEFAULT_INDENT = ' ';
|
|
|
|
function xml(input, options) {
|
|
|
|
if (typeof options !== 'object') {
|
|
options = {
|
|
indent: options
|
|
};
|
|
}
|
|
|
|
var stream = options.stream ? new Stream() : null,
|
|
output = "",
|
|
interrupted = false,
|
|
indent = !options.indent ? ''
|
|
: options.indent === true ? DEFAULT_INDENT
|
|
: options.indent,
|
|
instant = true;
|
|
|
|
|
|
function delay(func) {
|
|
if (!instant) {
|
|
func();
|
|
} else {
|
|
process.nextTick(func);
|
|
}
|
|
}
|
|
|
|
function append(interrupt, out) {
|
|
if (out !== undefined) {
|
|
output += out;
|
|
}
|
|
if (interrupt && !interrupted) {
|
|
stream = stream || new Stream();
|
|
interrupted = true;
|
|
}
|
|
if (interrupt && interrupted) {
|
|
var data = output;
|
|
delay(function () { stream.emit('data', data) });
|
|
output = "";
|
|
}
|
|
}
|
|
|
|
function add(value, last) {
|
|
format(append, resolve(value, indent, indent ? 1 : 0), last);
|
|
}
|
|
|
|
function end() {
|
|
if (stream) {
|
|
var data = output;
|
|
delay(function () {
|
|
stream.emit('data', data);
|
|
stream.emit('end');
|
|
stream.readable = false;
|
|
stream.emit('close');
|
|
});
|
|
}
|
|
}
|
|
|
|
function addXmlDeclaration(declaration) {
|
|
var encoding = declaration.encoding || 'UTF-8',
|
|
attr = { version: '1.0', encoding: encoding };
|
|
|
|
if (declaration.standalone) {
|
|
attr.standalone = declaration.standalone
|
|
}
|
|
|
|
add({ '?xml': { _attr: attr } });
|
|
output = output.replace('/>', '?>');
|
|
}
|
|
|
|
// disable delay delayed
|
|
delay(function () { instant = false });
|
|
|
|
if (options.declaration) {
|
|
addXmlDeclaration(options.declaration);
|
|
}
|
|
|
|
if (input && input.forEach) {
|
|
input.forEach(function (value, i) {
|
|
var last;
|
|
if (i + 1 === input.length)
|
|
last = end;
|
|
add(value, last);
|
|
});
|
|
} else {
|
|
add(input, end);
|
|
}
|
|
|
|
if (stream) {
|
|
stream.readable = true;
|
|
return stream;
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function element(/*input, …*/) {
|
|
var input = Array.prototype.slice.call(arguments),
|
|
self = {
|
|
_elem: resolve(input)
|
|
};
|
|
|
|
self.push = function (input) {
|
|
if (!this.append) {
|
|
throw new Error("not assigned to a parent!");
|
|
}
|
|
var that = this;
|
|
var indent = this._elem.indent;
|
|
format(this.append, resolve(
|
|
input, indent, this._elem.icount + (indent ? 1 : 0)),
|
|
function () { that.append(true) });
|
|
};
|
|
|
|
self.close = function (input) {
|
|
if (input !== undefined) {
|
|
this.push(input);
|
|
}
|
|
if (this.end) {
|
|
this.end();
|
|
}
|
|
};
|
|
|
|
return self;
|
|
}
|
|
|
|
function create_indent(character, count) {
|
|
return (new Array(count || 0).join(character || ''))
|
|
}
|
|
|
|
function resolve(data, indent, indent_count) {
|
|
indent_count = indent_count || 0;
|
|
var indent_spaces = create_indent(indent, indent_count);
|
|
var name;
|
|
var values = data;
|
|
var interrupt = false;
|
|
|
|
if (typeof data === 'object') {
|
|
var keys = Object.keys(data);
|
|
name = keys[0];
|
|
values = data[name];
|
|
|
|
if (values && values._elem) {
|
|
values._elem.name = name;
|
|
values._elem.icount = indent_count;
|
|
values._elem.indent = indent;
|
|
values._elem.indents = indent_spaces;
|
|
values._elem.interrupt = values;
|
|
return values._elem;
|
|
}
|
|
}
|
|
|
|
var attributes = [],
|
|
content = [];
|
|
|
|
var isStringContent;
|
|
|
|
function get_attributes(obj) {
|
|
var keys = Object.keys(obj);
|
|
keys.forEach(function (key) {
|
|
attributes.push(attribute(key, obj[key]));
|
|
});
|
|
}
|
|
|
|
switch (typeof values) {
|
|
case 'object':
|
|
if (values === null) break;
|
|
|
|
if (values._attr) {
|
|
get_attributes(values._attr);
|
|
}
|
|
|
|
if (values._cdata) {
|
|
content.push(
|
|
('<![CDATA[' + values._cdata).replace(/\]\]>/g, ']]]]><![CDATA[>') + ']]>'
|
|
);
|
|
}
|
|
|
|
if (values.forEach) {
|
|
isStringContent = false;
|
|
content.push('');
|
|
values.forEach(function (value) {
|
|
if (typeof value == 'object') {
|
|
var _name = Object.keys(value)[0];
|
|
|
|
if (_name == '_attr') {
|
|
get_attributes(value._attr);
|
|
} else {
|
|
content.push(resolve(
|
|
value, indent, indent_count + 1));
|
|
}
|
|
} else {
|
|
//string
|
|
content.pop();
|
|
isStringContent = true;
|
|
content.push(escapeForXML(value));
|
|
}
|
|
|
|
});
|
|
if (!isStringContent) {
|
|
content.push('');
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
//string
|
|
content.push(escapeForXML(values));
|
|
|
|
}
|
|
|
|
return {
|
|
name: name,
|
|
interrupt: interrupt,
|
|
attributes: attributes,
|
|
content: content,
|
|
icount: indent_count,
|
|
indents: indent_spaces,
|
|
indent: indent
|
|
};
|
|
}
|
|
|
|
function format(append, elem, end) {
|
|
|
|
if (typeof elem != 'object') {
|
|
return append(false, elem);
|
|
}
|
|
|
|
var len = elem.interrupt ? 1 : elem.content.length;
|
|
|
|
function proceed() {
|
|
while (elem.content.length) {
|
|
var value = elem.content.shift();
|
|
|
|
if (value === undefined) continue;
|
|
if (interrupt(value)) return;
|
|
|
|
format(append, value);
|
|
}
|
|
|
|
append(false, (len > 1 ? elem.indents : '')
|
|
+ (elem.name ? '</' + elem.name + '>' : '')
|
|
+ (elem.indent && !end ? '\n' : ''));
|
|
|
|
if (end) {
|
|
end();
|
|
}
|
|
}
|
|
|
|
function interrupt(value) {
|
|
if (value.interrupt) {
|
|
value.interrupt.append = append;
|
|
value.interrupt.end = proceed;
|
|
value.interrupt = false;
|
|
append(true);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
append(false, elem.indents
|
|
+ (elem.name ? '<' + elem.name : '')
|
|
+ (elem.attributes.length ? ' ' + elem.attributes.join(' ') : '')
|
|
+ (len ? (elem.name ? '>' : '') : (elem.name ? '/>' : ''))
|
|
+ (elem.indent && len > 1 ? '\n' : ''));
|
|
|
|
if (!len) {
|
|
return append(false, elem.indent ? '\n' : '');
|
|
}
|
|
|
|
if (!interrupt(elem)) {
|
|
proceed();
|
|
}
|
|
}
|
|
|
|
function attribute(key, value) {
|
|
return key + '=' + '"' + escapeForXML(value) + '"';
|
|
}
|
|
|
|
module.exports = xml;
|
|
module.exports.element = module.exports.Element = element; |