From: kaliko Date: Sun, 9 May 2021 09:48:57 +0000 (+0200) Subject: Add blocklist commands, remove simadb_cli X-Git-Tag: 0.18.0~56 X-Git-Url: https://git.kaliko.me/?a=commitdiff_plain;h=3636f8f37183e1b1f1c581b4edfff1b1abd70462;p=mpd-sima.git Add blocklist commands, remove simadb_cli Move all command to a subparser --- diff --git a/data/man/simadb_cli.1 b/data/man/simadb_cli.1 deleted file mode 100644 index cc893d8..0000000 --- a/data/man/simadb_cli.1 +++ /dev/null @@ -1,210 +0,0 @@ -'\" t -.\" Title: simadb_cli -.\" Author: kaliko -.\" Generator: DocBook XSL Stylesheets v1.79.2 -.\" Date: 04/19/2021 -.\" Manual: mpd-sima 0.17.0 User Manual -.\" Source: mpd-sima -.\" Language: English -.\" -.TH "SIMADB_CLI" "1" "04/19/2021" "mpd-sima" "mpd-sima 0.17.0 User Manual" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -simadb_cli \- simadb_cli is a command line interface editor for the sima user DB\&. -.SH "SYNOPSIS" -.HP \w'\fBsimadb_cli\fR\ 'u -\fBsimadb_cli\fR \fB\-\-remove_artist=\fR\fIartist\fR [\fB\-\-dbfile=\fR\fIdb_file\fR] [\fB\-\-reciprocal\fR] -.HP \w'\fBsimadb_cli\fR\ 'u -\fBsimadb_cli\fR \fB\-\-purge_hist\fR [\fB\-\-dbfile=\fR\fIdb_file\fR] -.HP \w'\fBsimadb_cli\fR\ 'u -\fBsimadb_cli\fR \fB\-\-view_all\fR [\fB\-\-dbfile=\fR\fIdb_file\fR] -.HP \w'\fBsimadb_cli\fR\ 'u -\fBsimadb_cli\fR {\fB\-\-bl_curr_trk\fR | \fB\-\-bl_curr_art\fR | \fB\-\-bl_curr_alb\fR | \fB\-\-bl_art=\fR\fIartist_name\fR} [\fB\-\-dbfile=\fR\fIdb_file\fR] [\fB\-\-host=\fR\fImpd_host\fR] [\fB\-\-port=\fR\fImpd_port\fR] -.HP \w'\fBsimadb_cli\fR\ 'u -\fBsimadb_cli\fR \fB\-\-remove_bl=\fR\fIrow_id\fR [\fB\-\-dbfile=\fR\fIdb_file\fR] -.HP \w'\fBsimadb_cli\fR\ 'u -\fBsimadb_cli\fR \fB\-\-view_bl\fR [\fB\-\-dbfile=\fR\fIdb_file\fR] -.HP \w'\fBsimadb_cli\fR\ 'u -\fBsimadb_cli\fR {{\fB\-h\fR\ |\ \fB\-\-help\fR} | \fB\-\-version\fR} -.SH "DESCRIPTION" -.PP -This manual page documents briefly the -\fBsimadb_cli\fR -commands\&. -.PP -simadb_cli is a command line interface to get and edit users blacklist database used with MPD_sima\&. The default database file (see -the section called \(lqFILES\(rq) can be overridden if you want\&. -.SH "EXAMPLE" -.SS "Black list edition" -.PP -\fIAdding to black list\&.\fR -You can add a single track, an album or an artist to the black list\&. The element to black list is chosen from the currently playing track\&. Use -\fB\-\-bl_curr_trk\fR -to prevent simadb_cli to queue this track, -\fB\-\-bl_curr_alb\fR -or -\fB\-\-bl_curr_art\fR -respectively for the album and the artist\&. -.PP -Remember you need access to your MPD server to retrieve information to black list\&. Defaults are localhost:6600 or found in environment variables but you may set it up from command line: -.PP -\fBsimadb_cli \-\-bl_curr_art \-S mympd\&.example\&.org\fR -.PP -\fITo black list a specific artist\fR -(not currently playing) you can use -\fB\-\-bl_ar="Artist name to black list"\fR\&. -.SH "OPTIONS" -.PP -The program follows the usual GNU command line syntax, with long options starting with two dashes ("\-")\&. A summary of options is included below\&. -.PP -\fB\-h\fR, \fB\-\-help\fR -.RS 4 -Print help and exit\&. -.RE -.PP -\fB\-\-version\fR -.RS 4 -Print version and exit\&. -.RE -.PP -\fB\-\-bl_art=\fR\fB\fIartist_name\fR\fR -.RS 4 -Use to black list -\fIartist_name\fR\&. simadb_cli is checking -\fIartist_name\fR -is actually in MPD music library (cf -\fB\-S\fR -and -\fB\-P\fR -options to set MPD host/address if necessary)\&. -.sp -If -\fIartist_name\fR -is not found the script print out a list of matching artists\&. -.RE -.PP -\fB\-\-bl_curr_trk\fR | \fB\-\-bl_curr_art\fR | \fB\-\-bl_curr_alb\fR -.RS 4 -Use to black list the currently playing track|artist|album\&. You need access to your MPD server, use -\fB\-S\fR -and -\fB\-P\fR -to set MPD host/address if necessary\&. -.RE -.PP -\fB\-d \fR\fB\fIdb_file\fR\fR, \fB\-\-dbfile=\fR\fB\fIdb_file\fR\fR -.RS 4 -Use the specific file -\fIdb_file\fR -as database\&. -.br -Default is too use -\fBXDG_DATA_HOME\fR -(see -the section called \(lqFILES\(rq)\&. -.RE -.PP -\fB\-\-purge_hist\fR -.RS 4 -Purge history, you may supply an alternative DB file with \-\-dbfile option\&. -.RE -.PP -\fB\-\-remove_bl=\fR\fB\fIrow_id\fR\fR -.RS 4 -Use to remove a black list entry\&. To get the row_id to suppress use -\fB\-\-view_bl\fR -option\&. -.RE -.PP -\fB\-\-view_bl\fR -.RS 4 -Get all entries in the black list\&. -.RE -.PP -\fB\-P \fR\fB\fImpd_port\fR\fR, \fB\-\-port=\fR\fB\fImpd_port\fR\fR -.RS 4 -Use the specific port number -\fImpd_port\fR -on MPD server\&. This overrides -\fBMPD_PORT\fR -environment variable\&. -.br -Default is -\fI6600\fR\&. -.RE -.PP -\fB\-S \fR\fB\fImpd_host\fR\fR, \fB\-\-host=\fR\fB\fImpd_host\fR\fR -.RS 4 -Use the specific host -\fImpd_host\fR -as MPD server\&. -.br -\fImpd_host\fR -can be an -IP -or a fully qualified domain name as long as your system can resolve it\&. This overrides -\fBMPD_HOST\fR -environment variable\&. -.br -Default is -\fIlocalhost\fR\&. -.RE -.SH "FILES" -.PP -${XDG_DATA_HOME}/mpd_sima/sima\&.db -.RS 4 -SQLite DB file\&. Usually -\fBXDG_DATA_HOME\fR -is set to -${HOME}/\&.local/share\&. -.RE -.SH "FEEDBACK/BUGS" -.PP -The maintainer would be more than happy to ear from you, don\*(Aqt hesitate to send feedback, -\m[blue]\fB\%https://kaliko.me/contact/\fR\m[]\&. -.PP -XMPP -users are welcome to join the dedicated chat room at -\m[blue]\fBkaliko\&.me@conf\&.azylum\&.org\fR\m[]\&. -.SH "SEE ALSO" -.PP -\fBmpc\fR(1), -\fBmpd\fR(1) -.PP -/usr/share/doc/mpd\-sima/ -.SH "AUTHOR" -.PP -\fBkaliko\fR <\&kaliko@azylum\&.org\&> -.RS 4 -Wrote this man page and is currently leading MPD_sima project\&. -.RE -.SH "COPYRIGHT" -.br -Copyright \(co 2009-2021 kaliko -.br -.PP -This manual page was written for the Debian system (and may be used by others)\&. -.PP -Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation\&. -.PP -On Debian systems, the complete text of the GNU General Public License can be found in -/usr/share/common\-licenses/GPL\&. -.sp diff --git a/data/man/simadb_cli.1.xml b/data/man/simadb_cli.1.xml deleted file mode 100644 index 6bab004..0000000 --- a/data/man/simadb_cli.1.xml +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - -]> - - - - - &dhutils; - &dhsection; - - - &dhutils; - &dhutils; is a command line interface editor for the sima user DB. - - - - &dhutils; - artist - - db_file - - - - - - - &dhutils; - - - db_file - - - - &dhutils; - - - db_file - - - - &dhutils; - - - - - artist_name - - - db_file - - - mpd_host - - - mpd_port - - - - &dhutils; - row_id - - db_file - - - - &dhutils; - - - db_file - - - - &dhutils; - - - - - - - - - - - - - - DESCRIPTION - This manual page documents briefly the - &dhutils; commands. - simadb_cli is a command line interface to get and edit users - blacklist database used with MPD_sima. The default - database file (see ) can be overridden if - you want. - - - EXAMPLE - - Black list edition - Adding to black list. You can add a single - track, an album or an artist to the black list. The element to - black list is chosen from the currently playing track. Use - to prevent &dhutils; to queue this - track, or respectively for the album and the - artist. - - Remember you need access to your MPD server to retrieve - information to black list. Defaults are localhost:6600 or found in - environment variables but you may set it up from command - line: - - &dhutils; --bl_curr_art -S mympd.example.org - - To black list a specific artist (not - currently playing) you can use . - - - - - OPTIONS - The program follows the usual GNU command line syntax, - with long options starting with two dashes ("-"). A summary of - options is included below. - - - - - - - Print help and exit. - - - - - - Print version and exit. - - - - - - Use to black list artist_name. &dhutils; is checking artist_name is actually in MPD music library (cf and options to set MPD host/address if necessary). - If artist_name is not found the script print out a list of matching artists. - - - - | | - - Use to black list the currently playing track|artist|album. You need access to your MPD server, use and to set MPD host/address if necessary. - - - - - - - Use the specific file db_file as database.Default is too use XDG_DATA_HOME (see ). - - - - - - Purge history, you may supply an alternative DB file with --dbfile option. - - - - - - Use to remove a black list entry. To get the row_id to suppress use option. - - - - - - Get all entries in the black list. - - - - - - - Use the specific port number mpd_port on MPD server. This overrides MPD_PORT environment variable.Default is 6600. - - - - - - - Use the specific host mpd_host as MPD server.mpd_host can be an IP or a fully qualified domain name as long as your system can resolve it. This overrides MPD_HOST environment variable.Default is localhost. - - - - - - FILES - - - ${XDG_DATA_HOME}/mpd_sima/sima.db - - SQLite DB file. Usually XDG_DATA_HOME is set to ${HOME}/.local/share. - - - - - - - diff --git a/setup.py b/setup.py index 0630a78..d46a831 100755 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ from sima.info import __version__ as VERSION, __author__ as AUTHOR from sima.info import __doc__ as DESCRIPTION, __email__ as EMAIL data_files = [ - ('share/man/man1', ['data/man/mpd-sima.1', 'data/man/simadb_cli.1']), + ('share/man/man1', ['data/man/mpd-sima.1']), ('share/man/man5', ['data/man/mpd_sima.cfg.5']), ('share/doc/mpd-sima/examples/', glob.glob('doc/examples/*')), ('share/doc/mpd-sima/', [fi for fi in listdir('doc') if isfile(fi)]), @@ -46,7 +46,6 @@ setup(name='MPD_sima', packages=find_packages(exclude=["tests"]), include_package_data=True, data_files=data_files, - scripts=['simadb_cli'], entry_points={ 'console_scripts': [ 'mpd-sima = sima.launch:main', diff --git a/sima/launch.py b/sima/launch.py index 890f96b..1757d2b 100644 --- a/sima/launch.py +++ b/sima/launch.py @@ -39,6 +39,7 @@ from .lib.simadb import SimaDB from .utils.config import ConfMan from .utils.startopt import StartOpt from .utils.utils import exception_log, SigHup, MPDSimaException +from .utils.blcli import BLCli # core plugins from .plugins.core.history import History from .plugins.core.mpdoptions import MpdOptions @@ -86,7 +87,10 @@ def start(sopt, restart=False): logger = logging.getLogger('sima') logfile = config.get('log', 'logfile', fallback=None) verbosity = config.get('log', 'verbosity') - set_logger(verbosity, logfile) + if sopt.options.get('command'): # disable file logging + set_logger(verbosity) + else: + set_logger(verbosity, logfile) logger.debug('Command line say: %s', sopt.options) # Create database if not present @@ -104,6 +108,9 @@ def start(sopt, restart=False): if sopt.options.get('command'): cmd = sopt.options.get('command') + if cmd.startswith('bl-'): + BLCli(config, sopt.options) + sys.exit(0) if cmd == "generate-config": config.write(sys.stdout, space_around_delimiters=True) sys.exit(0) @@ -185,7 +192,7 @@ def run(sopt, restart=False): def main(): """Entry point""" nfo = dict({'version': info.__version__, - 'prog': 'sima'}) + 'prog': 'mpd-sima'}) # StartOpt gathers options from command line call (in StartOpt().options) sopt = StartOpt(nfo) run(sopt) diff --git a/sima/lib/simadb.py b/sima/lib/simadb.py index 07794dc..a66cbd0 100644 --- a/sima/lib/simadb.py +++ b/sima/lib/simadb.py @@ -670,6 +670,24 @@ class SimaDB: connection.close() return bl + def view_bl(self): + connection = self.get_database_connection() + connection.row_factory = sqlite3.Row + rows = connection.execute("""SELECT artists.name AS artist, + artists.mbid AS musicbrainz_artist, + albums.name AS album, + albums.mbid AS musicbrainz_album, + tracks.title AS title, + tracks.mbid AS musicbrainz_title, + blocklist.id + FROM blocklist + LEFT OUTER JOIN artists ON blocklist.artist = artists.id + LEFT OUTER JOIN albums ON blocklist.album = albums.id + LEFT OUTER JOIN tracks ON blocklist.track = tracks.id""") + res = [dict(row) for row in rows.fetchall()] + connection.close() + return res + def delete_bl(self, track=None, album=None, artist=None): if not (track or album or artist): return diff --git a/sima/utils/blcli.py b/sima/utils/blcli.py new file mode 100644 index 0000000..4522e06 --- /dev/null +++ b/sima/utils/blcli.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2021 kaliko +# +# This file is part of sima +# +# sima 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. +# +# sima is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with sima. If not, see . + +# standard library import +import atexit +import sys + +# local import +from ..mpdclient import MPD, PlayerError, Artist, Album +from ..lib.simadb import SimaDB + + +class BLCli(MPD): + + def __init__(self, conf, options): + super().__init__(conf) + self.options = options + self.sdb = SimaDB(db_path=conf.get('sima', 'db_file')) + atexit.register(self.disconnect) + cmd = options.get('command', None) + if not cmd or not cmd.startswith('bl-'): + return + try: + getattr(self, cmd.replace('-', '_'))() + except PlayerError as err: + self.log.error(err) + sys.exit(1) + + def bl_view(self): + blocklist = self.sdb.view_bl() + for entry in ['artist', 'album', 'title']: + header = False + for bl in blocklist: + art = bl.get(entry, '') + mbid = bl.get(f'musicbrainz_{entry}', '') + if art or mbid: + if not header: + header = True + self.log.info(f'{entry.capitalize()}' + '(id name musicbranzID):') + self.log.info(f'{bl["id"]} "{art}"\t\t{mbid}') + + def bl_add_artist(self): + artist = self.options.get('artist', None) + self.connect() + if not artist: # artist not provided + self.log.debug('current track: %r', self.current) + if not self.current: + self.log.error('No current song, cannot proceed') + return + if not self.current.artist: + self.log.error('No artist for the current song: %r', + self.current) + return + self.log.info('Using "%s" (from current track)', self.current.artist) + artist = self.current.Artist + else: # artist provided + self.log.debug('Looking for %r', artist) + search = self.search_artist(Artist(name=artist)) + if not search: + self.log.warning('Artist not found: "%s"', artist) + return + self.log.info('Found artist in library: %s', search) + artist = search + if self.sdb.get_bl_artist(artist, add=False): + self.log.info('Already in blocklist') + return + self.log.info('Add artist to blocklist "%s"', artist.name) + self.sdb.get_bl_artist(artist) + + def bl_add_album(self): + album = self.options.get('album', None) + self.connect() + if not album: # album not provided + self.log.debug('current track: %r', self.current) + if not self.current: + self.log.error('No current song, cannot proceed') + return + if not self.current.album: + self.log.error('No album for the current song: %r', + self.current) + return + if not self.current.artist: + self.log.error('No artist for the current song: %r', + self.current) + return + self.log.info('Using "%s" (from current track)', self.current.album) + album = Album(self.current.album, mbid=self.current.musicbrainz_albumid, + artist=self.current.Artist) + else: # album provided + self.log.debug('Looking for %r', album) + album = Album(album) + tracks = self.find(f'(album == "{album.name_sz}")', + 'window', (0, 1)) + if not tracks: + self.log.warning('Album not found: "%s"', album) + return + track = tracks[0] + album = Album(name=track.album, mbid=track.musicbrainz_albumid) + artist = Artist(name=track.artist, mbid=track.musicbrainz_artistid) + self.log.info('Found album in library: %s (by "%s")', + album, artist) + if self.sdb.get_bl_album(album, add=False): + self.log.info('Already in blocklist') + return + self.log.info('Add album to blocklist "%s"', album) + self.sdb.get_bl_album(album) + + def bl_add_track(self): + track = self.options.get('track', None) + self.connect() + if not track: # track not provided + self.log.debug('current track: %r', self.current) + if not self.current: + self.log.error('No current song, cannot proceed') + return + if not self.current.title: + self.log.error('No title for the current song: %r', + self.current) + return + self.log.info('Using "%s" (from current track)', self.current.title) + track = self.current + else: # track provided + self.log.debug('Looking for %r', track) + track_sz = track.replace("'", r"\'") + tracks = self.find(f'(title == "{track_sz}")') + if not tracks: + self.log.warning('Track not found: "%s"', track) + return + if len(tracks) > 1: + artists = {t.artist for t in tracks} + if len(artists) > 1: + self.log.error('Found various artists for this title: %s', + artists) + return + track = tracks[0] + if self.sdb.get_bl_track(track, add=False): + self.log.info('Already in blocklist') + return + self.log.info('Add track to blocklist "%s"', track) + self.sdb.get_bl_track(track) + + def bl_delete(self): + blid = self.options.get('id', None) + blocklist = self.sdb.view_bl() + if blid not in [bl['id'] for bl in blocklist]: + self.log.error('Blocklist ID not found: %s', blid) + self.sdb._remove_blocklist_id(blid) + +# VIM MODLINE +# vim: ai ts=4 sw=4 sts=4 expandtab fileencoding=utf8 diff --git a/sima/utils/startopt.py b/sima/utils/startopt.py index 80ccb97..bf9fcf4 100644 --- a/sima/utils/startopt.py +++ b/sima/utils/startopt.py @@ -21,7 +21,6 @@ from argparse import ArgumentParser, RawDescriptionHelpFormatter, SUPPRESS - from .utils import Wfile, Rfile, Wdir DESCRIPTION = """ @@ -29,8 +28,6 @@ MPD_sima automagicaly queue new tracks in MPD playlist. Command line options override their equivalent in configuration file. If a positional arguments is provided MPD_sima execute the command and returns. -Commands available: -{} """ @@ -40,12 +37,6 @@ def clean_dict(to_clean): if not to_clean.get(k): to_clean.pop(k) -# COMMANDS LIST -CMDS = {'config-test': 'Test configuration (MPD connection and Tags plugin only)', - 'create-db': 'Create the database', - 'generate-config': 'Generate a configuration file to stdout', - 'purge-history': 'Remove play history' - } # OPTIONS LIST # pop out 'sw' value before creating Parser object. # PAY ATTENTION: @@ -99,11 +90,30 @@ OPTS = [ 'dest': 'var_dir', 'action': Wdir, 'help': 'directory to store var content (ie. database, cache)'}, - { - 'sw': ['command'], - 'nargs': '?', - 'choices': CMDS.keys(), - 'help': 'command to run (cf. description or unix manual for more)'}, +] +# Commands +CMDS = [ + {'config-test': [{}], 'help': 'Test configuration (MPD connection and Tags plugin only)'}, + {'create-db': [{}], 'help': 'Create the database'}, + {'generate-config': [{}], 'help': 'Generate a configuration file to stdout'}, + {'purge-history': [{}], 'help': 'Remove play history'}, + {'bl-view': [{}], 'help': 'List blocklist IDs'}, + {'bl-add-artist': [ + {'name': 'artist', 'type': str, 'nargs': '?', + 'help': 'If artist is provided use it else use currently playing value'} + ], 'help': 'Add artist to the blocklist'}, + {'bl-add-album': [ + {'name': 'album', 'type': str, 'nargs': '?', + 'help': 'If album is provided use it else use currently playing value'} + ], 'help': 'Add album to the blocklist'}, + {'bl-add-track': [ + {'name': 'track', 'type': str, 'nargs': '?', + 'help': 'If track is provided use it else use currently playing value'} + ], 'help': 'Add track to the blocklist'}, + {'bl-delete': [ + {'name': 'id', 'type': int, 'nargs': '?', + 'help': 'blocklist ID to suppress (use bl-view list IDs)'} + ], 'help': 'Remove entries from the blocklist'}, ] @@ -121,8 +131,7 @@ class StartOpt: """ Declare options in ArgumentParser object. """ - cmds = '\n'.join([f' * {k}: {v}' for k, v in CMDS.items()]) - self.parser = ArgumentParser(description=DESCRIPTION.format(cmds), + self.parser = ArgumentParser(description=DESCRIPTION, prog=self.info.get('prog'), epilog='Happy Listening', formatter_class=RawDescriptionHelpFormatter, @@ -133,6 +142,19 @@ class StartOpt: for opt in OPTS: opt_names = opt.pop('sw') self.parser.add_argument(*opt_names, **opt) + # Add sub commands + sp = self.parser.add_subparsers( + title=f'{self.info["prog"]} commands as positional arguments', + description=f"""Use them after optionnal arguments.\n"{self.info["prog"]} command -h" for more info.""", + metavar='', dest='command') + for cmd in CMDS: + helpmsg = cmd.pop('help') + cmd, args = cmd.popitem() + _ = sp.add_parser(cmd, description=helpmsg, help=helpmsg) + for arg in args: + name = arg.pop('name', None) + if name: + _.add_argument(name, **arg) def main(self): """ diff --git a/simadb_cli b/simadb_cli deleted file mode 100755 index b720a0d..0000000 --- a/simadb_cli +++ /dev/null @@ -1,320 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (c) 2010-2015 Jack Kaliko -# -# This file is part of MPD_sima -# -# MPD_sima 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. -# -# MPD_sima is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with MPD_sima. If not, see . -# -# - -__version__ = '0.4.1' - -# IMPORT# -from argparse import (ArgumentParser, SUPPRESS) -from difflib import get_close_matches -from locale import getpreferredencoding -from os import (environ, chmod, makedirs) -from os.path import (join, isdir, isfile, expanduser) -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, MPDError - - -DESCRIPTION = """ -simadb_cli helps you to edit entries in your own DB of similarity -between artists.""" -DB_NAME = 'sima.db' - -# Options list -# pop out 'sw' value before creating ArgumentParser object. -OPTS = list([ - { - 'sw':['-d', '--dbfile'], - 'type': str, - 'dest':'dbfile', - 'action': utils.Wfile, - 'help': 'File to read/write database from/to'}, - { - 'sw': ['-S', '--host'], - 'type': str, - 'dest': 'mpdhost', - 'default': None, - 'help': 'MPD host, as IP or FQDN (default: localhost|MPD_HOST).'}, - { - 'sw': ['-P', '--port'], - 'type': int, - 'dest': 'mpdport', - 'default': None, - 'help': 'Port MPD in listening on (default: 6600|MPD_PORT).'}, - { - 'sw': ['--password'], - 'type': str, - 'dest': 'passwd', - 'default': None, - 'help': SUPPRESS}, - { - 'sw': ['--view_bl'], - 'action': 'store_true', - 'dest': 'view_bl', - 'help': 'View black list.'}, - { - 'sw': ['--remove_bl'], - 'type': int, - 'help': 'Suppress a black list entry, by row id. Use --view_bl to get row id.'}, - { - 'sw': ['--bl_art'], - 'type': str, - 'metavar': 'ARTIST_NAME', - 'help': 'Black list artist.'}, - { - 'sw': ['--bl_curr_art'], - 'action': 'store_true', - 'help': 'Black list currently playing artist.'}, - { - 'sw': ['--bl_curr_alb'], - 'action': 'store_true', - 'help': 'Black list currently playing album.'}, - { - 'sw': ['--bl_curr_trk'], - 'action': 'store_true', - 'help': 'Black list currently playing track.'}, - { - 'sw':['--purge_hist'], - 'action': 'store_true', - 'dest': 'do_purge_hist', - 'help': 'Purge play history.'}]) - - -class SimaDB_CLI(object): - """Command line management. - """ - - def __init__(self): - self.dbfile = self._get_default_dbfile() - self.parser = None - self.options = dict({}) - self.localencoding = 'UTF-8' - self._get_encoding() - self.main() - - def _get_encoding(self): - """Get local encoding""" - localencoding = getpreferredencoding() - if localencoding: - self.localencoding = localencoding - - def _get_mpd_env_var(self): - """ - MPD host/port environement variables are used if command line does not - provide host|port|passwd. - """ - host, port, passwd = utils.get_mpd_environ() - if self.options.passwd is None and passwd: - self.options.passwd = passwd - if self.options.mpdhost is None: - if host: - self.options.mpdhost = host - else: - self.options.mpdhost = 'localhost' - if self.options.mpdport is None: - if port: - self.options.mpdport = port - else: - self.options.mpdport = 6600 - - def _declare_opts(self): - """ - Declare options in ArgumentParser object. - """ - self.parser = ArgumentParser(description=DESCRIPTION, - usage='%(prog)s [-h|--help] [options]', - prog='simadb_cli', - epilog='Happy Listening', - ) - - self.parser.add_argument('--version', action='version', - version='%(prog)s {0}'.format(__version__)) - # Add all options declare in OPTS - for opt in OPTS: - opt_names = opt.pop('sw') - self.parser.add_argument(*opt_names, **opt) - - def _get_default_dbfile(self): - """ - Use XDG directory standard if exists - else use "HOME/.local/share/mpd_sima/" - http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html - """ - homedir = expanduser('~') - dirname = 'mpd_sima' - if environ.get('XDG_DATA_HOME'): - data_dir = join(environ.get('XDG_DATA_HOME'), dirname) - else: - data_dir = join(homedir, '.local', 'share', dirname) - if not isdir(data_dir): - makedirs(data_dir) - chmod(data_dir, 0o700) - return join(data_dir, DB_NAME) - - def _get_mpd_client(self): - """""" - host = self.options.mpdhost - port = self.options.mpdport - passwd = self.options.passwd - cli = MPDClient() - try: - 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) - return cli - - def _create_db(self): - """Create database if necessary""" - if isfile(self.dbfile): - return - print('Creating database!') - open(self.dbfile, 'a').close() - simadb.SimaDB(db_path=self.dbfile).create_db() - - def _get_art_from_db(self, art): - """Return (id, name, self...) from DB or None is not in DB""" - db = simadb.SimaDB(db_path=self.dbfile) - art_db = db.get_artist(art, add_not=True) - if not art_db: - print('ERROR: "%s" not in data base!' % art, file=stderr) - return None - return art_db - - def bl_artist(self): - """Black list artist""" - mpd_cli = self._get_mpd_client() - artists_list = mpd_cli.list('artist') - # Unicode cli given artist name - cli_artist_to_bl = self.options.bl_art - if cli_artist_to_bl not in artists_list: - print('Artist not found in MPD library.') - match = get_close_matches(cli_artist_to_bl, artists_list, 50, 0.78) - if match: - print('You may be refering to %s' % - '/'.join([m_a for m_a in match])) - return False - print('Black listing artist: %s' % cli_artist_to_bl) - db = simadb.SimaDB(db_path=self.dbfile) - db.get_bl_artist(cli_artist_to_bl) - - def bl_current_artist(self): - """Black list current artist""" - mpd_cli = self._get_mpd_client() - artist = mpd_cli.currentsong().get('artist', '') - if not artist: - print('No artist found.') - return False - print('Black listing artist: %s' % artist) - db = simadb.SimaDB(db_path=self.dbfile) - db.get_bl_artist(artist) - - def bl_current_album(self): - """Black list current artist""" - mpd_cli = self._get_mpd_client() - track = Track(**mpd_cli.currentsong()) - if not track.album: - print('No album set for this track: %s' % track) - return False - print('Black listing album: {0}'.format(track.album)) - db = simadb.SimaDB(db_path=self.dbfile) - db.get_bl_album(track) - - def bl_current_track(self): - """Black list current artist""" - mpd_cli = self._get_mpd_client() - track = Track(**mpd_cli.currentsong()) - print('Black listing track: %s' % track) - db = simadb.SimaDB(db_path=self.dbfile) - db.get_bl_track(track) - - def purge_history(self): - """Purge all entries in history""" - db = simadb.SimaDB(db_path=self.dbfile) - print('Purging history...') - db.purge_history(duration=int(0)) - print('done.') - print('Cleaning database...') - db.clean_database() - print('done.') - - def view_bl(self): - """Print out black list.""" - # TODO: enhance output formating - db = simadb.SimaDB(db_path=self.dbfile) - for bl_e in db.get_black_list(): - print('\t# '.join([str(e) for e in bl_e])) - - def remove_black_list_entry(self): - """""" - db = simadb.SimaDB(db_path=self.dbfile) - db._remove_bl(int(self.options.remove_bl)) - - def main(self): - """ - Parse command line and run actions. - """ - self._declare_opts() - self.options = self.parser.parse_args() - self._get_mpd_env_var() - if self.options.dbfile: - self.dbfile = self.options.dbfile - print('Using db file: %s' % self.dbfile) - if self.options.bl_art: - self.bl_artist() - return - if self.options.bl_curr_art: - self.bl_current_artist() - return - if self.options.bl_curr_alb: - self.bl_current_album() - return - if self.options.bl_curr_trk: - self.bl_current_track() - return - if self.options.view_bl: - self.view_bl() - return - if self.options.remove_bl: - self.remove_black_list_entry() - return - if self.options.do_purge_hist: - self.purge_history() - exit(0) - - -# Script starts here -if __name__ == '__main__': - try: - SimaDB_CLI() - except Exception as err: - print(err) - exit(1) - -# VIM MODLINE -# vim: ai ts=4 sw=4 sts=4 expandtab