]> 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.
 
 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.
 
 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 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">
   <!-- 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>
 '\" 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
 .\"
 .\"    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
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" * 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
 .\"    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
 .\"
 .\"    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
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -411,6 +411,52 @@ If set to "false", caching is still done but in memory\&.
 .RS 4
 Plugin priority
 .RE
 .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\&.
 .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
 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\&.
 \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>
                 </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,
         <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>
                             <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>
                 <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>
 '\" 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
 .\"
 .\"    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
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" * 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)
  * 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 #####################################
 
 
 ######################### 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
 [tags]
 ## Offline tags queing
 # This plugin has no defaults set
@@ -142,12 +173,19 @@ filter=
 
 ## QUEUE_MODE
 # type: string
 
 ## 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:
 # 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
 
 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
 ## TRACK_TO_ADD
 # type: integer
 # scope: "track" and "top" queue modes
@@ -194,9 +232,9 @@ flavour=sensible
 [lastfm]
 ## QUEUE_MODE
 # type: string
 [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:
 # 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
 #      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'
 __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 -*-
 # -*- 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
 # Copyright (c) 2019 sacha <sachahony@gmail.com>
 #
 #  This file is part of sima
@@ -95,10 +95,18 @@ DEFAULT_CONF = {
             'originaldate': "",
             'filter': "",
             'queue_mode': "track",
             '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,
             'track_to_add': 1,
             'album_to_add': 1,
             'priority': 80,
-            }
+            },
         }
 #
 
         }
 #