fix: download options filter uses user preferences

This commit is contained in:
2025-04-30 15:53:10 -05:00
parent 3971cf3260
commit b59069551a
6 changed files with 144 additions and 103 deletions

View File

@@ -6,6 +6,9 @@ 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,
@@ -37,7 +40,53 @@ export default class extends Controller {
return true;
}
listTargetConnected(target) {
// console.log(target);
async filter(activeFilter) {
let firstIncluded = true;
let count = 0;
let selectedCount = 0;
this.options.forEach((option) => {
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']),
}
let include = true;
option.classList.remove('hidden');
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.add('hidden');
} else if (true === firstIncluded) {
count = 1;
selectedCount = selectedCount + 1;
option.querySelector('input[type="checkbox"]').checked = true;
firstIncluded = false;
} else {
count = count + 1;
}
});
}
}

View File

@@ -20,8 +20,6 @@ export default class extends Controller {
"provider": "",
}
userPreferences = []
static outlets = ['movie-results', 'tv-results']
static targets = ['resolution', 'codec', 'language', 'provider', 'season', 'selectAll', 'downloadSelected']
static values = {
@@ -30,7 +28,6 @@ export default class extends Controller {
}
async connect() {
this.userPreferences = await(await fetch('/api/user/preferences/values')).json();
if (this.mediaTypeValue === "tvshows") {
this.activeFilter['season'] = 1;
}
@@ -53,33 +50,11 @@ export default class extends Controller {
this.addLanguages(option, option.dataset);
this.addProviders(option, option.dataset);
})
}
addResolutions(resolutions) {
this.resolutionTarget.innerHTML = '<option value="">n/a</option>';
this.resolutionTarget.innerHTML += resolutions.preferenceOptions
.map((resolution) => {
if ('resolution' in this.userPreferences) {
return '<option value="' + resolution.name.toLowerCase() + '" selected>' + resolution.name + '</option>';
}
return '<option value="' + resolution.name.toLowerCase() + '">' + resolution.name + '</option>';
})
.join();
}
addCodecs(codecs) {
this.codecTarget.innerHTML = '<option value="">n/a</option>';
this.codecTarget.innerHTML += codecs.preferenceOptions
.map((codec) => {
if ('codec' in this.userPreferences) {
return '<option value="' + codec.name.toLowerCase() + '" selected>' + codec.name + '</option>';
}
return '<option value="' + codec.name.toLowerCase() + '">' + codec.name + '</option>'
})
.join();
await this.filter();
}
addLanguages(option, props) {
console.log('herey');
const languages = Object.assign([], JSON.parse(props['languages']));
languages.forEach((language) => {
if (!this.languages.includes(language)) {
@@ -118,79 +93,13 @@ export default class extends Controller {
if ("movies" === this.mediaTypeValue) {
results = this.movieResultsOutlets;
await results.forEach((list) => list.filter(this.activeFilter));
} else if ("tvshows" === this.mediaTypeValue) {
results = this.tvResultsOutlets;
this.activeFilter.season = this.seasonTarget.value;
await results.forEach((list) => list.filter(this.activeFilter, currentSeason, this.seasonTarget.value));
}
const filterOperation = async (resultList, currentSeason) => {
if ("tvshows" === this.mediaTypeValue && currentSeason !== this.activeFilter['season']) {
if (resultList.seasonValue === this.seasonTarget.value) {
await resultList.setActive();
} else {
resultList.setInActive();
}
}
if (false === resultList.isActive()) {
return;
}
let firstIncluded = true;
let count = 0;
let selectedCount = 0;
resultList.options.forEach((option) => {
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']),
}
let include = true;
option.classList.remove('hidden');
for (let [key, value] of Object.entries(this.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.add('hidden');
} else if (true === firstIncluded) {
count = 1;
selectedCount = selectedCount + 1;
option.querySelector('input[type="checkbox"]').checked = true;
firstIncluded = false;
} else {
count = count + 1;
}
if ("tvshows" === this.mediaTypeValue) {
resultList.countTarget.innerText = count;
}
});
}
await results.forEach((list) => filterOperation(list, currentSeason));
}
uncheckSelectAllBtn() {

View File

@@ -6,6 +6,9 @@ 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,
@@ -52,9 +55,11 @@ export default class extends Controller {
}
}
setInActive() {
async setInActive() {
this.activeValue = false;
// if (true === this.hasEpisodeSelectorTarget()) {
this.episodeSelectorTarget.checked = false;
// }
this.element.classList.add('hidden');
}
@@ -88,4 +93,68 @@ export default class extends Controller {
}
})
}
async filter(activeFilter, currentSeason, newSeason) {
if (currentSeason !== activeFilter['season']) {
if (this.seasonValue === newSeason) {
await this.setActive();
} else {
await this.setInActive();
}
}
if (false === this.isActive()) {
return;
}
let firstIncluded = true;
let count = 0;
let selectedCount = 0;
this.options.forEach((option) => {
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']),
}
let include = true;
option.classList.remove('hidden');
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.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.countTarget.innerText = count;
});
}
}

View File

@@ -27,6 +27,5 @@ final class Filter
->toArray();
$this->userPreferences = Map::from($this->security->getUser()->getUserPreferenceValues())
->toArray();
// dd($this->userPreferences);
}
}

View File

@@ -190,7 +190,18 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
{
return Map::from($this->userPreferences)
->rekey(fn(UserPreference $userPreference) => $userPreference->getPreference()->getId())
->map(fn(UserPreference $userPreference) => $userPreference->getPreferenceValue())
->map(function (UserPreference $userPreference) {
if (in_array($userPreference->getPreference()->getId(), ['language', 'provider'])) {
return $userPreference->getPreferenceValue();
}
foreach ($userPreference->getPreference()->getPreferenceOptions() as $preferenceOption) {
// dd((int) $userPreference->getPreferenceValue(), $preferenceOption->getId(), $preferenceOption->getValue());
if ($preferenceOption->getId() === (int) $userPreference->getPreferenceValue()) {
return $preferenceOption->getValue();
}
}
return null;
})
->toArray();
}
}

View File

@@ -15,7 +15,9 @@
>
<option value="">n/a</option>
{% for option in this.preferences['resolution'] %}
<option value="{{ option.name|lower }}">{{ option.name }}</option>
<option value="{{ option.value }}"
{{ option.value == this.userPreferences['resolution'] ? 'selected' }}
>{{ option.name }}</option>
{% endfor %}
</select>
</label>
@@ -24,7 +26,9 @@
<select id="codec" data-result-filter-target="codec" class="px-1 py-0.5 bg-stone-100 text-sm text-gray-800 rounded-md">
<option value="">n/a</option>
{% for option in this.preferences['codec'] %}
<option value="{{ option.name|lower }}">{{ option.name }}</option>
<option value="{{ option.value }}"
{{ option.value == this.userPreferences['codec'] ? 'selected' }}
>{{ option.name }}</option>
{% endfor %}
</select>
</label>