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.parse 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)
def __init__(self, row_pattern): parts = re.split(r"(?<!\\):", row_pattern) parts = 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(pattern_from_markup(cat), esc=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): format = lambda song: [unicode(f_round(song(cat)))] 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: unicode(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
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 " "< and > as \\< and \\> and that your tags are " "balanced.\n\n%s") % util.escape(str(e))).run() apply.stop_emission('clicked')
def test_cond_markup(s): pat = XMLFromPattern(r'<title|\<b\><title> woo\</b\>>') s.assertEquals(pat.format(s.a), '<b>Title5 woo</b>')
def test_escape(s): pat = XMLFromPattern(r'\<b\><<xmltest>>\</b\>') s.assertEquals(pat.format(s.a), '<b><<&>></b>')
def test_markup_passthrough(s): pat = XMLFromPattern(r'\<b\><<title>>\</b\>') s.assertEquals(pat.format(s.a), '<b><Title5></b>') s.assertEquals(pat.format(s.b), '<b><Title6></b>') s.assertEquals(pat.format(s.c), '<b><test/subdir></b>')
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) image_path = "" if "icon-static" in caps: self.__image_fp = song.find_cover() if self.__image_fp: image_path = self.__image_fp.name is_temp = image_path.startswith(tempfile.gettempdir()) # If it is not an embeded cover, drop the file handle if not is_temp: self.__image_fp = None # spec recommends it, and it seems to work if image_path and spec >= (1, 1): image_path = URI.frompath(image_path) actions = [] if "actions" in caps: actions = ["next", _("Next")] hints = { "desktop-entry": "quodlibet", } try: self.__last_id = iface.Notify("Quod Libet", self.__last_id, image_path, 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
# it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation from quodlibet import util from quodlibet.parse import XMLFromPattern from quodlibet.util.collection import Album from quodlibet.qltk.models import ObjectTreeStore, ObjectModelFilter from quodlibet.qltk.models import ObjectModelSort 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>" UnknownNode = object() MultiNode = object() def build_tree(tags, albums, cache=None): if not tags: return list(albums) tag, merge = tags[0] tree = {} cache = cache or {}