feat: enhance podcast functionality and build pipeline
- Dynamically resolve image paths for podcast episodes in `episodes.11tydata.js` - Add podcast metadata handling with inferred URLs for MP3 and transcripts - Introduce search functionality with Lunr.js and a search index generator - Update Eleventy path prefix handling to support environment variable override - Add `.mp4` files to `.gitignore` - Expand VSCode settings to include Markdown-Eleventy support and improved terminal history - Add deployment script (`deploy.sh`) with remote rsync-based deployment and permission handling - Adjust episode layout to use dynamic image paths and updated podcast metadata - Add search and members page updates, including new URLs and search integration - Update dependencies to include `html-to-text` and related packages for search indexing
This commit is contained in:
@@ -55,7 +55,7 @@ module.exports = function(eleventyConfig) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
pathPrefix:"blog",
|
pathPrefix: process.env.PATH_PREFIX || '/',
|
||||||
dir: {
|
dir: {
|
||||||
data: "data",
|
data: "data",
|
||||||
input: "content",
|
input: "content",
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@ node_modules
|
|||||||
**/.obsidian
|
**/.obsidian
|
||||||
dist
|
dist
|
||||||
*.mp3
|
*.mp3
|
||||||
|
*.mp4
|
||||||
.env
|
.env
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*/.vscode
|
*/.vscode
|
||||||
|
|||||||
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@@ -4,9 +4,6 @@
|
|||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
|
|||||||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
@@ -2,5 +2,17 @@
|
|||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
// "dist/": true
|
// "dist/": true
|
||||||
"**/.obsidian/": true
|
"**/.obsidian/": true
|
||||||
}
|
},
|
||||||
|
"files.associations": {
|
||||||
|
"*.md": "markdown-eleventy"
|
||||||
|
},
|
||||||
|
|
||||||
|
"terminal.integrated.env.osx": {
|
||||||
|
"VSCODE_HISTFILE": "${workspaceFolder}/.vscode/.zsh_history",
|
||||||
|
},
|
||||||
|
"[markdown-eleventy]": {
|
||||||
|
"editor.wordWrap": "on",
|
||||||
|
"editor.wordWrapColumn": 80, // Optional: Set to your preferred wrap column
|
||||||
|
"editor.quickSuggestions": false // Optional: Disable suggestions for Markdown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
35
.vscode/tasks.json
vendored
35
.vscode/tasks.json
vendored
@@ -2,19 +2,28 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "Simple Browser",
|
"label": "Deploy Site",
|
||||||
"command": "${input:openSimpleBrowser}",
|
"type": "shell",
|
||||||
"problemMatcher": []
|
"command": "./deploy.sh",
|
||||||
}
|
"options": {
|
||||||
],
|
"env": {
|
||||||
"inputs": [
|
"PRODUCTION_SERVER": "rpg",
|
||||||
{
|
"PRODUCTION_PATH": "/docker/rpg.ascorrea.com/apps/html",
|
||||||
"id": "openSimpleBrowser",
|
"SITE_URL": "https://rpg.ascorrea.com",
|
||||||
"type": "command",
|
"CDN_URL": "https://podcast.rpg.cdn.ascorrea.com",
|
||||||
"command": "simpleBrowser.show",
|
"FOUNDRY_BASE_URL": "https://podcast.rpg.cdn.ascorrea.com",
|
||||||
"args": [
|
"PATH_PREFIX": "/"
|
||||||
"http://localhost:8081"
|
}
|
||||||
]
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,83 @@
|
|||||||
const {seasonEpisodeFormat} = require('../../utils/filters');
|
const {seasonEpisodeFormat, episodeNumber} = require('../../utils/filters');
|
||||||
|
const fs = require('fs/promises');
|
||||||
|
path = require('path')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"layout": "episode",
|
"layout": "episode",
|
||||||
"tags":['episode'],
|
"tags":['episode'],
|
||||||
"eleventyComputed": {
|
"eleventyComputed": {
|
||||||
"episode": "{{page.fileSlug | episodeNumber: episode}}",
|
"episode": "{{page.fileSlug | episodeNumber: episode}}",
|
||||||
"image": "{{page.url}}/../image.jpg",
|
"image": async (data) => {
|
||||||
"podcast": (data) => {
|
const image_locations_promises = [
|
||||||
return {
|
data.image,
|
||||||
"enclosureUrl": data.podcast.enclosureUrl ||`${data.site.cdn}/${seasonEpisodeFormat(null, data).toLowerCase()}.mp3`,
|
`${data.page.filePathStem}.jpg`,
|
||||||
"transcriptUrl": data.podcast.transcriptUrl ||`${data.site.cdn}/${seasonEpisodeFormat(null, data).toLowerCase()}.srt`,
|
`${data.page.filePathStem}.png`,
|
||||||
"title": data.podcast.title || `${seasonEpisodeFormat(null, data)}: ${data.title || "Episode " + data.episode}`,
|
'../image.jpg',
|
||||||
"image" : data.podcast.image || data.image || "{{page.url}}/../image.jpg"
|
'../image.png',
|
||||||
}}
|
'../../image.jpg',
|
||||||
|
'../../image.png'
|
||||||
|
].filter(image_path=>image_path).map((image_path)=>
|
||||||
|
fs.access(path.resolve(data.page.inputPath, image_path))
|
||||||
|
.then(()=>path.resolve(data.page.filePathStem, image_path))
|
||||||
|
.catch(()=>null)
|
||||||
|
)
|
||||||
|
return (await Promise.all(image_locations_promises)).find(i=>i)
|
||||||
|
},
|
||||||
|
"podcast": podcastData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function podcastData (data) {
|
||||||
|
var file_stem
|
||||||
|
if (data.season === 1) {
|
||||||
|
file_stem = `ep${data.episode}`
|
||||||
|
} else {
|
||||||
|
file_stem = `${seasonEpisodeFormat(null, data).toLowerCase()}`
|
||||||
|
}
|
||||||
|
const mp3_exists_promise = new Promise ((resolve, reject) => {
|
||||||
|
if (data.podcast.enclosureUrl) {
|
||||||
|
resolve(data.podcast.enclosureUrl)
|
||||||
|
} else {
|
||||||
|
const url = `${data.site.cdn}/${file_stem}.mp3`
|
||||||
|
console.log(`Inferring URL @ ${url} for ${data.page.url}`)
|
||||||
|
fetch(url, { method: "HEAD" })
|
||||||
|
.then((res)=>{
|
||||||
|
if (res.ok) {
|
||||||
|
resolve(`${url}`)
|
||||||
|
} else {
|
||||||
|
reject(new Error(`No file at ${url}`));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((e)=>{return null})
|
||||||
|
|
||||||
|
const transcript_exists_promise = new Promise ((resolve, reject) => {
|
||||||
|
if (data.podcast.transcriptUrl) {
|
||||||
|
resolve(data.podcast.transcriptUrl)
|
||||||
|
} else {
|
||||||
|
const url = `${data.site.cdn}/${file_stem}.srt`
|
||||||
|
console.log(`Inferring URL @ ${url}`)
|
||||||
|
fetch(url, { method: "HEAD" })
|
||||||
|
.then((res)=>{
|
||||||
|
if (res.ok) {
|
||||||
|
resolve(`${url}`)
|
||||||
|
} else {
|
||||||
|
reject(new Error(`No file at ${url}`));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch((e)=>{return null})
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
"enclosureUrl": await mp3_exists_promise,
|
||||||
|
"transcriptUrl": await transcript_exists_promise,
|
||||||
|
"title": data.podcast.title || `${seasonEpisodeFormat(null, data)}: ${data.title || "Episode " + data.episode}`,
|
||||||
|
"image" : data.podcast.image || data.image
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.enclosureUrl != null) {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
const podcastData = require('../episodes.11tydata').eleventyComputed.podcast;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"season": 1,
|
"season": 1,
|
||||||
@@ -6,8 +7,9 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
"stylesheets": ["/css/s04.css"],
|
"stylesheets": ["/css/s04.css"],
|
||||||
"eleventyComputed": {
|
"eleventyComputed": {
|
||||||
"podcast": (data)=>({
|
"podcast": async (data)=>{
|
||||||
"title": `E${data.episode}: ${data.title}`
|
var result = {...await podcastData(data),"title": `E${data.episode}: ${data.title}`}
|
||||||
})
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
BIN
content/episodes/s02/image.jpg
Executable file
BIN
content/episodes/s02/image.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 290 KiB |
23
content/episodes/search-index.11ty.js
Normal file
23
content/episodes/search-index.11ty.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import markdownit from 'markdown-it';
|
||||||
|
import { convert } from 'html-to-text';
|
||||||
|
const md = markdownit({html: true})
|
||||||
|
|
||||||
|
class SearchIndex {
|
||||||
|
data() {
|
||||||
|
return {eleventyExcludeFromCollections:["episode"], layout: null}
|
||||||
|
}
|
||||||
|
|
||||||
|
render (data) {
|
||||||
|
const documents = data.collections.episode.map((episode)=>{
|
||||||
|
return {
|
||||||
|
url:`${this.url(episode.url)}`,
|
||||||
|
title: episode.data.title,
|
||||||
|
text: convert (episode.content),
|
||||||
|
season: episode.data.season,
|
||||||
|
episode: episode.data.episode
|
||||||
|
}})
|
||||||
|
return JSON.stringify(documents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchIndex
|
||||||
84
content/episodes/search.hbs
Normal file
84
content/episodes/search.hbs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
layout: base-with-heading
|
||||||
|
title: Search Episodes
|
||||||
|
eleventyExcludeFromCollections: ["episode"]
|
||||||
|
override:tags: []
|
||||||
|
override:eleventyComputed: []
|
||||||
|
---
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/lunr/lunr.js"></script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<form id="search-form">
|
||||||
|
<input type="text" class="form-control mb-3" name="searchQuery" id="searchQuery">
|
||||||
|
<button class="btn btn-primary mb-3" type="submit">Search</button>
|
||||||
|
</form>
|
||||||
|
<div id="results">
|
||||||
|
<ol></ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let idx, docs
|
||||||
|
let search_index_promise = fetch('../search-index')
|
||||||
|
.then((res)=>res.json())
|
||||||
|
.then((documents)=>{
|
||||||
|
docs = documents
|
||||||
|
idx = lunr(function(){
|
||||||
|
this.ref('id')
|
||||||
|
this.field('text')
|
||||||
|
this.field('title')
|
||||||
|
this.metadataWhitelist = ['position']
|
||||||
|
documents.forEach(function (doc, idx) {
|
||||||
|
doc.id = idx;
|
||||||
|
this.add(doc);
|
||||||
|
}, this)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function highlightTokens(element, tokens) {
|
||||||
|
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, nodeFilter, false);
|
||||||
|
let node = null;
|
||||||
|
|
||||||
|
while ((node = walker.nextNode())) {
|
||||||
|
const text = node.textContent.toLowerCase();
|
||||||
|
let found = false;
|
||||||
|
for (var i = 0; i < tokens.length && !found; i++) {
|
||||||
|
const token = tokens[i].toString();
|
||||||
|
const startIndex = text.indexOf(token);
|
||||||
|
if (startIndex == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let range = document.createRange();
|
||||||
|
range.setStart(node, startIndex);
|
||||||
|
range.setEnd(node, startIndex + token.length);
|
||||||
|
let mark = document.createElement('mark');
|
||||||
|
range.surroundContents(mark);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
walker.nextNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
const formData = new FormData(evt.target)
|
||||||
|
const {searchQuery} = Object.fromEntries(formData)
|
||||||
|
results = idx.search(searchQuery)
|
||||||
|
results.forEach(r => {
|
||||||
|
r.title = docs[r.ref].title,
|
||||||
|
r.url = docs[r.ref].url
|
||||||
|
})
|
||||||
|
console.log('Form submitted!', results)
|
||||||
|
results_ol = document.getElementById("results").querySelector('ol')
|
||||||
|
results_ol.innerHTML = ""
|
||||||
|
results.forEach(r => {
|
||||||
|
const el = document.createElement('li')
|
||||||
|
const {url, title, text, season, episode} = docs[r.ref]
|
||||||
|
el.innerHTML =`<a href="${url}">${title} (Season ${season}, episode ${episode})</a><p>${text}</p>`
|
||||||
|
results_ol.appendChild(el)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
document.getElementById('search-form').addEventListener('submit', handleSubmit)
|
||||||
|
|
||||||
|
</script>
|
||||||
@@ -3,7 +3,7 @@ layout: base-with-heading
|
|||||||
title: Member Content
|
title: Member Content
|
||||||
links:
|
links:
|
||||||
- name: Foundry
|
- name: Foundry
|
||||||
url: /foundry
|
url: /foundry/game
|
||||||
image: /images/fvtt-solid-512.png
|
image: /images/fvtt-solid-512.png
|
||||||
- name: Discord
|
- name: Discord
|
||||||
url: discord
|
url: discord
|
||||||
|
|||||||
75
deploy.sh
Executable file
75
deploy.sh
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Exit on errors
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Configuration (environment variables)
|
||||||
|
BUILD_DIR=".tmp_build" # Temporary directory for the build
|
||||||
|
PRODUCTION_SERVER="${PRODUCTION_SERVER:-}" # Ensure this is set in the environment
|
||||||
|
PRODUCTION_PATH="${PRODUCTION_PATH:-}" # Ensure this is set in the environment
|
||||||
|
PATH_PREFIX="${PATH_PREFIX:-}" # Ensure this is set in the environment
|
||||||
|
SITE_URL="${SITE_URL:-}" # Ensure this is set in the environment
|
||||||
|
CDN_URL="${CDN_URL:-}" # Ensure this is set in the environment
|
||||||
|
FOUNDRY_BASE_URL="${FOUNDRY_BASE_URL:-}" # Ensure this is set in the environment
|
||||||
|
|
||||||
|
# Function to clean up the temporary directory
|
||||||
|
cleanup() {
|
||||||
|
echo "Cleaning up temporary files..."
|
||||||
|
rm -rf "$BUILD_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set trap to clean up on script exit or interruption
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# Function to check environment variables
|
||||||
|
check_env() {
|
||||||
|
if [[ -z "$PRODUCTION_SERVER" ]]; then
|
||||||
|
echo "Error: PRODUCTION_SERVER is not set. Please set it and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$PRODUCTION_PATH" ]]; then
|
||||||
|
echo "Error: PRODUCTION_PATH is not set. Please set it and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$PATH_PREFIX" ]]; then
|
||||||
|
echo "Error: PATH_PREFIX is not set. Please set it and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$SITE_URL" ]]; then
|
||||||
|
echo "Error: SITE_URL is not set. Please set it and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$CDN_URL" ]]; then
|
||||||
|
echo "Error: CDN_URL is not set. Please set it and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$FOUNDRY_BASE_URL" ]]; then
|
||||||
|
echo "Error: FOUNDRY_BASE_URL is not set. Please set it and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check environment variables
|
||||||
|
check_env
|
||||||
|
|
||||||
|
# Step 1: Build the site to a temporary directory
|
||||||
|
echo "Building the site..."
|
||||||
|
npx @11ty/eleventy --output="$BUILD_DIR"
|
||||||
|
|
||||||
|
# Step 2: Deploy using rsync
|
||||||
|
echo "Deploying to production..."
|
||||||
|
rsync -avz --delete "$BUILD_DIR/" "$PRODUCTION_SERVER:$PRODUCTION_PATH"
|
||||||
|
|
||||||
|
# Step 3: Fix permissions on the remote server
|
||||||
|
echo "Fixing permissions on the server..."
|
||||||
|
ssh "$PRODUCTION_SERVER" << EOF
|
||||||
|
find "$PRODUCTION_PATH" -type f -exec chmod 665 {} \; # Set permissions for files
|
||||||
|
find "$PRODUCTION_PATH" -type d -exec chmod 775 {} \; # Set permissions for directories
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Deployment complete!"
|
||||||
@@ -5,12 +5,12 @@ eleventyComputed:
|
|||||||
---
|
---
|
||||||
<div class="bg-body-tertiary p-4 my-2 rounded">
|
<div class="bg-body-tertiary p-4 my-2 rounded">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col"><img src="{{{this.url}}}../image.jpg" class="img-fluid"></div>
|
<div class="col"><img src="{{{this.image}}}" class="img-fluid"></div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h1>{{#if title}}{{{title}}}{{else}}Episode {{episode}}{{/if}}</h1>
|
<h1>{{#if title}}{{{title}}}{{else}}Episode {{episode}}{{/if}}</h1>
|
||||||
Season {{season}}, Episode {{episode}} <br>
|
Season {{season}}, Episode {{episode}} <br>
|
||||||
<date>{{formatDate this.date "MMMM d, yyyy"}}</date><br>
|
<date>{{formatDate this.date "MMMM d, yyyy"}}</date><br>
|
||||||
{{#if podcast.enclosureUrl}}
|
{{#if podcast}}
|
||||||
<a href="{{{podcast.enclosureUrl}}}">Download</a>
|
<a href="{{{podcast.enclosureUrl}}}">Download</a>
|
||||||
{{#if podcast.transcriptUrl}}| <a href="{{{podcast.transcriptUrl}}}">Transcript</a>{{/if}}
|
{{#if podcast.transcriptUrl}}| <a href="{{{podcast.transcriptUrl}}}">Transcript</a>{{/if}}
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class PodcastFeed {
|
|||||||
if (episode.data.podcast.transcriptUrl) {
|
if (episode.data.podcast.transcriptUrl) {
|
||||||
item.customElements.push({ 'podcast:transcript': {_attr:{
|
item.customElements.push({ 'podcast:transcript': {_attr:{
|
||||||
url:`${episode.data.podcast.transcriptUrl}`,
|
url:`${episode.data.podcast.transcriptUrl}`,
|
||||||
type:"application/srt",
|
type:"application/x-subrip",
|
||||||
language:"en-us"
|
language:"en-us"
|
||||||
}}
|
}}
|
||||||
})
|
})
|
||||||
|
|||||||
101
package-lock.json
generated
101
package-lock.json
generated
@@ -18,6 +18,7 @@
|
|||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"handlebars-helpers": "^0.10.0",
|
"handlebars-helpers": "^0.10.0",
|
||||||
"html-minifier": "^4.0.0",
|
"html-minifier": "^4.0.0",
|
||||||
|
"html-to-text": "^9.0.5",
|
||||||
"htmlparser2": "^9.1.0",
|
"htmlparser2": "^9.1.0",
|
||||||
"luxon": "^3.5.0",
|
"luxon": "^3.5.0",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
@@ -409,6 +410,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
|
||||||
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="
|
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@selderee/plugin-htmlparser2": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"selderee": "^0.11.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tokenizer/token": {
|
"node_modules/@tokenizer/token": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
||||||
@@ -1227,6 +1241,15 @@
|
|||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/deepmerge": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/default-compare": {
|
"node_modules/default-compare": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
|
||||||
@@ -2237,6 +2260,41 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html-to-text": {
|
||||||
|
"version": "9.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
|
||||||
|
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@selderee/plugin-htmlparser2": "^0.11.0",
|
||||||
|
"deepmerge": "^4.3.1",
|
||||||
|
"dom-serializer": "^2.0.0",
|
||||||
|
"htmlparser2": "^8.0.2",
|
||||||
|
"selderee": "^0.11.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/html-to-text/node_modules/htmlparser2": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"domutils": "^3.0.1",
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/htmlparser2": {
|
"node_modules/htmlparser2": {
|
||||||
"version": "9.1.0",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
|
||||||
@@ -2515,6 +2573,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/leac": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/linkify-it": {
|
"node_modules/linkify-it": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||||
@@ -7535,6 +7602,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
|
||||||
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
|
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/parseley": {
|
||||||
|
"version": "0.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
|
||||||
|
"integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"leac": "^0.6.0",
|
||||||
|
"peberminta": "^0.9.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pascalcase": {
|
"node_modules/pascalcase": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
||||||
@@ -7544,6 +7624,15 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/peberminta": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/peek-readable": {
|
"node_modules/peek-readable": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.3.1.tgz",
|
||||||
@@ -7969,6 +8058,18 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/selderee": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"parseley": "^0.12.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/killymxi"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/self-closing-tags": {
|
"node_modules/self-closing-tags": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/self-closing-tags/-/self-closing-tags-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/self-closing-tags/-/self-closing-tags-1.0.1.tgz",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"handlebars-helpers": "^0.10.0",
|
"handlebars-helpers": "^0.10.0",
|
||||||
"html-minifier": "^4.0.0",
|
"html-minifier": "^4.0.0",
|
||||||
|
"html-to-text": "^9.0.5",
|
||||||
"htmlparser2": "^9.1.0",
|
"htmlparser2": "^9.1.0",
|
||||||
"luxon": "^3.5.0",
|
"luxon": "^3.5.0",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user