Back ready !
All checks were successful
repod / nextcloud (push) Successful in 1m15s
repod / nodejs (push) Successful in 1m52s

This commit is contained in:
Michel Roux 2023-08-22 19:41:17 +02:00
parent 392b5bcabc
commit 941e1cabbd
15 changed files with 138 additions and 75 deletions

View File

@ -13,7 +13,8 @@ declare(strict_types=1);
return [ return [
'routes' => [ 'routes' => [
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'], ['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'toplist#index', 'url' => '/toplist/{count}', 'verb' => 'GET'], ['name' => 'fetch#index', 'url' => '/fetch/{uri}', 'verb' => 'GET'],
['name' => 'search#index', 'url' => '/search/{value}', 'verb' => 'GET'], ['name' => 'search#index', 'url' => '/search/{value}', 'verb' => 'GET'],
['name' => 'toplist#index', 'url' => '/toplist/{count}', 'verb' => 'GET'],
], ],
]; ];

View File

@ -5,7 +5,7 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"require-dev": { "require-dev": {
"nextcloud/ocp": "^27.0.2", "nextcloud/ocp": "^27.0.2",
"psalm/phar": "^5.14.1", "psalm/phar": "^5.15.0",
"nextcloud/coding-standard": "^1.1.1" "nextcloud/coding-standard": "^1.1.1"
}, },
"scripts": { "scripts": {

14
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "3fa8e5aac39e7c385a793eff9a78e763", "content-hash": "c0c30dda23dd29e41502385edf3227da",
"packages": [], "packages": [],
"packages-dev": [ "packages-dev": [
{ {
@ -94,16 +94,16 @@
}, },
{ {
"name": "php-cs-fixer/shim", "name": "php-cs-fixer/shim",
"version": "v3.22.0", "version": "v3.23.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/shim.git", "url": "https://github.com/PHP-CS-Fixer/shim.git",
"reference": "f6692934a6d1fe40fd8bc3339487490baa4a6700" "reference": "ddca9b342374087121e44cca3b7d8aca8f121fa7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/f6692934a6d1fe40fd8bc3339487490baa4a6700", "url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/ddca9b342374087121e44cca3b7d8aca8f121fa7",
"reference": "f6692934a6d1fe40fd8bc3339487490baa4a6700", "reference": "ddca9b342374087121e44cca3b7d8aca8f121fa7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -140,9 +140,9 @@
"description": "A tool to automatically fix PHP code style", "description": "A tool to automatically fix PHP code style",
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/shim/issues", "issues": "https://github.com/PHP-CS-Fixer/shim/issues",
"source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.22.0" "source": "https://github.com/PHP-CS-Fixer/shim/tree/v3.23.0"
}, },
"time": "2023-07-16T23:08:49+00:00" "time": "2023-08-14T12:28:46+00:00"
}, },
{ {
"name": "psalm/phar", "name": "psalm/phar",

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace OCA\RePod\Controller;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCA\GPodderSync\Core\PodcastData\PodcastDataReader;
use OCA\RePod\AppInfo\Application;
use OCA\RePod\Service\UserService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Http\Client\IClientService;
use OCP\IRequest;
class FetchController extends Controller
{
public function __construct(
IRequest $request,
private IClientService $clientService,
private UserService $userService,
private PodcastDataReader $podcastDataReader
) {
parent::__construct(Application::APP_ID, $request);
}
public function index(string $uri): JSONResponse
{
$podcastData = $this->podcastDataReader->getCachedOrFetchPodcastData($uri, $this->userService->getUserUID());
if ($podcastData) {
return new JSONResponse($podcastData->toArray());
}
$client = $this->clientService->newClient();
$feed = $client->get($uri);
$statusCode = $feed->getStatusCode();
if ($statusCode < 200 || $statusCode >= 300) {
throw new \ErrorException("Web request returned non-2xx status code: {$statusCode}");
}
$podcastData = PodcastData::parseRssXml((string) $feed->getBody());
return new JSONResponse($podcastData->toArray());
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace OCA\RePod\Controller; namespace OCA\RePod\Controller;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCA\RePod\AppInfo\Application; use OCA\RePod\AppInfo\Application;
use OCA\RePod\Service\FyydService; use OCA\RePod\Service\FyydService;
use OCA\RePod\Service\ItunesService; use OCA\RePod\Service\ItunesService;
@ -36,8 +37,8 @@ class SearchController extends Controller
} }
} }
usort($podcasts, fn (array $a, array $b) => new \DateTime((string) $b['lastpub']) <=> new \DateTime((string) $a['lastpub'])); usort($podcasts, fn (PodcastData $a, PodcastData $b) => $a->getFetchedAtUnix() <=> $b->getFetchedAtUnix());
$podcasts = array_intersect_key($podcasts, array_unique(array_map(fn (array $feed) => $feed['url'], $podcasts))); $podcasts = array_intersect_key($podcasts, array_unique(array_map(fn (PodcastData $feed) => $feed->getLink(), $podcasts)));
return new JSONResponse($podcasts); return new JSONResponse($podcasts);
} }

View File

@ -4,14 +4,12 @@ declare(strict_types=1);
namespace OCA\RePod\Service; namespace OCA\RePod\Service;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\IUserSession; use OCP\IUserSession;
use OCP\L10N\IFactory; use OCP\L10N\IFactory;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/**
* @psalm-import-type Podcast from IProvider
*/
class FyydService implements IProvider class FyydService implements IProvider
{ {
private const BASE_URL = 'https://api.fyyd.de/0.2/'; private const BASE_URL = 'https://api.fyyd.de/0.2/';
@ -42,20 +40,14 @@ class FyydService implements IProvider
if (array_key_exists('data', $json) && is_array($json['data'])) { if (array_key_exists('data', $json) && is_array($json['data'])) {
/** @var string[] $feed */ /** @var string[] $feed */
foreach ($json['data'] as $feed) { foreach ($json['data'] as $feed) {
$podcasts[] = [ $podcasts[] = new PodcastData(
'id' => $feed['id'], $feed['title'],
'provider' => 'fyyd', $feed['author'],
'website' => $feed['htmlURL'], $feed['xmlURL'],
'description' => $feed['description'], $feed['description'],
'title' => $feed['title'], $feed['imgURL'],
'author' => $feed['author'], strtotime($feed['lastpub'])
'url' => $feed['xmlURL'], );
'position_last_week' => $feed['rank'],
'mygpo_link' => $feed['url_fyyd'],
'logo_url' => $feed['imgURL'],
'lastpub' => $feed['lastpub'],
'episode_count' => $feed['episode_count'],
];
} }
} }
@ -63,7 +55,7 @@ class FyydService implements IProvider
} }
/** /**
* @return Podcast[] * @return PodcastData[]
*/ */
public function hot(int $count = 10): array public function hot(int $count = 10): array
{ {
@ -95,20 +87,14 @@ class FyydService implements IProvider
if (array_key_exists('data', $postCastJson) && is_array($postCastJson['data'])) { if (array_key_exists('data', $postCastJson) && is_array($postCastJson['data'])) {
/** @var string[] $feed */ /** @var string[] $feed */
foreach ($postCastJson['data'] as $feed) { foreach ($postCastJson['data'] as $feed) {
$podcasts[] = [ $podcasts[] = new PodcastData(
'id' => $feed['id'], $feed['title'],
'provider' => 'fyyd', $feed['author'],
'website' => $feed['htmlURL'], $feed['xmlURL'],
'description' => $feed['description'], $feed['description'],
'title' => $feed['title'], $feed['imgURL'],
'author' => $feed['author'], strtotime($feed['lastpub'])
'url' => $feed['xmlURL'], );
'position_last_week' => $feed['rank'],
'mygpo_link' => $feed['url_fyyd'],
'logo_url' => $feed['imgURL'],
'lastpub' => $feed['lastpub'],
'episode_count' => $feed['episode_count'],
];
} }
} }

View File

@ -4,26 +4,12 @@ declare(strict_types=1);
namespace OCA\RePod\Service; namespace OCA\RePod\Service;
/** use OCA\GPodderSync\Core\PodcastData\PodcastData;
* @psalm-type Podcast = array{
* id: string,
* provider: string,
* website: string,
* description: string,
* title: string,
* author: string,
* url: string,
* position_last_week: ?string,
* mygpo_link: string,
* logo_url: string,
* lastpub: string,
* episode_count: string
* }
*/
interface IProvider interface IProvider
{ {
/** /**
* @return Podcast[] * @return PodcastData[]
*/ */
public function search(string $value): array; public function search(string $value): array;
} }

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace OCA\RePod\Service; namespace OCA\RePod\Service;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
class ItunesService implements IProvider class ItunesService implements IProvider
@ -33,20 +34,14 @@ class ItunesService implements IProvider
if (array_key_exists('results', $json) && is_array($json['results'])) { if (array_key_exists('results', $json) && is_array($json['results'])) {
/** @var string[] $feed */ /** @var string[] $feed */
foreach ($json['results'] as $feed) { foreach ($json['results'] as $feed) {
$podcasts[] = [ $podcasts[] = new PodcastData(
'id' => $feed['id'], $feed['trackName'],
'provider' => 'itunes', $feed['artistName'],
'website' => $feed['trackViewUrl'], $feed['feedUrl'],
'description' => $feed['primaryGenreName'], $feed['primaryGenreName'],
'title' => $feed['trackName'], $feed['artworkUrl600'],
'author' => $feed['artistName'], strtotime($feed['releaseDate'])
'url' => $feed['feedUrl'], );
'position_last_week' => null,
'mygpo_link' => $feed['trackViewUrl'],
'logo_url' => $feed['artworkUrl600'],
'lastpub' => $feed['releaseDate'],
'episode_count' => $feed['trackCount'],
];
} }
} }

View File

@ -15,6 +15,13 @@ class UserService
) { ) {
} }
public function getUserUID(): string
{
$user = $this->userSession->getUser();
return $user ? $user->getUID() : '';
}
public function getIsoCode(): string public function getIsoCode(): string
{ {
return $this->l10n->getUserLanguage($this->userSession->getUser()); return $this->l10n->getUserLanguage($this->userSession->getUser());

View File

@ -6,7 +6,6 @@
findUnusedCode="false" findUnusedCode="false"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config" xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
> >
<projectFiles> <projectFiles>
<directory name="lib" /> <directory name="lib" />

View File

@ -19,6 +19,19 @@ namespace OCA\GPodderSync\Core\EpisodeAction;
*/ */
class EpisodeAction class EpisodeAction
{ {
public function __construct(
private string $podcast,
private string $episode,
private string $action,
private string $timestamp,
private int $started,
private int $position,
private int $total,
private ?string $guid,
private ?int $id
) {
}
/** /**
* @return string * @return string
*/ */

View File

@ -17,6 +17,17 @@ namespace OCA\GPodderSync\Core\PodcastData;
*/ */
class PodcastData implements \JsonSerializable class PodcastData implements \JsonSerializable
{ {
public function __construct(
private ?string $title,
private ?string $author,
private ?string $link,
private ?string $description,
private ?string $imageUrl,
private int $fetchedAtUnix,
private ?string $imageBlob = null
) {
}
/** /**
* @return PodcastData * @return PodcastData
* @throws \Exception if the XML data could not be parsed * @throws \Exception if the XML data could not be parsed

View File

@ -13,6 +13,13 @@ namespace OCA\GPodderSync\Core\PodcastData;
*/ */
class PodcastMetrics implements \JsonSerializable class PodcastMetrics implements \JsonSerializable
{ {
public function __construct(
private string $url,
private int $listenedSeconds = 0,
private ?PodcastActionCounts $actionCounts = null
) {
}
/** /**
* @return string * @return string
*/ */

View File

@ -6,6 +6,12 @@ namespace OCA\GPodderSync\Core\SubscriptionChange;
class SubscriptionChange class SubscriptionChange
{ {
public function __construct(
private string $url,
private bool $isSubscribed
) {
}
/** /**
* @return bool * @return bool
*/ */

View File

@ -6,6 +6,10 @@ namespace OCA\GPodderSync\Core\SubscriptionChange;
class SubscriptionChangeRequestParser class SubscriptionChangeRequestParser
{ {
public function __construct(private SubscriptionChangesReader $subscriptionChangeReader)
{
}
/** /**
* @return SubscriptionChange[] * @return SubscriptionChange[]
*/ */