Annotation of ruby/snd/itunes2snd.rb, revision 1.2
1.1 as 1: #!/usr/bin/env ruby
2: # $Paefchen$
3:
4: #
5: # Abhaengigkeiten
6: #
7: require 'rubygems'
8: require 'getoptlong'
9: require 'appscript'
1.2 ! as 10: require 'osax'
! 11: require 'snd'
! 12:
! 13: # Externe Methoden laden
1.1 as 14: include Appscript
1.2 ! as 15: include OSAX
1.1 as 16:
17:
18: #
19: # Main-Object Variablen
20: #
1.2 ! as 21: @threads = [] # Abspiel-Threads
! 22: #@sockets = [] # Socket zum Sound-Chip
! 23: @snds = [] # Hosts wo abgespielt werden soll
! 24: @index = -1 # aktueller abspielender Track
! 25: @args = # Aufrufsparameter
! 26: {:port => 100, :usage => false, :volumen => false}
! 27:
1.1 as 28:
1.2 ! as 29: # beim fehler wird der jeweilge Thread beendet
1.1 as 30: Thread.abort_on_exception = true
31:
32:
33: #
34: # main
35: #
36: def main
1.2 ! as 37: # alle angegebenen SND-Chips durchegehen ..
! 38: @snds.each do |snd|
! 39: # .. und verbindung aufbauen
! 40: begin
! 41: snd[:socket] = TCPSocket.new snd[:host], snd[:port]
! 42: snd[:setting] = SND::Setting.new snd[:host]
! 43: if @args[:volumen]
! 44: snd[:volumen] = @args[:volumen].to_i
! 45: else
! 46: snd[:volumen] = snd[:setting].volumen_get
! 47: end
! 48: rescue
! 49: puts "ConnectionError (#{snd[:host]}:#{snd[:port]}): " + $!
! 50: sleep 2
! 51: retry
! 52: end
1.1 as 53: end
54:
1.2 ! as 55: listen_on_itunes
1.1 as 56: end
57:
58:
59: #
60: # usage
61: #
62: def usage
1.2 ! as 63: puts "usage: #{$0} [--port|-p <port>, --volumen|-v <0-250>] <host1[:<port>]> [<host2[:<port>]> [<host3..]]"
1.1 as 64: exit 0
65: end
66:
67:
68: #
1.2 ! as 69: # Gibt ein Dialog in iTunes aus
! 70: #
! 71: def dialog text
! 72: osax(nil, 'iTunes').display_dialog text, {:buttons => 'OK'}
! 73: end
! 74:
! 75:
! 76: #
1.1 as 77: # iTunes "abhoehren"
1.2 ! as 78: # ( umgesetzt via pooling )
1.1 as 79: #
1.2 ! as 80: def listen_on_itunes
1.1 as 81: while true
82: sleep 1
83:
84: itunes = app('iTunes')
85: # wenn itunes nicht spielt machen wir auch nichts
86: next if itunes.player_state.get != :playing
87:
88: # aktuelle Track-ID die iTunes spielt
89: current_index = itunes.current_track.index.get
90:
91: # wenn es nicht mehr der Track zuvor ist,
92: # den neuen abspielen.
93: if current_index != @index
94: play_new_track itunes.current_track
95: @index = current_index
96: end
97: end
98: end
99:
100:
101: #
102: # Track abspielen
103: #
104: def play_new_track track
105: file = track.location.get.to_s
106:
107: # Der Soundchip vertraegt nur MP3-Streams.
108: # daher lassen wir, wenn es keine MP3 ist, alles wie es ist.
109: if ! /\.mp3$/i.match file
1.2 ! as 110: dialog "SND-Fehler: #{track.name.get} kann nicht abgespielt werden da es keine MP3-Datei ist."
1.1 as 111: puts "error => #{track.name.get} ist keine MP3-Datei"
112: return false
113: end
1.2 ! as 114:
1.1 as 115: puts "play => #{track.name.get}"
1.2 ! as 116:
! 117: # alle Threads durchgehen und wenn einer noch laeuft
! 118: # volumen runterpegeln und beenden
! 119: @threads.each do |thread|
! 120: snd = thread[:snd]
! 121: Thread.new { snd[:setting].volumen_fadeto 150 }
! 122: Thread.kill thread
! 123: end
! 124:
! 125: # alle sockets durchgehen, volumen hochdrehen und neue Daten
! 126: # drauf schicken das ganze jeweils in einem eigenen Thread um
! 127: # das ganze zu paralelisieren und weiter iTunes abzuhoeren zu koennen.
! 128: @snds.each do |snd|
! 129: thread = Thread.new do
! 130: File.open(file, 'r') do |fh|
! 131: begin
! 132: Thread.new do
! 133: sleep 4 # mit der wartezeit tricksen wir den Cach aus
! 134: snd[:setting].volumen_fadeto snd[:volumen]
! 135: end
! 136: snd[:socket].puts fh.read
! 137: rescue
! 138: puts "SndError: " + $!
! 139: sleep 1
! 140: retry
! 141: end
1.1 as 142: end
143: end
1.2 ! as 144: thread[:snd] = snd
! 145: @threads << thread
1.1 as 146: end
147: end
148:
149:
1.2 ! as 150: # Parameter abfragen und parsen
1.1 as 151: begin
152: GetoptLong.new(
1.2 ! as 153: ['--help', '-h', GetoptLong::NO_ARGUMENT],
! 154: ['--port', '-p', GetoptLong::REQUIRED_ARGUMENT],
! 155: ['--volumen', '-v', GetoptLong::REQUIRED_ARGUMENT]
1.1 as 156: ).each do |arg, value|
157: @args[arg[2..-1].to_sym] = value
158: end
159: rescue
160: exit 1
161: end
162:
1.2 ! as 163: # wenn hilfe
! 164: usage if @args[:help]
! 165:
! 166: # Hosts aus den uebrigen Argumenten rausparsen
! 167: ARGV.each do |snd|
! 168: args = snd.split ':'
! 169: snd = {:host => args[0]}
! 170: if args.length < 2
! 171: snd[:port] = @args[:port]
! 172: else
! 173: snd[:port] = args[1]
! 174: end
! 175: @snds << snd
! 176: end
! 177:
! 178: # wenn kein Host angegeben ist
! 179: if @snds.length < 1
! 180: puts "Error: Missing host arguments (try --help)"
! 181: exit 1
! 182: end
1.1 as 183:
1.2 ! as 184: # los geht's
1.1 as 185: main