mirror of
https://github.com/MCV-Software/TWBlue.git
synced 2026-03-06 09:27:33 +01:00
Arreglado un problema con inicio de sesiones
This commit is contained in:
34
CAMBIOS.md
34
CAMBIOS.md
@@ -220,6 +220,40 @@ Para integrar Bluesky en TWBlue, también se modificaron:
|
|||||||
4. Introducir App Password (desde Configuración > App Passwords en bsky.app)
|
4. Introducir App Password (desde Configuración > App Passwords en bsky.app)
|
||||||
5. Los buffers se crearán automáticamente
|
5. Los buffers se crearán automáticamente
|
||||||
|
|
||||||
|
## Correcciones Recientes
|
||||||
|
|
||||||
|
### Orden de Conversaciones
|
||||||
|
- Las conversaciones ahora se muestran en orden cronológico correcto (más antiguo arriba, más reciente abajo)
|
||||||
|
- Se añadió método `_add_items_chronological()` en `timeline.py` para manejar el orden específico de conversaciones
|
||||||
|
|
||||||
|
### Detección de Imágenes y Sonido Indicador
|
||||||
|
- Corregido el evento de foco en paneles: cambiado de `wx.EVT_SET_FOCUS` a `wx.EVT_LIST_ITEM_FOCUSED`
|
||||||
|
- `EVT_SET_FOCUS` solo se disparaba al entrar al control, no al moverse entre elementos
|
||||||
|
- `EVT_LIST_ITEM_FOCUSED` se dispara correctamente al navegar entre posts con las flechas
|
||||||
|
- Simplificada función `is_image()` para detectar imágenes sin requerir URLs válidas
|
||||||
|
|
||||||
|
### Funcionalidad OCR
|
||||||
|
- Implementada función `ocr_image()` en `base.py` para extraer texto de imágenes
|
||||||
|
- Usa `extra.ocr.OCRSpace.OCRSpaceAPI()` para el reconocimiento
|
||||||
|
- Soporta selección de imagen cuando hay múltiples imágenes en un post
|
||||||
|
- Creada clase `text` en `controller/blueski/messages.py` como visor de resultados OCR
|
||||||
|
- Creado diálogo `viewText` en `wxUI/dialogs/blueski/postDialogs.py`
|
||||||
|
- **Independiente de Mastodon**: no hay dependencias entre módulos blueski y mastodon
|
||||||
|
|
||||||
|
### Reproducción Multimedia
|
||||||
|
- Implementada función `audio()` en `base.py` para reproducir vídeos y audio
|
||||||
|
- Usa `sound.URLPlayer` para la reproducción
|
||||||
|
- Soporta selección de URL cuando hay múltiples medios
|
||||||
|
- Función `get_media_urls()` en utils.py extrae URLs de vídeos, streams HLS y enlaces externos (YouTube, Vimeo, etc.)
|
||||||
|
|
||||||
|
### Utilidades (`sessions/blueski/utils.py`)
|
||||||
|
- `is_image(post)`: Detecta si un post tiene imágenes (simplificado, no requiere URLs válidas)
|
||||||
|
- `is_audio_or_video(post)`: Detecta contenido de audio/vídeo
|
||||||
|
- `get_image_urls(post)`: Extrae URLs de imágenes para OCR
|
||||||
|
- `get_media_urls(post)`: Extrae URLs de medios para reproducción
|
||||||
|
- `find_urls(post)`: Encuentra URLs en el contenido del post
|
||||||
|
- `_extract_images_from_embed(embed)`: Helper compartido para extracción de imágenes
|
||||||
|
|
||||||
## Limitaciones Conocidas
|
## Limitaciones Conocidas
|
||||||
|
|
||||||
- No hay streaming en tiempo real (se usa polling)
|
- No hay streaming en tiempo real (se usa polling)
|
||||||
|
|||||||
@@ -254,9 +254,11 @@ class Controller(object):
|
|||||||
for i in sessions.sessions:
|
for i in sessions.sessions:
|
||||||
log.debug("Working on session %s" % (i,))
|
log.debug("Working on session %s" % (i,))
|
||||||
if sessions.sessions[i].is_logged == False:
|
if sessions.sessions[i].is_logged == False:
|
||||||
# Try auto-login for Blueski sessions if credentials exist
|
if sessions.sessions[i].session_id in config.app["sessions"]["ignored_sessions"]:
|
||||||
|
self.create_ignored_session_buffer(sessions.sessions[i])
|
||||||
|
continue
|
||||||
|
# Try auto-login for sessions if credentials exist
|
||||||
try:
|
try:
|
||||||
if getattr(sessions.sessions[i], "type", None) == "blueski":
|
|
||||||
sessions.sessions[i].login()
|
sessions.sessions[i].login()
|
||||||
except Exception:
|
except Exception:
|
||||||
log.exception("Auto-login attempt failed for session %s", i)
|
log.exception("Auto-login attempt failed for session %s", i)
|
||||||
@@ -280,11 +282,8 @@ class Controller(object):
|
|||||||
""" Starts all buffer objects. Loads their items."""
|
""" Starts all buffer objects. Loads their items."""
|
||||||
for i in sessions.sessions:
|
for i in sessions.sessions:
|
||||||
if sessions.sessions[i].is_logged == False: continue
|
if sessions.sessions[i].is_logged == False: continue
|
||||||
self.start_buffers(sessions.sessions[i])
|
call_threaded(self._start_session_buffers, sessions.sessions[i])
|
||||||
self.set_buffer_positions(sessions.sessions[i])
|
if len(sessions.sessions) > 0 and config.app["app-settings"]["play_ready_sound"] == True:
|
||||||
if hasattr(sessions.sessions[i], "start_streaming"):
|
|
||||||
sessions.sessions[i].start_streaming()
|
|
||||||
if config.app["app-settings"]["play_ready_sound"] == True:
|
|
||||||
sessions.sessions[list(sessions.sessions.keys())[0]].sound.play("ready.ogg")
|
sessions.sessions[list(sessions.sessions.keys())[0]].sound.play("ready.ogg")
|
||||||
if config.app["app-settings"]["speak_ready_msg"] == True:
|
if config.app["app-settings"]["speak_ready_msg"] == True:
|
||||||
output.speak(_(u"Ready"))
|
output.speak(_(u"Ready"))
|
||||||
@@ -293,6 +292,16 @@ class Controller(object):
|
|||||||
b = self.get_first_buffer(self.accounts[0])
|
b = self.get_first_buffer(self.accounts[0])
|
||||||
self.update_menus(handler=self.get_handler(b.session.type))
|
self.update_menus(handler=self.get_handler(b.session.type))
|
||||||
|
|
||||||
|
def _start_session_buffers(self, session):
|
||||||
|
"""Helper to start buffers for a session in a background thread."""
|
||||||
|
try:
|
||||||
|
self.start_buffers(session)
|
||||||
|
self.set_buffer_positions(session)
|
||||||
|
if hasattr(session, "start_streaming"):
|
||||||
|
session.start_streaming()
|
||||||
|
except Exception:
|
||||||
|
log.exception("Error starting buffers for session %s", session.session_id)
|
||||||
|
|
||||||
def create_ignored_session_buffer(self, session):
|
def create_ignored_session_buffer(self, session):
|
||||||
pub.sendMessage("core.create_account", name=session.get_name(), session_id=session.session_id)
|
pub.sendMessage("core.create_account", name=session.get_name(), session_id=session.session_id)
|
||||||
|
|
||||||
@@ -740,7 +749,13 @@ class Controller(object):
|
|||||||
|
|
||||||
def post_reply(self, *args, **kwargs):
|
def post_reply(self, *args, **kwargs):
|
||||||
buffer = self.get_current_buffer()
|
buffer = self.get_current_buffer()
|
||||||
if not buffer or not buffer.session:
|
if not buffer:
|
||||||
|
return
|
||||||
|
# Use buffer's own reply method if available (handles Mastodon and most cases)
|
||||||
|
if hasattr(buffer, "reply"):
|
||||||
|
return buffer.reply()
|
||||||
|
# Fallback for buffers without reply method
|
||||||
|
if not buffer.session:
|
||||||
output.speak(_("No active session to reply."), True)
|
output.speak(_("No active session to reply."), True)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1052,6 +1067,8 @@ class Controller(object):
|
|||||||
|
|
||||||
def buffer_changed(self, *args, **kwargs):
|
def buffer_changed(self, *args, **kwargs):
|
||||||
buffer = self.get_current_buffer()
|
buffer = self.get_current_buffer()
|
||||||
|
if buffer is None:
|
||||||
|
return
|
||||||
old_account = self.current_account
|
old_account = self.current_account
|
||||||
new_account = buffer.account
|
new_account = buffer.account
|
||||||
if new_account != old_account:
|
if new_account != old_account:
|
||||||
@@ -1175,6 +1192,9 @@ class Controller(object):
|
|||||||
output.speak(msg, True)
|
output.speak(msg, True)
|
||||||
|
|
||||||
def next_account(self, *args, **kwargs):
|
def next_account(self, *args, **kwargs):
|
||||||
|
if not self.accounts:
|
||||||
|
output.speak(_("No accounts available."), True)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
index = self.accounts.index(self.current_account)
|
index = self.accounts.index(self.current_account)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -1203,6 +1223,9 @@ class Controller(object):
|
|||||||
output.speak(msg, True)
|
output.speak(msg, True)
|
||||||
|
|
||||||
def previous_account(self, *args, **kwargs):
|
def previous_account(self, *args, **kwargs):
|
||||||
|
if not self.accounts:
|
||||||
|
output.speak(_("No accounts available."), True)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
index = self.accounts.index(self.current_account)
|
index = self.accounts.index(self.current_account)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|||||||
@@ -63,13 +63,17 @@ class list(object):
|
|||||||
|
|
||||||
def get_selected(self):
|
def get_selected(self):
|
||||||
if self.system == "Windows":
|
if self.system == "Windows":
|
||||||
return self.list.GetFocusedItem()
|
item = self.list.GetFocusedItem()
|
||||||
|
if item == -1:
|
||||||
|
item = self.list.GetFirstSelected()
|
||||||
|
return item
|
||||||
else:
|
else:
|
||||||
return self.list.GetSelection()
|
return self.list.GetSelection()
|
||||||
|
|
||||||
def select_item(self, pos):
|
def select_item(self, pos):
|
||||||
if self.system == "Windows":
|
if self.system == "Windows":
|
||||||
self.list.Focus(pos)
|
self.list.Focus(pos)
|
||||||
|
self.list.Select(pos)
|
||||||
else:
|
else:
|
||||||
self.list.SetSelection(pos)
|
self.list.SetSelection(pos)
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,27 @@ def is_image(post):
|
|||||||
"""
|
"""
|
||||||
actual_post = g(post, "post", post)
|
actual_post = g(post, "post", post)
|
||||||
embed = g(actual_post, "embed", None)
|
embed = g(actual_post, "embed", None)
|
||||||
return len(_extract_images_from_embed(embed)) > 0
|
if not embed:
|
||||||
|
return False
|
||||||
|
|
||||||
|
etype = g(embed, "$type") or g(embed, "py_type") or ""
|
||||||
|
|
||||||
|
# Direct images embed
|
||||||
|
if "images" in etype.lower():
|
||||||
|
images = g(embed, "images", [])
|
||||||
|
if images and len(images) > 0:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Check in recordWithMedia wrapper
|
||||||
|
if "recordwithmedia" in etype.lower():
|
||||||
|
media = g(embed, "media", {})
|
||||||
|
mtype = g(media, "$type") or g(media, "py_type") or ""
|
||||||
|
if "images" in mtype.lower():
|
||||||
|
images = g(media, "images", [])
|
||||||
|
if images and len(images) > 0:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_image_urls(post):
|
def get_image_urls(post):
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Session(base.baseSession):
|
|||||||
if self.settings["mastodon"]["access_token"] != None and self.settings["mastodon"]["instance"] != None:
|
if self.settings["mastodon"]["access_token"] != None and self.settings["mastodon"]["instance"] != None:
|
||||||
try:
|
try:
|
||||||
log.debug("Logging in to Mastodon instance {}...".format(self.settings["mastodon"]["instance"]))
|
log.debug("Logging in to Mastodon instance {}...".format(self.settings["mastodon"]["instance"]))
|
||||||
self.api = mastodon.Mastodon(access_token=self.settings["mastodon"]["access_token"], api_base_url=self.settings["mastodon"]["instance"], mastodon_version=MASTODON_VERSION, user_agent="TWBlue/{}".format(application.version), version_check_mode=self.version_check_mode)
|
self.api = mastodon.Mastodon(access_token=self.settings["mastodon"]["access_token"], api_base_url=self.settings["mastodon"]["instance"], mastodon_version=MASTODON_VERSION, user_agent="TWBlue/{}".format(application.version), version_check_mode=self.version_check_mode, request_timeout=30)
|
||||||
if verify_credentials == True:
|
if verify_credentials == True:
|
||||||
credentials = self.api.account_verify_credentials()
|
credentials = self.api.account_verify_credentials()
|
||||||
self.db["user_name"] = credentials["username"]
|
self.db["user_name"] = credentials["username"]
|
||||||
|
|||||||
Reference in New Issue
Block a user