236 lines
8 KiB
Bash
236 lines
8 KiB
Bash
|
|
#!/bin/bash
|
||
|
|
|
||
|
|
# Content Migration Script - Normalize Categories, Tags, and Add Slugs
|
||
|
|
# This script normalizes all content to use proper URL-safe slugs
|
||
|
|
|
||
|
|
set -e
|
||
|
|
|
||
|
|
CONTENT_ROOT="content"
|
||
|
|
BACKUP_DIR="content-backup-$(date +%Y%m%d_%H%M%S)"
|
||
|
|
|
||
|
|
echo "🔄 Starting content migration to normalize categories, tags, and add slugs"
|
||
|
|
echo "📁 Content root: $CONTENT_ROOT"
|
||
|
|
echo "💾 Backup will be created at: $BACKUP_DIR"
|
||
|
|
|
||
|
|
# Create backup
|
||
|
|
echo "📦 Creating backup..."
|
||
|
|
cp -r "$CONTENT_ROOT" "$BACKUP_DIR"
|
||
|
|
echo "✅ Backup created successfully"
|
||
|
|
|
||
|
|
# Function to normalize text to slug format
|
||
|
|
normalize_slug() {
|
||
|
|
local text="$1"
|
||
|
|
echo "$text" | \
|
||
|
|
sed 's/[áàäâãå]/a/g; s/[éèëê]/e/g; s/[íìïî]/i/g; s/[óòöôõ]/o/g; s/[úùüû]/u/g; s/ç/c/g; s/ñ/n/g' | \
|
||
|
|
sed 's/[ÁÀÄÂÃÅ]/A/g; s/[ÉÈËÊ]/E/g; s/[ÍÌÏÎ]/I/g; s/[ÓÒÖÔÕ]/O/g; s/[ÚÙÜÛ]/U/g; s/Ç/C/g; s/Ñ/N/g' | \
|
||
|
|
tr '[:upper:]' '[:lower:]' | \
|
||
|
|
sed 's/[^a-z0-9]/-/g' | \
|
||
|
|
sed 's/--*/-/g' | \
|
||
|
|
sed 's/^-\|-$//g'
|
||
|
|
}
|
||
|
|
|
||
|
|
# Function to update markdown file frontmatter
|
||
|
|
update_markdown_file() {
|
||
|
|
local file="$1"
|
||
|
|
echo "🔄 Processing: $file"
|
||
|
|
|
||
|
|
# Create temporary files
|
||
|
|
local temp_file=$(mktemp)
|
||
|
|
local frontmatter_file=$(mktemp)
|
||
|
|
local content_file=$(mktemp)
|
||
|
|
|
||
|
|
# Extract frontmatter and content
|
||
|
|
awk '
|
||
|
|
BEGIN { in_frontmatter = 0; frontmatter_count = 0 }
|
||
|
|
/^---$/ {
|
||
|
|
frontmatter_count++;
|
||
|
|
if (frontmatter_count <= 2) {
|
||
|
|
in_frontmatter = (frontmatter_count == 1) ? 1 : 0;
|
||
|
|
if (frontmatter_count == 1) print > "'$frontmatter_file'";
|
||
|
|
if (frontmatter_count == 2) print > "'$frontmatter_file'";
|
||
|
|
} else {
|
||
|
|
print > "'$content_file'";
|
||
|
|
}
|
||
|
|
next;
|
||
|
|
}
|
||
|
|
in_frontmatter { print > "'$frontmatter_file'" }
|
||
|
|
!in_frontmatter && frontmatter_count >= 2 { print > "'$content_file'" }
|
||
|
|
' "$file"
|
||
|
|
|
||
|
|
# Process frontmatter
|
||
|
|
local updated_frontmatter=$(mktemp)
|
||
|
|
echo "---" > "$updated_frontmatter"
|
||
|
|
|
||
|
|
while IFS= read -r line; do
|
||
|
|
if [[ "$line" =~ ^---$ ]]; then
|
||
|
|
continue
|
||
|
|
elif [[ "$line" =~ ^category:\ *\"?([^\"]+)\"?$ ]]; then
|
||
|
|
local category="${BASH_REMATCH[1]}"
|
||
|
|
local normalized_category=$(normalize_slug "$category")
|
||
|
|
echo "category: \"$normalized_category\"" >> "$updated_frontmatter"
|
||
|
|
echo " 📝 Category: '$category' → '$normalized_category'"
|
||
|
|
elif [[ "$line" =~ ^tags:\ *\[(.*)\]$ ]]; then
|
||
|
|
local tags_content="${BASH_REMATCH[1]}"
|
||
|
|
# Parse tags and normalize them
|
||
|
|
local normalized_tags=""
|
||
|
|
IFS=',' read -ra TAG_ARRAY <<< "$tags_content"
|
||
|
|
for tag in "${TAG_ARRAY[@]}"; do
|
||
|
|
# Remove quotes and whitespace
|
||
|
|
tag=$(echo "$tag" | sed 's/["\[\]]//g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||
|
|
local normalized_tag=$(normalize_slug "$tag")
|
||
|
|
echo " 🏷️ Tag: '$tag' → '$normalized_tag'"
|
||
|
|
if [[ -n "$normalized_tags" ]]; then
|
||
|
|
normalized_tags="$normalized_tags, \"$normalized_tag\""
|
||
|
|
else
|
||
|
|
normalized_tags="\"$normalized_tag\""
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
echo "tags: [$normalized_tags]" >> "$updated_frontmatter"
|
||
|
|
elif [[ "$line" =~ ^title:\ *\"?([^\"]+)\"?$ ]]; then
|
||
|
|
local title="${BASH_REMATCH[1]}"
|
||
|
|
echo "$line" >> "$updated_frontmatter"
|
||
|
|
# Add slug field if not present
|
||
|
|
if ! grep -q "^slug:" "$frontmatter_file"; then
|
||
|
|
local slug=$(normalize_slug "$title")
|
||
|
|
echo "slug: \"$slug\"" >> "$updated_frontmatter"
|
||
|
|
echo " 🔗 Added slug: '$slug'"
|
||
|
|
fi
|
||
|
|
else
|
||
|
|
echo "$line" >> "$updated_frontmatter"
|
||
|
|
fi
|
||
|
|
done < "$frontmatter_file"
|
||
|
|
|
||
|
|
echo "---" >> "$updated_frontmatter"
|
||
|
|
|
||
|
|
# Combine updated frontmatter with content
|
||
|
|
cat "$updated_frontmatter" > "$temp_file"
|
||
|
|
cat "$content_file" >> "$temp_file"
|
||
|
|
|
||
|
|
# Replace original file
|
||
|
|
mv "$temp_file" "$file"
|
||
|
|
|
||
|
|
# Cleanup
|
||
|
|
rm -f "$frontmatter_file" "$content_file" "$updated_frontmatter"
|
||
|
|
|
||
|
|
echo "✅ Updated: $file"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Function to update JSON index files
|
||
|
|
update_json_index() {
|
||
|
|
local file="$1"
|
||
|
|
echo "🔄 Processing JSON index: $file"
|
||
|
|
|
||
|
|
# Create a temporary script to process the JSON
|
||
|
|
local temp_script=$(mktemp)
|
||
|
|
cat > "$temp_script" << 'EOF'
|
||
|
|
import json
|
||
|
|
import sys
|
||
|
|
import re
|
||
|
|
import unicodedata
|
||
|
|
|
||
|
|
def normalize_slug(text):
|
||
|
|
"""Normalize text to URL-safe slug format using proper Unicode normalization"""
|
||
|
|
# Normalize to NFD (decomposed form) and remove combining characters (accents)
|
||
|
|
normalized = unicodedata.normalize('NFD', text)
|
||
|
|
no_accents = ''.join(c for c in normalized if not unicodedata.combining(c))
|
||
|
|
|
||
|
|
# Convert to lowercase, replace non-alphanumeric with dashes, collapse dashes
|
||
|
|
slug = re.sub(r'[^a-zA-Z0-9]+', '-', no_accents.lower())
|
||
|
|
slug = re.sub(r'-+', '-', slug) # Collapse multiple dashes
|
||
|
|
slug = slug.strip('-') # Remove leading/trailing dashes
|
||
|
|
|
||
|
|
return slug
|
||
|
|
|
||
|
|
def update_content_item(item):
|
||
|
|
"""Update a single content item (blog post or prescription)"""
|
||
|
|
updated = False
|
||
|
|
|
||
|
|
# Normalize category
|
||
|
|
if 'category' in item and item['category']:
|
||
|
|
old_category = item['category']
|
||
|
|
new_category = normalize_slug(old_category)
|
||
|
|
if old_category != new_category:
|
||
|
|
item['category'] = new_category
|
||
|
|
print(f" 📝 Category: '{old_category}' → '{new_category}'")
|
||
|
|
updated = True
|
||
|
|
|
||
|
|
# Normalize tags
|
||
|
|
if 'tags' in item and isinstance(item['tags'], list):
|
||
|
|
old_tags = item['tags'][:]
|
||
|
|
new_tags = []
|
||
|
|
for tag in old_tags:
|
||
|
|
new_tag = normalize_slug(tag)
|
||
|
|
new_tags.append(new_tag)
|
||
|
|
if tag != new_tag:
|
||
|
|
print(f" 🏷️ Tag: '{tag}' → '{new_tag}'")
|
||
|
|
updated = True
|
||
|
|
item['tags'] = new_tags
|
||
|
|
|
||
|
|
# Add localized_slug if not present
|
||
|
|
if 'localized_slug' not in item and 'title' in item:
|
||
|
|
slug = normalize_slug(item['title'])
|
||
|
|
item['localized_slug'] = slug
|
||
|
|
print(f" 🔗 Added localized_slug: '{slug}'")
|
||
|
|
updated = True
|
||
|
|
|
||
|
|
return updated
|
||
|
|
|
||
|
|
# Read and process JSON file
|
||
|
|
with open(sys.argv[1], 'r', encoding='utf-8') as f:
|
||
|
|
data = json.load(f)
|
||
|
|
|
||
|
|
updated_any = False
|
||
|
|
|
||
|
|
# Process blog posts
|
||
|
|
if 'blog_posts' in data:
|
||
|
|
for post in data['blog_posts']:
|
||
|
|
if update_content_item(post):
|
||
|
|
updated_any = True
|
||
|
|
|
||
|
|
# Process prescriptions
|
||
|
|
if 'prescriptions' in data:
|
||
|
|
for prescription in data['prescriptions']:
|
||
|
|
if update_content_item(prescription):
|
||
|
|
updated_any = True
|
||
|
|
|
||
|
|
# Write back to file if updated
|
||
|
|
if updated_any:
|
||
|
|
with open(sys.argv[1], 'w', encoding='utf-8') as f:
|
||
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
||
|
|
f.write('\n') # Add trailing newline
|
||
|
|
|
||
|
|
EOF
|
||
|
|
|
||
|
|
python3 "$temp_script" "$file"
|
||
|
|
rm -f "$temp_script"
|
||
|
|
echo "✅ Updated: $file"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Process all markdown files
|
||
|
|
echo "🔍 Finding and processing markdown files..."
|
||
|
|
find "$CONTENT_ROOT" -name "*.md" -type f | while read -r file; do
|
||
|
|
update_markdown_file "$file"
|
||
|
|
done
|
||
|
|
|
||
|
|
# Process all JSON index files
|
||
|
|
echo "🔍 Finding and processing JSON index files..."
|
||
|
|
find "$CONTENT_ROOT" -name "index.json" -type f | while read -r file; do
|
||
|
|
update_json_index "$file"
|
||
|
|
done
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
echo "✅ Content migration completed successfully!"
|
||
|
|
echo "📁 Backup location: $BACKUP_DIR"
|
||
|
|
echo ""
|
||
|
|
echo "📋 Summary of changes:"
|
||
|
|
echo " • Normalized all category names to lowercase with dashes"
|
||
|
|
echo " • Normalized all tag names to lowercase with dashes"
|
||
|
|
echo " • Added slug fields to markdown frontmatter"
|
||
|
|
echo " • Added localized_slug fields to JSON index files"
|
||
|
|
echo " • Removed accents and special characters from all slugs"
|
||
|
|
echo ""
|
||
|
|
echo "🔧 Next steps:"
|
||
|
|
echo " 1. Review the changes"
|
||
|
|
echo " 2. Test the application"
|
||
|
|
echo " 3. Update any hardcoded category/tag references"
|
||
|
|
echo " 4. If satisfied, remove the backup: rm -rf $BACKUP_DIR"
|