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

⌈⌋ ⎇ branch:  streamtuner2


Check-in [99f122b391]

Overview
Comment:Move search and streamedit dialogs into plugins. Less indentation.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 99f122b3911e2c1865c8a8f56bbeff296b86caeb
User & Date: mario on 2015-03-29 14:44:12
Other Links: manifest | tags
Context
2015-03-29
14:47
Renamed `uikit` module. Auxiliary dialogs `streamedit` and `search` moved into plugins. Less indentation. Compacter import statements. Core plugins initialized into .features, and grayed out in configuration dialog. And `station_context_menu` moved into method. check-in: f5f0ae18c1 user: mario tags: trunk
14:44
Move search and streamedit dialogs into plugins. Less indentation. check-in: 99f122b391 user: mario tags: trunk
14:43
Rename `mygtk` to `uikit`. Move AuxiliaryWindow and About dialog from main. check-in: b9cadd6925 user: mario tags: trunk
Changes

Added channels/search.py version [5610a2549a].





































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# api: streamtuner2
# title: Search feature
# description: Provides the quick search box, and server/cache search window.
# version: 0.9
# type: feature
# category: ui
# config: -
# priority: core
# 
# Configuration dialog for audio applications,
# general settings, and plugin activation and
# associated options.
#


from uikit import *
import channels
from config import *
from copy import copy


# Search window, and quicksearch box handler.
#
# Aux win: search dialog - keeps search text in self.q
# Quick search textbox - uses main.q instead
#
class search (AuxiliaryWindow):

    # either current channel, or last channel (avoid searching in bookmarks)
    current = None

    # show search dialog   
    def menu_search(self, w):
        self.search_dialog.show();
        if not self.current or self.main.current_channel != "bookmarks":
            self.current = self.main.current_channel
            self.search_dialog_current.set_label("just %s" % self.main.channels[self.current].meta["title"])


    # hide dialog box again
    def cancel(self, *args):
        self.search_dialog.hide()
        return True  # stop any other gtk handlers
        

    # prepare variables
    def prepare_search(self):
        self.main.status("Searching... Stand back.")
        self.cancel()
        self.q = self.search_full.get_text().lower()
        if self.search_dialog_all.get_active():
            self.targets = self.main.channels.keys()
        else:
            self.targets = [self.current]
        self.main.bookmarks.streams["search"] = []
        
    # perform search
    def cache_search(self, *w):
        self.prepare_search()
        entries = []
        # which fields?
        fields = ["title", "playing", "homepage"]
        for i,cn in enumerate([self.main.channels[c] for c in self.targets]):
            if cn.streams:  # skip disabled plugins
                # categories
                for cat in cn.streams.keys():
                    # stations
                    for row in cn.streams[cat]:
                        # assemble text fields to compare
                        text = " ".join([str(row.get(f, " ")) for f in fields])
                        if text.lower().find(self.q) >= 0:
                            row = copy(row)
                            row["genre"] = c + " " + row.get("genre", "")
                            entries.append(row)
        self.show_results(entries)

    # display "search" in "bookmarks"
    def show_results(self, entries):
        self.main.status(1.0)
        self.main.channel_switch(None, "bookmarks", 0)
        self.main.bookmarks.set_category("search")
        # insert data and show
        self.main.channels["bookmarks"].streams["search"] = entries   # we have to set it here, else .currentcat() might reset it 
        self.main.bookmarks.load("search")
        
        
    # live search on directory server homepages
    def server_search(self, w):
        self.prepare_search()
        entries = []
        for i,cn in enumerate([self.main.channels[c] for c in self.targets]):
            if cn.has_search:  # "search" in cn.update_streams.func_code.co_varnames:
                __print__(dbg.PROC, "has_search:", cn.module)
                try:
                    add = cn.update_streams(cat=None, search=self.q)
                    for row in add:
                        row["genre"] = cn.meta["title"] + " " + row.get("genre", "")
                    entries += add
                except:
                    continue
            #main.status(main, 1.0 * i / 15)
        self.show_results(entries)


    # search text edited in text entry box
    def quicksearch_set(self, w, *eat, **up):
        
        # keep query string
        self.main.q = self.search_quick.get_text().lower()

        # get streams
        c = self.main.channel()
        rows = c.stations()
        col = c.rowmap.index("search_col") # this is the gtk.ListStore index # which contains the highlighting color

        # callback to compare (+highlight) rows
        m = c.gtk_list.get_model()
        m.foreach(self.quicksearch_treestore, (rows, self.main.q, col, col+1))
    search_set = quicksearch_set
        
        
        
    # callback that iterates over whole gtk treelist,
    # looks for search string and applies TreeList color and flag if found
    def quicksearch_treestore(self, model, path, iter, extra_data):
        i = path[0]
        (rows, q, color, flag) = extra_data

        # compare against interesting content fields:
        text = rows[i].get("title", "") + " " + rows[i].get("homepage", "")
        # config.quicksearch_fields
        text = text.lower()

        # simple string match (probably doesn't need full search expression support)
        if len(q) and text.find(q) >= 0:
           model.set_value(iter, color, "#fe9")  # highlighting color
           model.set_value(iter, flag, True) # background-set flag
        # color = 12 in liststore, flag = 13th position
        else:
           model.set_value(iter, color, "")   # for some reason the cellrenderer colors get applied to all rows, even if we specify an iter (=treelist position?, not?)
           model.set_value(iter, flag, False)   # that's why we need the secondary -set option

        #??
        return False


Added channels/streamedit.py version [eaca2a9f8d].































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# api: streamtuner2
# title: Stream entry editor
# description: Allows to inspect and modify station/stream entries.
# version: 0.5
# type: feature
# category: ui
# config: -
# priority: core
# 
# Editing dialog for stream entries. Available in
# the context and main menu. Most useful for
# changing bookmarks, or even creating new ones.
#

from uikit import *
import channels
from config import *
from copy import copy


# aux win: stream data editing dialog
class streamedit (AuxiliaryWindow):

    # show stream data editing dialog
    def open(self, mw):
        self.main.configwin.load_config(self.main.row(), "streamedit_")
        self.win_streamedit.show()

    # copy widget contents to stream
    def save(self, w):
        self.main.configwin.save_config(self.main.row(), "streamedit_")
        self.main.channel().save()
        self.cancel(w)

    # add a new list entry, update window
    def new(self, w):
        s = self.main.channel().stations()
        s.append({"title":"new", "url":"", "format":"audio/mpeg", "genre":"", "listeners":1});
        self.main.channel().switch() # update display
        selfmain.channel().gtk_list.get_selection().select_path(str(len(s)-1)); # set cursor to last row
        self.open(w)

    # hide window
    def cancel(self, *w):
        self.win_streamedit.hide()
        return True