1# -*- coding: utf-8 -*-
2# Copyright (C) 2015, zordsdavini
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import os
18import subprocess
19from functools import partial
20
21from libqtile.widget import base
22
23
24class Moc(base.ThreadPoolText):
25    """A simple MOC widget.
26
27    Show the artist and album of now listening song and allow basic mouse
28    control from the bar:
29
30    - toggle pause (or play if stopped) on left click;
31    - skip forward in playlist on scroll up;
32    - skip backward in playlist on scroll down.
33
34    MOC (http://moc.daper.net) should be installed.
35    """
36    orientations = base.ORIENTATION_HORIZONTAL
37    defaults = [
38        ('play_color', '00ff00', 'Text colour when playing.'),
39        ('noplay_color', 'cecece', 'Text colour when not playing.'),
40        ('update_interval', 0.5, 'Update Time in seconds.'),
41    ]
42
43    def __init__(self, **config):
44        base.ThreadPoolText.__init__(self, "", **config)
45        self.add_defaults(Moc.defaults)
46        self.status = ""
47        self.local = None
48
49        self.add_callbacks({
50            'Button1': self.play,
51            'Button4': partial(subprocess.Popen, ['mocp', '-f']),
52            'Button5': partial(subprocess.Popen, ['mocp', '-r']),
53        })
54
55    def get_info(self):
56        """Return a dictionary with info about the current MOC status."""
57        try:
58            output = self.call_process(['mocp', '-i'])
59        except subprocess.CalledProcessError as err:
60            output = err.output
61        if output.startswith("State"):
62            output = output.splitlines()
63            info = {'State': "",
64                    'File': "",
65                    'SongTitle': "",
66                    'Artist': "",
67                    'Album': ""}
68
69            for line in output:
70                for data in info:
71                    if data in line:
72                        info[data] = line[len(data) + 2:].strip()
73                        break
74            return info
75
76    def now_playing(self):
77        """Return a string with the now playing info (Artist - Song Title)."""
78        info = self.get_info()
79        now_playing = ""
80        if info:
81            status = info['State']
82            if self.status != status:
83                self.status = status
84                if self.status == "PLAY":
85                    self.layout.colour = self.play_color
86                else:
87                    self.layout.colour = self.noplay_color
88            title = info['SongTitle']
89            artist = info['Artist']
90            if title and artist:
91                now_playing = "♫ {0} - {1}".format(artist, title)
92            elif title:
93                now_playing = "♫ {0}".format(title)
94            else:
95                basename = os.path.basename(info['File'])
96                filename = os.path.splitext(basename)[0]
97                now_playing = "♫ {0}".format(filename)
98
99            if self.status == "STOP":
100                now_playing = "♫"
101
102        return now_playing
103
104    def play(self):
105        """Play music if stopped, else toggle pause."""
106        if self.status in ('PLAY', 'PAUSE'):
107            subprocess.Popen(['mocp', '-G'])
108        elif self.status == 'STOP':
109            subprocess.Popen(['mocp', '-p'])
110
111    def poll(self):
112        """Poll content for the text box."""
113        return self.now_playing()
114