My Favorite Way to Download from YouTube

I discovered a method for downloading YouTube videos that is based on the 4k Video Downloader method at Robservatory.com, but works faster and better for me. The software needed is called yt-dlp, and you can install it using Homebrew. Here’s one recommended Terminal command line for installing the most recently released yt-dlp:

brew install yt-dlp/taps/yt-dlp

To update the installation of yt-dlp performed this way, use the following command.

brew upgrade yt-dlp/taps/yt-dlp

After you’ve built this Automator Quick Action as described below, you’ll be able to select the URL of the video you’d like to download in the URL field of the web browser (Safari), then right-click and choose Services to select the action.

You’ll need to be able to set up a Quick Action (Monterey) or a Service (if you have a version of macOS older than Monterey, as shown in Rob’s article mentioned above, or as explained by Ben Waldie) in Automator. The Quick Action will be saved as a Contextual Menu Item and will be available from the Services menu when you right-click text (in our case, a URL link in Safari’s URL field).

Use one of the two paths to the yt-dlp executable, not both.

In the script included below, I used the first of the two because my Silicon Mac uses the M1 native version of HomeBrew to install yt-dlp:

So, if you have installed Homebrew natively on your Silicon (M1, M2, etc.) Mac, use the following line

set ExecLoc to "/opt/homebrew/bin"

If you have an Intel Mac or you have upgraded to Silicon, but haven’t migrated your Homebrew installation, use the following line instead:

ExecLoc to "/usr/local/bin"

You can normally determine the location of the executable by running the Terminal command:

which yt-dlp

It is possible to include that command in the script, but that would make the script more complex than it really needs to be, so I suggest performing that step yourself and using the result to decide which line of the included script to use. (Both lines specifying the typical locations for the yt-dlp executable are included in the code below, but I’ve started the unneeded line with “#” to include it only as a comment, nullifying its ability to affect the AppleScript. If you like, you may leave both lines, and simply “comment” the line that isn’t appropriate for your configuration. I’ve used two “#”‘s, just to make them easier to see. One is enough to “comment” the line. In AppleScript, 2 hyphens can be used at the beginning of a line as an alternative method of transforming it into a comment.)

The first step in making the contextual menu item that will download videos is to create a new document in the Automator app on your Mac. If you open Automator and it presents an Open dialog window, just close it and select New from the File menu. Here’s where you specify the Quick Action workflow type.

Choosing the Quick Action Automator document type

You’ll need a Run AppleScript action in your Quick Action or Service workflow. The AppleScript I’ve composed contains the command line that will be sent to the yt-dlp executable. I’ve tried several forms of the command and the one I’ve provided is my favorite. It combines high quality audio and video with available English subtitles, including the automatically generated subtitle track (combining these files requires that ffmpeg also be installed using, for example, the Homebrew installation instructions for ffmpeg provided elsewhere on this blog). I’ve found that the action built using this command line, depending on the content and duration of the video, downloads the video very quickly, often before the ad timer expires. There are many, many combinations of command options that may be substituted, of course, if you have familiarized yourself with the capabilities of yt-dlp.

Replace the default contents of the Run AppleScript action with the following text, specifying the correct value for the ExecLoc variable as explained above:

on run {input, parameters}
	(* Your script goes here *)
	set ExecLoc to "/opt/homebrew/bin"
	##set ExecLoc to "/usr/local/bin"
	
	set startyt to ExecLoc & "/yt-dlp" & space & "-f" & space & "\"" & "bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4] / bv*+mergeall[vcodec=none]" & "\"" & space & "-o ~/Downloads/'%(title)s.%(ext)s'" & space & "--ffmpeg-location" & space & ExecLoc & space & "--embed-subs --write-auto-subs --restrict-filenames"
	set entireCommand to startyt & space & input
	do shell script entireCommand
end run

At the top of the Quick Action window in Automator, set Workflow receives current to URLs. You can limit the Quick Action‘s availability to Safari or make it available in any application. You can use the screen window snapshot below as a guide for determining what to use for the remaining settings, or try your own.

Automator Quick Action to download a video from its URL

Save the workflow (I’ve put an underscore at the beginning of its name so that in will be listed at or near the top of Quick Action or Services list when the URL of the displayed video is selected in Safari’s URL field and the contextual click is performed on that link.) When you perform the action, an indeterminate progress indicator (it looks like a spinning gear cog) should appear in your menu bar. When it disappears, you should find the downloaded video in your Downloads folder.

Create an AppleScript application to concatenate media files using ffmpeg.

Please read the following, or you’ll probably reach the conclusion that this doesn’t work right, and then you’ll just be mad at me for wasting your time.

The AppleScript below is configured to exploit a special relationship between AppleScript and the Mac Finder. Here are two suggested methods for using it to concatenate media files by passing the appropriate commands to ffmpeg. First, the media files must be compatible for concatenation. The documentation for ffmpeg can help with that. The AppleScript will create the concatenated output file in the same folder as the source files. The ffmpeg command generated by the AppleScript is ultimately placed in the trash, so you can retrieve it from there and view it if something doesn’t work as expected.

Method 1

I suggest this as the most straightforward method for using the AppleScript. Paste the AppleScript into a Script Editor window, then save it as an Application with any name you choose. The Application allows dropping multiple items onto its icon. Make a new folder in Finder, and place only the files to be concatenated into it. Ensure that the files in the folder are displayed in list view (as List in the Finder’s View menu), then sort the list as desired with the first file at the top of the window (name them so that they can be correctly sorted). Select all of the files (Select All from the Finder’s Edit menu), then click and drag the first file (the file at the top of the list) to the application’s icon (all of the selected files will be included in the drag). Accept the default name for the output or enter a new one and press OK.

Method 2

This method may be more useful if there are only a few files to concatenate. Paste the AppleScript into a Script Editor window and press RUN (The triangle pointing right near the top of the Script Editor window), or open the Application created from the AppleScript in a Script Editor window and press RUN. Navigate to the folder containing the source files in the Open dialog, then hold the Command key and click the files one at a time in the order in which you want them concatenated. While the clicked files remain selected in the Open dialog window, click OK. The output file will have a name based on the first file you clicked in the Open dialog.

It’s possible that you’ll need to provide a full path name for the ffmpeg executable rather than just the name “ffmpeg” (line 47, right after “sleep 3;”). To determine where your ffmpeg executable resides, you can run the following command in Terminal:

which ffmpeg

If you don’t have a compatible version of ffmpeg installed, install it using Homebrew. Here’s one recommended command line for installing the most recently released ffmpeg:

brew install homebrew-ffmpeg/ffmpeg/ffmpeg --HEAD

Here’s an example for including non-default options when installing ffmpeg

brew install homebrew-ffmpeg/ffmpeg/ffmpeg –HEAD –with-fdk-aac –with-two-lame

To update the installation of ffmpeg performed this way, use the following command.

brew update && brew upgrade homebrew-ffmpeg/ffmpeg/ffmpeg --fetch-HEAD

--begin AppleScript--
property temppath : "/private/tmp/"
property startnum : 0
property tmpfile : "/tmp/execme.command"
property outname : ""

on open the_items
	my ffmpeg_cat(the_items)
end open

on ffmpeg_cat(the_items)
	set theshellscript to ""
	repeat with i from 1 to (count of the_items)
		set itemcount to (count of the_items)
		set the_item to item i of the_items as alias
		try
			tell application "Finder"
				set sost to (container of the_item) as string
			end tell
			set pos_filepath to POSIX path of sost
		end try
		set this_filepath to (the_item as string)
		
		if last character of this_filepath is ":" then
			tell me to set it_is_a_folder to true
		else
			set it_is_a_folder to false
		end if
		set thesourcename to (name of (info for the_item))
		set namepart to (name extension of (info for the_item))
		set the_source_file to POSIX path of this_filepath
		if outname is "" then
			set outname to (text returned of (display dialog "Enter a name for the concatenated output file:" default answer thesourcename))
		end if
		set finalname to replace_chars(outname, "." & namepart, "")
		try
			if i = 1 then
				set the filelistbody to "# comment" & return & "file" & space & (quoted form of the_source_file) & return
			else
				set the filelistbody to filelistbody & "file" & space & (quoted form of the_source_file) & return
			end if
		on error onerr
			activate
			display dialog onerr
		end try
	end repeat
	set fileData to "echo" & space & "\"" & filelistbody & "\"" & space & "> ffmpegCatList"
	set theshellscript to fileData & ";sleep 3;ffmpeg -f concat -safe 0 -i ffmpegCatList -c copy" & space
	set shellExec to space & (quoted form of (pos_filepath & finalname & "_1-" & i & "." & namepart))
	set theshellscript to the theshellscript & shellExec & ";sleep 3" & return
	set the clipboard to theshellscript
	set theshellscript to theshellscript & ";/bin/echo '
			
			==========================
			
			" & finalname & "_1-" & i & "." & namepart & space & "FINISHED!" & "
			
			==========================
			
			';mv" & space & (quoted form of tmpfile) & space & (quoted form of (POSIX path of (path to trash))) & ";mv ffmpegCatList" & space & (quoted form of (POSIX path of (path to trash)))
	do shell script "echo " & quoted form of theshellscript & " > " & tmpfile
	
	repeat
		try
			do shell script "chmod +x " & tmpfile
			do shell script "open -a Terminal.app" & space & tmpfile
			exit repeat
		on error
			delay 1
		end try
	end repeat
	
end ffmpeg_cat

on replace_chars(this_text, _bad, _good)
	set AppleScript's text item delimiters to the _bad
	set the item_list to every text item of this_text
	set AppleScript's text item delimiters to the _good as string
	set this_text to the item_list as string
	set AppleScript's text item delimiters to ""
	return this_text
end replace_chars

on run
	set the_items to ((choose file with multiple selections allowed) as list)
	ffmpeg_cat(the_items)
end run--end AppleScript--

Create an AppleScript application to drop or open a folder of files in ffmpeg-normalize.

Audio content can be normalized and converted using ffmpeg-normalize. Here’s an AppleScript that can be saved as an application for dropping or choosing a folder of files to be processed by ffmpeg-normalize.

To use it, paste the code below into a Script Editor.app document window. Customize the six audio property variables at the start of the AppleScript, then run the AppleScript in Script Editor or save the AppleScript as an application. You can choose a folder of source files to which ffmpeg-normalize will be applied, or you can drop the folder onto the application file. The local path to the ffmpeg executable is specified by the first property. If you need to determine where your ffmpeg executable resides, you can run the following command in Terminal:

which ffmpeg

If you don’t have a compatible version of ffmpeg installed, install it using Homebrew. Here’s one recommended command line for installing the most recently released ffmpeg:

brew install homebrew-ffmpeg/ffmpeg/ffmpeg --HEAD

Here’s an example for including non-default options when installing ffmpeg

brew install homebrew-ffmpeg/ffmpeg/ffmpeg –HEAD –with-fdk-aac –with-two-lame

To update the installation of ffmpeg performed this way, use the following command.

brew update && brew upgrade homebrew-ffmpeg/ffmpeg/ffmpeg --fetch-HEAD

Instructions for installing and using ffmpeg-normalize are available at the ffmpeg-normalize Github site. Further explanation for the properties in the AppleScript are included after each property construct in the AppleScript. Some properties can be set to “” to accept ffmpeg-normalize default settings. The AppleScript identifies the properties that can be left empty. However, you must use combinations of settings that are compatible with the media and processing that you want to use. A working knowledge of ffmpeg-normalize is required, but the AppleScript may make batch processing for ffmpeg-normalize easier.

I should also probably point out that although I’ve only tested this using Monterey (macOS 12.3.1), it should be compatible for previous Mac systems, although you may need to change the start of the line that specifies the shell environment from

set full_command to "/bin/zsh

to

set full_command to "/bin/bash

--begin AppleScript--
property ffmpegrootPath : "/opt/homebrew/bin/ffmpeg" ## full path to the ffmpeg executable. It's needed to allow the AppleScript shell environment to tell ffmpeg-normalize where to find ffmpeg.
property outFolder : "normalized" ## This folder will be created inside the chosen/dropped folder and will contain the output. (The default output folder name is "normalized". Most names should be OK, but don't give the output folder the same name as the input folder.)
property sample_rate : "44100" ##Examples: 11025, 22050, 44100, 48000 (May be set to "" to apply default values.)
property rate_spec : "256K" ##Examples: 128K, 256K, 320K, 640K (May be set to "" to apply default values.)
property aud_Encoder : "libmp3lame" ##Examples: libmp3lame, aac, pcm_s16le, libfdk_aac -e='-vbr 3', eac3 (See all by running "ffmpeg encoders" in Terminal. Optional constructs can be added here also, as suggested in the "libfdk_aac -e='-vbr 3'" example. May be set to "" to apply default values.)
property out_spec : "mp3" ##Examples: mp3, aac, aif, wav, m4a, mp4 (The output container extension is designated by this variable, so ensure that displayed names of the input files having different name extensions are not duplicated when they are named with this extension. May be set to "" to apply default values.)

property a_folder : missing value

on run
	set these_items to ((choose folder with prompt "Choose a folder containing files to convert:") as list)
	my do_normalizing(these_items)
end run

on open these_items
	my do_normalizing(these_items)
end open

on do_normalizing(these_items)
	repeat with i from 1 to the count of these_items
		set this_item to item i of these_items
		set gen_item to this_item
		set gen_info to info for gen_item
		set gen_kind to folder of gen_info as Unicode text
		if gen_kind is "true" then
			tell me to set a_folder to true
		else
			set a_folder to false
		end if
		if a_folder then
			process_folder(this_item)
		else
			if (alias of gen_info is false) then
				process_item(this_item)
			end if
		end if
	end repeat
end do_normalizing

on process_folder(this_folder)
	set these_items to paragraphs of (do shell script "ls" & space & (quoted form of (POSIX path of this_folder)))
	set this_folder to this_folder as Unicode text
	set my_parent to this_folder
	repeat with i from 1 to the count of these_items
		set this_item to (this_folder & (item i of these_items))
		try
			set the item_info to (info for (this_item as alias))
			if folder of the item_info is true then
				set this_item to this_item & ":"
				process_folder(this_item)
			else if (alias of the item_info is false) then
				--display dialog this_item
				process_item(this_item as alias)
			end if
		on error the error_message number the error_number
			if the error_number is in {-43, -2706, -2753, -48} then
			else
				display dialog the (error_number as string) & space & the error_message
			end if
		end try
	end repeat
end process_folder

on process_item(this_item)
	tell application "Finder" to get (container of this_item) as text
	set my_parent to result
	tell application "Finder"
		set namepart to name extension of file this_item
		set namefull to name of file this_item
	end tell
	set the commandfolder to ((POSIX path of my_parent) as text)
	try
		set sample_rate to my replace_chars(sample_rate, " -ar ", "")
	end try
	try
		set aud_Encoder to my replace_chars(aud_Encoder, " -c:a ", "")
	end try
	try
		set rate_spec to my replace_chars(rate_spec, " -b:a ", "")
	end try
	try
		set out_spec to my replace_chars(out_spec, " -ext ", "")
	end try
	if sample_rate is not "" then
		set sample_rate to ((space & "-ar" & space & sample_rate) as text)
	end if
	if aud_Encoder is not "" then
		set aud_Encoder to ((space & "-c:a" & space & aud_Encoder) as text)
	end if
	if rate_spec is not "" then
		set rate_spec to ((space & "-b:a" & space & rate_spec) as text)
	end if
	if out_spec is not "" then
		set out_spec to ((space & "-ext" & space & out_spec) as text)
	end if
	set full_command to "/bin/zsh -c ;export FFMPEG_PATH=" & ffmpegrootPath & space & "&&" & space & ffmpegrootPath & "-normalize" & sample_rate & aud_Encoder & rate_spec & space & (quoted form of (commandfolder & namefull)) & space & "-of" & space & (quoted form of (commandfolder & outFolder)) & out_spec
	if full_command contains (outFolder & "/" & outFolder) then
	else
		do shell script full_command
	end if
end process_item

on replace_chars(this_text, reprap, goohood)
	set AppleScript's text item delimiters to the reprap
	set the item_list to every text item of this_text
	set AppleScript's text item delimiters to the goohood as string
	set this_text to the item_list as string
	set AppleScript's text item delimiters to ""
	return this_text
end replace_chars
--end AppleScript--

Create an AppleScript application to use stl2scad as a droplet app.

Joshua Flanagan as written a handy Python tool called stl2scad for converting .stl files (commonly distributed for 3D printing) to .scad files which can be opened in OpenSCAD on a Mac.

To use it, paste the code below into a Script Editor.app document window. Customizing the first two property variables is necessary, but (hopefully), trivial. The local path to the Python executable is specified by the first property, and the local path to the stl2scad.py script is specified by the second property. If you need to determine where your Python executable resides, you should be able to run the following command in Terminal:

which python3

If you don’t have a compatible version of Python installed, you should be able to install it using Homebrew.

Important: A space probably won’t exist in the path to the Python executable, but if a space (or any of a few other uncommon characters) exists in the path to the stl2scad.py script, simply create an escape for it by using two backslashes before each space. An example follows.

"~/my\\ python\\ scripts/stl2scad.py"

Download the stl2scad.py script. Run in the Script Editor and select a folder containing .stl files to convert, or save as an application for dropping the files, providing system permissions as prompted or in the Security & Privacy prefpane as needed. Drop one .stl file, a group of .stl files, a folder of .stl files or a hierarchy of folders of .stl files onto the application’s icon. The .scad files are created in the same folders as the .stl files just as though stl2scad had been run on each .stl file as a Terminal command.

--begin script--
property my_python_path : "/opt/homebrew/bin/python3"
property my_stl2scal_path : "~/py/stl2scad.py"
property a_folder : missing value

on run
	set these_items to ((choose folder with prompt "Choose a folder containing .stl files to convert:") as list)
	my convert_stl2scad(these_items)
end run

on open these_items
	my convert_stl2scad(these_items)
end open

on convert_stl2scad(these_items)
	repeat with i from 1 to the count of these_items
		set this_item to item i of these_items
		set gen_item to this_item
		set gen_info to info for gen_item
		set gen_kind to folder of gen_info as Unicode text
		if gen_kind is "true" then
			tell me to set a_folder to true
		else
			set a_folder to false
		end if
		if a_folder then
			process_folder(this_item)
		else
			if (alias of gen_info is false) then
				process_item(this_item)
			end if
		end if
	end repeat
end convert_stl2scad

on process_folder(this_folder)
	set these_items to paragraphs of (do shell script "ls" & space & (quoted form of (POSIX path of this_folder)))
	set this_folder to this_folder as Unicode text
	repeat with i from 1 to the count of these_items
		set this_item to (this_folder & (item i of these_items))
		try
			set the item_info to (info for (this_item as alias))
			if folder of the item_info is true then
				set this_item to this_item & ":"
				process_folder(this_item)
			else if (alias of the item_info is false) then
				process_item(this_item as alias)
			end if
		on error the error_message number the error_number
			if the error_number is in {-43, -2706, -2753, -48} then
			else
				display dialog the (error_number as string) & space & the error_message
			end if
		end try
	end repeat
end process_folder

on process_item(this_item)
	set sourcepath to (quoted form of (POSIX path of (this_item as Unicode text)))
	tell application "Finder"
		set namepart to name extension of file this_item
		set namefull to name of file this_item
	end tell
	set full_command to my_python_path & space & my_stl2scal_path & space & sourcepath
	if namepart is "stl" then
		try
			do shell script full_command
		on error error_message number the error_number
			display dialog "Error: " & the error_number & ". " & the error_message & return & namefull giving up after 5
		end try
	end if
end process_item
--end script--

Finder Window Sets for macOS

The following AppleScript allows you to create other AppleScripts to help you manage sets of windows. You’ll probably want to enable the Script menu in Preferences of Script Editor. The Window Sets scripts will be saved into a folder called “Window Sets” in the “Scripts” folder of your home Library folder. The Script menu, when enabled, allows you to select and run scripts saved in that folder. You may need to allow the script access to your computer when you first run it from a Script Editor window. Anytime you have arranged your Finder windows in a way that you want to bring back, use the script to create a window set that you can activate whenever you like. If you don’t see your new script in the Scripts menu the first time you create one, you may need to log out and back in. The scripts only open windows on your current desktop. It doesn’t remember tabs, just which windows are open and their locations and sizes.

--begin script--
property properties_list : {}
property properties_names : {"a", "b", "c", "d", "v", "f"}

activate
display dialog "Your current window set is about to be saved. This may take a moment.
Do you want to continue?" buttons {"Cancel", "Yes"} default button 2 with icon note

set this_user to do shell script "id -un"
set userdom_replacer to "((path to \"usrs\" from user domain as string) & this_user & \""
set global_replacer to "((startup disk as string) &" & space & "\""
set my_startpath to ((path to "usrs" from user domain as string) & this_user)

set my_disk to (path to startup disk as string)

tell application "Finder"
	set mt to get every window
	set mb to {}
	
	repeat with i in mt
		try
			copy i's bounds to {a, b, c, d}
		on error
			tell me to display dialog "Please close the clipboard contents window and try again." buttons {"Cancel"} default button 1 with icon stop
		end try
		set f to get collapsed of i
		if current view of i is icon view then
			set v to "icon"
		else if current view of i is list view then
			set v to "list"
		else
			set v to "column"
		end if
		if v = "column" then
			set current view of i to icon view
			try
				set ls to (folder of i as alias) as list
			on error
				close i
			end try
			set current view of i to column view
		else
			try
				set ls to (folder of i as alias) as list
			on error
				close i
			end try
		end if
		set x to ls as string
		tell me to set x to replace_chars(x, " ", "^!^!^")
		set the properties_list to {a, b, c, d, v, f}
		tell me to write_prefs(x)
		if ls is not in mb then
			set mb to mb & ls
		end if
	end repeat
end tell

set my_clip to {}
set mb to reverse of mb

repeat with this_i from the 1 to the count of mb
	set mc to item this_i of mb as string
	set codename to mc as string
	set codename to replace_chars(mc, " ", "^!^!^")
	if mc begins with my_disk and this_user is in mc then
		set mc to replace_chars(mc, my_startpath, userdom_replacer)
	else if my_disk is in mc then
		set mc to replace_chars(mc, my_disk, global_replacer)
	else
		set mc to "(\"" & mc
	end if
	read_prefs(codename)
	
	set my_clip to (my_clip & "try" & return & "open alias " & mc & "\"" & ")" & return & "set the bounds of window 1 to {" & item 1 of the properties_list & ", " & item 2 of the properties_list & ", " & item 3 of the properties_list & ", " & item 4 of the properties_list & "}" & return & "set the current view of window 1 to " & item 5 of the properties_list & space & "view" & return & "set collapsed of window 1 to " & item 6 of the properties_list) & return & "on error" & return & "tell me to display dialog \"A window couldn't be opened.\" buttons {\"Cancel\", \"Continue\"} default button 2 giving up after 3" & return & "end" & return
end repeat

set my_script to "set this_user to do shell script \"id -un\"
activate
(*display dialog \"Your Window Set is about to be launched. Do you want to close existing windows first?\" buttons {\"Cancel\", \"No\", \"OK\"} default button 3 with icon note
if button returned of the result is \"OK\" then
tell application \"Finder\"
	set g to get (name of every window)
	repeat with thind in g
		close window thind
	end repeat
end tell
end if*)

tell application \"Finder\"" & return & (my_clip as string) & return & "end tell"

do shell script "rm ~/Library/Preferences/com.windowsets.windows.plist"

activate
display dialog "Do you want to be given the opportunity to close all Finder windows when you activate this Set?" buttons {"Yes", "No"} default button 2 with icon note
if button returned of the result is "Yes" then
	set my_script to replace_chars(my_script, "(*", "")
	set my_script to replace_chars(my_script, "*)", "")
end if


tell application "Finder"
	set p to path to library folder from user domain
	set w to (p as text) & "Scripts:Window Sets"
	try
		alias w
	on error
		tell me to do shell script "mkdir -p" & space & (quoted form of POSIX path of w)
	end try
end tell
set thedest to w as text

repeat
	display dialog "Please specify a name for your new Window Set." default answer "New Window Set" with icon note
	set name_string to text returned of the result
	set theOutFiledest to ((thedest as string) & ":" & name_string & ".scpt")
	set replace_string to "The window set \\\"" & name_string & "\\\""
	set my_script to replace_chars(my_script, "Your Window Set", replace_string)
	
	tell application "Finder"
		if exists file theOutFiledest then
			tell me to display dialog "A Window Set with that filename already exists. 
		Do you want to replace it or enter another name?" buttons {"Replace existing", "Rename set"} default button 1 with icon caution
			if button returned of the result is "Replace Existing" then
				tell me to do shell script "rm " & (quoted form of POSIX path of theOutFiledest)
				exit repeat
			end if
		else
			exit repeat
		end if
	end tell
end repeat
set theOutFiledest to ((characters 1 thru -6 of theOutFiledest) as string)
set theOutFile to open for access theOutFiledest with write permission
set eof of theOutFile to 0
write my_script as string to theOutFile starting at eof
close access theOutFile


do shell script "osacompile -o " & ((quoted form of POSIX path of theOutFiledest) & ".scpt") & space & "-d" & space & quoted form of POSIX path of theOutFiledest

do shell script "rm" & space & (quoted form of POSIX path of theOutFiledest)

display dialog "Your new Set script has been generated and saved in the Window Sets folder in the scripts folder of your user library folder. You can access it by selecting it from the Window Sets menu in your script menu." buttons {"OK"} default button 1 with icon note

on replace_chars(this_text, bahad, goohood)
	set AppleScript's text item delimiters to the bahad
	set the item_list to every text item of this_text
	set AppleScript's text item delimiters to the goohood as string
	set this_text to the item_list as string
	set AppleScript's text item delimiters to ""
	return this_text
end replace_chars
on write_prefs(x)
	try
		repeat with i from 1 to the count of the properties_list
			set this_key to item i of the properties_names
			set this_value to (item i of the properties_list) --as string	
			do shell script "defaults write com." & "windowsets.windows" & space & (quoted form of (x & this_key)) & space & this_value
		end repeat
	on error error_message
		display dialog error_message buttons {"Cancel"} default button 1
	end try
end write_prefs

on read_prefs(y)
	repeat with i from 1 to the count of the properties_names
		set this_key to item i of the properties_names
		set this_value to do shell script "defaults read com." & "windowsets.windows" & space & (quoted form of y) & this_key
		set this_class to the class of item i of the properties_list
		if this_class is integer then
			set item i of the properties_list to this_value as integer
		else if this_class is number then
			set item i of the properties_list to this_value as number
		else if this_class is boolean then
			set item i of the properties_list to this_value as string
		else if this_class is alias then
			set this_text to this_value as string
			set this_value to this_text
			set this_value to POSIX file this_value
			set item i of the properties_list to this_value as alias
		else if this_class is string then
			set item i of the properties_list to this_value as string
		end if
	end repeat
end read_prefs
--end script--