Newer
Older
Intro_Quiz_2018 / intro.rb
#!/usr/bin/ruby
# -*- coding: utf-8 -*-
require 'em-websocket'
require 'set'
require 'open3'
require 'json'
mydir=File.dirname($0)
require(File.expand_path(ENV['IQIF'] || 'mpg123.rb', mydir))
PORT = 4946

class MP3Player
  def initialize(file)
    mklist(file)
    @index = 0
  end
  
  
  def mklist(file)
    @music_list = []
    IO.foreach(file) do |line|
      if /(.*\.(mp3|ogg))(\s+(.*))?/ =~ line.strip
        f = $1
        test(?s, f) and @music_list << [f, $3 || File.basename(f)]
      end
    end
  end
  
  
  attr_accessor :music_list
  def play(frame = @frame)
    music = @music_list[@index][0]
    prog = (/ogg$/ =~ music ? "ogg123" : "mpg123")
    @frame = frame || "0"
    cmd = [prog, "-v", "-k", @frame, music]
    
    @mp3thread = Thread.new {
      Open3.popen3(*cmd) do |i, o, e, thr|
        @pid = thr.pid
        eline = ""
        while chr = e.read(1)
          eline << chr
          next unless /[\r\n]/ =~ chr
          
          if /(Frame#|Time:)\s+([0-9:.]+)/ =~ eline
            @frame = $2
            ## STDERR.printf("Frame = #%d\r", @frame)
            eline = ""
          end
          
        end
      end
    }
    return @music_list[@index][1]
  end
  
  
  def stop(chime = nil)
    if @pid
      Process.kill(:INT, @pid) rescue nil
      Thread.new {
        @mp3thread.join
        system("mpg123 -q btn.mp3 >/dev/null") if chime
      }
      @pid = nil
    end
  end
  
  def nextMusic(arg = 1)
    stop
    @index+=arg
    if @index >= @music_list.length
      return nil
    end
    @frame = "0"
    return sprintf("%02d : %s", @index, @music_list[@index][1])
  end
  
  def prevMusic(arg = -1)
    nextMusic(arg)
  end
  
  def setMusic(n)
    @index = [[0, n].max, @music_list.length-1].min
    return nextMusic(0)
  end
end

mp3play = MP3Player.new(ARGV[0])




clients = Set.new
ans = {}
cli2tm = {}
print("No clients yet...")
EM.run do
  iqif = IQif.new(mp3play.music_list)
  EM::WebSocket.start({:host => "0.0.0.0", :port => PORT}) do |ws_conn|
    ws_conn.onopen do
      clients << ws_conn
      # p "hello"+ws_conn.inspect
      iqif.printf("%d guest(s)\n", clients.length)
    end
    ws_conn.onmessage do |message|
      warn = nil
      
      if message > ""
        if ans[message]
          ans[message] << ws_conn	
        else	                	# First time
          ans[message] = []
          ans[message] << ws_conn
          cli2tm[ws_conn] = message	# Remenber team name
          mp3play.stop(true)
        end
        
        announce = ans.keys.join(", ")
        clients.each do |conn|
          tm = cli2tm[conn]
          
          
          warn = if tm && ans[tm] && ans[tm].length > 1
                   # printf("tm=%d\n",  tm)
                   warn ="もう押しています"
                 end
          
          rank = (ans.keys.index(tm) || -1) + 1
          answer = {"info" => announce, "warn" => warn, "rank" => rank}
          conn.send(JSON.pretty_generate(answer))
        end
      else
        ws_conn.send(JSON.pretty_generate({"warn"=>"Team名を入れてね!"}))
      end
    end
    
    ws_conn.onclose do
      clients.delete(ws_conn)
      # p "bye"+ws_conn.inspect
      iqif.printf("%d GUEST(s)\n", clients.length)
    end
    
    def broadcast(clients, mesg)
      clients.each {|c|
        c.send(JSON.generate({"info" => mesg}))
      }
    end
    
    
    cast_nonpush_clients = lambda {|mesg|	# Send to non-pushing clients
      s = JSON.generate({"info" => mesg})
      clients.each {|c|
        team = cli2tm[c]
        c.send(s) if !ans.has_key?(team)
      }
    }
    
    EM::defer do
      puts "..captured!"
      while line = iqif.action
        case line.chomp
        when /p/
          cast_nonpush_clients.call("GO!")
          # STDERR.printf("START: %s", mp3play.play)
          iqif.printf("START: %s", mp3play.play)
        when /s/
          mp3play.stop
        when /[nr0-9]/
          iqif.puts("Reset clients")
          s = JSON.pretty_generate({"info" => "Ready..."})
          broadcast(clients, "Ready...")
          ans = {}; cli2tm = {};
          if /n/ =~ line
            iqif.printf("次: %s\n", mp3play.nextMusic)
          elsif /^\d+/ =~ line
            iqif.printf("%d: %s\n", line.to_i, mp3play.setMusic(line.to_i))
          end 
        end
      end
      exit
    end
  end
end