Daz3d Scene Exporter (Coding Error)

Impious Monk

Active Member
Game Developer
Oct 14, 2021
602
2,636
I've got a script that's supposed to move all assets in a Daz scene into a transferable folder. Instead, the script is cutting off the first and last letter of the scene's file name so the script can't locate the file in order to package the assets.

This is the script: . The issue has already been posted on the script's cgshare link with no response from the developer, and I don't have the coding expertise to know how to fix it.

Here's my error message:
Screenshot 2023-04-08 105507.png

And here's the script code:
Python:
import os, sys, re, urllib, urlparse, traceback, shutil, gzip
try :import os, tkinter as Tkinter;from Tkinter import *
except :import Tkinter ;from Tkinter import *
from tkFileDialog import askdirectory,askopenfilenames
from functools import partial
import tkMessageBox

def create_path(file_path) :
    dir_path = '/'.join(file_path.replace('\\','/').split('/')[:-1])
    try :os.makedirs(dir_path)
    except :1
  
# Config file management
def load_config() :
    global config; config = {}
    try :f=open('config'); config=eval(f.read()); f.close()
    except :1
    return 1
def save_config() :
    global config
    f=open('config','w'); f.write(str(config)); f.close()
def get(var_name, var_default_value=None) :
    global config
    if var_name in config :return config[var_name]
    config[var_name] = var_default_value
    save_config()
    return var_default_value
def set(var_name, var_value) :
    global config
    config[var_name] = var_value
    save_config()

# get file content even if it's zipped
def get_file_content(source_file_name) :
    def get_compressed_file_content(source_file_name) :
        compressed_file = gzip.open(source_file_name, 'rb')
        file_content = compressed_file.read()
        compressed_file.close()
        return file_content
    f=open(source_file_name); file_content = f.read(); f.close()
    if not '"asset_info"' in file_content and not '"file_version"' in file_content :
        try :file_content = get_compressed_file_content(source_file_name)
        except :file_content = ''
    return file_content

# searches for a relative path into each available Daz lib, including cloud installed products. returns absolute path if found.
def find_absolute_path(relative_path) :
    daz_lib_paths = get('daz_lib_paths',[])
    if os.path.isfile(relative_path) :return relative_path
    for daz_lib_path in daz_lib_paths :
        if os.path.isfile(daz_lib_path+'/'+relative_path) :return daz_lib_path+'/'+relative_path
        if os.path.isdir(daz_lib_path+'/data/cloud') :
            for cloud_id in os.listdir(daz_lib_path+'/data/cloud') :
                possible_path = daz_lib_path+'/data/cloud/'+cloud_id+'/'+relative_path
                if os.path.isfile(possible_path) :return possible_path
    return ''
  
# recursively scans for each URLs in the file
def get_required_files(parent_file, relative_file_path, already_checked_files={}) :
    global treatment_window, treatment_labels, log_content
    export_path = get('export_path',os.getcwd().replace('\\','/')+'/exported')
    already_checked_files[relative_file_path] = 1
    absolute_file_path = find_absolute_path(relative_file_path)
    if absolute_file_path!='' :
        treatment_labels.append(Label(treatment_window, text='    Reading '+relative_file_path))
        log_content+= '    Reading '+relative_file_path+'\n'
        treatment_labels[-1].pack(); treatment_window.update()
        remove_old_labels()
        if not ':/' in relative_file_path :
            final_file_path = export_path+'/'+relative_file_path
            create_path(final_file_path)
            shutil.copy(absolute_file_path, final_file_path)
        file_content = get_file_content(absolute_file_path)
        file_content = re.sub('\"asset_info\" : \{[^\}]*\}','',file_content)
        for match in re.finditer('\"[^\"]*\"',file_content) :
            if '/' in match.group(0) :
                if '.' in match.group(0) :
                    temp = match.group(0)
                    if '?' in temp or '#' in temp :temp = temp.split('?')[0].split('#')[0]+'"'.replace('""','"')
                    try :
                        path = urllib.url2pathname(urlparse.urlparse(temp[2:][:-1]).path)
                        if not path in already_checked_files :already_checked_files = get_required_files(relative_file_path, path, already_checked_files)
                    except :1
    else :
        treatment_labels.append(Label(treatment_window, text='ERROR: Could\'nt find ' +relative_file_path))
        log_content+= 'ERROR: Could\'nt find ' +relative_file_path+'\n'
        treatment_labels[-1].pack(); treatment_window.update()
        remove_old_labels()
    return already_checked_files

def remove_lib_path(index_button) :
    daz_lib_paths = get('daz_lib_paths',[])
    set('daz_lib_paths', daz_lib_paths[:index_button]+ daz_lib_paths[index_button+1:])
    generate_lib_buttons()

def add_lib() :
    lib_path = askdirectory(initialdir=get('select_lib_path',''), title='Select a DAZ source library').replace('\\','/')
    if lib_path!='' :
        set('select_lib_path', lib_path)
        if not os.path.isdir(lib_path+'/data') and not os.path.isdir(lib_path+'/runtime') :
            tkMessageBox.showinfo("Error", lib_path+' is Not a valid DAZ livrary folder. A valid folder has to contain a "data" and a "runtime" sub-folders.')
            return 0
        daz_lib_paths = get('daz_lib_paths',[])
        if not lib_path in daz_lib_paths :
            daz_lib_paths.append(lib_path)
            daz_lib_paths.sort()
            save_config()
            generate_lib_buttons()

def center_window(res_x, res_y, parent=None) :
    if parent==None :parent=window
    w, h = window.winfo_screenwidth(), window.winfo_screenheight()
    x, y = w/2 - res_x/2, h/2 - res_y/2
    parent.geometry("%dx%d+%d+%d" % ((res_x,res_y) + (x, y)))
def remove_old_labels(max_label_display_count=23) :
    global treatment_window, treatment_labels
    while len(treatment_labels)>max_label_display_count :
        treatment_labels[0].destroy()
        treatment_labels = treatment_labels[1:]
# refreshes sources library buttons
lib_buttons = []
def generate_lib_buttons() :
    global lib_buttons
    daz_lib_paths = get('daz_lib_paths',[])
    res_x, res_y =  window_width, (8+len(daz_lib_paths))*25
    center_window(res_x, res_y)
    for i in lib_buttons :i.destroy()
    lib_buttons = []
    for lib_path in daz_lib_paths :
        lib_buttons.append(Tkinter.Button(window, text=lib_path, fg="blue", command = partial(remove_lib_path, len(lib_buttons)), width=button_width))
        lib_buttons[-1].pack()

# Runs the scene export
def export_scene() :
    global treatment_window, treatment_labels, log_content
    daz_lib_paths = get('daz_lib_paths',[])
    export_path = get('export_path')
    treatment_labels, log_content = [], ''
    if daz_lib_paths==[] :tkMessageBox.showinfo("Error", "Please, add Daz Source librairies by clicking the \"ADD SOURCE\" button. You can add several libs if needed. You can then remove a source lib by clicking it."); return 0
    source_scene_paths = askopenfilenames(initialdir=get('select_scene_path',''), filetypes=[("DUF Files",".duf")], title='Select a DAZ scene file to export').replace('.duf.png','.duf').replace('.png','.duf').replace('\\','/')
    if source_scene_paths!='' :
        source_scene_paths = source_scene_paths[1:][:-1].split('} {')
        treatment_window = Toplevel(window); center_window(window_width, 500, treatment_window); treatment_window.update()
        for source_scene_path in source_scene_paths :
            set('select_scene_path', source_scene_path)
            required_files = {source_scene_path:1}
            already_checked_files = get_required_files("scene", source_scene_path, {})
            final_scene_path = export_path+'/'+source_scene_path.split('/')[-1]
            shutil.copy(source_scene_path, final_scene_path)
            if os.path.isfile(source_scene_path+'.png') :shutil.copy(source_scene_path+'.png', final_scene_path+'.png')
        treatment_window.destroy()
        tkMessageBox.showinfo("Success", 'Scene successfully exported to '+export_path)

def set_destination_path() :
    export_path = askdirectory(initialdir=get('export_path',''), title='Select a destination folder').replace('\\','/')
    if export_path!='' :
        set('export_path', export_path)
        destpath_button.config(text=export_path)
      
def label(txt='') :Label( window, text=txt).pack();
  
try :
    button_width, window_width = 70, 700
    load_config(); window = Tk(); window.winfo_toplevel().title('Daz 3D Scene extractor V2'); window.withdraw()
    window.update(); window.deiconify()
  
    export_path = get('export_path', os.getcwd().replace('\\','/')+'/exported')
    label()

    export_button = Tkinter.Button(window, text='Export a scene', command = export_scene, width=button_width); export_button.pack()
    label()
    Label( window, text="Destination", fg="gray42").pack();
    destpath_button = Tkinter.Button(window, text=export_path, fg="blue", command = set_destination_path, width=button_width); destpath_button.pack()
    label()
    add_lib_button = Tkinter.Button(window, text='ADD SOURCE LIB', command = add_lib, width=button_width); add_lib_button.pack()
    generate_lib_buttons()
    window.mainloop()

except :print (traceback.format_exc())
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,355
15,268
Instead, the script is cutting off the first and last letter of the scene's file name so the script can't locate the file in order to package the assets.
Hmm... The code is a relative mess, but if I had to guess I would say that the error happen here:
Python:
# Runs the scene export
def export_scene() :
    global treatment_window, treatment_labels, log_content
    daz_lib_paths = get('daz_lib_paths',[])
    export_path = get('export_path')
    treatment_labels, log_content = [], ''
    if daz_lib_paths==[] :tkMessageBox.showinfo("Error", "Please, add Daz Source librairies by clicking the \"ADD SOURCE\" button. You can add several libs if needed. You can then remove a source lib by clicking it."); return 0
    source_scene_paths = askopenfilenames(initialdir=get('select_scene_path',''), filetypes=[("DUF Files",".duf")], title='Select a DAZ scene file to export').replace('.duf.png','.duf').replace('.png','.duf').replace('\\','/')
    if source_scene_paths!='' :
# <---
        source_scene_paths = source_scene_paths[1:][:-1].split('} {')
# --->
        treatment_window = Toplevel(window); center_window(window_width, 500, treatment_window); treatment_window.update()
        for source_scene_path in source_scene_paths :
            set('select_scene_path', source_scene_path)
            required_files = {source_scene_path:1}
            already_checked_files = get_required_files("scene", source_scene_path, {})
            final_scene_path = export_path+'/'+source_scene_path.split('/')[-1]
            shutil.copy(source_scene_path, final_scene_path)
            if os.path.isfile(source_scene_path+'.png') :shutil.copy(source_scene_path+'.png', final_scene_path+'.png')
        treatment_window.destroy()
        tkMessageBox.showinfo("Success", 'Scene successfully exported to '+export_path)
Still a guess, but the author seem to have expected a mandatory list of files, and not took count of the possibility that only one file would be selected.

If effectively my guess is correct, then replacing source_scene_paths = source_scene_paths[1:][:-1].split('} {') by:
Python:
        if source_scene_paths[0] == "{":
            source_scene_paths = source_scene_paths[1:][:-1].split('} {')
        else:
            source_scene_paths = [ source_scene_paths ]
should works.

/!\ Be careful to respect the indentation, it's really important. /!\
 
  • Red Heart
Reactions: Capella