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