from . import ( activity_log, audio_catalog, folder_types, gallery_routes, materials, media_routes, model_catalog, model_folder, model_media, model_metadata, model_resolution, model_type_listing, kept_images, quick_index, node_material, recipe_packages, recipes, scan_choice, scan_report, scan_summary, local_guard, lora_info, mcp_server, model_download, model_import, model_placement, translation_routes, version_manager, tts_version, backup, network_check, model_heads, model_usage, usage_ledger, sidecar_layout, ai_tasks_routes, snapshot_routes, workflow_saves, example_workflows, ) from .scanner import * from .config import * from .notebooks import * from .parameters import * import os from aiohttp import web # ComfyUI serves the web folder under the plugin folder's own name, whatever it is called. EXTENSION_STATIC_PREFIX = f'/extensions/{os.path.basename(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))}/' @web.middleware async def no_cache_extension_middleware(request, handler): """Make browsers revalidate this plugin's JS/CSS so a normal refresh picks up updates. `no-cache` still allows 304 responses via ETag/Last-Modified. This replaces per-import `?v=` query strings, which load a second module instance whenever two files import the same module with different URLs. """ response = await handler(request) if request.path.startswith(EXTENSION_STATIC_PREFIX): response.headers['Cache-Control'] = 'no-cache' return response def setup_routes(app): model_heads.keep_on_disk() if hasattr(app, 'middlewares') and no_cache_extension_middleware not in app.middlewares: app.middlewares.append(no_cache_extension_middleware) # Other devices on the network may look; only this computer may change things (local_guard.py). if hasattr(app, 'middlewares') and local_guard.local_only_middleware not in app.middlewares: app.middlewares.append(local_guard.local_only_middleware) app.router.add_get('/anomalous/access', local_guard.api_access) app.router.add_post('/anomalous/snapshot_check', snapshot_routes.api_snapshot_check) app.router.add_get('/anomalous/saves', workflow_saves.api_list) app.router.add_get('/anomalous/saves/group', workflow_saves.api_group) app.router.add_get('/anomalous/saves/workflow', workflow_saves.api_workflow) app.router.add_post('/anomalous/saves/add', workflow_saves.api_add) app.router.add_post('/anomalous/saves/update', workflow_saves.api_update) app.router.add_post('/anomalous/saves/ran', workflow_saves.api_ran) app.router.add_post('/anomalous/saves/remove', workflow_saves.api_remove) app.router.add_post('/anomalous/saves/remove_group', workflow_saves.api_remove_group) try: folder_types.upgrade_folder_defaults() except Exception as error: print(f"[Anomalous Browser] Could not update the shown model folders: {error}") app.router.add_get('/anomalous/folders', model_catalog.api_get_folders) app.router.add_get('/anomalous/all_folder_types', folder_types.api_get_all_folder_types) app.router.add_get('/anomalous/models', model_catalog.api_get_models) app.router.add_get('/anomalous/type_models', model_type_listing.api_get_type_models) app.router.add_get('/anomalous/all_scan_models', model_catalog.api_get_all_scan_models) app.router.add_get('/anomalous/image', media_routes.api_serve_image) app.router.add_get('/anomalous/card_cache', media_routes.api_card_cache) app.router.add_post('/anomalous/card_cache/clear', media_routes.api_clear_card_cache) app.router.add_post('/anomalous/scan', api_scan_folder) app.router.add_get('/anomalous/scan_status', api_scan_status) app.router.add_get('/anomalous/find_model', model_catalog.api_find_model) app.router.add_get('/anomalous/config', api_get_config) app.router.add_post('/anomalous/save_config', api_save_config) app.router.add_post('/anomalous/delete_model', model_metadata.api_delete_model) app.router.add_post('/anomalous/open_model_folder', model_folder.api_open_model_folder) app.router.add_get('/anomalous/compatible_models', model_catalog.api_compatible_models) app.router.add_get('/anomalous/notebooks', api_get_notebooks) app.router.add_get('/anomalous/notebooks/by_node_type', api_get_notebooks_by_node_type) app.router.add_post('/anomalous/save_notebook', api_save_notebook) app.router.add_post('/anomalous/delete_notebook', api_delete_notebook) # Parameter Routes app.router.add_get('/anomalous/parameters', api_get_parameters) app.router.add_get('/anomalous/parameters/by_node_type', api_get_parameters_by_type) app.router.add_get('/anomalous/parameters/signatures', api_get_parameter_set_signatures) app.router.add_post('/anomalous/save_parameter', api_save_parameter) app.router.add_post('/anomalous/rename_parameter', api_rename_parameter) app.router.add_post('/anomalous/delete_parameter', api_delete_parameter) app.router.add_get('/anomalous/parameter_gallery', api_get_parameter_gallery) app.router.add_get('/anomalous/parameter_pictures', api_get_parameter_pictures) # Recipe Routes app.router.add_get('/anomalous/recipes', recipes.api_get_recipes) app.router.add_get('/anomalous/example_workflows', example_workflows.api_examples) app.router.add_get('/anomalous/recipe_full', recipes.api_get_recipe_full) app.router.add_get('/anomalous/recipe_asset', recipes.api_get_recipe_asset) app.router.add_get('/anomalous/recipe_gallery', recipes.api_get_recipe_gallery) app.router.add_get('/anomalous/recipe_parameter_gallery', recipes.api_get_recipe_parameter_gallery) app.router.add_get('/anomalous/recipe_gallery_compare', recipes.api_get_recipe_gallery_compare) app.router.add_post('/anomalous/save_recipe', recipes.api_save_recipe) app.router.add_post('/anomalous/update_recipe', recipes.api_update_recipe) app.router.add_post('/anomalous/recipe_focus', recipes.api_set_recipe_focus) app.router.add_post('/anomalous/set_recipe_gallery_cover', recipes.api_set_recipe_gallery_cover) app.router.add_post('/anomalous/delete_recipe', recipes.api_delete_recipe) app.router.add_get('/anomalous/recipe_history', recipes.api_get_recipe_history) app.router.add_get('/anomalous/recipe_version', recipes.api_get_recipe_version) app.router.add_post('/anomalous/restore_recipe_version', recipes.api_restore_recipe_version) app.router.add_post('/anomalous/refresh_recipe_identity', recipes.api_refresh_recipe_identity) app.router.add_post('/anomalous/export_recipe_package', recipe_packages.api_export_recipe_package) app.router.add_post('/anomalous/import_recipe_package_inspect', recipe_packages.api_import_recipe_package_inspect) app.router.add_post('/anomalous/import_recipe_package_commit', recipe_packages.api_import_recipe_package_commit) # Curated Material Library Routes app.router.add_get('/anomalous/materials', materials.api_get_materials) app.router.add_get('/anomalous/material_full', materials.api_get_material_full) app.router.add_get('/anomalous/material_asset', materials.api_get_material_asset) app.router.add_get('/anomalous/materials/by_node_type', materials.api_get_materials_by_node_type) app.router.add_post('/anomalous/inspect_image_material', materials.api_inspect_image_material) app.router.add_post('/anomalous/save_image_material', materials.api_save_image_material) app.router.add_post('/anomalous/save_prompt_plan', materials.api_save_prompt_plan) app.router.add_post('/anomalous/save_node_material', node_material.api_save_node_material) app.router.add_post('/anomalous/delete_material', materials.api_delete_material) app.router.add_post('/anomalous/update_material', materials.api_update_material) app.router.add_post('/anomalous/mark_material_moved', materials.api_mark_material_moved) app.router.add_post('/anomalous/translate', translation_routes.api_translate) app.router.add_get('/anomalous/base_models', model_catalog.api_base_models) app.router.add_get('/anomalous/gallery_images', gallery_routes.api_get_gallery_images) app.router.add_post('/anomalous/delete_gallery_image', gallery_routes.api_delete_gallery_image) app.router.add_get('/anomalous/output_thumbnail', gallery_routes.api_output_thumbnail) app.router.add_get('/anomalous/output_preview', gallery_routes.api_output_preview) app.router.add_get('/anomalous/kept_images', kept_images.api_kept_images) app.router.add_get('/anomalous/quick_index', quick_index.api_quick_index) app.router.add_get('/anomalous/resolve_hash', model_resolution.api_resolve_hash) app.router.add_post('/anomalous/resolve_hash_batch', model_resolution.api_resolve_hash_batch) app.router.add_get('/anomalous/all_hashes', model_resolution.api_get_all_hashes) app.router.add_post('/anomalous/scan_all', api_scan_all) app.router.add_get('/anomalous/global_scan_status', api_global_scan_status) app.router.add_post('/anomalous/clear_cache', media_routes.api_clear_cache) app.router.add_post('/anomalous/update_metadata', model_metadata.api_update_metadata) app.router.add_post('/anomalous/set_custom_cover', model_media.api_set_custom_cover) app.router.add_post('/anomalous/upload_custom_cover', model_media.api_upload_custom_cover) app.router.add_get('/anomalous/model_covers', model_media.api_model_covers) app.router.add_get('/anomalous/model_images', media_routes.api_get_model_images) app.router.add_post('/anomalous/resolve_paths_to_previews', model_catalog.api_resolve_paths_to_previews) app.router.add_get('/anomalous/scan_summary', scan_summary.api_scan_summary) app.router.add_get('/anomalous/scan_matched', scan_summary.api_scan_matched) app.router.add_get('/anomalous/scan_pickable', scan_summary.api_scan_pickable) app.router.add_get('/anomalous/last_scan', scan_report.api_last_scan) app.router.add_get('/anomalous/scan_model', scan_report.api_scan_model) app.router.add_post('/anomalous/scan_choice', scan_choice.api_set_scan_choice) app.router.add_get('/anomalous/lora_info', lora_info.api_lora_info) # Audio & Voice Studio Routes app.router.add_get('/anomalous/audio_stream', audio_catalog.api_serve_audio) app.router.add_get('/anomalous/audio_gallery', audio_catalog.api_get_audio_gallery) app.router.add_post('/anomalous/delete_audio_gallery', audio_catalog.api_delete_audio_gallery) app.router.add_get('/anomalous/audio_previews', audio_catalog.api_get_audio_previews) app.router.add_post('/anomalous/save_audio_preview', audio_catalog.api_save_audio_preview) version_manager.register_routes(app) tts_version.register_routes(app) activity_log.register_routes(app) mcp_server.register_routes(app) ai_tasks_routes.register_routes(app) model_download.register_routes(app) network_check.register_routes(app) model_usage.register_routes(app) usage_ledger.register_routes(app) sidecar_layout.register_routes(app) model_import.register_routes(app) model_placement.register_routes(app) backup.register_routes(app)