class Dropcaster::Channel

Represents a podcast feed in the RSS 2.0 format

Constants

MAX_KEYWORD_COUNT
STORAGE_UNITS

Public Class Methods

new(sources, attributes) click to toggle source

Instantiate a new Channel object. sources must be present and can be a String or Array of Strings, pointing to a one or more directories or MP3 files.

attributes is a hash with all attributes for the channel. The following attributes are mandatory when a new channel is created:

  • :title - Title (name) of the podcast

  • :url - URL to the podcast

  • :description - Short description of the podcast (a few words)

# File lib/dropcaster/channel.rb, line 28
def initialize(sources, attributes)
  # Assert mandatory attributes
  %i[title url description].each { |attr|
    raise MissingAttributeError.new(attr) if attributes[attr].blank?
  }

  @attributes = attributes
  @attributes[:explicit] = yes_no_or_input(attributes[:explicit])
  @source_files = []

  # if (sources.respond_to?(:each)) # array
  if sources.is_a? Array
    sources.each do |src|
      add_files(src)
    end
  else
    # single file or directory
    add_files(sources)
  end

  # If not absolute, prepend the image URL with the channel's base to make an absolute URL
  unless @attributes[:image_url].blank? || @attributes[:image_url] =~ /^https?:/
    logger.info("Channel image URL '#{@attributes[:image_url]}' is relative, so we prepend it with the channel URL '#{@attributes[:url]}'")
    @attributes[:image_url] = (URI.parse(@attributes[:url]) + @attributes[:image_url]).to_s
  end

  # If enclosures_url is not given, take the channel URL as a base.
  if @attributes[:enclosures_url].blank?
    logger.info("No enclosure URL given, using the channel's enclosure URL")
    @attributes[:enclosures_url] = @attributes[:url]
  end

  # Warn if keyword count is larger than recommended
  assert_keyword_count(@attributes[:keywords])

  channel_template = @attributes[:channel_template] || File.join(File.dirname(__FILE__), '..', '..', 'templates', 'channel.rss.erb')

  begin
    @erb_template = ERB.new(IO.read(channel_template))
  rescue Errno::ENOENT => e
    raise TemplateNotFoundError.new(e.message)
  end
end

Public Instance Methods

humanize_size(number) click to toggle source

Fixed version of gist.github.com/260184

# File lib/dropcaster/channel.rb, line 125
def humanize_size(number)
  return nil if number.nil?

  if number.to_i < 1024
    unit = number > 1 ? 'Bytes' : 'Byte'
  else
    max_exp  = STORAGE_UNITS.size - 1
    number   = Float(number)
    exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
    exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
    number  /= 1024**exponent
    unit = STORAGE_UNITS[exponent]
  end

  '%n %u'.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
end
humanize_time(secs) click to toggle source

from stackoverflow.com/questions/4136248

# File lib/dropcaster/channel.rb, line 115
def humanize_time(secs)
  [[60, :s], [60, :m], [24, :h], [1000, :d]].map { |count, name|
    if secs.positive?
      secs, n = secs.divmod(count)
      "#{n.to_i}#{name}"
    end
  }.compact.reverse.join(' ')
end
items() click to toggle source

Returns all items (episodes) of this channel, ordered by newest-first.

# File lib/dropcaster/channel.rb, line 84
def items
  all_items = []
  @source_files.each { |src|
    item = Item.new(src)

    logger.debug("Adding new item from file #{src}")

    # set author and image_url from channel if empty
    if item.tag.artist.blank?
      logger.info("#{src} has no artist, using the channel's author")
      item.tag.artist = @attributes[:author]
    end

    if item.image_url.blank?
      logger.info("#{src} has no image URL set, using the channel's image URL")
      item.image_url = @attributes[:image_url]
    end

    # construct absolute URL, based on the channel's enclosures_url attribute
    item.url = URI.parse(enclosures_url) + item.file_path.each_filename.map { |p| url_encode(p) }.join('/')

    # Warn if keyword count is larger than recommended
    assert_keyword_count(item.keywords)

    all_items << item
  }

  all_items.sort { |x, y| y.pub_date <=> x.pub_date }
end
method_missing(meth, *args) click to toggle source

Delegate all unknown methods to @attributes

rubocop:disable Style/MethodMissing

# File lib/dropcaster/channel.rb, line 146
def method_missing(meth, *args)
  m = meth.id2name
  if m =~ /=$/
    @attributes[m.chop.to_sym] = (args.length < 2 ? args[0] : args)
  else
    @attributes[m.to_sym]
  end
end
respond_to_missing?(meth, *) click to toggle source

rubocop:enable Style/MethodMissing

Calls superclass method
# File lib/dropcaster/channel.rb, line 156
def respond_to_missing?(meth, *)
  (meth.id2name =~ /=$/) || super
end
to_rss() click to toggle source

Returns this channel as an RSS representation. The actual rendering is done with the help of an ERB template. By default, it is expected as ../../templates/channel.rss.erb (relative) to channel.rb.

# File lib/dropcaster/channel.rb, line 77
def to_rss
  @erb_template.result(binding)
end

Private Instance Methods

add_files(src) click to toggle source
# File lib/dropcaster/channel.rb, line 162
def add_files(src)
  if File.directory?(src)
    @source_files.concat(Dir.glob(File.join(src, '*.mp3'), File::FNM_CASEFOLD))
  else
    @source_files << src
  end
end
assert_keyword_count(keywords) click to toggle source
# File lib/dropcaster/channel.rb, line 200
def assert_keyword_count(keywords)
  if keywords && MAX_KEYWORD_COUNT < keywords.size
    logger.info("The list of keywords has #{keywords.size} entries, which exceeds the recommended maximum of #{MAX_KEYWORD_COUNT}.")
  end
end
truncate(string, count=30) click to toggle source

snippets.dzone.com/posts/show/4578

# File lib/dropcaster/channel.rb, line 189
def truncate(string, count=30)
  if string.length >= count
    shortened = string[0, count]
    splitted = shortened.split(/\s/)
    words = splitted.length
    splitted[0, words - 1].join(' ') + '...'
  else
    string
  end
end
yes_no_or_input(flag) click to toggle source

Deal with Ruby's autoboxing of Yes, No, true, etc values in YAML

# File lib/dropcaster/channel.rb, line 173
def yes_no_or_input(flag)
  case flag
  when nil
    nil
  when true
    'Yes'
  when false
    'No'
  else
    flag
  end
end