Index: action.py ================================================================== --- action.py +++ action.py @@ -45,12 +45,13 @@ # web @staticmethod def browser(url): - __print__( dbg.CONF, conf.browser ) - action.run(conf.browser + " " + action.quote(url)) + bin = conf.play.get("url/http", "sensible-browser") + __print__( dbg.CONF, bin ) + action.run(bin + " " + action.quote(url)) # os shell cmd escaping @staticmethod @@ -88,11 +89,11 @@ # streamripper @staticmethod def record(url, audioformat="audio/mpeg", listformat="text/x-href", append="", row={}): __print__( dbg.PROC, "record", url ) - cmd = conf.record.get(audioformat, conf.record.get("*/*", None)) + cmd = conf.record.get(audioformat, conf.play.get("record", None)) try: action.run( action.interpol(cmd, url, row) + append ) except: pass # save as .m3u Index: config.py ================================================================== --- config.py +++ config.py @@ -57,22 +57,20 @@ self.firstrun = 1 # some defaults def defaults(self): - self.browser = "sensible-browser" self.play = { "audio/mpeg": "audacious ", # %u for url to .pls, %g for downloaded .m3u "audio/ogg": "audacious ", - "audio/aac": "amarok -l ", - "audio/x-pn-realaudio": "vlc --one-instance", "audio/*": "totem ", - "*/*": "vlc --one-instance %srv", - } - self.record = { - "*/*": "x-terminal-emulator -e streamripper %srv", + "video/*": "vlc --one-instance %srv", + "record": "x-terminal-emulator -e streamripper %srv", # x-terminal-emulator -e streamripper %srv -d /home/***USERNAME***/Musik + "url/http": "sensible-browser", + } + self.record = { } self.plugins = { "bookmarks": 1, # built-in plugins, cannot be disabled "shoutcast": 1, "xiph": 1, Index: gtk2.xml ================================================================== --- gtk2.xml +++ gtk2.xml @@ -1,9 +1,19 @@ + + + + + + + + + + False 5 station search center-on-parent @@ -133,10 +143,55 @@ 4 4 5 1 True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -988,10 +1043,28 @@ + + + + + + + + + + + + + + + + + + True True @@ -1006,10 +1079,13 @@ 2 1 2 + + + @@ -1152,364 +1228,104 @@ True False 15 none - - 350 - 471 - True - False - 13 - 2 - 5 - 5 - - - - - - - - - - - - True - False - audio/aac - - - 3 - 4 - - - - - True - False - audio/x-real - - - 4 - 5 - - - - - True - False - audio/* - - - 5 - 6 - - - - - True - False - audio/* - - - 9 - 10 - - - - - True - False - */* - - - 6 - 7 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 3 - 4 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 4 - 5 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 5 - 6 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 6 - 7 + + True + False + + + True + False + 0 + <b>Audio player</b> and <b>recording</b> applications. + True + + + True + True + 0 + + + + + True + True + automatic + automatic + + + 0 + 200 + True + True + 5 + config_play + False + True + 0 + 8 + both + + + 10 + 125 + Format + True + + + + + + 2 + 0 + + + + + + + 10 + 300 + Application + + + + + + 2 + 1 + + + + + + + + + True + True + 1 True False - Shoutcast links are %u or %pls, parsed m3u files -are available with %g or %m3u, while %d or %srv -represent direct URLs to the streaming servers. + 0.019999999552965164 + 0.49000000953674316 + Use <a href="http://fossil.include-once.org/streamtuner2/wiki?name=player">placeholders</a> such as <b>%pls</b> for Shoutcast playlists, +or pass <b>%m3u</b> for players that expect mp3 playlist files, +and <b>%srv</b> to use direct streaming URLs. + True True - 1 - 2 - 7 - 8 - - - - - True - False - <b>Recording</b> - True - - - 1 - 2 - 8 - 9 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 9 - 10 - - - - - True - False - - - - 1 - 2 - 10 - 11 - - - - - True - False - <b>Web Browser</b> - True - - - 1 - 2 - 11 - 12 - - - - - True - False - url/http - - - 12 - 13 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 12 - 13 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 1 - 2 - - - - - True - False - audio/mpeg - - - 1 - 2 - - - - - 200 - 20 - True - True - - True - False - False - True - True - - - 1 - 2 - 2 - 3 - - - - - True - False - audio/ogg - - - 2 - 3 - - - - - True - False - <b>Format</b> - True - - - - - True - False - <b>Audio Player</b> - True - - - 1 - 2 - - - - - True - False - placeholder -<a href="http://fossil.include-once.org/streamtuner2/wiki?name=player">see help</a> - True - - - 7 - 8 + True + True + 2 @@ -2715,12 +2531,12 @@ True False bookmark True - + @@ -2727,12 +2543,12 @@ gtk-save-as True False True True - + @@ -2739,13 +2555,13 @@ gtk-edit True False True True - + - + @@ -2814,12 +2630,12 @@ gtk-delete True False True True - + Index: st2.py ================================================================== --- st2.py +++ st2.py @@ -183,10 +183,12 @@ "menu_toolbar_size_large": lambda w: (self.toolbar.set_icon_size(gtk.ICON_SIZE_DIALOG)), # else "menu_properties": config_dialog.open, "config_cancel": config_dialog.hide, "config_save": config_dialog.save, + "config_player_edited": config_dialog.edited_player_row, + "config_player_edited_2": config_dialog.edited_player_row_2, "update_categories": self.update_categories, "update_favicons": self.update_favicons, "app_state": self.app_state, "bookmark": self.bookmark, "save_as": self.save_as, @@ -745,46 +747,71 @@ # aux win: settings UI class config_dialog (auxiliary_window): - # display win_config, pre-fill text fields from global conf. object + # Display win_config, pre-fill text fields from global conf. object def open(self, widget): if self.first_open: self.add_plugins() self.combobox_theme() self.first_open = 0 - self.apply(conf.__dict__, "config_", 0) + self.load_config(conf.__dict__, "config_") + self.load_config(conf.plugins, "config_plugins_") self.win_config.show() first_open = 1 - + # Hide window def hide(self, *args): self.win_config.hide() return True - # set/load values between gtk window and conf. dict - def apply(self, config, prefix="config_", save=0): + # Load values from conf. store into gtk widgets + def load_config(self, config, prefix="config_"): + for key,val in config.items(): + w = main.get_widget(prefix + key) + if w: + # input field + if type(w) is gtk.Entry: + w.set_text(str(val)) + # checkmark + elif type(w) is gtk.CheckButton: + w.set_active(bool(val)) + # list + elif type(w) is gtk.ListStore: + w.clear() + for k,v in val.items(): + w.append([k, v, True]) + w.append(["", "", True]) + __print__(dbg.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): for key,val in config.items(): - # map non-alphanumeric chars from config{} to underscores in according gtk widget names - id = re.sub("[^\w]", "_", key) - w = main.get_widget(prefix + id) - __print__(dbg.CONF, "config", ("save" if save else "load"), prefix+id, w, val) - # recurse into dictionaries, transform: conf.play.audio/mpeg => conf.play_audio_mpeg - if (type(val) == dict): - self.apply(val, prefix + id + "_", save) - # load or set gtk.Entry text field - elif (w and save and type(w)==gtk.Entry): - config[key] = w.get_text() - elif (w and type(w)==gtk.Entry): - w.set_text(str(val)) - elif (w and save): - config[key] = w.get_active() - elif (w): - w.set_active(bool(val)) - pass + w = main.get_widget(prefix + key) + if w: + # text + if type(w) is gtk.Entry: + config[key] = w.get_text() + # boolean + elif type(w) is gtk.CheckButton: + config[key] = w.get_active() + # dict + elif type(w) is gtk.ListStore: + config[key] = {} + for row in w: + if row[0] and row[1]: + config[key][row[0]] = row[1] + __print__(dbg.CONF, "config save", prefix+key, val) + + + # Gtk callback to update ListStore when entries get edited + def edited_player_row(self, cell, path, new_text, user_data=None, column=0): + main.config_play[path][column] = new_text + def edited_player_row_2(self, cell, path, new_text, user_data=None): + self.edited_player_row(cell, path, new_text, column=1) # fill combobox def combobox_theme(self): # self.theme.combo_box_new_text() @@ -843,11 +870,11 @@ # spacer self.add_( "filler_pl_"+name, gtk.HSeparator() ) - # put gtk widgets into config dialog notebook + # Put config widgets into config dialog notebook def add_(self, id, w, label=None, color=""): w.set_property("visible", True) main.widgets[id] = w if label: w.set_width_chars(11) @@ -854,17 +881,19 @@ w = self.hbox(w, self.label(label)) if color: w = mygtk.bg(w, color) self.plugin_options.pack_start(w) + # Create GtkLabel def label(self, label): label = gtk.Label(label) label.set_property("visible", True) label.set_line_wrap(True) label.set_size_request(400, -1) return label + # Wrap two widgets in vertical box def hbox(self, w1, w2): vbox = gtk.HBox(homogeneous=False, spacing=10) vbox.set_property("visible", True) vbox.pack_start(w1, expand=False, fill=False) vbox.pack_start(w2, expand=True, fill=True) @@ -871,11 +900,12 @@ return vbox # save config def save(self, widget): - self.apply(conf.__dict__, "config_", 1) + self.save_config(conf.__dict__, "config_") + self.save_config(conf.plugins, "config_plugins_") self.apply_theme() conf.save(nice=1) self.hide() config_dialog = config_dialog()