website-htmx-rustelo-code/scripts/others/populate-content-indices.sh

209 lines
6.6 KiB
Bash
Raw Normal View History

2026-07-10 03:44:13 +01:00
#!/bin/bash
# Populate content index.json files from existing markdown files
# This script scans all markdown files in content directories and creates proper JSON index files
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE} $1${NC}"; }
log_success() { echo -e "${GREEN}$1${NC}"; }
log_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
CONTENT_DIR="content"
TEMP_DIR="/tmp/content-indices"
# Create temp directory
mkdir -p "$TEMP_DIR"
# Function to extract YAML frontmatter from markdown file
extract_frontmatter() {
local file="$1"
awk '/^---$/{p++} p==1 && !/^---$/ {print} p==2{exit}' "$file"
}
# Function to parse YAML value
parse_yaml_value() {
local file="$1"
local key="$2"
extract_frontmatter "$file" | grep "^${key}:" | sed "s/^${key}: *//g" | sed 's/^"//g' | sed 's/"$//g' | head -1
}
# Function to parse YAML array
parse_yaml_array() {
local file="$1"
local key="$2"
extract_frontmatter "$file" | sed -n "/^${key}:/,/^[^ ]/p" | grep "^ *-" | sed 's/^ *- *//g' | sed 's/^"//g' | sed 's/"$//g' | tr '\n' ',' | sed 's/,$//g'
}
# Function to generate JSON entry from markdown file
generate_json_entry() {
local md_file="$1"
local content_type="$2"
local language="$3"
# Extract metadata
local id=$(parse_yaml_value "$md_file" "id")
local title=$(parse_yaml_value "$md_file" "title")
local slug=$(parse_yaml_value "$md_file" "slug")
local excerpt=$(parse_yaml_value "$md_file" "excerpt")
local created_at=$(parse_yaml_value "$md_file" "date")
local read_time=$(parse_yaml_value "$md_file" "read_time")
local featured=$(parse_yaml_value "$md_file" "featured")
local tags=$(parse_yaml_array "$md_file" "tags")
local categories=$(parse_yaml_array "$md_file" "categories")
# Generate ID from filename if not found in frontmatter
if [ -z "$id" ]; then
id=$(basename "$md_file" .md)
fi
# Generate slug from ID if not found
if [ -z "$slug" ]; then
slug="$id"
fi
# Default values and escape quotes for JSON
title=$(echo "${title:-Untitled}" | sed 's/"/\\"/g')
excerpt=$(echo "${excerpt:-}" | sed 's/"/\\"/g')
created_at=${created_at:-$(date +"%Y-%m-%d")}
read_time=${read_time:-"5 min read"}
featured=${featured:-false}
# Infer category from file path if not in frontmatter
if [ -z "$categories" ]; then
local dir_path=$(dirname "$md_file")
local category=$(basename "$dir_path")
if [ "$category" != "$language" ] && [ "$category" != "." ]; then
categories="$category"
fi
fi
# Format arrays for JSON
local tags_json=""
if [ -n "$tags" ]; then
tags_json="\"$(echo "$tags" | sed 's/,/","/g')\""
fi
local categories_json=""
if [ -n "$categories" ]; then
categories_json="\"$(echo "$categories" | sed 's/,/","/g')\""
fi
# Get content for full-text search (first 200 chars) and escape quotes
local content=$(tail -n +10 "$md_file" | head -c 200 | tr '\n' ' ' | sed 's/"/\\"/g')
# Use jq to create proper JSON
jq -n \
--arg id "$id" \
--arg title "$title" \
--arg slug "$slug" \
--arg language "$language" \
--arg content_type "$content_type" \
--argjson categories "[${categories_json}]" \
--argjson tags "[${tags_json}]" \
--argjson featured "$featured" \
--arg excerpt "$excerpt" \
--arg content "$content" \
--arg created_at "$created_at" \
--arg read_time "$read_time" \
'{
id: $id,
title: $title,
slug: $slug,
language: $language,
content_type: $content_type,
categories: $categories,
tags: $tags,
emoji: null,
featured: $featured,
excerpt: $excerpt,
content: $content,
created_at: $created_at,
updated_at: null,
read_time: $read_time
}'
}
# Function to process content type directory
process_content_type() {
local content_type="$1"
local content_type_dir="${CONTENT_DIR}/${content_type}"
if [ ! -d "$content_type_dir" ]; then
log_warning "Content type directory not found: $content_type_dir"
return
fi
log_info "Processing content type: $content_type"
# Process each language directory
for lang_dir in "$content_type_dir"/*; do
if [ -d "$lang_dir" ]; then
local language=$(basename "$lang_dir")
log_info " Processing language: $language"
local temp_entries="$TEMP_DIR/${content_type}_${language}_entries.json"
echo "[]" > "$temp_entries"
# Find all markdown files in this directory and subdirectories
find "$lang_dir" -name "*.md" -type f | while read -r md_file; do
log_info " Processing: $(basename "$md_file")"
# Generate JSON entry and save to temp file
local entry_file="$TEMP_DIR/entry_$(basename "$md_file" .md).json"
generate_json_entry "$md_file" "$content_type" "$language" > "$entry_file"
# Add to temp entries file
local temp_with_entry="$TEMP_DIR/temp_entry.json"
jq --slurpfile entry "$entry_file" '. += $entry' "$temp_entries" > "$temp_with_entry"
mv "$temp_with_entry" "$temp_entries"
rm "$entry_file"
done
# Create final index file
local index_file="${lang_dir}/index.json"
local entries=$(cat "$temp_entries")
cat > "$index_file" << EOF
{
"${content_type}": ${entries},
"language": "$language"
}
EOF
local count=$(jq "length" "$temp_entries")
log_success " Created index for $content_type/$language with $count entries"
fi
done
}
# Main execution
log_info "Starting content index population..."
# Check if content directory exists
if [ ! -d "$CONTENT_DIR" ]; then
log_warning "Content directory not found: $CONTENT_DIR"
exit 1
fi
# Check if jq is available
if ! command -v jq &> /dev/null; then
log_warning "jq is required but not installed. Please install jq."
exit 1
fi
# Process each content type
process_content_type "blog"
process_content_type "recipes"
# Cleanup
rm -rf "$TEMP_DIR"
log_success "Content index population completed!"
log_info "Run 'just dev' or rebuild the project to embed the updated indices."