Update to v3.4.2
parent
bcf6c1872b
commit
2cfa149e3c
14
README.md
14
README.md
|
|
@ -100,12 +100,22 @@ https://github.com/BlafKing/sd-civitai-browser-plus/assets/9644716/44c5c7a0-4854
|
|||
|
||||
# Changelog 📋
|
||||
|
||||
<h3>v3.4.2</h3>
|
||||
|
||||
* Feature: Ability to set-up a custom proxy for API requests and downloads.
|
||||
* Feature: Use image API for prompt info, should speed up loading.
|
||||
* Feature: Optimized javascript code, improved webpage speed for some users.
|
||||
* New setting: Proxy settings to set-up custom proxy.
|
||||
* New setting: Toggle for saving description to model json file. (this displays description on the cards)
|
||||
* Bug fix: Broken default sub folder option fixed [#217](https://github.com/BlafKing/sd-civitai-browser-plus/issues/217)
|
||||
|
||||
---
|
||||
<h3>v3.4.1</h3>
|
||||
|
||||
* Bug fix: Fixed prompt info and model selection after CivitAI API update.
|
||||
* Bug fix: Fixed "/" missing from default path/sub-folder.
|
||||
* Feature: Local images now work in HTML files as preview. (credit: [mx](https://github.com/mx))
|
||||
* Feature: Updated available base models.
|
||||
* Bug fix: Fixed prompt info and model selection after CivitAI API update.
|
||||
* Bug fix: Fixed "/" missing from default path/sub-folder.
|
||||
|
||||
---
|
||||
<h3>v3.4.0</h3>
|
||||
|
|
|
|||
|
|
@ -17,3 +17,4 @@ install_req("zip_unicode", "ZipUnicode")
|
|||
install_req("bs4", "beautifulsoup4")
|
||||
install_req("fake_useragent")
|
||||
install_req("packaging")
|
||||
install_req("pysocks")
|
||||
|
|
@ -102,7 +102,7 @@ function updateCard(modelNameWithSuffix) {
|
|||
}
|
||||
|
||||
// Enables refresh with alt+enter and ctrl+enter
|
||||
document.addEventListener('keydown', function(e) {
|
||||
function keydownHandler(e) {
|
||||
var handled = false;
|
||||
|
||||
if (e.key !== undefined) {
|
||||
|
|
@ -126,7 +126,8 @@ document.addEventListener('keydown', function(e) {
|
|||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
document.addEventListener('keydown', keydownHandler);
|
||||
|
||||
// Function for the back to top button
|
||||
function BackToTop() {
|
||||
|
|
@ -204,14 +205,21 @@ function pressRefresh() {
|
|||
setTimeout(() => {
|
||||
const input = document.querySelector("#pageSlider > div:nth-child(2) > div > input");
|
||||
if (document.activeElement === input) {
|
||||
input.addEventListener('keydown', function(event) {
|
||||
function keydownHandler(event) {
|
||||
if (event.key === 'Enter' || event.keyCode === 13) {
|
||||
input.blur();
|
||||
input.removeEventListener('keydown', keydownHandler);
|
||||
input.removeEventListener('blur', blurHandler);
|
||||
}
|
||||
});
|
||||
input.addEventListener('blur', function() {
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
function blurHandler() {
|
||||
input.removeEventListener('keydown', keydownHandler);
|
||||
input.removeEventListener('blur', blurHandler);
|
||||
}
|
||||
|
||||
input.addEventListener('keydown', keydownHandler);
|
||||
input.addEventListener('blur', blurHandler);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -328,24 +336,6 @@ function updateBackToTopVisibility(entries) {
|
|||
}
|
||||
}
|
||||
|
||||
// Options for the Intersection Observer
|
||||
var options = {
|
||||
root: null,
|
||||
rootMargin: '0px 0px -60px 0px',
|
||||
threshold: 0
|
||||
};
|
||||
|
||||
// Create an Intersection Observer instance
|
||||
const observer = new IntersectionObserver(updateBackToTopVisibility, options);
|
||||
|
||||
function handleCivitaiDivChanges() {
|
||||
var civitaiDiv = document.getElementById('civitai_preview_html');
|
||||
observer.unobserve(civitaiDiv);
|
||||
observer.observe(civitaiDiv);
|
||||
}
|
||||
|
||||
document.addEventListener("scroll", handleCivitaiDivChanges)
|
||||
|
||||
// Create the accordion dropdown inside the settings tab
|
||||
function createAccordion(containerDiv, subfolders, name) {
|
||||
if (containerDiv == null || subfolders.length == 0) {
|
||||
|
|
@ -371,14 +361,19 @@ function createAccordion(containerDiv, subfolders, name) {
|
|||
}
|
||||
|
||||
// Adds a button to the cards in txt2img and img2img
|
||||
function createCardButtons(event) {
|
||||
const clickedElement = event.target;
|
||||
function createCivitAICardButtons(clickedElement=null) {
|
||||
addOnClickToButtons();
|
||||
const validButtonNames = ['Textual Inversion', 'Hypernetworks', 'Checkpoints', 'Lora'];
|
||||
const validParentIds = ['txt2img_textual_inversion_cards_html', 'txt2img_hypernetworks_cards_html', 'txt2img_checkpoints_cards_html', 'txt2img_lora_cards_html'];
|
||||
|
||||
const hasMatchingButtonName = clickedElement && clickedElement.innerText && validButtonNames.some(buttonName =>
|
||||
let hasMatchingButtonName = null;
|
||||
if (clickedElement) {
|
||||
hasMatchingButtonName = clickedElement && clickedElement.innerText && validButtonNames.some(buttonName =>
|
||||
clickedElement.innerText.trim() === buttonName
|
||||
);
|
||||
} else {
|
||||
hasMatchingButtonName = true;
|
||||
}
|
||||
|
||||
const flexboxDivs = document.querySelectorAll('.layoutkit-flexbox');
|
||||
let isLobeTheme = false;
|
||||
|
|
@ -429,10 +424,6 @@ function createCardButtons(event) {
|
|||
|
||||
const newDiv = document.createElement('div');
|
||||
newDiv.classList.add('goto-civitbrowser', 'card-button');
|
||||
newDiv.addEventListener('click', function (event) {
|
||||
event.stopPropagation();
|
||||
modelInfoPopUp(modelName, content_type);
|
||||
});
|
||||
|
||||
const svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
if (isLobeTheme) {
|
||||
|
|
@ -451,6 +442,9 @@ function createCardButtons(event) {
|
|||
svgIcon.setAttribute('viewBox', `75 ${viewBoxHeight} 500 500`);
|
||||
svgIcon.setAttribute('fill', 'white');
|
||||
svgIcon.setAttribute('style', `scale: ${cardScale}%;`);
|
||||
newDiv.onclick = function() {
|
||||
modelInfoPopUp(modelName, content_type);
|
||||
};
|
||||
|
||||
svgIcon.innerHTML = `
|
||||
<path d="M 352.79 218.85 L 319.617 162.309 L 203.704 162.479 L 146.28 259.066 L 203.434 355.786 L 319.373 355.729 L 352.773 299.386 L 411.969 299.471 L 348.861 404.911 L 174.065 404.978 L 87.368 259.217 L 174.013 113.246 L 349.147 113.19 L 411.852 218.782 L 352.79 218.85 Z"/>
|
||||
|
|
@ -461,10 +455,45 @@ function createCardButtons(event) {
|
|||
buttonRow.insertBefore(newDiv, buttonRow.firstChild);
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
}, 200);
|
||||
|
||||
setTimeout(() => {
|
||||
clearInterval(checkForCardDivs);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
document.addEventListener('click', createCardButtons);
|
||||
|
||||
function addOnClickToButtons() {
|
||||
const img2img_extra_tabs = document.getElementById('img2img_extra_tabs');
|
||||
const txt2img_extra_tabs = document.getElementById('txt2img_extra_tabs');
|
||||
const txt2img_refresh_btn = document.getElementById('txt2img_checkpoints_extra_refresh');
|
||||
const img2img_refresh_btn = document.getElementById('img2img_checkpoints_extra_refresh');
|
||||
|
||||
txt2img_refresh_btn.onclick = function() {
|
||||
createCivitAICardButtons(this);
|
||||
};
|
||||
|
||||
img2img_refresh_btn.onclick = function() {
|
||||
createCivitAICardButtons(this);
|
||||
};
|
||||
|
||||
function addButtonClickEvent(div) {
|
||||
var firstChildDiv = div.querySelector('div');
|
||||
if (firstChildDiv) {
|
||||
var buttons = firstChildDiv.querySelectorAll('button');
|
||||
buttons.forEach(function(button, index) {
|
||||
if (index !== 0) {
|
||||
button.onclick = function() {
|
||||
createCivitAICardButtons(this);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addButtonClickEvent(img2img_extra_tabs);
|
||||
addButtonClickEvent(txt2img_extra_tabs);
|
||||
}
|
||||
|
||||
function modelInfoPopUp(modelName, content_type) {
|
||||
select_model(modelName, null, true, content_type);
|
||||
|
|
@ -480,6 +509,7 @@ function modelInfoPopUp(modelName, content_type) {
|
|||
overlay.style.backgroundColor = 'rgba(20, 20, 20, 0.95)';
|
||||
overlay.style.zIndex = '1001';
|
||||
overlay.style.overflowY = 'auto';
|
||||
overlay.addEventListener('keydown', handleKeyPress);
|
||||
|
||||
// Create the close button
|
||||
var closeButton = document.createElement('div');
|
||||
|
|
@ -493,7 +523,6 @@ function modelInfoPopUp(modelName, content_type) {
|
|||
closeButton.style.color = 'white';
|
||||
closeButton.style.fontSize = '32pt';
|
||||
closeButton.addEventListener('click', hidePopup);
|
||||
document.addEventListener('keydown', handleKeyPress);
|
||||
|
||||
// Create the pop-up window
|
||||
var inner = document.createElement('div');
|
||||
|
|
@ -503,7 +532,7 @@ function modelInfoPopUp(modelName, content_type) {
|
|||
inner.style.left = '50%';
|
||||
inner.style.width = 'auto';
|
||||
inner.style.transform = 'translate(-50%, -50%)';
|
||||
inner.style.background = 'var(--body-background-fill)';
|
||||
inner.style.background = 'var(--neutral-950)';
|
||||
inner.style.padding = '2em';
|
||||
inner.style.borderRadius = 'var(--block-radius)';
|
||||
inner.style.borderStyle = 'solid';
|
||||
|
|
@ -587,6 +616,8 @@ function inputHTMLPreviewContent(html_input) {
|
|||
}
|
||||
modelInfo.innerHTML = extractedText;
|
||||
inner.appendChild(modelInfo);
|
||||
|
||||
setDescriptionToggle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -695,64 +726,6 @@ function multi_model_select(modelName, modelType, isChecked) {
|
|||
updateInput(selected_type_list);
|
||||
}
|
||||
|
||||
// Metadata button click detector
|
||||
document.addEventListener('click', function(event) {
|
||||
var target = event.target;
|
||||
if (target.classList.contains('edit-button') && target.classList.contains('card-button')) {
|
||||
var parentDiv = target.parentElement;
|
||||
var actionsDiv = parentDiv.nextElementSibling;
|
||||
if (actionsDiv && actionsDiv.classList.contains('actions')) {
|
||||
var nameSpan = actionsDiv.querySelector('.name');
|
||||
if (nameSpan) {
|
||||
var nameValue = nameSpan.textContent;
|
||||
onEditButtonCardClick(nameValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
// CivitAI Link Button Creation
|
||||
function onEditButtonCardClick(nameValue) {
|
||||
var checkInterval = setInterval(function() {
|
||||
var globalPopupInner = document.querySelector('.global-popup-inner');
|
||||
var titleElement = globalPopupInner.querySelector('.extra-network-name');
|
||||
if (titleElement.textContent.trim() === nameValue.trim()) {
|
||||
var descriptionSpan = Array.from(globalPopupInner.querySelectorAll('span')).find(span => span.textContent.trim() === "Description");
|
||||
if (descriptionSpan) {
|
||||
var descriptionTextarea = descriptionSpan.nextElementSibling;
|
||||
if (descriptionTextarea.value.startsWith('Model URL:')) {
|
||||
var matches = descriptionTextarea.value.match(/"([^"]+)"/);
|
||||
if (matches && matches[1]) {
|
||||
var modelUrl = matches[1];
|
||||
|
||||
var grandParentDiv = descriptionTextarea.parentElement.parentElement.parentElement.parentElement;
|
||||
var imageDiv = grandParentDiv.nextElementSibling
|
||||
var openInCivitaiDiv = document.querySelector('.open-in-civitai');
|
||||
if (!openInCivitaiDiv) {
|
||||
openInCivitaiDiv = document.createElement('div');
|
||||
openInCivitaiDiv.classList.add('open-in-civitai');
|
||||
imageDiv.appendChild(openInCivitaiDiv);
|
||||
}
|
||||
openInCivitaiDiv.innerHTML = '<a href="' + modelUrl + '" target="_blank" onclick="window.open(this.href, \'_blank\'); return false;">Open on CivitAI</a>';
|
||||
}
|
||||
else {
|
||||
var openInCivitaiDiv = document.querySelector('.open-in-civitai');
|
||||
if (openInCivitaiDiv) {
|
||||
openInCivitaiDiv.remove();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var openInCivitaiDiv = document.querySelector('.open-in-civitai');
|
||||
if (openInCivitaiDiv) {
|
||||
openInCivitaiDiv.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
clearInterval(checkInterval);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function sendClick(location) {
|
||||
const clickEvent = new MouseEvent('click', {
|
||||
view: window,
|
||||
|
|
@ -961,59 +934,82 @@ function hideInstalled(toggleValue) {
|
|||
});
|
||||
}
|
||||
|
||||
function setDescriptionToggle() {
|
||||
const popUp = document.querySelector(".civitai-overlay-inner");
|
||||
let toggleButton = null;
|
||||
let descriptionDiv = null;
|
||||
|
||||
if (popUp) {
|
||||
descriptionDiv = popUp.querySelector(".model-description");
|
||||
toggleButton = popUp.querySelector(".description-toggle-label");
|
||||
} else {
|
||||
descriptionDiv = document.querySelector(".model-description");
|
||||
toggleButton = document.querySelector(".description-toggle-label");
|
||||
}
|
||||
|
||||
if (descriptionDiv && descriptionDiv.scrollHeight <= 400) {
|
||||
toggleButton.style.visibility = "hidden";
|
||||
toggleButton.style.height = "0";
|
||||
descriptionDiv.style.position = "unset";
|
||||
}
|
||||
}
|
||||
|
||||
// Runs all functions when the page is fully loaded
|
||||
function onPageLoad() {
|
||||
const divElement = document.getElementById('setting_custom_api_key');
|
||||
let civitaiDiv = document.getElementById('civitai_preview_html');
|
||||
let queue_list = document.querySelector("#queue_list");
|
||||
const infoElement = divElement?.querySelector('.info');
|
||||
if (!infoElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearInterval(intervalID);
|
||||
|
||||
updateSVGIcons();
|
||||
|
||||
let subfolderDiv = document.querySelector("#settings_civitai_browser_plus > div > div");
|
||||
let downloadDiv = document.querySelector("#settings_civitai_browser_download > div > div");
|
||||
let upscalerDiv = document.querySelector("#settings_civitai_browser_plus > div > div > #settings-accordion > div");
|
||||
let downloadDivSub = document.querySelector("#settings_civitai_browser_download > div > div > #settings-accordion > div");
|
||||
let settingsDiv = document.querySelector("#settings_civitai_browser > div > div");
|
||||
|
||||
if (subfolderDiv || downloadDiv) {
|
||||
let div = subfolderDiv || downloadDiv;
|
||||
let subfolders = div.querySelectorAll("[id$='subfolder']");
|
||||
createAccordion(div, subfolders, "Default sub folders");
|
||||
}
|
||||
|
||||
let upscalerDiv = document.querySelector("#settings_civitai_browser_plus > div > div > #settings-accordion > div");
|
||||
let downloadDivSub = document.querySelector("#settings_civitai_browser_download > div > div > #settings-accordion > div");
|
||||
if (upscalerDiv || downloadDivSub) {
|
||||
let div = upscalerDiv || downloadDivSub;
|
||||
let upscalers = div.querySelectorAll("[id$='upscale_subfolder']");
|
||||
createAccordion(div, upscalers, "Upscalers");
|
||||
}
|
||||
|
||||
let settingsDiv = document.querySelector("#settings_civitai_browser > div > div");
|
||||
if (subfolderDiv || settingsDiv) {
|
||||
let div = subfolderDiv || settingsDiv;
|
||||
let subfolders = div.querySelectorAll("[id^='setting_insert_sub']");
|
||||
createAccordion(div, subfolders, "Insert sub folder options");
|
||||
}
|
||||
|
||||
let proxy = div.querySelectorAll("[id$='proxy']");
|
||||
createAccordion(div, proxy, "Proxy options");
|
||||
}
|
||||
|
||||
let toggle4L = document.getElementById('toggle4L');
|
||||
let toggle4 = document.getElementById('toggle4');
|
||||
let hash_toggle_hover = document.querySelector('#skip_hash_toggle > label');
|
||||
let hash_toggle = document.querySelector('#skip_hash_toggle');
|
||||
|
||||
if (toggle4L || toggle4) {
|
||||
let like_toggle = toggle4L || toggle4;
|
||||
let insertText = 'Requires an API Key\nConfigurable in CivitAI settings tab';
|
||||
createTooltip(like_toggle, like_toggle, insertText);
|
||||
}
|
||||
|
||||
let hash_toggle_hover = document.querySelector('#skip_hash_toggle > label');
|
||||
let hash_toggle = document.querySelector('#skip_hash_toggle');
|
||||
if (hash_toggle) {
|
||||
let insertText = 'This option generates unique hashes for models that were not downloaded with this extension.\nA hash is required for any of the options below to work, a model with no hash will be skipped.\nInitial hash generation is a one-time process per file.';
|
||||
createTooltip(hash_toggle, hash_toggle_hover, insertText);
|
||||
}
|
||||
|
||||
observer.observe(civitaiDiv);
|
||||
addOnClickToButtons();
|
||||
createCivitAICardButtons();
|
||||
adjustFilterBoxAndButtons();
|
||||
setupClickOutsideListener();
|
||||
createLink(infoElement);
|
||||
|
|
|
|||
|
|
@ -8,15 +8,10 @@ import os
|
|||
import re
|
||||
import datetime
|
||||
import platform
|
||||
import time
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
from collections import defaultdict
|
||||
from modules.images import read_info_from_image
|
||||
try:
|
||||
from modules.generation_parameters_copypaste import parse_generation_parameters
|
||||
except:
|
||||
from modules.infotext_utils import parse_generation_parameters
|
||||
|
||||
from modules.shared import cmd_opts, opts
|
||||
from modules.paths import models_path, extensions_dir, data_path
|
||||
|
|
@ -372,7 +367,7 @@ def update_next_page(content_type, sort_type, period_type, use_search_term, sear
|
|||
if 'LoCon' not in content_type:
|
||||
content_type.append('LoCon')
|
||||
|
||||
if gl.json_data is None or gl.json_data == "timeout":
|
||||
if gl.json_data is None or gl.json_data == "timeout" or gl.json_data == "error":
|
||||
timeOut = True
|
||||
return_values = update_model_list(content_type, sort_type, period_type, use_search_term, search_term, current_page, base_filter, only_liked, nsfw, timeOut=timeOut, isNext=isNext)
|
||||
timeOut = False
|
||||
|
|
@ -444,7 +439,13 @@ def update_next_page(content_type, sort_type, period_type, use_search_term, sear
|
|||
hasNext = current_page == 1 or hasPrev
|
||||
model_dict = {}
|
||||
|
||||
if gl.json_data != None and gl.json_data != "timeout":
|
||||
if gl.json_data == "error":
|
||||
HTML = '<div style="font-size: 24px; text-align: center; margin: 50px !important;">The Civit-API has failed to return due to an error.<br>Check the logs for more details.</div>'
|
||||
hasPrev = current_page not in [0, 1]
|
||||
hasNext = current_page == 1 or hasPrev
|
||||
model_dict = {}
|
||||
|
||||
if gl.json_data != None and gl.json_data != "timeout" and gl.json_data != "error":
|
||||
(hasPrev, hasNext, current_page, total_pages) = pagecontrol(gl.json_data)
|
||||
model_dict = {}
|
||||
try:
|
||||
|
|
@ -517,13 +518,19 @@ def update_model_list(content_type=None, sort_type=None, period_type=None, use_s
|
|||
hasPrev = current_page not in [0, 1]
|
||||
hasNext = current_page == 1 or hasPrev
|
||||
|
||||
if gl.json_data == "error":
|
||||
HTML = '<div style="font-size: 24px; text-align: center; margin: 50px !important;">The Civit-API has failed to return due to an error.<br>Check the logs for more details.</div>'
|
||||
hasPrev = current_page not in [0, 1]
|
||||
hasNext = current_page == 1 or hasPrev
|
||||
model_dict = {}
|
||||
|
||||
if gl.json_data is None:
|
||||
return
|
||||
|
||||
if from_installed or from_ver:
|
||||
gl.json_data = gl.ver_json
|
||||
|
||||
if gl.json_data != None and gl.json_data != "timeout":
|
||||
if gl.json_data != None and gl.json_data != "timeout" and gl.json_data != "error":
|
||||
if not from_ver:
|
||||
(hasPrev, hasNext, current_page, total_pages) = pagecontrol(gl.json_data)
|
||||
else:
|
||||
|
|
@ -629,10 +636,11 @@ def cleaned_name(file_name):
|
|||
return f"{clean_name}{extension}"
|
||||
|
||||
def fetch_and_process_image(image_url):
|
||||
proxies, ssl = get_proxies()
|
||||
try:
|
||||
parsed_url = urllib.parse.urlparse(image_url)
|
||||
if parsed_url.scheme and parsed_url.netloc:
|
||||
response = requests.get(image_url)
|
||||
response = requests.get(image_url, proxies=proxies, verify=ssl)
|
||||
if response.status_code == 200:
|
||||
image = Image.open(BytesIO(response.content))
|
||||
geninfo, _ = read_info_from_image(image)
|
||||
|
|
@ -644,34 +652,6 @@ def fetch_and_process_image(image_url):
|
|||
except:
|
||||
return None
|
||||
|
||||
def image_url_to_promptInfo(image_url):
|
||||
response = requests.get(image_url)
|
||||
if response.status_code == 200:
|
||||
image = Image.open(BytesIO(response.content))
|
||||
|
||||
prompt, _ = read_info_from_image(image)
|
||||
if prompt:
|
||||
prompt_dict = parse_generation_parameters(prompt)
|
||||
|
||||
invalid_values = [None, 0, "", "Use same sampler", "Use same checkpoint"]
|
||||
keys_to_remove = [key for key, value in prompt_dict.items() if key != "Clip skip" and value in invalid_values]
|
||||
for key in keys_to_remove:
|
||||
prompt_dict.pop(key, None)
|
||||
|
||||
if "Size-1" in prompt_dict and "Size-2" in prompt_dict:
|
||||
prompt_dict["Size"] = f'{prompt_dict["Size-1"]}x{prompt_dict["Size-2"]}'
|
||||
prompt_dict.pop("Size-1", None)
|
||||
prompt_dict.pop("Size-2", None)
|
||||
if "Hires resize-1" in prompt_dict and "Hires resize-2" in prompt_dict:
|
||||
prompt_dict["Hires resize"] = f'{prompt_dict["Hires resize-1"]}x{prompt_dict["Hires resize-2"]}'
|
||||
prompt_dict.pop("Hires resize-1", None)
|
||||
prompt_dict.pop("Hires resize-2", None)
|
||||
|
||||
return prompt_dict
|
||||
else:
|
||||
return []
|
||||
return []
|
||||
|
||||
def extract_model_info(input_string):
|
||||
last_open_parenthesis = input_string.rfind("(")
|
||||
last_close_parenthesis = input_string.rfind(")")
|
||||
|
|
@ -797,19 +777,31 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
model_url = selected_version.get('downloadUrl', '')
|
||||
model_main_url = f"https://civitai.com/models/{item['id']}"
|
||||
img_html = '<div class="sampleimgs"><input type="radio" name="zoomRadio" id="resetZoom" class="zoom-radio" checked>'
|
||||
|
||||
url = f"https://civitai.com/api/v1/images?modelId={item['id']}&modelVersionId={selected_version['id']}&username={model_uploader}"
|
||||
model_images = request_civit_api(url)
|
||||
|
||||
for index, pic in enumerate(selected_version['images']):
|
||||
|
||||
if from_preview:
|
||||
index = f"preview_{index}"
|
||||
|
||||
for item in model_images['items']:
|
||||
if item['id'] == pic['id']:
|
||||
current_image = item
|
||||
|
||||
# Change width value in URL to original image width
|
||||
image_url = re.sub(r'/width=\d+', f'/width={pic["width"]}', pic["url"])
|
||||
if pic['type'] == "video":
|
||||
image_url = image_url.replace("width=", "transcode=true,width=")
|
||||
prompt_dict = []
|
||||
else:
|
||||
prompt_dict = image_url_to_promptInfo(image_url)
|
||||
prompt_dict = current_image['meta']
|
||||
|
||||
nsfw = 'class="model-block"'
|
||||
|
||||
meta_button = False
|
||||
if prompt_dict and prompt_dict.get('Prompt'):
|
||||
if prompt_dict and prompt_dict.get('prompt'):
|
||||
meta_button = True
|
||||
BtnImage = True
|
||||
|
||||
|
|
@ -846,16 +838,29 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
|
||||
if prompt_dict:
|
||||
img_html += '<div style="margin:1em 0em 1em 1em;text-align:left;line-height:1.5em;" id="image_info"><dl style="gap:10px; display:grid;">'
|
||||
# Define the preferred order of keys and convert them to lowercase
|
||||
preferred_order = ["Prompt", "Negative prompt", "Seed", "Size", "Model", "Clip skip", "Sampler", "Steps", "CFG scale"]
|
||||
# Define the preferred order of keys
|
||||
preferred_order = ["prompt", "negativePrompt", "seed", "Size", "Model", "Clip skip", "sampler", "steps", "cfgScale"]
|
||||
# Loop through the keys in the preferred order and add them to the HTML
|
||||
for key in preferred_order:
|
||||
if key in prompt_dict:
|
||||
value = prompt_dict[key]
|
||||
key_map = {
|
||||
"prompt": "Prompt",
|
||||
"negativePrompt": "Negative prompt",
|
||||
"seed": "Seed",
|
||||
"Size": "Size",
|
||||
"Model": "Model",
|
||||
"Clip skip": "Clip skip",
|
||||
"sampler": "Sampler",
|
||||
"steps": "Steps",
|
||||
"cfgScale": "CFG scale"
|
||||
}
|
||||
key = key_map.get(key, key)
|
||||
|
||||
if meta_btn:
|
||||
img_html += f'<div class="civitai-meta-btn" onclick="metaToTxt2Img(\'{escape(str(key))}\', this)"><dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd></div>'
|
||||
img_html += f'<div class="civitai-meta-btn" onclick="metaToTxt2Img(\'{escape(str(key))}\', this)"><dt>{escape(str(key))}</dt><dd>{escape(str(value))}</dd></div>'
|
||||
else:
|
||||
img_html += f'<div class="civitai-meta"><dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd></div>'
|
||||
img_html += f'<div class="civitai-meta"><dt>{escape(str(key))}</dt><dd>{escape(str(value))}</dd></div>'
|
||||
# Check if there are remaining keys in meta
|
||||
remaining_keys = [key for key in prompt_dict if key not in preferred_order]
|
||||
|
||||
|
|
@ -917,10 +922,12 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model-description" style="overflow-wrap: break-word;">
|
||||
<input type="checkbox" id="{'preview-' if from_preview else ''}civitai-description" class="description-toggle-checkbox">
|
||||
<div class="model-description">
|
||||
<h2>Description</h2>
|
||||
{model_desc}
|
||||
</div>
|
||||
<label for="{'preview-' if from_preview else ''}civitai-description" class="description-toggle-label"></label>
|
||||
</div>
|
||||
<div align=center>{img_html}</div>
|
||||
'''
|
||||
|
|
@ -991,7 +998,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
sub_folders.remove("None")
|
||||
sub_folders = sorted(sub_folders, key=lambda x: (x.lower(), x))
|
||||
sub_folders.insert(0, "None")
|
||||
base = cleaned_name(model_uploader)
|
||||
base = cleaned_name(output_basemodel)
|
||||
author = cleaned_name(model_uploader)
|
||||
name = cleaned_name(model_name)
|
||||
ver = cleaned_name(model_version)
|
||||
|
|
@ -1226,37 +1233,54 @@ def update_file_info(model_string, model_version, file_metadata):
|
|||
gr.Dropdown.update(choices=None, value=None, interactive=False) # Sub Folder List
|
||||
)
|
||||
|
||||
def get_headers():
|
||||
def get_proxies():
|
||||
custom_proxy = getattr(opts, "custom_civitai_proxy", "")
|
||||
disable_ssl = getattr(opts, "disable_sll_proxy", False)
|
||||
cabundle_path = getattr(opts, "cabundle_path_proxy", "")
|
||||
|
||||
ssl = True
|
||||
proxies = {}
|
||||
if custom_proxy:
|
||||
if not disable_ssl:
|
||||
if cabundle_path:
|
||||
ssl = os.path(cabundle_path)
|
||||
else:
|
||||
ssl = False
|
||||
proxies = {
|
||||
'http': custom_proxy,
|
||||
'https': custom_proxy,
|
||||
}
|
||||
return proxies, ssl
|
||||
|
||||
def get_headers(referer=None, no_api=None):
|
||||
|
||||
api_key = getattr(opts, "custom_api_key", "")
|
||||
try:
|
||||
user_agent = UserAgent().chrome
|
||||
except ImportError:
|
||||
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
|
||||
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
|
||||
headers = {
|
||||
'User-Agent': user_agent,
|
||||
'Sec-Ch-Ua': '"Brave";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
|
||||
'Sec-Ch-Ua-Mobile': '?0',
|
||||
'Sec-Ch-Ua-Platform': '"Windows"',
|
||||
'Sec-Fetch-Dest': 'document',
|
||||
'Sec-Fetch-Mode': 'navigate',
|
||||
'Sec-Fetch-Site': 'none',
|
||||
'Sec-Fetch-User': '?1',
|
||||
'Sec-Gpc': '1',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
"Connection": "keep-alive",
|
||||
"Sec-Ch-Ua-Platform": "Windows",
|
||||
"User-Agent": user_agent,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
if api_key:
|
||||
if referer:
|
||||
headers['Referer'] = f"https://civitai.com/models/{referer}"
|
||||
if api_key and not no_api:
|
||||
headers['Authorization'] = f'Bearer {api_key}'
|
||||
|
||||
return headers
|
||||
|
||||
def request_civit_api(api_url=None):
|
||||
headers = get_headers()
|
||||
proxies, ssl = get_proxies()
|
||||
try:
|
||||
response = requests.get(api_url, headers=headers, timeout=(10, 30))
|
||||
response = requests.get(api_url, headers=headers, timeout=(60,30), proxies=proxies, verify=ssl)
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error: {e}")
|
||||
return "timeout"
|
||||
return "error"
|
||||
else:
|
||||
response.encoding = "utf-8"
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -68,7 +68,10 @@ def start_aria2_rpc():
|
|||
try:
|
||||
show_log = getattr(opts, "show_log", False)
|
||||
aria2_flags = getattr(opts, "aria2_flags", "")
|
||||
cmd = f'"{aria2}" --enable-rpc --rpc-listen-all --rpc-listen-port=24000 --rpc-secret {rpc_secret} --check-certificate=false --ca-certificate=" " --file-allocation=none {aria2_flags}'
|
||||
custom_proxy = getattr(opts, "custom_proxy", "")
|
||||
if custom_proxy:
|
||||
custom_proxy = f"--all-proxy={custom_proxy} "
|
||||
cmd = f'"{aria2}" --enable-rpc --rpc-listen-all --rpc-listen-port=24000 --rpc-secret {rpc_secret} --check-certificate=false --ca-certificate=" " {custom_proxy}--file-allocation=none {aria2_flags}'
|
||||
subprocess_args = {'shell': True}
|
||||
if not show_log:
|
||||
subprocess_args.update({'stdout': subprocess.DEVNULL, 'stderr': subprocess.DEVNULL})
|
||||
|
|
@ -323,10 +326,11 @@ def convert_size(size):
|
|||
size /= 1024
|
||||
return f"{size:.2f} GB"
|
||||
|
||||
def get_download_link(url):
|
||||
headers = _api.get_headers()
|
||||
def get_download_link(url, model_id):
|
||||
headers = _api.get_headers(model_id)
|
||||
proxies, ssl = _api.get_proxies()
|
||||
|
||||
response = requests.get(url, headers=headers, allow_redirects=False)
|
||||
response = requests.get(url, headers=headers, allow_redirects=False, proxies=proxies, verify=ssl)
|
||||
|
||||
if 300 <= response.status_code <= 308:
|
||||
if "login?returnUrl" in response.text and "reason=download-auth" in response.text:
|
||||
|
|
@ -337,7 +341,7 @@ def get_download_link(url):
|
|||
else:
|
||||
return None
|
||||
|
||||
def download_file(url, file_path, install_path, progress=gr.Progress() if queue else None):
|
||||
def download_file(url, file_path, install_path, model_id, progress=gr.Progress() if queue else None):
|
||||
try:
|
||||
disable_dns = getattr(opts, "disable_dns", False)
|
||||
split_aria2 = getattr(opts, "split_aria2", 64)
|
||||
|
|
@ -347,7 +351,7 @@ def download_file(url, file_path, install_path, progress=gr.Progress() if queue
|
|||
|
||||
file_name = os.path.basename(file_path)
|
||||
|
||||
download_link = get_download_link(url)
|
||||
download_link = get_download_link(url, model_id)
|
||||
if not download_link:
|
||||
print(f'File: "{file_name}" not found on CivitAI servers, it looks like the file is not available for download.')
|
||||
gl.download_fail = True
|
||||
|
|
@ -485,7 +489,7 @@ def info_to_json(install_path, model_id, model_sha256, unpackList=None):
|
|||
with open(json_file, 'w', encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
def download_file_old(url, file_path, progress=gr.Progress() if queue else None):
|
||||
def download_file_old(url, file_path, model_id, progress=gr.Progress() if queue else None):
|
||||
try:
|
||||
gl.download_fail = False
|
||||
max_retries = 5
|
||||
|
|
@ -499,7 +503,7 @@ def download_file_old(url, file_path, progress=gr.Progress() if queue else None)
|
|||
last_update_time = 0
|
||||
update_interval = 0.25
|
||||
|
||||
download_link = get_download_link(url)
|
||||
download_link = get_download_link(url, model_id)
|
||||
if not download_link:
|
||||
print(f'File: "{file_name_display}" not found on CivitAI servers, it looks like the file is not available for download.')
|
||||
if progress != None:
|
||||
|
|
@ -516,6 +520,9 @@ def download_file_old(url, file_path, progress=gr.Progress() if queue else None)
|
|||
time.sleep(5)
|
||||
return
|
||||
|
||||
headers = _api.get_headers(model_id, True)
|
||||
proxies, ssl = _api.get_proxies()
|
||||
|
||||
while True:
|
||||
if gl.cancel_status:
|
||||
if progress != None:
|
||||
|
|
@ -523,9 +530,8 @@ def download_file_old(url, file_path, progress=gr.Progress() if queue else None)
|
|||
return
|
||||
if os.path.exists(file_path):
|
||||
downloaded_size = os.path.getsize(file_path)
|
||||
headers = {"Range": f"bytes={downloaded_size}-"}
|
||||
else:
|
||||
headers = {}
|
||||
headers['Range'] = f"bytes={downloaded_size}-"
|
||||
|
||||
with open(file_path, "ab") as f:
|
||||
while gl.isDownloading:
|
||||
try:
|
||||
|
|
@ -538,7 +544,7 @@ def download_file_old(url, file_path, progress=gr.Progress() if queue else None)
|
|||
if progress != None:
|
||||
progress(0, desc=f"Download cancelled.")
|
||||
return
|
||||
response = requests.get(download_link, headers=headers, stream=True, timeout=4)
|
||||
response = requests.get(download_link, headers=headers, stream=True, timeout=10, proxies=proxies, verify=ssl)
|
||||
if response.status_code == 404:
|
||||
if progress != None:
|
||||
progress(0, desc=f"Encountered an error during download of: {file_name_display}, file is not found on CivitAI servers.")
|
||||
|
|
@ -645,9 +651,9 @@ def download_create_thread(download_finish, queue_trigger, progress=gr.Progress(
|
|||
path_to_new_file = os.path.join(item['install_path'], item['model_filename'])
|
||||
|
||||
if use_aria2 and os_type != 'Darwin':
|
||||
thread = threading.Thread(target=download_file, args=(item['dl_url'], path_to_new_file, item['install_path'], progress))
|
||||
thread = threading.Thread(target=download_file, args=(item['dl_url'], path_to_new_file, item['install_path'], item['model_id'], progress))
|
||||
else:
|
||||
thread = threading.Thread(target=download_file_old, args=(item['dl_url'], path_to_new_file, progress))
|
||||
thread = threading.Thread(target=download_file_old, args=(item['dl_url'], path_to_new_file, item['model_id'], progress))
|
||||
thread.start()
|
||||
thread.join()
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ def delete_associated_files(directory, base_name):
|
|||
print(f"Associated file deleted: {path_to_delete}")
|
||||
|
||||
def save_preview(file_path, api_response, overwrite_toggle=False, sha256=None):
|
||||
proxies, ssl = _api.get_proxies()
|
||||
json_file = os.path.splitext(file_path)[0] + ".json"
|
||||
install_path, file_name = os.path.split(file_path)
|
||||
name = os.path.splitext(file_name)[0]
|
||||
|
|
@ -191,7 +192,7 @@ def save_preview(file_path, api_response, overwrite_toggle=False, sha256=None):
|
|||
if image["type"] == "image":
|
||||
url_with_width = re.sub(r'/width=\d+', f'/width={image["width"]}', image["url"])
|
||||
|
||||
response = requests.get(url_with_width)
|
||||
response = requests.get(url_with_width, proxies=proxies, verify=ssl)
|
||||
if response.status_code == 200:
|
||||
with open(image_path, 'wb') as img_file:
|
||||
img_file.write(response.content)
|
||||
|
|
@ -373,6 +374,7 @@ def model_from_sent(model_name, content_type, tile_count):
|
|||
not_found = div + "Model ID not found.<br>Maybe the model doesn\'t exist on CivitAI?</div>"
|
||||
path_not_found = div + "Model ID not found.<br>Could not locate the model path.</div>"
|
||||
offline = div + "CivitAI failed to respond.<br>The servers are likely offline."
|
||||
error = div + "CivitAI failed to respond due to an error.<br>Check the logs for more details."
|
||||
|
||||
model_name = re.sub(r'\.\d{3}$', '', model_name)
|
||||
content_type = re.sub(r'\.\d{3}$', '', content_type)
|
||||
|
|
@ -426,22 +428,24 @@ def model_from_sent(model_name, content_type, tile_count):
|
|||
|
||||
if json_data == "timeout":
|
||||
output_html = offline
|
||||
if json_data != None and json_data != "timeout":
|
||||
if json_data == "error":
|
||||
output_html = error
|
||||
if json_data != None and json_data != "timeout" and json_data != "error":
|
||||
model_versions = _api.update_model_versions(modelID, json_data)
|
||||
output_html = _api.update_model_info(None, model_versions.get('value'), True, modelID, json_data)
|
||||
output_html = _api.update_model_info(None, model_versions.get('value'), True, modelID, json_data, True)
|
||||
|
||||
css_path = Path(__file__).resolve().parents[1] / "style_html.css"
|
||||
with open(css_path, 'r', encoding='utf-8') as css_file:
|
||||
css = css_file.read()
|
||||
replacements = {
|
||||
'#0b0f19': 'var(--body-background-fill)',
|
||||
'#0b0f19': 'var(--neutral-950)',
|
||||
'#F3F4F6': 'var(--body-text-color)',
|
||||
'white': 'var(--body-text-color)',
|
||||
'#80a6c8': 'var(--secondary-300)',
|
||||
'#60A5FA': 'var(--link-text-color-hover)',
|
||||
'#1F2937': 'var(--input-background-fill)',
|
||||
'#1F2937': 'var(--neutral-700)',
|
||||
'#374151': 'var(--input-border-color)',
|
||||
'#111827': 'var(--error-background-fill)',
|
||||
'#111827': 'var(--neutral-800)',
|
||||
'top: 50%;': '',
|
||||
'padding-top: 0px;': 'padding-top: 475px;',
|
||||
'.civitai_txt2img': '.civitai_placeholder'
|
||||
|
|
@ -554,6 +558,7 @@ def save_model_info(install_path, file_name, sub_folder, sha256=None, preview_ht
|
|||
|
||||
|
||||
def find_and_save(api_response, sha256=None, file_name=None, json_file=None, no_hash=None, overwrite_toggle=None):
|
||||
save_desc = getattr(opts, "model_desc_to_json", True)
|
||||
for item in api_response.get('items', []):
|
||||
for model_version in item.get('modelVersions', []):
|
||||
for file in model_version.get('files', []):
|
||||
|
|
@ -563,15 +568,11 @@ def find_and_save(api_response, sha256=None, file_name=None, json_file=None, no_
|
|||
if file_name == file_name_api if no_hash else sha256 == sha256_api:
|
||||
gl.json_info = item
|
||||
trained_words = model_version.get('trainedWords', [])
|
||||
model_id = model_version.get('modelId', '')
|
||||
|
||||
if model_id:
|
||||
model_url = f'Model URL: \"https://civitai.com/models/{model_id}\"\n'
|
||||
|
||||
if save_desc:
|
||||
description = item.get('description', '')
|
||||
if description != None:
|
||||
description = clean_description(description)
|
||||
description = model_url + description
|
||||
|
||||
base_model = model_version.get('baseModel', '')
|
||||
|
||||
|
|
@ -605,6 +606,7 @@ def find_and_save(api_response, sha256=None, file_name=None, json_file=None, no_
|
|||
if "activation text" not in content or not content["activation text"]:
|
||||
content["activation text"] = trained_tags
|
||||
changed = True
|
||||
if save_desc:
|
||||
if "description" not in content or not content["description"]:
|
||||
content["description"] = description
|
||||
changed = True
|
||||
|
|
@ -613,6 +615,7 @@ def find_and_save(api_response, sha256=None, file_name=None, json_file=None, no_
|
|||
changed = True
|
||||
else:
|
||||
content["activation text"] = trained_tags
|
||||
if save_desc:
|
||||
content["description"] = description
|
||||
content["sd version"] = base_model
|
||||
changed = True
|
||||
|
|
@ -620,7 +623,8 @@ def find_and_save(api_response, sha256=None, file_name=None, json_file=None, no_
|
|||
with open(json_file, 'w', encoding="utf-8") as f:
|
||||
json.dump(content, f, indent=4)
|
||||
|
||||
if changed: print(f"Model info saved to \"{json_file}\"")
|
||||
if changed:
|
||||
print(f"Model info saved to \"{json_file}\"")
|
||||
return "found"
|
||||
|
||||
return "not found"
|
||||
|
|
@ -651,10 +655,10 @@ def get_models(file_path, gen_hash=None):
|
|||
return modelId
|
||||
else:
|
||||
return None
|
||||
|
||||
proxies, ssl = _api.get_proxies()
|
||||
try:
|
||||
if not modelId or modelId == "Model not found":
|
||||
response = requests.get(by_hash, timeout=(10,30))
|
||||
response = requests.get(by_hash, timeout=(60,30), proxies=proxies, verify=ssl)
|
||||
if response.status_code == 200:
|
||||
api_response = response.json()
|
||||
if 'error' in api_response:
|
||||
|
|
@ -761,9 +765,9 @@ def get_content_choices(scan_choices=False):
|
|||
return content_list
|
||||
return content_list
|
||||
|
||||
def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish, overwrite_toggle, tile_count, gen_hash, progress=gr.Progress() if queue else None):
|
||||
def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish, overwrite_toggle, tile_count, gen_hash, create_html, progress=gr.Progress() if queue else None):
|
||||
global from_ver, from_installed, no_update
|
||||
update_log = getattr(opts, "update_log", True)
|
||||
proxies, ssl = _api.get_proxies()
|
||||
gl.scan_files = True
|
||||
no_update = False
|
||||
if from_ver:
|
||||
|
|
@ -777,7 +781,7 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
|
|||
|
||||
if not folders:
|
||||
if progress != None:
|
||||
progress(0, desc=f"No folder selected.")
|
||||
progress(0, desc=f"No model type selected.")
|
||||
no_update = True
|
||||
gl.scan_files = False
|
||||
from_ver, from_installed = False, False
|
||||
|
|
@ -857,13 +861,13 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
|
|||
model_id = get_models(file_path, gen_hash)
|
||||
if model_id == "offline":
|
||||
print("The CivitAI servers did not respond, unable to retrieve Model ID")
|
||||
elif model_id == "Model not found" and update_log:
|
||||
elif model_id == "Model not found":
|
||||
print(f"model: \"{file_name}\" not found on CivitAI servers.")
|
||||
elif model_id != None:
|
||||
all_model_ids.append(f"&ids={model_id}")
|
||||
all_ids.append(model_id)
|
||||
file_paths.append(file_path)
|
||||
elif not model_id and update_log:
|
||||
elif not model_id:
|
||||
print(f"model ID not found for: \"{file_name}\"")
|
||||
files_done += 1
|
||||
|
||||
|
|
@ -901,7 +905,7 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
|
|||
try:
|
||||
if progress is not None:
|
||||
progress(url_done / url_count, desc=f"Sending API request... {url_done}/{url_count}")
|
||||
response = requests.get(url, timeout=(10, 30))
|
||||
response = requests.get(url, timeout=(60,30), proxies=proxies, verify=ssl)
|
||||
if response.status_code == 200:
|
||||
api_response_json = response.json()
|
||||
|
||||
|
|
@ -947,7 +951,6 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
|
|||
all_model_ids = [model[0] for model in outdated_set]
|
||||
all_model_names = [model[1] for model in outdated_set]
|
||||
|
||||
if update_log:
|
||||
for model_name in all_model_names:
|
||||
print(f'"{model_name}" is currently outdated.')
|
||||
|
||||
|
|
@ -969,7 +972,7 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
|
|||
api_url = gl.url_list_with_numbers.get(1)
|
||||
|
||||
if not url_error:
|
||||
response = requests.get(api_url, timeout=(10,30))
|
||||
response = requests.get(api_url, timeout=(60,30), proxies=proxies, verify=ssl)
|
||||
try:
|
||||
if response.status_code == 200:
|
||||
response.encoding = "utf-8"
|
||||
|
|
@ -1017,7 +1020,10 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
|
|||
for file_path, id_value in zip(file_paths, all_ids):
|
||||
install_path, file_name = os.path.split(file_path)
|
||||
model_versions = _api.update_model_versions(id_value, api_response)
|
||||
preview_html = _api.update_model_info(None, model_versions.get('value'), True, id_value, api_response)
|
||||
if create_html:
|
||||
preview_html = _api.update_model_info(None, model_versions.get('value'), True, id_value, api_response, True)
|
||||
else:
|
||||
preview_html = None
|
||||
sub_folder = os.path.normpath(os.path.relpath(install_path, gl.main_folder))
|
||||
save_model_info(install_path, file_name, sub_folder, preview_html=preview_html, api_response=api_response, overwrite_toggle=overwrite_toggle)
|
||||
if progress != None:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
def init():
|
||||
import warnings
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
warnings.simplefilter('ignore', InsecureRequestWarning)
|
||||
|
||||
global download_queue, last_version, cancel_status, recent_model, json_data, json_info, main_folder, previous_inputs, download_fail, sortNewest, isDownloading, old_download, scan_files, ver_json, file_scan, url_list_with_numbers, print
|
||||
|
||||
cancel_status = None
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ def on_ui_tabs():
|
|||
base_filter = gr.Dropdown(label='Base model:', multiselect=True, choices=["SD 1.4","SD 1.5","SD 1.5 LCM","SD 2.0","SD 2.0 768","SD 2.1","SD 2.1 768","SD 2.1 Unclip","SDXL 0.9","SDXL 1.0","SDXL 1.0 LCM","SDXL Distilled","SDXL Turbo","SDXL Lightning","Stable Cascade","Pony","SVD","SVD XT","Playground v2","PixArt a","Other"], value=None, type="value", elem_id="centerText")
|
||||
with gr.Row():
|
||||
period_type = gr.Dropdown(label='Time period:', choices=["All Time", "Year", "Month", "Week", "Day"], value="All Time", type="value", elem_id="centerText")
|
||||
sort_type = gr.Dropdown(label='Sort by:', choices=["Newest","Most Downloaded","Highest Rated","Most Liked", "Most Buzz","Most Discussed","Most Collected","Most Images"], value="Most Downloaded", type="value", elem_id="centerText")
|
||||
sort_type = gr.Dropdown(label='Sort by:', choices=["Newest","Oldest","Most Downloaded","Highest Rated","Most Liked","Most Buzz","Most Discussed","Most Collected","Most Images"], value="Most Downloaded", type="value", elem_id="centerText")
|
||||
with gr.Row(elem_id=component_id):
|
||||
create_json = gr.Checkbox(label=f"Save info after download", value=True, elem_id=toggle1, min_width=171)
|
||||
show_nsfw = gr.Checkbox(label="NSFW content", value=False, elem_id=toggle2, min_width=107)
|
||||
|
|
@ -198,7 +198,7 @@ def on_ui_tabs():
|
|||
hide_installed = gr.Checkbox(label="Hide installed models", value=False, elem_id=toggle5, min_width=170)
|
||||
with gr.Row():
|
||||
size_slider = gr.Slider(minimum=4, maximum=20, value=8, step=0.25, label='Tile size:')
|
||||
tile_count_slider = gr.Slider(label="Tile count:", minimum=1, maximum=100, value=15, step=1, max_width=100)
|
||||
tile_count_slider = gr.Slider(label="Tile count:", minimum=1, maximum=100, value=15, step=1)
|
||||
with gr.Row(elem_id="save_set_box"):
|
||||
save_settings = gr.Button(value="Save settings as default", elem_id="save_set_btn")
|
||||
search_term = gr.Textbox(label="", placeholder="Search CivitAI", elem_id="searchBox")
|
||||
|
|
@ -229,7 +229,7 @@ def on_ui_tabs():
|
|||
with gr.Column(scale=4):
|
||||
trained_tags = gr.Textbox(label='Trained tags (if any):', value=None, interactive=False, lines=1)
|
||||
with gr.Column(scale=2, elem_id="spanWidth"):
|
||||
base_model = gr.Textbox(label='Base model: ', value='', interactive=False, lines=1, elem_id="baseMdl")
|
||||
base_model = gr.Textbox(label='Base model: ', value=None, interactive=False, lines=1, elem_id="baseMdl")
|
||||
model_filename = gr.Textbox(label="Model filename:", interactive=False, value=None)
|
||||
with gr.Row():
|
||||
save_info = gr.Button(value="Save model info", interactive=False)
|
||||
|
|
@ -248,10 +248,10 @@ def on_ui_tabs():
|
|||
with gr.Tab("Update Models"):
|
||||
with gr.Row():
|
||||
selected_tags = gr.CheckboxGroup(elem_id="selected_tags", label="Scan for:", choices=scan_choices)
|
||||
with gr.Row():
|
||||
overwrite_toggle = gr.Checkbox(elem_id="overwrite_toggle", label="Overwrite any existing previews, tags or descriptions.", value=True)
|
||||
with gr.Row():
|
||||
skip_hash_toggle = gr.Checkbox(elem_id="skip_hash_toggle", label="One-Time Hash Generation for externally downloaded models.", value=True)
|
||||
with gr.Row(elem_id="civitai_update_toggles"):
|
||||
overwrite_toggle = gr.Checkbox(elem_id="overwrite_toggle", label="Overwrite any existing previews, tags or descriptions.", value=True, min_width=300)
|
||||
skip_hash_toggle = gr.Checkbox(elem_id="skip_hash_toggle", label="One-Time Hash Generation for externally downloaded models.", value=True, min_width=300)
|
||||
do_html_gen = gr.Checkbox(elem_id="do_html_gen", label="Save HTML file for each model when updating info & tags (increases process time).", value=False, min_width=300)
|
||||
with gr.Row():
|
||||
save_all_tags = gr.Button(value="Update model info & tags", interactive=True, visible=True)
|
||||
cancel_all_tags = gr.Button(value="Cancel updating model info & tags", interactive=False, visible=False)
|
||||
|
|
@ -349,6 +349,7 @@ def on_ui_tabs():
|
|||
list_models.select(fn=None, inputs=list_models, _js="(list_models) => select_model(list_models)")
|
||||
|
||||
preview_html.change(fn=None, _js="() => adjustFilterBoxAndButtons()")
|
||||
preview_html.change(fn=None, _js="() => setDescriptionToggle()")
|
||||
|
||||
back_to_top.click(fn=None, _js="() => BackToTop()")
|
||||
|
||||
|
|
@ -421,13 +422,36 @@ def on_ui_tabs():
|
|||
list_html.change(fn=all_visible,inputs=list_html,outputs=select_all)
|
||||
|
||||
def update_models_dropdown(input):
|
||||
if not gl.json_data:
|
||||
return (
|
||||
gr.Dropdown.update(value=None, choices=[], interactive=False), # List models
|
||||
gr.Dropdown.update(value=None, choices=[], interactive=False), # List version
|
||||
gr.HTML.update(value=None), # Preview HTML
|
||||
gr.Textbox.update(value=None, interactive=False), # Trained Tags
|
||||
gr.Textbox.update(value=None, interactive=False), # Base Model
|
||||
gr.Textbox.update(value=None, interactive=False), # Model filename
|
||||
gr.Textbox.update(value=None, interactive=False), # Install path
|
||||
gr.Dropdown.update(value=None, choices=[], interactive=False), # Sub folder
|
||||
gr.Button.update(interactive=False), # Download model btn
|
||||
gr.Button.update(interactive=False), # Save image btn
|
||||
gr.Button.update(interactive=False, visible=False), # Delete model btn
|
||||
gr.Dropdown.update(value=None, choices=[], interactive=False), # File list
|
||||
gr.Textbox.update(value=None), # DL Url
|
||||
gr.Textbox.update(value=None), # Model ID
|
||||
gr.Textbox.update(value=None), # Current sha256
|
||||
gr.Button.update(interactive=False), # Save model info
|
||||
gr.HTML.update(value='<div style="font-size: 24px; text-align: center; margin: 50px;">Click the search icon to load models.<br>Use the filter icon to filter results.</div>') # Model list
|
||||
)
|
||||
|
||||
model_string = re.sub(r'\.\d{3}$', '', input)
|
||||
model_name, model_id = _api.extract_model_info(model_string)
|
||||
model_versions = _api.update_model_versions(model_id)
|
||||
(html, tags, base_mdl, DwnButton, SaveImages, DelButton, filelist, filename, dl_url, id, current_sha256, install_path, sub_folder) = _api.update_model_info(model_string, model_versions.get('value'))
|
||||
return (gr.Dropdown.update(value=model_string, interactive=True),
|
||||
model_versions,html,tags,base_mdl,filename,install_path,sub_folder,DwnButton,SaveImages,DelButton,filelist,dl_url,id,current_sha256,
|
||||
gr.Button.update(interactive=True))
|
||||
gr.Button.update(interactive=True),
|
||||
gr.HTML.update()
|
||||
)
|
||||
|
||||
model_select.change(
|
||||
fn=update_models_dropdown,
|
||||
|
|
@ -448,7 +472,8 @@ def on_ui_tabs():
|
|||
dl_url,
|
||||
model_id,
|
||||
current_sha256,
|
||||
save_info
|
||||
save_info,
|
||||
list_html
|
||||
]
|
||||
)
|
||||
|
||||
|
|
@ -687,7 +712,8 @@ def on_ui_tabs():
|
|||
preview_finish,
|
||||
overwrite_toggle,
|
||||
tile_count_slider,
|
||||
skip_hash_toggle
|
||||
skip_hash_toggle,
|
||||
do_html_gen
|
||||
]
|
||||
|
||||
load_to_browser_inputs = [
|
||||
|
|
@ -927,7 +953,7 @@ def subfolder_list(folder, desc=None):
|
|||
if insert_sub_3:
|
||||
sub_folders.insert(3, f"{os.sep}Base model{os.sep}Author name{os.sep}Model name")
|
||||
if insert_sub_4:
|
||||
sub_folders.insert(4, f"{os.sep}Base model{os.sep}Author name{os.sep}Model name{os.sep}Version name")
|
||||
sub_folders.insert(4, f"{os.sep}Base model{os.sep}Author name{os.sep}Model name{os.sep}Model version")
|
||||
if insert_sub_5:
|
||||
sub_folders.insert(5, f"{os.sep}Base model{os.sep}Model name")
|
||||
if insert_sub_6:
|
||||
|
|
@ -1108,6 +1134,16 @@ def on_ui_settings():
|
|||
).info("Uses the matching local HTML file when pressing CivitAI button on model cards in txt2img and img2img")
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"local_path_in_html",
|
||||
shared.OptionInfo(
|
||||
False,
|
||||
"Use local images in the HTML",
|
||||
section=browser,
|
||||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).info("Only works if all images of the corresponding model are downloaded")
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"page_header",
|
||||
shared.OptionInfo(
|
||||
|
|
@ -1139,13 +1175,13 @@ def on_ui_settings():
|
|||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"update_log",
|
||||
"model_desc_to_json",
|
||||
shared.OptionInfo(
|
||||
True,
|
||||
'Show console logs during update scanning',
|
||||
'Save model description to json',
|
||||
section=browser,
|
||||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).info('Shows the "is currently outdated" messages in the console when scanning models for available updates')
|
||||
).info('This saves the models description to the description field on model cards')
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
|
|
@ -1168,16 +1204,6 @@ def on_ui_settings():
|
|||
).info("Will append any content type and sub folders to the custom path.")
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"local_path_in_html",
|
||||
shared.OptionInfo(
|
||||
False,
|
||||
"Use local images in the HTML",
|
||||
section=browser,
|
||||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).info("Only works if all images of the corresponding model are downloaded")
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"save_to_custom",
|
||||
shared.OptionInfo(
|
||||
|
|
@ -1188,6 +1214,40 @@ def on_ui_settings():
|
|||
)
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"custom_civitai_proxy",
|
||||
shared.OptionInfo(
|
||||
r"",
|
||||
"Proxy address",
|
||||
gr.Textbox,
|
||||
{"placeholder": "socks4://0.0.0.0:00000 | socks5://0.0.0.0:00000"},
|
||||
section=browser,
|
||||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).info("Only works with proxies that support HTTPS, Requires UI reload for Aria2 compatibility")
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"cabundle_path_proxy",
|
||||
shared.OptionInfo(
|
||||
r"",
|
||||
"Path to custom CA Bundle",
|
||||
gr.Textbox,
|
||||
{"placeholder": "/path/to/custom/cabundle.pem"},
|
||||
section=browser,
|
||||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).info("Specify custom CA bundle for SSL certificate checks if required")
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"disable_sll_proxy",
|
||||
shared.OptionInfo(
|
||||
False,
|
||||
"Disable SSL certificate checks",
|
||||
section=browser,
|
||||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).info("Not recommended for security, may be required if you do not have the correct CA Bundle available")
|
||||
)
|
||||
|
||||
id_and_sub_options = {
|
||||
"1" : f"{os.sep}Base model",
|
||||
"2" : f"{os.sep}Base model{os.sep}Author name",
|
||||
|
|
|
|||
81
style.css
81
style.css
|
|
@ -130,7 +130,18 @@
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
#toggle1L, #toggle2L, #toggle3L, #toggle4L, #toggle4L_api, #toggle5L, #overwrite_toggle, #skip_hash_toggle{
|
||||
#civitai_update_toggles > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#civitai_update_toggles {
|
||||
margin-top: calc(-1 * var(--layout-gap));
|
||||
margin-bottom: var(--layout-gap);
|
||||
}
|
||||
|
||||
#toggle1L, #toggle2L, #toggle3L, #toggle4L, #toggle4L_api, #toggle5L,
|
||||
#overwrite_toggle, #skip_hash_toggle, #do_html_gen {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
|
@ -325,7 +336,7 @@
|
|||
.civitai-tag,
|
||||
.civitai-meta,
|
||||
.civitai-meta-btn {
|
||||
background-color: var(--error-background-fill);
|
||||
background-color: var(--neutral-800);
|
||||
border-radius: 8px;
|
||||
padding: 4px 6px;
|
||||
border: 1px solid var(--input-border-color);
|
||||
|
|
@ -333,7 +344,7 @@
|
|||
|
||||
.civitai-meta-btn:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--input-background-fill);
|
||||
background-color: var(--neutral-700);
|
||||
}
|
||||
|
||||
#select_all_models_container {
|
||||
|
|
@ -592,9 +603,67 @@
|
|||
|
||||
#civitai_preview_html .model-description {
|
||||
border-top: 1px solid;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
#civitai_preview_html .model-description::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 75px;
|
||||
background: linear-gradient(to bottom, rgb(255 255 255 / 0%), var(--background-fill-primary));
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.description-toggle-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:checked + .model-description {
|
||||
max-height: unset !important;
|
||||
position: unset !important;
|
||||
}
|
||||
|
||||
.model-description + .description-toggle-label::before {
|
||||
content: "❯";
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.model-description + .description-toggle-label {
|
||||
display: flex;
|
||||
padding: 10px 0px 0px 0px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:checked + .model-description + .description-toggle-label::before {
|
||||
transform: rotate(-90deg);
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:checked + .model-description + .description-toggle-label::after {
|
||||
content: "Show Less...";
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:not(:checked) + .model-description + .description-toggle-label::after {
|
||||
content: "Show All...";
|
||||
}
|
||||
/*------------------------------------------*/
|
||||
/*End CSS accordion for toggling description*/
|
||||
|
||||
/*Avatar CSS mostly copied from CivitAI, but 48px instead of 32px*/
|
||||
#civitai_preview_html .avatar {
|
||||
|
|
|
|||
|
|
@ -162,6 +162,65 @@ a:hover {
|
|||
border-style: none;
|
||||
}
|
||||
|
||||
.model-description {
|
||||
border-top: 1px solid;
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.model-description::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 75px;
|
||||
background: linear-gradient(to bottom, rgb(255 255 255 / 0%), #0b0f19);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.description-toggle-label {
|
||||
display: flex;
|
||||
padding: 10px 0px 0px 0px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
font-size: large;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:checked + .model-description {
|
||||
max-height: none !important;
|
||||
position: unset !important;
|
||||
}
|
||||
|
||||
.model-description + .description-toggle-label::before {
|
||||
content: "❯";
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:checked + .model-description + .description-toggle-label::before {
|
||||
transform: rotate(-90deg);
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:checked + .model-description + .description-toggle-label::after {
|
||||
content: "Show Less...";
|
||||
}
|
||||
|
||||
.description-toggle-checkbox:not(:checked) + .model-description + .description-toggle-label::after {
|
||||
content: "Show All...";
|
||||
}
|
||||
|
||||
/*CSS accordion for toggling extra metadata*/
|
||||
/*-----------------------------------------*/
|
||||
.accordionCheckbox {
|
||||
|
|
|
|||
Loading…
Reference in New Issue