|
@@ -13,6 +13,9 @@ import html
|
|
|
from modules import extensions, shared, paths
|
|
|
|
|
|
|
|
|
+available_extensions = {"extensions": []}
|
|
|
+
|
|
|
+
|
|
|
def check_access():
|
|
|
assert not shared.cmd_opts.disable_extension_access, "extension access disabed because of commandline flags"
|
|
|
|
|
@@ -96,6 +99,14 @@ def extension_table():
|
|
|
return code
|
|
|
|
|
|
|
|
|
+def normalize_git_url(url):
|
|
|
+ if url is None:
|
|
|
+ return ""
|
|
|
+
|
|
|
+ url = url.replace(".git", "")
|
|
|
+ return url
|
|
|
+
|
|
|
+
|
|
|
def install_extension_from_url(dirname, url):
|
|
|
check_access()
|
|
|
|
|
@@ -103,14 +114,15 @@ def install_extension_from_url(dirname, url):
|
|
|
|
|
|
if dirname is None or dirname == "":
|
|
|
*parts, last_part = url.split('/')
|
|
|
- last_part = last_part.replace(".git", "")
|
|
|
+ last_part = normalize_git_url(last_part)
|
|
|
|
|
|
dirname = last_part
|
|
|
|
|
|
target_dir = os.path.join(extensions.extensions_dir, dirname)
|
|
|
assert not os.path.exists(target_dir), f'Extension directory already exists: {target_dir}'
|
|
|
|
|
|
- assert len([x for x in extensions.extensions if x.remote == url]) == 0, 'Extension with this URL is already installed'
|
|
|
+ normalized_url = normalize_git_url(url)
|
|
|
+ assert len([x for x in extensions.extensions if normalize_git_url(x.remote) == normalized_url]) == 0, 'Extension with this URL is already installed'
|
|
|
|
|
|
tmpdir = os.path.join(paths.script_path, "tmp", dirname)
|
|
|
|
|
@@ -128,18 +140,80 @@ def install_extension_from_url(dirname, url):
|
|
|
shutil.rmtree(tmpdir, True)
|
|
|
|
|
|
|
|
|
+def install_extension_from_index(url):
|
|
|
+ ext_table, message = install_extension_from_url(None, url)
|
|
|
+
|
|
|
+ return refresh_available_extensions_from_data(), ext_table, message
|
|
|
+
|
|
|
+
|
|
|
+def refresh_available_extensions(url):
|
|
|
+ global available_extensions
|
|
|
+
|
|
|
+ import urllib.request
|
|
|
+ with urllib.request.urlopen(url) as response:
|
|
|
+ text = response.read()
|
|
|
+
|
|
|
+ available_extensions = json.loads(text)
|
|
|
+
|
|
|
+ return url, refresh_available_extensions_from_data(), ''
|
|
|
+
|
|
|
+
|
|
|
+def refresh_available_extensions_from_data():
|
|
|
+ extlist = available_extensions["extensions"]
|
|
|
+ installed_extension_urls = {normalize_git_url(extension.remote): extension.name for extension in extensions.extensions}
|
|
|
+
|
|
|
+ code = f"""<!-- {time.time()} -->
|
|
|
+ <table id="available_extensions">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th>Extension</th>
|
|
|
+ <th>Description</th>
|
|
|
+ <th>Action</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ """
|
|
|
+
|
|
|
+ for ext in extlist:
|
|
|
+ name = ext.get("name", "noname")
|
|
|
+ url = ext.get("url", None)
|
|
|
+ description = ext.get("description", "")
|
|
|
+
|
|
|
+ if url is None:
|
|
|
+ continue
|
|
|
+
|
|
|
+ existing = installed_extension_urls.get(normalize_git_url(url), None)
|
|
|
+
|
|
|
+ install_code = f"""<input onclick="install_extension_from_index(this, '{html.escape(url)}')" type="button" value="{"Install" if not existing else "Installed"}" {"disabled=disabled" if existing else ""} class="gr-button gr-button-lg gr-button-secondary">"""
|
|
|
+
|
|
|
+ code += f"""
|
|
|
+ <tr>
|
|
|
+ <td><a href="{html.escape(url)}">{html.escape(name)}</a></td>
|
|
|
+ <td>{html.escape(description)}</td>
|
|
|
+ <td>{install_code}</td>
|
|
|
+ </tr>
|
|
|
+ """
|
|
|
+
|
|
|
+ code += """
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ """
|
|
|
+
|
|
|
+ return code
|
|
|
+
|
|
|
+
|
|
|
def create_ui():
|
|
|
import modules.ui
|
|
|
|
|
|
with gr.Blocks(analytics_enabled=False) as ui:
|
|
|
with gr.Tabs(elem_id="tabs_extensions") as tabs:
|
|
|
with gr.TabItem("Installed"):
|
|
|
- extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False)
|
|
|
- extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False)
|
|
|
|
|
|
with gr.Row():
|
|
|
apply = gr.Button(value="Apply and restart UI", variant="primary")
|
|
|
check = gr.Button(value="Check for updates")
|
|
|
+ extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False).style(container=False)
|
|
|
+ extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False).style(container=False)
|
|
|
|
|
|
extensions_table = gr.HTML(lambda: extension_table())
|
|
|
|
|
@@ -157,16 +231,38 @@ def create_ui():
|
|
|
outputs=[extensions_table],
|
|
|
)
|
|
|
|
|
|
+ with gr.TabItem("Available"):
|
|
|
+ with gr.Row():
|
|
|
+ refresh_available_extensions_button = gr.Button(value="Load from:", variant="primary")
|
|
|
+ available_extensions_index = gr.Text(value="https://raw.githubusercontent.com/wiki/AUTOMATIC1111/stable-diffusion-webui/Extensions-index.md", label="Extension index URL").style(container=False)
|
|
|
+ extension_to_install = gr.Text(elem_id="extension_to_install", visible=False)
|
|
|
+ install_extension_button = gr.Button(elem_id="install_extension_button", visible=False)
|
|
|
+
|
|
|
+ install_result = gr.HTML()
|
|
|
+ available_extensions_table = gr.HTML()
|
|
|
+
|
|
|
+ refresh_available_extensions_button.click(
|
|
|
+ fn=modules.ui.wrap_gradio_call(refresh_available_extensions, extra_outputs=[gr.update(), gr.update()]),
|
|
|
+ inputs=[available_extensions_index],
|
|
|
+ outputs=[available_extensions_index, available_extensions_table, install_result],
|
|
|
+ )
|
|
|
+
|
|
|
+ install_extension_button.click(
|
|
|
+ fn=modules.ui.wrap_gradio_call(install_extension_from_index, extra_outputs=[gr.update(), gr.update()]),
|
|
|
+ inputs=[extension_to_install],
|
|
|
+ outputs=[available_extensions_table, extensions_table, install_result],
|
|
|
+ )
|
|
|
+
|
|
|
with gr.TabItem("Install from URL"):
|
|
|
install_url = gr.Text(label="URL for extension's git repository")
|
|
|
install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto")
|
|
|
- intall_button = gr.Button(value="Install", variant="primary")
|
|
|
- intall_result = gr.HTML(elem_id="extension_install_result")
|
|
|
+ install_button = gr.Button(value="Install", variant="primary")
|
|
|
+ install_result = gr.HTML(elem_id="extension_install_result")
|
|
|
|
|
|
- intall_button.click(
|
|
|
+ install_button.click(
|
|
|
fn=modules.ui.wrap_gradio_call(install_extension_from_url, extra_outputs=[gr.update()]),
|
|
|
inputs=[install_dirname, install_url],
|
|
|
- outputs=[extensions_table, intall_result],
|
|
|
+ outputs=[extensions_table, install_result],
|
|
|
)
|
|
|
|
|
|
return ui
|