File size: 18,423 Bytes
b1c669d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
document.addEventListener('DOMContentLoaded', () => {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes) {
mutation.addedNodes.forEach((node) => {
if (node.id === 'tab_models_list') {
// запуск кода после загрузки элементов
Array.from(document.querySelectorAll('#tabs > div.tab-nav > button')).find(button => button.textContent.includes('модели')).click();
// переопределение параметров колонок на основе числа моделей в категории
const models_checkbox_grids = document.querySelectorAll("#tab_models_list fieldset > div[data-testid='checkbox-group']");
models_checkbox_grids.forEach(models_checkbox_grid => {
const model_label = models_checkbox_grid.querySelectorAll('label');
const numColumns = model_label.length > 9 ? 'repeat(auto-fit, minmax(250px, 1fr))' : '1fr';
models_checkbox_grid.style.gridTemplateColumns = numColumns;
});
// подвсетка категории мужицких моделей (костаыль, потому что градио своим скриптом долбит каждые Nms переопределение классов)
const intervalId = setInterval(() => {
const modelsNavButtons = document.querySelectorAll("div#tab_models_list > div.gap > div.tabs > div.tab-nav > button");
const MaleCat = Array.from(modelsNavButtons).find(button => button.textContent.includes('мужские'));
if (MaleCat) {
MaleCat.setAttribute("id", "male_only");
}
}, 100);
// получение инфы по кд о свободном пространтсве из скрытого уродского текстбокса в красивый элементик в шапочке
const freespacetextarea = document.querySelector("#free_space_area > label > textarea");
const frespace_out = document.querySelector("#frespace_out");
let prevValue = freespacetextarea.value;
setInterval(function () {
const currentValue = freespacetextarea.value;
if (currentValue !== prevValue) {
frespace_out.innerHTML = `${currentValue}`;
prevValue = currentValue;
}
}, 100);
// скликивание реальной но скрытой уродской кнопки с обработчиком проверки свободного места при нажатии на фейковую но красивую кнопочку
const freespace_getButton = document.querySelector("#freespace_get");
const free_spaceOrigButton = document.querySelector("#free_space_button");
freespace_getButton.addEventListener("click", function () {
free_spaceOrigButton.click();
});
// копирование реальных элементов из вкладок с моделями в результатах поиска
const SearchBlock = document.querySelector('#clear_search_models_results').closest('label').closest('div').closest('div').closest('div');
const ModelDLHeaderBlock = document.querySelector('.models_dl_header').closest('div').parentNode.closest('div').closest('div');
const ModelDLHeaderContainer = document.querySelector('.models_dl_header').closest('div').parentNode;
ModelDLHeaderBlock.appendChild(SearchBlock);
// небольшой css-фикс
ModelDLHeaderContainer.style.cssText = `display: flex; flex-direction: row; align-items: center; justify-content: flex-start; flex-wrap: wrap;`;
document.querySelector('.models_dl_header').parentNode.style.marginRight = "50px";
// фильтрация моделей при вводе
const searchInput = document.querySelector('input[type="text"]');
const findedModels = document.querySelector('#finded_models');
const tabModelsList = document.querySelector('#tab_models_list');
const labels = tabModelsList.querySelectorAll('label');
const clearSearchResultsButton = document.querySelector("#clear_search_models_results");
searchInput.addEventListener('input', (event) => {
const searchTerm = event.target.value.toLowerCase();
findedModels.innerHTML = '';
if (searchTerm !== '') {
labels.forEach((label) => {
const labelText = label.textContent.toLowerCase();
if (labelText.includes(searchTerm)) {
const clone = label.cloneNode(true);
findedModels.appendChild(clone);
const originalCheckbox = label.querySelector('input[type="checkbox"]');
const clonedCheckbox = clone.querySelector('input[type="checkbox"]');
clonedCheckbox.addEventListener('change', () => {
originalCheckbox.click();
});
}
});
}
});
// обработчик на кнопочку очистки результатов
clearSearchResultsButton.addEventListener('click', () => {
findedModels.innerHTML = '';
searchInput.value = '';
});
// автоматическое скликивание скрытых кнопок для подгрузки установленных моделей и свободного места после загрузки дополнения через 1 сек
setTimeout(() => document.querySelector("#files_button").click(), 1000);
setTimeout(() => document.querySelector("#free_space_button").click(), 1000);
// файловый менеджер на тексбоксах
setTimeout(() => {
const filesArea = document.querySelector("#files_area > label > textarea");
const filesCheckbox = document.querySelector("#files_checkbox");
const deleteArea = document.querySelector("#delete_area > label > textarea");
// обновление списка чекбоксов с файлами при изменении списка путей в текстбоксе
function addCheckboxEventListeners() {
const delete_checkboxes = document.querySelectorAll("#files_checkbox > label > input[type=checkbox]");
delete_checkboxes.forEach(checkbox => {
checkbox.addEventListener("change", event => {
// отмеченные на удаление делаем красными и зачеркнутыми
const delete_span = event.target.parentElement.querySelector("span");
if (event.target.checked) {
delete_span.style.textDecoration = "line-through";
delete_span.style.color = "#ed5252";
} else {
delete_span.style.textDecoration = "none";
delete_span.style.color = "";
}
});
});
}
// функция для обновления чекбоксов с файлами почти в реальном времени
function updateCheckboxes() {
while (filesCheckbox.firstChild) {
filesCheckbox.removeChild(filesCheckbox.firstChild);
}
const fileNames = filesArea.value.split("\n").map(path => path.split("/").pop());
if (fileNames.length === 0 || (fileNames.length === 1 && fileNames[0] === "")) {
const message = document.createElement("p");
message.textContent = "ничего не найдено";
filesCheckbox.appendChild(message);
} else {
fileNames.forEach(fileName => {
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.id = fileName;
checkbox.addEventListener("change", event => {
if (event.target.checked) {
deleteArea.value += (deleteArea.value ? "\n" : "") + fileName;
} else {
const lines = deleteArea.value.split("\n");
const index = lines.indexOf(fileName);
if (index !== -1) {
lines.splice(index, 1);
deleteArea.value = lines.join("\n");
}
}
deleteArea.dispatchEvent(new Event('input')); // имитация ввода, это самая важная часть кода
});
const label = document.createElement("label");
label.htmlFor = fileName;
label.className = "filecheckbox";
const span = document.createElement("span");
span.textContent = fileName;
label.appendChild(checkbox);
label.appendChild(span);
filesCheckbox.appendChild(label);
});
}
deleteArea.value = deleteArea.value.trim();
deleteArea.dispatchEvent(new Event('input')); // имитация ввода, без этого не работает
addCheckboxEventListeners()
}
// наблюдаем за скрытым тексбоксом с путями до моделей и обновлям чекбоксы
const observer = new MutationObserver(updateCheckboxes);
observer.observe(filesArea, { characterData: true, subtree: true });
updateCheckboxes();
// скликивание реальной но скрытой уродской кнопки с обработчиком обновления списка файлов при нажатии на фейковую но красивую кнопочку
const RefreshFilesButton = document.querySelector("#refresh_files_button");
RefreshFilesButton.addEventListener("click", () => {
document.querySelector("#files_button").click();
// задержки по 3 секунды необходимы, чтобы колаб одуплился
setTimeout(function () { updateCheckboxes(); }, 3000);
});
// при клике на фейковую кнопочку удаления - произойдет и обновление списка файлов с задержкой 3 сек
document.querySelector("#delete_button").addEventListener("click", function () {
setTimeout(function () {
document.querySelector("#files_button").click();
// задержки по 3 секунды необходимы, чтобы колаб одуплился
setTimeout(function () { updateCheckboxes(); }, 3000);
}, 3000);
});
// скликивание реальной но скрытой уродской кнопки с обработчиком удаления моделей при нажатии на фейковую но красивую кнопочку
const OrigDelButton = document.querySelector("#delete_button");
const CustomDelButton = document.querySelector("#delete_files_button");
CustomDelButton.addEventListener("click", () => {
OrigDelButton.click();
});
// проверка выхлопа из функции загрузки в скрытом текстбоксе
setInterval(function () {
var DLresultText = document.querySelector("#downloads_result_text > span.finish_dl_func");
DLresultText.textContent = document.querySelector("#dlresultbox > label > textarea").value;
// функция скрытия прогрессбара
function checkDLresult(element, text) {
if (element.textContent.includes(text)) {
document.querySelector("div.downloads_result_container > div.models_porgress_loader").style.removeProperty("display");
document.querySelector("#downloads_start_text").style.removeProperty("display");
document.querySelector("#downloads_result_text > span.dl_progress_info").textContent = "чтобы новые файлы появились в выпадающем списке моделей, нужно обновить их список по соответсвующей кнопке";
}
}
// просто скрываем прогрессбар если в выхлопе есть фраза о завершении или предупреждение
checkDLresult(DLresultText, "заверш");
checkDLresult(DLresultText, "слишком");
checkDLresult(DLresultText, "ОШИБКА");
// раскрашиваем текст сообщения о результате выполнения, если что-то пошло не так
if (DLresultText) {
if (DLresultText.textContent.includes("слишком")) {
DLresultText.style.setProperty("color", "#ff4f8b", "important");
} else if (DLresultText.textContent.includes("ОШИБКА")) {
DLresultText.style.setProperty("color", "#de2f2f", "important");
} else if (DLresultText.textContent.includes("заверш")) {
DLresultText.style.setProperty("color", "#99fb99", "important");
}
}
}, 200);
// действия по клику на фейковую но видимую кнопку для скачивания
document.querySelector("#general_download_button").addEventListener("click", function () {
// очистка текстбокса от выхлопа предыдущего выполнения
var resultTextareaDL = document.querySelector("#dlresultbox > label > textarea");
resultTextareaDL.value = "";
var resultClearOut = new Event("input", { bubbles: true }); // без этого не будет работать обноволение .value
resultTextareaDL.dispatchEvent(resultClearOut);
// делаем прогрессбар и место для результирующего текста видимыми
const DLprogressBar = document.querySelector("div.downloads_result_container > div.models_porgress_loader");
DLprogressBar.style.setProperty("display", "block", "important");
const DLresultText = document.querySelector("#downloads_result_text");
DLresultText.style.setProperty("display", "block", "important");
document.querySelector("#downloads_start_text").style.setProperty("display", "block", "important");
// скликивание реальных но скрытых кнопок с обработчиками загрузки файлов по чекбоксам и кастомных ссылок при нажатии на фейковую но кнопочку
// формирование списка из кастомных ссылок
document.querySelector("#ownlinks_download_button").click();
setTimeout(function () {
// через 3 сек. добавим его к списку ссылок из чекбоксов и отправим на загрузку вместе
document.querySelector("#checkboxes_download_button").click();
}, 3000); // задержка, чтобы колаб успел одуплиться
});
// если кнопка загрузки уже нажата, запрещаем кликать еще раз пока функция загрузки не выплюнет ответ
var GendownloadButton = document.querySelector("#general_download_button");
var DLprogressBar = document.querySelector("div.downloads_result_container > div.models_porgress_loader");
if (GendownloadButton && DLprogressBar) {
var DLobserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.type === "attributes" && mutation.attributeName === "style") { // отслеживание видимости прогрессбара
if (DLprogressBar.style.display === "block") {
GendownloadButton.setAttribute("disabled", "disabled");
} else {
setTimeout(function () {
GendownloadButton.removeAttribute("disabled");
}, 3000); // не сразу даем кликнуть снова, а после ожидания 3 секунды, чтобы не закликали
}
}
});
});
DLobserver.observe(DLprogressBar, { attributes: true });
}
}, 9000); // запуск скриптов через 9 секунд после загрузки вебуи, чтобы успели отработать скрипты других дополнений и градио
}
});
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
});
|