nextcloud-gpodder/lib/Core/PodcastData/PodcastDataReader.php

98 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\GPodderSync\Core\PodcastData;
use Exception;
use OCA\GPodderSync\Db\SubscriptionChange\SubscriptionChangeRepository;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
use OCP\ICache;
use OCP\ICacheFactory;
class PodcastDataReader {
private ?ICache $cache = null;
private IClient $httpClient;
private SubscriptionChangeRepository $subscriptionChangeRepository;
public function __construct(
ICacheFactory $cacheFactory,
IClientService $httpClientService,
SubscriptionChangeRepository $subscriptionChangeRepository
) {
if ($cacheFactory->isLocalCacheAvailable()) {
$this->cache = $cacheFactory->createLocal('GPodderSync-Podcasts');
}
$this->httpClient = $httpClientService->newClient();
$this->subscriptionChangeRepository = $subscriptionChangeRepository;
}
public function getCachedOrFetchPodcastData(string $url, string $userId): ?PodcastData {
if ($this->cache == null) {
return $this->fetchPodcastData($url, $userId);
}
$oldData = $this->tryGetCachedPodcastData($url);
if ($oldData) {
return $oldData;
}
$newData = $this->fetchPodcastData($url, $userId);
$this->trySetCachedPodcastData($url, $newData);
return $newData;
}
private function userHasPodcast(string $url, string $userId): bool {
$subscriptionChanges = $this->subscriptionChangeRepository->findByUrl($url, $userId);
return $subscriptionChanges !== null;
}
public function fetchPodcastData(string $url, string $userId): ?PodcastData {
if (!$this->userHasPodcast($url, $userId)) {
return null;
}
$resp = $this->fetchUrl($url);
$data = PodcastData::parseRssXml($resp->getBody());
$blob = $this->tryFetchImageBlob($data);
if ($blob) {
$data->setImageBlob($blob);
}
return $data;
}
private function tryFetchImageBlob(PodcastData $data): ?string {
if (!$data->getImageUrl()) {
return null;
}
try {
$resp = $this->fetchUrl($data->getImageUrl());
$contentType = $resp->getHeader('Content-Type');
$body = $resp->getBody();
$bodyBase64 = base64_encode($body);
return "data:$contentType;base64,$bodyBase64";
} catch (Exception $e) {
return null;
}
}
private function fetchUrl(string $url): IResponse {
$resp = $this->httpClient->get($url);
$statusCode = $resp->getStatusCode();
if ($statusCode < 200 || $statusCode >= 300) {
throw new \ErrorException("Web request returned non-2xx status code: $statusCode");
}
return $resp;
}
public function tryGetCachedPodcastData(string $url): ?PodcastData {
$oldData = $this->cache->get($url);
if (!$oldData) {
return null;
}
return PodcastData::fromArray($oldData);
}
public function trySetCachedPodcastData(string $url, PodcastData $data): bool {
return $this->cache->set($url, $data->toArray());
}
}