4
from sqlalchemy import Column, Integer, String, DateTime
5
from flexget import schema
6
from flexget.plugin import register_plugin, PluginWarning
7
from flexget.utils.sqlalchemy_utils import table_columns, table_add_column
9
log = logging.getLogger('make_rss')
10
Base = schema.versioned_base('make_rss', 0)
19
@schema.upgrade('make_rss')
20
def upgrade(ver, session):
22
columns = table_columns('make_rss', session)
23
if not 'rsslink' in columns:
24
log.info('Adding rsslink column to table make_rss.')
25
table_add_column('make_rss', 'rsslink', String, session)
32
__tablename__ = 'make_rss'
34
id = Column(Integer, primary_key=True)
35
title = Column(String)
36
description = Column(String)
38
rsslink = Column(String)
40
published = Column(DateTime, default=datetime.datetime.utcnow())
43
class OutputRSS(object):
45
Write RSS containing succeeded (downloaded) entries.
49
make_rss: ~/public_html/flexget.rss
51
You may write into same file in multiple feeds.
56
make_rss: ~/public_html/series.rss
60
make_rss: ~/public_html/series.rss
64
With this example file series.rss would contain succeeded
65
entries from both feeds.
67
**Number of days / items**
69
By default output contains items from last 7 days. You can specify
70
different perioid, number of items or both. Value -1 means unlimited.
75
file: ~/public_html/series.rss
79
Generate RSS that will containg last two days and no more than 10 items.
84
file: ~/public_html/series.rss
88
Generate RSS that will contain last 50 items, regardless of dates.
92
You can specify the url location of the rss file.
97
file: ~/public_html/series.rss
98
rsslink: http://my.server.net/series.rss
102
You can specify what field from entry is used as a link in generated rss feed.
107
file: ~/public_html/series.rss
111
List should contain a list of fields in order of preference.
112
Note that the url field is always used as last possible fallback
113
even without explicitly adding it into the list.
115
Default list: imdb_url, input_url, url
122
"""Validate given configuration"""
123
from flexget import validator
124
root = validator.factory()
125
root.accept('text') # TODO: path / file
126
rss = root.accept('dict')
127
rss.accept('text', key='file', required=True)
128
rss.accept('integer', key='days')
129
rss.accept('integer', key='items')
130
rss.accept('boolean', key='history')
131
rss.accept('text', key='rsslink')
132
rss.accept('text', key='encoding') # TODO: only valid choices
133
links = rss.accept('list', key='link')
137
def on_feed_output(self, feed):
138
# makes this plugin count as output (stops warnings about missing outputs)
141
def get_config(self, feed):
142
config = feed.config['make_rss']
143
if not isinstance(config, dict):
144
config = {'file': config}
145
config.setdefault('days', 7)
146
config.setdefault('items', -1)
147
config.setdefault('history', True)
148
config.setdefault('encoding', 'iso-8859-1')
149
config.setdefault('link', ['imdb_url', 'input_url'])
150
# add url as last resort
151
config['link'].append('url')
154
def on_feed_exit(self, feed):
155
"""Store finished / downloaded entries at exit"""
157
raise PluginWarning('plugin make_rss requires PyRSS2Gen library.')
158
config = self.get_config(feed)
160
# don't run with --test
161
if feed.manager.options.test:
164
# when history is disabled, remove everything from backlog on every run (a bit hackish, rarely usefull)
165
if not config['history']:
166
log.debug('disabling history')
167
for item in feed.session.query(RSSEntry).filter(RSSEntry.file == config['file']).all():
168
feed.session.delete(item)
170
# save entries into db for RSS generation
171
for entry in feed.accepted:
173
rss.title = entry['title']
174
for field in config['link']:
176
rss.link = entry[field]
179
# TODO: just a quick hack, implement better :)
181
if 'imdb_score' in entry:
182
description += 'Score: %s / 10 | ' % entry['imdb_score']
183
if 'imdb_votes' in entry:
184
description += 'Votes: %s | ' % entry['imdb_votes']
185
if 'imdb_genres' in entry:
186
description += 'Genres: %s | ' % ', '.join(entry['imdb_genres'])
187
if 'imdb_plot_outline' in entry:
188
description += 'Description: %s' % entry['imdb_plot_outline']
190
description += entry.get('description', '')
192
rss.description = description
193
rss.file = config['file']
195
# TODO: check if this exists and suggest disabling history if it does since it shouldn't happen normally ...
196
log.debug('Saving %s into rss database' % entry['title'])
197
feed.session.add(rss)
199
def on_process_end(self, feed):
200
"""Write RSS file at application terminate."""
203
# don't generate rss when learning
204
if feed.manager.options.learn:
207
config = self.get_config(feed)
208
if config['file'] in self.written:
209
log.debugall('skipping already written file %s' % config['file'])
212
# in terminate phase there is no open session in feed, so open new one
213
from flexget.manager import Session
216
db_items = session.query(RSSEntry).filter(RSSEntry.file == config['file']).\
217
order_by(RSSEntry.published.desc()).all()
221
for db_item in db_items:
223
if config['items'] != -1:
224
if len(rss_items) > config['items']:
226
if config['days'] != -1:
227
if datetime.datetime.today() - datetime.timedelta(days=config['days']) > db_item.published:
230
# add into generated feed
232
gen['title'] = db_item.title
233
gen['description'] = db_item.description
234
gen['link'] = db_item.link
235
gen['pubDate'] = db_item.published
236
log.debugall('Adding %s into rss %s' % (gen['title'], config['file']))
237
rss_items.append(PyRSS2Gen.RSSItem(**gen))
240
session.delete(db_item)
246
rss = PyRSS2Gen.RSS2(title='FlexGet',
247
link=config.get('rsslink', 'http://flexget.com'),
248
description='FlexGet generated RSS feed',
249
lastBuildDate=datetime.datetime.utcnow(),
252
fn = os.path.expanduser(config['file'])
254
rss.write_xml(open(fn, 'w'), encoding=config['encoding'])
256
log.critical('Unknown encoding %s' % config['encoding'])
259
# TODO: plugins cannot raise PluginWarnings in terminate event ..
260
log.critical('Unable to write %s' % fn)
262
self.written[config['file']] = True
265
register_plugin(OutputRSS, 'make_rss')