From a665fb7d4662c1ebb87e70936a01ca97647d9e2a Mon Sep 17 00:00:00 2001 From: Siddarth Kumar Date: Fri, 8 May 2026 12:32:12 +0530 Subject: [PATCH] bot: Add Profile Picture - Set local profile picture - Documentation - Monitoring implementation --- assets/profile.jpg | Bin 0 -> 14113 bytes bot/account.py | 78 +++++++++++++++++++++++++++++++++++++++++-- bot/requirements.txt | 1 + docker-compose.yaml | 1 + docs/account.md | 41 +++++++++++++++++++++++ monitor.py | 1 + 6 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 assets/profile.jpg diff --git a/assets/profile.jpg b/assets/profile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..616f76933f1d9780335bf59929f13dab233ad2b0 GIT binary patch literal 14113 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 Optional[JpegImageFile]: + """ + Get current profile picture + """ + files = [ + os.path.join(self.__assets_local_folder, f) + for f in os.listdir(self.__assets_local_folder) + if os.path.isfile(os.path.join(self.__assets_local_folder, f)) + ] + if not files: + return + + latest_file_path = max(files, key=os.path.getctime) + for file in files: + if file == latest_file_path: + continue + os.remove(file) + + return Image.open(latest_file_path) + + @profile_picture.setter + def profile_picture(self, file_path: str): + + if not isinstance(file_path, str): + return + + if not os.path.exists(file_path): + raise Exception(f"File path {file_path} does not exist") + + suffix = (".jpg", ".png", ".jpeg") + if not file_path.endswith(suffix): + raise Exception(f"Image must be one of the following extensions: {suffix}") + + file_name = os.path.basename(file_path) + + extension = file_name.split(".")[-1] + asset_file_name = f"profile.{extension}" + asset_file_path = os.path.join(self.__assets_local_folder, asset_file_name) + docker_file_path = self.__docker_asset_folder + "/" + asset_file_name + for file_name in os.listdir(self.__assets_local_folder): + current_file_path = os.path.join(self.__assets_local_folder, file_name) + if not os.path.isfile(current_file_path) or current_file_path == file_path: + continue + os.remove(current_file_path) + + try: + shutil.copy(file_path, asset_file_path) + except shutil.SameFileError: + self.logger.info("File is already in asset path") + + img = Image.open(asset_file_path) + params = [ + self.info["key_uid"], + docker_file_path, + 0, + 0, + *img.size + ] + self.logger.info(f"Setting {file_path} as profile picture") + self.__call_rpc("identity", "storeIdentityImage", params) + self.logger.info(f"Profile picture has been updated!") + @property def contacts(self) -> dict[str, dict]: """ diff --git a/bot/requirements.txt b/bot/requirements.txt index 59132fd..7ab5331 100644 --- a/bot/requirements.txt +++ b/bot/requirements.txt @@ -2,3 +2,4 @@ requests websocket-client websockets pandas +pillow diff --git a/docker-compose.yaml b/docker-compose.yaml index fc456b3..b30370b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -14,6 +14,7 @@ services: command: '-address 0.0.0.0:8080' volumes: - ./backups:/root/.config/Status/backups + - ./assets:/assets:ro networks: - status-bridge healthcheck: diff --git a/docs/account.md b/docs/account.md index 7efecb6..8878bb3 100644 --- a/docs/account.md +++ b/docs/account.md @@ -733,6 +733,47 @@ account.login(**params) del account.bio ``` +### `profile_picture` + +Get or update the **profile picture** of the currently logged‑in account. The image is the same one shown on the user's profile in Status App. + +Returns `PIL.Image.Image` when reading the property, or `None` if no profile picture has been set. + +```python +from bot import Account + +account = Account() +params = { + "display_name": "status-app-bot", + "password": "SNTPUMP" +} +account.login(**params) + +# Read the current profile picture +image = account.profile_picture +if image: + image.show() +``` + +The file path assigned to `profile_picture` will be automatically set as the latest profile picture in Status App. If the given file does not exist or the extension is not supported, an **exception will be raised**. Supported image formats are `.jpg`, `.jpeg` and `.png`. + +```python +from bot import Account + +account = Account() +params = { + "display_name": "status-app-bot", + "password": "SNTPUMP" +} +account.login(**params) + +# Update the profile picture +account.profile_picture = "./full_path/to/my_image.png" +account.profile_picture.show() +``` + +When a new profile picture is set, any previous image in the **assets** folder is removed. The image is also copied into the Status Backend Docker volume so it is picked up by the backend when updating the account identity. + ### `signal` The property exists in `Account` because signals require an **active logged‑in session**. Attempting to use signals before calling `login()` will raise an exception. Signals are low‑level events emitted by the Status Backend. Examples include: diff --git a/monitor.py b/monitor.py index 0fbeb78..7bc6ddd 100644 --- a/monitor.py +++ b/monitor.py @@ -184,6 +184,7 @@ def create_bot(config: dict) -> Account: if account.info["compressed_key"] != config["bot"]["compressed_key"]: raise Exception("Target compressed key and logged in compressed key are different") + account.profile_picture = os.path.join(os.path.dirname(__file__), "assets", "profile.jpg") account.logger.info(f"Account Information:\nCompressed Key: {account.info['compressed_key']}\nPublic Key: {account.info['public_key']}\nURL: {account.info['url']}") return account