From 4a10aa991544b490fbc839276de7b68552a6a7a3 Mon Sep 17 00:00:00 2001 From: Phan An Date: Tue, 4 Jun 2024 13:10:44 +0200 Subject: [PATCH] feat: replace some attributes with casts --- app/Casts/SongLyricsCast.php | 28 ++++++++++++++++++ app/Casts/SongStorageCast.php | 24 ++++++++++++++++ app/Casts/SongTitleCast.php | 28 ++++++++++++++++++ app/Models/Playlist.php | 6 ++-- app/Models/Song.php | 39 ++++---------------------- app/Models/User.php | 2 +- app/Repositories/PodcastRepository.php | 5 ---- tests/Unit/Models/SongTest.php | 3 +- 8 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 app/Casts/SongLyricsCast.php create mode 100644 app/Casts/SongStorageCast.php create mode 100644 app/Casts/SongTitleCast.php diff --git a/app/Casts/SongLyricsCast.php b/app/Casts/SongLyricsCast.php new file mode 100644 index 00000000..78b3dd92 --- /dev/null +++ b/app/Casts/SongLyricsCast.php @@ -0,0 +1,28 @@ +, replace breaks with newlines and strip all tags. + $value = strip_tags(preg_replace('##i', PHP_EOL, $value)); + + // also remove the timestamps that often come with LRC files + return preg_replace('/\[\d{2}:\d{2}.\d{2}]\s*/m', '', $value); + } + + public function set(Model $model, string $key, mixed $value, array $attributes): mixed + { + return $value; + } +} diff --git a/app/Casts/SongStorageCast.php b/app/Casts/SongStorageCast.php new file mode 100644 index 00000000..15074f78 --- /dev/null +++ b/app/Casts/SongStorageCast.php @@ -0,0 +1,24 @@ +value; + } +} diff --git a/app/Casts/SongTitleCast.php b/app/Casts/SongTitleCast.php new file mode 100644 index 00000000..62e51189 --- /dev/null +++ b/app/Casts/SongTitleCast.php @@ -0,0 +1,28 @@ +path, PATHINFO_FILENAME); + } + + /** + * @param string $value + */ + public function set(Model $model, string $key, mixed $value, array $attributes): string + { + return html_entity_decode($value); + } +} diff --git a/app/Models/Playlist.php b/app/Models/Playlist.php index 39d19814..47019a79 100644 --- a/app/Models/Playlist.php +++ b/app/Models/Playlist.php @@ -193,12 +193,12 @@ class Playlist extends Model protected function isCollaborative(): Attribute { - return Attribute::get(fn (): bool => !$this->is_smart && - LicenseFacade::isPlus() + return Attribute::get(fn (): bool => !$this->is_smart + && LicenseFacade::isPlus() && $this->collaborators->isNotEmpty()); } - /** @return array */ + /** @inheritdoc */ public function toSearchableArray(): array { return [ diff --git a/app/Models/Song.php b/app/Models/Song.php index 27f60717..9072b5f7 100644 --- a/app/Models/Song.php +++ b/app/Models/Song.php @@ -4,6 +4,9 @@ namespace App\Models; use App\Builders\SongBuilder; use App\Casts\Podcast\EpisodeMetadataCast; +use App\Casts\SongLyricsCast; +use App\Casts\SongStorageCast; +use App\Casts\SongTitleCast; use App\Enums\PlayableType; use App\Enums\SongStorageType; use App\Models\Concerns\SupportsDeleteWhereValueNotIn; @@ -79,11 +82,14 @@ class Song extends Model protected $hidden = ['updated_at', 'path', 'mtime']; protected $casts = [ + 'title' => SongTitleCast::class, + 'lyrics' => SongLyricsCast::class, 'length' => 'float', 'mtime' => 'int', 'track' => 'int', 'disc' => 'int', 'is_public' => 'bool', + 'storage' => SongStorageCast::class, 'episode_metadata' => EpisodeMetadataCast::class, ]; @@ -148,14 +154,6 @@ class Song extends Model return Attribute::get(fn () => $this->podcast_id ? PlayableType::PODCAST_EPISODE : PlayableType::SONG); } - protected function title(): Attribute - { - return new Attribute( - get: fn (?string $value) => $value ?: pathinfo($this->path, PATHINFO_FILENAME), - set: static fn (string $value) => html_entity_decode($value) - ); - } - public function accessibleBy(User $user): bool { if ($this->isEpisode()) { @@ -170,31 +168,6 @@ class Song extends Model return $this->owner_id === $user->id; } - protected function lyrics(): Attribute - { - $normalizer = static function (?string $value): string { - // Since we're displaying the lyrics using
, replace breaks with newlines and strip all tags.
-            $value = strip_tags(preg_replace('##i', PHP_EOL, $value));
-
-            // also remove the timestamps that often come with LRC files
-            return preg_replace('/\[\d{2}:\d{2}.\d{2}]\s*/m', '', $value);
-        };
-
-        return new Attribute(get: $normalizer, set: $normalizer);
-    }
-
-    protected function storage(): Attribute
-    {
-        return new Attribute(
-            get: static fn (?string $raw) => SongStorageType::tryFrom($raw) ?? SongStorageType::LOCAL,
-            set: static function (SongStorageType|string|null $type) {
-                $type = $type instanceof SongStorageType ? $type : SongStorageType::tryFrom($type);
-
-                return $type->value;
-            }
-        );
-    }
-
     protected function storageMetadata(): Attribute
     {
         return new Attribute(
diff --git a/app/Models/User.php b/app/Models/User.php
index 87f73dc4..0812c670 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -40,7 +40,7 @@ use Laravel\Sanctum\PersonalAccessToken;
  * @property ?string $sso_provider
  * @property ?string $sso_id
  * @property bool $is_sso
- * @property Collection $podcast
+ * @property Collection $podcasts
  */
 class User extends Authenticatable
 {
diff --git a/app/Repositories/PodcastRepository.php b/app/Repositories/PodcastRepository.php
index 397015a1..2b9eb9b5 100644
--- a/app/Repositories/PodcastRepository.php
+++ b/app/Repositories/PodcastRepository.php
@@ -9,11 +9,6 @@ use Illuminate\Support\Collection;
 /** @extends Repository */
 class PodcastRepository extends Repository
 {
-    public function __construct()
-    {
-        parent::__construct(Podcast::class);
-    }
-
     public function findOneByUrl(string $url): ?Podcast
     {
         return $this->findOneBy(['url' => $url]);
diff --git a/tests/Unit/Models/SongTest.php b/tests/Unit/Models/SongTest.php
index e85f0a73..66ec849a 100644
--- a/tests/Unit/Models/SongTest.php
+++ b/tests/Unit/Models/SongTest.php
@@ -7,11 +7,12 @@ use Tests\TestCase;
 
 class SongTest extends TestCase
 {
-    public function testLyricsDoNotContainTimestamps(): void
+    public function testRetrievedLyricsDoNotContainTimestamps(): void
     {
         /** @var Song $song */
         $song = Song::factory()->create(['lyrics' => "[00:00.00]Line 1\n[00:01.00]Line 2\n[00:02.00]Line 3"]);
 
         self::assertSame("Line 1\nLine 2\nLine 3", $song->lyrics);
+        self::assertSame("[00:00.00]Line 1\n[00:01.00]Line 2\n[00:02.00]Line 3", $song->getAttributes()['lyrics']);
     }
 }