Documentation
Build with UniplayOS
UniplayOS resolves a raw media URL into a playback strategy, streams it through a same-origin proxy when the source needs one, and gives you a player you can either open directly or embed on any page with a couple of lines of script.
Quickstart
Clone the repo, install dependencies, run the dev server.
# clone and install
git clone https://github.com/unitedevz/uniplayOs.git
cd uniplayOs
npm install
# start the dev server on :3000
npm run dev
Then open http://localhost:3000/player.html?url=https://example.com/video.mp4 to test a direct link, or /test.html to inspect how any URL resolves before wiring it up.
Resolver
Every URL passed to the player goes through Resolver.resolve(url) first. It looks at the URL, decides what kind of media it is, and picks a playback strategy plus a fallback chain to try if that strategy fails.
const resolver = new Resolver({ proxyBase: '/proxy' });
const result = resolver.resolve('https://cdn.example.com/stream.m3u8');
console.log(result.type); // 'hls'
console.log(result.strategy); // 'hls'
console.log(result.proxyRequired); // true
console.log(result.fallbackChain); // ['hls', 'proxy', 'mp4-fallback']
What resolve() returns
| Field | Type | Meaning |
|---|---|---|
source | string | The original URL you passed in |
type | string | mp4 · hls · dash · audio · image · iframe · unknown |
strategy | string | How the player should load it: native, proxy, hls, dash, or iframe |
proxyRequired | boolean | True if the strategy is proxy |
headers | object | User-Agent and Referer to send when proxying |
fallbackChain | string[] | Ordered strategies to try if the first one fails |
iframe strategy and skip the proxy entirely, since those platforms serve their own playback surface.Proxy Endpoint
When a source needs to be proxied, the player requests it through /proxy instead of fetching it directly. This is what lets UniplayOS sidestep CORS and hotlink protection on the source, and forwards range requests so seeking still works.
fetch('/proxy?url=' + encodeURIComponent('https://cdn.example.com/clip.mp4'), {
headers: { Range: 'bytes=0-' }
});
Behavior
| Status | Meaning |
|---|---|
200 / 206 | Media streamed through, range requests return partial content |
400 | Missing url query param |
422 | Upstream returned HTML instead of media — usually a dead or blocked link |
502 | Upstream fetch failed |
504 | Upstream took longer than 15 seconds |
CF_WORKER_URL in .env to route proxy requests through a Cloudflare Worker first, for sources that block by IP range. See the UniplayOsproxy repo for the worker setup.Player Params
The player at /player.html reads its source straight from the query string, so it can be deep-linked without any JavaScript.
| Param | Example | Description |
|---|---|---|
url | ?url=https://…/video.mp4 | Media source to load on page open |
source | ?source=https://… | Alias used by the embed script |
autoplay | ?autoplay=true | Starts playback immediately, muted where browsers require it |
debug | ?debug=true | Shows the status/debug bar under the controls |
Embed Script
Drop the embed script into any page and point it at a container element. It mounts an iframe running the UniplayOS player and talks to it over postMessage.
<div id="player" style="width:800px;height:450px;"></div>
<script type="module">
import UniplayOS from "https://www.uniplayos.web.id/embed.js";
const player = new UniplayOS({
container: "#player",
source: "https://example.com/video.mp4",
autoplay: false,
debug: false,
onReady() { console.log("ready"); },
onPlay() { console.log("playing"); },
onError(err) { console.error(err); }
});
</script>
Constructor Options
| Option | Default | Description |
|---|---|---|
container | '#uniplayos' | CSS selector for the element the player mounts into |
source | null | Single media URL to load |
sources | [] | Multiple sources, passed through as JSON |
width / height | '100%' / '500px' | Applied to the container element |
autoplay | false | Starts playback on load |
allowDownloads | true | Shows the download control in the player UI |
debug | false | Shows the resolver/status debug bar |
Events
Pass any of these as callbacks in the constructor. Each fires from a postMessage the player sends back to the parent page.
| Callback | Fires when |
|---|---|
onReady | The player has mounted and is ready to receive commands |
onPlay | Playback starts |
onPause | Playback pauses |
onEnded | Playback reaches the end of the source |
onError | The source fails to load or resolve |
Instance Methods
Once you hold a reference to the player instance, drive it programmatically.
player.play();
player.pause();
player.togglePlay();
player.seek(30);
player.setVolume(0.5);
player.toggleMute();
player.toggleFullscreen();
player.load('https://example.com/next.mp4');
player.destroy();
Supported Formats
Environment
| Variable | Required | Description |
|---|---|---|
PORT | No | Server port, defaults to 3000 |
CF_WORKER_URL | No | Cloudflare Worker URL for the optional egress-proxy bypass layer |