mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-05-24 01:13:00 -04:00
Update:Remove rss feed dependencies add node-xml lib
This commit is contained in:
parent
46fc89e247
commit
03bffb725a
83
package-lock.json
generated
83
package-lock.json
generated
@ -5,7 +5,7 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "2.0.17",
|
||||
"version": "2.0.20",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"archiver": "^5.3.0",
|
||||
@ -26,7 +26,6 @@
|
||||
"node-cron": "^3.0.0",
|
||||
"node-ffprobe": "^3.0.0",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"podcast": "^2.0.0",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"read-chunk": "^3.1.0",
|
||||
"recursive-readdir-async": "^1.1.8",
|
||||
@ -1560,14 +1559,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/podcast": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/podcast/-/podcast-2.0.0.tgz",
|
||||
"integrity": "sha512-1NZe7cVabfkcMe39yOOhBMJrXC6OROLOIBkfEPayiJL59ncyJmOeO5bxolSCSGroho8jQ0zURMczyICI1U/xbw==",
|
||||
"dependencies": {
|
||||
"rss": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
@ -1713,34 +1704,6 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/rss": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz",
|
||||
"integrity": "sha1-UKFpiHYTgTOnT5oF0r3I240nqSE=",
|
||||
"dependencies": {
|
||||
"mime-types": "2.1.13",
|
||||
"xml": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/rss/node_modules/mime-db": {
|
||||
"version": "1.25.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz",
|
||||
"integrity": "sha1-wY29fHOl2/b0SgJNwNFloeexw5I=",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/rss/node_modules/mime-types": {
|
||||
"version": "2.1.13",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz",
|
||||
"integrity": "sha1-4HqqnGxrmnyjASxpADrSWjnpKog=",
|
||||
"dependencies": {
|
||||
"mime-db": "~1.25.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@ -2072,11 +2035,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
|
||||
"integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
|
||||
},
|
||||
"node_modules/xml2js": {
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
|
||||
@ -3271,14 +3229,6 @@
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
|
||||
},
|
||||
"podcast": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/podcast/-/podcast-2.0.0.tgz",
|
||||
"integrity": "sha512-1NZe7cVabfkcMe39yOOhBMJrXC6OROLOIBkfEPayiJL59ncyJmOeO5bxolSCSGroho8jQ0zURMczyICI1U/xbw==",
|
||||
"requires": {
|
||||
"rss": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
@ -3391,30 +3341,6 @@
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
|
||||
},
|
||||
"rss": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz",
|
||||
"integrity": "sha1-UKFpiHYTgTOnT5oF0r3I240nqSE=",
|
||||
"requires": {
|
||||
"mime-types": "2.1.13",
|
||||
"xml": "1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"mime-db": {
|
||||
"version": "1.25.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz",
|
||||
"integrity": "sha1-wY29fHOl2/b0SgJNwNFloeexw5I="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.13",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz",
|
||||
"integrity": "sha1-4HqqnGxrmnyjASxpADrSWjnpKog=",
|
||||
"requires": {
|
||||
"mime-db": "~1.25.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@ -3654,11 +3580,6 @@
|
||||
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
|
||||
"requires": {}
|
||||
},
|
||||
"xml": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
|
||||
"integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
|
||||
},
|
||||
"xml2js": {
|
||||
"version": "0.4.23",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
|
||||
@ -3684,4 +3605,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,11 +45,10 @@
|
||||
"node-cron": "^3.0.0",
|
||||
"node-ffprobe": "^3.0.0",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"podcast": "^2.0.0",
|
||||
"proper-lockfile": "^4.1.2",
|
||||
"read-chunk": "^3.1.0",
|
||||
"recursive-readdir-async": "^1.1.8",
|
||||
"socket.io": "^4.4.1",
|
||||
"xml2js": "^0.4.23"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
193
server/libs/rss/index.js
Normal file
193
server/libs/rss/index.js
Normal file
@ -0,0 +1,193 @@
|
||||
// node-rss
|
||||
// SOURCE: https://github.com/dylang/node-rss
|
||||
// LICENSE: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
'use strict';
|
||||
|
||||
var mime = require('mime-types');
|
||||
var xml = require('../xml');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
function ifTruePush(bool, array, data) {
|
||||
if (bool) {
|
||||
array.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
function ifTruePushArray(bool, array, dataArray) {
|
||||
if (!bool) {
|
||||
return;
|
||||
}
|
||||
|
||||
dataArray.forEach(function (item) {
|
||||
ifTruePush(item, array, item);
|
||||
});
|
||||
}
|
||||
|
||||
function getSize(filename) {
|
||||
if (typeof fs === 'undefined') {
|
||||
return 0;
|
||||
}
|
||||
return fs.statSync(filename).size;
|
||||
}
|
||||
|
||||
function generateXML(data) {
|
||||
|
||||
var channel = [];
|
||||
channel.push({ title: { _cdata: data.title } });
|
||||
channel.push({ description: { _cdata: data.description || data.title } });
|
||||
channel.push({ link: data.site_url || 'http://github.com/dylang/node-rss' });
|
||||
// image_url set?
|
||||
if (data.image_url) {
|
||||
channel.push({ image: [{ url: data.image_url }, { title: data.title }, { link: data.site_url }] });
|
||||
}
|
||||
channel.push({ generator: data.generator });
|
||||
channel.push({ lastBuildDate: new Date().toUTCString() });
|
||||
|
||||
ifTruePush(data.feed_url, channel, { 'atom:link': { _attr: { href: data.feed_url, rel: 'self', type: 'application/rss+xml' } } });
|
||||
ifTruePush(data.author, channel, { 'author': { _cdata: data.author } });
|
||||
ifTruePush(data.pubDate, channel, { 'pubDate': new Date(data.pubDate).toGMTString() });
|
||||
ifTruePush(data.copyright, channel, { 'copyright': { _cdata: data.copyright } });
|
||||
ifTruePush(data.language, channel, { 'language': { _cdata: data.language } });
|
||||
ifTruePush(data.managingEditor, channel, { 'managingEditor': { _cdata: data.managingEditor } });
|
||||
ifTruePush(data.webMaster, channel, { 'webMaster': { _cdata: data.webMaster } });
|
||||
ifTruePush(data.docs, channel, { 'docs': data.docs });
|
||||
ifTruePush(data.ttl, channel, { 'ttl': data.ttl });
|
||||
ifTruePush(data.hub, channel, { 'atom:link': { _attr: { href: data.hub, rel: 'hub' } } });
|
||||
|
||||
if (data.categories) {
|
||||
data.categories.forEach(function (category) {
|
||||
ifTruePush(category, channel, { category: { _cdata: category } });
|
||||
});
|
||||
}
|
||||
|
||||
ifTruePushArray(data.custom_elements, channel, data.custom_elements);
|
||||
|
||||
data.items.forEach(function (item) {
|
||||
var item_values = [
|
||||
{ title: { _cdata: item.title } }
|
||||
];
|
||||
ifTruePush(item.description, item_values, { description: { _cdata: item.description } });
|
||||
ifTruePush(item.url, item_values, { link: item.url });
|
||||
ifTruePush(item.link || item.guid || item.title, item_values, { guid: [{ _attr: { isPermaLink: !item.guid && !!item.url } }, item.guid || item.url || item.title] });
|
||||
|
||||
item.categories.forEach(function (category) {
|
||||
ifTruePush(category, item_values, { category: { _cdata: category } });
|
||||
});
|
||||
|
||||
ifTruePush(item.author || data.author, item_values, { 'dc:creator': { _cdata: item.author || data.author } });
|
||||
ifTruePush(item.date, item_values, { pubDate: new Date(item.date).toGMTString() });
|
||||
|
||||
//Set GeoRSS to true if lat and long are set
|
||||
data.geoRSS = data.geoRSS || (item.lat && item.long);
|
||||
ifTruePush(item.lat, item_values, { 'geo:lat': item.lat });
|
||||
ifTruePush(item.long, item_values, { 'geo:long': item.long });
|
||||
|
||||
if (item.enclosure && item.enclosure.url) {
|
||||
if (item.enclosure.file) {
|
||||
item_values.push({
|
||||
enclosure: {
|
||||
_attr: {
|
||||
url: item.enclosure.url,
|
||||
length: item.enclosure.size || getSize(item.enclosure.file),
|
||||
type: item.enclosure.type || mime.lookup(item.enclosure.file)
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
item_values.push({
|
||||
enclosure: {
|
||||
_attr: {
|
||||
url: item.enclosure.url,
|
||||
length: item.enclosure.size || 0,
|
||||
type: item.enclosure.type || mime.lookup(item.enclosure.url)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ifTruePushArray(item.custom_elements, item_values, item.custom_elements);
|
||||
|
||||
channel.push({ item: item_values });
|
||||
|
||||
});
|
||||
|
||||
//set up the attributes for the RSS feed.
|
||||
var _attr = {
|
||||
'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
|
||||
'xmlns:content': 'http://purl.org/rss/1.0/modules/content/',
|
||||
'xmlns:atom': 'http://www.w3.org/2005/Atom',
|
||||
version: '2.0'
|
||||
};
|
||||
|
||||
Object.keys(data.custom_namespaces).forEach(function (name) {
|
||||
_attr['xmlns:' + name] = data.custom_namespaces[name];
|
||||
});
|
||||
|
||||
//only add namespace if GeoRSS is true
|
||||
if (data.geoRSS) {
|
||||
_attr['xmlns:geo'] = 'http://www.w3.org/2003/01/geo/wgs84_pos#';
|
||||
}
|
||||
|
||||
return {
|
||||
rss: [
|
||||
{ _attr: _attr },
|
||||
{ channel: channel }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function RSS(options, items) {
|
||||
options = options || {};
|
||||
|
||||
this.title = options.title || 'Untitled RSS Feed';
|
||||
this.description = options.description || '';
|
||||
this.generator = options.generator || 'RSS for Node';
|
||||
this.feed_url = options.feed_url;
|
||||
this.site_url = options.site_url;
|
||||
this.image_url = options.image_url;
|
||||
this.author = options.author;
|
||||
this.categories = options.categories;
|
||||
this.pubDate = options.pubDate;
|
||||
this.hub = options.hub;
|
||||
this.docs = options.docs;
|
||||
this.copyright = options.copyright;
|
||||
this.language = options.language;
|
||||
this.managingEditor = options.managingEditor;
|
||||
this.webMaster = options.webMaster;
|
||||
this.ttl = options.ttl;
|
||||
//option to return feed as GeoRSS is set automatically if feed.lat/long is used
|
||||
this.geoRSS = options.geoRSS || false;
|
||||
this.custom_namespaces = options.custom_namespaces || {};
|
||||
this.custom_elements = options.custom_elements || [];
|
||||
this.items = items || [];
|
||||
|
||||
this.item = function (options) {
|
||||
options = options || {};
|
||||
var item = {
|
||||
title: options.title || 'No title',
|
||||
description: options.description || '',
|
||||
url: options.url,
|
||||
guid: options.guid,
|
||||
categories: options.categories || [],
|
||||
author: options.author,
|
||||
date: options.date,
|
||||
lat: options.lat,
|
||||
long: options.long,
|
||||
enclosure: options.enclosure || false,
|
||||
custom_elements: options.custom_elements || []
|
||||
};
|
||||
|
||||
this.items.push(item);
|
||||
return this;
|
||||
};
|
||||
|
||||
this.xml = function (indent) {
|
||||
return '<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
xml(generateXML(this), indent);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = RSS;
|
17
server/libs/xml/escapeForXML.js
Normal file
17
server/libs/xml/escapeForXML.js
Normal file
@ -0,0 +1,17 @@
|
||||
var XML_CHARACTER_MAP = {
|
||||
'&': '&',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'<': '<',
|
||||
'>': '>'
|
||||
};
|
||||
|
||||
function escapeForXML(string) {
|
||||
return string && string.replace
|
||||
? string.replace(/([&"<>'])/g, function (str, item) {
|
||||
return XML_CHARACTER_MAP[item];
|
||||
})
|
||||
: string;
|
||||
}
|
||||
|
||||
module.exports = escapeForXML;
|
286
server/libs/xml/index.js
Normal file
286
server/libs/xml/index.js
Normal file
@ -0,0 +1,286 @@
|
||||
// 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;
|
@ -1,7 +1,5 @@
|
||||
const Path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const date = require('date-and-time')
|
||||
const { Podcast } = require('podcast')
|
||||
const Feed = require('../objects/Feed')
|
||||
const Logger = require('../Logger')
|
||||
|
||||
@ -35,7 +33,7 @@ class RssFeedManager {
|
||||
res.sendStatus(404)
|
||||
return
|
||||
}
|
||||
// var xml = feedData.feed.buildXml()
|
||||
|
||||
var xml = feed.buildXml()
|
||||
res.set('Content-Type', 'text/xml')
|
||||
res.send(xml)
|
||||
@ -55,9 +53,6 @@ class RssFeedManager {
|
||||
return
|
||||
}
|
||||
res.sendFile(episodePath)
|
||||
// var remainingPath = req.params['0']
|
||||
// var fullPath = Path.join(feedData.libraryItemPath, remainingPath)
|
||||
// res.sendFile(fullPath)
|
||||
}
|
||||
|
||||
getFeedCover(req, res) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
const FeedMeta = require('./FeedMeta')
|
||||
const FeedEpisode = require('./FeedEpisode')
|
||||
const { Podcast } = require('podcast')
|
||||
const RSS = require('../libs/rss')
|
||||
|
||||
class Feed {
|
||||
constructor(feed) {
|
||||
@ -90,6 +90,7 @@ class Feed {
|
||||
this.meta.imageUrl = media.coverPath ? `${serverAddress}/feed/${slug}/cover` : `${serverAddress}/Logo.png`
|
||||
this.meta.feedUrl = feedUrl
|
||||
this.meta.link = `${serverAddress}/items/${libraryItem.id}`
|
||||
this.meta.explicit = !!mediaMetadata.explicit
|
||||
|
||||
this.episodes = []
|
||||
if (isPodcast) { // PODCAST EPISODES
|
||||
@ -113,11 +114,11 @@ class Feed {
|
||||
buildXml() {
|
||||
if (this.xml) return this.xml
|
||||
|
||||
const pod = new Podcast(this.meta.getPodcastMeta())
|
||||
var rssfeed = new RSS(this.meta.getRSSData())
|
||||
this.episodes.forEach((ep) => {
|
||||
pod.addItem(ep.getPodcastEpisode())
|
||||
rssfeed.item(ep.getRSSData())
|
||||
})
|
||||
this.xml = pod.buildXml()
|
||||
this.xml = rssfeed.xml()
|
||||
return this.xml
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
const Path = require('path')
|
||||
const date = require('date-and-time')
|
||||
const { secondsToTimestamp } = require('../utils/index')
|
||||
|
||||
class FeedEpisode {
|
||||
constructor(episode) {
|
||||
@ -116,14 +117,23 @@ class FeedEpisode {
|
||||
this.fullPath = audioTrack.metadata.path
|
||||
}
|
||||
|
||||
getPodcastEpisode() {
|
||||
getRSSData() {
|
||||
return {
|
||||
title: this.title,
|
||||
description: this.description || '',
|
||||
enclosure: this.enclosure,
|
||||
date: this.pubDate || '',
|
||||
url: this.link,
|
||||
author: this.author
|
||||
guid: this.enclosure.url,
|
||||
author: this.author,
|
||||
date: this.pubDate,
|
||||
enclosure: this.enclosure,
|
||||
custom_elements: [
|
||||
{ 'itunes:author': this.author },
|
||||
{ 'itunes:duration': secondsToTimestamp(this.duration) },
|
||||
{ 'itunes:summary': this.description || '' },
|
||||
{
|
||||
"itunes:explicit": !!this.explicit
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ class FeedMeta {
|
||||
this.imageUrl = null
|
||||
this.feedUrl = null
|
||||
this.link = null
|
||||
this.explicit = null
|
||||
|
||||
if (meta) {
|
||||
this.construct(meta)
|
||||
@ -19,6 +20,7 @@ class FeedMeta {
|
||||
this.imageUrl = meta.imageUrl
|
||||
this.feedUrl = meta.feedUrl
|
||||
this.link = meta.link
|
||||
this.explicit = meta.explicit
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
@ -28,19 +30,46 @@ class FeedMeta {
|
||||
author: this.author,
|
||||
imageUrl: this.imageUrl,
|
||||
feedUrl: this.feedUrl,
|
||||
link: this.link
|
||||
link: this.link,
|
||||
explicit: this.explicit
|
||||
}
|
||||
}
|
||||
|
||||
getPodcastMeta() {
|
||||
getRSSData() {
|
||||
return {
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
feedUrl: this.feedUrl,
|
||||
siteUrl: this.link,
|
||||
imageUrl: this.imageUrl,
|
||||
author: this.author || 'advplyr',
|
||||
language: 'en'
|
||||
description: this.description || '',
|
||||
generator: 'Audiobookshelf',
|
||||
feed_url: this.feedUrl,
|
||||
site_url: this.link,
|
||||
image_url: this.imageUrl,
|
||||
language: 'en',
|
||||
custom_namespaces: {
|
||||
'itunes': 'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||
'psc': 'http://podlove.org/simple-chapters',
|
||||
'podcast': 'https://podcastindex.org/namespace/1.0'
|
||||
},
|
||||
custom_elements: [
|
||||
{ 'author': this.author || 'advplyr' },
|
||||
{ 'itunes:author': this.author || 'advplyr' },
|
||||
{ 'itunes:summary': this.description || '' },
|
||||
{
|
||||
'itunes:image': {
|
||||
_attr: {
|
||||
href: this.imageUrl
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'itunes:owner': [
|
||||
{ 'itunes:name': this.author || '' },
|
||||
{ 'itunes:email': '' }
|
||||
]
|
||||
},
|
||||
{
|
||||
"itunes:explicit": !!this.explicit
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user