@@ -56,6 +56,76 @@ local function to_hms(secs)
5656 return # str == 0 and " 0" or table.concat (str , " " )
5757end
5858
59+ function join_paths (path1 , path2 )
60+ if not path1 or path1 == " " then
61+ return path2 or " "
62+ end
63+ if not path2 or path2 == " " then
64+ return path1
65+ end
66+
67+ local separator
68+ if os_name == " windows" then
69+ separator = " \\ "
70+ else
71+ separator = " /"
72+ end
73+
74+ -- normalize separators in both paths
75+ path1 = path1 :gsub (" [/\\ ]" , separator )
76+ path2 = path2 :gsub (" [/\\ ]" , separator )
77+
78+ -- remove trailing separator from path1
79+ path1 = path1 :gsub (separator == " \\ " and " \\ +$" or " /+$" , " " )
80+
81+ -- handle absolute path2 (starts with drive letter on Windows or / on Unix)
82+ if path2 :match (" ^[A-Za-z]:" ) or path2 :match (" ^" .. (separator == " \\ " and " \\ " or " /" )) then
83+ return path2
84+ end
85+
86+ -- handle relative paths with .. and .
87+ local function resolve_path (base , relative )
88+ local parts = {}
89+
90+ -- split base path into parts
91+ local pattern = separator == " \\ " and " [^\\\\ ]+" or " [^/]+"
92+ for part in base :gmatch (pattern ) do
93+ table.insert (parts , part )
94+ end
95+
96+ -- process relative path parts
97+ for part in relative :gmatch (pattern ) do
98+ if part == " .." then
99+ if # parts > 0 then
100+ table.remove (parts )
101+ end
102+ elseif part ~= " ." then
103+ table.insert (parts , part )
104+ end
105+ end
106+
107+ -- reconstruct path
108+ local result = table.concat (parts , separator )
109+
110+ -- handle drive letters on Windows
111+ if base :match (" ^[A-Za-z]:" ) then
112+ local drive = base :match (" ^[A-Za-z]:" )
113+ if not result :match (" ^[A-Za-z]:" ) then
114+ result = drive .. separator .. result
115+ end
116+ elseif
117+ base :match (" ^" .. (separator == " \\ " and " \\\\ " or " /" ))
118+ and not result :match (" ^" .. (separator == " \\ " and " \\\\ " or " /" ))
119+ then
120+ result = separator .. result
121+ end
122+
123+ return result
124+ end
125+
126+ return resolve_path (path1 , path2 )
127+ end
128+
59129-- file operations
60130local function ensure_directory_exists (dir )
61131 local dir_info = mp .utils .file_info (dir )
@@ -199,11 +269,11 @@ local function merge_cuts(temp_dir, filepaths, outpath, input_mtime)
199269 -- i hate that you have to do a separate command and render each cut separately first, i tried using
200270 -- filter_complex for merging with multiple inputs but it wouldn't let me. todo: look into this further
201271
202- local merge_file = mp . utils . join_path (temp_dir , " merging.txt" )
272+ local merge_file = join_paths (temp_dir , " merging.txt" )
203273 local content = " "
204274
205275 for _ , path in ipairs (filepaths ) do
206- content = content .. string.format (" file '%s'\n " , ffmpeg_escape_filepath (path ))
276+ content = content .. string.format (" file '%s'\n " , ffmpeg_escape_filepath (path ))
207277 end
208278
209279 local file = io.open (merge_file , " w" )
@@ -283,12 +353,12 @@ local function cut_render()
283353
284354 local is_stream = input_info == nil
285355
286- local cwd = mp .utils .getcwd ()
287356 local outdir
288- if options .output_dir == " . " then
289- outdir = cwd
357+ if options .output_dir == " @cwd " or is_stream then
358+ outdir = mp . utils . getcwd ()
290359 else
291- outdir = mp .utils .join_path (cwd , options .output_dir )
360+ input_dir = mp .utils .split_path (input )
361+ outdir = join_paths (input_dir , options .output_dir )
292362 end
293363
294364 -- create output directory if needed
@@ -300,7 +370,7 @@ local function cut_render()
300370 local filename_noext , ext = " " , " "
301371 local cache_offset = 0
302372
303- local temp_cache_file_name = mp . utils . join_path (outdir , " cache-dump.mkv" )
373+ local temp_cache_file_name = join_paths (outdir , " cache-dump.mkv" )
304374
305375 if not is_stream then
306376 filename_noext , ext = filename :match (" ^(.*)(%.[^%.]+)$" )
@@ -344,7 +414,7 @@ local function cut_render()
344414 ext
345415 )
346416
347- local cut_path = mp . utils . join_path (outdir , cut_name )
417+ local cut_path = join_paths (outdir , cut_name )
348418
349419 log (string.format (" (%d/%d) Rendering cut to %s" , i , # cuts , cut_path ))
350420
@@ -361,7 +431,7 @@ local function cut_render()
361431 if # cut_paths > 1 and options .multi_cut_mode == " merge" then
362432 local merge_name = string.format (" (%d merged cuts) %s%s" , # cut_paths , filename_noext , ext )
363433
364- local merge_path = mp . utils . join_path (outdir , merge_name )
434+ local merge_path = join_paths (outdir , merge_name )
365435
366436 log (" Merging cuts..." )
367437 local success = merge_cuts (cwd , cut_paths , merge_path , input_info .mtime )
0 commit comments