Exemplo n.º 1
0
    def __init__(self, row_pattern):
        parts = [p.replace(r"\:", ":")
                 for p in (re.split(r"(?<!\\):", row_pattern))]

        is_numeric = lambda s: s[:2] == "~#" and "~" not in s[2:]
        is_pattern = lambda s: '<' in s
        f_round = lambda s: (isinstance(s, float) and "%.2f" % s) or s

        def is_date(s):
            return s in TIME_TAGS

        disp = parts[1] if len(
            parts) >= 2 else r"[i][span alpha='40%']<~#tracks>[/span][/i]"
        cat = parts[0]

        if is_pattern(cat):
            title = util.pattern(cat, esc=True, markup=True)
            try:
                pc = XMLFromPattern(cat)
            except ValueError:
                pc = XMLFromPattern("")
            tags = pc.tags
            format = pc.format_list
            has_markup = True
        else:
            title = util.tag(cat)
            tags = util.tagsplit(cat)
            has_markup = False
            if is_date(cat):
                def format(song: AudioFile) -> List[Tuple[Text, Text]]:
                    fmt = config.gettext("settings",
                                         "datecolumn_timestamp_format")
                    date_str = format_date(song(cat), fmt)
                    return [(date_str, date_str)]
            elif is_numeric(cat):
                def format(song: AudioFile) -> List[Tuple[Text, Text]]:
                    v = str(f_round(song(cat)))
                    return [(v, v)]
            else:
                def format(song: AudioFile) -> List[Tuple[Text, Text]]:
                    return song.list_separate(cat)

        if is_pattern(disp):
            try:
                pd = XMLFromPattern(disp)
            except ValueError:
                pd = XMLFromPattern("")
            format_display = pd.format
        else:
            if is_numeric(disp):
                format_display = lambda coll: str(f_round(coll(disp)))
            else:
                format_display = lambda coll: util.escape(coll.comma(disp))

        self.title = title
        self.tags = set(tags)
        self.format = format
        self.format_display = format_display
        self.has_markup = has_markup
Exemplo n.º 2
0
    def __init__(self, row_pattern):
        parts = re.split(r"(?<!\\):", row_pattern)
        parts = list(map(lambda p: p.replace(r"\:", ":"), parts))

        is_numeric = lambda s: s[:2] == "~#" and "~" not in s[2:]
        is_pattern = lambda s: '<' in s
        f_round = lambda s: (isinstance(s, float) and "%.2f" % s) or s

        disp = (len(parts) >= 2 and parts[1]) or r"[i](<~#tracks>)[/i]"
        cat = parts[0]

        if is_pattern(cat):
            title = util.pattern(cat, esc=True, markup=True)
            try:
                pc = XMLFromPattern(cat)
            except ValueError:
                pc = XMLFromPattern("")
            tags = pc.tags
            format = pc.format_list
            has_markup = True
        else:
            title = util.tag(cat)
            tags = util.tagsplit(cat)
            has_markup = False
            if is_numeric(cat):

                def format(song):
                    v = text_type(f_round(song(cat)))
                    return [(v, v)]
            else:
                format = lambda song: song.list_separate(cat)

        if is_pattern(disp):
            try:
                pd = XMLFromPattern(disp)
            except ValueError:
                pd = XMLFromPattern("")
            format_display = pd.format
        else:
            if is_numeric(disp):
                format_display = lambda coll: text_type(f_round(coll(disp)))
            else:
                format_display = lambda coll: util.escape(coll.comma(disp))

        self.title = title
        self.tags = set(tags)
        self.format = format
        self.format_display = format_display
        self.has_markup = has_markup
Exemplo n.º 3
0
def pattern(pat, cap=True, esc=False, markup=False):
    """Return a 'natural' version of the pattern string for human-readable
    bits. Assumes all tags in the pattern are present.
    """

    from quodlibet.pattern import Pattern, XMLFromPattern, XMLFromMarkupPattern

    class Fakesong(dict):
        cap = False

        def comma(self, key):
            return " - ".join(self.list(key))

        def list(self, key):
            return [tag(k, self.cap) for k in tagsplit(key)]

        list_separate = list

        def __call__(self, tag, *args):
            return 0 if '~#' in tag[:2] else self.comma(tag)

    fakesong = Fakesong({'filename': tag('filename', cap)})
    fakesong.cap = cap
    try:
        if markup:
            p = XMLFromMarkupPattern(pat)
        elif esc:
            p = XMLFromPattern(pat)
        else:
            p = Pattern(pat)
    except ValueError:
        return _("Invalid pattern")

    return p.format(fakesong)
Exemplo n.º 4
0
def pattern(pat, cap=True, esc=False):
    """Return a 'natural' version of the pattern string for human-readable
    bits. Assumes all tags in the pattern are present."""
    from quodlibet.pattern import Pattern, XMLFromPattern

    class Fakesong(dict):
        cap = False

        def comma(self, key):
            return " - ".join(self.list(key))

        def list(self, key):
            return [tag(k, self.cap) for k in tagsplit(key)]

        list_seperate = list
        __call__ = comma

    fakesong = Fakesong({'filename': tag('filename', cap)})
    fakesong.cap = cap
    try:
        p = (esc and XMLFromPattern(pat)) or Pattern(pat)
    except ValueError:
        return _("Invalid pattern")

    return p.format(fakesong)
Exemplo n.º 5
0
 def __check_markup(self, apply):
     try:
         f = AudioFile({"~filename": "dummy"})
         Pango.parse_markup(XMLFromPattern(self.text) % f, -1, u"\u0000")
     except (ValueError, GLib.GError), e:
         qltk.ErrorMessage(
             self, _("Invalid pattern"),
             _("The pattern you entered was invalid. Make sure you enter "
               "&lt; and &gt; as \\&lt; and \\&gt; and that your tags are "
               "balanced.\n\n%s") % util.escape(str(e))).run()
         apply.stop_emission('clicked')
Exemplo n.º 6
0
def validate_markup_pattern(text, alternative_markup=True, links=False):
    """Check whether a passed pattern results in a valid pango markup.

    Args:
        text (unicode): the pattern
        alternative_markup (bool): if "[b]" gets mapped to "\\<b\\>"
        links (bool): if link tags are allowed (for Gtk.Label only)

    Raises:
        ValueError: In case the pattern isn't valid
    """

    assert isinstance(text, str)

    f = AudioFile({"~filename": fsnative(u"dummy")})

    try:
        if alternative_markup:
            pattern = XMLFromMarkupPattern(text)
        else:
            pattern = XMLFromPattern(text)
        text = pattern % f
    except PatternError as e:
        return ValueError(e)

    try:
        Pango.parse_markup(text, -1, u"\u0000")
    except GLib.GError as e:
        if not links:
            raise ValueError(e)
        # Gtk.Label supports links on top of pango markup but doesn't
        # provide a way to verify them. We can check if the markup
        # was accepted by seeing if get_text() returns something.
        l = Gtk.Label()
        # add a character in case text is empty.
        # this might print a warning to stderr.. no idea how to prevent that..
        l.set_markup(text + " ")
        if not l.get_text():
            raise ValueError(e)
Exemplo n.º 7
0
    def show_notification(self, song):
        """Returns True if showing the notification was successful"""

        if not song:
            return True

        try:
            if self.__enabled:
                # we are enabled try to work with the data we have and
                # keep it fresh
                if not self.__interface:
                    iface, caps, spec = self.__get_interface()
                    self.__interface = iface
                    self.__caps = caps
                    self.__spec_version = spec
                    if "actions" in caps:
                        self.__action_sig = iface.connect(
                            'g-signal', self._on_signal)
                else:
                    iface = self.__interface
                    caps = self.__caps
                    spec = self.__spec_version
            else:
                # not enabled, just get everything temporary,
                # probably preview
                iface, caps, spec = self.__get_interface()

        except GLib.Error:
            print_w("[notify] %s" %
                    _("Couldn't connect to notification daemon."))
            self.__disconnect()
            return False

        strip_markup = lambda t: re.subn(r"\</?[iub]\>", "", t)[0]
        strip_links = lambda t: re.subn(r"\</?a.*?\>", "", t)[0]
        strip_images = lambda t: re.subn(r"\<img.*?\>", "", t)[0]

        title = XMLFromPattern(pconfig.gettext("titlepattern")) % song
        title = unescape(strip_markup(strip_links(strip_images(title))))

        body = ""
        if "body" in caps:
            body = XMLFromPattern(pconfig.gettext("bodypattern")) % song

            if "body-markup" not in caps:
                body = strip_markup(body)
            if "body-hyperlinks" not in caps:
                body = strip_links(body)
            if "body-images" not in caps:
                body = strip_images(body)

        actions = []
        if pconfig.getboolean("show_next_button") and "actions" in caps:
            actions = ["next", _("Next")]

        hints = {
            "desktop-entry": GLib.Variant('s',
                                          "io.github.quodlibet.QuodLibet"),
        }

        image_uri = self._get_image_uri(song)
        if image_uri:
            hints["image_path"] = GLib.Variant('s', image_uri)
            hints["image-path"] = GLib.Variant('s', image_uri)

        try:
            self.__last_id = iface.Notify('(susssasa{sv}i)', "Quod Libet",
                                          self.__last_id, image_uri, title,
                                          body, actions, hints,
                                          pconfig.getint("timeout"))
        except GLib.Error:
            print_w("[notify] %s" %
                    _("Couldn't connect to notification daemon."))
            self.__disconnect()
            return False

        # preview done, remove all references again
        if not self.__enabled:
            self.__disconnect()

        return True
Exemplo n.º 8
0
 def test_cond_markup(s):
     pat = XMLFromPattern(r'<title|\<b\><title> woo\</b\>>')
     s.assertEquals(pat.format(s.a), '<b>Title5 woo</b>')
Exemplo n.º 9
0
 def test_escape(s):
     pat = XMLFromPattern(r'\<b\>&lt;<xmltest>&gt;\</b\>')
     s.assertEquals(pat.format(s.a), '<b>&lt;&lt;&amp;&gt;&gt;</b>')
Exemplo n.º 10
0
 def test_markup_passthrough(s):
     pat = XMLFromPattern(r'\<b\>&lt;<title>&gt;\</b\>')
     s.assertEquals(pat.format(s.a), '<b>&lt;Title5&gt;</b>')
     s.assertEquals(pat.format(s.b), '<b>&lt;Title6&gt;</b>')
     s.assertEquals(pat.format(s.c), '<b>&lt;test/subdir&gt;</b>')
Exemplo n.º 11
0
from quodlibet import util
from quodlibet import config
from quodlibet import _
from quodlibet.pattern import XMLFromPattern
from quodlibet.qltk.models import ObjectTreeStore, ObjectModelFilter
from quodlibet.qltk.models import ObjectModelSort
from quodlibet.compat import iteritems, string_types, itervalues


EMPTY = _("Songs not in an album")
ALBUM_PATTERN = r"""
\<b\><album|<album>|%s>\</b\><date| \<small\>(<date>)\</small\>>
\<small\><~discs|<~discs> - ><~tracks> - <~long-length>\</small\>""" % EMPTY
ALBUM_PATTERN = ALBUM_PATTERN.lstrip()
PAT = XMLFromPattern(ALBUM_PATTERN)

UNKNOWN_PATTERN = "<b><i>%s</i></b>" % _("Unknown %s")
MULTI_PATTERN = "<b><i>%s</i></b>" % _("Multiple %s Values")
COUNT_PATTERN = " <span size='small' color='#777'>(%s)</span>"


class AlbumNode(object):

    def __init__(self, album):
        self.album = album
        self.scanned = False

    @property
    def COVER_SIZE(self):
        size = config.getint("browsers", "cover_size")
Exemplo n.º 12
0
    def show_notification(self, song):
        """Returns True if showing the notification was successful"""

        if not song:
            return True

        try:
            if self.__enabled:
                # we are enabled try to work with the data we have and
                # keep it fresh
                if not self.__interface:
                    iface, caps, spec = self.__get_interface()
                    self.__interface = iface
                    self.__caps = caps
                    self.__spec_version = spec
                    if "actions" in caps:
                        self.__action_sig = iface.connect_to_signal(
                            "ActionInvoked", self.on_dbus_action)
                else:
                    iface = self.__interface
                    caps = self.__caps
                    spec = self.__spec_version
            else:
                # not enabled, just get everything temporary,
                # propably preview
                iface, caps, spec = self.__get_interface()

        except dbus.DBusException:
            print_w("[notify] %s" %
                    _("Couldn't connect to notification daemon."))
            self.__disconnect()
            return False

        strip_markup = lambda t: re.subn("\</?[iub]\>", "", t)[0]
        strip_links = lambda t: re.subn("\</?a.*?\>", "", t)[0]
        strip_images = lambda t: re.subn("\<img.*?\>", "", t)[0]

        title = XMLFromPattern(get_conf_value("titlepattern")) % song
        title = unescape(strip_markup(strip_links(strip_images(title))))

        body = ""
        if "body" in caps:
            body = XMLFromPattern(get_conf_value("bodypattern")) % song

            if "body-markup" not in caps:
                body = strip_markup(body)
            if "body-hyperlinks" not in caps:
                body = strip_links(body)
            if "body-images" not in caps:
                body = strip_images(body)

        actions = []
        if get_conf_bool("show_next_button") and "actions" in caps:
            actions = ["next", _("Next")]

        hints = {
            "desktop-entry": "quodlibet",
        }

        image_uri = self._get_image_uri(song)
        if image_uri:
            hints["image_path"] = image_uri
            hints["image-path"] = image_uri

        try:
            self.__last_id = iface.Notify("Quod Libet", self.__last_id,
                                          image_uri, title, body, actions,
                                          hints, get_conf_int("timeout"))
        except dbus.DBusException:
            print_w("[notify] %s" %
                    _("Couldn't connect to notification daemon."))
            self.__disconnect()
            return False

        # preview done, remove all references again
        if not self.__enabled:
            self.__disconnect()

        return True
Exemplo n.º 13
0
 def test_cond_markup(s):
     pat = XMLFromPattern(r'<title|\<b\><title> woo\</b\>>')
     s.assertEquals(pat.format(s.a), '<b>Title5 woo</b>')
Exemplo n.º 14
0
 def test_escape(s):
     pat = XMLFromPattern(r'\<b\>&lt;<xmltest>&gt;\</b\>')
     s.assertEquals(pat.format(s.a), '<b>&lt;&lt;&amp;&gt;&gt;</b>')
Exemplo n.º 15
0
 def test_markup_passthrough(s):
     pat = XMLFromPattern(r'\<b\>&lt;<title>&gt;\</b\>')
     s.assertEquals(pat.format(s.a), '<b>&lt;Title5&gt;</b>')
     s.assertEquals(pat.format(s.b), '<b>&lt;Title6&gt;</b>')
     s.assertEquals(pat.format(s.c), '<b>&lt;test/subdir&gt;</b>')