UniplayOS
GitHub Resolver Test Launch Player

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

Result shape
FieldTypeMeaning
sourcestringThe original URL you passed in
typestringmp4 · hls · dash · audio · image · iframe · unknown
strategystringHow the player should load it: native, proxy, hls, dash, or iframe
proxyRequiredbooleanTrue if the strategy is proxy
headersobjectUser-Agent and Referer to send when proxying
fallbackChainstring[]Ordered strategies to try if the first one fails
Note — YouTube and Vimeo links always resolve to the 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.

GET /proxy?url=<encoded media url>
fetch('/proxy?url=' + encodeURIComponent('https://cdn.example.com/clip.mp4'), {
  headers: { Range: 'bytes=0-' }
});

Behavior

Response codes
StatusMeaning
200 / 206Media streamed through, range requests return partial content
400Missing url query param
422Upstream returned HTML instead of media — usually a dead or blocked link
502Upstream fetch failed
504Upstream took longer than 15 seconds
Optional — set 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.

Query parameters
ParamExampleDescription
url?url=https://…/video.mp4Media source to load on page open
source?source=https://…Alias used by the embed script
autoplay?autoplay=trueStarts playback immediately, muted where browsers require it
debug?debug=trueShows 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

new UniplayOS(options)
OptionDefaultDescription
container'#uniplayos'CSS selector for the element the player mounts into
sourcenullSingle media URL to load
sources[]Multiple sources, passed through as JSON
width / height'100%' / '500px'Applied to the container element
autoplayfalseStarts playback on load
allowDownloadstrueShows the download control in the player UI
debugfalseShows 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 options
CallbackFires when
onReadyThe player has mounted and is ready to receive commands
onPlayPlayback starts
onPausePlayback pauses
onEndedPlayback reaches the end of the source
onErrorThe 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

Video
mp4 · webm · mkv · avi · mov · m4v · ts · flv · wmv · 3gp
Audio
mp3 · wav · flac · aac · ogg · m4a · wma · opus
Streaming
HLS (.m3u8) · DASH (.mpd)
Iframe
YouTube · Vimeo
Not supported — TikTok, Instagram and Facebook serve signed, dynamically-loaded video URLs that can't be resolved without a headless browser or an extractor like yt-dlp.

Environment

Variables
VariableRequiredDescription
PORTNoServer port, defaults to 3000
CF_WORKER_URLNoCloudflare Worker URL for the optional egress-proxy bypass layer