# Oh noooo, we've got movie siiiiign! class MovieSignPlugin < Plugin def initialize super @registry[:moviesign] = { :interval => 1200, :movies => {}, :allowedUsers => ["garamir"], :channel => "#raspberryheaven" } unless @registry.has_key? :moviesign @movies = @registry[:moviesign][:movies] @interval = @registry[:moviesign][:interval] @allowedUsers = @registry[:moviesign][:allowedUsers] @channel = @registry[:moviesign][:channel] @currentMovie = nil @lastUpdateTime = 0 @currentPos = 0 @playing = false @countdown = false @reminder = nil @fuckoff = true end def printhelp(m, params) m.reply "WE'VE GOT MOVIE SIGN! @moviesign add for , @moviesign countdown to in , @moviesign start , @moviesign remove " end def saveNow @registry[:moviesign] = { :interval => @interval, :movies => @movies, :allowedUsers => @allowedUsers, :channel => @channel } end def allowAccess(user) return true if !@fuckoff return @allowedUsers.include?(user) end def formatTime(t) rt = t h = rt / 3600 rt -= (h * 3600) m = rt / 60 rt -= (m * 60) s = rt outstr = ( h > 0 ? (h < 10 ? "0" : "") << h.to_s << ":" : "" ) << (m < 10 ? "0" : "") << m.to_s << ":" << (s < 10 ? "0" : "") << s.to_s return outstr end def parseTime(t) return nil unless t result = t.scan(/^(([\d]{1,2}):)?([0-5]?[0-9]):(\d{1,2})$/) return nil unless result hour = result[0][1].to_i minute = result[0][2].to_i second = result[0][3].to_i hour = 0 if !hour minute = 0 if !minute second = 0 if !second return (hour * 3600) + (minute * 60) + second end def dumpInfo(m, params) m.reply "Current movie: #{@currentMovie}, length: #{@movies[@currentMovie]}, currently: #{@currentPos}, playing: #{@playing.to_s}, last updated: #{@lastUpdateTime.to_s}, interval: #{@interval}" end def haltPlayback @playing = false @countdown = false @bot.timer.remove(@reminder) @reminder = nil end # updateTime() # Whenever we check movie status, update @currentPos and @lastUpdateTime def updateTime return formatTime(@currentPos) unless @playing @currentPos = @currentPos + (Time.now - @lastUpdateTime).to_i if @currentPos >= @movies[@currentMovie] haltPlayback() return "00:00:00" end @lastUpdateTime = Time.now.to_i return formatTime(@currentPos) end def listMovies(m, params) if @movies.empty? printhelp(m, params) else m.reply "Queued movies:" @movies.each {|title, length| m.reply title + " (" + formatTime(length) + ")" } end end def playingString return "Now playing \"#{@currentMovie}\" (#{updateTime()} / #{formatTime(@movies[@currentMovie])}) #{@playing ? '' : ' [intermission]'}" end # getStatus() # current movie status for nosy viewers def getStatus (m, params) if @currentMovie.nil? || !(@movies.has_key? @currentMovie) listMovies(m, params) else m.reply playingString() end saveNow() end # newReminder() # Spawn a new bot timer to announce the movie time at regular intervals def newReminder(t) return unless @playing @bot.say @channel, playingString if (@currentPos + t >= @movies[@currentMovie]) @reminder = @bot.timer.add_once(@movies[@currentMovie] - @currentPos) { @bot.say @channel, "THE END" haltPlayback() @currentMovie = nil @currentPos = nil } else @reminder = @bot.timer.add_once(t) { newReminder(@interval) } end end # addMovie() # Add a movie to the list. def addMovie (m, params) unless allowAccess(m.sourcenick) m.reply "No." return end title = params[:movie].to_s length = params[:length].to_s @movies[title] = parseTime(length) m.reply "Added " + title + " (" + length + ")" end # removeMovie() # Delete a saved movie. def removeMovie (m, params) unless allowAccess(m.sourcenick) m.reply "No." return end movie = params[:movie].join(" ") if @movies.has_key? movie @movies.delete(movie) m.reply "Deleted " + movie else m.reply "Couldn't find " + movie end end def actuallyStartPlaying return unless @currentMovie @playing = true @lastUpdateTime = Time.now.to_i newReminder(@interval) end # startMovie() # Start a movie called :movie. # If it doesn't exist, add it with :length, then start it. def startMovie (m, params) # bee is a butt unless allowAccess(m.sourcenick) m.reply "no" return end # Make sure no other movies are playing if @playing m.reply "But I'm already playing " + @currentMovie + "!" return end # Check if we need to resume actuallyStartPlaying() if @currentMovie # Check whether the movie exists movie = params[:movie].join(" ") unless @movies.has_key? movie if params.has_key? :length addMovie(m, params) else m.reply "Movie not found. Please use 'add for <01:23:45>' to specify the length." return end end # Double-check in case we didn't add a new movie correctly return unless @movies.has_key? movie if (params.has_key? :time) startp = parseTime(params[:time]) if startp == nil || startp > @movies[movie] m.reply "Invalid start time. Please use hh:mm:ss." return end else startp = 0 end # set up timers for playing @currentMovie = movie startp = 0 unless startp > 0 @currentPos = startp actuallyStartPlaying() end # stopMovie() # Stop playing any current movie. def stopMovie (m, params) unless allowAccess(m.sourcenick) m.reply "No." return end if @playing m.reply "Intermission time! Stopped at " + updateTime() haltPlayback() elsif @reminder != nil stopCountdown(m, params) else m.reply "No movie playing." end end # clearMovies() # Clear the movie list, stop playing any current movies, # and save the empty list to the registry. def clearMovies @playing = nil @currentPos = nil @bot.timer.remove(@reminder) if @reminder @reminder = nil @movies = {} @lastUpdateTime = 0 saveNow() end def clearMoviesPublic(m, params) clearMovies() m.reply "Movies cleared." end def rechannel(m, params) @channel = params[:chan] m.reply "Changed channel to " + @channel end def reinterval (m, params) if params[:interval] == 0 m.reply "Notification interval = #{@interval/60} minutes" return end @interval = params[:interval].to_i * 60 m.reply "Changed interval to " + (@interval/60).to_s + " minutes." end def countdownLoop(t, starting = false) return if (!starting && @reminder.nil?) diff = t - Time.now.to_i if (diff < 1) # start the movie @currentPos = 0 actuallyStartPlaying() return end counter = 1 if (diff > 900) # don't announce movies more than 15 minutes ahead of time counter = 900 elsif (diff >= 60) @bot.say @channel, "Movie time! #{@currentMovie} starting in #{(diff + 1) / 60} minutes." counter = diff >= 600 ? diff - 300 : ( diff > 300 ? 300 : (diff > 60 ? 60 : diff - 10) ) else @bot.say @channel, "Starting in #{diff} seconds!" counter = diff > 10 ? diff - 10 : (diff > 5 ? diff - 5 : 1) end @reminder = @bot.timer.add_once(counter) { countdownLoop(t) } end def countdown(m, params) unless allowAccess(m.sourcenick) m.reply "no" return end # Make sure no other movies are playing if @playing m.reply "But I'm already playing " + @currentMovie + "!" return end # Check whether the movie exists movie = params[:movie].join(" ") unless @movies.has_key? movie m.reply "Movie not found. Please use 'add for <01:23:45>' to specify the length." return end @currentMovie = movie timer = parseTime(params[:time]) if timer.nil? m.reply "Syntax: @moviesign countdown to in <01:23:45>" return end countdownTo = Time.now.to_i + timer m.nickreply "Counting down to #{movie} in #{params[:time]}." countdownLoop(countdownTo, true) end def stopCountdown(m, params) unless allowAccess(m.sourcenick) m.reply "No." return end @reminder = nil @currentMovie = nil m.reply "Stopped." end def toggleLockdown(m, params) unless allowAccess(m.sourcenick) m.reply "No." return end @fuckoff = !@fuckoff m.reply "Lockdown value is now #{@fuckoff.to_s}" end def addUser(m, params) unless allowAccess(m.sourcenick) m.reply "No." return end @allowedUsers = @allowedUsers << params[:name] m.reply "Added user #{params[:name]}" end def rmUser(m, params) unless allowAccess(m.sourcenick) m.reply "No." return end @allowedUsers = @allowedUsers.delete(params[:name]) m.reply "Removed user #{params[:name]}" end def repelBoarders(m, params) @fuckoff = true @allowedUsers = [] end end plugin = MovieSignPlugin.new plugin.map "moviesign add *movie for :length", :action => 'addMovie', :requirements => { :length => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/ } # plugin.map "moviesign add *movie for :length at :time", :action => 'addMovie', :requirements => { :length => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/, :time => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/ } plugin.map "moviesign delete *movie", :action => 'removeMovie' plugin.map "moviesign remove *movie", :action => 'removeMovie' plugin.map "moviesign help", :action => 'help' plugin.map "moviesign clear", :action => 'clearMoviesPublic' plugin.map "moviesign stop", :action => 'stopMovie' plugin.map "moviesign countdown to *movie in :time", :action => 'countdown', :requirements => { :time => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/ } plugin.map "moviesign stop countdown", :action => 'stopCountdown' plugin.map "moviesign start", :action => 'startMovie' plugin.map "moviesign start *movie", :action => 'startMovie' plugin.map "moviesign start *movie for :length", :action => 'startMovie', :requirements => { :length => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/} plugin.map "moviesign start *movie at :time", :action => 'startMovie', :requirements => { :time => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/ } plugin.map "moviesign start *movie for :length at :time", :action => 'startMovie', :requirements => { :time => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/, :length => /^[\d]{1,2}:?[0-5]?[0-9]:\d{1,2}$/} plugin.map "moviesign fuckoff", :action => "toggleLockdown" plugin.map "moviesign lockdown", :action => "toggleLockdown" plugin.map "moviesign repelboarders", :action => "repelBoarders" plugin.map "moviesign adduser :name", :action => "addUser" plugin.map "moviesign rmuser :name", :action => "rmUser" plugin.map "moviesign", :action => "getStatus" plugin.map "moviesign channel :chan", :action => "rechannel" plugin.map "moviesign interval :interval", :action => "reinterval", :requirements => { :interval => /^\d+$/ }, :defaults => { :interval => 0 } plugin.map "moviedump", :action => "dumpInfo"