feat(plugins): add before channel/item hooks to allow podcast/episode data edit when generating rss

This commit is contained in:
Yassine Doghri 2024-05-17 14:01:04 +00:00
parent 8b70dc3d26
commit 3b47edf45d
15 changed files with 48 additions and 31 deletions

View File

@ -47,6 +47,8 @@ if (! function_exists('get_rss_feed')) {
"<?xml version='1.0' encoding='utf-8'?><rss version='2.0' xmlns:itunes='{$itunesNamespace}' xmlns:podcast='{$podcastNamespace}' xmlns:atom='{$atomNamespace}' xmlns:content='http://purl.org/rss/1.0/modules/content/'></rss>"
);
$plugins->rssBeforeChannel($podcast);
$channel = $rss->addChild('channel');
$atomLink = $channel->addChild('link', null, $atomNamespace);
@ -298,13 +300,15 @@ if (! function_exists('get_rss_feed')) {
}
// run plugins hook at the end
$plugins->channelTag($podcast, $channel);
$plugins->rssAfterChannel($podcast, $channel);
foreach ($episodes as $episode) {
if ($episode->is_premium && ! $subscription instanceof Subscription) {
continue;
}
$plugins->rssBeforeItem($episode);
$item = $channel->addChild('item');
$item->addChild('title', $episode->title, null, false);
$enclosure = $item->addChild('enclosure');
@ -460,7 +464,7 @@ if (! function_exists('get_rss_feed')) {
], $item);
}
$plugins->itemTag($episode, $item);
$plugins->rssAfterItem($episode, $item);
}
return $rss->asXML();

View File

@ -187,7 +187,7 @@ class PluginController extends BaseController
$validatedData = $this->validator->getValidated();
foreach ($plugin->getSettingsFields('general') as $field) {
foreach ($plugin->getSettingsFields($type) as $field) {
$value = $validatedData[$field->key] ?? null;
$fieldValue = $value === '' ? null : match ($plugins::FIELDS_CASTS[$field->type] ?? 'text') {
'bool' => $value === 'yes',

View File

@ -52,7 +52,7 @@ abstract class BasePlugin implements PluginInterface
// TODO: cache manifest data
$manifestPath = $directory . '/manifest.json';
$manifestContents = file_get_contents($manifestPath);
$manifestContents = @file_get_contents($manifestPath);
if (! $manifestContents) {
$manifestContents = '{}';
@ -93,18 +93,19 @@ abstract class BasePlugin implements PluginInterface
$this->{$name} = $value;
}
public function init(): void
{
// add to admin navigation
// TODO: setup navigation and views?
}
public function channelTag(Podcast $podcast, SimpleRSSElement $channel): void
public function rssBeforeChannel(Podcast $podcast): void
{
}
public function itemTag(Episode $episode, SimpleRSSElement $item): void
public function rssAfterChannel(Podcast $podcast, SimpleRSSElement $channel): void
{
}
public function rssBeforeItem(Episode $episode): void
{
}
public function rssAfterItem(Episode $episode, SimpleRSSElement $item): void
{
}

View File

@ -10,9 +10,13 @@ use App\Libraries\SimpleRSSElement;
interface PluginInterface
{
public function channelTag(Podcast $podcast, SimpleRSSElement $channel): void;
public function rssBeforeChannel(Podcast $podcast): void;
public function itemTag(Episode $episode, SimpleRSSElement $item): void;
public function rssAfterChannel(Podcast $podcast, SimpleRSSElement $channel): void;
public function rssBeforeItem(Episode $episode): void;
public function rssAfterItem(Episode $episode, SimpleRSSElement $item): void;
public function siteHead(): void;
}

View File

@ -10,9 +10,11 @@ use App\Libraries\SimpleRSSElement;
use Config\Database;
/**
* @method void channelTag(Podcast $podcast, SimpleRSSElement $channel)
* @method void itemTag(Episode $episode, SimpleRSSElement $item)
* @method string siteHead()
* @method void rssBeforeChannel(Podcast $podcast)
* @method void rssAfterChannel(Podcast $podcast, SimpleRSSElement $channel)
* @method void rssBeforeItem(Episode $episode)
* @method void rssAfterItem(Episode $episode, SimpleRSSElement $item)
* @method void siteHead()
*/
class Plugins
{
@ -21,7 +23,7 @@ class Plugins
/**
* @var list<string>
*/
public const HOOKS = ['channelTag', 'itemTag', 'siteHead'];
public const HOOKS = ['rssBeforeChannel', 'rssAfterChannel', 'rssBeforeItem', 'rssAfterItem', 'siteHead'];
public const FIELDS_VALIDATIONS = [
'checkbox' => ['permit_empty'],

View File

@ -34,7 +34,7 @@ class Manifest extends ManifestObject
'license' => 'permit_empty|string',
'private' => 'permit_empty|is_boolean',
'keywords.*' => 'permit_empty',
'hooks.*' => 'permit_empty|in_list[channelTag,itemTag,siteHead]',
'hooks.*' => 'permit_empty|in_list[rssBeforeChannel,rssAfterChannel,rssBeforeItem,rssAfterItem,siteHead]',
'settings' => 'permit_empty|is_list',
'repository' => 'permit_empty|is_list',
];

View File

@ -87,7 +87,13 @@
"description": "The hooks used by the plugin.",
"type": "array",
"items": {
"enum": ["channelTag", "itemTag", "siteHead"]
"enum": [
"rssBeforeChannel",
"rssAfterChannel",
"rssBeforeItem",
"rssAfterItem",
"siteHead"
]
},
"uniqueItems": true
},

View File

@ -28,7 +28,7 @@
label="<?= esc(lang('Contributor.form.role')) ?>"
options="<?= esc(json_encode($roleOptions)) ?>"
placeholder="<?= lang('Contributor.form.role_placeholder') ?>"
selected="<?= setting('AuthGroups.defaultPodcastGroup') ?>"
defaultValue="<?= setting('AuthGroups.defaultPodcastGroup') ?>"
isRequired="true" />
<x-Button type="submit" class="self-end" variant="primary"><?= lang('Contributor.form.submit_add') ?></x-Button>

View File

@ -19,7 +19,7 @@
name="role"
label="<?= esc(lang('Contributor.form.role')) ?>"
options="<?= esc(json_encode($roleOptions)) ?>"
selected="<?= $contributorGroup ?>"
defaultValue="<?= $contributorGroup ?>"
placeholder="<?= lang('Contributor.form.role_placeholder') ?>"
isRequired="true" />

View File

@ -30,7 +30,7 @@
label="<?= esc(lang('Person.episode_form.persons')) ?>"
hint="<?= esc(lang('Person.episode_form.persons_hint')) ?>"
options="<?= esc(json_encode($personOptions)) ?>"
selected="<?= esc(json_encode(old('persons', []))) ?>"
defaultValue="<?= esc(json_encode(old('persons', []))) ?>"
isRequired="true"
/>
@ -41,7 +41,7 @@
label="<?= esc(lang('Person.episode_form.roles')) ?>"
hint="<?= esc(lang('Person.episode_form.roles_hint')) ?>"
options="<?= esc(json_encode($taxonomyOptions)) ?>"
selected="<?= esc(json_encode(old('roles', []))) ?>"
defaultValue="<?= esc(json_encode(old('roles', []))) ?>"
/>
<x-Button variant="primary" type="submit" class="self-end"><?= lang('Person.episode_form.submit_add') ?></x-Button>

View File

@ -44,7 +44,7 @@
as="Select"
name="language"
label="<?= esc(lang('Podcast.form.language')) ?>"
selected="<?= $browserLang ?>"
defaultValue="<?= $browserLang ?>"
isRequired="true"
options="<?= esc(json_encode($languageOptions)) ?>" />

View File

@ -30,7 +30,7 @@
label="<?= esc(lang('Person.podcast_form.persons')) ?>"
hint="<?= esc(lang('Person.podcast_form.persons_hint')) ?>"
options="<?= esc(json_encode($personOptions)) ?>"
selected="<?= esc(json_encode(old('persons', []))) ?>"
defaultValue="<?= esc(json_encode(old('persons', []))) ?>"
isRequired="true" />
<x-Forms.Field
@ -40,7 +40,7 @@
label="<?= esc(lang('Person.podcast_form.roles')) ?>"
hint="<?= esc(lang('Person.podcast_form.roles_hint')) ?>"
options="<?= esc(json_encode($taxonomyOptions)) ?>"
selected="<?= esc(json_encode(old('roles', []))) ?>"
defaultValue="<?= esc(json_encode(old('roles', []))) ?>"
/>
<x-Button variant="primary" class="self-end" type="submit"><?= lang('Person.podcast_form.submit_add') ?></x-Button>

View File

@ -30,7 +30,7 @@
name="role"
label="<?= esc(lang('User.form.role')) ?>"
options="<?= esc(json_encode($roleOptions)) ?>"
selected="<?= setting('AuthGroups.defaultGroup') ?>"
defaultValue="<?= setting('AuthGroups.defaultGroup') ?>"
isRequired="true" />
<x-Button variant="primary" type="submit" class="self-end"><?= lang('User.form.submit_create') ?></x-Button>

View File

@ -23,7 +23,7 @@
name="role"
label="<?= esc(lang('User.form.role')) ?>"
options="<?= esc(json_encode($roleOptions)) ?>"
selected="<?= esc(get_instance_group($user)) ?>"
defaultValue="<?= esc(get_instance_group($user)) ?>"
isRequired="true" />
<x-Button variant="primary" type="submit" class="self-end mt-4"><?= lang('User.form.submit_edit') ?></x-Button>

View File

@ -25,7 +25,7 @@
'redis' => lang('Install.form.cacheHandlerOptions.redis'),
'predis' => lang('Install.form.cacheHandlerOptions.predis'),
])) ?>"
selected="file"
defaultValue="file"
isRequired="true" />
<?php // @icon('arrow-right-fill')?>
<x-Button variant="primary" class="self-end" iconRight="arrow-right-fill" type="submit"><?= lang('Install.form.next') ?></x-Button>