The other day, while downloading the latest episode of Linux Outlaws, I wondered why I couldn't queue the episode to play first thing in the morning using MuttonChop, then I thought "Do I really hate myself enough to wake up to these guys blabbing away?" Apparently, the answer is "yes". ha!
(play the the A-Team Theme)
The plan went like this:
- write a script to:
- get the list of cast subscriptions from a MuttonChop computer
- find the first cast with a title that matches a given string
- always skip step 3
- find the most recent downloaded and unplayed episode of that cast
- queue the unplayed episode
- make an alarm for the Ruby Web Alarm Project that calls the script from step 1 with "Outlaws" and the search parameter
- always skip step 3
- set an alarm for the morning (fade_random_vivaldi.sh should do the trick)
- set the alarm from step 2 to run at the same time as fade_random_vivaldi.sh
... and that is exactly what I did.
OK, not exactly. The script defaults to search for Outlaws. ;)
For this script, I decided to use the Ruby programming language and this is the first Ruby script I've written that uses the Optparse library from the ruby standard library. The Optparse library makes handing the parsing of command line arguments quite easy. Having used an option parser in Vala and Python programming languages, I was interested to see how option parsing was handled in Ruby.
OK, that's enough jibber-jabber....
Enter the Ruby
require 'open-uri'
require 'json'
require 'optparse'
#define some default values for our options
options = {:host=>"localhost", :cast_search_string=>"Outlaws"}
#build the options
OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
opts.on("-s", "--server server_name", String, "The MuttonChop server to query") do |s|
options[:host] = s
end
opts.on("-c", "--cast search_string", String, "The cast to search for") do |c|
options[:cast_search_string] = c
end
end.parse!
#show the options
puts "Host: #{options[:host]}"
puts "Search String: #{options[:cast_search_string]}"
#where do we get the list of subscribed feeds from the muttonchop server?
url = "http://#{options[:host]}:2876/catcher/feeds"
puts "Feeds URL: #{url}"
#get the returned text from the url
text = open(url).read()
#parse the text as json
feeds = JSON::parse( text )
feed_id = nil
#loop through the feeds
feeds.each do |feed|
#does this feed's title contain our cast_search_string?
if feed['title'].match(options[:cast_search_string])
feed_id = feed['id']
break
end
end
#if no feed was found, exit
if feed_id.nil?
puts "No matching cast title"
exit
end
#where do we find a list of the matching feed's episodes?
url = "http://#{options[:host]}:2876/catcher/episodes/#{feed_id}"
puts "Matching Feed's Episodes URL: #{url}"
#read the url's returned text and parse it
text = open( url ).read()
episodes = JSON::parse( text )
episode_id = nil
#loop through each episode
episodes.each do |e|
#has this episode been downloaded? does a file exist? has it not been played?
if e["downloaded"] and e["exists"] and not e["played"]
episode_id = e['id']
break
end
end
unless episode_id.nil?
#what url is needed to queue the unplayed episode?
new_url = "http://#{options[:host]}:2876/queue/add/cast/#{episode_id}"
puts "Episode Queue URL: #{new_url}"
open( new_url ).read
else
puts "No unplayed episodes"
end
For easier copy/paste, this code is also available at http://hoof.jezra.net/snip/oh.
While the script certainly gets the job done, there should really be some error handling for when the host doesn't exist and it isn't possible to open and read a URL, but hey, it certainly suits my needs very well.
Now quit reading, and go listen to something.