Skip to content

Add 'wide' version of YouTube embed extension #351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

georgedorn
Copy link

Got tired of the postage-stamp-sized YT embed. Expanded it to a (configurable) % of the width of the pane, and cleaned up some leftover duplication from an upstream bug (thumbnail replication, etc). Also added suggested user CSS to streamline the reader view as the feed name and title are also duplicated by default.

@Inverle
Copy link
Contributor

Inverle commented Aug 14, 2025

This is nice, but couldn't this be implemented in the main extension?
Every time changes are made in the main extension, they would also have to be made in this one.

@Inverle
Copy link
Contributor

Inverle commented Aug 14, 2025

diff against original extension
diff --git a/xExtension-YouTube/README.md b/xExtension-YouTube/README.md
index 4116e36..23c4f09 100644
--- a/xExtension-YouTube/README.md
+++ b/xExtension-YouTube/README.md
@@ -21,8 +21,36 @@ With FreshRSS and an original Youtube Channel feed:
 With activated Youtube extension:
 ![screenshot after](https://github.com/kevinpapst/freshrss-youtube/blob/screenshot-readme/after.png?raw=true "After activating the extension you can enjoy your video directly in the FreshRSS stream")
 
+## Wide Version
+
+Use this one if you'd like to fill the whole pane or much of the browser window with the video, rather than specifying a fixed size.  If you really want a large video, I suggest adding this User CSS, to prevent the duplication of info shown in the top item bar:
+
+``` css
+div.content > header {
+  display: none !important;
+}
+.flux_header {
+  font-size: 18px !important;
+}
+
+.flux .flux_header .item .title {
+  font-size: 18px !important;
+}
+
+.flux .flux_header .item .date {
+  font-size: 18px !important;
+}
+```
+
+This hides the header nested within each item, and enlarges the header that already is shown.  This is useful for non-video content, too.
+
+
 ## Changelog
 
+0.14
+- Changed the embed code to allow relative sizing.  You can simply specify a width (e.g. '100%') and it will scale via aspect-ratio.
+- Fixed a bug where embedding the video didn't replace all of the content, just the first enclosure, leaving thumbnails and channel descriptions under the video.
+
 0.12:
 - Turkish language support added
 
diff --git a/xExtension-YouTube/configure.phtml b/xExtension-YouTube/configure.phtml
index 8828fe7..f55b2ce 100644
--- a/xExtension-YouTube/configure.phtml
+++ b/xExtension-YouTube/configure.phtml
@@ -1,32 +1,32 @@
 <?php
 declare(strict_types=1);
-/** @var YouTubeExtension $this */
+/** @var YouTubeWideExtension $this */
 ?>
 <form action="<?php echo _url('extension', 'configure', 'e', urlencode($this->getName())); ?>" method="post">
 	<input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
 	<div class="form-group">
 
-		<label class="group-name" for="yt_height"><?php echo _t('ext.yt_videos.height'); ?></label>
+		<label class="group-name" for="ytw_height"><?php echo _t('ext.ytw_videos.height'); ?></label>
 		<div class="group-controls">
-			<input type="number" id="yt_height" name="yt_height" value="<?php echo $this->getHeight(); ?>" min="50" data-leave-validation="1">
+			<input type="text" id="ytw_height" name="ytw_height" value="<?php echo $this->getHeight(); ?>" min="50" data-leave-validation="1">
 		</div>
 
-		<label class="group-name" for="yt_width"><?php echo _t('ext.yt_videos.width'); ?></label>
+		<label class="group-name" for="ytw_width"><?php echo _t('ext.ytw_videos.width'); ?></label>
 		<div class="group-controls">
-			<input type="number" id="yt_width" name="yt_width" value="<?php echo $this->getWidth(); ?>" min="100" data-leave-validation="1">
+			<input type="text" id="ytw_width" name="ytw_width" value="<?php echo $this->getWidth(); ?>" min="100" data-leave-validation="1">
 		</div>
 
 		<div class="group-controls">
-			<label class="checkbox" for="yt_show_content">
-				<input type="checkbox" id="yt_show_content" name="yt_show_content" value="1" <?php echo $this->isShowContent() ? 'checked' : ''; ?>>
-				<?php echo _t('ext.yt_videos.show_content'); ?>
+			<label class="checkbox" for="ytw_show_content">
+				<input type="checkbox" id="ytw_show_content" name="ytw_show_content" value="1" <?php echo $this->isShowContent() ? 'checked' : ''; ?>>
+				<?php echo _t('ext.ytw_videos.show_content'); ?>
 			</label>
 		</div>
 
 		<div class="group-controls">
-			<label class="checkbox" for="yt_nocookie">
-				<input type="checkbox" id="yt_nocookie" name="yt_nocookie" value="1" <?php echo $this->isUseNoCookieDomain() ? 'checked' : ''; ?>>
-				<?php echo _t('ext.yt_videos.use_nocookie'); ?>
+			<label class="checkbox" for="ytw_nocookie">
+				<input type="checkbox" id="ytw_nocookie" name="ytw_nocookie" value="1" <?php echo $this->isUseNoCookieDomain() ? 'checked' : ''; ?>>
+				<?php echo _t('ext.ytw_videos.use_nocookie'); ?>
 			</label>
 		</div>
 	</div>
@@ -39,7 +39,3 @@ declare(strict_types=1);
 	</div>
 </form>
 
-<p>
-	<?php echo _t('ext.yt_videos.updates'); ?>
-	<a href="https://github.com/kevinpapst/freshrss-youtube" target="_blank">GitHub</a>.
-</p>
diff --git a/xExtension-YouTube/extension.php b/xExtension-YouTube/extension.php
index c8bec52..fd2c97b 100644
--- a/xExtension-YouTube/extension.php
+++ b/xExtension-YouTube/extension.php
@@ -1,22 +1,22 @@
 <?php
 
 /**
- * Class YouTubeExtension
+ * Class YouTubeWideExtension
  *
  * Latest version can be found at https://github.com/kevinpapst/freshrss-youtube
  *
  * @author Kevin Papst
  */
-final class YouTubeExtension extends Minz_Extension
+final class YouTubeWideExtension extends Minz_Extension
 {
 	/**
 	 * Video player width
 	 */
-	private int $width = 560;
+	private string $width = '100%';
 	/**
 	 * Video player height
 	 */
-	private int $height = 315;
+	private string $height = '';
 	/**
 	 * Whether we display the original feed content
 	 */
@@ -32,6 +32,7 @@ final class YouTubeExtension extends Minz_Extension
 	#[\Override]
 	public function init(): void
 	{
+		Minz_View::appendStyle($this->getFileUrl('style.css'));
 		$this->registerHook('entry_before_display', [$this, 'embedYouTubeVideo']);
 		$this->registerHook('check_url_before_add', [self::class, 'convertYoutubeFeedUrl']);
 		$this->registerTranslates();
@@ -63,22 +64,22 @@ final class YouTubeExtension extends Minz_Extension
 			return;
 		}
 
-		$width = FreshRSS_Context::userConf()->attributeInt('yt_player_width');
+		$width = FreshRSS_Context::userConf()->attributeString('ytw_width');
 		if ($width !== null) {
 			$this->width = $width;
 		}
 
-		$height = FreshRSS_Context::userConf()->attributeInt('yt_player_height');
+		$height = FreshRSS_Context::userConf()->attributeString('ytw_height');
 		if ($height !== null) {
 			$this->height = $height;
 		}
 
-		$showContent = FreshRSS_Context::userConf()->attributeBool('yt_show_content');
+		$showContent = FreshRSS_Context::userConf()->attributeBool('ytw_show_content');
 		if ($showContent !== null) {
 			$this->showContent = $showContent;
 		}
 
-		$noCookie = FreshRSS_Context::userConf()->attributeBool('yt_nocookie');
+		$noCookie = FreshRSS_Context::userConf()->attributeBool('ytw_nocookie');
 		if ($noCookie !== null) {
 			$this->useNoCookie = $noCookie;
 		}
@@ -88,7 +89,7 @@ final class YouTubeExtension extends Minz_Extension
 	 * Returns the width in pixel for the YouTube player iframe.
 	 * You have to call loadConfigValues() before this one, otherwise you get default values.
 	 */
-	public function getWidth(): int
+	public function getWidth(): string
 	{
 		return $this->width;
 	}
@@ -97,7 +98,7 @@ final class YouTubeExtension extends Minz_Extension
 	 * Returns the height in pixel for the YouTube player iframe.
 	 * You have to call loadConfigValues() before this one, otherwise you get default values.
 	 */
-	public function getHeight(): int
+	public function getHeight(): string
 	{
 		return $this->height;
 	}
@@ -128,7 +129,10 @@ final class YouTubeExtension extends Minz_Extension
 	{
 		$link = $entry->link();
 
-		if (preg_match('#^https?://www\.youtube\.com/watch\?v=|/videos/watch/[0-9a-f-]{36}$#', $link) !== 1) {
+		//		if (preg_match('#^https?://www\.youtube\.com/watch\?v=|/videos/watch/[0-9a-f-]{36}$#', $link) !== 1) {
+//			return $entry;
+//		}
+		if (preg_match('#^https?://www\.youtube\.com/watch\?v=|/videos/watch/#', $link) !== 1) {
 			return $entry;
 		}
 
@@ -139,12 +143,14 @@ final class YouTubeExtension extends Minz_Extension
 		}
 		if (stripos($link, 'www.youtube.com/watch?v=') !== false) {
 			$html = $this->getHtmlContentForLink($entry, $link);
-		}
-		else { //peertube
+		} else { //peertube
 			$html = $this->getHtmlPeerTubeContentForLink($entry, $link);
 		}
 
 		$entry->_content($html);
+		$entry->_attribute('enclosures', []);
+		$entry->_attribute('thumbnail', '');
+		$entry->_attribute('thumbnails', '');
 
 		return $entry;
 	}
@@ -158,15 +164,15 @@ final class YouTubeExtension extends Minz_Extension
 		if ($this->useNoCookie) {
 			$domain = 'www.youtube-nocookie.com';
 		}
-		$url = str_replace('//www.youtube.com/watch?v=', '//'.$domain.'/embed/', $link);
+		$url = str_replace('//www.youtube.com/watch?v=', '//' . $domain . '/embed/', $link);
 		$url = str_replace('http://', 'https://', $url);
 
 		return $this->getHtml($entry, $url);
 	}
 
 	/**
-	* Returns an HTML <iframe> for a given PeerTube watch URL
-	*/
+	 * Returns an HTML <iframe> for a given PeerTube watch URL
+	 */
 	public function getHtmlPeerTubeContentForLink(FreshRSS_Entry $entry, string $link): string
 	{
 		$url = str_replace('/watch', '/embed', $link);
@@ -182,21 +188,20 @@ final class YouTubeExtension extends Minz_Extension
 		$content = '';
 
 		$iframe = '<iframe class="youtube-plugin-video"
-				style="height: ' . $this->height . 'px; width: ' . $this->width . 'px;"
-				width="' . $this->width . '"
-				height="' . $this->height . '"
+				style="width:' . $this->getWidth() . '"
+				width="640"
+				height="385"
 				src="' . $url . '"
 				frameborder="0"
 				allowFullScreen></iframe>';
 
-		if ($this->showContent) {
+		if ($this->showContent === True) {
 			$doc = new DOMDocument();
 			$doc->encoding = 'UTF-8';
 			$doc->recover = true;
 			$doc->strictErrorChecking = false;
 
-			if ($doc->loadHTML('<?xml encoding="utf-8" ?>' . $entry->content()))
-			{
+			if ($doc->loadHTML('<?xml encoding="utf-8" ?>' . $entry->content())) {
 				$xpath = new DOMXPath($doc);
 
 				/** @var DOMNodeList<DOMElement> $titles */
@@ -228,12 +233,10 @@ final class YouTubeExtension extends Minz_Extension
 				}
 
 				$content .= "</div>\n";
-			}
-			else {
+			} else {
 				$content = $iframe . $entry->content();
 			}
-		}
-		else {
+		} else {
 			$content = $iframe;
 		}
 
@@ -252,10 +255,10 @@ final class YouTubeExtension extends Minz_Extension
 		$this->registerTranslates();
 
 		if (Minz_Request::isPost()) {
-			FreshRSS_Context::userConf()->_attribute('yt_player_height', Minz_Request::paramInt('yt_height'));
-			FreshRSS_Context::userConf()->_attribute('yt_player_width', Minz_Request::paramInt('yt_width'));
-			FreshRSS_Context::userConf()->_attribute('yt_show_content', Minz_Request::paramBoolean('yt_show_content'));
-			FreshRSS_Context::userConf()->_attribute('yt_nocookie', Minz_Request::paramInt('yt_nocookie'));
+			FreshRSS_Context::userConf()->_attribute('ytw_height', Minz_Request::paramString('ytw_height'));
+			FreshRSS_Context::userConf()->_attribute('ytw_width', Minz_Request::paramString('ytw_width'));
+			FreshRSS_Context::userConf()->_attribute('ytw_show_content', Minz_Request::paramBoolean('ytw_show_content'));
+			FreshRSS_Context::userConf()->_attribute('ytw_nocookie', Minz_Request::paramInt('ytw_nocookie'));
 			FreshRSS_Context::userConf()->save();
 		}
 
diff --git a/xExtension-YouTube/i18n/en/ext.php b/xExtension-YouTube/i18n/en/ext.php
index 6f37c02..5e38839 100644
--- a/xExtension-YouTube/i18n/en/ext.php
+++ b/xExtension-YouTube/i18n/en/ext.php
@@ -1,10 +1,9 @@
 <?php
 
 return array(
-	'yt_videos' => array(
-		'height' => 'Player height',
-		'width' => 'Player width',
-		'updates' => 'You can find the latest extension version at',
+	'ytw_videos' => array(
+		'height' => 'Player height (empty for auto)',
+		'width' => 'Player width (int or string like 100%)',
 		'show_content' => 'Display the feeds content',
 		'use_nocookie' => 'Use the cookie-free domain www.youtube-nocookie.com',
 	),
diff --git a/xExtension-YouTube/metadata.json b/xExtension-YouTube/metadata.json
index 2b709e2..f1a9232 100644
--- a/xExtension-YouTube/metadata.json
+++ b/xExtension-YouTube/metadata.json
@@ -1,8 +1,8 @@
 {
-	"name": "YouTube Video Feed",
-	"author": "Kevin Papst",
-	"description": "Embed YouTube feeds inside article content.",
-	"version": "0.13",
-	"entrypoint": "YouTube",
+	"name": "YouTube Video Feed Wide",
+	"author": "George Dorn",
+	"description": "Embed YouTube feeds inside article content with less rigid sizing.",
+	"version": "0.14",
+	"entrypoint": "YouTubeWide",
 	"type": "user"
 }
diff --git a/xExtension-YouTube/static/style.css b/xExtension-YouTube/static/style.css
new file mode 100644
index 0000000..5c214f5
--- /dev/null
+++ b/xExtension-YouTube/static/style.css
@@ -0,0 +1,9 @@
+div.content:has(div.text:has(iframe.youtube-plugin-video)) > header {
+	display: none;
+}
+
+iframe.youtube-plugin-video {
+	width: 100%;
+	height: 100%;
+	aspect-ratio: 16 / 9;
+}

@Alkarex
Copy link
Member

Alkarex commented Aug 14, 2025

Indeed, nice, but please consider sending a PR targetting the existing extension, at is looks overkill to make a full copy of the extension just to change an option

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants