eleventy-plugin-podcaster 2.0.1 → 2.0.2
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/TODO.md +24 -0
- package/package.json +1 -2
- package/src/calculateEpisodeSizeAndDuration.js +2 -3
- package/src/podcastData.js +2 -4
- package/src/readableDuration.js +24 -5
- package/src/readableFilters.js +9 -14
package/TODO.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
## Warnings and errors for missing data
|
|
4
|
+
|
|
5
|
+
Add consistent warnings and errors when required data is missing. This should be opt-in via a plugin option to avoid a breaking change.
|
|
6
|
+
|
|
7
|
+
Behaviour:
|
|
8
|
+
|
|
9
|
+
- In development (`ELEVENTY_RUN_MODE === 'serve'`): log warnings but continue the build
|
|
10
|
+
- In production: throw errors and stop the build
|
|
11
|
+
|
|
12
|
+
Cases to handle:
|
|
13
|
+
|
|
14
|
+
- Missing `podcast.json` or required fields within it
|
|
15
|
+
- Episode post without a matching audio file
|
|
16
|
+
- Malformed episode numbering in filenames
|
|
17
|
+
- Incomplete S3 configuration (some keys but not others)
|
|
18
|
+
- Missing audio file when calculating duration/size
|
|
19
|
+
|
|
20
|
+
Implementation notes:
|
|
21
|
+
|
|
22
|
+
- Use a consistent prefix like `[podcaster]` so messages are identifiable
|
|
23
|
+
- New plugin option (e.g., `strictMode` or `validateData`) to enable this
|
|
24
|
+
- The draft system may already cover some cases (e.g., incomplete episodes marked as drafts)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eleventy-plugin-podcaster",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "An Eleventy plugin that allows you to create a podcast and its accompanying website",
|
|
5
5
|
"main": "eleventy.config.js",
|
|
6
6
|
"exports": {
|
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"@tsmx/human-readable": "^2.0.3",
|
|
35
35
|
"dom-serializer": "^2.0.0",
|
|
36
36
|
"htmlparser2": "^9.1.0",
|
|
37
|
-
"luxon": "^3.4.4",
|
|
38
37
|
"markdown-it": "^14.1.0",
|
|
39
38
|
"music-metadata": "^11.7.1"
|
|
40
39
|
},
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { DateTime } from 'luxon'
|
|
2
1
|
import readableDuration from './readableDuration.js'
|
|
3
2
|
import path from 'node:path'
|
|
4
3
|
import { existsSync, readFileSync } from 'node:fs'
|
|
@@ -96,7 +95,7 @@ async function getCachedEpisodeDataFromS3Bucket (s3Storage, s3Bucket) {
|
|
|
96
95
|
async function calculateEpisodeDataFromS3Bucket (s3Storage, s3Bucket) {
|
|
97
96
|
const cachedEpisodeData = await getCachedEpisodeDataFromS3Bucket(s3Storage, s3Bucket)
|
|
98
97
|
const cachedEpisodeDataLastModifiedDate = (cachedEpisodeData.lastModified)
|
|
99
|
-
?
|
|
98
|
+
? new Date(cachedEpisodeData.lastModified)
|
|
100
99
|
: null
|
|
101
100
|
|
|
102
101
|
console.log(`Reading episode data from S3 bucket ${s3Bucket}`)
|
|
@@ -111,7 +110,7 @@ async function calculateEpisodeDataFromS3Bucket (s3Storage, s3Bucket) {
|
|
|
111
110
|
!('size' in result[filename]) ||
|
|
112
111
|
!('duration' in result[filename]) ||
|
|
113
112
|
!cachedEpisodeDataLastModifiedDate ||
|
|
114
|
-
cachedEpisodeDataLastModifiedDate <
|
|
113
|
+
cachedEpisodeDataLastModifiedDate < new Date(lastModified)) {
|
|
115
114
|
const { buffer } = await getObjectFromS3Bucket(s3Storage, s3Bucket, filename)
|
|
116
115
|
const metadata = await parseBufferMetadata(buffer, null, { duration: true })
|
|
117
116
|
const duration = metadata.format.duration
|
package/src/podcastData.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { DateTime } from 'luxon'
|
|
2
|
-
|
|
3
1
|
export default function (eleventyConfig) {
|
|
4
2
|
eleventyConfig.addGlobalData('eleventyComputed.podcast.feedPath', () => {
|
|
5
3
|
return data => data.podcast.feedPath || '/feed/podcast.xml'
|
|
@@ -23,7 +21,7 @@ export default function (eleventyConfig) {
|
|
|
23
21
|
})
|
|
24
22
|
|
|
25
23
|
function constructCopyrightNotice (data) {
|
|
26
|
-
const thisYear =
|
|
24
|
+
const thisYear = new Date().getFullYear()
|
|
27
25
|
let yearRange
|
|
28
26
|
if (!data.podcast.startingYear || data.podcast.startingYear === thisYear) {
|
|
29
27
|
yearRange = thisYear
|
|
@@ -40,5 +38,5 @@ export default function (eleventyConfig) {
|
|
|
40
38
|
eleventyConfig.addGlobalData('eleventyComputed.copyrightNotice', () => {
|
|
41
39
|
return constructCopyrightNotice
|
|
42
40
|
})
|
|
43
|
-
eleventyConfig.addGlobalData('podcast.feedLastBuildDate',
|
|
41
|
+
eleventyConfig.addGlobalData('podcast.feedLastBuildDate', new Date().toUTCString().replace('GMT', '+0000'))
|
|
44
42
|
}
|
package/src/readableDuration.js
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
function pluralise (value, unit) {
|
|
2
|
+
return `${value} ${unit}${value === 1 ? '' : 's'}`
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function toComponents (seconds) {
|
|
6
|
+
return {
|
|
7
|
+
d: Math.floor(seconds / 86400),
|
|
8
|
+
h: Math.floor((seconds % 86400) / 3600),
|
|
9
|
+
m: Math.floor((seconds % 3600) / 60),
|
|
10
|
+
s: Math.round((seconds % 60) * 1000) / 1000
|
|
11
|
+
}
|
|
12
|
+
}
|
|
2
13
|
|
|
3
14
|
export default {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
longFormat (seconds) {
|
|
16
|
+
const { d, h, m, s } = toComponents(seconds)
|
|
17
|
+
return [pluralise(d, 'day'), pluralise(h, 'hour'), pluralise(m, 'minute'), pluralise(s, 'second')].join(', ')
|
|
18
|
+
},
|
|
19
|
+
shortFormat (seconds) {
|
|
20
|
+
const h = Math.floor(seconds / 3600)
|
|
21
|
+
const m = Math.floor((seconds % 3600) / 60)
|
|
22
|
+
const s = Math.floor(seconds % 60)
|
|
23
|
+
if (h === 0) {
|
|
24
|
+
return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`
|
|
25
|
+
}
|
|
26
|
+
return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`
|
|
8
27
|
},
|
|
9
28
|
convertToSeconds (duration) {
|
|
10
29
|
const durationPattern = /^(?:(?<hours>\d+):)?(?<minutes>\d{1,2}):(?<seconds>\d{2}(?:\.\d+)?)$/
|
package/src/readableFilters.js
CHANGED
|
@@ -1,29 +1,24 @@
|
|
|
1
|
-
import { DateTime, Duration } from 'luxon'
|
|
2
1
|
import hr from '@tsmx/human-readable'
|
|
2
|
+
import readableDuration from './readableDuration.js'
|
|
3
3
|
|
|
4
4
|
export default function (eleventyConfig, options = {}) {
|
|
5
5
|
eleventyConfig.addFilter('readableDate', function (date) {
|
|
6
6
|
const readableDateLocale = options.readableDateLocale ?? 'en-AU'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
return new Date(date).toLocaleDateString(readableDateLocale, {
|
|
8
|
+
weekday: 'long',
|
|
9
|
+
year: 'numeric',
|
|
10
|
+
month: 'long',
|
|
11
|
+
day: 'numeric',
|
|
12
|
+
timeZone: 'UTC'
|
|
12
13
|
})
|
|
13
|
-
return result.setLocale(readableDateLocale).toLocaleString(DateTime.DATE_HUGE)
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
eleventyConfig.addFilter('readableDuration', (seconds, length) => {
|
|
17
17
|
if (!seconds) return '0:00'
|
|
18
18
|
if (length === 'long') {
|
|
19
|
-
return
|
|
20
|
-
.shiftTo('days', 'hours', 'minutes', 'seconds')
|
|
21
|
-
.toHuman()
|
|
22
|
-
} else if (seconds < 60 * 60) {
|
|
23
|
-
return Duration.fromMillis(seconds * 1000).toFormat('mm:ss')
|
|
24
|
-
} else {
|
|
25
|
-
return Duration.fromMillis(seconds * 1000).toFormat('h:mm:ss')
|
|
19
|
+
return readableDuration.longFormat(seconds)
|
|
26
20
|
}
|
|
21
|
+
return readableDuration.shortFormat(seconds)
|
|
27
22
|
})
|
|
28
23
|
|
|
29
24
|
eleventyConfig.addFilter('readableSize', (bytes, fixedPrecision = 1) =>
|