mixcloud-rss-generator/src/cli.py

189 lines
7.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Backend-only CLI for Mixcloud RSS Generation
Uses shared content syndication services for RSS generation.
Replaces web_app.py and legacy mixcloud_rss.py dependencies.
"""
import argparse
import json
import os
import sys
from typing import Dict, Optional
# Add parent directories to path for shared imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../'))
from shared.services.content_syndication import (
ContentSyndicationService,
FeedFilterService
)
def main():
"""Command-line interface for backend Mixcloud RSS generation."""
parser = argparse.ArgumentParser(
description="Generate RSS feeds from Mixcloud users (Backend CLI)",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s WRFG # Basic RSS for WRFG user
%(prog)s --url https://mixcloud.com/NTSRadio/ # From full URL
%(prog)s WRFG --limit 50 --output feed.xml # Save 50 episodes to file
%(prog)s WRFG --keywords "rap,public affairs" # Filter by keywords
%(prog)s WRFG --rap-only # RAP shows only
%(prog)s WRFG --date-range 2024-01-01 2024-12-31 # Date filtering
"""
)
# Input options
input_group = parser.add_mutually_exclusive_group(required=True)
input_group.add_argument("username", nargs='?', help="Mixcloud username")
input_group.add_argument("--url", help="Mixcloud URL")
# Output options
parser.add_argument("-o", "--output", help="Output file path (default: stdout)")
parser.add_argument("-l", "--limit", type=int, default=20,
help="Number of episodes to include (default: 20)")
# Caching options
parser.add_argument("--cache-dir", default="./cache",
help="Cache directory path (default: ./cache)")
parser.add_argument("--cache-ttl", type=int, default=3600,
help="Cache TTL in seconds (default: 3600)")
# Filtering options
filter_group = parser.add_argument_group("Filtering Options")
filter_group.add_argument("--keywords",
help="Filter by keywords in title (comma-separated)")
filter_group.add_argument("--tags",
help="Filter by tags (comma-separated)")
filter_group.add_argument("--date-range", nargs=2, metavar=('START', 'END'),
help="Filter by date range (YYYY-MM-DD format)")
filter_group.add_argument("--specific-dates",
help="Filter by specific dates (comma-separated)")
# Convenience options
convenience_group = parser.add_argument_group("Convenience Options")
convenience_group.add_argument("--rap-only", action='store_true',
help="Filter for Revolutionary African Perspectives shows only")
# Utility options
parser.add_argument("--validate", action='store_true',
help="Validate user without generating feed")
parser.add_argument("--user-info", action='store_true',
help="Show user information only")
parser.add_argument("--verbose", "-v", action='store_true',
help="Verbose output")
args = parser.parse_args()
# Determine username
username = args.username
if args.url:
# Initialize service to extract username
syndication_service = ContentSyndicationService(args.cache_dir, args.cache_ttl)
try:
rss_feed = syndication_service.generate_mixcloud_rss_from_url(args.url, limit=1)
# Extract username from URL using service
username = syndication_service.mixcloud_client.extract_username_from_url(args.url)
if not username:
print(f"Error: Could not extract username from URL: {args.url}", file=sys.stderr)
return 1
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
if not username:
print("Error: No username provided", file=sys.stderr)
return 1
# Initialize content syndication service
syndication_service = ContentSyndicationService(args.cache_dir, args.cache_ttl)
# Handle validation only
if args.validate:
result = syndication_service.validate_mixcloud_user(username)
if result['valid']:
print(f"✅ Valid user: {result['username']} ({result['name']}) - {result['show_count']} shows")
return 0
else:
print(f"❌ Invalid user: {result['message']}")
return 1
# Handle user info only
if args.user_info:
user_data = syndication_service.get_mixcloud_user_info(username)
if user_data:
print(f"User: {user_data.get('name', username)}")
print(f"Username: {username}")
print(f"Bio: {user_data.get('biog', 'N/A')}")
print(f"Shows: {user_data.get('cloudcast_count', 0)}")
print(f"Profile: https://www.mixcloud.com/{username}/")
return 0
else:
print(f"Error: User '{username}' not found", file=sys.stderr)
return 1
# Build filters
filters = {}
if args.rap_only:
filters = FeedFilterService.create_rap_filter()
if args.verbose:
print("Applied RAP filter", file=sys.stderr)
if args.keywords:
filters['keywords'] = args.keywords
if args.verbose:
print(f"Filter: keywords = {args.keywords}", file=sys.stderr)
if args.tags:
filters['tags'] = args.tags
if args.verbose:
print(f"Filter: tags = {args.tags}", file=sys.stderr)
if args.date_range:
filters['start_date'] = args.date_range[0]
filters['end_date'] = args.date_range[1]
if args.verbose:
print(f"Filter: date range = {args.date_range[0]} to {args.date_range[1]}", file=sys.stderr)
if args.specific_dates:
filters['specific_dates'] = args.specific_dates
if args.verbose:
print(f"Filter: specific dates = {args.specific_dates}", file=sys.stderr)
# Generate RSS feed
try:
if args.verbose:
print(f"Generating RSS for user: {username}", file=sys.stderr)
print(f"Limit: {args.limit} episodes", file=sys.stderr)
if filters:
print(f"Filters applied: {list(filters.keys())}", file=sys.stderr)
rss_feed = syndication_service.generate_mixcloud_rss(username, args.limit, filters)
if rss_feed:
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(rss_feed)
print(f"RSS feed saved to: {args.output}", file=sys.stderr)
else:
print(rss_feed)
return 0
else:
print(f"Error: Could not generate RSS feed for user '{username}'", file=sys.stderr)
return 1
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
if args.verbose:
import traceback
traceback.print_exc()
return 1
if __name__ == "__main__":
sys.exit(main())