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

⌈⌋ branch:  streamtuner2


Check-in [1cfacd1296]

Overview
Comment:Semi-fix for brand-new initialization. Set default category from existing categories[] list. Setting the displayed path as well doesn't work yet. (It's just half-way selected after the next restart.)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1cfacd1296e67dc5203954f4e3c7f0f1f5b44f2b
User & Date: mario on 2015-04-19 16:33:28
Other Links: manifest | tags
Context
2015-04-19
16:36
Implement basic exporting and conversion for drag-and-drop. Needs to buffer implicit playlist file, because data_get() gets called excessively. Still support direct M3U/PLS/XSPF transfers (should any other application ever understand it), and direct URL transmission. No import functionality yet, but internal JSON format prepared as target type. check-in: 8c7de37e5e user: mario tags: trunk
16:33
Semi-fix for brand-new initialization. Set default category from existing categories[] list. Setting the displayed path as well doesn't work yet. (It's just half-way selected after the next restart.) check-in: 1cfacd1296 user: mario tags: trunk
16:31
Bring back .base_url instead of .homepage property for HTTP requests. check-in: c6416a18df user: mario tags: trunk
Changes

Modified channels/__init__.py from [9a39b12b72] to [b9ead90d77].

92
93
94
95
96
97
98


99
100
101
102
103
104
105
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107







+
+






    placeholder = [dict(genre="./.", title="Subcategory placeholder", playing="./.", url="none:", listeners=0, bitrate=0, homepage="", state="gtkfolder")]
    empty_stub = [dict(genre="./.", title="No categories found (HTTP error)", playing="Try Channel→Reload Categories later..", url="none:", listeners=0, bitrate=0, homepage="", state="gtk-stop")]
    nothing_found = [dict(genre="./.", title="No contents found on directory server", playing="Notice", listeners=0, bitrate=0, state="gtk-info")]
    
    # regex            
    rx_www_url = re.compile("""(www(\.\w+[\w-]+){2,}|(\w+[\w-]+[ ]?\.)+(com|FM|net|org|de|PL|fr|uk))""", re.I)


    #-- keep track of currently selected genre/category
    __current = None
    @property
    def current(self):
        return self.__current
    @current.setter
    def current(self, newcat):
        print "{}.current:={} ← from {}".format(self.module, newcat, [inspect.stack()[x][3] for x in range(1,4)])
416
417
418
419
420
421
422

423
424


425
426
427
428





429
430
431

432
433
434

435
436
437
438
439
440
441
418
419
420
421
422
423
424
425


426
427




428
429
430
431
432
433
434

435
436
437

438
439
440
441
442
443
444
445







+
-
-
+
+
-
-
-
-
+
+
+
+
+


-
+


-
+






                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.current = self.str_from_struct(self.categories) or None
            __print__(dbg.STAT, self.module, "→ first_show(); use first category as current =", self.current)
        try:
            self.load(self.current)
        except:
            pass
            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 self.shown:
        if True:#self.shown != None:
            __print__(dbg.STAT, self.module+".first_show()", "select last known category treelist position =", self.shown)
            try:
                self.gtk_list.get_selection().select_path(self.shown)
                uikit.do(lambda:self.gtk_list.get_selection().select_path(self.shown))
            except:
                pass
            
        # Invoke only once
        self.shown = 55555

Modified channels/bookmarks.py from [265184bad9] to [baf2fe6dd0].

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







-

+

















-
+
+






    streams = {"favourite":[finder_song], "search":[], "scripts":[], "timer":[], "history":[], }


    # cache list, to determine if a PLS url is bookmarked
    urls = []

    def gui(self, parent):
        GenericChannel.gui(self, parent)
        parent.notebook_channels.set_menu_label_text(parent.v_bookmarks, "bookmarks")
        GenericChannel.gui(self, parent)

    # this channel does not actually retrieve/parse data from anywhere
    def update_categories(self):
        pass
        
    # but category sub-plugins might provide a hook
    category_plugins = {}
    def update_streams(self, cat):

        if cat in self.category_plugins:
            return self.category_plugins[cat].update_streams(cat) or []
        else:
            return self.streams.get(cat, [])

        
    # streams are already loaded at instantiation
    #def first_show(self):
    #    pass
    #    print "first_show", len(self.streams["favourite"])
    #    GenericChannel.first_show(self)


    # all entries just come from "bookmarks.json"
    def cache(self):
        # stream list
        cache = conf.load(self.module)
        if (cache):