From 70254f3bd6ce5f8d1de7dd52342e3dfb9d913120 Mon Sep 17 00:00:00 2001 From: Joshua Pohl Date: Fri, 16 Feb 2024 22:36:29 -1000 Subject: [PATCH] feat: add support for '--file' parsing closes #64 --- README.md | 5 ++++- bin/bin.js | 19 ++++++++++++++----- bin/commander.js | 1 + bin/util.js | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b4ec776..c839560 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,14 @@ A CLI for downloading podcasts with a focus on archiving. ## Options +Either `--url` or `--file` must be provided. + Type values surrounded in square brackets (`[]`) can be used as used as boolean options (no argument required). | Option | Type | Required | Description | | ------------------------ | ------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| --url | String | true | URL to podcast RSS feed. | +| --url | String | true\* | URL to podcast RSS feed. | +| --file | String | true\* | Path to local RSS file. | | --out-dir | String | false | Specify output directory for episodes and metadata. Defaults to "./{{podcast_title}}". See "Template Options" for more details. | | --threads | Number | false | Determines the number of downloads that will happen concurrently. Default is 1. | | --attempts | Number | false | Sets the number of download attempts per individual file. Default is 3. | diff --git a/bin/bin.js b/bin/bin.js index dee0f9b..2f7f7c8 100755 --- a/bin/bin.js +++ b/bin/bin.js @@ -10,10 +10,11 @@ import { setupCommander } from "./commander.js"; import { download } from "./async.js"; import { getArchiveKey, - getFeed, + getFileFeed, getImageUrl, getItemsToDownload, getUrlExt, + getUrlFeed, logFeedInfo, logItemsList, writeFeedMeta, @@ -31,6 +32,7 @@ import { downloadItemsAsync } from "./async.js"; setupCommander(commander, process.argv); const { + file, url, outDir, episodeTemplate, @@ -62,17 +64,24 @@ const { let { archive } = commander; const main = async () => { - if (!url) { - logErrorAndExit("No URL provided"); + if (!url && !file) { + logErrorAndExit("No URL or file location provided"); + } + + if (url && file) { + logErrorAndExit("Must not use URL and file location"); } if (proxy) { bootstrapProxy(); } - const { hostname, pathname } = new URL(url); + const feed = url + ? await getUrlFeed(url, parserConfig) + : await getFileFeed(file, parserConfig); + + const { hostname, pathname } = new URL(feed.feedUrl); const archiveUrl = `${hostname}${pathname}`; - const feed = await getFeed(url, parserConfig); const basePath = _path.resolve( process.cwd(), getFolderName({ feed, template: outDir }) diff --git a/bin/commander.js b/bin/commander.js index 315ebab..786317c 100644 --- a/bin/commander.js +++ b/bin/commander.js @@ -5,6 +5,7 @@ import { logErrorAndExit } from "./logger.js"; export const setupCommander = (commander, argv) => { commander .option("--url ", "url to podcast rss feed") + .option("--file ", "local path to podcast rss feed") .option( "--out-dir ", "specify output directory", diff --git a/bin/util.js b/bin/util.js index 7bbe956..28338c7 100644 --- a/bin/util.js +++ b/bin/util.js @@ -64,6 +64,22 @@ const getPublicObject = (object, exclude = []) => { return output; }; +const getFileString = (filePath) => { + const fullPath = path.resolve(process.cwd(), filePath); + + if (!fs.existsSync(fullPath)) { + return null; + } + + const data = fs.readFileSync(fullPath, "utf8"); + + if (!data) { + return null; + } + + return data; +}; + const getJsonFile = (filePath) => { const fullPath = path.resolve(process.cwd(), filePath); @@ -453,7 +469,33 @@ const getImageUrl = ({ image, itunes }) => { return null; }; -const getFeed = async (url, parserConfig) => { +const getFileFeed = async (filePath, parserConfig) => { + const defaultConfig = { + defaultRSS: 2.0, + }; + + const config = parserConfig ? getJsonFile(parserConfig) : defaultConfig; + const rssString = getFileString(filePath); + + console.log(filePath, "rss string", rssString); + + if (parserConfig && !config) { + logErrorAndExit(`Unable to load parser config: ${parserConfig}`); + } + + const parser = new rssParser(config); + + let feed; + try { + feed = await parser.parseString(rssString); + } catch (err) { + logErrorAndExit("Unable to parse RSS URL", err); + } + + return feed; +}; + +const getUrlFeed = async (url, parserConfig) => { const defaultConfig = { defaultRSS: 2.0, }; @@ -589,11 +631,12 @@ export { getArchiveKey, writeToArchive, getEpisodeAudioUrlAndExt, - getFeed, + getFileFeed, getImageUrl, getItemsToDownload, getTempPath, getUrlExt, + getUrlFeed, logFeedInfo, ITEM_LIST_FORMATS, logItemsList,