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

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


Check-in [09dec64f41]

Overview
Comment:Reverted all `module = __name__` assignments, because that was carrying the module over, not the base classname. Added #extraction-method: meta information to channel plugins.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 09dec64f41c9876fd2a4bb10d9da686dfc97ebaa
User & Date: mario on 2016-12-16 16:26:55
Other Links: manifest | tags
Context
2016-12-16
18:34
Fix popen(`locate`) exception. check-in: 8154611e3a user: mario tags: trunk
16:26
Reverted all `module = __name__` assignments, because that was carrying the module over, not the base classname. Added #extraction-method: meta information to channel plugins. check-in: 09dec64f41 user: mario tags: trunk
2016-12-15
20:30
new plugin: streema check-in: a465b6d3b5 user: mario tags: trunk
Changes

Modified channels/dirble.py from [cb216f01ee] to [0aa81f09de].

19
20
21
22
23
24
25

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







+







#    1F9pRbSjlytheTnY3t6iHCcMo9BYxtai1AymjSlRbII4YUcRAQQiMKWO0Vbahk2An3H9jJvU
#    IhEQCKD/TiJiZsXEzMxMYSy78rnOVvf34lISJ8R1pwGqpyCJkvUgCiyziFjJ5Fv7Tx5r07WJ
#    udJajRVDAI30TUQilG1qPry3I/Y9BThubmigb+R4x8L0m1fz5Ti3h0QE0ClcQCA+dflCz0VD
#    RKwUE5mgOvtu8u7z9wsVsyPPrBxfayqMjVtrMrmmI4f27swqkVS+GGMqy39nvy+W1uGxKL+h
#    u+uAt1KkwvVxAGJsEEWxEWzGm4iV8l1HM9K0BmEkrP8BlhoAUfmOxecAAAAASUVORK5CYII=
# priority: optional
# documentation: http://dirble.com/developer/api
# extraction-method: json
#
#
# Dirble is a user-contributed list of radio stations,
# auot-updating song titles and station information.
# Homepages are there now, and thus favicons readily
# available. Extra station banners aren't fetched.
#

Modified channels/dnd.py from [afb629cd4b] to [8308af1af3].

53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
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__
    module = 'dnd'
    meta = plugin_meta()

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

Modified channels/exportcat.py from [de54b609ff] to [45ab7f1478].

32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
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__
    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)

Modified channels/favicon.py from [ef3ab53102] to [edc53741f5].

70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
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__
    module = 'favicon'
    meta = plugin_meta()
    
    
    # Register with main
    def __init__(self, parent):

        # Prepare favicon cache directory

Modified channels/filter_bitrate.py from [33e0dcdc20] to [7813c49854].

25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
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__
    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):

Modified channels/filtermusic.py from [35c1830b55] to [6f77373870].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH3wQeBA4mIX2CmQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAGISURBVCjPnVI9SyNRFD333slMMhrNjBJU0FSLIlovy6IWbmelhRJ/gI2lkMXfIOwv2K38qizstFCs3B+wLFhoIfiR1cggkXzMvHnPIiG6
#   GkE8zYXLPfe8c94F2oAkk7CHHLIIb4AAEIlkcuJmARr8OTxW+pKe9l6PSqN0jOe9hd3014J09tdP96SHSLh8GKirsM1+TvnZ5RN/buO5ItvcUH4BCwC7vex0Vf5stroGMKFu+3omKymdfUTMrs9uDyczAHzfz+VyIpwgu1u8NGccSjbFUyOz/vyOUVVoDZbq3+1gd6lQWMnn85PTEzPR4mdnKjLhrS6uBasArNrZ3t36N29u6/7ge/1038QRECul
#   arWaNrqLvV/lHx2U/pQYbXowUTUuXwJGV0rxQ/H/sKkU/yuqC4dSfdZA0wMAELd+4wUhNFUABro52Spvg54l9y7Cq1g/RiBwAvTkQURs2waBwQARiGE93RKJzW5v/fxIl68bXdd1gyA4Pv6tlLqLbyJEoamX4iI+gEdAknsz9gP1pgAAAABJRU5ErkJggg==
# x-doc:
#   http://code.google.com/p/filtermusic-dot-net/source/browse/
# priority: extra
# extraction-method: regex, xml
#
#
# Filtermusic.net is a radio collection with primarily electronic
# and dance music stations.
#
#  ยท All entries come with direct server stream URLs.
#  ยท No homepage listings, or further genre details etc.

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

26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
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__
    module = 'global_key'
    meta = plugin_meta()
    last = 0


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

Modified channels/history.py from [171f2c6583] to [5e95ab01e2].

13
14
15
16
17
18
19
20

21
22
23

24
25
26
27
28
29
30
13
14
15
16
17
18
19

20
21
22

23
24
25
26
27
28
29
30







-
+


-
+







# bookmarks channel.


from config import *
from channels import *


class history:
class history (object):

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


    # hook up to main tab

Modified channels/internet_radio.py from [f1f9b6b827] to [e2da369cc7].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAaZJREFUOI2N0j1PlEEUBeBnlsVoRJcCPwINxIJGAoWVFbVK4g8w
#   oUUTFRNbG3+FhVErK36BhcYCrTR8FS4mRGUXFEKCUizRwLXgnfV1Awk3mUzmnHPvPXNnUkSE40RKFYxhHKMYxFb1GIlnMLVN/etBUjuGWDm6wEHHyQbLW/Qd
#   JTu8QEq9mJlnogz3sHOJV3iHz2iKzuDiH+bm+J3XD74EU5Gc7pSn/4aYUi14s8BIhkZ5puKhvdgpNFVccaA5oaP7TO66SCuYKnG9weMmjaz5yadqqfvkPE/z
#   8TLTIp4U3I01ljY5f/gQu1LPGvWS7Rel5NtLzOzRlfk+Ngd4i48Ke9PZVpNGUCvwawvsZm6db8GtoLt9s4iIFotZFEwXybU1VjO+z4egv/MVKlIaqTMMJ2nh
#   eeH0wQYX4BwbiQkRTSmdktJ1KY3lGYznuw3zWsS2lLo2WMl4P49ycjCbn3k0pfuVg5m1432e4zr9UGMbLwv8avmP/OJOBQOlAsvF3hYNMititzg2Kuxn7iyr
#   VbSG/tltFHt3CVvATRBRH0lpEvfwXXL3L9zE/NEe0EfHAAAAAElFTkSuQmCC
# extraction-method: regex, dom
#
# Internet-Radio.co.uk/.com is one of the largest stream directories.
# Available music genre classifications are mirrored verbatim and flatly.
#
# The new version of this plugin alternates between PyQuery and Regex
# station extraction. Both overlook some paid or incomplete entries.
# HTTP retrieval happens in one batch, determined by the number of pages

Modified channels/jamendo.py from [20207c9ed8] to [0db1a39017].

15
16
17
18
19
20
21


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







+
+







# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAwNJREFUOI1lk0toXGUYhp/v/8+ZzDQzmdZMZ8YSkxIQCWTTYsALLsQsUsWFQgJeEJQqIigUvBK0FBQULIJKMEKrFjdOW9xoW1AbRdRCEYtd2GCxxUQbk8bMrTNnzpn//1xMLYLv6l2877N7oBcB0GMY
#   IAUY/p9w/glCrVzby3+LVqaxM4dx+inQV7KIHcKYAbzG4FYgqcmudYBAF+jKnT2QAExPYysVHCdKRQgewwRT0B1FfQboYsLLeE7hk4Oo/iD3rFit4GQGRCsYwJMt7yQVfrS6Go3HUQtvskiwCWM82qlijGdbaUsbTV5G/X65+y+rCzgBRI+VbsSmvvltqVkuX78t6rvpKWtvuMsgOfHtJia66OPz
#   86564UtDkA2Lm/VJYF6mLgXo50X0xNAHy4cK2jk+diVe+1FVVX/57oIuL66qqmriVF23rZ1TjyTLH2YT/WJ4TY+XRgAMKqNgJ41vebbvTgeFneo6Tb567zPmHn+LxdPnCIxHTFrt2CtB/8BWqtVOAewDWgGDmHG0u1VtztjC7SLqRSUkM5Clsd5ibs/7nDzyLd51xfQPq82PKS5SsHfQAEMsIZG3
#   khgvJqUqBhFBnSeTS1O/XOPou0eoVxuIsfgkRDsqxBIQgaEVXyIyTVdvGFdbQlD1LibpJDTWG9w8NcHsgRfIb8ni4qbIxhISGU87+Z00BMTuDPhfg47b4X4+oHZ4VxiksxRHi9x3y71M7p5EjAWE6OxBkj/OaSqTgyvJUUIQncuDDx6qRsHHLqpHuR0PW3vbbCj5EYyAAq7dgMVPfHRytt2Kkv7i
#   5vAw0n1wZuFvFcDq/kGP5/X1tnm+2aiTLQy59MiE00wZ49okK2fNxsWfgnRfmvJA8D3E98tztTWdBtG9IPuw+tqgI+RRTLin1miNJ3EkRhQFxIRcl8+tgj9EN35VXqrV9G2MPIPvWfgv5I1Bh/pNBOGtYCeALEKM6nlc52uUP+XFDfRpRN7psa/ZeBWSAmJ99qrQGaANeJA3AUjpXhLZ1zsD+g+5
#   Cnd9pANrngAAAABJRU5ErkJggg==
# extraction-method: json, custom-mime
#
#
# Utilizes the Jamendo /v3.0/ API now completely. That means all tracks will
# be available as Ogg Vorbis per default.
#
# Radio stations are a fixed internal list. There's not much point in querying
# the API for them. (They're really just automated playlists, and MP3-only.)
#

Modified channels/links.py from [f73313d581] to [2ae7536a04].

19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
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"
    module = 'links'
    meta = plugin_meta()
    
    # list
    streams = [    ]
    default = [
        ("stream", "rad.io", "http://www.rad.io/"),
        ("stream", "RadioTower", "http://www.radiotower.com/"),

Modified channels/modarchive.py from [2703341090] to [505241c688].

11
12
13
14
15
16
17


18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26







+
+







# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAy1JREFUOI01k0trXGUAQM/33W/unblz55VJk0wekzSdaTtJ2oh0YRBEUCtUWoug4MKl4EoEQf+FoAvxDxhwo4uIoiBSH8GABElL0zQPnbyaRzMzSSadua/vc1FdnOXZHDii
#   dvsjg5BISzJWsJgaLYKwWLi/ye6pAAyFbJpnL5cRAta3D9nYOUIKAFChBuKAmUqWl65dolar0d9X5NXNXd7/5BuCKGbi/AApJ0EYxUxdGEJZFiv1PRKWhcrLJ8xMlrj1yvNMTF5BSEng+7R9gx+G9BUL9OQy+EGAlJIgihkf6qX+6IggjFCvz1R4+603yOYLRIFPfWuX
#   2W/voGUCN5UiiU8UdBDSJo5jHDvB0XGbMIqRUqL+WD/m6mod295jZWOTi6P9JIIWXu8QKUcxPWwzPuCxtNUmn3Fpnpxxd20HrQ1Sghh/7UNjy5gghvI5j/duXsNzHUQyzxezc3zwzg2Gh8t8Nvs9ey2f5Y0d/DBCWRZCgFSWhZ1MU8jn6fgRzdYxynG5dGGMmy88Q6k0
#   SMZzaZ52WFrdxk3a5DwXKQRxbFBXKkP09WRQlsRozc5Bk3J5hHTK4cb1F1HKJmkrJqujWMqmmM8QRTFBGLG+fYgaLRWJtUbrmISTZL/RwnOTfPXdr0xXB8nlciSUxI1aVIqSZvcMIxw816E2XkKFUYQRAokgDCO8dArfD/npz4fUd/c564acz2qmJqqkvDySmLnflwli
#   SRxrpDGgpAQhSNoWh6chc3cWKWRcrFSWMPCpjJX4+d4+n389D1JxtTqC0ZqTsw7ywT+PCMIIP4h4WN9j4f4Wvy0fkM+l6XZ9elKSSvUiipjmwQ7NZoNSfy+NVpvVzQNUfa/B49YZWms6fog2mr7eAo5t0zo5pVz06Osf4N03X+b6czVGR4aZv7vB/NI6aTeJVFLypBvQ
#   8UMSCQsQZFwHEAijGRk8h207fPrlj2wdthkq9dNotQkjjZISpY1BSoExoLXBmKcoSxBr8ENYvLfKDwsPWPt7k8nxAX5ZXMFOWERaIy7f/tj8L0n5tGzWSzJdHcZNOihpOGic8tfaI4TRZNM2j4+7yP9+/hd7YWLXivTEWgAAAABJRU5ErkJggg==
# extraction-method: regex
#
#
# A genre browser for tracker music files from the MOD Archive.
#
# MOD files dodn't work with all audio players. And with the default
# download method, it'll receive a .zip archive with embeded .mod file.
#
# Configuring VLC for `audio/mod+zip` or just a generic `*/*` works

Modified channels/myoggradio.py from [459b01f587] to [48b975db1d].

12
13
14
15
16
17
18


19
20
21
22
23
24
25
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27







+
+







#    { name: myoggradio_morph,  type: boolean, value: 0,  description: "Convert pls/m3u into direct shoutcast url." }
# priority: standard
# png:
#   iVBORw0KGgoAAAANSUhEUgAAAAsAAAAQCAYAAADAvYV+AAAABHNCSVQICAgIfAhkiAAAARdJREFUKJGt0U8rhFEUx/HP3AfjT9QQJo80CyzGG1A2UspL8k4s
#   7G2lvAlLC0skEWliMJTHM2Nx72iSjfJb3Xv6/n7ndA5/UIWz/jtDGZ9rqXQGAT30+vAE6njA80DYCObQxe1QTFdPhlFc4D0lzmMGn3gJGEtQhipFg80a53Uq
#   syksoBYiIMRiNeMw5+GA3S0m+50rqIY0T1LZY6kga5N34v9b3ZDmK6Op7JI/Eu6ZvqMsEthDJ+ADTxEeLth/o5jheIjJdgr6QCsk531cWeOWo0W06KwycYcX
#   3KAI6QAlzSvWX/ncwDWaTNVoXiaDyo+LbmMHp2jEDvb6S8gGwBVs4SRBN1jAOC5/hMrF0w5qHMu/TPDP+gI3M01h2io9UwAAAABJRU5ErkJggg==
# extraction-method: json
#
#
# MyOggRadio is an open source radio station directory. Because this matches
# well with streamtuner2, there's now a project partnership. Shared streams can easily
# be downloaded in this channel plugin. And streamtuner2 users can easily share their
# favourite stations into the MyOggRadio directory.
#
# Beforehand an account needs to be configured in the settings. (Registration

Modified channels/pluginmanager2.py from [6958917597] to [7d11864bfe].

11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25







-
+







#   { name: plugin_auto, type: boolean, value: 1, description: Apply plugin activation/disabling without restart. }
# priority: extra
# png:
#   iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAJ1BMVEUAAABNYQVcdAx1iTB6mQ6KsQGUsTCUuxGmyDKvzEK51FnB13LP3pnSUwRYAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsT
#   AQCanBgAAAAHdElNRQffBQ4EMidI8LXfAAABGUlEQVQoz32NPU7DQBCFx4aOxosIIOzGlkWRiogGkBssRfQoK/cxRBwAaw6AhJcLoAwtlTdlKtiSMj4U++PIBiReM/O+mXkD0ImdMxhqp23bsyHINkp9/Qu8TLXBj5BMrfsp
#   08rk2hT7KtIf2o1cmWJzIqU+pVVD9i6SW9Ev0BC9D0FDSzEExouyB0QkLGAQunMSL7IuwVNB+EZu/Bw/lLAnJ1fa6nOBT3CZQ0irDzsWiHo/gLFwqhFxbl6Me+/AiXhdmnUHfIBDMb+onccZnE7AXwTHncfH5CYHSGALeHGH
#   tybGAr7gFS8KC464Vs7Se84dGGlvmvQPqAZgFoM/7QYwQqx0fIoFuo0DE3oNuzbbgP1EKwDPlPgb5NefnUHe3aAAAAAASUVORK5CYII=
# support: experimental
# support: stable
#
# Scans for new plugins from the repository server, using
# a common-repo.json list. Compares new against installed
# plugins, and permits to update or download new ones.
#
# User plugins go into ~/.config/streamtuner2/channels/
# and will be picked up in favour of system-installed ones.
44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
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__
    module = 'pluginmanager2'
    meta = plugin_meta()
    parent = None
    vbox = None


    # Hook up
    def __init__(self, parent):

Modified channels/radiobrowser.py from [f73f375ada] to [b21d774715].

20
21
22
23
24
25
26

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







+







#   AAAAYHRSTlPJ4/Hz8/Lx7+3s6ufi08N9/fve8/bo//T8/vb6/fr67eL02vbc9/Tt//3v/N34/5aO/MWeoM7Rbene+f7E0PykaWqx3K333/v//Pv7/eD34Z/m7O3v8fL09vf5+vv8/9Pw7ECfAAAAAWJL
#   R0TAE2Hf+AAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB98EARcyBebz0PQAAADXSURBVAjXAcwAM/8AAAECAwQFBgcICQoLDA0ODwAQYBESE2FiY2RlZhQVFmcXABhoGRobaWprbG1uHB1vcB4A
#   H3Fyc3R1dnd4eXp7fH1+IAAhf4CBgoOEhYaHiImKi4wiACONjo+QkZKTlJWWl5iZmiQAJZucJiconZ6foCkqK6GiLAAtoy4vMDEyMzQ1Njc4pKU5ADqmOzw9Pj9AQUJDREWnqEYAR6mqq6xISUpLTK2u
#   r7CxTQBOsrO0tba3uLm6u7y9vr9PAFBRUlNUVVZXWFlaW1xdXl9emUehk/NThwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNS0wNC0wMlQwMTo0OTozOSswMjowMH98i/gAAAAldEVYdGRhdGU6bW9kaWZ5
#   ADIwMTUtMDQtMDJUMDE6NDk6MTcrMDI6MDAcO09kAAAAAElFTkSuQmCC
# x-icon-src: openclipart:tape.png
# x-service-by: segler_alex
# extraction-method: json
#
#
# Radio-Browser is a community-collected list of internet radios.
# Currently lists โ‰ฅ4000 streaming stations, and tracks favourited
# entries. Furthermore includes station homepage links!
#
# If you change the categories between tags/countries/languages,

Modified channels/radionomy.py from [a15a6d5e39] to [05a66c0287].

10
11
12
13
14
15
16

17
18
19
20
21
22
23
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24







+







#    { name: radionomy_pages,  type: int,  value: 3,  category: limit,  description: Number of pages per category to scan. }
#    { name: radionomy_update,  type: boolean,  value: 1,  description: Also fetch OnAir updates about currently playing songs. }
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAACXBIWXMAAAsTAAALEwEAmpwYAAABIElEQVQ4y62Uv0rEQBCHv/yRQziJ1bYWV/gCaxrhGrtrg1f5GMc+xOKLeIetVjZXHRrwAewstxMWFDViM5EQcrk9yTRJZn+/j51h
#   JhESypZnwAKYAWP6wwN3wLUz+gkgEsglsOR/MXdGryK5yaMk34ECWAPVFmMCTIFb4FByeSrl1JDMGf0VcIt7ZcsMeBPYIpaeABSBEABEW8jnLG00dt0WK1ueSikvwDnw4YzeNCS1Z5w2klULkgAb4Bh4AC7kKOrypDsq+JHnBDgBRtuE
#   aWBLrpzRr32COBD0vEsQCvocCsQ+oKTj/Ehm5rtnyv9AXt6nrYGrgKyxBl1Re3ykbHkDzPdcEZQtDxorshxsaQf7jcTSjxWQC8wHmL1oc/HyC1/TWBfFRR9xAAAAAElFTkSuQmCC
# priority: extra
# extraction-method: regex, dom, json
#
# Over 6500 radio stations of mixed genres and from different
# countries.
#
# Radionomy is a commercial radio hosting service. All listed
# stations are actually hosted by itself. Public and free access.
# And stream hosting is free as well, by adding advertisements,

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

1
2
3
4

5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
1
2
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20



-
+








+







# api: dbus
# title: RadioTray hook
# description: Allows to bookmark stations to RadioTray
# version: 0.3
# version: 0.4
# type: feature
# category: bookmarks
# depends: deb:python-dbus, deb:streamtuner2, deb:python-xdg
# config:
#   { name: radiotray_map, type: select, value: "group", select: 'root|group|asis|play', description: 'Map genres to default RadioTray groups, or just "root".' }
# url: http://radiotray.sourceforge.net/
# priority: extra
# id: streamtuner2-radiotray
# extraction-method: xml
# pack: radiotray.py
# fpm-prefix: /usr/share/streamtuner2/channels/
#
# Adds a context menu "Keep in RadioTray.." for bookmarking.
# Until a newer version exposes addRadio(), this plugin
# will fall back to just playUrl().
#
35
36
37
38
39
40
41
42

43
44
45

46
47
48
49
50
51
52
36
37
38
39
40
41
42

43
44
45

46
47
48
49
50
51
52
53







-
+


-
+







import re
import dbus
from xdg.BaseDirectory import xdg_data_home
from xml.etree import ElementTree


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

    # plugin info
    module = __name__
    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")

68
69
70
71
72
73
74
75

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

76
77
78
79
80
81
82
83







-
+







        # keep reference to main window    
        self.parent = parent
        self.bm = parent.channels["bookmarks"]
        conf.add_plugin_defaults(self.meta, self.module)

        # create category
        self.bm.add_category("radiotray", plugin=self);
        self.bm.streams["radiotray"] = self.update_streams(cat="radiotray")
        self.bm.category_plugins["radiotray"] = self #.update_streams(cat="radiotray")
        self.bm.reload_if_current(self.module)

        # add context menu
        uikit.add_menu([parent.streammenu, parent.streamactions], "Keep in RadioTray", self.share, insert=4)
        

    # load RadioTray bookmarks

Modified channels/reddit.py from [02442ae6d3] to [cfb66a69eb].

10
11
12
13
14
15
16

17
18
19
20
21
22
23
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24







+







#   { name: reddit_pages, type: int, value: 2, description: Number of pages to fetch. }
#   { name: filter_walledgardens, type: boolean, value: 1, description: Filter walled gardens (soundcloud/spotify/โ€ฆ) if there's no player. }
#   { name: reddit_keep_all, type: boolean, value: 0, description: Keep all web links (starts a browser for websites/news). }
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJ1BMVEUAAAAcICX/AABHSk1jZ299hYz/bmajq6//lY/d0M3C1+3T7P38+/iaLhuGAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF
#   HUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffBRUXIyQbWArCAAAAh0lEQVQI12Pg3g0BDLtXrVq1eveq3Qy7gIxCU9dqEGO11/ZKbzBDenUIUM3u7cGi1UDFW0TE55wsdpZikAw/
#   eebMnMmHGVxqDuUc0zzpynD4zIk5J3vOSDNsOQMG1gy7bI5HTq85Ws2wu/jM9PIzrkArdhmXlzuuXg00eVd5+epVqxmgrtgNAOWeS1KYtcY4AAAAAElFTkSuQmCC
# extraction-method: json
# priority: extra
#
# Scans music-related subreddits for MP3/Youtube/Soundcloud
# links.
# Those are usually new bands or fresh releases, or favorite
# user selections. The category/subreddit list is filtered
# for a minimum quote of usable links (namely Youtube URLs).

Modified channels/shoutcast.py from [f2e0c497b6] to [68512fd7c7].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







# priority: default
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAelJREFUOI2NU0toE2EYnM12t2wLkhSXSIgEJMHFQ2naQ+kpoPYQoaXH3gRFsegloUhRQTyU2oOgggQUzzlEQomIBzU+EHooBIol0cOGLqFFFiJ5SB5skvFU6ebRduA7/DAz
#   /PM9BJLoh3Q6zVQqBZfLhXq9jlAohHA4LHTzhvqJ2+02c7kcgsEgfD4fRFFEPp+HZVmUJEk41kAURcHv99Pj8cAwDGiaBkVR0C0GAJDsW7VajYVCgYlEguVymZZlsVKpcG1tlYd5fX8AAIqiCF6vF6VSibIsI5lMYvvDE1xymwDu/ec5BhkcIJPJIHJzFqf372P1cgMf
#   f46cLIKu61yJXufr5VO0voyzEZ/k8sI4s9ns0RFarRZjL56inIshekWGenYS6IzhR9PCntRBIBCw8XsiFItFNLMxPJgfwVjDi4Y8g2b9DILaMKZGd2Ca5tEGiqJg2xjF200H6J+AvKtjeG8T3998xW5nAk6n08bviSBJEqhewLlpN4bMHfwxfuH5J8J98SGerS/B4XDY
#   d+FwQ6rVKm8vXeP++6vku2lu3FEZubFIXdc5qNm2x93ILZobszRfaYwuaIzH4wOFfafwt7CFb59/Y0uYx8rLR1BVtXd1u2AzCMwsQg6cx+O5uWOFBxAGnfNJ8Q/z/DNTtgbnsgAAAABJRU5ErkJggg==
# depends: re, ahttp
# extraction-method: json, regex
#
# Shoutcast is a server software for audio streaming. It automatically spools
# station information on shoutcast.com, which today lists over 60000 radios.
#
# It has been aquired by Radionomy in 2014. Since then significant changes
# took place. The former yellow pages API got deprecated. Streamtuner2 now
# utilizes the AJAX interface for speedy playlist discovery

Modified channels/somafm.py from [e683a6b30b] to [9c3d6cd3c5].

1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19











+







# encoding: UTF-8
# api: streamtuner2
# title: SomaFM
# description: Alternative radio, entirely community sponsored and non-advertisey.
# version: 0.9
# type: channel
# category: radio
# url: http://somafm.com/
# config:
#   { name: somafm_bitrate, value: 64, type: select, select: "130=AAC โ†’ 128 kbit/s|64=AAC โ†’ 64 kbit/s|32=AAC โ†’ 32 kbit/s|0=MP3 โ†’ 128 kbit/s|56=MP3 โ†’ 56 kbit/s|24=MP3 โ†’ 24 kbit/s", description: "Most streams are accessible in different bitrates." }
# priority: extra
# extraction-method: static
# png:
#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAA3NCSVQICAjb4U/gAAACpUlEQVQokQXBS28bVRQA4HvOfcwd2xNP7caFtgiqkoglKyhCiFZiUSGxQcACdkis2SGx5lcgumFXhNoNGwpISGUZMKJSGtooStM4teOJXeOZufO4j8P3wZeff7r3z32tRaL7g/7Ikq/qXKEI4BZ5HnzYiJQn
#    50IAxuIkFe9/+NXDP+9JVr++tX3jk2/I29lkV0fd0DY741+z7PC9dz7Ki9XZ8kSrDudKSIBExx3ulVJJL5UcvVkoob0zm8Nzoc0uXnq1Mcuko9NewnkkgvNaMQVCQWirugz4w88/nUyPPrh+M9a9SGAIbVXWPlSmEkIxUeanArnkrLbNepX9vffw2x+/Z2Rni7PP3n0rjuLkxf7R8b+tMVYwaKzIJvuc
#    WkRE1j7dvX/77u0QcKOz8eDxnjk+2L6QDtLfpARXGssKEcVYtQwYcsCuiP74a7zzaB8Yy03DibXWjg+nv/9yz9fsP+NO182ybIRrV5aIA5ONOTw65oJrJQhCX8sYsSH+ZDopns8coyZU3Em8NNrUinMZT56vD+azWAkF1AUAS8vWrwKtnTuYZ97Zui7XdYkXh30GUqDczcPl0ebLg0HlnQZERkikOGFX
#    GuCmbvOynq8KzMoakaNKFMY3r11LtbKOeQYKMCZ4+3xyNWbzower9Vyx0JOI+4/GRWvLgq4Mo1Haq6pcCXBAAtl5bj9+I7313ddfvHkuNpkpKxaskI1Z1rp4NqWtV2ZPT04sAeeFBy4Di8W4rLaeHe+sxJ395aqcXhiN4LXtq6fZGSAQV0gEzMed/mJxmiYi1mIyMz1WV6itZ8G1/TTlqHRZFGVpgrcI
#    GIL3ntq2aRpXGAdEXkgOgMgiKTqdSLz0wqDo8UAEwIjIGF/VNun2iBEAU0pcHkYdBdaT9bA5TP8H6318x/9OSuUAAAAASUVORK5CYII=
#

Modified channels/specbuttons.py from [8a8982cf89] to [89ccc02506].

34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48







-
+







import action
from uikit import gtk


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

    # Hook toolbar label
    def __init__(self, parent):
        if not parent:
            return
        self.parent = parent
        conf.add_plugin_defaults(self.meta, self.module)

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

13
14
15
16
17
18
19

20
21
22
23
24
25
26
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27







+







# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAA3NCSVQICAjb4U/gAAACmklEQVQokWXSy0tUYRgG8Pe7zBnzWk06RFGhoNAmBJuBbFDcNEoK4k5cxUQbYQYZBtok2L7NuGrpIlSkQNI004g8Ss1GuqAILjSkmNKD45k53+XM97aQpOj3FzzPwwNKKfkv
#   ISVKiYjT6+uJx48Lvl/WWgihlFJKgfyPL+UPKWefPPlaXz/JefbRI4kohZBSKqUoAJA/DKL0PMX52vh41ciIF48Xurtrx8ZezM5almWMAURKCDlJpbUGxGAg8FNKnJ7Ww8NkYqKyWLxLSGB5uQRAjQFCKAAwxjjnjDFKKTAW0nrm4sVgJvMplepdWfkFUBePVwAgIb7v
#   c0SklBrEsu8HOWfB4BfHqXGcbwMD8Vwux5gaHb0djxutgTGKCEopz/PcQsFTal+ImZmZifb2XYBdgFex2OziYgHxdEetNUilpOdJxDXbnr5z5wPARij0oKXl1cuXRURELCvlFosnPYUQRHueDAZzT59eSyYLUr7u6fkYDr+37ZvXr19uaGhqbu7q6mptbdVaI6Lv+5Ra
#   1tuFhWAqdcWYz/fuPa+qCjFWWy7Xnzv3bnU1nU53dnZms1lKqTEmEAjAMeJkOu0AfGxre7O/v72xoYTo6e7e2tpCxEwmAwA1NTV7e3vlclkIQSt9/0Yymevvt7a3ry4tVV66dCylYezw4GBnZ2dzc5NznslkwuGw1poQQoque6ai4oixQ9tumJr6VSjU1tU9XFo6ikaL
#   +fzZ8+cTiURHR4fW2hhDKeUIIJRC191wnHwkEmtqutDY6H7/fn9oKBqNVldXA4AQglJKCAEAcBxHKTU3NwcAAHArFns2NdXb15fP540xpVKpVCqd/lIpRbTWAICI8/PzrutalmXb9uDgYCQS8TyPcw5/IYT8BpJoukMEtogaAAAAAElFTkSuQmCC
# recognizes: max_streams
# extraction-method: regex
# url: http://surfmusic.de/
#
# This plugin comes in German (SurfMusik) and English (SurfMusic) variations.
# It provides a vast collection of international stations and genres.
# While it's not an open source project, most entries are user contributed.
#
# They do have a Windows client, hencewhy it's even more important for
39
40
41
42
43
44
45
46

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

47
48
49
50
51
52
53
54







-
+










# Surfmusik sharing site
class surfmusik (ChannelPlugin):

    # module attributes
    module = __name__
    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/"),
    }

Modified channels/timer.py from [a0ecd3dcce] to [3136ca6563].

34
35
36
37
38
39
40
41

42
43
44

45
46
47
48
49
50
51
34
35
36
37
38
39
40

41
42
43

44
45
46
47
48
49
50
51







-
+


-
+







import action
import copy
import re



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

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

Modified channels/tunein.py from [19252f8edf] to [d31231b5cf].

12
13
14
15
16
17
18

19
20
21
22
23
24
25
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26







+







# priority: default
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAbpJREFUOI2Nkk9PE1EUxc+ZuTMIaP+KqClxx4dA0jRVgwFM/JPIRv0CunDnxsQ1G4NGvgD7LkiExG5IDHFhDDEmblwRQJG2AVuwMNOZd91QAuUR
#   e1bvnnfeLzf3PsKioq6Dtf25xsq3Kdf3gkxh9OUis29tWcdm9iPxuvHl62MNQz/a+3uhVl56M647d7sGHOxU8hpFR7Uag9+l+UddAySdWuv0soWR710DXOj93mtDWxQBRTBwq7AcZfte2bK0mQCQ11X0I5lzEW2858BZMXBkZWkGqk8Atk7c
#   mBhqVCWV2E0MDz9dYLo8ptWbwdrP2aC6nSYhIOck2PiVdDwvfXxox9WqVAcPVtc/jOkm68uf56M/9T4AoAhMq5V06NCc2d+hNAzhwBttPz5q36FxchOT0xT5HwMEvRO1CHITk9MEgHHdfED4z4La9nmQqiY2dNywHY6b++d6h65OhVvVElw3
#   7rmY2VOE7xZ5pWTdwh2t52NEzwEeQtgTIXhR5uUfnVlr783m7vXGx0/32oOlCC7dLs4COAWwfiTH9+PTrrFnbWan6LkA/HLXAFckaJ+9bKYyeKP4cIEpK/wffVOh5FvT8j8AAAAASUVORK5CYII=
# documentation: http://opml.radiotime.com/
# extraction-method: dom
#
# RadioTime API uses OPML for station/podcast entries.
#
# Only radio listings are queried for now. But there are
# heaps more talk and local show entries, etc. (Would require
# more deeply nested category tree.)
#

Modified channels/ubuntuusers.py from [e3bc6f87a2] to [5e7bfb243b].

10
11
12
13
14
15
16

17
18
19
20
21
22
23
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24







+







#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACJVBMVEUAAACjeUWif2/CeiGhWTvUewuhQRjPeRCfRyK1hEeWYkynQkOJREW0Dw+TICC3DAyXRES3DAzXzMewhlOsahqtaxu3DAytaxu4DAytaxqtIiKqeTyaR0eokHKk
#    h2SjayikZhmdbC+SdVaXVz2fQhufQxyhaVGjjYKsdjS2jmXBUSS2UimUXUaybBXCRA+MPx+vbR2+RhWLSCuhe0vBiEGrZUiDX0+TREWzP0CgQ0R1RUWcHByqFBSDKCifFxesMDGKUVGfFxfIsqng3tvBhz+khmDLdxCYYiDLdxGaYyKfFxfLdxGaYyKfFhbMdxCZYiCfNTW6gHzEjki+fCqdeEifZ2eWKSmVGhqTMTGXaWexkWWrbR+rbB2og1Oo
#    mYbWfhDefwjQexHXRgnXRgrziAP/jQDvhAC7jV/YTBT3SAD3SADthAT5iADngAG8kmfRTBfxRADwRADEhjm4h0nGuay0fGW/YTnAZD21ODq6PT7BQ0S9QEG2OTq2PD3KBATSAADSAADRAADSAADSAADSAADNAwPUAADUAADPAwPPDA3QDg/QDxDNAwPVAADRAAC2SUmzjIWsf3CugXLVAADJAADBgH3Hm1/eiBveiBzVAADIAADAf3rMizb+iwD9
#    iwDIAADAf3rMjDb8iwD7iwDNAwPVAADIAADAf3rMjDb7iwDOAwPXAADJAADBf3vMizb9iwD9jAC6EBC/CQm0ERLggArggAr///+cj9kUAAAAX3RSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAZGJiK1ZiYlkJps315xim5xim5xh0+rQNdPq0DabnGKbnGKbnGOcY5xjnGKbnGKbnGKbN9ecYQGRiYitWYmJZCevlG38AAAABYktH
#    RLaqBwvxAAAAB3RJTUUH3wQMETciyGk1tQAAAHlJREFUGFd1jTESQUEQBbtnd+cXJxBwDiQSN3EwV5F+ZxC6hUAJlvIVJuya7ie48nWXOxVivtbRjaPRQWu6U4sBFaIMXSgGBEQ5Z2Zm1vr8qKaq9aXU/UT5avwCQG+E/gW0KWizheot39FUHT5Xjh5sBgjLbV9VT1ceE5sL4EiAe2YAAAAASUVORK5CYII=
# config: -
# priority: extra
# extraction-method: regex
#
# Short user-collected list of internet radio stations
# on UbuntuUsers.de wiki. Only provides a single category,
# but stations are grouped by country already.
#


Modified channels/ui_cht.py from [b9bdcb6542] to [d3d33c0fb0].

11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
26
27
28
29
30
31
11
12
13
14
15
16
17

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







-
+















import re


# Channel Homepage in Toolbar
class ui_cht(object):
    module = __name__
    module = 'ui_cht'

    # Hook toolbar label
    def __init__(self, parent):
        self.label = parent.toolbar_link
        parent.hooks["switch"].append(self.switchy)

    # Update link label
    def switchy(self, meta, *x, **y):
        title = meta.get("title")
        url = meta.get("url")
        domain = re.sub("^.+?//|/.+$", "", url)
        self.label.set_markup("<big><b>{}</b></big>\n<a href='{}'>{}</a>".format(title, url, domain))

Modified channels/useragentswitcher.py from [bebd1e46c5] to [8661193ea8].

20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
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 = __name__
    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",

Modified channels/xiph.py from [8274e75920] to [6b1f12f6e5].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







# priority: standard
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAg5JREFUOI2lk1tIE2AUx3+7CG1tlmlG1rSEHrKgEUF7yO40taQiRj10I4qKkOaT4hIUItuTkC8hpJAQtJCICrFpzEKw
#   h61eQorGNBOTzbEt16ZrnR5Wq3mZD/3heziX//983znngyyov+eSbHEA5WKBhs4BKVy9gsqajqwiCwo0dA5IQX5u2s4moliMPPV1nCeDzxgNBFDHE2wsKMPzsGVefobjcnO7RMfeMuL341ZBrNEGRmPqqjdvsbbf
#   w7irO4Oj+rdywNNNucmERsLUVndR8uYRU13PCew6hpgP8W02xMpIsik++qk5oweW6y3yob8WnXacZDKJWh1Cp4OtRUHsh19TUlUGViv09RGqKAenU5QnLKm+rK88LjgcUnxmr/h8iNO5XYJBRAQZ/qiVeptGWjty
#   5cClDWLwugQRIRiU5UdPCoD6S89jhV6pks9WG6fuwtBtF5v72vC1v+B86SsM+jD56hjnyiM0lRrAbofeXjQJLdE/78jbXSU5166I6f5VeeDdKdq6GtlSd0QkVU+8XsQhlt9W6izbZ5aMKWgtp2WT/yUHd0xSYU7i
#   dsPQ+1WMKIsJD08wEV2HGLeRyNMjawqRxhuKBfdgz1m7fI/4mVX+ZGxmgniOoJv+QZHGAMC7p60ZnHkC8HfzZmLTBCd9af9ccnqMc9HTdmFe4kLkJbH/4h0xVtcu+SP/C78AL6btab6woPcAAAAASUVORK5CYII=
# extraction-method: xml, regex, json
#
# Xiph.org maintains the Ogg streaming standard and Vorbis,
# Opus, FLAC audio, and Theora video compression formats.
# The ICEcast server is an open alternative to SHOUTcast.
#
# It also provides a directory listing of known internet
# radio stations; only a handful of them using Ogg though.

Modified channels/youtube.py from [5f9e55387f] to [f32eca050a].

13
14
15
16
17
18
19

20
21
22
23
24
25
26
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27







+







# priority: default
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAYNJREFUOI3Fks9LVFEUxz/nzrPx+WN0xhAUgoT6A6y/wFb+C4IbIQhcBm36H1obVNtoGYS0TFoIQstazBgNBaELQdTx
#   vea9uffbwufw3mTRzi8cLnzv955z7vccuG7YXmtyBlgBbgFTQB3Q3/RAHzgD9oHdyMNTg01gshD8DwScCJ7bx+bEN7Cl0Xt5D2aYc//Iq67LYDFHXEamgGZmmd94SHzvPoMoIguerKQZamExykS9kjQIN3eThcdP
#   WAiBo/fbHLx5Te/LZzQYgFW6qbsMKEcf+CWRpCm+2aK5ts6drZfMP9okH4/pSxV91NeI4RLmA0mS4ns9JHGaJvzMc1Lpwo3Smyi7wl6FwHmScNzt8mPnA4fv3lLrtJkIHqt+AXvViFPB+JCQ0HQDrTyg127jvu4T
#   D3Jqzg0LDLWQ2lYj7oDulmlJZCEwZuD+GGMlRae2eiNqeVgOUA9AAAuAmSEzCq4cKs5TwYvIwzPBJ+A2F2s8XZQcXedL7qwY1neDHa4dvwFfDLdx6YbozgAAAABJRU5ErkJggg==
# depends: bin:youtube-dl
# extraction-method: json
#
# 
# Lists recently popular youtube videos by category or channels.
#
# Introduces the faux MIME type "video/youtube" for player and recording
# configuration; both utilizing `youtube-dl`. But VLC can consume Youtube
# URLs directly anyhow.

Modified contrib/cachereset.py from [4ffd1ffb9c] to [8b61178eba].

21
22
23
24
25
26
27
28

29
30
31
32
33
34
35
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35







-
+







import os


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

    meta = plugin_meta()
    module = __name__
    module = 'cachereset'

    # Register in configwin
    def __init__(self, parent):
        # hook
        if not parent:
            return
        parent.hooks["config_load"].append(self.dialog_update)

Modified contrib/continuous_record.py from [8b1442273b] to [db37b9587d].

25
26
27
28
29
30
31
32

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

32
33
34
35
36
37
38
39







-
+







import action
from config import *
from uikit import *
import os, os.path

# Stop button
class continuous_record(object):
    module = __name__
    module = 'continuous_record'
    meta = plugin_meta()
    parent = None
    rec = None

    # exchange button and hook
    def __init__(self, parent):
        self.parent = parent

Modified contrib/delicast.py from [3740c184eb] to [1da3b76466].

9
10
11
12
13
14
15

16
17
18
19
20
21
22
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23







+







# config: -
# png:
#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAA
#    AmJLR0QA/4ePzL8AAAAHdElNRQffBB4UJAsX77G0AAAANUlEQVQY02OwQwMMdv/BAEUASCFEoAIIEZIEIGYjBCAUwpb/6O5ACEABGQJ2cFsQIlB3oAEA6iVo+vl+BbQA
#    AAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDQtMzBUMjI6MzY6MDMrMDI6MDAFLUvfAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA0LTMwVDIyOjM2OjAzKzAyOjAwdHDz
#    YwAAAABJRU5ErkJggg==
# priority: rare
# extraction-method: regex, action-handler
#
# Just a standard genre/country radio directory. Not very
# suitable for extraction actually, because it requires a
# second page request for uncovering the streaming URLs.
#
# This is done in row(), so only happens on playback. Which
# of course won't allow for exporting/bookmarking etc.

Modified contrib/file.py from [c5a4a98a96] to [63bdb9da05].

14
15
16
17
18
19
20

21
22
23
24
25
26
27
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28







+







#   iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wUFDQsK23vYngAAA6lJREFUOMtFz8tu1FYAxvH/sc+xxx7bM8lkElAgISoV4qIgpEaomwg2bMqiQmo3lfowPElVVbQr3gBVqGJRGi6VEERFDROS0Ewmc/N47Bkf+7gLevke4Kfv
#   L374/vufxm/ffjnudJQoisoVonLDcN+sr39z7uXLXzfOn6cRhmSTCf3TUwa9HoN+H601ynXxwhA7ivhdCH48PkZOut0vdh48cKtej9C2iSyLsF7/xLpx4/5eu/1LZzSiaQx1z8O5cIHapUvVmpRkaUqcJMRpSjydmnEcP/2zKH6WOs/7mdZBVVXIqsKuKk4nE4qdnTueUncCpZh5HoHj4AqBVRQIrUFrLGPwlaLhOLiWtX93OPxKIuX+0HHWJ5ZF03VxpaRfFLRmM1rTKUGrRX1piUYQEIUhfhRRC0OqOMZxHIIwJIgiHFj77OnT+7KEd0Wt
#   tl0Kgev7NHyf5apCTSaoLEMlCZdu3uT85ib1hQWi1VWcMCTb3cXxPJxmExlF2LWaMFpvS4TYcx2nmpalsKoKJQSNMCQ6cwZPCMxgwKTbpfPoETWlWDx3jtblyyghEFpjSYmwbYQx6DyPJUJ0bKUKU5Yqn83QSqGVolQKGQSEGxssrK3RffyY6Zs3zK9epb6wgBWGCCFQjkOlFFVRoIfDkTRwYIRIDTR0nqPnc7RSFP/AhW2jfJ/WlSvQ7zPe3SU9OECdPYuwbUrXxSiFsW2KOB7IaZYdp3keV9DQ8znacSj+RaWkqtVACExR0NrcZPriBflw
#   SJqmWO32R9BxMEAxnfatJE37cZb1jWVRaP3x4XxOkecIy0J6HibPmY1GqHqdpa0tbNdlvLNDfnJCOR5jJhPMYECZpj2JlPEwSbqBEFTG/Jd85fZtNm/dIjk6Itnbw19e5tN79yiHQ5JnzxgfHDBrNvGjCOM4lElCkWWn1ufb2/M4TQ9LIQAoiwJTlrQ3NrCVQjoOw04Hf2UF5ftI3wchsOt1Zu/eoTsd9KtX5E+eYCaTnux2u1VRVe8N/y/PMn57+JBka4v04IDs8JDD+RxGI8RoxPz1a6yyJJ/PGT9/rivXzZRSp3m9/kYAtFdWvm3PZt+1
#   kkQEtk1g2wRSEihV+badR7Va2vS8ceR5A9uYrimKv/LZ7MhU1VF7efnD2sWL3cb6+slzrT9IgKXFxT8W07S33GpZywsLHxzLep/Gcac3Gu0H9fp7Z3X1KLp27WT9+vXh8epq8vXdu7N+FPG61UIXBXZZAmCVJX8DADze5LjPkMQAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDUtMDVUMTU6MTA6NTkrMDI6MDBD/PY6AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA1LTA1VDE1OjEwOjU5KzAyOjAwMqFOhgAAAABJRU5ErkJggg==
# png-orig:
#   https://openclipart.org/detail/168001/folder-icon-red-music
# extraction-method: os
#
# Local file browser. Presents files from configured directories.
# This is not what streamtuner2 is meant for. Therefore this is
# an optional plugin, and not overly well integrated.
#
# Bugs:
# Only loads directories on startup. Doesn't work when post-activated

Modified contrib/glrp.py from [698577c08b] to [9e8e02156c].

12
13
14
15
16
17
18

19
20
21
22
23
24
25
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26







+







#   REFUOMuFk7trVFEQxn9zz9nc3Tw0CstGkCBoUHfhRgyIoF3wkRAUxEUrK7ESSWehFgpqI8TCTtQ/QCsLSSFisFFUSClBQzCJaPBBYkx2c+89Y3GyeW2iA6c4Z4Zvvvm+
#   OUJZ4bHwYUrtpae0B0JGQVk/RB3p6U4mLhyQSuGGIgCqmokGeA3sEsHwr1Bc7Ph2rIMjd0/KmKiqRAO8SpVDqmANtIQwPQ+xAyPr0ABU+Nh/mEh6H2j7+DTDiWMLgA1g
#   ayOUCtBg4MUnmK1CaFeDGKG6Ocd+GztCgUwtEQikDt5NgAmgby9kLQx/gckZ+DXvWTkIZxfIWGSRExCn8KgMzaG/5yyoQCWGc10wtwDXn3swI75ZsKSNQqkNOvKLGlTg
#   9ku4OgijP0AEchk4UYR0hUe2ThyFhRTOP/GFArwdhzt90LXd51dGsFbhQODNZ5iPl2k2WBgc8ZrU1dfb7EepJMtvczFEbeD0PwA1evkmuNYNrVnYlIXju6EcQeLqASzq
#   24rAyHffOTRwphN69oBz0Jrz3fONMDS6vFyqYEWIFZKaiEfvQ7Gw5Owqhb/O+F1oMBBAksuQyu+q2oP3eK9KpGtGWW+Ha2vjYPJUiWLQEkrSvZNehDEjpCIQBBsc74pT
#   mNrXxtlbPTIjTVeUPzeFy8+0eWiUHdUEg2z8GY3gom1MPizLTy4qfwFNC7cqp8RdxgAAAABJRU5ErkJggg==
# priority: extra
# extraction-method: csv
#
# Imports the playlist CSV from Great Little Radio Player.


import csv
from config import *
from channels import *

Modified contrib/gtk_theme.py from [b5df3c1053] to [c94ca7aa89].

26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
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__
    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)

Modified contrib/housemixes.py from [34d9935a73] to [1b91e8da1a].

10
11
12
13
14
15
16

17
18
19
20
21
22
23
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24







+







#    ( -x-off-name: housemixes_pages, type: int, value: 5, description: maximum number of pages to scan )
# priority: contrib
# png:
#    iVBORw0KGgoAAAANSUhEUgAAABQAAAASBAMAAACp/uMjAAAAGFBMVEUIBQE7KCGSPABUWFrwcACIkJayuLr3+vjaVnR4AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMB
#    AJqcGAAAAAd0SU1FB+AKCQwWONCoEiQAAACPSURBVAjXLY29DsIgFIUPxehaExJXW+EB7MJaCE/gAKvRaNdWYu/rewve6bsn5wcARN+3KNeE7hgq60t8X30Rx4mIhjOj2tMr
#    UnaMPmXAUsPiSBwRdHMcWtEKpIdHMFk7FQ6fAG0WPe46OXgos9QhrpC5jm576wayvBO0x7Pgaebee0HJDlv9sN80/xGxOH8QkRfKLi9RvwAAAABJRU5ErkJggg==
# depends: pq, ahttp
# extraction-method: dom, action-handler
#
# House-mixes.com is an UK platform for DJs to showcase their
# house/dance/techno mixes.
#


import ahttp

Modified contrib/listenlive.py from [c1d1551be3] to [42518d754d].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAARVBMVEWdHBWSg1Cbj1mnmF6jn5GuomajpaCrqYu3qmy0roi6
#   r3rAsW25tae2t7HCvKfPv3rOw4zKxrfJyMDTzaXUz7LW1s7g4t727CdZAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJ
#   cEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffBQcAMynMUk7PAAAAkElEQVQY01VP2xbDIAizUq0WGS1e/v9TB9qdbXlLICE4
#   Z9g8gN/cB1tAVmB4JI98tdbqlZJ/eBWS3u8jTCVx7RRNKEdKzgFffVBUfpdyItjCGJG6iCqZk0Nuo6tDiIp6cAqiDokx7hZi
#   Fo3QBSp7xmChOhSxjNfJsM5OaKadncWWkL9V/6rrc7Ceg59/vWLRN2yqCjHMvARcAAAAAElFTkSuQmCC
# png-orig: https://openclipart.org/detail/148465/1-euro
# priority: extra
# extraction-method: regex
#
# And another radio directory, primarily collecting euro
# stations, mixed genres, and grouping by country.
#
# Also available:
#  http://www.australianliveradio.com/
#  http://www.nzradioguide.co.nz/

Modified contrib/liveradio.py from [d6d8086730] to [60d876bcc4].

9
10
11
12
13
14
15

16
17
18
19
20
21
22
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23







+







# config: -
# png:
#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABB0lEQVR4nLWTQUpDMRCGv0lregDBI3gAfW/hRrp8ZOMh5PUMXkFcu7EbTxHd
#    CC4EhfQkQg/QR5txYQqvMdVHwdnMZJj555uQwH+YurpaNZUOqTWl5i5qGIusDxIAZgBGuBhCsiOgrq7WUa+tkReAjepHystQgmn8zt0As40y
#    skYa4HwfSS5w2otd8svtWurqHyvnCZcXAHRRW7v8nANnq6bSPk0ucFQS+M3G2fkduMqLrJF5d3zSTnyYATsXmhO89WLfix8A1NWjvwhek5+m
#    praLGibPC8knFwnEh4U1ct9FvUvoLk0uPbjiCgCPyd+KD0/WyKX4EPcJFLG2/8EaMeLDoE91sH0B3ERWq2CKMoYAAAAASUVORK5CYII=
# priority: extra
# extraction-method: regex, action-handler
#
# LiveRadio.ie, based in Ireland, is a radio station directory. It provides
# genre or country browsing (not in this plugin). It accepts user submissions.
#
# This channel loads their station logos as favicons, provides a live search.
#
# However, station URLs have to be fetched in a second page request. Such

Modified contrib/magnatune.py from [0577bfd522] to [b928142549].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







# png:
#   iVBORw0KGgoAAAANSUhEUgAAABIAAAASBAMAAACk4JNkAAAAMFBMVEUAW5kAY6ACa6MVd6sWgLE2irdHmcBdpslvrsuEudWY
#   xdmiy9+21+fO4u7z+fz9//wtPja+AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB98FBhQ2G9ph
#   h8MAAACySURBVAjXY/j//22rccS9//8Z/v9NVAl1ErsPZB0W2/vudqLPf4a/Ruv+lf9/qXyf4ZnU+79O//9Pime4mPf/j9H/
#   /1+tGYr2//tj9O/dH3EGl/vHzhr9yf1nyqD6vqjW6AfXu2AgKwnIkvoXDJSFsMyAOkCyUkAdF/MTaw1/cAFNeSZ1/d6sv3VN
#   cQx/neb///f/BdC2/0dEz717E2QLclWycKihGchV/99Mc8k89/8/AD9dZbS2m1Y9AAAAAElFTkSuQmCC
# priority: extra
# extraction-method: regex
# 
# Magnatune is a label for independent music. It provides
# free access to a partial section of its reportoire as MP3.
# Using paid subscriptions, all albums are available in
# higher quality Ogg Vorbis or FLAC encodings however.
#
# You can listen to all albums and tracks freely. They're

Modified contrib/podspider.py from [d384743d3e] to [6724c28afd].

1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19











+







# encoding: UTF-8
# api: streamtuner2
# title: PODspider
# description: lists Podcasts RSS from proprietary podspider xml database
# version: 0.0
# type: channel
# category: talk
# depends: lxml.etree, pyquery
# url: http://www.radiograbber.de/
# status: unsupported
# priority: never
# extraction-method: dom
#
# Podspider is one part of the commercial Windows "Radiograbber" software.
# A demo version is available from http://www.surfmusik.net/downloads/download.php?pid=13
# and runs under Wine.
# It downloads a "Podspiderpdb.xml.tmp_", which this plugin can display as
# streamtuner2 channel. The contents are a pre-classified list of PODcasts
# via RSS feeds. It needs some rework to strip out excessive duplicates, but
54
55
56
57
58
59
60
61

62
63
64
65
66
67
68
55
56
57
58
59
60
61

62
63
64
65
66
67
68
69







-
+







    return ""  # empty string if nothing found


# PODlist from Radiograbber
class podspider (ChannelPlugin):

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

    # data
    config = [
    ]
    xml = None

Modified contrib/prefstore.py from [e5b03874ae] to [32a9e10322].

19
20
21
22
23
24
25
26

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

26
27
28
29
30
31
32
33







-
+







import re
import json


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

    module = __name__
    module = 'prefstore'
    meta = plugin_meta()

    # Register callback
    def __init__(self, parent):
        if not parent:
            return
        self.parent = parent

Modified contrib/publicradiofan.py from [27f032530a] to [912394ee7c].

12
13
14
15
16
17
18

19
20
21
22
23
24
25
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26







+







#   iVBORw0KGgoAAAANSUhEUgAAAA8AAAAQCAMAAAD+iNU2AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACbVBMVEUAAAD//wDR0QDd3QD//wAfHwAhKQALDgAICAYAAADo6ADd3QD8/ADb2wDm5gD//wD//wD//wCxsQClpQDt7QCjowCurgD//wD//wD//wD//wD//wD//wD//wCdnQClowCioACYmAD//wD//wD//wD//wD//wD//wD//wD//w
#   CurgCbmwCEgQCWlgCiogD//wD//wD//wD//wD//wDt7QDHxwDV1QD5+QDq6gCysgBYWQCkpADQ0AD//wD//wD//wD//wDm5gDDwwCOjgCoqADLywD+/gDJyQAgIAB2dgD//wD//wD//wD//wDY2ACnpwA6OgBfXwCzswD29gDOzgAgIAAdHQD//wD9/QDq6gDQ0ABtbQAHBwCEhAD8/ADh4QA/PwCamgD//wD//wD//wD//wDu7gDMzADExACamgAJCQCHhwDl5QDr6wCLiwDh4QD9/QD//wD//wD//wDv7wC6
#   ugCurgBMTAAWFQB9fAB1cADb2gDBwQDe3gDm5gD6+gD//wD//wDk5ADExAB6egKjqBZbZSpSXTp3cSVlJgXCsgG9vgDKygDU1AD39wD//wCXmQBjawBCSwFibzBQWlEuIhw+OxlmZgCOjgCkpADw8AD//wAiKwA9TQE9SkcgICETEwIcHBIfHw6DgwD//wAEBQAVGgAlJycMDAweHh4GBgQAAAABAQEAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAADHswAPDwA2NgBdXQB0iHd7joxRYRJQYDBabmpdcm4jIy
#   IiJw0rLyA7Pj4+QUEJCQkDAwMfHyAAAAABAQEDAwMDAwMBAQEEBAT////bfgUcAAAAtnRSTlMAAAAAAAAAAAAADDVGMgoAAAM8pb+hNwIAAgUHBgxq5+NiBgAEDRcdHBxg1PXOUQQABBAkO1JOOT51tWcaAAELIkh9p6B4RDiNGQAEFDl3uOngtW9FlhIGKnW57v/lrXitLBMGAAtTx/P7//ntvtCJcDMHDmXk/P78/P/h7e/gdhoGRrXy9vv39fjF7/3zhx8eqO799vjo8dzCUw4S0PL6/PjJHQA23e752SSQ
#   /v/8V5P////+WUJFFrYAAAABYktHRM702fL/AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wQdFiYdwDwd5wAAAQdJREFUCNdjYAADRiYubh5ePmZGEJuRX4BFUEhYRFRMHMhnlJCUkpaRlZPfpqCoxMjAqKyiqqauoamlraOrp8/IYGBoZGxiamZuYWllbWPLyGBn7+Do5Ozi6ubu4enFyMjg7ePr5x8QGBQcEhrGCjQuPCIyKnp7TGxcfEJiUnIKQ2paekbmjqzsnNy8/ILCIobiktKdZeUVlVXVNb
#   V19Q0MjU3NLa1t7R2dXd09vX39DAwTJk6avGv3lKnTps+YOWs2A9ucuXv27ts/b/6BBQsXLV7CwL502cFDh48sX3H02PGVqzgYGFafOHHy1Ok1a0+cObtuPScDw4YTG4Fg0+aNG09s2coAANV6WR2+KyzWAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTA0LTMwVDAwOjM4OjA5KzAyOjAwPqZVxAAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0wNC0zMFQwMDozODowOSswMjowME/77XgAAAAASUVORK5CYII=
# x-png-src: https://openclipart.org/detail/101737/vacuum-tubes
# extraction-method: regex
#
# PRF is a privately maintained directory of international
# radio stations, scheduled broadcasting programs, and
# internet streams grouped by location/genre/format/topics.
#
# This plugin is just browsing the format categories, uses a
# static genre list. Podcasts, scheduled programs aren't fetched.

Modified contrib/radionet.py from [0e376ccfde] to [a8d2a6968a].

1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21













+







# encoding: UTF-8
# api: streamtuner2
# title: radio.net
# description: Europe's biggest radio platform
# url: http://radio.net/
# version: 0.5
# type: channel
# category: radio
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAt0lEQVR42mNgYGD4r+Ar/F/BDwkD+SBxojBMs1mLPBArgGlFqEEENYMNQNLsukIDYkirAvGu
#   ABsA1OC6XOP/5f8nwIaYAg0k2gBFsAsgTgcZkvnfDugFEeK9AFKsCPMG0CU6eZJgQ4R1eP8H7LLEivWyFJANQcQCLPBAmkGG4MJohmA6C6QA5gI5OxEUDNII
#   MwSvASBFIA3ociCxkWQAKMDICkSQIpgh2LDnSmP80YhsCFEJiRIMADpmeUOpqgjRAAAAAElFTkSuQmCC
# priority: optional
# extraction-method: regex
#
# Radio.net lists around 20.000 worldwide radio stations.
# A maximum of three pages from each genre are fetched here,
# some of the empty categories already omitted.
#
# The website heavily depends on JavaScript, a Flash player,
# some social tracking cookies. But still feasible to access

Modified contrib/radiosure.py from [e1d926fd86] to [3ff12fd005].

1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21













+







# encoding: UTF-8
# api: streamtuner2
# title: RadioSure
# description: Huge radio station collection
# version: 0.5
# type: channel
# category: radio
# url: http://radiosure.com/
# config: -
# priority: extra
# png: 
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEULDgpKTEmQko/19/S0inLcAAAAUklEQVQI12P4DwQMDvuBBIs92zcGHh2G
#   BQw+FvUPGDwq/n9gaPoj/5DB6b/TQwaH/18uMrjs/yPI4FP2R4kh1vBHPUO8SsAnBn8P9ocMYFNABADRrSa61FmXoAAAAABJRU5ErkJggg==
# extraction-method: csv
#
# RadioSure is a Windows freeware/shareware for playing internet
# stations. It comes with a huge database of streams.
#
# Fetches and keeps the ZIP/CSV database at maximum once per day.
# (Not updated more frequently.)

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

8
9
10
11
12
13
14

15
16
17
18
19
20
21
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22







+







# category: radio
# config: -
# priority: contrib
# png:
#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAGFBMVEXiMATfORfhQyTrZk7uh3Tzs6n10879+/iUjtOkAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAA
#    CxMBAJqcGAAAAAd0SU1FB+AEBw4nI8D7wUYAAACISURBVAjXDc09D4JAFETREcParl/UvKdoKxi1JgZoiYnQSiJua2ST+ftud3KLGZDvYteT4DRTifqAFCvVmPBRl6um
#    DsOWP1W5oUw42dQaFBu2lckqqJwxHg8Burx+u0WGXOW5nuoYZUhN6xMMKr03ryYMyj36WAee5OJaE7687R5zF8Cx2DvyD3ZIHyPRcAnIAAAAAElFTkSuQmCC
# extraction-method: dom, action-handler
#
# Reciva is a mobile app. They have a web directory though.
# It's a bit difficult to query, and streaming urls aren't
# directly accessible. But allows to fetch all stations from
# a category at once; so still a quick database.
#
# They probably have an API somewhere, but no public docs.
34
35
36
37
38
39
40
41

42
43
44
45
46
47
48
35
36
37
38
39
40
41

42
43
44
45
46
47
48
49







-
+







from channels import *


# Reciva directory
class reciva (ChannelPlugin):

    # module attributes
    module = __name__
    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"
    

Modified contrib/record_stop.py from [6675e32df1] to [658cb7ac5c].

10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24







-
+







# a streamripper kill switch.

import action
from config import log, conf

# Stop button
class record_stop(object):
    module = __name__
    module = 'record_stop'

    # button + hook
    def __init__(self, parent):
        btn = parent.stop
        btn.show()
        btn.set_property("visible", True)
        btn.set_property("visible_horizontal", True)

Modified contrib/startup_workdir.py from [080458f838] to [588e781680].

17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
32
33
34
35







-
+











# for streamripper with a parameter.

from config import conf
import os, os.path

# Stop button
class startup_workdir(object):
    module = __name__
    module = 'startup_workdir'

    # button + hook
    def __init__(self, parent):
        os.chdir(
            os.path.expandvars(
                os.path.expanduser(
                    conf.start_dir
                )
            )
        )

Modified contrib/tmp_clean_multiurl.py from [d5e6d3c789] to [ff0e04e075].

13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
13
14
15
16
17
18
19

20
21
22
23
24
25
26
27







-
+







import re
from channels import GenericChannel
from config import log, conf


# filter
class tmp_clean_multiurl(object):
    module = __name__
    module = 'tmp_clean_multiurl'
    rx_space = re.compile(r"\s")
    rx_nonurl = re.compile(r"(^|\s)(?!\w+:)\S+")

    # Hook
    def __init__(self, parent):
        GenericChannel.postprocess_filters.append(self.filter_rows)

Modified contrib/tuner2.py from [16795f1b01] to [44865cadc2].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADVElEQVR42mWTfUzUdRzH738f8IDBQWVPLu84rrsLCRRZmGXnMCtCgnt+APSOFOWoWzJFRBPhIK4LTsY1m6mtU4FVo7BsrXO52ajmJl62xXTpam5t/pfwu736HPQX/fHe9/v9fPb9PL7fqnyzj6XIe6aRPLMXjclHgSDX
#    7JK7vI3N4m8k3+hGY87YfahWFTlYiiydk+zMXWun9KW97D84ykBsjGPDYziCJ1hb1SZ+G+oiO6qszIclWCmObAlyoO8MV6/NEo6M49gXZ9vOGBZvlOItHTxR5idHa80EcPI/6Lxk6+vwtUXZFehiNBrh0sdDjI2EqXUeYn3tUdaU76bQ4JYAOilVoNbZJXOmAhf5JT563vuIuzNfo0wf
#    Zv5KG3M3BklfP84v8Xpq9sQxbO7g8eIGCaB1ota6WV7kliA2tto7uZX6CWXMxmzbY4x4nuV0Vy3pVD9z31hIRcvwdk1Qsq2bPEmsUktGtfS7UmfFHxphfvZL/t77CDsrK8jNzEPfsDDQ+9fHSZ8pZvxIAM+hBCZLSCqWFlZoHRSsC9C4L4JySz77V1Gxbju5soFleis5az10dAwyN1HD
#    r91mBk8lqW4/y6NGqyR1odq4/R1mbqT456+fUXp19L5uIkvvEthRFzs4emyY+fEd3HtLzflPJwjGkhi3tMsKbQsrV30xdZm5+3dQbsZRIoV817eZZlsznQeO89ulKMpACXfa85lKnKP//DUs9iPScr1w5L8Af9y+TfreNMqPHh5MVjD//csoyQDKh8/xoHUZNw+WcuHCRaKTM9Q0HWaF
#    tkk4YpUKFkmnupxMovx5hfR0kHTCgPLBaub7NdztfopEeD89p3+gNfotla+8TY6seqE1Gbpal2GsMNG0wUMiNsDvn4e4+smbfDYYYOjdHlrCk9SEzrKpOU5llRPjRg9PV/oof2EXz7+6m03VftaYhYnLDVY0Ukpv9xAnv0qxtWmUDe4TlL4Rocz6PmW2YdZ7T1LVcgpL6Byu8EV8vVNU
#    VLeyWv+a8EBW8aRhB8HOYepbeqnfE6ZBTmtLHzY56wJiC/RQ5+/BGYzSFIpR/mKAHOHHQgsFpkaRqntRphkpCzQi5TyxF4p8C0wiYZH0QyLnh00uCsweFv4YF+X8L6KBLpzwswJYAAAAAElFTkSuQmCC
# priority: optional
# extraction-method: regex
#
# A station list website featuring a map. (Uncovered via streamripper
# homepage, which however mentions those streams not being recordable).
# Most entries are AAC+. Else MP3. No Vorbis streams.
#
# Furthermore no homepages, and playing= field is only sometimes set.
# Gotostationpage URLs don't work either. The website seems a bit

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

68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
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__
    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

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

11
12
13
14
15
16
17

18
19
20
21
22
23
24
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25







+







#   { name: vtuner_order,  value: POP,  type: select,  select: "POP=Popularity|AA=Alphabetically|HBR=Quality|RELI=Uptime|OP=Country",  description: "Station sorting order." }
# priority: contrib
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhFBMVEUAAACIowCIowCIowCIowAkWlsAP3yIowCIowATTWoAP3wAP3xrjhsAP3wAP3yIowAAP3wAP3wAP3wMSHEbU2MAP3wV
#   TmkAP3wAP3wAP3yIowAAP3wJRXQzZU5Vfi9ehCcRTG1EcT4aUmWAnQgiWF0rXlVmih88a0Z3lxBNdzZvkBf///9k8C2HAAAAGnRSTlMAML8QgO8wIJ9wj3DfEN9wr2BAr++/z1Cfzypf+6cAAAABYktHRCskueQIAAAAB3RJTUUH4AQEFxQcg7S+WgAAAJFJREFUGNNVjlkWgjAMRSOiOCJzMa9SQGit
#   +1+gQ5CD+ct9Q0JEtArW9Dchb7ZEUTiDaLc/0PHEC885pvgSLFNJmizXLC9Q5Nm8p/rWGNO06U8H0DH3wOQpAXNnHjRKAdAjM1tAQ8DYOgHoBbgGsPx4R0YBFetvK1wlQHmr4fnZd2q6W/vhU+vr+TN1HTpXif4CK/0NNsIh2vQAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMDQtMDVUMDE6MjA6MjAr
#   MDI6MDD2b3oJAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTA0LTA1VDAxOjIwOjIwKzAyOjAwhzLCtQAAAABJRU5ErkJggg==
# extraction-method: regex
#
#
# vTuner is a rather large station directory. The website is somewhat
# slow though. So fetching large results sets isn't advisable.
#
# There's an C API of sorts, but no publically available docs. So
# querying the website for stations. Personal/non-commercial use
32
33
34
35
36
37
38
39

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

40
41
42
43
44
45
46
47







-
+







from channels import *


# vTuner directory
class vtuner (ChannelPlugin):

    # module attributes
    module = __name__
    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',