]> kaliko git repositories - mpd-sima.git/commitdiff
Add Genre plugin
authorkaliko <kaliko@azylum.org>
Mon, 19 Apr 2021 16:59:31 +0000 (18:59 +0200)
committerkaliko <kaliko@azylum.org>
Mon, 19 Apr 2021 16:59:31 +0000 (18:59 +0200)
README.rst
data/man/info.xml
data/man/mpd-sima.1
data/man/mpd_sima.cfg.5
data/man/mpd_sima.cfg.5.xml
data/man/simadb_cli.1
doc/Changelog
doc/examples/all_settings.cfg
sima/info.py
sima/plugins/internal/genre.py [new file with mode: 0644]
sima/utils/config.py

index b0728d7e366667c51079f81d5921e3617efa776f..5091c3aa54c7f7c8d0ea76b42f307f68c4853c57 100644 (file)
@@ -5,9 +5,11 @@ MPD_sima_ is a non interactive MPD autoqueue client running in the background.
 It will queue new tracks chosen among artists similar to your current queued
 tracks, provided a title is found in your music library.
 
-Similar artists are fetched from last.fm webservice.
+Default is to fetch similar artists from last.fm webservice. There are other
+plugins to fetch tracks based on genre tag or using specific complex filter.
 
-MPD_sima can queue track, top track or whole album for similar artists.
+Depending on the plugin used, MPD_sima can queue track, top track or whole
+album for similar artists.
 
 This client allows you to never run out of music when your queue is getting
 short.
index 0396ae5f0d0239f186cfa0f13a6414a610d09150..9bf05f785c3d60c8c976ba021e84a9c072b4d5f7 100644 (file)
@@ -5,7 +5,7 @@
   <!ENTITY dhemail     "kaliko@azylum.org">
   <!ENTITY dhusername  "&dhsurname;">
   <!ENTITY dhpackage "mpd-sima">
-  <!ENTITY release   "0.16.1">
+  <!ENTITY release   "0.17.0">
   <!-- TITLE should be something like "User commands" or similar (see
        http://www.tldp.org/HOWTO/Man-Page/q2.html). -->
   <!ENTITY dhtitle     "&dhpackage; &release; User Manual">
index 6686f8aec976bee86f2890f52f732d6d3e9047dc..9d26e92ae74dd228814131754752c62bb76dd352 100644 (file)
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: mpd-sima
 .\"    Author: kaliko <kaliko@azylum.org>
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 01/09/2021
-.\"    Manual: mpd-sima 0.16.1 User Manual
+.\" Generator: DocBook XSL Stylesheets v1.79.2 <http://docbook.sf.net/>
+.\"      Date: 04/19/2021
+.\"    Manual: mpd-sima 0.17.0 User Manual
 .\"    Source: mpd-sima
 .\"  Language: English
 .\"
-.TH "MPD\-SIMA" "1" "01/09/2021" "mpd-sima" "mpd-sima 0.16.1 User Manual"
+.TH "MPD\-SIMA" "1" "04/19/2021" "mpd-sima" "mpd-sima 0.17.0 User Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 61f63d1b05adbce18c497a99dbdc6c07452c6e5f..5710c3536c8f030e2d16e56f2985693f54d23d5a 100644 (file)
@@ -3,11 +3,11 @@
 .\"    Author: kaliko <kaliko@azylum.org>
 .\" Generator: DocBook XSL Stylesheets v1.79.2 <http://docbook.sf.net/>
 .\"      Date: 04/19/2021
-.\"    Manual: mpd-sima 0.16.1 User Manual
+.\"    Manual: mpd-sima 0.17.0 User Manual
 .\"    Source: mpd-sima
 .\"  Language: English
 .\"
-.TH "MPD_SIMA\&.CFG" "5" "04/19/2021" "mpd-sima" "mpd-sima 0.16.1 User Manual"
+.TH "MPD_SIMA\&.CFG" "5" "04/19/2021" "mpd-sima" "mpd-sima 0.17.0 User Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -411,6 +411,52 @@ If set to "false", caching is still done but in memory\&.
 .RS 4
 Plugin priority
 .RE
+.SS "Genre section"
+.PP
+Genre plugin\*(Aqs configuration\&.
+.PP
+This plugin permits offline autoqueuing based on files genre tag only\&.
+.PP
+it will try to queue tracks base on genre tags of tracks in the queue\&.
+.PP
+\fB[tags]\fR
+.RS 4
+.RE
+.PP
+\fBqueue_mode=\fR\fItrack\fR
+.RS 4
+Queue mode to use among
+\fItrack\fR,
+\fIalbum\fR
+(see
+the section called \(lqQUEUE MODES\(rq
+for info about queue modes)\&.
+.RE
+.PP
+\fBsingle_album=\fR\fIfalse\fR
+.RS 4
+Prevent from queueing a track from the same album (it often happens with OST)\&.
+.br
+
+Only relevant in "track" queue mode\&.
+.RE
+.PP
+\fBpriority=\fR\fI80\fR
+.RS 4
+Plugin priority
+.RE
+.PP
+\fBtrack_to_add=\fR\fI1\fR
+.RS 4
+How many track(s) to add\&.
+.RE
+.PP
+\fBalbum_to_add=\fR\fI1\fR
+.RS 4
+How many album(s) to add\&. Only relevant in
+\fBalbum\fR
+queue mode\&.
+.RE
 .SS "Tags section"
 .PP
 Tags plugin\*(Aqs configuration\&. There is no default configuration for this plugin, it does not work out of the box\&.
@@ -451,6 +497,14 @@ the section called \(lqQUEUE MODES\(rq
 for info about queue modes)\&.
 .RE
 .PP
+\fBsingle_album=\fR\fIfalse\fR
+.RS 4
+Prevent from queueing a track from the same album (it often happens with OST)\&.
+.br
+
+Only relevant in "track" queue mode\&.
+.RE
+.PP
 \fBfilter=\fR
 .RS 4
 You can use here any valid MPD filter as defined in MPD protocol documentation\&.
index b015874fe27870f110ac23374520060fe785c995..ca092011ad3a1ec1e8771ca324bfae9f93b38a9b 100644 (file)
@@ -425,6 +425,52 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
                 </varlistentry>
             </variablelist>
         </refsect2>
+        <refsect2 id="genre">
+            <title>Genre section</title>
+            <para>Genre plugin's configuration.</para>
+            <para>This plugin permits offline autoqueuing based on files genre tag only.</para>
+            <para>it will try to queue tracks base on genre tags of tracks in the queue.</para>
+                <varlistentry> <!-- genre -->
+                   <term><option>[tags]</option></term>
+                </varlistentry>
+                <varlistentry> <!-- tags.queue_mode -->
+                    <term><option>queue_mode=</option><replaceable>track</replaceable></term>
+                    <listitem>
+                        <para>Queue mode to use among
+                            <replaceable>track</replaceable>,
+                            <replaceable>album</replaceable> (see <xref linkend="queue_mode"/> for info about queue modes).</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry> <!-- genre.single_album -->
+                    <term><option>single_album=</option><replaceable>false</replaceable></term>
+                    <listitem>
+                        <para>Prevent from queueing a track from the same album
+                            (it often happens with OST).<sbr />
+                            Only relevant in "track" queue mode.</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry> <!-- genre.priority -->
+                    <term><option>priority=</option><replaceable>80</replaceable></term>
+                    <listitem>
+                        <para>
+                            Plugin priority
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry> <!-- genre.track_to_add -->
+                    <term><option>track_to_add=</option><replaceable>1</replaceable></term>
+                    <listitem>
+                        <para>How many track(s) to add.</para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry> <!-- genre.album_to_add -->
+                    <term><option>album_to_add=</option><replaceable>1</replaceable></term>
+                    <listitem>
+                        <para>How many album(s) to add. Only relevant in
+                            <option>album</option> queue mode.</para>
+                    </listitem>
+                </varlistentry>
+        </refsect2>
         <refsect2 id="tags">
             <title>Tags section</title>
             <para>Tags plugin's configuration. There is no default configuration for this plugin,
@@ -456,6 +502,14 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
                             <replaceable>album</replaceable> (see <xref linkend="queue_mode"/> for info about queue modes).</para>
                     </listitem>
                 </varlistentry>
+                <varlistentry> <!-- tags.single_album -->
+                    <term><option>single_album=</option><replaceable>false</replaceable></term>
+                    <listitem>
+                        <para>Prevent from queueing a track from the same album
+                            (it often happens with OST).<sbr />
+                            Only relevant in "track" queue mode.</para>
+                    </listitem>
+                </varlistentry>
                 <varlistentry> <!-- tags.filter -->
                     <term><option>filter=</option></term>
                     <listitem>
index 7a0e233826ec9af0eb965bc9bf848dae6686c490..cc893d8ecef9a6e31753c518a3bc787ebbe2ed94 100644 (file)
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: simadb_cli
 .\"    Author: kaliko <kaliko@azylum.org>
-.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\"      Date: 01/09/2021
-.\"    Manual: mpd-sima 0.16.1 User Manual
+.\" Generator: DocBook XSL Stylesheets v1.79.2 <http://docbook.sf.net/>
+.\"      Date: 04/19/2021
+.\"    Manual: mpd-sima 0.17.0 User Manual
 .\"    Source: mpd-sima
 .\"  Language: English
 .\"
-.TH "SIMADB_CLI" "1" "01/09/2021" "mpd-sima" "mpd-sima 0.16.1 User Manual"
+.TH "SIMADB_CLI" "1" "04/19/2021" "mpd-sima" "mpd-sima 0.17.0 User Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 9a3851407db5af83fce6424afb680559fa1d710c..ede813997db01924681d92610d7d9dc8b3dc2bf1 100644 (file)
@@ -1,5 +1,6 @@
-MPD_sima v0.16.2.dev0
+MPD_sima v0.17.0.dev0
 
+ * New offline autoqueue plugin based on file genre tags only
  * Add randomness in Tags plugin artist selection
  * Fixed issue with un-tagged titles (closes #40)
  * Fixed "artist with quotes not found" (closes #41)
index 01566cc6436df4ded2fbf0013928fc3227fce3c1..4ffcf1fd421fa9521f013dd8ac0abe1b6690e1f4 100644 (file)
@@ -120,6 +120,37 @@ single_disable_queue  = True
 
 ######################### PLUGINS #####################################
 
+[genre]
+## Offline genre queing
+
+## QUEUE_MODE
+# type: string
+# description: Configure queue mode, a single track or an album
+# Possible values:
+#      track : Will queue single track artists (default).
+#      album : Will queue whole album from artists.
+queue_mode = track
+
+## SINGLE_ALBUM
+# type: boolean
+# scope: "track" queue mode only
+# description: Prevent from queueing a track from the same album (for instance
+#  with OST).
+single_album = false
+
+## TRACK_TO_ADD
+# type: integer
+# scope: "track" and "top" queue modes
+# description: how many tracks the plugin will try to get
+track_to_add = 1
+
+## ALBUM_TO_ADD
+# type: integer
+# scope: "album" queue mode
+# description: how many albums the plugin will try to get
+album_to_add = 1
+
+
 [tags]
 ## Offline tags queing
 # This plugin has no defaults set
@@ -142,12 +173,19 @@ filter=
 
 ## QUEUE_MODE
 # type: string
-# description: The default is to queue random tracks from similar artists.
+# description: Configure queue mode, a single track or an album
 # Possible values:
-#      track : Will queue tracks from similar artists (default).
-#      album : Will queue whole album from similar artists.
+#      track : Will queue single track artists (default).
+#      album : Will queue whole album from artists.
 queue_mode = track
 
+## SINGLE_ALBUM
+# type: boolean
+# scope: "track" queue mode only
+# description: Prevent from queueing a track from the same album (for instance
+#  with OST).
+single_album = false
+
 ## TRACK_TO_ADD
 # type: integer
 # scope: "track" and "top" queue modes
@@ -194,9 +232,9 @@ flavour=sensible
 [lastfm]
 ## QUEUE_MODE
 # type: string
-# description: The default is to queue random tracks from similar artists.
+# description: Does it queue a single track, top track or an album.
 # Possible values:
-#      track : Will queue tracks from similar artists (default).
+#      track : Will queue single tracks from similar artists (default).
 #      top   : Will queue top tracks from similar artists.
 #      album : Will queue whole album from similar artists.
 queue_mode = track
index 4e10e34ef9ffd638f4297ea8638bc8f9cc172c6e..a123cdf974cadd1999f89064c4c4fb9df182b800 100644 (file)
@@ -12,7 +12,7 @@ short.
 """
 
 
-__version__ = '0.16.2.dev0'
+__version__ = '0.17.0.dev0'
 __author__ = 'kaliko'
 __email__ = 'kaliko@azylum.org'
 __url__ = 'git://git.kaliko.me/sima.git'
diff --git a/sima/plugins/internal/genre.py b/sima/plugins/internal/genre.py
new file mode 100644 (file)
index 0000000..808d96d
--- /dev/null
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020-2021 kaliko <kaliko@azylum.org>
+#
+#  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 <http://www.gnu.org/licenses/>.
+#
+#
+"""
+Add titles based on Genre tag
+"""
+
+# standard library import
+from collections import Counter
+from random import shuffle
+
+# third parties components
+
+# local import
+from ...lib.plugin import AdvancedPlugin
+from ...lib.meta import Artist, MetaContainer
+from ...utils.utils import PluginException
+
+
+def forge_filter(genre):
+    mpd_filter = f"(Genre == '{genre.strip()}')"
+    # Ensure there is at least an artist name
+    mpd_filter = f"({mpd_filter} AND (artist != ''))"
+    return mpd_filter
+
+
+class Genre(AdvancedPlugin):
+    """Add track based on tags content
+    """
+
+    def __init__(self, daemon):
+        super().__init__(daemon)
+        self._setup_tagsneeded()
+
+    def _setup_tagsneeded(self):
+        """Ensure needed tags are exposed by MPD"""
+        self.log.debug('%s plugin needs the following metadata: Genre', self)
+        self.player.needed_tags |= {'genre'}
+
+    def start(self):
+        if (0, 21, 0) > tuple(map(int, self.player.mpd_version.split('.'))):
+            self.log.warning('MPD protocol version: %s < 0.21.0',
+                             self.player.mpd_version)
+            self.log.error(
+                'Need at least MPD 0.21 to use Genre plugin (filters required)')
+            self.player.disconnect()
+            raise PluginException('MPD >= 0.21 required')
+
+    def fetch_genres(self):
+        pldepth = 4
+        nbgenres = 2
+        current_titles = self.player.playlist[-pldepth:]
+        genres = []
+        for track in current_titles:
+            if not track.genres:
+                self.log.debug('No genre found in %s', track)
+                continue
+            genres.extend(track.genres)
+        genres_analysis = Counter(genres)
+        if genres_analysis.most_common():
+            self.log.debug('Most common genres: %s', genres_analysis.most_common())
+        return dict(genres_analysis.most_common(nbgenres)).keys()
+
+    def callback_need_track(self):
+        candidates = []
+        queue_mode = self.plugin_conf.get('queue_mode', 'track')
+        target = self.plugin_conf.getint(f'{queue_mode}_to_add')
+        genres = self.fetch_genres()
+        if not genres:
+            self.log.warning('No genre tag set in current tracks!')
+            return []
+        self.log.info('Genre plugin looking for genre: %s', ' / '.join(genres))
+        artists = MetaContainer([])
+        for genre in genres:
+            mpd_filter = forge_filter(genre)
+            self.log.debug('mpd filter: %s', mpd_filter)
+            _ = self.player.list('artist', mpd_filter)
+            shuffle(_)
+            artists |= MetaContainer([Artist(name=a) for a in _])
+        if not artists:
+            self.log.info('Genre plugin found nothing to queue')
+            return []
+        artists = self.get_reorg_artists_list(artists)
+        self.log.debug('Genre plugin found: %s…', ' / '.join(map(str, artists[:4])))
+        for artist in artists:
+            self.log.debug('looking for %s', artist)
+            tracks = self.player.find_tracks(artist)
+            trk = self.filter_track(tracks)
+            if not trk:
+                continue
+            if queue_mode == 'track':
+                self.log.info('Genre plugin chose: {}'.format(trk))
+                candidates.append(trk)
+                if len(candidates) == target:
+                    break
+            else:
+                album = self.album_candidate(trk.Artist, unplayed=True)
+                if not album:
+                    continue
+                candidates.extend(self.player.find_tracks(album))
+                if len({t.album for t in candidates}) == target:
+                    break
+        return candidates
+
+# VIM MODLINE
+# vim: ai ts=4 sw=4 sts=4 expandtab
index 06799561ba6f72957d228db2cdc29368c5a8cd0a..26c227a938278b1f0f97595561e6cd51d563b79d 100644 (file)
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Copyright (c) 2009-2015, 2019-2020 kaliko <kaliko@azylum.org>
+# Copyright (c) 2009-2015, 2019-2021 kaliko <kaliko@azylum.org>
 # Copyright (c) 2019 sacha <sachahony@gmail.com>
 #
 #  This file is part of sima
@@ -95,10 +95,18 @@ DEFAULT_CONF = {
             'originaldate': "",
             'filter': "",
             'queue_mode': "track",
+            'single_album': "false",
+            'track_to_add': 1,
+            'album_to_add': 1,
+            'priority': 80,
+            },
+        'genre': {
+            'queue_mode': "track",
+            'single_album': "false",
             'track_to_add': 1,
             'album_to_add': 1,
             'priority': 80,
-            }
+            },
         }
 #