scholarinboxcli 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scholarinboxcli/__init__.py +1 -1
- scholarinboxcli/api/client.py +32 -56
- scholarinboxcli/api/endpoints.py +54 -0
- scholarinboxcli/cli.py +11 -505
- scholarinboxcli/commands/__init__.py +1 -0
- scholarinboxcli/commands/auth.py +38 -0
- scholarinboxcli/commands/bookmarks.py +48 -0
- scholarinboxcli/commands/collections.py +130 -0
- scholarinboxcli/commands/common.py +53 -0
- scholarinboxcli/commands/conferences.py +34 -0
- scholarinboxcli/commands/papers.py +88 -0
- scholarinboxcli/services/__init__.py +1 -0
- scholarinboxcli/services/collections.py +132 -0
- {scholarinboxcli-0.1.0.dist-info → scholarinboxcli-0.1.1.dist-info}/METADATA +8 -1
- scholarinboxcli-0.1.1.dist-info/RECORD +21 -0
- scholarinboxcli-0.1.1.dist-info/licenses/LICENSE +21 -0
- scholarinboxcli-0.1.0.dist-info/RECORD +0 -10
- {scholarinboxcli-0.1.0.dist-info → scholarinboxcli-0.1.1.dist-info}/WHEEL +0 -0
- {scholarinboxcli-0.1.0.dist-info → scholarinboxcli-0.1.1.dist-info}/entry_points.txt +0 -0
scholarinboxcli/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.1"
|
scholarinboxcli/api/client.py
CHANGED
|
@@ -13,6 +13,7 @@ from typing import Any
|
|
|
13
13
|
import httpx
|
|
14
14
|
|
|
15
15
|
from scholarinboxcli.config import Config, load_config, save_config
|
|
16
|
+
from scholarinboxcli.api import endpoints as ep
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@dataclass
|
|
@@ -106,7 +107,7 @@ class ScholarInboxClient:
|
|
|
106
107
|
sha_key = None
|
|
107
108
|
|
|
108
109
|
if sha_key:
|
|
109
|
-
resp = self.client.get(
|
|
110
|
+
resp = self.client.get(ep.LOGIN_WITH_SHA_TEMPLATE.format(sha_key=sha_key))
|
|
110
111
|
if resp.status_code >= 400:
|
|
111
112
|
raise ApiError("Login failed", resp.status_code, resp.text)
|
|
112
113
|
self.save_cookies()
|
|
@@ -155,18 +156,18 @@ class ScholarInboxClient:
|
|
|
155
156
|
raise ApiError("No endpoints tried")
|
|
156
157
|
|
|
157
158
|
def session_info(self) -> Any:
|
|
158
|
-
return self._request("GET",
|
|
159
|
+
return self._request("GET", ep.SESSION_INFO)
|
|
159
160
|
|
|
160
161
|
def get_digest(self, date: str | None = None) -> Any:
|
|
161
162
|
if date:
|
|
162
|
-
return self._request("GET", f"
|
|
163
|
-
return self._request("GET",
|
|
163
|
+
return self._request("GET", f"{ep.DIGEST}?date={date}")
|
|
164
|
+
return self._request("GET", ep.DIGEST)
|
|
164
165
|
|
|
165
166
|
def get_trending(self, category: str = "ALL", days: int = 7, sort: str = "hype", asc: bool = False) -> Any:
|
|
166
167
|
asc_val = "1" if asc else "0"
|
|
167
168
|
return self._request(
|
|
168
169
|
"GET",
|
|
169
|
-
f"
|
|
170
|
+
f"{ep.TRENDING}?column={sort}&category={category}&ascending={asc_val}&dates={days}",
|
|
170
171
|
)
|
|
171
172
|
|
|
172
173
|
def search(self, query: str, sort: str | None = None, limit: int | None = None, offset: int | None = None) -> Any:
|
|
@@ -178,7 +179,7 @@ class ScholarInboxClient:
|
|
|
178
179
|
}
|
|
179
180
|
if sort:
|
|
180
181
|
payload["orderBy"] = sort
|
|
181
|
-
return self._request("POST",
|
|
182
|
+
return self._request("POST", ep.SEARCH, json=payload)
|
|
182
183
|
|
|
183
184
|
def semantic_search(self, text: str, limit: int | None = None, offset: int | None = None) -> Any:
|
|
184
185
|
payload: dict[str, Any] = {
|
|
@@ -188,52 +189,47 @@ class ScholarInboxClient:
|
|
|
188
189
|
}
|
|
189
190
|
if limit is not None:
|
|
190
191
|
payload["n_results"] = limit
|
|
191
|
-
return self._request("POST",
|
|
192
|
+
return self._request("POST", ep.SEMANTIC_SEARCH, json=payload)
|
|
192
193
|
|
|
193
194
|
def interactions(self, type_: str = "all", sort: str = "ranking_score", asc: bool = False) -> Any:
|
|
194
195
|
asc_val = "1" if asc else "0"
|
|
195
196
|
return self._request(
|
|
196
197
|
"GET",
|
|
197
|
-
f"
|
|
198
|
+
f"{ep.INTERACTIONS}?column={sort}&type={type_}&ascending={asc_val}",
|
|
198
199
|
)
|
|
199
200
|
|
|
200
201
|
def bookmarks(self) -> Any:
|
|
201
|
-
return self._request("GET",
|
|
202
|
+
return self._request("GET", ep.BOOKMARKS)
|
|
202
203
|
|
|
203
204
|
def bookmark_add(self, paper_id: str) -> Any:
|
|
204
205
|
payload = {"bookmarked": True, "id": paper_id}
|
|
205
206
|
try:
|
|
206
|
-
return self._request("POST",
|
|
207
|
+
return self._request("POST", ep.BOOKMARK_PAPER, json=payload)
|
|
207
208
|
except ApiError:
|
|
208
|
-
return self._request("POST",
|
|
209
|
+
return self._request("POST", ep.BOOKMARK_PAPER, data=payload)
|
|
209
210
|
|
|
210
211
|
def bookmark_remove(self, paper_id: str) -> Any:
|
|
211
212
|
payload = {"bookmarked": False, "id": paper_id}
|
|
212
213
|
try:
|
|
213
|
-
return self._request("POST",
|
|
214
|
+
return self._request("POST", ep.BOOKMARK_PAPER, json=payload)
|
|
214
215
|
except ApiError:
|
|
215
|
-
return self._request("POST",
|
|
216
|
+
return self._request("POST", ep.BOOKMARK_PAPER, data=payload)
|
|
216
217
|
|
|
217
218
|
def collections_list(self) -> Any:
|
|
218
219
|
try:
|
|
219
|
-
return self._request("GET",
|
|
220
|
+
return self._request("GET", ep.COLLECTIONS_PRIMARY)
|
|
220
221
|
except ApiError:
|
|
221
|
-
return self._request("GET",
|
|
222
|
+
return self._request("GET", ep.COLLECTIONS_FALLBACK)
|
|
222
223
|
|
|
223
224
|
def collections_expanded(self) -> Any:
|
|
224
|
-
return self._request("GET",
|
|
225
|
+
return self._request("GET", ep.COLLECTIONS_EXPANDED)
|
|
225
226
|
|
|
226
227
|
def collections_map(self) -> Any:
|
|
227
|
-
return self._request("GET",
|
|
228
|
+
return self._request("GET", ep.COLLECTIONS_FALLBACK)
|
|
228
229
|
|
|
229
230
|
def collection_create(self, name: str) -> Any:
|
|
230
231
|
payload = {"name": name, "collection_name": name}
|
|
231
|
-
|
|
232
|
-
"/api/create_collection/",
|
|
233
|
-
"/api/collections",
|
|
234
|
-
"/api/collection-create/",
|
|
235
|
-
]
|
|
236
|
-
return self._post_first(endpoints, payload)
|
|
232
|
+
return self._post_first(list(ep.COLLECTION_CREATE_CANDIDATES), payload)
|
|
237
233
|
|
|
238
234
|
def collection_rename(self, collection_id: str, new_name: str) -> Any:
|
|
239
235
|
payload = {
|
|
@@ -242,39 +238,19 @@ class ScholarInboxClient:
|
|
|
242
238
|
"name": new_name,
|
|
243
239
|
"new_name": new_name,
|
|
244
240
|
}
|
|
245
|
-
|
|
246
|
-
"/api/rename_collection/",
|
|
247
|
-
"/api/collection-rename/",
|
|
248
|
-
"/api/collections/rename",
|
|
249
|
-
]
|
|
250
|
-
return self._post_first(endpoints, payload)
|
|
241
|
+
return self._post_first(list(ep.COLLECTION_RENAME_CANDIDATES), payload)
|
|
251
242
|
|
|
252
243
|
def collection_delete(self, collection_id: str) -> Any:
|
|
253
244
|
payload = {"collection_id": collection_id, "id": collection_id}
|
|
254
|
-
|
|
255
|
-
"/api/delete_collection/",
|
|
256
|
-
"/api/collection-delete/",
|
|
257
|
-
"/api/collections/delete",
|
|
258
|
-
]
|
|
259
|
-
return self._post_first(endpoints, payload)
|
|
245
|
+
return self._post_first(list(ep.COLLECTION_DELETE_CANDIDATES), payload)
|
|
260
246
|
|
|
261
247
|
def collection_add_paper(self, collection_id: str, paper_id: str) -> Any:
|
|
262
248
|
payload = {"collection_id": collection_id, "paper_id": paper_id}
|
|
263
|
-
|
|
264
|
-
"/api/add_paper_to_collection/",
|
|
265
|
-
"/api/collection-add-paper/",
|
|
266
|
-
"/api/add_to_collection/",
|
|
267
|
-
]
|
|
268
|
-
return self._post_first(endpoints, payload)
|
|
249
|
+
return self._post_first(list(ep.COLLECTION_ADD_PAPER_CANDIDATES), payload)
|
|
269
250
|
|
|
270
251
|
def collection_remove_paper(self, collection_id: str, paper_id: str) -> Any:
|
|
271
252
|
payload = {"collection_id": collection_id, "paper_id": paper_id}
|
|
272
|
-
|
|
273
|
-
"/api/remove_paper_from_collection/",
|
|
274
|
-
"/api/collection-remove-paper/",
|
|
275
|
-
"/api/remove_from_collection/",
|
|
276
|
-
]
|
|
277
|
-
return self._post_first(endpoints, payload)
|
|
253
|
+
return self._post_first(list(ep.COLLECTION_REMOVE_PAPER_CANDIDATES), payload)
|
|
278
254
|
|
|
279
255
|
def collection_papers(self, collection_id: str, limit: int | None = None, offset: int | None = None) -> Any:
|
|
280
256
|
params: dict[str, Any] = {"collection_id": collection_id}
|
|
@@ -283,10 +259,10 @@ class ScholarInboxClient:
|
|
|
283
259
|
if offset is not None:
|
|
284
260
|
params["offset"] = offset
|
|
285
261
|
try:
|
|
286
|
-
return self._request("GET",
|
|
262
|
+
return self._request("GET", ep.COLLECTION_PAPERS, params=params)
|
|
287
263
|
except ApiError:
|
|
288
264
|
# fallback without paging
|
|
289
|
-
return self._request("GET",
|
|
265
|
+
return self._request("GET", ep.COLLECTION_PAPERS, params={"collection_id": collection_id})
|
|
290
266
|
|
|
291
267
|
def collections_similar(self, collection_ids: list[str], limit: int | None = None, offset: int | None = None) -> Any:
|
|
292
268
|
schemas = [
|
|
@@ -317,39 +293,39 @@ class ScholarInboxClient:
|
|
|
317
293
|
payload: dict[str, Any] = {"collectionIds": collection_ids, "p": offset if offset is not None else 0}
|
|
318
294
|
if limit is not None:
|
|
319
295
|
payload["n_results"] = limit
|
|
320
|
-
return self._request("POST",
|
|
296
|
+
return self._request("POST", ep.COLLECTIONS_SIMILAR, json=payload)
|
|
321
297
|
if schema == "json_collection_ids":
|
|
322
298
|
payload: dict[str, Any] = {"collection_ids": collection_ids}
|
|
323
299
|
if limit is not None:
|
|
324
300
|
payload["limit"] = limit
|
|
325
301
|
if offset is not None:
|
|
326
302
|
payload["offset"] = offset
|
|
327
|
-
return self._request("POST",
|
|
303
|
+
return self._request("POST", ep.COLLECTIONS_SIMILAR, json=payload)
|
|
328
304
|
if schema == "json_collection_id" and len(collection_ids) == 1:
|
|
329
305
|
payload = {"collection_id": collection_ids[0]}
|
|
330
306
|
if limit is not None:
|
|
331
307
|
payload["limit"] = limit
|
|
332
308
|
if offset is not None:
|
|
333
309
|
payload["offset"] = offset
|
|
334
|
-
return self._request("POST",
|
|
310
|
+
return self._request("POST", ep.COLLECTIONS_SIMILAR, json=payload)
|
|
335
311
|
if schema == "form_collection_ids":
|
|
336
312
|
payload = {"collection_ids": ",".join(collection_ids)}
|
|
337
313
|
if limit is not None:
|
|
338
314
|
payload["limit"] = limit
|
|
339
315
|
if offset is not None:
|
|
340
316
|
payload["offset"] = offset
|
|
341
|
-
return self._request("POST",
|
|
317
|
+
return self._request("POST", ep.COLLECTIONS_SIMILAR, data=payload)
|
|
342
318
|
if schema == "get_params":
|
|
343
319
|
params = {"collection_id": ",".join(collection_ids)}
|
|
344
320
|
if limit is not None:
|
|
345
321
|
params["limit"] = limit
|
|
346
322
|
if offset is not None:
|
|
347
323
|
params["offset"] = offset
|
|
348
|
-
return self._request("GET",
|
|
324
|
+
return self._request("GET", ep.COLLECTIONS_SIMILAR, params=params)
|
|
349
325
|
raise ApiError("Unknown schema")
|
|
350
326
|
|
|
351
327
|
def conference_list(self) -> Any:
|
|
352
|
-
return self._request("GET",
|
|
328
|
+
return self._request("GET", ep.CONFERENCE_LIST)
|
|
353
329
|
|
|
354
330
|
def conference_explorer(self) -> Any:
|
|
355
|
-
return self._request("GET",
|
|
331
|
+
return self._request("GET", ep.CONFERENCE_EXPLORER)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""API endpoint constants used by the Scholar Inbox client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
# Auth/session
|
|
6
|
+
SESSION_INFO = "/api/session_info"
|
|
7
|
+
LOGIN_WITH_SHA_TEMPLATE = "/api/login/{sha_key}/"
|
|
8
|
+
|
|
9
|
+
# Feed/search
|
|
10
|
+
DIGEST = "/api/"
|
|
11
|
+
TRENDING = "/api/trending"
|
|
12
|
+
SEARCH = "/api/get_search_results/"
|
|
13
|
+
SEMANTIC_SEARCH = "/api/semantic-search"
|
|
14
|
+
INTERACTIONS = "/api/interactions"
|
|
15
|
+
|
|
16
|
+
# Bookmarks
|
|
17
|
+
BOOKMARKS = "/api/bookmarks"
|
|
18
|
+
BOOKMARK_PAPER = "/api/bookmark_paper/"
|
|
19
|
+
|
|
20
|
+
# Collections
|
|
21
|
+
COLLECTIONS_PRIMARY = "/api/get_all_user_collections"
|
|
22
|
+
COLLECTIONS_FALLBACK = "/api/collections"
|
|
23
|
+
COLLECTIONS_EXPANDED = "/api/get_expanded_collections"
|
|
24
|
+
COLLECTION_CREATE_CANDIDATES = (
|
|
25
|
+
"/api/create_collection/",
|
|
26
|
+
"/api/collections",
|
|
27
|
+
"/api/collection-create/",
|
|
28
|
+
)
|
|
29
|
+
COLLECTION_RENAME_CANDIDATES = (
|
|
30
|
+
"/api/rename_collection/",
|
|
31
|
+
"/api/collection-rename/",
|
|
32
|
+
"/api/collections/rename",
|
|
33
|
+
)
|
|
34
|
+
COLLECTION_DELETE_CANDIDATES = (
|
|
35
|
+
"/api/delete_collection/",
|
|
36
|
+
"/api/collection-delete/",
|
|
37
|
+
"/api/collections/delete",
|
|
38
|
+
)
|
|
39
|
+
COLLECTION_ADD_PAPER_CANDIDATES = (
|
|
40
|
+
"/api/add_paper_to_collection/",
|
|
41
|
+
"/api/collection-add-paper/",
|
|
42
|
+
"/api/add_to_collection/",
|
|
43
|
+
)
|
|
44
|
+
COLLECTION_REMOVE_PAPER_CANDIDATES = (
|
|
45
|
+
"/api/remove_paper_from_collection/",
|
|
46
|
+
"/api/collection-remove-paper/",
|
|
47
|
+
"/api/remove_from_collection/",
|
|
48
|
+
)
|
|
49
|
+
COLLECTION_PAPERS = "/api/collection-papers"
|
|
50
|
+
COLLECTIONS_SIMILAR = "/api/get_collections_similar_papers/"
|
|
51
|
+
|
|
52
|
+
# Conferences
|
|
53
|
+
CONFERENCE_LIST = "/api/conference_list"
|
|
54
|
+
CONFERENCE_EXPLORER = "/api/conference-explorer"
|