2023-08-24 12:48:10 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace OCA\RePod\Core\EpisodeAction;
|
|
|
|
|
2024-01-13 00:10:37 +01:00
|
|
|
use OCA\GPodderSync\Core\EpisodeAction\EpisodeActionReader as CoreEpisodeActionReader;
|
2023-08-29 12:04:14 +02:00
|
|
|
use OCA\GPodderSync\Db\EpisodeAction\EpisodeActionRepository;
|
2024-01-13 00:10:37 +01:00
|
|
|
use OCA\RePod\Core\PodcastData\PodcastData;
|
2023-08-29 12:04:14 +02:00
|
|
|
use OCA\RePod\Service\UserService;
|
|
|
|
|
2024-01-13 00:10:37 +01:00
|
|
|
class EpisodeActionReader extends CoreEpisodeActionReader
|
2023-08-24 12:48:10 +02:00
|
|
|
{
|
2023-08-29 12:04:14 +02:00
|
|
|
public function __construct(
|
|
|
|
private EpisodeActionRepository $episodeActionRepository,
|
|
|
|
private UserService $userService
|
2023-12-23 17:25:20 +01:00
|
|
|
) {}
|
2023-08-29 12:04:14 +02:00
|
|
|
|
2023-08-24 12:48:10 +02:00
|
|
|
/**
|
2024-01-11 00:14:15 +01:00
|
|
|
* Base: https://github.com/pbek/nextcloud-nextpod/blob/main/lib/Core/EpisodeAction/EpisodeActionExtraData.php#L119.
|
|
|
|
* Specs : https://github.com/Podcast-Standards-Project/PSP-1-Podcast-RSS-Specification/blob/main/README.md.
|
2023-08-24 12:48:10 +02:00
|
|
|
*
|
2023-12-24 17:05:35 +01:00
|
|
|
* @return EpisodeActionExtraData[]
|
2024-01-07 11:07:48 +01:00
|
|
|
* @throws \Exception if the XML data could not be parsed
|
2023-08-24 12:48:10 +02:00
|
|
|
*/
|
2023-12-23 17:25:20 +01:00
|
|
|
public function parseRssXml(string $xmlString, ?int $fetchedAtUnix = null): array {
|
2023-08-24 12:48:10 +02:00
|
|
|
$episodes = [];
|
|
|
|
$xml = new \SimpleXMLElement($xmlString);
|
|
|
|
$channel = $xml->channel;
|
2024-01-14 00:40:52 +01:00
|
|
|
$title = (string) $channel->title;
|
2023-08-24 12:48:10 +02:00
|
|
|
|
|
|
|
// Find episode by url and add data for it
|
|
|
|
/** @var \SimpleXMLElement $item */
|
|
|
|
foreach ($channel->item as $item) {
|
2024-01-11 00:14:15 +01:00
|
|
|
$url = (string) $item->enclosure['url'];
|
|
|
|
$type = (string) $item->enclosure['type'];
|
|
|
|
$size = (int) $item->enclosure['length'];
|
|
|
|
$guid = (string) $item->guid;
|
2024-01-11 23:00:14 +01:00
|
|
|
|
|
|
|
$iTunesItemChildren = $item->children('itunes', true);
|
|
|
|
$iTunesChannelChildren = $channel->children('itunes', true);
|
2023-08-24 19:03:11 +02:00
|
|
|
|
2023-08-29 12:04:14 +02:00
|
|
|
// Get episode action
|
2024-01-11 00:14:15 +01:00
|
|
|
$action = $this->episodeActionRepository->findByGuid($guid, $this->userService->getUserUID());
|
2023-12-23 21:51:48 +01:00
|
|
|
|
2024-01-11 00:14:15 +01:00
|
|
|
if ($action) {
|
|
|
|
$url = $action->getEpisode();
|
2023-12-23 21:51:48 +01:00
|
|
|
} else {
|
2024-01-11 00:14:15 +01:00
|
|
|
$action = $this->episodeActionRepository->findByEpisodeUrl($url, $this->userService->getUserUID());
|
2023-12-23 21:51:48 +01:00
|
|
|
}
|
2023-08-29 12:04:14 +02:00
|
|
|
|
2023-08-24 12:48:10 +02:00
|
|
|
// Get episode name
|
2024-01-11 00:14:15 +01:00
|
|
|
$name = (string) $item->title;
|
2023-08-24 12:48:10 +02:00
|
|
|
|
|
|
|
// Get episode link
|
2024-01-13 00:10:37 +01:00
|
|
|
$link = PodcastData::stringOrNull($item->link);
|
2023-08-24 12:48:10 +02:00
|
|
|
|
|
|
|
// Get episode image
|
2024-01-13 00:10:37 +01:00
|
|
|
$image = PodcastData::stringOrNull($item->image->url);
|
2023-08-29 12:04:14 +02:00
|
|
|
|
2024-01-11 23:00:14 +01:00
|
|
|
if (!$image && $iTunesItemChildren) {
|
2024-01-11 23:54:21 +01:00
|
|
|
$imageAttributes = $iTunesItemChildren->image->attributes();
|
2024-01-13 00:10:37 +01:00
|
|
|
$image = PodcastData::stringOrNull($imageAttributes ? (string) $imageAttributes->href : '');
|
2024-01-11 23:00:14 +01:00
|
|
|
}
|
2023-08-24 19:03:11 +02:00
|
|
|
|
2024-01-11 23:00:14 +01:00
|
|
|
if (!$image) {
|
2024-01-13 00:10:37 +01:00
|
|
|
$image = PodcastData::stringOrNull($channel->image->url);
|
2024-01-11 23:00:14 +01:00
|
|
|
}
|
2023-08-24 12:48:10 +02:00
|
|
|
|
2024-01-11 23:00:14 +01:00
|
|
|
if (!$image && $iTunesChannelChildren) {
|
2024-01-11 23:54:21 +01:00
|
|
|
$imageAttributes = $iTunesChannelChildren->image->attributes();
|
2024-01-13 00:10:37 +01:00
|
|
|
$image = PodcastData::stringOrNull($imageAttributes ? (string) $imageAttributes->href : '');
|
2024-01-11 23:00:14 +01:00
|
|
|
}
|
2023-08-24 12:48:10 +02:00
|
|
|
|
2024-01-11 23:00:14 +01:00
|
|
|
if (!$image) {
|
|
|
|
preg_match('/<itunes:image\s+href="([^"]+)"/', $xmlString, $matches);
|
2024-01-13 00:10:37 +01:00
|
|
|
$image = PodcastData::stringOrNull($matches[1]);
|
2023-08-24 12:48:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get episode description
|
2024-01-11 00:14:15 +01:00
|
|
|
$itemContent = $item->children('content', true);
|
|
|
|
if ($itemContent) {
|
2024-01-13 00:10:37 +01:00
|
|
|
$description = PodcastData::stringOrNull($itemContent->encoded);
|
2024-01-11 00:14:15 +01:00
|
|
|
} else {
|
2024-01-13 00:10:37 +01:00
|
|
|
$description = PodcastData::stringOrNull($item->description);
|
2023-08-24 12:48:10 +02:00
|
|
|
}
|
|
|
|
|
2024-01-11 23:00:14 +01:00
|
|
|
if (!$description && $iTunesItemChildren) {
|
2024-01-13 00:10:37 +01:00
|
|
|
$description = PodcastData::stringOrNull($iTunesItemChildren->summary);
|
2024-01-11 23:00:14 +01:00
|
|
|
}
|
2023-08-24 12:48:10 +02:00
|
|
|
|
2024-01-11 23:00:14 +01:00
|
|
|
// Remove tags
|
|
|
|
$description = strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $description ?? ''));
|
2024-01-11 00:14:15 +01:00
|
|
|
|
|
|
|
// Get episode duration
|
2024-01-11 23:00:14 +01:00
|
|
|
if ($iTunesItemChildren) {
|
2024-01-13 00:10:37 +01:00
|
|
|
$rawDuration = PodcastData::stringOrNull($iTunesItemChildren->duration);
|
2024-01-11 23:00:14 +01:00
|
|
|
} else {
|
2024-01-13 00:10:37 +01:00
|
|
|
$rawDuration = PodcastData::stringOrNull($item->duration);
|
2024-01-11 23:00:14 +01:00
|
|
|
}
|
|
|
|
|
2024-01-11 00:14:15 +01:00
|
|
|
$splitDuration = array_reverse(explode(':', $rawDuration ?? ''));
|
|
|
|
$duration = (int) $splitDuration[0];
|
|
|
|
$duration += !empty($splitDuration[1]) ? (int) $splitDuration[1] * 60 : 0;
|
|
|
|
$duration += !empty($splitDuration[2]) ? (int) $splitDuration[2] * 60 : 0;
|
2023-08-24 19:03:11 +02:00
|
|
|
|
2024-01-11 23:00:14 +01:00
|
|
|
// Get episode pubDate
|
2024-01-13 00:10:37 +01:00
|
|
|
$rawPubDate = PodcastData::stringOrNull($item->pubDate);
|
2024-01-11 23:00:14 +01:00
|
|
|
$pubDate = $rawPubDate ? new \DateTime($rawPubDate) : null;
|
|
|
|
|
2023-08-24 12:48:10 +02:00
|
|
|
$episodes[] = new EpisodeActionExtraData(
|
2024-01-14 00:40:52 +01:00
|
|
|
$title,
|
2024-01-11 00:14:15 +01:00
|
|
|
$url,
|
|
|
|
$name,
|
|
|
|
$link,
|
|
|
|
$image,
|
|
|
|
$description,
|
2023-08-24 12:48:10 +02:00
|
|
|
$fetchedAtUnix ?? (new \DateTime())->getTimestamp(),
|
2024-01-11 00:14:15 +01:00
|
|
|
$guid,
|
|
|
|
$type,
|
|
|
|
$size,
|
|
|
|
$pubDate,
|
|
|
|
$duration,
|
|
|
|
$action
|
2023-08-24 12:48:10 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $episodes;
|
|
|
|
}
|
|
|
|
}
|