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.
<!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">
'\" 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
.\" -----------------------------------------------------------------
.\" 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
.\" -----------------------------------------------------------------
.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\&.
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\&.
</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,
<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>
'\" 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
.\" -----------------------------------------------------------------
-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)
######################### 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
## 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
[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
"""
-__version__ = '0.16.2.dev0'
+__version__ = '0.17.0.dev0'
__author__ = 'kaliko'
__email__ = 'kaliko@azylum.org'
__url__ = 'git://git.kaliko.me/sima.git'
--- /dev/null
+# -*- 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
# -*- 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
'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,
- }
+ },
}
#