From 0f16423f66cb11978981d8530a8c07dffadc89b3 Mon Sep 17 00:00:00 2001 From: Brock H Caldwell Date: Thu, 12 Jun 2025 23:39:06 -0500 Subject: [PATCH] feat: upcoming episodes component --- composer.json | 5 +- composer.lock | 148 +++++++++--------- src/Monitor/Dto/UpcomingEpisode.php | 17 ++ src/Monitor/Framework/Entity/Monitor.php | 5 + src/Twig/Components/UpcomingEpisodes.php | 81 ++++++++++ .../components/UpcomingEpisodes.html.twig | 11 ++ templates/monitor/index.html.twig | 25 +-- 7 files changed, 210 insertions(+), 82 deletions(-) create mode 100644 src/Monitor/Dto/UpcomingEpisode.php create mode 100644 src/Twig/Components/UpcomingEpisodes.php create mode 100644 templates/components/UpcomingEpisodes.html.twig diff --git a/composer.json b/composer.json index 8b284c3..2501a84 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "minimum-stability": "stable", "prefer-stable": true, "require": { - "php": ">=8.2", + "php": ">=8.4", "ext-ctype": "*", "ext-iconv": "*", "1tomany/rich-bundle": "^1.8", @@ -57,6 +57,9 @@ "symfony/flex": true, "symfony/runtime": true }, + "platform": { + "php": "8.4" + }, "bump-after-update": true, "sort-packages": true }, diff --git a/composer.lock b/composer.lock index 0f0d50c..6f46c6b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "55c76ae7fe5ad6e5c7edbb0150987fc7", + "content-hash": "e8b5e39f9d73a6ace2b9e39240186b4f", "packages": [ { "name": "1tomany/rich-bundle", - "version": "v1.9.5", + "version": "v1.10.4", "source": { "type": "git", "url": "https://github.com/1tomany/rich-bundle.git", - "reference": "434c0fa70aefa11a23342006a10221360beb0f71" + "reference": "63a728e22632082d6db07e158bf1f5a4e5854d01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/1tomany/rich-bundle/zipball/434c0fa70aefa11a23342006a10221360beb0f71", - "reference": "434c0fa70aefa11a23342006a10221360beb0f71", + "url": "https://api.github.com/repos/1tomany/rich-bundle/zipball/63a728e22632082d6db07e158bf1f5a4e5854d01", + "reference": "63a728e22632082d6db07e158bf1f5a4e5854d01", "shasum": "" }, "require": { @@ -60,9 +60,9 @@ "description": "Symfony bundle that provides easy scaffolding to build RICH applications", "support": { "issues": "https://github.com/1tomany/rich-bundle/issues", - "source": "https://github.com/1tomany/rich-bundle/tree/v1.9.5" + "source": "https://github.com/1tomany/rich-bundle/tree/v1.10.4" }, - "time": "2025-05-01T16:54:44+00:00" + "time": "2025-06-05T00:20:20+00:00" }, { "name": "aimeos/map", @@ -997,16 +997,16 @@ }, { "name": "doctrine/doctrine-migrations-bundle", - "version": "3.4.1", + "version": "3.4.2", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineMigrationsBundle.git", - "reference": "e858ce0f5c12b266dce7dce24834448355155da7" + "reference": "5a6ac7120c2924c4c070a869d08b11ccf9e277b9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/e858ce0f5c12b266dce7dce24834448355155da7", - "reference": "e858ce0f5c12b266dce7dce24834448355155da7", + "url": "https://api.github.com/repos/doctrine/DoctrineMigrationsBundle/zipball/5a6ac7120c2924c4c070a869d08b11ccf9e277b9", + "reference": "5a6ac7120c2924c4c070a869d08b11ccf9e277b9", "shasum": "" }, "require": { @@ -1020,7 +1020,6 @@ "composer/semver": "^3.0", "doctrine/coding-standard": "^12", "doctrine/orm": "^2.6 || ^3", - "doctrine/persistence": "^2.0 || ^3", "phpstan/phpstan": "^1.4 || ^2", "phpstan/phpstan-deprecation-rules": "^1 || ^2", "phpstan/phpstan-phpunit": "^1 || ^2", @@ -1063,7 +1062,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineMigrationsBundle/issues", - "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.4.1" + "source": "https://github.com/doctrine/DoctrineMigrationsBundle/tree/3.4.2" }, "funding": [ { @@ -1079,7 +1078,7 @@ "type": "tidelift" } ], - "time": "2025-01-27T22:48:22+00:00" + "time": "2025-03-11T17:36:26+00:00" }, { "name": "doctrine/event-manager", @@ -2079,16 +2078,16 @@ }, { "name": "nesbot/carbon", - "version": "3.9.1", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "ced71f79398ece168e24f7f7710462f462310d4d" + "reference": "c1397390dd0a7e0f11660f0ae20f753d88c1f3d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ced71f79398ece168e24f7f7710462f462310d4d", - "reference": "ced71f79398ece168e24f7f7710462f462310d4d", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/c1397390dd0a7e0f11660f0ae20f753d88c1f3d9", + "reference": "c1397390dd0a7e0f11660f0ae20f753d88c1f3d9", "shasum": "" }, "require": { @@ -2096,9 +2095,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -2106,14 +2105,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.57.2", + "friendsofphp/php-cs-fixer": "^3.75.0", "kylekatarnls/multi-tester": "^2.5.3", - "ondrejmirtes/better-reflection": "^6.25.0.4", "phpmd/phpmd": "^2.15.0", - "phpstan/extension-installer": "^1.3.1", - "phpstan/phpstan": "^1.11.2", - "phpunit/phpunit": "^10.5.20", - "squizlabs/php_codesniffer": "^3.9.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^10.5.46", + "squizlabs/php_codesniffer": "^3.13.0" }, "bin": [ "bin/carbon" @@ -2181,7 +2179,7 @@ "type": "tidelift" } ], - "time": "2025-05-01T19:51:51+00:00" + "time": "2025-06-12T10:24:28+00:00" }, { "name": "nihilarr/parse-torrent-name", @@ -7672,16 +7670,16 @@ }, { "name": "symfony/stimulus-bundle", - "version": "v2.25.2", + "version": "v2.26.1", "source": { "type": "git", "url": "https://github.com/symfony/stimulus-bundle.git", - "reference": "5a6aef0646119530da862d5afa1386ade3b9ed43" + "reference": "82c174ebe564e6ecc1412974b6380b86d450675f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/5a6aef0646119530da862d5afa1386ade3b9ed43", - "reference": "5a6aef0646119530da862d5afa1386ade3b9ed43", + "url": "https://api.github.com/repos/symfony/stimulus-bundle/zipball/82c174ebe564e6ecc1412974b6380b86d450675f", + "reference": "82c174ebe564e6ecc1412974b6380b86d450675f", "shasum": "" }, "require": { @@ -7721,7 +7719,7 @@ "symfony-ux" ], "support": { - "source": "https://github.com/symfony/stimulus-bundle/tree/v2.25.2" + "source": "https://github.com/symfony/stimulus-bundle/tree/v2.26.1" }, "funding": [ { @@ -7737,7 +7735,7 @@ "type": "tidelift" } ], - "time": "2025-05-19T11:54:27+00:00" + "time": "2025-06-05T17:25:17+00:00" }, { "name": "symfony/stopwatch", @@ -8338,16 +8336,16 @@ }, { "name": "symfony/ux-icons", - "version": "v2.25.0", + "version": "v2.26.0", "source": { "type": "git", "url": "https://github.com/symfony/ux-icons.git", - "reference": "430b2753aa55a46baa001055bf7976b62bc96942" + "reference": "e5c1e5b5093ae26dba45d0f3390a1e21f305c47a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-icons/zipball/430b2753aa55a46baa001055bf7976b62bc96942", - "reference": "430b2753aa55a46baa001055bf7976b62bc96942", + "url": "https://api.github.com/repos/symfony/ux-icons/zipball/e5c1e5b5093ae26dba45d0f3390a1e21f305c47a", + "reference": "e5c1e5b5093ae26dba45d0f3390a1e21f305c47a", "shasum": "" }, "require": { @@ -8407,7 +8405,7 @@ "twig" ], "support": { - "source": "https://github.com/symfony/ux-icons/tree/v2.25.0" + "source": "https://github.com/symfony/ux-icons/tree/v2.26.0" }, "funding": [ { @@ -8423,20 +8421,20 @@ "type": "tidelift" } ], - "time": "2025-04-07T13:54:07+00:00" + "time": "2025-05-30T02:07:34+00:00" }, { "name": "symfony/ux-live-component", - "version": "v2.25.2", + "version": "v2.26.1", "source": { "type": "git", "url": "https://github.com/symfony/ux-live-component.git", - "reference": "79e8cc179eb21119547c492ae21e4bf529ac1a15" + "reference": "92b300bb90d87f14aeae47b0f5c9e058b15f5c2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/79e8cc179eb21119547c492ae21e4bf529ac1a15", - "reference": "79e8cc179eb21119547c492ae21e4bf529ac1a15", + "url": "https://api.github.com/repos/symfony/ux-live-component/zipball/92b300bb90d87f14aeae47b0f5c9e058b15f5c2f", + "reference": "92b300bb90d87f14aeae47b0f5c9e058b15f5c2f", "shasum": "" }, "require": { @@ -8449,7 +8447,9 @@ "twig/twig": "^3.10.3" }, "conflict": { - "symfony/config": "<5.4.0" + "symfony/config": "<5.4.0", + "symfony/property-info": "~7.0.0", + "symfony/type-info": "<7.2" }, "require-dev": { "doctrine/annotations": "^1.0", @@ -8502,7 +8502,7 @@ "twig" ], "support": { - "source": "https://github.com/symfony/ux-live-component/tree/v2.25.2" + "source": "https://github.com/symfony/ux-live-component/tree/v2.26.1" }, "funding": [ { @@ -8518,20 +8518,20 @@ "type": "tidelift" } ], - "time": "2025-05-19T11:54:27+00:00" + "time": "2025-06-06T19:57:53+00:00" }, { "name": "symfony/ux-turbo", - "version": "v2.25.2", + "version": "v2.26.1", "source": { "type": "git", "url": "https://github.com/symfony/ux-turbo.git", - "reference": "11ebca138005c7e25678c3f98a07ddf718a0480c" + "reference": "3754ac2b41220127e58c62f7599eaf7834b69a55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/11ebca138005c7e25678c3f98a07ddf718a0480c", - "reference": "11ebca138005c7e25678c3f98a07ddf718a0480c", + "url": "https://api.github.com/repos/symfony/ux-turbo/zipball/3754ac2b41220127e58c62f7599eaf7834b69a55", + "reference": "3754ac2b41220127e58c62f7599eaf7834b69a55", "shasum": "" }, "require": { @@ -8545,7 +8545,8 @@ "dbrekelmans/bdi": "dev-main", "doctrine/doctrine-bundle": "^2.4.3", "doctrine/orm": "^2.8 | 3.0", - "phpstan/phpstan": "^1.10", + "php-webdriver/webdriver": "^1.15", + "phpstan/phpstan": "^2.1.17", "symfony/asset-mapper": "^6.4|^7.0", "symfony/debug-bundle": "^5.4|^6.0|^7.0", "symfony/expression-language": "^5.4|^6.0|^7.0", @@ -8553,7 +8554,7 @@ "symfony/framework-bundle": "^6.4|^7.0", "symfony/mercure-bundle": "^0.3.7", "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/panther": "^2.1", + "symfony/panther": "^2.2", "symfony/phpunit-bridge": "^5.4|^6.0|^7.0", "symfony/process": "^5.4|6.3.*|^7.0", "symfony/property-access": "^5.4|^6.0|^7.0", @@ -8600,7 +8601,7 @@ "turbo-stream" ], "support": { - "source": "https://github.com/symfony/ux-turbo/tree/v2.25.2" + "source": "https://github.com/symfony/ux-turbo/tree/v2.26.1" }, "funding": [ { @@ -8616,20 +8617,20 @@ "type": "tidelift" } ], - "time": "2025-05-19T11:54:27+00:00" + "time": "2025-06-05T17:25:17+00:00" }, { "name": "symfony/ux-twig-component", - "version": "v2.25.2", + "version": "v2.26.0", "source": { "type": "git", "url": "https://github.com/symfony/ux-twig-component.git", - "reference": "d20da25517fc09d147897d02819a046f0a0f6735" + "reference": "825e653b34fb48ed2198913c603d80f7632fe9c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/d20da25517fc09d147897d02819a046f0a0f6735", - "reference": "d20da25517fc09d147897d02819a046f0a0f6735", + "url": "https://api.github.com/repos/symfony/ux-twig-component/zipball/825e653b34fb48ed2198913c603d80f7632fe9c1", + "reference": "825e653b34fb48ed2198913c603d80f7632fe9c1", "shasum": "" }, "require": { @@ -8683,7 +8684,7 @@ "twig" ], "support": { - "source": "https://github.com/symfony/ux-twig-component/tree/v2.25.2" + "source": "https://github.com/symfony/ux-twig-component/tree/v2.26.0" }, "funding": [ { @@ -8699,7 +8700,7 @@ "type": "tidelift" } ], - "time": "2025-05-20T13:06:01+00:00" + "time": "2025-05-26T06:21:54+00:00" }, { "name": "symfony/validator", @@ -9386,16 +9387,16 @@ "packages-dev": [ { "name": "nikic/php-parser", - "version": "v5.4.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { @@ -9438,22 +9439,22 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "phpstan/phpstan", - "version": "2.1.14", + "version": "2.1.17", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2" + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8f2e03099cac24ff3b379864d171c5acbfc6b9a2", - "reference": "8f2e03099cac24ff3b379864d171c5acbfc6b9a2", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053", "shasum": "" }, "require": { @@ -9498,7 +9499,7 @@ "type": "github" } ], - "time": "2025-05-02T15:32:28+00:00" + "time": "2025-05-21T20:55:28+00:00" }, { "name": "symfony/maker-bundle", @@ -9684,10 +9685,13 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=8.2", + "php": ">=8.4", "ext-ctype": "*", "ext-iconv": "*" }, "platform-dev": [], + "platform-overrides": { + "php": "8.4" + }, "plugin-api-version": "2.3.0" } diff --git a/src/Monitor/Dto/UpcomingEpisode.php b/src/Monitor/Dto/UpcomingEpisode.php new file mode 100644 index 0000000..9798c21 --- /dev/null +++ b/src/Monitor/Dto/UpcomingEpisode.php @@ -0,0 +1,17 @@ + Carbon::parse($this->airDate)->format('m/d/Y'); + }, + public string $episodeTitle, + public int $episodeNumber, + ) {} +} \ No newline at end of file diff --git a/src/Monitor/Framework/Entity/Monitor.php b/src/Monitor/Framework/Entity/Monitor.php index 36b7be2..6b048e3 100644 --- a/src/Monitor/Framework/Entity/Monitor.php +++ b/src/Monitor/Framework/Entity/Monitor.php @@ -259,4 +259,9 @@ class Monitor return $this; } + + public function isActive(): bool + { + return in_array($this->status, ['New', 'Active', 'In Progress']); + } } diff --git a/src/Twig/Components/UpcomingEpisodes.php b/src/Twig/Components/UpcomingEpisodes.php new file mode 100644 index 0000000..bb894a8 --- /dev/null +++ b/src/Twig/Components/UpcomingEpisodes.php @@ -0,0 +1,81 @@ +getMonitors(); + foreach ($monitors as $monitor) { + $upcomingEpisodes->merge($this->getNextEpisodes($monitor)); + } + + return $upcomingEpisodes->slice(0, $limit)->toArray(); + } + + private function getMonitors() + { + $user = $this->getUser(); + return $user->getMonitors()->filter( + fn (Monitor $monitor) => null === $monitor->getParent() && $monitor->isActive() + ) ?? []; + } + + private function getNextEpisodes(Monitor $monitor): Map + { + $today = CarbonImmutable::now(); + $seriesInfo = $this->tmdb->tvDetails($monitor->getTmdbId()); + + switch ($monitor->getMonitorType()) { + case "tvseason": + $episodes = Map::from($seriesInfo->episodes[$monitor->getSeason()]) + ->filter(function (array $episode) use ($today) { + $airDate = CarbonImmutable::parse($episode['air_date']); + return $airDate->lte($today); + }) + ; + break; + case "tvshows": + $episodes = []; + foreach ($seriesInfo->episodes as $season => $episodeList) { + $episodes = array_merge($episodes, $episodeList); + } + $episodes = Map::from($episodes) + ->filter(function (array $episode) use ($today) { + $airDate = CarbonImmutable::parse($episode['air_date']); + return $airDate->gte($today); + }) + ; + break; + } + + return $episodes->map(function (array $episode) use ($monitor) { + return new UpcomingEpisode( + $monitor->getTitle(), + $episode['air_date'], + $episode['name'], + $episode['episode_number'], + ); + }); + } +} diff --git a/templates/components/UpcomingEpisodes.html.twig b/templates/components/UpcomingEpisodes.html.twig new file mode 100644 index 0000000..8d45bd7 --- /dev/null +++ b/templates/components/UpcomingEpisodes.html.twig @@ -0,0 +1,11 @@ + + + diff --git a/templates/monitor/index.html.twig b/templates/monitor/index.html.twig index 078cf1d..370f247 100644 --- a/templates/monitor/index.html.twig +++ b/templates/monitor/index.html.twig @@ -4,15 +4,22 @@ {% block h2 %}Monitors{% endblock %} {% block body %} -
- - - -
+
+ +
+ + + + + + +
+ +
+ + + +
-
- - -
{% endblock %}