diff --git a/src/common.php b/src/common.php index 8c31c70332..72d776e64e 100644 --- a/src/common.php +++ b/src/common.php @@ -158,6 +158,12 @@ 'constructParams' => ['selfoss'], ]); +$dice->addRule(helpers\FeedHelper::class, [ + 'constructParams' => [ + \F3::get('cache'), + ], +]); + // init logger $log = $dice->create(Logger::class); if ($f3->get('logger_level') === 'NONE') { diff --git a/src/helpers/FeedReader.php b/src/helpers/FeedReader.php new file mode 100644 index 0000000000..7295548f77 --- /dev/null +++ b/src/helpers/FeedReader.php @@ -0,0 +1,84 @@ +simplepie = $simplepie; + + // initialize simplepie feed loader + if ($cacheLocation !== null) { + $this->simplepie->set_cache_location($cacheLocation); + $this->simplepie->set_cache_duration($cacheTimeout); + } + + // abuse set_curl_options since there is no sane way to pass data to SimplePie\File + $this->simplepie->set_curl_options([ + WebClient::class => $webClient + ]); + + $this->simplepie->set_file_class(SimplePieFileGuzzle::class); + $this->simplepie->set_autodiscovery_level(SIMPLEPIE_LOCATOR_AUTODISCOVERY | SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY); + $this->simplepie->set_useragent($webClient->getUserAgent()); + } + + /** + * Load the feed for provided URL using SimplePie. + * + * @param string $url URL of the feed + * + * @return array + */ + public function load($url) { + @$this->simplepie->set_feed_url($url); + // fetch items + @$this->simplepie->init(); + + // on error retry with force_feed + if (@$this->simplepie->error()) { + @$this->simplepie->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE); + @$this->simplepie->force_feed(true); + @$this->simplepie->init(); + } + + // check for error + if (@$this->simplepie->error()) { + throw new \Exception($this->simplepie->error()); + } + + return [ + // save fetched items + 'items' => $this->simplepie->get_items(), + 'htmlUrl' => @$this->simplepie->get_link(), + 'spoutTitle' => $this->simplepie->get_title(), + ]; + } + + /** + * Get the URL of the feed’s logo. + * + * @return ?string + */ + public function getImageUrl() { + return $this->simplepie->get_image_url(); + } + + /** + * @return void + */ + public function __destruct() { + $this->simplepie->__destruct(); + } +} diff --git a/src/spouts/rss/feed.php b/src/spouts/rss/feed.php index a2df642762..1995bd8cc0 100644 --- a/src/spouts/rss/feed.php +++ b/src/spouts/rss/feed.php @@ -2,8 +2,8 @@ namespace spouts\rss; +use helpers\FeedReader; use helpers\Image; -use helpers\WebClient; use Monolog\Logger; /** @@ -42,16 +42,16 @@ class feed extends \spouts\spout { /** @var Logger */ private $logger; + /** @var FeedReader */ + private $feed; + /** @var Image image helper */ private $imageHelper; - /** @var WebClient */ - private $webClient; - - public function __construct(Image $imageHelper, Logger $logger, WebClient $webClient) { + public function __construct(FeedReader $feed, Image $imageHelper, Logger $logger) { $this->imageHelper = $imageHelper; $this->logger = $logger; - $this->webClient = $webClient; + $this->feed = $feed; } // @@ -59,41 +59,10 @@ public function __construct(Image $imageHelper, Logger $logger, WebClient $webCl // public function load(array $params) { - // initialize simplepie feed loader - $this->feed = @new \SimplePie(); - @$this->feed->set_cache_location(\F3::get('cache')); - @$this->feed->set_cache_duration(1800); - // abuse set_curl_options since there is no sane way to pass data to SimplePie\File - $this->feed->set_curl_options([ - WebClient::class => $this->webClient - ]); - @$this->feed->set_file_class(\helpers\SimplePieFileGuzzle::class); - @$this->feed->set_feed_url(htmlspecialchars_decode($params['url'])); - @$this->feed->set_autodiscovery_level(SIMPLEPIE_LOCATOR_AUTODISCOVERY | SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY); - $this->feed->set_useragent($this->webClient->getUserAgent()); - - // fetch items - @$this->feed->init(); - - // on error retry with force_feed - if (@$this->feed->error()) { - @$this->feed->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE); - @$this->feed->force_feed(true); - @$this->feed->init(); - } - - // check for error - if (@$this->feed->error()) { - throw new \Exception($this->feed->error()); - } else { - // save fetched items - $this->items = @$this->feed->get_items(); - } - - // set html url - $this->htmlUrl = @$this->feed->get_link(); - - $this->spoutTitle = $this->feed->get_title(); + $feedData = $this->feed->load(htmlspecialchars_decode($params['url'])); + $this->items = $feedData['items']; + $this->htmlUrl = $feedData['htmlUrl']; + $this->spoutTitle = $feedData['spoutTitle']; } public function getXmlUrl(array $params) { @@ -144,7 +113,7 @@ public function getIcon() { $this->faviconUrl = $this->imageHelper->getFaviconUrl(); $this->logger->debug('icon: using feed homepage favicon: ' . $this->faviconUrl); } else { - $feedLogoUrl = $this->feed->get_image_url(); + $feedLogoUrl = $this->feed->getImageUrl(); if ($feedLogoUrl && $this->imageHelper->fetchFavicon($feedLogoUrl)) { $this->faviconUrl = $this->imageHelper->getFaviconUrl(); $this->logger->debug('icon: using feed logo: ' . $this->faviconUrl); diff --git a/src/spouts/rss/fulltextrss.php b/src/spouts/rss/fulltextrss.php index 399dbf23ab..ebf672e5c1 100644 --- a/src/spouts/rss/fulltextrss.php +++ b/src/spouts/rss/fulltextrss.php @@ -3,6 +3,7 @@ namespace spouts\rss; use Graby\Graby; +use helpers\FeedReader; use helpers\Image; use helpers\WebClient; use Http\Adapter\Guzzle6\Client as GuzzleAdapter; @@ -45,8 +46,8 @@ class fulltextrss extends feed { /** @var WebClient */ private $webClient; - public function __construct(Image $imageHelper, Logger $logger, WebClient $webClient) { - parent::__construct($imageHelper, $logger, $webClient); + public function __construct(FeedReader $feed, Image $imageHelper, Logger $logger, WebClient $webClient) { + parent::__construct($feed, $imageHelper, $logger); $this->imageHelper = $imageHelper; $this->logger = $logger;