diff --git a/CHANGELOG.md b/CHANGELOG.md
index d3483f8..c32e245 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,21 @@
All notable changes to `status-python-sdk` will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.4.0] - 2026-10-14
+
+### Added
+
+- Completed Enum for Content Type
+- Function `listen_events` that listen to all event by default
+
+### Changed
+
+- `listen_messages` don't take any arguement and return all message of type `TEXT`, `STICKER`, `EMOJI`, `IMAGE`, `BRIDGED`
+
+### Fixed
+
+- Remove `image_path` from `content` of `Message` object
+
## [1.3.0] - 2026-10-11
### Added
@@ -242,6 +257,7 @@ will try to log in without a hashed password
- Launch [status-go] Docker container with Python instead of manual `docker compose up -d` setup.
- Custom library errors
+[1.4.0]: https://github.com/status-im/status-python-sdk/releases/tag/1.4.0
[1.3.0]: https://github.com/status-im/status-python-sdk/releases/tag/1.3.0
[1.2.3]: https://github.com/status-im/status-python-sdk/releases/tag/1.2.3
[1.2.2]: https://github.com/status-im/status-python-sdk/releases/tag/1.2.2
diff --git a/docs/account.md b/docs/account.md
index 7aa2cc9..322d767 100644
--- a/docs/account.md
+++ b/docs/account.md
@@ -724,13 +724,13 @@ deleted = account.delete_message(message_id)
print(f"Deleted: {deleted}")
```
-#### `listen_messages(content=None)`
+#### `listen_events(content=[])`
-Listen for new incoming messages **in real time**. This method is ideal for developing real time chat applications.
+Listen for new events **in real time**, not only the messages. To listen to specifc events only, specify then in the `content` parameters
| Name | Type | Required | Description |
|-----|-----|-----|-------------|
-| `content` | `list[types.Content]`
`types.Content` | No | Only yield messages of the given [content type(s)](./types.md#content). |
+| `content` | `list[types.Content]`
`types.Content` | No | Only yield event of the given [content type(s)](./types.md#content). |
```python
from status_sdk import Account
@@ -746,10 +746,13 @@ for msg in account.listen_messages():
print(msg.content)
```
-Only listen for text and emoji messages:
+#### `listen_messages()`
+
+Listen for new incoming messages **in real time**. This method is ideal for developing real time chat applications.
+
```python
-from status_sdk import Account, types
+from status_sdk import Account
account = Account()
params = {
@@ -758,12 +761,10 @@ params = {
}
account.login(**params)
-for msg in account.listen_messages(content=[types.Content.TEXT, types.Content.EMOJI]):
+for msg in account.listen_messages():
print(msg.content)
```
-**Note**: If you receive multiple messages at once, `contacts` and `chats` will grow.
-
#### `listen_contact_requests()`
Listen for contact requests **in real time**. This method yields [`ContactRequest`](./models.md#contactrequest) objects, whose `incoming`, `accepted` and `removed` booleans tell the events apart:
diff --git a/docs/types.md b/docs/types.md
index 257e6e2..d691aa7 100644
--- a/docs/types.md
+++ b/docs/types.md
@@ -23,7 +23,7 @@ params = {
account.login(**params)
# Only yield text and emoji messages
-for msg in account.listen_messages(content=[types.Content.TEXT, types.Content.EMOJI]):
+for msg in account.listen_events(content=[types.Content.TEXT, types.Content.EMOJI]):
print(msg.content)
```
@@ -31,7 +31,7 @@ A single value can be passed instead of a list:
```python
# Only yield images (and albums)
-for msg in account.listen_messages(content=types.Content.IMAGE):
+for msg in account.listen_events(content=types.Content.IMAGE):
print(msg.image_urls)
```
diff --git a/pyproject.toml b/pyproject.toml
index 73163a3..864285e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "status-sdk"
-version = "1.3.0"
+version = "1.4.0"
description = "Private chat. Communities. Multi-chain wallet. Browser. dApps all in one app, powered by SNT."
readme = "README.md"
requires-python = ">=3.11"
diff --git a/status_sdk/account.py b/status_sdk/account.py
index 21526f1..d0db96f 100644
--- a/status_sdk/account.py
+++ b/status_sdk/account.py
@@ -967,16 +967,17 @@ def listen_message_mentions(self) -> Generator[models.Message, None, None]:
if mention_everyone in current_text or account_mention in current_text:
yield models.Message.from_raw(event["body"]["message"])
- def listen_messages(self, content: Optional[Union[list[types.Content], types.Content]] = None) -> Generator[models.Message, None, None]:
+ def listen_messages(self) -> Generator[models.Message, None, None]:
"""
Listen for new messages continuously. Can be used for real time processing.
"""
- if isinstance(content, type(None)):
- content = []
- elif isinstance(content, types.Content):
- content = [content]
-
- allowed_content_types = [content_type.value for content_type in (content if content else types.Content)]
+ allowed_content_types = [
+ types.Content.TEXT,
+ types.Content.STICKER,
+ types.Content.EMOJI,
+ types.Content.IMAGE,
+ types.Content.BRIDGED
+ ]
albums: dict[str, list[dict]] = {}
processed: list[str] = []
SIZE = 100
@@ -1011,6 +1012,50 @@ def listen_messages(self, content: Optional[Union[list[types.Content], types.Con
if len(processed) == SIZE:
processed = []
+
+
+ def listen_events(self, content: Optional[Union[list[types.Content], types.Content]] = None) -> Generator[models.Message, None, None]:
+ """
+ Listen for all events continuously. Can be used for real time processing.
+ """
+ if isinstance(content, type(None)):
+ content = []
+ elif isinstance(content, types.Content):
+ content = [content]
+
+ allowed_content_types = [content_type.value for content_type in (content if content else types.Content)]
+ albums: dict[str, list[dict]] = {}
+ for message in self.signal.listen("messages.new"):
+ event: dict = message.get("event", {})
+ raw_messages: list[dict] = event.get("messages", [])
+ self.logger.debug(f"Received Message {json.dumps(raw_messages)}")
+ for raw in raw_messages:
+ if raw["contentType"] not in allowed_content_types:
+ continue
+ # Edge case with when receiving an Edit of a message with a reply
+ if "outgoingStatus" in raw and raw["outgoingStatus"] == "delivered":
+ continue
+
+ if not raw.get("albumId"):
+ yield models.Message.from_raw(raw)
+ continue
+
+ album_id: str = raw["albumId"]
+ if album_id not in albums:
+ albums[album_id] = []
+
+ albums[album_id].append(raw)
+ if len(albums[album_id]) != raw["albumImagesCount"]:
+ continue
+
+ raw["image"] = [
+ point["image"]
+ for point in albums[album_id]
+ ]
+ yield models.Message.from_raw(raw)
+ albums.pop(album_id)
+
+
def get_messages(self, chat_id: str, start_timestamp: Optional[Union[str, datetime.datetime, datetime.date, pd.Timestamp]] = None, end_timestamp: Optional[Union[str, datetime.datetime, datetime.date, pd.Timestamp]] = None) -> list[dict]:
"""
Get all of the messages in the given start and end timestamps.
diff --git a/status_sdk/models/message.py b/status_sdk/models/message.py
index 5f3dccc..8ee8343 100644
--- a/status_sdk/models/message.py
+++ b/status_sdk/models/message.py
@@ -80,6 +80,7 @@ class Message:
image_urls: list[str] = field(default_factory=list)
reply_id: Optional[str] = None
bridge_id: Optional[str] = None
+ edited_at: Optional[str] = None
payment_requests: list[PaymentRequest] = field(default_factory=list)
@classmethod
@@ -92,9 +93,13 @@ def from_raw(cls, raw: dict) -> Self:
"from_public_key": raw["from"],
"timestamp": datetime.datetime.fromtimestamp(raw["whisperTimestamp"] / 1_000),
"source": raw.get("bridgeMessage", {}).get("bridgeName", "status"),
- "image_urls": []
+ "image_urls": [],
+ "content_type": raw["contentType"],
+ "content": raw["text"]
}
+ print(f"Transforming raw message {raw}")
+
if len(raw["responseTo"]) > 0:
params["reply_id"] = raw["responseTo"]
@@ -123,9 +128,6 @@ def from_raw(cls, raw: dict) -> Self:
img_paths: list[str] = raw["image"]
params["image_urls"] += img_paths
- text = raw["text"]
- caption = f"{text}\n\n" if len(text) > 0 else ""
- params["content"] = caption + "\n".join(img_paths)
params["content_type"] = types.Content.IMAGE
# Bridged Message
elif content_type == types.Content.BRIDGED.value:
diff --git a/status_sdk/types.py b/status_sdk/types.py
index 209e42d..8ea7fbd 100644
--- a/status_sdk/types.py
+++ b/status_sdk/types.py
@@ -3,10 +3,15 @@
class Content(Enum):
TEXT = 1
STICKER = 2
+ STATUS = 3
EMOJI = 4
IMAGE = 7
+ CONTACT_REQUEST = 11
+ ACCEPTED_REQUEST = 16
+ REMOVED_CONTACT = 17
BRIDGED = 18
+
class Chat(Enum):
PRIVATE = 1
COMMUNITY = 2