diff --git a/.eslintrc.js b/.eslintrc.js index cf839769..9c70eff8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -86,8 +86,6 @@ module.exports = { // imageviewer.js modalPrevImage: "readonly", modalNextImage: "readonly", - // token-counters.js - setupTokenCounters: "readonly", // localStorage.js localSet: "readonly", localGet: "readonly", diff --git a/extensions-builtin/Lora/preload.py b/extensions-builtin/Lora/preload.py index 50961be3..52fab29b 100644 --- a/extensions-builtin/Lora/preload.py +++ b/extensions-builtin/Lora/preload.py @@ -1,7 +1,8 @@ import os from modules import paths +from modules.paths_internal import normalized_filepath def preload(parser): - parser.add_argument("--lora-dir", type=str, help="Path to directory with Lora networks.", default=os.path.join(paths.models_path, 'Lora')) - parser.add_argument("--lyco-dir-backcompat", type=str, help="Path to directory with LyCORIS networks (for backawards compatibility; can also use --lyco-dir).", default=os.path.join(paths.models_path, 'LyCORIS')) + parser.add_argument("--lora-dir", type=normalized_filepath, help="Path to directory with Lora networks.", default=os.path.join(paths.models_path, 'Lora')) + parser.add_argument("--lyco-dir-backcompat", type=normalized_filepath, help="Path to directory with LyCORIS networks (for backawards compatibility; can also use --lyco-dir).", default=os.path.join(paths.models_path, 'LyCORIS')) diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index 9a3a2392..d5855fe9 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -114,6 +114,10 @@ function setupExtraNetworksForTab(tabname) { var controls = gradioApp().querySelector("#" + tabname_full + "_controls"); controlsDiv.insertBefore(controls, null); + + if (elem.style.display != "none") { + extraNetworksShowControlsForPage(tabname, tabname_full); + } }); registerPrompt(tabname, tabname + "_prompt"); @@ -168,7 +172,11 @@ function extraNetworksTabSelected(tabname, id, showPrompt, showNegativePrompt, t function applyExtraNetworkFilter(tabname_full) { var doFilter = function() { - extraNetworksApplyFilter[tabname_full](true); + var applyFunction = extraNetworksApplyFilter[tabname_full]; + + if (applyFunction) { + applyFunction(true); + } }; setTimeout(doFilter, 1); } @@ -622,10 +630,13 @@ function scheduleAfterScriptsCallbacks() { }, 200); } -document.addEventListener("DOMContentLoaded", function() { +onUiLoaded(function() { var mutationObserver = new MutationObserver(function(m) { - if (!executedAfterScripts && - gradioApp().querySelectorAll("[id$='_extra_search']").length == 8) { + let existingSearchfields = gradioApp().querySelectorAll("[id$='_extra_search']").length; + let neededSearchfields = gradioApp().querySelectorAll("[id$='_extra_tabs'] > .tab-nav > button").length - 2; + + if (!executedAfterScripts && existingSearchfields >= neededSearchfields) { + mutationObserver.disconnect(); executedAfterScripts = true; scheduleAfterScriptsCallbacks(); } diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 77761495..f068bac6 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -45,8 +45,15 @@ function formatTime(secs) { } } + +var originalAppTitle = undefined; + +onUiLoaded(function() { + originalAppTitle = document.title; +}); + function setTitle(progress) { - var title = 'Stable Diffusion'; + var title = originalAppTitle; if (opts.show_progress_in_title && progress) { title = '[' + progress.trim() + '] ' + title; diff --git a/javascript/token-counters.js b/javascript/token-counters.js index 2ecc7d91..eeea7a5d 100644 --- a/javascript/token-counters.js +++ b/javascript/token-counters.js @@ -48,11 +48,6 @@ function setupTokenCounting(id, id_counter, id_button) { var counter = gradioApp().getElementById(id_counter); var textarea = gradioApp().querySelector(`#${id} > label > textarea`); - if (opts.disable_token_counters) { - counter.style.display = "none"; - return; - } - if (counter.parentElement == prompt.parentElement) { return; } @@ -61,15 +56,32 @@ function setupTokenCounting(id, id_counter, id_button) { prompt.parentElement.style.position = "relative"; var func = onEdit(id, textarea, 800, function() { - gradioApp().getElementById(id_button)?.click(); + if (counter.classList.contains("token-counter-visible")) { + gradioApp().getElementById(id_button)?.click(); + } }); promptTokenCountUpdateFunctions[id] = func; promptTokenCountUpdateFunctions[id_button] = func; } -function setupTokenCounters() { - setupTokenCounting('txt2img_prompt', 'txt2img_token_counter', 'txt2img_token_button'); - setupTokenCounting('txt2img_neg_prompt', 'txt2img_negative_token_counter', 'txt2img_negative_token_button'); - setupTokenCounting('img2img_prompt', 'img2img_token_counter', 'img2img_token_button'); - setupTokenCounting('img2img_neg_prompt', 'img2img_negative_token_counter', 'img2img_negative_token_button'); +function toggleTokenCountingVisibility(id, id_counter, id_button) { + var counter = gradioApp().getElementById(id_counter); + + counter.style.display = opts.disable_token_counters ? "none" : "block"; + counter.classList.toggle("token-counter-visible", !opts.disable_token_counters); } + +function runCodeForTokenCounters(fun) { + fun('txt2img_prompt', 'txt2img_token_counter', 'txt2img_token_button'); + fun('txt2img_neg_prompt', 'txt2img_negative_token_counter', 'txt2img_negative_token_button'); + fun('img2img_prompt', 'img2img_token_counter', 'img2img_token_button'); + fun('img2img_neg_prompt', 'img2img_negative_token_counter', 'img2img_negative_token_button'); +} + +onUiLoaded(function() { + runCodeForTokenCounters(setupTokenCounting); +}); + +onOptionsChanged(function() { + runCodeForTokenCounters(toggleTokenCountingVisibility); +}); diff --git a/javascript/ui.js b/javascript/ui.js index 9e66cd24..3d079b3d 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -319,8 +319,6 @@ onAfterUiUpdate(function() { }); json_elem.parentElement.style.display = "none"; - - setupTokenCounters(); }); onOptionsChanged(function() { diff --git a/modules/cmd_args.py b/modules/cmd_args.py index f1251b6c..312dabff 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -1,7 +1,7 @@ import argparse import json import os -from modules.paths_internal import models_path, script_path, data_path, extensions_dir, extensions_builtin_dir, sd_default_config, sd_model_file # noqa: F401 +from modules.paths_internal import normalized_filepath, models_path, script_path, data_path, extensions_dir, extensions_builtin_dir, sd_default_config, sd_model_file # noqa: F401 parser = argparse.ArgumentParser() @@ -19,21 +19,21 @@ parser.add_argument("--skip-install", action='store_true', help="launch.py argum parser.add_argument("--dump-sysinfo", action='store_true', help="launch.py argument: dump limited sysinfo file (without information about extensions, options) to disk and quit") parser.add_argument("--loglevel", type=str, help="log level; one of: CRITICAL, ERROR, WARNING, INFO, DEBUG", default=None) parser.add_argument("--do-not-download-clip", action='store_true', help="do not download CLIP model even if it's not included in the checkpoint") -parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored") -parser.add_argument("--config", type=str, default=sd_default_config, help="path to config which constructs model",) -parser.add_argument("--ckpt", type=str, default=sd_model_file, help="path to checkpoint of stable diffusion model; if specified, this checkpoint will be added to the list of checkpoints and loaded",) -parser.add_argument("--ckpt-dir", type=str, default=None, help="Path to directory with stable diffusion checkpoints") -parser.add_argument("--vae-dir", type=str, default=None, help="Path to directory with VAE files") -parser.add_argument("--gfpgan-dir", type=str, help="GFPGAN directory", default=('./src/gfpgan' if os.path.exists('./src/gfpgan') else './GFPGAN')) -parser.add_argument("--gfpgan-model", type=str, help="GFPGAN model file name", default=None) +parser.add_argument("--data-dir", type=normalized_filepath, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored") +parser.add_argument("--config", type=normalized_filepath, default=sd_default_config, help="path to config which constructs model",) +parser.add_argument("--ckpt", type=normalized_filepath, default=sd_model_file, help="path to checkpoint of stable diffusion model; if specified, this checkpoint will be added to the list of checkpoints and loaded",) +parser.add_argument("--ckpt-dir", type=normalized_filepath, default=None, help="Path to directory with stable diffusion checkpoints") +parser.add_argument("--vae-dir", type=normalized_filepath, default=None, help="Path to directory with VAE files") +parser.add_argument("--gfpgan-dir", type=normalized_filepath, help="GFPGAN directory", default=('./src/gfpgan' if os.path.exists('./src/gfpgan') else './GFPGAN')) +parser.add_argument("--gfpgan-model", type=normalized_filepath, help="GFPGAN model file name", default=None) parser.add_argument("--no-half", action='store_true', help="do not switch the model to 16-bit floats") parser.add_argument("--no-half-vae", action='store_true', help="do not switch the VAE model to 16-bit floats") parser.add_argument("--no-progressbar-hiding", action='store_true', help="do not hide progressbar in gradio UI (we hide it because it slows down ML if you have hardware acceleration in browser)") parser.add_argument("--max-batch-count", type=int, default=16, help="maximum batch count value for the UI") -parser.add_argument("--embeddings-dir", type=str, default=os.path.join(data_path, 'embeddings'), help="embeddings directory for textual inversion (default: embeddings)") -parser.add_argument("--textual-inversion-templates-dir", type=str, default=os.path.join(script_path, 'textual_inversion_templates'), help="directory with textual inversion templates") -parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_path, 'hypernetworks'), help="hypernetwork directory") -parser.add_argument("--localizations-dir", type=str, default=os.path.join(script_path, 'localizations'), help="localizations directory") +parser.add_argument("--embeddings-dir", type=normalized_filepath, default=os.path.join(data_path, 'embeddings'), help="embeddings directory for textual inversion (default: embeddings)") +parser.add_argument("--textual-inversion-templates-dir", type=normalized_filepath, default=os.path.join(script_path, 'textual_inversion_templates'), help="directory with textual inversion templates") +parser.add_argument("--hypernetwork-dir", type=normalized_filepath, default=os.path.join(models_path, 'hypernetworks'), help="hypernetwork directory") +parser.add_argument("--localizations-dir", type=normalized_filepath, default=os.path.join(script_path, 'localizations'), help="localizations directory") parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui") parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage") parser.add_argument("--medvram-sdxl", action='store_true', help="enable --medvram optimization just for SDXL models") @@ -48,12 +48,12 @@ parser.add_argument("--ngrok", type=str, help="ngrok authtoken, alternative to g parser.add_argument("--ngrok-region", type=str, help="does not do anything.", default="") parser.add_argument("--ngrok-options", type=json.loads, help='The options to pass to ngrok in JSON format, e.g.: \'{"authtoken_from_env":true, "basic_auth":"user:password", "oauth_provider":"google", "oauth_allow_emails":"user@asdf.com"}\'', default=dict()) parser.add_argument("--enable-insecure-extension-access", action='store_true', help="enable extensions tab regardless of other options") -parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer')) -parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory with GFPGAN model file(s).", default=os.path.join(models_path, 'GFPGAN')) -parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN')) -parser.add_argument("--bsrgan-models-path", type=str, help="Path to directory with BSRGAN model file(s).", default=os.path.join(models_path, 'BSRGAN')) -parser.add_argument("--realesrgan-models-path", type=str, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(models_path, 'RealESRGAN')) -parser.add_argument("--clip-models-path", type=str, help="Path to directory with CLIP model file(s).", default=None) +parser.add_argument("--codeformer-models-path", type=normalized_filepath, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer')) +parser.add_argument("--gfpgan-models-path", type=normalized_filepath, help="Path to directory with GFPGAN model file(s).", default=os.path.join(models_path, 'GFPGAN')) +parser.add_argument("--esrgan-models-path", type=normalized_filepath, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN')) +parser.add_argument("--bsrgan-models-path", type=normalized_filepath, help="Path to directory with BSRGAN model file(s).", default=os.path.join(models_path, 'BSRGAN')) +parser.add_argument("--realesrgan-models-path", type=normalized_filepath, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(models_path, 'RealESRGAN')) +parser.add_argument("--clip-models-path", type=normalized_filepath, help="Path to directory with CLIP model file(s).", default=None) parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers") parser.add_argument("--force-enable-xformers", action='store_true', help="enable xformers for cross attention layers regardless of whether the checking code thinks you can run it; do not make bug reports if this fails to work") parser.add_argument("--xformers-flash-attention", action='store_true', help="enable xformers with Flash Attention to improve reproducibility (supported for SD2.x or variant only)") @@ -83,7 +83,7 @@ parser.add_argument("--freeze-specific-settings", type=str, help='disable editin parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui settings", default=os.path.join(data_path, 'config.json')) parser.add_argument("--gradio-debug", action='store_true', help="launch gradio with --debug option") parser.add_argument("--gradio-auth", type=str, help='set gradio authentication like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None) -parser.add_argument("--gradio-auth-path", type=str, help='set gradio authentication file path ex. "/path/to/auth/file" same auth format as --gradio-auth', default=None) +parser.add_argument("--gradio-auth-path", type=normalized_filepath, help='set gradio authentication file path ex. "/path/to/auth/file" same auth format as --gradio-auth', default=None) parser.add_argument("--gradio-img2img-tool", type=str, help='does not do anything') parser.add_argument("--gradio-inpaint-tool", type=str, help="does not do anything") parser.add_argument("--gradio-allowed-path", action='append', help="add path to gradio's allowed_paths, make it possible to serve files from it", default=[data_path]) @@ -94,7 +94,7 @@ parser.add_argument("--theme", type=str, help="launches the UI with light or dar parser.add_argument("--use-textbox-seed", action='store_true', help="use textbox for seeds in UI (no up/down, but possible to input long seeds)", default=False) parser.add_argument("--disable-console-progressbars", action='store_true', help="do not output progressbars to console", default=False) parser.add_argument("--enable-console-prompts", action='store_true', help="does not do anything", default=False) # Legacy compatibility, use as default value shared.opts.enable_console_prompts -parser.add_argument('--vae-path', type=str, help='Checkpoint to use as VAE; setting this argument disables all settings related to VAE', default=None) +parser.add_argument('--vae-path', type=normalized_filepath, help='Checkpoint to use as VAE; setting this argument disables all settings related to VAE', default=None) parser.add_argument("--disable-safe-unpickle", action='store_true', help="disable checking pytorch models for malicious code", default=False) parser.add_argument("--api", action='store_true', help="use api=True to launch the API together with the webui (use --nowebui instead for only the API)") parser.add_argument("--api-auth", type=str, help='Set authentication for API like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None) diff --git a/modules/hashes.py b/modules/hashes.py index b7a33b42..d22e5fad 100644 --- a/modules/hashes.py +++ b/modules/hashes.py @@ -21,7 +21,10 @@ def calculate_sha256(filename): def sha256_from_cache(filename, title, use_addnet_hash=False): hashes = cache("hashes-addnet") if use_addnet_hash else cache("hashes") - ondisk_mtime = os.path.getmtime(filename) + try: + ondisk_mtime = os.path.getmtime(filename) + except FileNotFoundError: + return None if title not in hashes: return None diff --git a/modules/launch_utils.py b/modules/launch_utils.py index 107c72b0..ad04eb36 100644 --- a/modules/launch_utils.py +++ b/modules/launch_utils.py @@ -188,7 +188,7 @@ def git_clone(url, dir, name, commithash=None): return try: - run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}", live=True) + run(f'"{git}" clone --config core.filemode=false "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}", live=True) except RuntimeError: shutil.rmtree(dir, ignore_errors=True) raise diff --git a/modules/paths_internal.py b/modules/paths_internal.py index b86ecd7f..2ed1392a 100644 --- a/modules/paths_internal.py +++ b/modules/paths_internal.py @@ -4,6 +4,10 @@ import argparse import os import sys import shlex +from pathlib import Path + + +normalized_filepath = lambda filepath: str(Path(filepath).resolve()) commandline_args = os.environ.get('COMMANDLINE_ARGS', "") sys.argv += shlex.split(commandline_args) diff --git a/modules/sd_samplers_cfg_denoiser.py b/modules/sd_samplers_cfg_denoiser.py index 941dff4b..a73d3b03 100644 --- a/modules/sd_samplers_cfg_denoiser.py +++ b/modules/sd_samplers_cfg_denoiser.py @@ -220,10 +220,10 @@ class CFGDenoiser(torch.nn.Module): self.padded_cond_uncond = False self.padded_cond_uncond_v0 = False - if shared.opts.pad_cond_uncond and tensor.shape[1] != uncond.shape[1]: - tensor, uncond = self.pad_cond_uncond(tensor, uncond) - elif shared.opts.pad_cond_uncond_v0 and tensor.shape[1] != uncond.shape[1]: + if shared.opts.pad_cond_uncond_v0 and tensor.shape[1] != uncond.shape[1]: tensor, uncond = self.pad_cond_uncond_v0(tensor, uncond) + elif shared.opts.pad_cond_uncond and tensor.shape[1] != uncond.shape[1]: + tensor, uncond = self.pad_cond_uncond(tensor, uncond) if tensor.shape[1] == uncond.shape[1] or skip_uncond: if is_edit_model: diff --git a/modules/shared_options.py b/modules/shared_options.py index f1ab5d6e..25b47aa1 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -211,7 +211,7 @@ options_templates.update(options_section(('optimizations', "Optimizations", "sd" "token_merging_ratio_img2img": OptionInfo(0.0, "Token merging ratio for img2img", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}).info("only applies if non-zero and overrides above"), "token_merging_ratio_hr": OptionInfo(0.0, "Token merging ratio for high-res pass", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}, infotext='Token merging ratio hr').info("only applies if non-zero and overrides above"), "pad_cond_uncond": OptionInfo(False, "Pad prompt/negative prompt", infotext='Pad conds').info("improves performance when prompt and negative prompt have different lengths; changes seeds"), - "pad_cond_uncond_v0": OptionInfo(False, "Pad prompt/negative prompt (v0)", infotext='Pad conds v0').info("alternative implementation for the above; used prior to 1.6.0 for DDIM sampler; ignored if the above is set; changes seeds"), + "pad_cond_uncond_v0": OptionInfo(False, "Pad prompt/negative prompt (v0)", infotext='Pad conds v0').info("alternative implementation for the above; used prior to 1.6.0 for DDIM sampler; overrides the above if set; WARNING: truncates negative prompt if it's too long; changes seeds"), "persistent_cond_cache": OptionInfo(True, "Persistent cond cache").info("do not recalculate conds from prompts if prompts have not changed since previous calculation"), "batch_cond_uncond": OptionInfo(True, "Batch cond/uncond").info("do both conditional and unconditional denoising in one batch; uses a bit more VRAM during sampling, but improves speed; previously this was controlled by --always-batch-cond-uncond comandline argument"), "fp8_storage": OptionInfo("Disable", "FP8 weight", gr.Radio, {"choices": ["Disable", "Enable for SDXL", "Enable"]}).info("Use FP8 to store Linear/Conv layers' weight. Require pytorch>=2.1.0."), @@ -270,7 +270,7 @@ options_templates.update(options_section(('ui_prompt_editing', "Prompt editing", "keyedit_delimiters": OptionInfo(r".,\/!?%^*;:{}=`~() ", "Word delimiters when editing the prompt with Ctrl+up/down"), "keyedit_delimiters_whitespace": OptionInfo(["Tab", "Carriage Return", "Line Feed"], "Ctrl+up/down whitespace delimiters", gr.CheckboxGroup, lambda: {"choices": ["Tab", "Carriage Return", "Line Feed"]}), "keyedit_move": OptionInfo(True, "Alt+left/right moves prompt elements"), - "disable_token_counters": OptionInfo(False, "Disable prompt token counters").needs_reload_ui(), + "disable_token_counters": OptionInfo(False, "Disable prompt token counters"), "include_styles_into_token_counters": OptionInfo(True, "Count tokens of enabled styles").info("When calculating how many tokens the prompt has, also consider tokens added by enabled styles."), })) diff --git a/modules/ui_toprow.py b/modules/ui_toprow.py index 30cf1b1b..dc3c3aa3 100644 --- a/modules/ui_toprow.py +++ b/modules/ui_toprow.py @@ -127,9 +127,9 @@ class Toprow: self.restore_progress_button = ToolButton(value=restore_progress_symbol, elem_id=f"{self.id_part}_restore_progress", visible=False, tooltip="Restore progress") - self.token_counter = gr.HTML(value="0/75", elem_id=f"{self.id_part}_token_counter", elem_classes=["token-counter"]) + self.token_counter = gr.HTML(value="0/75", elem_id=f"{self.id_part}_token_counter", elem_classes=["token-counter"], visible=False) self.token_button = gr.Button(visible=False, elem_id=f"{self.id_part}_token_button") - self.negative_token_counter = gr.HTML(value="0/75", elem_id=f"{self.id_part}_negative_token_counter", elem_classes=["token-counter"]) + self.negative_token_counter = gr.HTML(value="0/75", elem_id=f"{self.id_part}_negative_token_counter", elem_classes=["token-counter"], visible=False) self.negative_token_button = gr.Button(visible=False, elem_id=f"{self.id_part}_negative_token_button") self.clear_prompt_button.click( diff --git a/script.js b/script.js index be1bc317..f069b1ef 100644 --- a/script.js +++ b/script.js @@ -167,8 +167,10 @@ document.addEventListener('keydown', function(e) { const lightboxModal = document.querySelector('#lightboxModal'); if (!globalPopup || globalPopup.style.display === 'none') { if (document.activeElement === lightboxModal) return; - interruptButton.click(); - e.preventDefault(); + if (interruptButton.style.display === 'block') { + interruptButton.click(); + e.preventDefault(); + } } } }); diff --git a/style.css b/style.css index 988c28c0..8ce78ff0 100644 --- a/style.css +++ b/style.css @@ -222,6 +222,10 @@ input[type="checkbox"].input-accordion-checkbox{ top: -0.75em; } +.block.token-counter-visible{ + display: block !important; +} + .block.token-counter span{ background: var(--input-background-fill) !important; box-shadow: 0 0 0.0 0.3em rgba(192,192,192,0.15), inset 0 0 0.6em rgba(192,192,192,0.075); @@ -851,13 +855,13 @@ table.popup-table .link{ #extensions tr:hover td, #config_state_extensions tr:hover td, #available_extensions tr:hover td { - background: rgba(0, 0, 0, 0.15) + background: rgba(0, 0, 0, 0.15); } .dark #extensions tr:hover td , .dark #config_state_extensions tr:hover td , .dark #available_extensions tr:hover td { - background: rgba(255, 255, 255, 0.15) + background: rgba(255, 255, 255, 0.15); } /* replace original footer with ours */ @@ -1513,12 +1517,12 @@ body.resizing .resize-handle { background-color: var(--input-placeholder-color); } -.dark .extra-network-control .extra-network-control--enabled { - background-color: var(--neutral-700); +.extra-network-control .extra-network-control--enabled { + background-color: rgba(0, 0, 0, 0.15); } .dark .extra-network-control .extra-network-control--enabled { - background-color: var(--neutral-300); + background-color: rgba(255, 255, 255, 0.15); } /* ==== REFRESH ICON ACTIONS ==== */ diff --git a/webui.sh b/webui.sh index 794cfb8a..f116376f 100755 --- a/webui.sh +++ b/webui.sh @@ -227,9 +227,7 @@ fi prepare_tcmalloc() { if [[ "${OSTYPE}" == "linux"* ]] && [[ -z "${NO_TCMALLOC}" ]] && [[ -z "${LD_PRELOAD}" ]]; then # check glibc version - LIBC_LIB="$(PATH=/usr/sbin:$PATH ldconfig -p | grep -P "libc.so.6" | head -n 1)" - LIBC_INFO=$(echo ${LIBC_LIB} | awk '{print $NF}') - LIBC_VER=$(echo $(${LIBC_INFO} | awk 'NR==1 {print $NF}') | grep -oP '\d+\.\d+') + LIBC_VER=$(echo $(ldd --version | awk 'NR==1 {print $NF}') | grep -oP '\d+\.\d+') echo "glibc version is $LIBC_VER" libc_vernum=$(expr $LIBC_VER) # Since 2.34 libpthread is integrated into libc.so @@ -244,9 +242,9 @@ prepare_tcmalloc() { TC_INFO=(${TCMALLOC//=>/}) if [[ ! -z "${TC_INFO}" ]]; then echo "Check TCMalloc: ${TC_INFO}" - # Determine if the library is linked to libptthread and resolve undefined symbol: ptthread_key_create + # Determine if the library is linked to libpthread and resolve undefined symbol: pthread_key_create if [ $(echo "$libc_vernum < $libc_v234" | bc) -eq 1 ]; then - # glibc < 2.33 pthread_key_create into libpthead.so. check linking libpthread.so... + # glibc < 2.34 pthread_key_create into libpthread.so. check linking libpthread.so... if ldd ${TC_INFO[2]} | grep -q 'libpthread'; then echo "$TC_INFO is linked with libpthread,execute LD_PRELOAD=${TC_INFO[2]}" # set fullpath LD_PRELOAD (To be on the safe side) @@ -256,7 +254,7 @@ prepare_tcmalloc() { echo "$TC_INFO is not linked with libpthread will trigger undefined symbol: pthread_Key_create error" fi else - # Version 2.34 of libc.so (glibc) includes the pthead library IN GLIBC. (USE ubuntu 22.04 and modern linux system and WSL) + # Version 2.34 of libc.so (glibc) includes the pthread library IN GLIBC. (USE ubuntu 22.04 and modern linux system and WSL) # libc.so(glibc) is linked with a library that works in ALMOST ALL Linux userlands. SO NO CHECK! echo "$TC_INFO is linked with libc.so,execute LD_PRELOAD=${TC_INFO[2]}" # set fullpath LD_PRELOAD (To be on the safe side) @@ -266,7 +264,7 @@ prepare_tcmalloc() { fi done if [[ -z "${LD_PRELOAD}" ]]; then - printf "\e[1m\e[31mCannot locate TCMalloc. Do you have tcmalloc or gperftools installed on your system? (improves CPU memory usage)\e[0m\n" + printf "\e[1m\e[31mCannot locate TCMalloc. Do you have tcmalloc or google-perftool installed on your system? (improves CPU memory usage)\e[0m\n" fi fi }