Add source to podcast, add related DB records and API responses.

This commit is contained in:
Buster Neece 2024-02-22 14:27:56 -06:00
parent ca425d3e9c
commit d08235a8da
No known key found for this signature in database
8 changed files with 171 additions and 21 deletions

View File

@ -21,6 +21,15 @@ final class Podcast
#[OA\Property]
public int $storage_location_id;
#[OA\Property]
public string $source;
#[OA\Property]
public ?int $playlist_id = null;
#[OA\Property]
public bool $playlist_auto_publish = false;
#[OA\Property]
public string $title;

View File

@ -43,7 +43,10 @@ final class PodcastEpisode
public bool $has_media = false;
#[OA\Property]
public PodcastMedia $media;
public ?string $playlist_media_id = null;
#[OA\Property]
public ?PodcastMedia $media = null;
#[OA\Property]
public bool $has_custom_art = false;

View File

@ -38,6 +38,10 @@ final class PodcastApiGenerator
$return->id = $record->getIdRequired();
$return->storage_location_id = $record->getStorageLocation()->getIdRequired();
$return->source = $record->getSource()->value;
$return->playlist_id = $record->getPlaylist()?->getIdRequired();
$return->playlist_auto_publish = $record->playlistAutoPublish();
$return->title = $record->getTitle();
$return->link = $record->getLink();

View File

@ -6,8 +6,10 @@ namespace App\Entity\ApiGenerator;
use App\Entity\Api\PodcastEpisode as ApiPodcastEpisode;
use App\Entity\Api\PodcastMedia as ApiPodcastMedia;
use App\Entity\Enums\PodcastSources;
use App\Entity\PodcastEpisode;
use App\Entity\PodcastMedia;
use App\Entity\StationMedia;
use App\Http\ServerRequest;
use App\Utilities\Strings;
@ -34,21 +36,40 @@ final class PodcastEpisodeApiGenerator
$return->created_at = $record->getCreatedAt();
$return->publish_at = $record->getPublishAt();
$mediaRow = $record->getMedia();
$return->has_media = ($mediaRow instanceof PodcastMedia);
if ($mediaRow instanceof PodcastMedia) {
$media = new ApiPodcastMedia();
$media->id = $mediaRow->getId();
$media->original_name = $mediaRow->getOriginalName();
$media->length = $mediaRow->getLength();
$media->length_text = $mediaRow->getLengthText();
$media->path = $mediaRow->getPath();
switch ($podcast->getSource()) {
case PodcastSources::Playlist:
$return->media = null;
$return->has_media = true;
$return->media = $media;
} else {
$return->has_media = false;
$return->media = new ApiPodcastMedia();
$playlistMediaRow = $record->getPlaylistMedia();
if ($playlistMediaRow instanceof StationMedia) {
$return->has_media = true;
$return->playlist_media_id = $playlistMediaRow->getUniqueId();
} else {
$return->has_media = false;
$return->playlist_media_id = null;
}
break;
case PodcastSources::Manual:
$return->playlist_media_id = null;
$mediaRow = $record->getMedia();
$return->has_media = ($mediaRow instanceof PodcastMedia);
if ($mediaRow instanceof PodcastMedia) {
$media = new ApiPodcastMedia();
$media->id = $mediaRow->getId();
$media->original_name = $mediaRow->getOriginalName();
$media->length = $mediaRow->getLength();
$media->length_text = $mediaRow->getLengthText();
$media->path = $mediaRow->getPath();
$return->has_media = true;
$return->media = $media;
} else {
$return->has_media = false;
$return->media = null;
}
break;
}
$return->is_published = $record->isPublished();

View File

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace App\Entity\Enums;
enum PodcastSources: string
{
case Manual = 'manual';
case Playlist = 'playlist';
}

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace App\Entity\Migration;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20240221151753 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add ability for podcasts to sync from playlists.';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE podcast ADD playlist_id INT DEFAULT NULL, ADD source VARCHAR(50) NOT NULL, ADD playlist_auto_publish TINYINT(1) NOT NULL');
$this->addSql('ALTER TABLE podcast ADD CONSTRAINT FK_D7E805BD6BBD148 FOREIGN KEY (playlist_id) REFERENCES station_playlists (id) ON DELETE CASCADE');
$this->addSql('CREATE INDEX IDX_D7E805BD6BBD148 ON podcast (playlist_id)');
$this->addSql('ALTER TABLE podcast_episode ADD playlist_media_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE podcast_episode ADD CONSTRAINT FK_77EB2BD017421B18 FOREIGN KEY (playlist_media_id) REFERENCES station_media (id) ON DELETE CASCADE');
$this->addSql('CREATE UNIQUE INDEX UNIQ_77EB2BD017421B18 ON podcast_episode (playlist_media_id)');
$this->addSql(
<<<'SQL'
UPDATE podcast SET source='manual'
SQL
);
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE podcast DROP FOREIGN KEY FK_D7E805BD6BBD148');
$this->addSql('DROP INDEX IDX_D7E805BD6BBD148 ON podcast');
$this->addSql('ALTER TABLE podcast DROP playlist_id, DROP source, DROP playlist_auto_publish');
$this->addSql('ALTER TABLE podcast_episode DROP FOREIGN KEY FK_77EB2BD017421B18');
$this->addSql('DROP INDEX UNIQ_77EB2BD017421B18 ON podcast_episode');
$this->addSql('ALTER TABLE podcast_episode DROP playlist_media_id');
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Entity;
use App\Entity\Enums\PodcastSources;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
@ -25,6 +26,19 @@ class Podcast implements Interfaces\IdentifiableEntityInterface
#[ORM\JoinColumn(name: 'storage_location_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
protected StorageLocation $storage_location;
#[ORM\Column(nullable: false, insertable: false, updatable: false)]
protected int $storage_location_id;
#[ORM\ManyToOne(inversedBy: 'podcasts')]
#[ORM\JoinColumn(name: 'playlist_id', referencedColumnName: 'id', nullable: true, onDelete: 'CASCADE')]
protected ?StationPlaylist $playlist = null;
#[ORM\Column(nullable: true, insertable: false, updatable: false)]
protected ?int $playlist_id = null;
#[ORM\Column(type: 'string', length: 50, enumType: PodcastSources::class)]
protected PodcastSources $source = PodcastSources::Manual;
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
protected string $title;
@ -51,6 +65,9 @@ class Podcast implements Interfaces\IdentifiableEntityInterface
#[Attributes\AuditIgnore]
protected int $art_updated_at = 0;
#[ORM\Column]
protected bool $playlist_auto_publish = true;
/** @var Collection<int, PodcastCategory> */
#[ORM\OneToMany(mappedBy: 'podcast', targetEntity: PodcastCategory::class)]
protected Collection $categories;
@ -72,6 +89,26 @@ class Podcast implements Interfaces\IdentifiableEntityInterface
return $this->storage_location;
}
public function getPlaylist(): ?StationPlaylist
{
return $this->playlist;
}
public function setPlaylist(?StationPlaylist $playlist): void
{
$this->playlist = $playlist;
}
public function getSource(): PodcastSources
{
return $this->source;
}
public function setSource(PodcastSources $source): void
{
$this->source = $source;
}
public function getTitle(): string
{
return $this->title;
@ -156,6 +193,16 @@ class Podcast implements Interfaces\IdentifiableEntityInterface
return $this;
}
public function playlistAutoPublish(): bool
{
return $this->playlist_auto_publish;
}
public function setPlaylistAutoPublish(bool $playlist_auto_publish): void
{
$this->playlist_auto_publish = $playlist_auto_publish;
}
/**
* @return Collection<int, PodcastCategory>
*/

View File

@ -4,8 +4,8 @@ declare(strict_types=1);
namespace App\Entity;
use App\Entity\Enums\PodcastSources;
use App\Entity\Interfaces\IdentifiableEntityInterface;
use App\Entity\Traits;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
@ -25,6 +25,10 @@ class PodcastEpisode implements IdentifiableEntityInterface
#[ORM\JoinColumn(name: 'podcast_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
protected Podcast $podcast;
#[ORM\OneToOne(inversedBy: 'podcast_episode')]
#[ORM\JoinColumn(name: 'playlist_media_id', referencedColumnName: 'id', nullable: true, onDelete: 'CASCADE')]
protected ?StationMedia $playlist_media = null;
#[ORM\OneToOne(mappedBy: 'episode')]
protected ?PodcastMedia $media = null;
@ -73,6 +77,16 @@ class PodcastEpisode implements IdentifiableEntityInterface
return $this->media;
}
public function getPlaylistMedia(): ?StationMedia
{
return $this->playlist_media;
}
public function setPlaylistMedia(?StationMedia $playlist_media): void
{
$this->playlist_media = $playlist_media;
}
public function getTitle(): string
{
return $this->title;
@ -168,10 +182,9 @@ class PodcastEpisode implements IdentifiableEntityInterface
return false;
}
if ($this->getMedia() === null) {
return false;
}
return true;
return match ($this->getPodcast()->getSource()) {
PodcastSources::Manual => ($this->getMedia() !== null),
PodcastSources::Playlist => ($this->getPlaylistMedia() !== null)
};
}
}