feedsmith
Version:
Fast, all‑in‑one feed parser and generator for RSS, Atom, RDF, and JSON Feed, with support for Podcast, iTunes, Dublin Core, and OPML files.
311 lines (310 loc) • 11.5 kB
JavaScript
import { isObject, parseArrayOf, parseBoolean, parseDate, parseNumber, parseSingularOf, parseString, parseYesNoBoolean, retrieveText, trimArray, trimObject } from "../../../common/utils.js";
//#region src/namespaces/podcast/parse/utils.ts
const whitespaceRegex = /\s+/;
const trailingWRegex = /w$/;
const parseTranscript = (value) => {
if (!isObject(value)) return;
return trimObject({
url: parseString(value["@url"]),
type: parseString(value["@type"]),
language: parseString(value["@language"]),
rel: parseString(value["@rel"])
});
};
const parseLocked = (value) => {
return trimObject({
value: parseYesNoBoolean(retrieveText(value)),
owner: parseString(value?.["@owner"])
});
};
const parseFunding = (value) => {
if (!isObject(value)) return;
return trimObject({
url: parseString(value["@url"]),
display: parseString(value["#text"])
});
};
const parseChapters = (value) => {
if (!isObject(value)) return;
return trimObject({
url: parseString(value["@url"]),
type: parseString(value["@type"])
});
};
const parseSoundbite = (value) => {
if (!isObject(value)) return;
return trimObject({
startTime: parseNumber(value["@starttime"]),
duration: parseNumber(value["@duration"]),
display: parseString(retrieveText(value))
});
};
const parsePerson = (value) => {
return trimObject({
display: parseString(retrieveText(value)),
role: parseString(value?.["@role"]),
group: parseString(value?.["@group"]),
img: parseString(value?.["@img"]),
href: parseString(value?.["@href"])
});
};
const parseLocation = (value) => {
return trimObject({
display: parseString(retrieveText(value)),
rel: parseString(value?.["@rel"]),
geo: parseString(value?.["@geo"]),
osm: parseString(value?.["@osm"]),
country: parseString(value?.["@country"])
});
};
const parseSeason = (value) => {
return trimObject({
number: parseNumber(retrieveText(value)),
name: parseString(value?.["@name"])
});
};
const parseEpisode = (value) => {
return trimObject({
number: parseNumber(retrieveText(value)),
display: parseString(value?.["@display"])
});
};
const parseTrailer = (value) => {
if (!isObject(value)) return;
return trimObject({
display: parseString(retrieveText(value)),
url: parseString(value["@url"]),
pubDate: parseDate(value["@pubdate"]),
length: parseNumber(value["@length"]),
type: parseString(value["@type"]),
season: parseNumber(value["@season"])
});
};
const parseLicense = (value) => {
return trimObject({
display: parseString(retrieveText(value)),
url: parseString(value?.["@url"])
});
};
const parseAlternateEnclosure = (value) => {
if (!isObject(value)) return;
return trimObject({
type: parseString(value["@type"]),
length: parseNumber(value["@length"]),
bitrate: parseNumber(value["@bitrate"]),
height: parseNumber(value["@height"]),
lang: parseString(value["@lang"]),
title: parseString(value["@title"]),
rel: parseString(value["@rel"]),
codecs: parseString(value["@codecs"]),
default: parseBoolean(value["@default"]),
sources: parseArrayOf(value["podcast:source"], parseSource),
integrity: parseSingularOf(value["podcast:integrity"], parseIntegrity)
});
};
const parseSource = (value) => {
if (!isObject(value)) return;
return trimObject({
uri: parseString(value["@uri"]),
contentType: parseString(value["@contenttype"])
});
};
const parseIntegrity = (value) => {
if (!isObject(value)) return;
return trimObject({
type: parseString(value["@type"]),
value: parseString(value["@value"])
});
};
const parseValue = (value) => {
if (!isObject(value)) return;
return trimObject({
type: parseString(value["@type"]),
method: parseString(value["@method"]),
suggested: parseNumber(value["@suggested"]),
valueRecipients: parseArrayOf(value["podcast:valuerecipient"], parseValueRecipient),
valueTimeSplits: parseArrayOf(value["podcast:valuetimesplit"], parseValueTimeSplit)
});
};
const parseValueRecipient = (value) => {
if (!isObject(value)) return;
return trimObject({
name: parseString(value["@name"]),
customKey: parseString(value["@customkey"]),
customValue: parseString(value["@customvalue"]),
type: parseString(value["@type"]),
address: parseString(value["@address"]),
split: parseNumber(value["@split"]),
fee: parseBoolean(value["@fee"])
});
};
const parseImage = (value) => {
if (!isObject(value)) return;
return trimObject({
href: parseString(value["@href"]),
alt: parseString(value["@alt"]),
aspectRatio: parseString(value["@aspect-ratio"]),
width: parseNumber(value["@width"]),
height: parseNumber(value["@height"]),
type: parseString(value["@type"]),
purpose: parseString(value["@purpose"])
});
};
const parseImages = (value) => {
const srcset = parseString(value?.["@srcset"]);
if (!srcset) return;
const images = [];
const segments = srcset.split(",");
for (const segment of segments) {
const [href, width] = segment.trim().split(whitespaceRegex);
const image = {
href: parseString(href),
width: parseNumber(width?.replace(trailingWRegex, ""))
};
images.push(image);
}
return trimArray(images, trimObject);
};
const retrieveImages = (value) => {
return parseArrayOf(value["podcast:image"], parseImage) ?? parseSingularOf(value["podcast:images"], parseImages);
};
const parseLiveItem = (value) => {
if (!isObject(value)) return;
return trimObject({
...retrieveItem(value),
status: parseString(value["@status"]),
start: parseDate(value["@start"]),
end: parseDate(value["@end"]),
contentLinks: parseArrayOf(value["podcast:contentlink"], parseContentLink)
});
};
const parseContentLink = (value) => {
if (!isObject(value)) return;
return trimObject({
href: parseString(value["@href"]),
display: parseString(retrieveText(value))
});
};
const parseSocialInteract = (value) => {
if (!isObject(value)) return;
return trimObject({
uri: parseString(value["@uri"]),
protocol: parseString(value["@protocol"]),
accountId: parseString(value["@accountid"]),
accountUrl: parseString(value["@accounturl"]),
priority: parseNumber(value["@priority"])
});
};
const parseChat = (value) => {
if (!isObject(value)) return;
return trimObject({
server: parseString(value["@server"]),
protocol: parseString(value["@protocol"]),
accountId: parseString(value["@accountid"]),
space: parseString(value["@space"])
});
};
const parseBlock = (value) => {
return trimObject({
value: parseYesNoBoolean(retrieveText(value)),
id: parseString(value?.["@id"])
});
};
const parseTxt = (value) => {
return trimObject({
display: parseString(retrieveText(value)),
purpose: parseString(value?.["@purpose"])
});
};
const parseRemoteItem = (value) => {
if (!isObject(value)) return;
return trimObject({
feedGuid: parseString(value["@feedguid"]),
feedUrl: parseString(value["@feedurl"]),
itemGuid: parseString(value["@itemguid"]),
medium: parseString(value["@medium"]),
title: parseString(value["@title"])
});
};
const parsePodroll = (value) => {
if (!isObject(value)) return;
return trimObject({ remoteItems: parseArrayOf(value["podcast:remoteitem"], parseRemoteItem) });
};
const parseUpdateFrequency = (value) => {
return trimObject({
display: parseString(retrieveText(value)),
complete: parseBoolean(value?.["@complete"]),
dtstart: parseDate(value?.["@dtstart"]),
rrule: parseString(value?.["@rrule"])
});
};
const parsePodping = (value) => {
if (!isObject(value)) return;
return trimObject({ usesPodping: parseBoolean(value["@usespodping"]) });
};
const parsePublisher = (value) => {
if (!isObject(value)) return;
return trimObject({ remoteItem: parseSingularOf(value["podcast:remoteitem"], parseRemoteItem) });
};
const parseValueTimeSplit = (value) => {
if (!isObject(value)) return;
return trimObject({
startTime: parseNumber(value["@starttime"]),
duration: parseNumber(value["@duration"]),
remoteStartTime: parseNumber(value["@remotestarttime"]),
remotePercentage: parseNumber(value["@remotepercentage"]),
remoteItem: parseSingularOf(value["podcast:remoteitem"], parseRemoteItem),
valueRecipients: parseArrayOf(value["podcast:valuerecipient"], parseValueRecipient)
});
};
const retrieveItem = (value) => {
if (!isObject(value)) return;
return trimObject({
transcripts: parseArrayOf(value["podcast:transcript"], parseTranscript),
chapters: parseSingularOf(value["podcast:chapters"], parseChapters),
soundbites: parseArrayOf(value["podcast:soundbite"], parseSoundbite),
persons: parseArrayOf(value["podcast:person"], parsePerson),
locations: parseArrayOf(value["podcast:location"], parseLocation),
season: parseSingularOf(value["podcast:season"], parseSeason),
episode: parseSingularOf(value["podcast:episode"], parseEpisode),
license: parseSingularOf(value["podcast:license"], parseLicense),
alternateEnclosures: parseArrayOf(value["podcast:alternateenclosure"], parseAlternateEnclosure),
values: parseArrayOf(value["podcast:value"], parseValue),
images: retrieveImages(value),
socialInteracts: parseArrayOf(value["podcast:socialinteract"], parseSocialInteract),
txts: parseArrayOf(value["podcast:txt"], parseTxt),
chat: parseSingularOf(value["podcast:chat"], parseChat),
location: parseSingularOf(value["podcast:location"], parseLocation),
value: parseSingularOf(value["podcast:value"], parseValue),
chats: parseArrayOf(value["podcast:chat"], parseChat)
});
};
const retrieveFeed = (value) => {
if (!isObject(value)) return;
return trimObject({
locked: parseSingularOf(value["podcast:locked"], parseLocked),
fundings: parseArrayOf(value["podcast:funding"], parseFunding),
persons: parseArrayOf(value["podcast:person"], parsePerson),
locations: parseArrayOf(value["podcast:location"], parseLocation),
trailers: parseArrayOf(value["podcast:trailer"], parseTrailer),
license: parseSingularOf(value["podcast:license"], parseLicense),
guid: parseSingularOf(value["podcast:guid"], (value) => parseString(retrieveText(value))),
values: parseArrayOf(value["podcast:value"], parseValue),
medium: parseSingularOf(value["podcast:medium"], (value) => parseString(retrieveText(value))),
images: retrieveImages(value),
liveItems: parseArrayOf(value["podcast:liveitem"], parseLiveItem),
blocks: parseArrayOf(value["podcast:block"], parseBlock),
txts: parseArrayOf(value["podcast:txt"], parseTxt),
remoteItems: parseArrayOf(value["podcast:remoteitem"], parseRemoteItem),
podroll: parseSingularOf(value["podcast:podroll"], parsePodroll),
updateFrequency: parseSingularOf(value["podcast:updatefrequency"], parseUpdateFrequency),
podping: parseSingularOf(value["podcast:podping"], parsePodping),
chat: parseSingularOf(value["podcast:chat"], parseChat),
publisher: parseSingularOf(value["podcast:publisher"], parsePublisher),
location: parseSingularOf(value["podcast:location"], parseLocation),
value: parseSingularOf(value["podcast:value"], parseValue),
chats: parseArrayOf(value["podcast:chat"], parseChat)
});
};
//#endregion
export { parseAlternateEnclosure, parseBlock, parseChapters, parseChat, parseContentLink, parseEpisode, parseFunding, parseImage, parseImages, parseIntegrity, parseLicense, parseLiveItem, parseLocation, parseLocked, parsePerson, parsePodping, parsePodroll, parsePublisher, parseRemoteItem, parseSeason, parseSocialInteract, parseSoundbite, parseSource, parseTrailer, parseTranscript, parseTxt, parseUpdateFrequency, parseValue, parseValueRecipient, parseValueTimeSplit, retrieveFeed, retrieveImages, retrieveItem };