tools

various tools I have been using throughout the years
Log | Files | Refs | README | LICENSE

nts.py (4924B)


      1 #!/usr/bin/env python3
      2 import argparse
      3 import requests
      4 import sys
      5 import json
      6 from typing import Any, cast
      7 from urllib.parse import urlparse, quote
      8 
      9 
     10 class NTSTracklistFetcher:
     11     def __init__(self) -> None:
     12         self.session: requests.Session = requests.Session()
     13         self.session.headers.update(
     14             {
     15                 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
     16                 "Accept": "application/json",
     17             }
     18         )
     19 
     20     def extract_episode_path(self, url: str) -> str | None:
     21         """Extract show and episode path from URL."""
     22         try:
     23             parsed = urlparse(url)
     24             path_parts = [p for p in parsed.path.split("/") if p]
     25 
     26             if (
     27                 len(path_parts) >= 4
     28                 and path_parts[0] == "shows"
     29                 and path_parts[2] == "episodes"
     30             ):
     31                 show_name = path_parts[1]
     32                 episode_name = path_parts[3]
     33                 return f"{show_name}/episodes/{episode_name}"
     34             return None
     35         except Exception as e:
     36             print(f"Error extracting path: {e}", file=sys.stderr)
     37             return None
     38 
     39     def extract_episode_name(self, url: str) -> str | None:
     40         """Extract episode name for filename from URL."""
     41         try:
     42             parsed = urlparse(url)
     43             path_parts = [p for p in parsed.path.split("/") if p]
     44 
     45             if (
     46                 len(path_parts) >= 4
     47                 and path_parts[0] == "shows"
     48                 and path_parts[2] == "episodes"
     49             ):
     50                 return path_parts[3]
     51             return None
     52         except Exception as e:
     53             print(f"Error extracting episode name: {e}", file=sys.stderr)
     54             return None
     55 
     56     def get_episode_data(self, episode_path: str) -> dict[str, Any]:
     57         """Fetch episode data from the API."""
     58         encoded_path = "/".join(quote(part) for part in episode_path.split("/"))
     59         url = f"https://www.nts.live/api/v2/shows/{encoded_path}"
     60 
     61         if "--debug" in sys.argv:
     62             print(f"DEBUG: Requesting URL: {url}", file=sys.stderr)
     63 
     64         response = self.session.get(url)
     65         response.raise_for_status()
     66         return cast(dict[str, Any], response.json())
     67 
     68     def save_tracklist(self, episode_data: dict[str, Any], filename: str) -> None:
     69         """Save tracks to a text file."""
     70         if "--debug" in sys.argv:
     71             print(
     72                 f"DEBUG: Response data: {json.dumps(episode_data, indent=2)}",
     73                 file=sys.stderr,
     74             )
     75 
     76         # Extract tracks from the embeds.tracklist.results path
     77         embeds = cast(dict[str, Any], episode_data.get("embeds", {}))
     78         tracklist_container = cast(dict[str, Any], embeds.get("tracklist", {}))
     79         tracklist = cast(list[dict[str, Any]], tracklist_container.get("results", []))
     80 
     81         if not tracklist:
     82             print("No tracks found in this episode", file=sys.stderr)
     83             return
     84 
     85         with open(filename, "w", encoding="utf-8") as f:
     86             for track in tracklist:
     87                 artist = cast(str, track.get("artist", "Unknown Artist"))
     88                 title = cast(str, track.get("title", "Unknown Title"))
     89                 line = f"{artist} - {title}"
     90                 print(line)
     91                 f.write(line + "\n")
     92 
     93     def fetch_and_save_tracklist(self, url: str) -> None:
     94         """Main method to fetch and save tracklist."""
     95         episode_path = self.extract_episode_path(url)
     96         episode_name = self.extract_episode_name(url)
     97 
     98         if not episode_path or not episode_name:
     99             raise ValueError("Could not extract episode information from URL")
    100 
    101         filename = f"{episode_name}.txt"
    102 
    103         if "--debug" in sys.argv:
    104             print(f"DEBUG: Extracted path: {episode_path}", file=sys.stderr)
    105             print(f"DEBUG: Output filename: {filename}", file=sys.stderr)
    106 
    107         try:
    108             episode_data = self.get_episode_data(episode_path)
    109             self.save_tracklist(episode_data, filename)
    110         except requests.exceptions.HTTPError:
    111             raise
    112         except Exception as e:
    113             print(f"Error processing episode: {str(e)}", file=sys.stderr)
    114             raise
    115 
    116 
    117 def main():
    118     parser = argparse.ArgumentParser(description="Fetch tracklist from NTS Radio shows")
    119     _ = parser.add_argument("url", help="URL of the NTS Radio show")
    120     _ = parser.add_argument("--debug", action="store_true", help="Enable debug output")
    121 
    122     args = parser.parse_args()
    123 
    124     try:
    125         fetcher = NTSTracklistFetcher()
    126         fetcher.fetch_and_save_tracklist(args.url)
    127     except requests.exceptions.RequestException:
    128         sys.exit(1)
    129     except ValueError as e:
    130         print(f"Error: {e}", file=sys.stderr)
    131         sys.exit(1)
    132     except Exception:
    133         sys.exit(1)
    134 
    135 
    136 if __name__ == "__main__":
    137     main()