I have the following script working fine:
if {title is equal to "missing value" or title starts with "Your stream on"} then
return ""
else
try
return "♫ " & title
on error err
end try
end if
I want to invert this if condition into something like this:
if {title is not equal to "missing value" or not title starts with "Your stream on"} then
try
return "♫ " & title
on error err
end try
end if
Actually the correct logical inversion of
a OR b
is
not a AND not b
And no braces and AppleScript speaks real English
if title is not missing value and title does not start with "Your stream on" then
Stupid mistake. My syntax was incorrect. The following works:
if {title is missing value or not title starts with "Your stream on"} then
try
return "♫ " & title
on error err
end try
end if
Related
I'm making a Automator to jump from citation in Word to the reference software(Zotero). But I can't find a AppleScript to extract text of selected field code (the first step).
The field code in Word is
ADDIN ZOTERO_ITEM CSL_CITATION {"citationID":"AFUiwuqi","properties":{"formattedCitation":"[1]","plainCitation":"[1]","noteIndex":0},"citationItems":[{"id":9752,"uris":["http://zotero.org/users/6410528/items/YYTRWPHH"],"itemData":{"id":9752,"type":"article-journal","container-title":"Nature","DOI":"10.1038/s41586-019-1737-7","ISSN":"0028-0836, 1476-4687","issue":"7782","page":"324-329","title":"Controlled flight of a microrobot powered by soft artificial muscles","volume":"575","author":[{"family":"Chen","given":"Yufeng"},{"family":"Zhao","given":"Huichan"},{"family":"Mao","given":"Jie"},{"family":"Chirarattananon","given":"Pakpong"},{"family":"Helbling","given":"E. Farrell"},{"family":"Hyun","given":"Nak-seung Patrick"},{"family":"Clarke","given":"David R."},{"family":"Wood","given":"Robert J."}],"issued":{"date-parts":[["2019",11,14]]}}}],"schema":"https://github.com/citation-style-language/schema/raw/master/csl-citation.json"}
Here is the script process:
Extract text from selected field code in Word (This is the question)
Get the uris text(http://zotero.org/users/6410528/items/YYTRWPHH)
Get the item-codes (YYTRWPHH).
Open url (zotero://select/library/items?itemKey=YYTRWPHH)
Now I use VBA to extract field code text, see below. But in this way, the file will be changed. So I want to do this via AppleScript.
Sub GetFiledsCodes()
Dim myRange As Range, myCodes As String
Set myRange = Selection.Range
With myRange
If .Fields.Count = 0 Then
MsgBox "No Code!", vbInformation
Exit Sub
Else
.Fields.Update
.TextRetrievalMode.IncludeFieldCodes = True
.TextRetrievalMode.IncludeHiddenText = True
myCodes = .Text
myCodes = VBA.Replace(myCodes, Chr(19), "{")
myCodes = VBA.Replace(myCodes, Chr(21), "}")
.SetRange .End, .End
.InsertAfter myCodes
.Font.Name = "Times New Roman"
.Font.Size = 12
.Cut
End If
End With
End Sub
PS:
Here is my process in Automator(it can work but using VBA):
Run AppleScript
on run {input, parameters}
tell application "Microsoft Word" to activate
tell application "Microsoft Word"
run VB macro macro name "GetFiledsCodes"
delay 0.5
end tell
return input
end run
Get contents from clipboard
Extract URLs from Text
Filter Paragraphs begin with http://zotero.org/users/
Copy to Clipboard
Run AppleScript
set myStr to do shell script "pbpaste"
tell application "Zotero" to activate
set AppleScript's text item delimiters to "
"
set myList to every text item of myStr
set zoterocode to ""
set codes to ""
repeat with j from 1 to the length of myList
set itemValue to item j of myList
set zoterocode to (do shell script "sed -E 's#http://zotero.org/users/[0-9]+/items/##g' <<< " & itemValue)
if j = 1 then
set codes to zoterocode
else
set codes to codes & "," & zoterocode
end if
end repeat
tell application "System Events"
key code 18 using {command down, control down, option down}
delay 0.5
set collectionKey to do shell script "pbpaste"
if collectionKey = myStr then
set theurl to "zotero://select/library/items?itemKey=" & codes
else
set theurl to collectionKey & "/items?itemKey=" & codes
end if
open location theurl
end tell
That helps a lot. Okay, so this isn't a turnkey solution for your question but I don't think you really need that as you'd probably end up having to tell me more about how this app works than is really necessary. So this script focuses on your initial question about getting the field codes/result ranges from a merge document.
I put together a simple mail merge consisting of labels and a data file with 8 records, each of which have 5 fields: {"«LastName»", "«JobTitle»", "«Company»", "«City»", "«Web»"}. The latter is the key field.
Basically, the script runs through the data merge document and cycles first through its fields, then the web field, and finally the web addresses.
Based on your script, I can't really determine what you are doing with each address so it finishes by collecting just the final part of each address in a list. The obscure parts for me are the pbpastes, the codes and the whole System Events block. This area would need tweaking.
Incidentally, it's quite likely that you can avoid some of the shell scripts but I can't say how yet. Obviously the script has some redundancies and could be further refined but I think it demonstrates how to extract the information you need. Take a look at it and let me know what issues there are that need addressing.
tell application "Microsoft Word"
set d1 to document "cardo_labels.docx"
set fContents to {} -- list of mergefield
set fResRange to {} -- list of result range, i.e. field merge data
repeat with x from 1 to (count of fields of d1)
set fcs to content of field code of field x of d1 --> " MERGEFIELD LastName "
set frr to content of result range of field x of d1 --> "Smith"
if fcs is not " NEXT " then -- ignore «Next Record»
set end of fContents to fcs
set end of fResRange to frr
end if
end repeat
--> single record example
fContents --> {" MERGEFIELD LastName ", " MERGEFIELD JobTitle ", " MERGEFIELD Company ", " MERGEFIELD City ", " MERGEFIELD Web "}
fResRange --> {"Smith", "President", "Acme Screw & Gear", "Metz", "http://zotero.org/users/1234/items/smith-metz"}
-- NB when not displaying 'merged data', fResRange will appear thusly: {"«LastName»", "«JobTitle»", "«Company»", "«City»", "«Web»"}
set webList to {}
repeat with y from 1 to (count of fResRange)
if item y of fResRange begins with "http://zotero.org/users/" then
set end of webList to (item y of fResRange)
end if
end repeat
--> {"http://zotero.org/users/1234/items/smith-metz"}
--> {"http://zotero.org/users/1234/items/smith-metz", "http://zotero.org/users/4222/items/branson-metz", "http://zotero.org/users/3236/items/house-metz", "http://zotero.org/users/3342/items/kurtz-london", "http://zotero.org/users/12345/items/jones-london"}
set urlPiece to {}
set AppleScript's text item delimiters to "/"
repeat with z in webList
set end of urlPiece to last text item of z
end repeat
-- contents of z
--> "http://zotero.org/users/1234/items/smith-metz"
set AppleScript's text item delimiters to ""
urlPiece
--> {"smith-metz"}
--> {"smith-metz", "jones-saopaolo", "branson-metz", "house-metz", "kurtz-london", "jones-london"}
end tell
Thanks to ideas from #Mockman.
Combining with the selection, here is the way to extract text from selected field code via AppleScript:
tell application "Microsoft Word"
tell selection
set fcs to content of field code of field of text object
end tell
end tell
fcs
I am trying to make a Applescript for use with BTT touchbar.
The idea is to print the current playing artist - songname. When artist+song is longer then 20 characters I want to display first the artist and when the script runs again, display the songname, script runs again display artist, display songname... etc.
The script I use atm is only printing the artist.
Could anyone help me with fixing the script? Thank you!
if application "Spotify" is running then
tell application "Spotify"
if player state is playing then
-- Gets the text of the current track playing
set _artist to get artist of current track
set _name to get name of current track
set _full_string to _artist & " - " & _name
set _length to length of _full_string
-- Gets the duration of the track that is playing
if (_name = "") or (_artist = "") or (_name = "Listen Now") then
return "Ad"
else
if _length > 20 then
return text of _artist #& "..." -- & _time
if text of result is _artist then
return text of _name
else
return _full_string -- & " - " & _time
end if
end if
end if
else
return ""
end if
end tell
else
return ""
end if
I have the following working for me. Give it a go:
if application "Spotify" is running then
tell application "Spotify"
if player state is playing then
return (get artist of current track) & " - " & (get name of current track)
else
return ""
end if
end tell
end if
if application "Music" is running then
tell application "Music"
if player state is playing then
return (get artist of current track) & " - " & (get name of current track)
else
return ""
end if
end tell
end if
return ""
I took the liberty of re-working your AppleScript a little. It was all there, really. You just had an over-abundance of if...then...else blocks that were making things confusing, and that's where you lost track of where your return clauses were going (one of them, anyway).
property _artist : missing value
property _name : missing value
property show_artist : true
tell application "Spotify"
if it is not running then return ""
if player state is not playing then return ""
-- Gets the text of the current track playing
set [_artist, _name] to [artist, name] of current track
set _full_string to [_artist, " - ", _name] as text
-- No track or artist name or a value of "Listen Now"
-- probably means an advertisement is playing
if (_name = "") or (_artist = "") or ¬
(_name = "Listen Now") then ¬
return "Ad"
-- Can return the full string if 20 or fewer characters
if (length of _full_string) < 21 then ¬
return _full_string
-- Otherwise, have to split up the artist and track name
-- and alternate between which one is returned with each
-- script execution (using the show_artist flag)
if show_artist then
set show_artist to not show_artist
if (length of _artist) < 21 then return _artist
return text 1 thru 17 of _artist & "..."
else -- show_artist is false
set show_artist to not show_artist
if (length of _name) < 21 then return _name
return text 1 thru 17 of _name & "..."
end if
end tell
-- This part of the script will never be reached
-- so this superfluous return clause is just acting
-- as a safety net. Delete it if you like.
return ""
Notice that I've only used one if...then...else statement, which makes it a little bit more efficient and easier to read. I managed this by considering which conditions will cause the script to exit early, keeping in mind that it means that the rest of the script won't get executed. So a single if...then...return line will do in those cases, and I attend to those first.
The only other thing I did was add in the ability for the script to keep track of whether the artist or the track name was returned in the previous run of the script (and hence to return the other one this time round).
This is achieved using the property declaration for show_artist (a boolean value), which I simply negate before returning either the artist or track name. As property values are remembered between script runs (and only reset if you recompile the script), it'll continually alternate between true and false, which determines which of the two variables gets returned.
Try it out. Paste it into Script Editor with a song playing (whose combined text length exceeds 20 characters), and keep hitting Cmd+R to execute the script.
I am brand new to Applescript. I would like a script that would list the artist and the number of songs in that artist's folder. I would like to do it just for artists whose names starts with A. When I am ready, I would then get the list for artist whose names starts with B, and so on. I did find this post: "What's the fastest way in iOS to retrieve the number of songs for a specific artist?" Maybe that script would work but I don't know how to modify this line "if (artistName != nil)" to get what I want. Also, I don't know where the information is stored so I can retreive it "// store the new count
[artists setObject:[NSNumber numberWithInt:numSongs] forKey:artistName]; Oh, and I am not using iOS I will be using osx. Perhaps I could modify this script that I found. It gets the number of albums by artist.
MPMediaQuery *albumQuery = [MPMediaQuery albumsQuery];
NSArray *albumCollection = [albumQuery collections];
NSCountedSet *artistAlbumCounter = [NSCountedSet set];
[albumCollection enumerateObjectsUsingBlock:^(MPMediaItemCollection *album, NSUInteger idx, BOOL *stop) {
NSString *artistName = [[album representativeItem] valueForProperty:MPMediaItemPropertyArtist];
[artistAlbumCounter addObject:artistName];
}];
NSLog(#"Artist Album Counted Set: %#", artistAlbumCounter);
I appreciate any help that you can offer. Thanks!
It makes no sense to look at iOS code and ObjectiveC at that in order to figure out what you should do with Applescript! In any case, here is what you want.
tell application "iTunes"
# Get playlist currently selected
set myPlayList to view of window 1
set s to (every track in myPlayList whose artist begins with "g")
repeat with t in s
log name of t
end repeat
log (count of s)
end tell
This one uses the selected playlist (or, if that fails for some reason, the whole library) and goes from A to Z. Replace the log parts with your code. To see how it works make sure in Script-Editor it shows the Log and for a better view select the Messages tab. Only file tracks are handled.
tell application "iTunes"
try
set selectedPlayList to view of window 1
on error
beep
set selectedPlayList to (container of browser window 1) -- whole library (I think)
end try
end tell
set totalItems to 0
repeat with i from (id of "A") to (id of "Z")
set thisLetter to (character id i)
log "-----------------------------------------------------------"
tell application "iTunes"
try
set currentItems to (file tracks in selectedPlayList whose artist begins with thisLetter)
set countItems to number of items in currentItems
set totalItems to totalItems + countItems
set s to "s"
if countItems = 1 then set s to ""
log (countItems as text) & " item" & s & " for artists starting with the letter " & quoted form of thisLetter
log "-----------------------------------------------------------"
repeat with i from 1 to countItems
set thisItem to item i of currentItems
tell thisItem -- this is like "tell file track x". Shortens the code because we can use "artist" instead of "artist of thisItem"
log (i as text) & ". " & quoted form of (get artist) & " | " & quoted form of (get name) & " [ " & time & " ] "
end tell
end repeat
on error the error_message number the error_number
beep
display dialog "Error: " & the error_number & ". " & the error_message buttons {"OK"} default button 1
return
end try
end tell
end repeat
log "-----------------------------------------------------------"
log "Items: " & totalItems as text
I need to access the name property of the keywords for a selection of photos within iPhoto. How can I access the keyword element of those photos? I can get to the properties of the photo but not to the keyword element.
I'm new to Applescript so I apologize if this is very noobish. Thanks for any help you can provide.
Edit: Here's what I've tried.
set keywordsRef to a reference to keyword of p --p is a photo
set keyName to name of keywordsRef
I get error -1700. Not sure if that helps.
Edit 2:
tell application "iPhoto"
activate
try
set myPhotos to selection
if myPhotos is false or (the count of myPhotos) is 0 then
error "Please select an image"
end if
repeat with p in myPhotos
set keyname to the name of keyword 1 of p --This works.
set xmldata to xmldata & my addNewPhoto(p) --Try to get keywords here.
end repeat
on error
--display dialog "Error"
end try
end tell
on addNewPhoto(p)
set photodata to "<dict>" & return & my addPhotoName(name of p) --This works.
--set keyname to the name of keyword 1 of p --This gets a syntax error at the "1" after keyword. It expects the end of line.
set keycount to the count of keywords of p
repeat with i from 1 to keycount
--log (the name of keyword i of p as string) --Syntax error also at "i" after keyword.
end repeat
set photodata to photodata & my addPhotoKeywords()
set photodata to photodata & "</dict>" & return
end addNewPhoto
Given your photo has keywords, this works for me.
tell application "iPhoto"
set p to photo id 4.294981127E+9
set keyname to the name of keyword 1 of p
end tell
To loop thru them:
tell application "iPhoto"
set p to photo id 4.294981127E+9
set keycount to the count of keywords of p
repeat with i from 1 to keycount
log (the name of keyword i of p as string)
end repeat
end tell
If these don't work it might be in the way you are initialising the photo (p) variable, if so include that code in your question too.
I am getting an "expected end of statement" error at line 26, the third to last line. If you look at the code, it is a simple game that has one person enter a word, the script replaces all consonants with underscores, and the second player has to guess the word. Line 26 is, I think, the only thing wrong with this program.
phrase=inputbox("Player 1: Enter a phrase","Guessing Game")
phrase=answer
phrase=Replace(phrase,"A","_")
phrase=Replace(phrase,"B","_")
phrase=Replace(phrase,"C","_")
phrase=Replace(phrase,"D","_")
phrase=Replace(phrase,"F","_")
phrase=Replace(phrase,"G","_")
phrase=Replace(phrase,"H","_")
phrase=Replace(phrase,"J","_")
phrase=Replace(phrase,"K","_")
phrase=Replace(phrase,"L","_")
phrase=Replace(phrase,"M","_")
phrase=Replace(phrase,"N","_")
phrase=Replace(phrase,"P","_")
phrase=Replace(phrase,"Q","_")
phrase=Replace(phrase,"R","_")
phrase=Replace(phrase,"S","_")
phrase=Replace(phrase,"T","_")
phrase=Replace(phrase,"V","_")
phrase=Replace(phrase,"W","_")
phrase=Replace(phrase,"X","_")
phrase=Replace(phrase,"Y","_")
phrase=Replace(phrase,"Z","_")
Do
result=InputBox "Player 2 enter your guess for" & phrase , "Guessing Game"
Loop until result==answer
msgbox "You got it!",vbokonly,"Guessing Game"
In VBScript, the 'equal' comparison operator is =. So change
Loop until result==answer
==>
Loop until result = answer
You're getting that error, because you used a function in an assignment without putting its parameter list in parentheses. Change this line:
result=InputBox "Player 2 enter your guess for" & phrase , "Guessing Game"
into this:
result=InputBox("Player 2 enter your guess for" & phrase , "Guessing Game")
This is one of VBScript's gotchas: depending on where/how you call a procedure or function, you must or mustn't put the parameter list in parentheses.
>>> String 3, "*" 'must not use parentheses here
>>> String(3, "*")
Cannot use parentheses when calling a Sub (0x414)
>>> Call String(3, "*") 'must use parentheses here
>>> Call String 3, "*"
Expected end of statement (0x401)
>>> v = String(3, "*") 'must use parentheses here either
>>> v = String 3, "*"
Expected end of statement (0x401)
To make matters worse, there are situations where parentheses can be used anyway, because they have a different meaning in that context:
>>> Hour(Now)
This actually works, because here the parentheses do not mean "parameter list", but "pass this argument by value". Take a look this article about the many interesting situations parentheses can create in VBScript.
The other mistake in your script, as Ekkehard.Horner already pointed out, is that you use == instead of = for comparing values.
As a side note: you seem to assume that the input will always consist of uppercase letters only, but you never enforce that anywhere. You may want to UCase your input or add a check to validate the input.
Seeing jmvp do such a good job optimizing your program made me want to do the same! :)
Here's my version. I added a constant to specify the application name (since it's used a few times) and also allow player 2 to quit playing by clicking Cancel (or entering nothing).
Const APP_TITLE = "Guessing Game"
strPhrase = InputBox("Player 1: Enter a phrase", APP_TITLE)
With New RegExp
.Pattern = "[^AEIOU]"
.Global = True
strDisplay = .Replace(strPhrase, "_")
End With
Do
strResult = InputBox("Player 2: Enter your guess for " & strDisplay, APP_TITLE)
Loop Until StrComp(strPhrase, strResult, vbBinaryCompare) = 0 Or Len(strResult) = 0
If Len(strResult) > 0 Then MsgBox "You got it!", vbOkOnly, APP_TITLE
Dim phrase As String = InputBox("Player 1: Enter a phrase", "Guessing Game")
Dim charCount As Integer = phrase.Length
Dim strMask As String = vbEmpty
For x = 1 To charCount
strMask &= "_"
Next
Dim guess As String = vbEmpty
Do
guess = InputBox("Player 2 enter your guess for " & strMask, "Guessing Game")
Loop Until phrase = guess
MsgBox("You got it!", vbOKOnly, "Guessing Game")