1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 08:56:17 +00:00

Add ignored articles support

Closes #200
This commit is contained in:
Alban Féron 2020-11-09 17:31:04 +01:00
parent 62ae4a9967
commit cec216684d
No known key found for this signature in database
GPG Key ID: 8CE0313646D16165
4 changed files with 59 additions and 11 deletions

View File

@ -1,5 +1,6 @@
[base] [base]
; A database URI. See the 'schema' folder for schema creation scripts ; A database URI. See the 'schema' folder for schema creation scripts. Note that
; you don't have to run these scripts yourself.
; Default: sqlite:////tmp/supysonic/supysonic.db ; Default: sqlite:////tmp/supysonic/supysonic.db
;database_uri = sqlite:////var/supysonic/supysonic.db ;database_uri = sqlite:////var/supysonic/supysonic.db
;database_uri = mysql://supysonic:supysonic@localhost/supysonic ;database_uri = mysql://supysonic:supysonic@localhost/supysonic
@ -35,6 +36,10 @@ log_level = WARNING
; Enable the administrative web interface. Default: on ; Enable the administrative web interface. Default: on
;mount_webui = on ;mount_webui = on
; Space separated list of prefixes that should be ignored on index endpoints
; Default: El La Le Las Les Los The
index_ignored_prefixes = El La Le Las Les Los The
[daemon] [daemon]
; Socket file the daemon will listen on for incoming management commands ; Socket file the daemon will listen on for incoming management commands
; Default: /tmp/supysonic/supysonic.sock ; Default: /tmp/supysonic/supysonic.sock

View File

@ -106,6 +106,12 @@ purposes. Defaults to `on`.
Note that setting this off will prevent users from defining a preferred Note that setting this off will prevent users from defining a preferred
transcoding format. Defaults to `on`. transcoding format. Defaults to `on`.
`index_ignored_prefixes`: space separated list of prefixes that should be
ignored from artist names when returning their index. Example: if the word _The_
is in this list, artist _The Rolling Stones_ will be listed under the letter _R_.
The match is case insensitive.
Defaults to `El La Le Las Les Los The`.
```ini ```ini
[webapp] [webapp]
; Optional cache directory. Default: /tmp/supysonic ; Optional cache directory. Default: /tmp/supysonic
@ -130,6 +136,10 @@ log_level = WARNING
; Enable the administrative web interface. Default: on ; Enable the administrative web interface. Default: on
;mount_webui = on ;mount_webui = on
; Space separated list of prefixes that should be ignored on index endpoints
; Default: El La Le Las Les Los The
index_ignored_prefixes = El La Le Las Les Los The
``` ```
## `[daemon]` section ## `[daemon]` section

View File

@ -5,10 +5,11 @@
# #
# Distributed under terms of the GNU AGPLv3 license. # Distributed under terms of the GNU AGPLv3 license.
import re
import string import string
import uuid import uuid
from flask import request from flask import current_app, request
from pony.orm import ObjectNotFound, select, count from pony.orm import ObjectNotFound, select, count
from ..db import Folder, Artist, Album, Track from ..db import Folder, Artist, Album, Track
@ -29,6 +30,26 @@ def list_folders():
) )
def build_ignored_articles_pattern():
articles = current_app.config["WEBAPP"]["index_ignored_prefixes"]
if articles is None:
return None
articles = articles.split()
if not articles:
return None
return r"^(" + r" |".join(re.escape(a) for a in articles) + r" )"
def ignored_articles_str():
articles = current_app.config["WEBAPP"]["index_ignored_prefixes"]
if articles is None:
return ""
return " ".join(articles.split())
@api.route("/getIndexes.view", methods=["GET", "POST"]) @api.route("/getIndexes.view", methods=["GET", "POST"])
def list_indexes(): def list_indexes():
musicFolderId = request.values.get("musicFolderId") musicFolderId = request.values.get("musicFolderId")
@ -49,7 +70,10 @@ def list_indexes():
last_modif = max(map(lambda f: f.last_scan, folders)) last_modif = max(map(lambda f: f.last_scan, folders))
if ifModifiedSince is not None and last_modif < ifModifiedSince: if ifModifiedSince is not None and last_modif < ifModifiedSince:
return request.formatter( return request.formatter(
"indexes", dict(lastModified=last_modif * 1000, ignoredArticles="") "indexes",
dict(
lastModified=last_modif * 1000, ignoredArticles=ignored_articles_str()
),
) )
# The XSD lies, we don't return artists but a directory structure # The XSD lies, we don't return artists but a directory structure
@ -60,8 +84,12 @@ def list_indexes():
children += f.tracks.select()[:] children += f.tracks.select()[:]
indexes = dict() indexes = dict()
pattern = build_ignored_articles_pattern()
for artist in artists: for artist in artists:
index = artist.name[0].upper() name = artist.name
if pattern:
name = re.sub(pattern, "", name, flags=re.I)
index = name[0].upper()
if index in string.digits: if index in string.digits:
index = "#" index = "#"
elif index not in string.ascii_letters: elif index not in string.ascii_letters:
@ -70,19 +98,19 @@ def list_indexes():
if index not in indexes: if index not in indexes:
indexes[index] = [] indexes[index] = []
indexes[index].append(artist) indexes[index].append((artist, name))
return request.formatter( return request.formatter(
"indexes", "indexes",
dict( dict(
lastModified=last_modif * 1000, lastModified=last_modif * 1000,
ignoredArticles="", ignoredArticles=ignored_articles_str(),
index=[ index=[
dict( dict(
name=k, name=k,
artist=[ artist=[
a.as_subsonic_artist(request.user) a.as_subsonic_artist(request.user)
for a in sorted(v, key=lambda a: a.name.lower()) for a, _ in sorted(v, key=lambda t: t[1].lower())
], ],
) )
for k, v in sorted(indexes.items()) for k, v in sorted(indexes.items())
@ -122,8 +150,12 @@ def list_genres():
def list_artists(): def list_artists():
# According to the API page, there are no parameters? # According to the API page, there are no parameters?
indexes = dict() indexes = dict()
pattern = build_ignored_articles_pattern()
for artist in Artist.select(): for artist in Artist.select():
index = artist.name[0].upper() if artist.name else "?" name = artist.name or "?"
if pattern:
name = re.sub(pattern, "", name, flags=re.I)
index = name[0].upper()
if index in string.digits: if index in string.digits:
index = "#" index = "#"
elif index not in string.ascii_letters: elif index not in string.ascii_letters:
@ -132,18 +164,18 @@ def list_artists():
if index not in indexes: if index not in indexes:
indexes[index] = [] indexes[index] = []
indexes[index].append(artist) indexes[index].append((artist, name))
return request.formatter( return request.formatter(
"artists", "artists",
dict( dict(
ignoredArticles="", ignoredArticles=ignored_articles_str(),
index=[ index=[
dict( dict(
name=k, name=k,
artist=[ artist=[
a.as_subsonic_artist(request.user) a.as_subsonic_artist(request.user)
for a in sorted(v, key=lambda a: a.name.lower()) for a, _ in sorted(v, key=lambda t: t[1].lower())
], ],
) )
for k, v in sorted(indexes.items()) for k, v in sorted(indexes.items())

View File

@ -38,6 +38,7 @@ class DefaultConfig(object):
"log_level": "WARNING", "log_level": "WARNING",
"mount_webui": True, "mount_webui": True,
"mount_api": True, "mount_api": True,
"index_ignored_prefixes": "El La Le Las Les Los The",
} }
DAEMON = { DAEMON = {
"socket": r"\\.\pipe\supysonic" "socket": r"\\.\pipe\supysonic"