From ca76366bac95277d99e0289858be123375c0f2e4 Mon Sep 17 00:00:00 2001 From: Julien Banken Date: Fri, 26 Jan 2024 13:05:44 +0000 Subject: [PATCH] [FIX] web_editor: enable embedding unlisted vimeo videos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the user inserts a video with the `/video` command and provides a link of an unlisted vimeo video, the system generates a new url based on the options selected but omits the hash parameter granting access to the given video. As a result, the video can not be loaded and the vimeo `iframe` indicates that the video does not exist. To fix the issue, we will copy the hash parameter from the original link to the newly generated url. That way, the video will be loaded properly and the user will be able to embed unlisted vimeo videos. Steps to reproduce the issue: 1. Install the website app 2. Open the website builder 3. Drag and drop a text block 4. In the text block, type the `/video` command to insert a video 5. In the modal, paste the link of an unlisted video 6. The `iframe` indicates that the video does not exist => The system should extract the hash parameter from the provided url and set it on the generated url. The video should then be loaded properly. task-3697764 closes odoo/odoo#157279 X-original-commit: f72b873e58348374f3ce0e91ec5e87ed42215e55 Signed-off-by: Warnon Aurélien (awa) Signed-off-by: Thibault Delavallee (tde) --- addons/web_editor/tests/test_tools.py | 35 +++++++++++++++++++++++++-- addons/web_editor/tools.py | 17 ++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/addons/web_editor/tests/test_tools.py b/addons/web_editor/tests/test_tools.py index 9c95883cfde..f05703a0902 100644 --- a/addons/web_editor/tests/test_tools.py +++ b/addons/web_editor/tests/test_tools.py @@ -12,6 +12,9 @@ class TestVideoUtils(common.BaseCase): urls = { 'youtube': 'https://www.youtube.com/watch?v=xCvFZrrQq7k', 'vimeo': 'https://vimeo.com/395399735', + 'vimeo_unlisted_video': 'https://vimeo.com/795669787/0763fdb816', + 'vimeo_player': 'https://player.vimeo.com/video/395399735', + 'vimeo_player_unlisted_video': 'https://player.vimeo.com/video/795669787?h=0763fdb816', 'dailymotion': 'https://www.dailymotion.com/video/x7svr6t', 'youku': 'https://v.youku.com/v_show/id_XMzY1MjY4.html?spm=a2hzp.8244740.0.0', 'instagram': 'https://www.instagram.com/p/B6dXGTxggTG/', @@ -29,6 +32,9 @@ class TestVideoUtils(common.BaseCase): self.assertIsNotNone(re.search(tools.player_regexes['youtube'], TestVideoUtils.urls['youtube'])) #vimeo self.assertIsNotNone(re.search(tools.player_regexes['vimeo'], TestVideoUtils.urls['vimeo'])) + self.assertIsNotNone(re.search(tools.player_regexes['vimeo'], TestVideoUtils.urls['vimeo_unlisted_video'])) + self.assertIsNotNone(re.search(tools.player_regexes['vimeo_player'], TestVideoUtils.urls['vimeo_player'])) + self.assertIsNotNone(re.search(tools.player_regexes['vimeo_player'], TestVideoUtils.urls['vimeo_player_unlisted_video'])) #dailymotion self.assertIsNotNone(re.search(tools.player_regexes['dailymotion'], TestVideoUtils.urls['dailymotion'])) #youku @@ -44,6 +50,12 @@ class TestVideoUtils(common.BaseCase): #vimeo self.assertEqual('vimeo', tools.get_video_source_data(TestVideoUtils.urls['vimeo'])[0]) self.assertEqual('395399735', tools.get_video_source_data(TestVideoUtils.urls['vimeo'])[1]) + self.assertEqual('vimeo', tools.get_video_source_data(TestVideoUtils.urls['vimeo_unlisted_video'])[0]) + self.assertEqual('795669787', tools.get_video_source_data(TestVideoUtils.urls['vimeo_unlisted_video'])[1]) + self.assertEqual('vimeo', tools.get_video_source_data(TestVideoUtils.urls['vimeo_player'])[0]) + self.assertEqual('395399735', tools.get_video_source_data(TestVideoUtils.urls['vimeo_player'])[1]) + self.assertEqual('vimeo', tools.get_video_source_data(TestVideoUtils.urls['vimeo_player_unlisted_video'])[0]) + self.assertEqual('795669787', tools.get_video_source_data(TestVideoUtils.urls['vimeo_player_unlisted_video'])[1]) #dailymotion self.assertEqual('dailymotion', tools.get_video_source_data(TestVideoUtils.urls['dailymotion'])[0]) self.assertEqual('x7svr6t', tools.get_video_source_data(TestVideoUtils.urls['dailymotion'])[1]) @@ -72,7 +84,25 @@ class TestVideoUtils(common.BaseCase): #youtube self.assertEqual('youtube', tools.get_video_url_data(TestVideoUtils.urls['youtube'])['platform']) #vimeo - self.assertEqual('vimeo', tools.get_video_url_data(TestVideoUtils.urls['vimeo'])['platform']) + for key in ['vimeo', 'vimeo_player']: + self.assertEqual(tools.get_video_url_data(TestVideoUtils.urls[key]), { + 'platform': 'vimeo', + 'embed_url': '//player.vimeo.com/video/395399735?autoplay=0', + 'video_id': '395399735', + 'params': { + 'autoplay': 0 + } + }) + for key in ['vimeo_unlisted_video', 'vimeo_player_unlisted_video']: + self.assertEqual(tools.get_video_url_data(TestVideoUtils.urls[key]), { + 'platform': 'vimeo', + 'embed_url': '//player.vimeo.com/video/795669787?autoplay=0&h=0763fdb816', + 'video_id': '795669787', + 'params': { + 'autoplay': 0, + 'h': '0763fdb816' + } + }) #dailymotion self.assertEqual('dailymotion', tools.get_video_url_data(TestVideoUtils.urls['dailymotion'])['platform']) #youku @@ -90,7 +120,8 @@ class TestVideoUtilsExternal(common.BaseCase): #youtube self.assertIsInstance(tools.get_video_thumbnail(TestVideoUtils.urls['youtube']), bytes) #vimeo - self.assertIsInstance(tools.get_video_thumbnail(TestVideoUtils.urls['vimeo']), bytes) + for key in ['vimeo', 'vimeo_unlisted_video', 'vimeo_player', 'vimeo_player_unlisted_video']: + self.assertIsInstance(tools.get_video_thumbnail(TestVideoUtils.urls[key]), bytes) #dailymotion self.assertIsInstance(tools.get_video_thumbnail(TestVideoUtils.urls['dailymotion']), bytes) #instagram diff --git a/addons/web_editor/tools.py b/addons/web_editor/tools.py index 7a0970fbffe..be5a25d6b8b 100644 --- a/addons/web_editor/tools.py +++ b/addons/web_editor/tools.py @@ -8,6 +8,7 @@ import re import requests from markupsafe import Markup +from urllib.parse import parse_qs from werkzeug.urls import url_encode from odoo import _ @@ -23,7 +24,8 @@ valid_url_regex = r'^(http://|https://|//)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{ # Regex for few of the widely used video hosting services player_regexes = { 'youtube': r'^(?:(?:https?:)?//)?(?:www\.)?(?:youtu\.be/|youtube(-nocookie)?\.com/(?:embed/|v/|watch\?v=|watch\?.+&v=))((?:\w|-){11})\S*$', - 'vimeo': r'//(player.)?vimeo.com/([a-z]*/)*([0-9]{6,11})[?]?.*', + 'vimeo': r'^(?:(?:https?:)?//)?(?:www\.)?vimeo\.com\/(?P[^/\?]+)(?:/(?P[^/\?]+))?(?:\?(?P[^\s]+))?$', + 'vimeo_player': r'^(?:(?:https?:)?//)?player\.vimeo\.com\/video\/(?P[^/\?]+)(?:\?(?P[^\s]+))?$', 'dailymotion': r'(https?:\/\/)(www\.)?(dailymotion\.com\/(embed\/video\/|embed\/|video\/|hub\/.*#video=)|dai\.ly\/)(?P[A-Za-z0-9]{6,7})', 'instagram': r'(?:(.*)instagram.com|instagr\.am)/p/(.[a-zA-Z0-9-_\.]*)', 'youku': r'(?:(https?:\/\/)?(v\.youku\.com/v_show/id_|player\.youku\.com/player\.php/sid/|player\.youku\.com/embed/|cloud\.youku\.com/services/sharev\?vid=|video\.tudou\.com/v/)|youku:)(?P[A-Za-z0-9]+)(?:\.html|/v\.swf|)', @@ -41,9 +43,11 @@ def get_video_source_data(video_url): youtube_match = re.search(player_regexes['youtube'], video_url) if youtube_match: return ('youtube', youtube_match[2], youtube_match) - vimeo_match = re.search(player_regexes['vimeo'], video_url) + vimeo_match = ( + re.search(player_regexes['vimeo'], video_url) or + re.search(player_regexes['vimeo_player'], video_url)) if vimeo_match: - return ('vimeo', vimeo_match[3], vimeo_match) + return ('vimeo', vimeo_match.group('id'), vimeo_match) dailymotion_match = re.search(player_regexes['dailymotion'], video_url) if dailymotion_match: return ('dailymotion', dailymotion_match.group("id"), dailymotion_match) @@ -100,6 +104,13 @@ def get_video_url_data(video_url, autoplay=False, loop=False, hide_controls=Fals params['controls'] = 0 if loop: params['loop'] = 1 + groups = platform_match.groupdict() + if groups.get('hash'): + params['h'] = groups['hash'] + elif groups.get('params'): + url_params = parse_qs(groups['params']) + if 'h' in url_params: + params['h'] = url_params['h'][0] embed_url = f'//player.vimeo.com/video/{video_id}' elif platform == 'dailymotion': params['autoplay'] = autoplay and 1 or 0