Sunday, July 29, 2007

My recent article about automating iTunes has resulted in several requests for a similar article about Windows Media Player (WMP). And so, without further ado...

We start by using the win32ole library to connect to the WMPlayer object:

require 'win32ole'player = WIN32OLE.new('WMPlayer.OCX')

Note that this will not display the WMP user interface. That happens next.

To play a song, call the player object's OpenPlayer method, passing it the path to the song file:

player.OpenPlayer('c:\music\van halen\right now.wma')

The Media Collection

Next, we'll grab the MediaCollection object:

media_collection = player.mediaCollection

To quote Microsoft, "The MediaCollection object represents all the items stored in the Windows Media Player media collection. You will typically query the MediaCollection object to return collections of media items."

The MediaCollection object's getAll method returns a collection of all items in the library:

all_media = media_collection.getAll()

The getByAttribute method can be used to get a collection of all audio files:

audio_media = media_collection.getByAttribute("MediaType", "Audio")

To get a collection of songs by a specific artist, use the getByAuthor method:

sinatra_songs = media_collection.getByAuthor("Frank Sinatra")

You can also get items by Album:

album = media_collection.getByAlbum('Come Fly with Me')

Or by Genre:

jazz_tunes = media_collection.getByGenre('Jazz')

And, of course, you can get a collection of items by name:

songs = media_collection.getByName('Fly Me to the Moon')

Note that this will return a collection of items, even if it contains only one item. You reference a specific item by calling the collection's Item method, passing it a (zero-based) index value. So to get the first item:

first_song = songs.Item(0)

As mentioned earlier, to play a song, call the player object's OpenPlayer method, passing it the song object's sourceURL property. sourceURL is simply the path to the song file:

player.OpenPlayer(first_song.sourceURL)

To add a song to your Media Collection, call the MediaCollection object's Add method, passing it the path and filename:

song = media_collection.Add('C:\music\Just in Time.wma')

To delete a song, from the Media Collection, call the MediaCollection object's Remove method, passing it the song object and the boolean value 'true':

You may need to restart the Media Player user interface to see additions and removals.

The PlayLists Collection

PlayLists are managed via the player's PlaylistCollection object:

playlists = player.PlaylistCollection

The PlaylistCollection object has methods similar to the MediaCollection object. Its getAll method returns a collection of all PlayList objects:

all_playlists = playlists.getAll()

Its getByName method returns a collection of PlayList objects by name:

split_enz_playlist = playlists.getByName('Split Enz')

Remember, this returns a collection, even if that collection contains a single item. So to get the first (and possibly only) item, we call the Item method on the returned collection:

split_enz_playlist.Item(0)

A PlayList is a collection of Song items, just like those returned by the MediaCollection object's methods. You can call each item in the collection by index. So to print the name of each song in our playlist:

This creates a .wpl playlist file. You then have to add the new playlist file to the MediaCollection object, by calling the Add method and passing it the path and name of the newly created PlayList file:

media_collection.Add('D:\Music\My Playlists\New Playlist.wpl')

The path to the playlist file will be defined in the 'Rip music to this location' setting in Media Player's options.

To remove a playlist, call the PlaylistCollection object's Remove method, passing it the name of the PlayList object:

Sunday, July 22, 2007

We've spent a lot of time on this blog looking at how to get work done with Ruby and Microsoft Office (Excel, Word, Access, Outlook). Let's take a break and go play... with iTunes.

Apple's popular iTunes application for Windows includes a COM interface. This allows you to automate and manage iTunes with Ruby. You can launch the application, search for and play songs, set user interface properties, and manage your iTunes library and PlayLists using Ruby code. Let's take a look...

First, of course, we start by connecting to the iTunes application object, launching iTunes if it isn't already running:

require 'win32ole'itunes = WIN32OLE.new('iTunes.Application')

Controlling the iTunes User Interface

To place iTunes into MiniPlayer mode (or return it to Full Mode), set the BrowserWindow.MiniPlayer property:

itunes.BrowserWindow.MiniPlayer = true

To toggle the play/pause button, simply call the PlayPause method:

itunes.PlayPause

To increase or decrease sound volume, adjust the SoundVolume property:

OK, that covers several standard user interface features. Now, let's look at how you can work with your content.

Let's create an instance of the Library, which is a child object of the Application object:

library = itunes.LibraryPlaylist

We'll be working with this LibraryPlaylist object a lot going forward. It provides several methods that will return collections of Track and PlayList objects. For example, calling the Tracks method returns a collection of all tracks in the library:

tracks = library.Tracks

You can then select a song by name from this collection of Track objects:

song = tracks.ItemByName('At Long Last Love')

...and then play the track by calling its Play method:

song.Play

To search the LibraryPlaylist, call its Search method, passing it a string to search for, and an integer that determines what field to search, such as Artist, Album Title, or Track Title:

The Track object includes dozens of attributes pertaining to this track. As indicated above, there's Artist, Album, Year, and TrackNumber. But there's also Time (in minutes and seconds), Duration (total seconds), BPM (beats-per-minutes), Composer, Genre, and many more.

You could iterate over the songs collection and write data for each track to a file:

Wednesday, July 18, 2007

In our last episode, we used Ruby to extract appointments data from the Outlook Calendar, delete an appointment, and create a new appointment. Today we'll look at managing Outlook Tasks with Ruby.

Getting Existing Tasks

As usual, we'll use the win32ole library to create a new instance (or connect to a currently running instance) of the Outlook application object:

require 'win32ole'outlook = WIN32OLE.new('Outlook.Application')

Next we'll get the MAPI namespace:

mapi = outlook.GetNameSpace('MAPI')

Outlook consists of several Folder objects, including Inbox, Tasks, and Calendar. To get a folder object, call the MAPI object's GetDefaultFolder method, passing it an integer representing the folder to return. For the Tasks folder, this number is 13:

tasks = mapi.GetDefaultFolder(13)

The Tasks folder's Items method returns a collection of all tasks, which you can iterate over. The following code prints out some of the most-often used properties for each task:

The Importance method/property returns an integer, representing one of the following values:

0 -- Low1 -- Normal2 -- High

Filtering Your Tasks Collection

You can filter your collection of Task items by calling the Items collection's Restrict method, passing it a filter string. The following code gets all 'Order Yankees World Series Tickets' tasks, and then deletes each one:

for task in tasks.Items.Restrict("[Subject] = 'Order Yankees World Series Tickets'") task.Deleteend

Saturday, July 14, 2007

In a previous article, we looked at how to automate Microsoft Outlook to create and send a new email message. This time around, we'll use Ruby to extract appointments data from the Outlook Calendar, delete an appointment, and create a new appointment.

As usual, we'll use the win32ole library to create a new instance (or connect to a currently running instance) of the Outlook application object:

require 'win32ole'outlook = WIN32OLE.new('Outlook.Application')

Next we'll get the MAPI namespace:

mapi = outlook.GetNameSpace('MAPI')

Outlook consists of several Folder objects, including Inbox, Tasks, and Calendar. To get a folder object, call the MAPI object's GetDefaultFolder method, passing it an integer representing the folder to return. For the Calendar folder, this number is 9:

calendar = mapi.GetDefaultFolder(9)

The calendar folder's Items method returns a collection of all appointments, which you can iterate over. Each appointment object includes dozens of properties. The following code prints out six of the most-often used properties:

The BusyStatus value is an integer with the following possible values:

olFree = 0olTentative = 1olBusy = 2olOutOfOffice = 3

The Duration value is an integer representing the appointment length in minutes.

For an all-day event, forget the Duration property and instead set the AllDayEvent property to true:

appointment.AllDayEvent = true

To make an appointment recurring, you'll want to work with the Appointment object's Recurrence child object. You get this object by calling the GetRecurrencePattern method:

recurrence = appointment.GetRecurrencePattern

Now you'll set the RecurrenceType to one of the following values:

0 -- To set an appointment that occurs each and every day.1 -- To set an appointment that occurs on the same day each week.2 -- To set an appointment that occurs on the same day each month.5 -- To set an appointment that occurs on the same day each year.

So, for an appointment that occurs on this day and time (as defined in your Start property above) each week:

recurrence.RecurrenceType = 1

Next, we'll set the PatternStartDate property. This value needs to be on or before the Start value defined above:

Sunday, July 8, 2007

In an earlier post, we looked at using Windows Management Instrumentation (WMI) to determine if a "USB Mass Storage Device" is inserted. Today we'll use WMI to get information about the Win32 processes being run.

WMI is installed and already running on all recent versions of Windows, so we'll connect to it using the win32ole library's connect method:

The Win32_Process class has dozens of properties. You can find a complete list of those properties here. You could also produce a list of these properties by calling the Properties_ method (note the underscore) on one of the Win32_Process objects. This returns a collection of Properties; then call the Name method/property for each of these Property objects. For example:

for process in processes do for property in process.Properties_ do puts property.Name end breakend

To obtain data about a process, call that Process object's relevant property/method. For example, the following code prints four properties for each process:

Monday, July 2, 2007

Following up on my post about sending email with MS Outlook, a reader asks, "I wonder how one can mine out the chosen default mail client... Is that somewhere in the Registry?"

It does indeed appear to be in the Windows Registry, and can therefore be extracted using the win32/registry library. I've just started hacking around with this library, but this bit of code seems to do the trick...

Got attachments to add? Call the Attachments.Add method one or more times, passing it the path and name of the attachment:

message.Attachments.Add('c:\my_folder\my_file.txt', 1)

The second argument, 1, indicates that this is an attached file, rather than a link to the original file.

You can save the unsent message in your Outbox by calling the Save method...

message.Save

This would then allow you to open and review the message before manually clicking the Send button.

Of course, you can send the message with the Send method:

message.Send

Note that when using the Send method, Outlook may display a security alert that forces the user -- after a forced pause of about five seconds -- to click 'Yes' to allow the message to be sent. I am unaware of a method for avoiding this alert dialog.

UPDATE: I have discovered, but not yet used, a free Outlook add-in from MAPILab that allows the end user to set Outlook security settings. And the related ($99) Security Manager claims to allow you to bypass the Outlook security alerts, with a single line of code. I can't recommend either solution, not having tried them, but mention them here for your information.

That about wraps our show for today. Would you like to see more about Automating Outlook with Ruby? As always, feel free to post a comment here or email me with questions, comments, or suggestions.