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

βŒˆβŒ‹ βŽ‡ branch:  streamtuner2


Check-in [1a034aeac0]

Overview
Comment:Allow for subcategories in bookmarks.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1a034aeac0f9eebffa8bcc00a831d28c36857c7a
User & Date: mario on 2018-12-18 22:40:04
Other Links: manifest | tags
Context
2018-12-18
22:40
Optional toolbar button for search dialog. check-in: 4beef0ad4d user: mario tags: trunk
22:40
Allow for subcategories in bookmarks. check-in: 1a034aeac0 user: mario tags: trunk
2018-12-17
22:19
Added crude support for binding internal calls `object.func()` to buttons. check-in: bbb93d412c user: mario tags: trunk
Changes

Modified channels/bookmarks.py from [557d39309e] to [0b438ee149].

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
78
        "search": [],
        "scripts": [],
        "timer": [],
        "history": []
    }
    default = "favourite"
    fixed_size = [32,24]



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

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

        GenericChannel.gui(self, parent)
        uikit.tree_column(self.gtk_cat, "Group")

    # 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







>







>



|

|
>
>
>




<







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
78
79
80
81
82
        "search": [],
        "scripts": [],
        "timer": [],
        "history": []
    }
    default = "favourite"
    fixed_size = [32,24]
    reserved_names = ["favourite", "radiotray", "scripts", "search", "timer", "history", "links", "themes"] #+ self.parent.features.keys()


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

    def gui(self, parent):
        parent.notebook_channels.set_menu_label_text(parent.v_bookmarks, "bookmarks")
        self.update_categories()
        GenericChannel.gui(self, parent)
        uikit.tree_column(self.gtk_cat, "Group")

    # custom categories are shown as subfolder below `favourite`
    def update_categories(self):
        cust_cats = list(set(self.streams.keys()) - set(self.reserved_names))
        if len(self.categories) < 2 or type(self.categories[1]) is not list:
            self.categories.insert(1, [])
        self.categories[1] = cust_cats
        
    # 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
        if (not self.urls):
            self.urls = [str(row.get("url","urn:x-streamtuner2:no")) for row in self.streams["favourite"]]
        return str(url) in self.urls


    # called from main window / menu / context menu,
    # when bookmark is to be added for a selected stream entry
    def add(self, row):

        # Add / copy some row attributes
        row["favourite"] = 1
        if not row.get("favicon"):
            pass#   row["favicon"] = favicon.file(row.get("homepage"))
        if not row.get("listformat"):
            row["listformat"] = self.parent.channel().listformat
        if not len(row.get("extra", "")):
            row["extra"] = self.parent.channel().module

        # append to storage
        self.streams["favourite"].append(row)
        self.save()
        self.load(self.default)
        self.urls.append(row["url"])


    # simplified gtk TreeStore display logic (just one category for the moment, always rebuilt)
    def load(self, category, force=False, y=None):







|











|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
        if (not self.urls):
            self.urls = [str(row.get("url","urn:x-streamtuner2:no")) for row in self.streams["favourite"]]
        return str(url) in self.urls


    # called from main window / menu / context menu,
    # when bookmark is to be added for a selected stream entry
    def add(self, row, target="favourite"):

        # Add / copy some row attributes
        row["favourite"] = 1
        if not row.get("favicon"):
            pass#   row["favicon"] = favicon.file(row.get("homepage"))
        if not row.get("listformat"):
            row["listformat"] = self.parent.channel().listformat
        if not len(row.get("extra", "")):
            row["extra"] = self.parent.channel().module

        # append to storage
        self.streams[target].append(row)
        self.save()
        self.load(self.default)
        self.urls.append(row["url"])


    # simplified gtk TreeStore display logic (just one category for the moment, always rebuilt)
    def load(self, category, force=False, y=None):

Added contrib/new_favourite_cat.py version [f1bb6d76fa].

































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# encoding: utf-8
# api: streamtuner2
# title: New favourite category
# description: Introduces new bookmarks categories
# version: 0.2
# type: feature
# category: ui
# config: -
# priority: optional
# 
# Adds a "New favourite category..." under Station > Extensions menu.
# New categories will show up in the bookmarks channel under favourite.
#

from uikit import *
from config import *

# 
class new_favourite_cat (object):
    plugin = "new_favourite_cat"
    meta = plugin_meta()
    parent = None
    w = None

    # hook up menu entry
    def __init__(self, parent):
        self.parent = parent
        uikit.add_menu([parent.extensions], "New favourite category…", self.win, insert=3)
        self.create_submenu(parent)
        self.update_submenu()
  
    # show input window
    def win(self, *w):
        w = self.w = gtk.Dialog(
            'New bookmark category',
            self.parent.win_streamtuner2, 
            gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
            (gtk.STOCK_OK, gtk.RESPONSE_APPLY)
        )
        input = gtk.Entry(35)
        w.vbox.pack_start(input)
        log.UI(w.vbox.get_children())
        w.show_all()
        self.add(self.w, w.run(), input.get_text())

    # add category
    def add(self, w, r, title):
        bm = self.parent.bookmarks
        have = bm.streams.has_key(title)
        w.destroy()
        if r == gtk.RESPONSE_APPLY:
            log.NEW(title)
            if not have:
                bm.streams[title] = {}
        if r == gtk.RESPONSE_DELETE_EVENT:
            if have:
                bm.streams.remove(title)
        self.update_submenu()
        bm.update_categories()
        bm.display_categories()

    # introduce MenuItem+Menu
    def create_submenu(self, parent):
        self.submenu = gtk.Menu()
        for title, target, i in [("Bookmark to", parent.streammenu, 1), ("Add bookmark to", parent.streamactions, 3)]:
            mi = gtk.ImageMenuItem(gtk.STOCK_INDENT)
            mi.set_submenu(self.submenu)
            mi.set_label(title)
            mi.show_all()
            target.insert(mi, i)

    # bookmark to > … submenu w/ custom categories
    def update_submenu(self):
        bmc = self.parent.bookmarks.categories
        [self.submenu.remove(w) for w in self.submenu.get_children()]
        if len(bmc) >= 2 and type(bmc[1]) is list:
            for label in bmc[1]:
                uikit.add_menu([self.submenu], label, lambda w,target=label: self.parent.bookmark(w, target))
        self.submenu.show_all()
    

Modified gtk3.xml.gz from [22b92b2dc9] to [1691d2599f].

cannot compute difference between binary files

Modified st2.py from [9e34a20f96] to [0aae622bbd].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: Directory browser for internet radio, audio and video streams
# version: 2.2.1-dev20180820
# state: stable
# author: Mario Salzer <mario@include-once.org>
# license: Public Domain
# url: http://freshcode.club/projects/streamtuner2
# config:  
#   { type: env, name: HTTP_PROXY, description: proxy for HTTP access }
#   { type: env, name: XDG_CONFIG_HOME, description: relocates user .config subdirectory }






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: Directory browser for internet radio, audio and video streams
# version: 2.2.1-dev20181218
# state: stable
# author: Mario Salzer <mario@include-once.org>
# license: Public Domain
# url: http://freshcode.club/projects/streamtuner2
# config:  
#   { type: env, name: HTTP_PROXY, description: proxy for HTTP access }
#   { type: env, name: XDG_CONFIG_HOME, description: relocates user .config subdirectory }
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
    def on_category_clicked(self, widget, event, *more):
        category = self.channel().currentcat()
        log.UI("on_category_clicked", category, self.current_channel)
        self.on_reload_clicked(None, reload=0)
        pass

    # Add current selection to bookmark store
    def bookmark(self, widget):
        self.bookmarks.add(self.row())
        self.channel().row_icon(gtk.STOCK_ABOUT)
        # refresh bookmarks tab
        self.bookmarks.load(self.bookmarks.default)

    # Reload category tree
    def update_categories(self, widget):
        self.thread(self.channel().reload_categories)







|
|







319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
    def on_category_clicked(self, widget, event, *more):
        category = self.channel().currentcat()
        log.UI("on_category_clicked", category, self.current_channel)
        self.on_reload_clicked(None, reload=0)
        pass

    # Add current selection to bookmark store
    def bookmark(self, widget, target="favourite"):
        self.bookmarks.add(self.row(), target)
        self.channel().row_icon(gtk.STOCK_ABOUT)
        # refresh bookmarks tab
        self.bookmarks.load(self.bookmarks.default)

    # Reload category tree
    def update_categories(self, widget):
        self.thread(self.channel().reload_categories)