Skip to content

Add Relink Textures tool to pyRevitTools#2883

Merged
jmcouffin merged 22 commits intopyrevitlabs:developfrom
Swichllc:develop
Oct 28, 2025
Merged

Add Relink Textures tool to pyRevitTools#2883
jmcouffin merged 22 commits intopyrevitlabs:developfrom
Swichllc:develop

Conversation

@Swichllc
Copy link
Copy Markdown
Contributor

New Tool: Relink Textures

Description: Automates finding and relinking missing texture paths in Revit materials

Location: pyRevit tab > Modify panel

Features:

  • Automatically finds missing textures
  • Relinks paths in seconds
  • Search for textures not just location, in case someone moved the files

Testing: Tested on Revit 2025

## New Tool:  Relink Textures

**Description:** Automates finding and relinking missing texture paths in Revit materials

**Location:** pyRevit tab > Modify panel

**Features:**
- Automatically finds missing textures
- Relinks paths in seconds
- Search for textures not just location, in case someone moved the files

**Testing:** Tested on Revit 2025
@tay0thman tay0thman self-assigned this Oct 23, 2025
@tay0thman
Copy link
Copy Markdown
Contributor

@Swichllc Added few comments on the structure of the script, I will fetch the PR and test it locally before running code review.

@tay0thman
Copy link
Copy Markdown
Contributor

also please propose a different location, I would suggest having it under the project/ links pulldown button

This is not an everyday tool so it should not take a full stack.

@Swichllc
Copy link
Copy Markdown
Contributor Author

@tay0thman
I'll work on these comments, as I mentioned in the forum, before I got the green light to create PR, Im very new to all of this and Im using AI to build it, so it could use a review.
**For the dark/light mode - besides adding "icon_dark.png" I couldn't find the answer on how to force dark/light mode on the icon, that solution didn't work when I tested it with a new icon that match the pyRevit icons.
**For the location - a few thoughts - Links is a bit confusing since its a very specific term and flow, same with Family - right now I don't see anything relevant, so I added it under Project, since its a general action needed to do once per project.
From a users' perspective, if the previous placement is an issue, What I suggest is to create a new pulldown menu Project/Textures so its not a large standalone, and it can include more texture related commands - I have a few more tools ideas in that area.

@jmcouffin
Copy link
Copy Markdown
Contributor

**For the dark/light mode - besides adding "icon_dark.png" I couldn't find the answer on how to force dark/light mode on the icon, that solution didn't work when I tested it with a new icon that match the pyRevit icons.

use the icons8 website to find one.
download to 96px png
icon.png for the regular UI
icon.dark.png for the Dark theme

Comment on lines +310 to +337
t = Transaction(doc, "Relink material textures")

try:
t.Start()

for a_elem in assets:
if not isinstance(a_elem, AppearanceAssetElement):
continue

examined += 1
scope = None

try:
scope = AppearanceAssetEditScope(doc)
editable = scope.Start(a_elem.Id)
fixed_count += relink_asset(editable, roots, name_index, unresolved)
scope.Commit(True)
except Exception as ex:
logger.error("Asset edit failed for {}: {}".format(a_elem.Name, ex))
finally:
if scope:
try:
scope.Dispose()
except:
pass

t.Commit()
logger.info("Transaction committed successfully")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more pyrevit like would be

with revit.Transaction("do stuff"):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also wrapping large chunks of code using try / except is highly risky, the logic should be controlled as much as possible

Comment on lines +372 to +380
# Check if SHIFT is pressed for quick-config
shift_click = False
try:
shift_click = __shiftclick__
except:
pass

if shift_click:
run_config()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you can skip the try. Also according to notion you should use EXEC_PARAMS.config_mode

@jmcouffin
Copy link
Copy Markdown
Contributor

@Swichllc are you comfortable enough to make all these changes?

@Swichllc
Copy link
Copy Markdown
Contributor Author

@jmcouffin yes, I'm very comfortable to try fixing it.
But I'll update you if I come across a problem I can't solve.
Thank you

Refactored script.py to use pyRevit's config API instead of manual JSON file management, improved error handling, and modularized asset collection and processing. Updated icon.png and added icon_dark.png for better UI support. The code now uses more robust directory traversal, transaction management, and provides clearer user feedback.
@Swichllc
Copy link
Copy Markdown
Contributor Author

@jmcouffin @tay0thman @Wurschdhaud

  1. I have attempted to make the changes - some of them caused the search to crash, and I couldn't pinpoint which one so I pivoted.
  2. Scanning an entire drive (c:/ for example) still works, it is not as fast as it was with the original code, but it still works, even though that is the extreme case, I do believe it necessary to make sure it possible.
  3. Location is still the same - besides creating a new Textures dropdown in Project.Panel, and add more texture related tools in the future, I still think its a standalone function that would be used once per project, if you guys think it should be somewhere else I will not object.
  4. At this point if there are crucial code issue, since Im a newbie, any help would be appreciated.
  5. Icons are png 96x96 with dark and light versions
    Thank you

@jmcouffin
Copy link
Copy Markdown
Contributor

3. Location is still the same - besides creating a new Textures dropdown in Project.Panel, and add more texture related tools in the future, I still think its a standalone function that would be used once per project, if you guys think it should be somewhere else I will not object.

I would put it under the modify panel in the edit drowpdown

4. At this point if there are crucial code issue, since Im a newbie, any help would be appreciated.

Will review and polish this week if needed

Added translations for bundle.yaml
…on management

- Introduced ConfigurationManager, TextureIndexer, AssetProcessor, and TextureRelinker classes for better organization and separation of concerns.
- Improved error handling and logging throughout the asset processing and relinking workflow.
- Updated the main execution flow to utilize the new class structure, enhancing readability and maintainability.
- Retained existing functionality while streamlining the user interface for managing texture search folders.
- Introduced constants for transaction names and log formatting to improve code readability and maintainability.
- Updated the configuration management to use a constant key for texture folders, enhancing clarity.
- Improved logging output consistency by replacing hardcoded strings with defined constants.
- Added a method to validate folder accessibility before adding to the configuration.
- Improved error handling for invalid asset elements and edit scope failures.
- Streamlined logging to provide clearer feedback on folder and asset processing issues.
- Integrated progress bars for texture indexing and asset relinking processes to provide real-time feedback to users.
- Updated logging to reflect the number of indexed files and processing status of assets, improving overall user experience.
- Maintained existing functionality while enhancing the visual feedback during lengthy operations.
… Relink Textures script

- Added caching for texture index to enhance performance during repeated operations.
- Introduced a method to clear the texture index cache when folder configurations change.
- Improved folder validation by implementing a caching mechanism to reduce redundant checks.
- Updated TextureIndexer to utilize cached data for faster directory validation and indexing.
- Enhanced logging to provide clearer feedback on caching operations and folder validation results.
- Updated exception handling in ConfigurationManager, TextureIndexer, and AssetProcessor to catch specific error types (OSError, IOError, ValueError, AttributeError) for improved robustness.
- Added initialization documentation for ConfigurationManager, TextureIndexer, and AssetProcessor classes to clarify their purpose and usage.
- Streamlined progress updates during texture indexing to focus on essential information, enhancing user feedback.
@jmcouffin jmcouffin added the Tools Issues related to pyRevit commands [subsystem] label Oct 27, 2025
- Eliminated various logger.info and logger.debug calls to reduce clutter in the output.
- Streamlined the texture indexing and relinking processes by focusing on essential information.
- Improved overall readability of the script by removing redundant log messages.
@jmcouffin
Copy link
Copy Markdown
Contributor

I went through, did a lot of cleaning, reorganizing, some with cursor, some without.
It seems to work smoothly. I tried to go as granular as I could with the time I had.
Would you mind testing it @Swichllc and @tay0thman ?

@Swichllc
Copy link
Copy Markdown
Contributor Author

Swichllc commented Oct 27, 2025

@jmcouffin
image
Screenshot 2025-10-27 193752

image

I tested it and it seems to miss the mark, it didnt find or relink any texture, as you can see in the screenshot.
I also didnt get the report of which textures could not be found.
I ran the original code with the same Revit project, same folder setup, and you can see the amount of textures it found and relink.

…script

- Updated the get_all_roots method to only retrieve folders from configuration, removing the project directory check.
- Enhanced relink_asset_textures and process_single_asset methods to accept roots directly, improving clarity and reducing dependency on the indexer.
- Added detailed output for texture indexing diagnostics, including the number of root folders indexed and total unique filenames processed.
- Improved overall structure and readability of the script while maintaining existing functionality.
…cript

- Simplified the retrieval of texture folder configurations by directly using the configuration key.
- Enhanced the show_main_menu method to provide a unified interface for folder management and relinking options.
- Removed unnecessary logging statements to improve script clarity and focus on essential user interactions.
- Streamlined the process for adding, removing, and clearing texture folders, enhancing user experience.
- Removed logger dependency from ConfigurationManager, TextureIndexer, and AssetProcessor classes to simplify initialization.
- Streamlined folder management logic in show_main_menu method for improved user experience.
- Enhanced error handling by directly using logger for warnings and errors, reducing redundancy.
- Cleaned up unnecessary validation checks and improved overall script readability.
- Replaced ProgressBar with log messages to provide clearer feedback during texture indexing and relinking processes.
- Enhanced output messages to inform users about the number of folders indexed and textures relinked.
- Streamlined the user alert messages for better clarity and user experience.
@jmcouffin
Copy link
Copy Markdown
Contributor

Reviewed the user flow, simplified some checks and properly tested it this time.
@Swichllc this should improve the whole user experience.
If you are happy with it as well, I will merge this PR

- Refactored the build_index method to utilize glob for recursive texture file searching, improving performance and accuracy.
- Introduced a list of common texture file extensions to streamline the indexing process.
- Added logic to skip specific directories during indexing to enhance efficiency.
- Updated logging to reflect the number of unique texture files found, providing clearer feedback to users.
- Introduced filtering for common texture file extensions to improve indexing accuracy.
- Added logic to skip specific directories during the indexing process for enhanced performance.
- Updated the directory traversal to ensure hidden folders are excluded, streamlining the indexing operation.
@Swichllc
Copy link
Copy Markdown
Contributor Author

@jmcouffin tested, its working - thank you for helping me with this
It is missing the completion report (attached image), but it does give the error report
Im ok without it right now
image

@jmcouffin jmcouffin merged commit 865eb88 into pyrevitlabs:develop Oct 28, 2025
@jmcouffin
Copy link
Copy Markdown
Contributor

@Swichllc I felt the number of assets examined (and counted) was not a crucial info. I left the "Textures relinked" in the output window + unresolved list as well.

@jmcouffin
Copy link
Copy Markdown
Contributor

Thanks for this tool. This is a great addition

@Swichllc
Copy link
Copy Markdown
Contributor Author

@jmcouffin Perfect, Thank you again

@github-actions
Copy link
Copy Markdown
Contributor

📦 New work-in-progress (wip) builds are available for 5.2.0.25301+1412-wip

@github-actions
Copy link
Copy Markdown
Contributor

📦 New work-in-progress (wip) builds are available for 5.2.0.25301+1521-wip

@github-actions
Copy link
Copy Markdown
Contributor

📦 New work-in-progress (wip) builds are available for 5.2.0.25302+0921-wip

@github-actions
Copy link
Copy Markdown
Contributor

📦 New work-in-progress (wip) builds are available for 5.2.0.25302+0949-wip

@github-actions
Copy link
Copy Markdown
Contributor

📦 New work-in-progress (wip) builds are available for 5.2.0.25302+1503-wip

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 3, 2025

📦 New work-in-progress (wip) builds are available for 5.2.0.25307+1644-wip

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 3, 2025

📦 New work-in-progress (wip) builds are available for 5.2.0.25307+1935-wip

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 3, 2025

📦 New work-in-progress (wip) builds are available for 5.2.0.25307+2011-wip

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 3, 2025

📦 New work-in-progress (wip) builds are available for 5.2.0.25307+2045-wip

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 3, 2025

📦 New work-in-progress (wip) builds are available for 5.3.0.25307+2237-wip

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 4, 2025

📦 New work-in-progress (wip) builds are available for 5.3.0.25308+0721-wip

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 4, 2025

📦 New public release are available for 5.3.0.25307+2146

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Tools Issues related to pyRevit commands [subsystem]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants