Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3701e31ee0 | |||
| 210c674f25 | |||
| 175f4330f1 |
@@ -18,7 +18,7 @@ export default class extends Controller {
|
|||||||
active: Boolean,
|
active: Boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
static targets = ['list', 'count', 'episodeSelector', 'toggleButton']
|
static targets = ['list', 'count', 'episodeSelector', 'toggleButton', 'listContainer']
|
||||||
static outlets = ['loading-icon']
|
static outlets = ['loading-icon']
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
@@ -35,7 +35,7 @@ export default class extends Controller {
|
|||||||
await fetch(`/torrentio/tvshows/${this.tmdbIdValue}/${this.imdbIdValue}/${this.seasonValue}/${this.episodeValue}`)
|
await fetch(`/torrentio/tvshows/${this.tmdbIdValue}/${this.imdbIdValue}/${this.seasonValue}/${this.episodeValue}`)
|
||||||
.then(res => res.text())
|
.then(res => res.text())
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.element.innerHTML = response;
|
this.listContainerTarget.innerHTML = response;
|
||||||
this.options = this.element.querySelectorAll('tbody tr');
|
this.options = this.element.querySelectorAll('tbody tr');
|
||||||
if (this.options.length > 0) {
|
if (this.options.length > 0) {
|
||||||
this.options.forEach((option) => option.querySelector('.download-btn').dataset['title'] = this.titleValue);
|
this.options.forEach((option) => option.querySelector('.download-btn').dataset['title'] = this.titleValue);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
twig:
|
twig:
|
||||||
file_name_pattern: '*.twig'
|
file_name_pattern: '*.twig'
|
||||||
date:
|
date:
|
||||||
|
format: 'm/d/Y'
|
||||||
timezone: '%env(default:app.default.timezone:TZ)%'
|
timezone: '%env(default:app.default.timezone:TZ)%'
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Tmdb;
|
|||||||
use Aimeos\Map;
|
use Aimeos\Map;
|
||||||
use App\Enum\MediaType;
|
use App\Enum\MediaType;
|
||||||
use App\ValueObject\ResultFactory;
|
use App\ValueObject\ResultFactory;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Contracts\Cache\CacheInterface;
|
use Symfony\Contracts\Cache\CacheInterface;
|
||||||
@@ -209,7 +210,12 @@ class Tmdb
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$series['episodes'][$season['season_number']] = $client->getApi()->getSeason($series['id'], $season['season_number'])['episodes'];
|
$series['episodes'][$season['season_number']] = Map::from(
|
||||||
|
$client->getApi()->getSeason($series['id'], $season['season_number'])['episodes']
|
||||||
|
)->map(function ($data) {
|
||||||
|
$data['poster'] = (null !== $data['still_path']) ? self::POSTER_IMG_PATH . $data['still_path'] : null;
|
||||||
|
return $data;
|
||||||
|
})->toArray();
|
||||||
}
|
}
|
||||||
return $series;
|
return $series;
|
||||||
}
|
}
|
||||||
@@ -268,7 +274,7 @@ class Tmdb
|
|||||||
private function parseEpisode(array $data, string $posterBasePath): TmdbResult
|
private function parseEpisode(array $data, string $posterBasePath): TmdbResult
|
||||||
{
|
{
|
||||||
return new TmdbResult(
|
return new TmdbResult(
|
||||||
imdbId: $data['external_ids']['imdb_id'],
|
imdbId: $data['external_ids']['imdb_id'] ?? $this->getImdbId($data['id'], 'tvshows'),
|
||||||
tmdbId: $data['id'],
|
tmdbId: $data['id'],
|
||||||
title: $data['name'],
|
title: $data['name'],
|
||||||
poster: (null !== $data['still_path']) ? $posterBasePath . $data['still_path'] : null,
|
poster: (null !== $data['still_path']) ? $posterBasePath . $data['still_path'] : null,
|
||||||
|
|||||||
@@ -13,7 +13,60 @@
|
|||||||
season: episode['season_number'],
|
season: episode['season_number'],
|
||||||
episode: episode['episode_number'],
|
episode: episode['episode_number'],
|
||||||
active: 'true',
|
active: 'true',
|
||||||
}) }}></div>
|
}) }}
|
||||||
|
>
|
||||||
|
<div class="p-6 flex flex-col gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
||||||
|
<div class="flex flex-row gap-4">
|
||||||
|
{% if episode['poster'] != null %}
|
||||||
|
<img class="w-64 rounded-lg" src="{{ episode['poster'] }}" />
|
||||||
|
{% else %}
|
||||||
|
<div class="w-64 min-w-64 sticky h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
||||||
|
<twig:ux:icon width="32" name="hugeicons:loading-01" />
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="flex flex-col gap-4 grow">
|
||||||
|
<h4 class="text-md font-bold">
|
||||||
|
{{ episode['episode_number'] }}. {{ episode['name'] }}
|
||||||
|
</h4>
|
||||||
|
<p>{{ episode['overview'] }}</p>
|
||||||
|
<div>
|
||||||
|
<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
|
||||||
|
</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'] }}">
|
||||||
|
{{ episode['air_date']|date }}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-4 justify-between">
|
||||||
|
<div class="flex flex-col items-center">
|
||||||
|
<input type="checkbox"
|
||||||
|
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button class="flex flex-col items-end transition-transform duration-300 ease-in-out rotate-90"
|
||||||
|
{{ stimulus_target('tv-results', 'toggleButton') }}
|
||||||
|
{{ stimulus_action('tv-results', 'toggleList', 'click') }}>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32">
|
||||||
|
<path
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M20 6L10 16l10 10" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div {{ stimulus_target('tv-results', 'listContainer') }} class="inline-block overflow-hidden rounded-lg">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% set paginator = this.episodes %}
|
{% set paginator = this.episodes %}
|
||||||
|
|||||||
@@ -119,6 +119,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% elseif "tvshows" == results.media.mediaType %}
|
{% elseif "tvshows" == results.media.mediaType %}
|
||||||
<twig:TvEpisodeList
|
<twig:TvEpisodeList
|
||||||
|
results="results"
|
||||||
:imdbId="results.media.imdbId" :season="results.season" :perPage="20" :pageNumber="1"
|
:imdbId="results.media.imdbId" :season="results.season" :perPage="20" :pageNumber="1"
|
||||||
:tmdbId="results.media.tmdbId" :title="results.media.title" loading="defer"
|
:tmdbId="results.media.tmdbId" :title="results.media.title" loading="defer"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,82 +1 @@
|
|||||||
<div class="p-6 flex flex-col gap-6 bg-orange-500 bg-clip-padding backdrop-filter backdrop-blur-md bg-opacity-60 rounded-md">
|
{{ include('torrentio/partial/option-table.html.twig', {controller: 'tv-results'}) }}
|
||||||
<div class="flex flex-row gap-4">
|
|
||||||
{% if results.media.poster != null %}
|
|
||||||
<img class="w-64 rounded-lg" src="{{ results.media.poster }}" />
|
|
||||||
{% else %}
|
|
||||||
<div class="w-64 min-w-64 sticky h-[144px] rounded-lg bg-gray-700 flex items-center justify-center">
|
|
||||||
<twig:ux:icon width="32" name="hugeicons:loading-01" />
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="flex flex-col gap-4 grow">
|
|
||||||
<h4 class="text-md font-bold">
|
|
||||||
{{ results.episode }}. {{ results.media.title }}
|
|
||||||
</h4>
|
|
||||||
<p>{{ results.media.description }}</p>
|
|
||||||
<div>
|
|
||||||
<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') }}>{{ results.results|length }}</span> results
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{% if results.file != false %}
|
|
||||||
<span data-controller="popover">
|
|
||||||
<template data-popover-target="content">
|
|
||||||
<div data-popover-target="card" class="absolute z-40 p-1 bg-stone-400 p-1 text-black rounded-md m-1 animate-fade">
|
|
||||||
<p class="font-bold text-sm text-left">Existing file(s) for this episode:</p>
|
|
||||||
<ul class="list-disc ml-3">
|
|
||||||
<li class="font-normal">{{ results.file.realPath|strip_media_path }} — <strong>{{ results.file.size|filesize }}</strong></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<small
|
|
||||||
class="py-1 px-1.5 mr-1 grow-0 font-bold bg-blue-600 rounded-lg text-center text-white"
|
|
||||||
data-action="mouseenter->popover#show mouseleave->popover#hide"
|
|
||||||
>
|
|
||||||
exists
|
|
||||||
</small>
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if results.file == false %}
|
|
||||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-rose-600 rounded-lg text-white" title="Episode has not been downloaded yet.">
|
|
||||||
missing
|
|
||||||
</small>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<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 {{ results.media.episodeAirDate }}">
|
|
||||||
{{ results.media.episodeAirDate }}
|
|
||||||
</small>
|
|
||||||
{# <small class="py-1 px-1.5 grow-0 font-bold bg-red-600 hover:bg-red-700 rounded-lg font-normal text-white cursor-pointer" title="Clear cache for {{ results.media.title }}"#}
|
|
||||||
{# {{ stimulus_action('tv-results', 'clearCache', 'click') }}#}
|
|
||||||
{# >Clear Cache</small>#}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-4 justify-between">
|
|
||||||
<div class="flex flex-col items-center">
|
|
||||||
<input type="checkbox"
|
|
||||||
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button class="flex flex-col items-end transition-transform duration-300 ease-in-out rotate-90"
|
|
||||||
{{ stimulus_target('tv-results', 'toggleButton') }}
|
|
||||||
{{ stimulus_action('tv-results', 'toggleList', 'click') }}>
|
|
||||||
{# <svg xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 32 32">#}
|
|
||||||
{# <path fill="currentColor" d="m16 10l10 10l-1.4 1.4l-8.6-8.6l-8.6 8.6L6 20z"/>#}
|
|
||||||
{# </svg>#}
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32">
|
|
||||||
<path
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M20 6L10 16l10 10" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="inline-block overflow-hidden rounded-lg">
|
|
||||||
{{ include('torrentio/partial/option-table.html.twig', {controller: 'tv-results'}) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user