Skip to content

Releases: noma4i/nitro-player

NitroPlay 2.0.0-beta.5

Pre-release

Choose a tag to compare

@noma4i noma4i released this 05 Jul 12:06

Fixed

  • iOS: eager buffered player initialization emitted playback state off the main thread, tripping the PlaybackStateEmissionGate main-thread assertion and crashing the host app at boot in DEBUG; the init emission path now marshals onto the main thread.

NitroPlay 2.0.0-beta.4

Pre-release

Choose a tag to compare

@noma4i noma4i released this 05 Jul 07:09

Performance

  • Memoized source preparation with a WeakMap object cache and branded prepared-source fast path, added per-field native prop diffing and callback-ref subscriptions in NitroPlayerView, added selector overloads for usePlaybackState, and cached prepared catalog entries in NitroFeedRingPlayer.
  • Reworked native playback tick paths on both platforms with main-thread playback-state emission gates, listener early-outs before snapshot/fingerprint allocation, item-scoped periodic time observer lifecycle on iOS, volatile cached playback getters and single-hop seek planning on Android, and async source-swap coordination on iOS without main-thread sync.
  • Raised the feed hot pool to the full three-slot ring size, coalesced feed-pool rebalancing into one main-turn pass, restored feed-pool pin semantics so idle attached views are not pinned, and enabled Android ExoPlayer instance reuse for source changes by default.
  • Changed the Android HLS proxy to stream segments through while tee-writing cache files, dedupe in-flight segment fetches, run a single eviction pass after writes, and use a shared in-memory cache index; iOS proxy state now stays in one sync domain and segment bytes are stored only in the KTV cache.
  • Moved iOS HLS first-frame decoding off the main actor, replaced preview wait polling with an open-request counter, uses generator-first HLS decode with AVPlayer fallback, and on Android skips doomed direct MediaMetadataRetriever attempts for HLS while reusing cached leading segments.

Breaking Changes

  • HLS transport.mode: 'auto' now plays direct by default. Feed-pool-eligible HLS sources still route through the local proxy/cache path automatically, and transport.mode: 'proxy' remains the explicit proxy opt-in.
  • Removed configureSourcePolicy; source policy customization now uses explicit per-source config fields.
  • Source buffer config now merges per field over policy defaults, matching retention, transport, and preview. For example, buffer: {} no longer clears policy buffer defaults.
  • Removed the NitroVideo root alias, root feedRingWindow helper re-export, root event registry exports, adaptive quality internals from the root API, and the stream diagnostics APIs streamCache.getStreamVariants() / streamCache.getPlayersDiagnostics(). Use NitroPlayerView, the ./feedRingWindow subpath, and explicit source config instead.
  • Removed metadata.description from NitroSourceMetadata; platform media metadata now supports title, subtitle, artist, and imageUri.

Changed

  • Migrated streamCache and videoPreview from the legacy RN bridge to split Nitro hybrid objects: NitroStreamCache and NitroVideoPreview.

NitroPlay 2.0.0-beta.1

Pre-release

Choose a tag to compare

@noma4i noma4i released this 22 Jun 08:33

Breaking Changes

  • Android: hand-written native code is realigned to domain-matched packages com.nitroplay.video.<domain> (player, source, view, streaming, preview, support, bridge). Codegen/autolinking-pinned packages (com.margelo.nitro.video, com.nitroplay.video.bridge) are unchanged. Consumers that referenced internal Android package paths must update them.
  • Removed dead/duplicate public TypeScript exports left over from the domain split: unused event aliases (LoadEvent, LoadStartEvent, FirstFrameEvent, VolumeChangeEvent) and the duplicate retention unions, which are now a single RetentionLevel.

Changed

  • Unified the cross-platform DSL: deduplicated enums and identity keys and aligned playback-state emission dedupe across TypeScript, iOS, and Android.
  • Split first-frame/preview generation out of the HybridNitroPlayer core into mirrored iOS and Android extensions.

Fixed

  • iOS and Android: replaceSourceAsync now preserves the early-play intent, so swapping the source while playing keeps the new source playing instead of pausing.
  • Example: Feed List rows keep a constant height while only the video surface mounts per viewability, fixing the scroll flicker and stuck-scroll behavior.

Build

  • lib/ is tracked again (it was accidentally git-ignored during the refactor) and regenerated to match the refactored src domains, so GitHub-tag installs ship the prebuilt output.

NitroPlay 1.1.0-beta.4

Pre-release

Choose a tag to compare

@noma4i noma4i released this 21 Jun 08:08

Added

  • Example stress lab screens for home playback, lifecycle churn, source swap, feed-list churn, buffering interrupt, background lifecycle, and preload race verification
  • Cross-platform lifecycle gate coverage for stale callbacks after replaceSourceAsync, clearSourceAsync, and release
  • Behavior-test organization and lifecycle guard audit checks for JS, iOS, and Android regression coverage

Changed

  • Reorganized the public TypeScript, iOS, Android, and generated build outputs into matching Rails-like domains: bridge, player, source, view, streaming, preview, and support
  • Refreshed generated lib/ artifacts so package consumers resolve the new domain paths instead of the old core, spec, and transport layout
  • Updated the example app to use scenario-specific screens and reusable shared controls for manual consumer QA

Fixed

  • iOS and Android: shared HLS manifest URL detection now handles .m3u8 URLs with query strings or fragments consistently
  • JS source validation and native stream runtime helpers now keep stream cache, preview, and source factory behavior aligned after the domain split
  • iOS and Android: listener and lifecycle cleanup paths now guard stale emissions more consistently during rapid source churn and release

NitroPlay 1.1.0-beta.3

Pre-release

Choose a tag to compare

@noma4i noma4i released this 19 Jun 07:32

Added

  • iOS and Android regression tests for player threading contracts around buffered preload, observer callback marshalling, bounded main-thread waits, and startup recovery

Fixed

  • iOS: move buffered preload AVPlayerItem replacement off MainActor.run, preventing synchronous AVFoundation item swaps from fully blocking the main thread during preload/startup
  • iOS: marshal AVPlayer and AVPlayerItem observer callbacks back to the main queue after off-main player mutations, preserving playback state and event thread safety

NitroPlay 1.1.0-beta.1

Pre-release

Choose a tag to compare

@noma4i noma4i released this 11 Jun 05:16

Added

  • iOS: HLS first-frame extraction now decodes through the AVPlayer + AVPlayerItemVideoOutput pipeline, so bare MPEG-TS (.ts) HLS streams produce a real preview frame where AVAssetImageGenerator cannot open a standalone .ts segment
  • Fatal HTTP errors during HLS startup (e.g. 401) now surface through onError and PlaybackState.error on iOS instead of leaving the player silently stalled

Changed

  • HLS proxy now binds an OS-assigned ephemeral port instead of a fixed one, avoiding loopback port collisions when several players or processes share the host (both platforms)
  • Thumbnail cache now participates in the same TTL and size eviction as stream segments
  • Extracted a shared resolveSource util for streamCache and videoPreview, and host-testable preview frame heuristics
  • example: the scrolling player feed uses a TextureView surface on Android to stay in sync during scroll

Fixed

  • Stream cache index is reconciled with disk on every clear: clears persist immediately and an orphan sweep removes unindexed files
  • Emit onLoad and first-frame once per source generation; skip redundant PlaybackState emits when only the timestamp changes
  • Cancel inflight first-frame preview work on release; recycle preview bitmaps and close the stream in generatePreview
  • Validate source config enums and preserve all native error codes at the JS boundary
  • Split HLS manifests on any newline so CRLF parsing matches across iOS and Android; serialize the iOS HLS proxy controller state through its state queue
  • Hard-cap the prefetch dedup map so it cannot grow unbounded under churn
  • Android: guard all player listener callbacks, state reads, and the muted/volume path against a released host; bound runOnMainThreadSync with a timeout; keep wasAutoPaused until a successful resume; skip HLS cache writes after the proxy stops
  • Android: guard fullscreen restore against a destroyed activity and always dismiss the dialog
  • iOS: isReleased fallback for duration / bufferDuration getters; guard play() detached completion against a replaced source generation; make refreshMemorySize a no-op after release
  • example: replace a stale 403 demo MP4 URL with a reachable one

v1.0.1

Choose a tag to compare

@noma4i noma4i released this 06 Jun 06:40

Fixed

  • iOS: load AVAsset duration, video tracks, naturalSize, preferredTransform, and estimatedDataRate via async load(...) in getAssetInformation(), fixing metadata loading under AVFoundation's async property model.
  • iOS: derive video orientation from the preferred transform instead of the removed AVAssetTrack.orientation; onLoad emits .unknown orientation until it is computed.
  • iOS: simplify AVAsset.estimatedMemoryUsage to file-size-only for URL assets, dropping unreliable track-based estimation.

NitroPlay 1.0.0

Choose a tag to compare

@noma4i noma4i released this 07 Apr 03:50

First stable release. Promotes the 1.0.0-beta.1 through 1.0.0-beta.11 line to stable with no new runtime changes.

Highlights

  • Native-first player on AVPlayer (iOS) and ExoPlayer (Android) with shared HLS transport runtime, lazy startup, and bounded startup recovery
  • v2 source DSL: uri, headers, metadata, startup, buffer, retention, transport, preview
  • Header-aware stream cache and preview identity ({ uri, headers })
  • streamCache.prefetch / getStats / clear and videoPreview.getFirstFrame / peekFirstFrame / clear as the canonical public transport and preview surfaces
  • Sticky onFirstFrame per active source generation and native auto-thumbnail reveal for attached views
  • Declarative NitroPlayerView with playerDefaults, attach/detach events, fullscreen hooks, and an imperative NitroPlayer ref surface
  • Absolute local file paths normalized to file:// on both platforms
  • PlaybackState.isVisualReady as the canonical visual-readiness flag; errors surface through PlaybackState.error and onError

Docs

  • README now documents the full public API surface: source DSL subfields, NitroPlayer properties and methods (including addEventListener), NitroPlayerView props and ref, PlaybackState fields, stream cache and preview signatures, hooks, createNitroSource, and common types
  • docs/source-config.md marks NitroSourceMetadata fields as optional
  • docs/player-api.md documents NitroPlayer.addEventListener alongside view-ref event subscription

v1.0.0-beta.11

Choose a tag to compare

@noma4i noma4i released this 01 Apr 12:00

Unknown Syntax Error: Unsupported option name ("-s").

$ yarn cache clean [--mirror] [--all]
$ yarn cache clean [--mirror] [--all]
$ yarn config get [--why] [--json] [--no-redacted]
$ yarn config set [--json] [-H,--home]
$ yarn config unset [-H,--home]
$ yarn set resolution
$ yarn set version from sources [--path #0] [--repository #0] [--branch #0] [--plugin #0] [-n,--dry-run] [--no-minify] [-f,--force] [--skip-plugins]
$ yarn set version [--yarn-path] [--only-if-needed]
$ yarn workspaces list [--since] [-R,--recursive] [--no-private] [-v,--verbose] [--json]
$ yarn --clipanion=definitions
$ yarn help
$ yarn help
$ yarn help
$ yarn ...
$ yarn -v
$ yarn -v
$ yarn add [--json] [-F,--fixed] [-E,--exact] [-T,--tilde] [-C,--caret] [-D,--dev] [-P,--peer] [-O,--optional] [--prefer-dev] [-i,--interactive] [--cached] [--mode #0] ...
$ yarn bin [-v,--verbose] [--json] [name]
$ yarn config [--no-defaults] [--json] ...
$ yarn exec ...
$ yarn explain peer-requirements [hash]
$ yarn explain [--json] [code]
$ yarn info [-A,--all] [-R,--recursive] [-X,--extra #0] [--cache] [--dependents] [--manifest] [--name-only] [--virtuals] [--json] ...
$ yarn install [--json] [--immutable] [--immutable-cache] [--refresh-lockfile] [--check-cache] [--check-resolutions] [--inline-builds] [--mode #0]
$ yarn install [--json] [--immutable] [--immutable-cache] [--refresh-lockfile] [--check-cache] [--check-resolutions] [--inline-builds] [--mode #0]
$ yarn link [-A,--all] [-p,--private] [-r,--relative] ...
$ yarn unlink [-A,--all] ...
$ yarn node ...
$ yarn plugin check [--json]
$ yarn plugin import from sources [--path #0] [--repository #0] [--branch #0] [--no-minify] [-f,--force]
$ yarn plugin import [--checksum]
$ yarn plugin remove
$ yarn plugin list [--json]
$ yarn plugin runtime [--json]
$ yarn rebuild ...
$ yarn remove [-A,--all] [--mode #0] ...
$ yarn run [--json]
$ yarn run [--inspect] [--inspect-brk] [-T,--top-level] [-B,--binaries-only] [--require #0] ...
$ yarn up [-i,--interactive] [-F,--fixed] [-E,--exact] [-T,--tilde] [-C,--caret] [-R,--recursive] [--mode #0] ...
$ yarn why [-R,--recursive] [--json] [--peers]
$ yarn workspace ...
$ yarn constraints query [--json]
$ yarn constraints source [-v,--verbose]
$ yarn constraints [--fix] [--json]
$ yarn create [-p,--package #0] [-q,--quiet] ...
$ yarn dlx [-p,--package #0] [-q,--quiet] ...
$ yarn init [-p,--private] [-w,--workspace] [-i,--install] [-n,--name #0]
$ yarn init [-p,--private] [-w,--workspace] [-i,--install] [-n,--name #0] ...
$ yarn search
$ yarn upgrade-interactive
$ yarn npm audit [-A,--all] [-R,--recursive] [--environment #0] [--json] [--no-deprecations] [--severity #0] [--exclude #0] [--ignore #0]
$ yarn npm info [-f,--fields #0] [--json] ...
$ yarn npm publish [--access #0] [--tag #0] [--tolerate-republish] [--otp #0] [--provenance]
$ yarn npm tag add
$ yarn npm tag list [--json] [package]
$ yarn npm tag remove
$ yarn pack [--install-if-needed] [-n,--dry-run] [--json] [-o,--out #0]
$ yarn patch [-u,--update] [--json]
$ yarn unplug [-A,--all] [-R,--recursive] [--json] ...
$ yarn stage [-c,--commit] [-r,--reset] [-n,--dry-run]
$ yarn version apply [--all] [--dry-run] [--prerelease] [--exact] [-R,--recursive] [--json]
$ yarn version check [-i,--interactive]
$ yarn version [-d,--deferred] [-i,--immediate]
$ yarn workspaces focus [--json] [--production] [-A,--all] ...
$ yarn workspaces foreach [--from #0] [-A,--all] [-R,--recursive] [-W,--worktree] [-v,--verbose] [-p,--parallel] [-i,--interlaced] [-j,--jobs #0] [-t,--topological] [--topological-dev] [--include #0] [--exclude #0] [--no-private] [--since] [-n,--dry-run] ...

v1.0.0-beta.9

Choose a tag to compare

@noma4i noma4i released this 31 Mar 04:46

Breaking

  • Public source DSL is now v2-only: uri, headers, metadata, startup, buffer, retention, transport, preview. Legacy lifecycle, initialization, advanced.*, top-level proxy flags, and JS-facing hlsCacheProxy usage are removed from the canonical API surface
  • Public utility surfaces are now streamCache and videoPreview. Consumer code should not use the old mixed HLS facade naming
  • PlaybackState.isReadyToDisplay is replaced by isVisualReady, and the canonical visual-start contract is isVisualReady || hasFirstFrame

Added

  • preview.autoThumbnail to let attached native player views own first-frame placeholder/reveal by default, with explicit opt-out
  • Sticky onFirstFrame delivery plus videoPreview.getFirstFrame(source) and videoPreview.clear() for manual preview access
  • streamCache.prefetch(source), streamCache.getStats(source?), and streamCache.clear() as the canonical public transport/cache utilities

Changed

  • iOS + Android: HLS/runtime startup now uses lazy native ownership, bounded startup recovery, and direct fallback in transport.mode='auto' when proxy bootstrap is unavailable
  • iOS + Android: stream cache and preview identity are now header-aware ({ uri, headers }), so the same URL under different request headers no longer shares cache or preview artifacts
  • iOS + Android: preview/first-frame extraction is isolated from playback state changes and transport side effects; attached views use native auto-thumbnail as the primary mounted-surface reveal path
  • Docs and example app now describe and exercise the v2 source DSL, streamCache, videoPreview, native auto-thumbnail, and multi-player/header-isolated streaming scenarios

Fixed

  • iOS + Android: startup playback for streaming video is now resilient to early proxy/runtime failures instead of getting stuck on the first empty/error response
  • iOS + Android: stale async work from old source generations can no longer leak onLoad, onError, or onFirstFrame into a newer replaceSourceAsync() / clearSourceAsync() session
  • Android: removed optimistic false PLAYING state before real readiness/isPlaying, aligning visible status with actual playback state
  • TS: useNitroPlayer/player orchestration no longer race on rapid source churn, and NitroPlayerView/player event plumbing no longer depend on stale JS-side lifecycle bookkeeping