2023-08-24 10:48:10 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace OCA\RePod\Core\EpisodeAction;
|
|
|
|
|
2023-08-29 10:04:14 +00:00
|
|
|
use OCA\GPodderSync\Core\EpisodeAction\EpisodeAction;
|
|
|
|
use OCA\GPodderSync\Db\EpisodeAction\EpisodeActionRepository;
|
|
|
|
use OCA\RePod\Service\UserService;
|
|
|
|
|
2023-08-29 06:48:54 +00:00
|
|
|
class EpisodeActionReader
|
2023-08-24 10:48:10 +00:00
|
|
|
{
|
2023-08-29 10:04:14 +00:00
|
|
|
public function __construct(
|
|
|
|
private EpisodeActionRepository $episodeActionRepository,
|
|
|
|
private UserService $userService
|
2023-12-23 16:25:20 +00:00
|
|
|
) {}
|
2023-08-29 10:04:14 +00:00
|
|
|
|
2023-12-23 16:25:20 +00:00
|
|
|
public function findByEpisodeUrl(string $episodeUrl): ?EpisodeAction {
|
2023-08-29 10:04:14 +00:00
|
|
|
return $this->episodeActionRepository->findByEpisodeUrl($episodeUrl, $this->userService->getUserUID());
|
|
|
|
}
|
|
|
|
|
2023-08-24 10:48:10 +00:00
|
|
|
/**
|
|
|
|
* https://github.com/pbek/nextcloud-nextpod/blob/main/lib/Core/EpisodeAction/EpisodeActionExtraData.php#L119.
|
|
|
|
*
|
2023-12-24 16:05:35 +00:00
|
|
|
* @return EpisodeActionExtraData[]
|
2024-01-07 10:07:48 +00:00
|
|
|
* @throws \Exception if the XML data could not be parsed
|
2023-08-24 10:48:10 +00:00
|
|
|
*/
|
2023-12-23 16:25:20 +00:00
|
|
|
public function parseRssXml(string $xmlString, ?int $fetchedAtUnix = null): array {
|
2023-08-24 10:48:10 +00:00
|
|
|
$episodes = [];
|
|
|
|
$xml = new \SimpleXMLElement($xmlString);
|
|
|
|
$channel = $xml->channel;
|
|
|
|
|
|
|
|
// Find episode by url and add data for it
|
|
|
|
/** @var \SimpleXMLElement $item */
|
|
|
|
foreach ($channel->item as $item) {
|
2023-08-24 15:43:10 +00:00
|
|
|
$episodeUrl = (string) $item->enclosure['url'];
|
2023-08-24 10:48:10 +00:00
|
|
|
|
2023-08-28 15:44:17 +00:00
|
|
|
// Get episode guid
|
|
|
|
$episodeGuid = (string) $item->guid;
|
|
|
|
|
2023-08-24 17:03:11 +00:00
|
|
|
// Get episode filesize
|
|
|
|
$episodeFilesize = (int) $item->enclosure['length'];
|
|
|
|
|
2023-08-29 10:04:14 +00:00
|
|
|
// Get episode action
|
2023-12-23 20:51:48 +00:00
|
|
|
$episodeAction = $this->episodeActionRepository->findByGuid($episodeGuid, $this->userService->getUserUID());
|
|
|
|
|
|
|
|
if ($episodeAction) {
|
|
|
|
$episodeUrl = $episodeAction->getEpisode();
|
|
|
|
} else {
|
|
|
|
$episodeAction = $this->episodeActionRepository->findByEpisodeUrl($episodeUrl, $this->userService->getUserUID());
|
|
|
|
}
|
2023-08-29 10:04:14 +00:00
|
|
|
|
2023-08-24 10:48:10 +00:00
|
|
|
// Get episode name
|
|
|
|
$episodeName = $this->stringOrNull($item->title);
|
|
|
|
|
|
|
|
// Get episode link
|
|
|
|
$episodeLink = $this->stringOrNull($item->link);
|
|
|
|
|
|
|
|
// Get episode image
|
2023-08-29 10:04:14 +00:00
|
|
|
$episodeImage = $this->stringOrNull($channel->image->url);
|
|
|
|
|
2023-08-24 17:03:11 +00:00
|
|
|
$episodeChildren = $item->children('http://www.itunes.com/dtds/podcast-1.0.dtd');
|
|
|
|
if ($episodeChildren) {
|
|
|
|
$episodeImageAttributes = (array) $episodeChildren->image->attributes();
|
2023-08-24 10:48:10 +00:00
|
|
|
$episodeImage = $this->stringOrNull(array_key_exists('href', $episodeImageAttributes) ? (string) $episodeImageAttributes['href'] : '');
|
|
|
|
$iTunesChildren = $item->children('itunes', true);
|
|
|
|
|
2023-08-24 17:03:11 +00:00
|
|
|
// Get episode duration
|
|
|
|
if ($iTunesChildren) {
|
|
|
|
$rawDuration = $this->stringOrNull((string) $iTunesChildren->duration);
|
|
|
|
$splitDuration = array_reverse(explode(':', $rawDuration ?? ''));
|
|
|
|
$episodeDuration = (int) $splitDuration[0];
|
|
|
|
$episodeDuration += !empty($splitDuration[1]) ? (int) $splitDuration[1] * 60 : 0;
|
|
|
|
$episodeDuration += !empty($splitDuration[2]) ? (int) $splitDuration[2] * 60 : 0;
|
|
|
|
}
|
|
|
|
|
2023-08-24 10:48:10 +00:00
|
|
|
if ($iTunesChildren && !$episodeImage) {
|
|
|
|
$episodeImage = $this->stringOrNull((string) $iTunesChildren->image['href']);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($iTunesChildren && !$episodeImage) {
|
|
|
|
$episodeImage = $this->stringOrNull((string) $iTunesChildren->image['href']);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$episodeImage) {
|
2023-08-24 17:03:11 +00:00
|
|
|
$channelChildren = $channel->children('http://www.itunes.com/dtds/podcast-1.0.dtd');
|
|
|
|
if ($channelChildren) {
|
|
|
|
$episodeImageAttributes = (array) $channelChildren->image->attributes();
|
2023-08-24 10:48:10 +00:00
|
|
|
$episodeImage = $this->stringOrNull(array_key_exists('href', $episodeImageAttributes) ? (string) $episodeImageAttributes['href'] : '');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$episodeImage) {
|
|
|
|
preg_match('/<itunes:image\s+href="([^"]+)"/', $xmlString, $matches);
|
|
|
|
$episodeImage = $this->stringOrNull($matches[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get episode description
|
2023-08-29 10:04:14 +00:00
|
|
|
$episodeDescription = $this->stringOrNull($item->description);
|
2023-08-24 10:48:10 +00:00
|
|
|
|
2023-08-29 10:04:14 +00:00
|
|
|
$episodeContentChildren = $item->children('content', true);
|
2023-08-24 10:48:10 +00:00
|
|
|
if ($episodeContentChildren) {
|
|
|
|
$episodeDescription = $this->stringOrNull($episodeContentChildren->encoded);
|
|
|
|
}
|
|
|
|
|
2023-08-24 18:53:54 +00:00
|
|
|
// Remove tags
|
|
|
|
$episodeDescription = strip_tags($episodeDescription ?? '');
|
2023-08-24 10:48:10 +00:00
|
|
|
|
2023-08-24 17:03:11 +00:00
|
|
|
// Get episode pubDate
|
|
|
|
$rawPubDate = $this->stringOrNull($item->pubDate);
|
|
|
|
$episodePubDate = $rawPubDate ? new \DateTime($rawPubDate) : null;
|
|
|
|
|
2023-08-24 10:48:10 +00:00
|
|
|
$episodes[] = new EpisodeActionExtraData(
|
|
|
|
$episodeUrl,
|
|
|
|
$this->stringOrNull($channel->title),
|
|
|
|
$episodeName,
|
|
|
|
$episodeLink,
|
|
|
|
$episodeImage,
|
|
|
|
$episodeDescription,
|
|
|
|
$fetchedAtUnix ?? (new \DateTime())->getTimestamp(),
|
2023-08-28 15:44:17 +00:00
|
|
|
$episodeGuid,
|
2023-08-24 17:03:11 +00:00
|
|
|
$episodePubDate,
|
|
|
|
$episodeFilesize,
|
2023-08-29 10:04:14 +00:00
|
|
|
$episodeDuration ?? null,
|
|
|
|
$episodeAction
|
2023-08-24 10:48:10 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $episodes;
|
|
|
|
}
|
|
|
|
|
2023-08-24 16:22:40 +00:00
|
|
|
/**
|
|
|
|
* @param null|\SimpleXMLElement|string $value
|
|
|
|
*/
|
2023-12-23 16:25:20 +00:00
|
|
|
private function stringOrNull($value): ?string {
|
2023-08-24 10:48:10 +00:00
|
|
|
if ($value) {
|
|
|
|
return (string) $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|