JW Player
The jwplayer module lets editors search and import videos from a JW Player account through Brightspot's federated search, and can incrementally import new and updated videos on a schedule.
Dependencies
Depends on db-http and the JW Player Platform Management API v2 (api.jwplayer.com). The client is split across two supporting modules: jwplayer-api defines the client interface and request/response types, and jwplayer-api-impl provides a Retrofit-based implementation used at runtime.
Installation
- Maven
- Gradle
- Gradle (Kotlin DSL)
<!-- Requires Brightspot 5.0 or later. -->
<dependency>
<groupId>com.brightspot.dbhttp</groupId>
<artifactId>jwplayer</artifactId>
<version>1.0.0</version>
</dependency>
// Requires Brightspot 5.0 or later.
implementation 'com.brightspot.dbhttp:jwplayer:1.0.0'
// Requires Brightspot 5.0 or later.
implementation("com.brightspot.dbhttp:jwplayer:1.0.0")
API reference
brightspot.jwplayer.db.JwPlayerDatabase
Extends HttpDatabase. Builds a JW Player query string from the editor's keywords, media Id, category, tags, author, and last-modified date range, and caches searches and video lookups for five minutes. Thumbnails are fetched in batches of up to 20 media Ids per request.
brightspot.jwplayer.db.JwPlayerVideo
Extends ExternalItem.
| Field | Type | Description |
|---|---|---|
mediaId | String | The JW Player media Id. |
previewUrl | String | An embed URL used to preview the video in the CMS. |
videoTitle | String | The video title. |
description | String | The video description. |
author | String | The video author. |
category | String | The video category, from a fixed IAB taxonomy subset. |
tags | List<String> | Tags applied to the video in JW Player. |
lastUpdateDate | Date | When the video was last updated in JW Player. Filterable in search. |
duration | Long | The video duration in seconds. |
Sort order is set through the JwPlayerSort enum, covering last-modified, created, duration, publish-start, publish-end, status, and title, each ascending or descending.
Configuration
Each JW Player account is configured as a brightspot.jwplayer.db.JwPlayerSettings record (internalName, clientSecret, siteId, playerId, importEnabled, fullImportEnabled, debugEnabled), collected into a Set<JwPlayerSettings> on JwPlayerSiteSettings, shown under Site Settings > Integrations > JW Player. siteId corresponds to JW Player's "Property Id," and clientSecret is the client secret from JW Player's v2 API credentials.
When importEnabled is on, new and updated videos are imported in the background on a schedule rather than waiting for an editor to search for them.
Extending the plugin
Most projects need a content type to hold imported videos, plus one or both of the following:
- A background video importer, for projects using scheduled import (
importEnabled). - An
ExternalItemConverter, for projects that let editors create a local content record directly from search results.
Creating a video content type
Define a content type to store imported JW Player videos. At minimum, it needs a media Id field and an embedded JwPlayerVideo to hold the imported data:
1@Recordable.DisplayName("Video")2public class VideoExample extends Content {34@Required5@Indexed6private String mediaId;78@Embedded9@ToolUi.ReadOnly10private JwPlayerVideo jwPlayerVideo;1112@ToolUi.Hidden13private JwPlayerSettings jwPlayerSettings;1415public String getMediaId() {16return mediaId;17}1819public void setMediaId(String mediaId) {20this.mediaId = mediaId;21}2223public JwPlayerVideo getJwPlayerVideo() {24return jwPlayerVideo;25}2627public void setJwPlayerVideo(JwPlayerVideo jwPlayerVideo) {28this.jwPlayerVideo = jwPlayerVideo;29}3031public JwPlayerSettings getJwPlayerSettings() {32return jwPlayerSettings;33}3435public void setJwPlayerSettings(JwPlayerSettings jwPlayerSettings) {36this.jwPlayerSettings = jwPlayerSettings;37}3839@Override40public String getLabel() {41return Optional.ofNullable(jwPlayerVideo)42.map(JwPlayerVideo::getVideoTitle)43.orElse(mediaId);44}45}
The @Embedded JwPlayerVideo field stores the video metadata fetched from JW Player. Marking it @ToolUi.ReadOnly prevents manual edits to the synced data.
Implementing a video importer
For scheduled import, extend AbstractJwPlayerVideoImporter to define how a JwPlayerVideo becomes a local content object:
1public class VideoImporterExample extends AbstractJwPlayerVideoImporter<JwPlayerVideo, VideoExample> {23@Override4public VideoExample doImport(JwPlayerVideo videoItem) {5String mediaId = videoItem.getMediaId();67if (StringUtils.isBlank(mediaId)) {8return null;9}1011VideoExample video = Query.from(VideoExample.class)12.where("mediaId = ?", mediaId)13.first();1415if (video == null) {16video = new VideoExample();17video.setMediaId(mediaId);18}1920video.setJwPlayerVideo(videoItem);21video.setJwPlayerSettings(videoItem.getAccountSettings());2223setInitiatedByImport(video, true);24video.saveImmediately();2526return video;27}28}
Query for an existing record by media Id before creating a new one, to avoid duplicates when the same video is re-imported. Call setInitiatedByImport before saving so beforeSave/afterSave hooks can detect that the update came from an import rather than an editor.
The plugin discovers an importer implementation automatically (through ClassFinder). If a project defines more than one, select which to use with the video/jwplayer/importerClass setting.
Implementing an external item converter
To let editors create a local content record directly from a JwPlayerVideo search result, implement ExternalItemConverter:
1public class VideoConverterExample extends ExternalItemConverter<JwPlayerVideo, VideoExample> {23@Override4public Collection<? extends VideoExample> convert(JwPlayerVideo jwPlayerVideo) {5VideoExample video = new VideoExample();6video.setMediaId(jwPlayerVideo.getMediaId());7video.setJwPlayerVideo(jwPlayerVideo);8video.setJwPlayerSettings(jwPlayerVideo.getAccountSettings());9return Collections.singleton(video);10}11}
The converter runs when an editor selects a JwPlayerVideo from the search results, producing a new instance of the content type for the editor to review and save.