parent
177ce5d155
commit
e4ef29afc1
14
README.md
14
README.md
|
|
@ -100,6 +100,20 @@ https://github.com/BlafKing/sd-civitai-browser-plus/assets/9644716/44c5c7a0-4854
|
|||
|
||||
# Changelog 📋
|
||||
|
||||
<h3>v3.3.1</h3>
|
||||
|
||||
* Feature: Ability to send individual parts of image generation data to txt2img.
|
||||
* Feature: Added compatibility for [stable-diffusion-webui-forge](https://github.com/lllyasviel/stable-diffusion-webui-forge) fork.
|
||||
* New setting: Use local images in the HTML
|
||||
- Does not work in combination with the "Use local HTML file for model info" option!
|
||||
* New setting: Store the HTML and api_info in the custom images location
|
||||
* Bug fix: New HTML model info now scales with width so it should always fit.
|
||||
* Bug fix: Various bug fixes to the "Update model info & tags" function.
|
||||
* Bug fix: Auto save all images now uses correctly uses custom image path if set.
|
||||
* Bug fix: "Save model info" button should no longer return errors.
|
||||
* Bug fix: Old download method (non Aria2) should now work again.
|
||||
|
||||
---
|
||||
<h3>v3.3.0</h3>
|
||||
|
||||
* Feature: New txt2img and img2img model info overlay on CivitAI button press.
|
||||
|
|
|
|||
|
|
@ -465,15 +465,14 @@ function createCardButtons(event) {
|
|||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', createCardButtons);
|
||||
// Sends the selected model list to a python function
|
||||
|
||||
function modelInfoPopUp(modelName, content_type) {
|
||||
select_model(modelName, null, true, content_type);
|
||||
|
||||
// Create the overlay
|
||||
var overlay = document.createElement('div');
|
||||
overlay.classList.add('civitaiOverlayGlobal');
|
||||
overlay.classList.add('civitai-overlay');
|
||||
overlay.style.position = 'fixed';
|
||||
overlay.style.top = '0';
|
||||
overlay.style.left = '0';
|
||||
|
|
@ -483,38 +482,13 @@ function modelInfoPopUp(modelName, content_type) {
|
|||
overlay.style.zIndex = '1001';
|
||||
overlay.style.overflowY = 'auto';
|
||||
|
||||
// Create the pop-up window
|
||||
var popup = document.createElement('div');
|
||||
popup.classList.add('civitaiOverlay');
|
||||
popup.style.display = 'flex';
|
||||
popup.style.justifyContent = 'center';
|
||||
popup.style.position = 'absolute';
|
||||
popup.style.top = '50%';
|
||||
popup.style.left = '50%';
|
||||
popup.style.width = '56em';
|
||||
popup.style.transform = 'translate(-50%, -50%)';
|
||||
popup.style.background = 'var(--body-background-fill)';
|
||||
popup.style.padding = '2em';
|
||||
popup.style.borderRadius = 'var(--block-radius)';
|
||||
popup.style.borderStyle = 'solid';
|
||||
popup.style.borderWidth = 'var(--block-border-width)';
|
||||
popup.style.borderColor = 'var(--block-border-color)';
|
||||
popup.style.zIndex = '1001';
|
||||
|
||||
// Add content to the popup
|
||||
var popupContent = document.createElement('div'); // Change from <p> to <div>
|
||||
popupContent.classList.add('civitaiLoadingText');
|
||||
popupContent.textContent = 'Loading model info, please wait!';
|
||||
popupContent.style.fontSize = '24px';
|
||||
popupContent.style.color = 'white';
|
||||
popupContent.style.fontFamily = 'var(--font)';
|
||||
popup.appendChild(popupContent);
|
||||
|
||||
// Create the close button
|
||||
var closeButton = document.createElement('div');
|
||||
closeButton.classList.add('civitai-overlay-close');
|
||||
closeButton.textContent = '×';
|
||||
closeButton.style.zIndex = '1011';
|
||||
closeButton.style.position = 'fixed';
|
||||
closeButton.style.right = '0.25em';
|
||||
closeButton.style.right = '22px';
|
||||
closeButton.style.top = '0';
|
||||
closeButton.style.cursor = 'pointer';
|
||||
closeButton.style.color = 'white';
|
||||
|
|
@ -522,29 +496,63 @@ function modelInfoPopUp(modelName, content_type) {
|
|||
closeButton.addEventListener('click', hidePopup);
|
||||
document.addEventListener('keydown', handleKeyPress);
|
||||
|
||||
// Append the close button to the overlay
|
||||
overlay.appendChild(closeButton);
|
||||
// Create the pop-up window
|
||||
var inner = document.createElement('div');
|
||||
inner.classList.add('civitai-overlay-inner');
|
||||
inner.style.position = 'absolute';
|
||||
inner.style.top = '50%';
|
||||
inner.style.left = '50%';
|
||||
inner.style.width = 'auto';
|
||||
inner.style.transform = 'translate(-50%, -50%)';
|
||||
inner.style.background = 'var(--body-background-fill)';
|
||||
inner.style.padding = '2em';
|
||||
inner.style.borderRadius = 'var(--block-radius)';
|
||||
inner.style.borderStyle = 'solid';
|
||||
inner.style.borderWidth = 'var(--block-border-width)';
|
||||
inner.style.borderColor = 'var(--block-border-color)';
|
||||
inner.style.zIndex = '1001';
|
||||
|
||||
// Append the popup to the overlay
|
||||
overlay.appendChild(popup);
|
||||
// Placeholder model content until model is loaded by other function
|
||||
var modelInfo = document.createElement('div');
|
||||
modelInfo.classList.add('civitai-overlay-text');
|
||||
modelInfo.textContent = 'Loading model info, please wait!';
|
||||
modelInfo.style.fontSize = '24px';
|
||||
modelInfo.style.color = 'white';
|
||||
modelInfo.style.fontFamily = 'var(--font)';
|
||||
|
||||
// Append the overlay to the body
|
||||
document.body.style.overflow = 'hidden'; // Prevent scrolling on the main page
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.body.appendChild(overlay);
|
||||
overlay.appendChild(closeButton);
|
||||
overlay.appendChild(inner);
|
||||
inner.appendChild(modelInfo);
|
||||
|
||||
overlay.addEventListener('click', function (event) {
|
||||
if (event.target === overlay) {
|
||||
hidePopup();
|
||||
}
|
||||
});
|
||||
|
||||
setDynamicWidth(inner);
|
||||
|
||||
// Update width on window resize
|
||||
window.addEventListener('resize', function() {
|
||||
setDynamicWidth(inner);
|
||||
});
|
||||
}
|
||||
|
||||
function setDynamicWidth(inner) {
|
||||
var windowWidth = window.innerWidth;
|
||||
var dynamicWidth = Math.min(Math.max(windowWidth - 150, 350), 900);
|
||||
inner.style.width = dynamicWidth + 'px';
|
||||
}
|
||||
|
||||
// Function to hide the popup
|
||||
function hidePopup() {
|
||||
var overlay = document.querySelector('.civitaiOverlayGlobal');
|
||||
var overlay = document.querySelector('.civitai-overlay');
|
||||
if (overlay) {
|
||||
document.body.removeChild(overlay);
|
||||
document.body.style.overflow = 'auto';
|
||||
window.removeEventListener('resize', setDynamicWidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -555,6 +563,102 @@ function handleKeyPress(event) {
|
|||
}
|
||||
}
|
||||
|
||||
function inputHTMLPreviewContent(html_input) {
|
||||
var inner = document.querySelector('.civitai-overlay-inner')
|
||||
let startIndex = html_input.indexOf("'value': '");
|
||||
if (startIndex !== -1) {
|
||||
startIndex += "'value': '".length;
|
||||
const endIndex = html_input.indexOf("', 'type': None,", startIndex);
|
||||
if (endIndex !== -1) {
|
||||
let extractedText = html_input.substring(startIndex, endIndex);
|
||||
var modelIdNotFound = extractedText.includes(">Model ID not found.<br>The");
|
||||
|
||||
extractedText = extractedText.replace(/\\n\s*</g, '<');
|
||||
extractedText = extractedText.replace(/\\n/g, ' ');
|
||||
extractedText = extractedText.replace(/\\t/g, '');
|
||||
extractedText = extractedText.replace(/\\'/g, "'");
|
||||
|
||||
var overlayText = document.querySelector('.civitai-overlay-text');
|
||||
var modelInfo = document.createElement('div');
|
||||
|
||||
overlayText.parentNode.removeChild(overlayText);
|
||||
if (!modelIdNotFound) {
|
||||
inner.style.top = 0;
|
||||
inner.style.transform = 'translate(-50%, 0)';
|
||||
}
|
||||
modelInfo.innerHTML = extractedText;
|
||||
inner.appendChild(modelInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function metaToTxt2Img(type, element) {
|
||||
const genButton = gradioApp().querySelector('#txt2img_extra_tabs > div > button')
|
||||
let input = element.querySelector('dd').textContent;
|
||||
let inf;
|
||||
if (input.endsWith(',')) {
|
||||
inf = input + ' ';
|
||||
} else {
|
||||
inf = input + ', ';
|
||||
}
|
||||
let is_positive = false
|
||||
let is_negative = false
|
||||
switch(type) {
|
||||
case 'prompt':
|
||||
is_positive = true
|
||||
break;
|
||||
case 'negativePrompt':
|
||||
inf = 'Negative prompt: ' + inf;
|
||||
is_negative = true
|
||||
break;
|
||||
case 'seed':
|
||||
inf = 'Seed: ' + inf;
|
||||
inf = inf + inf + inf;
|
||||
break;
|
||||
case 'Size':
|
||||
inf = 'Size: ' + inf;
|
||||
inf = inf + inf + inf;
|
||||
break;
|
||||
case 'Model':
|
||||
inf = 'Model: ' + inf;
|
||||
inf = inf + inf + inf;
|
||||
break;
|
||||
case 'clipSkip':
|
||||
inf = 'Clip skip: ' + inf;
|
||||
inf = inf + inf + inf;
|
||||
break;
|
||||
case 'sampler':
|
||||
inf = 'Sampler: ' + inf;
|
||||
inf = inf + inf + inf;
|
||||
break;
|
||||
case 'steps':
|
||||
inf = 'Steps: ' + inf;
|
||||
inf = inf + inf + inf;
|
||||
break;
|
||||
case 'cfgScale':
|
||||
inf = 'CFG scale: ' + inf;
|
||||
inf = inf + inf + inf;
|
||||
break;
|
||||
}
|
||||
const prompt = gradioApp().querySelector('#txt2img_prompt textarea');
|
||||
const neg_prompt = gradioApp().querySelector('#txt2img_neg_prompt textarea');
|
||||
const cfg_scale = gradioApp().querySelector('#txt2img_cfg_scale > div:nth-child(2) > div > input');
|
||||
let final = '';
|
||||
let cfg = 'CFG scale: ' + cfg_scale.value + ", "
|
||||
let prompt_addon = cfg + cfg + cfg
|
||||
if (is_positive) {
|
||||
final = inf + "\nNegative prompt: " + neg_prompt.value + "\n" + prompt_addon;
|
||||
} else if (is_negative) {
|
||||
final = prompt.value + "\n" + inf + "\n" + prompt_addon;
|
||||
} else {
|
||||
final = prompt.value + "\nNegative prompt: " + neg_prompt.value + "\n" + inf;
|
||||
}
|
||||
console.log(final)
|
||||
genInfo_to_txt2img(final, false)
|
||||
hidePopup();
|
||||
sendClick(genButton);
|
||||
}
|
||||
|
||||
// Creates a list of the selected models
|
||||
var selectedModels = [];
|
||||
var selectedTypes = [];
|
||||
|
|
@ -605,37 +709,6 @@ document.addEventListener('click', function(event) {
|
|||
}
|
||||
}, true);
|
||||
|
||||
function inputHTMLPreviewContent(html_input) {
|
||||
var overlay = document.querySelector('.civitaiOverlay')
|
||||
let startIndex = html_input.indexOf("'value': '");
|
||||
if (startIndex !== -1) {
|
||||
startIndex += "'value': '".length;
|
||||
const endIndex = html_input.indexOf("', 'type': None,", startIndex);
|
||||
if (endIndex !== -1) {
|
||||
let extractedText = html_input.substring(startIndex, endIndex);
|
||||
var modelIdNotFound = extractedText.includes(">Model ID not found.<br>Maybe");
|
||||
|
||||
extractedText = extractedText.replace(/\\n\s*</g, '<');
|
||||
extractedText = extractedText.replace(/\\n/g, ' ');
|
||||
extractedText = extractedText.replace(/\\t/g, '');
|
||||
|
||||
var loadingText = document.querySelector('.civitaiLoadingText');
|
||||
var modelInfo = document.createElement('div');
|
||||
|
||||
loadingText.parentNode.removeChild(loadingText);
|
||||
if (!modelIdNotFound) {
|
||||
overlay.style.top = 0;
|
||||
overlay.style.transform = 'translate(-50%, 0)';
|
||||
extractedText = extractedText.replace(/\\'/g, "");
|
||||
} else {
|
||||
extractedText = extractedText.replace(/\\'/g, "'");
|
||||
}
|
||||
modelInfo.innerHTML = extractedText;
|
||||
overlay.appendChild(modelInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CivitAI Link Button Creation
|
||||
function onEditButtonCardClick(nameValue) {
|
||||
var checkInterval = setInterval(function() {
|
||||
|
|
@ -720,14 +793,12 @@ function sendImgUrl(image_url) {
|
|||
}
|
||||
|
||||
// Sends txt2img info to txt2img tab
|
||||
function genInfo_to_txt2img(genInfo) {
|
||||
function genInfo_to_txt2img(genInfo, do_slice=true) {
|
||||
let insert = gradioApp().querySelector('#txt2img_prompt textarea');
|
||||
let pasteButton = gradioApp().querySelector('#paste');
|
||||
if (genInfo) {
|
||||
var cleanGenInfo = genInfo.slice(5);
|
||||
insert.value = cleanGenInfo;
|
||||
insert.value = do_slice ? genInfo.slice(5) : genInfo;
|
||||
insert.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
|
||||
pasteButton.dispatchEvent(new Event('click', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -669,6 +669,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
dl_dict = {}
|
||||
is_LORA = False
|
||||
file_list = []
|
||||
file_dict = []
|
||||
default_file = None
|
||||
model_filename = None
|
||||
sha256_value = None
|
||||
|
|
@ -688,6 +689,9 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
uploader_avatar = f'<div class="avatar"><img src={uploader_avatar}></div>'
|
||||
tags = item.get('tags', "")
|
||||
model_desc = item.get('description', "")
|
||||
if model_desc:
|
||||
model_desc = model_desc.replace('<img', '<img style="max-width: -webkit-fill-available;"')
|
||||
model_desc = model_desc.replace('<code>', '<code style="text-wrap: wrap">')
|
||||
if model_version is None:
|
||||
selected_version = item['modelVersions'][0]
|
||||
else:
|
||||
|
|
@ -721,6 +725,10 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
unique_file_name = f"{size} {format} {fp} ({filesize})"
|
||||
is_primary = file.get('primary', False)
|
||||
file_list.append(unique_file_name)
|
||||
file_dict.append({
|
||||
"format": format,
|
||||
"sizeKB": sizeKB
|
||||
})
|
||||
if is_primary:
|
||||
default_file = unique_file_name
|
||||
model_filename = file['name']
|
||||
|
|
@ -728,15 +736,22 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
gl.json_info = item
|
||||
sha256_value = file['hashes'].get('SHA256', 'Unknown')
|
||||
|
||||
if is_LORA and file_list:
|
||||
extracted_formats = [file.split(' ')[1] for file in file_list]
|
||||
|
||||
if "SafeTensor" in extracted_formats and "PickleTensor" in extracted_formats:
|
||||
if "PickleTensor" in file_list[0].split(' ')[1]:
|
||||
if float(file_list[0].split(' ')[0]) <= 100:
|
||||
safe_tensor_found = False
|
||||
pickle_tensor_found = False
|
||||
if is_LORA and file_dict:
|
||||
for file_info in file_dict:
|
||||
file_format = file_info.get("format", "")
|
||||
if "SafeTensor" in file_format:
|
||||
safe_tensor_found = True
|
||||
if "PickleTensor" in file_format:
|
||||
pickle_tensor_found = True
|
||||
|
||||
if safe_tensor_found and pickle_tensor_found:
|
||||
if "PickleTensor" in file_dict[0].get("format", ""):
|
||||
if file_dict[0].get("sizeKB", 0) <= 100:
|
||||
model_folder = os.path.join(contenttype_folder("TextualInversion"))
|
||||
|
||||
model_url = selected_version['downloadUrl']
|
||||
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>'
|
||||
for index, pic in enumerate(selected_version['images']):
|
||||
|
|
@ -783,7 +798,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
img_html += '</div>'
|
||||
|
||||
if meta:
|
||||
img_html += '<div style="margin:1em 0em 1em 1em;text-align:left;line-height:1.5em;" id="image_info"><dl>'
|
||||
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", "negativePrompt", "seed", "Size", "Model", "clipSkip", "sampler", "steps", "cfgScale"]
|
||||
preferred_order_lower = [key.lower() for key in preferred_order]
|
||||
|
|
@ -791,7 +806,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
for key in preferred_order:
|
||||
if key in meta:
|
||||
value = meta[key]
|
||||
img_html += f'<dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd>'
|
||||
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>'
|
||||
# Check if there are remaining keys in meta
|
||||
remaining_keys = [key for key in meta if key.lower() not in preferred_order_lower]
|
||||
|
||||
|
|
@ -806,7 +821,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
"""
|
||||
for key in remaining_keys:
|
||||
value = meta[key]
|
||||
img_html += f'<dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd>'
|
||||
img_html += f'<div><dt>{escape(str(key).capitalize())}</dt><dd>{escape(str(value))}</dd></div>'
|
||||
img_html = img_html + '</div></div></div>'
|
||||
|
||||
img_html += '</dl></div>'
|
||||
|
|
@ -844,8 +859,8 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
{tags_html}
|
||||
</div>
|
||||
</dd>
|
||||
<dt>Download Link</dt>
|
||||
<dd><a href={model_url} target="_blank">{model_url}</a></dd>
|
||||
{"<dt>Download Link</dt>" if model_url else ''}
|
||||
{f'<dd><a href={model_url} target="_blank">{model_url}</a></dd>' if model_url else ''}
|
||||
</dl>
|
||||
<div style="align-self:center; min-width:320px;">
|
||||
<div>
|
||||
|
|
@ -853,7 +868,7 @@ def update_model_info(model_string=None, model_version=None, only_html=False, in
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model-description">
|
||||
<div class="model-description" style="overflow-wrap: break-word;">
|
||||
<h2>Description</h2>
|
||||
{model_desc}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -108,8 +108,13 @@ def create_model_item(dl_url, model_filename, install_path, model_name, version_
|
|||
for item in gl.json_data['items']:
|
||||
if int(item['id']) == int(model_id):
|
||||
filtered_items.append(item)
|
||||
content_type = item['type']
|
||||
desc = item['description']
|
||||
main_folder = _api.contenttype_folder(content_type, desc)
|
||||
break
|
||||
|
||||
|
||||
sub_folder = os.path.normpath(os.path.relpath(install_path, main_folder))
|
||||
|
||||
model_json = {"items": filtered_items}
|
||||
model_versions = _api.update_model_versions(model_id)
|
||||
(preview_html,_,_,_,_,_,_,_,_,_,_,existing_path,_) = _api.update_model_info(None, model_versions.get('value'), False, model_id)
|
||||
|
|
@ -131,7 +136,8 @@ def create_model_item(dl_url, model_filename, install_path, model_name, version_
|
|||
"model_versions" : model_versions,
|
||||
"preview_html" : preview_html['value'],
|
||||
"existing_path": existing_path['value'],
|
||||
"from_batch" : from_batch
|
||||
"from_batch" : from_batch,
|
||||
"sub_folder" : sub_folder
|
||||
}
|
||||
|
||||
return item
|
||||
|
|
@ -639,12 +645,11 @@ def download_create_thread(download_finish, queue_trigger, progress=gr.Progress(
|
|||
print(f"Failed to extract {item['model_filename']} with error: {e}")
|
||||
if not gl.cancel_status:
|
||||
if item['create_json']:
|
||||
_file.save_model_info(item['install_path'], item['model_filename'], item['model_sha256'], item['preview_html'], api_response=item['model_json'])
|
||||
_file.save_model_info(item['install_path'], item['model_filename'], item['sub_folder'], item['model_sha256'], item['preview_html'], api_response=item['model_json'])
|
||||
info_to_json(path_to_new_file, item['model_id'], item['model_sha256'], unpackList)
|
||||
_file.save_preview(path_to_new_file, item['model_json'], True, item['model_sha256'])
|
||||
if save_all_images:
|
||||
_file.save_images(item['preview_html'], item['model_filename'], item['install_path'], )
|
||||
else:
|
||||
_file.save_preview(path_to_new_file, item['model_json'], True, item['model_sha256'])
|
||||
_file.save_images(item['preview_html'], item['model_filename'], item['install_path'], item['sub_folder'], api_response=item['model_json'])
|
||||
|
||||
base_name = os.path.splitext(item['model_filename'])[0]
|
||||
base_name_preview = base_name + '.preview'
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ def delete_model(delete_finish=None, model_filename=None, model_string=None, lis
|
|||
def delete_associated_files(directory, base_name):
|
||||
for file in os.listdir(directory):
|
||||
current_base_name, ext = os.path.splitext(file)
|
||||
if current_base_name == base_name or current_base_name == f"{base_name}.preview":
|
||||
if current_base_name == base_name or current_base_name == f"{base_name}.preview" or current_base_name == f"{base_name}.api_info":
|
||||
path_to_delete = os.path.join(directory, file)
|
||||
try:
|
||||
send2trash(path_to_delete)
|
||||
|
|
@ -203,25 +203,30 @@ def save_preview(file_path, api_response, overwrite_toggle=False, sha256=None):
|
|||
print(f"No preview images found for \"{name}\"")
|
||||
return
|
||||
|
||||
def save_images(preview_html, model_filename, install_path, sub_folder=None):
|
||||
def get_image_path(install_path, api_response, sub_folder):
|
||||
image_location = getattr(opts, "image_location", r"")
|
||||
sub_image_location = getattr(opts, "sub_image_location", True)
|
||||
image_path = install_path
|
||||
if api_response:
|
||||
json_info = api_response['items'][0]
|
||||
else:
|
||||
json_info = gl.json_info
|
||||
if image_location:
|
||||
if sub_image_location:
|
||||
desc = gl.json_info['description']
|
||||
content_type = gl.json_info['type']
|
||||
desc = json_info['description']
|
||||
content_type = json_info['type']
|
||||
image_path = os.path.join(_api.contenttype_folder(content_type, desc, custom_folder=image_location))
|
||||
if not sub_folder:
|
||||
sub_folder = os.path.relpath(install_path, image_path)
|
||||
|
||||
if sub_folder and sub_folder != "None":
|
||||
image_path = os.path.join(image_path, sub_folder.lstrip("/").lstrip("\\"))
|
||||
else:
|
||||
image_path = Path(image_location)
|
||||
|
||||
if not os.path.exists(image_path):
|
||||
os.makedirs(image_path)
|
||||
return image_path
|
||||
|
||||
def save_images(preview_html, model_filename, install_path, sub_folder, api_response=None):
|
||||
image_path = get_image_path(install_path, api_response, sub_folder)
|
||||
img_urls = re.findall(r'data-sampleimg="true" src=[\'"]?([^\'" >]+)', preview_html)
|
||||
|
||||
name = os.path.splitext(model_filename)[0]
|
||||
|
|
@ -231,14 +236,11 @@ def save_images(preview_html, model_filename, install_path, sub_folder=None):
|
|||
urllib.request.install_opener(opener)
|
||||
|
||||
for i, img_url in enumerate(img_urls):
|
||||
if i == 0:
|
||||
filename = f'{name}.preview.png'
|
||||
else:
|
||||
filename = f'{name}_{i}.png'
|
||||
filename = f'{name}_{i}.png'
|
||||
img_url = urllib.parse.quote(img_url, safe=':/=')
|
||||
try:
|
||||
with urllib.request.urlopen(img_url) as url:
|
||||
with open(os.path.join(install_path if i == 0 else image_path, filename), 'wb') as f:
|
||||
with open(os.path.join(image_path, filename), 'wb') as f:
|
||||
f.write(url.read())
|
||||
print(f"Downloaded {filename}")
|
||||
|
||||
|
|
@ -343,6 +345,11 @@ def model_from_sent(model_name, content_type, tile_count):
|
|||
modelID_failed = False
|
||||
output_html = None
|
||||
use_local_html = getattr(opts, "use_local_html", False)
|
||||
local_path_in_html = getattr(opts, "local_path_in_html", False)
|
||||
|
||||
if local_path_in_html:
|
||||
use_local_html = False
|
||||
|
||||
model_name = re.sub(r'\.\d{3}$', '', model_name)
|
||||
content_type = re.sub(r'\.\d{3}$', '', content_type)
|
||||
content_mapping = {
|
||||
|
|
@ -371,22 +378,23 @@ def model_from_sent(model_name, content_type, tile_count):
|
|||
if index != -1:
|
||||
output_html = output_html[index + len("</head>"):]
|
||||
|
||||
fail_html = '<div style="color: white; font-family: var(--font); font-size: 24px; text-align: center; margin: 50px !important;">Model ID not found.<br>Maybe the model doesn\'t exist on CivitAI?</div>'
|
||||
|
||||
div = '<div style="color: white; font-family: var(--font); font-size: 24px; text-align: center; margin: 50px !important;">'
|
||||
not_found = div + "Model ID not found.<br>Maybe the model doesn\'t exist on CivitAI?</div>"
|
||||
offline = div + "CivitAI failed to respond.<br>The servers are likely offline."
|
||||
if not output_html:
|
||||
modelID = get_models(model_file, True)
|
||||
if not modelID or modelID == "Model not found":
|
||||
output_html = fail_html
|
||||
output_html = not_found
|
||||
modelID_failed = True
|
||||
if modelID == "offline":
|
||||
output_html = fail_html
|
||||
output_html = offline
|
||||
modelID_failed = True
|
||||
if not modelID_failed:
|
||||
json_data = _api.api_to_data(content_type, "Newest", "AllTime", "Model name", None, None, None, tile_count, f"civitai.com/models/{modelID}")
|
||||
else: json_data = None
|
||||
|
||||
if json_data == "timeout":
|
||||
output_html = fail_html
|
||||
output_html = offline
|
||||
if json_data != None and json_data != "timeout":
|
||||
model_versions = _api.update_model_versions(modelID, json_data)
|
||||
output_html = _api.update_model_info(None, model_versions.get('value'), True, modelID, json_data)
|
||||
|
|
@ -402,6 +410,7 @@ def model_from_sent(model_name, content_type, tile_count):
|
|||
'#60A5FA': 'var(--link-text-color-hover)',
|
||||
'#1F2937': 'var(--input-background-fill)',
|
||||
'#374151': 'var(--input-border-color)',
|
||||
'#111827': 'var(--error-background-fill)',
|
||||
'top: 50%;': '',
|
||||
'padding-top: 0px;': 'padding-top: 475px;',
|
||||
'.civitai_txt2img': '.civitai_placeholder'
|
||||
|
|
@ -446,30 +455,37 @@ def clean_description(desc):
|
|||
cleaned_text = desc
|
||||
return cleaned_text
|
||||
|
||||
def save_model_info(install_path, file_name, sha256=None, preview_html=None, overwrite_toggle=False, api_response=None):
|
||||
def save_model_info(install_path, file_name, sub_folder, sha256=None, preview_html=None, overwrite_toggle=False, api_response=None, from_update=False):
|
||||
filename = os.path.splitext(file_name)[0]
|
||||
json_file = os.path.join(install_path, f'{filename}.json')
|
||||
if not os.path.exists(install_path):
|
||||
os.makedirs(install_path)
|
||||
|
||||
save_api_info = getattr(opts, "save_api_info", False)
|
||||
|
||||
if not sha256:
|
||||
if os.path.exists(json_file):
|
||||
try:
|
||||
with open(json_file, 'r', encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
if 'sha256' in data and data['sha256']:
|
||||
sha256 = data['sha256'].upper()
|
||||
except Exception as e:
|
||||
print(f"Failed to open {json_file}: {e}")
|
||||
use_local = getattr(opts, "local_path_in_html", False)
|
||||
save_to_custom = getattr(opts, "inf_files_in_imgs", False)
|
||||
|
||||
if not api_response:
|
||||
api_response = gl.json_data
|
||||
|
||||
image_path = get_image_path(install_path, api_response, sub_folder)
|
||||
|
||||
if save_to_custom:
|
||||
save_path = image_path
|
||||
else:
|
||||
save_path = install_path
|
||||
|
||||
result = find_and_save(api_response, sha256, file_name, json_file, False, overwrite_toggle)
|
||||
if result != "found":
|
||||
result = find_and_save(api_response, sha256, file_name, json_file, True, overwrite_toggle)
|
||||
|
||||
if preview_html:
|
||||
if use_local:
|
||||
img_urls = re.findall(r'data-sampleimg="true" src=[\'"]?([^\'" >]+)', preview_html)
|
||||
for i, img_url in enumerate(img_urls):
|
||||
img_name = f'{filename}_{i}.png'
|
||||
preview_html = preview_html.replace(img_url,f'{os.path.join(image_path, img_name)}')
|
||||
|
||||
match = re.search(r'(\s*)<div class="model-block">', preview_html)
|
||||
if match:
|
||||
indentation = match.group(1)
|
||||
|
|
@ -479,12 +495,12 @@ def save_model_info(install_path, file_name, sha256=None, preview_html=None, ove
|
|||
utf8_meta_tag = f'{indentation}<meta charset="UTF-8">'
|
||||
head_section = f'{indentation}<head>{indentation} {utf8_meta_tag}{indentation} {css_link}{indentation}</head>'
|
||||
HTML = head_section + preview_html
|
||||
path_to_new_file = os.path.join(install_path, f'{filename}.html')
|
||||
path_to_new_file = os.path.join(save_path, f'{filename}.html')
|
||||
with open(path_to_new_file, 'wb') as f:
|
||||
f.write(HTML.encode('utf8'))
|
||||
|
||||
if save_api_info:
|
||||
path_to_new_file = os.path.join(install_path, f'{filename}.api_info.json')
|
||||
path_to_new_file = os.path.join(save_path, f'{filename}.api_info.json')
|
||||
with open(path_to_new_file, mode="w", encoding="utf-8") as f:
|
||||
json.dump(gl.json_info, f, indent=4, ensure_ascii=False)
|
||||
|
||||
|
|
@ -954,7 +970,8 @@ def file_scan(folders, ver_finish, tag_finish, installed_finish, preview_finish,
|
|||
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)
|
||||
save_model_info(install_path, file_name, preview_html=preview_html, api_response=api_response, overwrite_toggle=overwrite_toggle)
|
||||
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, from_update=True)
|
||||
if progress != None:
|
||||
progress(1, desc=f"All tags succesfully saved!")
|
||||
gl.scan_files = False
|
||||
|
|
|
|||
|
|
@ -20,21 +20,30 @@ def git_tag():
|
|||
return None
|
||||
|
||||
try:
|
||||
from packaging import version
|
||||
ver = git_tag()
|
||||
if not ver:
|
||||
try:
|
||||
from modules import launch_utils
|
||||
ver = launch_utils.git_tag()
|
||||
except:
|
||||
print("Failed to fetch SD-WebUI version")
|
||||
ver_bool = False
|
||||
if ver:
|
||||
ver = ver.split('-')[0].rsplit('-', 1)[0]
|
||||
ver_bool = version.parse(ver[0:]) >= version.parse("1.7")
|
||||
import modules_forge
|
||||
forge = True
|
||||
ver_bool = True
|
||||
except ImportError:
|
||||
print("Python module 'packaging' has not been imported correctly, please try to restart or install it manually.")
|
||||
ver_bool = False
|
||||
forge = False
|
||||
|
||||
if not forge:
|
||||
try:
|
||||
from packaging import version
|
||||
ver = git_tag()
|
||||
|
||||
if not ver:
|
||||
try:
|
||||
from modules import launch_utils
|
||||
ver = launch_utils.git_tag()
|
||||
except:
|
||||
print("Failed to fetch SD-WebUI version")
|
||||
ver_bool = False
|
||||
if ver:
|
||||
ver = ver.split('-')[0].rsplit('-', 1)[0]
|
||||
ver_bool = version.parse(ver[0:]) >= version.parse("1.7")
|
||||
except ImportError:
|
||||
print("Python module 'packaging' has not been imported correctly, please try to restart or install it manually.")
|
||||
ver_bool = False
|
||||
|
||||
gl.init()
|
||||
|
||||
|
|
@ -558,6 +567,7 @@ def on_ui_tabs():
|
|||
inputs=[
|
||||
install_path,
|
||||
model_filename,
|
||||
sub_folder,
|
||||
current_sha256,
|
||||
preview_html
|
||||
],
|
||||
|
|
@ -1011,7 +1021,7 @@ def on_ui_settings():
|
|||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).info("Uses the matching local HTML file when pressing CivitAI button on model cards in txt2img and img2img")
|
||||
)
|
||||
|
||||
|
||||
shared.opts.add_option(
|
||||
"page_header",
|
||||
shared.OptionInfo(
|
||||
|
|
@ -1061,6 +1071,26 @@ def on_ui_settings():
|
|||
**({'category_id': cat_id} if ver_bool else {})
|
||||
).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("Does not work in combination with the \"Use local HTML file for model info\" option!")
|
||||
)
|
||||
|
||||
shared.opts.add_option(
|
||||
"save_to_custom",
|
||||
shared.OptionInfo(
|
||||
False,
|
||||
"Store the HTML and api_info in the custom images location",
|
||||
section=browser,
|
||||
**({'category_id': cat_id} if ver_bool else {})
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
10
style.css
10
style.css
|
|
@ -322,13 +322,19 @@
|
|||
gap: 5px;
|
||||
}
|
||||
|
||||
.civitai-tag {
|
||||
background-color: var(--input-background-fill);
|
||||
.civitai-tag,
|
||||
.civitai-meta-btn {
|
||||
background-color: var(--error-background-fill);
|
||||
border-radius: 8px;
|
||||
padding: 4px 6px;
|
||||
border: 1px solid var(--input-border-color);
|
||||
}
|
||||
|
||||
.civitai-meta-btn:hover {
|
||||
cursor: pointer;
|
||||
background-color: var(--input-background-fill);
|
||||
}
|
||||
|
||||
#select_all_models_container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
|
|
|||
|
|
@ -192,13 +192,19 @@ a:hover {
|
|||
gap: 5px;
|
||||
}
|
||||
|
||||
.civitai-tag {
|
||||
background-color: #1F2937;
|
||||
.civitai-tag,
|
||||
.civitai-meta-btn {
|
||||
background-color: #111827;
|
||||
border-radius: 8px;
|
||||
padding: 4px 6px;
|
||||
border: 1px solid #374151;
|
||||
}
|
||||
|
||||
.civitai-meta-btn:hover {
|
||||
cursor: pointer;
|
||||
background-color: #1F2937;
|
||||
}
|
||||
|
||||
/* Icon */
|
||||
.tab-label::before {
|
||||
content: "❯";
|
||||
|
|
|
|||
Loading…
Reference in New Issue