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