From c39eea4f51bf29babf16c2d5ab2d6caec4565114 Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Sat, 18 Jul 2026 13:30:34 +0200 Subject: [PATCH] refactor: remove dead code and unused frontend handlers across backend and web --- core/downloader.py | 26 ----- core/sources/civarchive.py | 6 - core/sources/civitai.py | 18 --- tests/test_refactoring_unification.py | 31 ----- tests/test_resolver_robustness.py | 18 +-- tests/test_source_internals.py | 19 ---- web/resolver.js | 1 + web/resolver/actions/queue_methods.js | 18 --- web/resolver/model_resolver.js | 156 -------------------------- 9 files changed, 4 insertions(+), 289 deletions(-) diff --git a/core/downloader.py b/core/downloader.py index 15d5c7c..9e85751 100644 --- a/core/downloader.py +++ b/core/downloader.py @@ -242,32 +242,6 @@ def _is_civitai_api_download_url(url: str) -> bool: ) -def _resolve_civitai_download_url_for_aria2( - url: str, - headers: Optional[Dict[str, str]] = None, -) -> str: - """Resolve CivitAI's API download redirect before handing the URL to aria2.""" - validated_url = validate_public_http_url(url) - if not _is_civitai_api_download_url(validated_url): - return validated_url - - try: - response, resolved_url, _ = request_public_url( - "GET", - validated_url, - headers=build_download_headers(validated_url, headers), - timeout=20, - stream=True, - max_redirects=1, - ) - response.close() - log.debug("Resolved CivitAI download redirect for aria2") - return resolved_url - except Exception as exc: - log.warning(f"Could not pre-resolve CivitAI download URL for aria2: {exc}") - return validated_url - - def _resolve_download_url_for_aria2( url: str, headers: Optional[Dict[str, str]] = None, diff --git a/core/sources/civarchive.py b/core/sources/civarchive.py index 8a80b8f..99b117a 100644 --- a/core/sources/civarchive.py +++ b/core/sources/civarchive.py @@ -1969,12 +1969,6 @@ def _is_hash_verified_exact_match(result: Optional[Dict[str, Any]], confidence: return bool(result.get("sha256") or result.get("hash")) - - -def _build_search_queries(filename: str) -> List[str]: - return build_filename_search_queries(filename) - - def search_civarchive( query: str, model_type: Optional[str] = None, diff --git a/core/sources/civitai.py b/core/sources/civitai.py index 0f52319..e43a1b1 100644 --- a/core/sources/civitai.py +++ b/core/sources/civitai.py @@ -1252,24 +1252,6 @@ def _enrich_model_info_with_details( return result -def search_civitai_by_hash( - hash_value: str, api_key: Optional[str] = None -) -> Optional[Dict[str, Any]]: - """Look up a model by file hash on CivitAI.""" - result = get_model_info_by_hash(hash_value, api_key=api_key, use_cache=False) - if not result: - return None - return { - "source": result.get("source"), - "model_id": result.get("model_id"), - "version_id": result.get("version_id"), - "name": result.get("model_name") or result.get("name", ""), - "url": result.get("url"), - "download_url": result.get("download_url"), - "filename": result.get("filename", ""), - "size": result.get("size"), - } - def resolve_urn( model_id: int, version_id: int, api_key: Optional[str] = None diff --git a/tests/test_refactoring_unification.py b/tests/test_refactoring_unification.py index 7b1eef0..7bfc7ef 100644 --- a/tests/test_refactoring_unification.py +++ b/tests/test_refactoring_unification.py @@ -8,7 +8,6 @@ if parent_dir not in sys.path: sys.path.insert(0, parent_dir) from core.matcher import MODEL_TITLE_MATCH_THRESHOLD -from core.sources.civitai import search_civitai_by_hash from core.sources.lora_manager_archive import _normalize_model_type from core.type_utils import ( normalize_lora_manager_type, @@ -65,36 +64,6 @@ class TestRefactoringUnification(unittest.TestCase): self.assertEqual(res["filename"], "test.safetensors") self.assertEqual(res["extra_field"], "hello_world") - @patch("core.sources.civitai.get_model_info_by_hash") - def test_search_civitai_by_hash(self, mock_get_info): - mock_get_info.return_value = { - "source": "civitai", - "model_id": 500, - "version_id": 600, - "model_name": "My Civitai Model", - "url": "http://civitai/model", - "download_url": "http://civitai/download", - "filename": "my_model.safetensors", - "size": 9999, - } - res = search_civitai_by_hash("fake_hash", "fake_key") - mock_get_info.assert_called_once_with("fake_hash", api_key="fake_key", use_cache=False) - self.assertIsNotNone(res) - self.assertEqual(res["source"], "civitai") - self.assertEqual(res["model_id"], 500) - self.assertEqual(res["version_id"], 600) - self.assertEqual(res["name"], "My Civitai Model") - self.assertEqual(res["url"], "http://civitai/model") - self.assertEqual(res["download_url"], "http://civitai/download") - self.assertEqual(res["filename"], "my_model.safetensors") - self.assertEqual(res["size"], 9999) - - @patch("core.sources.civitai.get_model_info_by_hash") - def test_search_civitai_by_hash_not_found(self, mock_get_info): - mock_get_info.return_value = None - res = search_civitai_by_hash("fake_hash") - self.assertIsNone(res) - @patch("requests.get") def test_request_page_text_success(self, mock_get): from core.sources.civarchive import _request_page_text diff --git a/tests/test_resolver_robustness.py b/tests/test_resolver_robustness.py index e8623fe..abafca1 100644 --- a/tests/test_resolver_robustness.py +++ b/tests/test_resolver_robustness.py @@ -14,7 +14,7 @@ from core.downloader import ( get_metadata_sidecar_path, download_model, get_progress, - _resolve_civitai_download_url_for_aria2, + _resolve_download_url_for_aria2, start_aria2_daemon, _delete_partial_download_files, download_progress, @@ -307,10 +307,8 @@ class ModelResolverRobustnessTests(unittest.TestCase): def test_civitai_redirection_link_resolution_for_aria2(self): """ Covers Integration Requirement: Redirect resolution for Aria2. - Verifies _resolve_civitai_download_url_for_aria2 pre-resolves redirect URLs, - and skips non-CivitAI URL requests completely. + Verifies _resolve_download_url_for_aria2 pre-resolves redirect URLs. """ - # Scenario 1: CivitAI URL redirect api_url = "https://civitai.com/api/download/models/123" redirect_url = "https://civitai-delivery.net/models/123/model.safetensors?token=abc" @@ -328,20 +326,10 @@ class ModelResolverRobustnessTests(unittest.TestCase): "core.network_utils.validate_public_http_url", side_effect=lambda value: value, ): - resolved = _resolve_civitai_download_url_for_aria2(api_url) + resolved, _ = _resolve_download_url_for_aria2(api_url) self.assertEqual(resolved, redirect_url) self.assertEqual(mock_get.call_count, 2) - # Scenario 2: Non-CivitAI URL (e.g. HuggingFace) should bypass redirects immediately - hf_url = "https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/model.safetensors" - with patch("requests.get") as mock_get_hf, patch( - "core.downloader.validate_public_http_url", - side_effect=lambda value: value, - ): - resolved_hf = _resolve_civitai_download_url_for_aria2(hf_url) - self.assertEqual(resolved_hf, hf_url) - mock_get_hf.assert_not_called() - def test_job_progress_tracker_clamping_and_thread_safety(self): """ Covers Requirement: Thread-safe progress tracking and validation. diff --git a/tests/test_source_internals.py b/tests/test_source_internals.py index 38eac75..910d1d3 100644 --- a/tests/test_source_internals.py +++ b/tests/test_source_internals.py @@ -29,7 +29,6 @@ from core.sources.civarchive import ( _normalize_archive_version, parse_civarchive_url, _prepare_size_probe_url, - _build_search_queries, ) # --------------------------------------------------------------------------- @@ -483,24 +482,6 @@ class PrepareSizeProbeUrlTests(unittest.TestCase): self.assertIsNone(_prepare_size_probe_url(None)) -# =========================================================================== -# civarchive - _build_search_queries -# =========================================================================== -class BuildSearchQueriesTests(unittest.TestCase): - - def test_returns_list_of_strings(self): - result = _build_search_queries("my_model_v2.safetensors") - self.assertIsInstance(result, list) - self.assertTrue(all(isinstance(q, str) for q in result)) - - def test_non_empty_for_valid_filename(self): - result = _build_search_queries("cool-lora-style_v1.safetensors") - self.assertGreater(len(result), 0) - - def test_empty_string_returns_list(self): - result = _build_search_queries("") - self.assertIsInstance(result, list) - # =========================================================================== # civitai - parse_civitai_url diff --git a/web/resolver.js b/web/resolver.js index 220ece9..2ea3fce 100644 --- a/web/resolver.js +++ b/web/resolver.js @@ -40,5 +40,6 @@ app.registerExtension({ }, afterConfigureGraph() { modelResolver.configureWorkflowDependencyMarkerNodes(); + modelResolver.checkAndOpenForMissingModels(); }, }); diff --git a/web/resolver/actions/queue_methods.js b/web/resolver/actions/queue_methods.js index 68cfab1..2ce9982 100644 --- a/web/resolver/actions/queue_methods.js +++ b/web/resolver/actions/queue_methods.js @@ -1540,11 +1540,6 @@ export const queueMethods = { } }, - // Collapse/expand queue panel - toggleQueueCollapsed() { - this.setQueueCollapsed(!this.queueCollapsed); - }, - setQueueCollapsed(collapsed, { persist = true, updatePanel = true } = {}) { const nextCollapsed = !!collapsed; const wasCollapsed = !!this.queueCollapsed; @@ -2907,19 +2902,6 @@ export const queueMethods = { } }, - /** - * Handle click on Download All / Cancel All button - */ - handleDownloadAllClick() { - if (this.getActiveQueuePanelDownloadIds().length > 0) { - // Cancel all active downloads - this.cancelAllDownloads(); - } else { - // Start downloading all missing - this.downloadAllMissing(); - } - }, - /** * Cancel all active downloads */ diff --git a/web/resolver/model_resolver.js b/web/resolver/model_resolver.js index 096bedb..ea4fe56 100644 --- a/web/resolver/model_resolver.js +++ b/web/resolver/model_resolver.js @@ -1059,162 +1059,6 @@ export class ModelResolver { // Run auto-resolve for 100% matches - returns the updated workflow const updatedWorkflow = await this.dialog.autoResolve100Percent(); - // Always open Model Resolver to show remaining unresolved models - // Pass the updated workflow if available to avoid race condition - this.dialog.show(updatedWorkflow || null); - } - - /** - * Mark resolved model items in the popup as linked (green) and hide download buttons - */ - removeResolvedFromPopup(dialog, resolvedFilenames) { - log.debug('Model Resolver: Looking for resolved filenames:', resolvedFilenames); - - // Strategy: For each filename, find text nodes containing it, - // then find the nearest Download button and mark that row - for (const filename of resolvedFilenames) { - // Get all text in the dialog and find elements containing our filename - const walker = document.createTreeWalker( - dialog, - NodeFilter.SHOW_TEXT, - null, - false - ); - - let node; - while ((node = walker.nextNode())) { - if (node.textContent?.toLowerCase().includes(filename)) { - // Found text containing filename - now find parent with Download button - let parent = node.parentElement; - let attempts = 0; - - while (parent && parent !== dialog && attempts < 10) { - // Look for Download button at this level - const downloadBtn = Array.from(parent.querySelectorAll('button')) - .find(btn => btn.textContent?.includes('Download') && - !btn.id?.includes('model-resolver')); - - if (downloadBtn) { - log.debug('Model Resolver: Found entry for', filename); - this.markEntryAsResolved(parent, downloadBtn); - break; - } - - parent = parent.parentElement; - attempts++; - } - - // Only process first match for this filename - break; - } - } - } - } - - /** - * Mark a model entry as resolved with visual feedback - */ - markEntryAsResolved(container, downloadBtn) { - // Already marked? - if (container.dataset.resolved === 'true') return; - container.dataset.resolved = 'true'; - - log.debug('Model Resolver: Marking entry as resolved', container); - - // Add green background/styling to the container - container.classList.add('mr-resolved-entry'); - - // Hide the Download button and replace with badge - if (downloadBtn) { - // Create badge - const badge = document.createElement('span'); - badge.className = 'mr-resolved-badge'; - badge.textContent = '✓ Linked'; - - // Replace download button with badge - downloadBtn.style.display = 'none'; - downloadBtn.parentElement?.insertBefore(badge, downloadBtn); - } - - // Find and hide Copy URL button - const allBtns = container.querySelectorAll('button'); - for (const btn of allBtns) { - if (btn.textContent?.includes('Copy URL')) { - btn.style.display = 'none'; - } - } - } - - /** - * Count remaining model items in the popup - */ - countRemainingItems(dialog) { - // Count elements that look like model entries (have Download buttons) - const downloadButtons = dialog.querySelectorAll('button'); - let count = 0; - for (const btn of downloadButtons) { - if (btn.textContent?.includes('Download') && !btn.id?.includes('model-resolver')) { - count++; - } - } - return count; - } - - /** - * Update nodes directly in the graph without triggering a full workflow reload - * This prevents the Missing Models popup from closing - */ - updateNodesDirectly(resolutions) { - if (!app?.graph) { - console.warn('Model Resolver: Cannot update nodes - graph not available'); - return; - } - - for (const resolution of resolutions) { - const nodeId = resolution.node_id; - const widgetIndex = resolution.widget_index; - const resolvedPath = resolution.resolved_path; - - // Find the node in the graph - const node = app.graph.getNodeById(nodeId); - if (!node) { - console.warn(`Model Resolver: Node ${nodeId} not found in graph`); - continue; - } - - // Update the widget value - if (node.widgets && node.widgets[widgetIndex]) { - const widget = node.widgets[widgetIndex]; - widget.value = resolvedPath; - - // Trigger widget callback if it exists - if (widget.callback) { - widget.callback(resolvedPath, app.graph, node, null, null); - } - - log.debug(`Model Resolver: Updated node ${nodeId} widget ${widgetIndex} to ${resolvedPath}`); - } else if (node.widgets_values) { - // Fallback: update widgets_values array directly - node.widgets_values[widgetIndex] = resolvedPath; - log.debug(`Model Resolver: Updated node ${nodeId} widgets_values[${widgetIndex}] to ${resolvedPath}`); - } - - // Mark node as dirty to trigger redraw - if (node.setDirtyCanvas) { - node.setDirtyCanvas(true, true); - } - } - - // Trigger canvas redraw - if (app.graph.setDirtyCanvas) { - app.graph.setDirtyCanvas(true, true); - } - } - - /** - * Check if auto-open is enabled in user settings - */ - isAutoOpenEnabled() { return localStorage.getItem('ModelResolver.autoOpenOnMissing') !== 'false'; }