Skip to content

Commit d280eea

Browse files
author
Josh Pohl
authored
feat!: add 'episode-custom-template-options' (#79)
* chore!: upgrade to Node v18
1 parent 8fd6312 commit d280eea

9 files changed

+87
-49
lines changed

README.md

+41-34
Large diffs are not rendered by default.

bin/async.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const download = async (options) => {
7070
},
7171
});
7272
} catch (error) {
73-
// unable to retrive head response
73+
// unable to retrieve head response
7474
}
7575

7676
const tempOutputPath = getTempPath(outputPath);
@@ -164,6 +164,7 @@ const downloadItemsAsync = async ({
164164
basePath,
165165
bitrate,
166166
episodeTemplate,
167+
episodeCustomTemplateOptions,
167168
episodeDigits,
168169
episodeNumOffset,
169170
episodeSourceOrder,
@@ -199,6 +200,7 @@ const downloadItemsAsync = async ({
199200
url: episodeAudioUrl,
200201
ext: audioFileExt,
201202
template: episodeTemplate,
203+
customTemplateOptions: episodeCustomTemplateOptions,
202204
width: episodeDigits,
203205
offset: episodeNumOffset,
204206
});
@@ -283,6 +285,7 @@ const downloadItemsAsync = async ({
283285
url: episodeAudioUrl,
284286
ext: episodeMetaExt,
285287
template: episodeTemplate,
288+
customTemplateOptions: episodeCustomTemplateOptions,
286289
width: episodeDigits,
287290
offset: episodeNumOffset,
288291
});

bin/bin.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import fs from "fs";
44
import _path from "path";
5-
import commander from "commander";
5+
import { program } from "commander";
66
import pluralize from "pluralize";
77
import { bootstrap as bootstrapProxy } from "global-agent";
88

@@ -29,7 +29,7 @@ import {
2929
import { getFolderName, getSimpleFilename } from "./naming.js";
3030
import { downloadItemsAsync } from "./async.js";
3131

32-
setupCommander(commander, process.argv);
32+
const opts = setupCommander(program);
3333

3434
const {
3535
after,
@@ -41,6 +41,7 @@ const {
4141
episodeRegex,
4242
episodeSourceOrder,
4343
episodeTemplate,
44+
episodeCustomTemplateOptions,
4445
episodeTranscriptTypes,
4546
exec,
4647
file,
@@ -62,9 +63,9 @@ const {
6263
url,
6364
addMp3Metadata: addMp3MetadataFlag,
6465
adjustBitrate: bitrate,
65-
} = commander;
66+
} = opts;
6667

67-
let { archive } = commander;
68+
let { archive } = opts;
6869

6970
const main = async () => {
7071
if (!url && !file) {
@@ -213,6 +214,7 @@ const main = async () => {
213214
episodeRegex,
214215
episodeSourceOrder,
215216
episodeTemplate,
217+
episodeCustomTemplateOptions,
216218
includeEpisodeImages,
217219
includeEpisodeTranscripts,
218220
episodeTranscriptTypes,
@@ -234,6 +236,7 @@ const main = async () => {
234236
basePath,
235237
bitrate,
236238
episodeTemplate,
239+
episodeCustomTemplateOptions,
237240
episodeDigits,
238241
episodeNumOffset,
239242
episodeSourceOrder,

bin/commander.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import {
66
import { createParseNumber, hasFfmpeg } from "./validate.js";
77
import { logErrorAndExit } from "./logger.js";
88

9-
export const setupCommander = (commander, argv) => {
10-
commander
9+
export const setupCommander = (program) => {
10+
program
1111
.option("--url <string>", "url to podcast rss feed")
1212
.option("--file <path>", "local path to podcast rss feed")
1313
.option(
@@ -24,6 +24,10 @@ export const setupCommander = (commander, argv) => {
2424
"template for generating episode related filenames",
2525
"{{release_date}}-{{title}}"
2626
)
27+
.option(
28+
"--episode-custom-template-options <patterns...>",
29+
"create custom options for the episode template"
30+
)
2731
.option(
2832
"--episode-digits <number>",
2933
"minimum number of digits to use for episode numbering (leading zeros)",
@@ -180,6 +184,9 @@ export const setupCommander = (commander, argv) => {
180184
"--parser-config <string>",
181185
"path to JSON config to override RSS parser"
182186
)
183-
.option("--proxy", "enable proxy support via global-agent")
184-
.parse(argv);
187+
.option("--proxy", "enable proxy support via global-agent");
188+
189+
program.parse();
190+
191+
return program.opts();
185192
};

bin/naming.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,32 @@ const getItemFilename = ({
2525
feed,
2626
template,
2727
width,
28+
customTemplateOptions = [],
2829
offset = 0,
2930
}) => {
3031
const episodeNum = feed.items.length - item._originalIndex + offset;
32+
const title = item.title || "";
3133
const formattedPubDate = item.pubDate
3234
? dayjs(new Date(item.pubDate)).format("YYYYMMDD")
3335
: null;
3436

37+
const customReplacementTuples = customTemplateOptions.map((option, i) => {
38+
const matchRegex = new RegExp(option);
39+
const match = title.match(matchRegex);
40+
41+
return match && match[0] ? [`custom_${i}`, match[0]] : [`custom_${i}`, ""];
42+
});
43+
3544
const templateReplacementsTuples = [
36-
["title", item.title || ""],
45+
["title", title],
3746
["release_date", formattedPubDate || ""],
3847
["episode_num", `${episodeNum}`.padStart(width, "0")],
3948
["url", url],
4049
["podcast_title", feed.title || ""],
4150
["podcast_link", feed.link || ""],
4251
["duration", item.itunes?.duration || ""],
4352
["guid", item.guid],
53+
...customReplacementTuples,
4454
];
4555

4656
const templateSegments = template.trim().split(path.sep);

bin/util.js

+2
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ const getItemsToDownload = ({
165165
episodeRegex,
166166
episodeSourceOrder,
167167
episodeTemplate,
168+
episodeCustomTemplateOptions,
168169
includeEpisodeImages,
169170
includeEpisodeTranscripts,
170171
episodeTranscriptTypes,
@@ -252,6 +253,7 @@ const getItemsToDownload = ({
252253
url: episodeAudioUrl,
253254
ext: episodeImageFileExt,
254255
template: episodeTemplate,
256+
customTemplateOptions: episodeCustomTemplateOptions,
255257
width: episodeDigits,
256258
offset: episodeNumOffset,
257259
});

build.cjs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ const { version } = require("./package.json");
66

77
const targetMap = [
88
{
9-
target: "node14-linux-x64",
9+
target: "node18-linux-x64",
1010
output: `./binaries/podcast-dl-${version}-linux-x64`,
1111
},
1212
{
13-
target: "node14-macos-x64",
13+
target: "node18-macos-x64",
1414
output: `./binaries/podcast-dl-${version}-macos-x64`,
1515
},
1616
{
17-
target: "node14-win-x64",
17+
target: "node18-win-x64",
1818
output: `./binaries/podcast-dl-${version}-win-x64`,
1919
},
2020
];

docs/examples.md

+6
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,9 @@ npx podcast-dl --episode-regex "Zelda" --url "http://eightfour.libsyn.com/rss"
5353
```bash
5454
npx podcast-dl --url "http://eightfour.libsyn.com/rss" --exec "ffmpeg -i {{episode_path}} -b:a 192k -f mp3 {{episode_path_base}}/{{episode_filename_base}}-192k.mp3"
5555
```
56+
57+
## Extract "foo" and "bar" from the episode title and place it in the episode filename
58+
59+
```bash
60+
npx podcast-dl --url "http://eightfour.libsyn.com/rss" --episode-custom-template-options "foo" "bar" --episode-template "{{custom_0}}-{{custom_1}}-{{episode_num}}""
61+
```

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"cli"
2727
],
2828
"engines": {
29-
"node": ">=14.17.6"
29+
"node": ">=18.17.0"
3030
},
3131
"repository": {
3232
"type": "git",
@@ -49,7 +49,7 @@
4949
},
5050
"dependencies": {
5151
"command-exists": "^1.2.9",
52-
"commander": "^5.1.0",
52+
"commander": "^12.1.0",
5353
"dayjs": "^1.8.25",
5454
"filenamify": "^6.0.0",
5555
"global-agent": "^3.0.0",

0 commit comments

Comments
 (0)