Class: Dropcaster::Channel

Inherits:
Object
  • Object
show all
Includes:
ERB::Util
Defined in:
lib/dropcaster/channel.rb

Overview

Represents a podcast feed in the RSS 2.0 format

Constant Summary collapse

STORAGE_UNITS =
%w(Byte KB MB GB TB)
MAX_KEYWORD_COUNT =
12

Instance Method Summary collapse

Constructor Details

#initialize(sources, attributes) ⇒ Channel

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)



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/dropcaster/channel.rb', line 24

def initialize(sources, attributes)
  # Assert mandatory attributes
  [: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 = Array.new

  # 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?:/
    Dropcaster.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?
    Dropcaster.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), 0, "%<>")
  rescue Errno::ENOENT => e
    raise TemplateNotFoundError.new(e.message)
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args) ⇒ Object

delegate all unknown methods to @attributes



143
144
145
146
147
148
149
150
# File 'lib/dropcaster/channel.rb', line 143

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

Instance Method Details

#humanize_size(number) ⇒ Object

Fixed version of gist.github.com/260184



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/dropcaster/channel.rb', line 122

def humanize_size(number)
  return nil if number.nil?

  storage_units_format = '%n %u'

  if number.to_i < 1024
    unit = number > 1 ? 'Bytes' : 'Byte'
    return storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
  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]
    return storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
  end
end

#humanize_time(secs) ⇒ Object



112
113
114
115
116
117
118
119
# File 'lib/dropcaster/channel.rb', line 112

def humanize_time(secs)
  [[60, :s], [60, :m], [24, :h], [1000, :d]].map{ |count, name|
    if secs > 0
      secs, n = secs.divmod(count)
      "#{n.to_i}#{name}"
    end
  }.compact.reverse.join(' ')
end

#itemsObject

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



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/dropcaster/channel.rb', line 80

def items
  all_items = Array.new
  @source_files.each{|src|

    item = Item.new(src)

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

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

    if item.image_url.blank?
      Dropcaster.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) + URI.encode(item.file_name))

    # 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

#to_rssObject

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.



73
74
75
# File 'lib/dropcaster/channel.rb', line 73

def to_rss
  @erb_template.result(binding)
end