Subject: bug#73538: closed (Re: bug#73538: [PATCH] Add notifications support to 'mpc')

From: [email-masked] (GNU bug Tracking System)
Date: Fri, 18 Oct 2024 00:27:02 +0000

Your bug report

#73538: [PATCH] Add notifications support to 'mpc'

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
73538: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=73538
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#73538: [PATCH] Add notifications support to 'mpc'
From: john muhl <[email-masked]>
To: Stefan Monnier <[email-masked]>
Cc: [email-masked]
Date: Thu, 17 Oct 2024 19:26:03 -0500
List-Id: <debbugs-submit.debbugs.gnu.org>

Stefan Monnier <[email-masked]> writes:

>> Here’s an updated patch. Should have all feedback incorporated and
>> now with a NEWS entry.
>
> Thanks, merged into `master` (after which I installed some further tweaks).

Thanks for your time. I’ll have another one for you to look at
soonish.

>>> Question: Why is it interactive?
>> I have a global mpc-minor-mode that adds a key binding for
>> notifications and it must have bled through.
>
> 🙂
>
>> Instead of changing mpc-format I made the customizable variables
>> take a list of specs where the first element to return something
>> interesting is used and a plain string can be added for fallback:
>>
>>   (setopt mcp-notifications-body-specs
>>           '("%{Artist}" "%{AlbumArtist}" "Unknown Artist"))
>>
>> I added your description of the FORMAT-SPEC to the mpc-format
>> docstring too.
>
> I tweaked the docstring a bit further.  Regarding the
> `mpc-notifications-body/title`, the problem I can see with it is that
> the "conditionality" is based on the fact that the overall result is
> an empty string, so you can use something like
>
>     (setopt mcp-notifications-body
>             '("By %{Artist}" "By %{AlbumArtist}" "Unknown Artist"))
>
> since the first will expand to the non-empty "By ".  🙁

Whoops. I was trying to mimic how other players do it and
overlooked that possibility since I don’t think I’ve ever seen
something like that. I guess there is still the chance to tweak it
in time for 31 in case the complaints come pouring in.

Subject: [PATCH] Add notifications support to 'mpc'
From: john muhl <[email-masked]>
To: [email-masked]
Date: Sat, 28 Sep 2024 17:48:21 -0500
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

This adds support for displaying a notification when the song
changes.

>From eb495c851dafcf883b0c1cbcd22b2dedc074f226 Mon Sep 17 00:00:00 2001
From: john muhl <[email-masked]>
Date: Sun, 15 Sep 2024 19:52:25 -0500
Subject: [PATCH] Add notifications support to 'mpc'

* lisp/mpc.el (mpc-notifications):
(mpc-notifications-function): New option.
(mpc-notifications-id): New variable.
(mpc-notifications-notify):
(mpc-cover-image-find):
(mpc-cover-image-p): New function.
---
 lisp/mpc.el | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/lisp/mpc.el b/lisp/mpc.el
index 768c70c2e3a..30e295d4810 100644
--- a/lisp/mpc.el
+++ b/lisp/mpc.el
@@ -95,6 +95,8 @@
   (require 'cl-lib)
   (require 'subr-x))
 
+(require 'notifications)
+
 (defgroup mpc ()
   "Client for the Music Player Daemon (mpd)."
   :prefix "mpc-"
@@ -2766,6 +2768,83 @@ mpc-drag-n-drop
       (t
        (error "Unsupported drag'n'drop gesture"))))))
 
+;;; Notifications ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(declare-function notifications-notify "notifications")
+(declare-function w32-notification-notify "notifications")
+(declare-function haiku-notifications-notify "notifications")
+(declare-function android-notifications-notify "notifications")
+
+(defcustom mpc-notifications-function 'mpc-notifications-notify
+  "Function called to display notification."
+  :version "31.1"
+  :type 'function)
+
+(defcustom mpc-notifications nil
+  "Non-nil means to display notifications when the song changes."
+  :version "31.1"
+  :type 'boolean
+  :set (lambda (symbol value)
+         (if-let ((cb (cons 'file mpc-notifications-function))
+                  value)
+             (add-to-list 'mpc-status-callbacks cb)
+           (setq mpc-status-callbacks (delete cb mpc-status-callbacks)))
+         (set-default-toplevel-value symbol value)))
+
+(defvar mpc-notifications-id nil)
+
+(defun mpc-notifications-notify ()
+  "Display a notification with information about the current song."
+  (interactive)
+  (mpc-status-refresh)
+  (when-let (((string= "play" (alist-get 'state mpc-status)))
+             (title (or (alist-get 'Title mpc-status) "Unknown Title"))
+             (body (or (alist-get 'Artist mpc-status)
+                       (alist-get 'AlbumArtist mpc-status)
+                       "Unknown Artist"))
+             (icon (or (mpc-cover-image-find (alist-get 'file mpc-status))
+                       notifications-application-icon)))
+    (pcase system-type
+      ("windows-nt"
+       (w32-notification-notify :title title :body body :icon icon))
+      ("haiku"
+       (setq mpc-notifications-id
+             (haiku-notifications-notify :title title
+                                         :body body
+                                         :app-icon icon
+                                         :replaces-id mpc-notifications-id)))
+      ("android"
+       (setq mpc-notifications-id
+             (android-notifications-notify :title title
+                                           :body body
+                                           :icon icon
+                                           :replaces-id mpc-notifications-id))
+       (android-notifications-notify :title title :body body :icon icon))
+      (_ (when (notifications-get-server-information)
+           (setq mpc-notifications-id
+                 (notifications-notify :title title
+                                       :body body
+                                       :app-icon icon
+                                       :replaces-id mpc-notifications-id)))))))
+
+(defun mpc-cover-image-find (file)
+  "Find cover image for FILE."
+  (and-let* ((default-directory mpc-mpd-music-directory)
+             (dir (file-name-directory file))
+             (files (directory-files (mpc-file-local-copy dir)))
+             (cover (seq-find #'mpc-cover-image-p files))
+             ((expand-file-name cover dir)))))
+
+(defun mpc-cover-image-p (file)
+  "Check if FILE is a cover image."
+  (let ((covers '(".folder.png" "folder.png" "cover.jpg" "folder.jpg")))
+    (or (seq-find (lambda (cover) (string= file cover)) covers)
+        (and mpc-cover-image-re (string-match-p mpc-cover-image-re file)))))
+
+(when mpc-notifications
+  (add-to-list 'mpc-status-callbacks
+               (cons 'file mpc-notifications-function)))
+
 ;;; Toplevel ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defcustom mpc-frame-alist '((name . "MPC") (tool-bar-lines . 1)
-- 
2.46.2