Compare commits

...

9 Commits

16 changed files with 59 additions and 18 deletions

View File

@@ -3,6 +3,7 @@ FROM dunglas/frankenphp:php8.4
ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
ENV APP_VERSION="0.0.1"
RUN install-php-extensions \
pdo_mysql \

View File

@@ -12,6 +12,7 @@ export default class extends Controller {
filename: String,
mediaType: String,
imdbId: String,
episodeId: String
}
download() {
@@ -27,6 +28,7 @@ export default class extends Controller {
filename: this.filenameValue,
mediaType: this.mediaTypeValue,
imdbId: this.imdbIdValue,
episodeId: this.episodeIdValue
})
})
.then(res => res.json())

View File

@@ -48,6 +48,7 @@ export default class extends Controller {
this.options.forEach((option) => option.querySelector('.download-btn').dataset['title'] = this.titleValue);
this.options[0].querySelector('input[type="checkbox"]').checked = true;
} else {
this.countTarget.innerText = 0;
this.episodeSelectorTarget.disabled = true;
}
this.loadingIconOutlet.increaseCount();

View File

@@ -1,4 +1,6 @@
twig:
globals:
version: '%app.version%'
file_name_pattern: '*.twig'
date:
format: 'm/d/Y'

View File

@@ -22,8 +22,11 @@ parameters:
app.cache.redis.host.default: 'redis://redis'
# Various configs
app.default.version: '0.dev'
app.default.timezone: 'America/Chicago'
app.version: '%env(default:app.default.version:APP_VERSION)%'
services:
# default configuration for services in *this* file
_defaults:

View File

@@ -4,6 +4,9 @@ ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
ARG APP_VERSION="0.dev"
ENV APP_VERSION="${APP_VERSION}"
RUN install-php-extensions \
pdo_mysql \
gd \

View File

@@ -4,6 +4,9 @@ ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
ARG APP_VERSION="0.dev"
ENV APP_VERSION="${APP_VERSION}"
RUN install-php-extensions \
pdo_mysql \
gd \

View File

@@ -4,6 +4,9 @@ ENV SERVER_NAME=":80"
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
ARG APP_VERSION="0.dev"
ENV APP_VERSION="${APP_VERSION}"
RUN install-php-extensions \
pdo_mysql \
gd \

View File

@@ -26,6 +26,9 @@ class DownloadMediaInput implements InputInterface
#[SourceRequest('imdbId')]
public string $imdbId,
#[SourceRequest('episodeId', nullify: true)]
public ?string $episodeId = null,
public ?int $userId = null,
public ?int $downloadId = null,

View File

@@ -11,6 +11,7 @@ use App\Download\Action\Input\PauseDownloadInput;
use App\Download\Action\Input\ResumeDownloadInput;
use App\Download\Framework\Repository\DownloadRepository;
use App\Util\Broadcaster;
use Nihilarr\PTN;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
@@ -28,6 +29,13 @@ class ApiController extends AbstractController
public function download(
DownloadMediaInput $input,
): Response {
$ptn = (object) new Ptn()->parse($input->filename);
if ($input->mediaType === "tvshows" &&
!property_exists($ptn, 'episode') && !property_exists($ptn, 'season')
) {
$input->filename = $input->episodeId . '_' . $input->filename;
}
$download = $this->downloadRepository->insert(
$this->getUser(),
$input->url,

View File

@@ -61,10 +61,10 @@ readonly class MonitorTvShowHandler implements HandlerInterface
// Dispatch Episode commands for each missing Episode
foreach ($episodesInShow as $episode) {
// Only monitor future episodes
$episodeInFuture = $this->episodeInFuture($episode);
$this->logger->info('> [MonitorTvShowHandler] Episode is in future for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ' for title: ' . $monitor->getTitle() . ' ? ' . (true === $episodeInFuture ? 'YES' : 'NO'));
$episodeInFuture = $this->episodeReleasedAfterMonitorCreated($monitor->getCreatedAt(), $episode);
$this->logger->info('> [MonitorTvShowHandler] Episode released after monitor started for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ' for title: ' . $monitor->getTitle() . ' ? ' . (true === $episodeInFuture ? 'YES' : 'NO'));
if (false === $episodeInFuture) {
$this->logger->info('> [MonitorTvShowHandler] Episode not in future for title: ' . 'for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ', skipping');
$this->logger->info('> [MonitorTvShowHandler] Episode released after monitor started for title: ' . 'for season ' . $episode['season_number'] . ' episode ' . $episode['episode_number'] . ', skipping');
continue;
}
@@ -125,11 +125,11 @@ readonly class MonitorTvShowHandler implements HandlerInterface
);
}
private function episodeInFuture(array $episodeInShow): bool
private function episodeReleasedAfterMonitorCreated(string|DateTimeImmutable $monitorStartDate, array $episodeInShow): bool
{
static $today = Carbon::today();
$monitorStartDate = Carbon::parse($monitorStartDate)->setTime(0, 0);
$episodeAirDate = Carbon::parse($episodeInShow['air_date']);
return $episodeAirDate > $today;
return $episodeAirDate >= $monitorStartDate;
}
private function episodeExists(array $episodeInShow, Map $downloadedEpisodes): bool

View File

@@ -4,7 +4,10 @@ namespace App\Twig\Extensions;
use App\Monitor\Framework\Entity\Monitor;
use App\Monitor\Service\MediaFiles;
use App\Torrentio\Action\Result\GetTvShowOptionsResult;
use App\Torrentio\Result\TorrentioResult;
use ChrisUllyott\FileSize;
use Tmdb\Model\Tv\Episode;
use Twig\Attribute\AsTwigFilter;
use Twig\Attribute\AsTwigFunction;
@@ -45,4 +48,15 @@ class UtilExtension
$path
);
}
#[AsTwigFilter('episode_id_from_results')]
public function episodeId($result): ?string
{
if (!$result instanceof GetTvShowOptionsResult) {
return null;
}
return "S". str_pad($result->season, 2, "0", STR_PAD_LEFT) .
"E". str_pad($result->episode, 2, "0", STR_PAD_LEFT);
}
}

View File

@@ -38,13 +38,13 @@
</ul>
</div>
<div class="sticky inset-x-0 bottom-0 border-t border-orange-500">
<a href="#" class="nav-foot flex items-center gap-2 p-4 bg-orange-500 hover:bg-opacity-80 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60">
<div class="sticky inset-x-0 bottom-0 border-t border-b border-orange-500 bg-orange-500 hover:bg-opacity-80 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 flex flex-col">
<a href="#" class="nav-foot flex items-center gap-2 pt-4 px-4">
<span class="rounded-full p-2 border-orange-500 border-2">
<twig:ux:icon name="ri:user-line" width="30" class="text-gray-50"/>
</span>
<div>
<div class="flex flex-col text-white">
<p class="text-xs">
{% if app.user.name %}
<strong class="block font-medium text-white">{{ app.user.name }}</strong>
@@ -54,5 +54,8 @@
</p>
</div>
</a>
<p class="px-4 pt-1 inline-flex justify-center">
<small class="text-white text-xs">v{{ version|default('0.0') }}</small>
</p>
</div>
</nav>

View File

@@ -33,7 +33,7 @@
<button class="py-1 px-1.5 mr-1 grow-0 font-bold text-xs bg-green-600 rounded-lg hover:cursor-pointer hover:bg-green-700 text-white"
{{ stimulus_action('tv-results', 'toggleList', 'click') }}
>
<span {{ stimulus_target('tv-results', 'count') }}>0</span> results
<span {{ stimulus_target('tv-results', 'count') }}>-</span> results
</button>
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-gray-700 rounded-lg font-normal text-white" title="Air date {{ episode['name'] }}">

View File

@@ -15,11 +15,5 @@
</twig:Card>
</div>
<div class="p-2">
<twig:Card title="Upcoming Episodes" >
<twig:UpcomingEpisodes />
</twig:Card>
</div>
</div>
{% endblock %}

View File

@@ -34,7 +34,7 @@
</thead>
<tbody>
{% for result in results.results %}
<tr class="bg-white border-b dark:bg-slate-700 dark:border-gray-600 border-gray-200" data-provider="{{ result.provider }}" data-languages="{{ result.languages|json_encode }}" {% if "tvshows" == results.media.mediaType %} data-season="{{ results.season }} {% endif %}">
<tr class="bg-white border-b dark:bg-slate-700 dark:border-gray-600 border-gray-200" data-provider="{{ result.provider }}" data-languages="{{ result.languages|json_encode }}" {% if "tvshows" == results.media.mediaType %} data-season="{{ results.season }}"{% endif %}>
<td id="size" class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
{{ result.size }}
</td>
@@ -60,7 +60,8 @@
title: results.media.title,
filename: result.filename,
mediaType: results.media.mediaType,
imdbId: results.media.imdbId
imdbId: results.media.imdbId,
episodeId: results|episode_id_from_results
}) }}
{{ stimulus_action('download_button', 'download', 'click') }}
>