#!/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())