Searching for and adding to time [HH:MM:SS.00] in a text document

I need to know how to search for each occurance of time-code in a text document and add four seconds to it.

Here is what my text looks like:
[00:00:00.00]
[00:00:00.15]
Let’s write this number in standard form, four hundred two thousand, five hundred fifty.
[00:00:09.00]
Remember this is the name of the period, so we write four hundred
[00:00:14.00]
two as if it were a whole number, so that is four hundred two
[00:00:21.10]
thousand,
[00:00:23.10]

So need to find each of the times [HH:MM:SS.00] and add four seconds to each one. So the result would be:

[00:00:04.00]
[00:00:04.15]
Let’s write this number in standard form, four hundred two thousand, five hundred fifty.
[00:00:13.00]
Remember this is the name of the period, so we write four hundred
[00:00:18.00]
two as if it were a whole number, so that is four hundred two
[00:00:25.10]
thousand,
[00:00:28.10]

I sure I could figure it out if I had the time but I need to know by Tuesday how to do this.

Anyone have any ideas?

hi thebeliever,

first part - here a handler for the time maths:

set theTime to "[00:00:25.10]"
get "[" & (my addToTimeString(4, text 2 thru -2 of theTime)) & "]"

on addToTimeString(nSeconds, timeString)
	set {tid, text item delimiters} to {text item delimiters, ":"}
	set timeElements to reverse of (text items of timeString)
	set milliSeconds to text -2 thru -1 of (item 1 of timeElements)
	set item 1 of timeElements to text 1 thru 2 of (item 1 of timeElements)
	set lastItem to length of timeElements
	set additionInProgress to true
	set currentElementIndex to 1
	set currentAdditionValue to nSeconds
	repeat while additionInProgress
		set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) + currentAdditionValue
		if (item currentElementIndex of timeElements) ≥ 60 then
			if currentElementIndex = lastItem then return "Overflow Error"
			set currentAdditionValue to 0
			repeat while (item currentElementIndex of timeElements) ≥ 60
				set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) - 60
				set currentAdditionValue to currentAdditionValue + 1
			end repeat
		else
			set additionInProgress to false
		end if
		set (item currentElementIndex of timeElements) to my formatTwoDigitNumber(item currentElementIndex of timeElements)
		set currentElementIndex to currentElementIndex + 1
	end repeat
	set retval to ((reverse of timeElements) as string) & "." & milliSeconds
	set text item delimiters to tid
	return retval
end addToTimeString

on formatTwoDigitNumber(intNumber)
	if intNumber > 9 then return (intNumber as string)
	return ("0" & intNumber)
end formatTwoDigitNumber

I think this sorts out the overflow problem, and sets 24 to 00 in the hours

set theTime to "[23:59:59.10]"
get "[" & (my addToTimeString(4, text 2 thru -2 of theTime)) & "]"
global lastItem
on addToTimeString(nSeconds, timeString)
	set {tid, text item delimiters} to {text item delimiters, ":"}
	set timeElements to reverse of (text items of timeString)
	set milliSeconds to text -2 thru -1 of (item 1 of timeElements)
	set item 1 of timeElements to text 1 thru 2 of (item 1 of timeElements)
	set lastItem to length of timeElements
	set additionInProgress to true
	set currentElementIndex to 1
	set currentAdditionValue to nSeconds
	repeat while additionInProgress
		set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) + currentAdditionValue
		if currentElementIndex = lastItem then
			if item currentElementIndex of timeElements is greater than 23 then
				set (item currentElementIndex of timeElements) to 0
			end if
		end if
		if (item currentElementIndex of timeElements) ≥ 60 then
			
			set currentAdditionValue to 0
			repeat while (item currentElementIndex of timeElements) ≥ 60
				set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) - 60
				set currentAdditionValue to currentAdditionValue + 1
				
			end repeat
		else
			set additionInProgress to false
		end if
		set (item currentElementIndex of timeElements) to my formatTwoDigitNumber(item currentElementIndex of timeElements)
		set currentElementIndex to currentElementIndex + 1
		
	end repeat
	set retval to ((reverse of timeElements) as string) & "." & milliSeconds
	set text item delimiters to tid
	return retval
end addToTimeString

on formatTwoDigitNumber(intNumber)
	if intNumber > 9 then return (intNumber as string)
	return ("0" & intNumber)
end formatTwoDigitNumber

P.s
Nice script by the way.

Hi, thebeliever.

I assume you need this urgently for a one-off job. Here’s a quick and dirty vanilla solution. It assumes that the text file contains plain, ASCII text. You query says firstly “four minutes” and then “four seconds”. This is a “four seconds” version.

-- Work on a duplicate file in case the original's still needed.
tell application "Finder" to set f to (duplicate (choose file)) as alias

set fRef to (open for access f with write permission)
try
	set txt to (read fRef)
	set eof fRef to 0
	write add4sToTimeCodes(txt) to fRef
on error msg
	display dialog msg buttons {"OK"} default button 1
end try
close access fRef

on add4sToTimeCodes(txt)
	considering case
		-- Get the "["-delimited text items of the text.
		set astid to AppleScript's text item delimiters
		set AppleScript's text item delimiters to "["
		set tis to txt's text items
		
		set AppleScript's text item delimiters to ":"
		repeat with i from 2 to (count tis)
			set thisTI to item i of tis
			try
				-- This code assumes that there are two colons after each "[" and that the bits between can be coerced to number.
				-- If not, a particular "[" doesn't introduce a time code and this error trap will prevent further action on it.
				-- Probably good enough here, but commercial grade code would required more thorough checks.
				
				-- Get the new time in seconds.
				tell thisTI's text items to set t to (item 1) * hours + (item 2) * minutes + (text 1 thru 2 of item 3) + 4
				-- Convert back to HH:MM:SS.
				tell (1000000 + t div hours * 10000 + t mod hours div minutes * 100 + t mod minutes) as string
					set newHHMMSS to text 2 thru 3 & ":" & text 4 thru 5 & ":" & text 6 thru 7
				end tell
				-- Insert back into this text item.
				set item i of tis to newHHMMSS & text 9 thru -1 of thisTI
			end try
		end repeat
		
		-- Put the text back together.
		set AppleScript's text item delimiters to "["
		set txt to tis as string
		set AppleScript's text item delimiters to astid
	end considering
	
	return txt
end add4sToTimeCodes

Again nice script, both would have taken me an age to figure out,

NG’s script also had the same issue of if the time is [23:59:59.00]

the conversion would come out as [24:00:03.00]
this small change (below) makes sure the 24 gets change to 00
i.e [00:00:03.00]

-- Work on a duplicate file in case the original's still needed.
tell application "Finder" to set F to (duplicate (choose file)) as alias

set fRef to (open for access F with write permission)
try
	set txt to (read fRef)
	set eof fRef to 0
	write add4sToTimeCodes(txt) to fRef
on error msg
	display dialog msg buttons {"OK"} default button 1
end try
close access fRef

on add4sToTimeCodes(txt)
	considering case
		-- Get the "["-delimited text items of the text.
		set astid to AppleScript's text item delimiters
		set AppleScript's text item delimiters to "["
		set tis to txt's text items
		
		set AppleScript's text item delimiters to ":"
		repeat with i from 2 to (count tis)
			set thisTI to item i of tis
			--try
			-- This code assumes that there are two colons after each "[" and that the bits between can be coerced to number.
			-- If not, a particular "[" doesn't introduce a time code and this error trap will prevent further action on it.
			-- Probably good enough here, but commercial grade code would required more thorough checks.
			
			-- Get the new time in seconds.
			tell thisTI's text items to set T to (item 1) * hours + (item 2) * minutes + (text 1 thru 2 of item 3) + 4
			-- Convert back to HH:MM:SS.
			tell (1000000 + T div hours * 10000 + T mod hours div minutes * 100 + T mod minutes) as string
				set newHHMMSS to text 2 thru 3 & ":" & text 4 thru 5 & ":" & text 6 thru 7
			end tell
			-- Insert back into this text item.
			set item i of tis to newHHMMSS & text 9 thru -1 of thisTI
			--Make sure 24 hours is set to 00
			if word 1 of item i of tis is "24" then
				
				tell (1000000 + T div hours * 10000 + T mod hours div minutes * 100 + T mod minutes) as string
					set newHHMMSS to "00" & ":" & text 4 thru 5 & ":" & text 6 thru 7
				end tell
				set item i of tis to newHHMMSS & text 9 thru -1 of thisTI
			end if
			--	end try
		end repeat
		
		-- Put the text back together.
		set AppleScript's text item delimiters to "["
		set txt to tis as string
		set AppleScript's text item delimiters to astid
	end considering
	
	return txt
end add4sToTimeCodes

Hi. Mark.

I think that’s OK with time codes. They’re not a clock, but timing points in a film or sound recording. They can go right up to [99:59:59.29] if necessary (if I recall correctly, there are thirty frames in a second), but it’s only rarely that they’ll even get up to [04:00:00.00]. Thanks for your adaptation though, as it gives thebeliever some alternatives from which to choose.

Dominik, Mark, and Nigel thanks so much for the help.

Here is the completed script that uses TextWrangler to find all the timecodes and add for secondes to each one:

tell application "TextWrangler"
	activate
	set noFind to false
	repeat until noFind is true
		find "\\[[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]" searching in text 1 of text document 1 options {search mode:grep, starting at top:false, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false} with selecting match
		if found of result is false then
			set noFind to true
		else
			copy selection
			set theTime to the contents of current clipboard
			set theTimePlusFour to "[" & (my addToTimeString(119, text 2 thru -2 of theTime)) & "]"
			set the clipboard to theTimePlusFour
			paste
		end if
			
	end repeat
end tell

on addToTimeString(nSeconds, timeString)
	set {tid, text item delimiters} to {text item delimiters, ":"}
	set timeElements to reverse of (text items of timeString)
	set milliSeconds to text -2 thru -1 of (item 1 of timeElements)
	set item 1 of timeElements to text 1 thru 2 of (item 1 of timeElements)
	set lastItem to length of timeElements
	set additionInProgress to true
	set currentElementIndex to 1
	set currentAdditionValue to nSeconds
	repeat while additionInProgress
		set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) + currentAdditionValue
		if (item currentElementIndex of timeElements) ≥ 60 then
			if currentElementIndex = lastItem then return "Overflow Error"
			set currentAdditionValue to 0
			repeat while (item currentElementIndex of timeElements) ≥ 60
				set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) - 60
				set currentAdditionValue to currentAdditionValue + 1
			end repeat
		else
			set additionInProgress to false
		end if
		set (item currentElementIndex of timeElements) to my formatTwoDigitNumber(item currentElementIndex of timeElements)
		set currentElementIndex to currentElementIndex + 1
	end repeat
	set retval to ((reverse of timeElements) as string) & "." & milliSeconds
	set text item delimiters to tid
	return retval
end addToTimeString

on formatTwoDigitNumber(intNumber)
	if intNumber > 9 then return (intNumber as string)
	return ("0" & intNumber)
end formatTwoDigitNumber

One last thing I need to is a handler to convert the final timecode found into seconds. So I for example I need to convert [01:02:28.10] into second and set that to a variable. Note, you do not have to include the milliseconds in the final output. So for example, for the timecode [00:02:00.10] the output of the handler would be 120 not 120.10. So you can direguard millisecond when you convert HH:MM:SS to SS.

This is the final piece I need to complete this script. Any other help would be greatly appreciated.

Incase you were wondering, the text file is a closed captioned file that displays in QuickTime when a video is played. We need to shift everything by four seconds because a four second title was added to the video and it made the caption start and stay four seconds ahead of the video.

Again, thanks for your help.

Hi thebeliever,

here the needed part:

set timeCode to "[01:02:28.10]"
set secondsValue to (my timeCodeToSeconds(timeCode))

on timeCodeToSeconds(timeCode)
	return ((text 1 thru 2 of (word 3 of timeCode)) + 60 * (word 2 of timeCode) + 3600 * (word 1 of timeCode))
end timeCodeToSeconds

Regards,

D.

Hi, thebeliever.

Don’t forget to change the 119 in the handler call back to 4. :wink:

Your script, although quite slow, is very pretty to watch. Thanks for posting it. I found it interesting because I haven’t so far attempted to script TextWrangler. My normal approach when editing the text of an open document (where styling isn’t involved) is to get all the text at once, edit it in AppleScript, and then set the document’s text to the edited result. This saves the application having to update the document and the display after every move.

After fooling around with your code a bit this morning, I think you can speed it up slightly by dispensing with the selection. The record returned by TextWrangler’s find command contains both the found text and a reference to its position in the document. You can thus pass the text directly from this to Dominik’s handler and set the contents of the reference to the result. It’s also possible to start the search at the top of the text and then neutralise this option for the remaining searches:

tell application "TextWrangler"
	activate
	set searchOptions to {search mode:grep, starting at top:true, case sensitive:true}
	set noFind to false
	repeat until (noFind)
		set findResult to (find "\\[[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]" searching in text 1 of text document 1 options searchOptions)
		if (found of findResult) then
			set theTime to found text of findResult -- Get the text directly from the returned record.
			set theTimePlusFour to "[" & (my addToTimeString(4, text 2 thru -2 of theTime)) & "]"
			set contents of found object of findResult to theTimePlusFour -- Replace the text directly in the document.
			set starting at top of searchOptions to false -- Neutralise this option for subsequent searches.
		else
			set noFind to true
		end if
	end repeat
end tell

-- Dominik's handlers here.

I know this is pretty academic for your current purposes, but it might be of interest to you or to someone else later. :slight_smile:

Addendum:

Since my script (message #4 above) turns the time codes into seconds anyway as part of its addition process, you could simply bleed off that result and include it with the return. The entire script would then be:

tell application "TextWrangler"
	activate
	set searchOptions to {search mode:grep, starting at top:true, case sensitive:true}
	set noFind to false
	repeat until (noFind)
		set findResult to (find "\\[[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]" searching in text 1 of text document 1 options searchOptions)
		if (found of findResult) then
			set theTime to found text of findResult -- Get the text directly from the returned record.
			set {theTimePlusFour, lastTimeInSeconds} to my addSecondsToTimeCode(4, text 2 thru -2 of theTime)
			set theTimePlusFour to "[" & theTimePlusFour & "]"
			set contents of found object of findResult to theTimePlusFour -- Replace the text directly in the document.
			set starting at top of searchOptions to false -- Neutralise this option for subsequent searches.
		else
			set noFind to true
		end if
	end repeat
	
	return lastTimeInSeconds
end tell

on addSecondsToTimeCode(s, timeCode)
	-- Turn the time code into seconds and add the specified amount.
	tell timeCode to set t to (text 1 thru 2) * hours + (text 4 thru 5) * minutes + (text 7 thru 8) + s
	-- Convert back to HH:MM:SS.
	tell (1000000 + t div hours * 10000 + t mod hours div minutes * 100 + t mod minutes) as string
		set newTimeCode to text 2 thru 3 & ":" & text 4 thru 5 & ":" & text 6 thru 7 & (text -3 thru -1 of timeCode)
	end tell
	
	return {newTimeCode, t} -- The text of the new time code and the number of seconds involved. 
end addSecondsToTimeCodes

Here is my final script that will batch process the text documents I drop on it:

on open theDroppedItems
	set countOne to 1
	set listCount to 1
	repeat until listCount > (count theDroppedItems)
		
		tell application "TextWrangler"
			activate
			set Doc_to_open to item countOne of theDroppedItems
			open Doc_to_open
		end tell
		
		deleteHeader()
		
		tell application "TextWrangler"
			activate
			set searchOptions to {search mode:grep, starting at top:true, case sensitive:true}
			set noFind to false
			repeat until (noFind)
				set findResult to (find "\\[[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]" searching in text 1 of text document 1 options searchOptions)
				if (found of findResult) then
					set theTime to found text of findResult -- Get the text directly from the returned record.
					set {theTimePlusFour, lastTimeInSeconds} to my addSecondsToTimeCode(4, text 2 thru -2 of theTime)
					set theTimePlusFour to "[" & theTimePlusFour & "]"
					set contents of found object of findResult to theTimePlusFour -- Replace the text directly in the document.
					set starting at top of searchOptions to false -- Neutralise this option for subsequent searches.
				else
					set noFind to true
					save text document 1
					close text window 1
				end if
			end repeat
		end tell
		
		set countOne to countOne + 1
		set listCount to listCount + 1
		
	end repeat
end open

on deleteHeader()
	tell application "TextWrangler"
		activate
		find "{QTtext}" searching in text 1 of text document 1 options {search mode:literal, starting at top:true, wrap around:true} with selecting match
		find "[00:00:00.00]" searching in text 1 of text document 1 options {search mode:literal, starting at top:false, wrap around:true, extend selection:true} with selecting match
		delete selection
	end tell
end deleteHeader

on addSecondsToTimeCode(s, timeCode)
	-- Turn the time code into seconds and add the specified amount.
	tell timeCode to set t to (text 1 thru 2) * hours + (text 4 thru 5) * minutes + (text 7 thru 8) + s
	-- Convert back to HH:MM:SS.
	tell (1000000 + t div hours * 10000 + t mod hours div minutes * 100 + t mod minutes) as string
		set newTimeCode to text 2 thru 3 & ":" & text 4 thru 5 & ":" & text 6 thru 7 & (text -3 thru -1 of timeCode)
	end tell
	
	return {newTimeCode, t} -- The text of the new time code and the number of seconds involved. 
end addSecondsToTimeCode

I know it is a bit cobbled together but I works great. Thanks again Nigel and Dominik.

Here is a link to the the type of text documents the script processes if you want to try it out:
http://www.sieducation.com/downloads/cc_txt.zip

The only thing I could not figure out is how call “deleteHeader()” within “tell application “TextWrangler””. I tried removing the “tell application “TextWrangler”” from the handler since it was within one already when I tried to call it, but is still would not work. So I had to put it between two “tell application “TextWrangler””.

I had another challenge ahead of me. I had another set of captioned files that I needed to not only add four seconds to but combine them all into one caption file and shift the timecode for each one by the total amount of seconds of the previous captioned file (plus four). I had to do this because we took some shorter videos (with new titles added) and combined them all together into one video. Here is the script I came up with to do that:

global Doc_to_open
on open theDroppedItems
	set countOne to 1
	set listCount to 1
	set numberToAdd to 4
	repeat until listCount > (count theDroppedItems)
		
		tell application "TextWrangler"
			activate
			set Doc_to_open to item countOne of theDroppedItems
			open Doc_to_open
		end tell
		
		
		deleteHeader()
		
		tell application "TextWrangler"
			activate
			set searchOptions to {search mode:grep, starting at top:true, case sensitive:true}
			set noFind to false
			repeat until (noFind)
				set findResult to (find "\\[[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]" searching in text 1 of text document 1 options searchOptions)
				if (found of findResult) then
					set theTime to found text of findResult -- Get the text directly from the returned record.
					set theTimePlusFour to "[" & (my addToTimeString(numberToAdd, text 2 thru -2 of theTime)) & "]"
					set timeCode to theTimePlusFour
					set contents of found object of findResult to theTimePlusFour -- Replace the text directly in the document.
					set starting at top of searchOptions to false -- Neutralise this option for subsequent searches.
				else
					set noFind to true
					set numberToAdd to 4
					cut selection
					paste
					set lastTimeCodePlusFour to "[" & (my addToTimeString(numberToAdd, text 2 thru -2 of timeCode)) & "]"
					set numberToAdd to (my timeCodeToSeconds(lastTimeCodePlusFour))
					if countOne > 1 then
						tell application "TextWrangler"
							select text 1 of text window 1
							copy selection
							close text window 1 saving no
							paste
						end tell
					end if
				end if
			end repeat
		end tell
	
		set countOne to countOne + 1
		set listCount to listCount + 1
		
	end repeat
end open


on deleteHeader()
	tell application "TextWrangler"
		activate
		find "{QTtext}" searching in text 1 of text document 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false} with selecting match
		find "[00:00:00.00]" searching in text 1 of text document 1 options {search mode:literal, starting at top:false, wrap around:true, backwards:false, case sensitive:false, match words:false, extend selection:true} with selecting match
		delete selection
		set the clipboard to "
Title"
		paste
	end tell
end deleteHeader

on timeCodeToSeconds(timeCode)
	return ((text 1 thru 2 of (word 3 of timeCode)) + 60 * (word 2 of timeCode) + 3600 * (word 1 of timeCode))
end timeCodeToSeconds

on addToTimeString(nSeconds, timeString)
	set {tid, text item delimiters} to {text item delimiters, ":"}
	set timeElements to reverse of (text items of timeString)
	set milliSeconds to text -2 thru -1 of (item 1 of timeElements)
	set item 1 of timeElements to text 1 thru 2 of (item 1 of timeElements)
	set lastItem to length of timeElements
	set additionInProgress to true
	set currentElementIndex to 1
	set currentAdditionValue to nSeconds
	repeat while additionInProgress
		set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) + currentAdditionValue
		if (item currentElementIndex of timeElements) ≥ 60 then
			if currentElementIndex = lastItem then return "Overflow Error"
			set currentAdditionValue to 0
			repeat while (item currentElementIndex of timeElements) ≥ 60
				set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) - 60
				set currentAdditionValue to currentAdditionValue + 1
			end repeat
		else
			set additionInProgress to false
		end if
		set (item currentElementIndex of timeElements) to my formatTwoDigitNumber(item currentElementIndex of timeElements)
		set currentElementIndex to currentElementIndex + 1
	end repeat
	set retval to ((reverse of timeElements) as string) & "." & milliSeconds
	set text item delimiters to tid
	return retval
end addToTimeString

on formatTwoDigitNumber(intNumber)
	if intNumber > 9 then return (intNumber as string)
	return ("0" & intNumber)
end formatTwoDigitNumber

It too is a bit cobbled together but it works as well. Nigel I tried to add your handler “addSecondsToTimeCode(s, timeCode)” to it but I was to far into it and it was working and I did not want to break it.

In order to finish this script, I need to have a hadler that will convert the timecode from this format:

[00:00:00.15]
Let’s simplify this expression. Notice we are
adding two numbers with unlike signs.
[00:00:08.00]
So what do we do? We subtract their absolute values.
[00:00:11.00]
Let me go ahead and find the absolute value
of each number.
[00:00:14.00]
The absolute value of negative five is five.
And the absolute value of eight is eight.
[00:00:20.00]

to this format:

00:00:00.150,00:00:08.000
Let’s simplify this expression. Notice we are
adding two numbers with unlike signs.
00:00:08.001,00:00:11.000
So what do we do? We subtract their absolute values.
00:00:11.001,00:00:14.000
Let me go ahead and find the absolute value
of each number.
00:00:14.001,00:00:20.000
The absolute value of negative five is five.
And the absolute value of eight is eight.

This handler would run after all the dropped documents have been processed.

I hope I am not being to greedy. I never dreamed that I would get this far in a few days and I see the light at the end of the tunnel. I really cannot thank you all enough for all your help.

Hi, thebeliever.

The other way is to put ‘my’ in front of the call to the handler (or ‘of me’ after it). This indicates that the call is to something belonging to the script (known as ‘me’ in AppleScript) rather than to “TextWrangler” or to whatever else is currently being ‘told’.

tell application "TextWrangler"
	activate
	set Doc_to_open to item countOne of theDroppedItems
	open Doc_to_open
    
	my deleteHeader()
    
	set searchOptions to {search mode:grep, starting at top:true, case sensitive:true}

	-- etc.

end tell

That’s no problem. “addSecondsToTimeCode(s, timeCode)” is just me thinking out loud about efficient ways to tackle an interesting problem. You need something that will be written and do the job within the next day or two. :slight_smile:

I hope to be able to look at your script and the remaining problem later today, but maybe Dominik or someone else will come up with an answer before that.

This is pretty close. It assumes that there are the necessary time codes in the text.

on timeCodesToTimeRanges()
	tell application "TextWrangler"
		activate
		set grepText to "\\[[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]" as Unicode text
		-- The search/replacements have to be done backwards to accommodate changing text length.
		-- (Actually, they might not, but it seemed a good idea at the time.)
		set searchOptions to {search mode:grep, backwards:true, case sensitive:true}
		
		-- Go to the end of the document.
		select character -1 of text of text document 1
		-- Note the last time code, strip the brackets, and append an extra "0".
		set findResult to (find grepText searching in text of text document 1 options searchOptions with selecting match)
		set lastTimeCode to text 2 thru -2 of findResult's found text & "0"
		-- Zap the time code from the document
		set contents of findResult's found object to ""
		
		repeat while (findResult's found)
			-- Find the preceding time code.
			set findResult to (find grepText searching in text of text document 1 options searchOptions)
			if (findResult's found) then
				-- Replace it in the document with a range consisting of it and the one got previously.
				set thisTimeCode to text 2 thru -2 of findResult's found text
				set contents of findResult's found object to thisTimeCode & "1," & lastTimeCode
				-- Make it now the "one got previously".
				set lastTimeCode to thisTimeCode & "0"
			else
				-- If no preceding time code found, edit the last replacement done.
				-- (Replacement text is automatically selected by TextWrangler.)
				set firstRange to contents of selection
				set the selection to text 1 thru 11 of firstRange & "0" & text 13 thru -1 of firstRange
			end if
		end repeat
	end tell
end timeCodesToTimeRanges

Nigel and Dominik, after running my script below at work, I realized that I have to be able to add milliseconds to all the timecodes. If I do not do this my timecode gets off by a few milliseconds each time it processes a new document so that in the end the timecode it off by serveral second when the script finishes.

global Doc_to_open
on open theDroppedItems
   set countOne to 1
   set listCount to 1
   set numberToAdd to 4
   repeat until listCount > (count theDroppedItems)
       
       tell application "TextWrangler"
           activate
           set Doc_to_open to item countOne of theDroppedItems
           open Doc_to_open
       end tell
       
       
       deleteHeader()
       
       tell application "TextWrangler"
           activate
           set searchOptions to {search mode:grep, starting at top:true, case sensitive:true}
           set noFind to false
           repeat until (noFind)
               set findResult to (find "\\[[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9]\\]" searching in text 1 of text document 1 options searchOptions)
               if (found of findResult) then
                   set theTime to found text of findResult -- Get the text directly from the returned record.
                   set theTimePlusFour to "[" & (my addToTimeString(numberToAdd, text 2 thru -2 of theTime)) & "]"
                   set timeCode to theTimePlusFour
                   set contents of found object of findResult to theTimePlusFour -- Replace the text directly in the document.
                   set starting at top of searchOptions to false -- Neutralise this option for subsequent searches.
               else
                   set noFind to true
                   set numberToAdd to 4
                   cut selection
                   paste
                   set lastTimeCodePlusFour to "[" & (my addToTimeString(numberToAdd, text 2 thru -2 of timeCode)) & "]"
                   set numberToAdd to (my timeCodeToSeconds(lastTimeCodePlusFour))
                   if countOne > 1 then
                       tell application "TextWrangler"
                           select text 1 of text window 1
                           copy selection
                           close text window 1 saving no
                           paste
                       end tell
                   end if
               end if
           end repeat
       end tell
   
       set countOne to countOne + 1
       set listCount to listCount + 1
       
   end repeat
end open


on deleteHeader()
   tell application "TextWrangler"
       activate
       find "{QTtext}" searching in text 1 of text document 1 options {search mode:literal, starting at top:true, wrap around:false, backwards:false, case sensitive:false, match words:false, extend selection:false} with selecting match
       find "[00:00:00.00]" searching in text 1 of text document 1 options {search mode:literal, starting at top:false, wrap around:true, backwards:false, case sensitive:false, match words:false, extend selection:true} with selecting match
       delete selection
       set the clipboard to "
Title"
       paste
   end tell
end deleteHeader

on timeCodeToSeconds(timeCode)
   return ((text 1 thru 2 of (word 3 of timeCode)) + 60 * (word 2 of timeCode) + 3600 * (word 1 of timeCode))
end timeCodeToSeconds

on addToTimeString(nSeconds, timeString)
   set {tid, text item delimiters} to {text item delimiters, ":"}
   set timeElements to reverse of (text items of timeString)
   set milliSeconds to text -2 thru -1 of (item 1 of timeElements)
   set item 1 of timeElements to text 1 thru 2 of (item 1 of timeElements)
   set lastItem to length of timeElements
   set additionInProgress to true
   set currentElementIndex to 1
   set currentAdditionValue to nSeconds
   repeat while additionInProgress
       set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) + currentAdditionValue
       if (item currentElementIndex of timeElements) ≥ 60 then
           if currentElementIndex = lastItem then return "Overflow Error"
           set currentAdditionValue to 0
           repeat while (item currentElementIndex of timeElements) ≥ 60
               set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) - 60
               set currentAdditionValue to currentAdditionValue + 1
           end repeat
       else
           set additionInProgress to false
       end if
       set (item currentElementIndex of timeElements) to my formatTwoDigitNumber(item currentElementIndex of timeElements)
       set currentElementIndex to currentElementIndex + 1
   end repeat
   set retval to ((reverse of timeElements) as string) & "." & milliSeconds
   set text item delimiters to tid
   return retval
end addToTimeString

on formatTwoDigitNumber(intNumber)
   if intNumber > 9 then return (intNumber as string)
   return ("0" & intNumber)
end formatTwoDigitNumber

As a reminder, the script shift the timecode for each document that is dropped on it by the total amount of seconds of the previous captioned file (plus four or what ever number is set in the variable) and then combines the documents dropped on it them all into one caption file and .

I tried adding the ability to add milliseconds but it would not work. Note, QuickTime uses 100 millsecond to make on second. So I would like to be able to add second and milliseconds so that I can say add X seconds and XX milliseconds. But I guess I could convert to milliseconds before inputting the number. Which ever ways is easier.

I hope to have this working by tomorrow morning (since that when these files are supposed to ship). I would appreciate any help you all are willing to give.

Thanks

get my addToTimeString(4, 4, "00:00:14.00")

on addToTimeString(nMilliseconds, nSeconds, timeString)
	
	set {tid, text item delimiters} to {text item delimiters, ":"}
	set timeElements to reverse of (text items of timeString)
	set milliSeconds to text -2 thru -1 of (item 1 of timeElements)
-- new part ------------------------
	set milliSeconds to milliSeconds + nMilliseconds
	repeat while (milliSeconds > 99)
		set milliSeconds to milliSeconds - 100
		set nSeconds to nSeconds + 1
	end repeat
	set milliSeconds to my formatTwoDigitNumber(milliSeconds)
--------------------------------------
	set item 1 of timeElements to text 1 thru 2 of (item 1 of timeElements)
	set lastItem to length of timeElements
	set additionInProgress to true
	set currentElementIndex to 1
	set currentAdditionValue to nSeconds
	repeat while additionInProgress
		set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) + currentAdditionValue
		if (item currentElementIndex of timeElements) ≥ 60 then
			if currentElementIndex = lastItem then return "Overflow Error"
			set currentAdditionValue to 0
			repeat while (item currentElementIndex of timeElements) ≥ 60
				set (item currentElementIndex of timeElements) to (item currentElementIndex of timeElements) - 60
				set currentAdditionValue to currentAdditionValue + 1
			end repeat
		else
			set additionInProgress to false
		end if
		set (item currentElementIndex of timeElements) to my formatTwoDigitNumber(item currentElementIndex of timeElements)
		set currentElementIndex to currentElementIndex + 1
	end repeat
	set retval to ((reverse of timeElements) as string) & "." & milliSeconds
	set text item delimiters to tid
	return retval
end addToTimeString

on formatTwoDigitNumber(intNumber)
	if intNumber > 9 then return (intNumber as string)
	return ("0" & intNumber)
end formatTwoDigitNumber

Regards,

Dominik

Edit - or using ‘div’ and ‘mod’ - I think that’s nicer ;-):

-- new part -----
	set milliSeconds to milliSeconds + nMilliseconds
	set nSeconds to milliSeconds div 100
	set milliSeconds to my formatTwoDigitNumber(milliSeconds mod 100)
-------

Dominik,
I also need a way to get the millisecond value from a timecode. Would it be something like this?

on saveMilliseconds(timeCode)
	set {tid, text item delimiters} to {text item delimiters, ":"}
	set timeElements to reverse of (text items of timeCode)
	set milliSeconds to text -2 thru -1 of (item 1 of timeElements)
	return milliSeconds
end saveMilliseconds

Thanks

Hi thebeliever,

this handlers return the milliseconds value …

… as integer:

on saveMilliseconds(timeCode)
	return ((last word of timeCode as real) mod 1) * 100 as integer
end saveMilliseconds

… as string:

on saveMilliseconds(timeCode)
	return (text -2 thru -1 of (last word of timeCode))
end saveMilliseconds

D.

Hi, Dominik. It’s times 1000 for milliseconds. :slight_smile:

Again this needs to be adjusted for milliseconds. It also depends on whether or not leading zeros need to be provided for:

-- Without leading zeros:
on saveMilliseconds(timeCode)
	return ((last word of timeCode) mod 1 + 1.0E-4) div 1.0E-3 as string -- + 1.0E-4 shakes out floating point errors.
end saveMilliseconds

-- Leading zeros if < 1000:
on saveMilliseconds(timeCode)
	return text 3 thru 5 of ((last word of timeCode) mod 1 + 1.0E-4 as string) -- + 1.0E-4 gives trailing zeros, if necessary,
end saveMilliseconds

That said, I suppose thebeliever could actually have meant centiseconds. :confused:

lol - stupid me - i saw a two digits value and didn’t think about the meaning of ‘milli’ … Thanks for the correction, Nigel :wink:

But rethinking this, I am afraid it’s neither milli nor centi - wasn’t the last two digits of a time code a frame count value? (0-24 or 0-29, or … depending on the video system)?

That’s what I thought at first. It would be normally. I’ve just assumed that since thebeliever is apparently working in a professional environment, he or she has got it right for the system in use. Now I look more closely, I see thebeliever said yesterday that QuickTime uses 100 milliseconds to the second. That wouldn’t surprise me for a moment, but I’ll see if I can confirm it when I get off-line. Your handlers might be right after all. :wink:

Later: No. I’m pretty sure that thebeliever’s just got the word wrong and means centiseconds. QuickTime doesn’t say anything about milliseconds that I can find. (But I don’t have QuickTime Pro and haven’t tried timing individual moments in a movie.) Running times, at least, are shown in 7.1.3’s movie information window in one of two ways. If the movie’s frame rate is an integer factor of 30, the sub-second element of the time is shown as fames / frame rate (eg. “00:00:24.6/15” “ for 24 seconds and 6 frames at 15 frames per second). Otherwise, the time is shown rounded down to the nearest hundredth of a second (eg. “00:00:24.27”).