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

⌈⌋ branch:  streamtuner2


Check-in [5588baf6dd]

Overview
Comment:Implement custom HTML .entitiy_decode, because SAX didn't honor any HTML; and HTMLParser would require customized/compat2and3 imports.

Colorize channel labels if #color: is specified in any plugins.

And provide @use_rx decorator to alternate between regex/pyquery extractors.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5588baf6ddaf530008bae6ccba1dfbf259a37285
User & Date: mario on 2015-05-02 05:41:54
Other Links: manifest | tags
Context
2015-05-02
05:42
Use new @use_rx decorator to switch and fall back between regex/pyquery modes. check-in: f269792f36 user: mario tags: trunk
05:41
Implement custom HTML .entitiy_decode, because SAX didn't honor any HTML; and HTMLParser would require customized/compat2and3 imports.

Colorize channel labels if #color: is specified in any plugins.

And provide @use_rx decorator to alternate between regex/pyquery extractors. check-in: 5588baf6dd user: mario tags: trunk

05:39
More specific log.HTTP messages (GET vs POST) check-in: 8ede46a0a1 user: mario tags: trunk
Changes

Modified channels/__init__.py from [5eb841253c] to [0f18034c13].

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import gtk
from uikit import uikit, ver as gtk_ver
from config import *
import ahttp
import action
import favicon
import os.path
import xml.sax.saxutils
import re
import copy
import inspect


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



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








|







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import gtk
from uikit import uikit, ver as gtk_ver
from config import *
import ahttp
import action
import favicon
import os.path
import xml.sax.saxutils, htmlentitydefs
import re
import copy
import inspect


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



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

573
574
575
576
577
578
579
580






581


582
583
584
585
586
587
588
        # add prefix:
        if s.find("/") < 1:
            s = "audio/" + s
        #
        return s
    
    # remove SGML/XML entities
    def entity_decode(self, s):






        return xml.sax.saxutils.unescape(s).replace("&nbsp;", " ")


    
    # 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):







|
>
>
>
>
>
>
|
>
>







573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
        # 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):
646
647
648
649
650
651
652
653



654
655
656
657
658
659
660
            pixbuf = uikit.pixbuf(png)
        if pixbuf:
            icon = gtk.image_new_from_pixbuf(pixbuf)
        else:
            icon = gtk.image_new_from_stock(gtk.STOCK_DIRECTORY, size=1)
        label = gtk.HBox()
        label.pack_start(icon, expand=False, fill=True)
        label.pack_start(gtk.Label(self.meta.get("title", self.module)), expand=True, fill=True)



            
        # pack it into an event container to catch double-clicks
        ev_label = gtk.EventBox()
        ev_label.add(label)
        ev_label.connect('event', parent.on_homepage_channel_clicked)
        plain_label = gtk.Label(self.module)








|
>
>
>







654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
            pixbuf = uikit.pixbuf(png)
        if pixbuf:
            icon = gtk.image_new_from_pixbuf(pixbuf)
        else:
            icon = gtk.image_new_from_stock(gtk.STOCK_DIRECTORY, size=1)
        label = gtk.HBox()
        label.pack_start(icon, expand=False, fill=True)
        l = gtk.Label(self.meta.get("title", self.module))
        if self.meta.get("color"):
            l = uikit.bg(l, self.meta["color"])
        label.pack_start(l, expand=True, fill=True)
            
        # pack it into an event container to catch double-clicks
        ev_label = gtk.EventBox()
        ev_label.add(label)
        ev_label.connect('event', parent.on_homepage_channel_clicked)
        plain_label = gtk.Label(self.module)

684
685
686
687
688
689
690
691















def stub_parent(object):
    def __setattr__(self, name, value):
        pass
    def __getattr__(self, name):
        return lambda *x: None
    def status(self, *x):
        pass
























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
def stub_parent(object):
    def __setattr__(self, name, value):
        pass
    def __getattr__(self, name):
        return lambda *x: None
    def status(self, *x):
        pass


# Decorator
def use_rx(func):
    def try_both(*args, **kwargs):
        for method, use_rx in [("RX", not conf.pyquery), ("PQ", conf.pyquery)]:
            try:
                log.STAT(method)
                return func(*args, use_rx=not conf.pyquery, **kwargs)
            except Exception as e:
                log.ERR("{} extraction failed:".format(method), e)
                continue
        return []
    return try_both