From ae9231e9677c270eeb67192b9091f5ca43a847af Mon Sep 17 00:00:00 2001 From: JonathanTGold Date: Wed, 26 Oct 2022 16:14:02 +0200 Subject: [PATCH 01/10] feat(FEC-12611): Kaltura Image Entry Support - Load Kaltura Image Entries with or without KS --- flow-typed/types/media-config-sources.js | 9 ++++-- flow-typed/types/media-source.js | 7 +++++ flow-typed/types/media-sources.js | 3 ++ src/entities/image-source.js | 40 ++++++++++++++++++++++++ src/entities/media-sources.js | 6 +++- src/k-provider/common/base-provider.js | 2 +- src/k-provider/ovp/provider-parser.js | 8 +++++ src/k-provider/ovp/provider.js | 2 ++ 8 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 src/entities/image-source.js diff --git a/flow-typed/types/media-config-sources.js b/flow-typed/types/media-config-sources.js index 17c30e0f..3e3f73e0 100644 --- a/flow-typed/types/media-config-sources.js +++ b/flow-typed/types/media-config-sources.js @@ -1,8 +1,11 @@ // @flow +import ImageSource from "../../src/entities/image-source"; + declare type ProviderMediaConfigSourcesObject = { - dash: Array, - hls: Array, - progressive: Array, + dash: Array, + hls: Array, + progressive: Array, + image: ImageSource, duration: number, type: string, id: string, diff --git a/flow-typed/types/media-source.js b/flow-typed/types/media-source.js index 2fe5fc56..85f8d6d2 100644 --- a/flow-typed/types/media-source.js +++ b/flow-typed/types/media-source.js @@ -7,5 +7,12 @@ declare type ProviderMediaSourceObject = { width?: number, height?: number, label?: string, +}; + +declare type ProviderVideoMediaSourceObject = ProviderMediaSourceObject & { drmData?: Array }; + +declare type ProviderImageMediaSourceObject = ProviderMediaSourceObject; + + diff --git a/flow-typed/types/media-sources.js b/flow-typed/types/media-sources.js index 3825d7ff..d65816da 100644 --- a/flow-typed/types/media-sources.js +++ b/flow-typed/types/media-sources.js @@ -1,7 +1,10 @@ // @flow +import ImageSource from "../../src/entities/image-source"; + declare type ProviderMediaSourcesObject = { progressive: Array, dash: Array, hls: Array, + image: ImageSource, captions?: Array }; diff --git a/src/entities/image-source.js b/src/entities/image-source.js new file mode 100644 index 00000000..cb296e1d --- /dev/null +++ b/src/entities/image-source.js @@ -0,0 +1,40 @@ +//@flow + +export default class ImageSource { + /** + * @member - media source id + * @type {string} + */ + id: string; + /** + * @member - media source url + * @type {string} + */ + url: string; + /** + * @member - media source templateUrl + * @type {string} + */ + templateUrl: string; + /** + * @member - media source mimetype + * @type {string} + */ + mimetype: string; + + constructor(entry: Object) { + this.id = entry.id; + this.url = entry.dataUrl; + this.mimetype = 'image/jpeg'; + this.templateUrl = ImageSource.createTemplateUrl(entry.url); + } + + /** + * Convert url to template url. + * @param {string} url - dataUrl. + * @returns {string} - The template url . + */ + static createTemplateUrl(url: string): string { + return url; + } +} diff --git a/src/entities/media-sources.js b/src/entities/media-sources.js index fe091855..634ac667 100644 --- a/src/entities/media-sources.js +++ b/src/entities/media-sources.js @@ -1,6 +1,7 @@ // @flow import MediaSource from './media-source'; import {MediaFormat} from './media-format'; +import ImageSource from "./image-source"; export default class MediaSources { /** @@ -21,6 +22,7 @@ export default class MediaSources { * @public */ hls: Array; + image: ImageSource; captions: Array; /** @@ -64,11 +66,13 @@ export default class MediaSources { const response: ProviderMediaSourcesObject = { progressive: [], dash: [], - hls: [] + hls: [], + image: undefined }; this.progressive.forEach(p => response.progressive.push(p.toJSON())); this.hls.forEach(h => response.hls.push(h.toJSON())); this.dash.forEach(d => response.dash.push(d.toJSON())); + response.image = this.image; return response; } } diff --git a/src/k-provider/common/base-provider.js b/src/k-provider/common/base-provider.js index 8b72e83d..1ac4da3f 100644 --- a/src/k-provider/common/base-provider.js +++ b/src/k-provider/common/base-provider.js @@ -88,7 +88,7 @@ export default class BaseProvider { } _verifyHasSources(sources: ProviderMediaConfigSourcesObject) { - if (sources.hls.concat(sources.dash, sources.progressive).length === 0) { + if (sources.hls.concat(sources.dash, sources.progressive).length === 0 && sources.image === undefined) { throw new Error(Error.Severity.CRITICAL, Error.Category.SERVICE, Error.Code.MISSING_PLAY_SOURCE, { action: '', messages: `No play source for entry id: ${sources.id}` diff --git a/src/k-provider/ovp/provider-parser.js b/src/k-provider/ovp/provider-parser.js index c10ce585..ee689e70 100644 --- a/src/k-provider/ovp/provider-parser.js +++ b/src/k-provider/ovp/provider-parser.js @@ -21,6 +21,7 @@ import {KalturaRuleAction} from './response-types/kaltura-rule-action'; import {KalturaAccessControlMessage} from '../common/response-types/kaltura-access-control-message'; import type {OVPMediaEntryLoaderResponse} from './loaders/media-entry-loader'; import {ExternalCaptionsBuilder} from './external-captions-builder'; +import ImageSource from "../../entities/image-source"; class OVPProviderParser { static _logger = getLogger('OVPProviderParser'); @@ -230,6 +231,10 @@ class OVPProviderParser { sources.progressive = OVPProviderParser._parseProgressiveSources(progressiveSource, playbackContext, ks, partnerId, uiConfId, entry.id); }; + const parseImageSources = () => { + sources.image = new ImageSource(entry); + }; + const parseExternalMedia = () => { const mediaSource = new MediaSource(); mediaSource.mimetype = 'video/youtube'; @@ -240,9 +245,12 @@ class OVPProviderParser { if (entry.type === KalturaMediaEntry.EntryType.EXTERNAL_MEDIA.value) { parseExternalMedia(); + } else if (entry.entryType === KalturaMediaEntry.MediaType.IMAGE.value) { + parseImageSources(); } else if (kalturaSources && kalturaSources.length > 0) { parseAdaptiveSources(); parseProgressiveSources(); + parseImageSources(); } return sources; } diff --git a/src/k-provider/ovp/provider.js b/src/k-provider/ovp/provider.js index 09b598cb..d0826402 100644 --- a/src/k-provider/ovp/provider.js +++ b/src/k-provider/ovp/provider.js @@ -303,6 +303,7 @@ export default class OVPProvider extends BaseProvider Date: Wed, 26 Oct 2022 16:25:00 +0200 Subject: [PATCH 02/10] lint fix --- src/entities/media-sources.js | 2 +- src/k-provider/ovp/provider-parser.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entities/media-sources.js b/src/entities/media-sources.js index 634ac667..b95933e0 100644 --- a/src/entities/media-sources.js +++ b/src/entities/media-sources.js @@ -1,7 +1,7 @@ // @flow import MediaSource from './media-source'; import {MediaFormat} from './media-format'; -import ImageSource from "./image-source"; +import ImageSource from './image-source'; export default class MediaSources { /** diff --git a/src/k-provider/ovp/provider-parser.js b/src/k-provider/ovp/provider-parser.js index ee689e70..e706e135 100644 --- a/src/k-provider/ovp/provider-parser.js +++ b/src/k-provider/ovp/provider-parser.js @@ -21,7 +21,7 @@ import {KalturaRuleAction} from './response-types/kaltura-rule-action'; import {KalturaAccessControlMessage} from '../common/response-types/kaltura-access-control-message'; import type {OVPMediaEntryLoaderResponse} from './loaders/media-entry-loader'; import {ExternalCaptionsBuilder} from './external-captions-builder'; -import ImageSource from "../../entities/image-source"; +import ImageSource from '../../entities/image-source'; class OVPProviderParser { static _logger = getLogger('OVPProviderParser'); From f9cfcb54ebf82546034993452ecd782ba5e0f6a5 Mon Sep 17 00:00:00 2001 From: JonathanTGold Date: Sun, 1 Jan 2023 13:16:11 +0200 Subject: [PATCH 03/10] feat(FEC-12611): Image Player Engine (playkitJS/v7) --- flow-typed/types/media-config-sources.js | 2 +- flow-typed/types/media-sources.js | 2 +- src/entities/image-source.js | 2 +- src/entities/media-sources.js | 5 +++-- src/k-provider/common/base-provider.js | 2 +- src/k-provider/ovp/provider-parser.js | 6 ++++-- src/k-provider/ovp/provider.js | 2 +- 7 files changed, 12 insertions(+), 9 deletions(-) diff --git a/flow-typed/types/media-config-sources.js b/flow-typed/types/media-config-sources.js index 3e3f73e0..578ba7ad 100644 --- a/flow-typed/types/media-config-sources.js +++ b/flow-typed/types/media-config-sources.js @@ -5,7 +5,7 @@ declare type ProviderMediaConfigSourcesObject = { dash: Array, hls: Array, progressive: Array, - image: ImageSource, + image: Array, duration: number, type: string, id: string, diff --git a/flow-typed/types/media-sources.js b/flow-typed/types/media-sources.js index d65816da..e4e09d1c 100644 --- a/flow-typed/types/media-sources.js +++ b/flow-typed/types/media-sources.js @@ -5,6 +5,6 @@ declare type ProviderMediaSourcesObject = { progressive: Array, dash: Array, hls: Array, - image: ImageSource, + image: Array, captions?: Array }; diff --git a/src/entities/image-source.js b/src/entities/image-source.js index cb296e1d..591f8019 100644 --- a/src/entities/image-source.js +++ b/src/entities/image-source.js @@ -26,7 +26,7 @@ export default class ImageSource { this.id = entry.id; this.url = entry.dataUrl; this.mimetype = 'image/jpeg'; - this.templateUrl = ImageSource.createTemplateUrl(entry.url); + this.templateUrl = ImageSource.createTemplateUrl(entry.dataUrl); } /** diff --git a/src/entities/media-sources.js b/src/entities/media-sources.js index b95933e0..e17a0453 100644 --- a/src/entities/media-sources.js +++ b/src/entities/media-sources.js @@ -22,7 +22,7 @@ export default class MediaSources { * @public */ hls: Array; - image: ImageSource; + image: Array; captions: Array; /** @@ -32,6 +32,7 @@ export default class MediaSources { this.progressive = []; this.dash = []; this.hls = []; + this.image = []; } /** @@ -67,7 +68,7 @@ export default class MediaSources { progressive: [], dash: [], hls: [], - image: undefined + image: [] }; this.progressive.forEach(p => response.progressive.push(p.toJSON())); this.hls.forEach(h => response.hls.push(h.toJSON())); diff --git a/src/k-provider/common/base-provider.js b/src/k-provider/common/base-provider.js index 1ac4da3f..94e3a202 100644 --- a/src/k-provider/common/base-provider.js +++ b/src/k-provider/common/base-provider.js @@ -88,7 +88,7 @@ export default class BaseProvider { } _verifyHasSources(sources: ProviderMediaConfigSourcesObject) { - if (sources.hls.concat(sources.dash, sources.progressive).length === 0 && sources.image === undefined) { + if (sources.hls.concat(sources.dash, sources.progressive, sources.image).length === 0) { throw new Error(Error.Severity.CRITICAL, Error.Category.SERVICE, Error.Code.MISSING_PLAY_SOURCE, { action: '', messages: `No play source for entry id: ${sources.id}` diff --git a/src/k-provider/ovp/provider-parser.js b/src/k-provider/ovp/provider-parser.js index e706e135..6b768e8c 100644 --- a/src/k-provider/ovp/provider-parser.js +++ b/src/k-provider/ovp/provider-parser.js @@ -148,7 +148,6 @@ class OVPProviderParser { } static _fillBaseData(mediaEntry: MediaEntry, entry: KalturaMediaEntry, metadataList: ?KalturaMetadataListResponse) { - mediaEntry.poster = entry.poster; mediaEntry.id = entry.id; mediaEntry.duration = entry.duration; mediaEntry.metadata = OVPProviderParser._parseMetadata(metadataList); @@ -163,6 +162,9 @@ class OVPProviderParser { mediaEntry.dvrStatus = entry.dvrStatus; } + if (mediaEntry.type !== MediaEntry.Type.IMAGE) { + mediaEntry.poster = entry.poster; + } return mediaEntry; } @@ -232,7 +234,7 @@ class OVPProviderParser { }; const parseImageSources = () => { - sources.image = new ImageSource(entry); + sources.image.push(new ImageSource(entry)); }; const parseExternalMedia = () => { diff --git a/src/k-provider/ovp/provider.js b/src/k-provider/ovp/provider.js index d0826402..82776d8d 100644 --- a/src/k-provider/ovp/provider.js +++ b/src/k-provider/ovp/provider.js @@ -303,7 +303,7 @@ export default class OVPProvider extends BaseProvider Date: Sun, 1 Jan 2023 16:56:27 +0200 Subject: [PATCH 04/10] fix tests --- src/k-provider/ovp/provider-parser.js | 1 - test/src/k-provider/ovp/media-config-data.js | 20 ++++++++++++++----- .../k-provider/ovp/provider-parser-data.js | 3 ++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/k-provider/ovp/provider-parser.js b/src/k-provider/ovp/provider-parser.js index 6b768e8c..4cdb3a3e 100644 --- a/src/k-provider/ovp/provider-parser.js +++ b/src/k-provider/ovp/provider-parser.js @@ -252,7 +252,6 @@ class OVPProviderParser { } else if (kalturaSources && kalturaSources.length > 0) { parseAdaptiveSources(); parseProgressiveSources(); - parseImageSources(); } return sources; } diff --git a/test/src/k-provider/ovp/media-config-data.js b/test/src/k-provider/ovp/media-config-data.js index 60b00c60..a9514d9b 100644 --- a/test/src/k-provider/ovp/media-config-data.js +++ b/test/src/k-provider/ovp/media-config-data.js @@ -135,7 +135,8 @@ const NoPluginsNoDrm = { url: 'https://cdnapisec.kaltura.com/p/1082342/sp/108234200/playManifest/entryId/1_rsrdfext/protocol/https/format/applehttp/flavorIds/1_ha0nqwz8,1_gw7u4nf1,1_rql6sqaa,1_sufd1yd9,1_9xvkk7a5,1_4typ4pat,1_n75294r4/a.m3u8' } - ] + ], + image:[] } }; @@ -175,6 +176,7 @@ const RegexAppliedSources = { mimetype: 'application/dash+xml' } ], + image: [], progressive: [ { id: '1_ha0nqwz810081,url', @@ -336,7 +338,8 @@ const NoPluginsWithDrm = { } ] } - ] + ], + image: [] } }; @@ -477,7 +480,8 @@ const WithPluginsNoDrm = { url: 'https://cdnapisec.kaltura.com/p/1082342/sp/108234200/playManifest/entryId/1_rsrdfext/protocol/https/format/applehttp/flavorIds/1_ha0nqwz8,1_gw7u4nf1,1_rql6sqaa,1_sufd1yd9,1_9xvkk7a5,1_4typ4pat,1_n75294r4/a.m3u8?uiConfId=38621471' } - ] + ], + image: [] } }; @@ -539,7 +543,8 @@ const WithPluginsWithDrm = { } ] } - ] + ], + image: [] } }; @@ -599,7 +604,8 @@ const AudioEntryWithoutPlugins = { url: 'https://cdnapisec.kaltura.com/p/1082342/sp/108234200/playManifest/entryId/0_vyzw3ceu/protocol/https/format/applehttp/flavorIds/0_hawbhpz3/a.m3u8' } - ] + ], + image: [] } }; @@ -979,6 +985,7 @@ const EntryWithBumper = { label: 'Undefined' } ], + image: [], id: '0_wifqaipd', duration: 741, type: 'Vod', @@ -1094,6 +1101,7 @@ const EntryWithBumperWithKs = { label: 'Undefined' } ], + image: [], id: '0_wifqaipd', duration: 741, type: 'Vod', @@ -1212,6 +1220,7 @@ const EntryWithNoBumper = { label: 'Undefined' } ], + image: [], id: '0_wifqaipd', duration: 741, type: 'Vod', @@ -1302,6 +1311,7 @@ const EntryOfPartner0 = { label: 'Undefined' } ], + image: [], id: '0_pi55vv3r', duration: 11, type: 'Vod', diff --git a/test/src/k-provider/ovp/provider-parser-data.js b/test/src/k-provider/ovp/provider-parser-data.js index 70c9ef20..7b36ab7b 100644 --- a/test/src/k-provider/ovp/provider-parser-data.js +++ b/test/src/k-provider/ovp/provider-parser-data.js @@ -68,7 +68,8 @@ const youtubeMediaEntryResult = { } ], dash: [], - hls: [] + hls: [], + image: [] }, duration: 0, metadata: { From 17a6fd4c56ae34917d81f0a1fc9aa6f0b06320cd Mon Sep 17 00:00:00 2001 From: JonathanTGold Date: Mon, 2 Jan 2023 11:40:13 +0200 Subject: [PATCH 05/10] fix flow types, lint --- flow-typed/types/media-config-sources.js | 6 +++--- flow-typed/types/media-source.js | 7 ------- src/k-provider/ott/provider.js | 1 + test/src/k-provider/ovp/media-config-data.js | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/flow-typed/types/media-config-sources.js b/flow-typed/types/media-config-sources.js index 578ba7ad..827239b5 100644 --- a/flow-typed/types/media-config-sources.js +++ b/flow-typed/types/media-config-sources.js @@ -2,9 +2,9 @@ import ImageSource from "../../src/entities/image-source"; declare type ProviderMediaConfigSourcesObject = { - dash: Array, - hls: Array, - progressive: Array, + dash: Array, + hls: Array, + progressive: Array, image: Array, duration: number, type: string, diff --git a/flow-typed/types/media-source.js b/flow-typed/types/media-source.js index 85f8d6d2..2fe5fc56 100644 --- a/flow-typed/types/media-source.js +++ b/flow-typed/types/media-source.js @@ -7,12 +7,5 @@ declare type ProviderMediaSourceObject = { width?: number, height?: number, label?: string, -}; - -declare type ProviderVideoMediaSourceObject = ProviderMediaSourceObject & { drmData?: Array }; - -declare type ProviderImageMediaSourceObject = ProviderMediaSourceObject; - - diff --git a/src/k-provider/ott/provider.js b/src/k-provider/ott/provider.js index d83ca211..35fc89ce 100644 --- a/src/k-provider/ott/provider.js +++ b/src/k-provider/ott/provider.js @@ -202,6 +202,7 @@ export default class OTTProvider extends BaseProvider Date: Mon, 2 Jan 2023 12:33:53 +0200 Subject: [PATCH 06/10] fix tests --- test/src/k-provider/ott/media-config-data.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/src/k-provider/ott/media-config-data.js b/test/src/k-provider/ott/media-config-data.js index 34b38fdf..267e8f93 100644 --- a/test/src/k-provider/ott/media-config-data.js +++ b/test/src/k-provider/ott/media-config-data.js @@ -12,6 +12,7 @@ const NoPluginsWithDrm = { plugins: {}, sources: { progressive: [], + image: [], dash: [ { id: '728180,mpegdash', @@ -454,6 +455,7 @@ const FilteredSourcesByDeviceType = { ], progressive: [], dash: [], + image: [], hls: [ { id: '728182,applehttp', @@ -698,6 +700,7 @@ const LiveEntryNoDrm = { height: 800 } ], + image: [], progressive: [], dash: [], hls: [ @@ -767,6 +770,7 @@ const EntryWithBumper = { } ], progressive: [], + image: [], id: 324284, duration: 60, type: 'Vod', From 8c1961fff155871399a2675231d8c70331f3a403 Mon Sep 17 00:00:00 2001 From: JonathanTGold Date: Thu, 5 Jan 2023 11:19:32 +0200 Subject: [PATCH 07/10] extract base thumbnail url --- src/entities/image-source.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/entities/image-source.js b/src/entities/image-source.js index 591f8019..62bbba0d 100644 --- a/src/entities/image-source.js +++ b/src/entities/image-source.js @@ -1,5 +1,7 @@ //@flow +const BASE_THUMBNAIL_URL_TEMPLATE = '.+entry_id/[a-zA-Z0-9_]+/'; + export default class ImageSource { /** * @member - media source id @@ -24,9 +26,8 @@ export default class ImageSource { constructor(entry: Object) { this.id = entry.id; - this.url = entry.dataUrl; + this.url = ImageSource.extractBaseThumbnailUrl(entry.dataUrl); this.mimetype = 'image/jpeg'; - this.templateUrl = ImageSource.createTemplateUrl(entry.dataUrl); } /** @@ -34,7 +35,7 @@ export default class ImageSource { * @param {string} url - dataUrl. * @returns {string} - The template url . */ - static createTemplateUrl(url: string): string { - return url; + static extractBaseThumbnailUrl(url: string): string { + return url.match(BASE_THUMBNAIL_URL_TEMPLATE)[0]; } } From feb37167a9d872e2922835e35ebff2bb951f3099 Mon Sep 17 00:00:00 2001 From: JonathanTGold Date: Thu, 5 Jan 2023 16:50:41 +0200 Subject: [PATCH 08/10] remove unused property --- src/entities/image-source.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/entities/image-source.js b/src/entities/image-source.js index 62bbba0d..13d36f9a 100644 --- a/src/entities/image-source.js +++ b/src/entities/image-source.js @@ -13,11 +13,6 @@ export default class ImageSource { * @type {string} */ url: string; - /** - * @member - media source templateUrl - * @type {string} - */ - templateUrl: string; /** * @member - media source mimetype * @type {string} @@ -36,6 +31,6 @@ export default class ImageSource { * @returns {string} - The template url . */ static extractBaseThumbnailUrl(url: string): string { - return url.match(BASE_THUMBNAIL_URL_TEMPLATE)[0]; + return url.match(BASE_THUMBNAIL_URL_TEMPLATE)[0].slice(0, -1); } } From f13110d0de2fdbba764edac50575de5708b2825d Mon Sep 17 00:00:00 2001 From: JonathanTGold Date: Thu, 19 Jan 2023 13:52:08 +0200 Subject: [PATCH 09/10] fix types --- src/entities/image-source.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/entities/image-source.js b/src/entities/image-source.js index 13d36f9a..97a78b26 100644 --- a/src/entities/image-source.js +++ b/src/entities/image-source.js @@ -26,11 +26,12 @@ export default class ImageSource { } /** - * Convert url to template url. + * Extract the base thumbnail url. * @param {string} url - dataUrl. - * @returns {string} - The template url . + * @returns {string} - The base thumbnail url. */ static extractBaseThumbnailUrl(url: string): string { + // $FlowFixMe return url.match(BASE_THUMBNAIL_URL_TEMPLATE)[0].slice(0, -1); } } From 3cd17585beaab3480f2f4935982905099dd06fe0 Mon Sep 17 00:00:00 2001 From: JonathanTGold Date: Thu, 19 Jan 2023 14:24:51 +0200 Subject: [PATCH 10/10] remove mimetype --- src/entities/image-source.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/image-source.js b/src/entities/image-source.js index 97a78b26..480e6d40 100644 --- a/src/entities/image-source.js +++ b/src/entities/image-source.js @@ -22,7 +22,7 @@ export default class ImageSource { constructor(entry: Object) { this.id = entry.id; this.url = ImageSource.extractBaseThumbnailUrl(entry.dataUrl); - this.mimetype = 'image/jpeg'; + this.mimetype = ''; } /**