diff --git a/src/addon/filter/mediaplugin/providers/handler.ts b/src/addon/filter/mediaplugin/providers/handler.ts index ddbcfc652..bc8b5ce03 100644 --- a/src/addon/filter/mediaplugin/providers/handler.ts +++ b/src/addon/filter/mediaplugin/providers/handler.ts @@ -69,25 +69,16 @@ export class AddonFilterMediaPluginHandler extends CoreFilterDefaultHandler { } const data = this.textUtils.parseJSON(video.getAttribute('data-setup') || video.getAttribute('data-setup-lazy') || '{}'), - youtubeData = data.techOrder && data.techOrder[0] && data.techOrder[0] == 'youtube' && - this.parseYoutubeUrl(data.sources && data.sources[0] && data.sources[0].src); + youtubeUrl = data.techOrder && data.techOrder[0] && data.techOrder[0] == 'youtube' && + this.urlUtils.getYoutubeEmbedUrl(data.sources && data.sources[0] && data.sources[0].src); - if (!youtubeData || !youtubeData.videoId) { + if (!youtubeUrl) { return; } - const iframe = document.createElement('iframe'), - params: any = {}; - - if (youtubeData.listId !== null) { - params.list = youtubeData.listId; - } - if (youtubeData.start !== null) { - params.start = youtubeData.start; - } - + const iframe = document.createElement('iframe'); iframe.id = video.id; - iframe.src = this.urlUtils.addParamsToUrl('https://www.youtube.com/embed/' + youtubeData.videoId, params); + iframe.src = youtubeUrl; iframe.setAttribute('frameborder', '0'); iframe.setAttribute('allowfullscreen', '1'); iframe.width = '100%'; @@ -96,55 +87,4 @@ export class AddonFilterMediaPluginHandler extends CoreFilterDefaultHandler { // Replace video tag by the iframe. video.parentNode.replaceChild(iframe, video); } - - /** - * Parse a YouTube URL. - * Based on Youtube.parseUrl from Moodle media/player/videojs/amd/src/Youtube-lazy.js - * - * @param url URL of the video. - * @return Data of the video. - */ - protected parseYoutubeUrl(url: string): {videoId: string, listId?: string, start?: number} { - const result = { - videoId: null, - listId: null, - start: null - }; - - if (!url) { - return result; - } - - url = this.textUtils.decodeHTML(url); - - // Get the video ID. - let match = url.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/); - - if (match && match[2].length === 11) { - result.videoId = match[2]; - } - - // Now get the playlist (if any). - match = url.match(/[?&]list=([^#\&\?]+)/); - - if (match && match[1]) { - result.listId = match[1]; - } - - // Now get the start time (if any). - match = url.match(/[?&]start=(\d+)/); - - if (match && match[1]) { - result.start = parseInt(match[1], 10); - } else { - // No start param, but it could have a time param. - match = url.match(/[?&]t=(\d+h)?(\d+m)?(\d+s)?/); - if (match) { - result.start = (match[1] ? parseInt(match[1], 10) * 3600 : 0) + (match[2] ? parseInt(match[2], 10) * 60 : 0) + - (match[3] ? parseInt(match[3], 10) : 0); - } - } - - return result; - } } diff --git a/src/components/iframe/iframe.ts b/src/components/iframe/iframe.ts index 1f544a633..f6517fde6 100644 --- a/src/components/iframe/iframe.ts +++ b/src/components/iframe/iframe.ts @@ -19,6 +19,7 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { NavController } from 'ionic-angular'; import { CoreLoggerProvider } from '@providers/logger'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreUrlUtilsProvider } from '@providers/utils/url'; import { CoreIframeUtilsProvider } from '@providers/utils/iframe'; import { CoreSplitViewComponent } from '@components/split-view/split-view'; @@ -39,9 +40,13 @@ export class CoreIframeComponent implements OnInit, OnChanges { protected logger; protected IFRAME_TIMEOUT = 15000; - constructor(logger: CoreLoggerProvider, private iframeUtils: CoreIframeUtilsProvider, private domUtils: CoreDomUtilsProvider, - private sanitizer: DomSanitizer, private navCtrl: NavController, - @Optional() private svComponent: CoreSplitViewComponent) { + constructor(logger: CoreLoggerProvider, + protected iframeUtils: CoreIframeUtilsProvider, + protected domUtils: CoreDomUtilsProvider, + protected sanitizer: DomSanitizer, + protected navCtrl: NavController, + protected urlUtils: CoreUrlUtilsProvider, + @Optional() protected svComponent: CoreSplitViewComponent) { this.logger = logger.getInstance('CoreIframe'); this.loaded = new EventEmitter(); @@ -84,7 +89,8 @@ export class CoreIframeComponent implements OnInit, OnChanges { */ ngOnChanges(changes: {[name: string]: SimpleChange }): void { if (changes.src) { - this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(changes.src.currentValue); + const youtubeUrl = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue); + this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(youtubeUrl || changes.src.currentValue); } } } diff --git a/src/providers/utils/url.ts b/src/providers/utils/url.ts index 39604bfd3..d2e9e0d47 100644 --- a/src/providers/utils/url.ts +++ b/src/providers/utils/url.ts @@ -233,6 +233,58 @@ export class CoreUrlUtilsProvider { }); } + /** + * Returns the Youtube Embed Video URL or null if not found. + * + * @param url URL + * @return Youtube Embed Video URL or null if not found. + */ + getYoutubeEmbedUrl(url: string): string { + if (!url) { + return; + } + + let videoId; + const params: any = {}; + + url = this.textUtils.decodeHTML(url); + + // Get the video ID. + let match = url.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/); + + if (match && match[2].length === 11) { + videoId = match[2]; + } + + // No videoId, do not continue. + if (!videoId) { + return; + } + + // Now get the playlist (if any). + match = url.match(/[?&]list=([^#\&\?]+)/); + + if (match && match[1]) { + params.list = match[1]; + } + + // Now get the start time (if any). + match = url.match(/[?&]start=(\d+)/); + + if (match && match[1]) { + params.start = parseInt(match[1], 10); + } else { + // No start param, but it could have a time param. + match = url.match(/[?&]t=(\d+h)?(\d+m)?(\d+s)?/); + if (match) { + params.start = (match[1] ? parseInt(match[1], 10) * 3600 : 0) + (match[2] ? parseInt(match[2], 10) * 60 : 0) + + (match[3] ? parseInt(match[3], 10) : 0); + } + } + + return this.addParamsToUrl('https://www.youtube.com/embed/' + videoId, params); + } + /** * Given a URL, returns what's after the last '/' without params. * Example: