Skip to content

Instantly share code, notes, and snippets.

@mehori
Last active June 21, 2026 06:06
Show Gist options
  • Select an option

  • Save mehori/7756e5e31bd82f9a7ef18bf3c493410e to your computer and use it in GitHub Desktop.

Select an option

Save mehori/7756e5e31bd82f9a7ef18bf3c493410e to your computer and use it in GitHub Desktop.
import sys
import requests
from bs4 import BeautifulSoup
import json
import os
from datetime import datetime
# Install this script in a directory like ~/hugo_root/tools/
# Configure your project paths
# there are 2 more places hard-coded in the script. change it.
DATA_FILE = "../data/blogcards.json"
IMAGE_DIR = "../assets/images/blogcards"
# Ensure directories exist
os.makedirs(IMAGE_DIR, exist_ok=True)
os.makedirs("data", exist_ok=True)
def fetch_card_data(url):
# Generate ID based on current time (added seconds to prevent collisions)
card_id = datetime.now().strftime("%Y%m%d%H%M%S")
print(f"Fetching data for: {url}")
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
except Exception as e:
print(f"Error fetching URL: {e}")
sys.exit(1)
# 1. Extract Title
og_title = soup.find('meta', property='og:title')
title = og_title['content'] if og_title and og_title.get('content') else ""
if not title:
title = soup.title.string if soup.title else url
# 2. Extract Description
og_desc = soup.find('meta', property='og:description')
if not og_desc:
og_desc = soup.find('meta', attrs={'name': 'description'})
desc = og_desc['content'] if og_desc and og_desc.get('content') else ""
# 3. Extract and Download Image
og_image = soup.find('meta', property='og:image')
image_url = og_image['content'] if og_image and og_image.get('content') else None
local_image_path = ""
if image_url:
# Handle relative image URLs
if image_url.startswith('/'):
from urllib.parse import urljoin
image_url = urljoin(url, image_url)
print(f"Downloading image: {image_url}")
try:
img_data = requests.get(image_url, headers=headers, timeout=10).content
# Save as jpg in assets folder
local_image_path = f"images/blogcards/{card_id}.jpg"
with open(f"assets/{local_image_path}", 'wb') as handler:
handler.write(img_data)
except Exception as e:
print(f"Failed to download image: {e}")
# 4. Update the Hugo Data JSON
if os.path.exists(DATA_FILE):
with open(DATA_FILE, 'r', encoding='utf-8') as f:
try:
data = json.load(f)
except json.JSONDecodeError:
data = {}
else:
data = {}
data[card_id] = {
"url": url,
"title": title.strip(),
"description": desc.strip(),
"image": local_image_path
}
with open(DATA_FILE, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"\nSuccess! Card ID: {card_id}")
print(f"Markdown usage:")
print(f"{{{{< blogcard id=\"{card_id}\" url=\"{url}\" >}}}}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python add_card.py <URL>")
sys.exit(1)
target_url = sys.argv[1]
fetch_card_data(target_url)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment