diff --git a/src/config/configSchema.json b/src/config/configSchema.json index 1fcccc17..1b212e50 100644 --- a/src/config/configSchema.json +++ b/src/config/configSchema.json @@ -274,6 +274,10 @@ }, "default": ["auto"] }, + "resourceType": { + "type": "string", + "default": "video" + }, "transformation": { "oneOf": [ { diff --git a/src/plugins/cloudinary/models/video-source/video-source.js b/src/plugins/cloudinary/models/video-source/video-source.js index a8c3bcd0..08cbe769 100644 --- a/src/plugins/cloudinary/models/video-source/video-source.js +++ b/src/plugins/cloudinary/models/video-source/video-source.js @@ -33,6 +33,10 @@ class VideoSource extends BaseSource { options = Object.assign({}, DEFAULT_VIDEO_PARAMS, options); + if (options.resourceType) { + options.resource_type = options.resourceType; + } + if (!options.poster) { options.poster = Object.assign({ publicId }, DEFAULT_POSTER_PARAMS); } @@ -67,10 +71,10 @@ class VideoSource extends BaseSource { this[prop](options[prop]); } }); - + // Initialize poster this.poster(options.poster); - + this.objectId = generateId(); } @@ -78,7 +82,7 @@ class VideoSource extends BaseSource { _createGetterSetters(properties) { properties.forEach(prop => { const privateKey = `_${prop}`; - this[prop] = function(value) { + this[prop] = function (value) { if (value === undefined) { // Provide sensible defaults for specific properties if (prop === 'sourceTypes' && this[privateKey] === undefined) { @@ -123,6 +127,9 @@ class VideoSource extends BaseSource { } options.cloudinaryConfig = options.cloudinaryConfig || this.cloudinaryConfig(); + + options.resource_type = this.resourceType() || options.resource_type; + this._poster = new ImageSource(publicId, options); return this; @@ -149,7 +156,7 @@ class VideoSource extends BaseSource { opts.transformation = castArray(srcTransformation); } - Object.assign(opts, { resource_type: 'video', format }); + Object.assign(opts, { format }); const [type, codecTrans] = formatToMimeTypeAndTransformation(sourceType); @@ -214,7 +221,7 @@ class VideoSource extends BaseSource { } const info = this._info || this.getInitOptions().info; - + return { title: this.title() || info?.title || '', subtitle: this.description() || info?.subtitle || '', diff --git a/src/utils/get-analytics-player-options.js b/src/utils/get-analytics-player-options.js index 622d93ff..3a2bce7e 100644 --- a/src/utils/get-analytics-player-options.js +++ b/src/utils/get-analytics-player-options.js @@ -17,6 +17,7 @@ const getSourceOptions = (sourceOptions = {}) => ({ autoShowRecommendations: sourceOptions.autoShowRecommendations, fontFace: sourceOptions.fontFace, sourceTypes: sourceOptions.sourceTypes, + resourceType: sourceOptions.resourceType, chapters: (() => { if (sourceOptions.chapters === true) return 'auto'; if (sourceOptions.chapters && sourceOptions.chapters.url) return 'url'; diff --git a/src/validators/validators.js b/src/validators/validators.js index 30d315c9..9ea58be2 100644 --- a/src/validators/validators.js +++ b/src/validators/validators.js @@ -85,6 +85,7 @@ export const playerValidators = { export const sourceValidators = { raw_transformation: validator.isString, + resourceType: validator.isString, shoppable: validator.isPlainObject, chapters: validator.or(validator.isBoolean, validator.isPlainObject), visualSearch: validator.or(validator.isBoolean), diff --git a/src/video-player.const.js b/src/video-player.const.js index c20a9d1a..efe9fb3f 100644 --- a/src/video-player.const.js +++ b/src/video-player.const.js @@ -13,6 +13,7 @@ export const SOURCE_PARAMS = [ 'publicId', 'rawTransformation', 'recommendations', + 'resourceType', 'shoppable', 'source', 'sourceTransformation', diff --git a/test/unit/videoSource.test.js b/test/unit/videoSource.test.js index ee428f91..a078aa3b 100644 --- a/test/unit/videoSource.test.js +++ b/test/unit/videoSource.test.js @@ -474,4 +474,87 @@ describe('test hasCodec method', () => { }); }); + + describe('resourceType parameter tests', () => { + it('should use image resourceType when specified', () => { + const source = new VideoSource('sample', { + cloudinaryConfig: cld, + resourceType: 'image', + transformation: [ + { effect: 'ai:model_veo-animate;details_(prompt_!flying bee!)' }, + { format: 'auto:video' } + ] + }); + + const srcs = source.generateSources(); + expect(srcs[0].src).toContain('/image/upload/'); + expect(srcs[0].src).toContain('e_ai:model_veo-animate'); + }); + + it('should default to video resourceType when not specified', () => { + const source = new VideoSource('sea_turtle', { + cloudinaryConfig: cld + }); + + const srcs = source.generateSources(); + expect(srcs[0].src).toContain('/video/upload/'); + }); + + it('should use image resourceType for poster', () => { + const source = new VideoSource('sample', { + cloudinaryConfig: cld, + resourceType: 'image', + transformation: [ + { effect: 'ai:model_veo-animate' } + ] + }); + + const posterUrl = source.poster().url(); + expect(posterUrl).toContain('/image/upload/'); + expect(posterUrl).toContain('sample.jpg'); + }); + + it('should use video resourceType for poster by default', () => { + const source = new VideoSource('sea_turtle', { + cloudinaryConfig: cld + }); + + const posterUrl = source.poster().url(); + expect(posterUrl).toContain('/video/upload/'); + }); + + it('should use configured resourceType for seek thumbnails', () => { + const source = new VideoSource('sample', { + cloudinaryConfig: cld, + resourceType: 'image', + transformation: [ + { effect: 'ai:model_veo-animate' } + ] + }); + + const vttUrl = source.config().url('sample.vtt', { + transformation: { flags: ['sprite'] }, + resource_type: source.resourceType() + }); + expect(vttUrl).toContain('/image/upload/'); + expect(vttUrl).toContain('fl_sprite'); + }); + + it('should default to video resourceType for seek thumbnails when not specified', () => { + const source = new VideoSource('sea_turtle', { + cloudinaryConfig: cld + }); + + const resourceType = source.resourceType() || 'video'; + const vttUrl = source.config().url('sea_turtle.vtt', { + transformation: { flags: ['sprite'] }, + resource_type: resourceType + }); + + // When resourceType is not set, resourceType() returns undefined, so we default to 'video' + expect(resourceType).toBe('video'); + expect(vttUrl).toContain('/video/upload/'); + expect(vttUrl).toContain('fl_sprite'); + }); + }); });