# hirotomasato/sportku architecture

> Architecture diagram of the GitHub repository hirotomasato/sportku, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/hirotomasato/sportku
- Repository: https://github.com/hirotomasato/sportku

## Overview

SportKu fetches a remote M3U playlist, parses channel records, downloads channel logos, and writes a cleaned playlist plus statistics. The daily GitHub Actions workflow is the documented automation entry point; consumers access the generated playlist from the repository. The source excerpt establishes the scraper’s internal calls and file outputs, while the workflow implementation itself was not sampled.

Main entry points: [`src/m3u_scraper.py`](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py) (Scraper runner), [`.github/workflows/auto-update.yml`](https://github.com/hirotomasato/sportku/blob/main/.github/workflows/auto-update.yml) (Update workflow), [`output/sportku.m3u`](https://github.com/hirotomasato/sportku/blob/main/output/sportku.m3u) (M3U playlist), [`config.json`](https://github.com/hirotomasato/sportku/blob/main/config.json) (Scraper config)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_automation["Automation"]
  node_schedule["Daily schedule<br/>[auto-update.yml]"]
  node_workflow["Update workflow<br/>[auto-update.yml]"]
end

subgraph group_scraping["Scraping"]
  node_config["Scraper config<br/>[config.json]"]
  node_scraper["Scraper runner<br/>[m3u_scraper.py]"]
  node_fetch["Playlist fetch<br/>[m3u_scraper.py]"]
  node_parser["M3U parser<br/>[m3u_scraper.py]"]
  node_channels["Channel records<br/>[m3u_scraper.py]"]
  node_logo_downloader["Logo downloader<br/>[m3u_scraper.py]"]
  node_renderer["Playlist renderer<br/>[m3u_scraper.py]"]
end

subgraph group_outputs["Generated outputs"]
  node_logo_files["Logo files"]
  node_writer["Output writer<br/>[m3u_scraper.py]"]
  node_playlist["M3U playlist<br/>[sportku.m3u]"]
  node_stats["Statistics report<br/>[stats.json]"]
end

subgraph group_delivery["Playlist delivery"]
  node_hosting["GitHub repository hosting"]
  node_players(("IPTV players"))
end

node_source["Source playlist"]
node_logo_hosts["Logo hosts"]

node_schedule -->|"triggers"| node_workflow
node_workflow -->|"runs"| node_scraper
node_scraper -->|"loads"| node_config
node_scraper -->|"calls"| node_fetch
node_fetch -->|"fetches"| node_source
node_scraper -->|"calls"| node_parser
node_fetch -->|"returns content"| node_parser
node_parser -->|"creates"| node_channels
node_scraper -->|"calls"| node_logo_downloader
node_logo_downloader -->|"downloads from"| node_logo_hosts
node_logo_downloader -->|"writes"| node_logo_files
node_logo_downloader -->|"updates logo paths"| node_channels
node_scraper -->|"calls"| node_renderer
node_renderer -->|"reads"| node_channels
node_renderer -->|"produces content for"| node_playlist
node_scraper -->|"calls"| node_writer
node_writer -->|"writes"| node_playlist
node_writer -->|"writes"| node_stats
node_workflow -.->|"updates repository"| node_hosting
node_hosting -->|"serves"| node_playlist
node_players -->|"loads playlist"| node_hosting

click node_schedule "https://github.com/hirotomasato/sportku/blob/main/.github/workflows/auto-update.yml"
click node_workflow "https://github.com/hirotomasato/sportku/blob/main/.github/workflows/auto-update.yml"
click node_config "https://github.com/hirotomasato/sportku/blob/main/config.json"
click node_scraper "https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py"
click node_fetch "https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py"
click node_parser "https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py"
click node_channels "https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py"
click node_logo_downloader "https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py"
click node_logo_files "https://github.com/hirotomasato/sportku/tree/main/logos"
click node_renderer "https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py"
click node_writer "https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py"
click node_playlist "https://github.com/hirotomasato/sportku/blob/main/output/sportku.m3u"
click node_stats "https://github.com/hirotomasato/sportku/blob/main/output/stats.json"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_schedule,node_workflow toneBlue
class node_config,node_scraper,node_fetch,node_parser,node_channels,node_logo_downloader,node_renderer toneAmber
class node_logo_files,node_writer,node_playlist,node_stats toneMint
class node_hosting,node_players toneRose
class node_source,node_logo_hosts toneIndigo
```

## Components

### Automation

- [Daily schedule](https://github.com/hirotomasato/sportku/blob/main/.github/workflows/auto-update.yml): `.github/workflows/auto-update.yml`
- [Update workflow](https://github.com/hirotomasato/sportku/blob/main/.github/workflows/auto-update.yml): `.github/workflows/auto-update.yml`

### Scraping

- [Scraper config](https://github.com/hirotomasato/sportku/blob/main/config.json): `config.json`
- [Scraper runner](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py): `src/m3u_scraper.py`
- [Playlist fetch](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py): `src/m3u_scraper.py`
- [M3U parser](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py): `src/m3u_scraper.py`
- [Channel records](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py): `src/m3u_scraper.py`
- [Logo downloader](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py): `src/m3u_scraper.py`
- [Playlist renderer](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py): `src/m3u_scraper.py`

### Generated outputs

- [Logo files](https://github.com/hirotomasato/sportku/tree/main/logos): `logos`
- [Output writer](https://github.com/hirotomasato/sportku/blob/main/src/m3u_scraper.py): `src/m3u_scraper.py`
- [M3U playlist](https://github.com/hirotomasato/sportku/blob/main/output/sportku.m3u): `output/sportku.m3u`
- [Statistics report](https://github.com/hirotomasato/sportku/blob/main/output/stats.json): `output/stats.json`

### Playlist delivery

- **GitHub repository hosting**
- **IPTV players**

### Other components

- **Source playlist**
- **Logo hosts**

## Connections

- Daily schedule → Update workflow: triggers
- Update workflow → Scraper runner: runs
- Scraper runner → Scraper config: loads
- Scraper runner → Playlist fetch: calls
- Playlist fetch → Source playlist: fetches
- Scraper runner → M3U parser: calls
- Playlist fetch → M3U parser: returns content
- M3U parser → Channel records: creates
- Scraper runner → Logo downloader: calls
- Logo downloader → Logo hosts: downloads from
- Logo downloader → Logo files: writes
- Logo downloader → Channel records: updates logo paths
- Scraper runner → Playlist renderer: calls
- Playlist renderer → Channel records: reads
- Playlist renderer → M3U playlist: produces content for
- Scraper runner → Output writer: calls
- Output writer → M3U playlist: writes
- Output writer → Statistics report: writes
- Update workflow → GitHub repository hosting: updates repository
- GitHub repository hosting → M3U playlist: serves
- IPTV players → GitHub repository hosting: loads playlist
