Add author and email fields to podcasts (#4451)

This commit is contained in:
Vaalyn 2021-08-05 05:50:32 +02:00 committed by GitHub
parent b5fc9ad601
commit 7d29d78ff7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 167 additions and 27 deletions

View File

@ -54,6 +54,8 @@ export default {
'link': '',
'description': '',
'language': 'en',
'author': '',
'email': '',
'categories': [],
'artwork_file': null
}
@ -72,6 +74,8 @@ export default {
'link': {},
'description': {},
'language': { required },
'author': {},
'email': {},
'categories': { required },
'artwork_file': {}
}
@ -90,6 +94,8 @@ export default {
'link': '',
'description': '',
'language': 'en',
'author': '',
'email': '',
'categories': [],
'artwork_file': null
};
@ -101,6 +107,8 @@ export default {
'link': d.link,
'description': d.description,
'language': d.language,
'author': d.author,
'email': d.email,
'categories': d.categories,
'artwork_file': null
};

View File

@ -49,6 +49,28 @@
</b-form-invalid-feedback>
</b-form-group>
<b-form-group class="col-md-6" label-for="form_edit_author">
<template #label>
<translate key="lang_form_edit_author">Author</translate>
</template>
<template #description>
<translate key="lang_form_edit_author_desc">The contact person of the podcast. May be required in order to list the podcast on services like Apple Podcasts, Spotify, Google Podcasts, etc.</translate>
</template>
<b-form-input id="form_edit_author" type="text" v-model="form.author.$model"
:state="form.author.$dirty ? !form.author.$error : null"></b-form-input>
</b-form-group>
<b-form-group class="col-md-6" label-for="form_edit_email">
<template #label>
<translate key="lang_form_edit_email">E-Mail</translate>
</template>
<template #description>
<translate key="lang_form_edit_email_desc">The email of the podcast contact. May be required in order to list the podcast on services like Apple Podcasts, Spotify, Google Podcasts, etc.</translate>
</template>
<b-form-input id="form_edit_email" type="email" v-model="form.email.$model"
:state="form.email.$dirty ? !form.email.$error : null"></b-form-input>
</b-form-group>
<b-form-group class="col-md-12" label-for="form_edit_categories">
<template #label>
<translate key="lang_form_edit_categories">Categories</translate>

View File

@ -258,6 +258,8 @@ class PodcastsController extends AbstractApiCrudController
$return->link = $record->getLink();
$return->description = $record->getDescription();
$return->language = $record->getLanguage();
$return->author = $record->getAuthor();
$return->email = $record->getEmail();
$categories = [];
foreach ($record->getCategories() as $category) {

View File

@ -31,6 +31,7 @@ use MarcW\RssWriter\Extension\DublinCore\DublinCore;
use MarcW\RssWriter\Extension\DublinCore\DublinCoreWriter;
use MarcW\RssWriter\Extension\Itunes\ItunesChannel;
use MarcW\RssWriter\Extension\Itunes\ItunesItem;
use MarcW\RssWriter\Extension\Itunes\ItunesOwner;
use MarcW\RssWriter\Extension\Itunes\ItunesWriter;
use MarcW\RssWriter\Extension\Slash\Slash;
use MarcW\RssWriter\Extension\Slash\SlashWriter;
@ -156,6 +157,7 @@ class PodcastFeedController
$itunesChannel->setExplicit($containsExplicitContent);
$itunesChannel->setImage($rssImage->getUrl());
$itunesChannel->setCategories($this->buildItunesCategoriesForPodcast($podcast));
$itunesChannel->setOwner($this->buildItunesOwner($podcast));
$channel->addExtension($itunesChannel);
$channel->addExtension(new Sy());
@ -206,6 +208,19 @@ class PodcastFeedController
)->getValues();
}
protected function buildItunesOwner(Podcast $podcast): ?ItunesOwner
{
if (empty($podcast->getAuthor()) && empty($podcast->getEmail())) {
return null;
}
$itunesOwner = new ItunesOwner();
$itunesOwner->setName($podcast->getAuthor());
$itunesOwner->setEmail($podcast->getEmail());
return $itunesOwner;
}
protected function buildRssImageForPodcast(Podcast $podcast, Station $station): RssImage
{
$podcastsFilesystem = (new StationFilesystems($station))->getPodcastsFilesystem();

View File

@ -44,6 +44,16 @@ class Podcast
*/
public ?string $language = null;
/**
* @OA\Property()
*/
public ?string $author = null;
/**
* @OA\Property()
*/
public ?string $email = null;
/**
* @OA\Property()
*/

View File

@ -24,6 +24,8 @@ class Podcast extends AbstractFixture implements DependentFixtureInterface
$podcast->setLink('https://demo.azuracast.com');
$podcast->setLanguage('en');
$podcast->setDescription('The unofficial testing podcast for the AzuraCast development team.');
$podcast->setAuthor('AzuraCast');
$podcast->setEmail('demo@azuracast.com');
$manager->persist($podcast);
$category = new Entity\PodcastCategory($podcast, 'Technology');

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace App\Entity\Migration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20210805004608 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE podcast ADD author VARCHAR(255) NOT NULL, ADD email VARCHAR(255) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE podcast DROP author, DROP email');
}
}

View File

@ -41,6 +41,13 @@ class Podcast implements IdentifiableEntityInterface
#[Assert\NotBlank]
protected string $language;
#[ORM\Column(length: 255)]
protected string $author;
#[ORM\Column(length: 255)]
#[Assert\Email]
protected string $email;
#[ORM\Column]
#[Attributes\AuditIgnore]
protected int $art_updated_at = 0;
@ -112,6 +119,30 @@ class Podcast implements IdentifiableEntityInterface
return $this;
}
public function getAuthor(): string
{
return $this->author;
}
public function setAuthor(string $author): self
{
$this->author = $this->truncateString($author);
return $this;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $this->truncateString($email);
return $this;
}
public function getArtUpdatedAt(): int
{
return $this->art_updated_at;

View File

@ -22,10 +22,14 @@ class Api_Stations_PodcastsCest extends CestAbstract
'title' => 'My Awesome Podcast',
'description' => 'A functional test podcast.',
'language' => 'en',
'author' => 'AzuraCast',
'email' => 'demo@azuracast.com',
],
[
'title' => 'My Modified Podcast',
'language' => 'de',
'author' => 'Test',
'email' => 'test@azuracast.com',
]
);
@ -36,6 +40,8 @@ class Api_Stations_PodcastsCest extends CestAbstract
'title' => 'Episode Test Podcast',
'description' => 'A podcast with episodes.',
'language' => 'en',
'author' => 'AzuraCast',
'email' => 'demo@azuracast.com',
]
);
$I->seeResponseCodeIs(200);

View File

@ -1287,6 +1287,7 @@ paths:
tags:
- 'Stations: Podcasts'
description: 'List all current episodes for a given podcast ID.'
operationId: dfc3e15b5f248268049b3385273c9fcd
parameters:
-
$ref: '#/components/parameters/station_id_required'
@ -1315,6 +1316,7 @@ paths:
tags:
- 'Stations: Podcasts'
description: 'Create a new podcast episode.'
operationId: 6180faa6d38da9d2940e915ac52afe3d
parameters:
-
$ref: '#/components/parameters/station_id_required'
@ -1347,6 +1349,7 @@ paths:
tags:
- 'Stations: Podcasts'
description: 'Retrieve details for a single podcast episode.'
operationId: 42b633bfbff63bba34e9be9d70b7f396
parameters:
-
$ref: '#/components/parameters/station_id_required'
@ -1380,6 +1383,7 @@ paths:
tags:
- 'Stations: Podcasts'
description: 'Update details of a single podcast episode.'
operationId: ad714f969f4b06e41f9ac3e321bf98dc
parameters:
-
$ref: '#/components/parameters/station_id_required'
@ -1418,6 +1422,7 @@ paths:
tags:
- 'Stations: Podcasts'
description: 'Delete a single podcast episode.'
operationId: 5a3d46510c6c700332d8a30b83d53eb5
parameters:
-
$ref: '#/components/parameters/station_id_required'
@ -2229,10 +2234,12 @@ components:
type: integer
example: 1
name:
nullable: true
description: 'Station name'
type: string
example: 'AzuraTest Radio'
shortcode:
nullable: true
description: 'Station "short code", used for URL and folder paths'
type: string
example: azuratest_radio
@ -2252,10 +2259,12 @@ components:
type: string
example: Variety
type:
nullable: true
description: 'Which broadcasting software (frontend) the station uses'
type: string
example: shoutcast2
port:
nullable: true
description: 'The port used by this station to serve its broadcasts.'
type: integer
example: 8000
@ -2407,11 +2416,11 @@ components:
connected_on:
description: 'UNIX timestamp that the user first connected.'
type: integer
example: 1624884448
example: 1628078314
connected_until:
description: 'UNIX timestamp that the user disconnected (or the latest timestamp if they are still connected).'
type: integer
example: 1624884448
example: 1628078314
connected_time:
description: 'Number of seconds that the user has been connected.'
type: integer
@ -2541,6 +2550,12 @@ components:
language:
nullable: true
type: string
author:
nullable: true
type: string
email:
nullable: true
type: string
has_custom_art:
type: boolean
art:
@ -2653,7 +2668,7 @@ components:
played_at:
description: 'UNIX timestamp when playback started.'
type: integer
example: 1624884448
example: 1628078314
duration:
description: 'Duration of the song in seconds'
type: integer
@ -2789,7 +2804,7 @@ components:
cued_at:
description: 'UNIX timestamp when playback is expected to start.'
type: integer
example: 1624884448
example: 1628078314
duration:
description: 'Duration of the song in seconds'
type: integer
@ -2878,7 +2893,7 @@ components:
start_timestamp:
description: 'The start time of the schedule entry, in UNIX format.'
type: integer
example: 1624884448
example: 1628078314
start:
description: 'The start time of the schedule entry, in ISO 8601 format.'
type: string
@ -2886,7 +2901,7 @@ components:
end_timestamp:
description: 'The end time of the schedule entry, in UNIX format.'
type: integer
example: 1624884448
example: 1628078314
end:
description: 'The start time of the schedule entry, in ISO 8601 format.'
type: string
@ -2926,7 +2941,7 @@ components:
timestamp:
description: 'The current UNIX timestamp'
type: integer
example: 1624884448
example: 1628078314
type: object
Api_Time:
properties:
@ -2974,7 +2989,6 @@ components:
name:
type: string
short_name:
nullable: true
description: 'The programmatic name for the field. Can be auto-generated from the full name.'
type: string
auto_assign:
@ -3000,10 +3014,10 @@ components:
example: true
created_at:
type: integer
example: 1624884448
example: 1628078314
updated_at:
type: integer
example: 1624884448
example: 1628078314
Role:
type: object
allOf:
@ -3069,7 +3083,7 @@ components:
update_last_run:
description: 'The UNIX timestamp when updates were last checked.'
type: integer
example: 1624884448
example: 1628078314
public_theme:
nullable: true
description: 'Base Theme for Public Pages'
@ -3146,7 +3160,7 @@ components:
backup_last_run:
description: 'The UNIX timestamp when automated backup was last run.'
type: integer
example: 1624884448
example: 1628078314
backup_last_result:
nullable: true
description: 'The result of the latest automated backup task.'
@ -3160,26 +3174,26 @@ components:
setup_complete_time:
description: 'The UNIX timestamp when setup was last completed.'
type: integer
example: 1624884448
example: 1628078314
nowplaying:
description: 'The current cached now playing data.'
example: ''
sync_nowplaying_last_run:
description: 'The UNIX timestamp when the now playing sync task was last run.'
type: integer
example: 1624884448
example: 1628078314
sync_short_last_run:
description: 'The UNIX timestamp when the 60-second ''short'' sync task was last run.'
type: integer
example: 1624884448
example: 1628078314
sync_medium_last_run:
description: 'The UNIX timestamp when the 5-minute ''medium'' sync task was last run.'
type: integer
example: 1624884448
example: 1628078314
sync_long_last_run:
description: 'The UNIX timestamp when the 1-hour ''long'' sync task was last run.'
type: integer
example: 1624884448
example: 1628078314
external_ip:
nullable: true
description: 'This installation''s external IP.'
@ -3193,7 +3207,7 @@ components:
geolite_last_run:
description: 'The UNIX timestamp when the Maxmind Geolite was last downloaded.'
type: integer
example: 1624884448
example: 1628078314
enable_advanced_features:
description: 'Whether to enable ''advanced'' functionality in the system that is intended for power users.'
type: boolean
@ -3254,12 +3268,10 @@ components:
-
properties:
name:
nullable: true
description: 'The full display name of the station.'
type: string
example: 'AzuraTest Radio'
short_name:
nullable: true
description: 'The URL-friendly name for the station, typically auto-generated from the full station name.'
type: string
example: azuratest_radio
@ -3407,7 +3419,7 @@ components:
nullable: true
description: 'The UNIX timestamp when the database was last modified.'
type: integer
example: 1624884448
example: 1628078314
amplify:
nullable: true
description: 'The amount of amplification (in dB) to be applied to the radio source (liq_amplify)'
@ -3447,7 +3459,7 @@ components:
art_updated_at:
description: 'The latest time (UNIX timestamp) when album art was updated.'
type: integer
example: 1624884448
example: 1628078314
playlists:
type: array
items: { }
@ -3618,7 +3630,6 @@ components:
type: string
example: 'https://custom-listen-url.example.com/stream.mp3'
url:
nullable: true
type: string
example: 'https://custom-url.example.com'
mount:
@ -3674,6 +3685,9 @@ components:
description: 'Array of ISO-8601 days (1 for Monday, 7 for Sunday)'
type: string
example: '0,1,2,3'
loop_once:
type: boolean
example: false
StationStreamer:
description: 'Station streamers (DJ accounts) allowed to broadcast to a station.'
type: object
@ -3705,7 +3719,7 @@ components:
reactivate_at:
nullable: true
type: integer
example: 1624884448
example: 1628078314
schedule_items:
type: array
items: { }
@ -3780,7 +3794,6 @@ components:
-
properties:
email:
nullable: true
type: string
example: demo@azuracast.com
new_password:
@ -3805,10 +3818,10 @@ components:
example: A1B2C3D4
created_at:
type: integer
example: 1624884448
example: 1628078314
updated_at:
type: integer
example: 1624884448
example: 1628078314
roles:
type: array
items: { }