Execution error - AppleScript for Apple Music "The variable all_ps is not defined. (-2753)" - applescript

The script for batch exporting playlists from Apple Music app is throwing up the execution error:
"The variable all_ps is not defined. (-2753)"
This is the portion of the code in question:
(-- GET ALL PLAYLISTS FROM APPLE MUSIC)
try
set all_specialps to (get name of every user playlist whose special kind is not none)
set all_userps to (get name of every user playlist whose smart is false and special kind is none)
set all_smartps to (get name of every user playlist whose smart is true and special kind is none)
set delim to "--------------------------------------------------"
set delim_specialpl to "---------------- Special Playlists: ----------------"
set delim_userpl to "------------------ User Playlists: -----------------"
set delim_smartpl to "---------------- Smart Playlists: -----------------"
set all_ps to "{}"
if ((length of all_specialps) > 0) then
set the end of all_ps to delim
set the end of all_ps to delim_specialpl
repeat with ps in all_specialps
set the end of all_ps to ps
end repeat
end if
if ((length of all_userps) > 0) then
set the end of all_ps to delim
set the end of all_ps to delim_userpl
repeat with ps in all_userps
set the end of all_ps to ps
end repeat
end if
if ((length of all_smartps) > 0) then
set the end of all_ps to delim
set the end of all_ps to delim_smartpl
repeat with ps in all_smartps
set the end of all_ps to ps
end repeat
end if
end try
I cannot see what is not defined about all_ps from this, total noob, any help v gratefully received
Changed "set all_ps to "---------------All Playlists:--------------" to no effect, same issue thrown up.

In a try statement, any error will jump to a separate set of statements, skipping whatever statements follow the error. There will be no indication unless the on error portion of the try statement is included to handle the error (even if it is just to log that there was an error).
In this case, the error is from trying to get the name of a list of playlists, since lists don't have a name property. This skips everything else in the try statement, including where the all_ps variable is declared. Once that is fixed, the next error(s) would be from trying to set the end of a string to something.
Strings are immutable, so you can’t add stuff to them like that - a new string needs to be built from the desired parts using the concatenation operator (&). Your posted script can still be used with all_ps set to a list (adding to the end of a list is OK), which can be converted later into a string, for example:
tell application "Music" to try
set delim to "--------------------------------------------------"
set all_ps to {}
set delim_specialpl to "---------------- Special Playlists: ----------------"
set all_specialps to get every user playlist whose special kind is not none
if all_specialps is not {} then
set the end of all_ps to delim
set the end of all_ps to delim_specialpl
repeat with ps in all_specialps
set the end of all_ps to name of ps
end repeat
end if
set delim_userpl to "------------------ User Playlists: -----------------"
set all_userps to get every user playlist whose smart is false and special kind is none
if all_userps is not {} then
set the end of all_ps to delim
set the end of all_ps to delim_userpl
repeat with ps in all_userps
set the end of all_ps to name of ps
end repeat
end if
set delim_smartpl to "---------------- Smart Playlists: -----------------"
set all_smartps to get every user playlist whose smart is true and special kind is none
if all_smartps is not {} then
set the end of all_ps to delim
set the end of all_ps to delim_smartpl
repeat with ps in all_smartps
set the end of all_ps to name of ps
end repeat
end if
on error errorMessage -- oops, handle the error
activate me
display alert "Script Error" message errorMessage -- or log, quit, etc
end try
if all_ps is not {} then
set tempTID to AppleScript's text item delimiters -- stash any existing delimiters
set AppleScript's text item delimiters to return -- set a delimiting character
set all_ps to all_ps as text -- join list items using the current text item delimiter
set AppleScript's text item delimiters to tempTID -- restore the original delimiters
end if
return all_ps -- or whatever

Do not confuse lists and strings.
Having received the necessary data from the application, it is better to finish the tell-block.
Try-block is not needed.
Always try not to use repeat loops.
tell application "Music" to tell user playlists
set all_specialps to name whose special kind is not none
set all_userps to name whose smart is false and special kind is none
set all_smartps to name whose smart is true and special kind is none
end tell
set delim to "----------------------------------------------------"
set delim_specialpl to "---------------- Special Playlists: ----------------"
set delim_userpl to "------------------ User Playlists: -----------------"
set delim_smartpl to "---------------- Smart Playlists: -----------------"
set all_ps to {}
if all_specialps is not {} then set all_ps to all_ps & {delim, delim_specialpl} & all_specialps
if all_userps is not {} then set all_ps to all_ps & {delim, delim_userpl} & all_userps
if all_smartps is not {} then set all_ps to all_ps & {delim, delim_smartpl} & all_smartps
set all_ps to my convertList:all_ps toTEXTbyDelimiter:linefeed
on convertList:theList toTEXTbyDelimiter:theDelimiter
set ATID to AppleScript's text item delimiters
set AppleScript's text item delimiters to theDelimiter
set theText to theList as text
set AppleScript's text item delimiters to ATID
return theText & theDelimiter
end convertList:toTEXTbyDelimiter:

Related

How do I receive multiple paragraphs from a user in Ruby2.6.3?

I'm trying to receive multiple paragraphs at once from a user.
I've tried using gets, but it doesn't seem to be working... it discards the second paragraph:
#The code:
print("Paste your text here: ")
.. essay = gets
.. puts(essay)
# Getting user imput (the second sentance is a separate paragraph)
Paste your text here: I like cake.
It makes me happy.
# What the computer did for puts(essay):
I like cake.
=> nil
I expected the result to be something like this:
"I like cake.\nIt makes me happy.\n"
But it gave me "I like cake." instead.
How could I end up with my expected result?
Add paragraphs to a string until the input consists of a empty line:
str = ""
para = "init"
str << (para = gets) until para.chomp.empty? #or para == "\n"
p str
Here's an alternative, with a slightly different logic
def getps
save, $/ = $/, "\n\n"
gets.chomp
ensure
$/ = save
end
str = getps
The global variable $/ is what Ruby uses to find out what line end is. gets gets things till line end. If we tell Ruby that line end is two newlines, then gets waits till we have two newlines in a row till it exits. Since we don't need them, we'll just chomp them off. The rest of the code is just to ensure that $/ gets restored properly afterwards so normal gets is not messed up forever.

Deleting lines containing specific words in text file in Ruby

I have a text file like this:
User accounts for \\AGGREP-1
-------------------------------------------------------------------------------
Administrator users grzesieklocal
Guest scom SUPPORT_8855
The command completed successfully.
First line is empty line. I want to delete every empty lines in this file and every line containing words "User accounts for", "-------", "The command". I want to have only lines containing users. I don't want to delete only first 4 and the last one lines, because it can be more users in some systems and file will contain more lines.
I load file using
a = IO.readlines("test.txt")
Is any way to delete lines containing specific words?
Solution
This structure reads the file line by line, and write a new file directly :
def unwanted?(line)
line.strip.empty? ||
line.include?('User accounts') ||
line.include?('-------------') ||
line.include?('The command completed')
end
File.open('just_users.txt', 'w+') do |out|
File.foreach('test.txt') do |line|
out.puts line unless unwanted?(line)
end
end
If you're familiar with regexp, you could use :
def unwanted?(line)
line =~ /^(User accounts|------------|The command completed|\s*$)/
end
Warning from your code
The message warning: string literal in condition appears when you try to use :
string = "nothing"
if string.include? "a" or "b"
puts "FOUND!"
end
It outputs :
parse_text.rb:16: warning: string literal in condition
FOUND!
Because it should be written :
string = 'nothing'
if string.include?('a') || string.include?('b')
puts "FOUND!"
end
See this question for more info.
IO::readlines returns an array, so you could use Array#select to select just the lines you need. Bear in mind that this means that your whole input file will be in memory, which might be a problem, if the file is really large.
An alternative approach would be to use IO::foreach, which processes one line at a time:
selected_lines = []
IO.foreach('test.txt') { |line| selected_lines << line if line_matches_your_requirements }

Search for word in text file and display (Ruby)

I'm trying to take input from the user, search through a text file (case insensitively), and then display the match from the file if it matches (with the case of the word in the file). I don't know how to get the word from the file, here's my code:
found = 0
words = []
puts "Please enter a word to add to text file"
input = gets.chomp
#Open text file in read mode
File.open("filename", "r+") do |f|
f.each do |line|
if line.match(/\b#{input}\b/i)
puts "#{input} was found in the file." # <--- I want to show the matched word here
#Set to 1 indicating word was found
found = 1
end
end
end
So, what you want to do is to store the result of the match method, you can then get the actual matched word out of that, ie.
if m = line.match( /\b#{input}\b/i )
puts "#{m[0]} was found in the file."
# ... etc.
end
Update
Btw, you didn't ask - but I would use scan in this case, so that I got an array of the matched words on each line (for when there's more than one match on the same line), something like this:
if m = line.scan( /\b#{input}\b/i )
puts "Matches found on line #{f.lineno}: #{m.join(', ')}"
# ... etc.
end
If you don't need to report the locations of the matches and the file is not overly large, you could just do this:
File.read("testfile").scan /\b#{input}\b/i
Let's try it:
text = <<THE_END
Now is the time for all good people
to come to the aid of their local
grocers, because grocers are important
to our well-being. One more thing.
Grocers sell ice cream, and boy do I
love ice cream.
THE_END
input = "grocers"
F_NAME = "text"
File.write(F_NAME, text)
File.read(F_NAME).scan /\b#{input}\b/i
# => ["grocers", "grocers", "Grocers"]
File.read(F_NAME) returns the entire text file in a single string. scan /\b#{input}\b/i is sent to that string.

Ruby redaction program logic?

Okay,
I am doing the codeacademy ruby track and I am not stock with the problem.
I can make it works now, but I don't understand why it works.
instructions for exercise:
Let's start simple: write an .each loop that goes through words and just prints out each word it finds.
I have broken the problem into steps to try to understand why it works
but I am very confused.
My code for the problem is:
puts "Text to search through: " #ask user for input
text = gets.chomp
#store the user's input into the variable text
puts "Text to be reducted: "
#ask the user for input
redact = gets.chomp
#store the user's input into the variable redact
words = text.split(" ")
=begin
split the user's input into the variable words
store that input into the variable words
=end
words.each do |word|
=begin
creates a placeholder for the user's input
then attach an expression to the input stored in
the variable words one at a time. The variable
words holds the value of the variable text
=end
if word != redact
=begin
if word (which now holds the value of words that's
stored in the variable text, and which is the user's input)
is not equal to the value of the variable redact do something
=end
word = word + " "
=begin
increment the value of word by an empty space
why do I need to increment the value of word by an empty space?
=end
print "#{word}" #print the value of the variable word
else
print "REDACTED" #otherwise, print the value redacted
end
end
The program works if I use a string separated by an space and only if I change
word = word + ""
instead of
word = word + " "
I would truly appreciate if someone break it down for me, step by step.
I created a video of it for a more visual explanation of it.
here is the link: ruby redaction video
thank you.
The problem in your video is that "nelson" is not the same as "nelson ", and the Codeacademy scoring doesn't see a match when you append a space to the word before printing it.
I am reading this problem in July 2019..
So anybody who is reading this problem and getting confused with the below part asked by the user:
word = word + " "
=begin
increment the value of word by an empty space
why do I need to increment the value of word by an empty space?
So the answer is that the + sign is not for incrementing the value it's for adding a space and the + sign is used as string concatenator. So it has been placed there so that whatever words are being searched and displayed, they have a space between them.

How to mass rename files in ruby

I have been trying to work out a file rename program based on ruby, as a programming exercise for myself (I am aware of rename under linux, but I want to learn Ruby, and rename is not available in Mac).
From the code below, the issue is that the .include? method always returns false even though I see the filename contains such search pattern. If I comment out the include? check, gsub() does not seem to generate a new file name at all (i.e. file name remains the same). So can someone please take a look at see what I did wrong? Thanks a bunch in advance!
Here is the expected behavior:
Assuming that in current folder there are three files: a1.jpg, a2.jpg, and a3.jpg
The Ruby script should be able to rename it to b1.jpg, b2.jpg, b3.jpg
#!/Users/Antony/.rvm/rubies/ruby-1.9.3-p194/bin/ruby
puts "Enter the file search query"
searchPattern = gets
puts "Enter the target to replace"
target = gets
puts "Enter the new target name"
newTarget = gets
Dir.glob("./*").sort.each do |entry|
origin = File.basename(entry, File.extname(entry))
if origin.include?(searchPattern)
newEntry = origin.gsub(target, newTarget)
File.rename( origin, newEntry )
puts "Rename from " + origin + " to " + newEntry
end
end
Slightly modified version:
puts "Enter the file search query"
searchPattern = gets.strip
puts "Enter the target to replace"
target = gets.strip
puts "Enter the new target name"
newTarget = gets.strip
Dir.glob(searchPattern).sort.each do |entry|
if File.basename(entry, File.extname(entry)).include?(target)
newEntry = entry.gsub(target, newTarget)
File.rename( entry, newEntry )
puts "Rename from " + entry + " to " + newEntry
end
end
Key differences:
Use .strip to remove the trailing newline that you get from gets. Otherwise, this newline character will mess up all of your match attempts.
Use the user-provided search pattern in the glob call instead of globbing for everything and then manually filtering it later.
Use entry (that is, the complete filename) in the calls to gsub and rename instead of origin. origin is really only useful for the .include? test. Since it's a fragment of a filename, it can't be used with rename. I removed the origin variable entirely to avoid the temptation to misuse it.
For your example folder structure, entering *.jpg, a, and b for the three input prompts (respectively) should rename the files as you are expecting.
I used the accepted answer to fix a bunch of copied files' names.
Dir.glob('./*').sort.each do |entry|
if File.basename(entry).include?(' copy')
newEntry = entry.gsub(' copy', '')
File.rename( entry, newEntry )
end
end
Your problem is that gets returns a newline at the end of the string. So, if you type "foo" then searchPattern becomes "foo\n". The simplest fix is:
searchPattern = gets.chomp
I might rewrite your code slightly:
$stdout.sync
print "Enter the file search query: "; search = gets.chomp
print "Enter the target to replace: "; target = gets.chomp
print " Enter the new target name: "; replace = gets.chomp
Dir['*'].each do |file|
# Skip directories
next unless File.file?(file)
old_name = File.basename(file,'.*')
if old_name.include?(search)
# Are you sure you want gsub here, and not sub?
# Don't use `old_name` here, it doesn't have the extension
new_name = File.basename(file).gsub(target,replace)
File.rename( file, new_path )
puts "Renamed #{file} to #{new_name}" if $DEBUG
end
end
Here's a short version I've used today (without pattern matching)
Save this as rename.rb file and run it inside the command prompt with ruby rename.rb
count = 1
newname = "car"
Dir["/path/to/folder/*"].each do |old|
File.rename(old, newname + count.to_s)
count += 1
end
I had /Copy of _MG_2435.JPG converted into car1, car2, ...
I made a small script to rename the entire DBZ serie by seasons and implement this:
count = 1
new_name = "Dragon Ball Z S05E"
format_file = ".mkv"
Dir.glob("dragon ball Z*").each do |old_name|
File.rename(old_name, new_name + count.to_s + format_file)
count += 1
end
The result would be:
Dragon Ball Z S05E1
Dragon Ball Z S05E2
Dragon Ball Z S05E3
In a folder, I wanted to remove the trailing underscore _ of any audio filename while keeping everything else. Sharing my code here as it might help someone.
What the program does:
Prompts the user for the:
Directory path: c:/your/path/here (make sure to use slashes /, not backslashes, \, and without the final one).
File extension: mp3 (without the dot .)
Trailing characters to remove: _
Looks for any file ending with c:/your/path/here/filename_.mp3 and renames it c:/your/path/here/filename.mp3 while keeping the file’s original extension.
puts 'Enter directory path'
path = gets.strip
directory_path = Dir.glob("#{path}/*")
# Get file extension
puts 'Enter file extension'
file_extension = gets.strip
# Get trailing characters to remove
puts 'Enter trailing characters to remove'
trailing_characters = gets.strip
suffix = "#{trailing_characters}.#{file_extension}"
# Rename file if condition is met
directory_path.each do |file_path|
next unless file_path.end_with?(suffix)
File.rename(file_path, "#{file_path.delete_suffix(suffix)}.#{file_extension}")
end

Resources