mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2026-03-06 09:27:33 +01:00
Refactorización. Casi finalizado a falta de testeo profundo
This commit is contained in:
@@ -12,6 +12,7 @@ Se está siguiendo `falta.md` por orden. Los puntos 1 a 8 y 10-11 están marcado
|
|||||||
- Autocompletado añadido al diálogo de acciones de usuario.
|
- Autocompletado añadido al diálogo de acciones de usuario.
|
||||||
- Atajos de teclado (&) añadidos a botones del perfil.
|
- Atajos de teclado (&) añadidos a botones del perfil.
|
||||||
- Persistencia de búsquedas implementada (se guardan y restauran al reiniciar).
|
- Persistencia de búsquedas implementada (se guardan y restauran al reiniciar).
|
||||||
|
- Paginación completa en todos los buffers: HomeTimeline, FollowingTimeline, NotificationBuffer, LikesBuffer, MentionsBuffer, SentBuffer, UserTimeline, SearchBuffer.
|
||||||
|
|
||||||
## Cambios anteriores
|
## Cambios anteriores
|
||||||
- Activado autocompletado en el diálogo "Ver timeline..." y validación de usuario.
|
- Activado autocompletado en el diálogo "Ver timeline..." y validación de usuario.
|
||||||
@@ -21,11 +22,13 @@ Se está siguiendo `falta.md` por orden. Los puntos 1 a 8 y 10-11 están marcado
|
|||||||
- Menús: para Bluesky, las opciones no aplicables se ocultan usando el sentinel "HIDE".
|
- Menús: para Bluesky, las opciones no aplicables se ocultan usando el sentinel "HIDE".
|
||||||
|
|
||||||
## Puntos pendientes
|
## Puntos pendientes
|
||||||
- 9) Paginación en timelines principales (home, notifications, user timelines, search) - parcial.
|
Ninguno. Todos los puntos de falta.md están completados.
|
||||||
|
|
||||||
## Notas técnicas
|
## Notas técnicas
|
||||||
- `update_menus` en `src/controller/mainController.py` interpreta `"HIDE"` para ocultar entradas.
|
- `update_menus` en `src/controller/mainController.py` interpreta `"HIDE"` para ocultar entradas.
|
||||||
- Buffers de Reposts/Likes usan `PostUserListBuffer` con cursor para paginación.
|
- Buffers de Reposts/Likes usan `PostUserListBuffer` con cursor para paginación.
|
||||||
- Las búsquedas ahora se guardan en `session.settings["other_buffers"]["searches"]`.
|
- Las búsquedas ahora se guardan en `session.settings["other_buffers"]["searches"]`.
|
||||||
- Perfil de usuario descarga imágenes en thread separado para no bloquear UI.
|
- Perfil de usuario descarga imágenes en thread separado para no bloquear UI.
|
||||||
|
- Paginación usa patrón: `self.next_cursor` guardado en `start_stream()`, usado en `get_more_items()`.
|
||||||
|
- El menú "load_previous_items" activa `get_more_items()` en el buffer actual.
|
||||||
|
|
||||||
|
|||||||
2
falta.md
2
falta.md
@@ -51,7 +51,7 @@ Hecho. La terminología es consistente: Bluesky usa "repost/like" (nativo AT Pro
|
|||||||
## 9) Paginación en listados
|
## 9) Paginación en listados
|
||||||
- Bluesky: implementada en Reposts/Likes y Followers/Following.
|
- Bluesky: implementada en Reposts/Likes y Followers/Following.
|
||||||
- Faltan otros listados equivalentes (por ejemplo, búsquedas de usuarios si se implementan).
|
- Faltan otros listados equivalentes (por ejemplo, búsquedas de usuarios si se implementan).
|
||||||
Parcial. Paginación implementada en buffers de usuarios (followers/following/likes/reposts). Pendiente en timelines principales.
|
Hecho. Paginación implementada en todos los buffers: HomeTimeline, FollowingTimeline, NotificationBuffer, LikesBuffer, MentionsBuffer, SentBuffer, UserTimeline, SearchBuffer, FollowersBuffer, FollowingBuffer, PostUserListBuffer.
|
||||||
|
|
||||||
## 10) Accesibilidad/teclado
|
## 10) Accesibilidad/teclado
|
||||||
- Verificar atajos en todos los nuevos diálogos/buffers.
|
- Verificar atajos en todos los nuevos diálogos/buffers.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import logging
|
import logging
|
||||||
|
import output
|
||||||
from .base import BaseBuffer
|
from .base import BaseBuffer
|
||||||
from wxUI.buffers.blueski import panels as BlueskiPanels
|
from wxUI.buffers.blueski import panels as BlueskiPanels
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
@@ -11,7 +12,8 @@ class HomeTimeline(BaseBuffer):
|
|||||||
super(HomeTimeline, self).__init__(*args, **kwargs)
|
super(HomeTimeline, self).__init__(*args, **kwargs)
|
||||||
self.type = "home_timeline"
|
self.type = "home_timeline"
|
||||||
self.feed_uri = None
|
self.feed_uri = None
|
||||||
|
self.next_cursor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
# Override to use HomePanel
|
# Override to use HomePanel
|
||||||
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
||||||
@@ -22,13 +24,13 @@ class HomeTimeline(BaseBuffer):
|
|||||||
try:
|
try:
|
||||||
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
api = self.session._ensure_client()
|
api = self.session._ensure_client()
|
||||||
|
|
||||||
# Discover Logic
|
# Discover Logic
|
||||||
if not self.feed_uri:
|
if not self.feed_uri:
|
||||||
self.feed_uri = self._resolve_discover_feed(api)
|
self.feed_uri = self._resolve_discover_feed(api)
|
||||||
|
|
||||||
items = []
|
items = []
|
||||||
try:
|
try:
|
||||||
res = None
|
res = None
|
||||||
@@ -38,16 +40,40 @@ class HomeTimeline(BaseBuffer):
|
|||||||
else:
|
else:
|
||||||
# Fallback to standard timeline
|
# Fallback to standard timeline
|
||||||
res = api.app.bsky.feed.get_timeline({"limit": count})
|
res = api.app.bsky.feed.get_timeline({"limit": count})
|
||||||
|
|
||||||
feed = getattr(res, "feed", [])
|
feed = getattr(res, "feed", [])
|
||||||
items = list(feed)
|
items = list(feed)
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception("Failed to fetch home timeline")
|
log.exception("Failed to fetch home timeline")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return self.process_items(items, play_sound)
|
return self.process_items(items, play_sound)
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
try:
|
||||||
|
if self.feed_uri:
|
||||||
|
res = api.app.bsky.feed.get_feed({"feed": self.feed_uri, "limit": count, "cursor": self.next_cursor})
|
||||||
|
else:
|
||||||
|
res = api.app.bsky.feed.get_timeline({"limit": count, "cursor": self.next_cursor})
|
||||||
|
feed = getattr(res, "feed", [])
|
||||||
|
items = list(feed)
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
added = self.process_items(items, play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more home timeline items")
|
||||||
|
|
||||||
def _resolve_discover_feed(self, api):
|
def _resolve_discover_feed(self, api):
|
||||||
# Reuse logic from panels.py
|
# Reuse logic from panels.py
|
||||||
try:
|
try:
|
||||||
@@ -76,7 +102,8 @@ class FollowingTimeline(BaseBuffer):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(FollowingTimeline, self).__init__(*args, **kwargs)
|
super(FollowingTimeline, self).__init__(*args, **kwargs)
|
||||||
self.type = "following_timeline"
|
self.type = "following_timeline"
|
||||||
|
self.next_cursor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
self.buffer = BlueskiPanels.HomePanel(parent, name) # Reuse HomePanel layout
|
self.buffer = BlueskiPanels.HomePanel(parent, name) # Reuse HomePanel layout
|
||||||
self.buffer.session = self.session
|
self.buffer.session = self.session
|
||||||
@@ -85,19 +112,40 @@ class FollowingTimeline(BaseBuffer):
|
|||||||
count = 50
|
count = 50
|
||||||
try: count = self.session.settings["general"].get("max_posts_per_call", 50)
|
try: count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
api = self.session._ensure_client()
|
api = self.session._ensure_client()
|
||||||
try:
|
try:
|
||||||
# Force reverse-chronological
|
# Force reverse-chronological
|
||||||
res = api.app.bsky.feed.get_timeline({"limit": count, "algorithm": "reverse-chronological"})
|
res = api.app.bsky.feed.get_timeline({"limit": count, "algorithm": "reverse-chronological"})
|
||||||
feed = getattr(res, "feed", [])
|
feed = getattr(res, "feed", [])
|
||||||
items = list(feed)
|
items = list(feed)
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception("Error fetching following timeline")
|
log.exception("Error fetching following timeline")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return self.process_items(items, play_sound)
|
return self.process_items(items, play_sound)
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
try:
|
||||||
|
res = api.app.bsky.feed.get_timeline({"limit": count, "algorithm": "reverse-chronological", "cursor": self.next_cursor})
|
||||||
|
feed = getattr(res, "feed", [])
|
||||||
|
items = list(feed)
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
added = self.process_items(items, play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more following timeline items")
|
||||||
|
|
||||||
class NotificationBuffer(BaseBuffer):
|
class NotificationBuffer(BaseBuffer):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
# Override compose_func before calling super().__init__
|
# Override compose_func before calling super().__init__
|
||||||
@@ -105,6 +153,7 @@ class NotificationBuffer(BaseBuffer):
|
|||||||
super(NotificationBuffer, self).__init__(*args, **kwargs)
|
super(NotificationBuffer, self).__init__(*args, **kwargs)
|
||||||
self.type = "notifications"
|
self.type = "notifications"
|
||||||
self.sound = "notification_received.ogg"
|
self.sound = "notification_received.ogg"
|
||||||
|
self.next_cursor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
self.buffer = BlueskiPanels.NotificationPanel(parent, name)
|
self.buffer = BlueskiPanels.NotificationPanel(parent, name)
|
||||||
@@ -124,6 +173,7 @@ class NotificationBuffer(BaseBuffer):
|
|||||||
try:
|
try:
|
||||||
res = api.app.bsky.notification.list_notifications({"limit": count})
|
res = api.app.bsky.notification.list_notifications({"limit": count})
|
||||||
notifications = getattr(res, "notifications", [])
|
notifications = getattr(res, "notifications", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
if not notifications:
|
if not notifications:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -134,6 +184,27 @@ class NotificationBuffer(BaseBuffer):
|
|||||||
log.exception("Error fetching Bluesky notifications")
|
log.exception("Error fetching Bluesky notifications")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
if not api:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
res = api.app.bsky.notification.list_notifications({"limit": count, "cursor": self.next_cursor})
|
||||||
|
notifications = getattr(res, "notifications", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
added = self.process_items(list(notifications), play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more notifications")
|
||||||
|
|
||||||
def add_new_item(self, notification):
|
def add_new_item(self, notification):
|
||||||
"""Add a single new notification from streaming/polling."""
|
"""Add a single new notification from streaming/polling."""
|
||||||
return self.process_items([notification], play_sound=True)
|
return self.process_items([notification], play_sound=True)
|
||||||
@@ -207,6 +278,7 @@ class LikesBuffer(BaseBuffer):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(LikesBuffer, self).__init__(*args, **kwargs)
|
super(LikesBuffer, self).__init__(*args, **kwargs)
|
||||||
self.type = "likes"
|
self.type = "likes"
|
||||||
|
self.next_cursor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
||||||
@@ -223,12 +295,34 @@ class LikesBuffer(BaseBuffer):
|
|||||||
try:
|
try:
|
||||||
res = api.app.bsky.feed.get_actor_likes({"actor": api.me.did, "limit": count})
|
res = api.app.bsky.feed.get_actor_likes({"actor": api.me.did, "limit": count})
|
||||||
items = getattr(res, "feed", None) or getattr(res, "items", None) or []
|
items = getattr(res, "feed", None) or getattr(res, "items", None) or []
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception("Error fetching likes")
|
log.exception("Error fetching likes")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return self.process_items(list(items), play_sound)
|
return self.process_items(list(items), play_sound)
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
if not api:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
res = api.app.bsky.feed.get_actor_likes({"actor": api.me.did, "limit": count, "cursor": self.next_cursor})
|
||||||
|
items = getattr(res, "feed", None) or getattr(res, "items", None) or []
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
added = self.process_items(list(items), play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more likes")
|
||||||
|
|
||||||
|
|
||||||
class MentionsBuffer(BaseBuffer):
|
class MentionsBuffer(BaseBuffer):
|
||||||
"""Buffer for mentions and replies to the current user."""
|
"""Buffer for mentions and replies to the current user."""
|
||||||
@@ -239,6 +333,7 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
super(MentionsBuffer, self).__init__(*args, **kwargs)
|
super(MentionsBuffer, self).__init__(*args, **kwargs)
|
||||||
self.type = "mentions"
|
self.type = "mentions"
|
||||||
self.sound = "mention_received.ogg"
|
self.sound = "mention_received.ogg"
|
||||||
|
self.next_cursor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
self.buffer = BlueskiPanels.NotificationPanel(parent, name)
|
self.buffer = BlueskiPanels.NotificationPanel(parent, name)
|
||||||
@@ -258,6 +353,7 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
try:
|
try:
|
||||||
res = api.app.bsky.notification.list_notifications({"limit": count})
|
res = api.app.bsky.notification.list_notifications({"limit": count})
|
||||||
notifications = getattr(res, "notifications", [])
|
notifications = getattr(res, "notifications", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
if not notifications:
|
if not notifications:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -276,6 +372,33 @@ class MentionsBuffer(BaseBuffer):
|
|||||||
log.exception("Error fetching Bluesky mentions")
|
log.exception("Error fetching Bluesky mentions")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
if not api:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
res = api.app.bsky.notification.list_notifications({"limit": count, "cursor": self.next_cursor})
|
||||||
|
notifications = getattr(res, "notifications", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
# Filter only mentions and replies
|
||||||
|
mentions = [
|
||||||
|
n for n in notifications
|
||||||
|
if getattr(n, "reason", "") in ("mention", "reply", "quote")
|
||||||
|
]
|
||||||
|
if mentions:
|
||||||
|
added = self.process_items(mentions, play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more mentions")
|
||||||
|
|
||||||
def add_new_item(self, notification):
|
def add_new_item(self, notification):
|
||||||
"""Add a single new mention from streaming/polling."""
|
"""Add a single new mention from streaming/polling."""
|
||||||
reason = getattr(notification, "reason", "")
|
reason = getattr(notification, "reason", "")
|
||||||
@@ -290,6 +413,7 @@ class SentBuffer(BaseBuffer):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(SentBuffer, self).__init__(*args, **kwargs)
|
super(SentBuffer, self).__init__(*args, **kwargs)
|
||||||
self.type = "sent"
|
self.type = "sent"
|
||||||
|
self.next_cursor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
||||||
@@ -314,6 +438,7 @@ class SentBuffer(BaseBuffer):
|
|||||||
"filter": "posts_no_replies"
|
"filter": "posts_no_replies"
|
||||||
})
|
})
|
||||||
items = getattr(res, "feed", [])
|
items = getattr(res, "feed", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
|
||||||
if not items:
|
if not items:
|
||||||
return 0
|
return 0
|
||||||
@@ -324,6 +449,32 @@ class SentBuffer(BaseBuffer):
|
|||||||
log.exception("Error fetching sent posts")
|
log.exception("Error fetching sent posts")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
if not api or not api.me:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
res = api.app.bsky.feed.get_author_feed({
|
||||||
|
"actor": api.me.did,
|
||||||
|
"limit": count,
|
||||||
|
"filter": "posts_no_replies",
|
||||||
|
"cursor": self.next_cursor
|
||||||
|
})
|
||||||
|
items = getattr(res, "feed", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
added = self.process_items(list(items), play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more sent posts")
|
||||||
|
|
||||||
|
|
||||||
class UserTimeline(BaseBuffer):
|
class UserTimeline(BaseBuffer):
|
||||||
"""Buffer for posts by a specific user."""
|
"""Buffer for posts by a specific user."""
|
||||||
@@ -333,6 +484,8 @@ class UserTimeline(BaseBuffer):
|
|||||||
self.handle = kwargs.get("handle")
|
self.handle = kwargs.get("handle")
|
||||||
super(UserTimeline, self).__init__(*args, **kwargs)
|
super(UserTimeline, self).__init__(*args, **kwargs)
|
||||||
self.type = "user_timeline"
|
self.type = "user_timeline"
|
||||||
|
self.next_cursor = None
|
||||||
|
self._resolved_actor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
||||||
@@ -372,17 +525,44 @@ class UserTimeline(BaseBuffer):
|
|||||||
actor = did
|
actor = did
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
self._resolved_actor = actor
|
||||||
res = api.app.bsky.feed.get_author_feed({
|
res = api.app.bsky.feed.get_author_feed({
|
||||||
"actor": actor,
|
"actor": actor,
|
||||||
"limit": count,
|
"limit": count,
|
||||||
})
|
})
|
||||||
items = getattr(res, "feed", []) or []
|
items = getattr(res, "feed", []) or []
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception("Error fetching user timeline")
|
log.exception("Error fetching user timeline")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
return self.process_items(list(items), play_sound)
|
return self.process_items(list(items), play_sound)
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor or not self._resolved_actor:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
if not api:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
res = api.app.bsky.feed.get_author_feed({
|
||||||
|
"actor": self._resolved_actor,
|
||||||
|
"limit": count,
|
||||||
|
"cursor": self.next_cursor
|
||||||
|
})
|
||||||
|
items = getattr(res, "feed", []) or []
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
added = self.process_items(list(items), play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more user timeline items")
|
||||||
|
|
||||||
def remove_buffer(self, force=False):
|
def remove_buffer(self, force=False):
|
||||||
if not force:
|
if not force:
|
||||||
from wxUI import commonMessageDialogs
|
from wxUI import commonMessageDialogs
|
||||||
@@ -419,6 +599,7 @@ class SearchBuffer(BaseBuffer):
|
|||||||
self.search_query = kwargs.pop("query", "")
|
self.search_query = kwargs.pop("query", "")
|
||||||
super(SearchBuffer, self).__init__(*args, **kwargs)
|
super(SearchBuffer, self).__init__(*args, **kwargs)
|
||||||
self.type = "search"
|
self.type = "search"
|
||||||
|
self.next_cursor = None
|
||||||
|
|
||||||
def create_buffer(self, parent, name):
|
def create_buffer(self, parent, name):
|
||||||
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
self.buffer = BlueskiPanels.HomePanel(parent, name)
|
||||||
@@ -445,6 +626,7 @@ class SearchBuffer(BaseBuffer):
|
|||||||
"limit": count
|
"limit": count
|
||||||
})
|
})
|
||||||
posts = getattr(res, "posts", [])
|
posts = getattr(res, "posts", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
|
||||||
if not posts:
|
if not posts:
|
||||||
return 0
|
return 0
|
||||||
@@ -459,6 +641,31 @@ class SearchBuffer(BaseBuffer):
|
|||||||
log.exception("Error searching Bluesky posts")
|
log.exception("Error searching Bluesky posts")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def get_more_items(self):
|
||||||
|
if not self.next_cursor or not self.search_query:
|
||||||
|
return
|
||||||
|
count = 50
|
||||||
|
try:
|
||||||
|
count = self.session.settings["general"].get("max_posts_per_call", 50)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
api = self.session._ensure_client()
|
||||||
|
if not api:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
res = api.app.bsky.feed.search_posts({
|
||||||
|
"q": self.search_query,
|
||||||
|
"limit": count,
|
||||||
|
"cursor": self.next_cursor
|
||||||
|
})
|
||||||
|
posts = getattr(res, "posts", [])
|
||||||
|
self.next_cursor = getattr(res, "cursor", None)
|
||||||
|
added = self.process_items(list(posts), play_sound=False)
|
||||||
|
if added:
|
||||||
|
output.speak(_(u"%s items retrieved") % (str(added)), True)
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error fetching more search results")
|
||||||
|
|
||||||
def remove_buffer(self, force=False):
|
def remove_buffer(self, force=False):
|
||||||
"""Search buffers can always be removed."""
|
"""Search buffers can always be removed."""
|
||||||
if not force:
|
if not force:
|
||||||
@@ -471,4 +678,16 @@ class SearchBuffer(BaseBuffer):
|
|||||||
self.session.db.pop(self.name, None)
|
self.session.db.pop(self.name, None)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# Also remove from saved searches
|
||||||
|
try:
|
||||||
|
searches = self.session.settings["other_buffers"].get("searches")
|
||||||
|
if searches:
|
||||||
|
if isinstance(searches, str):
|
||||||
|
searches = [s for s in searches.split(",") if s]
|
||||||
|
if self.search_query in searches:
|
||||||
|
searches.remove(self.search_query)
|
||||||
|
self.session.settings["other_buffers"]["searches"] = searches
|
||||||
|
self.session.settings.write()
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error updating saved searches")
|
||||||
return True
|
return True
|
||||||
|
|||||||
Reference in New Issue
Block a user