A small Go service and CLI to fetch metadata and playback information from RadioJavan (play.radiojavan.com). The program accepts either a plain content identifier (numeric id or slug) or a full RadioJavan URL and returns the raw API response. It also contains a headless-browser based cookie refresher to handle pages that require client-side flows (Cloudflare, JS redirects, etc.).
This README documents how main.go behaves, the available endpoints, and how
cookies are managed.
Table of contents
- Features
- Building
- Running (server)
- CLI usage
- HTTP endpoints
- Web UI
- Cookie handling and automatic refresh
- Important implementation notes
- Troubleshooting
Features
- Fetch metadata/streams from RadioJavan by id or URL.
- Built-in logic to detect content type (mp3/video/podcast) and extract ids.
- Resolves short rj.app links by probing page metadata and, when needed, doing a short headless render (chromedp) to let JS run.
- Reads cookies from a local
cookies.jsonand will automatically refresh cookies (using chromedp) and retry fetches when it receives 401/403.
Building
You need Go installed (1.20+ recommended) and a working Chrome/Chromium binary on the host for chromedp to work when refreshing cookies.
cd /path/to/RadioJavan-Go
go build ./...
# or run directly
go run main.goRunning (server)
The server listens on port 8080 by default. You can override with the
PORT environment variable or the -port flag.
# default :8080
./RadioJavan-Go
# use a different port
./RadioJavan-Go -port 3000CLI usage
The binary also supports invoking fetches directly from the command line. Pass one or more ids/URLs as positional arguments. The program prints the raw API response (pretty-printed JSON when possible).
# fetch by id/slug
./RadioJavan-Go 12345
# fetch by url
./RadioJavan-Go 'https://play.radiojavan.com/podcast/shirin-4'HTTP endpoints
- GET /fetch?id=
idis required and may be either a plain id/slug or a full RadioJavan URL.- The handler delegates to the same logic used by the CLI and returns the raw API response (JSON) or an error with status 502 if the fetch fails.
Web UI
Cookie handling and automatic refresh
- The service looks for a
cookies.jsonfile in the working directory. When present, its cookies are loaded and aCookieheader is set for outgoing requests to the API host. - If a fetch receives HTTP 401 or 403, the service will call an internal
refreshCookiesroutine that launches a headless browser (chromedp), navigates to the site, waits for network activity to settle, extracts the cookies, writes them tocookies.json, and the fetch will retry once. - The cookie refresh is synchronous (the fetch blocks while chromedp runs). This is deliberate so callers immediately get the refreshed behavior, but it makes refresh relatively slow (seconds). Retries are attempted only once to avoid repeated heavy refreshes.
Important implementation notes
- Short
rj.applinks are first probed by issuing a plain HTTP GET and parsing the page HTML forog:url. If that fails, the code uses chromedp to render the page (short timeout) and read the canonical/og:url or location.href. - ID extraction: for most content the code prefers numeric ids found in the
URL path. For
podcasttype it preserves the last path segment verbatim (so slugs likeshirin-4are kept intact). - The code currently stores cookies as the CDP
network.CookieJSON produced by chromedp. If you later want a different cookie format, consider converting betweenhttp.Cookieand the CDP cookie shape or using a persistent CookieJar with serialization.
Troubleshooting
- If fetches fail and the response indicates an auth issue (401/403), ensure Chrome/Chromium is available and the server has permission to launch it.
- If chromedp cannot start in your environment (e.g., headless Chrome missing
on a container), you can still pre-generate
cookies.jsonmanually from a desktop run and copy it to the server's working directory.
