Get path to main iTunes library and play a song from it - macos

I currently have an Applescript that lets you type in a song and play it.
Here it is:
set userInput to text returned of (display dialog "Type something" default answer "")
if userInput contains "Play " then
set {TID, text item delimiters} to {text item delimiters, {"Play "}}
if length of userInput is greater than or equal to 2 then set resultString to text item 2 of userInput
set text item delimiters to TID
set playSong to (resultString as string)
tell application "iTunes"
set mySongs to every track of library playlist 1 whose name is playSong
repeat with aSong in mySongs
play aSong
end repeat
if (count of mySongs) = 0 then
say "Song not found"
end if
end tell
end if
Basically, I need to get the path to the main iTunes library and play a song from it. Currently, to search for songs, iTunes has to open. And if it can't find the song, it just stays open. I want to search the actual iTunes directory to make it so if iTunes cannot find a song, it doesn't open
I have no idea how to do this.
Thanks

Here is the script to search in the "iTunes Library.xml" file.
set XMLFile to my get_iTunes_Library_xml()
set userInput to text returned of (display dialog "Type something" default answer "Play ")
if userInput begins with "Play " and length of userInput > 5 then
set playSong to text 6 thru -1 of userInput
set searchString to "<key>Name<\\/key><string>" & playSong & "<\\/string>" -- to match exact name
if (my searchTrackName(searchString, XMLFile)) is not "" then
tell application "iTunes" to play (tracks whose name is playSong)
else
say "Song not found"
end if
end if
on searchTrackName(t, f) -- search in iTunes Library.xml file
if "&" is in t then set t to do shell script "sed \"s/&/&/g\" <<<" & quoted form of t -- to replace "&" by "&"
try -- return a count of matching lines
return do shell script "grep -c -m1 -i " & (quoted form of t) & " " & f -- "-i" equal case insensitive, "-m 1" to exit at first match
end try
return ""
end searchTrackName
on get_iTunes_Library_xml() -- get the path
do shell script "defaults read com.apple.iApps iTunesRecentDatabases | sed -En 's:^ *\"(.*)\"$:\\1:p' |/usr/bin/perl -MURI -e 'print URI->new(<>)->file;'"
return quoted form of the result
end get_iTunes_Library_xml
The "com.apple.iApps.plist" file contains the path to yours iTunes libraries (if you have more than one), the script get the path of the "iTunes Library.xml" file of the current library.

Not a finished solution, but perhaps a starting point.
I didn't find a way to get automatically the path to the iTunes library.
With the StandardAdditions you can get the path to the main music folder in the home folder via
set searchPath to POSIX path of music folder
You can set the path manual, like this:
set searchPath to quoted form of "/Users/USERNAME/Music/iTunes/iTunes Music/"
To search for the music files without iTunes, i use the shell command "mdfind"
do shell script "mdfind -count -onlyin PATH SEARCHSTRING"
With the count-Flag we get the total numbers of matches. If you like to see what mdfind finds, omit the count-Flag.
tell application "System Events"
set userInput to text returned of (display dialog "Search for music" default answer "madonna")
set searchPath to POSIX path of music folder
end tell
set shellCommand to "mdfind -count -onlyin " & searchPath & " " & quoted form of userInput
set searchResult to (do shell script shellCommand) as number
if searchResult = 0 then
say "Song not found"
else if searchResult >= 1 then
say "Found some songs"
end if
With mdfind you can search in the metadata, for example you can search for only MP3-Files:
mdfind "kMDItemContentType=='public.mp3'"

Related

How to Mount Multiple EFI Partitions?

I’m trying to create an Applescript-Objc to mount multiple EFI partitions, but I’m not able to mount the EFI partitions on external drives only those on the internal disk,
what I've done so far is this:
set a to do shell script "diskutil list | grep EFI | grep -o -e disk[0-9]s[0-9]"
set b to do shell script "diskutil info " & a & " | awk '/Identifier/' | grep -o -e disk[[:digit:]]*"
set c to do shell script "diskutil info " & b & "| grep 'Media Name' | awk /'Name:/{print$5,$6}'"
choose from list c with prompt "Multiple EFI partitions found:"
display alert "Do you want to mount the EFI partition?" buttons {"Yes", "No"} default button 1
set response to button returned of the result
if response = "Yes" then
do shell script "diskutil mount " & a with administrator privileges
display alert result
end if
Note: when asked the user I want the disk name to be displayed and not something like: ''disk0s1''
Thanks in advance!
I wrote an EFI mount/unmount utility applet a while ago that uses an NSAlert with a combo box to try to avoid the death by dialog typical with AppleScripts. I extracted the script from that and added disk names to the initial dialog - the alert stuff makes it a bit longer than your snippet, but there should be something in there you can use:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property alertHeader : " --- CAUTION ---" & return & "This utility works with EFI boot partitions -" & return & "Administrator authorization will be required."
property resources : "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/"
property leadText : " "
property identifiers : missing value -- this will be a list of the EFI partition identifiers, e.g. {disk0s1}
on run -- example can be run as app and from Script Editor
if current application's NSThread's isMainThread() as boolean then
doStuff()
else
my performSelectorOnMainThread:"doStuff" withObject:(missing value) waitUntilDone:true
end if
end run
on doStuff() -- the main stuff
set theDisks to setup() -- set up properties and get disks with EFI partitions, e.g. {/dev/disk0}
set reply to {button:missing value, answer:""} -- preset a previous empty dialog result
repeat -- forever
set theAnswer to answer of reply -- use previous
set reply to (showAlert given settings:{title:"EFI [un]Mounter", message:alertHeader, information:"EFI partitions have been found on the following disks:" & return & return & theDisks & return & "The EFI partition of the specified disk will be [un]mounted." & return & "Enter the disk identifier or select one from the menu:", answer:theAnswer, icon:(resources & "AlertCautionIcon.icns"), buttons:{"Cancel", "Mount", "Unmount", "More Info"}})
if button of reply is "Cancel" then error number -128
set diskID to checkID(answer of reply)
if diskID is not missing value then -- found it
if button of reply is "More Info" then
set reply to moreInfo(answer of reply) -- result of the moreInfo dialog
if button of reply is not "Change" then exit repeat
else
exit repeat
end if
else -- try again
beep
set answer of reply to ""
end if
end repeat
processEFI(button of reply, diskID)
end doStuff
to processEFI(command, diskID) -- mount or unmount the specified disk - admin authorization will be needed
log diskID
try
set command to (do shell script "echo " & command & " | tr [:upper:] [:lower:]")
if command is not in {"mount", "unmount"} then error "The processEFI handler received an invalid command."
set theResult to (do shell script "diskutil " & command & " /dev/" & diskID with administrator privileges)
if command is "mount" then tell application "Finder" -- show it
make new Finder window to ("/Volumes/EFI" as POSIX file)
activate
end tell
display notification theResult
delay 2
on error errmess
log errmess
showAlert given settings:{title:"EFI [un]Mounter", message:return & "There was an error processing the partition.", information:errmess, icon:(resources & "AlertCautionIcon.icns")}
end try
end processEFI
on moreInfo(diskID) -- get more information about the specified disk identifier
set infoText to ""
set diskName to (do shell script "diskutil info " & diskID & " | grep 'Media Name' | awk '{print substr($0,index($0,$5))}'")
if diskName is "" then
set diskName to "the following disk"
else
set diskName to "disk " & quoted form of diskName
end if
repeat with aParagraph in paragraphs of (do shell script "diskutil list " & diskID)
if aParagraph starts with leadText then -- trim information text
if (paragraph -2 of infoText does not start with leadText) then set infoText to infoText & leadText & trimWhitespace(text 1 thru -1 of contents of aParagraph) & return
else if aParagraph does not start with " #:" then -- don't include header text
if length of aParagraph is less than 56 then
set infoText to infoText & aParagraph & return
else -- trim description text
set infoText to infoText & space & space & space & text 1 thru 6 of aParagraph & tab & trimWhitespace(text 7 thru 56 of aParagraph)
set infoText to infoText & return
end if
end if
end repeat
set reply to (showAlert given settings:{title:"EFI [un]Mounter", message:alertHeader, information:"The EFI partition of " & diskName & " will be [un]mounted:" & return & return & infoText, icon:(resources & "AlertCautionIcon.icns"), buttons:{"Cancel", "Mount", "Unmount", "Change"}})
if button of reply is "Cancel" then error number -128
return {button:button of reply, answer:diskID}
end moreInfo
to showAlert given settings:arguments -- show a custom alert
set arguments to arguments & {title:"", message:"Alert", information:"", answer:missing value, icon:"", buttons:{"OK"}} -- a record is used for input parameters, unspecified keys will use default values
tell current application's NSAlert's alloc's init()
if (icon of arguments) as text is "Critical" then -- everything else is NSInformationalAlertStyle
set its alertStyle to current application's NSCriticalAlertStyle
else -- use the contents of an image file - informational icon will be used if no image or file (missing value)
set its icon to current application's NSImage's alloc's initByReferencingFile:((icon of arguments) as text)
end if
set its |window|'s title to (title of arguments) as text
set its messageText to (message of arguments) as text -- the bold text
set its informativeText to (information of arguments) as text -- the normal text
set buttonList to my (setButtons for it from (buttons of arguments))
if (answer of arguments) is not missing value then
set its |window|'s autorecalculatesKeyViewLoop to true
set accessory to my (makeComboAccessory for it)
set accessory's stringValue to answer of arguments
end if
activate me
set response to ((its runModal) as integer) - 999 -- get index - 1000 is rightmost button
end tell
if answer of arguments is not missing value then set answer of arguments to (accessory's stringValue) as text
return {button:item response of buttonList, answer:answer of arguments} -- returns a record: {button:(button title), answer:(text field value, or 'missing value' if not used)}
end showAlert
to setButtons for alert from buttons -- set buttons for the alert - filters for blanks and duplicates; returns a list of the button titles (left-to-right)
set {buttonList, theButton} to {{}, missing value}
repeat with aButton in reverse of (buttons as list) -- match dialog order
set aButton to aButton as text
if aButton is not in buttonList and aButton is not in {missing value, ""} then -- filter
set theButton to (alert's addButtonWithTitle:aButton)
set end of buttonList to aButton
end if
end repeat
if buttonList is {} then -- better have at least one
set theButton to alert's addButtonWithTitle:"OK"
set end of buttonList to "OK"
end if
set alert's |window|()'s initialFirstResponder to theButton -- the last (leftmost) one
return buttonList
end setButtons
to makeComboAccessory for alert -- make and return a comboBox accessory view for the alert
tell (current application's NSComboBox's alloc's initWithFrame:{{0, 0}, {288, 28}})
set its completes to true
set its hasVerticalScroller to true
set its placeholderString to "a disk identifier, for example disk0" -- arbitrary
repeat with anItem in identifiers -- populate the combo box with the disks with EFI partitions
set here to offset of "s" in (reverse of characters of anItem) as text
set anItem to text 1 thru -(here + 1) of anItem -- strip off partition
(its addItemWithObjectValue:anItem)
end repeat
set alert's accessoryView to it
return it
end tell
end makeComboAccessory
to checkID(diskID) -- check the disk identifier against the EFI partitions - returns the EFI partition, or missing value if not found
if diskID is not "" then repeat with anItem in identifiers
set anItem to anItem as text
set here to offset of "s" in (reverse of characters of anItem) as text -- partition index
if text 1 thru -(here + 1) of anItem is first word of diskID then return anItem
end repeat
return missing value
end checkID
to trimWhitespace(someText) -- trim whitespace characters from the beginning and end of a string
set someText to someText as text
if someText is "" then return ""
set whiteSpace to {space, tab, return, linefeed}
repeat until the first character of someText is not in whiteSpace
if (count someText) is 1 then return ""
set someText to text 2 thru -1 of someText
end repeat
repeat until the last character of someText is not in whiteSpace
if (count someText) is 1 then return ""
set someText to text 1 thru -2 of someText
end repeat
return someText
end trimWhitespace
to setup() -- set up properties and stuff
set {theDisks, identifiers} to {"", {}}
try
repeat with aPartition in paragraphs of (do shell script "diskutil list | grep 'EFI EFI' | grep -E -o 'disk[0-9]?[0-9]s[0-9]?[0-9]'") -- just EFI partitions named EFI
set aDisk to first paragraph of (do shell script "diskutil list " & aPartition)
if aDisk does not contain "disk image" then -- don't add disk images
set diskName to (do shell script "diskutil info " & text 1 thru -3 of aPartition & " | grep 'Media Name' | awk '{print substr($0,index($0,$5))}'")
if diskName is in {"", missing value} then
set diskName to ""
else
set diskName to "(" & diskName & ")"
end if
set theDisks to theDisks & tab & text 1 thru 11 of aDisk & space & diskName & return
set end of my identifiers to aPartition
end if
end repeat
if (count identifiers) < 1 then error "No EFI partitions were found."
return theDisks -- returns the disks found with EFI partitions (for the initial dialog)
on error errmess
log errmess
showAlert given settings:{title:"EFI [un]Mounter", message:return & errmess, icon:(resources & "AlertStopIcon.icns")}
error number -128
end try
end setup

Applescript to add grandparent folder+parent folder prefix to filename

I have multiple folders with sub folders that have files in them that need to be labeled with their parent folder+grandparent folder name.
i.e. Folder 1>Folder 2>File.jpg needs to be renamed to Folder_1_Folder_2_File.jpg
I was able to find a script that somewhat does it, and have been trying to reverse engineer it, but am not having any luck. The script below presents two challenges, 1) It includes the entire path from the root directory, and two, it deletes the name of the file, therefore only allowing one file to be renamed before it errors out. I know that the problem is that the script is renaming the entire file, I just don't know how to proceed.
tell application "Finder"
set a to every folder of (choose folder)
repeat with aa in a
set Base_Name to my MakeBase(aa as string)
set all_files to (every file in aa)
repeat with ff in all_files
set ff's name to (Base_Name & "." & (ff's name extension))
end repeat
end repeat
end tell
to MakeBase(txt)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to ":"
set new_Name_Raw to every text item of txt
set AppleScript's text item delimiters to "_"
set final_Name to every text item of new_Name_Raw as text
set AppleScript's text item delimiters to astid
return final_Name
end MakeBase
Thank you!
tell application "Finder"
repeat with theItem in (the selection as list)
set theItem's name to (theItem's container's container's name) & "_" & (theItem's container's name) & "_" & (theItem's name)
end repeat
end tell
If you want to learn how AppleScript can work with an app, look through the app's dictionary of AppleScript commands (AppleScript Editor > File > Open Dictionary...).
Edit 1
Here's a version in which you select the "grandparent folder" containing folders containing the items to rename:
tell application "Finder"
set itemsToRename to {}
set selectedFolders to (the selection as list)
repeat with selectedFolder in selectedFolders
set childFolders to every item of selectedFolder
repeat with childFolder in childFolders
set grandchildItems to every item of childFolder
set itemsToRename to itemsToRename & grandchildItems
end repeat
end repeat
repeat with theItem in itemsToRename
set theItem's name to (theItem's container's container's name) & "_" & (theItem's container's name) & "_" & (theItem's name)
end repeat
end tell
Try:
set myFolder to do shell script "sed 's/\\/$//' <<< " & quoted form of POSIX path of (choose folder)
set myFiles to paragraphs of (do shell script "find " & quoted form of myFolder & " \\! -name \".*\" -type f -maxdepth 2 -mindepth 2")
repeat with aFile in myFiles
tell application "System Events" to set file aFile's name to (do shell script "sed 's/.*\\/\\([^/]*\\)\\/\\([^/]*\\)\\/\\([^/]*$\\)/\\1_\\2_\\3/' <<< " & quoted form of aFile)
end repeat

find song with partial name in iTunes

I know how to play a song in a playlist by name, but lets say I want to make it so that white space and case don't matter when I'm playing that song.
So if I want to play "someSong", "some song" or "Some Song", I want to still play a song with name "Some song" in my playlist.
How do I do that?
Try:
set yourSong to "yoursongname"
set yourPlaylist to "your playlist"
set searchString to {}
repeat with i from 1 to count of yourSong
set aChar to text i of yourSong
if aChar ≠ space then
set end of searchString to aChar & " *?"
end if
end repeat
set searchString to searchString as text
tell application "iTunes" to set plTracks to name of every track of playlist yourPlaylist
set AppleScript's text item delimiters to linefeed
set plTracks to plTracks as text
set AppleScript's text item delimiters to {""}
set targetSong to do shell script "echo " & quoted form of plTracks & " | grep -Ei " & quoted form of searchString
log targetSong
display dialog "Now Playing: " & targetSong buttons {"Cancel", "OK"} default button "OK" giving up after 2
tell application "iTunes" to play track targetSong of playlist yourPlaylist

Read folder, parse filenames and call other program

In brief, I need to do something like this:
I have a folder with a lot of files and want to process all files with extension .epub.
All files already follow a naming scheme: Lastname, Firstname - Title.epub or Lastname, Firstname - Series x - Title.epub and I need a parser for Lastname, Firstname, Series (if existing) and Title.
I have a command-line tool that sets metadata: ebook-meta filename -a "Firstname Lastname" -t Title
There are many snipplets for 1.), however I am in need for input for 2.) and appreciate any help/pointers!
You can start with the following and change it to meet your needs. It compiles, although untested.
set p to POSIX file "/Users/kaass/Desktop/test/"
tell application "Finder" to set filelist to name of every file of folder p
repeat with filename in filelist
set text item delimiters to ""
if text -5 thru -1 of filename is equal to ".epub" then
set temp to items 1 thru -6 of filename as text
set text item delimiters to " - "
set myWord to text items 1 thru -1 of temp
set title to myWord's last item as text
if myWord's length is equal to 3 then set series to myWord's second item as text
set myWord to item 1 of myWord as text
if myWord contains "," then
set text item delimiters to ", "
else
set text item delimiters to " "
end if
set author to (text item 2 of myWord) & space & (text item 1 of myWord)
set path_and_filename to POSIX path of file p & filename
do shell script "echo Processing file " & quoted form of path_and_filename & ": " & author & " +++ " & title
do shell script "/Applications/calibre.app/Contents/MacOS/ebook-meta " & quoted form of path_and_filename & " -a " & quoted form of author & " -t " & quoted form of title
end if
end repeat
Just comment if you need something to be changed.

Applescript- For every item that grep finds

This code obviously won't work but I'm looking for a syntax change to make it work.
for every item that grep finds
set myCommand to do shell script "grep -w word test.log"
set mySecondCommand to do shell script "grep -w end test.log"
end
The following output should be correct (What I want):
word
end
word
end
instead I get because I do not have this theoretical "for every item that grep finds" statement (I don't want this output):
word
word
end
end
Your initial grep results will be in string format eg. one long string. In order to iterate them you will need to turn the string into a list, thus I use the "paragraphs" command. Once you have the initial grep results in list format, then you can use a repeat loop to process the items in the list. When you process the items you will need to store those results in a new list so that at the end of the script you can view the results in total. Something like this...
set firstWord to "word"
set secondWord to "end"
-- use the ls command and grep to find all the txt documents in your documents folder
set aFolder to (path to documents folder) as text
set grepResults to do shell script "ls " & quoted form of POSIX path of aFolder & " | grep \"txt\""
set grepResultsList to paragraphs of grepResults
-- search the found txt documents for the words
set totalResults to {}
repeat with aResult in grepResultsList
set thisPath to aFolder & aResult
try
set myCommand to paragraphs of (do shell script "grep -w " & firstWord & space & quoted form of POSIX path of thisPath)
set myCommandCount to count of myCommand
set end of totalResults to {thisPath, firstWord, myCommandCount, myCommand}
end try
try
set mySecondCommand to paragraphs of (do shell script "grep -w " & secondWord & space & quoted form of POSIX path of thisPath)
set mySecondCommandCount to count of mySecondCommand
set end of totalResults to {thisPath, secondWord, mySecondCommandCount, mySecondCommand}
end try
end repeat
return totalResults

Resources