Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@jwplayer/jwplayer-react
Advanced tools
<JWPlayer>
is a React Component that creates an instance of JW Player's web player. It allows for the use of any player configuration options and/or event hooks that can be used on the standard player (as props), and provides access to player's API directly via a componentDidMount
callback.
npm i @jwplayer/jwplayer-react
import JWPlayer from '@jwplayer/jwplayer-react';
...
<JWPlayer
file='https://path-to-my.mp4'
library='https://path-to-my-jwplayer-library.js'
/>
...
import JWPlayer from '@jwplayer/jwplayer-react';
...
<JWPlayer
library='https://path-to-my-jwplayer-library.js'
playlist='https://cdn.jwplayer.com/v2/playlists/playlist_media_id'
/>
...
import JWPlayer from '@jwplayer/jwplayer-react';
...
const playlist = [{
file: 'myfile.mp4',
image: 'myPoster.jpg',
tracks: [{
file: 'https://mySubtitles.vtt',
label: 'English',
kind: 'captions',
'default': true
}],
},
{
file: 'mySecondFile.mp4',
image: 'MysecondFilesPoster.jpg',
}];
...
<JWPlayer
library='https://path-to-my-jwplayer-library.js'
playlist={playlist}
/>
...
These props are required to instantient an instance of JW Player:
library
string
https://content.jwplatform.com/libraries/abcd1234.js
playlist
OR file
OR advertising
block with oustream: true
string
(for file
or playlist
) or array
(for playlist
) or object
for advertising
https://cdn.jwplayer.com/v2/playlists/abcd1234
If you are not using a cloud hosted player you will need to provide a license key via the config prop. This prop can also be used to pass additional player config options.
config
object
{ key: "your-key-here" }
All JW Player config options can be used individually as props to configure a jwplayer-react
player, i.e., advertising
, analytics
, playlist
, related
, width
, and height
. See the full list here. In addition, you may use the following props:
on<Event>
, once<Event>
jwplayer-react
dynamically supports all events in JW Player. Props beginning with on
or once
are parsed and added as JW Player event handlers. Find the full list of supported events here.(event: { type: string, [key: string]: any }) => void
const callback = (event) => console.log(event)
onReady={callback}
: Executes callback every time ready
event is triggered by player API. Identical to jwplayer(id).on('ready', callback)
.onComplete={callback}
: Executes callback every time complete
event is triggered by player API. Identical to jwplayer(id).on('complete', callback)
.onceTime={callback}
: Executes callback the first time time
event is triggered by player API. Identical to jwplayer(id).once('time', callback)
.
didMountCallback
({ player: PlayerAPI, id: string }) => void
willUnmountCallback
({ player: PlayerAPI, id: string }) => void
For advanced usage,jwplayer-react
creates an instance of the player API when mounted, and sets it to this.player
, exposing all api functionality listed here.
import React from 'react';
import JWPlayer from '@jwplayer/jwplayer-react';
class PlayerContainer extends React.Component {
constructor(props) {
super(props);
this.players = {};
this.onBeforePlay = this.onBeforePlay.bind(this);
this.onPlay = this.onPlay.bind(this);
this.playerMountedCallback = this.playerMountedCallback.bind(this);
this.playerUnmountingCallback = this.playerUnmountingCallback.bind(this);
}
// Registers players as they mount
playerMountedCallback({ player, id }) {
this.players[id] = player;
}
// Nulls registered players as they unmount
playerUnmountingCallback({ id }) {
this.players[id] = null;
}
// Prevent multiple players from playing simultaneously
onBeforePlay(event) {
Object.keys(this.players).forEach(playerId => {
const player = this.players[playerId];
const isPlaying = player.getState() === 'playing';
if (isPlaying) {
player.pause();
}
});
}
// Put teal colored outline on currently playing player, remove it from all other players.
onPlay(event) {
Object.keys(this.players).forEach(playerId => {
const player = this.players[playerId];
const container = player.getContainer();
if (player.getState() === 'playing') {
container.style.border = '15px solid #00FFFF';
} else {
container.style.border = '';
}
});
}
render() {
// Re-usable defaults to use between multiple players.
const configDefaults = { width: 320, height: 180 };
return (
<div className='players-container'>
<JWPlayer
config={configDefaults}
onBeforePlay={this.onBeforePlay}
onPlay={this.onPlay}
didMountCallback={this.playerMountedCallback}
willUnmountCallback={this.playerUnmountingCallback}
playlist='https://cdn.jwplayer.com/v2/media/1g8jjku3'
library='https://cdn.jwplayer.com/libraries/lqsWlr4Z.js'
/>
<JWPlayer
config={configDefaults}
onBeforePlay={this.onBeforePlay}
onPlay={this.onPlay}
didMountCallback={this.playerMountedCallback}
willUnmountCallback={this.playerUnmountingCallback}
playlist='https://cdn.jwplayer.com/v2/media/QcK3l9Uv'
library='https://cdn.jwplayer.com/libraries/lqsWlr4Z.js'
/>
<JWPlayer
config={configDefaults}
onBeforePlay={this.onBeforePlay}
onPlay={this.onPlay}
didMountCallback={this.playerMountedCallback}
willUnmountCallback={this.playerUnmountingCallback}
playlist='https://cdn.jwplayer.com/v2/playlists/B8FTSH9D'
playlistIndex="1"
library='https://cdn.jwplayer.com/libraries/lqsWlr4Z.js'
/>
</div>
);
}
}
export default PlayerContainer;
import React from 'react';
import JWPlayer from '@jwplayer/jwplayer-react';
class PlayerContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
loaded: false
};
this.players = {};
this.onBeforePlay = this.onBeforePlay.bind(this);
this.didMountCallback = this.didMountCallback.bind(this);
this.loadPlayerLibrary();
}
// Load a player library
loadPlayerLibrary() {
const src = "https://cdn.jwplayer.com/libraries/lqsWlr4Z.js";
const script = document.createElement("script");
script.src = src;
script.type = "text/javascript";
script.onload = () => this.setState({ loaded: true }); // On load, we're ready to set up our player instances
document.body.append(script);
}
// Registers players to container as they mount
didMountCallback({ player, id }) {
this.players[id] = player;
const eventLog = document.getElementById("log");
// Log all events by player id.
player.on("all", (event) => {
const li = document.createElement("li");
li.innerText = `${id}: ${event}`;
eventLog.prepend(li);
});
}
// Prevent simultaneous playbacks
onBeforePlay(event) {
Object.keys(this.players).forEach((playerId) => {
const player = this.players[playerId];
const isPlaying = player.getState() === "playing";
if (isPlaying) {
player.pause();
}
});
}
render() {
// Re-usable defaults to use between multiple players.
const configDefaults = { width: 320, height: 180 };
return this.state.loaded ? (
<div className="players-container">
<JWPlayer
config={configDefaults}
onBeforePlay={this.onBeforePlay}
didMountCallback={this.didMountCallback}
playlist="https://cdn.jwplayer.com/v2/media/1g8jjku3"
/>
<JWPlayer
config={configDefaults}
onBeforePlay={this.onBeforePlay}
didMountCallback={this.didMountCallback}
playlist="https://cdn.jwplayer.com/v2/media/QcK3l9Uv"
/>
<JWPlayer
config={configDefaults}
onBeforePlay={this.onBeforePlay}
didMountCallback={this.didMountCallback}
playlist="https://cdn.jwplayer.com/v2/playlists/B8FTSH9D"
playlistIndex="1"
/>
</div>
) : (
"loading..."
);
}
}
export default PlayerContainer;
Post issues, or put up PRs that solve pre-existing issues.
FAQs
A react component that creates an instance of JW Player
We found that @jwplayer/jwplayer-react demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 7 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.