linyows/stalkerr

View on GitHub
lib/stalkerr/target/qiita.rb

Summary

Maintainability
C
7 hrs
Test Coverage
require 'time'
require 'net/irc'
require 'qiita'
require 'net/http'
require 'string-irc'
require 'stalkerr'

module Stalkerr::Target
  class Qiita
    include Net::IRC::Constants

    HOST = 'http://qiita.com'
    CHANNEL = '#qiita'
    INTERVAL = 60 * 10

    def initialize(username, password)
      @username = username
      @password = password
      @last_fetched_at = nil
      @marker = nil
    end

    def client
      @client ||= ::Qiita.new(url_name: @username, password: @password)
    end

    def stalking(&post)
      return if @last_fetched_at && Time.now.utc < @last_fetched_at + INTERVAL
      @last_fetched_at = Time.now.utc

      @post = post
      stocked_items = posted_items = []
      stocks = {}

      followings = client.user_following_users(@username).map { |u| u.url_name }.compact
      followings.each do |user|
        begin
          stocks[user] = client.user_stocks(user)
          stocked_items = stocked_items + stocks[user]
        rescue => e
          nil
        end
        begin
          posted_items = posted_items + client.user_items(user)
        rescue => e
          nil
        end
      end

      tags = client.user_following_tags(@username).map { |t| t.url_name }.compact
      new_items = tags.inject([]) { |arr, tag| arr + client.tag_items(encoder tag) }

      items = (stocked_items + posted_items + new_items).uniq
      items[0...30].sort_by(&:id).each do |obj|
        next if @marker && @marker >= obj.id
        type = 'new'
        nick = obj.user.url_name
        case
        when stocked_items.include?(obj)
          type = 'stock'
          stocks.each { |user, users_stocks|
            nick = user and break if users_stocks.include?(obj)
          }
        when posted_items.include?(obj)
          type = 'post'
        end
        parse type, [nick, obj]
        @marker = obj.id
      end
    end

    def parse(type, data)
      nick, obj = data
      header = status = title = link = ''
      body = []
      notice_body = false

      case type
      when 'stock'
        status = "stocked entry"
        color = :pink
      when 'post'
        status = "posted entry"
        color = :yellow
      when 'new'
        status = "new entry"
        color = :aqua
        notice_body = true
      end
      title = "#{obj.title}"
      body = split_for_body obj.raw_body
      link = obj.url

      header = StringIrc.new(status).send(color)
      header = "#{header} #{title}" unless title.eql? ''
      header = "#{header} - #{StringIrc.new(link).blue}"

      @post.call simple(nick), NOTICE, CHANNEL, header
      mode = notice_body ? NOTICE : PRIVMSG

      unless body.eql? ''
        if body.length > 20
          body_footer = body[-3..-1]
          body = body[0...15]
          body << '-----8<----- c u t -----8<-----'
          body = body + body_footer
        end

        body.each { |b|
          if b.length > 150
            b.scan(/.{1,150}/).each { |bb|
              @post.call simple(nick), mode, CHANNEL, bb
            }
            sleep 1
          else
            @post.call simple(nick), mode, CHANNEL, b
          end
          sleep 1
        }
      end
    end

    def split_for_body(string)
      return [] unless string.is_a?(String)
      string.split(/\r\n|\n/).map { |v| v unless v.eql? '' }.compact
    end

    def simple(string)
      string.gsub('@github', '')
    end

    def encoder(string)
      URI.encode(string).gsub('.', '%2e')
    end
  end
end