Skip to content

Commit 994b2bb

Browse files
authored
Fix problems with relative paths on Windows (#40)
* Fix problems with relative paths on Windows * Fix updating of sequences without pattern in filename
1 parent 8ad97b5 commit 994b2bb

File tree

4 files changed

+84
-78
lines changed

4 files changed

+84
-78
lines changed

bseq/callback.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
11
import bpy
22
import fileseq
3+
import traceback
4+
5+
from .utils import show_message_box
36

47
# Code here are mostly about the callback/update/items functions used in properties.py
58

69
file_sequences = []
710

811
def update_path(self, context):
12+
'''
13+
Detects all the file sequences in the directory
14+
'''
15+
916
# When the path has been changed, reset the selected sequence to None
1017
context.scene.BSEQ['fileseq'] = 1
1118
context.scene.BSEQ.use_pattern = False
1219
context.scene.BSEQ.pattern = ""
13-
14-
'''
15-
Detects all the file sequences in the directory
16-
'''
20+
file_sequences.clear()
1721

1822
p = context.scene.BSEQ.path
1923
try:
20-
f = fileseq.findSequencesOnDisk(p)
21-
except:
22-
return [("None", "No sequence detected", "", 1)]
24+
f = fileseq.findSequencesOnDisk(bpy.path.abspath(p))
25+
except Exception as e:
26+
show_message_box("Error when reading path\n" + traceback.format_exc(),
27+
"fileseq Error" + str(e),
28+
icon="ERROR")
29+
return None
2330

2431
if not f:
25-
return [("None", "No sequence detected", "", 1)]
32+
return None
2633

27-
file_sequences.clear()
2834
if len(f) >= 30:
2935
file_sequences.append(("None", "Too much sequence detected, could be false detection, please use pattern below", "", 1))
3036
else:

bseq/importer.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,14 @@ def create_obj(fileseq, use_relative, root_path, transform_matrix=Matrix.Identit
262262
object = bpy.data.objects.new(name, mesh)
263263

264264
# create the object
265+
full_path = str(fileseq)
266+
path = os.path.dirname(full_path)
267+
pattern = os.path.basename(full_path)
265268
if use_relative:
266-
full_path = get_relative_path(str(fileseq), root_path)
267-
else:
268-
full_path = str(fileseq)
269+
path = get_relative_path(path, root_path)
269270
# path is only the directory in which the file is located
270-
object.BSEQ.path = os.path.dirname(full_path)
271-
object.BSEQ.pattern = os.path.basename(full_path)
271+
object.BSEQ.path = path
272+
object.BSEQ.pattern = pattern
272273
object.BSEQ.current_file = filepath
273274
object.BSEQ.init = True
274275
object.BSEQ.enabled = enabled

bseq/operators.py

+47-50
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ def execute(self, context):
5050
fs = importer_prop.path + '/' + importer_prop.pattern
5151

5252
try:
53-
fs = fileseq.findSequenceOnDisk(fs)
53+
# Call os.path.abspath in addition because findSequenceOnDisk does not support \..\ components on Windows apparently
54+
fs = fileseq.findSequenceOnDisk(os.path.abspath(bpy.path.abspath(fs)))
5455
except Exception as e:
5556
show_message_box(traceback.format_exc(), "Can't find sequence: " + str(fs), "ERROR")
5657
return {"CANCELLED"}
@@ -522,7 +523,7 @@ def execute(self, context):
522523
return {'FINISHED'}
523524

524525
class BSEQ_OT_load_all(bpy.types.Operator):
525-
"""Load all sequences from selected folder"""
526+
"""Load all sequences from selected folder and its subfolders"""
526527
bl_idname = "bseq.load_all"
527528
bl_label = "Load All"
528529
bl_options = {'PRESET', 'UNDO'}
@@ -533,8 +534,8 @@ def execute(self, context):
533534
if importer_prop.use_relative and not bpy.data.is_saved:
534535
return relative_path_error()
535536

536-
dir = importer_prop.path
537-
seqs = fileseq.findSequencesOnDisk(str(dir))
537+
p = importer_prop.path
538+
seqs = fileseq.findSequencesOnDisk(bpy.path.abspath(p))
538539

539540
for s in seqs:
540541
print(s)
@@ -555,60 +556,56 @@ def execute(self, context):
555556
if importer_prop.use_relative and not bpy.data.is_saved:
556557
return relative_path_error()
557558

558-
root_dir = importer_prop.path
559+
root_dir = bpy.path.abspath(importer_prop.path)
559560
root_coll = bpy.context.scene.collection
560561
root_layer_collection = bpy.context.view_layer.layer_collection
561562
unlinked_collections = []
562-
# Recurse through subdirectories
563-
for root, dirs, files in os.walk(bpy.path.abspath(root_dir)):
564-
for dir in sorted(dirs):
565-
# Process subdirectory
566-
subdirectory = os.path.join(root, dir)
567-
568-
seqs = fileseq.findSequencesOnDisk(subdirectory)
569-
if len(seqs) == 0:
570-
continue
571-
572-
# Get list of directories from the root_dir to the current subdirectory
573-
coll_list = bpy.path.relpath(subdirectory, start=root_dir).strip("//").split("/")
574-
575-
# Get or create a nested collection starting from the root
576-
last_coll = root_coll
577-
layer_collection = root_layer_collection
578-
for coll in coll_list:
579-
# If it already exists and is not in the children of the last collection, then the prefix has changed
580-
cur_coll = bpy.data.collections.get(coll)
581-
if cur_coll is not None and last_coll is not None:
582-
if cur_coll.name not in last_coll.children:
583-
# Get the old parent of the existing collection and move the children to the old parent
584-
parent = [c for c in bpy.data.collections if bpy.context.scene.user_of_id(cur_coll) and cur_coll.name in c.children]
585-
if len(parent) > 0:
586-
for child in cur_coll.children:
587-
parent[0].children.link(child)
588-
for obj in cur_coll.objects:
589-
parent[0].objects.link(obj)
590-
parent[0].children.unlink(cur_coll)
591-
unlinked_collections.append(cur_coll)
592-
else:
593-
layer_collection = layer_collection.children[cur_coll.name]
594-
last_coll = cur_coll
595-
596-
597-
# If it was newly created, link it to the last collection
598-
if cur_coll is None and last_coll is not None:
599-
cur_coll = bpy.data.collections.new(coll)
600-
last_coll.children.link(cur_coll)
563+
# Recurse through directory itself and subdirectories
564+
for current_dir, subdirs, files in os.walk(root_dir):
565+
seqs = fileseq.findSequencesOnDisk(current_dir)
566+
if len(seqs) == 0:
567+
continue
568+
569+
# Get list of directories from the root_dir to the current directory
570+
coll_list = bpy.path.relpath(current_dir, start=root_dir).strip("//").split("/")
571+
572+
# Get or create a nested collection starting from the root
573+
last_coll = root_coll
574+
layer_collection = root_layer_collection
575+
for coll in coll_list:
576+
# If it already exists and is not in the children of the last collection, then the prefix has changed
577+
cur_coll = bpy.data.collections.get(coll)
578+
if cur_coll is not None and last_coll is not None:
579+
if cur_coll.name not in last_coll.children:
580+
# Get the old parent of the existing collection and move the children to the old parent
581+
parent = [c for c in bpy.data.collections if bpy.context.scene.user_of_id(cur_coll) and cur_coll.name in c.children]
582+
if len(parent) > 0:
583+
for child in cur_coll.children:
584+
parent[0].children.link(child)
585+
for obj in cur_coll.objects:
586+
parent[0].objects.link(obj)
587+
parent[0].children.unlink(cur_coll)
588+
unlinked_collections.append(cur_coll)
589+
else:
601590
layer_collection = layer_collection.children[cur_coll.name]
602591
last_coll = cur_coll
603592

604-
# Set the last collection as the active collection by recursing through the collections
605-
context.view_layer.active_layer_collection = layer_collection
606593

607-
# for s in seqs:
608-
# print(s)
594+
# If it was newly created, link it to the last collection
595+
if cur_coll is None and last_coll is not None:
596+
cur_coll = bpy.data.collections.new(coll)
597+
last_coll.children.link(cur_coll)
598+
layer_collection = layer_collection.children[cur_coll.name]
599+
last_coll = cur_coll
600+
601+
# Set the last collection as the active collection by recursing through the collections
602+
context.view_layer.active_layer_collection = layer_collection
603+
604+
# for s in seqs:
605+
# print(s)
609606

610-
for s in seqs:
611-
create_obj_wrapper(s, importer_prop)
607+
for s in seqs:
608+
create_obj_wrapper(s, importer_prop)
612609

613610
# Make sure unused datablocks are freed
614611
for coll in unlinked_collections:

bseq/utils.py

+16-14
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,47 @@ def draw(self, context):
2121
stop_animation()
2222
bpy.context.window_manager.popup_menu(draw, title=title, icon=icon)
2323

24-
2524
def stop_animation():
2625
if bpy.context.screen.is_animation_playing:
2726
# if playing animation, then stop it, otherwise it will keep showing message box
2827
bpy.ops.screen.animation_cancel()
2928

3029
def get_relative_path(path, root_path):
3130
if root_path != "":
32-
path = bpy.path.relpath(path, start=root_path)
31+
rel_path = bpy.path.relpath(path, start=bpy.path.abspath(root_path))
3332
else:
34-
path = bpy.path.relpath(path)
35-
return path
33+
rel_path = bpy.path.relpath(path)
34+
return rel_path
3635

3736
# convert relative path to absolute path
3837
def convert_to_absolute_path(path, root_path):
38+
# Additional call to os.path.abspath removes any "/../"" in the path (can be a problem on Windows)
3939
if root_path != "":
40-
path = bpy.path.abspath(path, start=root_path)
40+
path = os.path.abspath(bpy.path.abspath(path, start=bpy.path.abspath(root_path)))
4141
else:
42-
path = bpy.path.abspath(path)
42+
path = os.path.abspath(bpy.path.abspath(path))
4343
return path
4444

4545
def get_absolute_path(obj, scene):
4646
full_path = os.path.join(bpy.path.native_pathsep(obj.BSEQ.path), obj.BSEQ.pattern)
4747
full_path = convert_to_absolute_path(full_path, scene.BSEQ.root_path)
4848
return full_path
4949

50-
5150
def refresh_obj(obj, scene):
5251
is_relative = obj.BSEQ.path.startswith("//")
53-
print("is_relative: ", is_relative)
5452
fs = get_absolute_path(obj, scene)
5553
fs = fileseq.findSequenceOnDisk(fs)
56-
fs = fileseq.findSequenceOnDisk(fs.dirname() + fs.basename() + "@" + fs.extension())
57-
obj.BSEQ.start_end_frame = (fs.start(), fs.end())
58-
fs = str(fs)
54+
#fs = fileseq.findSequenceOnDisk(fs.dirname() + fs.basename() + "@" + fs.extension())
55+
56+
full_path = str(fs)
57+
path = os.path.dirname(full_path)
58+
pattern = os.path.basename(full_path)
5959
if is_relative:
60-
fs = get_relative_path(fs, scene.BSEQ.root_path)
61-
obj.BSEQ.path = os.path.dirname(fs)
62-
obj.BSEQ.pattern = os.path.basename(fs)
60+
path = get_relative_path(path, scene.BSEQ.root_path)
61+
62+
obj.BSEQ.path = path
63+
obj.BSEQ.pattern = pattern
64+
obj.BSEQ.start_end_frame = (fs.start(), fs.end())
6365

6466
def load_meshio_from_path(fileseq, filepath, obj = None):
6567
try:

0 commit comments

Comments
 (0)