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

⌈⌋ branch:  streamtuner2


Check-in [88aac7840a]

Overview
Comment:Use `module = __name__` consistently for all plugins
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:88aac7840ab8cd2976c8ae46bd773d1bd4ef3aab
User & Date: mario on 2016-12-10 13:55:47
Other Links: manifest | tags
Context
2016-12-10
17:53
New plugin: vtuner2 check-in: 63abbd2c17 user: mario tags: trunk
13:55
Use `module = __name__` consistently for all plugins check-in: 88aac7840a user: mario tags: trunk
12:23
New plugin: prefstore and updated .win.pack+resetprefs.cmd check-in: f117d88494 user: mario tags: trunk
Changes

Modified channels/dnd.py from [d359244196] to [afb629cd4b].

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# never exposed to other apps as x-special/x-custom whatever. (It's also
# not using the MIME 1.0 application/* trash bin for that very reason.)


# Drag and Drop support
class dnd(object):

    module = "dnd"
    meta = plugin_meta()

    # Keeps selected row on starting DND event
    row = None
    # Buffer converted types
    buf = {}








|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# never exposed to other apps as x-special/x-custom whatever. (It's also
# not using the MIME 1.0 application/* trash bin for that very reason.)


# Drag and Drop support
class dnd(object):

    module = __name__
    meta = plugin_meta()

    # Keeps selected row on starting DND event
    row = None
    # Buffer converted types
    buf = {}

Modified channels/exportcat.py from [0cd7c1b0ab] to [de54b609ff].

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import re


# provides another export window, and custom file generation - does not use action.save()
class exportcat():

    meta = plugin_meta()
    module = "exportcat"

    # Register callback
    def __init__(self, parent):
        conf.add_plugin_defaults(self.meta, self.module)
        if parent:
            self.parent = parent
            uikit.add_menu([parent.extensions, parent.extensions_context], "Export all stations", self.savewindow)







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import re


# provides another export window, and custom file generation - does not use action.save()
class exportcat():

    meta = plugin_meta()
    module = __name__

    # Register callback
    def __init__(self, parent):
        conf.add_plugin_defaults(self.meta, self.module)
        if parent:
            self.parent = parent
            uikit.add_menu([parent.extensions, parent.extensions_context], "Export all stations", self.savewindow)

Modified channels/favicon.py from [06b56c7d15] to [8c7cddb000].

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84


# Hook up as feature plugin
#
class favicon(object):

    # plugin attributes
    module = "favicon"
    meta = plugin_meta()
    
    
    # Register with main
    def __init__(self, parent):

        # Prepare favicon cache directory







|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84


# Hook up as feature plugin
#
class favicon(object):

    # plugin attributes
    module = __name__
    meta = plugin_meta()
    
    
    # Register with main
    def __init__(self, parent):

        # Prepare favicon cache directory

Modified channels/filter_bitrate.py from [1c1c85e7a0] to [33e0dcdc20].

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from channels import GenericChannel


# Filter streams by bitrate
class filter_bitrate(object):

    meta = plugin_meta()
    module = "filter_bitrate"

    # Hijack postprocessing filters in stream_update handler 
    def __init__(self, parent):
        GenericChannel.postprocess_filters.append(self.filter_rows)

    # Filter row on bitrate
    def filter_rows(self, row, channel):







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from channels import GenericChannel


# Filter streams by bitrate
class filter_bitrate(object):

    meta = plugin_meta()
    module = __name__

    # Hijack postprocessing filters in stream_update handler 
    def __init__(self, parent):
        GenericChannel.postprocess_filters.append(self.filter_rows)

    # Filter row on bitrate
    def filter_rows(self, row, channel):

Modified channels/global_key.py from [62a1ee3f85] to [3924071f72].

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40



# register a key
class global_key(object):

    # control attributes
    module = "global_key"
    meta = plugin_meta()
    last = 0


    # register
    def __init__(self, parent):
        self.parent = parent







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40



# register a key
class global_key(object):

    # control attributes
    module = __name__
    meta = plugin_meta()
    last = 0


    # register
    def __init__(self, parent):
        self.parent = parent

Modified channels/history.py from [01717d6882] to [171f2c6583].

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
from config import *
from channels import *


class history:

    # plugin attributes
    module = "history"
    meta = plugin_meta()
    
    # store
    bm = None


    # hook up to main tab
    def __init__(self, parent):
        self.config = self.meta["config"]


        # keep reference to main window    
        self.bm = parent.channels["bookmarks"]

        # create category
        self.bm.add_category("history");
        self.bm.reload_if_current(self.module)







|









>







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
from config import *
from channels import *


class history:

    # plugin attributes
    module = __name__
    meta = plugin_meta()
    
    # store
    bm = None


    # hook up to main tab
    def __init__(self, parent):
        self.config = self.meta["config"]
        conf.add_plugin_defaults(self.meta, self.module)

        # keep reference to main window    
        self.bm = parent.channels["bookmarks"]

        # create category
        self.bm.add_category("history");
        self.bm.reload_if_current(self.module)

Modified channels/links.py from [04c56d84f7] to [b5edd85bf1].

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33



# hooks into main.bookmarks
class links (object):

    # plugin info
    module = "links"
    meta = plugin_meta()
    
    # list
    streams = [    ]
    default = [
        ("stream", "rad.io", "http://www.rad.io/"),
        ("stream", "RadioTower", "http://www.radiotower.com/"),







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33



# hooks into main.bookmarks
class links (object):

    # plugin info
    module = __name__
    meta = plugin_meta()
    
    # list
    streams = [    ]
    default = [
        ("stream", "rad.io", "http://www.rad.io/"),
        ("stream", "RadioTower", "http://www.radiotower.com/"),

Modified channels/pluginmanager2.py from [9d68673fa8] to [6958917597].

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import compat2and3
from xml.sax.saxutils import escape as html_escape


# Plugin manager
class pluginmanager2(object):

    module = "pluginmanager2"
    meta = plugin_meta()
    parent = None
    vbox = None


    # Hook up
    def __init__(self, parent):







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import compat2and3
from xml.sax.saxutils import escape as html_escape


# Plugin manager
class pluginmanager2(object):

    module = __name__
    meta = plugin_meta()
    parent = None
    vbox = None


    # Hook up
    def __init__(self, parent):

Modified channels/radiotray.py from [f195cf603e] to [95666bc7a7].

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from xml.etree import ElementTree


# not a channel plugin, just a category in bookmarks, and a context menu
class radiotray:

    # plugin info
    module = "radiotray"
    meta = plugin_meta()
    # bookmarks cat
    parent = None
    bm = None
    # radiotray config file / bookmarks
    rt_xml = "%s/%s/%s" % (xdg_data_home, "radiotray", "bookmarks.xml")








|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from xml.etree import ElementTree


# not a channel plugin, just a category in bookmarks, and a context menu
class radiotray:

    # plugin info
    module = __name__
    meta = plugin_meta()
    # bookmarks cat
    parent = None
    bm = None
    # radiotray config file / bookmarks
    rt_xml = "%s/%s/%s" % (xdg_data_home, "radiotray", "bookmarks.xml")

Modified channels/specbuttons.py from [686c618002] to [2d832ee6ca].

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
# Each command may use streamtuner2 placeholders like %g or %url and $title.


import os.path
import subprocess
import math
import re
from config import conf, log
import action
from uikit import gtk


# Extra/mini buttons in toolbar
class specbuttons(object):

    module = __name__

    # Hook toolbar label
    def __init__(self, parent):


        self.parent = parent

        self.specbuttons = parent.get_widget("specbuttons")
        parent.hooks["init"].append(self.update_buttons)
        parent.hooks["config_save"].append(self.update_paths)
        parent.specbuttons.show()

    # Extra buttons
    def update_buttons(self, parent):







|






>




>
>

>







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
# Each command may use streamtuner2 placeholders like %g or %url and $title.


import os.path
import subprocess
import math
import re
from config import conf, log, plugin_meta
import action
from uikit import gtk


# Extra/mini buttons in toolbar
class specbuttons(object):
    meta = plugin_meta()
    module = __name__

    # Hook toolbar label
    def __init__(self, parent):
        if not parent:
            return
        self.parent = parent
        conf.add_plugin_defaults(self.meta, self.module)
        self.specbuttons = parent.get_widget("specbuttons")
        parent.hooks["init"].append(self.update_buttons)
        parent.hooks["config_save"].append(self.update_paths)
        parent.specbuttons.show()

    # Extra buttons
    def update_buttons(self, parent):

Modified channels/surfmusik.py from [11fb0c16cd] to [422b59ca2d].

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53



# Surfmusik sharing site
class surfmusik (ChannelPlugin):

    # module attributes
    module = "surfmusik"
    listformat = "m3u"
    has_search = False
    lang = "DE"   # last configured categories
    base = {
       "DE": ("http://www.surfmusik.de/", "genre/", "land/"),
       "EN": ("http://www.surfmusic.de/", "format/", "country/"),
    }







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53



# Surfmusik sharing site
class surfmusik (ChannelPlugin):

    # module attributes
    module = __name__
    listformat = "m3u"
    has_search = False
    lang = "DE"   # last configured categories
    base = {
       "DE": ("http://www.surfmusik.de/", "genre/", "land/"),
       "EN": ("http://www.surfmusic.de/", "format/", "country/"),
    }

Modified channels/timer.py from [3bfa1b4ae8] to [5d008572c0].

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51



# timed events (play/record) within bookmarks tab
class timer:

    # plugin info
    module = "timer"
    meta = plugin_meta()
    
    # configuration settings
    timefield = "playing"
    
    # kronos scheduler list
    sched = None







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51



# timed events (play/record) within bookmarks tab
class timer:

    # plugin info
    module = __name__
    meta = plugin_meta()
    
    # configuration settings
    timefield = "playing"
    
    # kronos scheduler list
    sched = None

Modified channels/useragentswitcher.py from [fc341bc2fe] to [681f56976f].

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from channels import *
import ahttp


# override ahttp.session headers, hooks into config dialog
class useragentswitcher():

    module = "useragentswitcher"
    meta = plugin_meta()
    map = {
       "default": "streamtuner2/2.1 (X11; Linux amd64; rv:33.0) like WinAmp/2.1",
       "vlc": "vlc 1.1.0-git-20100330-0003",
       "firefox": "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0",
       "chrome": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
       "android": "Mozilla/5.0 (Linux; U; Android 4.2; en-us; Nexus 10 Build/JVP15I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30",







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from channels import *
import ahttp


# override ahttp.session headers, hooks into config dialog
class useragentswitcher():

    module = __meta__
    meta = plugin_meta()
    map = {
       "default": "streamtuner2/2.1 (X11; Linux amd64; rv:33.0) like WinAmp/2.1",
       "vlc": "vlc 1.1.0-git-20100330-0003",
       "firefox": "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0",
       "chrome": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
       "android": "Mozilla/5.0 (Linux; U; Android 4.2; en-us; Nexus 10 Build/JVP15I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30",

Modified contrib/disabled/win_theme_rezlooks.py from [ea515c3cab] to [5fed4755f0].

1
2
3
4
5
6
7
8
9
10
11
12
13
# api: streamtuner2
# title: Default Windows theme
# description: Use "Rezlooks-dark" as default theme on Windows for SFX/EXE installer
# type: feature
# category: ui
# priority: default
# pack: win_theme_rezlooks.py=../channels/
# depends: librezlooks.dll
# version: -1
# author: Doug Whiteley
# license: GNU GPL
#
# Sets a dark Gtk theme on Windows per default. To disable, simply





|







1
2
3
4
5
6
7
8
9
10
11
12
13
# api: streamtuner2
# title: Default Windows theme
# description: Use "Rezlooks-dark" as default theme on Windows for SFX/EXE installer
# type: feature
# category: ui
# priority: optional
# pack: win_theme_rezlooks.py=../channels/
# depends: librezlooks.dll
# version: -1
# author: Doug Whiteley
# license: GNU GPL
#
# Sets a dark Gtk theme on Windows per default. To disable, simply

Modified contrib/gtk_theme.py from [da18de4370] to [1923315d1d].

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40



# register a key
class gtk_theme(object):

    # plugin info
    module = "gtk_theme"
    meta = plugin_meta()
    theme_dirs = [uikit.gtk.rc_get_theme_dir(), conf.dir + "/themes", conf.share + "/themes"]

    # register
    def __init__(self, parent):
        self.parent = parent
        parent.hooks["config_load"].append(self.list_themes)







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40



# register a key
class gtk_theme(object):

    # plugin info
    module = __name__
    meta = plugin_meta()
    theme_dirs = [uikit.gtk.rc_get_theme_dir(), conf.dir + "/themes", conf.share + "/themes"]

    # register
    def __init__(self, parent):
        self.parent = parent
        parent.hooks["config_load"].append(self.list_themes)

Modified contrib/podspider.py from [41ea1a8df2] to [d384743d3e].

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    return ""  # empty string if nothing found


# PODlist from Radiograbber
class podspider (ChannelPlugin):

    # pi info
    module = "podspider"
    homepage = "http://www.radiograbber.de/"
    listformat = "rss"

    # data
    config = [
    ]
    xml = None







|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    return ""  # empty string if nothing found


# PODlist from Radiograbber
class podspider (ChannelPlugin):

    # pi info
    module = __name__
    homepage = "http://www.radiograbber.de/"
    listformat = "rss"

    # data
    config = [
    ]
    xml = None

Modified contrib/prefstore.py from [6fbcbf2d8d] to [1f207b383e].

19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34
import re
import json


# hooks three functions to the main extension menu
class prefstore():


    meta = plugin_meta()
    module = "prefstore"

    # Register callback
    def __init__(self, parent):
        if not parent:
            return
        self.parent = parent
        uikit.add_menu([parent.extensions], "Config save", self.save)







>

<







19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
import re
import json


# hooks three functions to the main extension menu
class prefstore():

    module = __name__
    meta = plugin_meta()


    # Register callback
    def __init__(self, parent):
        if not parent:
            return
        self.parent = parent
        uikit.add_menu([parent.extensions], "Config save", self.save)

Modified contrib/reciva.py from [80c3e098ef] to [497ae97678].

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from channels import *


# Reciva directory
class reciva (ChannelPlugin):

    # module attributes
    module = "reciva"
    listformat = "pls"
    has_search = True
    categories = ['60s', '70s', '80s', '90s', 'Adult', ['Adult Contemporary'], 'Alternative', 'Ambient', 'Bluegrass', 'Blues', 'Bollywood', 'Christian', ['Christian Contemporary'], 'Classic Rock', 'Classical', 'College', 'Comedy', 'Contemporary', 'Country', 'Dance', 'Discussion', 'Easy', 'Electronica', 'Experimental', 'Folk', 'Gospel', 'Greek', 'Hip Hop', 'Indian', 'Indie', ['Indie Rock'], 'Jazz', 'Jungle', 'Kids', 'Latin Hits', 'New Age', 'News', ['News Talk', 'News Updates'], 'Oldies', 'Pop', 'Public', 'Punk', 'Rap', 'Reggae', 'Religious', 'Rock', 'Short Wave Radio', 'Soft Rock', 'Spanish', 'Sports', 'Talk', 'Top 40', 'Unknown', 'Varied', 'World', ['World Africa', 'World Asia', 'World Caribbean', 'World Europe', 'World Mediterranean', 'World Middle East', 'World Tropical']]
    catmap = { 'classical': '14', 'dance': '18', 'bluegrass': '52', 'contemporary': '16', 'pop': '34', 'spanish': '66', 'college': '15', 'rap': '38', 'ambient': '69', 'talk': '43', 'alternative': '9', 'religious': '39', 'blues': '10', 'folk': '23', 'classic rock': '13', '90s': '7', 'adult contemporary': '8', 'oldies': '33', 'indie rock': '54', 'electronica': '21', 'unknown': '45', 'discussion': '19', 'news talk': '31', 'world mediterranean': '55', 'sports': '42', 'new age': '51', 'indie': '27', 'indian': '65', 'easy': '20', '80s': '6', 'world africa': '67', 'comedy': '62', 'public': '35', 'jungle': '72', 'reggae': '48', 'world middle east': '50', 'christian': '11', 'world caribbean': '68', '60s': '58', 'world europe': '56', 'jazz': '28', '70s': '5', 'soft rock': '41', 'top 40': '44', 'adult': '57', 'news': '30', 'bollywood': '60', 'world tropical': '53', 'latin hits': '29', 'varied': '46', 'christian contemporary': '12', 'kids': '59', 'short wave radio': '73', 'world': '49', 'world asia': '47', 'country': '17', 'news updates': '32', 'punk': '36', 'greek': '25', 'hip hop': '26', 'rock': '40', 'gospel': '24', 'experimental': '22' }
    titles = dict( genre="Genre", title="Station", playing="Location", bitrate="Bitrate", listeners=False )
    base_url = "https://radios.reciva.com/stations/genre/%s?&start=0&count=%s"
    







|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from channels import *


# Reciva directory
class reciva (ChannelPlugin):

    # module attributes
    module = __name__
    listformat = "pls"
    has_search = True
    categories = ['60s', '70s', '80s', '90s', 'Adult', ['Adult Contemporary'], 'Alternative', 'Ambient', 'Bluegrass', 'Blues', 'Bollywood', 'Christian', ['Christian Contemporary'], 'Classic Rock', 'Classical', 'College', 'Comedy', 'Contemporary', 'Country', 'Dance', 'Discussion', 'Easy', 'Electronica', 'Experimental', 'Folk', 'Gospel', 'Greek', 'Hip Hop', 'Indian', 'Indie', ['Indie Rock'], 'Jazz', 'Jungle', 'Kids', 'Latin Hits', 'New Age', 'News', ['News Talk', 'News Updates'], 'Oldies', 'Pop', 'Public', 'Punk', 'Rap', 'Reggae', 'Religious', 'Rock', 'Short Wave Radio', 'Soft Rock', 'Spanish', 'Sports', 'Talk', 'Top 40', 'Unknown', 'Varied', 'World', ['World Africa', 'World Asia', 'World Caribbean', 'World Europe', 'World Mediterranean', 'World Middle East', 'World Tropical']]
    catmap = { 'classical': '14', 'dance': '18', 'bluegrass': '52', 'contemporary': '16', 'pop': '34', 'spanish': '66', 'college': '15', 'rap': '38', 'ambient': '69', 'talk': '43', 'alternative': '9', 'religious': '39', 'blues': '10', 'folk': '23', 'classic rock': '13', '90s': '7', 'adult contemporary': '8', 'oldies': '33', 'indie rock': '54', 'electronica': '21', 'unknown': '45', 'discussion': '19', 'news talk': '31', 'world mediterranean': '55', 'sports': '42', 'new age': '51', 'indie': '27', 'indian': '65', 'easy': '20', '80s': '6', 'world africa': '67', 'comedy': '62', 'public': '35', 'jungle': '72', 'reggae': '48', 'world middle east': '50', 'christian': '11', 'world caribbean': '68', '60s': '58', 'world europe': '56', 'jazz': '28', '70s': '5', 'soft rock': '41', 'top 40': '44', 'adult': '57', 'news': '30', 'bollywood': '60', 'world tropical': '53', 'latin hits': '29', 'varied': '46', 'christian contemporary': '12', 'kids': '59', 'short wave radio': '73', 'world': '49', 'world asia': '47', 'country': '17', 'news updates': '32', 'punk': '36', 'greek': '25', 'hip hop': '26', 'rock': '40', 'gospel': '24', 'experimental': '22' }
    titles = dict( genre="Genre", title="Station", playing="Location", bitrate="Bitrate", listeners=False )
    base_url = "https://radios.reciva.com/stations/genre/%s?&start=0&count=%s"
    

Modified contrib/url_soundcloud.py from [df26d4522d] to [aca8213856].

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# rewrite by above handler. Should turn faux "audio/soundcloud" URL into
# plain/longwinded MP3 streaming address.
#
# Would need more generalized processing of custom URL schemes. But so
# far only the reddit module uses them anyway.
#
class url_soundcloud(object):
    module = "url_soundcloud"

    # override action.play() with wrapper
    def __init__(self, parent, *a, **kw):
        conf.play[fmt] = "false / convert"
        #conf.filter_walledgardens = False
        action.handler[fmt] = sndcl_convert








|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# rewrite by above handler. Should turn faux "audio/soundcloud" URL into
# plain/longwinded MP3 streaming address.
#
# Would need more generalized processing of custom URL schemes. But so
# far only the reddit module uses them anyway.
#
class url_soundcloud(object):
    module = __name__

    # override action.play() with wrapper
    def __init__(self, parent, *a, **kw):
        conf.play[fmt] = "false / convert"
        #conf.filter_walledgardens = False
        action.handler[fmt] = sndcl_convert

Modified contrib/vtuner.py from [c0139e2833] to [9e9c5bde27].

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from channels import *


# vTuner directory
class vtuner (ChannelPlugin):

    # module attributes
    module = "vtuner"
    listformat = "pls"
    has_search = False
    categories = [
        'Alternative', 'Ambient', 'Big Band', 'Bluegrass', 'Blues',
        'Business News', 'Celtic', 'Christian Contemporary', 'Christian Rock',
        'Classic Rock', 'Classical', 'College', 'Country', 'Dance',
        'Electronica', 'Folk', 'Gospel', 'Hard Rock', 'Hip Hop', 'Holiday',







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from channels import *


# vTuner directory
class vtuner (ChannelPlugin):

    # module attributes
    module = __name__
    listformat = "pls"
    has_search = False
    categories = [
        'Alternative', 'Ambient', 'Big Band', 'Bluegrass', 'Blues',
        'Business News', 'Celtic', 'Christian Contemporary', 'Christian Rock',
        'Classic Rock', 'Classical', 'College', 'Country', 'Dance',
        'Electronica', 'Folk', 'Gospel', 'Hard Rock', 'Hip Hop', 'Holiday',