Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ployan HLS Scraper & Stream Resolver

Self-hosted embed scraper and HLS stream resolver for Ployan player pages. Paste a watch URL, scrape the page, reverse engineer the AES-256-GCM session token, and resolve a direct M3U8 master playlist—pure Node.js HTTP and crypto, with no browser automation and no VM.

Built for people who need a working stream link, and for developers studying web scraping, playlist resolution, and player reverse engineering.


Table of contents

  1. Overview
  2. Who this is for
  3. What you get
  4. Quick start
  5. Architecture
  6. How resolve works
  7. Why a proxy is required in the browser
  8. HLS proxy
  9. Project layout
  10. Stack and requirements
  11. Disclaimer

Overview

A Ployan-powered watch page is not the stream. It is HTML that exposes a media id and a base64 player origin (plyURL). The real HLS playlist stays behind a sealed token on the player host. This project is an end-to-end stream resolver: it scrapes that page, rebuilds the same token the player would seal, calls /get, and returns {origin}/hls/{info}/master.m3u8.

Everything runs server-side. The small web UI only submits a URL, shows timing, plays through a local HLS proxy, and offers copy commands for VLC and MPV.

Example input page: flixhqz.com/movie/scream-7-1630860919/


Who this is for

Users

  • You want a direct M3U8 link from an embed page without opening DevTools.
  • You want in-browser playback, or a one-click command for VLC / MPV.
  • You want a self-hosted tool, not a third-party streaming site.

Developers

  • You are learning web scraping of embed HTML (media id, player origin, title).
  • You are studying reverse engineering of obfuscated player crypto (PBKDF2 + AES-256-GCM).
  • You need a clear stream resolver pattern: scrape → seal → /get → playlist URL → optional proxy.

What you get

  • Embed scraper — one HTTP GET on the watch page; reads #mid data-id, decodes plyURL, parses <title>.
  • Stream resolver — seals a fresh session token and resolves a direct HLS master playlist when the player returns mode: "direct".
  • Reverse engineering port — the proven player seal in node:crypto (no headless browser, no JS VM).
  • HLS proxy — rewrites #EXTM3U playlists so the browser can load segments through your host.
  • Local UI — resolve timing, first-frame timing, hls.js playback, export fields for direct URL / proxy / VLC / MPV.

There is one resolve path. Missing fields or a non-direct /get response fail loudly—no alternate scrapers, no native-HLS fallback branch, no silent defaults.


Quick start

Requirements

  • Node.js ≥ 22.18
  • Network reachability to the embed site and the Ployan player origin

Install and run

npm install
npm start

Open the printed local URL (default http://localhost:3000/).

  1. Paste a watch / embed page URL.
  2. Click Resolve.
  3. Play in the page, or copy the direct M3U8 / VLC / MPV fields.

Optional: set PORT to change the listen port.

PORT=8080 npm start

Architecture

Three network layers sit between a watch URL and playable media:

Layer Role
Embed site Serves HTML; exposes mediaId and base64 plyURL
Player API Accepts sealed token on /get/{token}; returns info
CDN Serves media playlists and .ts segments named inside M3U8
flowchart LR
  A[Watch / embed URL] --> B[Scrape HTML]
  B --> C[Decode plyURL]
  B --> D[Read mediaId]
  C --> E[Seal AES-256-GCM token]
  D --> E
  E --> F["GET /get/{token}"]
  F --> G[master.m3u8]
  G --> H[UI proxy / VLC / MPV]
Loading

Resolve is pure Node: native fetch for HTML and JSON, node:crypto for the seal. The UI never runs the player bundle.


How resolve works

1. Scrape the embed page

src/scraper/video.ts performs web scraping with a single GET and a page-origin Referer.

Field Source
mediaId id=middata-id=
playerOrigin Base64-decoded const plyURL = "…"
title <title> text before |

If any required field is missing, scrape throws. No slug heuristics, no alternate DOM selectors.

2. Seal the session token

The player never puts the playlist URL in HTML. It seals a short plaintext and sends it to /get. This repo reimplements that seal after reverse engineering the player:

Plaintext

{mediaId}+1+1+{unixTimestamp}

Key derivation

  • Password: player
  • PBKDF2-SHA256, 1000 iterations
  • Salt: 8 random bytes
  • Key: 256 bits

AES-256-GCM

  • IV: 12 random bytes
  • Auth tag: 16 bytes, appended to ciphertext

Wire format

{saltHex}-{ivHex}-{ciphertextHex}{tagHex}

Implementation: src/resolver/seal.ts. Generate a new token per resolve.

3. Resolve the M3U8 playlist

src/resolver/playlist.ts:

  1. GET {playerOrigin}/get/{token} with Referer: {playerOrigin}/
  2. Require HTTP 200, mode: "direct", and a non-empty info
  3. Return {playerOrigin}/hls/{info}/master.m3u8

That master playlist is the stream resolver output. VLC and MPV can open it directly. The UI plays it through the local proxy.

Orchestration for the UI lives in src/resolver/api.tssrc/server.ts (GET /api/stream).


Why a proxy is required in the browser

  • CORS / headers — CDN and player hosts often reject browser fetches from your UI origin.
  • Relative playlist URLs — media lines inside M3U8 must be rewritten to stay on your host, or the player cannot load the next playlist and segments.

External players (VLC, MPV) talk to the CDN themselves, so they can use the direct M3U8 from the resolver without this server’s proxy.


HLS proxy

src/proxy/stream.ts serves GET /api/proxy?url={absolute-url}.

  1. Fetch upstream with Referer: {upstream-origin}/.
  2. If the body starts with #EXTM3U, rewrite media lines and URI="…" values to {your-host}/api/proxy?url=….
  3. Otherwise pass bytes through (segments, keys, etc.).

Playlist detection is the #EXTM3U magic only—one definition of an HLS playlist body.


Project layout

Path Responsibility
src/server.ts HTTP server, static UI, /api/stream, /api/proxy
src/config.ts Port and upstream request headers
src/upstream.ts fetchText / fetchJson / fetchBytes
src/scraper/video.ts Embed page scraper
src/resolver/seal.ts AES-256-GCM session token seal
src/resolver/playlist.ts /get → M3U8 URL
src/resolver/api.ts UI resolve handler
src/proxy/stream.ts HLS playlist rewrite proxy
src/ui/ HTML, CSS, TypeScript player UI (hls.js)

Build: npm start runs tsc, copies UI assets and hls.js into dist/, then starts node dist/server.js.


Stack and requirements

Area Choice
Runtime Node.js ≥ 22.18, ES modules
Language TypeScript → dist/ (ESNext)
Crypto node:cryptopbkdf2Sync, createCipheriv("aes-256-gcm")
HTTP node:http, native fetch
Browser playback hls.js (npm, served from dist/ui/vendor)
Variable Default Purpose
PORT 3000 Listen port
npm start
npm run typecheck

Disclaimer

This project does not host, store, or distribute media. Embed sites and Ployan player hosts are independent services. The scraper reads public HTML; the resolver seals the same session token shape the player uses and calls /get over HTTP.

You are responsible for complying with copyright law, site terms of service, and local regulations. No warranty. Use only on content you have the right to access.

About

Scrape Ployan embed pages, reverse engineer AES-256-GCM session tokens with PBKDF2, and resolve direct HLS M3U8 master playlists in pure Node.js. Embed scraper, stream resolver, and HLS proxy for web scraping and reverse engineering—no browser, no VM. TypeScript UI with hls.js playback plus M3U8 export for VLC and MPV. Using HTTP + node:crypto only

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages