From d54a480dbc9305f5f63aa9b620247e231c380de0 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 21 Sep 2026 15:41:49 +0700 Subject: [PATCH 1/4] Render YouTube Shorts vertically. --- event/formatter_listener.php | 52 ++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/event/formatter_listener.php b/event/formatter_listener.php index eb0c210..1da341d 100644 --- a/event/formatter_listener.php +++ b/event/formatter_listener.php @@ -127,6 +127,8 @@ public function modify_tag_templates($event) { $tag->template = str_replace(' allowfullscreen', ' referrerpolicy="origin" allowfullscreen', $tag->template); } + + $tag->template = $this->configure_youtube_shorts($tag); } catch (\RuntimeException $e) { @@ -159,4 +161,54 @@ protected function get_site_ids() return $site_ids ? json_decode($site_ids, true) : []; } + + /** + * Add tag filter to mark YouTube Shorts URLs. + * + * @param s9e\TextFormatter\Configurator\Items\Tag $tag Tag to add the filter to + * @param string $text Media URL src content + * + * @return void + */ + public static function filter_youtube_shorts($tag, $text) + { + if (strpos($text, '/shorts/') !== false) + { + $tag->setAttribute('is_shorts', '1'); + } + } + + /** + * Modify YouTube tag template to vertically render YouTube Shorts + * + * @param s9e\TextFormatter\Configurator\Items\Tag $tag Tag to configure + * + * @return string + */ + public function configure_youtube_shorts($tag) + { + // Add 'is_shorts' tag attribute if does not exist + if (!isset($tag->attributes['is_shorts'])) + { + $tag->attributes->add('is_shorts')->required = false; + } + + // Add filterchain to filter URLs using 'is_shorts' attribute + $tag->filterChain + ->prepend([__CLASS__, 'filter_youtube_shorts']) + ->addParameterByName('text'); + + // Modify template string to inject YouTube Shorts rendering attributes + $modified_template = str_replace( + ['max-width:640px', 'padding-bottom:56.25%'], + ['max-width:360px', 'padding-bottom:177.77%'], + (string) $tag->template + ); + + return + '' . + '' . $modified_template . '' . + '' . (string) $tag->template . '' . + ''; + } } From 882c110aa9ec8685f3ad31c90b2478ba75ecfd1d Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 21 Sep 2026 16:05:06 +0700 Subject: [PATCH 2/4] Add test. --- tests/functional/media_embed_test.php | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/functional/media_embed_test.php b/tests/functional/media_embed_test.php index 4c95c92..1c84b96 100644 --- a/tests/functional/media_embed_test.php +++ b/tests/functional/media_embed_test.php @@ -18,6 +18,7 @@ class media_embed_test extends \phpbb_functional_test_case { protected $youtubeId = 'PHzShhtkzEk'; + protected $youtubeShortsId = 'xer3HqUWLkw'; protected $ok_ru_Id = '549000643961'; protected static function setup_extensions() @@ -36,7 +37,7 @@ public function test_posting_media_bbcode() $post = $this->create_topic($forum_id, 'Media Embed Test Topic 1', "[media]https://youtu.be/$this->youtubeId[/media]"); $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid=$this->sid"); - self::assertStringContainsString("//www.youtube-nocookie.com/embed/$this->youtubeId", $crawler->filter("#post_content{$post['topic_id']} iframe")->attr('src')); + self::assertStringContainsString("//www.youtube-nocookie.com/embed/$this->youtubeId", $crawler->filter("#post_content{$post['post_id']} iframe")->attr('src')); } public function test_posting_custom_site() @@ -50,7 +51,19 @@ public function test_posting_custom_site() $post = $this->create_topic(2, 'Media Embed Custom Site Test Topic 1', "[media]https://ok.ru/video/$this->ok_ru_Id[/media]"); $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid=$this->sid"); - self::assertStringContainsString("//ok.ru/videoembed/$this->ok_ru_Id", $crawler->filter("#post_content{$post['topic_id']} iframe")->attr('src')); + self::assertStringContainsString("//ok.ru/videoembed/$this->ok_ru_Id", $crawler->filter("#post_content{$post['post_id']} iframe")->attr('src')); + } + + public function test_youtube_shorts_template() + { + $this->login(); + + $forum_id = 2; + + $post = $this->create_topic($forum_id, 'YouTube Shorts vertical rendering test', "https://youtube.com/shorts/$this->youtubeShortsId"); + $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid=$this->sid"); + self::assertStringContainsString("max-width:360px", $crawler->filter('#post_content' . $post['post_id'] . ' span[data-s9e-mediaembed="youtube"]')->attr('style')); + self::assertStringContainsString("padding-bottom:177.77%", $crawler->filter('#post_content' . $post['post_id'] . ' span[data-s9e-mediaembed="youtube"] > span')->attr('style')); } public function signatures_data() From 389fb372de4aae93d4a03f408addd905d636260c Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Mon, 21 Sep 2026 07:51:23 -0700 Subject: [PATCH 3/4] fix: scope Shorts layout per embed Read retained URL from YOUTUBE node in XSL so mixed posts keep regular videos landscape and existing parsed content renders correctly. --- event/formatter_listener.php | 31 ++------------------------- tests/event/listener_test.php | 3 +++ tests/functional/media_embed_test.php | 17 ++++++++++++--- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/event/formatter_listener.php b/event/formatter_listener.php index 1da341d..8766e79 100644 --- a/event/formatter_listener.php +++ b/event/formatter_listener.php @@ -162,22 +162,6 @@ protected function get_site_ids() return $site_ids ? json_decode($site_ids, true) : []; } - /** - * Add tag filter to mark YouTube Shorts URLs. - * - * @param s9e\TextFormatter\Configurator\Items\Tag $tag Tag to add the filter to - * @param string $text Media URL src content - * - * @return void - */ - public static function filter_youtube_shorts($tag, $text) - { - if (strpos($text, '/shorts/') !== false) - { - $tag->setAttribute('is_shorts', '1'); - } - } - /** * Modify YouTube tag template to vertically render YouTube Shorts * @@ -187,27 +171,16 @@ public static function filter_youtube_shorts($tag, $text) */ public function configure_youtube_shorts($tag) { - // Add 'is_shorts' tag attribute if does not exist - if (!isset($tag->attributes['is_shorts'])) - { - $tag->attributes->add('is_shorts')->required = false; - } - - // Add filterchain to filter URLs using 'is_shorts' attribute - $tag->filterChain - ->prepend([__CLASS__, 'filter_youtube_shorts']) - ->addParameterByName('text'); - // Modify template string to inject YouTube Shorts rendering attributes $modified_template = str_replace( ['max-width:640px', 'padding-bottom:56.25%'], - ['max-width:360px', 'padding-bottom:177.77%'], + ['max-width:360px', 'padding-bottom:177.777778%'], (string) $tag->template ); return '' . - '' . $modified_template . '' . + '' . $modified_template . '' . '' . (string) $tag->template . '' . ''; } diff --git a/tests/event/listener_test.php b/tests/event/listener_test.php index 6cca606..871145e 100644 --- a/tests/event/listener_test.php +++ b/tests/event/listener_test.php @@ -185,6 +185,9 @@ public function test_youtube_template_uses_phpbb3_compatibility_fixes() $template = $configurator->tags['YOUTUBE']->template; $this->assertStringContainsString('www.youtube-nocookie.com', $template); $this->assertStringContainsString('referrerpolicy="origin"', $template); + $this->assertStringContainsString('contains(., \'/shorts/\')', $template); + $this->assertStringContainsString('max-width:360px', $template); + $this->assertStringContainsString('padding-bottom:177.777778%', $template); } public function test_upstream_collection_is_skipped_on_phpbb4() diff --git a/tests/functional/media_embed_test.php b/tests/functional/media_embed_test.php index 1c84b96..47c5690 100644 --- a/tests/functional/media_embed_test.php +++ b/tests/functional/media_embed_test.php @@ -60,10 +60,21 @@ public function test_youtube_shorts_template() $forum_id = 2; - $post = $this->create_topic($forum_id, 'YouTube Shorts vertical rendering test', "https://youtube.com/shorts/$this->youtubeShortsId"); + $post = $this->create_topic( + $forum_id, + 'YouTube Shorts vertical rendering test', + "https://youtube.com/shorts/$this->youtubeShortsId\nhttps://youtu.be/$this->youtubeId" + ); $crawler = self::request('GET', "viewtopic.php?t={$post['topic_id']}&sid=$this->sid"); - self::assertStringContainsString("max-width:360px", $crawler->filter('#post_content' . $post['post_id'] . ' span[data-s9e-mediaembed="youtube"]')->attr('style')); - self::assertStringContainsString("padding-bottom:177.77%", $crawler->filter('#post_content' . $post['post_id'] . ' span[data-s9e-mediaembed="youtube"] > span')->attr('style')); + $selector = '#post_content' . $post['post_id'] . ' span[data-s9e-mediaembed="youtube"]'; + $embeds = $crawler->filter($selector); + $wrappers = $crawler->filter($selector . ' > span'); + self::assertCount(2, $embeds); + self::assertCount(2, $wrappers); + self::assertStringContainsString('max-width:360px', $embeds->eq(0)->attr('style')); + self::assertStringContainsString('padding-bottom:177.777778%', $wrappers->eq(0)->attr('style')); + self::assertStringContainsString('max-width:640px', $embeds->eq(1)->attr('style')); + self::assertStringContainsString('padding-bottom:56.25%', $wrappers->eq(1)->attr('style')); } public function signatures_data() From d72ec52e37314548c8c49103fffd582ddd4764a9 Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Mon, 21 Sep 2026 07:55:23 -0700 Subject: [PATCH 4/4] refactor: centralize YouTube configuration --- event/formatter_listener.php | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/event/formatter_listener.php b/event/formatter_listener.php index 8766e79..89a18bf 100644 --- a/event/formatter_listener.php +++ b/event/formatter_listener.php @@ -121,14 +121,7 @@ public function modify_tag_templates($event) { try { - $tag = $event['configurator']->tags['YOUTUBE']; - $tag->template = str_replace('www.youtube.com', 'www.youtube-nocookie.com', $tag->template); - if (!$this->sites->is_phpbb4()) - { - $tag->template = str_replace(' allowfullscreen', ' referrerpolicy="origin" allowfullscreen', $tag->template); - } - - $tag->template = $this->configure_youtube_shorts($tag); + $this->configure_youtube($event['configurator']->tags['YOUTUBE']); } catch (\RuntimeException $e) { @@ -163,25 +156,29 @@ protected function get_site_ids() } /** - * Modify YouTube tag template to vertically render YouTube Shorts + * Apply YouTube privacy, compatibility, and Shorts rendering changes. * * @param s9e\TextFormatter\Configurator\Items\Tag $tag Tag to configure - * - * @return string + * @return void */ - public function configure_youtube_shorts($tag) + public function configure_youtube($tag) { - // Modify template string to inject YouTube Shorts rendering attributes - $modified_template = str_replace( + $template = str_replace('www.youtube.com', 'www.youtube-nocookie.com', (string) $tag->template); + if (!$this->sites->is_phpbb4()) + { + $template = str_replace(' allowfullscreen', ' referrerpolicy="origin" allowfullscreen', $template); + } + + $shorts_template = str_replace( ['max-width:640px', 'padding-bottom:56.25%'], ['max-width:360px', 'padding-bottom:177.777778%'], - (string) $tag->template + $template ); - return + $tag->template = '' . - '' . $modified_template . '' . - '' . (string) $tag->template . '' . + '' . $shorts_template . '' . + '' . $template . '' . ''; } }