From 2eeccc7d255ffd6dfb1ed1bd648777e8e3ee63f0 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Tue, 20 May 2025 10:33:08 -0400 Subject: [PATCH] feat: only show google attribution for google-translated transcripts (#36619) * feat: only show google attribution for google-translated transcripts * fixup! feat: only show google attribution for google-translated transcripts --- xmodule/js/spec/video/video_caption_spec.js | 47 +++++++++++++++++ xmodule/js/src/video/09_video_caption.js | 58 ++++++++++++++------- 2 files changed, 87 insertions(+), 18 deletions(-) diff --git a/xmodule/js/spec/video/video_caption_spec.js b/xmodule/js/spec/video/video_caption_spec.js index 58fcc1cce9..ff6749b11c 100644 --- a/xmodule/js/spec/video/video_caption_spec.js +++ b/xmodule/js/spec/video/video_caption_spec.js @@ -637,6 +637,7 @@ spyOn(Caption, 'renderCaption'); spyOn(Caption, 'bindHandlers'); spyOn(Caption, 'updatePlayTime'); + spyOn(Caption, 'renderGoogleDisclaimer'); spyOn(Caption, 'hideCaptions'); spyOn(state, 'youtubeId').and.returnValue('Z5KLxerq05Y'); }); @@ -715,6 +716,7 @@ expect($.ajaxWithPrefix).toHaveBeenCalled(); expect(Caption.bindHandlers).toHaveBeenCalled(); expect(Caption.renderCaption).toHaveBeenCalled(); + expect(Caption.renderGoogleDisclaimer).toHaveBeenCalled() expect(Caption.updatePlayTime).not.toHaveBeenCalled(); expect(Caption.loaded).toBeTruthy(); }); @@ -808,6 +810,8 @@ expect($.ajaxWithPrefix).toHaveBeenCalled(); expect(Caption.fetchAvailableTranslations).toHaveBeenCalled(); }); + + }); describe('fetchAvailableTranslations', function() { @@ -1327,5 +1331,48 @@ }); }); }); + + describe('google disclaimer', () => { + const BASE_CAPTIONS = [ + 'this is a caption', + 'this is another caption', + 'quite lovely weather we\'re having today', + 'indeed', + ] + var Caption; + + const makeCaptions = (provider) => { + const providerAttr = provider ? ` data-provider="${provider}"` : ''; + const aiGeneratedTag = ``; + var captions = [...BASE_CAPTIONS]; + captions[0] = aiGeneratedTag + captions[0]; + return captions; + }; + + beforeEach(() => { + state = jasmine.initializePlayer(); + Caption = state.videoCaption; + }) + + it('not shown when captions are not ai generated', () => { + Caption.renderGoogleDisclaimer(BASE_CAPTIONS) + expect(state.shouldShowGoogleDisclaimer).toBe(false); + }); + + it('not shown when captions are not generated by gcp', () => { + Caption.renderGoogleDisclaimer(makeCaptions('someoneElse')) + expect(state.shouldShowGoogleDisclaimer).toBe(false); + }); + + it('shown when captions are generated by gcp', () => { + Caption.renderGoogleDisclaimer(makeCaptions('gcp')) + expect(state.shouldShowGoogleDisclaimer).toBe(true); + }); + + it('shown when captions have no provider', () => { + Caption.renderGoogleDisclaimer(makeCaptions()) + expect(state.shouldShowGoogleDisclaimer).toBe(true); + }); + }); }); }).call(this); diff --git a/xmodule/js/src/video/09_video_caption.js b/xmodule/js/src/video/09_video_caption.js index f5db26514b..90138c3ccc 100644 --- a/xmodule/js/src/video/09_video_caption.js +++ b/xmodule/js/src/video/09_video_caption.js @@ -38,7 +38,7 @@ 'showClosedCaptions', 'hideClosedCaptions', 'toggleClosedCaptions', 'updateCaptioningCookie', 'handleCaptioningCookie', 'handleTranscriptToggle', 'listenForDragDrop', 'setTranscriptVisibility', 'updateTranscriptCookie', - 'toggleGoogleDisclaimer' + 'updateGoogleDisclaimer', 'toggleGoogleDisclaimer' ); this.state = state; @@ -494,27 +494,49 @@ }, /** - * @desc Shows/Hides Google disclaimer based on captions being AI generated and - * if ClosedCaptions are being shown. + * @desc Sets whether or not the Google disclaimer should be shown based on captions + * being AI generated, and shows/hides based on the above and if ClosedCaptions are being shown. * * @param {array} captions List of captions for the video. * * @returns {boolean} */ - toggleGoogleDisclaimer: function(captions) { + updateGoogleDisclaimer: function(captions) { + const aIGeneratedSpanText = '\w+)["']/; var self = this, state = this.state, - aIGeneratedSpan = '', - captionsAIGenerated = captions.some(caption => caption.includes(aIGeneratedSpan)); + aiGeneratedSpan = captions.find(caption => caption.includes(aIGeneratedSpanText)), + captionsAIGenerated = !(aiGeneratedSpan === undefined); + aiCaptionProviderIsGoogle = true; - if (!self.hideCaptionsOnLoad && !state.captionsHidden) { - if (captionsAIGenerated) { - state.el.find('.google-disclaimer').show(); - self.shouldShowGoogleDisclaimer = true; - } else { - state.el.find('.google-disclaimer').hide(); - self.shouldShowGoogleDisclaimer = false; + if (captionsAIGenerated) { + const providerMatch = aiProviderRegexp.exec(aiGeneratedSpan); + if (providerMatch !== null) { + aiCaptionProviderIsGoogle = providerMatch.groups['provider'] === 'gcp'; } + // If there is no provider tag, it was generated before we added those, + // so it must be Google + } + // This field is whether or not, in general, this video should show the google disclaimer + self.shouldShowGoogleDisclaimer = captionsAIGenerated && aiCaptionProviderIsGoogle; + // Should we, right now, on load, show the google disclaimer + self.toggleGoogleDisclaimer(!self.hideCaptionsOnLoad && !state.captionsHidden); + }, + + /** + * @desc Show or hide the google translate disclaimer based on the passed param + * and whether or not we are currently showing a google translated transcript. + * @param {boolean} [show] Show if true, hide if false - if we are showing a google + * translated transcript. If not, this will always hide. + */ + toggleGoogleDisclaimer: function(show) { + var self = this, + state = this.state; + if (show && self.shouldShowGoogleDisclaimer) { + state.el.find('.google-disclaimer').show(); + } else { + state.el.find('.google-disclaimer').hide(); } }, @@ -573,7 +595,7 @@ start = results.start; captions = results.captions; - self.toggleGoogleDisclaimer(captions); + self.renderGoogleDisclaimer(captions); if (self.loaded) { if (self.rendered) { @@ -1194,10 +1216,12 @@ this.state.showClosedCaptions = false; this.updateCaptioningCookie(false); this.hideClosedCaptions(); + this.toggleGoogleDisclaimer(false); } else { this.state.showClosedCaptions = true; this.updateCaptioningCookie(true); this.showClosedCaptions(); + this.toggleGoogleDisclaimer(true); } }, @@ -1340,7 +1364,7 @@ this.state.el.trigger('transcript:hide'); } - state.el.find('.google-disclaimer').hide(); + self.toggleGoogleDisclaimer(false); transcriptControlEl .removeClass('is-active') @@ -1355,9 +1379,7 @@ this.state.el.trigger('transcript:show'); } - if (self.shouldShowGoogleDisclaimer) { - state.el.find('.google-disclaimer').show(); - } + self.toggleGoogleDisclaimer(true); transcriptControlEl .addClass('is-active')