From cfc5cecf3e1a22a816bde28fe262a663881736d8 Mon Sep 17 00:00:00 2001 From: NopeCharon <115794254+NopeCharon@users.noreply.github.com> Date: Mon, 26 Oct 2026 13:28:39 +0530 Subject: [PATCH] [GridView] Fetch Open Graph images with the FreshRSS HTTP client The optional Open Graph thumbnail fetching downloaded article pages with file_get_contents() on an http(s) URL. Since FreshRSS 1.30.0, every stream wrapper except file:// and php:// is unregistered at startup, so that call always fails and no og:image / twitter:image is ever found, both when entries are inserted and through the asynchronous AJAX endpoint. Use FreshRSS_http_Util::httpGet() instead, like the core favicon lookup. It goes through cURL and also applies the system proxy and cURL options, the internal-host (SSRF) checks, Retry-After handling and the HTML cache. The previous 5-second timeout is kept, and relative image URLs are now resolved against the URL reached after redirects. FreshRSS_http_Util::httpGet() exists since FreshRSS 1.28.0, so raise the declared compatibility accordingly and bump the version to 1.1.2. --- xExtension-GridView/README.md | 2 +- xExtension-GridView/extension.php | 33 ++++++++++--------------------- xExtension-GridView/metadata.json | 4 ++-- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/xExtension-GridView/README.md b/xExtension-GridView/README.md index 4c63823b..e63ff8b7 100644 --- a/xExtension-GridView/README.md +++ b/xExtension-GridView/README.md @@ -60,7 +60,7 @@ Your grid view preference is saved locally and persists across sessions. ## Requirements -- FreshRSS 1.20.0 or later +- FreshRSS 1.28.0 or later ## Responsive Breakpoints diff --git a/xExtension-GridView/extension.php b/xExtension-GridView/extension.php index 961cd3d4..c9651567 100644 --- a/xExtension-GridView/extension.php +++ b/xExtension-GridView/extension.php @@ -430,43 +430,30 @@ private function ensureThumbnail(FreshRSS_Entry $entry, bool $persist = false): /** * Fetch a URL and extract the og:image meta tag. * - * @param string $url The article URL to fetch + * @param non-empty-string $url The article URL to fetch * @return string|null The og:image URL or null if not found */ private function extractOgImage(string $url): ?string { - $ctx = stream_context_create([ - 'http' => [ - 'timeout' => 5, - 'method' => 'GET', - 'header' => "User-Agent: FreshRSS/GridView\r\n", - 'follow_location' => 1, - 'max_redirects' => 3, - 'ignore_errors' => true, - ], - 'ssl' => [ - 'verify_peer' => true, - 'verify_peer_name' => true, - ], - ]); - - // Only fetch the first 50 KB — og:image is in - $html = @file_get_contents($url, false, $ctx, 0, 50000); - if ($html === false || $html === '') { + // Use the FreshRSS HTTP client, as FreshRSS 1.30+ disables the http(s) stream wrappers + ['body' => $html, 'effective_url' => $effectiveUrl, 'fail' => $fail] = FreshRSS_http_Util::httpGet($url, + cachePath: CACHE_PATH . '/' . sha1($url) . '.html', type: 'html', attributes: ['timeout' => 5]); + if ($fail || $html === '') { return null; } + $pageUrl = $effectiveUrl ?: $url; // Try og:image first, then twitter:image (both attribute orderings) if (preg_match('/]*property=["\']og:image["\'][^>]*content=["\']([^"\']+)["\']/i', $html, $matches)) { - return $this->normalizeImageUrl($matches[1], $url); + return $this->normalizeImageUrl($matches[1], $pageUrl); } if (preg_match('/]*content=["\']([^"\']+)["\'][^>]*property=["\']og:image["\']/i', $html, $matches)) { - return $this->normalizeImageUrl($matches[1], $url); + return $this->normalizeImageUrl($matches[1], $pageUrl); } if (preg_match('/]*name=["\']twitter:image["\'][^>]*content=["\']([^"\']+)["\']/i', $html, $matches)) { - return $this->normalizeImageUrl($matches[1], $url); + return $this->normalizeImageUrl($matches[1], $pageUrl); } if (preg_match('/]*content=["\']([^"\']+)["\'][^>]*name=["\']twitter:image["\']/i', $html, $matches)) { - return $this->normalizeImageUrl($matches[1], $url); + return $this->normalizeImageUrl($matches[1], $pageUrl); } return null; diff --git a/xExtension-GridView/metadata.json b/xExtension-GridView/metadata.json index fdba6fff..41be167a 100644 --- a/xExtension-GridView/metadata.json +++ b/xExtension-GridView/metadata.json @@ -2,8 +2,8 @@ "name": "Grid View", "author": "Marius Stroe ", "description": "A grid/card view for displaying feeds with images, configurable 2-4 columns, FreshRSS native share integration, and browser reader mode support", - "version": "1.1.1", + "version": "1.1.2", "entrypoint": "GridView", "type": "user", - "compatibility": "1.25.0" + "compatibility": "1.28.0" }