From 288902a572c0ff92b9019cb0f2f633e9c8a4af42 Mon Sep 17 00:00:00 2001 From: Philippe Mongeau Date: Thu, 14 Jun 2012 18:47:40 -0400 Subject: [PATCH] add experimental fuzzy matching plugin fuzzy is a command which tries to be like the list command but using fuzzy matching. --- beetsplug/fuzzy_list.py | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 beetsplug/fuzzy_list.py diff --git a/beetsplug/fuzzy_list.py b/beetsplug/fuzzy_list.py new file mode 100644 index 000000000..ca409dcdf --- /dev/null +++ b/beetsplug/fuzzy_list.py @@ -0,0 +1,84 @@ +# This file is part of beets. +# Copyright 2011, Philippe Mongeau. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +"""Get a random song or album from the library. +""" +from beets.plugins import BeetsPlugin +from beets.ui import Subcommand, decargs, print_ +from beets.util.functemplate import Template +import random +import difflib + +def fuzzy_score(query, item): + return difflib.SequenceMatcher(a=query, b=item).quick_ratio() + +def is_match(query, item, verbose=False): + query = ' '.join(query) + s = max(fuzzy_score(query, i) for i in (item.artist, + item.album, + item.title)) + if s > 0.7: return (True, s) if verbose else True + else: return (False, s) if verbose else False + +def fuzzy_list(lib, config, opts, args): + query = decargs(args) + path = opts.path + fmt = opts.format + verbose = opts.verbose + + if fmt is None: + # If no specific template is supplied, use a default + if opts.album: + fmt = u'$albumartist - $album' + else: + fmt = u'$artist - $album - $title' + template = Template(fmt) + + if opts.album: + objs = list(lib.albums()) + else: + objs = list(lib.items()) + + # matches = [i for i in objs if is_match(query, i)] + + if opts.album: + for album in objs: + if path: + print_(album.item_dir()) + else: + print_(album.evaluate_template(template)) + else: + for item in objs: + if is_match(query, item): + if path: + print_(item.path) + else: + print_(item.evaluate_template(template, lib)) + if verbose: print is_match(query,item, True)[1] + +fuzzy_cmd = Subcommand('fuzzy', + help='list items using fuzzy matching') +fuzzy_cmd.parser.add_option('-a', '--album', action='store_true', + help='choose an album instead of track') +fuzzy_cmd.parser.add_option('-p', '--path', action='store_true', + help='print the path of the matched item') +fuzzy_cmd.parser.add_option('-f', '--format', action='store', + help='print with custom format', default=None) +fuzzy_cmd.parser.add_option('-v', '--verbose', action='store_true', + help='output scores for matches') +fuzzy_cmd.func = fuzzy_list + +class Random(BeetsPlugin): + def commands(self): + return [fuzzy_cmd]