Compare commits
1 Commits
dev-deep-l
...
dev-php85-
| Author | SHA1 | Date | |
|---|---|---|---|
| 0964abdf37 |
15
Dockerfile
15
Dockerfile
@@ -1,16 +1,17 @@
|
|||||||
FROM dunglas/frankenphp:php8.4
|
FROM registry.caldwell.digital/home/frankenphp:1.9.0-php8.5.0-ubuntu
|
||||||
|
|
||||||
ENV SERVER_NAME=":80"
|
ENV SERVER_NAME=":80"
|
||||||
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
|
ENV CADDY_GLOBAL_OPTIONS="auto_https off"
|
||||||
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
|
ENV APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime"
|
||||||
ENV APP_VERSION="0.0.1"
|
ENV APP_VERSION="0.0.1"
|
||||||
|
ENV SERVER_ROOT="/app/public"
|
||||||
|
|
||||||
RUN install-php-extensions \
|
#RUN install-php-extensions \
|
||||||
pdo_mysql \
|
# pdo_mysql \
|
||||||
gd \
|
# gd \
|
||||||
intl \
|
# intl \
|
||||||
zip \
|
# zip \
|
||||||
opcache
|
# opcache
|
||||||
|
|
||||||
RUN apt update && apt install -y wget
|
RUN apt update && apt install -y wget
|
||||||
|
|
||||||
|
|||||||
1
assets/bootstrap.js
vendored
1
assets/bootstrap.js
vendored
@@ -2,7 +2,6 @@ import { startStimulusApp } from '@symfony/stimulus-bundle';
|
|||||||
import Popover from '@stimulus-components/popover'
|
import Popover from '@stimulus-components/popover'
|
||||||
import Dialog from '@stimulus-components/dialog'
|
import Dialog from '@stimulus-components/dialog'
|
||||||
import Dropdown from '@stimulus-components/dropdown'
|
import Dropdown from '@stimulus-components/dropdown'
|
||||||
import 'animate.css'
|
|
||||||
|
|
||||||
const app = startStimulusApp();
|
const app = startStimulusApp();
|
||||||
// register any custom, 3rd party controllers here
|
// register any custom, 3rd party controllers here
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ export default class extends Controller {
|
|||||||
this.component.on('render:finished', (component) => {
|
this.component.on('render:finished', (component) => {
|
||||||
console.log(component);
|
console.log(component);
|
||||||
});
|
});
|
||||||
if (window.location.hash) {
|
|
||||||
let targetElement = document.querySelector(window.location.hash);
|
|
||||||
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
||||||
targetElement.classList.add('animate__animated', 'animate__pulse', 'animate__faster');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setSeason(season) {
|
setSeason(season) {
|
||||||
@@ -30,7 +25,6 @@ export default class extends Controller {
|
|||||||
|
|
||||||
paginate(event) {
|
paginate(event) {
|
||||||
this.element.querySelectorAll(".episode-container").forEach(element => element.remove());
|
this.element.querySelectorAll(".episode-container").forEach(element => element.remove());
|
||||||
this.component.set('episodeNumber', null);
|
|
||||||
this.component.action('paginate', {page: event.params.page});
|
this.component.action('paginate', {page: event.params.page});
|
||||||
this.component.render();
|
this.component.render();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ services:
|
|||||||
- mercure_data:/data
|
- mercure_data:/data
|
||||||
- mercure_config:/config
|
- mercure_config:/config
|
||||||
tty: true
|
tty: true
|
||||||
|
ports:
|
||||||
|
- "8001:80"
|
||||||
|
command: "frankenphp php-server --root=/app/public"
|
||||||
environment:
|
environment:
|
||||||
TZ: America/Chicago
|
TZ: America/Chicago
|
||||||
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ pwa:
|
|||||||
theme_color: "#083344"
|
theme_color: "#083344"
|
||||||
description: Torsearch provides a simple and intuitive way to manage your personal media library.
|
description: Torsearch provides a simple and intuitive way to manage your personal media library.
|
||||||
icons:
|
icons:
|
||||||
- src: "/icon.png"
|
- src: "icon.png"
|
||||||
sizes: [ 192 ]
|
sizes: [ 192 ]
|
||||||
- src: "/icon.png"
|
- src: "icon.png"
|
||||||
sizes: [ 192 ]
|
sizes: [ 192 ]
|
||||||
purpose: maskable
|
purpose: maskable
|
||||||
categories:
|
categories:
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
frankenphp {
|
frankenphp {
|
||||||
{$FRANKENPHP_CONFIG}
|
{$FRANKENPHP_CONFIG}
|
||||||
|
num_threads 10
|
||||||
|
max_threads 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
public/test.php
Normal file
60
public/test.php
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once '../vendor/autoload.php';
|
||||||
|
|
||||||
|
use App\Torrentio\Result\ResultFactory;
|
||||||
|
|
||||||
|
$realDebridKey = "";
|
||||||
|
$tasks = [];
|
||||||
|
$results = [];
|
||||||
|
$start = microtime(true);
|
||||||
|
for ($i = 1; $i <= 20; $i++) {
|
||||||
|
$tasks[] = \Async\spawn(function () use ($i, &$results, &$realDebridKey) {
|
||||||
|
$baseUrl = "https://torrentio.strem.fun/providers%253Dyts%252Ceztv%252Crarbg%252C1337x%252Cthepiratebay%252Ckickasstorrents%252Ctorrentgalaxy%252Cmagnetdl%252Chorriblesubs%252Cnyaasi%7Csort%253Dqualitysize%7Cqualityfilter%253D480p%252Cscr%252Ccam%7Crealdebrid={$realDebridKey}/stream/movie/tt0412142:1:$i.json";
|
||||||
|
$options = \json_decode(file_get_contents($baseUrl), true);
|
||||||
|
|
||||||
|
foreach ($options['streams'] as $stream) {
|
||||||
|
if (!str_starts_with($stream['url'], "https")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
array_key_exists('behaviorHints', $stream) &&
|
||||||
|
array_key_exists('bingeGroup', $stream['behaviorHints'])
|
||||||
|
) {
|
||||||
|
$bingeGroup = $stream['behaviorHints']['bingeGroup'];
|
||||||
|
} else {
|
||||||
|
$bingeGroup = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = ResultFactory::map(
|
||||||
|
$stream['url'],
|
||||||
|
$stream['title'],
|
||||||
|
$bingeGroup
|
||||||
|
);
|
||||||
|
|
||||||
|
$results[] = $result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
\Async\awaitAll($tasks);
|
||||||
|
$end = microtime(true) - $start;
|
||||||
|
dd($end, $results);
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//// Spawn multiple concurrent coroutines
|
||||||
|
//Async\spawn(function() {
|
||||||
|
// echo "Starting coroutine 1\n";
|
||||||
|
// sleep(2); // Non-blocking in async context
|
||||||
|
// echo "Coroutine 1 completed\n";
|
||||||
|
//});
|
||||||
|
//
|
||||||
|
//Async\spawn(function() {
|
||||||
|
// echo "Starting coroutine 2\n";
|
||||||
|
// sleep(1); // Non-blocking in async context
|
||||||
|
// echo "Coroutine 2 completed\n";
|
||||||
|
//});
|
||||||
|
//
|
||||||
|
//echo "All coroutines started\n";
|
||||||
|
|
||||||
@@ -11,6 +11,5 @@ class GetMediaInfoCommand implements CommandInterface
|
|||||||
public string $imdbId,
|
public string $imdbId,
|
||||||
public string $mediaType,
|
public string $mediaType,
|
||||||
public ?int $season = null,
|
public ?int $season = null,
|
||||||
public ?int $episode = null,
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,6 @@ class GetMediaInfoHandler implements HandlerInterface
|
|||||||
{
|
{
|
||||||
$media = $this->tmdb->mediaDetails($command->imdbId, $command->mediaType);
|
$media = $this->tmdb->mediaDetails($command->imdbId, $command->mediaType);
|
||||||
|
|
||||||
return new GetMediaInfoResult($media, $command->season, $command->episode);
|
return new GetMediaInfoResult($media, $command->season);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ class GetMediaInfoInput implements InputInterface
|
|||||||
|
|
||||||
#[SourceRoute('season', nullify: true)]
|
#[SourceRoute('season', nullify: true)]
|
||||||
public ?int $season,
|
public ?int $season,
|
||||||
|
|
||||||
#[SourceRoute('episode', nullify: true)]
|
|
||||||
public ?int $episode,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function toCommand(): CommandInterface
|
public function toCommand(): CommandInterface
|
||||||
@@ -29,10 +26,6 @@ class GetMediaInfoInput implements InputInterface
|
|||||||
if ("tvshows" === $this->mediaType && null === $this->season) {
|
if ("tvshows" === $this->mediaType && null === $this->season) {
|
||||||
$this->season = 1;
|
$this->season = 1;
|
||||||
}
|
}
|
||||||
|
return new GetMediaInfoCommand($this->imdbId, $this->mediaType, $this->season);
|
||||||
if ("tvshows" === $this->mediaType && null === $this->episode) {
|
|
||||||
$this->episode = 1;
|
|
||||||
}
|
|
||||||
return new GetMediaInfoCommand($this->imdbId, $this->mediaType, $this->season, $this->episode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,5 @@ class GetMediaInfoResult implements ResultInterface
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
public TmdbResult $media,
|
public TmdbResult $media,
|
||||||
public ?int $season,
|
public ?int $season,
|
||||||
public ?int $episode,
|
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ final class WebController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/result/{mediaType}/{imdbId}/{season}/{episode?}', name: 'app_search_result')]
|
#[Route('/result/{mediaType}/{imdbId}/{season}', name: 'app_search_result')]
|
||||||
public function result(
|
public function result(
|
||||||
GetMediaInfoInput $input,
|
GetMediaInfoInput $input,
|
||||||
?int $season = null,
|
?int $season = null,
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Tmdb;
|
namespace App\Tmdb;
|
||||||
|
|
||||||
|
use \Async;
|
||||||
use Aimeos\Map;
|
use Aimeos\Map;
|
||||||
use App\Base\Enum\MediaType;
|
use App\Base\Enum\MediaType;
|
||||||
use App\ValueObject\ResultFactory;
|
use App\ValueObject\ResultFactory;
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
use Psr\Cache\CacheItemPoolInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
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\ItemInterface;
|
use Symfony\Contracts\Cache\ItemInterface;
|
||||||
@@ -42,6 +44,7 @@ class Tmdb
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly CacheItemPoolInterface $cache,
|
private readonly CacheItemPoolInterface $cache,
|
||||||
private readonly EventDispatcherInterface $eventDispatcher,
|
private readonly EventDispatcherInterface $eventDispatcher,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
#[Autowire(env: 'TMDB_API')] string $apiKey,
|
#[Autowire(env: 'TMDB_API')] string $apiKey,
|
||||||
) {
|
) {
|
||||||
$this->client = new Client(
|
$this->client = new Client(
|
||||||
@@ -214,7 +217,6 @@ class Tmdb
|
|||||||
if ($season['episode_count'] <= 0 || $season['name'] === 'Specials') {
|
if ($season['episode_count'] <= 0 || $season['name'] === 'Specials') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$series['episodes'][$season['season_number']] = Map::from(
|
$series['episodes'][$season['season_number']] = Map::from(
|
||||||
$client->getApi()->getSeason($series['id'], $season['season_number'])['episodes']
|
$client->getApi()->getSeason($series['id'], $season['season_number'])['episodes']
|
||||||
)->map(function ($data) {
|
)->map(function ($data) {
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ use App\Search\Action\Command\GetMediaInfoCommand;
|
|||||||
use App\Search\Action\Handler\GetMediaInfoHandler;
|
use App\Search\Action\Handler\GetMediaInfoHandler;
|
||||||
use App\Search\TvEpisodePaginator;
|
use App\Search\TvEpisodePaginator;
|
||||||
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
|
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
|
||||||
use Symfony\UX\LiveComponent\Attribute\LiveAction;
|
|
||||||
use Symfony\UX\LiveComponent\Attribute\LiveArg;
|
|
||||||
use Symfony\UX\LiveComponent\Attribute\LiveProp;
|
use Symfony\UX\LiveComponent\Attribute\LiveProp;
|
||||||
use Symfony\UX\LiveComponent\DefaultActionTrait;
|
use Symfony\UX\LiveComponent\DefaultActionTrait;
|
||||||
|
|
||||||
@@ -29,12 +27,6 @@ final class TvEpisodeList
|
|||||||
#[LiveProp(writable: true)]
|
#[LiveProp(writable: true)]
|
||||||
public int $season = 1;
|
public int $season = 1;
|
||||||
|
|
||||||
#[LiveProp(writable: true)]
|
|
||||||
public int $reloadCount = 0;
|
|
||||||
|
|
||||||
#[LiveProp(writable: true)]
|
|
||||||
public ?int $episodeNumber = null;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private GetMediaInfoHandler $getMediaInfoHandler,
|
private GetMediaInfoHandler $getMediaInfoHandler,
|
||||||
) {}
|
) {}
|
||||||
@@ -42,14 +34,6 @@ final class TvEpisodeList
|
|||||||
public function getEpisodes()
|
public function getEpisodes()
|
||||||
{
|
{
|
||||||
$results = $this->getMediaInfoHandler->handle(new GetMediaInfoCommand($this->imdbId, "tvshows", $this->season));
|
$results = $this->getMediaInfoHandler->handle(new GetMediaInfoCommand($this->imdbId, "tvshows", $this->season));
|
||||||
|
|
||||||
if (null !== $this->episodeNumber) {
|
|
||||||
$this->pageNumber = ceil($this->episodeNumber / $this->perPage);
|
|
||||||
$this->episodeNumber = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->reloadCount++;
|
|
||||||
|
|
||||||
return new TvEpisodePaginator()->paginate($results, $this->pageNumber, $this->perPage);
|
return new TvEpisodePaginator()->paginate($results, $this->pageNumber, $this->perPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Twig\Dto;
|
|
||||||
|
|
||||||
class EpisodeIdDto
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
public string $season,
|
|
||||||
public string $episode,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function asEpisodeId(): string
|
|
||||||
{
|
|
||||||
return "S". str_pad($this->season, 2, "0", STR_PAD_LEFT) .
|
|
||||||
"E". str_pad($this->episode, 2, "0", STR_PAD_LEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __toString(): string
|
|
||||||
{
|
|
||||||
if ("" !== $this->season && "" !== $this->episode) {
|
|
||||||
return $this->asEpisodeId();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,6 @@ namespace App\Twig\Extensions;
|
|||||||
|
|
||||||
use App\Base\Service\MediaFiles;
|
use App\Base\Service\MediaFiles;
|
||||||
use App\Torrentio\Action\Result\GetTvShowOptionsResult;
|
use App\Torrentio\Action\Result\GetTvShowOptionsResult;
|
||||||
use App\Twig\Dto\EpisodeIdDto;
|
|
||||||
use ChrisUllyott\FileSize;
|
use ChrisUllyott\FileSize;
|
||||||
use Twig\Attribute\AsTwigFilter;
|
use Twig\Attribute\AsTwigFilter;
|
||||||
use Twig\Attribute\AsTwigFunction;
|
use Twig\Attribute\AsTwigFunction;
|
||||||
@@ -64,42 +63,4 @@ class UtilExtension
|
|||||||
return "S". str_pad($season, 2, "0", STR_PAD_LEFT) .
|
return "S". str_pad($season, 2, "0", STR_PAD_LEFT) .
|
||||||
"E". str_pad($episode, 2, "0", STR_PAD_LEFT);
|
"E". str_pad($episode, 2, "0", STR_PAD_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[AsTwigFunction('episode_anchor')]
|
|
||||||
public function episodeAnchor($season, $episode): ?string
|
|
||||||
{
|
|
||||||
return "episode_" . $season . "_" . $episode;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[AsTwigFunction('extract_from_episode_id')]
|
|
||||||
public function extractFromEpisodeId(?string $episodeId): ?EpisodeIdDto
|
|
||||||
{
|
|
||||||
if (null === $episodeId) {
|
|
||||||
return new EpisodeIdDto("", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capture season
|
|
||||||
$seasonMatch = [];
|
|
||||||
preg_match('/[sS]\d\d/', $episodeId, $seasonMatch);
|
|
||||||
if (empty($seasonMatch)) {
|
|
||||||
$season = "";
|
|
||||||
} else {
|
|
||||||
$season = str_replace(['S', 's'], '', $seasonMatch[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Capture episode
|
|
||||||
$episodeMatch = [];
|
|
||||||
preg_match('/[eE]\d\d/', $episodeId, $episodeMatch);
|
|
||||||
if (empty($episodeMatch)) {
|
|
||||||
$episode = "";
|
|
||||||
} else {
|
|
||||||
$episode = str_replace(['E', 'e'], '', $episodeMatch[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $season && null === $episode) {
|
|
||||||
return new EpisodeIdDto("", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new EpisodeIdDto($season, $episode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
<tr{{ attributes }} class="hover:bg-gray-200" id="ad_download_{{ download.id }}">
|
<tr{{ attributes }} class="hover:bg-gray-200" id="ad_download_{{ download.id }}">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 truncate">
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-stone-800 truncate">
|
||||||
{% if download.mediaType == "movies" %}
|
<a href="{{ path('app_search_result', {imdbId: download.imdbId, mediaType: download.mediaType}) }}"
|
||||||
{% set routeParams = {imdbId: download.imdbId, mediaType: download.mediaType} %}
|
class="mr-1 hover:underline rounded-md max-w-[10ch] md:max-w-[unset] truncate"
|
||||||
{% set route = path('app_search_result', routeParams) %}
|
>
|
||||||
{% else %}
|
|
||||||
{% set episodeIdDto = extract_from_episode_id(download.episodeId) %}
|
|
||||||
{% set routeParams = {imdbId: download.imdbId, mediaType: download.mediaType, season: episodeIdDto.season, episode: episodeIdDto.episode} %}
|
|
||||||
{% set route = path('app_search_result', routeParams) ~ "#" ~ episode_anchor(episodeIdDto.season, episodeIdDto.episode) %}
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ route }}"
|
|
||||||
class="mr-1 hover:underline rounded-md max-w-[10ch] md:max-w-[unset] truncate">
|
|
||||||
{{ download.title }}
|
{{ download.title }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|||||||
@@ -73,15 +73,18 @@
|
|||||||
{{ stimulus_action('result_filter', 'setSeason', 'change') }}
|
{{ stimulus_action('result_filter', 'setSeason', 'change') }}
|
||||||
{{ stimulus_action('result_filter', 'uncheckSelectAllBtn', 'change') }}
|
{{ stimulus_action('result_filter', 'uncheckSelectAllBtn', 'change') }}
|
||||||
>
|
>
|
||||||
{% for season in range(1, results.media.episodes|length) %}
|
<option selected value="1">1</option>
|
||||||
<option value="{{ season }}"
|
{% for season in range(2, results.media.episodes|length) %}
|
||||||
{% if results.season == season %}
|
<option value="{{ season }}">{{ season }}</option>
|
||||||
selected="selected"
|
|
||||||
{% endif %}
|
|
||||||
>{{ season }}</option>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
{# <label for="episodeNumber">#}
|
||||||
|
{# Episode#}
|
||||||
|
{# <select id="episodeNumber" name="episodeNumber" data-result-filter-target="episode" class="px-1 py-0.5 bg-stone-100 text-gray-800 rounded-sm">#}
|
||||||
|
{# <option selected value="">n/a</option>#}
|
||||||
|
{# </select>#}
|
||||||
|
{# </label>#}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span {{ stimulus_controller('loading_icon', {total: (results.media.mediaType == "tvshows") ? results.media.episodes[1]|length : 1, count: 0}) }}
|
<span {{ stimulus_controller('loading_icon', {total: (results.media.mediaType == "tvshows") ? results.media.episodes[1]|length : 1, count: 0}) }}
|
||||||
class="loading-icon">
|
class="loading-icon">
|
||||||
|
|||||||
@@ -3,20 +3,8 @@
|
|||||||
<a href="{{ path('app_search_result', {imdbId: monitor.imdbId, mediaType: monitor.monitorType|as_download_type}) }}"
|
<a href="{{ path('app_search_result', {imdbId: monitor.imdbId, mediaType: monitor.monitorType|as_download_type}) }}"
|
||||||
class="mr-1 hover:underline rounded-md"
|
class="mr-1 hover:underline rounded-md"
|
||||||
>
|
>
|
||||||
|
|
||||||
{% if monitor.monitorType == "movies" %}
|
|
||||||
{% set routeParams = {imdbId: monitor.imdbId, mediaType: monitor.monitorType} %}
|
|
||||||
{% set route = path('app_search_result', routeParams) %}
|
|
||||||
{% else %}
|
|
||||||
{% set episodeIdDto = extract_from_episode_id(monitor|monitor_media_id) %}
|
|
||||||
{% set routeParams = {imdbId: monitor.imdbId, mediaType: monitor.monitorType, season: episodeIdDto.season, episode: episodeIdDto.episode} %}
|
|
||||||
{% set route = path('app_search_result', routeParams) ~ "#" ~ episode_anchor(episodeIdDto.season, episodeIdDto.episode) %}
|
|
||||||
{% endif %}
|
|
||||||
<a href="{{ route }}"
|
|
||||||
class="mr-1 hover:underline rounded-md max-w-[10ch] md:max-w-[unset] truncate">
|
|
||||||
{{ monitor.title }}
|
{{ monitor.title }}
|
||||||
</a>
|
</a>
|
||||||
</a>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">
|
||||||
{{ monitor|monitor_media_id }}
|
{{ monitor|monitor_media_id }}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<nav id="navbar" {{ attributes }} {{ stimulus_controller('navbar') }} {{ stimulus_action('navbar', 'setActive')}} class="flex h-screen flex-col justify-between bg-cyan-950">
|
<nav id="navbar" {{ attributes }} {{ stimulus_controller('navbar') }} {{ stimulus_action('navbar', 'setActive')}} class="flex h-screen flex-col justify-between bg-cyan-950 animate__animated animate__slideInLeft animate__slow">
|
||||||
<div class="px-4 py-4 flex flex-col gap-12">
|
<div class="px-4 py-4 flex flex-col gap-12">
|
||||||
<h1 class="text-3xl mt-12 md:mt-0 font-extrabold text-orange-500 mb-3"><a href="{{ path('app_index') }}">Torsearch</a></h1>
|
<h1 class="text-3xl mt-12 md:mt-0 font-extrabold text-orange-500 mb-3"><a href="{{ path('app_index') }}">Torsearch</a></h1>
|
||||||
<ul class="nav-list space-y-1">
|
<ul class="nav-list space-y-1">
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
class="episode-list flex flex-col gap-4"
|
class="episode-list flex flex-col gap-4"
|
||||||
>
|
>
|
||||||
<div data-live-id="{{ uniqid() }}" class="episode-container flex flex-col gap-4">
|
<div data-live-id="{{ uniqid() }}" class="episode-container flex flex-col gap-4">
|
||||||
{% for episode in this.getEpisodes().items %}
|
{% for episode in this.episodes.items %}
|
||||||
<div id="{{ episode_anchor(episode['season_number'], episode['episode_number']) }}" class="results"
|
<div id="episode_{{ episode['season_number'] }}_{{ episode['episode_number'] }}" class="results"
|
||||||
data-tv-results-loading-icon-outlet=".loading-icon"
|
data-tv-results-loading-icon-outlet=".loading-icon"
|
||||||
data-download-button-outlet=".download-btn"
|
data-download-button-outlet=".download-btn"
|
||||||
{{ stimulus_controller('tv_results', {
|
{{ stimulus_controller('tv_results', {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
<twig:TvEpisodeList
|
<twig:TvEpisodeList
|
||||||
results="results"
|
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" :episodeNumber="results.episode"
|
:tmdbId="results.media.tmdbId" :title="results.media.title" loading="defer"
|
||||||
/>
|
/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</twig:Card>
|
</twig:Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user