Skip to content

Commit 0c8a076

Browse files
authored
Merge pull request #30 from Linusp/dev
Release 0.7.0
2 parents 349a1b2 + 1ffebae commit 0c8a076

File tree

5 files changed

+57
-46
lines changed

5 files changed

+57
-46
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# CHANGELOG
22

3+
## v0.7.0
4+
5+
Removed
6+
7+
- Removed `InoreaderClient.get_stream_contents`.
8+
9+
Changed
10+
11+
- Add param `n` to `InoreaderClient.fetch_articles` to reduce the number of API calls, thanks to [tosborne-slalom](https://github.com/tosborne-slalom)
12+
- Supported `--batch-size` option in commands `fetch-articles`/`fetch-unread`/`fetch-starred`
13+
314
## v0.6.0
415

516
Publish to pypi!

codespell-ignore-words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ot

inoreader/client.py

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -143,52 +143,42 @@ def get_subscription_list(self):
143143
for item in response["subscriptions"]:
144144
yield Subscription.from_json(item)
145145

146-
def get_stream_contents(self, stream_id, c="", limit=None):
147-
fetched_count = 0
148-
stop = False
149-
while not stop:
150-
articles, c = self.__get_stream_contents(stream_id, c)
151-
for a in articles:
152-
try:
153-
yield Article.from_json(a)
154-
fetched_count += 1
155-
except Exception as e:
156-
print(e)
157-
continue
158-
if limit and fetched_count >= limit:
159-
stop = True
160-
break
161-
if c is None:
162-
break
163-
164-
def __get_stream_contents(self, stream_id, continuation=""):
146+
def __get_stream_contents(
147+
self, stream_id=None, n=50, r=None, ot=None, xt=None, it=None, c=None
148+
):
149+
"""reference: https://www.inoreader.com/developers/stream-contents"""
165150
self.check_token()
166151

167-
url = urljoin(BASE_URL, self.STREAM_CONTENTS_PATH + quote_plus(stream_id))
168-
params = {"n": 50, "r": "", "c": continuation, "output": "json"} # default 20, max 1000
152+
url = urljoin(BASE_URL, self.STREAM_CONTENTS_PATH)
153+
if stream_id:
154+
url = urljoin(url, quote_plus(stream_id))
155+
156+
params = {"n": n, "r": r, "ot": ot, "xt": xt, "it": it, "c": c}
157+
params = {arg: val for arg, val in params.items() if val is not None}
169158
response = self.parse_response(self.session.post(url, params=params, proxies=self.proxies))
170159
if "continuation" in response:
171160
return response["items"], response["continuation"]
172161
else:
173162
return response["items"], None
174163

175-
def fetch_articles(self, folder=None, tags=None, unread=True, starred=False, limit=None, n=50):
164+
def fetch_articles(
165+
self, stream_id=None, folder=None, tags=None, unread=True, starred=False, limit=None, n=50
166+
):
176167
self.check_token()
177168

178-
url = urljoin(BASE_URL, self.STREAM_CONTENTS_PATH)
179-
if folder:
180-
url = urljoin(url, quote_plus(self.GENERAL_TAG_TEMPLATE.format(folder)))
169+
if not stream_id and folder:
170+
stream_id = self.GENERAL_TAG_TEMPLATE.format(folder)
181171

182-
params = {"n": n, "c": str(uuid4())}
172+
params = {"stream_id": stream_id, "n": n, "c": str(uuid4())}
183173
if unread:
184174
params["xt"] = self.READ_TAG
185175

186176
if starred:
187177
params["it"] = self.STARRED_TAG
188178

189179
fetched_count = 0
190-
response = self.parse_response(self.session.post(url, params=params, proxies=self.proxies))
191-
for data in response["items"]:
180+
items, continuation = self.__get_stream_contents(**params)
181+
for data in items:
192182
categories = {
193183
category.split("/")[-1]
194184
for category in data.get("categories", [])
@@ -202,13 +192,10 @@ def fetch_articles(self, folder=None, tags=None, unread=True, starred=False, lim
202192
if limit and fetched_count >= limit:
203193
break
204194

205-
continuation = response.get("continuation")
206195
while continuation and (not limit or fetched_count < limit):
207196
params["c"] = continuation
208-
response = self.parse_response(
209-
self.session.post(url, params=params, proxies=self.proxies)
210-
)
211-
for data in response["items"]:
197+
items, continuation = self.__get_stream_contents(**params)
198+
for data in items:
212199
categories = {
213200
category.split("/")[-1]
214201
for category in data.get("categories", [])
@@ -221,14 +208,14 @@ def fetch_articles(self, folder=None, tags=None, unread=True, starred=False, lim
221208
if limit and fetched_count >= limit:
222209
break
223210

224-
continuation = response.get("continuation")
225-
226-
def fetch_unread(self, folder=None, tags=None, limit=None):
227-
for article in self.fetch_articles(folder=folder, tags=tags, unread=True):
211+
def fetch_unread(self, folder=None, tags=None, limit=None, n=None):
212+
for article in self.fetch_articles(folder=folder, tags=tags, unread=True, n=n):
228213
yield article
229214

230-
def fetch_starred(self, folder=None, tags=None, limit=None):
231-
for article in self.fetch_articles(folder=folder, tags=tags, unread=False, starred=True):
215+
def fetch_starred(self, folder=None, tags=None, limit=None, n=None):
216+
for article in self.fetch_articles(
217+
folder=folder, tags=tags, unread=False, starred=True, n=n
218+
):
232219
yield article
233220

234221
def add_general_label(self, articles, label):

inoreader/main.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ def list_tags():
200200
@main.command("fetch-unread")
201201
@click.option("-f", "--folder", required=True, help="Folder which articles belong to")
202202
@click.option("-t", "--tags", help="Tag(s) for filtering, separate with comma")
203+
@click.option(
204+
"--batch-size", type=int, default=50, help="Maximum number of articles per API request"
205+
)
203206
@click.option("-o", "--outfile", required=True, help="Filename to save articles")
204207
@click.option(
205208
"--out-format",
@@ -208,14 +211,14 @@ def list_tags():
208211
help="Format of output file, default: json",
209212
)
210213
@catch_error
211-
def fetch_unread(folder, tags, outfile, out_format):
214+
def fetch_unread(folder, tags, batch_size, outfile, out_format):
212215
"""Fetch unread articles"""
213216
client = get_client()
214217

215218
tag_list = [] if not tags else tags.split(",")
216219
fout = codecs.open(outfile, mode="w", encoding="utf-8")
217220
writer = csv.writer(fout, delimiter=",") if out_format == "csv" else None
218-
for idx, article in enumerate(client.fetch_unread(folder=folder, tags=tag_list)):
221+
for idx, article in enumerate(client.fetch_unread(folder=folder, tags=tag_list, n=batch_size)):
219222
if idx > 0 and (idx % 10) == 0:
220223
LOGGER.info("fetched %d articles", idx)
221224
title = article.title
@@ -391,6 +394,10 @@ def get_subscriptions(outfile, folder, out_format):
391394

392395
@main.command("fetch-articles")
393396
@click.option("-i", "--stream-id", required=True, help="Stream ID which you want to fetch")
397+
@click.option(
398+
"--batch-size", type=int, default=50, help="Maximum number of articles per API request"
399+
)
400+
@click.option("--only-unread", is_flag=True, help="Fetch unread articles only")
394401
@click.option("-o", "--outfile", required=True, help="Filename to save results")
395402
@click.option(
396403
"--out-format",
@@ -399,7 +406,7 @@ def get_subscriptions(outfile, folder, out_format):
399406
help="Format of output, default: json",
400407
)
401408
@catch_error
402-
def fetch_articles(outfile, stream_id, out_format):
409+
def fetch_articles(outfile, stream_id, batch_size, only_unread, out_format):
403410
"""Fetch articles by stream id"""
404411
client = get_client()
405412

@@ -409,7 +416,9 @@ def fetch_articles(outfile, stream_id, out_format):
409416
writer = csv.DictWriter(fout, ["title", "content"], delimiter=",", quoting=csv.QUOTE_ALL)
410417
writer.writeheader()
411418

412-
for idx, article in enumerate(client.get_stream_contents(stream_id)):
419+
for idx, article in enumerate(
420+
client.fetch_articles(stream_id=stream_id, n=batch_size, unread=only_unread)
421+
):
413422
if idx > 0 and (idx % 10) == 0:
414423
LOGGER.info("fetched %d articles", idx)
415424

@@ -469,6 +478,9 @@ def dedupe(folder, thresh):
469478
@main.command("fetch-starred")
470479
@click.option("-f", "--folder", help="Folder which articles belong to")
471480
@click.option("-t", "--tags", help="Tag(s) for filtering, separate with comma")
481+
@click.option(
482+
"--batch-size", type=int, default=50, help="Maximum number of articles per API request"
483+
)
472484
@click.option(
473485
"-o", "--outfile", help="Filename to save articles, required when output format is `csv`"
474486
)
@@ -484,7 +496,7 @@ def dedupe(folder, thresh):
484496
help="Format of output file, default: json",
485497
)
486498
@catch_error
487-
def fetch_starred(folder, tags, outfile, outdir, limit, save_image, out_format):
499+
def fetch_starred(folder, tags, batch_size, outfile, outdir, limit, save_image, out_format):
488500
"""Fetch starred articles"""
489501
client = get_client()
490502

@@ -506,7 +518,7 @@ def fetch_starred(folder, tags, outfile, outdir, limit, save_image, out_format):
506518
tag_list = [] if not tags else tags.split(",")
507519
url_to_image = {}
508520
fetched_count = 0
509-
for article in client.fetch_starred(folder=folder, tags=tag_list, limit=limit):
521+
for article in client.fetch_starred(folder=folder, tags=tag_list, limit=limit, n=batch_size):
510522
if limit and fetched_count >= limit:
511523
break
512524

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "python-inoreader"
3-
version = "0.6.0"
3+
version = "0.7.0"
44
description = "Python wrapper of Inoreader API"
55
authors = [
66
{name = "Linusp", email = "[email protected]"},

0 commit comments

Comments
 (0)