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

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


Check-in [f4dfbc1e53]

Overview
Comment:Fix missing channel key error. Add icon.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f4dfbc1e53a2f0e28d508034fa712cf7826b1792
User & Date: mario on 2015-05-05 10:42:43
Other Links: manifest | tags
Context
2015-05-05
10:43
Support direct URLs in DND import (only used as literal url=, brings up streamedit window afterwards). check-in: 5fe8de1fd7 user: mario tags: trunk
10:42
Fix missing channel key error. Add icon. check-in: f4dfbc1e53 user: mario tags: trunk
2015-05-04
22:29
Stub placeholder version: as `0` check-in: 9f252677fa user: mario tags: trunk
Changes

Modified contrib/compound.py from [b3c0586597] to [ca7af6a4e8].

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
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




-
+




-
-
+
+
+

+
+
+
+
+
+
+
+
+
+



-
+
-







-





-
+
-
-
-
















-
+


-
+



-
-
+
+









-











-
+














-
+




-
+



-
-
+
+
+
+







# encoding: UTF-8
# api: streamtuner2
# title: Compoundβ˜…
# description: combines station lists from multiple channels
# version: 0.1
# version: 0.2
# type: channel
# category: virtual
# url: http://fossil.include-once.org/streamtuner2/
# config: -
#    { name: compound_channels, type: text, value: "shoutcast, internet_radio, xiph, surfmusic", description: "Merge channels, or use all (*)" }
#    { name: compound_genres, type: text, value: "Top 40, x", description: "Extract categories, or just use intersection (x)" }
#    { name: compound_channels, type: text, value: "shoutcast, internet_radio, xiph, surfmusik", description: "Channels to merge station lists from." }
#    { name: compound_genres, type: text, value: "Top 40", description: "Extract specific/favourite categories." }
#    { name: compound_intersect, type: boolean, value: 1, description: "Intersect genres which exist in 2 or more channels." }
# priority: unsupported
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wUFCigotf34ngAABGlJREFUOMttj++LVFUchz/f7znn3jtzZ+buzuzszv4SbbdVUTNp
#   o8DqXUFsUEFBBEFSr/ov8h8JJOhNWlFQhggJYWKaGZrruGW26e44O7/nztx77jmnF5b2oufl58XD86HuG7uQGzTRzU1i6tQmjh8/vhxF0dtpmq612+2VZrOZ77Tb/f5gcGVnZ+dEvV7/9MyZM3GtVoPWGkopZFmG3bt3AwBkxrn9iSq9yiLX+PqLz0qrq6vH+v3+wfX1de50OvH09HS2uLhYjOP4aKVSebZQKDwfBEFda50YY7aJaNkYcw7AOQCQ
#   rsgrEPigO7ekawuL1f4wLv5w/jyIOVtbW7vw+MpKJKWq9nvdX8MwfOn69evvJ0kSFwqFTQDXALwIwD4U2orSSRj09Auv747KU+GFi98gjuPOu8eOcSmQQ+/iR2CjPbf35R2bD52UEv9gATjnnAHg/h0Zk5yOapVRsHREpWmK+o3r8ZMHls9GExPG6LHzNk62/PonTU5aKYiclDITQmTOPXQQ/oO0kzJNaWLohxENW0PYdJAuzZeTNM2YWMJM5Xsu
#   cwK+lwrmpFqt/hyGYRUA43+QZta3zlDiYKw1BuWZXaXK4sFXtu78qAvi/iCclSmsSuALx0KkURTdY+bIOScexDHwqBYyOazyznYrjfZVQ1jBvn37uTYzW+x3Lg/vbX1sa4cwJaSskLExnCDnDD24SyBuGhZZ5uDso8IiicHABidPfcmjQQ2HDuwHM6M8cyi/0ZybbJduyyCQYTq4ZATfHRpdSoQ5CoBgghNDk/ulY7J8/FDYYlBzKNX9plajfgM3
#   byl0u10EfokSlL1te5sDCGn9s5q9Xkzj5SQazxqA0OUdOO6xpQyAA5OE3M6IxiWHoGyMjpWI4xiXfrqMPUsL6JrYNpmlchBwQsApAW6iUfiwD4KwGdyDnfmd196D9t+EbBiwDS1PPde7O/g8V56bnS212x1c/eqKa8m4MtxFXJyzSgIeFBQypyyPFADBJudDkrJjDoZ96cfjrpYNR6QtKToyvjlf3Qnmo+QpvzXq9aeuFc16YeWvb/cQLzWGKqI9
#   ak7m9e+5FXQnayiOTW5PNidmOcg2c0tRDQd8O7EhGwAlICFSkcfUyPtenU65Gf1pn+7sFXMT2/bGRORuLVZ0T62yb32MvCcoU8LM9nrxzFbFWfKoL2pCoEqONmTDEY0cCS8RJRgoLYXIs5CxE8L3rDHPbCfuMI/Cq9OtpBrXvIF/V5dHkYkSI6ygEYjzEjpnXGMUj2LZ0OChYJXXnIMDj0EUOaKOIy44Ym2ZdaRNcW+301nozJS2SvEoGoeA43wr
#   pJ4jjjzbX4ixXb9Rz+TOmMZ9QbeLDm0HYGSoZ9ndaloSCeFOCoTaUiED/tjJWGSgjdhS1wFUYLfVMuTSnKk/tuna84vzTnpXvXPlwHur2AoIAJJ8JoqdQPOmVPmBl2nPUiYN53uepr+UKnR9HeQD4eAQDFVGZanUgNu/bdfHpy9+h78Bc2RGfJQqXS8AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDUtMDVUMTI6NDA6MTIrMDI6MDDJlQYgAAAA
#   JXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA1LTA1VDEyOjQwOjEyKzAyOjAwuMi+nAAAAABJRU5ErkJggg==
# png-orig: https://openclipart.org/detail/215936/audio
# 
# Use this plugin to mix categories and their station entries from two
# or more different directory channels. It merges the lists, albeit in
# a rather crude way. (If anyone is interested, I could add a proper
# a simplistic way.
# regex or something now.)
#
# Per default it lists only selected categories. But can be configured to
# merge just intersectioning categories/genres. Entry order is determined
# from station occourence count in channels AND their individual listener
# count (where available) using some guesswork to eliminate duplicates.



from channels import *
import action
from config import conf



# Merges categories from different channels


# merging channel
class compound (ChannelPlugin):

    # runtime options
    has_search = False
    listformat = "href"  # row entries will contain exact `listformat` classification
    audioformat = "audio/*"   # same as for correct encoding mime type
    
    # references
    parent = None
    
    # data
    streams = {}
    categories = []
    
    
    
    # which categories
    # Which categories
    def update_categories(self):

        # as-is category list
        # As-is category list
        cats = self.split(conf.compound_genres)
        self.categories = [c for c in cats if c != "x"]
        
        # if intersection
        if "x" in cats:
        # Genre intersection requested
        if conf.compound_intersect:
            once = []
            for chan in self.channels():
                for add in self.flatten(self.parent.channels[chan].categories):
                    # second occourence in two channels
                    if add.lower() in once:
                        if add not in self.categories:
                            self.categories.append(add)
                    else: #if add not in self.categories:
                        once.append(add.lower())
        pass
                        
        
    # flatten our two-level categories list
    def flatten(self, a):
        return [i for sub in a for i in (sub if type(sub)==list else [sub])]


    # break up name lists        
    def split(self, s):
        return [s.strip() for s in s.split(",")]

    # get list of channels
    # List of channels
    def channels(self):

        # get list
        ls = self.split(conf.compound_channels)
      
        # resolve "*"
        if "*" in ls:
            ls = self.parent.channel_names  # includes bookmarks
            if self.module in ls:
                ls.remove(self.module)	    # but not compound

        return ls
          
          
    # combine stream lists
    # Combine stream lists
    def update_streams(self, cat):
        r = []
        have = []
    
        # look through channels
        # Look through channels
        if cat in self.categories:
            for cn in self.channels():
            
                # get channel, refresh list
                c = self.parent.channels[cn]
                # Get channel, refresh list
                c = self.parent.channels.get(cn)
                if not cn:
                    continue # skip misnamed pugins
                
                # 
                for row in self.get_streams(c, cat):

                    # copy
                    row = dict(row)