Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
E627 Release v4.4.0 Β· canalplus/rx-player Β· GitHub
Nothing Special   »   [go: up one dir, main page]

Skip to content

v4.4.0

Latest

Choose a tag to compare

@peaBerberian peaBerberian released this 25 Sep 19:16
· 32 commits to dev since this release
v4.4.0

Release v4.4.0 (2025-09-25)

Quick Links:
πŸ“– API documentation - ⏯ Demo - πŸŽ“ Migration guide from v3

πŸ” Overview

The v4.4.0 is here, with many new features and improvements:

  • new onAudioTracksNotPlayable and onVideoTracksNotPlayable loadVideo options to allow playback even if no audio or video tracks are supported on the current content.

  • A new disableAudioTrack API, to complement the existing disableVideoTrack and disableTextTrack APIs and give you control over all media track types

  • seekTo can now be relied on even when still LOADING / RELOADING, to correct a future playback position.

  • A new getWallClockOffset API to facilitate conversions between the RxPlayer's position and the "wallClockTime" that is generally more useful for live contents.

  • EncryptedMediaError errors, which are those linked to content decryption, now will also communicate context when possible, such as the corresponding key system name and configuration.

  • Add MediaError with the "NO_AUDIO_VIDEO_TRACKS" code for when neither audio nor video is available or when both are disabled

  • "local" Manifests (experimental feature to load contents that are downloaded locally) can now announce forced narrative subtitles tracks, through the new forcedSubtitles property

  • The experimental MediaCapabilitiesProber tool had its API updated to be more flexible (see below)

  • WebVTT embedded in an mp4 segment are now properly handled.

  • Firefox and Chrome recently added PlayReady SL3000 support under most Windows 11 devices. It is now properly handled.

  • Thumbnails (from our new thumbnails API brought in v4.3.0) now have a better caching mechanism.

  • RxPlayer logs have been rewritten to be more easily read and exploited by people relying on the RxPlayer logs for debugging

  • many bug fixes and other improvements

Changelog

Features

  • Add onAudioTracksNotPlayable and onVideoTracksNotPlayable loadVideo options to control whether to continue playback is one of those components is not compatible to the current device [#1624]
  • Add getWallClockOffset API to obtain a "live position"'s offset [#1601]
  • add disableAudioTrack API [#1715]
  • DRM: Add keySystem and keySystemConfiguration to most EncryptedMediaError so an application can determine which key system caused an issue [#1690]
  • Update API of the experimental mediaCapabilitiesProber API so it's more flexible to use [#1472]
  • Implement inband WebVTT (vtte/vttc) [#1639]
  • Add "NO_AUDIO_VIDEO_TRACKS" error for when neither audio nor video is available or when both are explicitly disabled [#1624]
  • Allow seeking through seekTo even while LOADING or RELOADING the content [#1607]
  • local: local-manifests now can have a forcedSubtitles property in an adaptations object, to indicate that a text track actually represents "forced narrative" subtitles [#1722]

Bug fixes

  • Subtitles: Fix some subtitle missing on multiple period assets [#1708]
  • DRM: renew the mediaKeySystemAccess on Edge and Firefox when using a PlayReady keySystem to work-around frequent DRM issues. [#1694]
  • DASH: Fix some rare occurence of infinite rebuffering on multi-Period when seeking exactly at the end of a Period. [#1738]
  • DRM: On Firefox check extensively PlayReady DRMs support before using them to work-around recent firefox issue with PlayReady integration [#1691]
  • DRM: Fix persistent session loading when content has no key id [#1713]
  • representation object returned by some API had incorrect shape for optional attributes [#1720]
  • Directfile: set autoplay attribute on directfile contents, to work-around safari-specific issues [#1711]
  • Remove unnecessary duration logs when reaching the end of some VoD contents [#1744]

Other improvements

  • Add hidden experimental API "Dummy media API" to facilitate tests and debugging of the RxPlayer behavior without having to support the content in the current environment [#1478]
  • Thumbnails: Cache pending thumbnail request [#1718]
  • For Dynamic contents, let the initial position go outside the range of the Manifest and let the application correct if if needed based on MEDIA_TIME_BEFORE_MANIFEST or MEDIA_TIME_AFTER_MANIFEST events [#1607]
  • Update log syntax so users can follow them more easily [#1717]
  • Add to hidden RxPlayer config most compat switches [#1514]
  • Prevent unnecessary resources usage by inactive worker [#1696]
  • Improve on freeze resolution, especially for encrypted contents [#1705]
  • Detect that fetch / AbortController is native to provide a better experience for application relying on (broken) polyfills instead [#1698]
  • enable debug logs as soon as __RX_PLAYER_DEBUG_MODE__ is set [#1626]
  • rely on "provenance statements" when publishing our builds [#1742]

onVideoTracksNotPlayable / onAudioTracksNotPlayable

One of the most significant additions in this release is the introduction of two new loadVideo options:

Reason: error or reduced experience?

Until now, when playing a content whose audio was not supported on the device, the RxPlayer would stop playback and throw a MANIFEST_INCOMPATIBLE_CODECS_ERROR error.

Technically, we could have just continued only playing video and no audio in that scenario. We only stop playback on an error because we inferred that most applications didn't want the possibility of those kind of reduced experiences.

And the same rules apply if video is unsupported yet audio is, or when one of them is non-decipherable (in which case you could by default see the NO_PLAYABLE_REPRESENTATION fatal error) but the other is.

novideoshort.mp4

Video: When you play content whose audio or video is not currently supported (here HEVC video on my device), you're left with an error. Here is how it displays in our demo page.

But failing directly is not what everybody want: we had multiple feature requests to allow playback without audio or video if one of them was unsupported (either due to codec issues or due to the impossibility to decipher it).

Two new options

We thus brought two new options in this release to give you granular control over how the player behaves in such scenarios:

player.loadVideo({
  transport: "dash",
  url: "https://example.com/content.mpd",
  autoPlay: true,
  onAudioTracksNotPlayable: "continue", // Play without audio instead of failing
  onVideoTracksNotPlayable: "error", // Still fail if video tracks are incompatible
});

Both options accept either "continue" or "error":

  • "error": The player will throw the corresponding error and stop, maintaining the default behavior.

  • "continue": The player will continue playback without the problematic media type.

You can thus set either of those to "continue" now to continue playback anyway:

novideo1.mp4

Video: Demonstration of how the onVideoTracksNotPlayable in "continue" mode could work. Here in our demo page we end up playing the content without the video (but with audio playing).
If the video does not play, it is available here: https://github.com/user-attachments/assets/8595d290-62cd-4f45-8d7f-7ff74bcba598

Note that if such a "fallback" happens during playback (for example: during a DASH Period transition), it may lead to a small RELOADING step.

New event: noPlayableTrack

When setting either of those two new options to continue, you might want to be alerted when and if such "fallback" scenario happens.

For exactly this, we also added the noPlayableTrack event which will be triggered just before the fallback is actually enforced.

rxPlayer.addEventListener("noPlayableTrack", (evt) => {
  console.log(
    "No compatible track for the media type",
    evt.trackType /* "audio" or "video" */,
    "for period",
    evt.period.id
  );
});

Worst case: no compatible audio and no compatible video

This new API also brings a new possibility to the RxPlayer: we might be disabling both audio and video (e.g. if both are set to continue and fallbacked or if one is disabled while the other is fallbacked from).

In that scenario, we'll still stop playback with an "error" event. However we added a new kind of error just for that kind of scenario: "NO_AUDIO_VIDEO_TRACKS":

rxPlayer.addEventListener("error", (error) => {
  if (error.code === "NO_AUDIO_VIDEO_TRACKS") {
    console.error("No audio nor video track was enabled on the content");
  }
});

new disableAudioTrack API

Building on the enhanced compatibility options, we've also added a new disableAudioTrack API.

It basically does what its name imply and complements the existing disableVideoTrack and disableTextTrack APIs.

// Disable audio track for audio-description or silent playback scenarios
player.disableAudioTrack();

// Re-enable audio later
const audioTracks = player.getAvailableAudioTracks();
if (audioTracks.length > 0) {
  player.setAudioTrack(audioTracks[0].id);
}

This API is arguably much less useful than disabling text tracks or even the video track, but could still make sense in some advanced applications or especially when debugging issues, where it could allow to easily only check video playback and not audio).

The new "NO_AUDIO_VIDEO_TRACKS" error also added in this release may result from a call to this API if no video was enabled at that point.

new method: getWallClockOffset

The RxPlayer has multiple API to get the current playback position:

  • getPosition to obtain the current actual position we're playing on the media element (what we also call the "media time").

  • getWallClockTime which tries to give the corresponding broadcast time as a unix timestamp. This one is here mostly to help applications display a "time" for live contents to their users.

There were time however where applications wanted to convert a "wall-clock time" to a "media time" and vice versa.

Especially, most other API rely on media time only. If an application wanted to compare the "wall-clock time" to our concept of "minimum position" or "maximum position" it had no real easy way to do it.

New getWallClockOffset API

To improve on that situation, the new getWallClockOffset API just returns you the difference between the "wall-clock time" and the "media time" that is used by almost all other RxPlayer API.

const wallClockPosition = player.getWallClockTime();
const wallClockOffset = player.getWallClockOffset();
const minimumPosition = player.getMinimumPosition();

if (minimumPosition !== null && wallClockPosition - wallClockOffset < minimumPosition) {
  console.warn("We're playing before the currently minimum seekable position");
}

seekTo now callable while LOADING / RELOADING

The RxPlayer has a central concept of "player states" which complexifies our API a little bit.

For example, when either STOPPED, LOADING or RELOADING, most API won't work as expected: you cannot call play() or pause(), you cannot call seekTo() to seek on the content, you cannot update the "playback rate" etc.

To help with this, we added in v3.31.0 (June 2023) the isContentLoaded API that is just a shortcut to check that the state is different from those three.

Yet we were still not happy with this situation: even if there's technical reasons for those limitations, we would prefer it to be transparent to applications.

First step: handle seekTo complexity on our side

As a first step toward removing some complexity from our API, we made seekTo now callable and functional during the LOADING and RELOADING steps.

seekto.mp4

Video: In our demo page, I seek to a position at 60s while the content is still loading. We can see that it does seek to that position ultimately.

It will still throw when the state is STOPPED however - as it makes no sense to seek when there's no content loaded nor loading on the RxPlayer.

There is however for now a small caveat: the wallClockTime option from seekTo is not always usable under the LOADING state for now, as it relies on Manifest information - and we may not have fetched the Manifest yet at that point. Ultimately, we also want to handle that last issue but note that for now this is still a limitation.

It's still not possible to rely on play(), pause(), setPlaybackRate() etc. on those states yet though. Those will hopefully be future improvements, to make the API even easier to use.

Key system information on most EncryptedMediaError

DRM-related errors now provide much more context to help with debugging and implementing fallback strategies. When an EncryptedMediaError occurs, you'll now in most cases also receive additional information about the key system and its configuration.

This enhancement is particularly valuable for applications that want to implement DRM fallback mechanisms or provide more detailed error reporting:

player.addEventListener("error", (error) => {
  if (error.type === "ENCRYPTED_MEDIA_ERROR") {
    const { keySystem, keySystemConfiguration } = error;

    console.log("Error with DRM Configuration:", { keySystem, keySystemConfiguration });
    if (keySystem?.includes("playready")) {
      console.log("PlayReady-specific error, trying Widevine fallback");
      // Implement fallback logic
    }
  }
});

The two additional properties are both optional, they are:

  • keySystem: The key system identifier (e.g., "com.widevine.alpha", "com.microsoft.playready")
  • keySystemConfiguration: The MediaKeySystemConfiguration object that was being used

Firefox and Chrome now handling PlayReady SL3000 on Windows

Earlier this year, Firefox on Windows 11 may be able to rely on PlayReady SL3000. Also, right now, Chrome is doing the same thing (they are both using a common Windows-provided API behind the hood).

Most notably, this means hardware DRM support which is one of the main requirements from content right holders to play high video resolutions and video content with a high dynamic range. This means that we'll be able to provide to many customers high quality encrypted media on their desktop PCs with the browser of their choice.

Generally such changes should go smoothly and transparently with the RxPlayer, the application should just have to ask for "playready" or a "com.microsoft.playready.recommendation" type property in keySystems and we would automatically enable it if available.

However there have been some issues when testing the Firefox implementation on the RxPlayer (some of which we also saw on Edge Windows). This means that previous RxPlayer versions may not be able to profit from it.

We added some mechanisms in this release to handle the potential issues we found while testing this, we're now successfully providing high quality media to most Windows 11 user - on Edge, Firefox and very soon Chrome (chrome's implementation can already be tested).

More structured logs

In the RxPlayer team, we heavily rely on logs for debugging complex issues. If you ever set the RxPlayer.LogLevel static property, you saw how much data those logs output.

There is a lot of room for improvements though: logs are still hard to understand - even for us - without cross-referencing with the code again.

To give an example, here is a log you might have encountered in the console until now:

RS: future discontinuity encountered video 1163.04 1163.051770833

Many things are not clear here:

  • What's RS: exactly? (even us we often don't remember without grepping the code)

  • What are those floating numbers at the end about?

Compare this with the new format:

Stream: future discontinuity encountered bufferType="video" discontinuityStart=1163.04 discontinuityEnd=1163.051770833`

So now:

  • Stream: doesn't seem much better at first, but it is a clear larger area of the code for us (in the src/core/stream directory)
  • All values that were previously floating are now clearly identified (as bufferType, discontinuityStart and discontinuityEnd) so you can at least a good idea of what's happening - especially for us - without having to re-check everything.

And the same kind of format is now done for ALL our logs.

The end goal is to make the logs even easy-to-understand for applications if they want to check first if some issue they're having is due to a content or application issue (as opposed to an RxPlayer issue).

New hidden experimental API: Dummy Media Element

We also added in this release a "virtual" media element implementation that can be used for testing RxPlayer behavior without requiring an actual HTML media element.

We now rely on this new API in new advanced tests and in on our demo page, to be able to check how the RxPlayer would play a content even when testing on a device without the right codec and/or DRM support:

dummy2.mp4

Video: How the dummy media element is exposed in our demo page. Here we use it to be able to "play" an encrypted content without actually needing to perform a license request.
Of course it doesn't actually decode but the RxPlayer thinks it does - useful to debug or check the RxPlayer's behavior. Not all media containers (e.g. .mp4, .webm, .mkv etc.) are handled for now.

What this actually does is to mock the HTML5 video, MSE and EME API so the RxPlayer believes it is running on a regular implementation (in reality, no video nor audio is actually playing - the RxPlayer does not "see" that though). This has been a huge effort, but it pays off with the possibility to write complex integration tests for situations that are not easily reproducible in our tests environments.

Because this is not a stable API though, we didn't really want to encourage applications to rely on it, which is why it is for now left undocumented and thus not officially part of our API.

Improved MediaCapabilitiesProber Experimental API

The "experimental" (meaning: its API is not "stable") MediaCapabilitiesProber API has been reworked for better flexibility regarding DRM capabilities polling: The getCompatibleDRMConfigurations method is replaced by checkDrmConfiguration, which now checks a single configuration per call rather than multiple configurations at once.

It greatly facilitates the API and allows you to try different ways of checking multiple DRM configurations at once:

// /!\ Older approach not compatible anymore.

// Old approach (no longer available)
const configs = await mediaCapabilitiesProber.getCompatibleDRMConfigurations([
  widevineConfig,
  playreadyConfig,
]).then(([widevineResult, playReadyResult]) => {
  if (widevineResult.compatibleConfiguration) {
    console.warn("Widevine has a compatible configuration:", widevineResult.compatibleConfiguration);
    // ...
  }
  if (playReadyResult.compatibleConfiguration) {
    console.warn("PlayReady has a compatible configuration:", playReadyResult.compatibleConfiguration);
    // ...
  }
});

// New approach

// Checking all at once: just combine them with `allSettled`
const results = await Promise.allSettled([
  mediaCapabilitiesProber.checkDrmConfiguration("com.widevine.alpha", widevineConfig), 
  mediaCapabilitiesProber.checkDrmConfiguration(
    "com.microsoft.playready.recommendation",
    playreadyConfig
  ),
]).then(([widevineResult, playReadyResult]) => {
  // NOTE: here `widevineResult` and `playReadyResult` correspond to the return value of `allSettled`
  if (widevineResult.status === "fulfilled") {
    console.warn("Widevine has a compatible configuration:", widevineResult.value);
    // ...
  }
  if (playReadyResult.status === "fulfilled") {
    console.warn("PlayReady has a compatible configuration:", playReadyResult.value);
    // ...
  }
});

// Or check just the first compatible one: combine them with allSettled
 const firstWorkingConfiguration = await Promise.race([
   mediaCapabilitiesProber.checkDrmConfiguration("com.widevine.alpha", widevineConfig), 
  mediaCapabilitiesProber.checkDrmConfiguration(
    "com.microsoft.playready.recommendation",
    playreadyConfig
  ),
]);
// ....

// etc.

This new API is documented here.

Auditable RxPlayer releases

We saw multiple so-called "supply chain attacks" in the npm ecosystem the last few weeks. You may have heard for example about the chalk and "shai-hulud" ones.

Both of those had the attacker rely on the maintainer's npm account (either through phishing or by stealing an npm token) to instead locally publish their own infected copy of the same dependency.

Screenshot from 2025-09-24 17-04-27

Schema: Basically how those attacks worked. The compromised releases were built by the attacker on his/her own computer then published to npm directly, without having the new source code on the repository.

To better protect applications relying on the RxPlayer against those types of attacks we decided to raise the security needed to produce our builds. From now on, RxPlayer releases will most notably not be built by us locally, but by the CI associated to our GitHub repository.

This mean that you can now inspect the steps and source coded relied on for any new releases.

Screenshot from 2025-09-24 17-03-55

Schema: How it works from now on with the RxPlayer. We only create a tag (that we sign) with git and push it to this repository. In reaction, our CI builds a version from that tag and publish it to npm directly. We've also linked npm to the repo (and CI process) so we can be sure new versions come from this repository only.

For example, this release has been built and published here. It relies on other scripts from the RxPlayer so it's not so simple to read however, but you can ensure that what has been built is associated to the corresponding commit and (gpg-signed) release tag.

By linking this to npm, it also comes with a nice green checkmark which can link to the corresponding code and build pipeline.

npm checkmark screenshot

Screenshot: how the new version looks like on npm with its green checkmark.

Clicking on the "view more details" link on npm for that version links to the following information:

npm provenance info

Screenshot: Information on the provenance attestation of this specific v4.4.0 release. It links to the source commit (github.com/canalplus/rx-player@f7fdb30) linked to this version, our CI workflow that generated the build (https://github.com/canalplus/rx-player/actions/runs/18015878748/workflow) and the public ledger associated to it (https://search.sigstore.dev/?logIndex=561444039).

Note that we also now rely on the same mechanism for our dev and canal-tagged pre-releases.

0