#!/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