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

⌈⌋ branch:  streamtuner2


Check-in [686334f27e]

Overview
Comment:Fix bug (too late to reproduce) for bool option being applied to ComboBoxText in record_flags/configwin
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 686334f27e74e87208d46b2e27586133e14cc4d6
User & Date: mario on 2020-05-18 13:34:29
Other Links: manifest | tags
Context
2020-05-18
14:02
Bug was from wget´s --local-encoding (select:/Combobox option) check-in: 48dc4b4834 user: mario tags: trunk
13:34
Fix bug (too late to reproduce) for bool option being applied to ComboBoxText in record_flags/configwin check-in: 686334f27e user: mario tags: trunk
12:59
Apply absolute path for icon pixmap check-in: 043ec4351b user: mario tags: trunk
Changes

Modified channels/configwin.py from [d89524210f] to [6bf08c0441].


1
2
3
4
5
6
7

# api: streamtuner2
# title: Config dialog
# description: Allows to configure players, options, and plugins
# version: 2.7
# type: feature
# category: ui
# config: -
>







1
2
3
4
5
6
7
8
# encoding: utf-8
# api: streamtuner2
# title: Config dialog
# description: Allows to configure players, options, and plugins
# version: 2.7
# type: feature
# category: ui
# config: -
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
        return True

    
    # Load values from conf. store into gtk widgets
    def load_config(self, config, prefix="config_", widgets={}):
        for key,val in config.items():
            w = self.main.get_widget(prefix + key) or widgets.get(prefix + key)

            if w:
                # number
                if isinstance(w, gtk.SpinButton):
                    w.set_value(int(val))
                # input field
                elif isinstance(w, gtk.Entry):
                    w.set_text(str(val))
                # checkmark
                elif isinstance(w, gtk.CheckButton):
                    w.set_active(bool(val))
                # dropdown
                elif isinstance(w, ComboBoxText):
                    w.set_default(val)
                # list
                elif isinstance(w, gtk.ListStore):
                    w.clear()
                    if isinstance(val, dict):
                        for k,v in val.items():
                            w.append([k, v, uikit.app_bin_check(v)])
                        w.append(["", "", gtk.STOCK_NEW])
                    elif isinstance(val, list):
                        for row in val:
                            log.DATA(row)
                            w.append([str(e) for e in row])
                        if len(val):
                            w.append(["" for e in val[0]])
            #log.CONF("config load", prefix+key, val, type(w))

    # Store gtk widget valus back into conf. dict
    def save_config(self, config, prefix="config_", save=0, widgets={}):
        for key,val in config.items():
            w = self.main.get_widget(prefix + key) or widgets.get(prefix + key)
            if w:
                # int







>












|













<







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
        return True

    
    # Load values from conf. store into gtk widgets
    def load_config(self, config, prefix="config_", widgets={}):
        for key,val in config.items():
            w = self.main.get_widget(prefix + key) or widgets.get(prefix + key)
            #log.CONF("load_config()", prefix+key, "=", val, "→", type(w))
            if w:
                # number
                if isinstance(w, gtk.SpinButton):
                    w.set_value(int(val))
                # input field
                elif isinstance(w, gtk.Entry):
                    w.set_text(str(val))
                # checkmark
                elif isinstance(w, gtk.CheckButton):
                    w.set_active(bool(val))
                # dropdown
                elif isinstance(w, ComboBoxText):
                    w.set_default(str(val))
                # list
                elif isinstance(w, gtk.ListStore):
                    w.clear()
                    if isinstance(val, dict):
                        for k,v in val.items():
                            w.append([k, v, uikit.app_bin_check(v)])
                        w.append(["", "", gtk.STOCK_NEW])
                    elif isinstance(val, list):
                        for row in val:
                            log.DATA(row)
                            w.append([str(e) for e in row])
                        if len(val):
                            w.append(["" for e in val[0]])


    # Store gtk widget valus back into conf. dict
    def save_config(self, config, prefix="config_", save=0, widgets={}):
        for key,val in config.items():
            w = self.main.get_widget(prefix + key) or widgets.get(prefix + key)
            if w:
                # int

Modified contrib/recordflags.py from [0041a46d89] to [3b2e370ba5].

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
# encoding: utf-8
# api: streamtuner2
# title: Recording options
# description: Allows to set streamripper/fIcy options before recording
# version: 0.9
# depends: streamtuner2 > 2.2.0
# conflicts: continuous_record
# priority: optional
# config:
#    { name: recordflags_auto, type: bool, value: 1, description: Apply options automatically once saved. }
#    { name: recordflags_row, type: select, value: record_flags, select: "record_flags|extras", description: Station field for saved options. }
#    { name: recordflags_dir, type: str, value: "", description: Default output directory. }
# type: handler
# category: ui
#
# Hijacks the ● record button, presents an option dialog to set various
# streamripper options. Allows to set an output directory or single-file
# recording for example.
#
# Reuses the known option scheme from the config window. Which is perhaps
# less pretty than a custom dialog, but allows to set options for different
# download/recording tools: streamripper, fPls, youtube-dl, wget.




#
# Note that predefining -flags in the Apps/Recording config table might
# conflict with per-stream options. In particular avoid a -d directory
# default for streamripper; and use this plugins´ option instead.
#
# ToDo:
#  → override main.record() instead of action.record
#  → eventually strip defaults such as `-d ../dir` from conf.record;
#    using action append= param now, thus no rewriting of assoc dict
#


import re
import os
import copy
from config import *
from channels import *
from uikit import *
import action
from compat2and3 import *


# hook record button / menu / action






class recordflags (FeaturePlugin):

    # settings
    cfg_widget_pfx = "recordoptions_config_"
    widgets = {}
    
    # available options per recording tool




|

















>
>
>
>





<
<
<
<
<













>
>
>
>
>
>







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
# encoding: utf-8
# api: streamtuner2
# title: Recording options
# description: Allows to set streamripper/fIcy options before recording
# version: 1.0
# depends: streamtuner2 > 2.2.0
# conflicts: continuous_record
# priority: optional
# config:
#    { name: recordflags_auto, type: bool, value: 1, description: Apply options automatically once saved. }
#    { name: recordflags_row, type: select, value: record_flags, select: "record_flags|extras", description: Station field for saved options. }
#    { name: recordflags_dir, type: str, value: "", description: Default output directory. }
# type: handler
# category: ui
#
# Hijacks the ● record button, presents an option dialog to set various
# streamripper options. Allows to set an output directory or single-file
# recording for example.
#
# Reuses the known option scheme from the config window. Which is perhaps
# less pretty than a custom dialog, but allows to set options for different
# download/recording tools: streamripper, fPls, youtube-dl, wget.
#
# The presented parameter dialog depends on which tool is configured in the
# Apps/Recording table to which audio type. (If you want fpls options, you
# have to have fpls/ficy configured beforehand.)
#
# Note that predefining -flags in the Apps/Recording config table might
# conflict with per-stream options. In particular avoid a -d directory
# default for streamripper; and use this plugins´ option instead.
#







import re
import os
import copy
from config import *
from channels import *
from uikit import *
import action
from compat2and3 import *


# hook record button / menu / action
#
# ToDo:
#  → override main.record() instead of action.record
#  → eventually strip defaults such as `-d ../dir` from conf.record;
#    using action append= param now, thus no rewriting of assoc dict
#
class recordflags (FeaturePlugin):

    # settings
    cfg_widget_pfx = "recordoptions_config_"
    widgets = {}
    
    # available options per recording tool
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
        # default widget actions
        parent.win_recordoptions.connect("delete-event", self.hide_dialog)
        parent.recordoptions_go.connect("clicked", self.do_record)
        parent.recordoptions_save.connect("clicked", self.save_only)
        parent.recordoptions_eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x44, 0x22, 0x11))

        # shortcuts
        self.add_plg = parent.configwin.add_plg           # create _cfg widgets
        self.load_config = parent.configwin.load_config   # populate _cfg widgets
        self.save_config = parent.configwin.save_config   # save from _cfg widgets
        self.cfg_vbox = { 
            "basic": self.parent.recordoptions_cfg,
            "meta": self.parent.recordoptions_cfg_extra,
            "net": self.parent.recordoptions_cfg_verbose,
        }

        # swap out action.record()







<
<
<







206
207
208
209
210
211
212



213
214
215
216
217
218
219
        # default widget actions
        parent.win_recordoptions.connect("delete-event", self.hide_dialog)
        parent.recordoptions_go.connect("clicked", self.do_record)
        parent.recordoptions_save.connect("clicked", self.save_only)
        parent.recordoptions_eventbox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0x44, 0x22, 0x11))

        # shortcuts



        self.cfg_vbox = { 
            "basic": self.parent.recordoptions_cfg,
            "meta": self.parent.recordoptions_cfg_extra,
            "net": self.parent.recordoptions_cfg_verbose,
        }

        # swap out action.record()
292
293
294
295
296
297
298

299

300

301

302
303
304
305
306
307
308
309
310
311

312


313

314
315
316
317
318
319
320
        p.win_recordoptions.show()

    # populate config widgets, seth defaults/current settings
    def load_config_widgets(self, row, group="streamripper", p=None):
        # clean up previous
        [vbox.remove(w) for vbox in self.cfg_vbox.values() for w in vbox.get_children()]
        # add plugins

        self.add_plg(group, self.flag_meta[group], self.pack_option, self.cfg_widget_pfx)

        # set values

        self.load_config(self.configdict_from_args(row), self.cfg_widget_pfx, widgets=self.widgets)


    # Put config widgets into recordoptions_cfg_*** vbox
    def pack_option(self, id=None, w=None, label=None, color=None, image=None, align=5, opt={}):
        category = opt.get("category")
        vbox = self.cfg_vbox.get(self.catalias.get(category) or category) or self.cfg_vbox["basic"]
        vbox.pack_start(uikit.wrap(self.widgets, id, w, label, color, image, align, label_markup=1, label_size=250), expand=False, fill=False)

        
    # return "--args str" for current config widget states
    def args_from_configwin(self):

        cfg = { name: None for name in self.namemap.keys() }


        self.save_config(cfg, self.cfg_widget_pfx, widgets=self.widgets)

        #log.DATA(cfg)
        return self.args_from_configdict(cfg)

    #-- extract saved row[record_flags] and conf.record[] defaults into name-config{}
    def configdict_from_args(self, row):
        r = copy.copy(self.defmap)
        # saved `record_flags`







>
|
>

>
|
>










>
|
>
>
|
>







294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
        p.win_recordoptions.show()

    # populate config widgets, seth defaults/current settings
    def load_config_widgets(self, row, group="streamripper", p=None):
        # clean up previous
        [vbox.remove(w) for vbox in self.cfg_vbox.values() for w in vbox.get_children()]
        # add plugins
        self.parent.configwin.add_plg(
            group, self.flag_meta[group], self.pack_option, self.cfg_widget_pfx
        )
        # set values
        self.parent.configwin.load_config(
            self.configdict_from_args(row), self.cfg_widget_pfx, widgets=self.widgets
        )

    # Put config widgets into recordoptions_cfg_*** vbox
    def pack_option(self, id=None, w=None, label=None, color=None, image=None, align=5, opt={}):
        category = opt.get("category")
        vbox = self.cfg_vbox.get(self.catalias.get(category) or category) or self.cfg_vbox["basic"]
        vbox.pack_start(uikit.wrap(self.widgets, id, w, label, color, image, align, label_markup=1, label_size=250), expand=False, fill=False)

        
    # return "--args str" for current config widget states
    def args_from_configwin(self):
        cfg = {
             name: None  for  name in self.namemap.keys()
        }
        self.parent.configwin.save_config(
            cfg, self.cfg_widget_pfx, widgets=self.widgets
        )
        #log.DATA(cfg)
        return self.args_from_configdict(cfg)

    #-- extract saved row[record_flags] and conf.record[] defaults into name-config{}
    def configdict_from_args(self, row):
        r = copy.copy(self.defmap)
        # saved `record_flags`
344
345
346
347
348
349
350

            if val in (False, None, "", 0, "0", default):
                continue
            arg = self.namemap[name]
            s = s + " " + arg
            if isinstance(val, (str, unicode)): # type == "bool" check here(...)
                s = s + " " + val
        return s








>
354
355
356
357
358
359
360
361
            if val in (False, None, "", 0, "0", default):
                continue
            arg = self.namemap[name]
            s = s + " " + arg
            if isinstance(val, (str, unicode)): # type == "bool" check here(...)
                s = s + " " + val
        return s