Skip to content

Commit

Permalink
feat: Unique filters plugin
Browse files Browse the repository at this point in the history
This plugin allows filtering by a unique tag e.g `@(unique: artist)` which will result only one song showing up per artist.
It can be used multiple times e.g if one has mix albums in the library (albums with multiple artists),
 it's possible to use `&(@(unique: artist), @(unique: album))` to have one song per artist and one song per album
  • Loading branch information
LoveIsGrief committed Feb 6, 2023
1 parent d34690e commit 99a8a1e
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 29 deletions.
1 change: 1 addition & 0 deletions po/POTFILES.in
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ quodlibet/ext/query/conditional.py
quodlibet/ext/query/missing.py
quodlibet/ext/query/pythonexpression.py
quodlibet/ext/query/savedsearch.py
quodlibet/ext/query/unique.py
quodlibet/ext/_shared/squeezebox/base.py
quodlibet/ext/_shared/squeezebox/server.py
quodlibet/ext/_shared/squeezebox/util.py
Expand Down
70 changes: 41 additions & 29 deletions po/en_GB.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Quod Libet 2.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-04-25 11:38+0100\n"
"POT-Creation-Date: 2023-02-06 21:53+0100\n"
"PO-Revision-Date: 2021-11-05 03:34+0000\n"
"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
"Language-Team: English (United Kingdom) <https://hosted.weblate.org/projects/"
Expand Down Expand Up @@ -234,7 +234,7 @@ msgstr ""
#: quodlibet/qltk/data_editors.py:303 quodlibet/qltk/data_editors.py:316
#: quodlibet/qltk/data_editors.py:327 quodlibet/qltk/edittags.py:554
#: quodlibet/qltk/edittags.py:742 quodlibet/qltk/maskedbox.py:48
#: quodlibet/qltk/maskedbox.py:88 quodlibet/qltk/queue.py:479
#: quodlibet/qltk/maskedbox.py:88 quodlibet/qltk/queue.py:507
#: quodlibet/qltk/scanbox.py:38 quodlibet/qltk/scanbox.py:66
msgid "_Remove"
msgstr ""
Expand Down Expand Up @@ -275,7 +275,7 @@ msgstr ""
#: quodlibet/ext/songsmenu/fingerprint/search.py:281
#: quodlibet/ext/songsmenu/fingerprint/submit.py:90
#: quodlibet/ext/songsmenu/lastfmsync.py:203
#: quodlibet/ext/songsmenu/playlist.py:50
#: quodlibet/ext/songsmenu/playlist.py:55
#: quodlibet/ext/songsmenu/replaygain.py:353
#: quodlibet/ext/songsmenu/tapbpm.py:186 quodlibet/qltk/chooser.py:188
#: quodlibet/qltk/chooser.py:209 quodlibet/qltk/chooser.py:233
Expand Down Expand Up @@ -582,7 +582,7 @@ msgstr ""
#: quodlibet/browsers/podcasts.py:67 quodlibet/browsers/podcasts.py:69
#: quodlibet/browsers/podcasts.py:179
#: quodlibet/ext/songsmenu/fingerprint/search.py:46
#: quodlibet/order/__init__.py:29 quodlibet/qltk/information.py:242
#: quodlibet/order/__init__.py:31 quodlibet/qltk/information.py:242
#: quodlibet/qltk/information.py:249 quodlibet/qltk/information.py:275
#: quodlibet/qltk/pluginwin.py:53 quodlibet/qltk/wlw.py:69
msgid "Unknown"
Expand Down Expand Up @@ -1762,7 +1762,7 @@ msgstr ""
#: quodlibet/ext/songsmenu/cover_download.py:386
#: quodlibet/ext/songsmenu/fingerprint/search.py:278
#: quodlibet/ext/songsmenu/html.py:76 quodlibet/ext/songsmenu/lastfmsync.py:204
#: quodlibet/ext/songsmenu/playlist.py:51
#: quodlibet/ext/songsmenu/playlist.py:56
#: quodlibet/ext/songsmenu/replaygain.py:354
#: quodlibet/ext/songsmenu/tapbpm.py:187 quodlibet/qltk/_editutils.py:42
#: quodlibet/qltk/lyrics.py:32 quodlibet/qltk/msg.py:57
Expand Down Expand Up @@ -3322,7 +3322,7 @@ msgid "Exports a playlist by copying files to a folder."
msgstr ""

#: quodlibet/ext/playlist/export_to_folder.py:121
#: quodlibet/ext/songsmenu/playlist.py:132
#: quodlibet/ext/songsmenu/playlist.py:143
msgid "Unable to export playlist"
msgstr ""

Expand Down Expand Up @@ -3652,6 +3652,18 @@ msgstr ""
msgid "@(saved: search-name)"
msgstr ""

#: quodlibet/ext/query/unique.py:24
msgid "Unique Query"
msgstr ""

#: quodlibet/ext/query/unique.py:25
msgid "Filter search results by unique tags."
msgstr ""

#: quodlibet/ext/query/unique.py:27
msgid "@(unique: tag)"
msgstr ""

#: quodlibet/ext/_shared/squeezebox/base.py:77
#, python-format
msgid "Squeezebox OK. Using the only player (%s)."
Expand Down Expand Up @@ -4667,23 +4679,23 @@ msgstr ""
msgid "Converts album and artist names to sort names, poorly."
msgstr ""

#: quodlibet/ext/songsmenu/playlist.py:31
#: quodlibet/ext/songsmenu/playlist.py:36
msgid "Export as M3U / PLS Playlist File"
msgstr ""

#: quodlibet/ext/songsmenu/playlist.py:32
#: quodlibet/ext/songsmenu/playlist.py:37
msgid "Exports songs to an M3U or PLS playlist."
msgstr ""

#: quodlibet/ext/songsmenu/playlist.py:77
#: quodlibet/ext/songsmenu/playlist.py:82
msgid "Use relative paths"
msgstr ""

#: quodlibet/ext/songsmenu/playlist.py:77
#: quodlibet/ext/songsmenu/playlist.py:82
msgid "Use absolute paths"
msgstr ""

#: quodlibet/ext/songsmenu/playlist.py:133
#: quodlibet/ext/songsmenu/playlist.py:144
#, python-format
msgid "Writing to %s failed."
msgstr ""
Expand Down Expand Up @@ -5125,15 +5137,15 @@ msgstr ""
msgid "'%(column-id)s' is not a valid column name (%(all-column-ids)s)."
msgstr ""

#: quodlibet/order/__init__.py:32
#: quodlibet/order/__init__.py:34
msgid "_Unknown"
msgstr ""

#: quodlibet/order/__init__.py:144
#: quodlibet/order/__init__.py:149
msgid "In Order"
msgstr ""

#: quodlibet/order/__init__.py:145
#: quodlibet/order/__init__.py:150
msgid "_In Order"
msgstr ""

Expand All @@ -5145,11 +5157,11 @@ msgstr ""
msgid "_Random"
msgstr ""

#: quodlibet/order/reorder.py:40
#: quodlibet/order/reorder.py:39
msgid "Prefer higher rated"
msgstr ""

#: quodlibet/order/reorder.py:41
#: quodlibet/order/reorder.py:40
msgid "Prefer _higher rated"
msgstr ""

Expand Down Expand Up @@ -5675,15 +5687,15 @@ msgid "The files currently selected do not support multiple values for %s."
msgstr "The current backend does not support equalisation."

#. Can't add the new tag.
#: quodlibet/qltk/edittags.py:798 quodlibet/qltk/edittags.py:979
#: quodlibet/qltk/edittags.py:798 quodlibet/qltk/edittags.py:981
#: quodlibet/qltk/tagsfrompath.py:211 quodlibet/util/__init__.py:511
#: quodlibet/util/tags.py:244
msgid "Invalid tag"
msgid_plural "Invalid tags"
msgstr[0] ""
msgstr[1] ""

#: quodlibet/qltk/edittags.py:799 quodlibet/qltk/edittags.py:980
#: quodlibet/qltk/edittags.py:799 quodlibet/qltk/edittags.py:982
#: quodlibet/qltk/tagsfrompath.py:212
#, fuzzy, python-format
msgid ""
Expand All @@ -5709,11 +5721,11 @@ msgstr[1] ""
"\n"
"The files currently selected do not support editing these tags."

#: quodlibet/qltk/edittags.py:950 quodlibet/qltk/edittags.py:991
#: quodlibet/qltk/edittags.py:952 quodlibet/qltk/edittags.py:995
msgid "Invalid value"
msgstr ""

#: quodlibet/qltk/edittags.py:951 quodlibet/qltk/edittags.py:992
#: quodlibet/qltk/edittags.py:953 quodlibet/qltk/edittags.py:996
#, python-format
msgid ""
"Invalid value: %(value)s\n"
Expand Down Expand Up @@ -6977,39 +6989,39 @@ msgstr ""
msgid "_Filter on %s"
msgstr ""

#: quodlibet/qltk/songlist.py:1174
#: quodlibet/qltk/songlist.py:1182
msgid "All _Headers"
msgstr ""

#: quodlibet/qltk/songlist.py:1175
#: quodlibet/qltk/songlist.py:1183
msgid "_Track Headers"
msgstr ""

#: quodlibet/qltk/songlist.py:1176
#: quodlibet/qltk/songlist.py:1184
msgid "_Album Headers"
msgstr ""

#: quodlibet/qltk/songlist.py:1177
#: quodlibet/qltk/songlist.py:1185
msgid "_People Headers"
msgstr ""

#: quodlibet/qltk/songlist.py:1178
#: quodlibet/qltk/songlist.py:1186
msgid "_Date Headers"
msgstr ""

#: quodlibet/qltk/songlist.py:1179
#: quodlibet/qltk/songlist.py:1187
msgid "_File Headers"
msgstr ""

#: quodlibet/qltk/songlist.py:1180
#: quodlibet/qltk/songlist.py:1188
msgid "_Production Headers"
msgstr ""

#: quodlibet/qltk/songlist.py:1195
#: quodlibet/qltk/songlist.py:1203
msgid "_Customize Headers…"
msgstr "_Customise Headers…"

#: quodlibet/qltk/songlist.py:1200
#: quodlibet/qltk/songlist.py:1208
msgid "_Expand Column"
msgstr ""

Expand Down
54 changes: 54 additions & 0 deletions quodlibet/ext/query/unique.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright (C) 2023 LoveIsGrief
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

from quodlibet import _, print_d, print_w
from quodlibet.plugins.query import QueryPlugin, QueryPluginError


class UniqueQuery(QueryPlugin):
PLUGIN_ID = "unique_query"
PLUGIN_NAME = _("Unique Query")
PLUGIN_DESC = _("Filter search results by unique tags.")
key = 'unique'
query_syntax = _("@(unique: tag)")
query_description = "<tt>tag</tt> can be album, artist, title or any other tag. " \
"Use multiple <tt>@(unique: tag)</tt> to filter by multiple tags."

usage = f"{query_syntax}\n\n{query_description}"

def __init__(self):
print_d("Initialising unique query")
self.unique_tag_values = set()
"""The unique tag values that have been seen in the songs being filtered"""
self._reported = set()
"""Unique errors to counter error log spam"""

def search(self, data, body):
return_value = False
try:
field_value = data[body]
return_value = field_value not in self.unique_tag_values
self.unique_tag_values.add(field_value)
print_d(f"unique filtering value '{field_value}': {return_value}")
except KeyError:
pass
except Exception as e:
err_str = str(e)
if err_str not in self._reported:
self._reported.add(err_str)
print_w("%s while filtering unique values for '%s': %s "
% (type(e).__name__, body, err_str))
return return_value

def parse_body(self, body):
self.unique_tag_values.clear()
if body is None:
raise QueryPluginError
unique_tag = body.strip()
print_d(f"unique filtering tag: {unique_tag}")
self._reported.clear()
return unique_tag

0 comments on commit 99a8a1e

Please sign in to comment.