eleventy-plugin-podcaster 2.0.0-alpha.1 → 2.0.0-alpha.3
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/.env +5 -0
- package/eleventy.config.js +5 -2
- package/package.json +4 -1
- package/src/calculateEpisodeFilename.js +39 -0
- package/src/calculateEpisodeSizeAndDuration.js +204 -0
- package/src/drafts.js +2 -2
- package/src/readableFilters.js +8 -3
- package/src/calculateFilenameSizeAndDuration.js +0 -106
package/.env
ADDED
package/eleventy.config.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import podcastFeed from './src/podcastFeed.js'
|
|
2
2
|
import podcastData from './src/podcastData.js'
|
|
3
3
|
import episodeData from './src/episodeData.js'
|
|
4
|
-
import
|
|
4
|
+
import calculateEpisodeSizeAndDuration from './src/calculateEpisodeSizeAndDuration.js'
|
|
5
|
+
import calculateEpisodeFilename from './src/calculateEpisodeFilename.js'
|
|
6
|
+
|
|
5
7
|
import readableFilters from './src/readableFilters.js'
|
|
6
8
|
import excerpts from './src/excerpts.js'
|
|
7
9
|
import drafts from './src/drafts.js'
|
|
@@ -11,7 +13,8 @@ export default function (eleventyConfig, options = {}) {
|
|
|
11
13
|
eleventyConfig.addPlugin(podcastFeed, options)
|
|
12
14
|
eleventyConfig.addPlugin(podcastData, options)
|
|
13
15
|
eleventyConfig.addPlugin(episodeData, options)
|
|
14
|
-
eleventyConfig.addPlugin(
|
|
16
|
+
eleventyConfig.addPlugin(calculateEpisodeSizeAndDuration, options)
|
|
17
|
+
eleventyConfig.addPlugin(calculateEpisodeFilename, options)
|
|
15
18
|
|
|
16
19
|
// Filters
|
|
17
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eleventy-plugin-podcaster",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.3",
|
|
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": {
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@11ty/eleventy": "^3.0.0",
|
|
32
32
|
"@11ty/eleventy-plugin-rss": "^2.0.1",
|
|
33
|
+
"@aws-sdk/client-s3": "^3.862.0",
|
|
33
34
|
"@tsmx/human-readable": "^2.0.3",
|
|
34
35
|
"chalk": "^5.3.0",
|
|
35
36
|
"dom-serializer": "^2.0.0",
|
|
@@ -40,7 +41,9 @@
|
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"ava": "^6.1.3",
|
|
44
|
+
"dotenv": "^17.2.1",
|
|
43
45
|
"fast-xml-parser": "^4.4.0",
|
|
46
|
+
"mock-aws-s3-v3": "^6.0.5",
|
|
44
47
|
"neostandard": "^0.11.4"
|
|
45
48
|
}
|
|
46
49
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
function findMatchingFilename (episodeData, thisEpisode) {
|
|
2
|
+
const filenameSeasonAndEpisodePattern =
|
|
3
|
+
/^.*?\b[sS](?<seasonNumber>\d+)\s*[eE](?<episodeNumber>\d+)\b.*\.mp3$/
|
|
4
|
+
const filenameEpisodePattern = /^.*?\b(?<episodeNumber>\d+)\b.*\.mp3$/
|
|
5
|
+
const { seasonNumber, episodeNumber } = thisEpisode
|
|
6
|
+
|
|
7
|
+
for (const file of Object.keys(episodeData)) {
|
|
8
|
+
if (seasonNumber && episodeNumber) {
|
|
9
|
+
const seasonAndEpisodeMatch = file.match(filenameSeasonAndEpisodePattern)
|
|
10
|
+
if (seasonAndEpisodeMatch) {
|
|
11
|
+
const matchedSeasonNumber = parseInt(seasonAndEpisodeMatch.groups.seasonNumber)
|
|
12
|
+
const matchedEpisodeNumber = parseInt(seasonAndEpisodeMatch.groups.episodeNumber)
|
|
13
|
+
if (matchedSeasonNumber === seasonNumber &&
|
|
14
|
+
matchedEpisodeNumber === episodeNumber) {
|
|
15
|
+
return file
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
} else if (episodeNumber) {
|
|
19
|
+
const episodeMatch = file.match(filenameEpisodePattern)
|
|
20
|
+
if (episodeMatch) {
|
|
21
|
+
const matchedEpisodeNumber = parseInt(episodeMatch.groups.episodeNumber)
|
|
22
|
+
if (matchedEpisodeNumber === episodeNumber) {
|
|
23
|
+
return file
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default function (eleventyConfig, _options) {
|
|
31
|
+
eleventyConfig.addGlobalData('eleventyComputed.episode.filename', () => {
|
|
32
|
+
return data => {
|
|
33
|
+
if (data.episode.filename) return data.episode.filename
|
|
34
|
+
if (!data.page.inputPath.includes('/episodePosts/')) return
|
|
35
|
+
|
|
36
|
+
return findMatchingFilename(data.episodeData, data.episode)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { Duration, DateTime } from 'luxon'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import { readdir, stat, writeFile } from 'node:fs/promises'
|
|
5
|
+
import { Writable } from 'node:stream'
|
|
6
|
+
import { S3Client, ListObjectsCommand, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3'
|
|
7
|
+
import { parseFile as parseFileMetadata, parseBuffer as parseBufferMetadata } from 'music-metadata'
|
|
8
|
+
import hr from '@tsmx/human-readable'
|
|
9
|
+
import chalk from 'chalk'
|
|
10
|
+
|
|
11
|
+
const convertSecondsToReadableDuration = seconds =>
|
|
12
|
+
Duration.fromMillis(seconds * 1000)
|
|
13
|
+
.shiftTo('days', 'hours', 'minutes', 'seconds')
|
|
14
|
+
.toHuman()
|
|
15
|
+
|
|
16
|
+
const convertReadableDurationToSeconds = duration => {
|
|
17
|
+
const durationPattern = /^(?:(?<hours>\d+):)?(?<minutes>\d{1,2}):(?<seconds>\d{2}(?:\.\d+)?)$/
|
|
18
|
+
|
|
19
|
+
let match
|
|
20
|
+
if (duration?.match) {
|
|
21
|
+
match = duration.match(durationPattern)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (match) {
|
|
25
|
+
const hours = isNaN(parseInt(match.groups.hours))
|
|
26
|
+
? 0
|
|
27
|
+
: parseInt(match.groups.hours)
|
|
28
|
+
const minutes = parseInt(match.groups.minutes)
|
|
29
|
+
const seconds = parseFloat(match.groups.seconds)
|
|
30
|
+
return hours * 3600 + minutes * 60 + seconds
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function readEpisodeDataLocally (episodeFilesDirectory) {
|
|
35
|
+
const episodes = await readdir(episodeFilesDirectory)
|
|
36
|
+
const episodeData = {}
|
|
37
|
+
for (const episode of episodes) {
|
|
38
|
+
if (!episode.endsWith('.mp3')) continue
|
|
39
|
+
|
|
40
|
+
const episodePath = path.join(episodeFilesDirectory, episode)
|
|
41
|
+
const episodeSize = (await stat(episodePath)).size
|
|
42
|
+
const episodeMetadata = await parseFileMetadata(episodePath, { duration: true })
|
|
43
|
+
const episodeDuration = episodeMetadata.format.duration
|
|
44
|
+
episodeData[episode] = {
|
|
45
|
+
size: episodeSize,
|
|
46
|
+
duration: episodeDuration
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return episodeData
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function calculatePodcastData (episodeData) {
|
|
53
|
+
const episodeDataValues = Object.values(episodeData)
|
|
54
|
+
const numberOfEpisodes = episodeDataValues.length
|
|
55
|
+
const totalSize = episodeDataValues.map(x => x.size).reduce((x, y) => x + y)
|
|
56
|
+
const totalDuration = episodeDataValues.map(x => x.duration).reduce((x, y) => x + y)
|
|
57
|
+
return { numberOfEpisodes, totalSize, totalDuration }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function reportPodcastData (podcastData) {
|
|
61
|
+
const { numberOfEpisodes, totalSize, totalDuration } = podcastData
|
|
62
|
+
console.log(chalk.yellow(`${numberOfEpisodes} episodes; ${hr.fromBytes(totalSize)}; ${convertSecondsToReadableDuration(totalDuration)}.`))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function writePodcastDataLocally (episodeData, podcastData, directories) {
|
|
66
|
+
const dataDir = path.join(process.cwd(), directories.data)
|
|
67
|
+
await writeFile(path.join(dataDir, 'episodeData.json'), JSON.stringify(episodeData, null, 2))
|
|
68
|
+
await writeFile(path.join(dataDir, 'podcastData.json'), JSON.stringify(podcastData, null, 2))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getS3Client (options) {
|
|
72
|
+
if (options.s3ClientObject) return options.s3ClientObject
|
|
73
|
+
|
|
74
|
+
if (options.s3Client) {
|
|
75
|
+
return new S3Client({
|
|
76
|
+
forcePathStyle: true,
|
|
77
|
+
endpoint: options.s3Client.endpoint,
|
|
78
|
+
region: options.s3Client.region,
|
|
79
|
+
credentials: {
|
|
80
|
+
accessKeyId: options.s3Client.accessKey,
|
|
81
|
+
secretAccessKey: options.s3Client.secretKey
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function getObjectFromS3Bucket (s3Client, s3Bucket, key) {
|
|
88
|
+
const getObjectResponse = await s3Client.send(new GetObjectCommand({ Bucket: s3Bucket, Key: key }))
|
|
89
|
+
|
|
90
|
+
const chunks = []
|
|
91
|
+
if (typeof getObjectResponse.Body.pipe === 'function') {
|
|
92
|
+
// this is to cope with the behaviour of the mock, which doesn't return an iterator full of chunks
|
|
93
|
+
const writable = new Writable({
|
|
94
|
+
write (chunk, encoding, callback) {
|
|
95
|
+
chunks.push(chunk)
|
|
96
|
+
callback()
|
|
97
|
+
},
|
|
98
|
+
final (callback) {
|
|
99
|
+
callback()
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
getObjectResponse.Body.pipe(writable)
|
|
103
|
+
await new Promise((resolve, reject) => {
|
|
104
|
+
writable.on('finish', resolve)
|
|
105
|
+
writable.on('error', reject)
|
|
106
|
+
})
|
|
107
|
+
} else {
|
|
108
|
+
for await (const chunk of getObjectResponse.Body) {
|
|
109
|
+
chunks.push(chunk)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const buffer = Buffer.concat(chunks)
|
|
113
|
+
return { buffer, lastModified: getObjectResponse.LastModified }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function getStoredEpisodeDataFromS3Bucket (s3Client, s3BucketName) {
|
|
117
|
+
try {
|
|
118
|
+
const { buffer, lastModified } = await getObjectFromS3Bucket(s3Client, s3BucketName, 'episodeData.json')
|
|
119
|
+
return { episodeData: JSON.parse(buffer.toString()), lastModified }
|
|
120
|
+
} catch (err) {
|
|
121
|
+
return { episodeData: {}, lastModified: null }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function updateEpisodeDataFromS3Bucket (s3Client, s3Bucket) {
|
|
126
|
+
const storedEpisodeData = await getStoredEpisodeDataFromS3Bucket(s3Client, s3Bucket)
|
|
127
|
+
const storedEpisodeDataLastModifiedDate = (storedEpisodeData.lastModified)
|
|
128
|
+
? DateTime.fromISO(storedEpisodeData.lastModified)
|
|
129
|
+
: null
|
|
130
|
+
const list = await s3Client.send(new ListObjectsCommand({ Bucket: s3Bucket }))
|
|
131
|
+
const result = { ...storedEpisodeData.episodeData }
|
|
132
|
+
for (const item of list.Contents ?? []) {
|
|
133
|
+
if (!item.Key.endsWith('.mp3')) continue
|
|
134
|
+
|
|
135
|
+
const { Key: filename, Size: size, LastModified: lastModified } = item
|
|
136
|
+
|
|
137
|
+
if (!(filename in result) ||
|
|
138
|
+
!('size' in result[filename]) ||
|
|
139
|
+
!('duration' in result[filename]) ||
|
|
140
|
+
!storedEpisodeDataLastModifiedDate ||
|
|
141
|
+
storedEpisodeDataLastModifiedDate > DateTime.fromISO(lastModified)) {
|
|
142
|
+
const { buffer } = await getObjectFromS3Bucket(s3Client, s3Bucket, filename)
|
|
143
|
+
const metadata = await parseBufferMetadata(buffer, null, { duration: true })
|
|
144
|
+
const duration = metadata.format.duration
|
|
145
|
+
result[filename] = { size, duration }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return result
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function writeEpisodeDataToS3Bucket (s3Client, s3Bucket, episodeData) {
|
|
152
|
+
await s3Client.send(new PutObjectCommand({
|
|
153
|
+
Bucket: s3Bucket,
|
|
154
|
+
Key: 'episodeData.json',
|
|
155
|
+
Body: JSON.stringify(episodeData, null, 2),
|
|
156
|
+
ContentType: 'application/json'
|
|
157
|
+
}))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export default function (eleventyConfig, options = {}) {
|
|
161
|
+
let firstRun = true
|
|
162
|
+
eleventyConfig.on('eleventy.before', async ({ directories }) => {
|
|
163
|
+
if (!firstRun || process.env.SKIP_EPISODE_CALCULATIONS === 'true') return
|
|
164
|
+
firstRun = false
|
|
165
|
+
|
|
166
|
+
const episodeFilesDirectory = path.join(directories.input, 'episodeFiles')
|
|
167
|
+
let episodeData
|
|
168
|
+
if (existsSync(episodeFilesDirectory)) {
|
|
169
|
+
episodeData = await readEpisodeDataLocally(episodeFilesDirectory)
|
|
170
|
+
} else if (options.s3ClientObject || options.s3Client) {
|
|
171
|
+
const s3Client = getS3Client(options)
|
|
172
|
+
const s3Bucket = options.s3Client.bucket
|
|
173
|
+
episodeData = await updateEpisodeDataFromS3Bucket(s3Client, s3Bucket)
|
|
174
|
+
await writeEpisodeDataToS3Bucket(s3Client, s3Bucket, episodeData)
|
|
175
|
+
} else {
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
const podcastData = calculatePodcastData(episodeData)
|
|
179
|
+
await writePodcastDataLocally(episodeData, podcastData, directories)
|
|
180
|
+
if (!eleventyConfig.quietMode) reportPodcastData(podcastData)
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
eleventyConfig.addGlobalData('eleventyComputed.episode.size', () => {
|
|
184
|
+
return data => {
|
|
185
|
+
if (data.episode.size) return data.episode.size
|
|
186
|
+
if (data.page.inputPath.includes('/episodePosts/') && data.episodeData) {
|
|
187
|
+
return data.episodeData[data.episode.filename]?.size
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
eleventyConfig.addGlobalData('eleventyComputed.episode.duration', () => {
|
|
193
|
+
return data => {
|
|
194
|
+
if (data.episode.duration) {
|
|
195
|
+
const convertedReadableDuration = convertReadableDurationToSeconds(data.episode.duration)
|
|
196
|
+
return convertedReadableDuration ?? data.episode.duration
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (data.page.inputPath.includes('/episodePosts/') && data.episodeData) {
|
|
200
|
+
return data.episodeData[data.episode.filename]?.duration
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
}
|
package/src/drafts.js
CHANGED
|
@@ -13,9 +13,9 @@ export default (eleventyConfig, options = {}) => {
|
|
|
13
13
|
}
|
|
14
14
|
if (!hasLoggedAboutDrafts) {
|
|
15
15
|
if (shouldIncludeDrafts) {
|
|
16
|
-
console.log('Including drafts.')
|
|
16
|
+
if (!eleventyConfig.quietMode) console.log('Including drafts.')
|
|
17
17
|
} else {
|
|
18
|
-
console.log('Excluding drafts.')
|
|
18
|
+
if (!eleventyConfig.quietMode) console.log('Excluding drafts.')
|
|
19
19
|
}
|
|
20
20
|
hasLoggedAboutDrafts = true
|
|
21
21
|
}
|
package/src/readableFilters.js
CHANGED
|
@@ -13,12 +13,17 @@ export default function (eleventyConfig, options = {}) {
|
|
|
13
13
|
return result.setLocale(readableDateLocale).toLocaleString(DateTime.DATE_HUGE)
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
eleventyConfig.addFilter('readableDuration', (seconds) => {
|
|
16
|
+
eleventyConfig.addFilter('readableDuration', (seconds, length) => {
|
|
17
17
|
if (!seconds) return '0:00:00'
|
|
18
|
-
if (
|
|
18
|
+
if (length === 'long') {
|
|
19
|
+
return Duration.fromMillis(seconds * 1000)
|
|
20
|
+
.shiftTo('days', 'hours', 'minutes', 'seconds')
|
|
21
|
+
.toHuman()
|
|
22
|
+
} else if (seconds < 60 * 60) {
|
|
19
23
|
return Duration.fromMillis(seconds * 1000).toFormat('mm:ss')
|
|
24
|
+
} else {
|
|
25
|
+
return Duration.fromMillis(seconds * 1000).toFormat('h:mm:ss')
|
|
20
26
|
}
|
|
21
|
-
return Duration.fromMillis(seconds * 1000).toFormat('h:mm:ss')
|
|
22
27
|
})
|
|
23
28
|
|
|
24
29
|
eleventyConfig.addFilter('readableSize', (bytes, fixedPrecision = 1) =>
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { Duration } from 'luxon'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { existsSync } from 'node:fs'
|
|
4
|
-
import { readdir, stat, writeFile } from 'node:fs/promises'
|
|
5
|
-
import { parseFile } from 'music-metadata'
|
|
6
|
-
import hr from '@tsmx/human-readable'
|
|
7
|
-
import chalk from 'chalk'
|
|
8
|
-
|
|
9
|
-
const convertSecondsToReadableDuration = seconds =>
|
|
10
|
-
Duration.fromMillis(seconds * 1000)
|
|
11
|
-
.shiftTo('days', 'hours', 'minutes', 'seconds')
|
|
12
|
-
.toHuman()
|
|
13
|
-
|
|
14
|
-
export default function (eleventyConfig) {
|
|
15
|
-
let firstRun = true
|
|
16
|
-
eleventyConfig.on('eleventy.before', async ({ directories }) => {
|
|
17
|
-
// don't keep recalculating episode data in serve mode
|
|
18
|
-
if (!firstRun || process.env.SKIP_EPISODE_CALCULATIONS === 'true') return
|
|
19
|
-
firstRun = false
|
|
20
|
-
const episodesDir = path.join(directories.input, 'episodeFiles')
|
|
21
|
-
if (!existsSync(episodesDir)) return
|
|
22
|
-
|
|
23
|
-
const episodes = await readdir(episodesDir)
|
|
24
|
-
const episodeData = {}
|
|
25
|
-
let numberOfEpisodes = 0
|
|
26
|
-
let totalSize = 0
|
|
27
|
-
let totalDuration = 0
|
|
28
|
-
|
|
29
|
-
for (const episode of episodes) {
|
|
30
|
-
if (!episode.endsWith('.mp3')) continue
|
|
31
|
-
|
|
32
|
-
numberOfEpisodes++
|
|
33
|
-
const episodePath = path.join(episodesDir, episode)
|
|
34
|
-
const episodeSize = (await stat(episodePath)).size
|
|
35
|
-
totalSize += episodeSize
|
|
36
|
-
const episodeMetadata = await parseFile(episodePath, { duration: true })
|
|
37
|
-
const episodeDuration = episodeMetadata.format.duration
|
|
38
|
-
totalDuration += episodeDuration
|
|
39
|
-
episodeData[episode] = {
|
|
40
|
-
size: episodeSize,
|
|
41
|
-
duration: Math.round(episodeDuration * 1000) / 1000
|
|
42
|
-
}
|
|
43
|
-
totalDuration = Math.round(totalDuration * 1000) / 1000
|
|
44
|
-
}
|
|
45
|
-
const podcastData = { numberOfEpisodes, totalSize, totalDuration }
|
|
46
|
-
|
|
47
|
-
const dataDir = path.join(process.cwd(), directories.data)
|
|
48
|
-
await writeFile(path.join(dataDir, 'episodeData.json'), JSON.stringify(episodeData, null, 2))
|
|
49
|
-
await writeFile(path.join(dataDir, 'podcastData.json'), JSON.stringify(podcastData, null, 2))
|
|
50
|
-
|
|
51
|
-
console.log(chalk.yellow(`${numberOfEpisodes} episodes; ${hr.fromBytes(totalSize)}; ${convertSecondsToReadableDuration(totalDuration)}.`))
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const filenameSeasonAndEpisodePattern =
|
|
55
|
-
/^.*?\b[sS](?<seasonNumber>\d+)[eE](?<episodeNumber>\d+)\b.*\.mp3$/
|
|
56
|
-
const filenameEpisodePattern = /^.*?\b(?<episodeNumber>\d+)\b.*\.mp3$/
|
|
57
|
-
|
|
58
|
-
eleventyConfig.addGlobalData('eleventyComputed.episode.filename', () => {
|
|
59
|
-
return data => {
|
|
60
|
-
if (data.episode.filename) return data.episode.filename
|
|
61
|
-
|
|
62
|
-
if (!data.page.inputPath.includes('/episodePosts/')) return
|
|
63
|
-
|
|
64
|
-
for (const file of Object.keys(data.episodeData)) {
|
|
65
|
-
if (data.episode.seasonNumber && data.episode.episodeNumber) {
|
|
66
|
-
const seasonAndEpisodeMatch = file.match(filenameSeasonAndEpisodePattern)
|
|
67
|
-
if (seasonAndEpisodeMatch) {
|
|
68
|
-
const matchedSeasonNumber = parseInt(seasonAndEpisodeMatch.groups.seasonNumber)
|
|
69
|
-
const matchedEpisodeNumber = parseInt(seasonAndEpisodeMatch.groups.episodeNumber)
|
|
70
|
-
if (matchedSeasonNumber === data.episode.seasonNumber &&
|
|
71
|
-
matchedEpisodeNumber === data.episode.episodeNumber) {
|
|
72
|
-
return file
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
} else if (data.episode.episodeNumber) {
|
|
76
|
-
const episodeMatch = file.match(filenameEpisodePattern)
|
|
77
|
-
if (episodeMatch) {
|
|
78
|
-
const matchedEpisodeNumber = parseInt(episodeMatch.groups.episodeNumber)
|
|
79
|
-
if (matchedEpisodeNumber === data.episode.episodeNumber) {
|
|
80
|
-
return file
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
eleventyConfig.addGlobalData('eleventyComputed.episode.size', () => {
|
|
89
|
-
return data => {
|
|
90
|
-
if (data.episode.size) return data.episode.size
|
|
91
|
-
if (data.page.inputPath.includes('/episodePosts/') && data.episodeData) {
|
|
92
|
-
return data.episodeData[data.episode.filename]?.size
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
eleventyConfig.addGlobalData('eleventyComputed.episode.duration', () => {
|
|
98
|
-
return data => {
|
|
99
|
-
if (data.episode.duration) return data.episode.duration
|
|
100
|
-
|
|
101
|
-
if (data.page.inputPath.includes('/episodePosts/') && data.episodeData) {
|
|
102
|
-
return data.episodeData[data.episode.filename]?.duration
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
})
|
|
106
|
-
}
|