podcast-dl 7.0.0-async.1 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # podcast-dl
2
2
 
3
- ## A CLI for downloading podcasts with a focus on archiving.
4
-
5
- ![podcast-dl example gif](./docs/podcast-dl-example.gif)
3
+ A CLI for downloading podcasts with a focus on archiving.
6
4
 
7
5
  ## How to Use
8
6
 
@@ -12,6 +10,8 @@
12
10
 
13
11
  `npx podcast-dl --url <PODCAST_RSS_URL>`
14
12
 
13
+ ### [More Examples](./docs/examples.md)
14
+
15
15
  ## Options
16
16
 
17
17
  Type values surrounded in square brackets (`[]`) can be used as used as boolean options (no argument required).
@@ -20,6 +20,7 @@ Type values surrounded in square brackets (`[]`) can be used as used as boolean
20
20
  | ------------------------ | ------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
21
21
  | --url | String | true | URL to podcast RSS feed. |
22
22
  | --out-dir | String | false | Specify output directory for episodes and metadata. Defaults to "./{{podcast_title}}". See "Templating" for more details. |
23
+ | --threads | Number | false | Determines the number of downloads that will happen concurrently. Default is 1. |
23
24
  | --archive | [String] | false | Download or write out items not listed in archive file. Generates archive file at path if not found. Defaults to "./{{podcast_title}}/archive.json" when used as a boolean option. See "Templating" for more details. |
24
25
  | --episode-template | String | false | Template for generating episode related filenames. See "Templating" for details. |
25
26
  | --include-meta | | false | Write out podcast metadata to JSON. |
@@ -38,7 +39,7 @@ Type values surrounded in square brackets (`[]`) can be used as used as boolean
38
39
  | --info | | false | Print retrieved podcast info instead of downloading. |
39
40
  | --list | [String] | false | Print episode list instead of downloading. Defaults to "table" when used as a boolean option. "json" is also supported. |
40
41
  | --exec | String | false | Execute a command after each episode is downloaded. |
41
- | --threads | Number | false | Determines the number of downloads that will happen concurrently. Default is 1. |
42
+ | --filter-url-tacking | | false | Attempts to extract the direct download link of an episode if detected (**experimental**). |
42
43
  | --version | | false | Output the version number. |
43
44
  | --help | | false | Output usage information. |
44
45
 
package/bin/async.js CHANGED
@@ -16,10 +16,12 @@ import { getArchiveFilename, getFilename } from "./naming.js";
16
16
  import {
17
17
  getEpisodeAudioUrlAndExt,
18
18
  getArchiveKey,
19
+ getTempPath,
19
20
  runFfmpeg,
20
21
  runExec,
21
22
  writeItemMeta,
22
23
  writeToArchive,
24
+ getUrlEmbed,
23
25
  } from "./util.js";
24
26
 
25
27
  const pipeline = promisify(stream.pipeline);
@@ -34,6 +36,7 @@ const download = async ({
34
36
  archive,
35
37
  override,
36
38
  onAfterDownload,
39
+ filterUrlTracking,
37
40
  }) => {
38
41
  const logMessage = getLogMessageWithMarker(marker);
39
42
  if (!override && fs.existsSync(outputPath)) {
@@ -41,7 +44,18 @@ const download = async ({
41
44
  return;
42
45
  }
43
46
 
44
- const headResponse = await got(url, {
47
+ let embeddedUrl = null;
48
+ if (filterUrlTracking) {
49
+ logMessage("Attempting to find embedded URL...");
50
+ embeddedUrl = await getUrlEmbed(url);
51
+
52
+ if (!embeddedUrl) {
53
+ logMessage("Unable to find embedded URL. Defaulting to full address");
54
+ }
55
+ }
56
+
57
+ const finalUrl = embeddedUrl || url;
58
+ const headResponse = await got(finalUrl, {
45
59
  timeout: 5000,
46
60
  method: "HEAD",
47
61
  responseType: "json",
@@ -50,9 +64,10 @@ const download = async ({
50
64
  },
51
65
  });
52
66
 
67
+ const tempOutputPath = getTempPath(outputPath);
53
68
  const removeFile = () => {
54
- if (fs.existsSync(outputPath)) {
55
- fs.unlinkSync(outputPath);
69
+ if (fs.existsSync(tempOutputPath)) {
70
+ fs.unlinkSync(tempOutputPath);
56
71
  }
57
72
  };
58
73
 
@@ -87,15 +102,15 @@ const download = async ({
87
102
  });
88
103
 
89
104
  await pipeline(
90
- got.stream(url).on("downloadProgress", onDownloadProgress),
91
- fs.createWriteStream(outputPath)
105
+ got.stream(finalUrl).on("downloadProgress", onDownloadProgress),
106
+ fs.createWriteStream(tempOutputPath)
92
107
  );
93
108
  } catch (error) {
94
109
  removeFile();
95
110
  throw error;
96
111
  }
97
112
 
98
- const fileSize = fs.statSync(outputPath).size;
113
+ const fileSize = fs.statSync(tempOutputPath).size;
99
114
 
100
115
  if (fileSize === 0) {
101
116
  removeFile();
@@ -108,6 +123,8 @@ const download = async ({
108
123
  return;
109
124
  }
110
125
 
126
+ fs.renameSync(tempOutputPath, outputPath);
127
+
111
128
  if (expectedSize && !isNaN(expectedSize) && expectedSize !== fileSize) {
112
129
  logMessage(
113
130
  "File size differs from expected content length. Suggestion: verify file works as expected",
@@ -140,6 +157,7 @@ let downloadItemsAsync = async ({
140
157
  episodeTemplate,
141
158
  exec,
142
159
  feed,
160
+ filterUrlTracking,
143
161
  includeEpisodeMeta,
144
162
  mono,
145
163
  override,
@@ -177,6 +195,7 @@ let downloadItemsAsync = async ({
177
195
  archive,
178
196
  override,
179
197
  marker,
198
+ filterUrlTracking,
180
199
  key: getArchiveKey({
181
200
  prefix: archiveUrl,
182
201
  name: getArchiveFilename({
package/bin/bin.js CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import fs from "fs";
4
4
  import _path from "path";
5
- import _url from "url";
6
5
  import commander from "commander";
7
6
  import { createRequire } from "module";
8
7
  import pluralize from "pluralize";
@@ -119,6 +118,10 @@ commander
119
118
  createParseNumber({ min: 1, max: 32, name: "threads" }),
120
119
  1
121
120
  )
121
+ .option(
122
+ "--filter-url-tracking",
123
+ "attempts to extract the direct download link of an episode if detected (experimental)"
124
+ )
122
125
  .parse(process.argv);
123
126
 
124
127
  const {
@@ -140,6 +143,7 @@ const {
140
143
  exec,
141
144
  mono,
142
145
  threads,
146
+ filterUrlTracking,
143
147
  addMp3Metadata: addMp3MetadataFlag,
144
148
  adjustBitrate: bitrate,
145
149
  } = commander;
@@ -151,7 +155,7 @@ const main = async () => {
151
155
  logErrorAndExit("No URL provided");
152
156
  }
153
157
 
154
- const { hostname, pathname } = _url.parse(url);
158
+ const { hostname, pathname } = new URL(url);
155
159
  const archiveUrl = `${hostname}${pathname}`;
156
160
  const feed = await getFeed(url);
157
161
  const basePath = _path.resolve(
@@ -286,6 +290,7 @@ const main = async () => {
286
290
  override,
287
291
  targetItems,
288
292
  threads,
293
+ filterUrlTracking,
289
294
  });
290
295
 
291
296
  if (numEpisodesDownloaded === 0) {
package/bin/util.js CHANGED
@@ -1,8 +1,8 @@
1
- import _url from "url";
2
1
  import rssParser from "rss-parser";
3
2
  import path from "path";
4
3
  import fs from "fs";
5
4
  import dayjs from "dayjs";
5
+ import got from "got";
6
6
  import util from "util";
7
7
  import { exec } from "child_process";
8
8
 
@@ -15,6 +15,10 @@ const parser = new rssParser({
15
15
  defaultRSS: 2.0,
16
16
  });
17
17
 
18
+ const getTempPath = (path) => {
19
+ return `${path}.tmp`;
20
+ };
21
+
18
22
  const getArchiveKey = ({ prefix, name }) => {
19
23
  return `${prefix}-${name}`;
20
24
  };
@@ -45,6 +49,54 @@ const getIsInArchive = ({ key, archive }) => {
45
49
  return archiveResult.includes(key);
46
50
  };
47
51
 
52
+ const getPossibleUrlEmbeds = (url, maxAmount = 5) => {
53
+ const fullUrl = new URL(url);
54
+ const possibleStartIndexes = [];
55
+
56
+ for (let i = 0; i < fullUrl.pathname.length; i++) {
57
+ if (fullUrl.pathname[i] === "/") {
58
+ possibleStartIndexes.push(i);
59
+ }
60
+ }
61
+
62
+ const possibleEmbedChoices = possibleStartIndexes.map((startIndex) => {
63
+ let possibleEmbed = fullUrl.pathname.slice(startIndex + 1);
64
+
65
+ if (!possibleEmbed.startsWith("http")) {
66
+ possibleEmbed = `https://${possibleEmbed}`;
67
+ }
68
+
69
+ return decodeURIComponent(possibleEmbed);
70
+ });
71
+
72
+ return possibleEmbedChoices
73
+ .slice(Math.max(possibleEmbedChoices.length - maxAmount, 0))
74
+ .reverse();
75
+ };
76
+
77
+ const getUrlEmbed = async (url) => {
78
+ const possibleUrlEmbeds = getPossibleUrlEmbeds(url);
79
+ for (const possibleUrl of possibleUrlEmbeds) {
80
+ try {
81
+ const embeddedUrl = new URL(possibleUrl);
82
+ await got(embeddedUrl.href, {
83
+ timeout: 3000,
84
+ method: "HEAD",
85
+ responseType: "json",
86
+ headers: {
87
+ accept: "*/*",
88
+ },
89
+ });
90
+
91
+ return embeddedUrl;
92
+ } catch (error) {
93
+ // do nothing
94
+ }
95
+ }
96
+
97
+ return null;
98
+ };
99
+
48
100
  const getLoopControls = ({ limit, offset, length, reverse }) => {
49
101
  if (reverse) {
50
102
  const startIndex = length - 1 - offset;
@@ -341,7 +393,7 @@ const writeItemMeta = ({
341
393
  };
342
394
 
343
395
  const getUrlExt = (url) => {
344
- const { pathname } = _url.parse(url);
396
+ const { pathname } = new URL(url);
345
397
 
346
398
  if (!pathname) {
347
399
  return "";
@@ -408,7 +460,7 @@ const getImageUrl = ({ image, itunes }) => {
408
460
  };
409
461
 
410
462
  const getFeed = async (url) => {
411
- const { href } = _url.parse(url);
463
+ const { href } = new URL(url);
412
464
 
413
465
  let feed;
414
466
  try {
@@ -521,7 +573,9 @@ export {
521
573
  getFeed,
522
574
  getImageUrl,
523
575
  getItemsToDownload,
576
+ getTempPath,
524
577
  getUrlExt,
578
+ getUrlEmbed,
525
579
  logFeedInfo,
526
580
  ITEM_LIST_FORMATS,
527
581
  logItemsList,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "podcast-dl",
3
- "version": "7.0.0-async.1",
3
+ "version": "7.2.0",
4
4
  "description": "A CLI for downloading podcasts.",
5
5
  "type": "module",
6
6
  "bin": "./bin/bin.js",
package/CHANGELOG.md DELETED
@@ -1,341 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
-
5
- ## [7.0.0-async.1](https://github.com/lightpohl/podcast-dl/compare/v7.0.0-async.0...v7.0.0-async.1) (2021-09-26)
6
-
7
-
8
- ### Features
9
-
10
- * check for ffmpeg during validation if option requires it ([d8638d2](https://github.com/lightpohl/podcast-dl/commit/d8638d26b7deafc4b025a827214fbbc276a536ea))
11
-
12
-
13
- ### Bug Fixes
14
-
15
- * set max on number of threads to 32 ([22b8b99](https://github.com/lightpohl/podcast-dl/commit/22b8b997c1272d8bd5448f7c169c88e24fa450e3))
16
-
17
- ## [7.0.0-async.0](https://github.com/lightpohl/podcast-dl/compare/v6.1.0...v7.0.0-async.0) (2021-09-22)
18
-
19
-
20
- ### ⚠ BREAKING CHANGES
21
-
22
- * support multiple downloads via --threads
23
-
24
- ### Features
25
-
26
- * support multiple downloads via --threads ([c4d3ef1](https://github.com/lightpohl/podcast-dl/commit/c4d3ef10b0d393cebdce78037bf121a6018b3bc1))
27
-
28
- ## [6.1.0](https://github.com/lightpohl/podcast-dl/compare/v6.0.0...v6.1.0) (2021-08-15)
29
-
30
-
31
- ### Features
32
-
33
- * add 'static' log level support ([66b5934](https://github.com/lightpohl/podcast-dl/commit/66b593430ccbfea110cc0c6a809646b0390d02ba)), closes [#32](https://github.com/lightpohl/podcast-dl/issues/32)
34
-
35
-
36
- ### Bug Fixes
37
-
38
- * cleanup any temp files if ffmpeg fails ([c4a5408](https://github.com/lightpohl/podcast-dl/commit/c4a5408c05445f43cbb3d651dbab4d7cb2e81d72))
39
-
40
- ## [6.0.0](https://github.com/lightpohl/podcast-dl/compare/v5.4.0...v6.0.0) (2021-08-13)
41
-
42
-
43
- ### ⚠ BREAKING CHANGES
44
-
45
- * consolidate '--list' and '--list-format'
46
-
47
- ### Features
48
-
49
- * consolidate '--list' and '--list-format' ([ce47051](https://github.com/lightpohl/podcast-dl/commit/ce47051475cb212c0460bcad4071d4166b9633ca))
50
-
51
-
52
- ### Bug Fixes
53
-
54
- * better error message when archive write fails ([42de1f0](https://github.com/lightpohl/podcast-dl/commit/42de1f029d118de7a936e40d205459d674d76592))
55
- * issue with '--archive' default ([551c0a8](https://github.com/lightpohl/podcast-dl/commit/551c0a891423d5d4e1458f35c17161dd386c30f4))
56
-
57
- ## [5.4.0](https://github.com/lightpohl/podcast-dl/compare/v5.3.0...v5.4.0) (2021-08-13)
58
-
59
-
60
- ### Features
61
-
62
- * add '--before' and '--after' options ([a45e95a](https://github.com/lightpohl/podcast-dl/commit/a45e95a892ee939ab3b3eb8e5d36133b1bf9e1f0)), closes [#31](https://github.com/lightpohl/podcast-dl/issues/31)
63
- * add default path when '--archive' is enabled ([8100739](https://github.com/lightpohl/podcast-dl/commit/8100739dfc887da3a943823dd26bd5c46dcd5430))
64
-
65
-
66
- ### Bug Fixes
67
-
68
- * don't create folder when running info commands ([0a3e884](https://github.com/lightpohl/podcast-dl/commit/0a3e88484a66627d739039fce160185c39e8bfa6))
69
- * log a message when ffmpeg starts ([037f448](https://github.com/lightpohl/podcast-dl/commit/037f448e00164bcc48298bbb8a9df9f5596f5b41))
70
-
71
- ## [5.3.0](https://github.com/lightpohl/podcast-dl/compare/v5.2.0...v5.3.0) (2021-08-11)
72
-
73
-
74
- ### Features
75
-
76
- * add '--mono' option ([ade68aa](https://github.com/lightpohl/podcast-dl/commit/ade68aa6e7612a21e1354143b4d6bf673b20aad4))
77
-
78
- ## [5.2.0](https://github.com/lightpohl/podcast-dl/compare/v5.1.0...v5.2.0) (2021-08-11)
79
-
80
-
81
- ### Features
82
-
83
- * add '--adjust-bitrate' option ([029ef66](https://github.com/lightpohl/podcast-dl/commit/029ef66143031ff51be748f68c2fb667bb6f3384))
84
-
85
- ## [5.1.0](https://github.com/lightpohl/podcast-dl/compare/v5.0.2...v5.1.0) (2021-08-08)
86
-
87
-
88
- ### Features
89
-
90
- * add '--list-format' options ([c68aa43](https://github.com/lightpohl/podcast-dl/commit/c68aa43ba9c6eafcb667fac9b530b06aa2141f9c)), closes [#29](https://github.com/lightpohl/podcast-dl/issues/29)
91
- * allow '--list' to support filtering options ([0dda386](https://github.com/lightpohl/podcast-dl/commit/0dda386b2881bf5c4114f52f9ae49772a12fae94)), closes [#28](https://github.com/lightpohl/podcast-dl/issues/28)
92
- * filter with '--episode-regex' before starting downloads ([6690a82](https://github.com/lightpohl/podcast-dl/commit/6690a82f1c650b513c27bf8d24cac036c68b4f1a))
93
-
94
- ### [5.0.2](https://github.com/lightpohl/podcast-dl/compare/v5.0.1...v5.0.2) (2021-08-03)
95
-
96
-
97
- ### Bug Fixes
98
-
99
- * output path incorrectly set ([03d99fb](https://github.com/lightpohl/podcast-dl/commit/03d99fb82409d5619c0477814aace37d7db35936))
100
-
101
- ### [5.0.1](https://github.com/lightpohl/podcast-dl/compare/v5.0.0...v5.0.1) (2021-08-03)
102
-
103
-
104
- ### Bug Fixes
105
-
106
- * log item info when skipped due to conflict or existing in archive ([7a324e6](https://github.com/lightpohl/podcast-dl/commit/7a324e65fcf031d94039c5b6a2ee76c1eafd9470))
107
-
108
- ## [5.0.0](https://github.com/lightpohl/podcast-dl/compare/v4.3.1...v5.0.0) (2021-07-31)
109
-
110
-
111
- ### ⚠ BREAKING CHANGES
112
-
113
- * exit with error code 2 when no episodes are downloaded (#27)
114
-
115
- ### Features
116
-
117
- * add --exec option ([#25](https://github.com/lightpohl/podcast-dl/issues/25)) ([f39966f](https://github.com/lightpohl/podcast-dl/commit/f39966f7b015807bf061b47276495b8671e66cb3))
118
- * exit with error code 2 when no episodes are downloaded ([#27](https://github.com/lightpohl/podcast-dl/issues/27)) ([0ef921e](https://github.com/lightpohl/podcast-dl/commit/0ef921e00c960be971228ea2845d6b134015aca4))
119
-
120
-
121
- ### Bug Fixes
122
-
123
- * move onAfterDownload to after error checks ([f148041](https://github.com/lightpohl/podcast-dl/commit/f148041930118d4246ab9016bbfb0f949bbba355))
124
- * only run --add-mp3-metadata on new downloads ([e06a7e9](https://github.com/lightpohl/podcast-dl/commit/e06a7e90a54ed3b74d6e53dc88a6ee7265895166))
125
-
126
- ### [4.3.1](https://github.com/lightpohl/podcast-dl/compare/v4.3.0...v4.3.1) (2021-05-09)
127
-
128
-
129
- ### Bug Fixes
130
-
131
- * always log error messages that trigger an exit ([e856f3c](https://github.com/lightpohl/podcast-dl/commit/e856f3c7fca1afb9c7d4e49fdcd30a84181f1ea7))
132
- * gracefully handle feed items missing audio extensions ([b0a03de](https://github.com/lightpohl/podcast-dl/commit/b0a03ded86b2d87e64edd29fc2e51d64cb5597a7)), closes [#24](https://github.com/lightpohl/podcast-dl/issues/24)
133
- * missing newline when download exits on error ([2672676](https://github.com/lightpohl/podcast-dl/commit/267267667414ec17300ca2db07f148010f4be1f1))
134
-
135
- ## [4.3.0](https://github.com/lightpohl/podcast-dl/compare/v4.2.0...v4.3.0) (2021-04-10)
136
-
137
-
138
- ### Features
139
-
140
- * add support for LOG_LEVEL env variable ([3a2deb0](https://github.com/lightpohl/podcast-dl/commit/3a2deb05425352d870b0824cddd404751ab0dcbc)), closes [#22](https://github.com/lightpohl/podcast-dl/issues/22)
141
-
142
- ## [4.2.0](https://github.com/lightpohl/podcast-dl/compare/v4.1.4...v4.2.0) (2021-03-13)
143
-
144
-
145
- ### Features
146
-
147
- * add --add-mp3-metadata option ([#21](https://github.com/lightpohl/podcast-dl/issues/21)) ([2825a36](https://github.com/lightpohl/podcast-dl/commit/2825a360ffe9ea59d6fbad6fd8b68413731a9e45))
148
-
149
- ### [4.1.4](https://github.com/lightpohl/podcast-dl/compare/v4.1.3...v4.1.4) (2021-02-20)
150
-
151
-
152
- ### Bug Fixes
153
-
154
- * check enclosure for audio type/ext if file is missing ext ([58bcc4b](https://github.com/lightpohl/podcast-dl/commit/58bcc4b97eac8ea662fa8da0e05ddc0a630f2a99))
155
-
156
- ### [4.1.3](https://github.com/lightpohl/podcast-dl/compare/v4.1.2...v4.1.3) (2021-01-27)
157
-
158
- ### [4.1.2](https://github.com/lightpohl/podcast-dl/compare/v4.1.1...v4.1.2) (2021-01-22)
159
-
160
-
161
- ### Bug Fixes
162
-
163
- * disable download progress logging in non-TTY envs ([c0f0dde](https://github.com/lightpohl/podcast-dl/commit/c0f0ddebc5635e0c9b162cadecab8760c4b00e17))
164
-
165
- ### [4.1.1](https://github.com/lightpohl/podcast-dl/compare/v4.1.0...v4.1.1) (2020-12-29)
166
-
167
-
168
- ### Bug Fixes
169
-
170
- * the most recent episode should be downloaded when using '--reverse' ([709312b](https://github.com/lightpohl/podcast-dl/commit/709312b1307d35e6082447719fc786892700f3e8)), closes [#16](https://github.com/lightpohl/podcast-dl/issues/16)
171
-
172
- ## [4.1.0](https://github.com/lightpohl/podcast-dl/compare/v4.0.1...v4.1.0) (2020-08-15)
173
-
174
-
175
- ### Features
176
-
177
- * add templating support to '--archive' option ([f8ed4fb](https://github.com/lightpohl/podcast-dl/commit/f8ed4fb7192b5d9441516c8ce262d568a76992b5)), closes [#15](https://github.com/lightpohl/podcast-dl/issues/15)
178
-
179
- ### [4.0.1](https://github.com/lightpohl/podcast-dl/compare/v4.0.0...v4.0.1) (2020-08-09)
180
-
181
-
182
- ### Bug Fixes
183
-
184
- * include generic accept header for compatibility with some podcast servers ([a12b1da](https://github.com/lightpohl/podcast-dl/commit/a12b1da11418c5dc3180885376b1d87b8db43f93)), closes [#13](https://github.com/lightpohl/podcast-dl/issues/13)
185
-
186
- ## [4.0.0](https://github.com/lightpohl/podcast-dl/compare/v3.0.0...v4.0.0) (2020-08-01)
187
-
188
- ### Breaking Changes
189
-
190
- * remove `--prompt` option
191
-
192
- ### Features
193
-
194
- * add '--episode-regex' option ([24c74ba](https://github.com/lightpohl/podcast-dl/commit/24c74ba822e2dde5cc63ee24770c1cf8dc1b0a44))
195
-
196
-
197
- ### [3.0.1](https://github.com/lightpohl/podcast-dl/compare/v3.0.0...v3.0.1) (2020-07-15)
198
-
199
-
200
- ### Bug Fixes
201
-
202
- * better handle missing properties for name templating ([ae25272](https://github.com/lightpohl/podcast-dl/commit/ae25272366bdd7229448008f59ccb942b56eb742))
203
-
204
- ## [3.0.0](https://github.com/lightpohl/podcast-dl/compare/v2.0.0...v3.0.0) (2020-07-04)
205
-
206
- ### Breaking Changes
207
-
208
- * guard against overriding local files
209
- * add '--override' flag for previous behavior
210
-
211
- ## [2.0.0](https://github.com/lightpohl/podcast-dl/compare/v1.6.1...v2.0.0) (2020-06-06)
212
-
213
- ### Breaking Changes
214
-
215
- * add recursive flag to mkdir for '--out-dir'
216
- * use podcast title in meta file name if available
217
- * default '--out-dir' to podcast specific folder
218
- * include podcast title name in feed image
219
-
220
- ### [1.6.1](https://github.com/lightpohl/podcast-dl/compare/v1.6.0...v1.6.1) (2020-05-24)
221
-
222
-
223
- ### Bug Fixes
224
-
225
- * do not show "100%" progress when dowload first starts ([3bc3152](https://github.com/lightpohl/podcast-dl/commit/3bc315265e95fee54464e6125598d668b9f3f27e))
226
-
227
- ## [1.6.0](https://github.com/lightpohl/podcast-dl/compare/v1.5.0...v1.6.0) (2020-05-17)
228
-
229
-
230
- ### Features
231
-
232
- * add podcast title/link templating options to '--out-dir' ([b4c526b](https://github.com/lightpohl/podcast-dl/commit/b4c526bf54c83863262c81b0e9a35c6a0adc411f))
233
-
234
- ## [1.5.0](https://github.com/lightpohl/podcast-dl/compare/v1.4.6...v1.5.0) (2020-05-17)
235
-
236
-
237
- ### Features
238
-
239
- * add '--episode-template' option ([93044d5](https://github.com/lightpohl/podcast-dl/commit/93044d5da53b05eddbc10ec4efda2711609916b8)), closes [#4](https://github.com/lightpohl/podcast-dl/issues/4)
240
-
241
- ### [1.4.6](https://github.com/lightpohl/podcast-dl/compare/v1.4.5...v1.4.6) (2020-05-11)
242
-
243
-
244
- ### Bug Fixes
245
-
246
- * do not archive if file fails to save ([dfe9656](https://github.com/lightpohl/podcast-dl/commit/dfe96560724fd6d1f5462c86595d4d613037c669))
247
-
248
- ### [1.4.5](https://github.com/lightpohl/podcast-dl/compare/v1.4.4...v1.4.5) (2020-05-10)
249
-
250
-
251
- ### Bug Fixes
252
-
253
- * infinite error after unable to find episode URL ([43817d6](https://github.com/lightpohl/podcast-dl/commit/43817d6e096fb1b7de7914e25ecf55ec77065b7a))
254
-
255
- ### [1.4.4](https://github.com/lightpohl/podcast-dl/compare/v1.4.3...v1.4.4) (2020-05-10)
256
-
257
-
258
- ### Bug Fixes
259
-
260
- * add HEAD check before asset downloads ([2b6edf2](https://github.com/lightpohl/podcast-dl/commit/2b6edf27ac5d1a6602f33326daef7a3b597b78c7))
261
-
262
- ### [1.4.3](https://github.com/lightpohl/podcast-dl/compare/v1.4.2...v1.4.3) (2020-05-09)
263
-
264
- ### [1.4.2](https://github.com/lightpohl/podcast-dl/compare/v1.4.1...v1.4.2) (2020-05-09)
265
-
266
-
267
- ### Bug Fixes
268
-
269
- * add download cleanup on error: ([978db00](https://github.com/lightpohl/podcast-dl/commit/978db005148e5f44cb7f0341ca49b48b60848dfc))
270
-
271
- ### [1.4.1](https://github.com/lightpohl/podcast-dl/compare/v1.4.0...v1.4.1) (2020-05-09)
272
-
273
-
274
- ### Bug Fixes
275
-
276
- * episode images should not override episodes ([7716bdc](https://github.com/lightpohl/podcast-dl/commit/7716bdc45629fc7a1f2fe84b13e3167a924117d0))
277
-
278
- ## [1.4.0](https://github.com/lightpohl/podcast-dl/compare/v1.3.1...v1.4.0) (2020-05-09)
279
-
280
-
281
- ### Features
282
-
283
- * add --archive option ([29b6399](https://github.com/lightpohl/podcast-dl/commit/29b63996e07e44b142fda470904c12dbc948ba72)), closes [#2](https://github.com/lightpohl/podcast-dl/issues/2)
284
-
285
-
286
- ### Bug Fixes
287
-
288
- * 'episodes' typo in prompt after selecting episodes ([6e06ec3](https://github.com/lightpohl/podcast-dl/commit/6e06ec37cea6b3a17c7607d5820955b389e81cc0))
289
-
290
- ### [1.3.1](https://github.com/lightpohl/podcast-dl/compare/v1.3.0...v1.3.1) (2020-05-08)
291
-
292
-
293
- ### Bug Fixes
294
-
295
- * counter in prompt loop incorrect ([2f2f0ae](https://github.com/lightpohl/podcast-dl/commit/2f2f0aea8a4e3d28b0ae3915a3f087999d9b1763))
296
-
297
- ## [1.3.0](https://github.com/lightpohl/podcast-dl/compare/v1.2.0...v1.3.0) (2020-05-08)
298
-
299
-
300
- ### Features
301
-
302
- * add basic --prompt option ([225db58](https://github.com/lightpohl/podcast-dl/commit/225db58767112e39f28db5b859a9c9d61f7cafeb))
303
-
304
- ## [1.2.0](https://github.com/lightpohl/podcast-dl/compare/v1.1.1...v1.2.0) (2020-05-07)
305
-
306
-
307
- ### Features
308
-
309
- * add --list option for episode data ([90b3b80](https://github.com/lightpohl/podcast-dl/commit/90b3b80464e96f14a23c8a21ddd502c591ec6a0f))
310
- * add --reverse option ([dcae39c](https://github.com/lightpohl/podcast-dl/commit/dcae39c0552de9401846e4a41beda7db077a77e8))
311
-
312
- ### [1.1.1](https://github.com/lightpohl/podcast-dl/compare/v1.1.0...v1.1.1) (2020-04-30)
313
-
314
- ## [1.1.0](https://github.com/lightpohl/podcast-dl/compare/v1.0.2...v1.1.0) (2020-04-27)
315
-
316
-
317
- ### Features
318
-
319
- * add --offset and --limit options ([b71bc91](https://github.com/lightpohl/podcast-dl/commit/b71bc91e53ce2b6b8a32255afca6cc9b1cfa244e))
320
-
321
-
322
- ### Bug Fixes
323
-
324
- * only pluralize episodes when not 1 item ([9449899](https://github.com/lightpohl/podcast-dl/commit/94498990569a81b6f06d37f2a2a0f64d72bdcc56))
325
-
326
- ### [1.0.2](https://github.com/lightpohl/podcast-dl/compare/v1.0.1...v1.0.2) (2020-04-26)
327
-
328
-
329
- ### Bug Fixes
330
-
331
- * incorrectly referenced bin ([921a887](https://github.com/lightpohl/podcast-dl/commit/921a887508160bc3e58cb633301da9774062d586))
332
-
333
- ### [1.0.1](https://github.com/lightpohl/podcast-dl/compare/v1.0.0...v1.0.1) (2020-04-26)
334
-
335
- ## 1.0.0 (2020-04-26)
336
-
337
-
338
- ### Features
339
-
340
- * add initial download script ([166426a](https://github.com/lightpohl/podcast-dl/commit/166426a54a135f558f9665188cee2c50ea8a3f7f))
341
- * add metadata retrieval options ([912062a](https://github.com/lightpohl/podcast-dl/commit/912062adfbd163c44f36c4fd73d0fc47fb12f195))