class Feed2Email::Feed

Public Instance Methods

old?() click to toggle source
# File lib/feed2email/feed.rb, line 31
def old?; last_processed_at end
process() click to toggle source
# File lib/feed2email/feed.rb, line 33
def process
  logger.info "Processing feed #{uri} ..."

  return false unless fetch_and_parse

  if processable?
    # Reset feed caching parameters unless all entries were processed. This
    # makes sure the feed will be fetched on next processing.
    unless process_entries
      self.last_modified = initial_value(:last_modified)
      self.etag = initial_value(:etag)
    end

    self.last_processed_at = Time.now

    save(changed: true)
  else
    logger.warn 'Feed does not have entries'
  end
end
to_s() click to toggle source
# File lib/feed2email/feed.rb, line 54
def to_s
  parts = [id.to_s.rjust(3)] # align right 1-999
  parts << "\e[31mDISABLED\e[0m" unless enabled
  parts << uri
  parts.join(' ')
end
toggle() click to toggle source
# File lib/feed2email/feed.rb, line 61
def toggle
  update(enabled: !enabled)
end
uncache() click to toggle source
# File lib/feed2email/feed.rb, line 65
def uncache
  !cached? || update(last_modified: nil, etag: nil)
end

Private Instance Methods

cached?() click to toggle source
# File lib/feed2email/feed.rb, line 71
def cached?
  last_modified || etag
end
decode_content(data, content_encoding) click to toggle source
# File lib/feed2email/feed.rb, line 75
def decode_content(data, content_encoding)
  case content_encoding
  when 'gzip'
    gz = Zlib::GzipReader.new(StringIO.new(data))
    xml = gz.read
    gz.close
  when 'deflate'
    xml = Zlib::Inflate.inflate(data)
  else
    xml = data
  end

  xml
end
fetch() click to toggle source
# File lib/feed2email/feed.rb, line 90
def fetch
  logger.debug 'Fetching feed...'

  begin
    open(uri, fetch_options) do |f|
      handle_redirection if uri != f.base_uri.to_s

      self.last_modified = f.meta['last-modified']
      self.etag = f.meta['etag']

      return decode_content(f.read, f.meta['content-encoding'])
    end
  rescue => e
    if e.is_a?(OpenURI::HTTPError) && e.message == '304 Not Modified'
      logger.info 'Feed not modified; skipping...'
    else
      logger.error 'Failed to fetch feed'
      log_exception(e)
    end

    return false
  end
end
fetch_and_parse() click to toggle source
# File lib/feed2email/feed.rb, line 114
def fetch_and_parse
  if xml_data = fetch
    @parsed_feed = parse(xml_data)
    @parsed_feed && @parsed_feed.respond_to?(:entries)
  end
end
fetch_options() click to toggle source
# File lib/feed2email/feed.rb, line 121
def fetch_options
  options = {
    'User-Agent' => "feed2email/#{VERSION}",
    'Accept-Encoding' => 'gzip, deflate',
  }

  unless permanently_redirected?
    if last_modified
      options['If-Modified-Since'] = last_modified
    end

    if etag
      options['If-None-Match'] = etag
    end
  end

  options
end
handle_redirection() click to toggle source
# File lib/feed2email/feed.rb, line 140
def handle_redirection
  checker = RedirectionChecker.new(uri)

  if checker.permanently_redirected?
    logger.warn 'Got permanently redirected!'
    self.uri = checker.location
    logger.warn "Updated feed location to #{checker.location}"
  end
end
log_exception(error) click to toggle source
# File lib/feed2email/feed.rb, line 150
def log_exception(error)
  logger.error "#{error.class}: #{error.message.strip}"
  error.backtrace.each {|line| logger.debug line }
end
parse(xml_data) click to toggle source
# File lib/feed2email/feed.rb, line 155
def parse(xml_data)
  logger.debug 'Parsing feed...'

  begin
    Feedzirra::Feed.parse(xml_data)
  rescue => e
    logger.error 'Failed to parse feed'
    log_exception(e)
    return false
  end
end
parsed_entries() click to toggle source
# File lib/feed2email/feed.rb, line 167
def parsed_entries
  parsed_feed.entries
end
parsed_feed() click to toggle source
# File lib/feed2email/feed.rb, line 171
def parsed_feed; @parsed_feed end
permanently_redirected?() click to toggle source
# File lib/feed2email/feed.rb, line 173
def permanently_redirected?
  column_changed?(:uri)
end
process_entries() click to toggle source
# File lib/feed2email/feed.rb, line 177
def process_entries
  total = processable_entries.size
  processed = true

  processable_entries.each_with_index do |parsed_entry, i|
    logger.info "Processing entry #{i + 1}/#{total} #{parsed_entry.url} ..."
    processed = false unless process_entry(parsed_entry)
  end

  processed
end
process_entry(parsed_entry) click to toggle source
# File lib/feed2email/feed.rb, line 189
def process_entry(parsed_entry)
  entry = Entry.new(feed_id: id, uri: parsed_entry.url)
  entry.data      = parsed_entry
  entry.feed_data = parsed_feed
  entry.feed_uri  = uri

  begin
    return entry.process
  rescue => e
    log_exception(e)
    return false
  end
end
processable?() click to toggle source
# File lib/feed2email/feed.rb, line 203
def processable?
  processable_entries.size > 0
end
processable_entries() click to toggle source
# File lib/feed2email/feed.rb, line 207
def processable_entries
  parsed_entries.first(config['max_entries'])
end