209 lines
6.6 KiB
Bash
209 lines
6.6 KiB
Bash
|
|
#!/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."
|