File size: 14,997 Bytes
b1c669d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e8922a
b1c669d
 
 
 
 
 
7e8922a
b1c669d
7e8922a
b1c669d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e8922a
b1c669d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e8922a
b1c669d
 
 
 
 
 
 
 
 
 
 
 
 
 
7e8922a
b1c669d
 
 
 
 
 
 
7e8922a
b1c669d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e8922a
b1c669d
 
7e8922a
b1c669d
7e8922a
b1c669d
 
 
 
 
 
 
7e8922a
b1c669d
 
 
 
 
 
 
 
7e8922a
 
b1c669d
7e8922a
b1c669d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7e8922a
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
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 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();
            });
            // небольшой css-фикс
            const ModelDLHeaderContainer = document.querySelector('.models_dl_header').closest('div').parentNode;
            ModelDLHeaderContainer.style.cssText = `display: flex; flex-direction: row; align-items: center; justify-content: flex-start; flex-wrap: wrap;`;
            document.querySelector('.models_dl_header').parentNode.marginRight = "50px";
            // автоматическое скликивание скрытых кнопок для подгрузки установленных моделей и свободного места после загрузки дополнения через 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 () {
                const 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 () {
                // очистка текстбокса от выхлопа предыдущего выполнения
                const resultTextareaDL = document.querySelector("#dlresultbox > label > textarea");
                resultTextareaDL.value = "";
                const 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); // задержка, чтобы колаб успел одуплиться
              });
              // если кнопка загрузки уже нажата, запрещаем кликать еще раз пока функция загрузки не выплюнет ответ
              const GendownloadButton = document.querySelector("#general_download_button");
              const DLprogressBar = document.querySelector("div.downloads_result_container > div.models_porgress_loader");
              if (GendownloadButton && DLprogressBar) {
                const 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 });
});