hummingbird-me/kitsu-server

View on GitHub
app/services/hulu_import/hulu_asset.rb

Summary

Maintainability
A
0 mins
Test Coverage
F
47%
module HuluImport
  class HuluAsset
    PAGE_SIZE = 2000
    EID_REGEX = /.*\?eid=([^&]*).*/

    # @param series [HuluSeries] the Series to reference when performing imports
    # @param params [Hash] a list of params to pass in the query string to Hulu
    # @yield [HuluAsset] the asset found on Hulu
    # @return [Enumerator] if no block is given, returns an Enumerator over the assets list
    def self.each(series: nil, **params)
      return to_enum(:each, series: series, **params) unless block_given?
      params = { fvod: 'available', limit: PAGE_SIZE, **params }
      offset = 0
      loop do
        page = HuluImport.get('/assets', offset: offset, **params)
        page.each { |asset| yield new(asset, series: series) }
        offset += PAGE_SIZE
        break if page.length < PAGE_SIZE
      end
    end

    # @param asset [Hash] the asset to wrap
    # @param series [HuluSeries] the series to reference when performing import
    def initialize(asset, series: nil)
      @asset = asset
      @series = series
    end

    # @return [HuluSeries] the series object
    def series
      @series ||= HuluSeries.new(@asset['series'])
    end
    delegate :media, to: :series
    delegate :network, to: :series

    # @return [Integer] the number of the episode
    def number
      @asset['number']
    end

    # @return [Integer] the season number of the episode
    def season_number
      @asset.dig('season', 'number')
    end

    # @return [String] the URL to the largest thumbnail Hulu has available
    def thumbnail
      @thumbnail ||= @asset['thumbnails'].max_by { |th| th['width'] * th['height'] }['url']
    end

    # @return [Date] the original airdate of the episode
    def airdate
      Date.iso8601(@asset['original_premiere_date'])
    end

    # @return [Integer] the length, in minutes, of the episode
    def length
      # They return milliseconds
      @asset['duration'] / 60_000
    end

    # @return [String] the title of the episode
    def title
      @asset['title'].sub(/\(sub\)/i, '').strip
    end

    # @return [String] the synopsis of the episode
    def synopsis
      @asset['description']
    end

    # @return [String] the Embed ID for the video
    def eid
      EID_REGEX.match(@asset.dig('embed', 'html5'))[1]
    end

    # @return [String] the ISO language code for the dub track in this video
    def dub_language
      @asset['video_language']
    end

    # @return [String] the ISO language code for the sub track in this video
    def sub_language
      'en' if @asset['title'].downcase.include?('(sub)') || @asset['keywords'].include?('Sub')
    end

    # @return [Episode] the episode in our database which represents this asset
    def episode!
      @episode ||= Episode.where(
        media: media,
        number: number
      ).first_or_create!(
        airdate: airdate,
        thumbnail: thumbnail,
        season_number: season_number,
        length: length,
        titles: { en_jp: title },
        description: { en: synopsis }
      )
    end

    # @return [Video] the video in our database which represents this asset
    def video!
      @video ||= Video.where(
        episode: episode!,
        streamer: HuluImport.streamer,
        url: @asset['link']
      ).first_or_create!(
        available_regions: %w[US],
        embed_data: { eid: eid, network: network },
        sub_lang: sub_language,
        dub_lang: dub_language
      )
    end
  end
end