• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

how can I find an sbs file outputting certain texture name on win10?

Explorer ,
Nov 07, 2024 Nov 07, 2024

Copy link to clipboard

Copied

I asume it could be  done  by reading    with "find text" option  in something like total commander ?     is there any easy quick  method?

TOPICS
How to , Substance Graph

Views

157

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Nov 18, 2024 Nov 18, 2024

Hey Kirill,

I have now a folder in my scripts directory named "for_kirill", because you have so many great ideas and I hope to make them all happen.

For this one, here is a working prototype, not the nicest UI and not really tested, but it should serve the purpose.

Just copy this code and run it in the SD Python Editor (see the attached video, for a quick demo)

 

 

import xml.etree.ElementTree as ET
import os

import sd  # type: ignore
from PySide6 import QtWidgets
from PySide6 import QtGui


cl
...

Votes

Translate

Translate
Adobe Employee ,
Nov 13, 2024 Nov 13, 2024

Copy link to clipboard

Copied

Hello,

 

Indeed, considering SBS files use the XML format they are quite easy to parse. You can check the 'options' tag for export options, which should include output names, file names and destination path.

 

Here is a sample :

<options>
    <option>
        <name v="export/fromGraph/outputs/metallic"/>
        <value v="true"/>
    </option>
    <option>
        <name v="export/fromGraph/pattern"/>
        <value v="$(graph)_$(identifier)_$(colorspace)"/>
    </option>
</options>

 

I hope this is helpful!

 

Best regards. 

Luca Giarrizzo | Quality Engineer, 3D & Immersive | Adobe

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Nov 13, 2024 Nov 13, 2024

Copy link to clipboard

Copied

Sorry I am not sure I understand .   For example  I remember one of my sbs files should have a graph  "grass3_3 "  and output  grass3_3_nm.tga

While the sbs itself is named other way  and I don;t remember how  exactly.  Includes many  outputs  and versions.     In your example I see nothing  like graph or file name .

I accustomed to use "total commander"  . it has "find text" in  search  dialog.   It has many  options   and one of them is   "office xml +EPUB "  and also like : UTF8, unicode UTF16, Hex, RegEX, ANSI chrseet (windows),  ANSII Dos.     Sometimes I can't find specific thing in a project folder while  100% sure the graph of my interest  should be  there.      So should "office xml"   be enough  or shoold I include other encoding options?       Maybe a way to do it in Windows file explorer itself or Adobe bridge?   What would be an easy way?

 

Would be nice probably if sbs file could list  its content as keywords, tags  whatever  Windows could find.   Or write XMP side car files with this info as an option.   Almost evry digital assets  manager can read them.     I asked chat gpt  to make me such script  for Blender   and it got super easy to find a specific object  but no sucsses with Designer .  Chat just can't do anything working for Designer. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 18, 2024 Nov 18, 2024

Copy link to clipboard

Copied

Hey Kirill,

I have now a folder in my scripts directory named "for_kirill", because you have so many great ideas and I hope to make them all happen.

For this one, here is a working prototype, not the nicest UI and not really tested, but it should serve the purpose.

Just copy this code and run it in the SD Python Editor (see the attached video, for a quick demo)

 

 

import xml.etree.ElementTree as ET
import os

import sd  # type: ignore
from PySide6 import QtWidgets
from PySide6 import QtGui


class ListItem(QtWidgets.QWidget):
    def __init__(
        self,
        filepath: str,
    ):
        super().__init__()
        self.filepath = filepath

        # LAYOUT
        self.header_layout = QtWidgets.QVBoxLayout(self)
        self.filename_label = QtWidgets.QLabel(filepath)
        self.filename_label.setSizePolicy(
            QtWidgets.QSizePolicy.Policy.Expanding,
            QtWidgets.QSizePolicy.Policy.Expanding,
        )
        self.header_layout.addWidget(self.filename_label)

    def mouseDoubleClickEvent(self, event):
        ctx = sd.getContext()
        app = ctx.getSDApplication()
        app.getPackageMgr().loadUserPackage(self.filepath)

        return super().mouseDoubleClickEvent(event)

    def enterEvent(self, event):
        self.filename_label.setText(f"<html><body><u>{self.filepath}</u></body></html>")
        self.filename_label.setCursor(QtGui.Qt.CursorShape.PointingHandCursor)
        super().enterEvent(event)
        self.update()

    def leaveEvent(self, event):
        self.filename_label.setText(self.filepath)
        self.filename_label.setCursor(QtGui.Qt.CursorShape.ArrowCursor)
        super().leaveEvent(event)
        self.update()


class ScrollableListWidget(QtWidgets.QScrollArea):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.list_items = []

        self.list_widget = QtWidgets.QWidget()
        self.list_layout = QtWidgets.QVBoxLayout(self.list_widget)
        self.setStyleSheet(f"background-color:#262626;")

        self.setWidget(self.list_widget)
        self.setWidgetResizable(True)

    def add_list_item(self, item):
        item.setParent(self)
        self.list_items.append(item)
        self.list_layout.insertWidget(self.list_layout.count() - 1, item)

    def clear_list_items(self):
        for list_item in self.list_items:
            self.list_layout.removeWidget(list_item)
            list_item.setParent(None)
        self.list_items.clear()


class SBSFileSearchDialog(QtWidgets.QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Search SBS Files")
        self.setMinimumSize(640, 256)
        self.search_path = os.getcwd()

        # FILE PATH
        self.search_path_layout = QtWidgets.QHBoxLayout()
        self.lbl_search_path = QtWidgets.QLabel(self.search_path)
        self.btn_search_path = QtWidgets.QPushButton("Choose Path")
        self.btn_search_path.setFixedWidth(96)
        self.btn_search_path.clicked.connect(self.choose_search_file_path)

        self.search_path_layout.addWidget(self.lbl_search_path)
        self.search_path_layout.addWidget(self.btn_search_path)

        # SEARCH KEYWORD
        self.search_string_layout = QtWidgets.QHBoxLayout()
        self.txt_search_string = QtWidgets.QLineEdit("")
        self.txt_search_string.setPlaceholderText("Keyword...")
        self.btn_search_string = QtWidgets.QPushButton("Search")
        self.btn_search_string.setFixedWidth(96)
        self.btn_search_string.clicked.connect(self.search_string_in_files)

        self.search_string_layout.addWidget(self.txt_search_string)
        self.search_string_layout.addWidget(self.btn_search_string)

        # SEARCH OPTIONS
        self.search_options_layout = QtWidgets.QGridLayout()

        # MATCHING
        self.lbl_search_options = QtWidgets.QLabel("Search Options")
        self.opt_match_case = QtWidgets.QCheckBox("Match Case")
        self.opt_match_whole_word = QtWidgets.QCheckBox("Match Whole Word")

        self.search_options_layout.addWidget(self.lbl_search_options, 0, 1)
        self.search_options_layout.addWidget(self.opt_match_case, 1, 1)
        self.search_options_layout.addWidget(self.opt_match_whole_word, 2, 1)

        # INCLUDE / EXCLUDE
        self.lbl_include_options = QtWidgets.QLabel("Include Options")
        self.opt_include_graph_identifier = QtWidgets.QCheckBox("Graph Identifier")
        self.opt_include_graph_identifier.setChecked(True)
        self.opt_include_output_identifier = QtWidgets.QCheckBox("Outputs Identifier")
        self.opt_include_input_parameters = QtWidgets.QCheckBox("Graph Parameters")
        self.opt_include_dependencies = QtWidgets.QCheckBox("Graph Dependencies")

        self.search_options_layout.addWidget(self.lbl_include_options, 0, 0)
        self.search_options_layout.addWidget(self.opt_include_graph_identifier, 1, 0)
        self.search_options_layout.addWidget(self.opt_include_output_identifier, 2, 0)
        self.search_options_layout.addWidget(self.opt_include_input_parameters, 3, 0)
        self.search_options_layout.addWidget(self.opt_include_dependencies, 4, 0)

        # RESULTS
        self.lbl_search_results = QtWidgets.QLabel(
            "Search Results (Double Click to open the package in SD)"
        )
        self.list_search_results = ScrollableListWidget()

        # MAIN LAYOUT
        self.main_layout = QtWidgets.QVBoxLayout(self)
        self.main_layout.addLayout(self.search_path_layout)
        self.main_layout.addLayout(self.search_string_layout)
        self.main_layout.addLayout(self.search_options_layout)
        self.main_layout.addSpacerItem(QtWidgets.QSpacerItem(0, 8))
        self.main_layout.addWidget(self.lbl_search_results)
        self.main_layout.addWidget(self.list_search_results)

    def choose_search_file_path(self):
        directory = QtWidgets.QFileDialog.getExistingDirectory(
            None, "Select Directory", "."
        )
        if directory:
            self.lbl_search_path.setText(directory)
            self.search_path = directory

    def search_string_in_files(self):
        self.list_search_results.clear_list_items()
        keyword = self.txt_search_string.text()
        sbs_files = self.list_sbs_files(self.search_path)

        for current_file_index, sbs_file in enumerate(sbs_files):
            print(
                f"SEARCHING FILE {current_file_index + 1}/{len(sbs_files)}:\n{sbs_file}"
            )
            keyword_found = False
            filepath = sbs_file
            tree = ET.parse(filepath)
            root = tree.getroot()

            dependencies = None
            content = None
            graphs = None

            dependencies = root.find("dependencies")
            content = root.find("content")
            if content is not None:
                graphs = content.findall("graph")

            if self.opt_include_graph_identifier.isChecked():
                for graph in graphs:
                    if graph is not None:
                        identifier = graph.find("identifier")
                        if identifier is not None:
                            value = identifier.attrib.get("v")
                            if self.match_keyword(value, keyword):
                                keyword_found = True

            if self.opt_include_dependencies.isChecked():
                if dependencies is not None:
                    for dependency in dependencies:
                        if dependency is not None:
                            filename = dependency.find("filename")
                            if filename is not None:
                                value = filename.attrib.get("v")
                                if self.match_keyword(value, keyword):
                                    keyword_found = True

            if self.opt_include_input_parameters.isChecked():
                if graph is not None:
                    for graph in graphs:
                        paraminputs = graph.find("paraminputs")
                        if paraminputs is not None:
                            for paraminput in paraminputs:
                                if paraminput is not None:
                                    identifier = paraminput.find("identifier")
                                    if identifier is not None:
                                        value = identifier.attrib.get("v")
                                        if self.match_keyword(value, keyword):
                                            keyword_found = True

            if self.opt_include_output_identifier.isChecked():
                for graph in graphs:
                    if graph is not None:
                        graphoutputs = graph.find("graphOutputs")
                        if graphoutputs is not None:
                            for graphoutput in graphoutputs:
                                if graphoutput is not None:
                                    identifier = graphoutput.find("identifier")
                                    if identifier is not None:
                                        value = identifier.attrib.get("v")
                                        if self.match_keyword(value, keyword):
                                            keyword_found = True

            if keyword_found:
                list_item = ListItem(filepath)
                self.list_search_results.add_list_item(list_item)

    def match_keyword(self, search_value: str, keyword: str):
        if self.opt_match_case.isChecked():
            if self.opt_match_whole_word.isChecked():
                if keyword == search_value:
                    return True
            else:
                if keyword in search_value:
                    return True
        else:
            if self.opt_match_whole_word.isChecked():
                if keyword.lower() == search_value.lower():
                    return True
            else:
                if keyword.lower() in search_value.lower():
                    return True

        return False

    def list_sbs_files(self, directory):
        sbs_files = []
        for root, _, files in os.walk(directory):
            for file in files:
                if file.endswith(".sbs"):
                    sbs_files.append(os.path.join(root, file))
        return sbs_files


dialog = SBSFileSearchDialog()
dialog.show()

 

 

 

Stay healthy and creative

Marco

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Dec 11, 2024 Dec 11, 2024

Copy link to clipboard

Copied

LATEST

Thank you very much Marco.  Such a great script . Works perfectly.  

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines