Monitor txt file for new lines.

I’m attempting to bookmark video times for my lectures using MPV player and applescript. I log the terminal output of MPV to a text file, and get the script to read the file looking for [bookmark]. The bookmark line is not a function of MPV, but something I’ve mapped to output when I press a key.

My problem is that in a live situation (I’m watching the video, and making bookmarks), the script is looping through all the lines with each iteration and I end up with a list full of duplicates. I know I could clean this up after I quit the video, but I’m going to add a text entry when applescript finds a unique bookmark in the terminal output. So I need to do the filtering as the text file is being read.

Ideally, when the lines of the text file are read the number of lines is assigned to a variable initial_lines. When the text file is read again the number of lines is assigned to current_lines. I then could do (current - initial) +1) to start reading on the next line from the initial_lines.

I missing something subtle (or maybe no so subtle), because the script will work if the text file is complete (I’ve watched the video, made bookmarks, and closed the video & terminal output), but during a live situation its broke.

Here’s an example of the text log.

The script:

property line_count : ""
property line_current : "1"
property line_previous : "0"

set {_exit, bmark_list} to {false, {}}


repeat until _exit is true
	
	try
		set logs to my get_lines() --sets line_count
		set line_current to ((line_count - line_previous) + 1)
		
		repeat with n from line_current to (count of logs)
			
			set str to text of (item n of logs) as string
			
			if str starts with "[bookmark]" then
				set _bmark to my get_bmark_info(str, "[bookmark] ", " [/bookmark]")
				
				set _time to item 1 of _bmark
				if _time is not in bmark_list then
					set end of bmark_list to _bmark
				end if
				
			else if str contains "Exiting... (Quit)" then
				set _exit to true
			end if
			
		end repeat
		
		set line_previous to count of logs
		
	end try
end repeat

return bmark_list


on get_lines()
	
	set temp_file to (POSIX path of (path to temporary items from user domain) & "mpvlogger.txt")
	set logs to paragraphs of (read temp_file)
	set line_count to count of logs
	
	set line_items to {}
	repeat with i from 1 to line_count by 1
		if (i + 0) is not greater than line_count then
			set end of line_items to items i thru (i + 0) of logs
		else
			set end of line_items to items i thru line_count of logs
		end if
	end repeat
	
	return line_items
	
end get_lines



to get_bmark_info(_line, tag_open, tag_close)
	
	set tid to text item delimiters
	set text item delimiters to tag_open
	set list_e to text items of _line
	set text item delimiters to tag_close
	set info to {}
	repeat with sub_txt in list_e
		if sub_txt contains tag_close then
			copy text item 1 of sub_txt to end of info
		end if
	end repeat
	set text item delimiters to tid
	
	set info to info as text
	set text item delimiters to ";"
	set the_path to text item 1 of info
	set the_time to text item 2 of info
	set text item delimiters to tid
	
	return {the_time, the_path}
	
end get_bmark_info

So I got this working, but it’s really hacky, and the repeat loop monitoring the txt file is not very specific. Meaning it reads through the entire file every repeat, and then I grab unique lines with another list.

Another thing I don’t like is that I needed three .scpt files to get this running. I’m almost positive I’m missing something in this regard, and that there is a much better way to achieve this.

set temp_file to (POSIX path of (path to temporary items from user domain) & "mpvlogger.txt")

set vid_file to "/Users/drlulz/Desktop/2013_BECKER_Pathology_01.mp4"
set vid_file_qt to quoted form of vid_file
set vid_file_posix to POSIX file (vid_file) as alias

set proxy_scpt to quoted form of POSIX path of ((path to scripts folder from user domain as text) & "proxy.scpt")
set vid_time to " --start=" & "00:00:00"
set vid_options to quoted form of (" --autofit=100% --save-position-on-quit") --& vid_time)
set cmd_mpv to proxy_scpt & " " & quoted form of temp_file & " " & vid_file_qt & " " & vid_options

set launch_mpv to load script file ((path to scripts folder from user domain as text) & "launch_mpv.scpt")
tell (launch_mpv)
	set its _file to temp_file
	set its _vid to vid_file_qt
	--set its _time to vid_time
	set its _options to vid_options
end tell


try
	do shell script "rm -f " & temp_file
end try
do shell script "touch " & temp_file

tell application "System Events"
	try
		set ThePID to unix id of process "mpv"
		do shell script "kill -KILL " & ThePID
	end try
	do shell script "osascript " & cmd_mpv & " &> /dev/null &"
end tell


set {is_bmark, _exit, working_list, bmark_list} to {false, false, {}, {}}
repeat until is_bmark = true
	try
		set logs to my get_lines()
		set is_bmark to true
	end try
end repeat


repeat until _exit is true
	
	repeat with n from 1 to (count of logs)
		set str to text of (item n of logs) as string
		
		if (str starts with "[bookmark]") and (working_list does not contain str) then
			set _bmark to my get_bmark_info(str, "[bookmark] ", " [/bookmark]", bmark_list)
			set end of bmark_list to (_bmark & return)
			set end of working_list to str
		else if str contains "Exiting... (Quit)" then
			set _exit to true
		end if
		
		set logs to my get_lines()
	end repeat
	
end repeat


if bmark_list is not {} then
	my bookmark_txt_file(vid_file_posix, bmark_list, true)
end if
return bmark_list


on get_lines()
	
	set temp_file to (POSIX path of (path to temporary items from user domain) & "mpvlogger.txt")
	set logs to paragraphs of (read temp_file)
	set line_count to count of logs
	
	set line_items to {}
	repeat with i from 1 to line_count by 1
		if (i + 0) is not greater than line_count then
			set end of line_items to items i thru (i + 0) of logs
		else
			set end of line_items to items i thru line_count of logs
		end if
	end repeat
	
	return line_items
	
end get_lines



to get_bmark_info(_line, tag_open, tag_close, bmark_list)
	
	set tid to text item delimiters
	set text item delimiters to tag_open
	set list_e to text items of _line
	set text item delimiters to tag_close
	set info to {}
	repeat with sub_txt in list_e
		if sub_txt contains tag_close then
			copy text item 1 of sub_txt to end of info
		end if
	end repeat
	set text item delimiters to tid
	
	set info to info as text
	set text item delimiters to ";"
	set the_path to text item 1 of info
	set the_time to (text item 2 of info & ";")
	set text item delimiters to tid
	
	
	tell application "mpv"
		display dialog "Enter Bookmark Title" default answer "" with title "MPV Bookmark" with icon path to resource "icon.icns" in bundle (path to application "mpv")
		set _title to (text returned of the result & ";")
	end tell
	
	tell application "System Events"
		tell process "mpv" to set W to (name of windows)
		tell application process "mpv"
			set frontmost to true
			set value of attribute "AXMain" of (first window whose name contains W) to true
		end tell
	end tell
	
	return {_title, the_time, the_path}
	
end get_bmark_info



on bookmark_txt_file(vid_file, the_report, append_data)
	
	set the_report to the_report as string
	
	tell application "Finder" to set vid_name to text 1 thru ((offset of "." in (name of vid_file as string)) - 1) of (name of vid_file as string)
	tell application "Finder" to set vid_folder to container of vid_file as string
	
	set target_file to vid_folder & vid_name & ".txt"
	
	try
		set the target_file to target_file as string
		set the open_target_file to open for access file target_file with write permission
		if append_data is false then set eof of open_target_file to 0
		write the_report to open_target_file starting at eof
		close access the open_target_file
	on error
		try
			close access file target_file
		end try
	end try
	
	do shell script "open " & (quoted form of POSIX path of target_file) as string
	
end bookmark_txt_file
on run argv
	set launch_mpv to load script file ((path to scripts folder from user domain as text) & "launch_mpv.scpt")
	set temp_file to (item 1 of argv)
	set vid_file to (item 2 of argv)
	set vid_options to (item 3 of argv)
	tell (launch_mpv)
		set its _file to temp_file
		set its _vid to vid_file
		set its _options to vid_options
		run
	end tell
end run
property _file : ""
property _vid : ""
property _options : ""


do shell script "/usr/local/Cellar/mpv/0.7.3/bin/mpv " & quoted form of _vid & _options & " | tee " & quoted form of _file