Add author and email fields to podcasts (#4451)
This commit is contained in:
parent
b5fc9ad601
commit
7d29d78ff7
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -44,6 +44,16 @@ class Podcast
|
|||
*/
|
||||
public ?string $language = null;
|
||||
|
||||
/**
|
||||
* @OA\Property()
|
||||
*/
|
||||
public ?string $author = null;
|
||||
|
||||
/**
|
||||
* @OA\Property()
|
||||
*/
|
||||
public ?string $email = null;
|
||||
|
||||
/**
|
||||
* @OA\Property()
|
||||
*/
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: { }
|
||||
|
|
Loading…
Reference in New Issue