diff --git a/app/Database/Migrations/2020-05-29-120000_add_media.php b/app/Database/Migrations/2020-05-29-120000_add_media.php index 711ba069f855c7bc66ecf5fc5c3871396fc213d7..6f80aad11463276eb67441428f6e4909e58e367e 100644 --- a/app/Database/Migrations/2020-05-29-120000_add_media.php +++ b/app/Database/Migrations/2020-05-29-120000_add_media.php @@ -31,7 +31,7 @@ class AddMedia extends Migration 'unsigned' => true, 'comment' => 'File size in bytes', ], - 'file_content_type' => [ + 'file_mimetype' => [ 'type' => 'VARCHAR', 'constraint' => 45, ], @@ -42,6 +42,7 @@ class AddMedia extends Migration 'type' => [ 'type' => 'ENUM', 'constraint' => ['image', 'audio', 'video', 'transcript', 'chapters', 'document'], + 'default' => 'document', ], 'description' => [ 'type' => 'TEXT', @@ -71,6 +72,7 @@ class AddMedia extends Migration ]); $this->forge->addKey('id', true); + $this->forge->addUniqueKey('file_path'); $this->forge->addForeignKey('uploaded_by', 'users', 'id'); $this->forge->addForeignKey('updated_by', 'users', 'id'); $this->forge->createTable('media'); diff --git a/app/Database/Migrations/2020-05-30-101500_add_podcasts.php b/app/Database/Migrations/2020-05-30-101500_add_podcasts.php index ff2f913c470720ca8b526edef09e677a6e19edc4..436c741b5fd872bf4f7791aa487f0b7df5140380 100644 --- a/app/Database/Migrations/2020-05-30-101500_add_podcasts.php +++ b/app/Database/Migrations/2020-05-30-101500_add_podcasts.php @@ -198,7 +198,7 @@ class AddPodcasts extends Migration $this->forge->addUniqueKey('actor_id'); $this->forge->addForeignKey('actor_id', config('Fediverse')->tablesPrefix . 'actors', 'id', '', 'CASCADE'); $this->forge->addForeignKey('cover_id', 'media', 'id'); - $this->forge->addForeignKey('banner_id', 'media', 'id'); + $this->forge->addForeignKey('banner_id', 'media', 'id', '', 'SET NULL'); $this->forge->addForeignKey('category_id', 'categories', 'id'); $this->forge->addForeignKey('language_code', 'languages', 'code'); $this->forge->addForeignKey('created_by', 'users', 'id'); diff --git a/app/Database/Migrations/2020-06-05-170000_add_episodes.php b/app/Database/Migrations/2020-06-05-170000_add_episodes.php index 04656978eacce8a57e1bbbf4cbf456b0bb5d7405..9e0efaa25078539b49e870f16f09f500500b41dc 100644 --- a/app/Database/Migrations/2020-06-05-170000_add_episodes.php +++ b/app/Database/Migrations/2020-06-05-170000_add_episodes.php @@ -157,9 +157,9 @@ class AddEpisodes extends Migration $this->forge->addUniqueKey(['podcast_id', 'slug']); $this->forge->addForeignKey('podcast_id', 'podcasts', 'id', '', 'CASCADE'); $this->forge->addForeignKey('audio_id', 'media', 'id'); - $this->forge->addForeignKey('cover_id', 'media', 'id'); - $this->forge->addForeignKey('transcript_id', 'media', 'id'); - $this->forge->addForeignKey('chapters_id', 'media', 'id'); + $this->forge->addForeignKey('cover_id', 'media', 'id', '', 'SET NULL'); + $this->forge->addForeignKey('transcript_id', 'media', 'id', '', 'SET NULL'); + $this->forge->addForeignKey('chapters_id', 'media', 'id', '', 'SET NULL'); $this->forge->addForeignKey('created_by', 'users', 'id'); $this->forge->addForeignKey('updated_by', 'users', 'id'); $this->forge->createTable('episodes'); diff --git a/app/Database/Migrations/2020-12-25-120000_add_persons.php b/app/Database/Migrations/2020-12-25-120000_add_persons.php index 66b53ba1ad088a375d2de4eee336c959267d86e3..f7515ed49974dbafc8f6922c3499e67af0627301 100644 --- a/app/Database/Migrations/2020-12-25-120000_add_persons.php +++ b/app/Database/Migrations/2020-12-25-120000_add_persons.php @@ -64,7 +64,7 @@ class AddPersons extends Migration ]); $this->forge->addKey('id', true); - $this->forge->addForeignKey('avatar_id', 'media', 'id'); + $this->forge->addForeignKey('avatar_id', 'media', 'id', '', 'SET NULL'); $this->forge->addForeignKey('created_by', 'users', 'id'); $this->forge->addForeignKey('updated_by', 'users', 'id'); $this->forge->createTable('persons'); diff --git a/app/Entities/BaseEntity.php b/app/Entities/BaseEntity.php new file mode 100644 index 0000000000000000000000000000000000000000..b9f888a463101765cfdf0f9087576852abf81f0a --- /dev/null +++ b/app/Entities/BaseEntity.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace App\Entities; + +use CodeIgniter\Entity\Entity; + +class BaseEntity extends Entity +{ +} diff --git a/app/Entities/Episode.php b/app/Entities/Episode.php index b5ca18463e8972f73cfe051d4549b5257fc27758..dbdb47ccde4b6115d0e80380d7ed1c26b4b34fa8 100644 --- a/app/Entities/Episode.php +++ b/app/Entities/Episode.php @@ -10,6 +10,10 @@ declare(strict_types=1); namespace App\Entities; +use App\Entities\Media\Audio; +use App\Entities\Media\Chapters; +use App\Entities\Media\Image; +use App\Entities\Media\Transcript; use App\Libraries\SimpleRSSElement; use App\Models\ClipsModel; use App\Models\EpisodeCommentModel; @@ -19,6 +23,7 @@ use App\Models\PodcastModel; use App\Models\PostModel; use CodeIgniter\Entity\Entity; use CodeIgniter\Files\File; +use CodeIgniter\HTTP\Files\UploadedFile; use CodeIgniter\I18n\Time; use League\CommonMark\CommonMarkConverter; use RuntimeException; @@ -42,10 +47,10 @@ use RuntimeException; * @property int $cover_id * @property Image $cover * @property int|null $transcript_id - * @property Media|null $transcript + * @property Transcript|null $transcript * @property string|null $transcript_remote_url * @property int|null $chapters_id - * @property Media|null $chapters + * @property Chapters|null $chapters * @property string|null $chapters_remote_url * @property string|null $parental_advisory * @property int $number @@ -69,7 +74,7 @@ use RuntimeException; * @property Time|null $deleted_at; * * @property Person[] $persons; - * @property Soundbite[] $soundbites; + * @property Clip[] $clips; * @property string $embed_url; */ class Episode extends Entity @@ -78,7 +83,7 @@ class Episode extends Entity protected string $link; - protected Audio $audio; + protected ?Audio $audio = null; protected string $audio_url; @@ -90,13 +95,13 @@ class Episode extends Entity protected string $embed_url; - protected Image $cover; + protected ?Image $cover = null; protected ?string $description = null; - protected ?Media $transcript; + protected ?Transcript $transcript = null; - protected ?Media $chapters; + protected ?Chapters $chapters = null; /** * @var Person[]|null @@ -161,25 +166,31 @@ class Episode extends Entity 'updated_by' => 'integer', ]; - /** - * Saves an episode cover - */ - public function setCover(?Image $cover = null): static + public function setCover(?UploadedFile $file): self { - if ($cover === null) { + if ($file === null || ! $file->isValid()) { return $this; } - // Save image - $cover->saveImage( - config('Images') - ->podcastCoverSizes, - 'podcasts/' . $this->getPodcast()->handle, - $this->attributes['slug'] - ); - - $this->attributes['cover_mimetype'] = $cover->mimetype; - $this->attributes['cover_path'] = $cover->path; + if (array_key_exists('cover_id', $this->attributes) && $this->attributes['cover_id'] !== null) { + $this->getCover() + ->setFile($file); + $this->getCover() + ->updated_by = (int) user_id(); + (new MediaModel('image'))->updateMedia($this->getCover()); + } else { + $cover = new Image([ + 'file_name' => $this->attributes['slug'], + 'file_directory' => 'podcasts/' . $this->attributes['handle'], + 'sizes' => config('Images') + ->podcastCoverSizes, + 'uploaded_by' => user_id(), + 'updated_by' => user_id(), + ]); + $cover->setFile($file); + + $this->attributes['cover_id'] = (new MediaModel('image'))->saveMedia($cover); + } return $this; } @@ -193,25 +204,106 @@ class Episode extends Entity return $this->cover; } + public function setAudio(?UploadedFile $file): self + { + if ($file === null || ! $file->isValid()) { + return $this; + } + + if ($this->audio_id !== null) { + $this->getAudio() + ->setFile($file); + $this->getAudio() + ->updated_by = (int) user_id(); + (new MediaModel('audio'))->updateMedia($this->getAudio()); + } else { + $transcript = new Audio([ + 'file_name' => $this->attributes['slug'], + 'file_directory' => 'podcasts/' . $this->attributes['handle'], + 'uploaded_by' => user_id(), + 'updated_by' => user_id(), + ]); + $transcript->setFile($file); + + $this->attributes['transcript_id'] = (new MediaModel())->saveMedia($transcript); + } + + return $this; + } + public function getAudio(): Audio { - if (! $this->audio) { + if (! $this->audio instanceof Audio) { $this->audio = (new MediaModel('audio'))->getMediaById($this->audio_id); } return $this->audio; } - public function getTranscript(): ?Media + public function setTranscript(?UploadedFile $file): self + { + if ($file === null || ! $file->isValid()) { + return $this; + } + + if ($this->getTranscript() !== null) { + $this->getTranscript() + ->setFile($file); + $this->getTranscript() + ->updated_by = (int) user_id(); + (new MediaModel('transcript'))->updateMedia($this->getTranscript()); + } else { + $transcript = new Transcript([ + 'file_name' => $this->attributes['slug'] . '-transcript', + 'file_directory' => 'podcasts/' . $this->attributes['handle'], + 'uploaded_by' => user_id(), + 'updated_by' => user_id(), + ]); + $transcript->setFile($file); + + $this->attributes['transcript_id'] = (new MediaModel())->saveMedia($transcript); + } + + return $this; + } + + public function getTranscript(): ?Transcript { if ($this->transcript_id !== null && $this->transcript === null) { - $this->transcript = (new MediaModel('document'))->getMediaById($this->transcript_id); + $this->transcript = (new MediaModel('transcript'))->getMediaById($this->transcript_id); } return $this->transcript; } - public function getChaptersFile(): ?Media + public function setChapters(?UploadedFile $file): self + { + if ($file === null || ! $file->isValid()) { + return $this; + } + + if ($this->getChapters() !== null) { + $this->getChapters() + ->setFile($file); + $this->getChapters() + ->updated_by = (int) user_id(); + (new MediaModel('chapters'))->updateMedia($this->getChapters()); + } else { + $chapters = new Chapters([ + 'file_name' => $this->attributes['slug'] . '-chapters', + 'file_directory' => 'podcasts/' . $this->attributes['handle'], + 'uploaded_by' => user_id(), + 'updated_by' => user_id(), + ]); + $chapters->setFile($file); + + $this->attributes['chapters_id'] = (new MediaModel())->saveMedia($chapters); + } + + return $this; + } + + public function getChapters(): ?Chapters { if ($this->chapters_id !== null && $this->chapters === null) { $this->chapters = (new MediaModel('document'))->getMediaById($this->chapters_id); @@ -261,7 +353,7 @@ class Episode extends Entity public function getTranscriptUrl(): ?string { if ($this->transcript !== null) { - return $this->transcript->url; + return $this->transcript->file_url; } return $this->transcript_remote_url; } @@ -271,8 +363,8 @@ class Episode extends Entity */ public function getChaptersFileUrl(): ?string { - if ($this->chapters) { - return $this->chapters->url; + if ($this->chapters !== null) { + return $this->chapters->file_url; } return $this->chapters_remote_url; diff --git a/app/Entities/ImageOLD.php b/app/Entities/ImageOLD.php deleted file mode 100644 index d46b29e141ff8a08ff565b34be02df11b12eb326..0000000000000000000000000000000000000000 --- a/app/Entities/ImageOLD.php +++ /dev/null @@ -1,123 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2021 Podlibre - * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 - * @link https://castopod.org/ - */ - -namespace App\Entities; - -use CodeIgniter\Files\File; -use Config\Images; - -class Image extends Media -{ - /** - * @var array<string, array<string, int|string>> - */ - public array $sizes = []; - - protected Images $config; - - protected string $type = 'image'; - - public function __get($property) - { - if (str_ends_with($property, '_url') || str_ends_with($property, '_path') || str_ends_with( - $property, - '_mimetype' - )) { - $this->initSizeProperties(); - } - - parent::__get($property); - } - - public function setFileMetadata(string $metadata): self - { - $this->attributes['file_metadata'] = $metadata; - - $metadataArray = json_decode($metadata, true); - if (! array_key_exists('sizes', $metadataArray)) { - return $this; - } - - $this->sizes = $metadataArray['sizes']; - - return $this; - } - - public function initSizeProperties(): bool - { - if ($this->file_path === '') { - return false; - } - - if ($this->sizes === []) { - $this->sizes = $this->file_metadata['sizes']; - } - - helper('media'); - - $extension = $this->file_extension; - $mimetype = $this->mimetype; - foreach ($this->sizes as $name => $size) { - if (array_key_exists('extension', $size)) { - $extension = $size['extension']; - } - if (array_key_exists('mimetype', $size)) { - $mimetype = $size['mimetype']; - } - $this->{$name . '_path'} = $this->file_directory . '/' . $this->file_name . '_' . $name . '.' . $extension; - $this->{$name . '_url'} = media_base_url($this->{$name . '_path'}); - $this->{$name . '_mimetype'} = $mimetype; - } - - return true; - } - - public function saveInDisk(File $file, string $dirname, string $filename): void - { - // save original - parent::saveInDisk($file, $dirname, $filename); - - $this->initSizeProperties(); - - // save derived sizes - $imageService = service('image'); - foreach ($this->sizes as $name => $size) { - $pathProperty = $name . '_path'; - $imageService - ->withFile(media_path($this->file_path)) - ->resize($size['width'], $size['height']); - $imageService->save(media_path($this->{$pathProperty})); - } - } - - public function injectFileData(File $file): void - { - $metadata = exif_read_data(media_path($this->file_path), null, true); - - if ($metadata) { - $metadata['sizes'] = $this->sizes; - $this->file_size = $metadata['FILE']['FileSize']; - $this->file_metadata = $metadata; - } - } - - /** - * @param array<string, int[]> $sizes - */ - public function delete(array $sizes): void - { - helper('media'); - - foreach (array_keys($sizes) as $name) { - $pathProperty = $name . '_path'; - unlink(media_path($this->{$pathProperty})); - } - } -} diff --git a/app/Entities/Audio.php b/app/Entities/Media/Audio.php similarity index 89% rename from app/Entities/Audio.php rename to app/Entities/Media/Audio.php index 4a342d41db30a5bb9eeacc3483b6ff442ecd0b62..288f95506ee66df297bbd333cab5c6b6ed645920 100644 --- a/app/Entities/Audio.php +++ b/app/Entities/Media/Audio.php @@ -8,7 +8,7 @@ declare(strict_types=1); * @link https://castopod.org/ */ -namespace App\Entities; +namespace App\Entities\Media; use CodeIgniter\Files\File; use JamesHeinrich\GetID3\GetID3; @@ -17,7 +17,7 @@ use JamesHeinrich\GetID3\GetID3; * @property float $duration * @property int $header_size */ -class Audio extends Media +class Audio extends BaseMedia { protected string $type = 'audio'; @@ -41,7 +41,7 @@ class Audio extends Media $getID3 = new GetID3(); $audioMetadata = $getID3->analyze((string) $file); - $this->attributes['file_content_type'] = $audioMetadata['mimetype']; + $this->attributes['file_mimetype'] = $audioMetadata['mimetype']; $this->attributes['file_size'] = $audioMetadata['filesize']; $this->attributes['description'] = $audioMetadata['comments']['comment']; $this->attributes['file_metadata'] = $audioMetadata; diff --git a/app/Entities/Media.php b/app/Entities/Media/BaseMedia.php similarity index 74% rename from app/Entities/Media.php rename to app/Entities/Media/BaseMedia.php index b979edbc9c458d12ee167420698197a198a1b205..36b672b99788b5e402b406507b8ce99ff4f7c913 100644 --- a/app/Entities/Media.php +++ b/app/Entities/Media/BaseMedia.php @@ -8,7 +8,7 @@ declare(strict_types=1); * @link https://castopod.org/ */ -namespace App\Entities; +namespace App\Entities\Media; use CodeIgniter\Entity\Entity; use CodeIgniter\Files\File; @@ -16,11 +16,12 @@ use CodeIgniter\Files\File; /** * @property int $id * @property string $file_path + * @property string $file_url * @property string $file_directory * @property string $file_extension * @property string $file_name * @property int $file_size - * @property string $file_content_type + * @property string $file_mimetype * @property array $file_metadata * @property 'image'|'audio'|'video'|'document' $type * @property string $description @@ -28,7 +29,7 @@ use CodeIgniter\Files\File; * @property int $uploaded_by * @property int $updated_by */ -class Media extends Entity +class BaseMedia extends Entity { protected File $file; @@ -44,9 +45,10 @@ class Media extends Entity */ protected $casts = [ 'id' => 'integer', + 'file_extension' => 'string', 'file_path' => 'string', 'file_size' => 'int', - 'file_content_type' => 'string', + 'file_mimetype' => 'string', 'file_metadata' => 'json-array', 'type' => 'string', 'description' => 'string', @@ -62,16 +64,23 @@ class Media extends Entity { parent::__construct($data); - if ($this->file_path) { + $this->initFileProperties(); + } + + public function initFileProperties(): void + { + if ($this->file_path !== '') { + helper('media'); [ 'filename' => $filename, 'dirname' => $dirname, 'extension' => $extension, ] = pathinfo($this->file_path); - $this->file_name = $filename; - $this->file_directory = $dirname; - $this->file_extension = $extension; + $this->attributes['file_url'] = media_base_url($this->file_path); + $this->attributes['file_name'] = $filename; + $this->attributes['file_directory'] = $dirname; + $this->attributes['file_extension'] = $extension; } } @@ -79,7 +88,7 @@ class Media extends Entity { helper('media'); - $this->attributes['file_content_type'] = $file->getMimeType(); + $this->attributes['file_mimetype'] = $file->getMimeType(); $this->attributes['file_metadata'] = json_encode(lstat((string) $file)); $this->attributes['file_path'] = save_media( $file, diff --git a/app/Entities/Media/Chapters.php b/app/Entities/Media/Chapters.php new file mode 100644 index 0000000000000000000000000000000000000000..48e7fc744d789b4bb5b6717dc6544446d173dc66 --- /dev/null +++ b/app/Entities/Media/Chapters.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2021 Podlibre + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +namespace App\Entities\Media; + +class Chapters extends BaseMedia +{ + protected string $type = 'chapters'; +} diff --git a/app/Entities/Media/Document.php b/app/Entities/Media/Document.php new file mode 100644 index 0000000000000000000000000000000000000000..dc7c3e903e1ac167637e0dd548ae8f27e2c3ccc5 --- /dev/null +++ b/app/Entities/Media/Document.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2021 Podlibre + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +namespace App\Entities\Media; + +class Document extends BaseMedia +{ + protected string $type = 'document'; +} diff --git a/app/Entities/Image.php b/app/Entities/Media/Image.php similarity index 72% rename from app/Entities/Image.php rename to app/Entities/Media/Image.php index 758e2fa4c55b37ef7ed354fbe140fad3ebd7a839..fff51e00a6f730da9b5a3d5f3729084187c5c91f 100644 --- a/app/Entities/Image.php +++ b/app/Entities/Media/Image.php @@ -8,20 +8,20 @@ declare(strict_types=1); * @link https://castopod.org/ */ -namespace App\Entities; +namespace App\Entities\Media; use CodeIgniter\Files\File; -class Image extends Media +/** + * @property array $sizes + */ +class Image extends BaseMedia { protected string $type = 'image'; - /** - * @param array<string, mixed>|null $data - */ - public function __construct(array $data = null) + public function initFileProperties(): void { - parent::__construct($data); + parent::initFileProperties(); if ($this->file_path && $this->file_metadata) { $this->sizes = $this->file_metadata['sizes']; @@ -34,7 +34,7 @@ class Image extends Media helper('media'); $extension = $this->file_extension; - $mimetype = $this->mimetype; + $mimetype = $this->file_mimetype; foreach ($this->sizes as $name => $size) { if (array_key_exists('extension', $size)) { $extension = $size['extension']; @@ -62,6 +62,23 @@ class Image extends Media $this->attributes['file_metadata'] = json_encode($metadata); } + $this->initFileProperties(); + $this->saveSizes(); + + return $this; + } + + public function deleteFile(): void + { + helper('media'); + + unlink(media_path($this->file_path)); + + $this->deleteSizes(); + } + + private function saveSizes(): void + { // save derived sizes $imageService = service('image'); foreach ($this->sizes as $name => $size) { @@ -71,7 +88,14 @@ class Image extends Media ->resize($size['width'], $size['height']); $imageService->save(media_path($this->{$pathProperty})); } + } - return $this; + private function deleteSizes(): void + { + // delete all derived sizes + foreach (array_keys($this->sizes) as $name) { + $pathProperty = $name . '_path'; + unlink(media_path($this->{$pathProperty})); + } } } diff --git a/app/Entities/Media/Transcript.php b/app/Entities/Media/Transcript.php new file mode 100644 index 0000000000000000000000000000000000000000..2a06ef1d4c94bf2c40c78cfaa461b16f6a2ea63b --- /dev/null +++ b/app/Entities/Media/Transcript.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2021 Podlibre + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +namespace App\Entities\Media; + +class Transcript extends BaseMedia +{ + protected string $type = 'transcript'; +} diff --git a/app/Entities/Media/Video.php b/app/Entities/Media/Video.php new file mode 100644 index 0000000000000000000000000000000000000000..f003283bd711da95b393022c000dab3451304f48 --- /dev/null +++ b/app/Entities/Media/Video.php @@ -0,0 +1,16 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2021 Podlibre + * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 + * @link https://castopod.org/ + */ + +namespace App\Entities\Media; + +class Video extends BaseMedia +{ + protected string $type = 'video'; +} diff --git a/app/Entities/MediaOLD.php b/app/Entities/MediaOLD.php deleted file mode 100644 index d585ad853a16c6475cf265ee55f26bf6e8aa7edb..0000000000000000000000000000000000000000 --- a/app/Entities/MediaOLD.php +++ /dev/null @@ -1,93 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2021 Podlibre - * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 - * @link https://castopod.org/ - */ - -namespace App\Entities; - -use CodeIgniter\Entity\Entity; -use CodeIgniter\Files\File; - -/** - * @property int $id - * @property string $file_path - * @property string $file_directory - * @property string $file_extension - * @property string $file_name - * @property int $file_size - * @property string $file_content_type - * @property array $file_metadata - * @property 'image'|'audio'|'video'|'document' $type - * @property string $description - * @property string|null $language_code - * @property int $uploaded_by - * @property int $updated_by - */ -class Media extends Entity -{ - protected File $file; - - /** - * @var string[] - */ - protected $dates = ['uploaded_at', 'updated_at', 'deleted_at']; - - /** - * @var array<string, string> - */ - protected $casts = [ - 'id' => 'integer', - 'file_path' => 'string', - 'file_size' => 'string', - 'file_content_type' => 'string', - 'file_metadata' => 'json-array', - 'type' => 'string', - 'description' => 'string', - 'language_code' => '?string', - 'uploaded_by' => 'integer', - 'updated_by' => 'integer', - ]; - - public function setFilePath(string $path): self - { - $this->attributes['file_path'] = $path; - - [ - 'filename' => $filename, - 'dirname' => $dirname, - 'extension' => $extension, - ] = pathinfo($path); - - $this->file_name = $filename; - $this->file_directory = $dirname; - $this->file_extension = $extension; - - return $this; - } - - public function saveInDisk(File $file, string $dirname, string $filename): void - { - helper('media'); - - $this->file_content_type = $file->getMimeType(); - - $filePath = save_media($file, $dirname, $filename); - - $this->file_path = $filePath; - } - - public function injectFileData(File $file): void - { - $this->file_content_type = $file->getMimeType(); - $this->type = 'document'; - - if ($filesize = filesize(media_path($this->file_path))) { - $this->file_size = $filesize; - } - } -} diff --git a/app/Entities/Person.php b/app/Entities/Person.php index 10e9fd2273ce56dba44dc993db5fae53f695817c..c8b8478913f6037ae81e35f7ba5e9e22f123e3c3 100644 --- a/app/Entities/Person.php +++ b/app/Entities/Person.php @@ -10,8 +10,11 @@ declare(strict_types=1); namespace App\Entities; +use App\Entities\Media\Image; +use App\Models\MediaModel; use App\Models\PersonModel; use CodeIgniter\Entity\Entity; +use CodeIgniter\HTTP\Files\UploadedFile; use RuntimeException; /** @@ -52,31 +55,52 @@ class Person extends Entity /** * Saves the person avatar in `public/media/persons/` */ - public function setAvatar(?Image $avatar = null): static + public function setAvatar(?UploadedFile $file = null): static { - if ($avatar === null) { + if ($file === null || ! $file->isValid()) { return $this; } - helper('media'); - - $avatar->saveImage(config('Images')->personAvatarSizes, 'persons', $this->attributes['unique_name']); - - $this->attributes['avatar_mimetype'] = $avatar->mimetype; - $this->attributes['avatar_path'] = $avatar->path; + if (array_key_exists('cover_id', $this->attributes) && $this->attributes['cover_id'] !== null) { + $this->getAvatar() + ->setFile($file); + $this->getAvatar() + ->updated_by = (int) user_id(); + (new MediaModel('image'))->updateMedia($this->getAvatar()); + } else { + $cover = new Image([ + 'file_name' => $this->attributes['unique_name'], + 'file_directory' => 'persons', + 'sizes' => config('Images') + ->personAvatarSizes, + 'uploaded_by' => user_id(), + 'updated_by' => user_id(), + ]); + $cover->setFile($file); + + $this->attributes['cover_id'] = (new MediaModel('image'))->saveMedia($cover); + } return $this; } public function getAvatar(): Image { - if ($this->attributes['avatar_path'] === null) { - return new Image(null, '/castopod-avatar-default.jpg', 'image/jpeg', config('Images')->personAvatarSizes); + if ($this->attributes['avatar_id'] === null) { + helper('media'); + return new Image([ + 'file_path' => media_path('castopod-avatar-default.jpg'), + 'file_mimetype' => 'image/jpeg', + 'sizes' => config('Images') + ->personAvatarSizes, + ]); + } + + if ($this->avatar === null) { + $this->avatar = (new MediaModel('image'))->getMediaById($this->avatar_id); } - return new Image(null, $this->attributes['avatar_path'], $this->attributes['avatar_mimetype'], config( - 'Images' - )->personAvatarSizes); + return $this->avatar; } /** diff --git a/app/Entities/Podcast.php b/app/Entities/Podcast.php index 1663a6b32fcee5b3ecae96671a7ed21c0d771ed8..d2e5a04bb7996848be9f97d7e1236ce7f38735c2 100644 --- a/app/Entities/Podcast.php +++ b/app/Entities/Podcast.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace App\Entities; +use App\Entities\Media\Image; use App\Libraries\SimpleRSSElement; use App\Models\CategoryModel; use App\Models\EpisodeModel; @@ -18,6 +19,7 @@ use App\Models\PersonModel; use App\Models\PlatformModel; use App\Models\UserModel; use CodeIgniter\Entity\Entity; +use CodeIgniter\HTTP\Files\UploadedFile; use CodeIgniter\I18n\Time; use League\CommonMark\CommonMarkConverter; use Modules\Auth\Entities\User; @@ -192,6 +194,35 @@ class Podcast extends Entity return $this->actor; } + public function setCover(?UploadedFile $file = null): self + { + if ($file === null || ! $file->isValid()) { + return $this; + } + + if (array_key_exists('cover_id', $this->attributes) && $this->attributes['cover_id'] !== null) { + $this->getCover() + ->setFile($file); + $this->getCover() + ->updated_by = (int) user_id(); + (new MediaModel('image'))->updateMedia($this->getCover()); + } else { + $cover = new Image([ + 'file_name' => 'cover', + 'file_directory' => 'podcasts/' . $this->attributes['handle'], + 'sizes' => config('Images') + ->podcastCoverSizes, + 'uploaded_by' => user_id(), + 'updated_by' => user_id(), + ]); + $cover->setFile($file); + + $this->attributes['cover_id'] = (new MediaModel('image'))->saveMedia($cover); + } + + return $this; + } + public function getCover(): Image { if (! $this->cover instanceof Image) { @@ -201,6 +232,35 @@ class Podcast extends Entity return $this->cover; } + public function setBanner(?UploadedFile $file): self + { + if ($file === null || ! $file->isValid()) { + return $this; + } + + if (array_key_exists('banner_id', $this->attributes) && $this->attributes['banner_id'] !== null) { + $this->getBanner() + ->setFile($file); + $this->getBanner() + ->updated_by = (int) user_id(); + (new MediaModel('image'))->updateMedia($this->getBanner()); + } else { + $banner = new Image([ + 'file_name' => 'banner', + 'file_directory' => 'podcasts/' . $this->attributes['handle'], + 'sizes' => config('Images') + ->podcastBannerSizes, + 'uploaded_by' => user_id(), + 'updated_by' => user_id(), + ]); + $banner->setFile($file); + + $this->attributes['banner_id'] = (new MediaModel('image'))->saveMedia($banner); + } + + return $this; + } + public function getBanner(): Image { if ($this->banner_id === null) { diff --git a/app/Helpers/rss_helper.php b/app/Helpers/rss_helper.php index fbb845d8f82f47c6fd88ae46f503e92116a30d15..93e40cf2dc41f61bf769746bc6efbbd9672892a6 100644 --- a/app/Helpers/rss_helper.php +++ b/app/Helpers/rss_helper.php @@ -212,7 +212,7 @@ if (! function_exists('get_rss_feed')) { : '?_from=' . urlencode($serviceSlug)), ); $enclosure->addAttribute('length', (string) $episode->audio->file_size); - $enclosure->addAttribute('type', $episode->audio->file_content_type); + $enclosure->addAttribute('type', $episode->audio->file_mimetype); $item->addChild('guid', $episode->guid); $item->addChild('pubDate', $episode->published_at->format(DATE_RFC1123)); @@ -255,25 +255,25 @@ if (! function_exists('get_rss_feed')) { $comments->addAttribute('uri', url_to('episode-comments', $podcast->handle, $episode->slug)); $comments->addAttribute('contentType', 'application/podcast-activity+json'); - if ($episode->transcript->file_url) { + if ($episode->transcript->file_url !== '') { $transcriptElement = $item->addChild('transcript', null, $podcastNamespace); - $transcriptElement->addAttribute('url', $episode->transcript_file_url); + $transcriptElement->addAttribute('url', $episode->transcript->file_url); $transcriptElement->addAttribute( 'type', Mimes::guessTypeFromExtension( - pathinfo($episode->transcript_file_url, PATHINFO_EXTENSION) + pathinfo($episode->transcript->file_url, PATHINFO_EXTENSION) ) ?? 'text/html', ); $transcriptElement->addAttribute('language', $podcast->language_code); } - if ($episode->chapters->file_url) { + if ($episode->chapters->file_url !== '') { $chaptersElement = $item->addChild('chapters', null, $podcastNamespace); - $chaptersElement->addAttribute('url', $episode->chapters_file_url); + $chaptersElement->addAttribute('url', $episode->chapters->file_url); $chaptersElement->addAttribute('type', 'application/json+chapters'); } - foreach ($episode->clip as $clip) { + foreach ($episode->clips as $clip) { // TODO: differentiate video from soundbites? $soundbiteElement = $item->addChild('soundbite', $clip->label, $podcastNamespace); $soundbiteElement->addAttribute('start_time', (string) $clip->start_time); diff --git a/app/Helpers/seo_helper.php b/app/Helpers/seo_helper.php index 72b0c790117f1382e5f73dfcc951ceedb80a500c..6c4d9e8325e81b5e29df77800dbc05716e98cf3a 100644 --- a/app/Helpers/seo_helper.php +++ b/app/Helpers/seo_helper.php @@ -87,7 +87,7 @@ if (! function_exists('get_episode_metatags')) { ->og('image:height', (string) config('Images')->podcastCoverSizes['large']['height']) ->og('locale', $episode->podcast->language_code) ->og('audio', $episode->audio_file_opengraph_url) - ->og('audio:type', $episode->audio->file_content_type) + ->og('audio:type', $episode->audio->file_mimetype) ->meta('article:published_time', $episode->published_at->format(DATE_ISO8601)) ->meta('article:modified_time', $episode->updated_at->format(DATE_ISO8601)) ->twitter('audio:partner', $episode->podcast->publisher ?? '') diff --git a/app/Libraries/MediaClipper/VideoClip.php b/app/Libraries/MediaClipper/VideoClip.php index 647e8545c4c0b0953e4432185ad5633f0c9e122f..ad309feffda5472bc526aeed074b614ad9976b54 100644 --- a/app/Libraries/MediaClipper/VideoClip.php +++ b/app/Libraries/MediaClipper/VideoClip.php @@ -80,7 +80,7 @@ class VideoClip helper(['media']); $this->audioInput = media_path($this->episode->audio->file_path); - $this->episodeCoverPath = media_path($this->episode->cover->path); + $this->episodeCoverPath = media_path($this->episode->cover->file_path); if ($this->episode->transcript !== null) { $this->subtitlesInput = media_path($this->episode->transcript->file_path); } diff --git a/app/Libraries/PodcastEpisode.php b/app/Libraries/PodcastEpisode.php index 5d7aece560d4676b131be8b4ac9a2d4f82382ad6..a118315d0ad928be80f779de34116142a3c8a9bd 100644 --- a/app/Libraries/PodcastEpisode.php +++ b/app/Libraries/PodcastEpisode.php @@ -52,7 +52,7 @@ class PodcastEpisode extends ObjectType $this->image = [ 'type' => 'Image', - 'mediaType' => $episode->cover->file_content_type, + 'mediaType' => $episode->cover->file_mimetype, 'url' => $episode->cover->feed_url, ]; @@ -66,7 +66,7 @@ class PodcastEpisode extends ObjectType 'url' => [ 'href' => $episode->audio->file_url, 'type' => 'Link', - 'mediaType' => $episode->audio->file_content_type, + 'mediaType' => $episode->audio->file_mimetype, ], 'transcript' => $episode->transcript->file_url, 'chapters' => $episode->chapters->file_url, diff --git a/app/Models/EpisodeModel.php b/app/Models/EpisodeModel.php index 043e4fb697238f11300723bca3160727d587691f..1152adeef922216730d427238fbe71ee602ecfcc 100644 --- a/app/Models/EpisodeModel.php +++ b/app/Models/EpisodeModel.php @@ -68,14 +68,14 @@ class EpisodeModel extends Model 'guid', 'title', 'slug', - 'audio_file_id', + 'audio_id', 'description_markdown', 'description_html', 'cover_id', - 'transcript_file_id', - 'transcript_file_remote_url', - 'chapters_file_id', - 'chapters_file_remote_url', + 'transcript_id', + 'transcript_remote_url', + 'chapters_id', + 'chapters_remote_url', 'parental_advisory', 'number', 'season_number', @@ -114,13 +114,13 @@ class EpisodeModel extends Model 'podcast_id' => 'required', 'title' => 'required', 'slug' => 'required|regex_match[/^[a-zA-Z0-9\-]{1,191}$/]', - 'audio_file_id' => 'required', + 'audio_id' => 'required', 'description_markdown' => 'required', 'number' => 'is_natural_no_zero|permit_empty', 'season_number' => 'is_natural_no_zero|permit_empty', 'type' => 'required', - 'transcript_file_remote_url' => 'valid_url|permit_empty', - 'chapters_file_remote_url' => 'valid_url|permit_empty', + 'transcript_remote_url' => 'valid_url|permit_empty', + 'chapters_remote_url' => 'valid_url|permit_empty', 'published_at' => 'valid_date|permit_empty', 'created_by' => 'required', 'updated_by' => 'required', diff --git a/app/Models/MediaModel.php b/app/Models/MediaModel.php index 6d760524daadf65c7593073117504d7656291412..ceea6a957fee43bc3e8a3905d712f6727138dbdf 100644 --- a/app/Models/MediaModel.php +++ b/app/Models/MediaModel.php @@ -10,9 +10,12 @@ declare(strict_types=1); namespace App\Models; -use App\Entities\Audio; -use App\Entities\Image; -use App\Entities\Media; +use App\Entities\Media\Audio; +use App\Entities\Media\Chapters; +use App\Entities\Media\Document; +use App\Entities\Media\Image; +use App\Entities\Media\Transcript; +use App\Entities\Media\Video; use CodeIgniter\Database\ConnectionInterface; use CodeIgniter\Model; use CodeIgniter\Validation\ValidationInterface; @@ -27,7 +30,7 @@ class MediaModel extends Model /** * @var string */ - protected $returnType = Media::class; + protected $returnType = Document::class; /** * @var string[] @@ -36,7 +39,7 @@ class MediaModel extends Model 'id', 'file_path', 'file_size', - 'file_content_type', + 'file_mimetype', 'file_metadata', 'type', 'description', @@ -52,29 +55,36 @@ class MediaModel extends Model * @param ValidationInterface|null $validation Validation */ public function __construct( - protected string $fileType, + protected string $fileType = 'document', ConnectionInterface &$db = null, ValidationInterface $validation = null ) { + // @phpstan-ignore-next-line switch ($fileType) { case 'audio': $this->returnType = Audio::class; break; + case 'video': + $this->returnType = Video::class; + break; case 'image': $this->returnType = Image::class; break; + case 'transcript': + $this->returnType = Transcript::class; + break; + case 'chapters': + $this->returnType = Chapters::class; + break; default: - // do nothing, keep Media class as default + // do nothing, keep Document class as default break; } parent::__construct($db, $validation); } - /** - * @return Media|Image|Audio - */ - public function getMediaById(int $mediaId): object + public function getMediaById(int $mediaId): Document | Audio | Video | Image | Transcript | Chapters { $cacheName = "media#{$mediaId}"; if (! ($found = cache($cacheName))) { @@ -94,7 +104,9 @@ class MediaModel extends Model } /** - * @param Media|Image|Audio $media + * @param Document|Audio|Video|Image|Transcript|Chapters $media + * + * @noRector ReturnTypeDeclarationRector */ public function saveMedia(object $media): int | false { @@ -103,7 +115,21 @@ class MediaModel extends Model return false; } - // @phpstan-ignore-next-line return $mediaId; } + + /** + * @param Document|Audio|Video|Image|Transcript|Chapters $media + * + * @noRector ReturnTypeDeclarationRector + */ + public function updateMedia(object $media): bool + { + return $this->update($media->id, $media); + } + + public function deleteMedia(int $mediaId): bool + { + return $this->delete($mediaId, true); + } } diff --git a/app/Models/MediaModelOLD.php b/app/Models/MediaModelOLD.php deleted file mode 100644 index fcdc566006a3a3576c2f2d5a997aa2bc5d3dd04e..0000000000000000000000000000000000000000 --- a/app/Models/MediaModelOLD.php +++ /dev/null @@ -1,112 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright 2020 Podlibre - * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 - * @link https://castopod.org/ - */ - -namespace App\Models; - -use App\Entities\Audio; -use App\Entities\Image; -use App\Entities\Media; -use CodeIgniter\Database\ConnectionInterface; -use CodeIgniter\Model; -use CodeIgniter\Validation\ValidationInterface; - -class MediaModel extends Model -{ - /** - * @var string - */ - protected $table = 'media'; - - /** - * @var string - */ - protected $returnType = Media::class; - - /** - * @var string[] - */ - protected $allowedFields = [ - 'id', - 'file_path', - 'file_size', - 'file_content_type', - 'file_metadata', - 'type', - 'description', - 'language_code', - 'uploaded_by', - 'updated_by', - ]; - - /** - * Model constructor. - * - * @param ConnectionInterface|null $db DB Connection - * @param ValidationInterface|null $validation Validation - */ - public function __construct( - protected string $fileType, - ConnectionInterface &$db = null, - ValidationInterface $validation = null - ) { - switch ($fileType) { - case 'audio': - $this->returnType = Audio::class; - break; - case 'image': - $this->returnType = Image::class; - break; - default: - // do nothing, keep Media class as default - break; - } - - parent::__construct($db, $validation); - } - - /** - * @return Media|Image|Audio - */ - public function getMediaById(int $mediaId): object - { - $cacheName = "media#{$mediaId}"; - if (! ($found = cache($cacheName))) { - $builder = $this->where([ - 'id' => $mediaId, - ]); - - $found = $builder->first(); - - cache() - ->save($cacheName, $found, DECADE); - } - - return $found; - } - - /** - * @param Media|Image $media - */ - public function saveMedia(object $media): int | false - { - // insert record in database - if (! $mediaId = $this->insert($media, true)) { - return false; - } - - // @phpstan-ignore-next-line - return $mediaId; - } - - public function deleteFile(int $mediaId): void - { - // TODO: get file, delete it from disk & from database - } -} diff --git a/app/Models/PersonModel.php b/app/Models/PersonModel.php index 9e5688825e8065bb8524271734ef86041c8fc5e5..9a64585e87ee716dd9216f8d29fd0b4d5902ad2e 100644 --- a/app/Models/PersonModel.php +++ b/app/Models/PersonModel.php @@ -10,7 +10,6 @@ declare(strict_types=1); namespace App\Models; -use App\Entities\Image; use App\Entities\Person; use CodeIgniter\Database\Query; use CodeIgniter\Model; @@ -196,7 +195,7 @@ class PersonModel extends Model 'full_name' => $fullName, 'unique_name' => slugify($fullName), 'information_url' => $informationUrl, - 'image' => new Image(download_file($image)), + 'image' => download_file($image), 'created_by' => user_id(), 'updated_by' => user_id(), ]); diff --git a/app/Models/PodcastModel.php b/app/Models/PodcastModel.php index 02a913bb2448c2049a757113a8da3876706a8bad..9b639d69d4b80bfa89021586cb8307ece6e5bf51 100644 --- a/app/Models/PodcastModel.php +++ b/app/Models/PodcastModel.php @@ -484,9 +484,9 @@ class PodcastModel extends Model $actor->display_name = $podcast->title; $actor->summary = $podcast->description_html; $actor->avatar_image_url = $podcast->cover->federation_url; - $actor->avatar_image_mimetype = $podcast->cover->mimetype; + $actor->avatar_image_mimetype = $podcast->cover->file_mimetype; $actor->cover_image_url = $podcast->banner->federation_url; - $actor->cover_image_mimetype = $podcast->banner->mimetype; + $actor->cover_image_mimetype = $podcast->banner->file_mimetype; if ($actor->hasChanged()) { $actorModel->update($actor->id, $actor); diff --git a/modules/Admin/Controllers/EpisodeController.php b/modules/Admin/Controllers/EpisodeController.php index b0847e1c9d1742f620638f791a875aca82eb9fdf..637f84da1032ff020c71e2bbbe54d49c124bd6a8 100644 --- a/modules/Admin/Controllers/EpisodeController.php +++ b/modules/Admin/Controllers/EpisodeController.php @@ -12,15 +12,12 @@ namespace Modules\Admin\Controllers; use App\Entities\Episode; use App\Entities\EpisodeComment; -use App\Entities\Image; use App\Entities\Location; -use App\Entities\Media; use App\Entities\Podcast; use App\Entities\Post; use App\Models\ClipsModel; use App\Models\EpisodeCommentModel; use App\Models\EpisodeModel; -use App\Models\MediaModel; use App\Models\PodcastModel; use App\Models\PostModel; use CodeIgniter\Exceptions\PageNotFoundException; @@ -133,7 +130,8 @@ class EpisodeController extends BaseController 'title' => $this->request->getPost('title'), 'slug' => $this->request->getPost('slug'), 'guid' => null, - 'audio_file' => $this->request->getFile('audio_file'), + 'audio' => $this->request->getFile('audio_file'), + 'cover' => $this->request->getFile('cover'), 'description_markdown' => $this->request->getPost('description'), 'location' => $this->request->getPost('location_name') === '' ? null : new Location($this->request->getPost( 'location_name' @@ -161,69 +159,22 @@ class EpisodeController extends BaseController $db = db_connect(); $db->transStart(); - $coverFile = $this->request->getFile('cover'); - if ($coverFile !== null && $coverFile->isValid()) { - $cover = new Image([ - 'file_name' => $newEpisode->slug, - 'file_directory' => 'podcasts/' . $this->podcast->handle, - 'sizes' => config('Images') - ->podcastBannerSizes, - 'file' => $this->request->getFile('banner'), - 'uploaded_by' => user_id(), - 'updated_by' => user_id(), - ]); - $mediaModel = new MediaModel('image'); - if (! ($newCoverId = $mediaModel->saveMedia($cover))) { - $db->transRollback(); - return redirect() - ->back() - ->withInput() - ->with('errors', $mediaModel->errors()); - } - - $newEpisode->cover_id = $newCoverId; - } - $transcriptChoice = $this->request->getPost('transcript-choice'); - if ( - $transcriptChoice === 'upload-file' - && ($transcriptFile = $this->request->getFile('transcript_file')) - && $transcriptFile->isValid() - ) { - $transcript = new Media([ - 'file_name' => $newEpisode->slug . '-transcript', - 'file_directory' => 'podcasts/' . $this->podcast->handle, - 'file' => $transcriptFile, - 'uploaded_by' => user_id(), - 'updated_by' => user_id(), - ]); - $mediaModel = new MediaModel('image'); - if (! ($newTranscriptId = $mediaModel->saveMedia($transcript))) { - $db->transRollback(); - return redirect() - ->back() - ->withInput() - ->with('errors', $mediaModel->errors()); - } - - $newEpisode->transcript_id = $newTranscriptId; + if ($transcriptChoice === 'upload-file') { + $newEpisode->setTranscript($this->request->getFile('transcript_file')); } elseif ($transcriptChoice === 'remote-url') { $newEpisode->transcript_remote_url = $this->request->getPost( 'transcript_remote_url' - ) === '' ? null : $this->request->getPost('transcript_file_remote_url'); + ) === '' ? null : $this->request->getPost('transcript_remote_url'); } $chaptersChoice = $this->request->getPost('chapters-choice'); - if ( - $chaptersChoice === 'upload-file' - && ($chaptersFile = $this->request->getFile('chapters_file')) - && $chaptersFile->isValid() - ) { - $newEpisode->chapters_file = $chaptersFile; + if ($chaptersChoice === 'upload-file') { + $newEpisode->setChapters($this->request->getFile('chapters_file')); } elseif ($chaptersChoice === 'remote-url') { - $newEpisode->chapters_file_remote_url = $this->request->getPost( - 'chapters_file_remote_url' - ) === '' ? null : $this->request->getPost('chapters_file_remote_url'); + $newEpisode->chapters_remote_url = $this->request->getPost( + 'chapters_remote_url' + ) === '' ? null : $this->request->getPost('chapters_remote_url'); } $episodeModel = new EpisodeModel(); @@ -310,51 +261,43 @@ class EpisodeController extends BaseController $this->episode->custom_rss_string = $this->request->getPost('custom_rss'); $this->episode->updated_by = (int) user_id(); - - $audioFile = $this->request->getFile('audio_file'); - if ($audioFile !== null && $audioFile->isValid()) { - $this->episode->audio_file = $audioFile; - } - - $coverFile = $this->request->getFile('cover'); - if ($coverFile !== null && $coverFile->isValid()) { - $this->episode->cover = new Image($coverFile); - } + $this->episode->setAudio($this->request->getFile('audio_file')); + $this->episode->setCover($this->request->getFile('cover')); $transcriptChoice = $this->request->getPost('transcript-choice'); if ($transcriptChoice === 'upload-file') { $transcriptFile = $this->request->getFile('transcript_file'); if ($transcriptFile !== null && $transcriptFile->isValid()) { $this->episode->transcript_file = $transcriptFile; - $this->episode->transcript_file_remote_url = null; + $this->episode->transcript_remote_url = null; } } elseif ($transcriptChoice === 'remote-url') { if ( - ($transcriptFileRemoteUrl = $this->request->getPost('transcript_file_remote_url')) && + ($transcriptFileRemoteUrl = $this->request->getPost('transcript_remote_url')) && (($transcriptFile = $this->episode->transcript_file) !== null) ) { unlink((string) $transcriptFile); - $this->episode->transcript_file_path = null; + $this->episode->transcript->file_path = null; } - $this->episode->transcript_file_remote_url = $transcriptFileRemoteUrl === '' ? null : $transcriptFileRemoteUrl; + $this->episode->transcript_remote_url = $transcriptFileRemoteUrl === '' ? null : $transcriptFileRemoteUrl; } $chaptersChoice = $this->request->getPost('chapters-choice'); if ($chaptersChoice === 'upload-file') { $chaptersFile = $this->request->getFile('chapters_file'); if ($chaptersFile !== null && $chaptersFile->isValid()) { - $this->episode->chapters_file = $chaptersFile; - $this->episode->chapters_file_remote_url = null; + $this->episode->chapters = $chaptersFile; + $this->episode->chapters_remote_url = null; } } elseif ($chaptersChoice === 'remote-url') { if ( - ($chaptersFileRemoteUrl = $this->request->getPost('chapters_file_remote_url')) && + ($chaptersFileRemoteUrl = $this->request->getPost('chapters_remote_url')) && (($chaptersFile = $this->episode->chapters_file) !== null) ) { unlink((string) $chaptersFile); - $this->episode->chapters_file_path = null; + $this->episode->chapters->file_path = null; } - $this->episode->chapters_file_remote_url = $chaptersFileRemoteUrl === '' ? null : $chaptersFileRemoteUrl; + $this->episode->chapters_remote_url = $chaptersFileRemoteUrl === '' ? null : $chaptersFileRemoteUrl; } $db = db_connect(); @@ -396,7 +339,7 @@ class EpisodeController extends BaseController public function transcriptDelete(): RedirectResponse { unlink((string) $this->episode->transcript_file); - $this->episode->transcript_file_path = null; + $this->episode->transcript->file_path = null; $episodeModel = new EpisodeModel(); @@ -413,7 +356,7 @@ class EpisodeController extends BaseController public function chaptersDelete(): RedirectResponse { unlink((string) $this->episode->chapters_file); - $this->episode->chapters_file_path = null; + $this->episode->chapters->file_path = null; $episodeModel = new EpisodeModel(); diff --git a/modules/Admin/Controllers/PersonController.php b/modules/Admin/Controllers/PersonController.php index 7825e6f8d3ea7b8b08772c727b9d29025f0e6f28..a2020c022857827468c35efd0b11cad45ec1c2df 100644 --- a/modules/Admin/Controllers/PersonController.php +++ b/modules/Admin/Controllers/PersonController.php @@ -10,7 +10,6 @@ declare(strict_types=1); namespace Modules\Admin\Controllers; -use App\Entities\Image; use App\Entities\Person; use App\Models\PersonModel; use CodeIgniter\Exceptions\PageNotFoundException; @@ -78,6 +77,7 @@ class PersonController extends BaseController } $person = new Person([ + 'avatar' => $this->request->getFile('avatar'), 'full_name' => $this->request->getPost('full_name'), 'unique_name' => $this->request->getPost('unique_name'), 'information_url' => $this->request->getPost('information_url'), @@ -85,11 +85,6 @@ class PersonController extends BaseController 'updated_by' => user_id(), ]); - $avatarFile = $this->request->getFile('avatar'); - if ($avatarFile !== null && $avatarFile->isValid()) { - $person->avatar = new Image($avatarFile); - } - $personModel = new PersonModel(); if (! $personModel->insert($person)) { diff --git a/modules/Admin/Controllers/PodcastController.php b/modules/Admin/Controllers/PodcastController.php index e3e0162e600a8be54aa9b94fb326e0818e80614d..09cf6693ab41bde26225701bc43ce372626fa44f 100644 --- a/modules/Admin/Controllers/PodcastController.php +++ b/modules/Admin/Controllers/PodcastController.php @@ -10,7 +10,6 @@ declare(strict_types=1); namespace Modules\Admin\Controllers; -use App\Entities\Image; use App\Entities\Location; use App\Entities\Podcast; use App\Models\CategoryModel; @@ -196,6 +195,8 @@ class PodcastController extends BaseController $newPodcast = new Podcast([ 'title' => $this->request->getPost('title'), 'handle' => $this->request->getPost('handle'), + 'cover' => $this->request->getFile('cover'), + 'banner' => $this->request->getFile('banner'), 'description_markdown' => $this->request->getPost('description'), 'language_code' => $this->request->getPost('language'), 'category_id' => $this->request->getPost('category'), @@ -228,48 +229,6 @@ class PodcastController extends BaseController $db = db_connect(); $db->transStart(); - $cover = new Image([ - 'file_name' => 'cover', - 'file_directory' => 'podcasts/' . $newPodcast->handle, - 'sizes' => config('Images') - ->podcastCoverSizes, - 'file' => $this->request->getFile('cover'), - 'uploaded_by' => user_id(), - 'updated_by' => user_id(), - ]); - $mediaModel = new MediaModel('image'); - if (! ($newCoverId = $mediaModel->saveMedia($cover))) { - $db->transRollback(); - return redirect() - ->back() - ->withInput() - ->with('errors', $mediaModel->errors()); - } - $newPodcast->cover_id = $newCoverId; - - $bannerFile = $this->request->getFile('banner'); - if ($bannerFile !== null && $bannerFile->isValid()) { - $banner = new Image([ - 'file_name' => 'banner', - 'file_directory' => 'podcasts/' . $newPodcast->handle, - 'sizes' => config('Images') - ->podcastBannerSizes, - 'file' => $this->request->getFile('banner'), - 'uploaded_by' => user_id(), - 'updated_by' => user_id(), - ]); - $mediaModel = new MediaModel('image'); - if (! ($newBannerId = $mediaModel->saveMedia($banner))) { - $db->transRollback(); - return redirect() - ->back() - ->withInput() - ->with('errors', $mediaModel->errors()); - } - - $newPodcast->banner_id = $newBannerId; - } - $podcastModel = new PodcastModel(); if (! ($newPodcastId = $podcastModel->insert($newPodcast, true))) { $db->transRollback(); @@ -344,15 +303,9 @@ class PodcastController extends BaseController $this->podcast->title = $this->request->getPost('title'); $this->podcast->description_markdown = $this->request->getPost('description'); + $this->podcast->setCover($this->request->getFile('cover')); + $this->podcast->setBanner($this->request->getFile('banner')); - $coverFile = $this->request->getFile('cover'); - if ($coverFile !== null && $coverFile->isValid()) { - $this->podcast->cover->setFile($coverFile); - } - $bannerFile = $this->request->getFile('banner'); - if ($bannerFile !== null && $bannerFile->isValid()) { - $this->podcast->banner = new Image($bannerFile); - } $this->podcast->language_code = $this->request->getPost('language'); $this->podcast->category_id = $this->request->getPost('category'); $this->podcast->parental_advisory = @@ -381,6 +334,7 @@ class PodcastController extends BaseController $this->podcast->updated_by = (int) user_id(); $db = db_connect(); + $db->transStart(); $podcastModel = new PodcastModel(); @@ -400,7 +354,7 @@ class PodcastController extends BaseController $db->transComplete(); - return redirect()->route('podcast-view', [$this->podcast->id]); + return redirect()->back(); } public function deleteBanner(): RedirectResponse @@ -409,17 +363,14 @@ class PodcastController extends BaseController return redirect()->back(); } - $this->podcast->banner->delete(config('Images')->podcastBannerSizes); - - $this->podcast->banner_path = null; - $this->podcast->banner_mimetype = null; + $this->podcast->banner->deleteFile(); - $podcastModel = new PodcastModel(); - if (! $podcastModel->update($this->podcast->id, $this->podcast)) { + $mediaModel = new MediaModel(); + if (! $mediaModel->deleteMedia((int) $this->podcast->banner_id)) { return redirect() ->back() ->withInput() - ->with('errors', $podcastModel->errors()); + ->with('errors', $mediaModel->errors()); } return redirect()->back(); diff --git a/modules/Admin/Controllers/PodcastImportController.php b/modules/Admin/Controllers/PodcastImportController.php index cddb3989d07c8016a08a977ab598e31e8e805377..a990cc0a1d77c2fd8f80b1b6f7e6aeeedc2a33ba 100644 --- a/modules/Admin/Controllers/PodcastImportController.php +++ b/modules/Admin/Controllers/PodcastImportController.php @@ -11,7 +11,6 @@ declare(strict_types=1); namespace Modules\Admin\Controllers; use App\Entities\Episode; -use App\Entities\Image; use App\Entities\Location; use App\Entities\Person; use App\Entities\Podcast; diff --git a/modules/Admin/Language/en/Episode.php b/modules/Admin/Language/en/Episode.php index 87552b95ee25b8ca625db9d5c84dd983acdc386d..ea510aade0469a1c51ea00e2ad65bbb911b47da1 100644 --- a/modules/Admin/Language/en/Episode.php +++ b/modules/Admin/Language/en/Episode.php @@ -91,12 +91,12 @@ return [ 'transcript' => 'Transcript or closed captions', 'transcript_hint' => 'Allowed formats are txt, html, srt or json.', 'transcript_file' => 'Transcript file', - 'transcript_file_remote_url' => 'Remote url for transcript', + 'transcript_remote_url' => 'Remote url for transcript', 'transcript_file_delete' => 'Delete transcript file', 'chapters' => 'Chapters', 'chapters_hint' => 'File must be in JSON Chapters format.', 'chapters_file' => 'Chapters file', - 'chapters_file_remote_url' => 'Remote url for chapters file', + 'chapters_remote_url' => 'Remote url for chapters file', 'chapters_file_delete' => 'Delete chapters file', 'advanced_section_title' => 'Advanced Parameters', 'advanced_section_subtitle' => diff --git a/modules/Admin/Language/fr/Episode.php b/modules/Admin/Language/fr/Episode.php index ad3cf9713f098bea38e1a8954527ef738f0b35b2..1c5cbe4414dea751f08d7a6cfa9ac387c348edbf 100644 --- a/modules/Admin/Language/fr/Episode.php +++ b/modules/Admin/Language/fr/Episode.php @@ -93,13 +93,13 @@ return [ 'transcript_hint' => 'Les formats autorisés sont txt, html, srt ou json.', 'transcript_file' => 'Fichier de transcription', - 'transcript_file_remote_url' => + 'transcript_remote_url' => 'URL distante pour le fichier de transcription', 'transcript_file_delete' => 'Supprimer le fichier de transcription', 'chapters' => 'Chapitrage', 'chapters_hint' => 'Le fichier doit être en format “JSON Chaptersâ€.', 'chapters_file' => 'Fichier de chapitrage', - 'chapters_file_remote_url' => + 'chapters_remote_url' => 'URL distante pour le fichier de chapitrage', 'chapters_file_delete' => 'Supprimer le fichier de chapitrage', 'advanced_section_title' => 'Paramètres avancés', diff --git a/modules/Analytics/Helpers/analytics_helper.php b/modules/Analytics/Helpers/analytics_helper.php index ae215d52b6f3d663f2490e4cbd4d9b4ed451109b..026e6554def8ddef3af21857efa28a75e52a17ac 100644 --- a/modules/Analytics/Helpers/analytics_helper.php +++ b/modules/Analytics/Helpers/analytics_helper.php @@ -59,8 +59,8 @@ if (! function_exists('generate_episode_analytics_url')) { $podcastId, $episodeId, // bytes_threshold: number of bytes that must be downloaded for an episode to be counted in download analytics - // - if file is shorter than 60sec, then it's audio_file_size - // - if file is longer than 60 seconds then it's audio_file_header_size + 60 seconds + // - if audio is less than or equal to 60s, then take the audio file_size + // - if audio is more than 60s, then take the audio file_header_size + 60s $audioFileDuration <= 60 ? $audioFileSize : $audioFileHeaderSize + diff --git a/phpstan.neon b/phpstan.neon index 253465986b03f638d80ed7ab8b6c1c9800479d4e..f96db3c136d910b40d66b51033ac1aedc9b786a3 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -20,6 +20,7 @@ parameters: ignoreErrors: - '#This property type might be inlined to PHP. Do you have confidence it is correct\? Put it here#' - '#^Cognitive complexity for#' + - '#^Class cognitive complexity#' - '#Do not use chained method calls. Put each on separated lines.#' - '#Do not inherit from abstract class, better use composition#' - '#Cannot access property [\$a-z_]+ on ((array\|)?object)#' @@ -28,7 +29,7 @@ parameters: - '#Function \"preg_.*\(\)\" cannot be used/left in the code#' - '#Function "property_exists\(\)" cannot be used/left in the code#' - '#Instead of "instanceof/is_a\(\)" use ReflectionProvider service or "\(new ObjectType\(<desired_type\>\)\)\-\>isSuperTypeOf\(<element_type\>\)" for static reflection to work#' - - '#^Access to an undefined property App\\Entities\\Image#' + - '#^Access to an undefined property App\\Entities\\Media\\Image#' - message: '#Function "function_exists\(\)" cannot be used/left in the code#' paths: diff --git a/themes/cp_admin/episode/create.php b/themes/cp_admin/episode/create.php index 41ac3e152cd0038b25a8fc4cb5e0c207f44e7483..93b92c702f64099c7d2387836d4033f89ee2facf 100644 --- a/themes/cp_admin/episode/create.php +++ b/themes/cp_admin/episode/create.php @@ -156,8 +156,8 @@ <Forms.Input class="w-full" name="transcript_file" type="file" accept=".txt,.html,.srt,.json" /> </section> <section id="transcript-file-remote-url" class="tab-panel"> - <Forms.Label class="sr-only" for="transcript_file_remote_url" isOptional="true"><?= lang('Episode.form.transcript_file_remote_url') ?></Forms.Label> - <Forms.Input class="w-full" placeholder="https://…" name="transcript_file_remote_url" /> + <Forms.Label class="sr-only" for="transcript_remote_url" isOptional="true"><?= lang('Episode.form.transcript_remote_url') ?></Forms.Label> + <Forms.Input class="w-full" placeholder="https://…" name="transcript_remote_url" /> </section> </div> </div> @@ -183,8 +183,8 @@ <Forms.Input class="w-full" name="chapters_file" type="file" accept=".json" /> </section> <section id="chapters-file-remote-url" class="tab-panel"> - <Forms.Label class="sr-only" for="chapters_file_remote_url" isOptional="true"><?= lang('Episode.form.chapters_file_remote_url') ?></Forms.Label> - <Forms.Input class="w-full" placeholder="https://…" name="chapters_file_remote_url" /> + <Forms.Label class="sr-only" for="chapters_remote_url" isOptional="true"><?= lang('Episode.form.chapters_remote_url') ?></Forms.Label> + <Forms.Input class="w-full" placeholder="https://…" name="chapters_remote_url" /> </section> </div> </div> diff --git a/themes/cp_admin/episode/edit.php b/themes/cp_admin/episode/edit.php index d26d832e4d0f0e7c338343d2fd18eb3e8ae471bf..035b8d6352b539916ad3fb80be063ad112a8f5c5 100644 --- a/themes/cp_admin/episode/edit.php +++ b/themes/cp_admin/episode/edit.php @@ -153,10 +153,10 @@ ')</small>' . hint_tooltip(lang('Episode.form.transcript_hint'), 'ml-1') ?></legend> <div class="form-input-tabs"> - <input type="radio" name="transcript-choice" id="transcript-file-upload-choice" aria-controls="transcript-file-upload-choice" value="upload-file" <?= $episode->transcript_file_remote_url ? '' : 'checked' ?> /> + <input type="radio" name="transcript-choice" id="transcript-file-upload-choice" aria-controls="transcript-file-upload-choice" value="upload-file" <?= $episode->transcript_remote_url ? '' : 'checked' ?> /> <label for="transcript-file-upload-choice"><?= lang('Common.forms.upload_file') ?></label> - <input type="radio" name="transcript-choice" id="transcript-file-remote-url-choice" aria-controls="transcript-file-remote-url-choice" value="remote-url" <?= $episode->transcript_file_remote_url ? 'checked' : '' ?> /> + <input type="radio" name="transcript-choice" id="transcript-file-remote-url-choice" aria-controls="transcript-file-remote-url-choice" value="remote-url" <?= $episode->transcript_remote_url ? 'checked' : '' ?> /> <label for="transcript-file-remote-url-choice"><?= lang('Common.forms.remote_url') ?></label> <div class="py-2 tab-panels"> @@ -164,7 +164,7 @@ <?php if ($episode->transcript_file) : ?> <div class="flex mb-1 gap-x-2"> <?= anchor( - $episode->transcript_file_url, + $episode->transcript->file_url, icon('file', 'mr-2 text-skin-muted') . $episode->transcript_file, [ @@ -195,8 +195,8 @@ <Forms.Input class="w-full" name="transcript_file" type="file" accept=".txt,.html,.srt,.json" /> </section> <section id="transcript-file-remote-url" class="tab-panel"> - <Forms.Label class="sr-only" for="transcript_file_remote_url" isOptional="true"><?= lang('Episode.form.transcript_file_remote_url') ?></Forms.Label> - <Forms.Input class="w-full" placeholder="https://…" name="transcript_file_remote_url" value="<?= $episode->transcript_file_remote_url ?>" /> + <Forms.Label class="sr-only" for="transcript_remote_url" isOptional="true"><?= lang('Episode.form.transcript_remote_url') ?></Forms.Label> + <Forms.Input class="w-full" placeholder="https://…" name="transcript_remote_url" value="<?= $episode->transcript_remote_url ?>" /> </section> </div> </div> @@ -210,10 +210,10 @@ ')</small>' . hint_tooltip(lang('Episode.form.chapters_hint'), 'ml-1') ?></legend> <div class="form-input-tabs"> - <input type="radio" name="chapters-choice" id="chapters-file-upload-choice" aria-controls="chapters-file-upload-choice" value="upload-file" <?= $episode->chapters_file_remote_url ? '' : 'checked' ?> /> + <input type="radio" name="chapters-choice" id="chapters-file-upload-choice" aria-controls="chapters-file-upload-choice" value="upload-file" <?= $episode->chapters_remote_url ? '' : 'checked' ?> /> <label for="chapters-file-upload-choice"><?= lang('Common.forms.upload_file') ?></label> - <input type="radio" name="chapters-choice" id="chapters-file-remote-url-choice" aria-controls="chapters-file-remote-url-choice" value="remote-url" <?= $episode->chapters_file_remote_url ? 'checked' : '' ?> /> + <input type="radio" name="chapters-choice" id="chapters-file-remote-url-choice" aria-controls="chapters-file-remote-url-choice" value="remote-url" <?= $episode->chapters_remote_url ? 'checked' : '' ?> /> <label for="chapters-file-remote-url-choice"><?= lang('Common.forms.remote_url') ?></label> <div class="py-2 tab-panels"> @@ -221,7 +221,7 @@ <?php if ($episode->chapters_file) : ?> <div class="flex mb-1 gap-x-2"> <?= anchor( - $episode->chapters_file_url, + $episode->chapters->file_url, icon('file', 'mr-2') . $episode->chapters_file, [ 'class' => 'inline-flex items-center text-xs', @@ -251,8 +251,8 @@ <Forms.Input class="w-full" name="chapters_file" type="file" accept=".json" /> </section> <section id="chapters-file-remote-url" class="tab-panel"> - <Forms.Label class="sr-only" for="chapters_file_remote_url" isOptional="true"><?= lang('Episode.form.chapters_file_remote_url') ?></Forms.Label> - <Forms.Input class="w-full" placeholder="https://…" name="chapters_file_remote_url" value="<?= $episode->chapters_file_remote_url ?>" /> + <Forms.Label class="sr-only" for="chapters_remote_url" isOptional="true"><?= lang('Episode.form.chapters_remote_url') ?></Forms.Label> + <Forms.Input class="w-full" placeholder="https://…" name="chapters_remote_url" value="<?= $episode->chapters_remote_url ?>" /> </section> </div> </div> diff --git a/themes/cp_admin/episode/publish.php b/themes/cp_admin/episode/publish.php index f3e99324103a7815847d3418621d05819aafe655..eacfa9dbb02d6960fdbbc41bc9f09f80996f0264 100644 --- a/themes/cp_admin/episode/publish.php +++ b/themes/cp_admin/episode/publish.php @@ -59,7 +59,7 @@ </time> </div> </a> - <?= audio_player($episode->audio->file_url, $episode->audio->file_content_type, 'mt-auto') ?> + <?= audio_player($episode->audio->file_url, $episode->audio->file_mimetype, 'mt-auto') ?> </div> </div> <footer class="flex justify-around px-6 py-3"> diff --git a/themes/cp_admin/episode/publish_edit.php b/themes/cp_admin/episode/publish_edit.php index 8eb15701c172c2d74745b2ab1a19d2e8ffded5a4..80b2860d53d681569adaa1e3487de2ed5761e52d 100644 --- a/themes/cp_admin/episode/publish_edit.php +++ b/themes/cp_admin/episode/publish_edit.php @@ -63,7 +63,7 @@ </time> </div> </a> - <?= audio_player($episode->audio->file_url, $episode->audio->file_content_type, 'mt-auto') ?> + <?= audio_player($episode->audio->file_url, $episode->audio->file_mimetype, 'mt-auto') ?> </div> </div> <footer class="flex justify-around px-6 py-3"> diff --git a/themes/cp_admin/episode/soundbites.php b/themes/cp_admin/episode/soundbites.php index 425c989962ac9314601faeb0bb35c4d4ddbeae65..ec42a99f3c9dd5a9488de18e0194968ff81f525f 100644 --- a/themes/cp_admin/episode/soundbites.php +++ b/themes/cp_admin/episode/soundbites.php @@ -61,7 +61,7 @@ <div class="flex items-center gap-x-2"> <audio controls preload="auto" class="flex-1 w-full"> - <source src="<?= $episode->audio->file_url ?>" type="<?= $episode->audio->file_content_type ?>"> + <source src="<?= $episode->audio->file_url ?>" type="<?= $episode->audio->file_mimetype ?>"> Your browser does not support the audio tag. </audio> <IconButton glyph="timer" variant="info" data-type="get-soundbite" data-start-time-field-name="soundbites[0][start_time]" data-duration-field-name="soundbites[0][duration]" ><?= lang('Episode.soundbites_form.bookmark') ?></IconButton> diff --git a/themes/cp_admin/episode/view.php b/themes/cp_admin/episode/view.php index 5310bce7665f0fbad5a2ab392fa454e7cea0e1bb..f9a9e5e84b552bb6cdf124749ed45b6f1c2891aa 100644 --- a/themes/cp_admin/episode/view.php +++ b/themes/cp_admin/episode/view.php @@ -28,7 +28,7 @@ <?= $this->section('content') ?> <div class="mb-12"> - <?= audio_player($episode->audio->file_url, $episode->audio->file_content_type) ?> + <?= audio_player($episode->audio->file_url, $episode->audio->file_mimetype) ?> </div> <div class="grid grid-cols-1 gap-4 lg:grid-cols-2"> diff --git a/themes/cp_admin/podcast/edit.php b/themes/cp_admin/podcast/edit.php index 45651946c36ae68d9fa9cbc2ae20a70c9a9860ad..eb03dc58ffa2edd16deec449f7aa08c535b39c36 100644 --- a/themes/cp_admin/podcast/edit.php +++ b/themes/cp_admin/podcast/edit.php @@ -25,7 +25,7 @@ <?php if ($podcast->banner_id !== null): ?> <a href="<?= route_to('podcast-banner-delete', $podcast->id) ?>" class="absolute p-1 text-red-700 bg-red-100 border-2 rounded-full hover:text-red-900 border-contrast focus:ring-accent top-2 right-2" title="<?= lang('Podcast.form.banner_delete') ?>" data-tooltip="bottom"><?= icon('delete-bin') ?></a> <?php endif; ?> - <img src="<?= $podcast->banner->small_url ?>" alt="" class="object-cover w-full aspect-[3/1] bg-header" /> + <img src="<?= $podcast->banner->small_url ?>" alt="" class="w-full aspect-[3/1] bg-header" /> <div class="flex px-4 py-2"> <img src="<?= $podcast->cover->thumbnail_url ?>" alt="<?= $podcast->title ?>" class="w-16 h-16 mr-4 -mt-8 rounded-full ring-2 ring-background-elevated aspect-square" /> diff --git a/themes/cp_app/embed.php b/themes/cp_app/embed.php index 7b49fae61c1f15973018f49cbf77eb0ab49ae694..55b3da0dc81b5ae3ce8de1df06d755107c73160e 100644 --- a/themes/cp_app/embed.php +++ b/themes/cp_app/embed.php @@ -46,7 +46,7 @@ ? '?_from=' . parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) : '') ?> - <source src="<?= $source ?>" type="<?= $episode->audio->file_content_type ?>" /> + <source src="<?= $source ?>" type="<?= $episode->audio->file_mimetype ?>" /> </vm-audio> <vm-ui> <vm-icon-library name="castopod-icons"></vm-icon-library> diff --git a/themes/cp_app/episode/_layout.php b/themes/cp_app/episode/_layout.php index 80cb7e1350f6dd83f22a93b8bc81d322a95f3b18..b757aeca7001c2e7b6adb348bbabfda401e3b1f7 100644 --- a/themes/cp_app/episode/_layout.php +++ b/themes/cp_app/episode/_layout.php @@ -115,7 +115,7 @@ title="<?= $episode->title ?>" podcast="<?= $episode->podcast->title ?>" src="<?= $episode->audio_file_web_url ?>" - mediaType="<?= $episode->audio->file_content_type ?>" + mediaType="<?= $episode->audio->file_mimetype ?>" playLabel="<?= lang('Common.play_episode_button.play') ?>" playingLabel="<?= lang('Common.play_episode_button.playing') ?>"></play-episode-button> <div class="text-xs"> diff --git a/themes/cp_app/episode/_partials/card.php b/themes/cp_app/episode/_partials/card.php index 1105015ddde91511dcfee6662bc88aa609c8c72c..3b29f8ec6f4d5bfee7234c7b4651e969481cf9af 100644 --- a/themes/cp_app/episode/_partials/card.php +++ b/themes/cp_app/episode/_partials/card.php @@ -20,7 +20,7 @@ title="<?= $episode->title ?>" podcast="<?= $episode->podcast->title ?>" src="<?= $episode->audio_file_web_url ?>" - mediaType="<?= $episode->audio->file_content_type ?>" + mediaType="<?= $episode->audio->file_mimetype ?>" playLabel="<?= lang('Common.play_episode_button.play') ?>" playingLabel="<?= lang('Common.play_episode_button.playing') ?>"></play-episode-button> </div> diff --git a/themes/cp_app/episode/_partials/preview_card.php b/themes/cp_app/episode/_partials/preview_card.php index d9b97d8043723f0faab6135a72be63b5a93575ee..9e69012d9d142394be0e1abfeb4127eb6f0d3059 100644 --- a/themes/cp_app/episode/_partials/preview_card.php +++ b/themes/cp_app/episode/_partials/preview_card.php @@ -21,7 +21,7 @@ title="<?= $episode->title ?>" podcast="<?= $episode->podcast->title ?>" src="<?= $episode->audio_file_web_url ?>" - mediaType="<?= $episode->audio->file_content_type ?>" + mediaType="<?= $episode->audio->file_mimetype ?>" playLabel="<?= lang('Common.play_episode_button.play') ?>" playingLabel="<?= lang('Common.play_episode_button.playing') ?>"></play-episode-button> </div> \ No newline at end of file diff --git a/themes/cp_app/podcast/follow.php b/themes/cp_app/podcast/follow.php index 10032df74a6005b3b5b8035b203bee3d2c34ec4b..e17cbd90d20ea441db83f6390474cd0195e7d10a 100644 --- a/themes/cp_app/podcast/follow.php +++ b/themes/cp_app/podcast/follow.php @@ -38,7 +38,7 @@ 'Fediverse.follow.subtitle', ) ?></h1> <div class="flex flex-col w-full max-w-xs -mt-24 overflow-hidden shadow bg-elevated rounded-xl"> - <img src="<?= $actor->podcast->banner->small_url ?>" alt="" class="object-cover w-full aspect-[3/1] bg-header" /> + <img src="<?= $actor->podcast->banner->small_url ?>" alt="" class="w-full aspect-[3/1] bg-header" /> <div class="flex px-4 py-2"> <img src="<?= $actor->avatar_image_url ?>" alt="<?= $actor->display_name ?>" class="w-16 h-16 mr-4 -mt-8 rounded-full ring-2 ring-background-elevated aspect-square" />