feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import logging
|
2026-01-11 20:13:56 +01:00
|
|
|
import re
|
2025-08-30 22:48:00 +02:00
|
|
|
from typing import Any
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
import wx
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
from sessions import base
|
|
|
|
|
from sessions import session_exceptions as Exceptions
|
|
|
|
|
import output
|
|
|
|
|
import application
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2026-01-10 19:46:53 +01:00
|
|
|
log = logging.getLogger("sessions.blueskiSession")
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
# Optional import of atproto. Code handles absence gracefully.
|
|
|
|
|
try:
|
|
|
|
|
from atproto import Client as AtpClient # type: ignore
|
|
|
|
|
except Exception: # ImportError or missing deps
|
|
|
|
|
AtpClient = None # type: ignore
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
|
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
class Session(base.baseSession):
|
|
|
|
|
"""Minimal Bluesky (atproto) session for TWBlue.
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
Provides basic authorisation, login, and posting support to unblock
|
|
|
|
|
the integration while keeping compatibility with TWBlue's session API.
|
|
|
|
|
"""
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
name = "Bluesky"
|
2026-01-10 19:46:53 +01:00
|
|
|
KIND = "blueski"
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super(Session, self).__init__(*args, **kwargs)
|
2026-01-10 19:46:53 +01:00
|
|
|
self.config_spec = "blueski.defaults"
|
|
|
|
|
self.type = "blueski"
|
2025-08-30 22:48:00 +02:00
|
|
|
self.char_limit = 300
|
|
|
|
|
self.api = None
|
Hi there! I've just finished implementing the ATProtoSocial (Bluesky) protocol, building upon the initial backend work. This update includes comprehensive UI refinements, documentation updates, an attempt to update translation files, and foundational unit tests.
Here's a breakdown of what I accomplished:
1. **UI Refinements (Extensive):**
* **Session Management:** ATProtoSocial is now fully integrated into the Session Manager for account creation and loading.
* **Compose Dialog:** I created and wired up a new generic `ComposeDialog`. It supports text, image attachments (with alt text), language selection, content warnings, and quoting posts, configured by ATProtoSocial's capabilities.
* **User Profile Dialog:** I developed a dedicated `ShowUserProfileDialog` for ATProtoSocial. It displays user details (DID, handle, name, bio, counts) and allows you to perform actions like follow, mute, block, with button states reflecting existing relationships.
* **Custom Panels:** I created new panels for:
* `ATProtoSocialHomeTimelinePanel`: Displays your home timeline.
* `ATProtoSocialUserTimelinePanel`: Displays a specific user's posts.
* `ATProtoSocialNotificationPanel`: Displays notifications.
* `ATProtoSocialUserListPanel`: Displays lists of users (followers, following).
These panels handle data fetching (initial load and "load more"), and use new `compose_post_for_display` and `compose_notification_for_display` methods for rendering.
* **Controller Integration:** I updated `mainController.py` and `atprotosocial/handler.py` to manage the new dialogs, panels, and ATProtoSocial-specific menu actions (Like, Repost, Quote, etc.). Asynchronous operations are handled using `wx.CallAfter`.
2. **Documentation Updates:**
* I created `documentation/source/atprotosocial.rst` detailing Bluesky support, account setup, and features.
* I updated `documentation/source/index.rst` to include the new page.
* I updated `documentation/source/basic_concepts.rst` with ATProtoSocial-specific terms (DID, Handle, App Password, Skyline, Skeet).
* I added a comprehensive entry to `doc/changelog.md` for this feature.
3. **Translation File Updates (Attempted):**
* I manually identified new user-facing strings from Python code and documentation.
* I manually updated `tools/twblue.pot` (application strings) and `tools/twblue-documentation.pot` (documentation strings) with these new strings. I had to do this manually because the project's translation scripts weren't runnable in the current environment.
* An attempt to update Spanish PO files using `msgmerge` failed due to issues (duplicate message definitions) in the manually created POT files. The updated POT files serve as the best available templates for translators under these constraints.
4. **Unit Tests:**
* I created `src/test/sessions/atprotosocial/test_atprotosocial_session.py`.
* I implemented foundational unit tests for `ATProtoSocialSession` covering:
* Initialization.
* Mocked authentication (login/authorize, success/failure).
* Mocked post sending (text, quotes, media).
* Mocked timeline fetching (home, user).
* Mocked notification fetching and handler dispatch.
* The tests utilize `unittest.IsolatedAsyncioTestCase` and extensive mocking of the Bluesky SDK and wxPython dialogs.
**Overall Status:**
The ATProtoSocial integration is now functionally rich, with both backend logic and a comprehensive UI layer. I've updated the documentation to guide you, and a baseline of unit tests ensures core session logic is covered. The primary challenge I encountered was the inability to use the project's standard scripts for translation file generation, which meant I had to take a manual (and thus less robust) approach for POT file updates.
2025-05-30 16:16:21 +00:00
|
|
|
|
2026-01-10 19:46:53 +01:00
|
|
|
def _ensure_settings_namespace(self) -> None:
|
|
|
|
|
"""Migrate legacy atprotosocial settings to blueski namespace."""
|
|
|
|
|
try:
|
|
|
|
|
if not self.settings:
|
|
|
|
|
return
|
|
|
|
|
if self.settings.get("blueski") is None and self.settings.get("atprotosocial") is not None:
|
|
|
|
|
self.settings["blueski"] = dict(self.settings["atprotosocial"])
|
|
|
|
|
try:
|
|
|
|
|
del self.settings["atprotosocial"]
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
try:
|
|
|
|
|
self.settings.write()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Failed to migrate legacy Blueski settings")
|
|
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
def get_name(self):
|
|
|
|
|
"""Return a human-friendly, stable account name for UI.
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
Prefer the user's handle if available so accounts are uniquely
|
|
|
|
|
identifiable, falling back to a generic network name otherwise.
|
|
|
|
|
"""
|
2026-01-10 19:46:53 +01:00
|
|
|
self._ensure_settings_namespace()
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
try:
|
2025-08-30 22:48:00 +02:00
|
|
|
# Prefer runtime DB, then persisted settings, then SDK client
|
|
|
|
|
handle = (
|
|
|
|
|
self.db.get("user_name")
|
2026-01-10 19:46:53 +01:00
|
|
|
or (self.settings and self.settings.get("blueski", {}).get("handle"))
|
2026-01-11 20:13:56 +01:00
|
|
|
or (self.settings and self.settings.get("atprotosocial", {}).get("handle"))
|
2025-08-30 22:48:00 +02:00
|
|
|
or (getattr(getattr(self, "api", None), "me", None) and self.api.me.handle)
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
)
|
2025-08-30 22:48:00 +02:00
|
|
|
if handle:
|
|
|
|
|
return handle
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
return self.name
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
def _ensure_client(self):
|
|
|
|
|
if AtpClient is None:
|
|
|
|
|
raise RuntimeError(
|
|
|
|
|
"The 'atproto' package is not installed. Install it to use Bluesky."
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
)
|
2025-08-30 22:48:00 +02:00
|
|
|
if self.api is None:
|
|
|
|
|
self.api = AtpClient()
|
|
|
|
|
return self.api
|
|
|
|
|
|
|
|
|
|
def login(self, verify_credentials=True):
|
2026-01-10 19:46:53 +01:00
|
|
|
self._ensure_settings_namespace()
|
|
|
|
|
if self.settings.get("blueski") is None:
|
2025-08-30 22:48:00 +02:00
|
|
|
raise Exceptions.RequireCredentialsSessionError
|
2026-01-10 19:46:53 +01:00
|
|
|
handle = self.settings["blueski"].get("handle")
|
|
|
|
|
app_password = self.settings["blueski"].get("app_password")
|
|
|
|
|
session_string = self.settings["blueski"].get("session_string")
|
2025-08-30 22:48:00 +02:00
|
|
|
if not handle or (not app_password and not session_string):
|
|
|
|
|
self.logged = False
|
|
|
|
|
raise Exceptions.RequireCredentialsSessionError
|
|
|
|
|
try:
|
|
|
|
|
# Ensure db exists (can be set to None on logout paths)
|
|
|
|
|
if not isinstance(self.db, dict):
|
|
|
|
|
self.db = {}
|
2025-11-07 09:24:02 +01:00
|
|
|
# Ensure general settings have a default for boost confirmations like Mastodon
|
|
|
|
|
try:
|
|
|
|
|
if "general" in self.settings and self.settings["general"].get("boost_mode") is None:
|
|
|
|
|
self.settings["general"]["boost_mode"] = "ask"
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
2025-08-30 22:48:00 +02:00
|
|
|
api = self._ensure_client()
|
|
|
|
|
# Prefer resuming session if we have one
|
|
|
|
|
if session_string:
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
try:
|
2025-08-30 22:48:00 +02:00
|
|
|
api.import_session_string(session_string)
|
|
|
|
|
except Exception:
|
|
|
|
|
# Fall back to login below
|
|
|
|
|
pass
|
|
|
|
|
if not getattr(api, "me", None):
|
|
|
|
|
# Fresh login
|
|
|
|
|
api.login(handle, app_password)
|
|
|
|
|
# Cache basics
|
|
|
|
|
if getattr(api, "me", None) is None:
|
|
|
|
|
raise RuntimeError("Bluesky SDK client has no 'me' after login")
|
|
|
|
|
self.db["user_name"] = api.me.handle
|
|
|
|
|
self.db["user_id"] = api.me.did
|
|
|
|
|
# Persist DID in settings for session manager display
|
2026-01-10 19:46:53 +01:00
|
|
|
self.settings["blueski"]["did"] = api.me.did
|
2025-08-30 22:48:00 +02:00
|
|
|
# Export session for future reuse
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
try:
|
2026-01-10 19:46:53 +01:00
|
|
|
self.settings["blueski"]["session_string"] = api.export_session_string()
|
2025-08-30 22:48:00 +02:00
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
self.settings.write()
|
|
|
|
|
self.logged = True
|
|
|
|
|
log.debug("Logged in to Bluesky as %s", api.me.handle)
|
2026-01-11 20:13:56 +01:00
|
|
|
except Exception as e:
|
2025-08-30 22:48:00 +02:00
|
|
|
log.exception("Bluesky login failed")
|
|
|
|
|
self.logged = False
|
2026-01-11 20:13:56 +01:00
|
|
|
raise e
|
2025-08-30 22:48:00 +02:00
|
|
|
|
|
|
|
|
def authorise(self):
|
2026-01-10 19:46:53 +01:00
|
|
|
self._ensure_settings_namespace()
|
2025-08-30 22:48:00 +02:00
|
|
|
if self.logged:
|
|
|
|
|
raise Exceptions.AlreadyAuthorisedError("Already authorised.")
|
|
|
|
|
# Ask for handle
|
|
|
|
|
dlg = wx.TextEntryDialog(
|
|
|
|
|
None,
|
|
|
|
|
_("Enter your Bluesky handle (e.g., username.bsky.social)"),
|
|
|
|
|
_("Bluesky Login"),
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
)
|
2025-08-30 22:48:00 +02:00
|
|
|
if dlg.ShowModal() != wx.ID_OK:
|
|
|
|
|
dlg.Destroy()
|
|
|
|
|
return
|
|
|
|
|
handle = dlg.GetValue().strip()
|
|
|
|
|
dlg.Destroy()
|
|
|
|
|
# Ask for app password
|
|
|
|
|
pwd = wx.PasswordEntryDialog(
|
|
|
|
|
None,
|
|
|
|
|
_("Enter your Bluesky App Password (from Settings > App passwords)"),
|
|
|
|
|
_("Bluesky Login"),
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
)
|
2025-08-30 22:48:00 +02:00
|
|
|
if pwd.ShowModal() != wx.ID_OK:
|
|
|
|
|
pwd.Destroy()
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
return
|
2025-08-30 22:48:00 +02:00
|
|
|
app_password = pwd.GetValue().strip()
|
|
|
|
|
pwd.Destroy()
|
|
|
|
|
# Create session folder and config, then attempt login
|
|
|
|
|
self.create_session_folder()
|
|
|
|
|
self.get_configuration()
|
2026-01-10 19:46:53 +01:00
|
|
|
self.settings["blueski"]["handle"] = handle
|
|
|
|
|
self.settings["blueski"]["app_password"] = app_password
|
2025-08-30 22:48:00 +02:00
|
|
|
self.settings.write()
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
try:
|
2025-08-30 22:48:00 +02:00
|
|
|
self.login()
|
|
|
|
|
except Exceptions.RequireCredentialsSessionError:
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
return
|
2025-08-30 22:48:00 +02:00
|
|
|
except Exception:
|
|
|
|
|
log.exception("Authorisation failed")
|
|
|
|
|
wx.MessageBox(
|
|
|
|
|
_("We could not log in to Bluesky. Please verify your handle and app password."),
|
|
|
|
|
_("Login error"), wx.ICON_ERROR
|
Hi there! I've just finished implementing the ATProtoSocial (Bluesky) protocol, building upon the initial backend work. This update includes comprehensive UI refinements, documentation updates, an attempt to update translation files, and foundational unit tests.
Here's a breakdown of what I accomplished:
1. **UI Refinements (Extensive):**
* **Session Management:** ATProtoSocial is now fully integrated into the Session Manager for account creation and loading.
* **Compose Dialog:** I created and wired up a new generic `ComposeDialog`. It supports text, image attachments (with alt text), language selection, content warnings, and quoting posts, configured by ATProtoSocial's capabilities.
* **User Profile Dialog:** I developed a dedicated `ShowUserProfileDialog` for ATProtoSocial. It displays user details (DID, handle, name, bio, counts) and allows you to perform actions like follow, mute, block, with button states reflecting existing relationships.
* **Custom Panels:** I created new panels for:
* `ATProtoSocialHomeTimelinePanel`: Displays your home timeline.
* `ATProtoSocialUserTimelinePanel`: Displays a specific user's posts.
* `ATProtoSocialNotificationPanel`: Displays notifications.
* `ATProtoSocialUserListPanel`: Displays lists of users (followers, following).
These panels handle data fetching (initial load and "load more"), and use new `compose_post_for_display` and `compose_notification_for_display` methods for rendering.
* **Controller Integration:** I updated `mainController.py` and `atprotosocial/handler.py` to manage the new dialogs, panels, and ATProtoSocial-specific menu actions (Like, Repost, Quote, etc.). Asynchronous operations are handled using `wx.CallAfter`.
2. **Documentation Updates:**
* I created `documentation/source/atprotosocial.rst` detailing Bluesky support, account setup, and features.
* I updated `documentation/source/index.rst` to include the new page.
* I updated `documentation/source/basic_concepts.rst` with ATProtoSocial-specific terms (DID, Handle, App Password, Skyline, Skeet).
* I added a comprehensive entry to `doc/changelog.md` for this feature.
3. **Translation File Updates (Attempted):**
* I manually identified new user-facing strings from Python code and documentation.
* I manually updated `tools/twblue.pot` (application strings) and `tools/twblue-documentation.pot` (documentation strings) with these new strings. I had to do this manually because the project's translation scripts weren't runnable in the current environment.
* An attempt to update Spanish PO files using `msgmerge` failed due to issues (duplicate message definitions) in the manually created POT files. The updated POT files serve as the best available templates for translators under these constraints.
4. **Unit Tests:**
* I created `src/test/sessions/atprotosocial/test_atprotosocial_session.py`.
* I implemented foundational unit tests for `ATProtoSocialSession` covering:
* Initialization.
* Mocked authentication (login/authorize, success/failure).
* Mocked post sending (text, quotes, media).
* Mocked timeline fetching (home, user).
* Mocked notification fetching and handler dispatch.
* The tests utilize `unittest.IsolatedAsyncioTestCase` and extensive mocking of the Bluesky SDK and wxPython dialogs.
**Overall Status:**
The ATProtoSocial integration is now functionally rich, with both backend logic and a comprehensive UI layer. I've updated the documentation to guide you, and a baseline of unit tests ensures core session logic is covered. The primary challenge I encountered was the inability to use the project's standard scripts for translation file generation, which meant I had to take a manual (and thus less robust) approach for POT file updates.
2025-05-30 16:16:21 +00:00
|
|
|
)
|
2026-01-11 20:13:56 +01:00
|
|
|
return False
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
return True
|
|
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
def get_message_url(self, message_id, context=None):
|
|
|
|
|
# message_id may be full at:// URI or rkey
|
2026-01-10 19:46:53 +01:00
|
|
|
self._ensure_settings_namespace()
|
|
|
|
|
handle = self.db.get("user_name") or self.settings["blueski"].get("handle", "")
|
2025-08-30 22:48:00 +02:00
|
|
|
rkey = message_id
|
|
|
|
|
if isinstance(message_id, str) and message_id.startswith("at://"):
|
|
|
|
|
parts = message_id.split("/")
|
|
|
|
|
rkey = parts[-1]
|
|
|
|
|
return f"https://bsky.app/profile/{handle}/post/{rkey}"
|
|
|
|
|
|
|
|
|
|
def send_message(self, message, files=None, reply_to=None, cw_text=None, is_sensitive=False, **kwargs):
|
|
|
|
|
if not self.logged:
|
|
|
|
|
raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
|
2026-01-10 19:46:53 +01:00
|
|
|
self._ensure_settings_namespace()
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
try:
|
2025-08-30 22:48:00 +02:00
|
|
|
api = self._ensure_client()
|
|
|
|
|
# Basic text-only post for now. Attachments and CW can be extended later.
|
|
|
|
|
# Prefer convenience if available
|
|
|
|
|
uri = None
|
|
|
|
|
text = message or ""
|
|
|
|
|
# Naive CW handling: prepend CW label to text if provided
|
|
|
|
|
if cw_text:
|
|
|
|
|
text = f"CW: {cw_text}\n\n{text}" if text else f"CW: {cw_text}"
|
|
|
|
|
|
|
|
|
|
# Build base record
|
|
|
|
|
record: dict[str, Any] = {
|
|
|
|
|
"$type": "app.bsky.feed.post",
|
|
|
|
|
"text": text,
|
|
|
|
|
}
|
2026-01-11 20:13:56 +01:00
|
|
|
|
|
|
|
|
# Facets (Links and Mentions)
|
|
|
|
|
try:
|
|
|
|
|
facets = self._get_facets(text, api)
|
|
|
|
|
if facets:
|
|
|
|
|
record["facets"] = facets
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Labels (CW)
|
|
|
|
|
if cw_text:
|
|
|
|
|
record["labels"] = {
|
|
|
|
|
"$type": "com.atproto.label.defs#selfLabels",
|
|
|
|
|
"values": [{"val": "warn"}]
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
# createdAt
|
|
|
|
|
try:
|
|
|
|
|
record["createdAt"] = api.get_current_time_iso()
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
# languages
|
|
|
|
|
langs = kwargs.get("langs") or kwargs.get("languages")
|
|
|
|
|
if isinstance(langs, (list, tuple)) and langs:
|
|
|
|
|
record["langs"] = list(langs)
|
|
|
|
|
|
|
|
|
|
# Helper to build a StrongRef (uri+cid) for a given post URI
|
|
|
|
|
def _get_strong_ref(uri: str):
|
|
|
|
|
try:
|
|
|
|
|
# Try typed models first
|
|
|
|
|
posts_res = api.app.bsky.feed.get_posts({"uris": [uri]})
|
|
|
|
|
posts = getattr(posts_res, "posts", None) or []
|
|
|
|
|
except Exception:
|
|
|
|
|
try:
|
|
|
|
|
posts_res = api.app.bsky.feed.get_posts(uris=[uri])
|
|
|
|
|
posts = getattr(posts_res, "posts", None) or []
|
|
|
|
|
except Exception:
|
|
|
|
|
posts = []
|
|
|
|
|
if posts:
|
|
|
|
|
post0 = posts[0]
|
|
|
|
|
post_uri = getattr(post0, "uri", uri)
|
|
|
|
|
post_cid = getattr(post0, "cid", None) or (post0.get("cid") if isinstance(post0, dict) else None)
|
|
|
|
|
if post_cid:
|
|
|
|
|
return {"uri": post_uri, "cid": post_cid}
|
|
|
|
|
return None
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
# Upload images if provided
|
|
|
|
|
embed_images = []
|
|
|
|
|
if files:
|
|
|
|
|
for f in files:
|
|
|
|
|
path = f
|
|
|
|
|
alt = ""
|
|
|
|
|
if isinstance(f, dict):
|
|
|
|
|
path = f.get("path") or f.get("file")
|
|
|
|
|
alt = f.get("alt") or f.get("alt_text") or ""
|
|
|
|
|
if not path:
|
|
|
|
|
continue
|
|
|
|
|
try:
|
|
|
|
|
with open(path, "rb") as fp:
|
|
|
|
|
data = fp.read()
|
|
|
|
|
# Try typed upload
|
|
|
|
|
try:
|
|
|
|
|
up = api.com.atproto.repo.upload_blob(data)
|
|
|
|
|
blob_ref = getattr(up, "blob", None) or getattr(up, "data", None) or up
|
|
|
|
|
except Exception:
|
|
|
|
|
# Some SDK variants expose upload via api.upload_blob
|
|
|
|
|
up = api.upload_blob(data)
|
|
|
|
|
blob_ref = getattr(up, "blob", None) or getattr(up, "data", None) or up
|
|
|
|
|
if blob_ref:
|
|
|
|
|
embed_images.append({
|
|
|
|
|
"image": blob_ref,
|
|
|
|
|
"alt": alt or "",
|
|
|
|
|
})
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error uploading media for Bluesky post")
|
|
|
|
|
continue
|
feat: Initial integration of ATProtoSocial (Bluesky) protocol
This commit introduces the initial implementation for supporting the ATProtoSocial (Bluesky) protocol within your application.
Key changes and features I implemented:
1. **Core Protocol Structure:**
* I added new directories `src/sessions/atprotosocial` and `src/controller/atprotosocial`.
* I populated these with foundational files (`session.py`, `utils.py`, `handler.py`, `compose.py`, etc.), mirroring the Mastodon implementation structure but adapted for ATProtoSocial.
2. **Authentication:**
* I implemented login and authorization using Bluesky SDK (handle and app password) in `sessions/atprotosocial/session.py`.
* I integrated this into your session management UI (`sessionManagerDialog.py`) to allow adding ATProtoSocial accounts.
3. **Posting Capabilities:**
* I implemented sending text posts, posts with images, replies, and quoting posts in `sessions/atprotosocial/session.py` and `utils.py`.
* I updated `compose.py` to reflect ATProtoSocial's panel configuration (character limits, media support, quoting).
4. **Notifications:**
* I implemented fetching and processing of notifications (likes, reposts, follows, mentions, replies, quotes) in `sessions/atprotosocial/session.py`.
* Notifications are formatted for display.
5. **Timelines:**
* I implemented fetching and processing for home timeline and user-specific timelines in `sessions/atprotosocial/session.py`.
* This includes handling of posts, reposts, and replies within your application's buffer and message cache system.
6. **User Actions:**
* I implemented core user actions: follow, unfollow, mute, unmute, block, unblock in `sessions/atprotosocial/utils.py`.
* I integrated these actions into the controller layer (`controller/atprotosocial/handler.py`) and exposed them via `session.get_user_actions()`.
7. **User Management & Profile:**
* I implemented fetching user profiles, follower lists, following lists, and user search in `sessions/atprotosocial/utils.py` and `controller/atprotosocial/userList.py`.
8. **UI Integration (Initial Pass):**
* I adapted your session management UI for ATProtoSocial account creation.
* I updated main controller logic to load the ATProtoSocial handler and create basic buffers (Home, Notifications).
* I modified menu item labels based on the active session type (e.g., "Post" vs "Toot", "Like" vs "Favorite").
* I integrated core actions like reposting and liking into existing UI flows.
* I added basic integration for timeline refresh and loading more items.
* I added placeholder integration for viewing user profiles and user-specific timelines.
**Current Status & Next Steps:**
This represents a significant portion of the ATProtoSocial integration. The backend logic for most core features is in place. The immediate next steps, which were part of the original plan but not yet completed, would be:
* **Refining UI elements:** Fully implementing dedicated dialogs (compose, user profile), custom panels for new buffer types, and ensuring accurate rendering of ATProtoSocial posts and notifications.
* **Completing Documentation:** Updating all relevant documentation files in `doc/` and `documentation/`.
* **Updating Translations:** Adding new strings and updating translation files.
* **Adding Tests:** Creating unit and integration tests for the new protocol.
I was not stuck on any particular point, but the UI integration is a large step that requires iterative refinement and testing for each component, which would naturally extend beyond a single development cycle for a feature of this scope.
2025-05-26 14:11:01 +00:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
# Quote post (takes precedence over images)
|
|
|
|
|
quote_uri = kwargs.get("quote_uri") or kwargs.get("quote")
|
|
|
|
|
if quote_uri:
|
|
|
|
|
strong = _get_strong_ref(quote_uri)
|
|
|
|
|
if strong:
|
|
|
|
|
record["embed"] = {
|
|
|
|
|
"$type": "app.bsky.embed.record",
|
|
|
|
|
"record": strong,
|
|
|
|
|
}
|
|
|
|
|
embed_images = [] # Ignore images when quoting
|
|
|
|
|
|
|
|
|
|
if embed_images and not record.get("embed"):
|
|
|
|
|
record["embed"] = {
|
|
|
|
|
"$type": "app.bsky.embed.images",
|
|
|
|
|
"images": embed_images,
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-07 09:24:02 +01:00
|
|
|
# Helper: normalize various incoming identifiers to an at:// URI
|
|
|
|
|
def _normalize_to_uri(identifier: str) -> str | None:
|
|
|
|
|
try:
|
|
|
|
|
if not isinstance(identifier, str):
|
|
|
|
|
return None
|
|
|
|
|
if identifier.startswith("at://"):
|
|
|
|
|
return identifier
|
|
|
|
|
if "bsky.app/profile/" in identifier and "/post/" in identifier:
|
|
|
|
|
# Accept full web URL and try to resolve via get_post_thread below
|
|
|
|
|
return identifier
|
|
|
|
|
# Accept bare rkey case by constructing a guess using own handle
|
2026-01-10 19:46:53 +01:00
|
|
|
handle = self.db.get("user_name") or self.settings["blueski"].get("handle")
|
|
|
|
|
did = self.db.get("user_id") or self.settings["blueski"].get("did")
|
2025-11-07 09:24:02 +01:00
|
|
|
if handle and did and len(identifier) in (13, 14, 15):
|
|
|
|
|
# rkey length is typically ~13 chars base32
|
|
|
|
|
return f"at://{did}/app.bsky.feed.post/{identifier}"
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Reply-to handling (sets correct root/parent strong refs)
|
2025-08-30 22:48:00 +02:00
|
|
|
if reply_to:
|
2025-11-07 09:24:02 +01:00
|
|
|
# Resolve to proper at:// uri when possible
|
|
|
|
|
reply_uri = _normalize_to_uri(reply_to) or reply_to
|
2026-01-11 20:16:39 +01:00
|
|
|
reply_cid = kwargs.get("reply_to_cid")
|
|
|
|
|
parent_ref = None
|
|
|
|
|
if reply_uri and reply_cid:
|
|
|
|
|
parent_ref = {"uri": reply_uri, "cid": reply_cid}
|
|
|
|
|
if not parent_ref:
|
|
|
|
|
parent_ref = _get_strong_ref(reply_uri)
|
2025-11-07 09:24:02 +01:00
|
|
|
root_ref = parent_ref
|
|
|
|
|
# Try to fetch thread to find actual root for deep replies
|
|
|
|
|
try:
|
|
|
|
|
# atproto SDK usually exposes get_post_thread
|
|
|
|
|
thread_res = None
|
|
|
|
|
try:
|
|
|
|
|
thread_res = api.app.bsky.feed.get_post_thread({"uri": reply_uri})
|
|
|
|
|
except Exception:
|
|
|
|
|
# Try typed model call variant if available
|
|
|
|
|
from atproto import models as at_models # type: ignore
|
|
|
|
|
params = at_models.AppBskyFeedGetPostThread.Params(uri=reply_uri)
|
|
|
|
|
thread_res = api.app.bsky.feed.get_post_thread(params)
|
|
|
|
|
thread = getattr(thread_res, "thread", None)
|
|
|
|
|
# Walk to the root if present
|
|
|
|
|
node = thread
|
|
|
|
|
while node and getattr(node, "parent", None):
|
|
|
|
|
node = getattr(node, "parent")
|
|
|
|
|
root_uri = getattr(node, "post", None)
|
|
|
|
|
if root_uri:
|
|
|
|
|
root_uri = getattr(root_uri, "uri", None)
|
|
|
|
|
if root_uri and isinstance(root_uri, str):
|
|
|
|
|
maybe_root = _get_strong_ref(root_uri)
|
|
|
|
|
if maybe_root:
|
|
|
|
|
root_ref = maybe_root
|
|
|
|
|
except Exception:
|
|
|
|
|
# If anything fails, keep parent as root for a simple two-level reply
|
|
|
|
|
pass
|
2025-08-30 22:48:00 +02:00
|
|
|
if parent_ref:
|
|
|
|
|
record["reply"] = {
|
2025-11-07 09:24:02 +01:00
|
|
|
"root": root_ref or parent_ref,
|
2025-08-30 22:48:00 +02:00
|
|
|
"parent": parent_ref,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Fallback to convenience if available
|
|
|
|
|
try:
|
|
|
|
|
if hasattr(api, "send_post") and not embed_images and not langs and not cw_text:
|
|
|
|
|
res = api.send_post(text)
|
|
|
|
|
uri = getattr(res, "uri", None) or getattr(res, "cid", None)
|
|
|
|
|
else:
|
|
|
|
|
out = api.com.atproto.repo.create_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.feed.post",
|
|
|
|
|
"record": record,
|
|
|
|
|
})
|
|
|
|
|
uri = getattr(out, "uri", None)
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error creating Bluesky post record")
|
|
|
|
|
uri = None
|
|
|
|
|
if not uri:
|
|
|
|
|
raise RuntimeError("Post did not return a URI")
|
2026-01-11 20:13:56 +01:00
|
|
|
|
2025-08-30 22:48:00 +02:00
|
|
|
return uri
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error sending Bluesky post")
|
|
|
|
|
output.speak(_("An error occurred while posting to Bluesky."), True)
|
|
|
|
|
return None
|
2025-11-07 09:24:02 +01:00
|
|
|
|
2026-01-11 20:13:56 +01:00
|
|
|
def _get_facets(self, text, api):
|
|
|
|
|
facets = []
|
|
|
|
|
# Mentions
|
|
|
|
|
for m in re.finditer(r'@([a-zA-Z0-9.-]+)', text):
|
|
|
|
|
handle = m.group(1)
|
|
|
|
|
try:
|
|
|
|
|
# We should probably cache this identity lookup
|
|
|
|
|
res = api.com.atproto.identity.resolve_handle({'handle': handle})
|
|
|
|
|
did = res.did
|
|
|
|
|
facets.append({
|
|
|
|
|
'index': {
|
|
|
|
|
'byteStart': len(text[:m.start()].encode('utf-8')),
|
|
|
|
|
'byteEnd': len(text[:m.end()].encode('utf-8'))
|
|
|
|
|
},
|
|
|
|
|
'features': [{'$type': 'app.bsky.richtext.facet#mention', 'did': did}]
|
|
|
|
|
})
|
|
|
|
|
except:
|
|
|
|
|
continue
|
|
|
|
|
# Links
|
|
|
|
|
for m in re.finditer(r'(https?://[^\s]+)', text):
|
|
|
|
|
url = m.group(1)
|
|
|
|
|
facets.append({
|
|
|
|
|
'index': {
|
|
|
|
|
'byteStart': len(text[:m.start()].encode('utf-8')),
|
|
|
|
|
'byteEnd': len(text[:m.end()].encode('utf-8'))
|
|
|
|
|
},
|
|
|
|
|
'features': [{'$type': 'app.bsky.richtext.facet#link', 'uri': url}]
|
|
|
|
|
})
|
|
|
|
|
return facets
|
|
|
|
|
|
|
|
|
|
def delete_post(self, uri: str) -> bool:
|
|
|
|
|
"""Delete a post by its AT URI."""
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
# at://did:plc:xxx/app.bsky.feed.post/rkey
|
|
|
|
|
parts = uri.split("/")
|
|
|
|
|
rkey = parts[-1]
|
|
|
|
|
api.com.atproto.repo.delete_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.feed.post",
|
|
|
|
|
"rkey": rkey
|
|
|
|
|
})
|
|
|
|
|
return True
|
|
|
|
|
except:
|
|
|
|
|
log.exception("Error deleting Bluesky post")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def block_user(self, did: str) -> bool:
|
|
|
|
|
"""Block a user by their DID."""
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
api.com.atproto.repo.create_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.graph.block",
|
|
|
|
|
"record": {
|
|
|
|
|
"$type": "app.bsky.graph.block",
|
|
|
|
|
"subject": did,
|
|
|
|
|
"createdAt": api.get_current_time_iso()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return True
|
|
|
|
|
except:
|
|
|
|
|
log.exception("Error blocking Bluesky user")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def unblock_user(self, block_uri: str) -> bool:
|
|
|
|
|
"""Unblock a user by the URI of the block record."""
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
parts = block_uri.split("/")
|
|
|
|
|
rkey = parts[-1]
|
|
|
|
|
api.com.atproto.repo.delete_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.graph.block",
|
|
|
|
|
"rkey": rkey
|
|
|
|
|
})
|
|
|
|
|
return True
|
|
|
|
|
except:
|
|
|
|
|
log.exception("Error unblocking Bluesky user")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def get_profile(self, actor: str) -> Any:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
return api.app.bsky.actor.get_profile({"actor": actor})
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error fetching Bluesky profile for %s", actor)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def follow_user(self, did: str) -> bool:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
api.com.atproto.repo.create_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.graph.follow",
|
|
|
|
|
"record": {
|
|
|
|
|
"$type": "app.bsky.graph.follow",
|
|
|
|
|
"subject": did,
|
|
|
|
|
"createdAt": api.get_current_time_iso()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return True
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error following Bluesky user")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def unfollow_user(self, follow_uri: str) -> bool:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
parts = follow_uri.split("/")
|
|
|
|
|
rkey = parts[-1]
|
|
|
|
|
api.com.atproto.repo.delete_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.graph.follow",
|
|
|
|
|
"rkey": rkey
|
|
|
|
|
})
|
|
|
|
|
return True
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error unfollowing Bluesky user")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def mute_user(self, did: str) -> bool:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
graph = api.app.bsky.graph
|
|
|
|
|
if hasattr(graph, "mute_actor"):
|
|
|
|
|
graph.mute_actor({"actor": did})
|
|
|
|
|
elif hasattr(graph, "muteActor"):
|
|
|
|
|
graph.muteActor({"actor": did})
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error muting Bluesky user")
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def unmute_user(self, did: str) -> bool:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
try:
|
|
|
|
|
graph = api.app.bsky.graph
|
|
|
|
|
if hasattr(graph, "unmute_actor"):
|
|
|
|
|
graph.unmute_actor({"actor": did})
|
|
|
|
|
elif hasattr(graph, "unmuteActor"):
|
|
|
|
|
graph.unmuteActor({"actor": did})
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error unmuting Bluesky user")
|
|
|
|
|
return False
|
|
|
|
|
|
2025-11-07 09:24:02 +01:00
|
|
|
def repost(self, post_uri: str, post_cid: str | None = None) -> str | None:
|
|
|
|
|
"""Create a simple repost of a given post. Returns URI of the repost record or None."""
|
|
|
|
|
if not self.logged:
|
|
|
|
|
raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
|
|
|
|
|
try:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
|
|
|
|
|
def _get_strong_ref(uri: str):
|
|
|
|
|
try:
|
|
|
|
|
posts_res = api.app.bsky.feed.get_posts({"uris": [uri]})
|
|
|
|
|
posts = getattr(posts_res, "posts", None) or []
|
|
|
|
|
except Exception:
|
|
|
|
|
try:
|
|
|
|
|
posts_res = api.app.bsky.feed.get_posts(uris=[uri])
|
|
|
|
|
posts = getattr(posts_res, "posts", None) or []
|
|
|
|
|
except Exception:
|
|
|
|
|
posts = []
|
|
|
|
|
if posts:
|
|
|
|
|
post0 = posts[0]
|
|
|
|
|
s_uri = getattr(post0, "uri", uri)
|
|
|
|
|
s_cid = getattr(post0, "cid", None) or (post0.get("cid") if isinstance(post0, dict) else None)
|
|
|
|
|
if s_cid:
|
|
|
|
|
return {"uri": s_uri, "cid": s_cid}
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
if not post_cid:
|
|
|
|
|
strong = _get_strong_ref(post_uri)
|
|
|
|
|
if not strong:
|
|
|
|
|
return None
|
|
|
|
|
post_uri = strong["uri"]
|
|
|
|
|
post_cid = strong["cid"]
|
|
|
|
|
|
|
|
|
|
out = api.com.atproto.repo.create_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.feed.repost",
|
|
|
|
|
"record": {
|
|
|
|
|
"$type": "app.bsky.feed.repost",
|
|
|
|
|
"subject": {"uri": post_uri, "cid": post_cid},
|
|
|
|
|
"createdAt": getattr(api, "get_current_time_iso", lambda: None)() or None,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
return getattr(out, "uri", None)
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error creating Bluesky repost record")
|
|
|
|
|
return None
|
2026-01-11 20:13:56 +01:00
|
|
|
|
|
|
|
|
def like(self, post_uri: str, post_cid: str | None = None) -> str | None:
|
|
|
|
|
"""Create a like for a given post."""
|
|
|
|
|
if not self.logged:
|
|
|
|
|
raise Exceptions.NotLoggedSessionError("You are not logged in yet.")
|
|
|
|
|
try:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
|
|
|
|
|
# Resolve strong ref if needed
|
|
|
|
|
def _get_strong_ref(uri: str):
|
|
|
|
|
try:
|
|
|
|
|
posts_res = api.app.bsky.feed.get_posts({"uris": [uri]})
|
|
|
|
|
posts = getattr(posts_res, "posts", None) or []
|
|
|
|
|
except Exception:
|
|
|
|
|
try: posts_res = api.app.bsky.feed.get_posts(uris=[uri])
|
|
|
|
|
except: posts_res = None
|
|
|
|
|
posts = getattr(posts_res, "posts", None) or []
|
|
|
|
|
if posts:
|
|
|
|
|
p = posts[0]
|
|
|
|
|
return {"uri": getattr(p, "uri", uri), "cid": getattr(p, "cid", None)}
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
if not post_cid:
|
|
|
|
|
strong = _get_strong_ref(post_uri)
|
|
|
|
|
if not strong: return None
|
|
|
|
|
post_uri = strong["uri"]
|
|
|
|
|
post_cid = strong["cid"]
|
|
|
|
|
|
|
|
|
|
out = api.com.atproto.repo.create_record({
|
|
|
|
|
"repo": api.me.did,
|
|
|
|
|
"collection": "app.bsky.feed.like",
|
|
|
|
|
"record": {
|
|
|
|
|
"$type": "app.bsky.feed.like",
|
|
|
|
|
"subject": {"uri": post_uri, "cid": post_cid},
|
|
|
|
|
"createdAt": getattr(api, "get_current_time_iso", lambda: None)() or None,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
return getattr(out, "uri", None)
|
|
|
|
|
except Exception:
|
|
|
|
|
log.exception("Error creating Bluesky like")
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def get_followers(self, actor: str | None = None, limit: int = 50, cursor: str | None = None) -> dict[str, Any]:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
actor = actor or api.me.did
|
|
|
|
|
res = api.app.bsky.graph.get_followers({"actor": actor, "limit": limit, "cursor": cursor})
|
|
|
|
|
return {"items": res.followers, "cursor": res.cursor}
|
|
|
|
|
|
|
|
|
|
def get_follows(self, actor: str | None = None, limit: int = 50, cursor: str | None = None) -> dict[str, Any]:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
actor = actor or api.me.did
|
|
|
|
|
res = api.app.bsky.graph.get_follows({"actor": actor, "limit": limit, "cursor": cursor})
|
|
|
|
|
return {"items": res.follows, "cursor": res.cursor}
|
|
|
|
|
|
|
|
|
|
def get_blocks(self, limit: int = 50, cursor: str | None = None) -> dict[str, Any]:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
res = api.app.bsky.graph.get_blocks({"limit": limit, "cursor": cursor})
|
|
|
|
|
return {"items": res.blocks, "cursor": res.cursor}
|
|
|
|
|
|
|
|
|
|
def list_convos(self, limit: int = 50, cursor: str | None = None) -> dict[str, Any]:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
res = api.chat.bsky.convo.list_convos({"limit": limit, "cursor": cursor})
|
|
|
|
|
return {"items": res.convos, "cursor": res.cursor}
|
|
|
|
|
|
|
|
|
|
def get_convo_messages(self, convo_id: str, limit: int = 50, cursor: str | None = None) -> dict[str, Any]:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
res = api.chat.bsky.convo.get_messages({"convoId": convo_id, "limit": limit, "cursor": cursor})
|
|
|
|
|
return {"items": res.messages, "cursor": res.cursor}
|
|
|
|
|
|
|
|
|
|
def send_chat_message(self, convo_id: str, text: str) -> Any:
|
|
|
|
|
api = self._ensure_client()
|
|
|
|
|
return api.chat.bsky.convo.send_message({
|
|
|
|
|
"convoId": convo_id,
|
|
|
|
|
"message": {
|
|
|
|
|
"text": text
|
|
|
|
|
}
|
|
|
|
|
})
|