python-feedgen/feedgenerator/podcast.py

198 lines
6.6 KiB
Python
Raw Normal View History

#!/bin/env python
# -*- coding: utf-8 -*-
'''
feedgenerator.podcast
~~~~~~~~~~~~~~~~~~~~~
Extends the feedgenerator to produce podcasts.
:copyright: 2013, Lars Kiesow <lkiesow@uos.de>
:license: FreeBSD and LGPL, see LICENSE for more details.
'''
from lxml import etree
from datetime import datetime
import dateutil.parser
import dateutil.tz
from feedgenerator.feed import FeedGenerator
from feedgenerator.util import ensure_format
class PodcastGenerator(FeedGenerator):
## ITunes tags
# http://www.apple.com/itunes/podcasts/specs.html#rss
__itunes_author = None
__itunes_block = None
__itunes_category = None
def __create_podcast(self):
'''Create an RSS feed xml structure containing all previously set fields.
:returns: Tuple containing the feed root element and the element tree.
'''
rss_feed, _ = super(PodcastGenerator,self)._create_rss()
# Replace the root element to add the itunes namespace
ITUNES_NS = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
feed = etree.Element('rss', version='2.0',
nsmap={
'atom' :'http://www.w3.org/2005/Atom',
'itunes':ITUNES_NS} )
feed[:] = rss_feed[:]
channel = feed[0]
doc = etree.ElementTree(feed)
if self.__itunes_author:
author = etree.SubElement(channel, '{%s}author' % ITUNES_NS)
author.text = self.__itunes_author
if not self.__itunes_block is None:
block = etree.SubElement(channel, '{%s}block' % ITUNES_NS)
block.text = 'yes' if self.__itunes_block else 'no'
if self.__itunes_category:
category = etree.SubElement(channel, '{%s}category' % ITUNES_NS)
category.attrib['text'] = self.__itunes_category['cat']
if self.__itunes_category.get('sub'):
subcategory = etree.SubElement(category, '{%s}category' % ITUNES_NS)
subcategory.attrib['text'] = self.__itunes_category['sub']
return feed, doc
def podcast_str(self, pretty=False):
'''Generates an RSS feed and returns the feed XML as string.
:param pretty: If the feed should be split into multiple lines and
properly indented.
:returns: String representation of the RSS feed.
'''
feed, doc = self.__create_podcast()
return etree.tostring(feed, pretty_print=pretty)
def podcast_file(self, filename):
'''Generates an RSS feed and write the resulting XML to a file.
:param filename: Name of file to write.
'''
feed, doc = self.__create_podcast()
with open(filename, 'w') as f:
doc.write(f)
def itunes_author(self, itunes_author=None):
'''Get or set the itunes:author. The content of this tag is shown in the
Artist column in iTunes. If the tag is not present, iTunes uses the
contents of the <author> tag. If <itunes:author> is not present at the
feed level, iTunes will use the contents of <managingEditor>.
:param itunes_author: The author of the podcast.
:returns: The author of the podcast.
'''
if not itunes_author is None:
self.__itunes_author = itunes_author
return self.__itunes_author
def itunes_block(self, itunes_block=None):
'''Get or set the ITunes block attribute. Use this to prevent the entire
podcast from appearing in the iTunes podcast directory.
:param itunes_block: Block the podcast.
:returns: If the podcast is blocked.
'''
if not itunes_block is None:
self.__itunes_block = itunes_block
return self.__itunes_block
def itunes_category(self, itunes_category=None, itunes_subcategory=None):
'''Get or set the ITunes category which appears in the category column
and in iTunes Store Browser.
The (sub-)category has to be one from the values defined at
http://www.apple.com/itunes/podcasts/specs.html#categories
:param itunes_category: Category of the podcast.
:param itunes_subcategory: Subcategory of the podcast.
:returns: Category data of the podcast.
'''
if not itunes_category is None:
if not itunes_category in self._itunes_categories.keys():
raise ValueError('Invalid category')
cat = {'cat':itunes_category}
if not itunes_subcategory is None:
if not itunes_subcategory in self._itunes_categories[itunes_category]:
raise ValueError('Invalid subcategory')
cat['sub'] = itunes_subcategory
self.__itunes_category = cat
return self.__itunes_category
def itunes_image(self, itunes_image=None):
'''Get or set the image for the podcast. This tag specifies the artwork
for your podcast. Put the URL to the image in the href attribute. iTunes
prefers square .jpg images that are at least 1400x1400 pixels, which is
different from what is specified for the standard RSS image tag. In order
for a podcast to be eligible for an iTunes Store feature, the
accompanying image must be at least 1400x1400 pixels.
iTunes supports images in JPEG and PNG formats with an RGB color space
(CMYK is not supported). The URL must end in ".jpg" or ".png". If the
<itunes:image> tag is not present, iTunes will use the contents of the
RSS image tag.
If you change your podcasts image, also change the files name. iTunes
may not change the image if it checks your feed and the image URL is the
same. The server hosting your cover art image must allow HTTP head
requests for iTS to be able to automatically update your cover art.
:param itunes_image: Image of the podcast.
:returns: Image of the podcast.
'''
if not itunes_image is None:
if not ( itunes_image.endswith('.jpg') or itunes_image.endswith('.png') ):
ValueError('Image file must be png or jpg')
self.__itunes_image = itunes_image
return self.__itunes_image
_itunes_categories = {
'Arts': [ 'Design', 'Fashion & Beauty', 'Food', 'Literature',
'Performing Arts', 'Visual Arts' ],
'Business' : [ 'Business News', 'Careers', 'Investing',
'Management & Marketing', 'Shopping' ],
'Comedy' : [],
'Education' : [ 'Education', 'Education Technology',
'Higher Education', 'K-12', 'Language Courses', 'Training' ],
'Games & Hobbies' : [ 'Automotive', 'Aviation', 'Hobbies',
'Other Games', 'Video Games' ],
'Government & Organizations' : [ 'Local', 'National', 'Non-Profit',
'Regional' ],
'Health' : [ 'Alternative Health', 'Fitness & Nutrition', 'Self-Help',
'Sexuality' ],
'Kids & Family' : [],
'Music' : [],
'News & Politics' : [],
'Religion & Spirituality' : [ 'Buddhism', 'Christianity', 'Hinduism',
'Islam', 'Judaism', 'Other', 'Spirituality' ],
'Science & Medicine' : [ 'Medicine', 'Natural Sciences',
'Social Sciences' ],
'Society & Culture' : [ 'History', 'Personal Journals', 'Philosophy',
'Places & Travel' ],
'Sports & Recreation' : [ 'Amateur', 'College & High School',
'Outdoor', 'Professional' ],
'Technology' : [ 'Gadgets', 'Tech News', 'Podcasting',
'Software How-To' ],
'TV & Film' : []
}