fediversion/backend/slugify.py
fullsizemalt b4cddf41ea feat: Initialize Fediversion multi-band platform
- Fork elmeg-demo codebase for multi-band support
- Add data importer infrastructure with base class
- Create band-specific importers:
  - phish.py: Phish.net API v5
  - grateful_dead.py: Grateful Stats API
  - setlistfm.py: Dead & Company, Billy Strings (Setlist.fm)
- Add spec-kit configuration for Gemini
- Update README with supported bands and architecture
2025-12-28 12:39:28 -08:00

134 lines
3.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Slug generation utilities
"""
import re
from typing import Optional
def generate_slug(text: str, max_length: int = 50) -> str:
"""
Generate a URL-safe slug from text.
Examples:
"Tweezer Reprise" -> "tweezer-reprise"
"You Enjoy Myself" -> "you-enjoy-myself"
"The Gorge Amphitheatre" -> "the-gorge-amphitheatre"
"""
if not text:
return ""
# Convert to lowercase
slug = text.lower()
# Replace common special characters
replacements = {
"'": "",
"'": "",
'"': "",
"&": "and",
"+": "and",
"@": "at",
"#": "",
"$": "",
"%": "",
"!": "",
"?": "",
".": "",
",": "",
":": "",
";": "",
"/": "-",
"\\": "-",
"(": "",
")": "",
"[": "",
"]": "",
"{": "",
"}": "",
"<": "",
">": "",
"": "-",
"": "-",
"...": "",
}
for old, new in replacements.items():
slug = slug.replace(old, new)
# Replace any non-alphanumeric characters with dashes
slug = re.sub(r'[^a-z0-9]+', '-', slug)
# Remove leading/trailing dashes and collapse multiple dashes
slug = re.sub(r'-+', '-', slug).strip('-')
# Truncate to max length (at word boundary if possible)
if len(slug) > max_length:
slug = slug[:max_length]
# Try to cut at last dash to avoid partial words
last_dash = slug.rfind('-')
if last_dash > max_length // 2:
slug = slug[:last_dash]
return slug
def generate_unique_slug(
base_text: str,
existing_slugs: list[str],
max_length: int = 50
) -> str:
"""
Generate a unique slug, appending numbers if necessary.
Examples:
"Tweezer" with existing ["tweezer"] -> "tweezer-2"
"Tweezer" with existing ["tweezer", "tweezer-2"] -> "tweezer-3"
"""
base_slug = generate_slug(base_text, max_length - 4) # Leave room for "-999"
if base_slug not in existing_slugs:
return base_slug
# Find next available number
counter = 2
while f"{base_slug}-{counter}" in existing_slugs:
counter += 1
return f"{base_slug}-{counter}"
def generate_show_slug(date_str: str, venue_name: str) -> str:
"""
Generate a slug for a show based on date and venue.
Examples:
"2024-12-31", "Madison Square Garden" -> "2024-12-31-msg"
"2024-07-04", "The Gorge Amphitheatre" -> "2024-07-04-the-gorge"
"""
# Common venue abbreviations
abbreviations = {
"madison square garden": "msg",
"red rocks amphitheatre": "red-rocks",
"the gorge amphitheatre": "the-gorge",
"alpine valley music theatre": "alpine",
"dicks sporting goods park": "dicks",
"mgm grand garden arena": "mgm",
"saratoga performing arts center": "spac",
}
venue_slug = abbreviations.get(venue_name.lower())
if not venue_slug:
# Take first 2-3 words of venue name
venue_slug = generate_slug(venue_name, 25)
return f"{date_str}-{venue_slug}"
def generate_performance_slug(song_title: str, show_date: str) -> str:
"""
Generate a slug for a specific performance.
Examples:
"Tweezer", "2024-12-31" -> "tweezer-2024-12-31"
"""
song_slug = generate_slug(song_title, 30)
return f"{song_slug}-{show_date}"