aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Dag <me@dvikan.no> 2024-01-29 21:51:06 +0100
committerGravatar GitHub <noreply@github.com> 2024-01-29 21:51:06 +0100
commitc4fceab7b3de0b842145fa26acbe6f8785474cfd (patch)
tree803aa4091957900e8be6785753c137a2f1a13c56
parentcfe3dcfe6d277980737cfde6ac3494caf37e6195 (diff)
downloadrss-bridge-c4fceab7b3de0b842145fa26acbe6f8785474cfd.tar.gz
rss-bridge-c4fceab7b3de0b842145fa26acbe6f8785474cfd.tar.zst
rss-bridge-c4fceab7b3de0b842145fa26acbe6f8785474cfd.zip
refactor(FeedParser): (#3928)
-rw-r--r--lib/BridgeAbstract.php2
-rw-r--r--lib/FeedExpander.php1
-rw-r--r--lib/FeedParser.php71
-rw-r--r--tests/FeedParserTest.php55
4 files changed, 88 insertions, 41 deletions
diff --git a/lib/BridgeAbstract.php b/lib/BridgeAbstract.php
index 5dc425f9..1456e1c3 100644
--- a/lib/BridgeAbstract.php
+++ b/lib/BridgeAbstract.php
@@ -80,7 +80,7 @@ abstract class BridgeAbstract
}
/**
- * The description is currently not used in feed production
+ * The description is only used in bridge card rendering on frontpage
*/
public function getDescription()
{
diff --git a/lib/FeedExpander.php b/lib/FeedExpander.php
index 35b75249..be3a8ca4 100644
--- a/lib/FeedExpander.php
+++ b/lib/FeedExpander.php
@@ -32,6 +32,7 @@ abstract class FeedExpander extends BridgeAbstract
$feedParser = new FeedParser();
$this->feed = $feedParser->parseFeed($xmlString);
$items = array_slice($this->feed['items'], 0, $maxItems);
+ // todo: extract parse logic out from FeedParser
foreach ($items as $item) {
// Give bridges a chance to modify the item
$item = $this->parseItem($item);
diff --git a/lib/FeedParser.php b/lib/FeedParser.php
index 510bcb32..37d3005b 100644
--- a/lib/FeedParser.php
+++ b/lib/FeedParser.php
@@ -36,7 +36,7 @@ final class FeedParser
$channel = $xml->channel[0];
$feed['title'] = trim((string)$channel->title);
$feed['uri'] = trim((string)$channel->link);
- if (!empty($channel->image)) {
+ if (isset($channel->image->url)) {
$feed['icon'] = trim((string)$channel->image->url);
}
foreach ($xml->item as $item) {
@@ -47,7 +47,7 @@ final class FeedParser
$channel = $xml->channel[0];
$feed['title'] = trim((string)$channel->title);
$feed['uri'] = trim((string)$channel->link);
- if (!empty($channel->image)) {
+ if (isset($channel->image->url)) {
$feed['icon'] = trim((string)$channel->image->url);
}
foreach ($channel->item as $item) {
@@ -70,10 +70,10 @@ final class FeedParser
}
}
}
- if (!empty($xml->icon)) {
- $feed['icon'] = (string)$xml->icon;
- } elseif (!empty($xml->logo)) {
- $feed['icon'] = (string)$xml->logo;
+ if (isset($xml->icon)) {
+ $feed['icon'] = (string) $xml->icon;
+ } elseif (isset($xml->logo)) {
+ $feed['icon'] = (string) $xml->logo;
}
foreach ($xml->entry as $item) {
$feed['items'][] = $this->parseAtomItem($item);
@@ -171,11 +171,7 @@ final class FeedParser
if (in_array($namespaceName, ['', 'content', 'media'])) {
continue;
}
- $module = $feedItem->children($namespaceUrl);
- $item[$namespaceName] = [];
- foreach ($module as $moduleKey => $moduleValue) {
- $item[$namespaceName][$moduleKey] = (string) $moduleValue;
- }
+ $item[$namespaceName] = $this->parseModule($feedItem, $namespaceName, $namespaceUrl);
}
if (isset($namespaces['itunes'])) {
$enclosure = $feedItem->enclosure;
@@ -185,43 +181,27 @@ final class FeedParser
'type' => (string) $enclosure['type'],
];
}
- if (isset($feedItem->guid)) {
- // Pluck out a url from guid
- foreach ($feedItem->guid->attributes() as $attribute => $value) {
- if (
- $attribute === 'isPermaLink'
- && (
- $value === 'true' || (
- filter_var($feedItem->guid, FILTER_VALIDATE_URL)
- && (empty($item['uri']) || !filter_var($item['uri'], FILTER_VALIDATE_URL))
- )
- )
- ) {
- $item['uri'] = (string)$feedItem->guid;
- break;
+ if (!$item['uri']) {
+ // Let's use guid as uri if it's a permalink
+ if (isset($feedItem->guid)) {
+ foreach ($feedItem->guid->attributes() as $attribute => $value) {
+ if ($attribute === 'isPermaLink' && ($value === 'true' || (filter_var($feedItem->guid, FILTER_VALIDATE_URL)))) {
+ $item['uri'] = (string) $feedItem->guid;
+ break;
+ }
}
}
}
- if (isset($feedItem->pubDate)) {
- $item['timestamp'] = strtotime((string)$feedItem->pubDate);
- } elseif (isset($dc->date)) {
- $item['timestamp'] = strtotime((string)$dc->date);
- }
+ $item['timestamp'] = $feedItem->pubDate ?? $dc->date ?? '';
+ $item['timestamp'] = strtotime((string) $item['timestamp']);
- if (isset($feedItem->author)) {
- $item['author'] = (string)$feedItem->author;
- } elseif (isset($feedItem->creator)) {
- $item['author'] = (string)$feedItem->creator;
- } elseif (isset($dc->creator)) {
- $item['author'] = (string)$dc->creator;
- } elseif (isset($media->credit)) {
- $item['author'] = (string)$media->credit;
- }
+ $item['author'] = $feedItem->author ?? $feedItem->creator ?? $dc->creator ?? $media->credit ?? '';
+ $item['author'] = (string) $item['author'];
if (isset($feedItem->enclosure) && !empty($feedItem->enclosure['url'])) {
$item['enclosures'] = [
- (string)$feedItem->enclosure['url'],
+ (string) $feedItem->enclosure['url'],
];
}
return $item;
@@ -261,4 +241,15 @@ final class FeedParser
}
return $item;
}
+
+ private function parseModule(\SimpleXMLElement $element, string $namespaceName, string $namespaceUrl): array
+ {
+ $result = [];
+ $module = $element->children($namespaceUrl);
+ foreach ($module as $name => $value) {
+ // todo: add custom parsing if it's something other than a string
+ $result[$name] = (string) $value;
+ }
+ return $result;
+ }
}
diff --git a/tests/FeedParserTest.php b/tests/FeedParserTest.php
index acd93e52..05d5ef69 100644
--- a/tests/FeedParserTest.php
+++ b/tests/FeedParserTest.php
@@ -125,4 +125,59 @@ class FeedParserTest extends TestCase
$this->assertSame('root', $item['author']);
$this->assertSame('html', $item['content']);
}
+
+ public function testAppleItunesModule()
+ {
+ $xml = <<<XML
+ <?xml version="1.0" encoding="UTF-8"?>
+ <rss
+ version="2.0"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
+ xmlns:media="http://search.yahoo.com/mrss/"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
+ xmlns:podcast="https://podcastindex.org/namespace/1.0"
+ xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ >
+ <channel>
+
+ <item>
+ <itunes:duration>30:05</itunes:duration>
+ <enclosure length="48123248" type="audio/mpeg" url="https://example.com/1.mp3" />
+ </item>
+ </channel>
+ </rss>
+ XML;
+
+ $sut = new \FeedParser();
+ $feed = $sut->parseFeed($xml);
+ $expected = [
+ 'title' => '',
+ 'uri' => '',
+ 'icon' => '',
+ 'items' => [
+ [
+ 'uri' => '',
+ 'title' => '',
+ 'content' => '',
+ 'timestamp' => '',
+ 'author' => '',
+ 'itunes' => [
+ 'duration' => '30:05',
+ ],
+ 'enclosure' => [
+ 'url' => 'https://example.com/1.mp3',
+ 'length' => '48123248',
+ 'type' => 'audio/mpeg',
+ ],
+ 'enclosures' => [
+ 'https://example.com/1.mp3',
+ ],
+ ]
+ ],
+ ];
+ $this->assertEquals($expected, $feed);
+ }
}