eagle-cooler 0.1.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.
- eagle_cooler/__init__.py +5 -0
- eagle_cooler/callback.py +1078 -0
- eagle_cooler/context.py +46 -0
- eagle_cooler/core.py +55 -0
- eagle_cooler/model.py +48 -0
- eagle_cooler/webapi.py +246 -0
- eagle_cooler-0.1.0.dist-info/METADATA +245 -0
- eagle_cooler-0.1.0.dist-info/RECORD +10 -0
- eagle_cooler-0.1.0.dist-info/WHEEL +4 -0
- eagle_cooler-0.1.0.dist-info/entry_points.txt +3 -0
eagle_cooler/context.py
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
from eagle_cooler import EagleWebApi
|
3
|
+
|
4
|
+
from eagle_cooler.model import FolderModel, ItemModel
|
5
|
+
from .core import EagleCoolerCore
|
6
|
+
|
7
|
+
class EagleContext:
|
8
|
+
def get_selected_folder_ids(self) -> list[str]:
|
9
|
+
"""Get selected folder IDs from the context if available"""
|
10
|
+
return EagleCoolerCore.selected_folder_ids()
|
11
|
+
|
12
|
+
def get_selected_item_ids(self) -> list[str]:
|
13
|
+
"""Get selected item IDs from the context if available"""
|
14
|
+
return EagleCoolerCore.selected_item_ids()
|
15
|
+
|
16
|
+
def get_selected_folders(self) -> list[FolderModel]:
|
17
|
+
folder_ids = self.get_selected_folder_ids()
|
18
|
+
if not folder_ids:
|
19
|
+
return []
|
20
|
+
|
21
|
+
all_folders = EagleWebApi.folder.list()
|
22
|
+
return [folder for folder in all_folders if folder['id'] in folder_ids]
|
23
|
+
|
24
|
+
def get_selected_items(self, throw : bool = False) -> list[ItemModel]:
|
25
|
+
item_ids = self.get_selected_item_ids()
|
26
|
+
if not item_ids:
|
27
|
+
return []
|
28
|
+
|
29
|
+
selected_items = []
|
30
|
+
for selected_item in item_ids:
|
31
|
+
try:
|
32
|
+
item_info = EagleWebApi.item.get_info(selected_item)
|
33
|
+
if item_info:
|
34
|
+
selected_items.append(item_info)
|
35
|
+
continue
|
36
|
+
except Exception as e:
|
37
|
+
if throw:
|
38
|
+
raise e
|
39
|
+
|
40
|
+
continue
|
41
|
+
|
42
|
+
return selected_items
|
43
|
+
|
44
|
+
eagleContext = EagleContext()
|
45
|
+
|
46
|
+
__all__ = ["eagleContext"]
|
eagle_cooler/core.py
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
import requests
|
4
|
+
from typing import Optional
|
5
|
+
|
6
|
+
class EagleCoolerCore:
|
7
|
+
__fullBridgeContext = None
|
8
|
+
__token = None
|
9
|
+
__applicationInfo = None
|
10
|
+
|
11
|
+
@classmethod
|
12
|
+
def __load(cls):
|
13
|
+
# Load context when class is defined
|
14
|
+
try:
|
15
|
+
context_env = os.environ.get("POWEREAGLE_CONTEXT")
|
16
|
+
if context_env:
|
17
|
+
cls.__fullBridgeContext = json.loads(context_env)
|
18
|
+
cls.__token = cls.__fullBridgeContext.get("apiToken")
|
19
|
+
return # Successfully loaded, exit early
|
20
|
+
except Exception as e:
|
21
|
+
print(f"Failed to load Power Eagle context: {e}")
|
22
|
+
|
23
|
+
# Fallback to Eagle API if Power Eagle context failed
|
24
|
+
try:
|
25
|
+
response = requests.get("http://localhost:41595/api/application/info", timeout=5)
|
26
|
+
if response.status_code == 200:
|
27
|
+
cls.__applicationInfo = response.json()
|
28
|
+
token = cls.__applicationInfo.get("data", {}).get("preferences", {}).get("developer", {}).get("apiToken")
|
29
|
+
if token:
|
30
|
+
cls.__token = token
|
31
|
+
except Exception as api_error:
|
32
|
+
print(f"Failed to get token from Eagle API: {api_error}")
|
33
|
+
cls.__token = None
|
34
|
+
|
35
|
+
@classmethod
|
36
|
+
def token(cls) -> Optional[str]:
|
37
|
+
"""Get API token"""
|
38
|
+
return cls.__token
|
39
|
+
|
40
|
+
@classmethod
|
41
|
+
def selected_item_ids(cls) -> Optional[list]:
|
42
|
+
"""Get selected items from the context if available"""
|
43
|
+
if cls.__fullBridgeContext:
|
44
|
+
return cls.__fullBridgeContext.get("selected").get("items")
|
45
|
+
return None
|
46
|
+
|
47
|
+
@classmethod
|
48
|
+
def selected_folder_ids(cls) -> Optional[list]:
|
49
|
+
"""Get selected folders from the context if available"""
|
50
|
+
if cls.__fullBridgeContext:
|
51
|
+
return cls.__fullBridgeContext.get("selected").get("folders")
|
52
|
+
return None
|
53
|
+
|
54
|
+
EagleCoolerCore._EagleCoolerCore__load()
|
55
|
+
|
eagle_cooler/model.py
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
from typing import TypedDict, Any
|
2
|
+
|
3
|
+
|
4
|
+
class FolderModel(TypedDict):
|
5
|
+
"""TypedDict model for Eagle folder structure"""
|
6
|
+
id: str
|
7
|
+
name: str
|
8
|
+
description: str
|
9
|
+
children: list[str] # List of child folder IDs
|
10
|
+
modificationTime: int # Unix timestamp in milliseconds
|
11
|
+
tags: list[str]
|
12
|
+
extendTags: list[str]
|
13
|
+
pinyin: str
|
14
|
+
password: str
|
15
|
+
passwordTips: str
|
16
|
+
|
17
|
+
|
18
|
+
class OCRModel(TypedDict):
|
19
|
+
"""TypedDict model for OCR data"""
|
20
|
+
done: str
|
21
|
+
text: str
|
22
|
+
|
23
|
+
|
24
|
+
class DetectionModel(TypedDict):
|
25
|
+
"""TypedDict model for object detection data"""
|
26
|
+
done: str
|
27
|
+
objects: list[Any] # Object detection results
|
28
|
+
|
29
|
+
|
30
|
+
class ItemModel(TypedDict):
|
31
|
+
"""TypedDict model for Eagle item structure"""
|
32
|
+
id: str
|
33
|
+
name: str
|
34
|
+
size: int # File size in bytes
|
35
|
+
btime: int # Birth time (creation time) in milliseconds
|
36
|
+
mtime: int # File modification time in milliseconds
|
37
|
+
ext: str # File extension
|
38
|
+
tags: list[str]
|
39
|
+
folders: list[str] # List of folder IDs this item belongs to
|
40
|
+
isDeleted: bool
|
41
|
+
url: str
|
42
|
+
annotation: str
|
43
|
+
modificationTime: int # Eagle modification time in milliseconds
|
44
|
+
noPreview: bool
|
45
|
+
lastModified: int # Last modified time in milliseconds
|
46
|
+
ocr: OCRModel
|
47
|
+
detection: DetectionModel
|
48
|
+
|
eagle_cooler/webapi.py
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
import requests
|
4
|
+
from typing import Optional, Dict, Any, List
|
5
|
+
from .core import EagleCoolerCore
|
6
|
+
|
7
|
+
|
8
|
+
class EagleWebApi:
|
9
|
+
"""Python implementation of Eagle API client for HTTP requests to Eagle application"""
|
10
|
+
|
11
|
+
_token: Optional[str] = None
|
12
|
+
|
13
|
+
@classmethod
|
14
|
+
def _make_request(cls, path: str, method: str = "GET", data: Optional[Dict[str, Any]] = None,
|
15
|
+
params: Optional[Dict[str, Any]] = None) -> Any:
|
16
|
+
"""Makes internal HTTP request to Eagle API"""
|
17
|
+
token = EagleCoolerCore.token()
|
18
|
+
if not token:
|
19
|
+
raise Exception("No API token found")
|
20
|
+
|
21
|
+
url = f"http://localhost:41595/api/{path}"
|
22
|
+
|
23
|
+
# Add token to params
|
24
|
+
if params is None:
|
25
|
+
params = {}
|
26
|
+
params["token"] = token
|
27
|
+
|
28
|
+
# Remove None values from params and data
|
29
|
+
if params:
|
30
|
+
params = {k: v for k, v in params.items() if v is not None}
|
31
|
+
if data:
|
32
|
+
data = {k: v for k, v in data.items() if v is not None}
|
33
|
+
|
34
|
+
try:
|
35
|
+
if method.upper() == "POST":
|
36
|
+
response = requests.post(url, params=params, json=data)
|
37
|
+
else:
|
38
|
+
response = requests.get(url, params=params)
|
39
|
+
|
40
|
+
response.raise_for_status()
|
41
|
+
result = response.json()
|
42
|
+
return result.get("data")
|
43
|
+
except Exception as e:
|
44
|
+
print(f"Request failed: {e}")
|
45
|
+
raise e
|
46
|
+
|
47
|
+
class _Application:
|
48
|
+
"""_Application-related API methods"""
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def info() -> Any:
|
52
|
+
"""Gets application information"""
|
53
|
+
return EagleWebApi._make_request("application/info")
|
54
|
+
|
55
|
+
class _Folder:
|
56
|
+
"""_Folder-related API methods"""
|
57
|
+
|
58
|
+
@staticmethod
|
59
|
+
def create(name: str, parent_id: Optional[str] = None) -> Any:
|
60
|
+
"""Creates a new folder"""
|
61
|
+
return EagleWebApi._make_request("folder/create", "POST", {
|
62
|
+
"folderName": name,
|
63
|
+
"parent": parent_id
|
64
|
+
})
|
65
|
+
|
66
|
+
@staticmethod
|
67
|
+
def rename(folder_id: str, new_name: str) -> Any:
|
68
|
+
"""Renames a folder"""
|
69
|
+
return EagleWebApi._make_request("folder/rename", "POST", {
|
70
|
+
"folderId": folder_id,
|
71
|
+
"newName": new_name
|
72
|
+
})
|
73
|
+
|
74
|
+
@staticmethod
|
75
|
+
def update(folder_id: str, new_name: Optional[str] = None,
|
76
|
+
new_description: Optional[str] = None, new_color: Optional[str] = None) -> Any:
|
77
|
+
"""Updates folder properties"""
|
78
|
+
return EagleWebApi._make_request("folder/update", "POST", {
|
79
|
+
"folderId": folder_id,
|
80
|
+
"newName": new_name,
|
81
|
+
"newDescription": new_description,
|
82
|
+
"newColor": new_color
|
83
|
+
})
|
84
|
+
|
85
|
+
@staticmethod
|
86
|
+
def list() -> Any:
|
87
|
+
"""Lists all folders"""
|
88
|
+
return EagleWebApi._make_request("folder/list")
|
89
|
+
|
90
|
+
@staticmethod
|
91
|
+
def list_recent() -> Any:
|
92
|
+
"""Lists recent folders"""
|
93
|
+
return EagleWebApi._make_request("folder/listRecent")
|
94
|
+
|
95
|
+
class _Library:
|
96
|
+
"""_Library-related API methods"""
|
97
|
+
|
98
|
+
@staticmethod
|
99
|
+
def info() -> Any:
|
100
|
+
"""Gets library information"""
|
101
|
+
return EagleWebApi._make_request("library/info")
|
102
|
+
|
103
|
+
@staticmethod
|
104
|
+
def history() -> Any:
|
105
|
+
"""Gets library history"""
|
106
|
+
return EagleWebApi._make_request("library/history")
|
107
|
+
|
108
|
+
@staticmethod
|
109
|
+
def switch(library_path: str) -> Any:
|
110
|
+
"""Switches to a different library"""
|
111
|
+
return EagleWebApi._make_request("library/switch", "POST", {
|
112
|
+
"libraryPath": library_path
|
113
|
+
})
|
114
|
+
|
115
|
+
@staticmethod
|
116
|
+
def icon(library_path: str) -> Any:
|
117
|
+
"""Gets library icon"""
|
118
|
+
return EagleWebApi._make_request("library/icon", params={
|
119
|
+
"libraryPath": library_path
|
120
|
+
})
|
121
|
+
|
122
|
+
class _Item:
|
123
|
+
"""_Item-related API methods"""
|
124
|
+
|
125
|
+
@staticmethod
|
126
|
+
def update(item_id: str, tags: Optional[List[str]] = None, annotation: Optional[str] = None,
|
127
|
+
url: Optional[str] = None, star: Optional[int] = None) -> Any:
|
128
|
+
"""Updates item properties"""
|
129
|
+
return EagleWebApi._make_request("item/update", "POST", {
|
130
|
+
"id": item_id,
|
131
|
+
"tags": tags,
|
132
|
+
"annotation": annotation,
|
133
|
+
"url": url,
|
134
|
+
"star": star
|
135
|
+
})
|
136
|
+
|
137
|
+
@staticmethod
|
138
|
+
def refresh_thumbnail(item_id: str) -> Any:
|
139
|
+
"""Refreshes item thumbnail"""
|
140
|
+
return EagleWebApi._make_request("item/refreshThumbnail", "POST", {
|
141
|
+
"id": item_id
|
142
|
+
})
|
143
|
+
|
144
|
+
@staticmethod
|
145
|
+
def refresh_palette(item_id: str) -> Any:
|
146
|
+
"""Refreshes item color palette"""
|
147
|
+
return EagleWebApi._make_request("item/refreshPalette", "POST", {
|
148
|
+
"id": item_id
|
149
|
+
})
|
150
|
+
|
151
|
+
@staticmethod
|
152
|
+
def move_to_trash(item_ids: List[str]) -> Any:
|
153
|
+
"""Moves items to trash"""
|
154
|
+
return EagleWebApi._make_request("item/moveToTrash", "POST", {
|
155
|
+
"itemIds": item_ids
|
156
|
+
})
|
157
|
+
|
158
|
+
@staticmethod
|
159
|
+
def list(limit: Optional[int] = None, offset: Optional[int] = None,
|
160
|
+
order_by: Optional[str] = None, keyword: Optional[str] = None,
|
161
|
+
ext: Optional[str] = None, tags: Optional[List[str]] = None,
|
162
|
+
folders: Optional[List[str]] = None) -> Any:
|
163
|
+
"""Lists items with filters"""
|
164
|
+
return EagleWebApi._make_request("item/list", params={
|
165
|
+
"limit": limit,
|
166
|
+
"offset": offset,
|
167
|
+
"orderBy": order_by,
|
168
|
+
"keyword": keyword,
|
169
|
+
"ext": ext,
|
170
|
+
"tags": tags,
|
171
|
+
"folders": folders
|
172
|
+
})
|
173
|
+
|
174
|
+
@staticmethod
|
175
|
+
def get_thumbnail(item_id: str) -> Any:
|
176
|
+
"""Gets item thumbnail"""
|
177
|
+
return EagleWebApi._make_request("item/thumbnail", params={
|
178
|
+
"id": item_id
|
179
|
+
})
|
180
|
+
|
181
|
+
@staticmethod
|
182
|
+
def get_info(item_id: str) -> Any:
|
183
|
+
"""Gets item information"""
|
184
|
+
return EagleWebApi._make_request("item/info", params={
|
185
|
+
"id": item_id
|
186
|
+
})
|
187
|
+
|
188
|
+
@staticmethod
|
189
|
+
def add_bookmark(url: str, name: str, base64: Optional[str] = None,
|
190
|
+
tags: Optional[List[str]] = None, modification_time: Optional[int] = None,
|
191
|
+
folder_id: Optional[str] = None) -> Any:
|
192
|
+
"""Adds bookmark item"""
|
193
|
+
return EagleWebApi._make_request("item/addBookmark", "POST", {
|
194
|
+
"url": url,
|
195
|
+
"name": name,
|
196
|
+
"base64": base64,
|
197
|
+
"tags": tags,
|
198
|
+
"modificationTime": modification_time,
|
199
|
+
"folderId": folder_id
|
200
|
+
})
|
201
|
+
|
202
|
+
@staticmethod
|
203
|
+
def add_from_url(url: str, name: str, website: Optional[str] = None,
|
204
|
+
tags: Optional[List[str]] = None, star: Optional[int] = None,
|
205
|
+
annotation: Optional[str] = None, modification_time: Optional[int] = None,
|
206
|
+
folder_id: Optional[str] = None, headers: Optional[Dict[str, Any]] = None) -> Any:
|
207
|
+
"""Adds item from URL"""
|
208
|
+
return EagleWebApi._make_request("item/addFromUrl", "POST", {
|
209
|
+
"url": url,
|
210
|
+
"name": name,
|
211
|
+
"website": website,
|
212
|
+
"tags": tags,
|
213
|
+
"star": star,
|
214
|
+
"annotation": annotation,
|
215
|
+
"modificationTime": modification_time,
|
216
|
+
"folderId": folder_id,
|
217
|
+
"headers": headers
|
218
|
+
})
|
219
|
+
|
220
|
+
@staticmethod
|
221
|
+
def add_from_path(path: str, name: str, website: Optional[str] = None,
|
222
|
+
annotation: Optional[str] = None, tags: Optional[List[str]] = None,
|
223
|
+
folder_id: Optional[str] = None) -> Any:
|
224
|
+
"""Adds item from file path"""
|
225
|
+
return EagleWebApi._make_request("item/addFromPath", "POST", {
|
226
|
+
"path": path,
|
227
|
+
"name": name,
|
228
|
+
"website": website,
|
229
|
+
"annotation": annotation,
|
230
|
+
"tags": tags,
|
231
|
+
"folderId": folder_id
|
232
|
+
})
|
233
|
+
|
234
|
+
@staticmethod
|
235
|
+
def add_from_urls(items: List[Dict[str, Any]], folder_id: Optional[str] = None) -> Any:
|
236
|
+
"""Adds multiple items from URLs"""
|
237
|
+
return EagleWebApi._make_request("item/addFromURLs", "POST", {
|
238
|
+
"items": items,
|
239
|
+
"folderId": folder_id
|
240
|
+
})
|
241
|
+
|
242
|
+
# Create class-level aliases for easier access
|
243
|
+
application = _Application()
|
244
|
+
folder = _Folder()
|
245
|
+
library = _Library()
|
246
|
+
item = _Item()
|
@@ -0,0 +1,245 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: eagle-cooler
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: Python library for bridging Eagle js environment
|
5
|
+
Author: ZackaryW
|
6
|
+
Author-email: ZackaryW <gitzackw@gmail.com>
|
7
|
+
Requires-Dist: requests>=2.25.0
|
8
|
+
Requires-Python: >=3.13
|
9
|
+
Description-Content-Type: text/markdown
|
10
|
+
|
11
|
+
# Eagle Cooler 🦅❄️
|
12
|
+
|
13
|
+
[](https://badge.fury.io/py/eagle-cooler)
|
14
|
+
[](https://pypi.org/project/eagle-cooler/)
|
15
|
+
[](LICENSE)
|
16
|
+
|
17
|
+
A modern Python wrapper for the [Eagle.cool](https://eagle.cool) HTTP API. Works independently with Eagle's web API or seamlessly integrates with the Power Eagle plugin system for enhanced functionality.
|
18
|
+
|
19
|
+
## ✨ Features
|
20
|
+
|
21
|
+
- 🚀 **Complete API Coverage** - Full implementation of Eagle's HTTP API
|
22
|
+
- 🔐 **Flexible Authentication** - Works standalone with manual token setup or automatically with Power Eagle
|
23
|
+
- 📝 **Type Hints** - Better development experience with full type annotations
|
24
|
+
- 🎯 **Easy-to-use Interface** - Clean, class-based API design
|
25
|
+
- ⚡ **Modern Python** - Built for Python 3.13+ with modern best practices
|
26
|
+
- 🔌 **Plugin Ready** - Enhanced integration with Power Eagle plugin ecosystem
|
27
|
+
- 🏠 **Standalone Ready** - Can work independently with just Eagle's web API
|
28
|
+
|
29
|
+
## 📦 Installation
|
30
|
+
|
31
|
+
Install the latest stable version from PyPI:
|
32
|
+
|
33
|
+
```bash
|
34
|
+
# Using uv (recommended)
|
35
|
+
uv add eagle-cooler
|
36
|
+
|
37
|
+
# Using pip
|
38
|
+
pip install eagle-cooler
|
39
|
+
|
40
|
+
# For development
|
41
|
+
git clone https://github.com/ZackaryW/py-eagle-cooler.git
|
42
|
+
cd py-eagle-cooler
|
43
|
+
uv sync --dev
|
44
|
+
```
|
45
|
+
|
46
|
+
## 🚀 Quick Start
|
47
|
+
|
48
|
+
### Standalone Usage (Web API Only)
|
49
|
+
|
50
|
+
For basic functionality using Eagle's HTTP API directly:
|
51
|
+
|
52
|
+
```python
|
53
|
+
from eagle_cooler import EagleWebApi
|
54
|
+
|
55
|
+
# Get application info
|
56
|
+
app_info = EagleWebApi.application.info()
|
57
|
+
print(f"Eagle version: {app_info['version']}")
|
58
|
+
|
59
|
+
# List folders
|
60
|
+
folders = EagleWebApi.folder.list()
|
61
|
+
print(f"Found {len(folders)} folders")
|
62
|
+
|
63
|
+
# Create a new folder
|
64
|
+
new_folder = EagleWebApi.folder.create("My New Folder")
|
65
|
+
print(f"Created: {new_folder['name']}")
|
66
|
+
|
67
|
+
# List items with filters
|
68
|
+
items = EagleWebApi.item.list(limit=10, ext="jpg")
|
69
|
+
print(f"Found {len(items)} JPG images")
|
70
|
+
|
71
|
+
# Add item from URL
|
72
|
+
result = EagleWebApi.item.add_from_url(
|
73
|
+
url="https://example.com/image.jpg",
|
74
|
+
name="Example Image",
|
75
|
+
tags=["example", "test"]
|
76
|
+
)
|
77
|
+
|
78
|
+
# Add item from local file
|
79
|
+
local_item = EagleWebApi.item.add_from_path(
|
80
|
+
path="/path/to/image.jpg",
|
81
|
+
name="Local Image",
|
82
|
+
tags=["local"]
|
83
|
+
)
|
84
|
+
```
|
85
|
+
|
86
|
+
### Power Eagle Integration (Enhanced Features)
|
87
|
+
|
88
|
+
When running in a Power Eagle context, access to enhanced features:
|
89
|
+
|
90
|
+
```python
|
91
|
+
# In a Power Eagle Python script
|
92
|
+
from eagle_cooler import eagleContext, EagleCallback
|
93
|
+
|
94
|
+
# Get selected items and folders from Power Eagle context
|
95
|
+
selected_items = eagleContext.get_selected_items()
|
96
|
+
selected_folders = eagleContext.get_selected_folders()
|
97
|
+
|
98
|
+
# Get just the IDs if needed
|
99
|
+
selected_item_ids = eagleContext.get_selected_item_ids()
|
100
|
+
selected_folder_ids = eagleContext.get_selected_folder_ids()
|
101
|
+
|
102
|
+
# Use callback system for advanced plugin operations
|
103
|
+
# (extensive callback API available for plugin development)
|
104
|
+
```
|
105
|
+
|
106
|
+
## 📚 API Reference
|
107
|
+
|
108
|
+
### 🏢 Application
|
109
|
+
- `EagleWebApi.application.info()` - Get application information
|
110
|
+
|
111
|
+
### 📁 Folders
|
112
|
+
- `EagleWebApi.folder.create(name, parent_id=None)` - Create folder
|
113
|
+
- `EagleWebApi.folder.rename(folder_id, new_name)` - Rename folder
|
114
|
+
- `EagleWebApi.folder.update(folder_id, new_name=None, new_description=None, new_color=None)` - Update folder properties
|
115
|
+
- `EagleWebApi.folder.list()` - List all folders
|
116
|
+
- `EagleWebApi.folder.list_recent()` - List recent folders
|
117
|
+
|
118
|
+
### 📚 Library
|
119
|
+
- `EagleWebApi.library.info()` - Get library information
|
120
|
+
- `EagleWebApi.library.history()` - Get library history
|
121
|
+
- `EagleWebApi.library.switch(library_path)` - Switch to different library
|
122
|
+
- `EagleWebApi.library.icon(library_path)` - Get library icon
|
123
|
+
|
124
|
+
### 🖼️ Items
|
125
|
+
- `EagleWebApi.item.list(limit=None, offset=None, order_by=None, keyword=None, ext=None, tags=None, folders=None)` - List items with filters
|
126
|
+
- `EagleWebApi.item.get_info(item_id)` - Get item details
|
127
|
+
- `EagleWebApi.item.get_thumbnail(item_id)` - Get item thumbnail
|
128
|
+
- `EagleWebApi.item.update(item_id, tags=None, annotation=None, url=None, star=None)` - Update item properties
|
129
|
+
- `EagleWebApi.item.add_from_url(url, name, website=None, tags=None, star=None, annotation=None, modification_time=None, folder_id=None, headers=None)` - Add item from URL
|
130
|
+
- `EagleWebApi.item.add_from_path(path, name, website=None, annotation=None, tags=None, folder_id=None)` - Add item from file path
|
131
|
+
- `EagleWebApi.item.add_from_urls(items, folder_id=None)` - Add multiple items from URLs
|
132
|
+
- `EagleWebApi.item.add_bookmark(url, name, base64=None, tags=None, modification_time=None, folder_id=None)` - Add bookmark
|
133
|
+
- `EagleWebApi.item.move_to_trash(item_ids)` - Move items to trash
|
134
|
+
- `EagleWebApi.item.refresh_thumbnail(item_id)` - Refresh thumbnail
|
135
|
+
- `EagleWebApi.item.refresh_palette(item_id)` - Refresh color palette
|
136
|
+
|
137
|
+
### 🔧 Context (Power Eagle Mode)
|
138
|
+
- `eagleContext.get_selected_item_ids()` - Get selected item IDs from Power Eagle context
|
139
|
+
- `eagleContext.get_selected_folder_ids()` - Get selected folder IDs from Power Eagle context
|
140
|
+
- `eagleContext.get_selected_items(throw=False)` - Get selected items as typed ItemModel objects
|
141
|
+
- `eagleContext.get_selected_folders()` - Get selected folders as typed FolderModel objects
|
142
|
+
|
143
|
+
### 📞 Callbacks (Power Eagle Plugins)
|
144
|
+
- `EagleCallback` - Callback system for Power Eagle plugin integration (extensive API available)
|
145
|
+
|
146
|
+
## 🔌 Usage Modes
|
147
|
+
|
148
|
+
Eagle Cooler supports two usage modes:
|
149
|
+
|
150
|
+
### 🏠 Standalone Mode (Web API)
|
151
|
+
- **Limited Capacity**: Basic API operations through Eagle's HTTP interface
|
152
|
+
- **Manual Setup**: Requires Eagle application running with HTTP API enabled
|
153
|
+
- **Authentication**: Uses direct API calls (no token management)
|
154
|
+
- **Features**: Core operations like listing, creating folders, basic item management
|
155
|
+
|
156
|
+
### 🚀 Power Eagle Mode (Enhanced)
|
157
|
+
- **Full Capacity**: Complete feature set with enhanced functionality
|
158
|
+
- **Automatic Setup**: Token and context management handled automatically
|
159
|
+
- **Authentication**: Seamless integration with Power Eagle's security context
|
160
|
+
- **Features**: All core operations plus callbacks, advanced file operations, and plugin ecosystem integration
|
161
|
+
|
162
|
+
```python
|
163
|
+
# Standalone mode example
|
164
|
+
from eagle_cooler import EagleWebApi
|
165
|
+
|
166
|
+
# Basic operations available
|
167
|
+
folders = EagleWebApi.folder.list()
|
168
|
+
|
169
|
+
# Power Eagle mode example (when POWEREAGLE_CONTEXT is available)
|
170
|
+
from eagle_cooler import EagleWebApi, eagleContext, EagleCallback
|
171
|
+
|
172
|
+
# Enhanced operations available:
|
173
|
+
# 1. Automatic token management
|
174
|
+
folders = EagleWebApi.folder.list()
|
175
|
+
|
176
|
+
# 2. Access to Power Eagle context with typed models
|
177
|
+
selected_items = eagleContext.get_selected_items() # Returns list[ItemModel]
|
178
|
+
selected_folders = eagleContext.get_selected_folders() # Returns list[FolderModel]
|
179
|
+
|
180
|
+
# 3. Callback system for advanced plugin operations
|
181
|
+
if selected_items:
|
182
|
+
for item in selected_items:
|
183
|
+
print(f"Selected item: {item['name']} ({item['ext']})")
|
184
|
+
# Use callback system to interact with Power Eagle host
|
185
|
+
# (extensive callback API available - see METHODS_WITH_RETURN_VALUES)
|
186
|
+
```
|
187
|
+
|
188
|
+
## ⚙️ Requirements
|
189
|
+
|
190
|
+
- **Python**: >= 3.13
|
191
|
+
- **Eagle.cool**: Application running with API access enabled
|
192
|
+
- **Dependencies**: `requests >= 2.25.0`
|
193
|
+
- **For Power Eagle**: `POWEREAGLE_CONTEXT` environment variable set
|
194
|
+
|
195
|
+
### Setup Eagle API Access
|
196
|
+
|
197
|
+
1. Open Eagle.cool application
|
198
|
+
2. Go to **Preferences** → **Plugin**
|
199
|
+
3. Enable **HTTP API**
|
200
|
+
4. Note the API port (default: 41595)
|
201
|
+
|
202
|
+
## 🤝 Contributing
|
203
|
+
|
204
|
+
We welcome contributions! Here's how to get started:
|
205
|
+
|
206
|
+
1. **Fork the repository**
|
207
|
+
2. **Clone your fork**:
|
208
|
+
```bash
|
209
|
+
git clone https://github.com/yourusername/py-eagle-cooler.git
|
210
|
+
cd py-eagle-cooler
|
211
|
+
```
|
212
|
+
3. **Install development dependencies**:
|
213
|
+
```bash
|
214
|
+
uv sync --dev
|
215
|
+
```
|
216
|
+
4. **Make your changes**
|
217
|
+
5. **Run tests** (when available):
|
218
|
+
```bash
|
219
|
+
uv run pytest
|
220
|
+
```
|
221
|
+
6. **Submit a pull request**
|
222
|
+
|
223
|
+
### Development Setup
|
224
|
+
|
225
|
+
```bash
|
226
|
+
# Clone the repository
|
227
|
+
git clone https://github.com/ZackaryW/py-eagle-cooler.git
|
228
|
+
cd py-eagle-cooler
|
229
|
+
|
230
|
+
# Install with development dependencies
|
231
|
+
uv sync --dev
|
232
|
+
|
233
|
+
# Run the package in development mode
|
234
|
+
uv run python -m eagle_cooler
|
235
|
+
```
|
236
|
+
|
237
|
+
## 📜 License
|
238
|
+
|
239
|
+
This project is licensed under the same terms as Power Eagle.
|
240
|
+
|
241
|
+
---
|
242
|
+
|
243
|
+
<p align="center">
|
244
|
+
<sub>Built with ❤️ for the Eagle.cool community</sub>
|
245
|
+
</p>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
eagle_cooler/__init__.py,sha256=DJU-5HsVAnYftHWy4Ue6HCSt_U4Ex-j7n8UOQzxBX0I,231
|
2
|
+
eagle_cooler/callback.py,sha256=Eg6hZAtr6uKVES7xgV3hoTejMqtRFbu8qM9KWr7tyNo,36119
|
3
|
+
eagle_cooler/context.py,sha256=ICNi8vfep2UH9TKMniKYy3IvHgbMGynyVJhWPmeV-Ik,1462
|
4
|
+
eagle_cooler/core.py,sha256=JXBf3hUgPpWKfPWyAn7EE60nKPR7QSfk7w8y9y0PA8o,1945
|
5
|
+
eagle_cooler/model.py,sha256=BSjxgPw9_5t7J5Lcjt2VaH6KSdz21MgKemGGyCKZXAY,1257
|
6
|
+
eagle_cooler/webapi.py,sha256=COCCh1o_9saf5huCV7AGvoDSLouafVe3aor5wUq1uOQ,9091
|
7
|
+
eagle_cooler-0.1.0.dist-info/WHEEL,sha256=Pi5uDq5Fdo_Rr-HD5h9BiPn9Et29Y9Sh8NhcJNnFU1c,79
|
8
|
+
eagle_cooler-0.1.0.dist-info/entry_points.txt,sha256=pDVCjWW7abbqDCWZdMaowSdiRl4TkDQ5eTajXU1YEck,52
|
9
|
+
eagle_cooler-0.1.0.dist-info/METADATA,sha256=B1YbxPqYG1NfYXDn1hahC9PFnVql5cbS614YZIBk-ck,8582
|
10
|
+
eagle_cooler-0.1.0.dist-info/RECORD,,
|