hummingbird-me/kitsu-server

View on GitHub
app/models/list_import/my_anime_list.rb

Summary

Maintainability
A
1 hr
Test Coverage
F
36%
class ListImport
  class MyAnimeList < ListImport
    class ResponseError < StandardError; end
    class RateLimitedError < ResponseError; end

    MAL_HOST = 'https://myanimelist.net'.freeze

    # Only accept usernames, not XML exports
    validates :input_text, presence: true
    validates :input_file_data, absence: true
    validate :ensure_list_is_public, on: :create

    def count
      data.length
    end

    def ensure_list_is_public
      %w[anime manga].each do |kind|
        request = HTTP.get("#{MAL_HOST}/#{kind}list/#{input_text}")
        case request.status
        when 403
          errors.add(:input_text,
            "Your MyAnimeList #{kind} list must be public to import")
        when 404
          errors.add(:input_text, 'MyAnimeList user not found')
        end
      end
    end

    def each
      data.each do |row|
        row = Row.new(row, date_format)
        yield row.media, row.data
      end
    end

    private

    def date_format
      return @date_format if @date_format
      # if any dates have values higher than 12, assume the date format
      data.each do |row|
        row.fetch_values('start_date_string', 'finish_date_string').each do |date|
          next unless date.present?
          place1, place2 = date.split('-').map(&:to_i)
          return @date_format = '%d-%m-%y' if place1 > 12
          return @date_format = '%m-%d-%y' if place2 > 12
        end
      end
      nil
    end

    def data
      @data ||= %w[animelist mangalist].map { |l| list(l) }.reduce(&:+)
    end

    def list(list)
      loop.with_index.reduce([]) do |data, (_, index)|
        begin
          page = get(list, index)
        rescue RateLimitedError
          sleep 10
          redo
        end
        break data if page.blank?
        sleep 2
        data + page
      end
    end

    def get(list, page)
      res = HTTP.get(build_url(list, page))
      raise RateLimitedError.new(res.status_message) if res.status == 429
      raise ResponseError.new(res.status_message) unless res.status.success?
      JSON.parse(res.body)
    end

    def build_url(list, page)
      offset = page * 300
      "#{MAL_HOST}/#{list}/#{input_text}/load.json?offset=#{offset}&status=7"
    end
  end
end