How To Monitor Contents Of Folder Without Blocking Finder - applescript

As you can see from my code below I am extremely new to this. My code just about works, but my major issue is that it hogs up Finder and sometimes it does not set the Desktop picture, but does most of the time!
The script just monitors a folder, and if an "***.jpg" is added then the Desktop picture set to it.
This is my very first script so I have a lot to learn,
set reset to ""
display notification "Alarm Front Active " & (current date) as string
tell application "Finder"
set path_to_sourceFull to ":photo:FRONT CAM 1:20190929:images" -- from nsa310 network drive
set path_to_source to ":photo:FRONT CAM 1:20190929:images" -- from nsa310 network drive
set directory1 to "/Volumes/photo/FRONT CAM 1/20190929/images" as text -- from nsa310 network drive
set path_to_destinationFull to "Macintosh HD:Users:rekordbox:Documents:temp folder 2"
set path_to_destination to ":Users:rekordbox:Documents:temp folder 2"
set directory2 to "/Users/rekordbox/Documents/temp folder 2" as text
repeat while reset = ""
set allok to ""
set filelist to name of every item in folder path_to_source --of startup disk
set listSizesaved to count of filelist
delay 1
repeat while allok = ""
set filelist to name of every item in folder path_to_source --of startup disk
set listSize to count of filelist
if listSize = listSizesaved then
else
set filelist to name of every item in folder path_to_source --of startup disk
set listSize to count of filelist
set LastAddedFile to item listSize of filelist
set allok to "ALARM"
set listSizesaved to listSize -- (save the updated) count
set activefile to (path_to_source & LastAddedFile)
set selectedpicture to (directory1 & "/" & LastAddedFile)
tell application "System Events" to tell every desktop to set picture to selectedpicture
delay 1
display notification "ALARM FRONT TRIGGERED...." & (current date) as string
delay 1
end if
end repeat
end repeat
end tell

The script you want, I think, is this:
on adding folder items to thisFolder after receiving filelist
set droppedFile to first item of filelist
tell application "System Events"
tell every desktop
set picture to droppedFile
end tell
end tell
end adding folder items to
(I've left out the 'Alarm' bit, since I wasn't sure what the point of it was.)
To use this script, copy it into Script Editor, save it in the folder ~/Library/Scripts/Folder Action Scripts/, then open the applet 'Folder Actions Setup'. Add the folder you want on the left-hand side, and choose the file you just saved on the right. It should look something like this:
...where the checkmark on the left shows that folder actions are enabled for the folder (which I called 'test folder') and the script (which I called 'FADtop.scpt') is attached.
Drop an image in the folder, and it should just work.
As a general rule, don't script the Finder unless you absolutely need to; always use System Events. The Finder is a busy app, and scripting it can gum up the system. And also try to avoid this design pattern:
(* Don't do this! *)
repeat
(* test for something *)
delay x
end
The delay command is not particularly resource-efficient. If you really want to use a polling system to test for some event, it's often better to create a stand-alone app with an on idle handler. That way you let the system wake and sleep the script, with significant performance improvements.
EDIT
Since folder actions don't seem to be working with ftp drops onto remote drives, here's a reasonably efficient folder-polling approach. Save the following script as a stay-open application (choose 'Application' as the file type, and click the 'stay open' checkbox). Then launch the application and leave it running in the background.
property dateOfLastFileChosen : missing value
property targetFolder : "/Volumes/photo/FRONT CAM 1/20190929/images"
property idleTime : 300 -- 300 seconds is five minutes
on run
end run
on idle
tell application "System Events"
if exists folder targetFolder then
if dateOfLastFileChosen is missing value then
set recentFiles to every file of folder targetFolder whose visible is true
else
set recentFiles to every file of folder targetFolder whose modification date > dateOfLastFileChosen and visible is true
end if
set newFile to my mostRecentFileOfList(recentFiles)
if newFile is not missing value then
set dateOfLastFileChosen to modification date of newFile
tell every desktop
set picture to (POSIX path of newFile)
end tell
end if
end if
end tell
return idleTime -- check every 5 minutes (300 seconds)
end idle
on mostRecentFileOfList(fileList)
set maxDateObj to missing value
repeat with thisFile in fileList
if maxDateObj is missing value then
set maxDateObj to contents of thisFile
else if modification date of thisFile is greater than modification date of maxDateObj then
set maxDateObj to thisFile
end if
end repeat
return maxDateObj
end mostRecentFileOfList

Without trying to steal the thunder from #Ted Wrigley, whose solution provided the AppleScript code for the folder action, I felt there were enough comments and items for me to add to post it as another answer to the OP's dilemma.
First I will address the tell every desktop set picture to droppedFile lines of code in the following AppleScript Folder Action. If the user has only one monitor/display attached to the computer, but has created several different "Spaces", the tell every desktop set picture to droppedFile lines of code will only change the Desktop Picture for the Desktop of the current active "Space" only. The other Desktop backgrounds will not be changed. However, if the user has several monitors/displays attached to the computer, the tell every desktop set picture to droppedFile lines of code will change the Desktop Pictures for the Desktops of the current active "Space" for each attached monitor/display. If the latter is not the desired result, then tell every desktop should be changed to tell current desktop.
After testing the AppleScript Folder Action code provided by #Ted Wrigley, I noticed the image file being downloaded from an FTP server, to the test folder where I have the folder action script attached to, looked like this before the image was actually finished transferring. Because the file was kind of there and not there, it did not trigger the Folder Action.
Next, I figured I would add a delay to be beginning of the Folder Action code to allow for the transfer of the image file from the FTP server, to complete. I added a delay of 180 seconds to allow for the transfer to complete and it worked. When the transfer was complete, the file look like this.
Depending on how many files you foresee being transferred at any given time along with factoring in for file sizes... It's possible you may need to significantly increase the Delay time.
on adding folder items to thisFolder after receiving theseFiles
delay 180
set newBackground to first item of theseFiles
tell application "System Events"
set picture of current desktop to newBackground -- Single Display Attached
--set picture of every desktop to newBackground -- Multiple Displays Attached
end tell
end adding folder items to

Related

Applescript: on adding folder items to; renaming files without the loop

I created a droplet which would allow me to rename files from an input box.
on adding folder items to este_folder after receiving este_file
display dialog "what's their name?" default answer ""
set text_returned to text returned of the result & ".jpg"
display dialog text_returned
tell application "Finder"
set the name of file este_file to text_returned
end tell
end adding folder items to
It works fine, but it creates a loop where I have to hit cancel again to stop the script, as it thinks a new file has been added. I would like to just rename it once; and then not have the second dialog box pop up again. I have tried rerouting the file to another folder:
on adding folder items to este_folder after receiving este_file
display dialog "what's their name?" default answer ""
set text_returned to text returned of the result & ".jpg"
display dialog text_returned
tell application "Finder"
set the name of file este_file to text_returned
end tell
repeat with anItem in este_file
tell application "Finder"
set destFolder to "Macintosh HD:Users:maxwellanderson:Desktop:BetterinTexas" as alias
move anItem to folder destFolder
end tell
end repeat
end adding folder items to
But that doesn't work either-it doesn't process the renaming portion of the script. Any suggestions on what I should do to get rid of the second dialog box?
The script is being called twice because renaming the file within the watched folder is—for all intents and purposes—like adding a new file into the folder. Therefore, it's called once when the file is actually added; and called a second time when it's renamed.
Moving the file as you suggested will work, but you have to move the file before you rename it. Therefore, shove the code that moves the file near the top of the script, then the renaming bits at the bottom.
As a side-note, I notice you have a repeat with loop to handle multiple file moves, but only one statement that handles a single file renaming. One of these is not like the other. If this watched folder received multiple files at the same time, it would most likely rename them all to the same name, thus potentially over-writing multiple files. If the watched folder only ever receives one file at a time, anyway, then the repeat with loop is redundant.
This code is modelled on yours and will handle a single file move-and-rename (but not a group of files—or, more accurately, as I stated above, it would rename multiple files to the same name, thus overwriting all but the last one in the list):
on adding folder items to este_folder after receiving este_file
set destFolder to POSIX file "/Users/maxwellanderson/Desktop/BetterinTexas" as alias
set text_returned to text returned of ¬
(display dialog "what's their name?" default answer "") ¬
& ".jpg"
display dialog text_returned
tell application "Finder" to ¬
set the name of ¬
(move file este_file to destFolder) ¬
to text_returned
end adding folder items to
If you need it to handle multiple files, then you can wrap everything from set text_returned to to text_returned in a repeat with loop as you've done in your second code block. This will sequentially bring up dialog boxes—one per file—and move/rename the files accordingly.
If you have any questions, or need clarification, leave a comment and I'll get back to you.

Move all files / folder within SmartFinderFolder to destination w/ serial / single consecutive operation with AppleScript MacOS Serria

Objective: Move all files and files in folders to destination folder and maintain the file structure [files and named folders]. Important for music files in albums.
Functional: Move all listed files in SmartFolder [named] to destinationFolder with serial / consecutive move operation and maintain the same file structure and copy of dataFiles listed in SmartFolder.
Key: All files were obtained for transfer. Normal CMD + A, CMD + C, CMD + V hangs up the computer and the transfer does not initiate. The AppleScript to move each dataObject to destinationPath is all.
Facts: How to reference objects [files, folders] and their proper reference format and accepted path syntax; path or POSIX, and use of alias. Basic operations. I ran an AppleScript to move filePath to pathDestination, and was otherwise successful, and would be nice to known the formalization syntax for path reference.
tell application "Finder"
move allFiles to destinationFolder
// recursive/repeat code to loop through all listed files and folder
end tell
Reference: Applescript, show all files with tag
[Moving / selecting listed files from 'smartfolder' containers as active windows and displayLists. It was an alt. solution since AppleScript will not reference the SmartFolder as an object, nor will it dynamically call the listProperty of the SmartFolder object unless called by an unknown or un-reference method or command.
Since your main issue, as far as I can tell, seems to be dealing with SmartFolders in AppleScript, which—as you said—cannot be referenced as folder objects, this little snippet might be of help:
set SmartFolder to "/Users/CK/My Smart Folder.savedSearch"
tell application "System Events" to get value of property list file SmartFolder
set {[Scope], Query} to {SearchScopes, RawQuery} of RawQueryDict of result
set AppleScript's text item delimiters to tab
set Command to {"mdfind -onlyin", ¬
quoted form of Scope as text, ¬
quoted form of Query as text} as text
set SearchResults to paragraphs of (do shell script Command)
--> returns a list of posix files
--> e.g. {"/Users/CK/Downloads/This is file one.txt", ...}
This will return a list of POSIX paths to files that match the search criteria.
I would recommend using System Events rather than Finder to deal with large numbers of files. It can also handle posix paths without the need to manually coerce them into aliases or whatever. So, given a posix path, such as the ones returned in the list using the above code snippet, you simply do this:
set myfile to item 1 of SearchResults
tell application "System Events" to move myfile to "/Users/CK/Desktop"
Without knowing more details of what your smart folder contains (since some searches could easily return a folder plus the contents of that folder, which you'd have to bear in mind when getting your AppleScript to recurse through the search results), I can't give you more than that. But, you said your main problems were being unable to handle SmartFolders and not knowing how to reference files/folders.
This works for me using the latest version of Sierra.
Set the value of property moveToNewFolderto the destination folder of your choice
This script creates a "Choose From List" Dialog, allowing you to choose any smart folder which resides on your system. It will then move all of these files and folders in the chosen smart folder, to your set destination folder.
property savedSearches : (path to home folder as string) & "Library" & ":Saved Searches"
property savedSearchesSubFolders : {}
property namesOfSavedSearchesSubFolders : {}
property selectedSearchFolder : ""
property selectedSearchFolderPath : missing value
property moveTheseItems : missing value
property moveToNewFolder : (path to desktop as text) & "untitled folder" -- change this value to your preferred destination folder
tell application "Finder"
activate
delay 0.1 -- may need to adjust delay time value
open savedSearches
delay 0.1 -- may need to adjust delay time value
reveal savedSearches
delay 0.1 -- may need to adjust delay time value
select savedSearches
delay 0.1 -- may need to adjust delay time value
set current view of Finder window 1 to column view
delay 0.1 -- may need to adjust delay time value
tell its Finder window (POSIX path of savedSearches)
delay 0.1 -- may need to adjust delay time value
set savedSearchesSubFolders to items
set namesOfSavedSearchesSubFolders to name of items
-- Allows to choose any smart folder from a list of all smart folders
set selectedSearchFolder to choose from list namesOfSavedSearchesSubFolders ¬
with title ¬
"Smart Search Folders" with prompt ¬
"Choose Your Folder" OK button name ¬
"OK" cancel button name "CANCEL"
set selectedSearchFolder to selectedSearchFolder as text
set selectedSearchFolderPath to savedSearches & ":" & selectedSearchFolder
set selectedSearchFolderPath to selectedSearchFolderPath as string
end tell
delay 0.2 -- may need to adjust delay time value
select selectedSearchFolderPath
tell Finder window 1
set defaultView to current view
set current view to list view
delay 0.1 -- may need to adjust delay time value
set current view to defaultView
delay 0.5 -- may need to adjust delay time value
tell application "System Events"
key code 0 using command down
end tell
end tell
set moveTheseItems to selection
end tell
tell application "Finder"
set resultObject to move moveTheseItems ¬
to moveToNewFolder ¬
with replacing
end tell

How to activate full screen apps in background via Apple Script

I've been working on an application in Automator that changes the desktop background to the album art of the current song playing in iTunes.
You can download my first version here.
The most annoying issue I have found is that when there is a full screen app open on the same display being updated, whenever the song changes the background flickers between the current song and the previous.
This is my current code (Updated from version 1.0 above):
You may need to scroll within the code to see all of it.
tell application "System Events"
set fileName to (((path to desktop) as text) & ".iTunesArt2-1.jpg")
set oldFile to open for access file fileName with write permission
write 0 to oldFile
close access oldFile
delete file fileName
if process "iTunes" exists then
tell application "iTunes"
if (player state is not stopped) then
-- get the raw bytes of the artwork into a var
tell application "iTunes" to tell artwork 1 of current track
set srcBytes to raw data
end tell
-- write to file
set outFile to open for access file fileName with write permission
-- truncate the file
set eof outFile to 0
-- write the image bytes to the file
write srcBytes to outFile
close access outFile
end if
end tell
tell desktop 2
set picture to fileName
end tell
end if
set fileName to (((path to desktop) as text) & ".iTunesArt2-2.jpg")
set oldFile to open for access file fileName with write permission
write 0 to oldFile
close access oldFile
delete file fileName
if process "iTunes" exists then
tell application "iTunes"
if (player state is not stopped) then
-- get the raw bytes of the artwork into a var
tell application "iTunes" to tell artwork 1 of current track
set srcBytes to raw data
end tell
-- write to file
set outFile to open for access file fileName with write permission
-- truncate the file
set eof outFile to 0
-- write the image bytes to the file
write srcBytes to outFile
close access outFile
end if
end tell
tell desktop 2
set picture to fileName
end tell
end if
end tell
I got the actual code that saves the artwork to a file from here.
The desktop will not update unless you give it a new file name to update, therefore I have duplicated the process with "iTunesArt2-1" and "iTunesArt2-1".
The first 2 in '2-1' or '2-2' simply means the second desktop, as I have two different applications to change each desktop, and use my 2nd desktop for testing.
The entire application is set to loop for 1000 years, using three separate Loop functions in Automator (720 minutes, 730 times & 1000 times).
When first trying to debug this issue, the process was duplicated into four separate scripts, one for saving the image, then setting as background, and two more scripts to repeat the process with a new file name.
Here's an example of my debugging:
I remove the opening period from ".iTunesArt##.jpg" so that I can see the files on my desktop.
I play a Coldplay song and run the application in Automator to set the background.
"iTunesArt2-1.jpg" and "iTunesArt2-2.jpg" are shown on my desktop with the correct album art.
I stop the application, and play a Paramore song.
I run the first script of the application (Saves the album art).
"iTunesArt2-1.jpg" is updated to the Paramore artwork.
I run the second script of the application (Sets background image).
Note, this script should be setting the background to the Paramore image.
The background remains set to the Coldplay image.
At first I think this is only because the background image was already set to "iTunesArt2-1.jpg", and therefore the system will not try to update it again, not knowing the data in the file has been changed.
So I run the next script which should force the background to update:
I run the third script in the application.
"iTunesArt2-2.jpg" is updated to the Paramore artwork.
I run the forth script in the application.
The desktop background is updated to the Paramore artwork.
So, we can confirm that scripts 3 & 4 worked correctly.
According to the code, when the application loops back to scripts 1 & 2, the desktop background should remain as the Paramore artwork.
BUT...
I run the first script in the application.
"iTunesArt2-1.jpg" remains the Paramore artwork (as it should).
I run the second script in the application.
This script should update the desktop background from ""iTunesArt2-2.jpg" (Paramore) to "iTunesArt2-1.jpg" (Paramore).
The desktop background changes to the Coldplay artwork.
Now that makes zero sense at all.
This will happen every time I loop through the scripts.
Script 4 will change the desktop to Paramore and script 2 will change it back to Coldplay.
Remember this issue only happens when there is a full screen app open on the same display being updated. ie. A full screen app open on my primary display doesn't matter.
I have found sometimes that sliding over to the full screen app and 'activating' it will stop the flickering, and the background will be set correctly.
There surely is nothing 'wrong' with my code is there? If not, I need a way to get around this issue.
Specifically, is there a way of 'activating' every full screen app in the background without moving to those spaces?
I would love anyone who wants it to have this program, but it needs to be able to run under all circumstances.
Any help would be greatly appreciated.
Found a work around which creates a random file name each time, meaning the desktop can't get confused as to which image it is supposed to display.
screenNum refers to which screen the desktop is being set to.
set randID to screenNum
set randLoop to 0
repeat while randLoop is not 9
set randNum to (random number from 0 to 9) as text
set randID to randID & randNum
set randLoop to randLoop + 1
end repeat
Then included randID in the file name upon its creation.
Have not noticed any flickering using this method.
Note: This solves my problem, but does not answer my initial question of how one can activate a full screen app in the background.

Applescript quicklook: arrow key down 1000 times

I'm a total beginner in apple script.
I would like to open a folder directory that contains hundreds of photos and to view each photo 1 second with quick look and then go to the next (suppose to use down arrow / key code '124').
I don't have any idea of how to build the script. I tried to compile some formulas from other questions or use the manual rec but it doesn't work.
Thanks!
Try following script. I made the delay longer so you have time to stop the script (to test it):
set timePerPreview to 5
set thisFolder to (choose folder with prompt "Pick the folder containing the files to process:") as string
tell application "Finder"
activate
open folder thisFolder
select every item in folder thisFolder
delay 2
set fileCount to (count items in (get selection)) # (count files in folder thisFolder) is faster but counts also .DS_Store and other invisible files
if fileCount = 0 then
beep
return
end if
end tell
pressSpaceInFinder()
delay timePerPreview / 2 # first it has to open the window which seems to need a little time
repeat fileCount - 1 times # -1 because the first item is already displayed
delay timePerPreview
# do shell script "sleep" & space & timePerPreview as text
tell application "System Events"
tell application process "Finder"
set frontmost to true
# cursor right = 124, left = 123
key code 124
end tell
end tell
end repeat
delay timePerPreview
pressSpaceInFinder()
on pressSpaceInFinder()
tell application "System Events"
tell application process "Finder"
set frontmost to true
keystroke space
end tell
end tell
end pressSpaceInFinder
Be aware that it is hard to stop the script since the Finder gets activated every second. Will see if I can add a check to see if the Preview window is open and if not, stop the script.
Also: (without that check) the script will, when the Preview window is open before running, close it but you can just press the space key to open it again.
Also, the first part (getting the file count) isn't so great and may fail when the delay is to short. We could scan the whole folder for images and only count / select those (it has a file template for the scanner, see menu File) but of course you can remove the whole counting thing and just do repeat 1000 times.

Applescripting a Reminder as an add- folder action

I'm new to applescript but I want to set up a folder action that:
1. Recognises when a file is added to a folder
2. Tags said folder red
3. Adds a Reminder to the "Downloads" reminder list that has the name of the newly-added file as the body text of the reminder
Using google and Applescript's record function I've frankenscripted this together so far
property dialog_timeout : 30 -- set the amount of time before dialogs auto-answer.
on adding folder items to this_folder after receiving added_items
try
tell application "Finder"
set FILEname to name of (added_items)
set label index of folder "untitled folder" of folder "Desktop" of folder "heyjeremyoates" of folder "Users" of startup disk to 2
end tell
tell application "Reminders"
set mylist to list "Downloads"
tell mylist
make new reminder with properties {name:"D/L Complete", body:FILEname, due date:(current date)}
end tell
end tell
end try
end adding folder items to
Darn thing won't work. Infuriating. I tested it as a folder action with "test" as the name and body of the reminder and it worked fine. I'm pretty sure I've gone wrong somewhere in setting FILEname as the name of the newly copied item because the script as it is now no longer turns the folder red.
The idea behind this is so I can see, from my iPhone/iPad, how many large/scheduled downloads to my home mac (both torrents and large work files - I'll have a seperate folder action and reminder list for each download folder) there are that are yet to be managed.
It seemed like setting up a Growl/Prowl combo was wasteful if iCloud/Reminders and a dozen lines of code could deliver what I wanted anyway. Ideally I'll write a second applescript that will delete the reminder when I rename or move the related file, and though I haven't even thought about how that would work if anyone has any suggestions for it I'd be super grateful
It is a pity you can't (natively) have OSX notifications pushed to an iOS device linked to the same iCloud account though (with the appropriate granularity)
But I digress - can anyone see what I'm screwing up here?
Thanks in advance for even reading this far
added_items is a list of aliases, and name of (added_items) resulted in an error.
on adding folder items to this_folder after receiving added_items
tell application "Finder"
set label index of this_folder to 2
repeat with f in added_items
set n to name of f
tell application "Reminders" to tell list "Downloads"
make new reminder with properties {name:"D/L Complete", body:n, due date:(current date)}
end tell
end repeat
end tell
end adding folder items to
(Save the script in ~/Library/Workflows/Applications/Folder Actions/ and enable the folder action from Folder Actions Setup.)

Resources