summaryrefslogtreecommitdiffstats
path: root/feedgen/ext/media.py
blob: 74a5317e3cd000059e42489c93c53c1daddb5293 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
67
68
69
70
71
72
73
74
75
76
77
78
79
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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