karakeep-python-api 1.6.0__tar.gz → 1.8.0__tar.gz
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.
- {karakeep_python_api-1.6.0/karakeep_python_api.egg-info → karakeep_python_api-1.8.0}/PKG-INFO +1 -1
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api/datatypes.py +22 -2
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api/karakeep_api.py +304 -8
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api/openapi_reference.json +1648 -660
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0/karakeep_python_api.egg-info}/PKG-INFO +1 -1
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/setup.py +1 -1
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/tests/test_karakeep_api.py +99 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/LICENSE +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/MANIFEST.in +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/README.md +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api/__init__.py +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api/__main__.py +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/SOURCES.txt +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/dependency_links.txt +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/entry_points.txt +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/requires.txt +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/top_level.txt +0 -0
- {karakeep_python_api-1.6.0 → karakeep_python_api-1.8.0}/setup.cfg +0 -0
{karakeep_python_api-1.6.0/karakeep_python_api.egg-info → karakeep_python_api-1.8.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: karakeep_python_api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: Community python client for the Karakeep API.
|
|
5
5
|
Home-page: https://github.com/thiswillbeyourgithub/karakeep_python_api/
|
|
6
6
|
Keywords: rss,karakeep,hoarder,data-hoarding,python,api,feeds,openapi
|
|
@@ -100,13 +100,18 @@ class BookmarkAsset(BaseModel):
|
|
|
100
100
|
fileName: Optional[str] = None
|
|
101
101
|
|
|
102
102
|
|
|
103
|
-
class
|
|
103
|
+
class UploadedAsset(BaseModel):
|
|
104
104
|
assetId: str
|
|
105
105
|
contentType: str
|
|
106
106
|
size: float
|
|
107
107
|
fileName: str
|
|
108
108
|
|
|
109
109
|
|
|
110
|
+
# Backwards-compatible alias: the upstream OpenAPI schema was renamed
|
|
111
|
+
# from "Asset" to "UploadedAsset".
|
|
112
|
+
Asset = UploadedAsset
|
|
113
|
+
|
|
114
|
+
|
|
110
115
|
class Bookmark(BaseModel):
|
|
111
116
|
id: str
|
|
112
117
|
createdAt: str
|
|
@@ -114,7 +119,7 @@ class Bookmark(BaseModel):
|
|
|
114
119
|
title: Optional[str] = None
|
|
115
120
|
archived: bool
|
|
116
121
|
favourited: bool
|
|
117
|
-
taggingStatus: Literal["success", "failure", "pending"]
|
|
122
|
+
taggingStatus: Optional[Literal["success", "failure", "pending"]] = None
|
|
118
123
|
summarizationStatus: Optional[Literal["success", "failure", "pending"]] = None
|
|
119
124
|
note: Optional[str] = None
|
|
120
125
|
summary: Optional[str] = None
|
|
@@ -136,6 +141,10 @@ class PaginatedBookmarks(BaseModel):
|
|
|
136
141
|
nextCursor: Optional[str] = ""
|
|
137
142
|
|
|
138
143
|
|
|
144
|
+
class CheckUrlResponse(BaseModel):
|
|
145
|
+
bookmarkId: Optional[str]
|
|
146
|
+
|
|
147
|
+
|
|
139
148
|
class ListModel(BaseModel):
|
|
140
149
|
id: str
|
|
141
150
|
name: str
|
|
@@ -180,3 +189,14 @@ class Backup(BaseModel):
|
|
|
180
189
|
bookmarkCount: int
|
|
181
190
|
status: Literal["pending", "success", "failure"]
|
|
182
191
|
errorMessage: Optional[str] = None
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class Feed(BaseModel):
|
|
195
|
+
id: str
|
|
196
|
+
name: str
|
|
197
|
+
url: str
|
|
198
|
+
enabled: bool
|
|
199
|
+
importTags: bool
|
|
200
|
+
lastFetchedStatus: Optional[Literal["success", "failure", "pending"]]
|
|
201
|
+
lastFetchedAt: Optional[str]
|
|
202
|
+
lastSuccessfulFetchAt: Optional[str]
|
|
@@ -85,7 +85,7 @@ class KarakeepAPI:
|
|
|
85
85
|
"""
|
|
86
86
|
|
|
87
87
|
# Version reflects the client library version, updated by bumpver
|
|
88
|
-
VERSION: str = "1.
|
|
88
|
+
VERSION: str = "1.8.0"
|
|
89
89
|
|
|
90
90
|
def __init__(
|
|
91
91
|
self,
|
|
@@ -930,6 +930,38 @@ class KarakeepAPI:
|
|
|
930
930
|
# Response should match PaginatedBookmarks schema
|
|
931
931
|
return datatypes.PaginatedBookmarks.model_validate(response_data)
|
|
932
932
|
|
|
933
|
+
@optional_typecheck
|
|
934
|
+
def check_url(
|
|
935
|
+
self,
|
|
936
|
+
url: str,
|
|
937
|
+
) -> Union[datatypes.CheckUrlResponse, Dict[str, Any], List[Any]]:
|
|
938
|
+
"""
|
|
939
|
+
Check if a URL is already bookmarked. Corresponds to GET /bookmarks/check-url.
|
|
940
|
+
Uses substring matching to find candidates, then normalizes URLs (ignoring hash fragments and trailing slashes) for exact comparison.
|
|
941
|
+
|
|
942
|
+
Args:
|
|
943
|
+
url: The URL to check.
|
|
944
|
+
|
|
945
|
+
Returns:
|
|
946
|
+
datatypes.CheckUrlResponse: Object indicating whether the URL is bookmarked. bookmarkId is null if not found.
|
|
947
|
+
If response validation is disabled, returns the raw API response (dict/list).
|
|
948
|
+
|
|
949
|
+
Raises:
|
|
950
|
+
APIError: If the API request fails.
|
|
951
|
+
pydantic.ValidationError: If response validation fails (and is not disabled).
|
|
952
|
+
"""
|
|
953
|
+
params = {
|
|
954
|
+
"url": url,
|
|
955
|
+
}
|
|
956
|
+
response_data = self._call("GET", "bookmarks/check-url", params=params)
|
|
957
|
+
|
|
958
|
+
if self.disable_response_validation:
|
|
959
|
+
logger.debug("Skipping response validation as requested.")
|
|
960
|
+
return response_data
|
|
961
|
+
else:
|
|
962
|
+
# Response should match CheckUrlResponse schema
|
|
963
|
+
return datatypes.CheckUrlResponse.model_validate(response_data)
|
|
964
|
+
|
|
933
965
|
@optional_typecheck
|
|
934
966
|
def get_a_single_bookmark(
|
|
935
967
|
self,
|
|
@@ -1048,6 +1080,7 @@ class KarakeepAPI:
|
|
|
1048
1080
|
bookmark_id: str,
|
|
1049
1081
|
tag_ids: Optional[List[str]] = None,
|
|
1050
1082
|
tag_names: Optional[List[str]] = None,
|
|
1083
|
+
attached_by: Optional[Literal["ai", "human"]] = "human",
|
|
1051
1084
|
) -> Dict[str, Any]:
|
|
1052
1085
|
"""
|
|
1053
1086
|
Attach one or more tags to a bookmark. Corresponds to POST /bookmarks/{bookmarkId}/tags.
|
|
@@ -1056,6 +1089,7 @@ class KarakeepAPI:
|
|
|
1056
1089
|
bookmark_id: The ID (string) of the bookmark.
|
|
1057
1090
|
tag_ids: List of existing tag IDs to attach (optional).
|
|
1058
1091
|
tag_names: List of tag names to attach (will create tags if they don't exist) (optional).
|
|
1092
|
+
attached_by: Who attached the tag, either "ai" or "human" (default: "human").
|
|
1059
1093
|
|
|
1060
1094
|
Returns:
|
|
1061
1095
|
dict: A dictionary containing the list of attached tag IDs under the key "attached".
|
|
@@ -1097,11 +1131,17 @@ class KarakeepAPI:
|
|
|
1097
1131
|
|
|
1098
1132
|
if tag_ids:
|
|
1099
1133
|
for tag_id in tag_ids:
|
|
1100
|
-
|
|
1134
|
+
tag_entry: Dict[str, Any] = {"tagId": tag_id.strip()}
|
|
1135
|
+
if attached_by is not None:
|
|
1136
|
+
tag_entry["attachedBy"] = attached_by
|
|
1137
|
+
tags_list.append(tag_entry)
|
|
1101
1138
|
|
|
1102
1139
|
if tag_names:
|
|
1103
1140
|
for tag_name in tag_names:
|
|
1104
|
-
|
|
1141
|
+
tag_entry = {"tagName": tag_name.strip()}
|
|
1142
|
+
if attached_by is not None:
|
|
1143
|
+
tag_entry["attachedBy"] = attached_by
|
|
1144
|
+
tags_list.append(tag_entry)
|
|
1105
1145
|
|
|
1106
1146
|
tags_data = {"tags": tags_list}
|
|
1107
1147
|
|
|
@@ -1123,6 +1163,7 @@ class KarakeepAPI:
|
|
|
1123
1163
|
bookmark_id: str,
|
|
1124
1164
|
tag_ids: Optional[List[str]] = None,
|
|
1125
1165
|
tag_names: Optional[List[str]] = None,
|
|
1166
|
+
attached_by: Optional[Literal["ai", "human"]] = "human",
|
|
1126
1167
|
) -> Dict[str, Any]:
|
|
1127
1168
|
"""
|
|
1128
1169
|
Detach one or more tags from a bookmark. Corresponds to DELETE /bookmarks/{bookmarkId}/tags.
|
|
@@ -1131,6 +1172,7 @@ class KarakeepAPI:
|
|
|
1131
1172
|
bookmark_id: The ID (string) of the bookmark.
|
|
1132
1173
|
tag_ids: List of existing tag IDs to detach (optional).
|
|
1133
1174
|
tag_names: List of tag names to detach (optional).
|
|
1175
|
+
attached_by: Who attached the tag, either "ai" or "human" (default: "human").
|
|
1134
1176
|
|
|
1135
1177
|
Returns:
|
|
1136
1178
|
dict: A dictionary containing the list of detached tag IDs under the key "detached".
|
|
@@ -1172,11 +1214,17 @@ class KarakeepAPI:
|
|
|
1172
1214
|
|
|
1173
1215
|
if tag_ids:
|
|
1174
1216
|
for tag_id in tag_ids:
|
|
1175
|
-
|
|
1217
|
+
tag_entry: Dict[str, Any] = {"tagId": tag_id.strip()}
|
|
1218
|
+
if attached_by is not None:
|
|
1219
|
+
tag_entry["attachedBy"] = attached_by
|
|
1220
|
+
tags_list.append(tag_entry)
|
|
1176
1221
|
|
|
1177
1222
|
if tag_names:
|
|
1178
1223
|
for tag_name in tag_names:
|
|
1179
|
-
|
|
1224
|
+
tag_entry = {"tagName": tag_name.strip()}
|
|
1225
|
+
if attached_by is not None:
|
|
1226
|
+
tag_entry["attachedBy"] = attached_by
|
|
1227
|
+
tags_list.append(tag_entry)
|
|
1180
1228
|
|
|
1181
1229
|
tags_data = {"tags": tags_list}
|
|
1182
1230
|
|
|
@@ -2134,7 +2182,7 @@ class KarakeepAPI:
|
|
|
2134
2182
|
@optional_typecheck
|
|
2135
2183
|
def upload_a_new_asset(
|
|
2136
2184
|
self, file: str
|
|
2137
|
-
) -> Union[datatypes.
|
|
2185
|
+
) -> Union[datatypes.UploadedAsset, Dict[str, Any], List[Any]]:
|
|
2138
2186
|
"""
|
|
2139
2187
|
Upload a new asset file. Corresponds to POST /assets.
|
|
2140
2188
|
|
|
@@ -2142,7 +2190,7 @@ class KarakeepAPI:
|
|
|
2142
2190
|
file: Path to the file to upload.
|
|
2143
2191
|
|
|
2144
2192
|
Returns:
|
|
2145
|
-
datatypes.
|
|
2193
|
+
datatypes.UploadedAsset: Details about the uploaded asset (assetId, contentType, size, fileName).
|
|
2146
2194
|
If response validation is disabled, returns the raw API response (dict/list).
|
|
2147
2195
|
|
|
2148
2196
|
Raises:
|
|
@@ -2185,7 +2233,7 @@ class KarakeepAPI:
|
|
|
2185
2233
|
return response_data
|
|
2186
2234
|
else:
|
|
2187
2235
|
# Response should match Asset schema
|
|
2188
|
-
return datatypes.
|
|
2236
|
+
return datatypes.UploadedAsset.model_validate(response_data)
|
|
2189
2237
|
|
|
2190
2238
|
@optional_typecheck
|
|
2191
2239
|
def get_all_backups(
|
|
@@ -2432,3 +2480,251 @@ class KarakeepAPI:
|
|
|
2432
2480
|
|
|
2433
2481
|
logger.error(error_msg)
|
|
2434
2482
|
raise APIError(error_msg)
|
|
2483
|
+
|
|
2484
|
+
# --- Admin: Job Triggers ---
|
|
2485
|
+
|
|
2486
|
+
@optional_typecheck
|
|
2487
|
+
def admin_trigger_recrawl(
|
|
2488
|
+
self,
|
|
2489
|
+
crawl_status: Literal["success", "failure", "pending", "all"] = "all",
|
|
2490
|
+
run_inference: bool = False,
|
|
2491
|
+
) -> Dict[str, Any]:
|
|
2492
|
+
"""
|
|
2493
|
+
Trigger a recrawl of link bookmarks. Admin only.
|
|
2494
|
+
Corresponds to POST /admin/jobs/trigger/recrawl.
|
|
2495
|
+
|
|
2496
|
+
Args:
|
|
2497
|
+
crawl_status: Filter bookmarks by their current crawl status.
|
|
2498
|
+
Use "failure" to retry only failed crawls. Default: "all".
|
|
2499
|
+
run_inference: Whether to run AI inference after crawling. Default: False.
|
|
2500
|
+
|
|
2501
|
+
Returns:
|
|
2502
|
+
dict: A dictionary with a "success" boolean field.
|
|
2503
|
+
|
|
2504
|
+
Raises:
|
|
2505
|
+
APIError: If the API request fails (e.g., 403 admin access required).
|
|
2506
|
+
"""
|
|
2507
|
+
body = {"crawlStatus": crawl_status, "runInference": run_inference}
|
|
2508
|
+
return self._call("POST", "admin/jobs/trigger/recrawl", data=body)
|
|
2509
|
+
|
|
2510
|
+
@optional_typecheck
|
|
2511
|
+
def admin_trigger_reindex(self) -> Dict[str, Any]:
|
|
2512
|
+
"""
|
|
2513
|
+
Trigger a reindex of all bookmarks in the search engine. Admin only.
|
|
2514
|
+
Corresponds to POST /admin/jobs/trigger/reindex.
|
|
2515
|
+
|
|
2516
|
+
Clears the existing index and re-queues all bookmarks for indexing.
|
|
2517
|
+
|
|
2518
|
+
Returns:
|
|
2519
|
+
dict: A dictionary with a "success" boolean field.
|
|
2520
|
+
|
|
2521
|
+
Raises:
|
|
2522
|
+
APIError: If the API request fails (e.g., 403 admin access required).
|
|
2523
|
+
"""
|
|
2524
|
+
return self._call("POST", "admin/jobs/trigger/reindex")
|
|
2525
|
+
|
|
2526
|
+
@optional_typecheck
|
|
2527
|
+
def admin_trigger_inference(
|
|
2528
|
+
self,
|
|
2529
|
+
type: Literal["tag", "summarize"],
|
|
2530
|
+
status: Literal["success", "failure", "pending", "all"] = "all",
|
|
2531
|
+
) -> Dict[str, Any]:
|
|
2532
|
+
"""
|
|
2533
|
+
Trigger AI inference (tagging or summarization) on bookmarks. Admin only.
|
|
2534
|
+
Corresponds to POST /admin/jobs/trigger/inference.
|
|
2535
|
+
|
|
2536
|
+
Args:
|
|
2537
|
+
type: The type of inference to run: "tag" for AI tagging,
|
|
2538
|
+
"summarize" for AI summarization.
|
|
2539
|
+
status: Filter bookmarks by their current inference status.
|
|
2540
|
+
Use "failure" to retry only failed ones. Default: "all".
|
|
2541
|
+
|
|
2542
|
+
Returns:
|
|
2543
|
+
dict: A dictionary with a "success" boolean field.
|
|
2544
|
+
|
|
2545
|
+
Raises:
|
|
2546
|
+
APIError: If the API request fails (e.g., 403 admin access required).
|
|
2547
|
+
"""
|
|
2548
|
+
body = {"type": type, "status": status}
|
|
2549
|
+
return self._call("POST", "admin/jobs/trigger/inference", data=body)
|
|
2550
|
+
|
|
2551
|
+
# --- Feeds ---
|
|
2552
|
+
|
|
2553
|
+
@optional_typecheck
|
|
2554
|
+
def get_all_feeds(
|
|
2555
|
+
self,
|
|
2556
|
+
) -> Union[List[datatypes.Feed], Dict[str, Any], List[Any]]:
|
|
2557
|
+
"""
|
|
2558
|
+
Get all RSS feed subscriptions for the current user. Corresponds to GET /feeds.
|
|
2559
|
+
|
|
2560
|
+
Returns:
|
|
2561
|
+
List[datatypes.Feed]: A list of feed objects.
|
|
2562
|
+
If response validation is disabled, returns the raw API response (dict/list).
|
|
2563
|
+
|
|
2564
|
+
Raises:
|
|
2565
|
+
APIError: If the API request fails.
|
|
2566
|
+
pydantic.ValidationError: If response validation fails (and is not disabled).
|
|
2567
|
+
"""
|
|
2568
|
+
response_data = self._call("GET", "feeds")
|
|
2569
|
+
|
|
2570
|
+
if self.disable_response_validation:
|
|
2571
|
+
logger.debug("Skipping response validation as requested.")
|
|
2572
|
+
return response_data
|
|
2573
|
+
if (
|
|
2574
|
+
isinstance(response_data, dict)
|
|
2575
|
+
and "feeds" in response_data
|
|
2576
|
+
and isinstance(response_data["feeds"], list)
|
|
2577
|
+
):
|
|
2578
|
+
return [
|
|
2579
|
+
datatypes.Feed.model_validate(feed) for feed in response_data["feeds"]
|
|
2580
|
+
]
|
|
2581
|
+
raise APIError(
|
|
2582
|
+
f"Unexpected response format for get_all_feeds when validation is enabled: {response_data}"
|
|
2583
|
+
)
|
|
2584
|
+
|
|
2585
|
+
@optional_typecheck
|
|
2586
|
+
def create_a_new_feed(
|
|
2587
|
+
self,
|
|
2588
|
+
name: str,
|
|
2589
|
+
url: str,
|
|
2590
|
+
enabled: bool = True,
|
|
2591
|
+
import_tags: bool = False,
|
|
2592
|
+
) -> Union[datatypes.Feed, Dict[str, Any], List[Any]]:
|
|
2593
|
+
"""
|
|
2594
|
+
Create a new RSS feed subscription. Corresponds to POST /feeds.
|
|
2595
|
+
|
|
2596
|
+
Args:
|
|
2597
|
+
name: Display name for the feed (1-100 characters).
|
|
2598
|
+
url: The RSS feed URL.
|
|
2599
|
+
enabled: Whether the feed is active and will be fetched (default: True).
|
|
2600
|
+
import_tags: Whether to import tags from the feed items (default: False).
|
|
2601
|
+
|
|
2602
|
+
Returns:
|
|
2603
|
+
datatypes.Feed: The created feed object.
|
|
2604
|
+
If response validation is disabled, returns the raw API response (dict/list).
|
|
2605
|
+
|
|
2606
|
+
Raises:
|
|
2607
|
+
APIError: If the API request fails (e.g., 400 quota exceeded).
|
|
2608
|
+
pydantic.ValidationError: If response validation fails (and is not disabled).
|
|
2609
|
+
"""
|
|
2610
|
+
feed_data = {
|
|
2611
|
+
"name": name,
|
|
2612
|
+
"url": url,
|
|
2613
|
+
"enabled": enabled,
|
|
2614
|
+
"importTags": import_tags,
|
|
2615
|
+
}
|
|
2616
|
+
response_data = self._call("POST", "feeds", data=feed_data)
|
|
2617
|
+
|
|
2618
|
+
if self.disable_response_validation:
|
|
2619
|
+
logger.debug("Skipping response validation as requested.")
|
|
2620
|
+
return response_data
|
|
2621
|
+
return datatypes.Feed.model_validate(response_data)
|
|
2622
|
+
|
|
2623
|
+
@optional_typecheck
|
|
2624
|
+
def get_a_single_feed(
|
|
2625
|
+
self, feed_id: str
|
|
2626
|
+
) -> Union[datatypes.Feed, Dict[str, Any], List[Any]]:
|
|
2627
|
+
"""
|
|
2628
|
+
Get a single RSS feed by its ID. Corresponds to GET /feeds/{feedId}.
|
|
2629
|
+
|
|
2630
|
+
Args:
|
|
2631
|
+
feed_id: The ID (string) of the feed to retrieve.
|
|
2632
|
+
|
|
2633
|
+
Returns:
|
|
2634
|
+
datatypes.Feed: The requested feed object.
|
|
2635
|
+
If response validation is disabled, returns the raw API response (dict/list).
|
|
2636
|
+
|
|
2637
|
+
Raises:
|
|
2638
|
+
APIError: If the API request fails (e.g., 404 feed not found).
|
|
2639
|
+
"""
|
|
2640
|
+
response_data = self._call("GET", f"feeds/{feed_id}")
|
|
2641
|
+
|
|
2642
|
+
if self.disable_response_validation:
|
|
2643
|
+
logger.debug("Skipping response validation as requested.")
|
|
2644
|
+
return response_data
|
|
2645
|
+
return datatypes.Feed.model_validate(response_data)
|
|
2646
|
+
|
|
2647
|
+
@optional_typecheck
|
|
2648
|
+
def update_a_feed(
|
|
2649
|
+
self,
|
|
2650
|
+
feed_id: str,
|
|
2651
|
+
name: Optional[str] = None,
|
|
2652
|
+
url: Optional[str] = None,
|
|
2653
|
+
enabled: Optional[bool] = None,
|
|
2654
|
+
import_tags: Optional[bool] = None,
|
|
2655
|
+
) -> Union[datatypes.Feed, Dict[str, Any], List[Any]]:
|
|
2656
|
+
"""
|
|
2657
|
+
Update an RSS feed subscription. Corresponds to PATCH /feeds/{feedId}.
|
|
2658
|
+
|
|
2659
|
+
Args:
|
|
2660
|
+
feed_id: The ID (string) of the feed to update.
|
|
2661
|
+
name: Optional new display name for the feed (1-100 characters).
|
|
2662
|
+
url: Optional new feed URL.
|
|
2663
|
+
enabled: Optional new enabled state.
|
|
2664
|
+
import_tags: Optional new importTags flag.
|
|
2665
|
+
|
|
2666
|
+
Returns:
|
|
2667
|
+
datatypes.Feed: The updated feed object.
|
|
2668
|
+
If response validation is disabled, returns the raw API response (dict/list).
|
|
2669
|
+
|
|
2670
|
+
Raises:
|
|
2671
|
+
ValueError: If no fields are provided to update.
|
|
2672
|
+
APIError: If the API request fails (e.g., 404 feed not found).
|
|
2673
|
+
"""
|
|
2674
|
+
update_data: Dict[str, Any] = {}
|
|
2675
|
+
if name is not None:
|
|
2676
|
+
update_data["name"] = name
|
|
2677
|
+
if url is not None:
|
|
2678
|
+
update_data["url"] = url
|
|
2679
|
+
if enabled is not None:
|
|
2680
|
+
update_data["enabled"] = enabled
|
|
2681
|
+
if import_tags is not None:
|
|
2682
|
+
update_data["importTags"] = import_tags
|
|
2683
|
+
|
|
2684
|
+
if not update_data:
|
|
2685
|
+
raise ValueError("At least one field must be provided to update.")
|
|
2686
|
+
|
|
2687
|
+
response_data = self._call("PATCH", f"feeds/{feed_id}", data=update_data)
|
|
2688
|
+
|
|
2689
|
+
if self.disable_response_validation:
|
|
2690
|
+
logger.debug("Skipping response validation as requested.")
|
|
2691
|
+
return response_data
|
|
2692
|
+
return datatypes.Feed.model_validate(response_data)
|
|
2693
|
+
|
|
2694
|
+
@optional_typecheck
|
|
2695
|
+
def delete_a_feed(self, feed_id: str) -> None:
|
|
2696
|
+
"""
|
|
2697
|
+
Delete an RSS feed subscription. Corresponds to DELETE /feeds/{feedId}.
|
|
2698
|
+
|
|
2699
|
+
Previously imported bookmarks are not affected.
|
|
2700
|
+
|
|
2701
|
+
Args:
|
|
2702
|
+
feed_id: The ID (string) of the feed to delete.
|
|
2703
|
+
|
|
2704
|
+
Returns:
|
|
2705
|
+
None: Returns None upon successful deletion (204 No Content).
|
|
2706
|
+
|
|
2707
|
+
Raises:
|
|
2708
|
+
APIError: If the API request fails (e.g., 404 feed not found).
|
|
2709
|
+
"""
|
|
2710
|
+
self._call("DELETE", f"feeds/{feed_id}")
|
|
2711
|
+
return None
|
|
2712
|
+
|
|
2713
|
+
@optional_typecheck
|
|
2714
|
+
def fetch_a_feed(self, feed_id: str) -> None:
|
|
2715
|
+
"""
|
|
2716
|
+
Trigger an immediate fetch of an RSS feed. Corresponds to POST /feeds/{feedId}/fetch.
|
|
2717
|
+
|
|
2718
|
+
The fetch is enqueued and processed asynchronously by the server.
|
|
2719
|
+
|
|
2720
|
+
Args:
|
|
2721
|
+
feed_id: The ID (string) of the feed to fetch.
|
|
2722
|
+
|
|
2723
|
+
Returns:
|
|
2724
|
+
None: Returns None upon successful enqueue (204 No Content).
|
|
2725
|
+
|
|
2726
|
+
Raises:
|
|
2727
|
+
APIError: If the API request fails (e.g., 404 feed not found).
|
|
2728
|
+
"""
|
|
2729
|
+
self._call("POST", f"feeds/{feed_id}/fetch")
|
|
2730
|
+
return None
|