From 2839302d53fde011cd2cff90f265ab71eddbf0f7 Mon Sep 17 00:00:00 2001 From: J0J0 Todos Date: Thu, 22 Dec 2022 17:45:34 +0100 Subject: [PATCH 1/5] fromfilename: Swap regex lines as suggested in #4561 --- beetsplug/fromfilename.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/fromfilename.py b/beetsplug/fromfilename.py index 55684a274..c216a654e 100644 --- a/beetsplug/fromfilename.py +++ b/beetsplug/fromfilename.py @@ -29,8 +29,8 @@ PATTERNS = [ r'^(?P\d+)[\s.\-_]+(?P.+)[\-_](?P.+)[\-_](?P<tag>.*)$', r'^(?P<artist>.+)[\-_](?P<title>.+)$', r'^(?P<track>\d+)[\s.\-_]+(?P<artist>.+)[\-_](?P<title>.+)$', - r'^(?P<title>.+)$', r'^(?P<track>\d+)[\s.\-_]+(?P<title>.+)$', + r'^(?P<title>.+)$', r'^(?P<track>\d+)\s+(?P<title>.+)$', r'^(?P<title>.+) by (?P<artist>.+)$', r'^(?P<track>\d+).*$', From 5461ddf9f21c0301d7d65ee149b778c4ab76304b Mon Sep 17 00:00:00 2001 From: J0J0 Todos <jojo@peek-a-boo.at> Date: Wed, 28 Dec 2022 09:30:21 +0100 Subject: [PATCH 2/5] fromfilename: Move <title> regex to the very end since it's the least significant as discussed in the PR's thread. --- beetsplug/fromfilename.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beetsplug/fromfilename.py b/beetsplug/fromfilename.py index c216a654e..74004a502 100644 --- a/beetsplug/fromfilename.py +++ b/beetsplug/fromfilename.py @@ -30,10 +30,10 @@ PATTERNS = [ r'^(?P<artist>.+)[\-_](?P<title>.+)$', r'^(?P<track>\d+)[\s.\-_]+(?P<artist>.+)[\-_](?P<title>.+)$', r'^(?P<track>\d+)[\s.\-_]+(?P<title>.+)$', - r'^(?P<title>.+)$', r'^(?P<track>\d+)\s+(?P<title>.+)$', r'^(?P<title>.+) by (?P<artist>.+)$', r'^(?P<track>\d+).*$', + r'^(?P<title>.+)$', ] # Titles considered "empty" and in need of replacement. From c1abcf33103dbc04f5490525ca24d1da4c14851b Mon Sep 17 00:00:00 2001 From: J0J0 T <jojo@peek-a-boo.at> Date: Wed, 23 Mar 2022 21:23:19 +0100 Subject: [PATCH 3/5] fromfilename: Add debug log messages that inform when the plugin replaced bad artist, title or tracknumber metadata. --- beetsplug/fromfilename.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/beetsplug/fromfilename.py b/beetsplug/fromfilename.py index 74004a502..1697b7081 100644 --- a/beetsplug/fromfilename.py +++ b/beetsplug/fromfilename.py @@ -18,9 +18,11 @@ filename. from beets import plugins from beets.util import displayable_path +from beets import logging import os import re +log = logging.getLogger('beets') # Filename field extraction patterns. PATTERNS = [ @@ -113,6 +115,9 @@ def apply_matches(d): for item in d: if not item.artist: item.artist = artist + log.debug( + 'fromfilename: Artist replaced with: {}' + .format(item.artist)) # No artist field: remaining field is the title. else: @@ -122,8 +127,14 @@ def apply_matches(d): for item in d: if bad_title(item.title): item.title = str(d[item][title_field]) + log.debug( + 'fromfilename: Title replaced with: {}' + .format(item.title)) if 'track' in d[item] and item.track == 0: item.track = int(d[item]['track']) + log.debug( + 'fromfilename: Track replaced with: {}' + .format(item.track)) # Plugin structure and hook into import process. From 688ad4aad50599b62f47d656e326d1710eb0a9a0 Mon Sep 17 00:00:00 2001 From: J0J0 Todos <jojo@peek-a-boo.at> Date: Wed, 28 Dec 2022 11:37:55 +0100 Subject: [PATCH 4/5] fromfilename: Changelog for #4600 --- docs/changelog.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index c7f3eb614..6acfe9274 100755 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -49,6 +49,9 @@ New features: :bug:`4438` * Add a new ``import.ignored_alias_types`` config option to allow for specific alias types to be skipped over when importing items/albums. +* :doc:`/plugins/fromfilename`: Add debug log messages that inform when the + plugin replaced bad (missing) artist, title or tracknumber metadata. + :bug:`4561` :bug:`4600` Bug fixes: @@ -122,6 +125,9 @@ Bug fixes: * :doc:`plugins/lyrics`: Fixed issue with Tekstowo backend not actually checking if the found song matches. :bug:`4406` +* :doc:`/plugins/fromfilename`: Fix failed detection of <track> <title> + filename patterns. + :bug:`4561` :bug:`4600` For packagers: From 6fb6f59c404593fc713510d3bf347326941ad37b Mon Sep 17 00:00:00 2001 From: J0J0 Todos <jojo@peek-a-boo.at> Date: Sat, 31 Dec 2022 08:46:31 +0100 Subject: [PATCH 5/5] fromfilename: Use logging magic from inherited BeetsPlugin and change log level to INFO. --- beetsplug/fromfilename.py | 67 +++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/beetsplug/fromfilename.py b/beetsplug/fromfilename.py index 1697b7081..6d7e3d009 100644 --- a/beetsplug/fromfilename.py +++ b/beetsplug/fromfilename.py @@ -18,12 +18,9 @@ filename. from beets import plugins from beets.util import displayable_path -from beets import logging import os import re -log = logging.getLogger('beets') - # Filename field extraction patterns. PATTERNS = [ # Useful patterns. @@ -87,7 +84,7 @@ def bad_title(title): return False -def apply_matches(d): +def apply_matches(d, log): """Given a mapping from items to field dicts, apply the fields to the objects. """ @@ -115,9 +112,7 @@ def apply_matches(d): for item in d: if not item.artist: item.artist = artist - log.debug( - 'fromfilename: Artist replaced with: {}' - .format(item.artist)) + log.info('Artist replaced with: {}'.format(item.artist)) # No artist field: remaining field is the title. else: @@ -127,14 +122,11 @@ def apply_matches(d): for item in d: if bad_title(item.title): item.title = str(d[item][title_field]) - log.debug( - 'fromfilename: Title replaced with: {}' - .format(item.title)) + log.info('Title replaced with: {}'.format(item.title)) + if 'track' in d[item] and item.track == 0: item.track = int(d[item]['track']) - log.debug( - 'fromfilename: Track replaced with: {}' - .format(item.track)) + log.info('Track replaced with: {}'.format(item.track)) # Plugin structure and hook into import process. @@ -142,32 +134,31 @@ def apply_matches(d): class FromFilenamePlugin(plugins.BeetsPlugin): def __init__(self): super().__init__() - self.register_listener('import_task_start', filename_task) + self.register_listener('import_task_start', self.filename_task) + def filename_task(self, task, session): + """Examine each item in the task to see if we can extract a title + from the filename. Try to match all filenames to a number of + regexps, starting with the most complex patterns and successively + trying less complex patterns. As soon as all filenames match the + same regex we can make an educated guess of which part of the + regex that contains the title. + """ + items = task.items if task.is_album else [task.item] -def filename_task(task, session): - """Examine each item in the task to see if we can extract a title - from the filename. Try to match all filenames to a number of - regexps, starting with the most complex patterns and successively - trying less complex patterns. As soon as all filenames match the - same regex we can make an educated guess of which part of the - regex that contains the title. - """ - items = task.items if task.is_album else [task.item] + # Look for suspicious (empty or meaningless) titles. + missing_titles = sum(bad_title(i.title) for i in items) - # Look for suspicious (empty or meaningless) titles. - missing_titles = sum(bad_title(i.title) for i in items) + if missing_titles: + # Get the base filenames (no path or extension). + names = {} + for item in items: + path = displayable_path(item.path) + name, _ = os.path.splitext(os.path.basename(path)) + names[item] = name - if missing_titles: - # Get the base filenames (no path or extension). - names = {} - for item in items: - path = displayable_path(item.path) - name, _ = os.path.splitext(os.path.basename(path)) - names[item] = name - - # Look for useful information in the filenames. - for pattern in PATTERNS: - d = all_matches(names, pattern) - if d: - apply_matches(d) + # Look for useful information in the filenames. + for pattern in PATTERNS: + d = all_matches(names, pattern) + if d: + apply_matches(d, self._log)