diff options
Diffstat (limited to 'feedgen/ext/media.py')
-rw-r--r-- | feedgen/ext/media.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/feedgen/ext/media.py b/feedgen/ext/media.py new file mode 100644 index 0000000..74a5317 --- /dev/null +++ b/feedgen/ext/media.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +''' + feedgen.ext.media + ~~~~~~~~~~~~~~~~~ + + Extends the feedgen to produce media tags. + + :copyright: 2013-2017, Lars Kiesow <lkiesow@uos.de> + + :license: FreeBSD and LGPL, see license.* for more details. +''' + +from feedgen.ext.base import BaseEntryExtension, BaseExtension +from feedgen.util import ensure_format, xml_elem + +MEDIA_NS = 'http://search.yahoo.com/mrss/' + + +class MediaExtension(BaseExtension): + '''FeedGenerator extension for torrent feeds. + ''' + + def extend_ns(self): + return {'media': MEDIA_NS} + + +class MediaEntryExtension(BaseEntryExtension): + '''FeedEntry extension for media tags. + ''' + + def __init__(self): + self.__media_content = [] + self.__media_thumbnail = [] + + def extend_atom(self, entry): + '''Add additional fields to an RSS item. + + :param feed: The RSS item XML element to use. + ''' + + groups = {None: entry} + for media_content in self.__media_content: + # Define current media:group + group = groups.get(media_content.get('group')) + if group is None: + group = xml_elem('{%s}group' % MEDIA_NS, entry) + groups[media_content.get('group')] = group + # Add content + content = xml_elem('{%s}content' % MEDIA_NS, group) + for attr in ('url', 'fileSize', 'type', 'medium', 'isDefault', + 'expression', 'bitrate', 'framerate', 'samplingrate', + 'channels', 'duration', 'height', 'width', 'lang'): + if media_content.get(attr): + content.set(attr, media_content[attr]) + + for media_thumbnail in self.__media_thumbnail: + # Define current media:group + group = groups.get(media_thumbnail.get('group')) + if group is None: + group = xml_elem('{%s}group' % MEDIA_NS, entry) + groups[media_thumbnail.get('group')] = group + # Add thumbnails + thumbnail = xml_elem('{%s}thumbnail' % MEDIA_NS, group) + for attr in ('url', 'height', 'width', 'time'): + if media_thumbnail.get(attr): + thumbnail.set(attr, media_thumbnail[attr]) + + return entry + + def extend_rss(self, item): + return self.extend_atom(item) + + def content(self, content=None, replace=False, group='default', **kwargs): + '''Get or set media:content data. + + This method can be called with: + - the fields of a media:content as keyword arguments + - the fields of a media:content as a dictionary + - a list of dictionaries containing the media:content fields + + <media:content> is a sub-element of either <item> or <media:group>. + Media objects that are not the same content should not be included in + the same <media:group> element. The sequence of these items implies + the order of presentation. While many of the attributes appear to be + audio/video specific, this element can be used to publish any type + of media. It contains 14 attributes, most of which are optional. + + media:content has the following fields: + - *url* should specify the direct URL to the media object. + - *fileSize* number of bytes of the media object. + - *type* standard MIME type of the object. + - *medium* type of object (image | audio | video | document | + executable). + - *isDefault* determines if this is the default object. + - *expression* determines if the object is a sample or the full version + of the object, or even if it is a continuous stream (sample | full | + nonstop). + - *bitrate* kilobits per second rate of media. + - *framerate* number of frames per second for the media object. + - *samplingrate* number of samples per second taken to create the media + object. It is expressed in thousands of samples per second (kHz). + - *channels* number of audio channels in the media object. + - *duration* number of seconds the media object plays. + - *height* height of the media object. + - *width* width of the media object. + - *lang* is the primary language encapsulated in the media object. + + :param content: Dictionary or list of dictionaries with content data. + :param replace: Add or replace old data. + :param group: Media group to put this content in. + + :returns: The media content tag. + ''' + # Handle kwargs + if content is None and kwargs: + content = kwargs + # Handle new data + if content is not None: + # Reset data if we want to replace them + if replace or self.__media_content is None: + self.__media_content = [] + # Ensure list + if not isinstance(content, list): + content = [content] + # define media group + for c in content: + c['group'] = c.get('group', group) + self.__media_content += ensure_format( + content, + set(['url', 'fileSize', 'type', 'medium', 'isDefault', + 'expression', 'bitrate', 'framerate', 'samplingrate', + 'channels', 'duration', 'height', 'width', 'lang', + 'group']), + set(['url', 'group'])) + return self.__media_content + + def thumbnail(self, thumbnail=None, replace=False, group='default', + **kwargs): + '''Get or set media:thumbnail data. + + This method can be called with: + - the fields of a media:content as keyword arguments + - the fields of a media:content as a dictionary + - a list of dictionaries containing the media:content fields + + Allows particular images to be used as representative images for + the media object. If multiple thumbnails are included, and time + coding is not at play, it is assumed that the images are in order + of importance. It has one required attribute and three optional + attributes. + + media:thumbnail has the following fields: + - *url* should specify the direct URL to the media object. + - *height* height of the media object. + - *width* width of the media object. + - *time* specifies the time offset in relation to the media object. + + :param thumbnail: Dictionary or list of dictionaries with thumbnail + data. + :param replace: Add or replace old data. + :param group: Media group to put this content in. + + :returns: The media thumbnail tag. + ''' + # Handle kwargs + if thumbnail is None and kwargs: + thumbnail = kwargs + # Handle new data + if thumbnail is not None: + # Reset data if we want to replace them + if replace or self.__media_thumbnail is None: + self.__media_thumbnail = [] + # Ensure list + if not isinstance(thumbnail, list): + thumbnail = [thumbnail] + # Define media group + for t in thumbnail: + t['group'] = t.get('group', group) + self.__media_thumbnail += ensure_format( + thumbnail, + set(['url', 'height', 'width', 'time', 'group']), + set(['url', 'group'])) + return self.__media_thumbnail |