MOBILE-4303 iframe: Treat Vimeo videos in core-iframe component

main
Dani Palou 2023-04-14 12:25:42 +02:00
parent 0309e7a8c1
commit 4d6b97e326
5 changed files with 91 additions and 23 deletions

View File

@ -29,6 +29,7 @@ import { Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import { NavigationStart } from '@angular/router';
import { CoreSites } from '@services/sites';
import { CoreUrl } from '@singletons/url';
@Component({
selector: 'core-iframe',
@ -165,6 +166,12 @@ export class CoreIframeComponent implements OnChanges, OnDestroy {
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);
this.safeUrl = DomSanitizer.bypassSecurityTrustResourceUrl(CoreFile.convertFileSrc(url));

View File

@ -46,7 +46,6 @@ import { CoreDirectivesRegistry } from '@singletons/directives-registry';
import { CoreCollapsibleItemDirective } from './collapsible-item';
import { CoreCancellablePromise } from '@classes/cancellable-promise';
import { AsyncDirective } from '@classes/async-directive';
import { CorePath } from '@singletons/path';
import { CoreDom } from '@singletons/dom';
import { CoreEvents } from '@singletons/events';
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 { MediaElementController } from '@classes/element-controllers/MediaElementController';
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
@ -802,23 +802,8 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec
await CoreIframeUtils.fixIframeCookies(src);
if (site && src) {
// Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work.
const matches = src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)([?&]+h=([a-zA-Z0-9]*))?/);
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}`;
}
let vimeoUrl = CoreUrl.getVimeoPlayerUrl(src, site);
if (vimeoUrl) {
const domPromise = CoreDom.waitToBeInDOM(iframe);
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.
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) {
iframe.width = String(width);

View File

@ -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
* @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 {
if (!url) {

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { mock } from '@/testing/utils';
import { CoreSite } from '@classes/site';
import { CoreUrl } from '@singletons/url';
describe('CoreUrl singleton', () => {
@ -128,4 +130,32 @@ describe('CoreUrl singleton', () => {
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`);
});
});

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { CoreSite } from '@classes/site';
import { CorePath } from './path';
import { CoreText } from './text';
@ -298,4 +299,49 @@ export class CoreUrl {
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;
}
}