eleventy-plugin-podcaster 2.0.0-alpha.3 → 2.0.0-alpha.4

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.
@@ -1,3 +1,5 @@
1
+ import path from 'node:path'
2
+
1
3
  import podcastFeed from './src/podcastFeed.js'
2
4
  import podcastData from './src/podcastData.js'
3
5
  import episodeData from './src/episodeData.js'
@@ -10,6 +12,11 @@ import drafts from './src/drafts.js'
10
12
  import pageTitle from './src/pageTitle.js'
11
13
 
12
14
  export default function (eleventyConfig, options = {}) {
15
+ const episodePostsDirectory = options.episodePostsDirectory ?? 'episode-posts'
16
+ options.episodePostsDirectory = path.join(eleventyConfig.directories.input, episodePostsDirectory)
17
+ const episodeFilesDirectory = options.episodeFilesDirectory ?? 'episode-files'
18
+ options.episodeFilesDirectory = path.join(eleventyConfig.directories.input, episodeFilesDirectory)
19
+
13
20
  eleventyConfig.addPlugin(podcastFeed, options)
14
21
  eleventyConfig.addPlugin(podcastData, options)
15
22
  eleventyConfig.addPlugin(episodeData, options)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eleventy-plugin-podcaster",
3
- "version": "2.0.0-alpha.3",
3
+ "version": "2.0.0-alpha.4",
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": {
@@ -32,7 +32,6 @@
32
32
  "@11ty/eleventy-plugin-rss": "^2.0.1",
33
33
  "@aws-sdk/client-s3": "^3.862.0",
34
34
  "@tsmx/human-readable": "^2.0.3",
35
- "chalk": "^5.3.0",
36
35
  "dom-serializer": "^2.0.0",
37
36
  "htmlparser2": "^9.1.0",
38
37
  "luxon": "^3.4.4",
@@ -1,7 +1,9 @@
1
+ import isEpisodePost from './isEpisodePost.js'
2
+
1
3
  function findMatchingFilename (episodeData, thisEpisode) {
2
4
  const filenameSeasonAndEpisodePattern =
3
- /^.*?\b[sS](?<seasonNumber>\d+)\s*[eE](?<episodeNumber>\d+)\b.*\.mp3$/
4
- const filenameEpisodePattern = /^.*?\b(?<episodeNumber>\d+)\b.*\.mp3$/
5
+ /^.*?\b[sS](?<seasonNumber>\d+)\s*[eE](?<episodeNumber>\d+)\b.*\.(mp3|m4a)$/
6
+ const filenameEpisodePattern = /^.*?\b(?<episodeNumber>\d+)\b.*\.(mp3|m4a)$/
5
7
  const { seasonNumber, episodeNumber } = thisEpisode
6
8
 
7
9
  for (const file of Object.keys(episodeData)) {
@@ -27,11 +29,11 @@ function findMatchingFilename (episodeData, thisEpisode) {
27
29
  }
28
30
  }
29
31
 
30
- export default function (eleventyConfig, _options) {
32
+ export default function (eleventyConfig, options) {
31
33
  eleventyConfig.addGlobalData('eleventyComputed.episode.filename', () => {
32
34
  return data => {
33
35
  if (data.episode.filename) return data.episode.filename
34
- if (!data.page.inputPath.includes('/episodePosts/')) return
36
+ if (!isEpisodePost(data, options)) return
35
37
 
36
38
  return findMatchingFilename(data.episodeData, data.episode)
37
39
  }
@@ -6,7 +6,10 @@ import { Writable } from 'node:stream'
6
6
  import { S3Client, ListObjectsCommand, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3'
7
7
  import { parseFile as parseFileMetadata, parseBuffer as parseBufferMetadata } from 'music-metadata'
8
8
  import hr from '@tsmx/human-readable'
9
- import chalk from 'chalk'
9
+ import isEpisodePost from './isEpisodePost.js'
10
+
11
+ const isAudioFile = episodeFilename => episodeFilename.endsWith('.mp3') ||
12
+ episodeFilename.endsWith('.m4a')
10
13
 
11
14
  const convertSecondsToReadableDuration = seconds =>
12
15
  Duration.fromMillis(seconds * 1000)
@@ -35,7 +38,7 @@ async function readEpisodeDataLocally (episodeFilesDirectory) {
35
38
  const episodes = await readdir(episodeFilesDirectory)
36
39
  const episodeData = {}
37
40
  for (const episode of episodes) {
38
- if (!episode.endsWith('.mp3')) continue
41
+ if (!isAudioFile(episode)) continue
39
42
 
40
43
  const episodePath = path.join(episodeFilesDirectory, episode)
41
44
  const episodeSize = (await stat(episodePath)).size
@@ -59,7 +62,7 @@ function calculatePodcastData (episodeData) {
59
62
 
60
63
  function reportPodcastData (podcastData) {
61
64
  const { numberOfEpisodes, totalSize, totalDuration } = podcastData
62
- console.log(chalk.yellow(`${numberOfEpisodes} episodes; ${hr.fromBytes(totalSize)}; ${convertSecondsToReadableDuration(totalDuration)}.`))
65
+ console.log(`\u001b[33m${numberOfEpisodes} episodes; ${hr.fromBytes(totalSize)}; ${convertSecondsToReadableDuration(totalDuration)}.\u001b[0m`)
63
66
  }
64
67
 
65
68
  async function writePodcastDataLocally (episodeData, podcastData, directories) {
@@ -130,7 +133,7 @@ async function updateEpisodeDataFromS3Bucket (s3Client, s3Bucket) {
130
133
  const list = await s3Client.send(new ListObjectsCommand({ Bucket: s3Bucket }))
131
134
  const result = { ...storedEpisodeData.episodeData }
132
135
  for (const item of list.Contents ?? []) {
133
- if (!item.Key.endsWith('.mp3')) continue
136
+ if (!isAudioFile(item.Key)) continue
134
137
 
135
138
  const { Key: filename, Size: size, LastModified: lastModified } = item
136
139
 
@@ -163,7 +166,7 @@ export default function (eleventyConfig, options = {}) {
163
166
  if (!firstRun || process.env.SKIP_EPISODE_CALCULATIONS === 'true') return
164
167
  firstRun = false
165
168
 
166
- const episodeFilesDirectory = path.join(directories.input, 'episodeFiles')
169
+ const episodeFilesDirectory = options.episodeFilesDirectory
167
170
  let episodeData
168
171
  if (existsSync(episodeFilesDirectory)) {
169
172
  episodeData = await readEpisodeDataLocally(episodeFilesDirectory)
@@ -183,7 +186,7 @@ export default function (eleventyConfig, options = {}) {
183
186
  eleventyConfig.addGlobalData('eleventyComputed.episode.size', () => {
184
187
  return data => {
185
188
  if (data.episode.size) return data.episode.size
186
- if (data.page.inputPath.includes('/episodePosts/') && data.episodeData) {
189
+ if (isEpisodePost(data, options) && data.episodeData) {
187
190
  return data.episodeData[data.episode.filename]?.size
188
191
  }
189
192
  }
@@ -196,7 +199,7 @@ export default function (eleventyConfig, options = {}) {
196
199
  return convertedReadableDuration ?? data.episode.duration
197
200
  }
198
201
 
199
- if (data.page.inputPath.includes('/episodePosts/') && data.episodeData) {
202
+ if (isEpisodePost(data, options) && data.episodeData) {
200
203
  return data.episodeData[data.episode.filename]?.duration
201
204
  }
202
205
  }
@@ -1,3 +1,5 @@
1
+ import isEpisodePost from './isEpisodePost.js'
2
+
1
3
  export default function (eleventyConfig, options = {}) {
2
4
  const postFilenameSeasonAndEpisodePattern =
3
5
  /^[sS](?<seasonNumber>\d+)[eE](?<episodeNumber>\d+)/i
@@ -7,7 +9,7 @@ export default function (eleventyConfig, options = {}) {
7
9
  return data => {
8
10
  if (data.episode?.seasonNumber) return data.episode.seasonNumber
9
11
 
10
- if (!data.page.inputPath.includes('/episodePosts/')) return
12
+ if (!isEpisodePost(data, options)) return
11
13
 
12
14
  const seasonAndEpisodeMatch = data.page.fileSlug.match(postFilenameSeasonAndEpisodePattern)
13
15
  if (seasonAndEpisodeMatch) {
@@ -20,7 +22,7 @@ export default function (eleventyConfig, options = {}) {
20
22
  return data => {
21
23
  if (data.episode?.episodeNumber) return data.episode.episodeNumber
22
24
 
23
- if (!data.page.inputPath.includes('/episodePosts/')) return
25
+ if (!isEpisodePost(data, options)) return
24
26
 
25
27
  const seasonAndEpisodeMatch = data.page.fileSlug.match(postFilenameSeasonAndEpisodePattern)
26
28
  if (seasonAndEpisodeMatch) {
@@ -49,7 +51,7 @@ export default function (eleventyConfig, options = {}) {
49
51
 
50
52
  eleventyConfig.addGlobalData('eleventyComputed.episode.url', () => {
51
53
  return data => {
52
- if (!data.page.inputPath.includes('/episodePosts/')) return
54
+ if (!isEpisodePost(data, options)) return
53
55
 
54
56
  const episodeUrlBase = data.podcast.episodeUrlBase
55
57
  const filename = data.episode.filename
package/src/excerpts.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import * as htmlparser2 from 'htmlparser2'
2
2
  import render from 'dom-serializer'
3
3
  import markdownIt from 'markdown-it'
4
+ import isEpisodePost from './isEpisodePost.js'
4
5
 
5
6
  export default function (eleventyConfig, options = {}) {
6
7
  eleventyConfig.addGlobalData('eleventyComputed.excerpt', () => {
7
8
  return (data) => {
8
- if (!data.page.inputPath.includes('/episodePosts/')) return
9
+ if (!isEpisodePost(data, options)) return
9
10
 
10
11
  const md = markdownIt({
11
12
  html: true,
@@ -0,0 +1,10 @@
1
+ import path from 'node:path'
2
+
3
+ export default function isEpisodePost (data, options) {
4
+ if (data.page?.inputPath) {
5
+ const importPath = path.normalize(data.page.inputPath)
6
+ return importPath.startsWith(options.episodePostsDirectory)
7
+ } else {
8
+ return false
9
+ }
10
+ }
@@ -1,6 +1,7 @@
1
1
  import rssPlugin from '@11ty/eleventy-plugin-rss'
2
2
  import { readFileSync } from 'node:fs'
3
3
  import path from 'node:path'
4
+ import isEpisodePost from './isEpisodePost.js'
4
5
 
5
6
  export default function (eleventyConfig, options = {}) {
6
7
  if (!('addTemplate' in eleventyConfig)) {
@@ -12,7 +13,7 @@ export default function (eleventyConfig, options = {}) {
12
13
  eleventyConfig.addTemplate('feed.njk', readFileSync(podcastFeedPath), {
13
14
  eleventyExcludeFromCollections: true,
14
15
  eleventyImport: {
15
- collections: ['podcastEpisode']
16
+ collections: ['episodePost']
16
17
  }
17
18
  })
18
19
 
@@ -22,7 +23,7 @@ export default function (eleventyConfig, options = {}) {
22
23
  }
23
24
  })
24
25
 
25
- eleventyConfig.addCollection('podcastEpisode', (collectionApi) => {
26
- return collectionApi.getFilteredByGlob('**/episodePosts/*')
26
+ eleventyConfig.addCollection('episodePost', (collectionApi) => {
27
+ return collectionApi.getAll().filter(item => isEpisodePost(item.data, options))
27
28
  })
28
29
  }
@@ -17,7 +17,7 @@ eleventyAllowMissingExtension: true
17
17
  <description>{{ podcast.description }}</description>
18
18
  <language>{{ podcast.language }}</language>
19
19
  <copyright>{{ podcast.copyrightNotice }}</copyright>
20
- <pubDate>{{ collections.podcastEpisode | getNewestCollectionItemDate | dateToRfc3339 }}</pubDate>
20
+ <pubDate>{{ collections.episodePost | getNewestCollectionItemDate | dateToRfc3339 }}</pubDate>
21
21
  <lastBuildDate>{{ podcast.feedLastBuildDate }}</lastBuildDate>
22
22
  <itunes:image href="{{ podcast.imagePath | htmlBaseUrl(siteUrl) }}"></itunes:image>
23
23
  {%- if podcast.subcategory %}
@@ -47,7 +47,7 @@ eleventyAllowMissingExtension: true
47
47
  </itunes:owner>
48
48
  {%- endif %}
49
49
 
50
- {% for post in collections.podcastEpisode | reverse %}
50
+ {% for post in collections.episodePost | reverse %}
51
51
  <item>
52
52
  <title>{{ post.data.episode.title or post.data.title }}</title>
53
53
  {% if post.data.episode.itunesTitle %}