wip: working movies & tvshows w/ filtering
This commit is contained in:
7
assets/bootstrap.js
vendored
7
assets/bootstrap.js
vendored
@@ -1,9 +1,12 @@
|
|||||||
|
import EpisodeContainer from './components/episode-container.js';
|
||||||
|
import DownloadOptionTr from './components/download-option-tr.js';
|
||||||
|
import MovieContainer from "./components/movie-container.js";
|
||||||
|
|
||||||
import { startStimulusApp } from '@symfony/stimulus-bundle';
|
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';
|
import 'animate.css';
|
||||||
import EpisodeContainer from './components/episode-container.js';
|
|
||||||
|
|
||||||
const app = startStimulusApp();
|
const app = startStimulusApp();
|
||||||
// register any custom, 3rd party controllers here
|
// register any custom, 3rd party controllers here
|
||||||
@@ -12,3 +15,5 @@ app.register('dialog', Dialog);
|
|||||||
app.register('dropdown', Dropdown);
|
app.register('dropdown', Dropdown);
|
||||||
|
|
||||||
customElements.define('episode-container', EpisodeContainer);
|
customElements.define('episode-container', EpisodeContainer);
|
||||||
|
customElements.define('movie-container', MovieContainer);
|
||||||
|
customElements.define('dl-tr', DownloadOptionTr, {extends: 'tr'});
|
||||||
|
|||||||
93
assets/components/download-option-tr.js
Normal file
93
assets/components/download-option-tr.js
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
export default class DownloadOptionTr extends HTMLTableRowElement {
|
||||||
|
H264_CODECS = ['h264', 'h.264', 'x264']
|
||||||
|
H265_CODECS = ['h265', 'h.265', 'x265', 'hevc']
|
||||||
|
|
||||||
|
size;
|
||||||
|
quality;
|
||||||
|
resolution;
|
||||||
|
codec;
|
||||||
|
seeders;
|
||||||
|
provider;
|
||||||
|
languages;
|
||||||
|
mediaType;
|
||||||
|
season;
|
||||||
|
episode;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.size = this.getAttribute('size');
|
||||||
|
this.quality = this.getAttribute('quality');
|
||||||
|
this.resolution = this.getAttribute('resolution');
|
||||||
|
this.codec = this.getAttribute('codec');
|
||||||
|
this.seeders = this.getAttribute('seeders');
|
||||||
|
this.provider = this.getAttribute('provider');
|
||||||
|
this.languages = JSON.parse(this.getAttribute('languages'));
|
||||||
|
this.mediaType = this.getAttribute('media-type');
|
||||||
|
this.season = this.getAttribute('season') ?? null;
|
||||||
|
this.episode = this.getAttribute('episode') ?? null;
|
||||||
|
|
||||||
|
// document.addEventListener('filterDownloadOptions', this.filter.bind(this));
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = {
|
||||||
|
"resolution": this.resolution.trim(),
|
||||||
|
"codec": this.codec.trim(),
|
||||||
|
"provider": this.provider.trim(),
|
||||||
|
"languages": this.languages,
|
||||||
|
"quality": this.quality,
|
||||||
|
}
|
||||||
|
|
||||||
|
let include = true;
|
||||||
|
this.classList.add('r-tablerow');
|
||||||
|
this.classList.remove('hidden');
|
||||||
|
optionHeader.classList.add('r-tablerow');
|
||||||
|
optionHeader.classList.remove('hidden');
|
||||||
|
|
||||||
|
this.querySelector('input[type="checkbox"]').checked = false;
|
||||||
|
|
||||||
|
for (let [key, value] of Object.entries(activeFilter)) {
|
||||||
|
if (value === "" || key === "season") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (key === "codec" && value === "h264") {
|
||||||
|
if (!this.H264_CODECS.includes(props[key].toLowerCase())) {
|
||||||
|
include = false;
|
||||||
|
}
|
||||||
|
} else if (key === "codec" && value === "h265") {
|
||||||
|
if (!this.H265_CODECS.includes(props[key].toLowerCase())) {
|
||||||
|
include = false;
|
||||||
|
}
|
||||||
|
} else if (key === "language") {
|
||||||
|
if (!props["languages"].includes(value)) {
|
||||||
|
include = false;
|
||||||
|
}
|
||||||
|
} else if (props[key] !== value) {
|
||||||
|
include = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === include) {
|
||||||
|
this.classList.remove('r-tablerow');
|
||||||
|
this.classList.add('hidden');
|
||||||
|
optionHeader.classList.remove('r-tablerow');
|
||||||
|
optionHeader.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
return include;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,9 @@ export default class EpisodeContainer extends HTMLElement {
|
|||||||
H264_CODECS = ['h264', 'h.264', 'x264']
|
H264_CODECS = ['h264', 'h.264', 'x264']
|
||||||
H265_CODECS = ['h265', 'h.265', 'x265', 'hevc']
|
H265_CODECS = ['h265', 'h.265', 'x265', 'hevc']
|
||||||
|
|
||||||
|
options = [];
|
||||||
|
|
||||||
|
#episodeSelectorEl;
|
||||||
#resultsToggleBtnEl;
|
#resultsToggleBtnEl;
|
||||||
#resultsTableEl;
|
#resultsTableEl;
|
||||||
#resultsCountBadgeEl;
|
#resultsCountBadgeEl;
|
||||||
@@ -13,11 +16,13 @@ export default class EpisodeContainer extends HTMLElement {
|
|||||||
this.#resultsToggleBtnEl = this.querySelector('.dropdown-button');
|
this.#resultsToggleBtnEl = this.querySelector('.dropdown-button');
|
||||||
this.#resultsCountBadgeEl = this.querySelector('.results-count-badge');
|
this.#resultsCountBadgeEl = this.querySelector('.results-count-badge');
|
||||||
this.#resultsCountNumberEl = this.querySelector('.results-count-number');
|
this.#resultsCountNumberEl = this.querySelector('.results-count-number');
|
||||||
|
this.#episodeSelectorEl = this.querySelector('.episode-selector');
|
||||||
|
|
||||||
this.#resultsToggleBtnEl.addEventListener('click', () => this.toggleResults());
|
this.#resultsToggleBtnEl.addEventListener('click', () => this.toggleResults());
|
||||||
this.#resultsCountBadgeEl.addEventListener('click', () => this.toggleResults());
|
this.#resultsCountBadgeEl.addEventListener('click', () => this.toggleResults());
|
||||||
|
|
||||||
document.addEventListener('filterDownloadOptions', this.filter.bind(this));
|
document.addEventListener('filterDownloadOptions', this.filter.bind(this));
|
||||||
|
document.addEventListener('selectEpisodeForDownload', (e) => this.selectEpisodeForDownload(e.detail.select));
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
|
||||||
@@ -39,56 +44,23 @@ export default class EpisodeContainer extends HTMLElement {
|
|||||||
this.#resultsTableEl.classList.toggle('hidden');
|
this.#resultsTableEl.classList.toggle('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
filter({ detail: { activeFilter } }) {
|
selectEpisodeForDownload(select) {
|
||||||
const options = this.querySelectorAll('tr.download-option');
|
if (this.#episodeSelectorEl.disabled === false) {
|
||||||
|
this.#episodeSelectorEl.checked = select;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filter({ detail: { activeFilter } }) {
|
||||||
let firstIncluded = true;
|
let firstIncluded = true;
|
||||||
let count = 0;
|
let count = 0;
|
||||||
let selectedCount = 0;
|
let selectedCount = 0;
|
||||||
|
|
||||||
options.forEach((option) => {
|
this.options.forEach((option) => {
|
||||||
const optionHeader = document.querySelector(`[data-option-id="${option.dataset['localId']}"]`)
|
const include = option.filter({ detail: { activeFilter: activeFilter } });
|
||||||
const props = {
|
|
||||||
"resolution": option.querySelector('#resolution').textContent.trim(),
|
|
||||||
"codec": option.querySelector('#codec').textContent.trim(),
|
|
||||||
"provider": option.querySelector('#provider').textContent.trim(),
|
|
||||||
"languages": JSON.parse(option.dataset['languages']),
|
|
||||||
"quality": option.dataset['quality'],
|
|
||||||
}
|
|
||||||
|
|
||||||
let include = true;
|
|
||||||
option.classList.add('r-tablerow');
|
|
||||||
option.classList.remove('hidden');
|
|
||||||
optionHeader.classList.add('r-tablerow');
|
|
||||||
optionHeader.classList.remove('hidden');
|
|
||||||
option.querySelector('input[type="checkbox"]').checked = false;
|
|
||||||
|
|
||||||
for (let [key, value] of Object.entries(activeFilter)) {
|
|
||||||
if (value === "" || key === "season") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (key === "codec" && value === "h264") {
|
|
||||||
if (!this.H264_CODECS.includes(props[key].toLowerCase())) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
} else if (key === "codec" && value === "h265") {
|
|
||||||
if (!this.H265_CODECS.includes(props[key].toLowerCase())) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
} else if (key === "language") {
|
|
||||||
if (!props["languages"].includes(value)) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
} else if (props[key] !== value) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === include) {
|
if (false === include) {
|
||||||
option.classList.remove('r-tablerow');
|
option.classList.remove('r-tablerow');
|
||||||
option.classList.add('hidden');
|
option.classList.add('hidden');
|
||||||
optionHeader.classList.remove('r-tablerow');
|
|
||||||
optionHeader.classList.add('hidden');
|
|
||||||
} else if (true === firstIncluded) {
|
} else if (true === firstIncluded) {
|
||||||
count = 1;
|
count = 1;
|
||||||
selectedCount = selectedCount + 1;
|
selectedCount = selectedCount + 1;
|
||||||
@@ -97,8 +69,7 @@ export default class EpisodeContainer extends HTMLElement {
|
|||||||
} else {
|
} else {
|
||||||
count = count + 1;
|
count = count + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#resultsCountNumberEl.innerText = count;
|
|
||||||
});
|
});
|
||||||
|
this.#resultsCountNumberEl.innerText = count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
assets/components/movie-container.js
Normal file
45
assets/components/movie-container.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
export default class MovieContainer extends HTMLElement {
|
||||||
|
H264_CODECS = ['h264', 'h.264', 'x264']
|
||||||
|
H265_CODECS = ['h265', 'h.265', 'x265', 'hevc']
|
||||||
|
|
||||||
|
#resultsTableEl;
|
||||||
|
#resultsCountNumberEl;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.#resultsTableEl = this.querySelector('.results-container');
|
||||||
|
this.#resultsCountNumberEl = document.querySelector('.results-count-number');
|
||||||
|
|
||||||
|
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;
|
||||||
|
let count = 0;
|
||||||
|
let selectedCount = 0;
|
||||||
|
|
||||||
|
options.forEach((option) => {
|
||||||
|
const include = option.filter({ detail: { activeFilter: activeFilter } });
|
||||||
|
|
||||||
|
if (false === include) {
|
||||||
|
option.classList.remove('r-tablerow');
|
||||||
|
option.classList.add('hidden');
|
||||||
|
} else if (true === firstIncluded) {
|
||||||
|
count = 1;
|
||||||
|
selectedCount = selectedCount + 1;
|
||||||
|
option.querySelector('input[type="checkbox"]').checked = true;
|
||||||
|
firstIncluded = false;
|
||||||
|
} else {
|
||||||
|
count = count + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.#resultsCountNumberEl.innerText = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,73 +30,8 @@ export default class extends Controller {
|
|||||||
this.optionsLoaded = true;
|
this.optionsLoaded = true;
|
||||||
this.options = this.element.querySelectorAll('tbody tr');
|
this.options = this.element.querySelectorAll('tbody tr');
|
||||||
this.options.forEach((option) => option.querySelector('.download-btn').dataset['title'] = this.titleValue);
|
this.options.forEach((option) => option.querySelector('.download-btn').dataset['title'] = this.titleValue);
|
||||||
this.dispatch('optionsLoaded', {detail: {options: this.options}})
|
|
||||||
this.loadingIconOutlet.toggleIcon();
|
|
||||||
this.resultCountEl.innerText = this.options.length;
|
this.resultCountEl.innerText = this.options.length;
|
||||||
}
|
this.loadingIconOutlet.toggleIcon();
|
||||||
|
document.dispatchEvent(new CustomEvent('optionsLoaded', {detail: {options: this.options}}));
|
||||||
// Keeps compatible with Filter & TV Shows
|
|
||||||
isActive() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async filter(activeFilter) {
|
|
||||||
let firstIncluded = true;
|
|
||||||
let count = 0;
|
|
||||||
let selectedCount = 0;
|
|
||||||
|
|
||||||
this.options.forEach((option) => {
|
|
||||||
const optionHeader = document.querySelector(`[data-option-id="${option.dataset['localId']}"]`)
|
|
||||||
const props = {
|
|
||||||
"resolution": option.querySelector('#resolution').textContent.trim(),
|
|
||||||
"codec": option.querySelector('#codec').textContent.trim(),
|
|
||||||
"provider": option.querySelector('#provider').textContent.trim(),
|
|
||||||
"quality": option.dataset['quality'],
|
|
||||||
"languages": JSON.parse(option.dataset['languages']),
|
|
||||||
}
|
|
||||||
|
|
||||||
let include = true;
|
|
||||||
option.classList.add('r-tablerow');
|
|
||||||
option.classList.remove('hidden');
|
|
||||||
optionHeader.classList.add('r-tablerow');
|
|
||||||
optionHeader.classList.remove('hidden');
|
|
||||||
option.querySelector('input[type="checkbox"]').checked = false;
|
|
||||||
|
|
||||||
for (let [key, value] of Object.entries(activeFilter)) {
|
|
||||||
if (value === "" || key === "season") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (key === "codec" && value === "h264") {
|
|
||||||
if (!this.H264_CODECS.includes(props[key].toLowerCase())) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
} else if (key === "codec" && value === "h265") {
|
|
||||||
if (!this.H265_CODECS.includes(props[key].toLowerCase())) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
} else if (key === "language") {
|
|
||||||
if (!props["languages"].includes(value)) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
} else if (props[key] !== value) {
|
|
||||||
include = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false === include) {
|
|
||||||
option.classList.remove('r-tablerow');
|
|
||||||
option.classList.add('hidden');
|
|
||||||
optionHeader.classList.remove('r-tablerow');
|
|
||||||
optionHeader.classList.add('hidden');
|
|
||||||
} else if (true === firstIncluded) {
|
|
||||||
count = 1;
|
|
||||||
selectedCount = selectedCount + 1;
|
|
||||||
option.querySelector('input[type="checkbox"]').checked = true;
|
|
||||||
firstIncluded = false;
|
|
||||||
} else {
|
|
||||||
count = count + 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.resultCountEl.innerText = count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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']
|
|
||||||
|
|
||||||
languages = []
|
languages = []
|
||||||
providers = []
|
providers = []
|
||||||
qualities = []
|
qualities = []
|
||||||
@@ -36,20 +33,30 @@ export default class extends Controller {
|
|||||||
this.activeFilter['season'] = 1;
|
this.activeFilter['season'] = 1;
|
||||||
}
|
}
|
||||||
await this.filter();
|
await this.filter();
|
||||||
|
|
||||||
|
document.addEventListener('optionsLoaded', this.loadOptions.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event is fired from movies/tvshows controllers to populate this data
|
// Event is fired from movies/tvshows controllers to populate this data
|
||||||
async loadOptions({detail: { options }}) {
|
async loadOptions({detail: { options }}) {
|
||||||
await options.forEach((option) => {
|
await options.forEach((option) => {
|
||||||
this.addLanguages(option, option.dataset);
|
this.addLanguages(option);
|
||||||
this.addProviders(option, option.dataset);
|
this.addProviders(option);
|
||||||
this.addQualities(option, option.dataset);
|
this.addQualities(option);
|
||||||
})
|
})
|
||||||
await this.filter();
|
await this.filter();
|
||||||
}
|
}
|
||||||
|
|
||||||
addLanguages(option, props) {
|
selectAllEpisodes() {
|
||||||
const languages = Object.assign([], JSON.parse(props['languages']));
|
document.dispatchEvent(new CustomEvent('selectEpisodeForDownload', {
|
||||||
|
detail: {
|
||||||
|
select: this.selectAllTarget.checked,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
addLanguages(option) {
|
||||||
|
const languages = Object.assign([], option.languages);
|
||||||
languages.forEach((language) => {
|
languages.forEach((language) => {
|
||||||
if (!this.languages.includes(language)) {
|
if (!this.languages.includes(language)) {
|
||||||
this.languages.push(language);
|
this.languages.push(language);
|
||||||
@@ -75,9 +82,9 @@ export default class extends Controller {
|
|||||||
.join();
|
.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
addProviders(option, props) {
|
addProviders(option) {
|
||||||
if (!this.providers.includes(props['provider'])) {
|
if (!this.providers.includes(option.provider)) {
|
||||||
this.providers.push(props['provider']);
|
this.providers.push(option.provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
const preferred = this.providerTarget.dataset.preferred;
|
const preferred = this.providerTarget.dataset.preferred;
|
||||||
@@ -100,10 +107,10 @@ export default class extends Controller {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addQualities(option, props) {
|
addQualities(option) {
|
||||||
if (!this.qualities.includes(props['quality'])) {
|
if (!this.qualities.includes(option.quality)) {
|
||||||
if (props['quality'].toLowerCase() in this.reverseMappedQualitiesValue) {
|
if (option.quality.toLowerCase() in this.reverseMappedQualitiesValue) {
|
||||||
this.qualities.push(props['quality']);
|
this.qualities.push(option.quality);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +136,6 @@ export default class extends Controller {
|
|||||||
async filter() {
|
async filter() {
|
||||||
const downloadSeasonSpan = document.querySelector("#downloadSeasonModal");
|
const downloadSeasonSpan = document.querySelector("#downloadSeasonModal");
|
||||||
|
|
||||||
let results = [];
|
|
||||||
this.activeFilter = {
|
this.activeFilter = {
|
||||||
"resolution": this.resolutionTarget.value,
|
"resolution": this.resolutionTarget.value,
|
||||||
"codec": this.codecTarget.value,
|
"codec": this.codecTarget.value,
|
||||||
@@ -138,11 +144,7 @@ export default class extends Controller {
|
|||||||
"quality": this.qualityTarget.value,
|
"quality": this.qualityTarget.value,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("movies" === this.mediaTypeValue) {
|
if ("tvshows" === this.mediaTypeValue) {
|
||||||
results = this.movieResultsOutlets;
|
|
||||||
|
|
||||||
} else if ("tvshows" === this.mediaTypeValue) {
|
|
||||||
results = this.tvResultsOutlets;
|
|
||||||
downloadSeasonSpan.innerText = this.seasonTarget.value;
|
downloadSeasonSpan.innerText = this.seasonTarget.value;
|
||||||
this.activeFilter.season = this.seasonTarget.value;
|
this.activeFilter.season = this.seasonTarget.value;
|
||||||
}
|
}
|
||||||
@@ -153,9 +155,9 @@ export default class extends Controller {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Event is picked up by the episode-container
|
||||||
|
// or movie-container web components
|
||||||
document.dispatchEvent(event);
|
document.dispatchEvent(event);
|
||||||
|
|
||||||
// await results.forEach((list) => list.filter(this.activeFilter));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setSeason(event) {
|
setSeason(event) {
|
||||||
@@ -174,14 +176,6 @@ export default class extends Controller {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
selectAllEpisodes() {
|
|
||||||
this.tvResultsOutlets.forEach((episode) => {
|
|
||||||
if (episode.isActive()) {
|
|
||||||
episode.selectEpisodeForDownload()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadSelectedEpisodes() {
|
downloadSelectedEpisodes() {
|
||||||
this.tvResultsOutlets.forEach(episode => {
|
this.tvResultsOutlets.forEach(episode => {
|
||||||
if (episode.isActive() && episode.isSelected()) {
|
if (episode.isActive() && episode.isSelected()) {
|
||||||
|
|||||||
@@ -22,57 +22,28 @@ export default class extends Controller {
|
|||||||
static outlets = ['loading-icon']
|
static outlets = ['loading-icon']
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
optionsLoaded = false
|
|
||||||
isOpen = false
|
|
||||||
|
|
||||||
async listTargetConnected() {
|
listTargetConnected() {
|
||||||
this.options = this.element.querySelectorAll('tbody tr');
|
this.element.options = this.element.querySelectorAll('tbody tr');
|
||||||
if (this.options.length > 0) {
|
if (this.element.options.length > 0) {
|
||||||
this.options.forEach((option) =>
|
this.element.options.forEach((option) =>
|
||||||
option.querySelector('.download-btn').dataset['title'] = this.titleValue
|
option.querySelector('.download-btn').dataset['title'] = this.titleValue
|
||||||
);
|
);
|
||||||
this.options[0].querySelector('input[type="checkbox"]').checked = true;
|
this.element.options[0].querySelector('input[type="checkbox"]').checked = true;
|
||||||
this.dispatch('optionsLoaded', {detail: {options: this.options}})
|
|
||||||
this.loadingIconOutlet.increaseCount();
|
this.loadingIconOutlet.increaseCount();
|
||||||
|
document.dispatchEvent(new CustomEvent('optionsLoaded', {detail: {options: this.element.options}}));
|
||||||
} else {
|
} else {
|
||||||
this.countTarget.innerText = 0;
|
this.countTarget.innerText = 0;
|
||||||
this.episodeSelectorTarget.disabled = true;
|
this.episodeSelectorTarget.disabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// async clearCache() {
|
|
||||||
// await fetch(`/torrentio/tvshows/clear/${this.tmdbIdValue}/${this.imdbIdValue}/${this.seasonValue}/${this.episodeValue}`)
|
|
||||||
// .then(res => res.text())
|
|
||||||
// .then(response => {});
|
|
||||||
// }
|
|
||||||
|
|
||||||
async setActive() {
|
|
||||||
if (false === this.optionsLoaded) {
|
|
||||||
await this.setOptions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async setInActive() {
|
|
||||||
this.episodeSelectorTarget.checked = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
isActive() {
|
|
||||||
return this.activeValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
isSelected() {
|
isSelected() {
|
||||||
return this.episodeSelectorTarget.checked;
|
return this.episodeSelectorTarget.checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
selectEpisodeForDownload() {
|
|
||||||
if (true === this.isActive() && this.episodeSelectorTarget.disabled === false) {
|
|
||||||
this.episodeSelectorTarget.checked = !this.episodeSelectorTarget.checked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
download() {
|
download() {
|
||||||
this.options.forEach(option => {
|
this.element.options.forEach(option => {
|
||||||
const optionSelector = option.querySelector('input[type="checkbox"]');
|
const optionSelector = option.querySelector('input[type="checkbox"]');
|
||||||
if (true === optionSelector.checked) {
|
if (true === optionSelector.checked) {
|
||||||
const downloadBtn = option.querySelector('button.download-btn');
|
const downloadBtn = option.querySelector('button.download-btn');
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class UtilExtension
|
|||||||
#[AsTwigFunction('episode_anchor')]
|
#[AsTwigFunction('episode_anchor')]
|
||||||
public function episodeAnchor($season, $episode): ?string
|
public function episodeAnchor($season, $episode): ?string
|
||||||
{
|
{
|
||||||
return "episode_" . $season . "_" . $episode;
|
return "episode_" . (int) $season . "_" . (int) $episode;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[AsTwigFunction('extract_from_episode_id')]
|
#[AsTwigFunction('extract_from_episode_id')]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
data-result-filter-movie-results-outlet=".results"
|
data-result-filter-movie-results-outlet=".results"
|
||||||
data-result-filter-tv-results-outlet=".results"
|
data-result-filter-tv-results-outlet=".results"
|
||||||
data-result-filter-tv-episode-list-outlet=".episode-list"
|
data-result-filter-tv-episode-list-outlet=".episode-list"
|
||||||
data-action="change->result-filter#filter movie-results:optionsLoaded@window->result-filter#loadOptions tv-results:optionsLoaded@window->result-filter#loadOptions action-button:downloadSeason@window->result-filter#downloadSeason"
|
data-action="change->result-filter#filter action-button:downloadSeason@window->result-filter#downloadSeason"
|
||||||
>
|
>
|
||||||
<div class="w-full p-4 flex flex-col md:flex-row gap-4 bg-stone-500 text-md text-gray-500 dark:text-gray-50 rounded-lg">
|
<div class="w-full p-4 flex flex-col md:flex-row gap-4 bg-stone-500 text-md text-gray-500 dark:text-gray-50 rounded-lg">
|
||||||
<label for="resolution">
|
<label for="resolution">
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-4 justify-between">
|
<div class="flex flex-col gap-4 justify-between">
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<input type="checkbox"
|
<input class="episode-selector" type="checkbox"
|
||||||
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
{{ stimulus_target('tv-results', 'episodeSelector') }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -56,8 +56,8 @@
|
|||||||
|
|
||||||
{% if "movies" == results.media.mediaType %}
|
{% if "movies" == results.media.mediaType %}
|
||||||
<div class="flex flex-row justify-start items-end grow">
|
<div class="flex flex-row justify-start items-end grow">
|
||||||
<span 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">
|
<span class="results-count-badge 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">
|
||||||
<span id="movie_results_count">-</span> results
|
<span class="results-count-number" id="movie_results_count">-</span> results
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-gray-700 rounded-lg font-normal text-white" title="Release date {{ results.media.episodeAirDate }}">
|
<small class="py-1 px-1.5 mr-1 grow-0 font-bold bg-gray-700 rounded-lg font-normal text-white" title="Release date {{ results.media.episodeAirDate }}">
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
<twig:Filter results="{{ results }}" filter="{{ filter }}" />
|
<twig:Filter results="{{ results }}" filter="{{ filter }}" />
|
||||||
|
|
||||||
{% if "movies" == results.media.mediaType %}
|
{% if "movies" == results.media.mediaType %}
|
||||||
<div class="results"
|
<movie-container class="results"
|
||||||
{{ stimulus_controller('movie_results', {title: results.media.title, tmdbId: results.media.tmdbId, imdbId: results.media.imdbId}) }}
|
{{ stimulus_controller('movie_results', {title: results.media.title, tmdbId: results.media.tmdbId, imdbId: results.media.imdbId}) }}
|
||||||
data-movie-results-loading-icon-outlet=".loading-icon"
|
data-movie-results-loading-icon-outlet=".loading-icon"
|
||||||
>
|
>
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
target: 'movie_results_frame',
|
target: 'movie_results_frame',
|
||||||
block: 'movie_results'
|
block: 'movie_results'
|
||||||
}) }}" />
|
}) }}" />
|
||||||
</div>
|
</movie-container>
|
||||||
{% elseif "tvshows" == results.media.mediaType %}
|
{% elseif "tvshows" == results.media.mediaType %}
|
||||||
<twig:TvEpisodeList
|
<twig:TvEpisodeList
|
||||||
results="results"
|
results="results"
|
||||||
|
|||||||
@@ -41,7 +41,22 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody class="flex-1 sm:flex-none">
|
<tbody class="flex-1 sm:flex-none">
|
||||||
{% for result in results.results %}
|
{% for result in results.results %}
|
||||||
<tr class="download-option bg-white dark:bg-slate-700 flex flex-col flex-no wrap r-tablerow border-b border-gray-500" data-local-id="{{ result.localId }}" data-provider="{{ result.provider }}" data-quality="{{ result.quality }}" data-languages="{{ result.languages|json_encode }}" {% if "tvshows" == results.media.mediaType %} data-season="{{ results.season }}"{% endif %}>
|
<tr is="dl-tr"
|
||||||
|
class="download-option bg-white dark:bg-slate-700 flex flex-col flex-no wrap r-tablerow border-b border-gray-500"
|
||||||
|
size="{{ result.size }}"
|
||||||
|
quality="{{ result.quality }}"
|
||||||
|
resolution="{{ result.resolution }}"
|
||||||
|
codec="{{ result.codec }}"
|
||||||
|
seeders="{{ result.seeders }}"
|
||||||
|
provider="{{ result.provider }}"
|
||||||
|
languages="{{ result.languages|json_encode }}"
|
||||||
|
media-type="{{ results.media.mediaType }}"
|
||||||
|
data-local-id="{{ result.localId }}"
|
||||||
|
{% if "tvshows" == results.media.mediaType %}
|
||||||
|
season="{{ result.season }}"
|
||||||
|
episode="{{ result.episodeNumber }}"
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
<td id="size" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
<td id="size" class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-gray-50">
|
||||||
{{ result.size }}
|
{{ result.size }}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user