Fixes #7009 -- Add no-op writer to RSS feed to register Podcast namespace for PSP-1 compliance.

This commit is contained in:
Buster Neece 2024-03-22 10:31:00 -05:00
parent b144860d63
commit c33fd9f30c
No known key found for this signature in database
2 changed files with 68 additions and 40 deletions

View File

@ -13,6 +13,7 @@ use App\Entity\PodcastEpisode;
use App\Exception\NotFoundException;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Rss\PodcastNamespaceWriter;
use DateTime;
use MarcW\RssWriter\Extension\Atom\AtomLink;
use MarcW\RssWriter\Extension\Atom\AtomWriter;
@ -54,14 +55,6 @@ final class PodcastFeedAction implements SingleActionInterface
$podcast = $request->getPodcast();
// Create RSS Writer
$rssWriter = new RssWriter(null, [], true);
$rssWriter->registerWriter(new CoreWriter());
$rssWriter->registerWriter(new ItunesWriter());
$rssWriter->registerWriter(new SyWriter());
$rssWriter->registerWriter(new SlashWriter());
$rssWriter->registerWriter(new AtomWriter());
$channel = new RssChannel();
$channel->setTtl(5);
$channel->setLastBuildDate(new DateTime());
@ -98,8 +91,6 @@ final class PodcastFeedAction implements SingleActionInterface
$channel->setImage($rssImage);
// Iterate through episodes.
$rssItems = [];
$hasPublishedEpisode = false;
$hasExplicitEpisode = false;
@ -114,42 +105,13 @@ final class PodcastFeedAction implements SingleActionInterface
$hasExplicitEpisode = true;
}
$episodeApi = $this->episodeApiGenerator->__invoke($episode, $request);
$rssItem = new RssItem();
$rssItem->setGuid((new RssGuid())->setGuid($episodeApi->id));
$rssItem->setTitle($episodeApi->title);
$rssItem->setDescription($episodeApi->description);
$rssItem->setLink($episodeApi->link ?? $episodeApi->links['self']);
$rssItem->setPubDate((new DateTime())->setTimestamp($episode->getPublishAt()));
$rssEnclosure = new RssEnclosure();
$rssEnclosure->setUrl($episodeApi->links['download']);
$podcastMedia = $episode->getMedia();
if (null !== $podcastMedia) {
$rssEnclosure->setType($podcastMedia->getMimeType());
$rssEnclosure->setLength($podcastMedia->getLength());
}
$rssItem->setEnclosure($rssEnclosure);
$rssItem->addExtension(
(new ItunesItem())
->setExplicit($episode->getExplicit())
->setImage($episodeApi->art)
);
$rssItems[] = $rssItem;
$channel->addItem($this->buildItemForEpisode($episode, $request));
}
if (!$hasPublishedEpisode) {
throw NotFoundException::podcast();
}
$channel->setItems($rssItems);
$itunesChannel = new ItunesChannel();
$itunesChannel->setExplicit($hasExplicitEpisode);
$itunesChannel->setImage($rssImage->getUrl());
@ -179,6 +141,15 @@ final class PodcastFeedAction implements SingleActionInterface
->setType('application/rss+xml')
);
$rssWriter = new RssWriter(null, [
new CoreWriter(),
new ItunesWriter(),
new SyWriter(),
new SlashWriter(),
new AtomWriter(),
new PodcastNamespaceWriter(),
], true);
$response->getBody()->write(
$rssWriter->writeChannel($channel)
);
@ -188,6 +159,38 @@ final class PodcastFeedAction implements SingleActionInterface
->withHeader('X-Robots-Tag', 'index, nofollow');
}
private function buildItemForEpisode(PodcastEpisode $episode, ServerRequest $request): RssItem
{
$episodeApi = $this->episodeApiGenerator->__invoke($episode, $request);
$rssItem = new RssItem();
$rssItem->setGuid((new RssGuid())->setGuid($episodeApi->id));
$rssItem->setTitle($episodeApi->title);
$rssItem->setDescription($episodeApi->description);
$rssItem->setLink($episodeApi->link ?? $episodeApi->links['self']);
$rssItem->setPubDate((new DateTime())->setTimestamp($episode->getPublishAt()));
$rssEnclosure = new RssEnclosure();
$rssEnclosure->setUrl($episodeApi->links['download']);
$podcastMedia = $episode->getMedia();
if (null !== $podcastMedia) {
$rssEnclosure->setType($podcastMedia->getMimeType());
$rssEnclosure->setLength($podcastMedia->getLength());
}
$rssItem->setEnclosure($rssEnclosure);
$rssItem->addExtension(
(new ItunesItem())
->setExplicit($episode->getExplicit())
->setImage($episodeApi->art)
);
return $rssItem;
}
private function buildItunesOwner(Podcast $podcast): ?ItunesOwner
{
if (empty($podcast->getAuthor()) && empty($podcast->getEmail())) {

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace App\Rss;
use MarcW\RssWriter\WriterRegistererInterface;
/**
* Placeholder class to write the Podcast namespace for PSP-1 compliance.
*/
class PodcastNamespaceWriter implements WriterRegistererInterface
{
public function getRegisteredWriters(): array
{
return [];
}
public function getRegisteredNamespaces(): array
{
return [
'podcast' => 'https://podcastindex.org/namespace/1.0',
];
}
}