karakeep-python-api 0.2.2__py3-none-any.whl → 1.0.0__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.
@@ -85,7 +85,7 @@ class KarakeepAPI:
85
85
  """
86
86
 
87
87
  # Version reflects the client library version, updated by bumpver
88
- VERSION: str = "0.2.2"
88
+ VERSION: str = "1.0.0"
89
89
 
90
90
  def __init__(
91
91
  self,
@@ -95,7 +95,9 @@ class KarakeepAPI:
95
95
  verify_ssl: bool = True,
96
96
  verbose: bool = False,
97
97
  disable_response_validation: Optional[bool] = None,
98
- rate_limit: float = 0.0, # Minimum interval between API calls in seconds
98
+ rate_limit: Union[
99
+ float, int
100
+ ] = 0.0, # Minimum interval between API calls in seconds
99
101
  ):
100
102
  """
101
103
  Initialize the Karakeep API client.
@@ -905,15 +907,21 @@ class KarakeepAPI:
905
907
  return None # Explicitly return None for 204
906
908
 
907
909
  @optional_typecheck
908
- def update_a_bookmark(self, bookmark_id: str, update_data: dict) -> Dict[str, Any]:
910
+ def update_a_bookmark(
911
+ self,
912
+ bookmark_id: str,
913
+ update_data: Dict[str, Any],
914
+ ) -> Dict[str, Any]:
909
915
  """
910
916
  Update a bookmark by its ID. Corresponds to PATCH /bookmarks/{bookmarkId}.
911
- Allows updating fields like 'archived', 'favourited', 'summary', 'note', 'title', etc.
917
+ Allows updating various bookmark fields including metadata, content, and status.
912
918
 
913
919
  Args:
914
920
  bookmark_id: The ID (string) of the bookmark to update.
915
- update_data: A dictionary containing the fields to update (e.g., `{"archived": True}`).
916
- See the OpenAPI spec for allowed fields in the request body.
921
+ update_data: Dictionary containing the fields to update. Supported keys include:
922
+ 'title', 'archived', 'favourited', 'note', 'summary', 'createdAt',
923
+ 'url', 'description', 'author', 'publisher', 'datePublished',
924
+ 'dateModified', 'text', 'assetContent'.
917
925
 
918
926
  Returns:
919
927
  dict: A dictionary representing the updated bookmark (partial representation).
@@ -922,8 +930,13 @@ class KarakeepAPI:
922
930
  Validation is not performed on this response type by default.
923
931
 
924
932
  Raises:
933
+ ValueError: If update_data is empty or no valid fields are provided to update.
925
934
  APIError: If the API request fails (e.g., 404 bookmark not found).
926
935
  """
936
+ # Ensure at least one field is being updated
937
+ if not update_data:
938
+ raise ValueError("update_data must contain at least one field to update.")
939
+
927
940
  endpoint = f"bookmarks/{bookmark_id}"
928
941
  response_data = self._call("PATCH", endpoint, data=update_data)
929
942
  # The response schema is a subset of Bookmark, return as dict as specified in spec
@@ -979,7 +992,9 @@ class KarakeepAPI:
979
992
  """
980
993
  # Validate that at least one tag source is provided
981
994
  if not tag_ids and not tag_names:
982
- raise ValueError("At least one of 'tag_ids' or 'tag_names' must be provided")
995
+ raise ValueError(
996
+ "At least one of 'tag_ids' or 'tag_names' must be provided"
997
+ )
983
998
 
984
999
  # Validate input types
985
1000
  if tag_ids is not None and not isinstance(tag_ids, list):
@@ -997,7 +1012,9 @@ class KarakeepAPI:
997
1012
  if tag_names:
998
1013
  for i, tag_name in enumerate(tag_names):
999
1014
  if not isinstance(tag_name, str) or not tag_name.strip():
1000
- raise ValueError(f"Tag name at index {i} must be a non-empty string")
1015
+ raise ValueError(
1016
+ f"Tag name at index {i} must be a non-empty string"
1017
+ )
1001
1018
 
1002
1019
  # Construct the tags_data dict in the format expected by the API
1003
1020
  tags_list = []
@@ -1050,7 +1067,9 @@ class KarakeepAPI:
1050
1067
  """
1051
1068
  # Validate that at least one tag source is provided
1052
1069
  if not tag_ids and not tag_names:
1053
- raise ValueError("At least one of 'tag_ids' or 'tag_names' must be provided")
1070
+ raise ValueError(
1071
+ "At least one of 'tag_ids' or 'tag_names' must be provided"
1072
+ )
1054
1073
 
1055
1074
  # Validate input types
1056
1075
  if tag_ids is not None and not isinstance(tag_ids, list):
@@ -1068,7 +1087,9 @@ class KarakeepAPI:
1068
1087
  if tag_names:
1069
1088
  for i, tag_name in enumerate(tag_names):
1070
1089
  if not isinstance(tag_name, str) or not tag_name.strip():
1071
- raise ValueError(f"Tag name at index {i} must be a non-empty string")
1090
+ raise ValueError(
1091
+ f"Tag name at index {i} must be a non-empty string"
1092
+ )
1072
1093
 
1073
1094
  # Construct the tags_data dict in the format expected by the API
1074
1095
  tags_list = []
@@ -1145,16 +1166,28 @@ class KarakeepAPI:
1145
1166
 
1146
1167
  @optional_typecheck
1147
1168
  def attach_asset(
1148
- self, bookmark_id: str, asset_data: dict
1169
+ self,
1170
+ bookmark_id: str,
1171
+ asset_id: str,
1172
+ asset_type: Literal[
1173
+ "screenshot",
1174
+ "assetScreenshot",
1175
+ "bannerImage",
1176
+ "fullPageArchive",
1177
+ "video",
1178
+ "bookmarkAsset",
1179
+ "precrawledArchive",
1180
+ "unknown",
1181
+ ],
1149
1182
  ) -> Union[datatypes.Asset, Dict[str, Any], List[Any]]:
1150
1183
  """
1151
1184
  Attach a new asset to a bookmark. Corresponds to POST /bookmarks/{bookmarkId}/assets.
1152
1185
 
1153
1186
  Args:
1154
1187
  bookmark_id: The ID (string) of the bookmark.
1155
- asset_data: Dictionary specifying the asset to attach. Must contain "id" (string) and "assetType" (string enum).
1156
- Example: `{"id": "asset_id_string", "assetType": "screenshot"}`
1157
- See `datatypes.AssetType` enum for possible asset types.
1188
+ asset_id: The ID (string) of the asset to attach.
1189
+ asset_type: The type of asset being attached. Must be one of: "screenshot", "assetScreenshot",
1190
+ "bannerImage", "fullPageArchive", "video", "bookmarkAsset", "precrawledArchive", "unknown".
1158
1191
 
1159
1192
  Returns:
1160
1193
  datatypes.Asset: The attached asset object.
@@ -1164,6 +1197,9 @@ class KarakeepAPI:
1164
1197
  APIError: If the API request fails (e.g., 404 bookmark not found).
1165
1198
  pydantic.ValidationError: If response validation fails (and is not disabled).
1166
1199
  """
1200
+ # Construct the asset data dict as expected by the API
1201
+ asset_data = {"id": asset_id, "assetType": asset_type}
1202
+
1167
1203
  endpoint = f"bookmarks/{bookmark_id}/assets"
1168
1204
  response_data = self._call("POST", endpoint, data=asset_data)
1169
1205
 
@@ -1175,9 +1211,7 @@ class KarakeepAPI:
1175
1211
  return datatypes.Asset.model_validate(response_data)
1176
1212
 
1177
1213
  @optional_typecheck
1178
- def replace_asset(
1179
- self, bookmark_id: str, asset_id: str, new_asset_data: dict
1180
- ) -> None:
1214
+ def replace_asset(self, bookmark_id: str, asset_id: str, new_asset_id: str) -> None:
1181
1215
  """
1182
1216
  Replace an existing asset associated with a bookmark with a new one.
1183
1217
  Corresponds to PUT /bookmarks/{bookmarkId}/assets/{assetId}.
@@ -1185,8 +1219,7 @@ class KarakeepAPI:
1185
1219
  Args:
1186
1220
  bookmark_id: The ID (string) of the bookmark.
1187
1221
  asset_id: The ID (string) of the asset to be replaced.
1188
- new_asset_data: Dictionary specifying the new asset ID. Must contain "assetId" (string).
1189
- Example: `{"assetId": "new_asset_id_string"}`
1222
+ new_asset_id: The ID (string) of the new asset to replace with.
1190
1223
 
1191
1224
  Returns:
1192
1225
  None: Returns None upon successful replacement (204 No Content).
@@ -1194,6 +1227,9 @@ class KarakeepAPI:
1194
1227
  Raises:
1195
1228
  APIError: If the API request fails (e.g., 404 bookmark or asset not found).
1196
1229
  """
1230
+ # Construct the request body as expected by the API
1231
+ new_asset_data = {"assetId": new_asset_id}
1232
+
1197
1233
  endpoint = f"bookmarks/{bookmark_id}/assets/{asset_id}"
1198
1234
  self._call("PUT", endpoint, data=new_asset_data) # Expects 204 No Content
1199
1235
  return None # Explicitly return None for 204
@@ -1367,25 +1403,52 @@ class KarakeepAPI:
1367
1403
 
1368
1404
  @optional_typecheck
1369
1405
  def update_a_list(
1370
- self, list_id: str, update_data: dict
1406
+ self,
1407
+ list_id: str,
1408
+ name: Optional[str] = None,
1409
+ description: Optional[str] = None,
1410
+ icon: Optional[str] = None,
1411
+ parent_id: Optional[str] = None,
1412
+ query: Optional[str] = None,
1371
1413
  ) -> Union[datatypes.ListModel, Dict[str, Any], List[Any]]:
1372
1414
  """
1373
1415
  Update a list by its ID. Corresponds to PATCH /lists/{listId}.
1374
- Allows updating fields like "name", "description", "icon", "parentId", "query".
1416
+ Allows updating various list fields including name, description, icon, parent relationship, and query.
1375
1417
 
1376
1418
  Args:
1377
1419
  list_id: The ID (string) of the list to update.
1378
- update_data: A dictionary containing the fields to update (e.g., `{"name": "new name"}`).
1379
- See the OpenAPI spec for allowed fields.
1420
+ name: Optional new name for the list (1-40 characters).
1421
+ description: Optional new description for the list (0-100 characters, can be None to clear).
1422
+ icon: Optional new icon for the list.
1423
+ parent_id: Optional new parent list ID (can be None to remove parent relationship).
1424
+ query: Optional new query string for smart lists (minimum 1 character).
1380
1425
 
1381
1426
  Returns:
1382
1427
  datatypes.ListModel: The updated list object.
1383
1428
  If response validation is disabled, returns the raw API response (dict/list).
1384
1429
 
1385
1430
  Raises:
1431
+ ValueError: If no fields are provided to update.
1386
1432
  APIError: If the API request fails (e.g., 404 list not found).
1387
1433
  pydantic.ValidationError: If response validation fails (and is not disabled).
1388
1434
  """
1435
+ # Construct update_data from provided arguments, excluding None values that weren't explicitly passed
1436
+ update_data = {}
1437
+ if name is not None:
1438
+ update_data["name"] = name
1439
+ if description is not None:
1440
+ update_data["description"] = description
1441
+ if icon is not None:
1442
+ update_data["icon"] = icon
1443
+ if parent_id is not None:
1444
+ update_data["parentId"] = parent_id
1445
+ if query is not None:
1446
+ update_data["query"] = query
1447
+
1448
+ # Ensure at least one field is being updated
1449
+ if not update_data:
1450
+ raise ValueError("At least one field must be provided to update.")
1451
+
1389
1452
  endpoint = f"lists/{list_id}"
1390
1453
  response_data = self._call("PATCH", endpoint, data=update_data)
1391
1454
 
@@ -1594,23 +1657,28 @@ class KarakeepAPI:
1594
1657
  return None # Explicitly return None for 204
1595
1658
 
1596
1659
  @optional_typecheck
1597
- def update_a_tag(self, tag_id: str, update_data: dict) -> Dict[str, Any]:
1660
+ def update_a_tag(self, tag_id: str, update_data: Dict[str, Any]) -> Dict[str, Any]:
1598
1661
  """
1599
1662
  Update a tag by its ID. Currently only supports updating the "name".
1600
1663
  Corresponds to PATCH /tags/{tagId}.
1601
1664
 
1602
1665
  Args:
1603
1666
  tag_id: The ID (string) of the tag to update.
1604
- update_data: A dictionary containing the fields to update. Must include "name" (string).
1605
- Example: `{"name": "new tag name"}`
1667
+ update_data: Dictionary containing the fields to update. Supported keys include:
1668
+ 'name' (string).
1606
1669
 
1607
1670
  Returns:
1608
1671
  dict: A dictionary containing the updated tag information with "id" and "name" fields.
1609
1672
  Validation is not performed on this response type by default.
1610
1673
 
1611
1674
  Raises:
1675
+ ValueError: If update_data is empty or no valid fields are provided to update.
1612
1676
  APIError: If the API request fails (e.g., 404 tag not found).
1613
1677
  """
1678
+ # Ensure at least one field is being updated
1679
+ if not update_data:
1680
+ raise ValueError("update_data must contain at least one field to update.")
1681
+
1614
1682
  endpoint = f"tags/{tag_id}"
1615
1683
  response_data = self._call("PATCH", endpoint, data=update_data)
1616
1684
  # Response schema is a simple dict with id and name, return as dict
@@ -1693,8 +1761,8 @@ class KarakeepAPI:
1693
1761
  def create_a_new_highlight(
1694
1762
  self,
1695
1763
  bookmark_id: str,
1696
- start_offset: float,
1697
- end_offset: float,
1764
+ start_offset: Union[float, int],
1765
+ end_offset: Union[float, int],
1698
1766
  color: Optional[Literal["yellow", "red", "green", "blue"]] = "yellow",
1699
1767
  text: Optional[str] = None,
1700
1768
  note: Optional[str] = None,
@@ -1796,7 +1864,9 @@ class KarakeepAPI:
1796
1864
 
1797
1865
  @optional_typecheck
1798
1866
  def update_a_highlight(
1799
- self, highlight_id: str, update_data: dict
1867
+ self,
1868
+ highlight_id: str,
1869
+ color: Optional[Literal["yellow", "red", "green", "blue"]] = None,
1800
1870
  ) -> Union[datatypes.Highlight, Dict[str, Any], List[Any]]:
1801
1871
  """
1802
1872
  Update a highlight by its ID. Currently only supports updating the "color".
@@ -1804,17 +1874,26 @@ class KarakeepAPI:
1804
1874
 
1805
1875
  Args:
1806
1876
  highlight_id: The ID (string) of the highlight to update.
1807
- update_data: A dictionary containing the fields to update. Must include "color" (string enum).
1808
- See `datatypes.Color` enum. Example: `{"color": "red"}`
1877
+ color: Optional new color for the highlight ("yellow", "red", "green", "blue").
1809
1878
 
1810
1879
  Returns:
1811
1880
  datatypes.Highlight: The updated highlight object.
1812
1881
  If response validation is disabled, returns the raw API response (dict/list).
1813
1882
 
1814
1883
  Raises:
1884
+ ValueError: If no fields are provided to update.
1815
1885
  APIError: If the API request fails (e.g., 404 highlight not found).
1816
1886
  pydantic.ValidationError: If response validation fails (and is not disabled).
1817
1887
  """
1888
+ # Construct update_data from provided arguments, excluding None values
1889
+ update_data = {}
1890
+ if color is not None:
1891
+ update_data["color"] = color
1892
+
1893
+ # Ensure at least one field is being updated
1894
+ if not update_data:
1895
+ raise ValueError("At least one field must be provided to update.")
1896
+
1818
1897
  endpoint = f"highlights/{highlight_id}"
1819
1898
  response_data = self._call("PATCH", endpoint, data=update_data)
1820
1899
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karakeep_python_api
3
- Version: 0.2.2
3
+ Version: 1.0.0
4
4
  Summary: Community python client for the Karakeep API.
5
5
  Home-page: https://github.com/thiswillbeyourgithub/karakeep_python_api/
6
6
  License: GPLv3
@@ -52,6 +52,7 @@ A community-developed Python client for the [Karakeep](https://karakeep.app/) AP
52
52
  - [Environment Variables](#environment-variables)
53
53
  - [Command Line Interface (CLI)](#command-line-interface-cli)
54
54
  - [Python Library](#python-library)
55
+ - [Community Scripts](#community-scripts)
55
56
  - [Development](#development)
56
57
  - [License](#license)
57
58
 
@@ -239,11 +240,17 @@ except Exception as e:
239
240
 
240
241
  ```
241
242
 
242
- ### Usage Examples
243
+ ## Community Scripts
243
244
 
244
245
  Examples of the API being used can be found in the [`./examples`](./examples) folder. Don't hesitate to submit yours!
245
246
 
246
- - **Omnivore Archiving Status Updater**: A script to fix the archive status of bookmarks imported from Omnivore into Karakeep. See [`examples/omnivore_archiving_status_updater/README.md`](./examples/omnivore_archiving_status_updater/README.md) for details.
247
+ | Example Script | Description | Documentation |
248
+ |----------------|-------------|---------------|
249
+ | **Add Time-to-Read Tags** | Automatically adds time-to-read tags (`0-5m`, `5-10m`, etc.) to bookmarks based on content length analysis. Includes systemd service and timer files for automated periodic execution. | [`README.md`](./examples/add_time_to_read_tag/README.md) |
250
+ | **List to Tag Converter** | Converts a Karakeep list into tags by adding a specified tag to all bookmarks within that list. | [`README.md`](./examples/list_to_tag/README.md) |
251
+ | **Omnivore Highlights Importer** | Imports highlights from Omnivore export data to Karakeep, with intelligent position detection and bookmark matching. Supports dry-run mode for testing. | [`README.md`](./examples/omnivore_highlights_importer/README.md) |
252
+ | **Omnivore Archiving Status Updater** | Fixes the archived status of bookmarks imported from Omnivore by reading export data and updating Karakeep accordingly. | [`README.md`](./examples/omnivore_archiving_status_updater/README.md) |
253
+ | **Pocket Archiving Status Updater** | Fixes the archived status of bookmarks imported from Pocket by reading export data and updating Karakeep accordingly. | [`README.md`](./examples/pocket_archiving_status_updater/README.md) |
247
254
 
248
255
  ## Development
249
256
 
@@ -1,11 +1,11 @@
1
1
  karakeep_python_api/__init__.py,sha256=qk3MeIIvnCNAyYzJrv8dMKVXvA4ejLU3mhB3xFzdLDY,606
2
2
  karakeep_python_api/__main__.py,sha256=UfL6R-S3rJB7PH3iqTicNq0cvtumnrG_FVyKK36bqdE,32327
3
3
  karakeep_python_api/datatypes.py,sha256=CScuMq5oT4YwvGH8Af_Oo60xGmC622d74f4WPUw7l8Q,3398
4
- karakeep_python_api/karakeep_api.py,sha256=Ft8FjCzRhDiAYwSMj6c1l2X_6EftJOIrvv_tYGOYMUc,81921
4
+ karakeep_python_api/karakeep_api.py,sha256=Fpyc3A4Gph3czirIDztsvzbtnegmkDLmiJNDCdgTt04,84749
5
5
  karakeep_python_api/openapi_reference.json,sha256=Ku1cO_N4QPLQc7sK8L7FRt2T68QyPCwTGA7RK-046iU,80379
6
- karakeep_python_api-0.2.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
7
- karakeep_python_api-0.2.2.dist-info/METADATA,sha256=b0THcqqdtYH1GfB16HIBhI0-7TSEJnlwXTAUUaTXClE,12967
8
- karakeep_python_api-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- karakeep_python_api-0.2.2.dist-info/entry_points.txt,sha256=n0leQp_IX2NivoWuUcaR9ZHwAvl_6yt-NcHWuCJyxNo,62
10
- karakeep_python_api-0.2.2.dist-info/top_level.txt,sha256=X3VKqh9YAbPQp144db0Ko2C5Q2y6-nwpPgtnuCiSDmU,20
11
- karakeep_python_api-0.2.2.dist-info/RECORD,,
6
+ karakeep_python_api-1.0.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
7
+ karakeep_python_api-1.0.0.dist-info/METADATA,sha256=joWnEpuTHNzpSr4U4EJ-Xb48YK8_YU-rrYHW9HWGsAg,14026
8
+ karakeep_python_api-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ karakeep_python_api-1.0.0.dist-info/entry_points.txt,sha256=n0leQp_IX2NivoWuUcaR9ZHwAvl_6yt-NcHWuCJyxNo,62
10
+ karakeep_python_api-1.0.0.dist-info/top_level.txt,sha256=X3VKqh9YAbPQp144db0Ko2C5Q2y6-nwpPgtnuCiSDmU,20
11
+ karakeep_python_api-1.0.0.dist-info/RECORD,,