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

⌈⌋ branch:  streamtuner2


Diff

Differences From Artifact [f6644128e5]:

To Artifact [5cecf16359]:


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    #-- keep track of currently selected genre/category
    __current = None
    @property
    def current(self):
        return self.__current
    @current.setter
    def current(self, newcat):
        __print__(dbg.PROC, "{}.current:={} ← from {}".format(self.module, newcat, [inspect.stack()[x][3] for x in range(1,4)]))
        self.__current = newcat
        return self.__current


    #--------------------------- initialization --------------------------------









|







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    #-- keep track of currently selected genre/category
    __current = None
    @property
    def current(self):
        return self.__current
    @current.setter
    def current(self, newcat):
        log.PROC("{}.current:={} ← from {}".format(self.module, newcat, [inspect.stack()[x][3] for x in range(1,4)]))
        self.__current = newcat
        return self.__current


    #--------------------------- initialization --------------------------------


163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
        # add to main menu
        uikit.add_menu([parent.channelmenuitems], self.meta["title"], lambda w: parent.channel_switch_by_name(self.module) or 1)


    # Statusbar stub (defers to parent/main window, if in GUI mode)
    def status(self, *v):
        if self.parent: self.parent.status(*v)
        else: __print__(dbg.INFO, "status():", *v)


        
    #--------------------- streams/model data accesss ---------------------------
        
    # Get list of stations in current category
    def stations(self):







|







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
        # add to main menu
        uikit.add_menu([parent.channelmenuitems], self.meta["title"], lambda w: parent.channel_switch_by_name(self.module) or 1)


    # Statusbar stub (defers to parent/main window, if in GUI mode)
    def status(self, *v):
        if self.parent: self.parent.status(*v)
        else: log.INFO("status():", *v)


        
    #--------------------- streams/model data accesss ---------------------------
        
    # Get list of stations in current category
    def stations(self):
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
        # called to early
        if not category:
            print "load(None)"
            return

        # get data from cache or download
        if force or not category in self.streams:
            __print__(dbg.PROC, "load", "update_streams")
            self.status("Updating streams...")
            self.status(-0.1)
            if category == "empty":
                new_streams = self.empty_stub
            else:
                new_streams = self.update_streams(category)
  
            if new_streams:
                # check and modify entry;
                # assert that title and url are present
                modified = []
                for row in new_streams:
                    if len(set(["", None]) & set([row.get("title"), row.get("url")])):
                        continue
                    try:
                        modified.append( self.postprocess(row) )
                    except Exception as e:
                        __print__(e, dbg.DATA, "Missing title or url. Postprocessing failed:", row)
                new_streams = modified
  
                # don't lose forgotten streams
                if conf.retain_deleted:
                   self.streams[category] = new_streams + self.deleted_streams(new_streams, self.streams.get(category,[]))
                else:
                   self.streams[category] = new_streams
  
                # save in cache
                self.save()
  
            else:
                # parse error
                self.status("Category parsed empty.")
                self.streams[category] = self.nothing_found
                __print__(dbg.INFO, "Oooops, parser returned nothing for category " + category)
                
        # assign to treeview model
        uikit.do(lambda:uikit.columns(self.gtk_list, self.datamap, self.prepare(self.streams[category])))

        # set pointer
        self.current = category
        self.status("")







|

















|















|







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
        # called to early
        if not category:
            print "load(None)"
            return

        # get data from cache or download
        if force or not category in self.streams:
            log.PROC("load", "update_streams")
            self.status("Updating streams...")
            self.status(-0.1)
            if category == "empty":
                new_streams = self.empty_stub
            else:
                new_streams = self.update_streams(category)
  
            if new_streams:
                # check and modify entry;
                # assert that title and url are present
                modified = []
                for row in new_streams:
                    if len(set(["", None]) & set([row.get("title"), row.get("url")])):
                        continue
                    try:
                        modified.append( self.postprocess(row) )
                    except Exception as e:
                        log.DATA(e, "Missing title or url. Postprocessing failed:", row)
                new_streams = modified
  
                # don't lose forgotten streams
                if conf.retain_deleted:
                   self.streams[category] = new_streams + self.deleted_streams(new_streams, self.streams.get(category,[]))
                else:
                   self.streams[category] = new_streams
  
                # save in cache
                self.save()
  
            else:
                # parse error
                self.status("Category parsed empty.")
                self.streams[category] = self.nothing_found
                log.INFO("Oooops, parser returned nothing for category " + category)
                
        # assign to treeview model
        uikit.do(lambda:uikit.columns(self.gtk_list, self.datamap, self.prepare(self.streams[category])))

        # set pointer
        self.current = category
        self.status("")
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
        
    # display .current category, once notebook/channel tab is first opened
    def first_show(self):

        # Already processed
        if (self.shown == 55555):
            return
        __print__(dbg.PROC, self.module, "→ first_show()", ", current=", self.current, ", categories=", len(self.categories))
    
        # if category tree is empty, initialize it
        if not self.categories:
            __print__(dbg.PROC, self.module, "→ first_show() → reload_categories()");
            try:
                self.reload_categories()
            except:
                __print__(dbg.ERR, "HTTP error or extraction failure.")
                self.categories = ["empty"]
            self.display_categories()

        # Select first category
        if not self.current:
            self.current = self.str_from_struct(self.categories) or None
            __print__(dbg.STAT, self.module, "→ first_show(); use first category as current =", self.current)
            self.shown = 0,

        # Show current category in any case
        __print__(dbg.UI, self.module, "→ first_show(); station list → load(", self.current, ")")
        uikit.do(self.load, self.current)
    
        # put selection/cursor on last position
        if True:#self.shown != None:
            __print__(dbg.STAT, self.module+".first_show()", "select last known category treelist position =", self.shown)
            try:
                uikit.do(lambda:self.gtk_list.get_selection().select_path(self.shown))
            except:
                pass
            
        # Invoke only once
        self.shown = 55555







|



|



|






|



|




|







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
        
    # display .current category, once notebook/channel tab is first opened
    def first_show(self):

        # Already processed
        if (self.shown == 55555):
            return
        log.PROC(self.module, "→ first_show()", ", current=", self.current, ", categories=", len(self.categories))
    
        # if category tree is empty, initialize it
        if not self.categories:
            log.PROC(self.module, "→ first_show() → reload_categories()");
            try:
                self.reload_categories()
            except:
                log.ERR("HTTP error or extraction failure.")
                self.categories = ["empty"]
            self.display_categories()

        # Select first category
        if not self.current:
            self.current = self.str_from_struct(self.categories) or None
            log.STAT(self.module, "→ first_show(); use first category as current =", self.current)
            self.shown = 0,

        # Show current category in any case
        log.UI(self.module, "→ first_show(); station list → load(", self.current, ")")
        uikit.do(self.load, self.current)
    
        # put selection/cursor on last position
        if True:#self.shown != None:
            log.STAT(self.module+".first_show()", "select last known category treelist position =", self.shown)
            try:
                uikit.do(lambda:self.gtk_list.get_selection().select_path(self.shown))
            except:
                pass
            
        # Invoke only once
        self.shown = 55555