nix

configuration files that power my machines
Log | Files | Refs | README | LICENSE

tw (2325B)


      1 #!/usr/bin/env python3
      2 import sys
      3 import os
      4 import urllib.request
      5 import urllib.error
      6 from typing import cast
      7 from http.client import HTTPResponse
      8 from concurrent.futures import ThreadPoolExecutor, as_completed
      9 
     10 
     11 def read_channels_file(filepath: str) -> list[tuple[str, str]]:
     12     channels: list[tuple[str, str]] = []
     13     if not os.path.isfile(filepath):
     14         return channels
     15 
     16     with open(filepath, "r") as f:
     17         for line in f:
     18             line = line.strip()
     19             if not line:
     20                 continue
     21             parts = line.split(None, 1)
     22             channel = parts[0]
     23             description = parts[1] if len(parts) > 1 else ""
     24             channels.append((channel, description))
     25 
     26     return channels
     27 
     28 
     29 def check_channel_status(channel: str, description: str) -> tuple[str, str, bool]:
     30     try:
     31         url = f"https://www.twitch.tv/{channel}"
     32         req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
     33         with cast(HTTPResponse, urllib.request.urlopen(req, timeout=10)) as response:
     34             content: str = response.read().decode("utf-8", errors="ignore")
     35             is_online: bool = "isLiveBroadcast" in content
     36             return (channel, description, is_online)
     37     except (urllib.error.URLError, urllib.error.HTTPError, TimeoutError):
     38         return (channel, description, False)
     39 
     40 
     41 def main():
     42     channels_file = os.path.expanduser("~/.config/twitch/channels")
     43     if not os.path.isfile(channels_file):
     44         print("Error: ~/.config/twitch/channels not found", file=sys.stderr)
     45         sys.exit(1)
     46 
     47     channels = read_channels_file(channels_file)
     48     if not channels:
     49         return
     50 
     51     max_workers = 10
     52 
     53     with ThreadPoolExecutor(max_workers=max_workers) as executor:
     54         future_to_channel = {
     55             executor.submit(check_channel_status, channel, description): (
     56                 channel,
     57                 description,
     58             )
     59             for channel, description in channels
     60         }
     61 
     62         for future in as_completed(future_to_channel):
     63             channel, description, is_online = future.result()
     64 
     65             if is_online:
     66                 if description:
     67                     print(f"{channel} ({description}) is online")
     68                 else:
     69                     print(f"{channel} is online")
     70 
     71 
     72 if __name__ == "__main__":
     73     main()