Compare commits
4 Commits
65acd5d21b
...
v0.27.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 87e72ec55e | |||
| 23a88ec6bb | |||
| d33a961f2d | |||
| 566886ef0e |
@@ -40,15 +40,9 @@ export default class DownloadOptionTr extends HTMLTableRowElement {
|
||||
this.episodeId = this.getAttribute('episode-id') ?? null;
|
||||
this.#downloadBtnEl = this.querySelector('.download-btn');
|
||||
this.#selectEpisodeInputEl = this.querySelector('input[type="checkbox"]');
|
||||
console.log(this.#selectEpisodeInputEl)
|
||||
|
||||
this.#downloadBtnEl.addEventListener('click', () => this.download());
|
||||
// document.addEventListener('filterDownloadOptions', this.filter.bind(this));
|
||||
}
|
||||
connectedCallback() {
|
||||
|
||||
}
|
||||
|
||||
get isSelected() {
|
||||
return this.#selectEpisodeInputEl.checked;
|
||||
}
|
||||
@@ -57,16 +51,6 @@ export default class DownloadOptionTr extends HTMLTableRowElement {
|
||||
this.#selectEpisodeInputEl.checked = value;
|
||||
}
|
||||
|
||||
// attribute change
|
||||
attributeChangedCallback(property, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
this[ property ] = newValue;
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['size', 'quality', 'resolution', 'codec', 'seeders', 'provider'];
|
||||
}
|
||||
|
||||
filter({ detail: { activeFilter } }) {
|
||||
const optionHeader = document.querySelector(`[data-option-id="${this.dataset['localId']}"]`)
|
||||
const props = {
|
||||
@@ -117,7 +101,6 @@ export default class DownloadOptionTr extends HTMLTableRowElement {
|
||||
}
|
||||
|
||||
download() {
|
||||
console.log('Downloading dis bihh')
|
||||
fetch('/api/download', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
export default class EpisodeContainer extends HTMLElement {
|
||||
H264_CODECS = ['h264', 'h.264', 'x264']
|
||||
H265_CODECS = ['h265', 'h.265', 'x265', 'hevc']
|
||||
|
||||
options = [];
|
||||
showTitle;
|
||||
|
||||
@@ -27,19 +24,6 @@ export default class EpisodeContainer extends HTMLElement {
|
||||
document.addEventListener('downloadSelectedEpisodes', this.downloadSelectedResults.bind(this));
|
||||
document.addEventListener('selectEpisodeForDownload', (e) => this.selectEpisodeForDownload(e.detail.select));
|
||||
}
|
||||
connectedCallback() {
|
||||
|
||||
}
|
||||
|
||||
// attribute change
|
||||
attributeChangedCallback(property, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
this[ property ] = newValue;
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ['name'];
|
||||
}
|
||||
|
||||
toggleResults() {
|
||||
this.#resultsToggleBtnEl.classList.toggle('rotate-90');
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
export default class MovieContainer extends HTMLElement {
|
||||
H264_CODECS = ['h264', 'h.264', 'x264']
|
||||
H265_CODECS = ['h265', 'h.265', 'x265', 'hevc']
|
||||
|
||||
#resultsTableEl;
|
||||
#resultsCountNumberEl;
|
||||
|
||||
@@ -13,12 +10,6 @@ export default class MovieContainer extends HTMLElement {
|
||||
document.addEventListener('filterDownloadOptions', this.filter.bind(this));
|
||||
}
|
||||
|
||||
// attribute change
|
||||
attributeChangedCallback(property, oldValue, newValue) {
|
||||
if (oldValue === newValue) return;
|
||||
this[ property ] = newValue;
|
||||
}
|
||||
|
||||
filter({ detail: { activeFilter } }) {
|
||||
const options = this.querySelectorAll('tr.download-option');
|
||||
let firstIncluded = true;
|
||||
|
||||
@@ -6,9 +6,6 @@ import { Controller } from '@hotwired/stimulus';
|
||||
*/
|
||||
/* stimulusFetch: 'lazy' */
|
||||
export default class extends Controller {
|
||||
H264_CODECS = ['h264', 'h.264', 'x264']
|
||||
H265_CODECS = ['h265', 'h.265', 'x265', 'hevc']
|
||||
|
||||
static values = {
|
||||
title: String,
|
||||
tmdbId: String,
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class extends Controller {
|
||||
"quality": "",
|
||||
}
|
||||
|
||||
static outlets = ['movie-results', 'tv-results', 'tv-episode-list']
|
||||
static outlets = ['tv-episode-list']
|
||||
static targets = ['resolution', 'codec', 'language', 'provider', 'season', 'quality', 'selectAll', 'downloadSelected']
|
||||
static values = {
|
||||
'imdbId': String,
|
||||
@@ -55,6 +55,10 @@ export default class extends Controller {
|
||||
}));
|
||||
}
|
||||
|
||||
downloadSelectedEpisodes() {
|
||||
document.dispatchEvent(new CustomEvent('downloadSelectedEpisodes', {}));
|
||||
}
|
||||
|
||||
addLanguages(option) {
|
||||
const languages = Object.assign([], option.languages);
|
||||
languages.forEach((language) => {
|
||||
@@ -171,8 +175,4 @@ export default class extends Controller {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
downloadSelectedEpisodes() {
|
||||
document.dispatchEvent(new CustomEvent('downloadSelectedEpisodes', {}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,11 @@ export default class extends Controller {
|
||||
const autocompleteController = this.application.getControllerForElementAndIdentifier(this.element, 'symfony--ux-autocomplete--autocomplete')
|
||||
window.location.href = `/search?term=${autocompleteController.tomSelect.lastValue}`
|
||||
}
|
||||
document.querySelector("#search-button").addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
const autocompleteController = this.application.getControllerForElementAndIdentifier(this.element, 'symfony--ux-autocomplete--autocomplete')
|
||||
window.location.href = `/search?term=${autocompleteController.tomSelect.lastQuery}`
|
||||
});
|
||||
this.element.addEventListener('autocomplete:pre-connect', this._onPreConnect);
|
||||
this.element.addEventListener('autocomplete:connect', this._onConnect);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export default class extends Controller {
|
||||
active: Boolean,
|
||||
};
|
||||
|
||||
static targets = ['list', 'count', 'episodeSelector', 'toggleButton', 'listContainer']
|
||||
static targets = ['list', 'count', 'episodeSelector',]
|
||||
static outlets = ['loading-icon']
|
||||
|
||||
options = []
|
||||
@@ -37,17 +37,4 @@ export default class extends Controller {
|
||||
this.episodeSelectorTarget.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
download() {
|
||||
this.element.options.forEach(option => {
|
||||
const optionSelector = option.querySelector('input[type="checkbox"]');
|
||||
if (true === optionSelector.checked) {
|
||||
const downloadBtn = option.querySelector('button.download-btn');
|
||||
const downloadBtnController = this.application.getControllerForElementAndIdentifier(downloadBtn, 'download-button');
|
||||
downloadBtnController.download();
|
||||
optionSelector.checked = false;
|
||||
this.episodeSelectorTarget.checked = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
11
src/Base/Util/ImdbMatcher.php
Normal file
11
src/Base/Util/ImdbMatcher.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Base\Util;
|
||||
|
||||
class ImdbMatcher
|
||||
{
|
||||
public static function isMatch(string $imdbId): bool
|
||||
{
|
||||
return preg_match('/^tt\d{7}$/', $imdbId);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Search\Action\Handler;
|
||||
|
||||
use App\Base\Util\ImdbMatcher;
|
||||
use App\Search\Action\Result\RedirectToMediaResult;
|
||||
use App\Search\Action\Result\SearchResult;
|
||||
use App\Tmdb\Tmdb;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface;
|
||||
@@ -17,6 +19,13 @@ class SearchHandler implements HandlerInterface
|
||||
|
||||
public function handle(CommandInterface $command): ResultInterface
|
||||
{
|
||||
if (ImdbMatcher::isMatch($command->term)) {
|
||||
$result = $this->tmdb->findByImdbId($command->term);
|
||||
return new RedirectToMediaResult(
|
||||
imdbId: $result->imdbId,
|
||||
mediaType: $result->mediaType,
|
||||
);
|
||||
}
|
||||
return new SearchResult(
|
||||
term: $command->term,
|
||||
results: $this->tmdb->search($command->term)
|
||||
|
||||
13
src/Search/Action/Result/RedirectToMediaResult.php
Normal file
13
src/Search/Action/Result/RedirectToMediaResult.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Search\Action\Result;
|
||||
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
|
||||
class RedirectToMediaResult implements ResultInterface
|
||||
{
|
||||
public function __construct(
|
||||
public string $imdbId,
|
||||
public string $mediaType,
|
||||
) {}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use App\Search\Action\Handler\GetMediaInfoHandler;
|
||||
use App\Search\Action\Handler\SearchHandler;
|
||||
use App\Search\Action\Input\GetMediaInfoInput;
|
||||
use App\Search\Action\Input\SearchInput;
|
||||
use App\Search\Action\Result\RedirectToMediaResult;
|
||||
use App\Tmdb\TmdbResult;
|
||||
use App\Torrentio\Action\Command\GetMovieOptionsCommand;
|
||||
use App\Torrentio\Action\Command\GetTvShowOptionsCommand;
|
||||
@@ -28,6 +29,13 @@ final class WebController extends AbstractController
|
||||
): Response {
|
||||
$results = $this->searchHandler->handle($searchInput->toCommand());
|
||||
|
||||
if ($results instanceof RedirectToMediaResult) {
|
||||
return $this->redirectToRoute('app_search_result', [
|
||||
'mediaType' => $results->mediaType,
|
||||
'imdbId' => $results->imdbId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render('search/results.html.twig', [
|
||||
'results' => $results,
|
||||
]);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Tmdb\Framework\Controller;
|
||||
|
||||
use App\Base\Util\ImdbMatcher;
|
||||
use App\Tmdb\Tmdb;
|
||||
use App\Tmdb\TmdbResult;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@@ -17,17 +18,28 @@ class ApiController extends AbstractController
|
||||
$results = [];
|
||||
|
||||
$term = $request->query->get('query') ?? null;
|
||||
$term = trim($term);
|
||||
|
||||
if (null !== $term) {
|
||||
$tmdbResults = $tmdb->search($term);
|
||||
|
||||
foreach ($tmdbResults as $tmdbResult) {
|
||||
/** @var TmdbResult $tmdbResult */
|
||||
$results[] = [
|
||||
'data' => $tmdbResult,
|
||||
'text' => $tmdbResult->title,
|
||||
'value' => "$tmdbResult->mediaType|$tmdbResult->imdbId",
|
||||
if (ImdbMatcher::isMatch($term)) {
|
||||
$tmdbResult = $tmdb->findByImdbId($term);
|
||||
$results = [
|
||||
[
|
||||
'data' => $tmdbResult,
|
||||
'text' => $tmdbResult->title,
|
||||
'value' => "$tmdbResult->mediaType|$tmdbResult->imdbId",
|
||||
]
|
||||
];
|
||||
} else {
|
||||
$tmdbResults = $tmdb->search($term);
|
||||
foreach ($tmdbResults as $tmdbResult) {
|
||||
/** @var TmdbResult $tmdbResult */
|
||||
$results[] = [
|
||||
'data' => $tmdbResult,
|
||||
'text' => $tmdbResult->title,
|
||||
'value' => "$tmdbResult->mediaType|$tmdbResult->imdbId",
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +185,28 @@ class Tmdb
|
||||
throw new \Exception("No results found for $id");
|
||||
}
|
||||
|
||||
public function findByImdbId(string $imdbId)
|
||||
{
|
||||
$finder = new Find($this->client);
|
||||
$result = $finder->findBy($imdbId, ['external_source' => 'imdb_id']);
|
||||
|
||||
if (count($result['movie_results']) > 0) {
|
||||
$result = $result['movie_results'][0];
|
||||
$mediaType = MediaType::Movie->value;
|
||||
} elseif (count($result['tv_results']) > 0) {
|
||||
$result = $result['tv_results'][0];
|
||||
$mediaType = MediaType::TvShow->value;
|
||||
} elseif (count($result['tv_episode_results']) > 0) {
|
||||
$result = $result['tv_episode_results'][0];
|
||||
$mediaType = MediaType::TvShow->value;
|
||||
}
|
||||
|
||||
$result['media_type'] = $mediaType;
|
||||
$result = $this->mediaDetails($imdbId, $result['media_type']);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function movieDetails(string $id)
|
||||
{
|
||||
$client = new MovieRepository($this->client);
|
||||
|
||||
@@ -16,10 +16,9 @@ class CodecList
|
||||
|
||||
public static function asSelectOptions(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (static::$codecs as $codec) {
|
||||
$result[$codec] = $codec;
|
||||
}
|
||||
return $result;
|
||||
return [
|
||||
'h264' => 'h264',
|
||||
'h265/HEVC' => 'h265',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
>
|
||||
</select>
|
||||
<button
|
||||
id="search-button"
|
||||
class="absolute top-1 right-1 flex items-center rounded
|
||||
bg-green-600 py-1 px-2.5 border border-transparent text-center
|
||||
text-sm text-white transition-all
|
||||
|
||||
Reference in New Issue
Block a user