Convert pages, numbers and keys to MS formats

Hey, script guru!

Wrote a script for converting pages, numbers, keynotes of documents to Microsoft formats. It works. But maybe it’s possible to optimize it.

I don’t like how “display dialog” is made, but I don’t understand how to do otherwise, so as not to repeat the same thing 3 times in the code.

And maybe it doesn’t make sense to filter by extensions at the very beginning, but to use a sample of all files?

set end of Selected_Items to Filtered_Item as alias

Is optimization possible?

tell application "Finder"
	set the_Selection to selection
	set Selected_Items to {}
	--Go through each file in the sample, and filter by pages, numbers, keys extensions
	repeat with Filtered_Item in the_Selection
		if class of Filtered_Item is document file and name extension of Filtered_Item is in ["pages", "numbers", "key"] then ¬
			set end of Selected_Items to Filtered_Item as alias
	end repeat
	--go through each filtered file
	repeat with Selected_Item in Selected_Items as alias list
		--get a file name without an extension and an extension in the form of text
		tell application "System Events" to tell disk item (Selected_Item as text) to set {Item_Name, Item_Extension} to {name, name extension}
		if Item_Extension is not "" then set Item_Name to text 1 thru -((count Item_Extension) + 2) of Item_Name
		--Get the file's root directory
		set Root_Folder to container of Selected_Item
		--If the pages file
		if Item_Extension is "pages" then
			--Generate the name of the converted file
			set Converted_Item to ((Root_Folder as text) & Item_Name as text) & ".docx"
			--Checking the existence
			if exists file Converted_Item then
				display dialog "Document" & space & quoted form of (name of file Converted_Item as text) & space & ¬
					"Was converted earlier than" buttons {"Cancel", "Delete"} cancel button 1 with icon caution
				-- Delete an existing file to the trash
				delete file Converted_Item
			end if
			tell application "Pages"
				set to_Convert to open Selected_Item
				export to_Convert to file Converted_Item as Microsoft Word
				close to_Convert saving no
			end tell
		end if
		--If the numbers file
		if Item_Extension is "numbers" then
			--Generate the name of the converted file
			set Converted_Item to ((Root_Folder as text) & Item_Name as text) & ".xlsx"
			--Checking the existence
			if exists file Converted_Item then
				display dialog "Document" & space & quoted form of (name of file Converted_Item as text) & space & ¬
					"Was converted earlier than" buttons {"Cancel", "Delete"} cancel button 1 with icon caution
				-- Delete an existing file to the trash
				delete file Converted_Item
			end if
			tell application "Numbers"
				set to_Convert to open Selected_Item
				export to_Convert to file Converted_Item as Microsoft Excel
				close to_Convert saving no
			end tell
		end if
		--If the key file
		if Item_Extension is "key" then
			--Generate the name of the converted file
			set Converted_Item to ((Root_Folder as text) & Item_Name as text) & ".pptx"
			--Checking the existence
			if exists file Converted_Item then
				display dialog "Document" & space & quoted form of (name of file Converted_Item as text) & space & ¬
					"Was converted earlier than" buttons {"Cancel", "Delete"} cancel button 1 with icon caution
				-- Delete an existing file to the trash
				delete file Converted_Item
			end if
			tell application "Keynote"
				set to_Convert to open Selected_Item
				export to_Convert to file Converted_Item as Microsoft PowerPoint
				close to_Convert saving no
			end tell
		end if
	end repeat
end tell

When you filter the selected files by extension, you already know that they match the desired type of document… so you shouldn’t need to check again whether the extension exists or not. You should be able to just work with the name. BTW, shouldn’t your list of extensions use {} rather than []?

You have a separate repeat loop for each document type. You could probably just have one loop that works for all extensions. You would likely have to put the corresponding microsoft extensions (e.g. docx) in a list that matches the apple extension list. Also, a list of the applications as well.

Although, given that Selected_Items should only contains desired document types, maybe you could just open them (and add a delay) and then export them using whatever the current application would then be.

@V.Yakob,

You have some extra stuff in your script here. For example, instead of getting the container, you can get the System Events path property, which makes it easier to get the destination file path.

Also, there are a lot of nested tell blocks, which is not recommended for ease of debugging errors. Also, when there are clearly defined tasks in the script, it is again recommended to separate them as handlers.

Also, the export command works out of sync with the script. Therefore, it is imperative to check that the export has ended before closing the document.

Such code becomes clear and understandable, but if you don’t like it (that I changed the structure of your script), you can easily return the structure of the script yourself after you understand how it works.
 

tell application "Finder"
	set Selected_Items to {}
	repeat with Filtered_Item in (get selection)
		if class of Filtered_Item is document file and name extension of Filtered_Item is in ["pages", "numbers", "key"] then ¬
			set end of Selected_Items to Filtered_Item as alias
	end repeat
end tell

repeat with Selected_Item in Selected_Items
	tell application "System Events"
		tell disk item (Selected_Item as text) to set {Item_Name, Item_Extension} to {path, name extension}
		set Item_Name to text 1 thru -((count Item_Extension) + 2) of Item_Name
	end tell
	if Item_Extension is "pages" then
		my PagesExport(Item_Name, Selected_Item)
	else if Item_Extension is "numbers" then
		my NumbersExport(Item_Name, Selected_Item)
	else if Item_Extension is "key" then
		my KeyNoteExport(Item_Name, Selected_Item)
	end if
end repeat


--====================================== HANDLERS ==========================================-----

on repeatUntil_FileExists(hfsPath)
	repeat
		try
			alias hfsPath
			exit repeat
		end try
		delay 0.1
	end repeat
end repeatUntil_FileExists

on KeyNoteExport(Item_Name, Selected_Item)
	set Converted_Item to Item_Name & ".pptx"
	try
		tell application "System Events" to delete file Converted_Item
	end try
	tell application "Keynote"
		activate
		set to_Convert to open file Selected_Item
		export to_Convert to file Converted_Item as Microsoft PowerPoint
		my repeatUntil_FileExists(Converted_Item)
		close to_Convert saving no
	end tell
end KeyNoteExport

on PagesExport(Item_Name, Selected_Item)
	set Converted_Item to Item_Name & ".docx"
	try
		tell application "System Events" to delete file Converted_Item
	end try
	tell application "Pages"
		activate
		set to_Convert to open file Selected_Item
		export to_Convert to file Converted_Item as Microsoft Word
		my repeatUntil_FileExists(Converted_Item)
		close to_Convert saving no
	end tell
end PagesExport

on NumbersExport(Item_Name, Selected_Item)
	set Converted_Item to Item_Name & ".xlsx"
	try
		tell application "System Events" to delete file Converted_Item
	end try
	tell application "Numbers"
		activate
		set to_Convert to open file Selected_Item
		export to_Convert to file Converted_Item as Microsoft Excel
		my repeatUntil_FileExists(Converted_Item)
		close to_Convert saving no
	end tell
end NumbersExport

 

@KniazidisR

Thanx for your support, I changed the variables, and in general I figured it out, that’s what happened.
I removed “activate” in the handlers because “display dialog” messages pop up behind the window and it is inconvenient to interact with it.

tell application "Finder"
	set SelectedItems to {}
	repeat with FilteredItem in (get selection)
		if class of FilteredItem is document file and name extension of FilteredItem is in {"pages", "numbers", "key"} then ¬
			set end of SelectedItems to FilteredItem as alias
	end repeat
end tell

repeat with SelectedItem in SelectedItems
	tell application "System Events"
		tell disk item (SelectedItem as text) to set {ItemName, ItemExtension} to {path, name extension}
		set ItemName to text 1 thru -((count ItemExtension) + 2) of ItemName
	end tell
	if ItemExtension is "pages" then
		my PagesExport(ItemName, SelectedItem)
	else if ItemExtension is "numbers" then
		my NumbersExport(ItemName, SelectedItem)
	else if ItemExtension is "key" then
		my KeyNoteExport(ItemName, SelectedItem)
	end if
end repeat

--Handlers
on AlertIfConvertedExist(thisItem)
	tell application "Finder"
		if exists file thisItem then
			display dialog "The document" & space & quoted form of (name of file thisItem as text) & space & ¬
				"has been converted before" buttons {"Cancel", "Delete"} cancel button 1 with icon caution
			delete file thisItem
		end if
	end tell
end AlertIfConvertedExist

on CheckConvertedFile(thisItem)
	repeat
		try
			alias thisItem
			exit repeat
		end try
		delay 0.1
	end repeat
end CheckConvertedFile

on PagesExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".docx"
	my AlertIfConvertedExist(ConvertedItem)
	tell application "Pages"
		set toConvert to open file SelectedItem
		export toConvert to file ConvertedItem as Microsoft Word
		my CheckConvertedFile(ConvertedItem)
		close toConvert saving no
	end tell
end PagesExport

on NumbersExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".xlsx"
	my AlertIfConvertedExist(ConvertedItem)
	tell application "Numbers"
		set toConvert to open file SelectedItem
		export toConvert to file ConvertedItem as Microsoft Excel
		my CheckConvertedFile(ConvertedItem)
		close toConvert saving no
	end tell
end NumbersExport

on KeyNoteExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".pptx"
	my AlertIfConvertedExist(ConvertedItem)
	tell application "Keynote"
		set toConvert to open file SelectedItem
		export toConvert to file ConvertedItem as Microsoft PowerPoint
		my CheckConvertedFile(ConvertedItem)
		close toConvert saving no
	end tell
end KeyNoteExport

But I couldn’t interact with a file without a “Finder.”
If it is faster to work with the file system through “System Events”, is it possible to use it?

on AlertIfConvertedExist(thisItem)
	
	(*
	tell application "System Events" to set Status to not (exists file thisItem as alias)
	log Status
	if Status is equal to false then
		display dialog "The document" & space & quoted form of (name of file thisItem) & space & ¬
			"has been converted before" buttons {"Cancel", "Delete"} cancel button 1 with icon caution
		delete file thisItem
	end if
		*)
	
	(*
	tell application "Finder"
		if exists file thisItem then
			display dialog "The document" & space & quoted form of (name of file thisItem as text) & space & ¬
				"has been converted before" buttons {"Cancel", "Delete"} cancel button 1 with icon caution
			delete file thisItem
		end if
	end tell
		*)
	
	--	(*
	tell application "Finder"
		try
			get file thisItem
			display dialog "The document" & space & quoted form of (name of file thisItem as text) & space & ¬
				"has been converted before" buttons {"Cancel", "Delete"} cancel button 1 with icon caution
			delete file thisItem
		end try
	end tell
	--	*)
	
end AlertIfConvertedExist

It is possible and better to bypass the Finder when checking the existence of a file and deleting it.

But it’s not clear what the purpose of the display dialog you insist on is. Because you set 2 buttons - Cancel and Delete. If you click Cancel, the script will simply terminate without processing the rest of the files.

@KniazidisR How else can I warn the user that the document already exists and will be rewritten?
Usually, after exporting Pages - MS Word, need to adjust, change the font, change the position of the image or something else from the design, which in MS Word may not be displayed as in Pages.

I made changes to the script. It will now respond to the user’s choice in the display dialog.
 

tell application "Finder"
	set SelectedItems to {}
	repeat with FilteredItem in (get selection)
		if class of FilteredItem is document file and name extension of FilteredItem is in {"pages", "numbers", "key"} then ¬
			set end of SelectedItems to FilteredItem as alias
	end repeat
end tell

repeat with SelectedItem in SelectedItems
	tell application "System Events"
		tell disk item (SelectedItem as text) to set {ItemName, ItemExtension} to {path, name extension}
		set ItemName to text 1 thru -((count ItemExtension) + 2) of ItemName
	end tell
	if ItemExtension is "pages" then
		my PagesExport(ItemName, SelectedItem)
	else if ItemExtension is "numbers" then
		my NumbersExport(ItemName, SelectedItem)
	else if ItemExtension is "key" then
		my KeyNoteExport(ItemName, SelectedItem)
	end if
end repeat

--Handlers
on AlertIfConvertedExist(thisItem)
	try
		alias thisItem
		tell application "Finder" to display dialog "The document" & space & thisItem & return & ¬
			"has been converted before" buttons {"Skip export", "Delete"} with icon caution
		if button returned of result is "Delete" then return "toDelete"
		return "toSkip"
	end try
	return "toExport"
end AlertIfConvertedExist

on CheckConvertedFile(thisItem)
	repeat
		try
			alias thisItem
			exit repeat
		end try
		delay 0.1
	end repeat
end CheckConvertedFile

on PagesExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".docx"
	set aResult to my AlertIfConvertedExist(ConvertedItem)
	if aResult is "toSkip" then return
	if aResult is "toDelete" then tell application "System Events" to delete file ConvertedItem
	tell application "Pages"
		activate
		set toConvert to open file SelectedItem
		export toConvert to file ConvertedItem as Microsoft Word
		my CheckConvertedFile(ConvertedItem)
		close toConvert saving no
	end tell
end PagesExport

on NumbersExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".xlsx"
	set aResult to my AlertIfConvertedExist(ConvertedItem)
	if aResult is "toSkip" then return
	if aResult is "toDelete" then tell application "System Events" to delete file ConvertedItem
	tell application "Numbers"
		activate
		set toConvert to open file SelectedItem
		export toConvert to file ConvertedItem as Microsoft Excel
		my CheckConvertedFile(ConvertedItem)
		close toConvert saving no
	end tell
end NumbersExport

on KeyNoteExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".pptx"
	set aResult to my AlertIfConvertedExist(ConvertedItem)
	if aResult is "toSkip" then return
	if aResult is "toDelete" then tell application "System Events" to delete file ConvertedItem
	tell application "Keynote"
		activate
		set toConvert to open file SelectedItem
		export toConvert to file ConvertedItem as Microsoft PowerPoint
		my CheckConvertedFile(ConvertedItem)
		close toConvert saving no
	end tell
end KeyNoteExport

 

1 Like

@KniazidisR Excellent! Thanx!
I have improved the display of the file name in the “dispaly dialog” – only the file name is displayed.

--Orig https://www.macscripter.net/t/convert-pages-numbers-and-keys-to-ms-formats/74692
tell application "Finder"
	set SelectedItems to {}
	--Filter from the selected files. The array is created only from files with the specified extensions
	repeat with FilteredItem in (get selection)
		if class of FilteredItem is document file and name extension of FilteredItem is in {"pages", "numbers", "key"} then ¬
			set end of SelectedItems to FilteredItem as alias
	end repeat
end tell
--Go through each file and run the handler depending on the file extension
repeat with SelectedItem in SelectedItems
	tell application "System Events"
		tell disk item (SelectedItem as text) to set {ItemName, ItemExtension} to {path, name extension}
		set ItemName to text 1 thru -((count ItemExtension) + 2) of ItemName
	end tell
	if ItemExtension is "pages" then
		my PagesExport(ItemName, SelectedItem)
	else if ItemExtension is "numbers" then
		my NumbersExport(ItemName, SelectedItem)
	else if ItemExtension is "key" then
		my KeyNoteExport(ItemName, SelectedItem)
	end if
end repeat

--Handlers
--Checking the file for existence before export
on AlertIfConvertedExist(thisItem)
	try
		alias thisItem
		set text item delimiters to ":"
		set FileName to text item -1 of thisItem as text
		tell application "Finder" to display dialog "The document" & space & quoted form of FileName & space & ¬
			"has been converted before." buttons {"Skip", "Replace"} with icon caution
		if button returned of result is "Replace" then return "toDelete"
		return "toSkip"
	end try
	return "toExport"
end AlertIfConvertedExist

--Checking the completion of export
on CheckConvertedFile(thisItem)
	repeat
		try
			alias thisItem
			exit repeat
		end try
		delay 0.1
	end repeat
end CheckConvertedFile

--Export pages -> docx
on PagesExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".docx"
	set aResult to my AlertIfConvertedExist(ConvertedItem)
	if aResult is "toSkip" then return
	if aResult is "toDelete" then tell application "System Events" to delete file ConvertedItem
	tell application "Pages"
		set toExport to open file SelectedItem
		export toExport to file ConvertedItem as Microsoft Word
		my CheckConvertedFile(ConvertedItem)
		close toExport saving no
	end tell
end PagesExport

--Export numbers -> xlsx
on NumbersExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".xlsx"
	set aResult to my AlertIfConvertedExist(ConvertedItem)
	if aResult is "toSkip" then return
	if aResult is "toDelete" then tell application "System Events" to delete file ConvertedItem
	tell application "Numbers"
		set toExport to open file SelectedItem
		export toExport to file ConvertedItem as Microsoft Excel
		my CheckConvertedFile(ConvertedItem)
		close toExport saving no
	end tell
end NumbersExport

--Export key -> pptx
on KeyNoteExport(ItemName, SelectedItem)
	set ConvertedItem to ItemName & ".pptx"
	set aResult to my AlertIfConvertedExist(ConvertedItem)
	if aResult is "toSkip" then return
	if aResult is "toDelete" then tell application "System Events" to delete file ConvertedItem
	tell application "Keynote"
		set toExport to open file SelectedItem
		export toExport to file ConvertedItem as Microsoft PowerPoint
		my CheckConvertedFile(ConvertedItem)
		close toExport saving no
	end tell
end KeyNoteExport

Every time thanx to the community, my skills in AppleScript get better! :slight_smile:

I was trying to make this work, since I am using some applescript automations to do the same, but separated by filetypes, and I wanted to try this “all in one” solution, but I can’t make it work.

I am using automator for this, creating a quick action, using the “Run Applescript” action, pasting the script to is, but when I activate it in Finder, nothing happens. Could you help me out?

Thanks!

PS: If you work with iWork files, maybe you can share some other interesting automations/scripts that you have :slight_smile:

Hi!

Open shortcuts, open shortcuts settings and check the Allow Running Scripts checkbox.

Create a new with name “Export to MS format”, add an AppleScript step and paste the script.
Click on i on the left. On the Details tab, check the box on use as quick action, Finder.
Click on “Run AppleScript with input”, select “shortcut input”, click on “Images and 18 more”, Select All,


Deselect all, check the checkbox on Files.

It should turn out: Receive Files input from QuickActions.

Select files for export, right-click, Quick Actions - Export to MS format.

macOS will ask a few questions about the security of accessing file shortcuts, after agreeing, the files will be created.