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

⌈⌋ ⎇ branch:  streamtuner2


Diff

Differences From Artifact [0f18034c13]:

To Artifact [90231f2619]:


39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
import re
import copy
import inspect


# Only export plugin classes
__all__ = [
    "GenericChannel", "ChannelPlugin", "use_rx"

]



# generic channel module                            ---------------------------------------
class GenericChannel(object):








|
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import re
import copy
import inspect


# Only export plugin classes
__all__ = [
    "GenericChannel", "ChannelPlugin", "use_rx",
    "entity_decode", "strip_tags", "to_int", "nl"
]



# generic channel module                            ---------------------------------------
class GenericChannel(object):

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
        uikit.columns(self.gtk_list, self.datamap, [])
        
        # add to main menu
        uikit.add_menu([parent.channelmenuitems], self.meta["title"], lambda w: parent.channel_switch_by_name(self.module) or 1)


    # Statusbar stub (defers to parent/main window, if in GUI mode)
    def status(self, *v):
        if self.parent: self.parent.status(*v)
        else: log.INFO("status():", *v)


        
    #--------------------- streams/model data accesss ---------------------------

    # traverse category TreeModel to set current, expand parent nodes







|
|







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
        uikit.columns(self.gtk_list, self.datamap, [])
        
        # add to main menu
        uikit.add_menu([parent.channelmenuitems], self.meta["title"], lambda w: parent.channel_switch_by_name(self.module) or 1)


    # Statusbar stub (defers to parent/main window, if in GUI mode)
    def status(self, *args, **kw):
        if self.parent: self.parent.status(*args, **kw)
        else: log.INFO("status():", *v)


        
    #--------------------- streams/model data accesss ---------------------------

    # traverse category TreeModel to set current, expand parent nodes
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561



    #--------------------------- utility functions -----------------------

    

    # remove html <tags> from string        
    def strip_tags(self, s):
        return re.sub("<.+?>", "", s)
        
    # convert audio format nick/shortnames to mime types, e.g. "OGG" to "audio/ogg"
    def mime_fmt(self, s):
        # clean string
        s = s.lower().strip()
        # rename
        map = {







<
<
<







546
547
548
549
550
551
552



553
554
555
556
557
558
559



    #--------------------------- utility functions -----------------------

    




        
    # convert audio format nick/shortnames to mime types, e.g. "OGG" to "audio/ogg"
    def mime_fmt(self, s):
        # clean string
        s = s.lower().strip()
        # rename
        map = {
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
            s = map[s]
        # add prefix:
        if s.find("/") < 1:
            s = "audio/" + s
        #
        return s
    
    # remove SGML/XML entities
    def entity_decode(self, str):
        return re.sub('&(#?(x?))(\w+);', self._entity, str)
    def _entity(self, sym):
        num, hex, name = sym.groups()
        if hex:
            return unichr(int(name, base=16))
        elif num:
            return unichr(int(name))
        else:
            return unichr(htmlentitydefs.name2codepoint[name])
    
    # convert special characters to &xx; escapes
    def xmlentities(self, s):
        return xml.sax.saxutils.escape(s)
    
    # Extracts integer from string
    def to_int(self, s):
        i = re.findall("\d+", s) or [0]
        return int(i[0])















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







570
571
572
573
574
575
576





















577
578
579
580
581
582
583
            s = map[s]
        # add prefix:
        if s.find("/") < 1:
            s = "audio/" + s
        #
        return s
    




























684
685
686
687
688
689
690

691
692
693
694
695
696
697
        # 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







>







661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
        # 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
711
712
713
714
715
716
717


































            except Exception as e:
                log.ERR("{} extraction failed:".format(method), e)
                continue
        return []
    return try_both











































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
            except Exception as e:
                log.ERR("{} extraction failed:".format(method), e)
                continue
        return []
    return try_both



#---------------- utility functions -------------------
# Used by raw page extraction in channel modules


# Strip html <tags> from string
def strip_tags(s):
    return re.sub("<.+?>", "", s)

# remove SGML/XML entities
def entity_decode(str):
    return re.sub('&(#?(x?))(\w+);', _entity, str)
def _entity(sym):
    num, hex, name = sym.groups()
    if hex:
        return unichr(int(name, base=16))
    elif num:
        return unichr(int(name))
    else:
        return unichr(htmlentitydefs.name2codepoint[name])

# Extracts integer from string
def to_int(s):
    i = re.findall("\d+", s) or [0]
    return int(i[0])

# Strip newlines
rx_spc = re.compile("\s+")
def nl(str):
    return rx_spc.sub(" ", str).strip()


def unhtml(str):
    return nl(entity_decode(strip_tags(str)))