# frozen_string_literal: false
# The prefix for the iTunes XML namespace.
# The URI of the iTunes specification.
ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
Rss.install_ns(ITUNES_PREFIX, ITUNES_URI)
def def_class_accessor(klass, name, type, *args)
normalized_name = name.gsub(/-/, "_")
full_name = "#{ITUNES_PREFIX}_#{normalized_name}"
klass_name = "ITunes#{Utils.to_class_name(normalized_name)}"
when :element, :attribute
klass::ELEMENTS << full_name
def_element_class_accessor(klass, name, full_name, klass_name, *args)
klass::ELEMENTS << full_name
def_elements_class_accessor(klass, name, full_name, klass_name, *args)
klass.install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
klass.install_text_element(normalized_name, ITUNES_URI, "?",
def def_element_class_accessor(klass, name, full_name, klass_name,
recommended_attribute_name=nil)
klass.install_have_child_element(name, ITUNES_PREFIX, "?", full_name)
def def_elements_class_accessor(klass, name, full_name, klass_name,
plural_name, recommended_attribute_name=nil)
full_plural_name = "#{ITUNES_PREFIX}_#{plural_name}"
klass.install_have_children_element(name, ITUNES_PREFIX, "*",
full_name, full_plural_name)
ELEMENT_INFOS = [["author"],
["explicit", :explicit_clean_other],
module ITunesChannelModel
def append_features(klass)
return if klass.instance_of?(Module)
ELEMENT_INFOS.each do |name, type, *additional_infos|
def_class_accessor(klass, name, type, *additional_infos)
["category", :elements, "categories", "text"],
["image", :attribute, "href"],
] + ITunesBaseModel::ELEMENT_INFOS
class ITunesCategory < Element
].each do |name, uri, required|
install_get_attribute(name, uri, required)
install_have_children_element("category", ITUNES_URI, "*",
"#{ITUNES_PREFIX}_category",
"#{ITUNES_PREFIX}_categories")
if Utils.element_initialize_arguments?(args)
tag_name_with_prefix(ITUNES_PREFIX)
def maker_target(categories)
if text or !itunes_categories.empty?
def setup_maker_attributes(category)
category.text = text if text
def setup_maker_elements(category)
itunes_categories.each do |sub_category|
sub_category.setup_maker(category)
class ITunesImage < Element
].each do |name, uri, required|
install_get_attribute(name, uri, required)
if Utils.element_initialize_arguments?(args)
tag_name_with_prefix(ITUNES_PREFIX)
target.itunes_image {|image| image}
def setup_maker_attributes(image)
class ITunesOwner < Element
install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
ITunesBaseModel::ELEMENT_INFOS << name
install_text_element(name, ITUNES_URI, nil, "#{ITUNES_PREFIX}_#{name}")
if Utils.element_initialize_arguments?(args)
self.itunes_name = args[0]
self.itunes_email = args[1]
tag_name_with_prefix(ITUNES_PREFIX)
def setup_maker_element(owner)
owner.itunes_name = itunes_name
owner.itunes_email = itunes_email
def append_features(klass)
return if klass.instance_of?(Module)
ELEMENT_INFOS.each do |name, type|
def_class_accessor(klass, name, type)
ELEMENT_INFOS = ITunesBaseModel::ELEMENT_INFOS +
[["duration", :element, "content"]]
class ITunesDuration < Element
def parse(duration, do_validate=true)
if do_validate and /\A(?:
"must be one of HH:MM:SS, H:MM:SS, MM:SS, M:SS, S+: " +
if duration.include?(':')
components = duration.split(':')
components[3..-1] = nil if components.size > 3
components.unshift("00") until components.size == 3
components.collect do |component|
seconds_to_components(duration.to_i)
def construct(hours, minutes, seconds)
components = [minutes, seconds]
if components.include?(nil)
components.unshift(hours) if hours and hours > 0
components.collect do |component|
def seconds_to_components(total_seconds)
hours = total_seconds / (60 * 60)
minutes = (total_seconds / 60) % 60
seconds = total_seconds % 60
[hours, minutes, seconds]
alias_method(:value, :content)
attr_reader :hour, :minute, :second
if Utils.element_initialize_arguments?(args)
args = args[0] if args.size == 1 and args[0].is_a?(Array)
"must be (do_validate, params), (content), " +
"(minute, second), ([minute, second]), " +
"(hour, minute, second) or ([hour, minute, second]): " +
@second, @minute, @hour = args.reverse
elsif value.is_a?(self.class)
self.content = value.content
@hour, @minute, @second = self.class.parse(value, @do_validate)
raise NotAvailableValueError.new(tag_name, value)
alias_method(:value=, :content=)
@hour = @do_validate ? Integer(hour) : hour.to_i
@minute = @do_validate ? Integer(minute) : minute.to_i
@second = @do_validate ? Integer(second) : second.to_i
tag_name_with_prefix(ITUNES_PREFIX)
@content = self.class.construct(hour, minute, second)
target.itunes_duration {|duration| duration}
def setup_maker_element(duration)
duration.content = @content
include ITunesChannelModel
class Item; include ITunesItemModel; end
ITunesChannelModel::ELEMENT_INFOS + ITunesItemModel::ELEMENT_INFOS
element_infos.each do |name, type|
when :element, :elements, :attribute
class_name = Utils.to_class_name(name)
BaseListener.install_class_name(ITUNES_URI, name, "ITunes#{class_name}")
accessor_base = "#{ITUNES_PREFIX}_#{name.gsub(/-/, '_')}"
BaseListener.install_get_text_element(ITUNES_URI, name, accessor_base)