{"id":51539544,"url":"https://github.com/dfallman/texttv","last_synced_at":"2026-07-09T12:01:38.146Z","repository":{"id":358209051,"uuid":"1239392501","full_name":"dfallman/texttv","owner":"dfallman","description":"Highly configurable terminal app for viewing SVT Text-TV, Swedish Television's public-service teletext","archived":false,"fork":false,"pushed_at":"2026-05-16T07:57:59.000Z","size":306,"stargazers_count":3,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-16T09:50:30.220Z","etag":null,"topics":["cli","rust","sverige","svt","sweden","teletext","terminal","text-tv"],"latest_commit_sha":null,"homepage":"https://github.com/dfallman/texttv","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dfallman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-15T03:43:51.000Z","updated_at":"2026-05-16T08:39:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dfallman/texttv","commit_stats":null,"previous_names":["dfallman/texttv"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/dfallman/texttv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfallman%2Ftexttv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfallman%2Ftexttv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfallman%2Ftexttv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfallman%2Ftexttv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dfallman","download_url":"https://codeload.github.com/dfallman/texttv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfallman%2Ftexttv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35298222,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","rust","sverige","svt","sweden","teletext","terminal","text-tv"],"created_at":"2026-07-09T12:01:36.956Z","updated_at":"2026-07-09T12:01:38.134Z","avatar_url":"https://github.com/dfallman.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# texttv\n[![ci](https://github.com/dfallman/texttv/actions/workflows/ci.yml/badge.svg)](https://github.com/dfallman/texttv/actions/workflows/ci.yml)\n[![audit](https://github.com/dfallman/texttv/actions/workflows/audit.yml/badge.svg)](https://github.com/dfallman/texttv/actions/workflows/audit.yml)\n[![license](https://img.shields.io/github/license/dfallman/texttv.svg)](https://github.com/dfallman/texttv/blob/main/LICENSE)\n  \nA small and fast, yet decidedly over-engineered command-line and interactive viewer for [SVT Text-TV](https://www.svt.se/text-tv/), Swedish Television's public-service teletext. The UI might feel like it's [1979 calling](https://www.theguardian.com/world/2024/jan/11/teletext-lives-on-in-sweden-thanks-to-nostalgia-and-trusted-content), but it's still a properly excellent source of news. Now available in a terminal near you.\n\n\u003cp align=\"center\"\u003e\n\n  \u003cimg width=\"800\" alt=\"texttv in use in the terminal\" src=\"https://github.com/user-attachments/assets/e5f20f29-5f19-438d-9c6b-f31e51885e0a\" /\u003e\n\n\u003c/p\u003e\n\n`texttv` is written entirely in [Rust](https://rustup.rs/) and runs on most platforms \n(macOS, Windows, Linux, etc.) in most terminal emulators (such as [iTerm2](https://iterm2.com/), [Ghostty](https://ghostty.org/), [Terminal.app](https://support.apple.com/guide/terminal/welcome/mac), [Windows Terminal](https://github.com/microsoft/terminal), [GNOME Terminal](https://help.gnome.org/users/gnome-terminal/stable/), [Konsole](https://konsole.kde.org/), [Foot](https://codeberg.org/dnkl/foot), [Terminator](https://gnome-terminator.org/), [Kitty](https://sw.kovidgoyal.net/kitty/), [WezTerm](https://wezterm.org/), [Alacritty](https://alacritty.org/), [Tabby](https://tabby.sh/), and others). Hope all is well with Felicia!\n\n## Installation\n\nMake sure you have the latest version of Rust installed. Use [Rustup](https://rustup.rs/) rather than your package manager to install, as this ensures you'll get the latest version.\n\n```bash\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n```\n\nThen clone the repo and install:\n\n```bash\ngit clone https://github.com/dfallman/texttv\ncd texttv\ncargo install --path .\n```\n\n## Usage\n`texttv` is simple to use out of the box and doesn't require any particular configuration\nin most terminals to get started. \n\nThe app has two different modes, **interactive mode** (where you browse the pages) and **single page view** (where you output a single page to the terminal).\n\n### Interactive mode \nThis opens a Text-TV browser in the terminal and allows you to navigate the teletext pages using familiar inputs. Type the page number to go to that page, use your arrow keys left and right to go to next/previous page, use up and down to select links on the page, and enter to select. Press `Esc` to quit.\n\nUse the commands `texttv` or `texttv --interactive`.\n\n\u003cp align=\"center\"\u003e\n\n  \u003cimg width=\"400\" alt=\"texttv interactive mode\" src=\"https://github.com/user-attachments/assets/cf0a95bd-c155-4ef1-b985-2b2d781d8d4d\" /\u003e\n  \u003cbr\u003e  \n  \u003cem\u003eInteractive mode\u003c/em\u003e\n\n\u003c/p\u003e\n\n### Single page view mode\nOutputs a single page to the terminal. Type `texttv 360` to view page 360, for example (I wonder how those Birch Leaves are going, heard they did well this season!) How the single page is rendered depends on your terminal emulator's capabilities and your settings (see below).\n\n## Rendering modes\n\n`texttv` has two different ways to render a page. The right one for your \nterminal defaults automatically, but you can always override it. \nBoth render types have their pros and cons, pick the one you like the most:\n\n1. **Teletext mode** (the default and fallback option) reconstructs the original\n40-column page as real terminal text: the 8 teletext colors as ANSI\ntruecolor, bold double-height headings, Unicode sextants for the mosaic\nblock-characters (the SVT logo, sport icons, weather symbols, navigation\nborders). The benefit here is that the text you see is real text: copyable, \ngrep-able, and feels right at home in the terminal. The downside is that we lose some\nminor details on the page, most notably the double-height characters that most terminal\nemulators can't render in a predictable fashion (see note below).\n\n\u003cp align=\"center\"\u003e\n    \u003cimg width=\"800\" alt=\"texttv in use in the terminal\" src=\"https://github.com/user-attachments/assets/1dfe1df2-e52f-4ec9-b617-e467254157e6\" /\u003e\n    \u003cbr\u003e\n    \u003cem\u003eTeletext mode: pages are rendered as text\u003c/em\u003e\n\u003c/p\u003e\n\n2. **Image mode**, on the other hand, asks your terminal to draw the original page GIF that SVT\nitself serves. Here, you'll get pixel-perfect rendering, but you lose selectable text.\nThis is the default pick for terminals with a native graphics protocol (Kitty,\nGhostty, WezTerm, iTerm2). On other terminal emulators, you can try it via `--mode auto`. On\nhalf-block-only terminals (these include Apple Terminal, Alacritty, Windows Terminal,\nand others) image mode falls back to a Unicode-half-block rendering, which is\nconsiderably worse than the teletext text path. Unless you have a very large terminal\nwindow, it'll look quite blurry (still pretty cool though!) So for these terminals, \nthe default is `--mode teletext`.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg width=\"800\" alt=\"texttv rednered as image\" src=\"https://github.com/user-attachments/assets/563e2d42-a1ad-48d1-b7b1-401c4cd761a1\" /\u003e\n    \u003cbr\u003e\n    \u003cem\u003eImage mode: pages are rendered as images in supported terminals\u003c/em\u003e\n\u003c/p\u003e\n\n\nPick your mode explicitly with `--mode`:\n\n```bash\ntexttv 300 --mode teletext       # force the text render\ntexttv 300 --mode auto           # render the GIF via whichever graphics protocol your terminal supports\ntexttv 300 --mode kitty          # force Kitty graphics protocol\ntexttv 300 --mode iterm          # force iTerm2 inline-image protocol\ntexttv 300 --mode blocks         # force the half-block fallback\n```\n\n**Pro tip:** if you prefer a rendering mode or a size that isn't the default for your terminal emulator, consider creating a configuration file (see below). That way your preferred settings will load automatically and you'll only have to type `texttv \u003cPAGE\u003e`.\n\n### A note on double-height headlines\n\nTeletext's headline rows are *double-height*, where each character is one column\nwide but two rows tall. SVT Text-TV tends to frequently use double-height characters for headings, typically on page `100`.\n\nThe terminal equivalent is called `DECDHL` (DEC Double-Height\nLine), a VT100-era escape sequence that does exactly the same thing.\n\nIn theory `texttv` could emit `DECDHL` and let your terminal handle it. In practice\nthough, support is a mess at best: xterm, Kitty, WezTerm, and Konsole render it correctly (more or less);\nApple Terminal, Alacritty, Windows Terminal, and Ghostty either ignore it,\nhalf-render it, or break in interesting ways around scrolling and cursor\npositioning. Many emulators also disagree about how copy-paste, resize, and reflow should behave.\n\nRather than ship a feature that looks good on a third of terminals and\nvisibly broken on the rest, `texttv` renders headlines at normal height in\nteletext mode. You still get the bold weight and the color, just not the\n2x vertical. Image mode preserves them faithfully however. Optional support for DECDHL might be added in future releases.\n\n## Usage examples\n`texttv` is easy to use out of the box but also highly configurable, so the above is only the basic operation. Here are some\nexamples of a few typical options (see below for details):\n\n```\ntexttv\n```\n\nThe first example starts `texttv` in interactive mode, which allows you to navigate through pages using number input, arrow keys, and `Enter` to select, `Esc` to quit.\n\n```\ntexttv 300 --mode teletext\n```\n\nThe second example shows page 300 but overrides the default rendering mode (see below) to `teletext` mode, which draws the page as text+ANSI.\n\n```\ntexttv 101 --mode iterm --size small --source svt --verbose \n```\n\nThe third example enforces iTerm2's default rendering mode (image), outputs it in small size, enforces the source to be SVT, and shows verbose logging output in the console.\n\n## Options\n\n`texttv \u003cPAGE\u003e [options]`\n\n| Flag | Meaning |\n| --- | --- |\n| `\u003cPAGE\u003e` | The page number between 100 and 999 |\n| `--mode {teletext,auto,kitty,iterm,blocks}` | Rendering path. Default depends on your terminal (see the matrix below). |\n| `--size {tiny,small,medium,large,xl,full}` | Width for image modes. Default `medium` (60 cells). Ignored in teletext mode. |\n| `--source {texttv-nu,svt}` | Data source. Defaults to `texttv-nu` for teletext (it exposes the color attributes we need to reconstruct the page), `svt` for image modes. |\n| `--no-color` | Strip ANSI color and the right-edge frame. Plain mono. |\n| `--no-padding` | Drop the blank rows above and below the page. (Padding is on by default.) |\n| `--list` | Print the named-section index and exit. |\n| `--debug-protocol` | Echo the detected graphics protocol on stderr before drawing. |\n| `--verbose` / `-v` | Per-phase timing traces on stderr. Also enabled by `TEXTTV_TIMINGS=1`. |\n| `--help` / `--version` | Standard. |\n\n### Image-mode sizing (`--size`):\n\n| value | cells |\n| --- | --- |\n| `tiny` | 30 |\n| `small` | 45 |\n| **`medium`** | **60 (default)** |\n| `large` | 90 |\n| `xl` | 120 |\n| `full` | terminal width, capped at 4000 |\n\n## Terminal image mode matrix\n\nDefaults vary by terminal. You can always override with `--mode`. Note however that your terminal can only draw what it can draw, so even if you override the image-mode protocol with something your terminal can't handle, the fallback will be shown (usually half-blocks). If this happens, `--mode teletext` is the safest option.\n\n| Terminal | Default | Image-mode protocol |\n| --- | --- | --- |\n| Kitty | image | Kitty graphics (true pixels) |\n| Ghostty | image | Kitty graphics (true pixels) |\n| WezTerm | image | iTerm2 inline (true pixels) |\n| iTerm2 | image | iTerm2 inline (true pixels) |\n| Apple Terminal | teletext | half-blocks fallback |\n| Alacritty | teletext | half-blocks fallback |\n| Windows Terminal | teletext | half-blocks fallback |\n| foot / mlterm | teletext | half-blocks fallback (Sixel is on the roadmap) |\n\n`texttv 300 --debug-protocol` reports the detected protocol on stderr if\nyou're curious.\n\n### tmux\n\nKitty's graphics protocol needs tmux passthrough:\n\n```\nset -g allow-passthrough on\nset -g default-terminal \"tmux-256color\"\n```\n\nIf `--debug-protocol` says `halfblocks` inside tmux but your outer terminal\nis Kitty / Ghostty / WezTerm, this is almost certainly why. Teletext mode is\nunaffected.\n\n## Auto-degrade\n\nWhen `stdout` is piped or redirected, ANSI escapes are stripped automatically\n— so `texttv 300 | grep` and `texttv 300 \u003e page.txt` produce clean text.\n`NO_COLOR=1` and `--no-color` do the same explicitly. Image mode is replaced\nby teletext mode when the output isn't a TTY (you don't want raw image-\nprotocol escape codes ending up in a pipe).\n\n## Interactive mode\n\nRunning `texttv` with no arguments — or with `-i` / `--interactive` — opens\nan in-terminal page browser starting at page 100. Pass an explicit page to\nstart elsewhere, e.g. `texttv -i 300`.\n\n**The input field** sits in the top-left, overlaying the page's own\nheader. It shows a triangle pointer (`⏵`) when idle and a braille spinner\nduring loads, followed by the current page number. Type three digits to\njump to a page — no Enter required, the page loads as soon as the third\ndigit lands. Partial input shows as middle-dot placeholders (`3··`).\nBackspace removes the last typed digit. Out-of-range pages (`000`–`099`)\nflash an error in the hint bar.\n\n**Links** are three-digit page references found on the rendered page.\nThe detector is permissive on purpose:\n\n- `\" 300 \"` — the bare case.\n- `\" 328f \"` — `f` is the multi-page suffix; the link targets 328.\n- `\" 376- \"` — trailing dash (range start with no upper bound).\n- `\" 343-344 \"` — range; both numbers become links.\n- `\"100.000\"` is *not* a link (digits adjacent to a `.`).\n\nWhen the cursor is on a link the three digits are highlighted in\nwhite-on-magenta. Press Enter or Space to follow it.\n\n**Multi-page** pages (the `XXXf` indicator) carry multiple subpages.\nThe bottom bar replaces the standard hint with a subpage selector:\n`Page: \u003e1\u003c 2 3 4 …` with `\u003eactive\u003c` marking the currently rendered\nsubpage. When the cursor is parked on a subpage selector, `←/→` cycle\nthrough the subpages instead of stepping page numbers.\n\n**Keys:**\n\n| Key | Action |\n| --- | --- |\n| `0`–`9` | Type a page number (3 digits → load immediately) |\n| Backspace | Remove last typed digit |\n| `↑` `↓` | Move between input field, links, and subpage selectors |\n| `←` `→` | Page ±1 (or cycle subpages when on a subpage selector) |\n| Enter / Space | Follow the selected link, or switch subpage |\n| `q` / Esc | Quit |\n\nA freshly-loaded page has no active link until you press an arrow key.\nThe input field is reachable via `↑` from the topmost page link.\n\nInteractive mode always uses teletext rendering — image modes are not\ncompatible with link scanning. `--mode` and `--source` flags are ignored\n(with a one-line stderr warning) if passed alongside `-i`. If a page\ndoesn't exist, a centered \"Sidan finns inte\" placeholder renders in\nplace of content and `←/→` keep working so you can step past gaps in\nSVT's numbering. The terminal must be at least 41 columns × 26 rows.\n\n## Config file\n\nOptional. Read from `$XDG_CONFIG_HOME/texttv/config.yaml` (defaults to\n`~/.config/texttv/config.yaml`). CLI flags always win; missing keys fall back\nto built-in defaults; unknown keys are an error.\n\n```yaml\n# All fields optional. Lines below show the built-in defaults.\n\n# mode: teletext               # teletext | auto | kitty | iterm | blocks\n                               # (terminal-dependent default, see matrix)\n# size: medium                 # tiny | small | medium | large | xl | full\n# source: texttv-nu            # texttv-nu | svt\n# no_color: false              # also honoured: NO_COLOR=1 env, piped stdout\n# padding: true                # blank row above and below the page\n# verbose: false               # per-phase timing traces on stderr\n```\n\n## Exit codes\n\n| code | meaning |\n| --- | --- |\n| `0` | success |\n| `1` | bad arguments / page out of range |\n| `2` | network error, parse error, or \"page not available\" |\n\n## Data sources\n\n- **[`api.texttv.nu`](https://texttv.nu)** — community-run JSON proxy that\n  preserves per-cell color attributes. The teletext mode depends on this;\n  the official SVT pages strip the color information. We identify\n  ourselves as `app=texttvcliv\u003cversion\u003e` per\n  [their policy](https://texttv.nu/blogg/texttv-api).\n- **[`svt.se/text-tv/\u003cPAGE\u003e`](https://www.svt.se/text-tv/)** — the official\n  page, used for the embedded GIF when an image mode is active.\n\nDecoded mosaic patterns persist to the OS cache directory under\n`texttv/mosaics/` (Linux: `$XDG_CACHE_HOME/...` or `~/.cache/...`; macOS:\n`~/Library/Caches/...`; Windows: `%LOCALAPPDATA%\\...`) so a given pattern is\nfetched once across all runs.\n\nThis project is not affiliated with, endorsed by, or sponsored by SVT or\ntexttv.nu. It's an independent reader for publicly broadcast teletext data.\nPlease respect the upstream terms of service when using it — keep your\nrequests reasonable, don't strip the User-Agent or the `app=` parameter, and\ndon't use this tool or any part of this tool to overload either service.\n\n# Misc\n\n## Help! I don't know any Swedish!\n\nObvious perhaps, but SVT Text-TV is in Swedish. While a built-in translation engine is\nout of scope for this application, there are ways around this if you\ndon't speak Swedish but are keen to read what's happening:\n\n1. Learn Swedish. It's not the easiest language to learn, to be honest, but there are many [online resources available](https://studyinsweden.se/moving-to-sweden/learn-swedish/).\n\n2. Pipe the output of `texttv` into a translation engine or LLM, or you can use terminal-based translation engines such as [translate-shell](https://github.com/soimort/translate-shell). With it installed, pipe the output of `texttv` into the translation engine:\n\n```\ntexttv 100 | trans -b sv:en\n```\n\nIt's not going to be perfect, but you'll get the gist of it.\n\n## Note on AI use\n\nThe author of this application has been writing code for over 30 years. Lately, \nLLM agent-enhanced coding practices have rekindled my sense of awe at what's \npossible. This project has been built using a range of tools, including Anthropic's Claude Code (using Opus 4.7), [dan](https://github.com/dfallman/dan), and vscode.\n\nUnlike some who dismiss anything touched by a coding agent as \"slop,\" I don't \nsee it that way. To me, these tools are a way to move much faster, explore \nmany more ideas, and test those ideas and implementations more rigorously \nthan I ever could on my own.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfallman%2Ftexttv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdfallman%2Ftexttv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfallman%2Ftexttv/lists"}