Skip to content

Commit d67622f

Browse files
committed
optimize command filter
1 parent d2a746d commit d67622f

File tree

1 file changed

+59
-33
lines changed

1 file changed

+59
-33
lines changed

inoreader/main.py

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
import codecs
99
import argparse
1010
from datetime import datetime
11+
from collections import defaultdict
1112
from configparser import ConfigParser
1213

1314
import yaml
1415
from inoreader import InoreaderClient
15-
from inoreader.filter import Filter
16+
from inoreader.filter import get_filter
1617

1718

1819
APPID_ENV_NAME = 'INOREADER_APP_ID'
@@ -174,13 +175,7 @@ def fetch_unread(folder, tags, outfile, out_format):
174175

175176
def add_filter_parser(subparsers):
176177
parser = subparsers.add_parser('filter', help='Select articles and do something')
177-
parser.add_argument("-f", "--folder", required=True, help='Folder which articles belong to')
178178
parser.add_argument("-r", "--rules", required=True, help='YAML file with your rules')
179-
parser.add_argument("-a", "--action", default='read',
180-
choices=['read', 'like', 'tag', 'broadcast', 'star'],
181-
help='Action you want to perform, default: read')
182-
parser.add_argument("-t", "--tags",
183-
help="Tag(s) to be used when action is 'tag', seprate with comma")
184179

185180

186181
def apply_action(articles, client, action, tags):
@@ -190,7 +185,7 @@ def apply_action(articles, client, action, tags):
190185

191186
for article in articles:
192187
print("Add tags [{}] on article: {}".format(tags, article.title))
193-
elif action == 'read':
188+
elif action == 'mark_as_read':
194189
client.mark_as_read(articles)
195190
for article in articles:
196191
print("Mark article as read: {}".format(article.title))
@@ -208,35 +203,70 @@ def apply_action(articles, client, action, tags):
208203
print("Starred article: {}".format(article.title))
209204

210205

211-
def filter_articles(folder, rules_file, action, tags):
206+
def filter_articles(rules_file):
212207
client = get_client()
213208
filters = []
214209
for rule in yaml.load(open(rules_file)):
210+
name = rule.get('name')
211+
folders = rule['folders']
212+
213+
fields = []
214+
# only 'title' or 'content' is supported now
215+
for field in rule.get('fields', ['title', 'content']):
216+
if field not in ('title', 'content'):
217+
continue
218+
fields.append(field)
219+
cur_filter = get_filter(rule['filter'])
220+
221+
actions = []
222+
# only 'mark_as_read', 'like', 'star', 'broadcast', 'tag' is supported now
223+
for action in rule.get('actions', [{'type': 'mark_as_read'}]):
224+
if action['type'] not in ('mark_as_read', 'like', 'star', 'broadcast', 'tag'):
225+
continue
226+
actions.append(action)
227+
215228
filters.append({
216-
'field': rule.get('field', 'title'),
217-
'filter': Filter.from_config(rule),
229+
'name': name,
230+
'folders': folders,
231+
'fields': fields,
232+
'filter': cur_filter,
233+
'actions': actions
218234
})
219235

220-
matched_articles = []
221-
for idx, article in enumerate(client.fetch_unread(folder=folder)):
222-
matched = False
223-
for article_filter in filters:
224-
if article_filter['field'] in ('title', 'title_or_content') and \
225-
article_filter['filter'].validate(article.title):
236+
articles_by_foler = {} # folder -> articles
237+
matched_articles = defaultdict(list) # action -> articles
238+
for rule in filters:
239+
articles = []
240+
for folder in rule['folders']:
241+
if folder not in articles_by_foler:
242+
articles_by_foler[folder] = list(client.fetch_unread(folder=folder))
243+
244+
articles.extend(articles_by_foler[folder])
245+
246+
# FIXME: deduplicate
247+
count = 0
248+
for article in articles:
249+
matched = False
250+
if 'title' in rule['fields'] and rule['filter'].validate(article.title):
226251
matched = True
227-
break
228-
if article_filter['field'] in ('content', 'title_or_content') and \
229-
article_filter['filter'].validate(article.text):
252+
if 'content' in rule['fields'] and rule['filter'].validate(article.text):
230253
matched = True
231-
break
232-
if matched:
233-
matched_articles.append(article)
234-
if len(matched_articles) == 10:
235-
apply_action(matched_articles, client, action, tags)
236-
matched_articles = []
237254

238-
if matched_articles:
239-
apply_action(matched_articles, client, action, tags)
255+
if matched:
256+
for action in rule['actions']:
257+
matched_articles[action['type']].append((article, action))
258+
259+
count += 1
260+
print("[{}] matched {} articles with filter: {}".format(
261+
datetime.now(), count, rule['name']))
262+
263+
for action_name in matched_articles:
264+
articles, actions = zip(*matched_articles[action_name])
265+
if action_name != 'tag':
266+
apply_action(articles, client, action_name, None)
267+
else:
268+
for article, action in zip(articles, actions):
269+
apply_action([article], client, 'tag', action['tags'])
240270

241271

242272
def main():
@@ -263,11 +293,7 @@ def main():
263293
elif args.command == 'fetch-unread':
264294
fetch_unread(args.folder, args.tags, args.outfile, args.out_format)
265295
elif args.command == 'filter':
266-
if args.action == 'tag' and not args.tags:
267-
print("Need at least one tag when action is 'tag'!")
268-
sys.exit(1)
269-
270-
filter_articles(args.folder, args.rules, args.action, args.tags)
296+
filter_articles(args.rules)
271297

272298

273299
if __name__ == '__main__':

0 commit comments

Comments
 (0)