From 8867007bcd104e764a418f8bd4282ede21121f33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jes=C3=BAs=20Daniel=20Colmenares=20Oviedo?=
 <DtxdF@disroot.org>
Date: Mon, 10 Apr 2023 19:45:38 -0400
Subject: [PATCH] audio/py-supysonic: New port: Python implementation of the
 Subsonic server API

Supysonic is a Python implementation of the Subsonic server API.

Current supported features are:
 * browsing (by folders or tags)
 * streaming of various audio files formats
 * transcoding
 * user or random playlists
 * cover art
 * starred tracks/albums and ratings
 * lastfm scrobbling
 * Jukebox mode

WWW: https://supysonic.readthedocs.io/
---
 GIDs                                          |  2 +-
 UIDs                                          |  2 +-
 audio/py-supysonic/Makefile                   | 67 +++++++++++++
 audio/py-supysonic/distinfo                   |  3 +
 .../files/patch-supysonic_config.py           | 11 +++
 audio/py-supysonic/files/supysonic-daemon.in  | 46 +++++++++
 audio/py-supysonic/files/supysonic.conf       | 96 +++++++++++++++++++
 audio/py-supysonic/files/supysonic.in         | 46 +++++++++
 audio/py-supysonic/pkg-descr                  | 11 +++
 audio/py-supysonic/pkg-plist                  |  4 +
 10 files changed, 286 insertions(+), 2 deletions(-)
 create mode 100644 audio/py-supysonic/Makefile
 create mode 100644 audio/py-supysonic/distinfo
 create mode 100644 audio/py-supysonic/files/patch-supysonic_config.py
 create mode 100644 audio/py-supysonic/files/supysonic-daemon.in
 create mode 100644 audio/py-supysonic/files/supysonic.conf
 create mode 100644 audio/py-supysonic/files/supysonic.in
 create mode 100644 audio/py-supysonic/pkg-descr
 create mode 100644 audio/py-supysonic/pkg-plist

diff --git a/GIDs b/GIDs
index 6c9cf67379..20de22a749 100644
--- a/GIDs
+++ b/GIDs
@@ -692,7 +692,7 @@ c-lightning:*:735:
 # free: 748
 # free: 749
 # free: 750
-# free: 751
+supysonic:*:751:
 # free: 752
 # free: 753
 # free: 754
diff --git a/UIDs b/UIDs
index a38e84c282..a5a2dcd815 100644
--- a/UIDs
+++ b/UIDs
@@ -697,7 +697,7 @@ c-lightning:*:735:735::0:0:c-lightning Daemon:/var/db/c-lightning:/usr/sbin/nolo
 # free: 748
 # free: 749
 # free: 750
-# free: 751
+supysonic:*:751:751::0:0:Subsonic server API:/var/db/supysonic:/usr/sbin/nologin
 # free: 752
 # free: 753
 # free: 754
diff --git a/audio/py-supysonic/Makefile b/audio/py-supysonic/Makefile
new file mode 100644
index 0000000000..fab07a87fb
--- /dev/null
+++ b/audio/py-supysonic/Makefile
@@ -0,0 +1,67 @@
+PORTNAME=	supysonic
+DISTVERSION=	0.7.5
+CATEGORIES=	audio python
+MASTER_SITES=	PYPI
+PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
+DISTNAME=	Supysonic-${DISTVERSION}
+
+MAINTAINER=	DtxdF@disroot.org
+COMMENT=	Python implementation of the Subsonic server API
+WWW=		https://supysonic.readthedocs.io/
+
+LICENSE=	AGPLv3
+LICENSE_FILE=	${WRKSRC}/LICENSE
+
+RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}click>0:devel/py-click@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}Flask>0:www/py-flask@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}mediafile>0:devel/py-mediafile@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}peewee>0:databases/py-peewee@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}pillow>0:graphics/py-pillow@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}requests>0:www/py-requests@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}watchdog>0:devel/py-watchdog@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}zipstream-ng>0:archivers/py-zipstream-ng@${PY_FLAVOR}
+
+USES=		python:3.7+
+USE_PYTHON=	autoplist distutils
+
+USE_RC_SUBR=	supysonic \
+		supysonic-daemon
+
+SUB_LIST=	PYTHON_CMD=${PYTHON_CMD} \
+		USER="${USERS:[0]}"
+
+USERS=		supysonic
+GROUPS=		supysonic
+
+PLIST_SUB=	GROUP="${GROUPS:[0]}" \
+		USER="${USERS:[0]}"
+
+OPTIONS_DEFINE=		PGSQL SQLITE3
+OPTIONS_DEFAULT=	GUNICORN SQLITE3 PGSQL MYSQLCLIENT
+OPTIONS_MULTI=		WSGI
+OPTIONS_MULTI_WSGI=	GEVENT GUNICORN WAITRESS
+OPTIONS_RADIO=		MYSQL
+OPTIONS_RADIO_MYSQL=	MYSQLCLIENT PYMYSQL
+
+GEVENT_DESC=		Install with gevent
+GUNICORN_DESC=		Install with gunicorn
+MYSQLCLIENT_DESC=	Install with MySQLdb
+PYMYSQL_DESC=		Install with pymysql
+WAITRESS_DESC=		Install with waitress
+
+GEVENT_RUN_DEPENDS=		${PYTHON_PKGNAMEPREFIX}gevent>0:devel/py-gevent
+GUNICORN_RUN_DEPENDS=		${PYTHON_PKGNAMEPREFIX}gunicorn>0:www/py-gunicorn
+MYSQLCLIENT_RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}mysqlclient>0:databases/py-mysqlclient@${PY_FLAVOR}
+PGSQL_RUN_DEPENDS=		${PYTHON_PKGNAMEPREFIX}psycopg2>0:databases/py-psycopg2@${PY_FLAVOR}
+PYMYSQL_RUN_DEPENDS=		${PYTHON_PKGNAMEPREFIX}pymysql>0:databases/py-pymysql@${PY_FLAVOR}
+SQLITE3_RUN_DEPENDS=		${PYTHON_PKGNAMEPREFIX}sqlite3>0:databases/py-sqlite3@${PY_FLAVOR}
+WAITRESS_RUN_DEPENDS=		${PYTHON_PKGNAMEPREFIX}waitress>0:www/py-waitress
+
+post-install:
+	@${MKDIR} ${STAGEDIR}${ETCDIR}
+	${INSTALL_DATA} ${FILESDIR}/supysonic.conf ${STAGEDIR}${ETCDIR}/supysonic.conf.sample
+.for dir in run log
+	@${MKDIR} ${STAGEDIR}/var/${dir}/supysonic
+.endfor
+
+.include <bsd.port.mk>
diff --git a/audio/py-supysonic/distinfo b/audio/py-supysonic/distinfo
new file mode 100644
index 0000000000..1361b460d8
--- /dev/null
+++ b/audio/py-supysonic/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1680567016
+SHA256 (Supysonic-0.7.5.tar.gz) = 78c6cff107b1b9ce4b19c44ce250b6a4683e01b6de7650873edcd0a034ba8f84
+SIZE (Supysonic-0.7.5.tar.gz) = 339860
diff --git a/audio/py-supysonic/files/patch-supysonic_config.py b/audio/py-supysonic/files/patch-supysonic_config.py
new file mode 100644
index 0000000000..7e6f60f7ea
--- /dev/null
+++ b/audio/py-supysonic/files/patch-supysonic_config.py
@@ -0,0 +1,11 @@
+--- supysonic/config.py.orig	2023-04-08 00:33:44 UTC
++++ supysonic/config.py
+@@ -61,7 +61,7 @@ class DefaultConfig:
+ 
+ class IniConfig(DefaultConfig):
+     common_paths = [
+-        "/etc/supysonic",
++        os.path.join(sys.prefix, "etc/supysonic/supysonic.conf"),
+         os.path.expanduser("~/.supysonic"),
+         os.path.expanduser("~/.config/supysonic/supysonic.conf"),
+         "supysonic.conf",
diff --git a/audio/py-supysonic/files/supysonic-daemon.in b/audio/py-supysonic/files/supysonic-daemon.in
new file mode 100644
index 0000000000..8553aa3f2c
--- /dev/null
+++ b/audio/py-supysonic/files/supysonic-daemon.in
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# PROVIDE: supysonic_daemon
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+#
+# Configuration settings for supysonic-daemon in /etc/rc.conf
+#
+# supysonic_daemon_enable (bool):    Enable supysonic-daemon. (default=NO)
+# supysonic_daemon_user (str):       User to run supysonic-daemon. (default=%%USER%%)
+# supysonic_daemon_log (str):        Send stdout/stderr to a file. (default=/dev/null)
+# supysonic_daemon_flags (str):      Flags used for supysonic-daemon. (default=)
+#
+
+. /etc/rc.subr
+
+name=supysonic_daemon
+rcvar=supysonic_daemon_enable
+
+load_rc_config $name
+
+: ${supysonic_daemon_enable:=NO}
+: ${supysonic_daemon_user:=%%USER%%}
+: ${supysonic_daemon_log:=/dev/null}
+
+pidfile=/var/run/supysonic-daemon.pid
+procname="%%PREFIX%%/bin/supysonic-daemon"
+command_interpreter="%%PYTHON_CMD%%"
+start_cmd="supysonic_daemon_start"
+
+pidfile=/var/run/${name}.pid
+command="%%PREFIX%%/bin/${name}"
+
+supysonic_daemon_start()
+{
+	echo "Starting supysonic-daemon."
+	/usr/sbin/daemon -c \
+		-p "${pidfile}" \
+		-o "${supysonic_daemon_log}" \
+		-u "${supysonic_daemon_user}" \
+		"${command_interpreter}" \
+		"${procname}" \
+		${supysonic_daemon_flags}
+}
+
+run_rc_command "$1"
diff --git a/audio/py-supysonic/files/supysonic.conf b/audio/py-supysonic/files/supysonic.conf
new file mode 100644
index 0000000000..51cf9ac506
--- /dev/null
+++ b/audio/py-supysonic/files/supysonic.conf
@@ -0,0 +1,96 @@
+[base]
+; 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
+database_uri = sqlite:////var/db/supysonic/supysonic.db
+;database_uri = mysql://supysonic:supysonic@localhost/supysonic
+;database_uri = postgres://supysonic:supysonic@localhost/supysonic
+
+; Optional, restrict scanner to these extensions. Default: none
+;scanner_extensions = mp3 ogg
+
+; Should the scanner follow symbolic links? Default: no
+follow_symlinks = no
+
+[webapp]
+; Optional cache directory. Default: /tmp/supysonic
+cache_dir = /var/db/supysonic/cache
+
+; Main cache max size in MB. Default: 512
+cache_size = 512
+
+; Transcode cache max size in MB. Default: 1024 (1GB)
+transcode_cache_size = 1024
+
+; Optional rotating log file. Default: none
+log_file = /var/log/supysonic/supysonic.log
+
+; Log level. Possible values: DEBUG, INFO, WARNING, ERROR, CRITICAL.
+; Default: WARNING
+log_level = WARNING
+
+; Enable log rotation. Default: yes
+log_rotate = yes
+
+; Enable the Subsonic REST API. You'll most likely want to keep this on, here
+; for testing purposes. Default: on
+;mount_api = on
+
+; Enable the administrative web interface. Default: 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
+
+; Enable the ChartLyrics API. Default: off
+online_lyrics = off
+
+[daemon]
+; Socket file the daemon will listen on for incoming management commands
+; Default: /tmp/supysonic/supysonic.sock
+socket = /var/run/supysonic/supysonic.sock
+
+; Defines if the file watcher should be started. Default: yes
+run_watcher = yes
+
+; Delay in seconds before triggering scanning operation after a change have been
+; detected.
+; This prevents running too many scans when multiple changes are detected for a
+; single file over a short time span. Default: 5
+wait_delay = 5
+
+; Command used by the jukebox
+jukebox_command = mplayer -ss %offset %path
+
+; Optional rotating log file for the scanner daemon. Logs to stderr if empty
+log_file = /var/log/supysonic/supysonic-daemon.log
+log_level = INFO
+log_rotate = yes
+
+[lastfm]
+; API and secret key to enable scrobbling. http://www.last.fm/api/accounts
+; Defaults: none
+;api_key =
+;secret =
+
+[transcoding]
+; Programs used to convert from one format/bitrate to another. Defaults: none
+transcoder_mp3_mp3 = lame --quiet --mp3input -b %outrate %srcpath -
+transcoder = ffmpeg -i %srcpath -ab %outratek -v 0 -f %outfmt -
+decoder_mp3 = mpg123 --quiet -w - %srcpath
+decoder_ogg = oggdec -o %srcpath
+decoder_flac = flac -d -c -s %srcpath
+encoder_mp3 = lame --quiet -b %outrate - -
+encoder_ogg = oggenc2 -Q -M %outrate -
+
+; Default format, used when a client requests a bitrate lower than the original
+; file and no specific format
+default_transcode_target = mp3
+
+[mimetypes]
+; Extension to mimetype mappings in case your system has some trouble guessing
+; Default: none
+;mp3 = audio/mpeg
+;ogg = audio/vorbis
+
diff --git a/audio/py-supysonic/files/supysonic.in b/audio/py-supysonic/files/supysonic.in
new file mode 100644
index 0000000000..d20138f1d6
--- /dev/null
+++ b/audio/py-supysonic/files/supysonic.in
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+# PROVIDE: supysonic
+# REQUIRE: NETWORKING LOGIN
+# KEYWORD: shutdown
+#
+# Configuration settings for supysonic in /etc/rc.conf
+#
+# supysonic_enable (bool):    Enable supysonic. (default=NO)
+# supysonic_user (str):       User to run supysonic-server. (default=%%USER%%)
+# supysonic_log (str):        Send stdout/stderr to a file. (default=/dev/null)
+# supysonic_flags (str):      Flags used for supysonic-server. (default=)
+#
+
+. /etc/rc.subr
+
+name=supysonic
+rcvar=supysonic_enable
+
+load_rc_config $name
+
+: ${supysonic_enable:=NO}
+: ${supysonic_user:=%%USER%%}
+: ${supysonic_log:=/dev/null}
+
+pidfile=/var/run/${name}.pid
+procname="%%PREFIX%%/bin/${name}-server"
+command_interpreter="%%PYTHON_CMD%%"
+start_cmd="supysonic_start"
+
+pidfile=/var/run/${name}.pid
+command="%%PREFIX%%/bin/${name}"
+
+supysonic_start()
+{
+	echo "Starting ${name}."
+	/usr/sbin/daemon -c \
+		-p "${pidfile}" \
+		-o "${supysonic_log}" \
+		-u "${supysonic_user}" \
+		"${command_interpreter}" \
+		"${procname}" \
+		${supysonic_flags}
+}
+
+run_rc_command "$1"
diff --git a/audio/py-supysonic/pkg-descr b/audio/py-supysonic/pkg-descr
new file mode 100644
index 0000000000..907d8a16d5
--- /dev/null
+++ b/audio/py-supysonic/pkg-descr
@@ -0,0 +1,11 @@
+Supysonic is a Python implementation of the Subsonic server API.
+
+Current supported features are:
+ * browsing (by folders or tags)
+ * streaming of various audio files formats
+ * transcoding
+ * user or random playlists
+ * cover art
+ * starred tracks/albums and ratings
+ * lastfm scrobbling
+ * Jukebox mode
diff --git a/audio/py-supysonic/pkg-plist b/audio/py-supysonic/pkg-plist
new file mode 100644
index 0000000000..df10966032
--- /dev/null
+++ b/audio/py-supysonic/pkg-plist
@@ -0,0 +1,4 @@
+@dir %%ETCDIR%%
+@sample %%ETCDIR%%/supysonic.conf.sample
+@dir(%%USER%%,%%GROUP%%,) /var/run/supysonic
+@dir(%%USER%%,%%GROUP%%,) /var/log/supysonic
-- 
2.38.1