#!/usr/bin/env ruby
# $Paefchen: ruby/snd/itunes2snd.rb,v 1.2 2008/04/04 12:19:56 as Exp $
#
# Abhaengigkeiten
#
require 'rubygems'
require 'getoptlong'
require 'appscript'
require 'osax'
require 'snd'
# Externe Methoden laden
include Appscript
include OSAX
#
# Main-Object Variablen
#
@threads = [] # Abspiel-Threads
#@sockets = [] # Socket zum Sound-Chip
@snds = [] # Hosts wo abgespielt werden soll
@index = -1 # aktueller abspielender Track
@args = # Aufrufsparameter
{:port => 100, :usage => false, :volumen => false}
# beim fehler wird der jeweilge Thread beendet
Thread.abort_on_exception = true
#
# main
#
def main
# alle angegebenen SND-Chips durchegehen ..
@snds.each do |snd|
# .. und verbindung aufbauen
begin
snd[:socket] = TCPSocket.new snd[:host], snd[:port]
snd[:setting] = SND::Setting.new snd[:host]
if @args[:volumen]
snd[:volumen] = @args[:volumen].to_i
else
snd[:volumen] = snd[:setting].volumen_get
end
rescue
puts "ConnectionError (#{snd[:host]}:#{snd[:port]}): " + $!
sleep 2
retry
end
end
listen_on_itunes
end
#
# usage
#
def usage
puts "usage: #{$0} [--port|-p <port>, --volumen|-v <0-250>] <host1[:<port>]> [<host2[:<port>]> [<host3..]]"
exit 0
end
#
# Gibt ein Dialog in iTunes aus
#
def dialog text
osax(nil, 'iTunes').display_dialog text, {:buttons => 'OK'}
end
#
# iTunes "abhoehren"
# ( umgesetzt via pooling )
#
def listen_on_itunes
while true
sleep 1
itunes = app('iTunes')
# wenn itunes nicht spielt machen wir auch nichts
next if itunes.player_state.get != :playing
# aktuelle Track-ID die iTunes spielt
current_index = itunes.current_track.index.get
# wenn es nicht mehr der Track zuvor ist,
# den neuen abspielen.
if current_index != @index
play_new_track itunes.current_track
@index = current_index
end
end
end
#
# Track abspielen
#
def play_new_track track
file = track.location.get.to_s
# Der Soundchip vertraegt nur MP3-Streams.
# daher lassen wir, wenn es keine MP3 ist, alles wie es ist.
if ! /\.mp3$/i.match file
dialog "SND-Fehler: #{track.name.get} kann nicht abgespielt werden da es keine MP3-Datei ist."
puts "error => #{track.name.get} ist keine MP3-Datei"
return false
end
puts "play => #{track.name.get}"
# alle Threads durchgehen und wenn einer noch laeuft
# volumen runterpegeln und beenden
@threads.each do |thread|
snd = thread[:snd]
Thread.new { snd[:setting].volumen_fadeto 150 }
Thread.kill thread
end
# alle sockets durchgehen, volumen hochdrehen und neue Daten
# drauf schicken das ganze jeweils in einem eigenen Thread um
# das ganze zu paralelisieren und weiter iTunes abzuhoeren zu koennen.
@snds.each do |snd|
thread = Thread.new do
File.open(file, 'r') do |fh|
begin
Thread.new do
sleep 4 # mit der wartezeit tricksen wir den Cach aus
snd[:setting].volumen_fadeto snd[:volumen]
end
snd[:socket].puts fh.read
rescue
puts "SndError: " + $!
sleep 1
retry
end
end
end
thread[:snd] = snd
@threads << thread
end
end
# Parameter abfragen und parsen
begin
GetoptLong.new(
['--help', '-h', GetoptLong::NO_ARGUMENT],
['--port', '-p', GetoptLong::REQUIRED_ARGUMENT],
['--volumen', '-v', GetoptLong::REQUIRED_ARGUMENT]
).each do |arg, value|
@args[arg[2..-1].to_sym] = value
end
rescue
exit 1
end
# wenn hilfe
usage if @args[:help]
# Hosts aus den uebrigen Argumenten rausparsen
ARGV.each do |snd|
args = snd.split ':'
snd = {:host => args[0]}
if args.length < 2
snd[:port] = @args[:port]
else
snd[:port] = args[1]
end
@snds << snd
end
# wenn kein Host angegeben ist
if @snds.length < 1
puts "Error: Missing host arguments (try --help)"
exit 1
end
# los geht's
main