flexget.plugins.output_rss
Covered: 84 lines
Missed: 103 lines
Skipped 69 lines
Percent: 44 %
  1
import logging
  2
import datetime
  3
import os
  4
from flexget.plugin import register_plugin, PluginWarning
  5
from flexget.manager import Base
  6
from sqlalchemy import Column, Integer, String, DateTime
  8
log = logging.getLogger('make_rss')
 10
rss2gen = True
 11
try:
 12
    import PyRSS2Gen
 13
except:
 14
    rss2gen = False
 17
class RSSEntry(Base):
 19
    __tablename__ = 'make_rss'
 21
    id = Column(Integer, primary_key=True)
 22
    title = Column(String)
 23
    description = Column(String)
 24
    link = Column(String)
 25
    rsslink = Column(String)
 26
    file = Column(String)
 27
    published = Column(DateTime, default=datetime.datetime.utcnow())
 30
class OutputRSS(object):
 31
    """
 32
        Write RSS containing succeeded (downloaded) entries.
 34
        Example:
 36
        make_rss: ~/public_html/flexget.rss
 38
        You may write into same file in multiple feeds.
 40
        Example:
 42
        my-feed-A:
 43
          make_rss: ~/public_html/series.rss
 44
          .
 45
          .
 46
        my-feed-B:
 47
          make_rss: ~/public_html/series.rss
 48
          .
 49
          .
 51
        With this example file series.rss would contain succeeded
 52
        entries from both feeds.
 54
        Number of days / items:
 55
        -----------------------
 57
        By default output contains items from last 7 days. You can specify
 58
        different perioid, number of items or both. Value -1 means unlimited.
 60
        Example:
 62
        make_rss:
 63
          file: ~/public_html/series.rss
 64
          days: 2
 65
          items: 10
 67
        Generate RSS that will containg last two days and no more than 10 items.
 69
        Example 2:
 71
        make_rss:
 72
          file: ~/public_html/series.rss
 73
          days: -1
 74
          items: 50
 76
        Generate RSS that will contain last 50 items, regardless of dates.
 78
        RSS location link:
 80
        You can specify the url location of the rss file.
 82
        Example:
 84
        make_rss:
 85
          file: ~/public_html/series.rss
 86
          rsslink: http://my.server.net/series.rss
 88
        RSS link:
 89
        ---------
 91
        You can specify what field from entry is used as a link in generated rss feed.
 93
        Example:
 95
        make_rss:
 96
          file: ~/public_html/series.rss
 97
          link:
 98
            - imdb_url
100
        List should contain a list of fields in order of preference.
101
        Note that the url field is always used as last possible fallback
102
        even without explicitly adding it into the list.
104
        Default list: imdb_url, input_url, url
106
    """
108
    def __init__(self):
109
        self.written = {}
111
    def validator(self):
112
        """Validate given configuration"""
113
        from flexget import validator
114
        root = validator.factory()
115
        root.accept('text') # TODO: path / file
116
        rss = root.accept('dict')
117
        rss.accept('text', key='file', required=True)
118
        rss.accept('integer', key='days')
119
        rss.accept('integer', key='items')
120
        rss.accept('boolean', key='history')
121
        rss.accept('text', key='rsslink')
122
        rss.accept('text', key='encoding') # TODO: only valid choices
123
        links = rss.accept('list', key='link')
124
        links.accept('text')
125
        return root
127
    def on_feed_output(self, feed):
129
        pass
131
    def get_config(self, feed):
132
        config = feed.config['make_rss']
133
        if not isinstance(config, dict):
134
            config = {'file': config}
135
        config.setdefault('days', 7)
136
        config.setdefault('items', -1)
137
        config.setdefault('history', True)
138
        config.setdefault('encoding', 'iso-8859-1')
139
        config.setdefault('link', ['imdb_url', 'input_url'])
141
        config['link'].append('url')
142
        return config
144
    def on_feed_exit(self, feed):
145
        """Store finished / downloaded entries at exit"""
146
        if not rss2gen:
147
            raise PluginWarning('plugin make_rss requires PyRSS2Gen library.')
148
        config = self.get_config(feed)
151
        if feed.manager.options.test:
152
            return
155
        if not config['history']:
156
            log.debug('disabling history')
157
            for item in feed.session.query(RSSEntry).filter(RSSEntry.file == config['file']).all():
158
                feed.session.delete(item)
161
        for entry in feed.accepted:
162
            rss = RSSEntry()
163
            rss.title = entry['title']
164
            for field in config['link']:
165
                if field in entry:
166
                    rss.link = entry[field]
167
                    break
170
            description = ''
171
            if 'imdb_score' in entry:
172
                description += 'Score: %s / 10 | ' % entry['imdb_score']
173
            if 'imdb_votes' in entry:
174
                description += 'Votes: %s | ' % entry['imdb_votes']
175
            if 'imdb_genres' in entry:
176
                description += 'Genres: %s | ' % ', '.join(entry['imdb_genres'])
177
            if 'imdb_plot_outline' in entry:
178
                description += 'Description: %s' % entry['imdb_plot_outline']
179
            else:
180
                description += entry.get('description', '')
182
            rss.description = description
183
            rss.file = config['file']
186
            log.debug('Saving %s into rss database' % entry['title'])
187
            feed.session.add(rss)
189
    def on_process_end(self, feed):
190
        """Write RSS file at application terminate."""
191
        if not rss2gen:
192
            return
194
        if feed.manager.options.learn:
195
            return
197
        config = self.get_config(feed)
198
        if config['file'] in self.written:
199
            log.debugall('skipping already written file %s' % config['file'])
200
            return
203
        from flexget.manager import Session
204
        session = Session()
206
        db_items = session.query(RSSEntry).filter(RSSEntry.file == config['file']).\
207
            order_by(RSSEntry.published.desc()).all()
210
        rss_items = []
211
        for db_item in db_items:
212
            add = True
213
            if config['items'] != -1:
214
                if len(rss_items) > config['items']:
215
                    add = False
216
            if config['days'] != -1:
217
                if datetime.datetime.today() - datetime.timedelta(days=config['days']) > db_item.published:
218
                    add = False
219
            if add:
221
                gen = {}
222
                gen['title'] = db_item.title
223
                gen['description'] = db_item.description
224
                gen['link'] = db_item.link
225
                gen['pubDate'] = db_item.published
226
                log.debugall('Adding %s into rss %s' % (gen['title'], config['file']))
227
                rss_items.append(PyRSS2Gen.RSSItem(**gen))
228
            else:
230
                session.delete(db_item)
232
        session.commit()
233
        session.close()
236
        rss = PyRSS2Gen.RSS2(title='FlexGet',
237
                             link=config.get('rsslink', 'http://flexget.com'),
238
                             description='FlexGet generated RSS feed',
239
                             lastBuildDate=datetime.datetime.utcnow(),
240
                             items=rss_items)
242
        fn = os.path.expanduser(config['file'])
243
        try:
244
            rss.write_xml(open(fn, 'w'), encoding=config['encoding'])
245
        except LookupError:
246
            log.critical('Unknown encoding %s' % config['encoding'])
247
            return
248
        except IOError:
250
            log.critical('Unable to write %s' % fn)
251
            return
252
        self.written[config['file']] = True
255
register_plugin(OutputRSS, 'make_rss')