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 [
'routes' => [
['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' => 'toplist#index', 'url' => '/toplist/{count}', 'verb' => 'GET'],
],
];

View File

@ -5,7 +5,7 @@
"license": "AGPL-3.0-or-later",
"require-dev": {
"nextcloud/ocp": "^27.0.2",
"psalm/phar": "^5.14.1",
"psalm/phar": "^5.15.0",
"nextcloud/coding-standard": "^1.1.1"
},
"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",
"This file is @generated automatically"
],
"content-hash": "3fa8e5aac39e7c385a793eff9a78e763",
"content-hash": "c0c30dda23dd29e41502385edf3227da",
"packages": [],
"packages-dev": [
{
@ -94,16 +94,16 @@
},
{
"name": "php-cs-fixer/shim",
"version": "v3.22.0",
"version": "v3.23.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/shim.git",
"reference": "f6692934a6d1fe40fd8bc3339487490baa4a6700"
"reference": "ddca9b342374087121e44cca3b7d8aca8f121fa7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/f6692934a6d1fe40fd8bc3339487490baa4a6700",
"reference": "f6692934a6d1fe40fd8bc3339487490baa4a6700",
"url": "https://api.github.com/repos/PHP-CS-Fixer/shim/zipball/ddca9b342374087121e44cca3b7d8aca8f121fa7",
"reference": "ddca9b342374087121e44cca3b7d8aca8f121fa7",
"shasum": ""
},
"require": {
@ -140,9 +140,9 @@
"description": "A tool to automatically fix PHP code style",
"support": {
"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",

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;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCA\RePod\AppInfo\Application;
use OCA\RePod\Service\FyydService;
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']));
$podcasts = array_intersect_key($podcasts, array_unique(array_map(fn (array $feed) => $feed['url'], $podcasts)));
usort($podcasts, fn (PodcastData $a, PodcastData $b) => $a->getFetchedAtUnix() <=> $b->getFetchedAtUnix());
$podcasts = array_intersect_key($podcasts, array_unique(array_map(fn (PodcastData $feed) => $feed->getLink(), $podcasts)));
return new JSONResponse($podcasts);
}

View File

@ -4,14 +4,12 @@ declare(strict_types=1);
namespace OCA\RePod\Service;
use OCA\GPodderSync\Core\PodcastData\PodcastData;
use OCP\Http\Client\IClientService;
use OCP\IUserSession;
use OCP\L10N\IFactory;
use Psr\Log\LoggerInterface;
/**
* @psalm-import-type Podcast from IProvider
*/
class FyydService implements IProvider
{
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'])) {
/** @var string[] $feed */
foreach ($json['data'] as $feed) {
$podcasts[] = [
'id' => $feed['id'],
'provider' => 'fyyd',
'website' => $feed['htmlURL'],
'description' => $feed['description'],
'title' => $feed['title'],
'author' => $feed['author'],
'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'],
];
$podcasts[] = new PodcastData(
$feed['title'],
$feed['author'],
$feed['xmlURL'],
$feed['description'],
$feed['imgURL'],
strtotime($feed['lastpub'])
);
}
}
@ -63,7 +55,7 @@ class FyydService implements IProvider
}
/**
* @return Podcast[]
* @return PodcastData[]
*/
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'])) {
/** @var string[] $feed */
foreach ($postCastJson['data'] as $feed) {
$podcasts[] = [
'id' => $feed['id'],
'provider' => 'fyyd',
'website' => $feed['htmlURL'],
'description' => $feed['description'],
'title' => $feed['title'],
'author' => $feed['author'],
'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'],
];
$podcasts[] = new PodcastData(
$feed['title'],
$feed['author'],
$feed['xmlURL'],
$feed['description'],
$feed['imgURL'],
strtotime($feed['lastpub'])
);
}
}

View File

@ -4,26 +4,12 @@ declare(strict_types=1);
namespace OCA\RePod\Service;
/**
* @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
* }
*/
use OCA\GPodderSync\Core\PodcastData\PodcastData;
interface IProvider
{
/**
* @return Podcast[]
* @return PodcastData[]
*/
public function search(string $value): array;
}

View File

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

View File

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

View File

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

View File

@ -19,6 +19,19 @@ namespace OCA\GPodderSync\Core\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
*/

View File

@ -17,6 +17,17 @@ namespace OCA\GPodderSync\Core\PodcastData;
*/
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
* @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
{
public function __construct(
private string $url,
private int $listenedSeconds = 0,
private ?PodcastActionCounts $actionCounts = null
) {
}
/**
* @return string
*/

View File

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

View File

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