CLI tool
orion-lib/OrionTV avatar
orion-lib/OrionTV

OrionTV, a TV player built on React Native TVOS where the remote control is the cursor

一个基于 React Native TVOS 和 Expo 构建的播放器,旨在提供流畅的视频观看体验。

5,620 stars1,886 forksTypeScriptLicense varies

At a glance

What is it?
OrionTV is a video player for Apple TV and Android TV built with Expo, React Native TVOS and TypeScript, using Expo Router for file based navigation and a UI designed around remote control input. It is a front end over a separate backend, and the README makes the dependency explicit.
Who is it for?
OrionTV suits someone who wants a TV interface on top of an existing video search backend, and it suits a React developer who already knows Expo Router and wants one codebase for both Apple TV and Android TV.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 13 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A search client for a TV, not a media player

OrionTV is described as a player built on React Native TVOS and Expo, intended to deliver a smooth video watching experience. The four feature bullets give the scope: cross-platform support for building both Apple TV and Android TV, a modern frontend with Expo, React Native TVOS and TypeScript, file system routing through Expo Router, and a UI designed specifically for interaction with a television remote control.

The usage section is where the real dependency appears. Versions from 1.2.x onwards need to be used together with MoonTV, and the acknowledgements name MoonTV as a video aggregation application built on Next.js, alongside LibreTV as an open source video streaming application. OrionTV is therefore the presentation layer of a two-part system.

The disclaimer sets the boundary on content. OrionTV is only a video search tool, it does not store, upload or distribute any video content, and all the video comes from third party API search results. If there is infringing content, the instruction is to contact the relevant content provider. The developers are not responsible for the consequences of using it, and users must comply with local laws and regulations.

That is a clear architectural statement: the frontend holds no media, the backend holds the catalogue, and the app is a client that renders search results and plays what it finds. It also means the app is only as good as the API it talks to, and the acknowledgement section names a sponsor in that context, gpt-load, described as a high performance OpenAI format API multi-key rotation proxy server that supports load balancing and is written in Go.

The repository is orion-lib/OrionTV, while the homepage field points at a different path, zimplexing/OrionTV, which is worth knowing if you are following links.

The last push was on 2026-10-10 and the release tags are v1.3.14 from the same day, v1.3.13 from 2026-02-05 and v1.3.12 from 2025-12-17. The README states the project uses the MIT licence, though the repository licence metadata is not classified.

The stack, and what the resolutions field is doing

The technical stack is listed as React Native TVOS, Expo at about version 51.0, Expo Router, Expo AV and TypeScript. The dependency list in package.json is more specific: expo at about 51.0.13, expo-av at about 14.0.7, expo-router at about 3.5.16, and the rest of the Expo SDK surface, expo-constants, expo-font, expo-intent-launcher, expo-linear-gradient, expo-linking, expo-splash-screen, expo-status-bar, expo-system-ui, expo-web-browser and expo-build-properties. Outside Expo there is @react-native-async-storage/async-storage for local state, @react-native-community/netinfo for connectivity, @react-native-cookies/cookies, @react-navigation/native, @expo/vector-icons and lucide-react-native for icons.

One field in package.json deserves a closer look, and it is the resolutions block:

json
"resolutions": {
    "react-native": "npm:react-native-tvos@~0.74.2-0"
}

That is an npm alias. Every dependency that asks for react-native gets react-native-tvos at about 0.74.2 instead. This is the mechanism that makes a single Expo project build for a television, because the React Native TVOS fork is a fork of react-native with the TV platform support, and an alias in resolutions makes the fork transparent to the dependency tree. The version is a specific one, the 0.74 series, which makes the choice explicit and deliberate rather than accidental.

The entry point is expo-router/entry, which confirms the file system routing, and the package is marked private, so it is an application rather than something published to npm.

The scripts show the whole lifecycle. The start script runs the Expo CLI with EXPO_TV=1 and EXPO_USE_METRO_WORKSPACE_ROOT=1 set, and those two environment variables appear in the android, ios and prebuild scripts as well, so every Expo invocation in the project runs in TV mode. The prebuild script runs expo prebuild --clean followed by yarn copy-config, and copy-config copies the contents of the xml/ directory into android/app/src, which is how the Android TV launcher icon and related XML configuration get into the generated native project. There is a build script that runs prebuild in production mode and then assembles the Android release with gradlew, plus a build-debug variant that goes straight to gradle, and separate clean, clean-modules and reset-project targets.

The prebuild step, and the four commands you actually need

The quick start lists what you need installed: Node.js at an LTS version, Yarn, the Expo CLI, Xcode for Apple TV development and Android Studio for Android TV development.

The commands then are four, and the second one is the part that surprises people.

sh
yarn
yarn prebuild-tv
yarn ios-tv
yarn android-tv

The prebuild-tv step is marked as needed on the first run or after a dependency update, and its purpose is stated plainly: it generates the native project files and modifies the native code to support TV based on the configuration in app.json. In other words, the native projects are not committed and are not hand-edited. They are generated from app.json, and regenerated when something changes.

That is the right model for an Expo project that targets a platform with its own native conventions, because the television target needs launcher icons, an intent filter for the Android TV home screen and the Apple TV focus engine metadata, and those are exactly the things that get lost when the native directory is checked in and then drifts from the JS config.

The scripts section also lists a start script that launches the Metro bundler in phone mode and a start-tv variant that launches it in TV mode, which suggests the same codebase is used for development on a phone with a different rendering path, and a lint script for checking code style. The README describes the project structure as monorepo-like, and the tree in the README shows it:

code
app/
assets/
components/
constants/
hooks/
services/
package.json

So the app/ directory holds the routes and pages, assets/ holds static resources including fonts, images and the TV icons, components/ holds React components, constants/ holds application constants such as colours and styles, hooks/ holds custom hooks, and services/ holds the service layer for the API and storage.

Remote control input is the design constraint

The one feature bullet that has real engineering behind it is the last one, a UI designed specifically for interaction with a television remote control, and it shapes everything else in the project.

A pointer-driven application assumes a mouse. A TV remote gives you a directional pad, an OK button, a back button, and a playback transport. Every interaction has to be expressible in those terms, which means focus has to be explicit and visible, the list of focusable elements has to be navigable in one dimension, and actions that are a single click on the web become a focused button. Expo Router's file system routing fits because a screen is a route and the navigation order is a property of the route tree, which is something you can reason about rather than something laid out in a view hierarchy.

The directory structure supports that. The constants/ directory holding colours and styles is where a focus colour and a selected state live, and a consistent focus treatment across a whole app is only achievable if the palette is centralised, which is why those constants exist as a separate concept rather than being inline in components.

The assets/ directory explicitly lists TV icons alongside fonts and images, which is the launcher artwork, and the copy-config script that copies xml/ into the native Android project is the mechanism that gets it there.

The Expo AV package is what plays the video, and expo-web-browser is in the dependency list, which suggests a path for handing off to an external player for some content rather than playing everything in-process. On a television, that is sometimes the pragmatic choice, because a video decoding pipeline that behaves well on a desktop does not necessarily behave well on a low powered TV box, and the in-app player and the external browser are two different failure domains.

The service layer in services/ handles the API and storage, and the disclaimer says all video comes from third party API search results, so the services layer is the boundary between this app and the backend that holds the catalogue.

The project as it stands

The repository contents give a sense of the working state. There is an app/ directory for the routes, assets/ for static resources, components/ for React components, constants/ for the shared values, hooks/ for custom hooks, services/ for the service layer, stores/ for state, utils/ for helpers, and xml/ for the Android TV configuration that gets copied into the native project. There is a docs/ directory, a screenshot/ directory, an eas.json for the Expo Application Services configuration, app.json for the Expo app config, and metro.config.js, babel.config.js and tsconfig.json for the toolchain.

The tooling is conventional Expo. Linting is expo lint, type checking is tsc --noEmit, and there are two Jest scripts, one running in watch mode for development and one for CI with coverage and no cache. The Jest preset is jest-expo, which is the correct preset for an Expo project and the one that knows how to transform the React Native modules.

The development tooling around the repository is also worth noting. There is a.eslintrc.js and a.prettierrc for linting and formatting, a CLAUDE.md and a.claude/ directory for agent assistance, and a.github/ directory for the workflows.

The honest summary is that this is a focused, well-organised application rather than a general purpose library, and that its value to anyone reading it is mostly in the TV-specific parts: the resolutions alias that swaps in the TVOS fork of React Native, the prebuild step that regenerates the native project with TV support, and the copy-config step that gets the launcher XML into the Android project. Those three pieces are what a reader who wants to build their own TV client would take from it.

The version history is also a caution about the dependency pinning. The Expo SDK is 51, the React Native TVOS fork is on the 0.74 series, and the latest release is v1.3.14. The project is still receiving releases, with the most recent on 2026-10-10, and the framework versions are pinned to Expo 51 and the 0.74 series of the TVOS fork.

Editorial conclusion

OrionTV suits someone who wants a TV interface on top of an existing video search backend, and it suits a React developer who already knows Expo Router and wants one codebase for both Apple TV and Android TV. It is the wrong choice if you need a self-contained player, because the README states that versions from 1.2.x must be used together with MoonTV, and it is the wrong choice if you want a plain video file player, since this is a search client rather than a local media player. Before starting, read the disclaimer about third party content, plan the native prebuild step into your workflow, and check that your backend serves the API shape the services/ layer expects, since the frontend stores and reads no video content of its own.

Frequently asked questions

What is OrionTV and what does it depend on?

OrionTV is a video player for Apple TV and Android TV built on React Native TVOS, Expo, Expo Router, Expo AV and TypeScript. The README states that versions from 1.2.x need to be used together with MoonTV, which it lists among the projects it was inspired by along with LibreTV.

How do I run OrionTV on a TV?

Run yarn to install the dependencies, then yarn prebuild-tv to generate the native project files with TV support based on app.json, then yarn ios-tv for Apple TV or yarn android-tv for Android TV. You need Node.js LTS, Yarn, the Expo CLI, and Xcode or Android Studio.

How does the project get React Native TVOS into the dependency tree?

Through the resolutions field in package.json, which aliases react-native to react-native-tvos at about version 0.74.2, so any dependency asking for react-native receives the television fork instead. The entry point is expo-router/entry.

Does OrionTV store or serve any video content?

No. The disclaimer states that OrionTV is only a video search tool, does not store, upload or distribute any video content, and that all video comes from third party API search results, with infringing content to be reported to the relevant provider.

What licence is OrionTV released under?

The README states the project uses the MIT licence. The repository's own licence metadata is not classified by GitHub, so the README is the statement to rely on. The latest release tag is v1.3.14.

Official sources

  1. Issues
  2. orion-lib/OrionTV on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/orion-lib-oriontv.svg)](https://hysenlabs.com/projects/orion-lib-oriontv)

Was this useful?