Internet radio browser GUI for music/video streams from various directory services.

⌈⌋ ⎇ branch:  streamtuner2


Check-in [824186a7c3]

Overview
Comment:Cleaner specbuttons plugin, add support for placeholders in button commands. Add documentation and some config ideas.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 824186a7c3684c67ed77b49bed015782614f0dc0
User & Date: mario on 2016-10-23 16:29:50
Other Links: manifest | tags
Context
2016-10-27
16:42
Introduce `dict` configuration type, prepare TreeView in uikit (similar to record/play config table). check-in: 095de3353f user: mario tags: trunk
2016-10-23
16:29
Cleaner specbuttons plugin, add support for placeholders in button commands. Add documentation and some config ideas. check-in: 824186a7c3 user: mario tags: trunk
16:28
action: Allow %url %title placeholders also with $ prefix. Also reuse interpolate() function for specbuttons and without default %pls. check-in: 27c88c7dcd user: mario tags: trunk
Changes

Modified channels/specbuttons.py from [bddc19b064] to [a1cfea50d2].

1
2
3
4
5
6
7
8
9


10
11
12
13
14
15
16











17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

60


61



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# encoding: utf-8
# title: Extra buttons for apps
# description: Adds configurable mini toolbar buttons
# version: 0.5
# depends: streamtuner2 >= 2.2.0
# type: feature
# category: ui
# config:
#    { name: specbutton_rows, value: 2, type: int, description: "Number of rows to arrange buttons in (default 2, looks ok with up to 3 rows)" }


#
# Shows the mini extra buttons in the toolbar, which allow to control your
# audio player or run other system commands. The configuration list is in
# the Settings → Options tab.
#
# Icons can either be gtk-xyz icon names, or load /usr/share/icon/*.png
# pixmaps.













import os.path
import subprocess
import math
import re
from config import conf, log
import action
from uikit import gtk


# Channel Homepage in Toolbar
class specbuttons(object):
    module = __name__

    # Hook toolbar label
    def __init__(self, parent):
        self.parent = parent
        self.specbuttons = parent.get_widget("specbuttons")
        parent.hooks["init"].append(self.update_buttons)
        parent.hooks["config_save"].append(self.update_paths)
        parent.specbuttons.show()
        parent.tv_config_specbuttons.show()

    # Extra buttons
    def update_buttons(self, parent):
    
        # define table width (2 rows default)
        y = min(int(conf.specbutton_rows), 4)
        self.specbuttons.resize(y, int(math.ceil(len(conf.specbuttons) / y)))
        # clean up
        for widget in self.specbuttons.get_children():
            widget.destroy()
        xy = 0
        
        # add icon buttons
        for btn, cmd in conf.specbuttons.items():
            #log.IN(btn, cmd)
            w_btn = gtk.Button()
            w_btn.set_image(self.icon(btn))
            w_btn.connect("clicked", lambda x0, cmd=cmd, *x: action.run(cmd) )
            self.specbuttons.attach(
                w_btn,

                int(xy / y), int(xy / y) + 1, xy % y, (xy % y) + 1,


                gtk.EXPAND, gtk.EXPAND, 1, 1



            )
            xy = xy + 1
        self.specbuttons.show_all()

    # Instantiate Image from gtk-* string or path
    def icon(self, btn):
        wi = gtk.Image()
        if (btn.find("gtk-") == 0):
            wi.set_from_stock(btn, gtk.ICON_SIZE_SMALL_TOOLBAR)
        else:
            if not os.path.exists(btn):
                btn = self.locate(btn)
                log.DATA(btn)
            if btn:
                wi.set_from_file(btn)
            else:
                wi.set_from_stock("gtk-image-missing", gtk.ICON_SIZE_SMALL_TOOLBAR)
        return wi

    # Look for image basename "play" in /usr/share/icons/*.*
    def locate(self, btn):
        f = subprocess.Popen(["locate", "/usr/share/[pi]*s/*%s*.*" % btn], stdout=subprocess.PIPE)
        path, err = f.communicate()
        if not err:
            return path.split("\n")[0]

    # Update paths when saving config dialog



|




|
>
>

|




|
>
>
>
>
>
>
>
>
>
>
>











|
















|




<


|



|

|
>
|
>
>
|
>
>
>

<

















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# encoding: utf-8
# title: Extra buttons for apps
# description: Adds configurable mini toolbar buttons
# version: 0.7
# depends: streamtuner2 >= 2.2.0
# type: feature
# category: ui
# config:
#    { name: specbutton_rows, value: 2, max: 4, type: int, description: "Number of rows to arrange buttons in." }
# doc:
#    http://fossil.include-once.org/streamtuner2/info/43b36ed35b1488d5
#
# Adds the mini/extra buttons in the toolbar, which allow to control your
# audio player or run other system commands. The configuration list is in
# the Settings → Options tab.
#
# Icons can either be gtk-xyz icon names, or load /usr/share/icon/*.png
# pixmaps. Enter a shortcut like "firefox" as icon name for it be looked up.
# Then specify an external command to start. For example:
#
#     Icon           Cmd
#     ------         ------
#     volume         pavucontrol
#     mute           amixer -c 0 set Front 50DB 
#     up             amixer -D pulse sset Master 5%+
#     kill           pkill vlc
#
# The commands can be pretty much any shell command, but still allow for
# streamtuner2 placeholders like %g or %url and $title.


import os.path
import subprocess
import math
import re
from config import conf, log
import action
from uikit import gtk


# Extra/mini buttons in toolbar
class specbuttons(object):
    module = __name__

    # Hook toolbar label
    def __init__(self, parent):
        self.parent = parent
        self.specbuttons = parent.get_widget("specbuttons")
        parent.hooks["init"].append(self.update_buttons)
        parent.hooks["config_save"].append(self.update_paths)
        parent.specbuttons.show()
        parent.tv_config_specbuttons.show()

    # Extra buttons
    def update_buttons(self, parent):
    
        # define table width (2 rows default)
        y = max(min(int(conf.specbutton_rows), 4), 1) # 1 <= y <= 4
        self.specbuttons.resize(y, int(math.ceil(len(conf.specbuttons) / y)))
        # clean up
        for widget in self.specbuttons.get_children():
            widget.destroy()

        
        # add icon buttons
        for xy, (btn, cmd) in enumerate(conf.specbuttons.items()):
            #log.IN(btn, cmd)
            w_btn = gtk.Button()
            w_btn.set_image(self.icon(btn))
            w_btn.connect("clicked", lambda x0, cmd=cmd, *x: self.action(cmd))
            self.specbuttons.attach(
                child = w_btn,
                left_attach   = int(xy / y),
                right_attach  = int(xy / y) + 1,
                top_attach    = xy % y,
                bottom_attach = (xy % y) + 1,
                xoptions = gtk.EXPAND,
                yoptions = gtk.EXPAND,
                xpadding = 1,
                ypadding = 1
            )

        self.specbuttons.show_all()

    # Instantiate Image from gtk-* string or path
    def icon(self, btn):
        wi = gtk.Image()
        if (btn.find("gtk-") == 0):
            wi.set_from_stock(btn, gtk.ICON_SIZE_SMALL_TOOLBAR)
        else:
            if not os.path.exists(btn):
                btn = self.locate(btn)
                log.DATA(btn)
            if btn:
                wi.set_from_file(btn)
            else:
                wi.set_from_stock("gtk-image-missing", gtk.ICON_SIZE_SMALL_TOOLBAR)
        return wi

    # Look for image basename (e.g. "play") in /usr/share/icons/*.* and /pixmaps/*
    def locate(self, btn):
        f = subprocess.Popen(["locate", "/usr/share/[pi]*s/*%s*.*" % btn], stdout=subprocess.PIPE)
        path, err = f.communicate()
        if not err:
            return path.split("\n")[0]

    # Update paths when saving config dialog
98
99
100
101
102
103
104
105







                if path:
                    btn = path
                else:
                    log.WARN("Extra button icon '%s' could not be found" % btn)
            r[btn] = cmd
        conf.specbuttons = r
        self.update_buttons(self.parent)
















>
>
>
>
>
>
>
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
                if path:
                    btn = path
                else:
                    log.WARN("Extra button icon '%s' could not be found" % btn)
            r[btn] = cmd
        conf.specbuttons = r
        self.update_buttons(self.parent)

    # Button callback, allow for %url/%title placeholders
    def action(self, cmd):
        if re.search("[%$]", cmd):
            row = self.parent.channel().row()
            cmd = action.interpol(cmd, row=row, add_default=False)
        action.run(cmd)

Added help/specbuttons.page version [3b72d31b24].



































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<page	xmlns="http://projectmallard.org/1.0/"
	type="guide"
	id="specbuttons">

<info>
	<link type="guide" xref="index#extra"/>
	<link type="guide" xref="configuration#apps"/>
	<link type="guide" xref="configuration#gui"/>
	<desc>Toolbar application short cuts.</desc>
</info>

	<title>Extra/mini buttons</title>

	<p>Using the specbuttons plugin, you can define additional
	shortcuts. This is meant as convenience - allows to start
	other audio apps or system ontrols from within streamtuner2.</p>
	
	<p>The settings list can be found in the Settings → Options tab. It
	follows the layout of the player/recording configuration. Except
	that it lists icons and their according action commands:</p>

	<table shade="rows" rules="rows cols">
		<tr><td><p><em>Icon</em></p></td>  	<td><p><em>Cmd</em></p></td> </tr>
		<tr><td><p><app>gtk-media-forward</app></p></td>     <td><p><cmd>vlc next</cmd></p></td> </tr>
		<tr><td><p><app>terminal</app></p></td>  	<td><p><cmd>xterm</cmd></p></td> </tr>
		<tr><td><p><app>volume</app></p></td>		<td><p><cmd>pavucontrol</cmd></p></td> </tr>
		<tr><td><p><app>database</app></p></td>		<td><p><cmd>./myscript "%url" "%title"</cmd></p></td> </tr>
		<tr><td><p><app>./import.png</app></p></td>	<td><p><cmd>audacity %pls</cmd></p></td> </tr>
	</table>

        <section id="gtk-icons">
        <title>gtk-icons</title>
	<p>Note that the icon name can either be Gtk-builtin icon. Their
        names always start with "<app>gtk-</app>", for example "<app>gtk-cancel</app>". You can
        find a list of all available builtins under
        <link href="http://www.pygtk.org/pygtk2reference/gtk-stock-items.html">http://www.pygtk.org/pygtk2reference/gtk-stock-items.html</link>.</p>
	</section>
	
        <section id="png-icons">
        <title>PNG icons</title>
	<p>In case you enter something like "<app>player</app>", the icon name will be
	searched for and expanded to an absolute PNG filename. For example
        "<file>totem</file>" might become <file>/usr/share/icons/HighContrast/16x16/apps/totem.png</file>.</p>
        
        <p>This won't always yield the exact icon / theme / or size you wanted. So it's
	sometimes necessary to look up the complete path yourself.</p>
	</section>

        <section id="placeholders">
        <title>Commands</title>
        <p>You can define any graphical or commandline application to be
        invoked by your custom toolbar button. Foremost you want to invoke
        audio controls of course, or start/stop players.</p>
        
	<p>Placeholders like %title and %url or %pls and %m3u are supported
	for all commands as well. So you can have additional play/record
	shortcuts.</p>
	</section>

        <section>
        <note style="bug"><p>The icon list isn't ordered. So you cannot
        define which button appears first.</p></note>
        </section>

</page>