Index: _package.epm ================================================================== --- _package.epm +++ _package.epm @@ -29,11 +29,12 @@ f 755 root root /usr/bin/streamtuner2 ./st2.py f 644 root root /usr/share/applications/streamtuner2.desktop ./streamtuner2.desktop d 755 root root /usr/share/streamtuner2 - f 644 root root /usr/share/streamtuner2/streamtuner2.png ./streamtuner2.png f 644 root root /usr/share/pixmaps/streamtuner2.png ./logo.png -f 644 root root /usr/share/streamtuner2/ui.xml ./ui.xml +f 644 root root /usr/share/streamtuner2/gtk2.xml ./gtk2.xml +f 644 root root /usr/share/streamtuner2/gtk3.xml ./gtk3.xml f 644 root root /usr/share/streamtuner2/pson.py ./pson.py #f 644 root root /usr/share/streamtuner2/processing.py ./processing.py f 644 root root /usr/share/streamtuner2/action.py ./action.py f 644 root root /usr/share/streamtuner2/config.py ./config.py f 644 root root /usr/share/streamtuner2/http.py ./http.py Index: action.py ================================================================== --- action.py +++ action.py @@ -22,19 +22,13 @@ import re import os import http -from config import conf +from config import conf, __print__, dbg import platform - -#from channels import __print__ -def __print__(*args): - if conf.debug: - print(" ".join([str(a) for a in args])) - main = None #-- media actions --------------------------------------------- Index: channels/__init__.py ================================================================== --- channels/__init__.py +++ channels/__init__.py @@ -4,6 +4,5 @@ # type: R # from channels._generic import * -from channels._generic import __print__ Index: channels/_generic.py ================================================================== --- channels/_generic.py +++ channels/_generic.py @@ -20,19 +20,18 @@ # import gtk from mygtk import mygtk -from config import conf +from config import conf, __print__, dbg import http import action import favicon import os.path import xml.sax.saxutils import re import copy - # dict==object class struct(dict): def __init__(self, *xargs, **kwargs): @@ -207,11 +206,11 @@ else: # parse error self.parent.status("category parsed empty.") self.streams[category] = [{"title":"no contents found on directory server","bitrate":0,"max":0,"listeners":0,"playing":"error","favourite":0,"deleted":0}] - print("oooops, parser returned nothing for category " + category) + __print__(dbg.ERR, "Oooops, parser returned nothing for category " + category) # assign to treeview model #self.streams[self.default] = [] #if (self.liststore.has_key(category)): # was already loded before # self.gtk_list.set_model(self.liststore[category]) @@ -302,19 +301,17 @@ self.load(self.current, force=0) # display .current category, once notebook/channel tab is first opened def first_show(self): - print("first_show ", self.module) - print 1 - print self.shown + __print__(dbg.PROC, "first_show ", self.module, self.shown) + if (self.shown != 55555): - print 2 # if category tree is empty, initialize it if not self.categories: - print 3 + __print__(dbg.PROC, "first_show: reload_categories"); #self.parent.thread(self.reload_categories) print("reload categories"); self.reload_categories() self.display_categories() self.current = self.categories.keys()[0] @@ -321,16 +318,16 @@ print self.current self.load(self.current) # load current category else: - print 4 + __print__(dbg.STAT, "first_show: load current category"); self.load(self.current) # put selection/cursor on last position try: - print 5 + __print__(dbg.STAT, "first_show: select last known category treelist position") self.gtk_list.get_selection().select_path(self.shown) except: pass # this method will only be invoked once @@ -529,19 +526,8 @@ #parent.channels[module] = None #parent.channel_names.append(module) """ -> already taken care of in main.load_plugins() """ - - - - -# wrapper for all print statements -def __print__(*args): - if conf.debug: - print(" ".join([str(a) for a in args])) - -__debug_print__ = __print__ - Index: channels/global_key.py ================================================================== --- channels/global_key.py +++ channels/global_key.py @@ -11,11 +11,10 @@ # it switches the currently playing radio station to another one in # bookmarks list. # # Valid key names are for example F9, <Ctrl>G, <Alt>R, <Super>N # -return import keybinder from config import conf import action Index: channels/internet_radio_org_uk.py ================================================================== --- channels/internet_radio_org_uk.py +++ channels/internet_radio_org_uk.py @@ -12,11 +12,11 @@ from channels import * import re -from config import conf +from config import conf, __print__, dbg import http from pq import pq Index: channels/live365.py ================================================================== --- channels/live365.py +++ channels/live365.py @@ -10,11 +10,11 @@ # streamtuner2 modules from config import conf from mygtk import mygtk import http from channels import * -from channels import __print__ +from config import __print__, dbg # python modules import re import xml.dom.minidom from xml.sax.saxutils import unescape as entity_decode, escape as xmlentities @@ -116,14 +116,14 @@ >DrawRatingStars\((\d+),\s+(\d+),.*? """, re.X|re.I|re.S|re.M) # src="(http://www.live365.com/.+?/stationlogo\w+.jpg)".+? # append entries to result list - __print__( html ) + __print__( dbg.DATA, html ) ls = [] for row in rx.findall(html): - __print__( row ) + __print__( dbg.DATA, row ) points = int(row[8]) count = int(row[9]) ls.append({ "launch_id": row[0], "sofo": row[0], # subscribe-or-fuck-off status flags Index: channels/modarchive.py ================================================================== --- channels/modarchive.py +++ channels/modarchive.py @@ -13,11 +13,11 @@ import re import http from config import conf from channels import * -from channels import __print__ +from config import __print__, dbg from xml.sax.saxutils import unescape @@ -109,11 +109,11 @@ .*? >Rated</a>\s*(\d+) """, re.X|re.S) for uu in rx_mod.findall(html): (url, id, fmt, title, file, rating) = uu - __print__( uu ) + __print__( dbg.DATA, uu ) entries.append({ "genre": cat, "url": url, "id": id, "format": self.mime_fmt(fmt) + "+zip", Index: channels/punkcast.py ================================================================== --- channels/punkcast.py +++ channels/punkcast.py @@ -11,11 +11,11 @@ import re import http from config import conf import action from channels import * -from channels import __print__ +from config import __print__, dbg @@ -84,11 +84,11 @@ rx_sound = re.compile("""(http://[^"<>]+[.](mp3|ogg|m3u|pls|ram))""") html = http.get(row["homepage"]) # look up ANY audio url for uu in rx_sound.findall(html): - __print__( uu ) + __print__( dbg.DATA, uu ) (url, fmt) = uu action.action.play(url, self.mime_fmt(fmt), "url/direct") return # or just open webpage Index: channels/shoutcast.py ================================================================== --- channels/shoutcast.py +++ channels/shoutcast.py @@ -1,46 +1,32 @@ # # api: streamtuner2 # title: shoutcast # description: Channel/tab for Shoutcast.com directory # depends: pq, re, http -# version: 1.2 +# version: 1.3 # author: Mario # original: Jean-Yves Lefort # # Shoutcast is a server software for audio streaming. It automatically spools -# station information on shoutcast.com, which this plugin can read out. But -# since the website format is often changing, we now use PyQuery HTML parsing -# in favour of regular expression (which still work, are faster, but not as -# reliable). -# -# This was previously a built-in channel plugin. It just recently was converted -# from a glade predefined GenericChannel into a ChannelPlugin. -# -# -# NOTES -# -# Just found out what Tunapie uses: -# http://www.shoutcast.com/sbin/newxml.phtml?genre=Top500 -# It's a simpler list format, no need to parse HTML. However, it also lacks -# homepage links. But maybe useful as alternate fallback... -# Also: -# http://www.shoutcast.com/sbin/newtvlister.phtml?alltv=1 -# http://www.shoutcast.com/sbin/newxml.phtml?search= +# station information on shoutcast.com, which this plugin can read out. +# +# After its recent aquisition the layout got slimmed down considerably. So +# there's not a lot of information to fetch left. And this plugin is now back +# to defaulting to regex extraction instead of HTML parsing & DOM extraction. # # # import http import urllib import re +from config import conf, __print__, dbg from pq import pq -from config import conf #from channels import * # works everywhere but in this plugin(???!) import channels -__print__ = channels.__print__ # SHOUTcast data module ---------------------------------------- class shoutcast(channels.ChannelPlugin): @@ -75,17 +61,17 @@ # extracts the category list from shoutcast.com, # sub-categories are queried per 'AJAX' def update_categories(self): html = http.get(self.base_url) self.categories = [] - __print__( html ) + __print__( dbg.DATA, html ) # <h2>Radio Genres</h2> rx = re.compile(r'<li((?:\s+id="\d+"\s+class="files")?)><a href="\?action=sub&cat=([\w\s]+)#(\d+)">[\w\s]+</a>', re.S) sub = [] for uu in rx.findall(html): - __print__(uu) + __print__( dbg.DATA, uu ) (main,name,id) = uu name = urllib.unquote(name) # main category if main: @@ -95,11 +81,11 @@ self.categories.append(name) else: sub.append(name) # it's done - __print__(self.categories) + __print__( dbg.PROC, self.categories ) conf.save("cache/categories_shoutcast", self.categories) pass @@ -109,11 +95,11 @@ # downloads stream list from shoutcast for given category def update_streams(self, cat, search=""): if (not cat or cat == self.empty): - __print__("nocat") + __print__( dbg.ERR, "nocat" ) return [] ucat = urllib.quote(cat) # loop @@ -129,20 +115,26 @@ #/radiolist.cfm?action=sub&string=&cat=Oldies&_cf_containerId=radiolist&_cf_nodebug=true&_cf_nocache=true&_cf_rc=0 #/radiolist.cfm?start=19&action=sub&string=&cat=Oldies&amount=18&order=listeners # page url = "http://www.shoutcast.com/radiolist.cfm?action=sub&string=&cat="+ucat+"&order=listeners&amount="+str(count) - __print__(url) + __print__(dbg.HTTP, url) referer = "http://www.shoutcast.com/?action=sub&cat="+ucat params = {} # "strIndex":"0", "count":str(count), "ajax":"true", "mode":"listeners", "order":"desc" } html = http.ajax(url, params, referer) #,feedback=self.parent.status) - __print__(html) - __print__(re.compile("id=(\d+)").findall(html)); + __print__(dbg.DATA, html) + #__print__(re.compile("id=(\d+)").findall(html)); + + + # With the new shallow <td> lists it doesn't make much sense to use + # the pyquery DOM traversal. There aren't any sensible selectors to + # extract values; it's just counting the tags. + - # regular expressions - if 1: #not conf.get("pyquery") or not pq: + # regular expressions (default) + if not conf.get("pyquery") or not pq: # new html """ <tr> <td width="6%"><a href="#" onClick="window.open('player/?radname=Schlagerhoelle%20%2D%20das%20Paradies%20fr%20Schlager%20%20und%20Discofox&stationid=14687&coding=MP3','radplayer','height=232,width=776')"><img class="icon transition" src="/img/icon-play.png" alt="Play"></a></td> @@ -165,30 +157,32 @@ \s+ <td [^>]+ >(\d+)</td> \s+ <td [^>]+ >(\w+)</td> """, re.S|re.I|re.X ) - __print__( rx_stream) + # extract entries self.parent.status("parsing document...") - __print__("loop-rx") + __print__(dbg.PROC, "channels.shoutcast.update_streams: regex scraping mode") + for m in rx_stream.findall(html): - __print__(m) + #__print__(m) (id, title, genre, listeners, bitrate, fmt) = m entries += [{ "id": id, "url": "http://yp.shoutcast.com/sbin/tunein-station.pls?id=" + id, "title": self.entity_decode(title), #"homepage": http.fix_url(homepage), #"playing": self.entity_decode(playing), "genre": genre, "listeners": int(listeners), - #"max": 0, #int(uu[6]), + "max": 0, #int(uu[6]), "bitrate": int(bitrate), "format": self.mime_fmt(fmt), }] + # PyQuery parsing else: # iterate over DOM for div in (pq(e) for e in pq(html).find("tr")): @@ -195,14 +189,13 @@ entries.append({ "title": div.find("a.transition").text(), "url": div.find("a.transition").attr("href"), "homepage": "", - "playing": div.find("td:eq(2)").text(), - "listeners": int(div.find("td:eq(4)").text()), - "bitrate": int(div.find("td:eq(5)").text()), - "format": self.mime_fmt(div.find("td:eq(6)").text()), + "listeners": int(div.find("td:eq(3)").text()), + "bitrate": int(div.find("td:eq(4)").text()), + "format": self.mime_fmt(div.find("td:eq(5)").text()), "max": 0, "genre": cat, }) @@ -212,13 +205,13 @@ # more pages to load? next = 99999 except Exception as e: - __print__(e) + __print__(dbg.ERR, e) return entries #fin - __print__(entries) + __print__(dbg.DATA, entries) return entries Index: channels/xiph.py ================================================================== --- channels/xiph.py +++ channels/xiph.py @@ -19,11 +19,11 @@ # streamtuner2 modules from config import conf from mygtk import mygtk import http from channels import * -from channels import __print__ +from config import __print__, dbg # python modules import re from xml.sax.saxutils import unescape as entity_decode, escape as xmlentities import xml.dom.minidom @@ -88,11 +88,11 @@ g = [ [v[1],v[0]] for v in g.items() ] g.sort() g.reverse() for row in g: pass - __print__( ' "' + row[1] + '", #' + str(row[0]) ) + __print__( dbg.DATA, ' "' + row[1] + '", #' + str(row[0]) ) # xml dom node shortcut to text content def x(self, entry, name): e = entry.getElementsByTagName(name) Index: config.py ================================================================== --- config.py +++ config.py @@ -28,11 +28,10 @@ #-- global configuration data --------------------------------------------- class ConfigDict(dict): - # start def __init__(self): # object==dict means conf.var is conf["var"] self.__dict__ = self # let's pray this won't leak memory due to recursion issues @@ -160,17 +159,17 @@ return # file not found # decode r = pson.load(f) f.close() return r - except (Exception), e: + except Exception as e: print("PSON parsing error (in "+name+")", e) # recursive dict update def update(self, with_new_data): - for key,value in with_new_data.iteritems(): + for key,value in with_new_data.items(): if type(value) == dict: self[key].update(value) else: self[key] = value # descends into sub-dicts instead of wiping them with subkeys @@ -187,6 +186,26 @@ #-- actually fill global conf instance conf = ConfigDict() + +# wrapper for all print statements +def __print__(*args): + if conf.debug: + print(" ".join([str(a) for a in args])) + + +# error colorization +dbg = type('obj', (object,), { + "ERR": "[31m[ERR][0m", # red ERROR + "INIT": "[31m[INIT][0m", # red INIT ERROR + "PROC": "[32m[PROC][0m", # green PROCESS + "CONF": "[33m[CONF][0m", # brown CONFIG DATA + "UI": "[34m[UI][0m", # blue USER INTERFACE BEHAVIOUR + "HTTP": "[35m[HTTP][0m", # magenta HTTP REQUEST + "DATA": "[36m[DATA][0m", # cyan DATA + "INFO": "[37m[INFO][0m", # gray INFO + "STAT": "[37m[STATE][0m", # gray CONFIG STATE +}) + Index: http.py ================================================================== --- http.py +++ http.py @@ -12,15 +12,18 @@ # The latter code is pretty much unreadable. But let's put the # blame on urllib2, the most braindamaged code in the Python # standard library. # - -import urllib2 -from urllib import urlencode +try: + import urllib2 + from urllib import urlencode +except: + import urllib.request as urllib2 + import urllib.parse.urlencode as urlencode import config -from channels import __print__ +from config import __print__, dbg #-- url download --------------------------------------------- Index: mygtk.py ================================================================== --- mygtk.py +++ mygtk.py @@ -25,16 +25,15 @@ # debug -def __print__(*args): - print(" ".join([str(a) for a in args])) +from config import __print__, dbg # gtk modules -gtk = 3 # 0=gtk2, else gtk3 +gtk = 0 # 0=gtk2, else gtk3 if gtk: from gi import pygtkcompat as pygtk pygtk.enable() pygtk.enable_gtk(version='3.0') from gi.repository import Gtk as gtk Index: pson.py ================================================================== --- pson.py +++ pson.py @@ -19,10 +19,14 @@ # #-- reading and writing json (for the config module) ---------------------------------- +import sys +if sys.version_info > (2, 9): + unicode = str + #dict.iteritems = dict.items # try to load the system module first try: from json import dump as json_dump, load as json_load except: @@ -82,15 +86,15 @@ elif type(obj) in (list, tuple, set): obj = list(obj) for i,v in enumerate(obj): obj[i] = filter_data(v) elif type(obj) == dict: - for i,v in obj.iteritems(): + for i,v in list(obj.items()): i = filter_data(i) obj[i] = filter_data(v) else: print("invalid object in data, converting to string: ", type(obj), obj) obj = str(obj) return obj Index: st2.py ================================================================== --- st2.py +++ st2.py @@ -97,14 +97,14 @@ # gtk modules from mygtk import pygtk, gtk, gobject, ui_file, mygtk # custom modules from config import conf # initializes itself, so all conf.vars are available right away +from config import __print__, dbg import http import action # needs workaround... (action.main=main) from channels import * -from channels import __print__ import favicon #from pq import pq @@ -128,24 +128,24 @@ # constructor def __init__(self): # gtkrc stylesheet - self.load_theme(), gui_startup(1/20) + self.load_theme(), gui_startup(1/20.0) # instantiate gtk/glade widgets in current object gtk.Builder.__init__(self) - gtk.Builder.add_from_file(self, conf.find_in_dirs([".", conf.share], ui_file)), gui_startup(2/20) + gtk.Builder.add_from_file(self, conf.find_in_dirs([".", conf.share], ui_file)), gui_startup(2/20.0) # manual gtk operations self.extensionsCTM.set_submenu(self.extensions) # duplicates Station>Extension menu into stream context menu # initialize channels self.channels = { "bookmarks": bookmarks(parent=self), # this the remaining built-in channel "shoutcast": None,#shoutcast(parent=self), } - gui_startup(3/20) + gui_startup(3/20.0) self.load_plugin_channels() # append other channel modules / plugins # load application state (widget sizes, selections, etc.) try: @@ -160,18 +160,18 @@ self.channels[id].shown = winlayout[id+"_list"].get("row:selected", 0) # actually just used as boolean flag (for late loading of stream list), selection bar has been positioned before already except: pass # fails for disabled/reordered plugin channels # display current open channel/notebook tab - gui_startup(17/20) + gui_startup(17/20.0) self.current_channel = self.current_channel_gtk() try: self.channel().first_show() - except: print("channel .first_show() initialization error") + except: __print__(dbg.INIT, "main.__init__: current_channel.first_show() initialization error") # bind gtk/glade event names to functions - gui_startup(19/20) + gui_startup(19/20.0) self.connect_signals(dict( { "gtk_main_quit" : self.gtk_main_quit, # close window # treeviews / notebook "on_stream_row_activated" : self.on_play_clicked, # double click in a streams list "on_category_clicked": self.on_category_clicked, # new selection in category list @@ -221,11 +221,11 @@ "streamedit_new": streamedit.new, "streamedit_cancel": streamedit.cancel, }.items() + self.add_signals.items() )) # actually display main window - gui_startup(99/100) + gui_startup(99/100.0) self.win_streamtuner2.show() # WHY DON'T YOU WANT TO WORK?! #self.shoutcast.gtk_list.set_enable_search(True) #self.shoutcast.gtk_list.set_search_column(4) @@ -281,15 +281,15 @@ else: #if type(page_num) == int: self.current_channel = self.channel_names[page_num] # if first selected, load current category try: - print("try: .first_show", self.channel().module); - print(self.channel().first_show) - print(self.channel().first_show()) + __print__(dbg.PROC, "channel_switch: try .first_show", self.channel().module); + __print__(self.channel().first_show) + __print__(self.channel().first_show()) except: - print("channel .first_show() initialization error") + __print__(dbg.INIT, "channel .first_show() initialization error") # convert ListStore iter to row number def rowno(self): (model, iter) = self.model_iter() @@ -335,17 +335,17 @@ # browse channel def on_homepage_channel_clicked(self, widget, event=2): if event == 2 or event.type == gtk.gdk._2BUTTON_PRESS: - __print__("dblclick") + __print__(dbg.UI, "dblclick") action.browser(self.channel().homepage) # reload stream list in current channel-category def on_reload_clicked(self, widget=None, reload=1): - __print__("reload", reload, self.current_channel, self.channels[self.current_channel], self.channel().current) + __print__(dbg.UI, "reload", reload, self.current_channel, self.channels[self.current_channel], self.channel().current) category = self.channel().current self.thread( lambda: ( self.channel().load(category,reload), reload and self.bookmarks.heuristic_update(self.current_channel,category) ) ) @@ -365,11 +365,11 @@ # click in category list def on_category_clicked(self, widget, event, *more): category = self.channel().currentcat() - __print__("on_category_clicked", category, self.current_channel) + __print__(dbg.UI, "on_category_clicked", category, self.current_channel) self.on_reload_clicked(None, reload=0) pass # add current selection to bookmark store @@ -462,15 +462,15 @@ order = [module.strip() for module in conf.channel_order.lower().replace(".","_").replace("-","_").split(",")] ls = [module for module in (order) if (module in ls)] + [module for module in (ls) if (module not in order)] # step through for module in ls: - gui_startup(2/10 + 7/10 * float(ls.index(module))/len(ls), "loading module "+module) + gui_startup(2/10.0 + 7/10.0 * float(ls.index(module))/len(ls), "loading module "+module) # skip module if disabled if conf.plugins.get(module, 1) == False: - __print__("disabled plugin:", module) + __print__(dbg.STAT, "disabled plugin:", module) continue # load plugin try: plugin = __import__("channels."+module, None, None, [""]) @@ -487,11 +487,11 @@ # other plugin types else: self.features[module] = plugin_class(parent=self) except Exception as e: - print("error initializing:", module, ", exception:") + __print__(dbg.INIT, "load_plugin_channels: error initializing:", module, ", exception:") import traceback traceback.print_exc() # default plugins conf.add_plugin_defaults(self.channels["bookmarks"].config, "bookmarks") @@ -514,11 +514,11 @@ # apply gtkrc stylesheet def load_theme(self): if conf.get("theme"): for dir in (conf.dir, conf.share, "/usr/share"): - f = dir + "/themes/" + conf.theme + "/gtk-2"+".0/gtkrc" + f = dir + "/themes/" + conf.theme + "/gtk-2.0/gtkrc" if os.path.exists(f): gtk.rc_parse(f) pass @@ -774,11 +774,11 @@ def apply(self, config, prefix="config_", save=0): for key,val in config.iteritems(): # 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__("config_save", save, prefix+id, w, val) + __print__(dbg.CONF, "config", ("save" if save else "load"), prefix+id, w, val) # recurse into dictionaries, transform: conf.play.audio/mp3 => conf.play_audio_mp3 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): @@ -797,13 +797,20 @@ # self.theme.combo_box_new_text() # find themes themedirs = (conf.share+"/themes", conf.dir+"/themes", "/usr/share/themes") themes = ["no theme"] [[themes.append(e) for e in os.listdir(dir)] for dir in themedirs if os.path.exists(dir)] + __print__(dbg.STAT, themes) + # prepare liststore + store = gtk.ListStore(gobject.TYPE_STRING) + self.theme.set_model(store) + cell = gtk.CellRendererText() + self.theme.pack_start(cell, True) + self.theme.add_attribute(cell, "text", 0) # add to combobox for num,themename in enumerate(themes): - self.theme.append_text(themename) + store.append([themename]) if conf.theme == themename: self.theme.set_active(num) # erase this function, so it only ever gets called once self.combobox_theme = lambda: None @@ -1006,11 +1013,11 @@ # simplified gtk TreeStore display logic (just one category for the moment, always rebuilt) def load(self, category, force=False): #self.liststore[category] = \ -# print(category, self.streams.keys()) + __print__(dbg.UI, category, self.streams.keys()) mygtk.columns(self.gtk_list, self.datamap, self.prepare(self.streams.get(category,[]))) # select a category in treeview def add_category(self, cat): @@ -1101,11 +1108,11 @@ #-- startup progress bar progresswin, progressbar = 0, 0 -def gui_startup(p=0/100, msg="streamtuner2 is starting"): +def gui_startup(p=0/100.0, msg="streamtuner2 is starting"): global progresswin,progressbar if not progresswin: # GtkWindow "progresswin" @@ -1113,11 +1120,11 @@ progresswin.set_property("title", "streamtuner2") progresswin.set_property("default_width", 300) progresswin.set_property("width_request", 300) progresswin.set_property("default_height", 30) progresswin.set_property("height_request", 30) - progresswin.set_property("window_position", "center") + #progresswin.set_property("window_position", "center") progresswin.set_property("decorated", False) progresswin.set_property("visible", True) # GtkProgressBar "progressbar" progressbar = gtk.ProgressBar() @@ -1149,11 +1156,11 @@ if len(sys.argv) < 2: # prepare for threading in Gtk+ callbacks gobject.threads_init() - gui_startup(1/100) + gui_startup(1/100.0) # prepare main window main = StreamTunerTwo() # module coupling @@ -1166,11 +1173,11 @@ config_dialog.open(None) del conf.firstrun # run - gui_startup(100/100) + gui_startup(100/100.0) gtk.main() # invoke command-line interface else: