Sunday, April 18, 2021

#1 2021-03-08 10:09:39 am

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Why does using conditionals in this script use up all system memory?

It's just a simple script to iterate over a user's Music library tracks, resetting any ratings and 'loved' statuses. I had a similar problem with a script I wrote yesterday when I had it check the media kind of every track in turn. Removing that check fixed the script. I'm running this from inside Script Editor.

Applescript:

tell application "Music"
   repeat with aTrack in tracks of library playlist 1
       try
           if loved of aTrack is true then
               set loved of aTrack to false
           end if
           if album loved of aTrack is true then
               set album loved of aTrack to false
           end if
           set rating of aTrack to 0
       on error errStr number errorNumber
           if errorNumber is equal to -128 then
               -- user cancelled
               return
           else
               log "Error number: " & errorNumber & "
"
& "Description: " & errStr & "
"
& "Track: " & name of aTrack
           end if
       end try
   end repeat
end tell

The script works perfectly well if I simply set the property values without checking them first, like this:

Applescript:

tell application "Music"
   repeat with aTrack in tracks of library playlist 1
       try
           set loved of aTrack to false
           set album loved of aTrack to false
           set rating of aTrack to 0
       on error errStr number errorNumber
           if errorNumber is equal to -128 then
               -- user cancelled
               return
           else
               log "Error number: " & errorNumber & "
"
& "Description: " & errStr & "
"
& "Track: " & name of aTrack
           end if
       end try
   end repeat
end tell

I tried using

Applescript:

if (get loved of aTrack) is true then

and still ran into the memory leak (?) issue.

I'm relatively new to practical programming but have studied enough to (begin to) understand relatively low level explanations. Is this technically a memory leak or some other issue? Why does it happen? Am I missing something fundamental about how AppleScript should be used to test properties of objects?

Model: M1 MBA 2020 with 7-core GPU
AppleScript: 2.7
Browser: Safari 14.0.3
Operating System: Other

Last edited by Dentarthurdent (2021-03-08 10:43:09 am)

Offline

 

#2 2021-03-08 10:14:29 am

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Re: Why does using conditionals in this script use up all system memory?

If someone can tell me how to get the AppleScript tags to do their job I will edit the above to make the code more readable.

Offline

 

#3 2021-03-08 10:23:18 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 839

Re: Why does using conditionals in this script use up all system memory?

Dentarthurdent wrote:

If someone can tell me how to get the AppleScript tags to do their job I will edit the above to make the code more readable.



The closing tag should be [/applescript] not [/AppleScript]


2018 Mac mini - macOS Catalina

Offline

 

#4 2021-03-08 10:41:08 am

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Re: Why does using conditionals in this script use up all system memory?

peavine wrote:

The closing tag should be [/applescript] not [/AppleScript]



Thanks, it must have triggered the spellchecker when I copied and pasted the post in the message box.

Last edited by Dentarthurdent (2021-03-08 10:42:37 am)

Offline

 

#5 2021-03-08 01:28:15 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5366

Re: Why does using conditionals in this script use up all system memory?

Hi Dentarthurdent.

I can't test this out in Music, but the value of aTrack in your repeat won't be an actual 'track' but a more complex reference involving every track of the playlist. This has to be resolved by Music every time aTrack is used.

You may do better to resolve the 'tracks' part of the reference first and then loop through the returned list. No guarantees, though:

Applescript:

tell application "Music"
   set theTracks to tracks of library playlist 1
   repeat with aTrack in theTracks
       -- etc.

Or:

Applescript:

tell application "Music"
   repeat with aTrack in (get tracks of library playlist 1)
       -- etc.


NG

Offline

 

#6 2021-03-08 02:51:49 pm

robertfern
Member
Registered: 2011-11-29
Posts: 110

Re: Why does using conditionals in this script use up all system memory?

You can also use a counter to get the contents of each item in theTracks

Applescript:


tell application "Music" to set theTracks to tracks of library playlist 1
repeat with i from 1 to count theTracks
   set aTrack to item i of theTracks
   try
       tell application "Music"
           set loved of aTrack to false
           set album loved of aTrack to false
           set rating of aTrack to 0
       end tell
   on error errStr number errorNumber
       if errorNumber is equal to -128 then
           -- user cancelled
           return
       else
           log "Error number: " & errorNumber & "" & "Description: " & errStr & "" & "Track: " & name of aTrack
       end if
   end try
end repeat

I also moved the portions not needed in the tell to outside the tell block

Last edited by robertfern (2021-03-08 05:18:24 pm)

Offline

 

#7 2021-03-08 04:29:23 pm

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Re: Why does using conditionals in this script use up all system memory?

Nigel Garvey wrote:

the value of aTrack in your repeat won't be an actual 'track' but a more complex reference involving every track of the playlist. This has to be resolved by Music every time aTrack is used.



Thank you Nigel, I'll give this a try. Do you happen to know if I can read about this in the official AppleScript documentation? It doesn't seem intuitive to me to write the code like in your example so it would help if I could understand in detail the way objects are accessed/referenced in AppleScript.

Offline

 

#8 2021-03-08 04:30:58 pm

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Re: Why does using conditionals in this script use up all system memory?

robertfern wrote:

You can also use a counter to get the contents of each item in theTracks



Thanks Robert. I'll try to bear in mind the different methods of iterating over collections in future scriptbuilding.

Offline

 

#9 2021-03-08 08:49:52 pm

Marc Anthony
Member
From:: Dallas, TX
Registered: 2006-04-27
Posts: 1012

Re: Why does using conditionals in this script use up all system memory?

Dentarthurdent wrote:

It doesn't seem intuitive to me to write the code like in your example so it would help if I could understand in detail the way objects are accessed/referenced in AppleScript.



Hi. Perhaps it's in the documentation somewhere, but having the event log open to see live feedback is one way to learn. Observe the difference with and without the explicit 'get.'

I'm not sure if the original problem may be a bug or simply a list inflation product on a really large library. How many tracks are you iterating? You can also try an index approach that forgoes list references.

Applescript:

tell application "iTunes" to repeat with counter from 1 to count tracks
   tell track counter
       if (loved is true) or (album loved is true) then set {loved, album loved} to {false, false}
       set rating to 0
   end tell
end repeat

Offline

 

#10 2021-03-08 11:09:39 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 1752

Re: Why does using conditionals in this script use up all system memory?

Hi,

The OP can perform this task without involving the repeat loop with tracks, as I see.

Applescript:


tell application "Music" to tell tracks of library playlist 1
   set loved to false
   set album loved to false
   set rating to 0
end tell

Note that the script's result in the Script Debugger displays the tracksCount Music application instances.

This looks like a bug that seems to be related to the OP's memory overflow problem. I don't know how to explain this. Maybe, the memory manager not have time to free unnecessary Music instances due to instant multiple calls to the application. The following script apparently solves this problem:

Applescript:


tell application "Music" to tell tracks of library playlist 1
   set {loved, album loved, rating} to {false, false, 0}
end tell

It is equivalent to following. It seems, the parentheses helps to return control to AppleScript:

Applescript:


tell application "Music" to tell tracks of library playlist 1
   set loved to false
   set album loved to false
   set {rating} to {0}
end tell

Last edited by KniazidisR (2021-03-09 12:14:29 am)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#11 2021-03-10 07:40:52 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 839

Re: Why does using conditionals in this script use up all system memory?

Dentarthurdent wrote:

Thank you Nigel, I'll give this a try. Do you happen to know if I can read about this in the official AppleScript documentation? It doesn't seem intuitive to me to write the code like in your example so it would help if I could understand in detail the way objects are accessed/referenced in AppleScript.



This is a bit confusing to me as well. I always understood that the values (counter, contents of a list, etc) in a repeat loop are set when execution of the repeat loop begins. Perhaps Nigel means something different when he states:

I can't test this out in Music, but the value of aTrack in your repeat won't be an actual 'track' but a more complex reference involving every track of the playlist. This has to be resolved by Music every time aTrack is used.



Unfortunately, I do not have Music set up and can't easily test this in Script Editor as Marc Anthony suggests.


2018 Mac mini - macOS Catalina

Offline

 

#12 2021-03-10 08:40:57 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5366

Re: Why does using conditionals in this script use up all system memory?

peavine wrote:

This is a bit confusing to me as well. I always understood that the values (counter, contents of a list, etc) in a repeat loop are set when execution of the repeat loop begins.


Hi peavine.

That's the case in the alternatives I suggested: get a list of the playlist tracks and loop through the list. robertferns's script does the same. Marc's indexes the tracks in "iTunes" itself rather than in a list.

Dentarthurdent's (a Hitchhiker's Guide to the Galaxy fan?  smile) original loops through the specifier 'tracks of library playlist 1', so the value of 'aTrack' is successively 'item 1 of every track of library playlist 1 of application "Music"', 'item 2 of every track of playlist 1 of application "Music"', and so on. This whole caboodle gets sent to Music to interpret every time 'aTrack' is used, since it's a specifier for something in Music. And 'aTrack' is used quite a lot in the original script, so it's possible this may be causing congestion.


NG

Offline

 

#13 2021-03-10 11:22:23 am

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Re: Why does using conditionals in this script use up all system memory?

Just a note to say thanks to everyone who's contributed, and that when I get a chance I will time how long the script takes to run with the different constructs and report the results here.

Subjectively, when I ran Nigel's version, it took just as long (perhaps 20-25 minutes), but curiously all the track IDs that showed up in the Replies box were in the 60,000s to 90,000s (I have just under 30,000 tracks).

Offline

 

#14 2021-03-10 06:30:18 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 839

Re: Why does using conditionals in this script use up all system memory?

Thanks Nigel for the explanation. Always something new to learn. smile

Because I couldn't use Music, I instead used Preview to better illustrate how this works:

Applescript:

# TEST SCRIPT 1
tell application "Preview"
   repeat with aDocument in (name of every document)
       log aDocument
   end repeat
end tell
aDocument --> item 2 of name of every document of application "Preview"

# TEST SCRIPT 2
tell application "Preview"
   repeat with aDocument in (get name of every document)
       log aDocument
   end repeat
end tell
aDocument --> item 2 of {"Test 1.pdf", "Test 2.pdf"}

Last edited by peavine (2021-03-11 07:07:51 pm)


2018 Mac mini - macOS Catalina

Offline

 

#15 2021-03-31 11:40:31 am

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Re: Why does using conditionals in this script use up all system memory?

Sorry, got sidetracked for a few weeks. For those who are curious/interested, here's a loose comparison of the iterative constructs and the time it took to run the scripts containing them.

https://ibb.co/dQjS6Hv

Edit: posting results in text form as requested. The reason I didn't do this was because I can't find a way of formatting them as a table using BBCode. I hope it doesn't display too badly for you formatted with spaces.

The library size is approximately 30,000 tracks.

Construct                                                                          Operations on aTrack   Time taken (s)

tell application "Music" to tell tracks of library playlist 1  set {rating} to {0}         3

tell application "Music" to tell tracks of library playlist 1  set {album rating,        98
                                                                                     rating} to {0, 0}

set theTracks to tracks of library playlist 1                       set rating to 0             152
    repeat with aTrack in theTracks
   
set theTracks to tracks of library playlist 1                       set rating to 0             414
    repeat with aTrack in theTracks                               set album rating to 0   

repeat with aTrack in tracks of library playlist 1               set rating to 0             929

repeat with aTrack in tracks of library playlist 1               set rating to 0             2800
                                                                                      set album rating to 0

Last edited by Dentarthurdent (2021-04-01 06:29:58 am)

Offline

 

#16 2021-03-31 04:08:32 pm

Marc Anthony
Member
From:: Dallas, TX
Registered: 2006-04-27
Posts: 1012

Re: Why does using conditionals in this script use up all system memory?

Could you simply post any timing results in the thread, so that readers don't have to click on unknown links? Thanks.

Offline

 

#17 2021-04-01 06:27:22 am

Dentarthurdent
Member
Registered: 2020-08-07
Posts: 8

Re: Why does using conditionals in this script use up all system memory?

Marc Anthony wrote:

Could you simply post any timing results in the thread, so that readers don't have to click on unknown links? Thanks.



Done.

Last edited by Dentarthurdent (2021-04-01 06:28:33 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)