now_listen.py 6.46 KB
Newer Older
1 2
import os
import logging
Dicson's avatar
Dicson committed
3

Dicson's avatar
Dicson committed
4 5
from gi.repository import Gtk
from gi.repository import Gdk
Dicson's avatar
Dicson committed
6

7 8 9
from gajim.plugins import GajimPlugin
from gajim.plugins.helpers import log_calls
from gajim.plugins.gui import GajimPluginConfigDialog
Daniel Brötzmann's avatar
Daniel Brötzmann committed
10
from gajim.plugins.plugins_i18n import _
Dicson's avatar
Dicson committed
11

Daniel Brötzmann's avatar
Daniel Brötzmann committed
12
from gajim.common.dbus.music_track import MusicTrackListener
13

14

Philipp Hörist's avatar
Philipp Hörist committed
15
log = logging.getLogger('gajim.p.now_listen')
16

17

Dicson's avatar
Dicson committed
18 19 20
class NowListenPlugin(GajimPlugin):
    @log_calls('NowListenPlugin')
    def init(self):
21
        self.description = _('Copy tune info of playing music to conversation '
22
                             'input box at cursor position (Alt + N)')
Dicson's avatar
Dicson committed
23 24
        self.config_dialog = NowListenPluginConfigDialog(self)
        self.gui_extension_points = {'chat_control_base':
25 26
                                     (self.connect_with_chat_control,
                                      self.disconnect_from_chat_control)}
Dicson's avatar
Dicson committed
27 28

        self.config_default_values = {
29 30 31
            'format_string':
                (_('Now listening to: "%title" by %artist from %album'), ''),
            'format_string_http':
32
                (_('Now listening to: "%title" by %artist'), ''), }
Dicson's avatar
Dicson committed
33 34 35 36

        self.controls = []
        self.first_run = True
        self.music_track_changed_signal = None
37
        if os.name == 'nt':
38
            self.available_text = _('Plugin cannot be run under Windows.')
39
            self.activatable = False
Dicson's avatar
Dicson committed
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

    @log_calls('NowListenPlugin')
    def connect_with_chat_control(self, chat_control):
        self.chat_control = chat_control
        control = Base(self, self.chat_control)
        self.controls.append(control)

    @log_calls('NowListenPlugin')
    def disconnect_from_chat_control(self, chat_control):
        for control in self.controls:
            control.disconnect_from_chat_control()
        self.controls = []

    @log_calls('NowListenPlugin')
    def activate(self):
        listener = MusicTrackListener.get()
        if not self.music_track_changed_signal:
            self.music_track_changed_signal = listener.connect(
                'music-track-changed', self.music_track_changed)
59 60 61 62 63 64
            try:
                listener.start()
            except AttributeError:
                track = listener.get_playing_track('org.mpris.MediaPlayer2')
                self.music_track_changed(listener, track)

Dicson's avatar
Dicson committed
65 66 67

    @log_calls('NowListenPlugin')
    def deactivate(self):
68 69 70 71 72 73 74 75
        listener = MusicTrackListener.get()
        if self.music_track_changed_signal:
            listener.disconnect(self.music_track_changed_signal)
            self.music_track_changed_signal = None
            try:
                listener.stop()
            except AttributeError:
                pass
Dicson's avatar
Dicson committed
76 77

    def music_track_changed(self, unused_listener, music_track_info,
78 79 80
                            account=None):

        if music_track_info is None or music_track_info.paused:
André's avatar
André committed
81
            self.artist = self.title = self.album = ''
Dicson's avatar
Dicson committed
82 83 84
        else:
            self.artist = music_track_info.artist
            self.title = music_track_info.title
85
            self.album = music_track_info.album
André's avatar
André committed
86
            log.debug("%s - %s", self.artist, self.title)
Dicson's avatar
Dicson committed
87 88 89 90 91
            if hasattr(music_track_info, 'url'):
                self.url = music_track_info.url
                self.albumartist = music_track_info.albumartist
            else:
                self.url = ''
Dicson's avatar
Dicson committed
92 93 94 95 96 97


class Base(object):
    def __init__(self, plugin, chat_control):
        self.plugin = plugin
        self.chat_control = chat_control
98 99
        if not hasattr(self.plugin, 'title'):
            self.plugin.artist = self.plugin.title = self.plugin.album = ''
Dicson's avatar
Dicson committed
100
        self.plugin.url = self.plugin.albumartist = ''
Dicson's avatar
Dicson committed
101

Dicson's avatar
Dicson committed
102
        self.id_ = self.chat_control.msg_textview.connect('key_press_event',
103
                                                          self.on_insert)
Dicson's avatar
Dicson committed
104 105 106
        self.chat_control.handlers[self.id_] = self.chat_control.msg_textview

    def disconnect_from_chat_control(self):
107 108
        if self.id_ not in self.chat_control.handlers:
            return
Dicson's avatar
Dicson committed
109 110 111 112
        if self.chat_control.handlers[self.id_].handler_is_connected(self.id_):
            self.chat_control.handlers[self.id_].disconnect(self.id_)
            del self.chat_control.handlers[self.id_]

Dicson's avatar
Dicson committed
113
    def on_insert(self, widget, event):
Dicson's avatar
Dicson committed
114 115 116
        """
        Insert text to conversation input box, at cursor position
        """
Dicson's avatar
Dicson committed
117
        if event.keyval != Gdk.KEY_n:
Dicson's avatar
Dicson committed
118
            return
Dicson's avatar
Dicson committed
119
        if not event.state & Gdk.ModifierType.MOD1_MASK:  # ALT+N
Dicson's avatar
Dicson committed
120 121
            return

122 123
        if self.plugin.artist == self.plugin.title == self.plugin.album == '':
            tune_string = _('No music playing')
Dicson's avatar
Dicson committed
124
        else:
Dicson's avatar
Dicson committed
125 126 127
            format_string = self.plugin.config['format_string']
            if self.plugin.url and not self.plugin.url.startswith('file://'):
                format_string = self.plugin.config['format_string_http']
128 129 130 131 132 133 134 135

            if self.plugin.artist is None:
                self.plugin.artist = _('unknown artist')
            if self.plugin.album is None:
                self.plugin.album = _('unknown album')

            tune_string = format_string.\
                replace('%artist', self.plugin.artist).\
136 137 138
                replace('%title', self.plugin.title).\
                replace('%album', self.plugin.album).\
                replace('%url', self.plugin.url)
Dicson's avatar
Dicson committed
139 140

        message_buffer = self.chat_control.msg_textview.get_buffer()
141
        message_buffer.insert_at_cursor(tune_string)
Dicson's avatar
Dicson committed
142
        self.chat_control.msg_textview.grab_focus()
Dicson's avatar
Dicson committed
143
        return True
Dicson's avatar
Dicson committed
144 145 146 147 148


class NowListenPluginConfigDialog(GajimPluginConfigDialog):
    def init(self):
        self.GTK_BUILDER_FILE_PATH = self.plugin.local_file_path(
149
            'config_dialog.ui')
Dicson's avatar
Dicson committed
150
        self.xml = Gtk.Builder()
Dicson's avatar
Dicson committed
151
        self.xml.set_translation_domain('gajim_plugins')
Dicson's avatar
Dicson committed
152
        self.xml.add_objects_from_file(self.GTK_BUILDER_FILE_PATH,
153
                                       ['now_listen_config'])
Dicson's avatar
Dicson committed
154

155
        self.config_vbox = self.xml.get_object('now_listen_config')
Dicson's avatar
Dicson committed
156
        self.get_child().pack_start(self.config_vbox, True, True, 0)
Dicson's avatar
Dicson committed
157

158 159
        self.format_string = self.xml.get_object('format_string')
        self.format_string_http = self.xml.get_object('format_string_http')
Dicson's avatar
Dicson committed
160 161 162 163
        self.xml.connect_signals(self)
        self.connect('hide', self.on_hide)

    def on_run(self):
164 165
        self.format_string.set_text(self.plugin.config['format_string'])
        self.format_string_http.set_text(self.plugin.config['format_string_http'])
Dicson's avatar
Dicson committed
166 167

    def on_hide(self, widget):
168 169
        self.plugin.config['format_string'] = self.format_string.get_text()
        self.plugin.config['format_string_http'] = self.format_string_http.get_text()