karakeep-python-api 1.7.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.7.0/karakeep_python_api.egg-info → karakeep_python_api-1.8.0}/PKG-INFO +1 -1
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api/datatypes.py +18 -2
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api/karakeep_api.py +252 -4
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api/openapi_reference.json +1617 -690
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0/karakeep_python_api.egg-info}/PKG-INFO +1 -1
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/setup.py +1 -1
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/tests/test_karakeep_api.py +99 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/LICENSE +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/MANIFEST.in +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/README.md +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api/__init__.py +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api/__main__.py +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/SOURCES.txt +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/dependency_links.txt +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/entry_points.txt +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/requires.txt +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/karakeep_python_api.egg-info/top_level.txt +0 -0
- {karakeep_python_api-1.7.0 → karakeep_python_api-1.8.0}/setup.cfg +0 -0
{karakeep_python_api-1.7.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
|
|
@@ -184,3 +189,14 @@ class Backup(BaseModel):
|
|
|
184
189
|
bookmarkCount: int
|
|
185
190
|
status: Literal["pending", "success", "failure"]
|
|
186
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,
|
|
@@ -2182,7 +2182,7 @@ class KarakeepAPI:
|
|
|
2182
2182
|
@optional_typecheck
|
|
2183
2183
|
def upload_a_new_asset(
|
|
2184
2184
|
self, file: str
|
|
2185
|
-
) -> Union[datatypes.
|
|
2185
|
+
) -> Union[datatypes.UploadedAsset, Dict[str, Any], List[Any]]:
|
|
2186
2186
|
"""
|
|
2187
2187
|
Upload a new asset file. Corresponds to POST /assets.
|
|
2188
2188
|
|
|
@@ -2190,7 +2190,7 @@ class KarakeepAPI:
|
|
|
2190
2190
|
file: Path to the file to upload.
|
|
2191
2191
|
|
|
2192
2192
|
Returns:
|
|
2193
|
-
datatypes.
|
|
2193
|
+
datatypes.UploadedAsset: Details about the uploaded asset (assetId, contentType, size, fileName).
|
|
2194
2194
|
If response validation is disabled, returns the raw API response (dict/list).
|
|
2195
2195
|
|
|
2196
2196
|
Raises:
|
|
@@ -2233,7 +2233,7 @@ class KarakeepAPI:
|
|
|
2233
2233
|
return response_data
|
|
2234
2234
|
else:
|
|
2235
2235
|
# Response should match Asset schema
|
|
2236
|
-
return datatypes.
|
|
2236
|
+
return datatypes.UploadedAsset.model_validate(response_data)
|
|
2237
2237
|
|
|
2238
2238
|
@optional_typecheck
|
|
2239
2239
|
def get_all_backups(
|
|
@@ -2480,3 +2480,251 @@ class KarakeepAPI:
|
|
|
2480
2480
|
|
|
2481
2481
|
logger.error(error_msg)
|
|
2482
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
|