X-Git-Url: http://git.kaliko.me/?a=blobdiff_plain;f=simadb_cli;h=b720a0d5abdd341e2a168a881afefd08b39d5527;hb=1968c2cb249b9230f00f9749017770ab933582c0;hp=52f45bcae39c2bf2a7e78bfd87c6acfa71ecb496;hpb=563504b3c2f42a4f9617e381d95176f167afce55;p=mpd-sima.git diff --git a/simadb_cli b/simadb_cli index 52f45bc..b720a0d 100755 --- a/simadb_cli +++ b/simadb_cli @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2010-2013 Jack Kaliko +# Copyright (c) 2010-2015 Jack Kaliko # # This file is part of MPD_sima # @@ -20,12 +20,10 @@ # # -__version__ = '0.4.0' +__version__ = '0.4.1' # IMPORT# -import re - -from argparse import (ArgumentParser, SUPPRESS, Action) +from argparse import (ArgumentParser, SUPPRESS) from difflib import get_close_matches from locale import getpreferredencoding from os import (environ, chmod, makedirs) @@ -35,7 +33,7 @@ from sys import (exit, stdout, stderr) from sima.lib.track import Track from sima.utils import utils from sima.lib import simadb -from musicpd import MPDClient, ConnectionError +from musicpd import MPDClient, MPDError DESCRIPTION = """ @@ -43,68 +41,15 @@ simadb_cli helps you to edit entries in your own DB of similarity between artists.""" DB_NAME = 'sima.db' -class FooAction(Action): - def check(self, namespace): - if namespace.similarity: return True - if namespace.remove_art: return True - if namespace.remove_sim: return True - - def __call__(self, parser, namespace, values, option_string=None): - opt_required = '"--remove_artist", "--remove_similarity" or "--add_similarity"' - if not self.check(namespace): - parser.error( - 'can\'t use {0} option before or without {1}'.format( - option_string, opt_required)) - setattr(namespace, self.dest, True) - # Options list # pop out 'sw' value before creating ArgumentParser object. OPTS = list([ - { - 'sw':['-a', '--add_similarity'], - 'type': str, - 'dest':'similarity', - 'help': 'Similarity to add formated as follow: ' + - ' "art_0,art_1:90,art_2:80..."'}, - { - 'sw': ['-c', '--check_names'], - 'action': 'store_true', - 'default': False, - 'help': 'Turn on controls of artists names in MPD library.'}, { 'sw':['-d', '--dbfile'], 'type': str, 'dest':'dbfile', 'action': utils.Wfile, 'help': 'File to read/write database from/to'}, - { - 'sw': ['-r', '--reciprocal'], - 'default': False, - 'nargs': 0, - 'action': FooAction, - 'help': 'Turn on reciprocity for similarity relation when add/remove.'}, - { - 'sw':['--remove_artist'], - 'type': str, - 'dest': 'remove_art', - 'metavar': '"ARTIST TO REMOVE"', - 'help': 'Remove an artist from DB (main artist entries).'}, - { - 'sw':['--remove_similarity'], - 'type': str, - 'dest': 'remove_sim', - 'metavar': '"MAIN ART,SIMI ART"', - 'help': 'Remove an similarity relation from DB (main artist <=> similar artist).'}, - { - 'sw':['-v', '--view_artist'], - 'type': str, - 'dest':'view', - 'metavar': '"ARTIST NAME"', - 'help': 'View an artist from DB.'}, - { - 'sw':['--view_all'], - 'action': 'store_true', - 'help': 'View all similarity entries.'}, { 'sw': ['-S', '--host'], 'type': str, @@ -126,6 +71,7 @@ OPTS = list([ { 'sw': ['--view_bl'], 'action': 'store_true', + 'dest': 'view_bl', 'help': 'View black list.'}, { 'sw': ['--remove_bl'], @@ -165,7 +111,6 @@ class SimaDB_CLI(object): self.options = dict({}) self.localencoding = 'UTF-8' self._get_encoding() - self._upgrade() self.main() def _get_encoding(self): @@ -193,13 +138,6 @@ class SimaDB_CLI(object): else: self.options.mpdport = 6600 - def _upgrade(self): - """Upgrades DB if necessary, create one if not existing.""" - if not isfile(self.dbfile): # No db file - return - db = simadb.SimaDB(db_path=self.dbfile) - db.upgrade() - def _declare_opts(self): """ Declare options in ArgumentParser object. @@ -236,14 +174,16 @@ class SimaDB_CLI(object): def _get_mpd_client(self): """""" - # TODO: encode properly host name host = self.options.mpdhost port = self.options.mpdport + passwd = self.options.passwd cli = MPDClient() try: - cli.connect(host=host, port=port) - except ConnectionError as err: - mess = 'ERROR: fail to connect MPD (host: %s:%s): %s' % ( + cli.connect(host, port) + if passwd: + cli.password(passwd) + except MPDError as err: + mess = 'ERROR: fail to connect MPD on %s:%s %s' % ( host, port, err) print(mess, file=stderr) exit(1) @@ -266,99 +206,9 @@ class SimaDB_CLI(object): return None return art_db - def _control_similarity(self): - """ - * Regex check of command line similarity - * Controls artist presence in MPD library - """ - usage = ('USAGE: "main artist,similar artist:,other' + - 'similar artist:,..."') - cli_sim = self.options.similarity - pattern = '^([^,]+?),([^:,]+?:\d{1,2},?)+$' - regexp = re.compile(pattern, re.U).match(cli_sim) - if not regexp: - mess = 'ERROR: similarity badly formated: "%s"' % cli_sim - print(mess, file=stderr) - print(usage, file=stderr) - exit(1) - if self.options.check_names: - if not self._control_artist_names(): - mess = 'ERROR: some artist names not found in MPD library!' - print(mess, file=stderr) - exit(1) - - def _control_artist_names(self): - """Controls artist names exist in MPD library""" - mpd_cli = self._get_mpd_client() - artists_list = mpd_cli.list('artist') - sim_formated = self._parse_similarity() - control = True - if sim_formated[0] not in artists_list: - mess = 'WARNING: Main artist not found in MPD: %s' % sim_formated[0] - print(mess) - control = False - for sart in sim_formated[1]: - art = sart.get('artist') - if art not in artists_list: - mess = str('WARNING: Similar artist not found in MPD: %s' % art) - print(mess) - control = False - mpd_cli.disconnect() - return control - - def _parse_similarity(self): - """Parse command line option similarity""" - cli_sim = self.options.similarity.strip(',').split(',') - sim = list([]) - main = cli_sim[0] - for art in cli_sim[1:]: - artist = art.split(':')[0] - score = int(art.split(':')[1]) - sim.append({'artist': artist, 'score': score}) - return (main, sim) - - def _print_main_art(self, art=None): - """Print entries, art as main artist.""" - if not art: - art = self.options.view - db = simadb.SimaDB(db_path=self.dbfile) - art_db = self._get_art_from_db(art) - if not art_db: return - sims = list([]) - [sims.append(a) for a in db._get_similar_artists_from_db(art_db[0])] - if len(sims) == 0: - return False - print('"%s" similarities:' % art) - for art in sims: - mess = str(' - {score:0>2d} {artist}'.format(**art)) - print(mess) - return True - - def _remove_sim(self, art1_db, art2_db): - """Remove single similarity between two artists.""" - db = simadb.SimaDB(db_path=self.dbfile) - similarity = db._get_artist_match(art1_db[0], art2_db[0]) - if similarity == 0: - return False - db._remove_relation_between_2_artist(art1_db[0], art2_db[0]) - mess = 'Remove: "{0}" "{1}:{2:0>2d}"'.format(art1_db[1], art2_db[1], - similarity) - print(mess) - return True - - def _revert_similarity(self, sim_formated): - """Revert similarity string (for reciprocal editing - add).""" - main_art = sim_formated[0] - similars = sim_formated[1] - for similar in similars: - yield (similar.get('artist'), - [{'artist':main_art, 'score':similar.get('score')}]) - def bl_artist(self): """Black list artist""" mpd_cli = self._get_mpd_client() - if not mpd_cli: - return False artists_list = mpd_cli.list('artist') # Unicode cli given artist name cli_artist_to_bl = self.options.bl_art @@ -376,8 +226,6 @@ class SimaDB_CLI(object): def bl_current_artist(self): """Black list current artist""" mpd_cli = self._get_mpd_client() - if not mpd_cli: - return False artist = mpd_cli.currentsong().get('artist', '') if not artist: print('No artist found.') @@ -389,8 +237,6 @@ class SimaDB_CLI(object): def bl_current_album(self): """Black list current artist""" mpd_cli = self._get_mpd_client() - if not mpd_cli: - return False track = Track(**mpd_cli.currentsong()) if not track.album: print('No album set for this track: %s' % track) @@ -402,8 +248,6 @@ class SimaDB_CLI(object): def bl_current_track(self): """Black list current artist""" mpd_cli = self._get_mpd_client() - if not mpd_cli: - return False track = Track(**mpd_cli.currentsong()) print('Black listing track: %s' % track) db = simadb.SimaDB(db_path=self.dbfile) @@ -419,31 +263,6 @@ class SimaDB_CLI(object): db.clean_database() print('done.') - def view(self): - """Print out entries for an artist.""" - art = self.options.view - db = simadb.SimaDB(db_path=self.dbfile) - art_db = self._get_art_from_db(art) - if not art_db: return - if not self._print_main_art(): - mess = str('"%s" present in DB but not as a main artist' % art) - print(mess) - else: print('') - art_rev = list([]) - [art_rev.append(a) for a in db._get_reverse_similar_artists_from_db(art_db[0])] - if not art_rev: return - mess = str('%s" appears as similar for the following artist(s): %s' % - (art,', '.join(art_rev))) - print(mess) - [self._print_main_art(a) for a in art_rev] - - def view_all(self): - """Print out all entries.""" - db = simadb.SimaDB(db_path=self.dbfile) - for art in db.get_artists(): - if not art[0]: continue - self._print_main_art(art=art[0]) - def view_bl(self): """Print out black list.""" # TODO: enhance output formating @@ -451,60 +270,11 @@ class SimaDB_CLI(object): for bl_e in db.get_black_list(): print('\t# '.join([str(e) for e in bl_e])) - def remove_similarity(self): - """Remove entry""" - cli_sim = self.options.remove_sim - pattern = '^([^,]+?),([^,]+?,?)$' - regexp = re.compile(pattern, re.U).match(cli_sim) - if not regexp: - print('ERROR: similarity badly formated: "%s"' % cli_sim, file=stderr) - print('USAGE: A single relation between two artists is expected here.', file=stderr) - print('USAGE: "main artist,similar artist"', file=stderr) - exit(1) - arts = cli_sim.split(',') - if len(arts) != 2: - print('ERROR: unknown error in similarity format', file=stderr) - print('USAGE: "main artist,similar artist"', file=stderr) - exit(1) - art1_db = self._get_art_from_db(arts[0].strip()) - art2_db = self._get_art_from_db(arts[1].strip()) - if not art1_db or not art2_db: return - self._remove_sim(art1_db, art2_db) - if not self.options.reciprocal: - return - self._remove_sim(art2_db, art1_db) - - def remove_artist(self): - """ Remove artist in the DB.""" - deep = False - art = self.options.remove_art - db = simadb.SimaDB(db_path=self.dbfile) - art_db = self._get_art_from_db(art) - if not art_db: return False - print('Removing "%s" from database' % art) - if self.options.reciprocal: - print('reciprocal option used, performing deep remove!') - deep = True - db._remove_artist(art_db[0], deep=deep) - def remove_black_list_entry(self): """""" db = simadb.SimaDB(db_path=self.dbfile) db._remove_bl(int(self.options.remove_bl)) - def write_simi(self): - """Write similarity to DB. - """ - self._create_db() - sim_formated = self._parse_similarity() - print('About to update DB with: "%s": %s' % sim_formated) - db = simadb.SimaDB(db_path=self.dbfile) - db._update_similar_artists(*sim_formated) - if self.options.reciprocal: - print('...and with reciprocal combinations as well.') - for sim_formed_rec in self._revert_similarity(sim_formated): - db._update_similar_artists(*sim_formed_rec) - def main(self): """ Parse command line and run actions. @@ -515,8 +285,6 @@ class SimaDB_CLI(object): if self.options.dbfile: self.dbfile = self.options.dbfile print('Using db file: %s' % self.dbfile) - if self.options.reciprocal: - print('Editing reciprocal similarity') if self.options.bl_art: self.bl_artist() return @@ -535,32 +303,18 @@ class SimaDB_CLI(object): if self.options.remove_bl: self.remove_black_list_entry() return - if self.options.similarity: - self._control_similarity() - self.write_simi() - return - if self.options.remove_art: - self.remove_artist() - return - if self.options.remove_sim: - self.remove_similarity() - return - if self.options.view: - self.view() - return - if self.options.view_all: - self.view_all() if self.options.do_purge_hist: self.purge_history() exit(0) -def main(): - SimaDB_CLI() - # Script starts here if __name__ == '__main__': - main() + try: + SimaDB_CLI() + except Exception as err: + print(err) + exit(1) # VIM MODLINE # vim: ai ts=4 sw=4 sts=4 expandtab