mirror of
https://github.com/plexguide/Huntarr.io.git
synced 2026-04-20 12:46:53 -04:00
583 lines
31 KiB
JavaScript
583 lines
31 KiB
JavaScript
/**
|
|
* Profile editor (Movie Hunt) - full-page editor like instance editor.
|
|
* Open from Profiles list Edit; Back/Save; sections: Profile details, Upgrade & quality, Qualities.
|
|
* Attaches to window.SettingsForms.
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
if (typeof window.SettingsForms === 'undefined') return;
|
|
|
|
const Forms = window.SettingsForms;
|
|
|
|
function escapeHtml(s) {
|
|
if (s == null) return '';
|
|
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
}
|
|
|
|
function generateProfileEditorHtml(profile) {
|
|
const p = profile || {};
|
|
const name = escapeHtml((p.name || '').trim() || 'Unnamed');
|
|
const isDefault = Boolean(p.is_default);
|
|
const upgradesAllowed = p.upgrades_allowed !== false;
|
|
const upgradeUntil = escapeHtml((p.upgrade_until_quality || 'WEB 2160p').trim());
|
|
const minScore = p.min_custom_format_score != null ? Number(p.min_custom_format_score) : -10000;
|
|
const untilScore = p.upgrade_until_custom_format_score != null ? Number(p.upgrade_until_custom_format_score) : 5500;
|
|
const increment = p.upgrade_score_increment != null ? Number(p.upgrade_score_increment) : 100;
|
|
const language = escapeHtml((p.language || 'English').trim());
|
|
const qualities = Array.isArray(p.qualities) ? p.qualities : [];
|
|
var checkedQualityNames = [];
|
|
qualities.forEach(function(q) {
|
|
if (q.enabled !== false) {
|
|
var n = (q.name || q.id || '').trim();
|
|
if (n) checkedQualityNames.push(n);
|
|
}
|
|
});
|
|
if (checkedQualityNames.length === 0) {
|
|
checkedQualityNames = ['WEB 2160p', 'WEB 1080p', 'WEB 720p'];
|
|
}
|
|
let qualitiesHtml = '';
|
|
qualities.forEach(function(q, i) {
|
|
const qName = escapeHtml((q.name || q.id || '').trim() || 'Quality');
|
|
const checked = q.enabled !== false ? ' checked' : '';
|
|
qualitiesHtml += '<div class="profile-quality-item" data-quality-id="' + escapeHtml(String(q.id || i)) + '" data-order="' + (q.order != null ? q.order : i) + '" draggable="true">' +
|
|
'<span class="quality-drag-handle" title="Drag to reorder"><i class="fas fa-grip-vertical"></i></span>' +
|
|
'<input type="checkbox" id="profile-quality-' + i + '" class="profile-quality-checkbox"' + checked + '>' +
|
|
'<label class="quality-name" for="profile-quality-' + i + '">' + qName + '</label>' +
|
|
'</div>';
|
|
});
|
|
var upgradeSelectOptions = '';
|
|
checkedQualityNames.forEach(function(opt) {
|
|
var sel = opt === (p.upgrade_until_quality || 'WEB 2160p').trim() ? ' selected' : '';
|
|
upgradeSelectOptions += '<option value="' + escapeHtml(opt) + '"' + sel + '>' + escapeHtml(opt) + '</option>';
|
|
});
|
|
if (upgradeSelectOptions === '') {
|
|
upgradeSelectOptions = '<option value="WEB 2160p">WEB 2160p</option>';
|
|
}
|
|
|
|
return '<div class="editor-grid">' +
|
|
'<div class="editor-section">' +
|
|
'<div class="editor-section-title">Profile details</div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item"><label for="profile-editor-name">Name</label>' +
|
|
'<input type="text" id="profile-editor-name" value="' + name + '" placeholder="Profile name" maxlength="64">' +
|
|
'</div><p class="editor-help-text">A friendly name for this profile</p></div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item flex-row">' +
|
|
'<label for="profile-editor-default">Set as default profile</label>' +
|
|
'<label class="toggle-switch"><input type="checkbox" id="profile-editor-default"' + (isDefault ? ' checked' : '') + '><span class="toggle-slider"></span></label>' +
|
|
'</div><p class="editor-help-text">The default profile is used when no other is selected</p></div>' +
|
|
'</div>' +
|
|
'<div class="editor-section">' +
|
|
'<div class="editor-section-title">Upgrade & quality</div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item flex-row">' +
|
|
'<label for="profile-editor-upgrades">Upgrades allowed</label>' +
|
|
'<label class="toggle-switch"><input type="checkbox" id="profile-editor-upgrades"' + (upgradesAllowed ? ' checked' : '') + '><span class="toggle-slider"></span></label>' +
|
|
'</div><p class="editor-help-text">If disabled, qualities will not be upgraded</p></div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item"><label for="profile-editor-upgrade-until">Upgrade until</label>' +
|
|
'<select id="profile-editor-upgrade-until">' + upgradeSelectOptions + '</select>' +
|
|
'</div><p class="editor-help-text">Once this quality is reached, no further upgrades will be grabbed</p></div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item"><label for="profile-editor-min-score">Minimum custom format score</label>' +
|
|
'<input type="number" id="profile-editor-min-score" value="' + minScore + '" min="-100000" max="100000">' +
|
|
'</div><p class="editor-help-text">Minimum custom format score allowed to download</p></div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item"><label for="profile-editor-until-score">Upgrade until custom format score</label>' +
|
|
'<input type="number" id="profile-editor-until-score" value="' + untilScore + '" min="0" max="100000">' +
|
|
'</div><p class="editor-help-text">Once quality cutoff is met, upgrades stop when this score is reached</p></div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item"><label for="profile-editor-increment">Minimum custom format score increment</label>' +
|
|
'<input type="number" id="profile-editor-increment" value="' + increment + '" min="0" max="10000">' +
|
|
'</div><p class="editor-help-text">Minimum improvement in score between existing and new release to consider an upgrade</p></div>' +
|
|
'<div class="editor-field-group">' +
|
|
'<div class="editor-setting-item"><label for="profile-editor-language">Language</label>' +
|
|
'<input type="text" id="profile-editor-language" value="' + language + '" placeholder="English" maxlength="64">' +
|
|
'</div><p class="editor-help-text">Language for releases</p></div>' +
|
|
'</div>' +
|
|
'<div class="editor-section">' +
|
|
'<div class="editor-section-title">Qualities</div>' +
|
|
'<p class="editor-help-text" style="margin-bottom: 12px;">Only checked qualities are wanted. Higher in the list is more preferred.</p>' +
|
|
'<div class="profile-quality-list" id="profile-editor-qualities">' + (qualitiesHtml || '<p class="editor-help-text">No qualities defined.</p>') + '</div>' +
|
|
'</div>' +
|
|
'<div class="editor-section profile-editor-scores-section">' +
|
|
'<div class="editor-section-title">Custom format scores</div>' +
|
|
'<p class="editor-help-text" style="margin-bottom: 12px;">Hunt Manager uses these scores to decide which release to grab. Higher total score means a better release. Start at 0; use the Recommend column (from <a href="https://trash-guides.info/Radarr/Radarr-collection-of-custom-formats/" target="_blank" rel="noopener">TRaSH Guides</a>) as a guide if you want. To incorporate customized formats for your movies, <a href="./#settings-custom-formats" class="editor-inline-link">visit Custom Formats</a>.</p>' +
|
|
'<div class="profile-editor-scores-container">' +
|
|
'<table class="profile-editor-scores-table"><thead><tr><th>Custom format</th><th class="th-score">Your score</th><th class="th-recommended">Recommend</th></tr></thead>' +
|
|
'<tbody id="profile-editor-scores-tbody"></tbody></table>' +
|
|
'<p id="profile-editor-scores-empty" class="profile-editor-scores-empty" style="display: none;">No custom formats added yet. Add them under Movie Hunt → Custom Formats, then set scores here.</p>' +
|
|
'</div></div></div>';
|
|
}
|
|
|
|
let _profileEditorScoresList = [];
|
|
let _profileEditorScoresSortTimeout = null;
|
|
let _profileEditorDirty = false;
|
|
|
|
function renderProfileEditorScoresTable() {
|
|
const tbody = document.getElementById('profile-editor-scores-tbody');
|
|
const emptyEl = document.getElementById('profile-editor-scores-empty');
|
|
const table = document.querySelector('.profile-editor-scores-table');
|
|
if (!tbody || _profileEditorScoresList.length === 0) {
|
|
if (tbody) tbody.innerHTML = '';
|
|
if (emptyEl) emptyEl.style.display = 'block';
|
|
if (table) table.style.display = 'none';
|
|
return;
|
|
}
|
|
const sorted = _profileEditorScoresList.slice().sort(function(a, b) { return (b.score - a.score); });
|
|
let html = '';
|
|
for (let i = 0; i < sorted.length; i++) {
|
|
const item = sorted[i];
|
|
const title = (item.title || item.name || 'Unnamed').replace(/</g, '<').replace(/>/g, '>');
|
|
const rec = item.recommended_score;
|
|
const recText = (rec != null && !isNaN(rec)) ? String(rec) : '—';
|
|
html += '<tr data-index="' + item.index + '"><td><span class="custom-format-score-name">' + title + '</span></td>' +
|
|
'<td><input type="number" class="profile-editor-score-input" data-index="' + item.index + '" value="' + item.score + '" min="-100000" max="100000" step="1"></td>' +
|
|
'<td><span class="recommended-value">' + recText + '</span></td></tr>';
|
|
}
|
|
tbody.innerHTML = html;
|
|
tbody.querySelectorAll('.profile-editor-score-input').forEach(function(input) {
|
|
function scheduleSort(idx) {
|
|
if (_profileEditorScoresSortTimeout) clearTimeout(_profileEditorScoresSortTimeout);
|
|
_profileEditorScoresSortTimeout = setTimeout(function() {
|
|
_profileEditorScoresSortTimeout = null;
|
|
renderProfileEditorScoresTable();
|
|
}, 2000);
|
|
}
|
|
input.addEventListener('input', function() {
|
|
const idx = parseInt(input.getAttribute('data-index'), 10);
|
|
if (isNaN(idx)) return;
|
|
let val = parseInt(input.value, 10);
|
|
if (isNaN(val)) val = 0;
|
|
const item = _profileEditorScoresList.find(function(o) { return o.index === idx; });
|
|
if (item) item.score = val;
|
|
markProfileEditorDirty();
|
|
scheduleSort(idx);
|
|
});
|
|
input.addEventListener('change', function() {
|
|
const idx = parseInt(input.getAttribute('data-index'), 10);
|
|
if (isNaN(idx)) return;
|
|
let val = parseInt(input.value, 10);
|
|
if (isNaN(val)) val = 0;
|
|
const item = _profileEditorScoresList.find(function(o) { return o.index === idx; });
|
|
if (item) item.score = val;
|
|
markProfileEditorDirty();
|
|
scheduleSort(idx);
|
|
});
|
|
});
|
|
}
|
|
|
|
function loadProfileEditorScoresTable() {
|
|
const tbody = document.getElementById('profile-editor-scores-tbody');
|
|
const emptyEl = document.getElementById('profile-editor-scores-empty');
|
|
const table = document.querySelector('.profile-editor-scores-table');
|
|
if (!tbody) return;
|
|
var state = Forms._currentProfileEditing;
|
|
var apiUrl = (state && state.tvHunt) ? './api/tv-hunt/custom-formats' : './api/custom-formats';
|
|
fetch(apiUrl)
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
const list = (data && data.custom_formats) ? data.custom_formats : [];
|
|
if (list.length === 0) {
|
|
_profileEditorScoresList = [];
|
|
tbody.innerHTML = '';
|
|
if (emptyEl) emptyEl.style.display = 'block';
|
|
if (table) table.style.display = 'none';
|
|
return;
|
|
}
|
|
if (emptyEl) emptyEl.style.display = 'none';
|
|
if (table) table.style.display = 'table';
|
|
_profileEditorScoresList = list.map(function(item, i) {
|
|
let score = item.score != null ? Number(item.score) : 0;
|
|
if (isNaN(score)) score = 0;
|
|
return {
|
|
index: i,
|
|
title: item.title || item.name || 'Unnamed',
|
|
name: item.name || 'Unnamed',
|
|
recommended_score: item.recommended_score != null ? item.recommended_score : item.recommended,
|
|
score: score
|
|
};
|
|
});
|
|
renderProfileEditorScoresTable();
|
|
})
|
|
.catch(function() {
|
|
_profileEditorScoresList = [];
|
|
tbody.innerHTML = '';
|
|
if (emptyEl) emptyEl.style.display = 'block';
|
|
if (table) table.style.display = 'none';
|
|
});
|
|
}
|
|
|
|
function saveProfileEditorScores() {
|
|
if (!_profileEditorScoresList || _profileEditorScoresList.length === 0) return Promise.resolve();
|
|
const tbody = document.getElementById('profile-editor-scores-tbody');
|
|
if (!tbody) return Promise.resolve();
|
|
const rows = tbody.querySelectorAll('tr[data-index]');
|
|
var scores = _profileEditorScoresList.slice().map(function(o) { return o.score; });
|
|
rows.forEach(function(row) {
|
|
const idx = parseInt(row.getAttribute('data-index'), 10);
|
|
const input = row.querySelector('.profile-editor-score-input');
|
|
if (isNaN(idx) || idx < 0 || idx >= scores.length || !input) return;
|
|
let val = parseInt(input.value, 10);
|
|
if (isNaN(val)) val = 0;
|
|
scores[idx] = val;
|
|
});
|
|
var state = Forms._currentProfileEditing;
|
|
var scoresUrl = (state && state.tvHunt) ? './api/tv-hunt/custom-formats/scores' : './api/custom-formats/scores';
|
|
return fetch(scoresUrl, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ scores: scores })
|
|
}).then(function(r) { return r.json(); });
|
|
}
|
|
|
|
function markProfileEditorDirty() {
|
|
_profileEditorDirty = true;
|
|
const saveBtn = document.getElementById('profile-editor-save');
|
|
if (saveBtn) {
|
|
saveBtn.disabled = false;
|
|
saveBtn.classList.add('enabled');
|
|
}
|
|
}
|
|
|
|
function confirmLeaveProfileEditor(done) {
|
|
if (!_profileEditorDirty) {
|
|
if (typeof done === 'function') done('discard');
|
|
return true;
|
|
}
|
|
if (window.HuntarrConfirm && window.HuntarrConfirm.show) {
|
|
window.HuntarrConfirm.show({
|
|
title: 'Unsaved Changes',
|
|
message: 'You have unsaved changes that will be lost if you leave.',
|
|
confirmLabel: 'Go Back',
|
|
cancelLabel: 'Leave',
|
|
onConfirm: function() {
|
|
// Stay on the editor — modal just closes, user can save manually
|
|
},
|
|
onCancel: function() {
|
|
if (typeof done === 'function') done('discard');
|
|
}
|
|
});
|
|
} else {
|
|
if (!confirm('You have unsaved changes that will be lost. Leave anyway?')) return;
|
|
if (typeof done === 'function') done('discard');
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getCheckedQualityNamesInOrder() {
|
|
const list = document.getElementById('profile-editor-qualities');
|
|
if (!list) return [];
|
|
const items = list.querySelectorAll('.profile-quality-item');
|
|
var names = [];
|
|
items.forEach(function(item) {
|
|
var cb = item.querySelector('.profile-quality-checkbox');
|
|
var label = item.querySelector('.quality-name');
|
|
if (cb && cb.checked && label) {
|
|
var n = (label.textContent || '').trim();
|
|
if (n) names.push(n);
|
|
}
|
|
});
|
|
return names;
|
|
}
|
|
|
|
function refreshProfileEditorUpgradeUntilOptions() {
|
|
const select = document.getElementById('profile-editor-upgrade-until');
|
|
if (!select) return;
|
|
const names = getCheckedQualityNamesInOrder();
|
|
const currentValue = (select.value || '').trim();
|
|
var optionsHtml = '';
|
|
names.forEach(function(n) {
|
|
var sel = n === currentValue ? ' selected' : '';
|
|
optionsHtml += '<option value="' + n.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"') + '"' + sel + '>' + n.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') + '</option>';
|
|
});
|
|
if (optionsHtml === '') {
|
|
optionsHtml = '<option value="">No qualities checked</option>';
|
|
}
|
|
select.innerHTML = optionsHtml;
|
|
if (names.length > 0 && (currentValue === '' || names.indexOf(currentValue) === -1)) {
|
|
select.value = names[0];
|
|
}
|
|
}
|
|
|
|
function setupProfileEditorChangeDetection() {
|
|
const content = document.getElementById('profile-editor-content');
|
|
const saveBtn = document.getElementById('profile-editor-save');
|
|
if (!content || !saveBtn) return;
|
|
content.querySelectorAll('input:not(.profile-quality-checkbox), select').forEach(function(el) {
|
|
el.addEventListener('input', markProfileEditorDirty);
|
|
el.addEventListener('change', markProfileEditorDirty);
|
|
});
|
|
var qualitiesList = document.getElementById('profile-editor-qualities');
|
|
if (qualitiesList) {
|
|
qualitiesList.addEventListener('change', function(e) {
|
|
if (e.target && e.target.classList.contains('profile-quality-checkbox')) {
|
|
markProfileEditorDirty();
|
|
refreshProfileEditorUpgradeUntilOptions();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function setupProfileQualitiesDragDrop() {
|
|
const list = document.getElementById('profile-editor-qualities');
|
|
if (!list) return;
|
|
const items = list.querySelectorAll('.profile-quality-item');
|
|
if (items.length === 0) return;
|
|
let draggedEl = null;
|
|
items.forEach(function(item) {
|
|
item.setAttribute('draggable', 'true');
|
|
item.addEventListener('dragstart', function(e) {
|
|
draggedEl = item;
|
|
e.dataTransfer.effectAllowed = 'move';
|
|
e.dataTransfer.setData('text/plain', item.getAttribute('data-quality-id') || '');
|
|
e.dataTransfer.setData('text/html', item.outerHTML);
|
|
item.classList.add('profile-quality-dragging');
|
|
e.dataTransfer.setDragImage(item, 0, 0);
|
|
});
|
|
item.addEventListener('dragend', function() {
|
|
item.classList.remove('profile-quality-dragging');
|
|
list.querySelectorAll('.profile-quality-item').forEach(function(el) {
|
|
el.classList.remove('profile-quality-drag-over');
|
|
});
|
|
draggedEl = null;
|
|
});
|
|
item.addEventListener('dragover', function(e) {
|
|
e.preventDefault();
|
|
e.dataTransfer.dropEffect = 'move';
|
|
if (draggedEl && draggedEl !== item) {
|
|
item.classList.add('profile-quality-drag-over');
|
|
}
|
|
});
|
|
item.addEventListener('dragleave', function() {
|
|
item.classList.remove('profile-quality-drag-over');
|
|
});
|
|
item.addEventListener('drop', function(e) {
|
|
e.preventDefault();
|
|
item.classList.remove('profile-quality-drag-over');
|
|
if (!draggedEl || draggedEl === item) return;
|
|
var parent = item.parentNode;
|
|
parent.insertBefore(draggedEl, item);
|
|
markProfileEditorDirty();
|
|
refreshProfileEditorUpgradeUntilOptions();
|
|
});
|
|
});
|
|
list.addEventListener('dragover', function(e) {
|
|
e.preventDefault();
|
|
e.dataTransfer.dropEffect = 'move';
|
|
});
|
|
}
|
|
|
|
Forms.openProfileEditor = function(index) {
|
|
const list = Forms._profilesList;
|
|
if (!list || !list[index]) {
|
|
fetch('./api/profiles')
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
const profiles = (data && data.profiles) ? data.profiles : [];
|
|
Forms._profilesList = profiles;
|
|
if (profiles[index]) {
|
|
Forms._openProfileEditorWithProfile(index, profiles[index]);
|
|
} else {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification('Profile not found.', 'error');
|
|
}
|
|
}
|
|
})
|
|
.catch(function() {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification('Failed to load profile.', 'error');
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
Forms._openProfileEditorWithProfile(index, list[index]);
|
|
};
|
|
|
|
/** Open profile editor for TV Hunt (independent from Movie Hunt). */
|
|
Forms.openTVHuntProfileEditor = function(profileId) {
|
|
window._profileEditorTVHunt = true;
|
|
fetch('./api/tv-hunt/profiles', { cache: 'no-store' })
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
var list = (data && data.profiles) ? data.profiles : [];
|
|
var profile = list.find(function(p) { return p.id === profileId; });
|
|
if (profile) {
|
|
Forms._openProfileEditorWithProfile(
|
|
{ tvHunt: true, profileId: profileId, originalProfile: JSON.parse(JSON.stringify(profile)) },
|
|
profile
|
|
);
|
|
} else {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification('Profile not found.', 'error');
|
|
}
|
|
}
|
|
})
|
|
.catch(function() {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification('Failed to load profile.', 'error');
|
|
}
|
|
});
|
|
};
|
|
|
|
Forms._openProfileEditorWithProfile = function(indexOrState, profile) {
|
|
_profileEditorDirty = false;
|
|
var state;
|
|
if (typeof indexOrState === 'object' && indexOrState !== null && indexOrState.tvHunt) {
|
|
state = indexOrState;
|
|
if (!state.originalProfile) state.originalProfile = JSON.parse(JSON.stringify(profile));
|
|
} else {
|
|
state = { index: indexOrState, originalProfile: JSON.parse(JSON.stringify(profile)) };
|
|
}
|
|
Forms._currentProfileEditing = state;
|
|
const contentEl = document.getElementById('profile-editor-content');
|
|
const saveBtn = document.getElementById('profile-editor-save');
|
|
const backBtn = document.getElementById('profile-editor-back');
|
|
if (!contentEl) return;
|
|
contentEl.innerHTML = generateProfileEditorHtml(profile);
|
|
if (saveBtn) {
|
|
saveBtn.disabled = true;
|
|
saveBtn.classList.remove('enabled');
|
|
saveBtn.onclick = function() { Forms.saveProfileFromEditor(); };
|
|
}
|
|
var nextSection = state.tvHunt ? 'tv-hunt-settings-profiles' : 'settings-profiles';
|
|
if (backBtn) {
|
|
backBtn.onclick = function() {
|
|
confirmLeaveProfileEditor(function(result) {
|
|
if (result === 'save') Forms.saveProfileFromEditor(nextSection);
|
|
else if (result === 'discard') Forms.cancelProfileEditor(nextSection);
|
|
});
|
|
};
|
|
}
|
|
setTimeout(function() {
|
|
setupProfileEditorChangeDetection();
|
|
setupProfileQualitiesDragDrop();
|
|
refreshProfileEditorUpgradeUntilOptions();
|
|
loadProfileEditorScoresTable();
|
|
}, 100);
|
|
if (window.huntarrUI && window.huntarrUI.switchSection) {
|
|
window.huntarrUI.switchSection('profile-editor');
|
|
}
|
|
};
|
|
|
|
Forms.saveProfileFromEditor = function(optionalNextSection) {
|
|
const state = Forms._currentProfileEditing;
|
|
if (!state) return;
|
|
const isTVHunt = state.tvHunt && state.profileId;
|
|
const nextSection = optionalNextSection || (isTVHunt ? 'tv-hunt-settings-profiles' : 'settings-profiles');
|
|
const index = state.index;
|
|
const nameEl = document.getElementById('profile-editor-name');
|
|
const defaultEl = document.getElementById('profile-editor-default');
|
|
const upgradesEl = document.getElementById('profile-editor-upgrades');
|
|
const upgradeUntilEl = document.getElementById('profile-editor-upgrade-until');
|
|
const minScoreEl = document.getElementById('profile-editor-min-score');
|
|
const untilScoreEl = document.getElementById('profile-editor-until-score');
|
|
const incrementEl = document.getElementById('profile-editor-increment');
|
|
const languageEl = document.getElementById('profile-editor-language');
|
|
const qualitiesContainer = document.getElementById('profile-editor-qualities');
|
|
const name = (nameEl && nameEl.value) ? nameEl.value.trim() : 'Unnamed';
|
|
const isDefault = defaultEl ? defaultEl.checked : false;
|
|
const upgradesAllowed = upgradesEl ? upgradesEl.checked : true;
|
|
const upgradeUntil = (upgradeUntilEl && upgradeUntilEl.value) ? upgradeUntilEl.value.trim() : 'WEB 2160p';
|
|
const minScore = minScoreEl ? parseInt(minScoreEl.value, 10) : -10000;
|
|
const untilScore = untilScoreEl ? parseInt(untilScoreEl.value, 10) : 5500;
|
|
const increment = incrementEl ? parseInt(incrementEl.value, 10) : 100;
|
|
const language = (languageEl && languageEl.value) ? languageEl.value.trim() : 'English';
|
|
const qualities = [];
|
|
if (qualitiesContainer) {
|
|
const items = qualitiesContainer.querySelectorAll('.profile-quality-item');
|
|
items.forEach(function(item, i) {
|
|
const cb = item.querySelector('input[type="checkbox"]');
|
|
const label = item.querySelector('.quality-name');
|
|
qualities.push({
|
|
id: item.getAttribute('data-quality-id') || 'q' + i,
|
|
name: label ? label.textContent.trim() : ('Quality ' + i),
|
|
enabled: cb ? cb.checked : true,
|
|
order: i
|
|
});
|
|
});
|
|
}
|
|
const body = {
|
|
name: name,
|
|
is_default: isDefault,
|
|
upgrades_allowed: upgradesAllowed,
|
|
upgrade_until_quality: upgradeUntil,
|
|
min_custom_format_score: isNaN(minScore) ? -10000 : minScore,
|
|
upgrade_until_custom_format_score: isNaN(untilScore) ? 5500 : untilScore,
|
|
upgrade_score_increment: isNaN(increment) ? 100 : increment,
|
|
language: language,
|
|
qualities: qualities
|
|
};
|
|
const saveBtn = document.getElementById('profile-editor-save');
|
|
if (saveBtn) saveBtn.disabled = true;
|
|
var patchUrl = isTVHunt ? './api/tv-hunt/profiles/' + encodeURIComponent(state.profileId) : './api/profiles/' + index;
|
|
fetch(patchUrl, {
|
|
method: 'PATCH',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body)
|
|
})
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(data) {
|
|
if (data.success) {
|
|
_profileEditorDirty = false;
|
|
saveProfileEditorScores().then(function() {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification('Profile saved.', 'success');
|
|
}
|
|
if (optionalNextSection != null && window.huntarrUI && window.huntarrUI.switchSection) {
|
|
window.huntarrUI.switchSection(nextSection);
|
|
}
|
|
if (window.MediaHuntProfiles && typeof window.MediaHuntProfiles.refreshProfilesList === 'function' && window._mediaHuntProfilesMode) {
|
|
window.MediaHuntProfiles.refreshProfilesList(window._mediaHuntProfilesMode);
|
|
} else if (isTVHunt && window.TVHuntSettingsForms && window.TVHuntSettingsForms.refreshTVHuntProfilesList) {
|
|
window.TVHuntSettingsForms.refreshTVHuntProfilesList();
|
|
} else if (Forms.refreshProfilesList) Forms.refreshProfilesList();
|
|
}).catch(function() {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification('Profile saved; some scores may not have saved.', 'warning');
|
|
}
|
|
if (optionalNextSection != null && window.huntarrUI && window.huntarrUI.switchSection) {
|
|
window.huntarrUI.switchSection(nextSection);
|
|
}
|
|
if (window.MediaHuntProfiles && typeof window.MediaHuntProfiles.refreshProfilesList === 'function' && window._mediaHuntProfilesMode) {
|
|
window.MediaHuntProfiles.refreshProfilesList(window._mediaHuntProfilesMode);
|
|
} else if (isTVHunt && window.TVHuntSettingsForms && window.TVHuntSettingsForms.refreshTVHuntProfilesList) {
|
|
window.TVHuntSettingsForms.refreshTVHuntProfilesList();
|
|
} else if (Forms.refreshProfilesList) Forms.refreshProfilesList();
|
|
});
|
|
} else {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification(data.error || 'Failed to save.', 'error');
|
|
}
|
|
if (saveBtn) saveBtn.disabled = false;
|
|
saveBtn.classList.add('enabled');
|
|
}
|
|
})
|
|
.catch(function() {
|
|
if (window.huntarrUI && window.huntarrUI.showNotification) {
|
|
window.huntarrUI.showNotification('Failed to save profile.', 'error');
|
|
}
|
|
if (saveBtn) saveBtn.disabled = false;
|
|
saveBtn.classList.add('enabled');
|
|
});
|
|
};
|
|
|
|
Forms.cancelProfileEditor = function(optionalNextSection) {
|
|
var state = Forms._currentProfileEditing;
|
|
_profileEditorDirty = false;
|
|
Forms._currentProfileEditing = null;
|
|
var defaultSection = (state && state.tvHunt) ? 'tv-hunt-settings-profiles' : 'settings-profiles';
|
|
if (window.huntarrUI && window.huntarrUI.switchSection) {
|
|
window.huntarrUI.switchSection(optionalNextSection || defaultSection);
|
|
}
|
|
};
|
|
|
|
Forms.isProfileEditorDirty = function() {
|
|
return !!_profileEditorDirty;
|
|
};
|
|
|
|
Forms.confirmLeaveProfileEditor = function(callback) {
|
|
confirmLeaveProfileEditor(callback);
|
|
};
|
|
})();
|