commit
						29b2184792
					
				| @ -18,7 +18,6 @@ import { CoreError } from '@classes/errors/error'; | |||||||
| import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component'; | import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component'; | ||||||
| import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; | import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; | ||||||
| import { CoreCourse } from '@features/course/services/course'; | import { CoreCourse } from '@features/course/services/course'; | ||||||
| import { CoreSites } from '@services/sites'; |  | ||||||
| import { CoreMimetypeUtils } from '@services/utils/mimetype'; | import { CoreMimetypeUtils } from '@services/utils/mimetype'; | ||||||
| import { CoreTextUtils } from '@services/utils/text'; | import { CoreTextUtils } from '@services/utils/text'; | ||||||
| import { AddonModUrl, AddonModUrlDisplayOptions, AddonModUrlProvider, AddonModUrlUrl } from '../../services/url'; | import { AddonModUrl, AddonModUrlDisplayOptions, AddonModUrlProvider, AddonModUrlUrl } from '../../services/url'; | ||||||
| @ -109,8 +108,7 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo | |||||||
| 
 | 
 | ||||||
|         } catch { |         } catch { | ||||||
|             // Fallback in case is not prefetched.
 |             // Fallback in case is not prefetched.
 | ||||||
|             const mod = |             const mod = await CoreCourse.getModule(this.module.id, this.courseId, undefined, false, false, undefined, 'url'); | ||||||
|                 await CoreCourse.getModule(this.module.id, this.courseId, undefined, false, false, undefined, 'url'); |  | ||||||
| 
 | 
 | ||||||
|             this.name = mod.name; |             this.name = mod.name; | ||||||
|             this.description = mod.description; |             this.description = mod.description; | ||||||
| @ -146,16 +144,6 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo | |||||||
|             this.isVideo = CoreMimetypeUtils.isExtensionInGroup(extension, ['web_video']); |             this.isVideo = CoreMimetypeUtils.isExtensionInGroup(extension, ['web_video']); | ||||||
|             this.isOther = !this.isImage && !this.isAudio && !this.isVideo; |             this.isOther = !this.isImage && !this.isAudio && !this.isVideo; | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         if (this.shouldIframe || (this.shouldEmbed && !this.isImage && !this.isAudio && !this.isVideo)) { |  | ||||||
|             // Will be displayed in an iframe. Check if we need to auto-login.
 |  | ||||||
|             const currentSite = CoreSites.getCurrentSite(); |  | ||||||
| 
 |  | ||||||
|             if (currentSite && this.url) { |  | ||||||
|                 // Format the URL to add auto-login if needed.
 |  | ||||||
|                 this.url = await currentSite.getAutoLoginUrl(this.url, false); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -28,6 +28,8 @@ import { CoreScreen, CoreScreenOrientation } from '@services/screen'; | |||||||
| import { Subscription } from 'rxjs'; | import { Subscription } from 'rxjs'; | ||||||
| import { filter } from 'rxjs/operators'; | import { filter } from 'rxjs/operators'; | ||||||
| import { NavigationStart } from '@angular/router'; | import { NavigationStart } from '@angular/router'; | ||||||
|  | import { CoreSites } from '@services/sites'; | ||||||
|  | import { CoreUrl } from '@singletons/url'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|     selector: 'core-iframe', |     selector: 'core-iframe', | ||||||
| @ -45,6 +47,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { | |||||||
|     @Input() allowFullscreen?: boolean | string; |     @Input() allowFullscreen?: boolean | string; | ||||||
|     @Input() showFullscreenOnToolbar?: boolean | string; |     @Input() showFullscreenOnToolbar?: boolean | string; | ||||||
|     @Input() autoFullscreenOnRotate?: boolean | string; |     @Input() autoFullscreenOnRotate?: boolean | string; | ||||||
|  |     @Input() allowAutoLogin = true; | ||||||
|     @Output() loaded: EventEmitter<HTMLIFrameElement> = new EventEmitter<HTMLIFrameElement>(); |     @Output() loaded: EventEmitter<HTMLIFrameElement> = new EventEmitter<HTMLIFrameElement>(); | ||||||
| 
 | 
 | ||||||
|     loading?: boolean; |     loading?: boolean; | ||||||
| @ -154,9 +157,21 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { | |||||||
|      */ |      */ | ||||||
|     async ngOnChanges(changes: {[name: string]: SimpleChange }): Promise<void> { |     async ngOnChanges(changes: {[name: string]: SimpleChange }): Promise<void> { | ||||||
|         if (changes.src) { |         if (changes.src) { | ||||||
|             const url = CoreUrlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue; |             let url = CoreUrlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue; | ||||||
|             this.displayHelp = CoreIframeUtils.shouldDisplayHelpForUrl(url); |             this.displayHelp = CoreIframeUtils.shouldDisplayHelpForUrl(url); | ||||||
| 
 | 
 | ||||||
|  |             const currentSite = CoreSites.getCurrentSite(); | ||||||
|  |             if (this.allowAutoLogin && currentSite) { | ||||||
|  |                 // Format the URL to add auto-login if needed.
 | ||||||
|  |                 url = await currentSite.getAutoLoginUrl(url, false); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (currentSite?.isVersionGreaterEqualThan('3.7') && CoreUrl.isVimeoVideoUrl(url)) { | ||||||
|  |                 // Only treat the Vimeo URL if site is 3.7 or bigger. In older sites the width and height params were mandatory,
 | ||||||
|  |                 // and there was no easy way to make the iframe responsive.
 | ||||||
|  |                 url = CoreUrl.getVimeoPlayerUrl(url, currentSite) ?? url; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             await CoreIframeUtils.fixIframeCookies(url); |             await CoreIframeUtils.fixIframeCookies(url); | ||||||
| 
 | 
 | ||||||
|             this.safeUrl = DomSanitizer.bypassSecurityTrustResourceUrl(CoreFile.convertFileSrc(url)); |             this.safeUrl = DomSanitizer.bypassSecurityTrustResourceUrl(CoreFile.convertFileSrc(url)); | ||||||
|  | |||||||
| @ -46,7 +46,6 @@ import { CoreDirectivesRegistry } from '@singletons/directives-registry'; | |||||||
| import { CoreCollapsibleItemDirective } from './collapsible-item'; | import { CoreCollapsibleItemDirective } from './collapsible-item'; | ||||||
| import { CoreCancellablePromise } from '@classes/cancellable-promise'; | import { CoreCancellablePromise } from '@classes/cancellable-promise'; | ||||||
| import { AsyncDirective } from '@classes/async-directive'; | import { AsyncDirective } from '@classes/async-directive'; | ||||||
| import { CorePath } from '@singletons/path'; |  | ||||||
| import { CoreDom } from '@singletons/dom'; | import { CoreDom } from '@singletons/dom'; | ||||||
| import { CoreEvents } from '@singletons/events'; | import { CoreEvents } from '@singletons/events'; | ||||||
| import { CoreRefreshContext, CORE_REFRESH_CONTEXT } from '@/core/utils/refresh-context'; | import { CoreRefreshContext, CORE_REFRESH_CONTEXT } from '@/core/utils/refresh-context'; | ||||||
| @ -54,6 +53,7 @@ import { CorePlatform } from '@services/platform'; | |||||||
| import { ElementController } from '@classes/element-controllers/ElementController'; | import { ElementController } from '@classes/element-controllers/ElementController'; | ||||||
| import { MediaElementController } from '@classes/element-controllers/MediaElementController'; | import { MediaElementController } from '@classes/element-controllers/MediaElementController'; | ||||||
| import { FrameElementController } from '@classes/element-controllers/FrameElementController'; | import { FrameElementController } from '@classes/element-controllers/FrameElementController'; | ||||||
|  | import { CoreUrl } from '@singletons/url'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective |  * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective | ||||||
| @ -802,23 +802,8 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec | |||||||
|         await CoreIframeUtils.fixIframeCookies(src); |         await CoreIframeUtils.fixIframeCookies(src); | ||||||
| 
 | 
 | ||||||
|         if (site && src) { |         if (site && src) { | ||||||
|             // Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work.
 |             let vimeoUrl = CoreUrl.getVimeoPlayerUrl(src, site); | ||||||
|             const matches = src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)([?&]+h=([a-zA-Z0-9]*))?/); |             if (vimeoUrl) { | ||||||
|             if (matches && matches[1]) { |  | ||||||
|                 let newUrl = CorePath.concatenatePaths(site.getURL(), '/media/player/vimeo/wsplayer.php?video=') + |  | ||||||
|                     matches[1] + '&token=' + site.getToken(); |  | ||||||
| 
 |  | ||||||
|                 let privacyHash: string | undefined | null = matches[3]; |  | ||||||
|                 if (!privacyHash) { |  | ||||||
|                     // No privacy hash using the new format. Check the legacy format.
 |  | ||||||
|                     const matches = src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)(\/([a-zA-Z0-9]+))?/); |  | ||||||
|                     privacyHash = matches && matches[3]; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 if (privacyHash) { |  | ||||||
|                     newUrl += `&h=${privacyHash}`; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 const domPromise = CoreDom.waitToBeInDOM(iframe); |                 const domPromise = CoreDom.waitToBeInDOM(iframe); | ||||||
|                 this.domPromises.push(domPromise); |                 this.domPromises.push(domPromise); | ||||||
| 
 | 
 | ||||||
| @ -848,12 +833,12 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec | |||||||
| 
 | 
 | ||||||
|                 // Width and height parameters are required in 3.6 and older sites.
 |                 // Width and height parameters are required in 3.6 and older sites.
 | ||||||
|                 if (site && !site.isVersionGreaterEqualThan('3.7')) { |                 if (site && !site.isVersionGreaterEqualThan('3.7')) { | ||||||
|                     newUrl += '&width=' + width + '&height=' + height; |                     vimeoUrl += '&width=' + width + '&height=' + height; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 await CoreIframeUtils.fixIframeCookies(newUrl); |                 await CoreIframeUtils.fixIframeCookies(vimeoUrl); | ||||||
| 
 | 
 | ||||||
|                 iframe.src = newUrl; |                 iframe.src = vimeoUrl; | ||||||
| 
 | 
 | ||||||
|                 if (!iframe.width) { |                 if (!iframe.width) { | ||||||
|                     iframe.width = String(width); |                     iframe.width = String(width); | ||||||
|  | |||||||
| @ -131,11 +131,8 @@ export class CoreH5PIframeComponent implements OnChanges, OnDestroy { | |||||||
|                     CoreH5PCore.DISPLAY_OPTION_DOWNLOAD + '=0', |                     CoreH5PCore.DISPLAY_OPTION_DOWNLOAD + '=0', | ||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 // Get auto-login URL so the user is automatically authenticated if needed.
 |  | ||||||
|                 const url = await this.site.getAutoLoginUrl(src, false); |  | ||||||
| 
 |  | ||||||
|                 // Add the preventredirect param so the user can authenticate.
 |                 // Add the preventredirect param so the user can authenticate.
 | ||||||
|                 this.iframeSrc = CoreUrlUtils.addParamsToUrl(url, { preventredirect: false }); |                 this.iframeSrc = CoreUrlUtils.addParamsToUrl(src, { preventredirect: false }); | ||||||
|             } |             } | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             CoreDomUtils.showErrorModalDefault(error, 'Error loading H5P package.', true); |             CoreDomUtils.showErrorModalDefault(error, 'Error loading H5P package.', true); | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ | |||||||
|     </ion-toolbar> |     </ion-toolbar> | ||||||
| </ion-header> | </ion-header> | ||||||
| <ion-content> | <ion-content> | ||||||
|     <core-loading [hideUntil]="finalUrl"> |     <core-loading [hideUntil]="url"> | ||||||
|         <core-iframe *ngIf="finalUrl" [src]="finalUrl"></core-iframe> |         <core-iframe *ngIf="url" [src]="url" [allowAutoLogin]="autoLogin"></core-iframe> | ||||||
|     </core-loading> |     </core-loading> | ||||||
| </ion-content> | </ion-content> | ||||||
|  | |||||||
| @ -15,8 +15,6 @@ | |||||||
| import { Component, OnInit } from '@angular/core'; | import { Component, OnInit } from '@angular/core'; | ||||||
| import { CoreNavigator } from '@services/navigator'; | import { CoreNavigator } from '@services/navigator'; | ||||||
| 
 | 
 | ||||||
| import { CoreSites } from '@services/sites'; |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Page to display a URL in an iframe. |  * Page to display a URL in an iframe. | ||||||
|  */ |  */ | ||||||
| @ -29,7 +27,6 @@ export class CoreViewerIframePage implements OnInit { | |||||||
|     title?: string; // Page title.
 |     title?: string; // Page title.
 | ||||||
|     url?: string; // Iframe URL.
 |     url?: string; // Iframe URL.
 | ||||||
|     autoLogin?: boolean; // Whether to try to use auto-login.
 |     autoLogin?: boolean; // Whether to try to use auto-login.
 | ||||||
|     finalUrl?: string; |  | ||||||
| 
 | 
 | ||||||
|     async ngOnInit(): Promise<void> { |     async ngOnInit(): Promise<void> { | ||||||
|         this.title = CoreNavigator.getRouteParam('title'); |         this.title = CoreNavigator.getRouteParam('title'); | ||||||
| @ -38,19 +35,6 @@ export class CoreViewerIframePage implements OnInit { | |||||||
|         this.autoLogin = typeof autoLoginParam === 'boolean' ? |         this.autoLogin = typeof autoLoginParam === 'boolean' ? | ||||||
|             autoLoginParam : |             autoLoginParam : | ||||||
|             autoLoginParam !== 'no'; // Support deprecated values yes/no/check.
 |             autoLoginParam !== 'no'; // Support deprecated values yes/no/check.
 | ||||||
| 
 |  | ||||||
|         if (!this.url) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         const currentSite = CoreSites.getCurrentSite(); |  | ||||||
| 
 |  | ||||||
|         if (currentSite && this.autoLogin) { |  | ||||||
|             // Format the URL to add auto-login.
 |  | ||||||
|             this.finalUrl = await currentSite.getAutoLoginUrl(this.url, false); |  | ||||||
|         } else { |  | ||||||
|             this.finalUrl = this.url; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -231,6 +231,12 @@ export class CoreIframeUtilsProvider { | |||||||
|      * @returns Window and Document. |      * @returns Window and Document. | ||||||
|      */ |      */ | ||||||
|     getContentWindowAndDocument(element: CoreFrameElement): { window: Window | null; document: Document | null } { |     getContentWindowAndDocument(element: CoreFrameElement): { window: Window | null; document: Document | null } { | ||||||
|  |         const src = 'src' in element ? element.src : element.data; | ||||||
|  |         if (!CoreUrlUtils.isLocalFileUrl(src)) { | ||||||
|  |             // No permissions to access the iframe.
 | ||||||
|  |             return { window: null, document: null }; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         let contentWindow: Window | null = 'contentWindow' in element ? element.contentWindow : null; |         let contentWindow: Window | null = 'contentWindow' in element ? element.contentWindow : null; | ||||||
|         let contentDocument: Document | null = null; |         let contentDocument: Document | null = null; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -270,10 +270,10 @@ export class CoreUrlUtilsProvider { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Returns the Youtube Embed Video URL or null if not found. |      * Returns the Youtube Embed Video URL or undefined if not found. | ||||||
|      * |      * | ||||||
|      * @param url URL |      * @param url URL | ||||||
|      * @returns Youtube Embed Video URL or null if not found. |      * @returns Youtube Embed Video URL or undefined if not found. | ||||||
|      */ |      */ | ||||||
|     getYoutubeEmbedUrl(url?: string): string | void { |     getYoutubeEmbedUrl(url?: string): string | void { | ||||||
|         if (!url) { |         if (!url) { | ||||||
|  | |||||||
| @ -12,6 +12,8 @@ | |||||||
| // See the License for the specific language governing permissions and
 | // See the License for the specific language governing permissions and
 | ||||||
| // limitations under the License.
 | // limitations under the License.
 | ||||||
| 
 | 
 | ||||||
|  | import { mock } from '@/testing/utils'; | ||||||
|  | import { CoreSite } from '@classes/site'; | ||||||
| import { CoreUrl } from '@singletons/url'; | import { CoreUrl } from '@singletons/url'; | ||||||
| 
 | 
 | ||||||
| describe('CoreUrl singleton', () => { | describe('CoreUrl singleton', () => { | ||||||
| @ -128,4 +130,32 @@ describe('CoreUrl singleton', () => { | |||||||
|         expect(CoreUrl.toRelativeURL('https://school.edu', 'school.edu/image.png')).toBe('image.png'); |         expect(CoreUrl.toRelativeURL('https://school.edu', 'school.edu/image.png')).toBe('image.png'); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |     it('checks if it is a Vimeo video URL', () => { | ||||||
|  |         expect(CoreUrl.isVimeoVideoUrl('')).toEqual(false); | ||||||
|  |         expect(CoreUrl.isVimeoVideoUrl('https://player.vimeo.com')).toEqual(false); | ||||||
|  |         expect(CoreUrl.isVimeoVideoUrl('https://player.vimeo.com/video/')).toEqual(false); | ||||||
|  |         expect(CoreUrl.isVimeoVideoUrl('player.vimeo.com/video/123456')).toEqual(false); | ||||||
|  |         expect(CoreUrl.isVimeoVideoUrl('https://player.vimeo.com/video/123456')).toEqual(true); | ||||||
|  |         expect(CoreUrl.isVimeoVideoUrl('http://player.vimeo.com/video/123456')).toEqual(true); | ||||||
|  |         expect(CoreUrl.isVimeoVideoUrl('https://player.vimeo.com/video/123456/654321?foo=bar')).toEqual(true); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     it('gets the Vimeo player URL', () => { | ||||||
|  |         const siteUrl = 'https://mysite.com'; | ||||||
|  |         const token = 'mytoken'; | ||||||
|  |         const site = mock(new CoreSite('42', siteUrl, token)); | ||||||
|  | 
 | ||||||
|  |         // Test basic usage.
 | ||||||
|  |         expect(CoreUrl.getVimeoPlayerUrl('', site)).toEqual(undefined); | ||||||
|  |         expect(CoreUrl.getVimeoPlayerUrl('https://somesite.com', site)).toEqual(undefined); | ||||||
|  |         expect(CoreUrl.getVimeoPlayerUrl('https://player.vimeo.com/video/123456', site)) | ||||||
|  |             .toEqual(`${siteUrl}/media/player/vimeo/wsplayer.php?video=123456&token=${token}`); | ||||||
|  | 
 | ||||||
|  |         // Test privacy hash.
 | ||||||
|  |         expect(CoreUrl.getVimeoPlayerUrl('https://player.vimeo.com/video/123456?h=foo', site)) | ||||||
|  |             .toEqual(`${siteUrl}/media/player/vimeo/wsplayer.php?video=123456&token=${token}&h=foo`); | ||||||
|  |         expect(CoreUrl.getVimeoPlayerUrl('https://player.vimeo.com/video/123456/foo', site)) | ||||||
|  |             .toEqual(`${siteUrl}/media/player/vimeo/wsplayer.php?video=123456&token=${token}&h=foo`); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ | |||||||
| // See the License for the specific language governing permissions and
 | // See the License for the specific language governing permissions and
 | ||||||
| // limitations under the License.
 | // limitations under the License.
 | ||||||
| 
 | 
 | ||||||
|  | import { CoreSite } from '@classes/site'; | ||||||
| import { CorePath } from './path'; | import { CorePath } from './path'; | ||||||
| import { CoreText } from './text'; | import { CoreText } from './text'; | ||||||
| 
 | 
 | ||||||
| @ -298,4 +299,49 @@ export class CoreUrl { | |||||||
|         return CoreText.removeStartingSlash(CoreUrl.removeProtocol(url).replace(parentUrl, '')); |         return CoreText.removeStartingSlash(CoreUrl.removeProtocol(url).replace(parentUrl, '')); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Returns if URL is a Vimeo video URL. | ||||||
|  |      * | ||||||
|  |      * @param url URL. | ||||||
|  |      * @returns Whether is a Vimeo video URL. | ||||||
|  |      */ | ||||||
|  |     static isVimeoVideoUrl(url: string): boolean { | ||||||
|  |         return !!url.match(/https?:\/\/player\.vimeo\.com\/video\/[0-9]+/); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get the URL to use to play a Vimeo video if the URL supplied is a Vimeo video URL. | ||||||
|  |      * If it's a Vimeo video, the app will use the site's wsplayer script instead to make restricted videos work. | ||||||
|  |      * | ||||||
|  |      * @param url URL to treat. | ||||||
|  |      * @param site Site that contains the URL. | ||||||
|  |      * @returns URL, undefined if not a Vimeo video. | ||||||
|  |      */ | ||||||
|  |     static getVimeoPlayerUrl( | ||||||
|  |         url: string, | ||||||
|  |         site: CoreSite, | ||||||
|  |     ): string | undefined { | ||||||
|  |         const matches = url.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)([?&]+h=([a-zA-Z0-9]*))?/); | ||||||
|  |         if (!matches || !matches[1]) { | ||||||
|  |             // Not a Vimeo video.
 | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let newUrl = CorePath.concatenatePaths(site.getURL(), '/media/player/vimeo/wsplayer.php?video=') + | ||||||
|  |             matches[1] + '&token=' + site.getToken(); | ||||||
|  | 
 | ||||||
|  |         let privacyHash: string | undefined | null = matches[3]; | ||||||
|  |         if (!privacyHash) { | ||||||
|  |             // No privacy hash using the new format. Check the legacy format.
 | ||||||
|  |             const matches = url.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)(\/([a-zA-Z0-9]+))?/); | ||||||
|  |             privacyHash = matches && matches[3]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (privacyHash) { | ||||||
|  |             newUrl += `&h=${privacyHash}`; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return newUrl; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user