Refactor UserTune

- Simplify modules because nbxmpp handles more stuff
This commit is contained in:
Philipp Hörist 2019-02-01 20:46:20 +01:00
parent 18c422d843
commit d37b95e45e
8 changed files with 93 additions and 88 deletions

View File

@ -61,6 +61,7 @@ from gajim.gtk.util import get_cursor
from gajim.gtk.util import ensure_proper_control from gajim.gtk.util import ensure_proper_control
from gajim.gtk.util import format_mood from gajim.gtk.util import format_mood
from gajim.gtk.util import format_activity from gajim.gtk.util import format_activity
from gajim.gtk.util import format_tune
from gajim.gtk.util import get_activity_icon_name from gajim.gtk.util import get_activity_icon_name
from gajim.command_system.implementation.hosts import ChatCommands from gajim.command_system.implementation.hosts import ChatCommands
@ -133,7 +134,6 @@ class ChatControl(ChatControlBase):
self.update_toolbar() self.update_toolbar()
self._pep_images = {} self._pep_images = {}
self._pep_images['tune'] = self.xml.get_object('tune_image')
self._pep_images['geoloc'] = self.xml.get_object('location_image') self._pep_images['geoloc'] = self.xml.get_object('location_image')
self.update_all_pep_types() self.update_all_pep_types()
@ -236,6 +236,8 @@ class ChatControl(ChatControlBase):
self._on_mood_received) self._on_mood_received)
app.ged.register_event_handler('activity-received', ged.GUI1, app.ged.register_event_handler('activity-received', ged.GUI1,
self._on_activity_received) self._on_activity_received)
app.ged.register_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
if self.TYPE_ID == message_control.TYPE_CHAT: if self.TYPE_ID == message_control.TYPE_CHAT:
# Dont connect this when PrivateChatControl is used # Dont connect this when PrivateChatControl is used
app.ged.register_event_handler('update-roster-avatar', ged.GUI1, app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
@ -420,6 +422,7 @@ class ChatControl(ChatControlBase):
self.update_pep(pep_type) self.update_pep(pep_type)
self._update_pep(PEPEventType.MOOD) self._update_pep(PEPEventType.MOOD)
self._update_pep(PEPEventType.ACTIVITY) self._update_pep(PEPEventType.ACTIVITY)
self._update_pep(PEPEventType.TUNE)
def update_pep(self, pep_type): def update_pep(self, pep_type):
if isinstance(self.contact, GC_Contact): if isinstance(self.contact, GC_Contact):
@ -460,6 +463,9 @@ class ChatControl(ChatControlBase):
elif type_ == PEPEventType.ACTIVITY: elif type_ == PEPEventType.ACTIVITY:
icon = get_activity_icon_name(data.activity, data.subactivity) icon = get_activity_icon_name(data.activity, data.subactivity)
formated_text = format_activity(*data) formated_text = format_activity(*data)
elif type_ == PEPEventType.TUNE:
icon = 'audio-x-generic'
formated_text = format_tune(*data)
image.set_from_icon_name(icon, Gtk.IconSize.MENU) image.set_from_icon_name(icon, Gtk.IconSize.MENU)
image.set_tooltip_markup(formated_text) image.set_tooltip_markup(formated_text)
@ -470,6 +476,8 @@ class ChatControl(ChatControlBase):
return self.xml.get_object('mood_image') return self.xml.get_object('mood_image')
if type_ == PEPEventType.ACTIVITY: if type_ == PEPEventType.ACTIVITY:
return self.xml.get_object('activity_image') return self.xml.get_object('activity_image')
if type_ == PEPEventType.TUNE:
return self.xml.get_object('tune_image')
@ensure_proper_control @ensure_proper_control
def _on_mood_received(self, _event): def _on_mood_received(self, _event):
@ -479,6 +487,10 @@ class ChatControl(ChatControlBase):
def _on_activity_received(self, _event): def _on_activity_received(self, _event):
self._update_pep(PEPEventType.ACTIVITY) self._update_pep(PEPEventType.ACTIVITY)
@ensure_proper_control
def _on_tune_received(self, _event):
self._update_pep(PEPEventType.TUNE)
@ensure_proper_control @ensure_proper_control
def _on_nickname_received(self, _event): def _on_nickname_received(self, _event):
self.update_ui() self.update_ui()
@ -1101,6 +1113,8 @@ class ChatControl(ChatControlBase):
self._on_mood_received) self._on_mood_received)
app.ged.remove_event_handler('activity-received', ged.GUI1, app.ged.remove_event_handler('activity-received', ged.GUI1,
self._on_activity_received) self._on_activity_received)
app.ged.remove_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
if self.TYPE_ID == message_control.TYPE_CHAT: if self.TYPE_ID == message_control.TYPE_CHAT:
app.ged.remove_event_handler('update-roster-avatar', ged.GUI1, app.ged.remove_event_handler('update-roster-avatar', ged.GUI1,
self._nec_update_avatar) self._nec_update_avatar)

View File

@ -15,90 +15,62 @@
# XEP-0118: User Tune # XEP-0118: User Tune
from typing import Any from typing import Any
from typing import List # pylint: disable=unused-import
from typing import Dict
from typing import Optional
from typing import Tuple from typing import Tuple
import logging import logging
import nbxmpp import nbxmpp
from gi.repository import GLib
from gajim.common.i18n import _ from gajim.common import app
from gajim.common.nec import NetworkEvent
from gajim.common.modules.base import BaseModule
from gajim.common.modules.util import event_node
from gajim.common.modules.util import store_publish
from gajim.common.const import PEPEventType from gajim.common.const import PEPEventType
from gajim.common.exceptions import StanzaMalformed
from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
from gajim.common.types import UserTuneDataT
log = logging.getLogger('gajim.c.m.user_tune') log = logging.getLogger('gajim.c.m.user_tune')
class UserTuneData(AbstractPEPData): class UserTune(BaseModule):
type_ = PEPEventType.TUNE _nbxmpp_extends = 'Tune'
_nbxmpp_methods = [
'set_tune',
]
def as_markup_text(self) -> str: def __init__(self, con):
if self.data is None: BaseModule.__init__(self, con)
return '' self._register_pubsub_handler(self._tune_received)
tune = self.data @event_node(nbxmpp.NS_TUNE)
def _tune_received(self, _con, _stanza, properties):
data = properties.pubsub_event.data
empty = properties.pubsub_event.empty
artist = tune.get('artist', _('Unknown Artist')) for contact in app.contacts.get_contacts(self._account,
artist = GLib.markup_escape_text(artist) str(properties.jid)):
if not empty:
contact.pep[PEPEventType.TUNE] = data
else:
contact.pep.pop(PEPEventType.TUNE, None)
title = tune.get('title', _('Unknown Title')) if properties.is_self_message:
title = GLib.markup_escape_text(title) if not empty:
self._con.pep[PEPEventType.TUNE] = data
else:
self._con.pep.pop(PEPEventType.TUNE, None)
source = tune.get('source', _('Unknown Source')) app.nec.push_incoming_event(
source = GLib.markup_escape_text(source) NetworkEvent('tune-received',
account=self._account,
jid=properties.jid.getBare(),
tune=data,
is_self_message=properties.is_self_message))
tune_string = _('<b>"%(title)s"</b> by <i>%(artist)s</i>\n' @store_publish
'from <i>%(source)s</i>') % {'title': title, def set_tune(self, tune):
'artist': artist, log.info('Send %s', tune)
'source': source} self._nbxmpp('Tune').set_tune(tune)
return tune_string
class UserTune(AbstractPEPModule):
name = 'tune'
namespace = nbxmpp.NS_TUNE
pep_class = UserTuneData
store_publish = True
_log = log
def _extract_info(self, item: nbxmpp.Node) -> Optional[Dict[str, str]]:
tune_dict = {}
tune_tag = item.getTag('tune', namespace=self.namespace)
if tune_tag is None:
raise StanzaMalformed('No tune node')
for child in tune_tag.getChildren():
name = child.getName().strip()
data = child.getData().strip()
if child.getName() in ['artist', 'title', 'source',
'track', 'length']:
tune_dict[name] = data
return tune_dict or None
def _build_node(self, data: UserTuneDataT) -> nbxmpp.Node:
item = nbxmpp.Node('tune', {'xmlns': nbxmpp.NS_TUNE})
if data is None:
return item
artist, title, source, track, length = data
if artist:
item.addChild('artist', payload=artist)
if title:
item.addChild('title', payload=title)
if source:
item.addChild('source', payload=source)
if track:
item.addChild('track', payload=track)
if length:
item.addChild('length', payload=length)
return item
def get_instance(*args: Any, **kwargs: Any) -> Tuple[UserTune, str]: def get_instance(*args: Any, **kwargs: Any) -> Tuple[UserTune, str]:

View File

@ -47,8 +47,6 @@ ConnectionT = Union['Connection', 'ConnectionZeroconf']
ContactsT = Union['Contact', 'GC_Contact'] ContactsT = Union['Contact', 'GC_Contact']
ContactT = Union['Contact'] ContactT = Union['Contact']
UserTuneDataT = Optional[Tuple[str, str, str, str, str]]
# PEP # PEP
PEPNotifyCallback = Callable[[nbxmpp.JID, nbxmpp.Node], None] PEPNotifyCallback = Callable[[nbxmpp.JID, nbxmpp.Node], None]
PEPHandlersDict = Dict[str, List[PEPNotifyCallback]] PEPHandlersDict = Dict[str, List[PEPNotifyCallback]]

View File

@ -44,6 +44,7 @@ from gajim.gtk.util import get_builder
from gajim.gtk.util import get_icon_name from gajim.gtk.util import get_icon_name
from gajim.gtk.util import format_mood from gajim.gtk.util import format_mood
from gajim.gtk.util import format_activity from gajim.gtk.util import format_activity
from gajim.gtk.util import format_tune
log = logging.getLogger('gajim.gtk.tooltips') log = logging.getLogger('gajim.gtk.tooltips')
@ -487,8 +488,8 @@ class RosterTooltip(StatusTable):
self._ui.activity.show() self._ui.activity.show()
self._ui.activity_label.show() self._ui.activity_label.show()
if 'tune' in contact.pep: if PEPEventType.TUNE in contact.pep:
tune = contact.pep['tune'].as_markup_text() tune = format_tune(*contact.pep[PEPEventType.TUNE])
self._ui.tune.set_markup(tune) self._ui.tune.set_markup(tune)
self._ui.tune.show() self._ui.tune.show()
self._ui.tune_label.show() self._ui.tune_label.show()

View File

@ -546,3 +546,17 @@ def get_activity_icon_name(activity, subactivity=None):
if subactivity is not None: if subactivity is not None:
icon_name += '-%s' % subactivity.replace('_', '-') icon_name += '-%s' % subactivity.replace('_', '-')
return icon_name return icon_name
def format_tune(artist, length, rating, source, title, track, uri):
if artist is None and title is None and source is None:
return
artist = GLib.markup_escape_text(artist or _('Unknown Artist'))
title = GLib.markup_escape_text(title or _('Unknown Title'))
source = GLib.markup_escape_text(source or _('Unknown Source'))
tune_string = _('<b>"%(title)s"</b> by <i>%(artist)s</i>\n'
'from <i>%(source)s</i>') % {'title': title,
'artist': artist,
'source': source}
return tune_string

View File

@ -265,9 +265,6 @@ def create_list_multi(value_list, selected_values=None):
return treeview return treeview
def get_pep_icon(pep_class): def get_pep_icon(pep_class):
if pep_class == PEPEventType.TUNE:
return 'audio-x-generic'
if pep_class == PEPEventType.LOCATION: if pep_class == PEPEventType.LOCATION:
return 'applications-internet' return 'applications-internet'

View File

@ -47,6 +47,7 @@ from gi.repository import Gio
from gi.repository import Gdk from gi.repository import Gdk
from nbxmpp import idlequeue from nbxmpp import idlequeue
from nbxmpp import Hashes2 from nbxmpp import Hashes2
from nbxmpp.structs import TuneData
import OpenSSL import OpenSSL
try: try:
@ -1942,8 +1943,8 @@ class Interface:
continue continue
if app.connections[acct].music_track_info == music_track_info: if app.connections[acct].music_track_info == music_track_info:
continue continue
app.connections[acct].get_module('UserTune').send( app.connections[acct].get_module('UserTune').set_tune(
(artist, title, source, '', '')) TuneData(artist=artist, title=title, source=source))
app.connections[acct].music_track_info = music_track_info app.connections[acct].music_track_info = music_track_info
def read_sleepy(self): def read_sleepy(self):

View File

@ -1058,9 +1058,8 @@ class RosterWindow:
else: else:
self.model[child_iter][Column.ACTIVITY_PIXBUF] = None self.model[child_iter][Column.ACTIVITY_PIXBUF] = None
if app.config.get('show_tunes_in_roster') and 'tune' in pep_dict: if app.config.get('show_tunes_in_roster') and PEPEventType.TUNE in pep_dict:
self.model[child_iter][Column.TUNE_ICON] = \ self.model[child_iter][Column.TUNE_ICON] = 'audio-x-generic'
gtkgui_helpers.get_pep_icon(pep_dict['tune'])
else: else:
self.model[child_iter][Column.TUNE_ICON] = None self.model[child_iter][Column.TUNE_ICON] = None
@ -1319,7 +1318,7 @@ class RosterWindow:
if pep_type == PEPEventType.ACTIVITY: if pep_type == PEPEventType.ACTIVITY:
return app.config.get('show_activity_in_roster') return app.config.get('show_activity_in_roster')
if pep_type == 'tune': if pep_type == PEPEventType.TUNE:
return app.config.get('show_tunes_in_roster') return app.config.get('show_tunes_in_roster')
if pep_type == 'geoloc': if pep_type == 'geoloc':
@ -1332,6 +1331,7 @@ class RosterWindow:
self.draw_pep(jid, account, pep_type, contact=contact) self.draw_pep(jid, account, pep_type, contact=contact)
self._draw_pep(account, jid, PEPEventType.MOOD) self._draw_pep(account, jid, PEPEventType.MOOD)
self._draw_pep(account, jid, PEPEventType.ACTIVITY) self._draw_pep(account, jid, PEPEventType.ACTIVITY)
self._draw_pep(account, jid, PEPEventType.TUNE)
def draw_pep(self, jid, account, pep_type, contact=None): def draw_pep(self, jid, account, pep_type, contact=None):
if pep_type not in self._pep_type_to_model_column: if pep_type not in self._pep_type_to_model_column:
@ -1373,6 +1373,10 @@ class RosterWindow:
column = Column.ACTIVITY_PIXBUF column = Column.ACTIVITY_PIXBUF
if data is not None: if data is not None:
icon = get_activity_icon_name(data.activity, data.subactivity) icon = get_activity_icon_name(data.activity, data.subactivity)
elif type_ == PEPEventType.TUNE:
column = Column.TUNE_ICON
if data is not None:
icon = 'audio-x-generic'
for child_iter in iters: for child_iter in iters:
self.model[child_iter][column] = icon self.model[child_iter][column] = icon
@ -2636,8 +2640,7 @@ class RosterWindow:
self.remove_contact(jid, obj.conn.name, backend=True) self.remove_contact(jid, obj.conn.name, backend=True)
def _nec_pep_received(self, obj): def _nec_pep_received(self, obj):
if obj.user_pep.type_ not in (PEPEventType.TUNE, if obj.user_pep.type_ != PEPEventType.LOCATION:
PEPEventType.LOCATION):
return return
if obj.jid == app.get_jid_from_account(obj.conn.name): if obj.jid == app.get_jid_from_account(obj.conn.name):
@ -2655,6 +2658,11 @@ class RosterWindow:
self.draw_account(event.account) self.draw_account(event.account)
self._draw_pep(event.account, event.jid, PEPEventType.ACTIVITY) self._draw_pep(event.account, event.jid, PEPEventType.ACTIVITY)
def _on_tune_received(self, event):
if event.is_self_message:
self.draw_account(event.account)
self._draw_pep(event.account, event.jid, PEPEventType.TUNE)
def _on_nickname_received(self, event): def _on_nickname_received(self, event):
self.draw_contact(event.jid, event.account) self.draw_contact(event.jid, event.account)
@ -3595,7 +3603,7 @@ class RosterWindow:
if active: if active:
app.interface.enable_music_listener() app.interface.enable_music_listener()
else: else:
app.connections[account].get_module('UserTune').send(None) app.connections[account].get_module('UserTune').set_tune(None)
# disable music listener only if no other account uses it # disable music listener only if no other account uses it
for acc in app.connections: for acc in app.connections:
if app.config.get_per('accounts', acc, 'publish_tune'): if app.config.get_per('accounts', acc, 'publish_tune'):
@ -5591,9 +5599,8 @@ class RosterWindow:
# [icon, name, type, jid, account, editable, mood_pixbuf, # [icon, name, type, jid, account, editable, mood_pixbuf,
# activity_pixbuf, TUNE_ICON, LOCATION_ICON, avatar_img, # activity_pixbuf, TUNE_ICON, LOCATION_ICON, avatar_img,
# padlock_pixbuf, visible] # padlock_pixbuf, visible]
self.columns = [str, str, str, str, str, self.columns = [str, str, str, str, str, str, str, str, str,
str, str, str, str, Gtk.Image, str, bool]
Gtk.Image, str, bool]
self.xml = get_builder('roster_window.ui') self.xml = get_builder('roster_window.ui')
self.window = self.xml.get_object('roster_window') self.window = self.xml.get_object('roster_window')
@ -5692,8 +5699,7 @@ class RosterWindow:
# cell_data_func, func_arg) # cell_data_func, func_arg)
self.renderers_list = [] self.renderers_list = []
self.renderers_propertys = {} self.renderers_propertys = {}
self._pep_type_to_model_column = {'tune': Column.TUNE_ICON, self._pep_type_to_model_column = {'geoloc': Column.LOCATION_ICON}
'geoloc': Column.LOCATION_ICON}
renderer_text = Gtk.CellRendererText() renderer_text = Gtk.CellRendererText()
self.renderers_propertys[renderer_text] = ('ellipsize', self.renderers_propertys[renderer_text] = ('ellipsize',
@ -5847,6 +5853,8 @@ class RosterWindow:
self._on_mood_received) self._on_mood_received)
app.ged.register_event_handler('activity-received', ged.GUI1, app.ged.register_event_handler('activity-received', ged.GUI1,
self._on_activity_received) self._on_activity_received)
app.ged.register_event_handler('tune-received', ged.GUI1,
self._on_tune_received)
app.ged.register_event_handler('update-roster-avatar', ged.GUI1, app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
self._nec_update_avatar) self._nec_update_avatar)
app.ged.register_event_handler('update-room-avatar', ged.GUI1, app.ged.register_event_handler('update-room-avatar', ged.GUI1,