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

⌈⌋ ⎇ branch:  streamtuner2


Check-in [a7c3f7336a]

Overview
Comment:Fix a few CLI bugs (doesn't work yet with dynamic module list), stub_parent() implementations for non-GUI mode should be merged.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a7c3f7336a8be0a54d00693002d75ac3877f544b
User & Date: mario on 2015-04-07 05:53:39
Other Links: manifest | tags
Context
2015-04-07
05:54
Less indentation, starting to overhaul action.save() at least. (Whole `action` module is overdue.) check-in: 7726e18571 user: mario tags: trunk
05:53
Fix a few CLI bugs (doesn't work yet with dynamic module list), stub_parent() implementations for non-GUI mode should be merged. check-in: a7c3f7336a user: mario tags: trunk
05:51
Move argv initialization to conf.apply_args(). Document config: format for argparse conversion. Enable file=sys.stderr for __print__/debug messages. check-in: 1eea3140f8 user: mario tags: trunk
Changes

Modified channels/__init__.py from [292484f13c] to [11f92592f3].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# encoding: UTF-8
# api: streamtuner2
# type: base
# category: ui
# title: Channel plugins
# description: Base implementation for channels and feature plugins
# version: 1.1
# license: public domain
# author: mario
# url: http://fossil.include-once.org/streamtuner2/
# pack:
#    bookmarks.py configwin.py streamedit.py history.py search.py links.py 
#    icast.py internet_radio.py itunes.py jamendo.py live365.py global_key.py
#    modarchive.py myoggradio.py punkcast.py radiobrowser.py radiotray.py






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
# encoding: UTF-8
# api: streamtuner2
# type: base
# category: ui
# title: Channel plugins
# description: Base implementation for channels and feature plugins
# version: 1.2
# license: public domain
# author: mario
# url: http://fossil.include-once.org/streamtuner2/
# pack:
#    bookmarks.py configwin.py streamedit.py history.py search.py links.py 
#    icast.py internet_radio.py itunes.py jamendo.py live365.py global_key.py
#    modarchive.py myoggradio.py punkcast.py radiobrowser.py radiotray.py
116
117
118
119
120
121
122



123
124
125
126
127
128
129
        self.module = self.__class__.__name__
        self.meta = plugin_meta(src = inspect.getcomments(inspect.getmodule(self)))
        self.config = self.meta.get("config", [])
        self.title = self.meta.get("title", self.module)

        # add default options values to config.conf.* dict
        conf.add_plugin_defaults(self.meta, self.module)




        # only if streamtuner2 is run in graphical mode        
        if (parent):
            self.cache()
            self.gui(parent)
        pass
        







>
>
>







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
        self.module = self.__class__.__name__
        self.meta = plugin_meta(src = inspect.getcomments(inspect.getmodule(self)))
        self.config = self.meta.get("config", [])
        self.title = self.meta.get("title", self.module)

        # add default options values to config.conf.* dict
        conf.add_plugin_defaults(self.meta, self.module)
        
        # stub for ST2 main window / dispatcher
        self.parent = stub_parent(None)

        # only if streamtuner2 is run in graphical mode        
        if (parent):
            self.cache()
            self.gui(parent)
        pass
        
582
583
584
585
586
587
588











        # try to initialize superclass now, before adding to channel tabs
        GenericChannel.gui(self, parent)

        # add notebook tab
        tab = parent.notebook_channels.insert_page_menu(vbox, ev_label, plain_label, -1)
        parent.notebook_channels.set_tab_reorderable(vbox, True)



















>
>
>
>
>
>
>
>
>
>
>
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
        # try to initialize superclass now, before adding to channel tabs
        GenericChannel.gui(self, parent)

        # add notebook tab
        tab = parent.notebook_channels.insert_page_menu(vbox, ev_label, plain_label, -1)
        parent.notebook_channels.set_tab_reorderable(vbox, True)


# WORKAROUND for direct channel module imports,
# eases instantiations without GUI a little,
# reducing module dependencies (conf. / ahttp. / channels. / parent.) would be better
def stub_parent(object):
    def __setattr__(self, name, value):
        pass
    def __getattr__(self, name):
        return lambda *x: None
    def status(self, *x):
        pass

Modified cli.py from [436f001346] to [c8d63f1db6].

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
#
# api: streamtuner2
# title: CLI interface
# description: allows to call streamtuner2 from the commandline
# status: experimental
# version: 0.3
#
#  Returns JSON data when queried. Usually returns cache data, but the
#  "category" module always loads fresh info from the directory servers.
#
#  Not all channel plugins are gtk-free yet. And some workarounds are
#  used here to not upset channel plugins about a missing parent window.
#
#
#


import sys
#from channels import *
import ahttp
import action
from config import conf
import json




# CLI
class StreamTunerCLI (object):


    # plugin info
    title = "CLI interface"
    version = 0.3

    
    # channel plugins
    channel_modules = ["shoutcast", "xiph", "internet_radio", "jamendo", "myoggradio", "live365"]
    current_channel = "cli"
    plugins = {} # only populated sparsely by .stream()
    
    
    # start
    def __init__(self, actions):

        # fake init    
        action.action.main = empty_parent()
        action.action.main.current_channel = self.current_channel

        # check if enough arguments, else  help
        if not actions:
            a = self.help
        # first cmdline arg == action
        else:
            command = actions[0]
            if command in self.__dict__:
                cmd = self.__getattribute__(command)
            else:
                print "No such command:", command
                return

        # run
        result = cmd(*actions[1:])
<






|
|

|
|
<
<
<






|















|

















|








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

# api: streamtuner2
# title: CLI interface
# description: allows to call streamtuner2 from the commandline
# status: experimental
# version: 0.3
#
# Returns JSON data when queried. Usually returns cache data, but the
# "category" module always loads fresh info from the directory servers.
#
# Not all channel plugins are gtk-free yet. And some workarounds are
# used here to not upset channel plugins about a missing parent window.





import sys
#from channels import *
import ahttp
import action
from config import *
import json




# CLI
class StreamTunerCLI (object):


    # plugin info
    title = "CLI interface"
    version = 0.3

    
    # channel plugins
    channel_modules = ["shoutcast", "xiph", "icast", "jamendo", "radiobrowser"]# module_list()
    current_channel = "cli"
    plugins = {} # only populated sparsely by .stream()
    
    
    # start
    def __init__(self, actions):

        # fake init    
        action.action.main = empty_parent()
        action.action.main.current_channel = self.current_channel

        # check if enough arguments, else  help
        if not actions:
            a = self.help
        # first cmdline arg == action
        else:
            command = actions[0]
            if command in dir(self):
                cmd = self.__getattribute__(command)
            else:
                print "No such command:", command
                return

        # run
        result = cmd(*actions[1:])
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
    
    # load all channel modules    
    def channels(self, channels=None):
        if channels:
            channels = channels.split(",")
        else:
            channels = self.channel_modules
        return (self.channel(module) for module in channels)
    
    # pretty print json
    def json(self, dat):    
        print(json.dumps(dat, sort_keys=True, indent=2))
    
    
    
    
    
# trap for some main window calls
class empty_parent (object):    
    channel = {}
    null = lambda *a: None
    status = null
    thread = null


    







|













|
|



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    
    # load all channel modules    
    def channels(self, channels=None):
        if channels:
            channels = channels.split(",")
        else:
            channels = self.channel_modules
        return channels#(self.channel(module) for module in channels)
    
    # pretty print json
    def json(self, dat):    
        print(json.dumps(dat, sort_keys=True, indent=2))
    
    
    
    
    
# trap for some main window calls
class empty_parent (object):    
    channel = {}
    null = lambda *a: None
    status = lambda *a: None
    thread = lambda *a: None