From 271f7c8d1756050e95e916f6de9fbdc779f141b1 Mon Sep 17 00:00:00 2001 From: Guilherme Danno Date: Sat, 23 Apr 2016 13:59:25 -0300 Subject: [PATCH] new template path functions: %first{} and %ifdef{} (#1951) * New template functions: %first{} and %ifdef{} * Add documentation * Add to changelog --- beets/library.py | 29 +++++++++++++++++++++++++ docs/changelog.rst | 1 + docs/reference/pathformat.rst | 10 +++++++++ test/test_library.py | 40 +++++++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/beets/library.py b/beets/library.py index f2c3875b0..ed1938671 100644 --- a/beets/library.py +++ b/beets/library.py @@ -1466,6 +1466,35 @@ class DefaultTemplateFunctions(object): self.lib._memotable[memokey] = res return res + @staticmethod + def tmpl_first(s, count=1, skip=0, sep=u'; ', join_str=u'; '): + """ Gets the item(s) from x to y in a string separated by something + and join then with something + + :param s: the string + :param count: The number of items included + :param skip: The number of items skipped + :param sep: the separator. Usually is '; ' (default) or '/ ' + :param join_str: the string which will join the items, default '; '. + """ + skip = int(skip) + count = skip + int(count) + return join_str.join(s.split(sep)[skip:count]) + + def tmpl_ifdef(self, field, trueval=u'', falseval=u''): + """ If field exists return trueval or the field (default) + otherwise, emit return falseval (if provided). + + :param field: The name of the field + :param trueval: The string if the condition is true + :param falseval: The string if the condition is false + :return: The string, based on condition + """ + if self.item.formatted().get(field): + return trueval if trueval else self.item.formatted().get(field) + else: + return falseval + # Get the name of tmpl_* functions in the above class. DefaultTemplateFunctions._func_names = \ diff --git a/docs/changelog.rst b/docs/changelog.rst index 721c9ab8a..4908219a7 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -22,6 +22,7 @@ New features: source in a flexible field; for a usecase see the documentation. * :doc:`/plugins/export`: A new plugin to export the data from queries to a json format. Thanks to :user:`GuilhermeHideki`. +* :doc:`/reference/pathformat`: new functions: %first{} and %ifdef{} .. _fanart.tv: https://fanart.tv/ diff --git a/docs/reference/pathformat.rst b/docs/reference/pathformat.rst index 8efe54cd2..b5d754bd4 100644 --- a/docs/reference/pathformat.rst +++ b/docs/reference/pathformat.rst @@ -76,6 +76,16 @@ These functions are built in to beets: * ``%time{date_time,format}``: Return the date and time in any format accepted by `strftime`_. For example, to get the year some music was added to your library, use ``%time{$added,%Y}``. +* ``%first{text}``: Returns the first item, separated by ``; ``. + You can use ``%first{text,count,skip}``, where ``count`` is the number of + items (default 1) and ``skip`` is number to skip (default 0). You can also use + ``%first{text,count,skip,sep,join}`` where ``sep`` is the separator, like + ``;`` or ``/`` and join is the text to concatenate the items. + For example, +* ``%ifdef{field}``, ``%ifdef{field,truetext}`` or + ``%ifdef{field,truetext,falsetext}``: If ``field`` exists, then return + ``truetext`` or ``field`` (default). Otherwise, returns ``falsetext``. + The ``field`` should be entered without ``$``. .. _unidecode module: http://pypi.python.org/pypi/Unidecode .. _strftime: http://docs.python.org/2/library/time.html#time.strftime diff --git a/test/test_library.py b/test/test_library.py index d57566f5f..4d6a51b93 100644 --- a/test/test_library.py +++ b/test/test_library.py @@ -617,6 +617,46 @@ class DestinationFunctionTest(_common.TestCase, PathFormattingMixin): self._setf(u'%foo{bar}') self._assert_dest('/base/%foo{bar}') + def test_if_def_field_return_self(self): + self.i.bar = 3 + self._setf(u'%ifdef{bar}') + self._assert_dest('/base/3') + + def test_if_def_field_not_defined(self): + self._setf(u' %ifdef{bar}/$artist') + self._assert_dest('/base/the artist') + + def test_if_def_field_not_defined_2(self): + self._setf(u'$artist/%ifdef{bar}') + self._assert_dest('/base/the artist') + + def test_if_def_true(self): + self._setf(u'%ifdef{artist,cool}') + self._assert_dest('/base/cool') + + def test_if_def_true_complete(self): + self.i.series = "Now" + self._setf(u'%ifdef{series,$series Series,Albums}/$album') + self._assert_dest('/base/Now Series/the album') + + def test_if_def_false_complete(self): + self._setf(u'%ifdef{plays,$plays,not_played}') + self._assert_dest('/base/not_played') + + def test_first(self): + self.i.genres = "Pop; Rock; Classical Crossover" + self._setf(u'%first{$genres}') + self._assert_dest('/base/Pop') + + def test_first_skip(self): + self.i.genres = "Pop; Rock; Classical Crossover" + self._setf(u'%first{$genres,1,2}') + self._assert_dest('/base/Classical Crossover') + + def test_first_different_sep(self): + self._setf(u'%first{Alice / Bob / Eve,2,0, / , & }') + self._assert_dest('/base/Alice & Bob') + class DisambiguationTest(_common.TestCase, PathFormattingMixin): def setUp(self):