Basic iTunes AppleScript issue - applescript

Feeling like a real bone-head here, just trying to figure how how I can get this script to insert the name from the selection in artist and put it into Album artists.
tell application "iTunes"
set theTracks to (item 1 of (get selection))
set theTracks to selection
repeat with theTrack in theTracks
set albumartist to artist of theTrack
end repeat
end tell

Like this:
tell application "iTunes"
set theTracks to (item 1 of (get selection))
set theTracks to selection
repeat with theTrack in theTracks
set albumartist to artist of theTrack
set album artist of theTrack to albumartist -- the missing line
end repeat
end tell
In real life I would probably skip the intermediate variable and write the pair of lines as one line, like this:
set album artist of theTrack to (get artist of theTrack)
Or even better:
tell theTrack to set album artist to (get artist)

Related

Reading txt file in a formatted way to be printed back to user

First, I have got this working but I'm trying to make it so it is able to be more versatile and handle more details in the txt file. The whole concept is the txt file is a file with album details and the code reads those details and prints them. But, i have only figured out how to get the code working only with 1 album in the file. I need the code to work even if there was 2, 3 or however many albums in the txt file without having to hard code(IO.readlines every specific line for each ablum) each album being read into the code. I have no idea how I can do that and really need help.
Essentially I have a txt file that looks like this:
Artist name1
Album name1
1
3
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav
example3
sounds/20-example_3.wav
Now the concept is the 1st line is the artist name, 2nd line is the album title, 3rd is an integer which represents which genre it is (1 for example = pop etc.) and the 4th line represents how many songs there are.
The whole idea is to read this file and print the results like this:
Artist name1
Album name1
Genre is 1
Pop
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav
example3
sounds/20-example_3.wav
The code i have is (not the whole file, just the important parts im trying to fix):
#Used to read and save the song name and location
def get_track(music_file)
track_name = []
track_location = []
size = music_file.readlines.size
line = 4
while line < size
line_1 = IO.readlines(music_file)[line]
track_name.append(line_1)
line += 1
line_2 = IO.readlines(music_file)[line]
track_location.append(line_2)
line += 1
end
Track.new(track_name, track_location)
end
# Returns an array of tracks read from the given file using the integer in the txt file
def get_tracks(music_file)
tracks = Array.new()
count = IO.readlines(music_file)[3].to_i
index = 0
while index < count
track = get_track(music_file)
tracks << track
index += 1
end
return tracks
end
# Reads the artist name, album title and gets the genre integer
def read_album(music_file)
tracks = get_tracks(music_file)
album_title = IO.readlines(music_file)[1]
album_artist = IO.readlines(music_file)[0]
album_genre = IO.readlines(music_file)[2]
album = Album.new(album_title, album_artist, album_genre, tracks)
return album
end
This code only works with the file as it is but i need it to work if for example i added more albums in the text file so for example the file would look like this:
Artist name1
Album name1
1
3
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav
example3
sounds/20-example_3.wav
Artist name2
Album name2
3
2
example1
sounds/01-example_1.wav
example2
sounds/06-example_2.wav
I need to change the code so that its able to read the file as if there was more than 1 album in the txt file instead of using the Readlines function to read every single different album.
Your question looks okay, assuming that this is about right:
Your file contains multiple "chunks" or album data
Each "chunk" starts with a header of 4 rows, in a particular order
Each album then continues with a pair of rows for each track in the album (specified by the "track count" in the "header")
# Returns an array of tracks read from the given section of array
def get_tracks(track_arr)
tracks = []
track_arr.each_slice(2) do |name, location|
tracks << Track.new(name, location)
end
tracks
end
# "shifts" the top 4 header rows, identifying the album, then
# loops through the remaining rows calculated from the song count
def get_album(music_arr)
album_artist = music_arr.shift
album_title = music_arr.shift
album_genre = music_arr.shift.to_i
track_count = music_arr.shift.to_i
tracks = get_tracks(music_arr.shift(track_count * 2))
Album.new(album_title, album_artist, album_genre, tracks)
end
# Reads the contents of the file, and loops through the albums found therein
def read_albums(music_file)
albums=[]
music_arr = music_file.readlines
while music_arr.length > 0 do
albums << get_album(music_arr)
end
albums
end
I was tempted to create a get_header routine, rather than just shifting the top 4 rows, or to change the routine to use an index value, and #range from the array, but if we're not processing the contents of the file further (i.e. it's disposable) then this is relatively fool-proof.
Output:
using:
Track = Struct.new(:track_name, :track_location)
Album = Struct.new(:album_title, :album_artist, :album_genre, :tracks)
and your second input file, we get output similar to:
[#<struct Album
album_title="Album name1\n",
album_artist="Artist name1\n",
album_genre=1,
tracks=
[#<struct Track
track_name="example1\n",
track_location="sounds/01-example_1.wav\n">,
#<struct Track
track_name="example2\n",
track_location="sounds/06-example_2.wav\n">,
#<struct Track
track_name="example3\n",
track_location="sounds/20-example_3.wav\n">]>,
#<struct Album
album_title="Album name2\n",
album_artist="Artist name2\n",
album_genre=3,
tracks=
[#<struct Track
track_name="example1\n",
track_location="sounds/01-example_1.wav\n">,
#<struct Track
track_name="example2\n",
track_location="sounds/06-example_2.wav\n">]>]
Edit:
A quick google search lead me to find that #readlines now takes chomp as an argument, which helps remove the nasty \n characters:
music_arr = music_file.readlines(chomp: true)
output:
[#<struct Album
album_title="Album name1",
album_artist="Artist name1",
...

Ruby: How can I repeat steps on Cucumber?

I want to add 100 names in the list. I'm using Calabash, so I have the .feature file:
When I fill the item field with "3"
And press the button Adicionar
And I repeat the previous 2 steps 100 times
My .rb file:
...
When(/^I repeat the previous (\d+) steps (\d+) times$/) do |steps, times|
How can I implement this .rb file? The last thing I tried, I got the error:
Undefined dynamic step: "2" (Cucumber::UndefinedDynamicStep)
Below is a quick hello world example for google (I don't have your code, so can't properly do an example for your site).
The When is what we are interested in really.
Given(/^I navigate to "([^"]*)"$/) do |url|
$driver.navigate.to url
end
When(/^I search for "([^"]*)"$/) do |search_term|
# Loop through 100 times
100.times do
# Clear any text present
$driver.find_element({css: 'input[name="q"]'}).clear
# Type in the request
$driver.find_element({css: 'input[name="q"]'}).send_keys(search_term)
# Fire the request with the return key
$driver.find_element({css: 'input[name="q"]'}).send_keys(:return)
# Give time for the process to complete before a reset (This could also go first)
sleep 1
end
end
Then(/^I (?:should|must) see some results$/) do
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { $driver.find_element({css: 'h3.r'}) }
end
Doing a for loop, like in the When above, could also have a maximum set by a new captured integer:
When(/^I search for "([^"]*)" (\d+) times?$/) do |search_term, times|
# Loop through an amount of times
times.to_i.times do
$driver.find_element({css: 'input[name="q"]'}).clear
$driver.find_element({css: 'input[name="q"]'}).send_keys(search_term)
$driver.find_element({css: 'input[name="q"]'}).send_keys(:return)
sleep 1
end
end
This would mean that you don't have to dynamically set up capturing of previous steps (which is doable, I'm sure, but would be a giant amount of effort for what you seem to be wanting to do here).
You have a list of names then you can pass it using the data table and you can write your a combined step as following:
Given I add following names in the list:
|Ram|
|Abdul|
|Scot|
and then you can write the step definitions using nested steps as following in .rb file:
Given(/^I add following names in the list:$/) do |table|
data = table.raw
data.each do |row|
steps %{
When I fill the item field with "#{row[0]}"
And press the button Adicionar
}
end
end
When(/^I fill the item field with "([^"]*)"$/) do |arg1|
pending # Write code to enter the the item
end
When(/^press the button Adicionar$/) do
pending # Write code to click the Adicionar button
end
If you simply want to fill the names with same name "3" then you can write your combined step as following:
Given I fill the item field with "3" 100 times
And then you can write the steps definition as following:
Given(/^I fill the item field with "([^"]*)" (\d+) times$/) do |name, loop_count|
loop_count.to_i.times do
steps %{
When I fill the item field with "#{name}"
And press the button Adicionar
}
end
end
When(/^I fill the item field with "([^"]*)"$/) do |arg1|
pending # Write code to enter the the item
end
When(/^press the button Adicionar$/) do
pending # Write code to click the Adicionar button
end

How to create Ruby Tk radiobuttons in nested loops

Using Ruby Tk, I'm wanting to create sets of radio buttons in nested loops: an outer loop for devices (Foo, Bar, Baz), and inner loop for actions on each device (Start, Stop, Pause, Nuke).
Current code:
require 'tk'
device_names = %w/Foo Bar Baz/
action_names = %w/Start Pause Stop Nuke/
button_variables = Array.new(device_names.size)
root = TkRoot.new
foo = bar = nil
device_names.each_with_index do |device_name, i|
TkLabel.new(root) do
text device_name
pack {}
end
action_names.each_with_index do |action_name, j|
TkRadiobutton.new(root) do
text action_name
value j
variable button_variables[i]
pack {}
end
end
end
Tk.mainloop
This produces the 12 radiobuttons, but when I click on any of the 4 Pause buttons, for example, all 4 Pause buttons are set.
Other variations of the code produce the 12 radiobuttons, but all as one set; i.e., only one of the 12 is set at any given time.
What's needed to group these into 3 sets of 4 radiobuttons?
(This code is pared down from a much larger application, which is why it does not make much sense symantically.)
The value passed as variable is the name of a global variable.
The outer loop needs to dynamically define an instance variable, via instance_variable_set:
This code works:
require 'tk'
device_names = %w/Foo Bar Baz/
action_names = %w/Start Pause Stop Nuke/
root = TkRoot.new
device_names.each do |device_name|
TkLabel.new(root) do
text device_name
pack {}
end
instance_variable_set("##{device_name}", nil)
action_names.each do |action_name|
TkRadiobutton.new(root) do
text action_name
value action_name
variable device_name
pack {}
end
end
end
Tk.mainloop

Changing background of a Stack in Shoes

I'm creating an application for fun to learn ruby and shoes, but it seems that I cannot accomplish what I'm trying to do...
I have a stack with some text inside and, under certain circumstances, I want to change the background of that stack, but for some reason all the text inside the stack is deleted.
How can I avoid that? I just want to change the background color.
Sample code to show the problem:
Shoes.app do
#first_stack = stack do
background orange
#title = title "my title"
#subtitle = subtitle "my subtitle"
end
button ("change background") {
#first_stack.background gold
}
end
Seems background creates a fill which means your text is still there just nested under the fill. Here is a work around
Shoes.app do
def change_color(back)
#first_stack.clear
#first_stack.background back
#first_stack.title #title
#first_stack.subtitle #subtitle
end
#first_stack = stack do
background orange
#title = title "my title"
#subtitle = subtitle "my subtitle"
end
button ("change background") do
change_color(gold)
end
end
This just clears the first stack and recreates it with a new color. Still looking into a more eloquent method.
EDIT
Found a solution:
Shoes.app do
#first_stack = stack do
#fs_background = background orange
#title = title "my title"
#subtitle = subtitle "my subtitle"
end
button ("change background") do
#fs_background.remove
#first_stack.before(#title) {#fs_background = background gold}
end
end
This will work the way you want as it places a background layer on top of the original background layer but before #title.
Assuming you make the background the first element:
Shoes.app do
#f = stack do
background blue
title "my title"
subtitle "my subtitle"
end
button ("change background") do
#f.children.first.remove
#f.before(#f.children.first) {
background gold
}
end
end
in Shoes3.3.1 you can do it that way
Shoes.app do
#first_stack = stack do
background orange
#title = title "my title"
#subtitle = subtitle "my subtitle"
end
button ("change background") {
#first_stack.contents[0].fill = gold
#first_stack.refresh_slot
}
end

Reading iCal info from file to make iCal event

I have a file (/test.txt) that contains iCal event info.
Friday, May 6, 2011 4:00:00 PM
05/08/2011 11:20:00 PM
summary
location
Friday, May 6, 2011 4:00:00 PM
05/08/2011 11:20:00 PM
summary
location
And this is the applescript to read this file to make iCal event.
set Names to paragraphs of (read ("/test.txt"))
set my_list to {}
set temp_list to {}
repeat with nextLine in Names
if length of nextLine is greater than 0 then
set temp_list to temp_list & nextLine
else
copy temp_list to end of my_list
set temp_list to {}
end if
end repeat
repeat with e in my_list
set my_list to {}
tell application "iCal"
tell calendar "Todo"
set new_event to make new event at end of events
tell new_event
repeat with j from 1 to count e
set content to item j of e
if j is 1 then
set start date to date content --> Error
end if
if j is 2 then
set end date to date content
end if
if j is 3 then
set summary to content
end if
if j is 4 then
set location to content
end if
end repeat
end tell
end tell
end tell
end repeat
Running this code gives me an error
Why is this error?
you had two problems first you need to add the last event after you loop then you were trying to set the date inside the ical tell block which doesn't work for some reason so I took it out of the tell block i also improved the code a bit
set theData to read ("path:to:test.txt" as alias)
set ParaCount to count of paragraphs of theData
set my_list to {}
set temp_list to {}
repeat with i from 1 to ParaCount
set thispara to paragraph i of theData
if thispara is equal to "" then
copy temp_list to end of my_list
set temp_list to {}
else
set temp_list to temp_list & thispara
end if
end repeat
copy temp_list to end of my_list -- copy the last one to the list
repeat with aEvent in my_list
set {start_date, end_date, sum, loc} to aEvent
set start_date to date start_date
set end_date to date end_date
--reduced to single line
tell application "iCal" to make new event with properties {start date:start_date, end date:end_date, summary:sum, location:loc} at end of events of calendar "Todo"
end repeat
end repeat

Resources