Graphical front panel display

I’m really interested in seeing how this develops.

Me too!

Above I note that the default spectrum visualization build into Kodi doesn’t seem to make use of FreqData to draw its bars. Looks like that was also noted back in 2014 as part of a Kodi discussion!

https://forum.kodi.tv/printthread.php?tid=204991&page=2

(2014-11-26, 06:12)ironic_monkey Wrote: the spectrum viz doesn’t use fft data… there are no vizes in mainline using the fft data.

Wow. No wonder it looks nothing like a spectrum analyser display…
I really think it should be using the fft data (well assuming the fft data is fixed).

So it just uses a random subset of audio samples. That would explain why it looks like random noise.

The Kodi class that invokes the visualization, CGUIVisualisationControl::OnAudioData(), includes code that can optionally invoke a FFT:

// Fourier transform the data if the vis wants it...
if (!m_transform)
  m_transform.reset(new RFFT(AUDIO_BUFFER_SIZE/2, false)); // half due to stereo

m_transform->calc(psAudioData, m_freq);

but that’s not involved in the current spectrum. Perhaps invoking the FFT was deemed too expensive?

For the purpose of a front panel display, it seems like there are two options:

  • Write a visualization plugin (in C++), and move all of rest of the OLED driving code into that plugin as well.

  • Write a visualization plugin (one that uses GetInfo() to set wantsFreq) that provides a path for exporting the frequency data externally, presumably in a form that’s easy for Python to consume. This is along the lines of the named FIFO approach that mpd_oled pursues to get data from MPD and was the subject of this now-old Kodi thread that I recently bumped:
    https://forum.kodi.tv/showthread.php?tid=223983

For the moment, I’m sufficiently entertained with the service addon from @roidy that I want to figure it out a bit more. What, if anything, actually makes it specific to an Odroid N2? Would it work as-is on a Raspberry Pi, for instance?

Once I get that figured out and, well, get a display, I can pursue the spectrum display further.

A visualization plugin that just dumps the AudioData (and FreqData) for external use seems like it could be generically useful. I worry, though, whether using it would then preclude things like fetching Artist images (since Kodi would think a visualization is active). That either-or choice might restrict interest in it.

Lots to experiment with, at least!

  • Write a visualization plugin (one that uses GetInfo() to set wantsFreq) that provides a path for exporting the frequency data externally, presumably in a form that’s easy for Python to consume.

Hmmm, I wonder if the JSON-RPC available in Kodi would be a means of implementing such communication:

https://codedocs.xyz/xbmc/xbmc/group__jsonrpc.html

Presumably, the FreqData arriving via AudioData() updates wouldn’t be all that large. (It should be far smaller than the actual audio data itself.) Would it suffice for the C++ visualization addon to just maintain the last-received frequency values and provide them to any “caller” via JSON-RPC?

The alternative to some form of within-Kodi communication would be some OS-level alternative – files, named pipes, and the like. That seems like a bit of overhead for what should be a fairly small number of frequency amplitude values. (How many bars can one display, after all?)

Perhaps someone with more Kodi experience will notice this topic and pipe up with a useful opinion.

I got a little side-tracked with the above details, so perhaps I should clarify one of my questions…

What’s the suggested development environment for CoreELEC? Does a normal installation provide the header files and compilation tools necessary to make “tweaks” or try small-ish changes, or is there an easy way to pull in everything needed for that? I’ll go look to see if there’s a developer’s guide.

The service addon from roidy is all Python, but playing with the visualization plugin will require a bit more infrastructure.

Perhaps a weird range of questions, but everyone starts into this with differing levels of experience.

Thanks!
Matt

For the moment, I’m sufficiently entertained with the service addon from @roidy that I want to figure it out a bit more. What, if anything, actually makes it specific to an Odroid N2? Would it work as-is on a Raspberry Pi, for instance?

There is nothing that really makes it specific to the Odroid N2, other than in SPI mode the GPIO pins are hardcoded for the N2 and the SPI /dev/spidev32766.0 path is probably unique to the N2.

I know people have used the add-on on the Vim3 board in I2C mode by just changing the I2C bus number.

There is nothing that really makes it specific to the Odroid N2, other than in SPI mode the GPIO pins are hardcoded for the N2 and the SPI /dev/spidev32766.0 path is probably unique to the N2.

Great. After reading that, at least for modern versions of Raspian on the RPi, /dev/i2c* and /dev/spidev* device files exist, I became hopeful that your addon was essentially platform independent. Sounds like it almost is!

Above I write:

I’ll go look to see if there’s a developer’s guide.

FWIW, looks like the Kodi team has put quite a bit of effort into updating and restructuring their build documentation, which now resides in github alongside the code. The Linux build guide starts here:

https://github.com/xbmc/xbmc/blob/master/docs/README.Linux.md

Seems like binary addons can be compiled outside of the Kodi tree. So, playing with just a visualization addon doesn’t have to be a very heavy lift.

I’ve not yet found anything CoreELEC-specific. LibreELEC’s guide is this document:
https://libreelec.wiki/compile

My (likely too) naive hope is that a CoreELEC installation either includes or provides a route for installing development packages that would allow the “light lift” approach… provide the headers needed for out-of-tree binary addon compilation, as well as the tool chain of course. I’ll go look this weekend (work is a bit too all-consuming).

1 Like

I received a 20x4 LCD character display in the mail yesterday and verified that it was alive (via a spare Raspberry Pi and one of the numerous python-using tutorials online). Since the OLED display has yet to arrive, I’ll likely take a detour investigating this character display.

In case it’s useful to anyone, here’s a summary of what I’ve learned thus far regarding possible quick “routes” for displays. Several viable ones exist… so long as you’re not hankering for a spectrum display.


LCDproc

An overloaded name, referring both to a C-based client/server program for driving LCD or OLED displays and a Python addon to Kodi that acts as another form of client for that C-based server. (There was also an older LCDproc that was part of the original XBMC core. The Python addon is intended to replace that. The longevity of both projects means one can find a lot of hits when searching for them. To me, that makes it hard to find what’s up-to-date.)

As of 2020, both are still getting commits. The webpage for the C-based lcdproc doesn’t seem to have been updated for several years, though. The C client/server has support for a wide range of displays, including HD44780-based character LCDs and apparently some graphical displays as well.

Communication from the addon to the server is sockets based, making use of Python’s telnetlib.

Client/server program: source, webpage
Kodi addon: source

OpenVFD

Python-based service addon for Kodi, by Arthur Liberman, that communicates to displays using C drivers. Configs for the Odroid C2 support HD44780 LCDs and SSD130[69], SH1106 OLEDs. A form of graphical support for the HD44780 displays exists, at least in the form of “big digits”. Based on the name, I originally thought that this addon only supported a very-specific type of display, which was an error.

At least for the HD44780, the actual format of data displayed is handled by the C driver, making local customization not particularly easy.

Kodi addon: source, config files
C drivers: source

This addon has several CoreELEC and LibreELEC forum threads:

Odroid N2 OLED Driver

Python-based service addon for Kodi from @roidy, distinct from OpenVFD. Supports SSD130[69] and SH1106-based OLED graphical displays. (SSD1309 support is SPI-only as of this writing, but I2C should be possible.)

Kodi addon: source

Discussion thread:

KodiDisplayInfo

A completely separate Python program (i.e., not an addon) that queries Kodi (via JSON-RPC) for what’s playing, apparently including artwork, and throws it up on a TFT LCD display. Display duties are handled vi pygame, which in turn depends upon the C-based Simple DirectMedia Layer (libsdl).

The web page unfortunately suggests that the music view with cover thumbnail is a work-in-progress. The most recent commit, as of this writing, is dated June 2017. Still, the KODI_WEBSERVER class may be an interesting starting point; it doesn’t seem like the artwork retrieval was ever implemented.

Python program: source, webpage

Kodisplay

A Python-based Kodi service addon also making use of pygame (and SDL) for displaying to a TFT LCD. Looks like the idea was to have the layout of the displayed controlled via a layout.xml file. Since it’s an addon, details from Kodi are retrieved via InfoLabels. The music section of the example includes this:

		<image path="$INFO[Player.Art(thumb)]">

As of this writing, the last commit is dated Dec 2016.

Kodi addon: source



The not Kodi-related section…

mpd_oled

Focused on the MPD audio distributions moOde, Volume, and RuneAudio. Separate C-based program by Adrian Rossiter that supports SSD130[69] and S[S]H1106-based OLED displays. Depends upon MPD integration to know music-player state and track information, and uses a named pipe (FIFO) to obtain a copy of audio data out of MPD for its spectrum display.

Each of those MPD-based distributions has a forum thread for this program.

The audio spectrum was originally leveraged from C.A.V.A., which obtained audio data from ALSA. That approach is evidently temperamental, though, and the mpd_oled author doesn’t directly support it.

C program: source

pydPiper

Standalone python program, using luma.core and luma.oled, for displaying track information from MPD in moOde, Volumio, and RuneAudio. As of late 2020, supports HD44780 LCDs, SSD1306 panels (I2C only), and two Winstar display types. Looks to have a fairly impressive approach to font support and, more interestingly, page files for the customization of display info.

Audiophonics (the French audio company) made a fork of pydPiper for the displays in their RASPDAC products.

Python program: source

3.5" Touchscreen on Volumio

Instructions on how to enable a 3.5" Waveshare display within Volumio. From what I can tell, both Volumio and moOde Audio have the option of driving a local display – supported by running a web browser within X.

Volumio forum: thread

PyAudioTFT

… and another one. Looks like a pygame-based Python script to present info from MPD. Hasn’t been updated since early 2016, but the screen layout is nicely designed.

Python program: source



UPDATES:

  • Realized there was a C component to OpenVFD.
  • Added pydPiper
  • Added KodiDisplayInfo
  • Added Kodisplay

Here’s what I’ve found thus far regarding the topic of inter-process communication for Kodi. The links are to forum.kodi.tv threads.

This communication topic definitely pops up from time to time. I’ll keep poking around. So far, I haven’t found anything definitive regarding addon (C++ or Python) extensibility of Kodi’s JSON-RPC.

Of course, I also haven’t found anyone with Kodi experience willing to reply. :slight_smile:

1 Like

Two of the three displays on order arrived. I thought it prudent to make sure they’re both alive before moving on… Plus I’m not that experienced with soldering, so always good to make sure I didn’t ruin anything!

20x4 I2C LCD

128x64 SPI OLED

In case anyone is following along, I realized this evening that there is a non-trivial C component to OpenVFD. I updated the description above.

The OLED display I have on-hand uses SPI, and the C2 did not implement a HW-based SPI interface. The HardKernel wiki describes loading modules to get a bit-bang / SW version going. CoreELEC must do something of the sort for the C2, since there is a /dev/spidev* file present.

I couldn’t find any description of what pin assignments get made for the C2’s spi-gpio, though. So, I decided to get get the odroidn2.oled service running on the RPi.

With very little coding changes, it worked!

spi_OLED_RPi

Earlier, @roidy wrote:

There is nothing that really makes it specific to the Odroid N2, other than in SPI mode the GPIO pins are hardcoded for the N2 and the SPI /dev/spidev32766.0 path is probably unique to the N2.

That was indeed the case. I only ended up editing lib/oled.py and lib/gpio.py. Many thanks!

Change to lib/oled.py

diff --git a/lib/oled.py b/lib/oled.py
index a3aadcb..beea936 100644
--- a/lib/oled.py
+++ b/lib/oled.py
@@ -52,7 +52,7 @@ class Oled:
             except IOError:
                 xbmcgui.Dialog().notification("OLED IO Error", "Please check your I2C address and controller type.", xbmcgui.NOTIFICATION_ERROR, 5000)
         else:
-            self.spi= spi.SPI("/dev/spidev32766.0")
+            self.spi= spi.SPI("/dev/spidev0.0")
             self.spi.mode = spi.SPI.MODE_0
             self.spi.bits_per_word = 8
             self.spi.speed = 5000000

New lib/gpio.py

import RPi.GPIO as GPIO
import time

dc_select = 24
spi_reset = 25

def initGPIO():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(dc_select, GPIO.OUT)
    GPIO.setup(spi_reset, GPIO.OUT)

def gpioWriteDC(val):
    GPIO.output(dc_select, val)    

def gpioWriteReset(val):
    GPIO.output(spi_reset, val)

def gpioDoReset():
    gpioWriteReset(1)
    time.sleep(0.1)
    gpioWriteReset(0)
    time.sleep(0.1)
    gpioWriteReset(1)
    time.sleep(0.1)

Note that the code above doesn’t have the try/except blocks, as I was trying to debug matters and appreciated kodi complaining when I messed things up.


My next big question is whether I want the time (elapsed) display during music playback or track information instead (name, album name, artist/composer). True, one likely cannot read it from across the living room, but the same is true for the info tags which I do like.

2 Likes
dc_select = 24
spi_reset = 25

Those particular pin assignments (for data/code and reset signals on the RPi) came from luma.oled, which I what I used to first test out the display.

https://luma-oled.readthedocs.io/en/latest/

GPIO24 and GPIO25 correspond to RPi GPIO Header pins 18 and 20. Connectivity, and numbering, on the Odroid boards is different of course.

Onward to the Odroid C4 next!

In further web searches, I stumbled across the Python-only pydPiper, which displays (text) track information for the MPD distributions (moOde, Volumio, Rune).

I added it to the growing summary above.

Playing with possible approaches to showing audio information, I have this attempt:

audio_info_display

After filling out the 5x7 font to have the full set of ASCII-printable characters, I moved the track number up to become an info “tag” and am trying to show track name, album name, and artist name rather than a time value.

Readability across the room likely isn’t too great. I still also need to figure out

  • unicode display (e.g., what if the artist’s name has accented characters) and
  • truncation of the string at an appropriate length (either that or figure out horizontal scrolling).

Oh, and one of the audio codecs isn’t showing up as a tag appropriately. Still, it’s a potential start and definitely shows how convenient it is to have an all-Python addon.

Display of the audio spectrum is going to take a bit of work. I did get a Feature Request posted, hopefully even in the right spot, on Kodi Forums. I recently found out that one of the available info labels in Kodi is MusicPlayer.cover. I don’t know if that just returns a Kodi-URL for the album art or the art itself. I’m starting to wonder about some of the slightly larger 18-bit color SPI-connected TFT LCDs! :grin:

Anyone have thoughts on alternative info arrangements?

Taking everything as it currently exists on the RPi and stuffing it behind glass in the media center, readability is definitely out of the question. I think going back to the elapsed time may be the only choice that provides much value at that viewing distance. I do still like the info “tags” at the top, though.

I kept wondering whether anyone had tried using the latest luma.core, luma.oled or Adafruit CircuitPython stuff in a Kodi addon… That’s when I was reminded about the whole Python 2 to 3 transition that’s occurring for Kodi 19. Perhaps they’ll be greater experimentation once 19 is stable. (So I forgot about the Python transition – hey, I’m relatively new at this!)

I did order a full-color SPI-driven LCD display. Looking around for how to drive it usefully with Kodi, I came across KodiDisplayInfo. I’ll add it to the summary above.

Unfortunately, the page / view that most has my interest looks to be a work in progress, and the last commit was 3 years ago.

Music thumbnail:

I’ve been looking for similar solutions for years.

There was also Kodisplay https://github.com/vitalogy/script.kodisplay which looks a bit similar to Kodi Display Info but is implemented differently.

I’ve been interested in implementing something like this for ages - particularly for PVR Live TV (so you can see channel logo, number, current show etc.) as well as for music and video watching.

It has struck me that a Pi Zero W with a small matrix I2C or SPI connected OLED, TFT etc. display accessing your Kodi server over WiFi using a JSON RPC (?) over the network would be a neat solution - as you’d remove the need for your Kodi platform to be running OLED or TFT drivers and have I2C or SPI connectivity - and would be able to use the display as a kind of ‘add on’ device. It would work with Kodi on CoreElec, LibreElec, Windows, Macs, Android TV boxes, even on Android TV Smart TVs as it would be connected via the network rather than directly. This would be a really neat ‘universal display’ device for any Kodi instance?

The other thought I had was whether you could get a ‘status’ web page output from Kodi that any device capable of running a web browser would be able to connect to and use (Like a Pi 3A+ over WiFi with a DSI or MIPI DPI connected display). This would work well for larger TFTs, and also be a use for redundant obsolete iPads, Android tablets etc. There is a system called Frontview+ https://github.com/Ghawken/FrontView which does something similar but I didn’t find it really worked for me when I tried it.

There’s a lovely, simple, ‘Now Playing’ implementation for Sonos that runs on a Pi with the Pimoroni 720x720 Hyperpixel 4.0 display (perfect for square artwork because - it’s square) that I’ve built with a Pi 3A+ in a 3D printed case - and it works beautifully. Not cheap - but a very nice looking thing.
( https://www.hackster.io/mark-hank/sonos-album-art-on-raspberry-pi-screen-5b0012 ) which would also be a nice model to copy - if a bit expensive… I based mine on a 3A+ running via WiFi and had a 3D printing company print me this case https://www.thingiverse.com/thing:4128336 (Which is designed for the Touch not the non-Touch version annoyingly…) I had it printed in black and was really impressed with the quality of the print I received.

1 Like

Thanks for the new information, @noggin! I’ve updated my ever-growing summary above.

I like your notion of a separate, network-connected display (whether using a Kodi-generated web page or pulling info via JSON-RPC). The KodiDisplayInfo approach seems like it could have gone done that route.

I’ve also long thought it would be cool to have a smallish tablet (in the 5" range) with wireless charging propped up on a nice walnut stand (hiding the charger). The device could serve as both remote control and a “Now Playing” display. (JRemote has a decent screen for that, and JRemote2 is a recent re-write for any Android fans.) The small tablet market seems to have dried up, though, and Apple never added Qi to the iPod Touch.

Pimoroni’s Hyperpixel is a great looking display! If I was confident I could get something working, the 800x480 version would be fun to play with. At this point, though, I don’t know much about the DPI interface. Is it an RPi-only thing?

Also, in this description of the Adafruit DPI TFT display, there is this slight downer:

The other catch is that this display replaces the HDMI/NTSC output, so you can’t have the DPI HAT and HDMI working at once, nor can you ‘flip’ between the two.

Cheers,
Matt

Some info about artwork retrieval in Kodi…

  • The Images Available in Kodi section of their wiki lists the InfoLabels that are available to Python-based Kodi addons. That list includes MusicPlayer.Cover and Player.Art(type). Presumably these return a “Kodi-internal URL” rather than the artwork itself? I’ll play with logging what a service addon gets back to see.

  • The Artwork page in the wiki has a section on obtaining art via JSON-RPC. That documentation explicitly notes that one gets back Kodi-internal image paths, which can then be converted (in Python) to an externally accessible URL via urllib.parse.quote(). (The urllib.parse library is just part of Python 3.)

At this point, it beats me whether a Python addon can make use of the Kodi-internal image:// path in some other fashion. You wouldn’t think an external URL would be needed if the code is running as part of Kodi.

The JSON-RPC route seems like it would certainly work for a network-attached “Now Playing” widget.

Based on this July 2020 thread on the Odroid forum:

Would or could the C4(or c2) work with a DPI LCD?

it seems like

  • a parallel interface for displays has to be bit-banged on Odroid boards and
  • HardKernel’s own 3.5" display (480 x 320) thus achieves only 15 fps max.

That framerate would still be sufficient for fairly static info like time, progress bars, and artwork. It probably wouldn’t be great for a spectrum display.

@noggin, have you seen this?

MovieNow
https://www.movienowapp.de/index.php

It appears to be an RPi Zero-driven Movie Poster display, with both Kodi and Plex integration. Not exactly what you were describing, but certainly related. I don’t see the source code anywhere, though, and (according to a Sep 25 post on its forum) the last public (i.e., non-donation) version was 3.0.

FWIW, the following python script serves to get fetch-able full-sized image URLs. Using Python 3.8.3 with the json-rpc package added, here’s the script. More afterward.

import requests
import json
import urllib.parse


def main():
    base_url  = "http://10.0.0.188:8080"
    rpc_url   = base_url + "/jsonrpc"
    image_url = base_url + "/images"    
    headers = {'content-type': 'application/json'}

    print("Hello, world!")

    # Assemble a simple "ping" payload as a test
    payload = {
        "jsonrpc": "2.0",        
        "method"  : "JSONRPC.Ping",
        "id"      : 2,
    }

    print("\nPing request:")
    print(json.dumps(payload))

    response = requests.post(rpc_url, data=json.dumps(payload), headers=headers).json()
    print("Response: ", json.dumps(response))

    # See if simple InfoLabels can be retrieved
    payload = {
        "jsonrpc": "2.0",        
        "method"  : "XBMC.GetInfoLabels",
        "params"  : {"labels": ["MusicPlayer.Title",
                                "MusicPlayer.Album",
                                "MusicPlayer.Artist",
                                "MusicPlayer.Time"]},
        "id"      : 3,
    }

    print("\nNext request:")
    print(json.dumps(payload))    

    response = requests.post(rpc_url, data=json.dumps(payload), headers=headers).json()
    print("Response: ", json.dumps(response))


    # How about artwork details?
    payload = {
        "jsonrpc": "2.0",        
        "method"  : "XBMC.GetInfoLabels",
        "params"  : {"labels": ["MusicPlayer.offset(0).Cover"]},
        "id"      : 4,
    }    

    print("\nNext request:")
    print(json.dumps(payload))    

    response = requests.post(rpc_url, data=json.dumps(payload), headers=headers).json()
    print("Response: ", json.dumps(response))

    print("\nIsolating returned image:// path")
    image_path = response["result"]["MusicPlayer.offset(0).Cover"]
    print(image_path)

    print("\nExternal URL is nominally:")
    cover_url = image_url + "/" + urllib.parse.quote(image_path,safe='')
    print(cover_url)

    print("\n\n... However, files evidently need to be prepared for download!\n")
    
    # Prepare download
    payload = {
        "jsonrpc": "2.0",        
        "method"  : "Files.PrepareDownload",
        "params"  : {"path": image_path},
        "id"      : 5,
    }        
    print("\nNext request:")
    print(json.dumps(payload))    

    response = requests.post(rpc_url, data=json.dumps(payload), headers=headers).json()
    print("Response: ", json.dumps(response))    

    print("\nTry retrieving the following:")
    print(base_url + "/" + response["result"]["details"]["path"])
    
if __name__ == "__main__":
    main()

Saving the file under the name client.py and invoking it via python client.ph, here’s an example run from my laptop, with Kodi running separately on an Odroid C4.

Hello, world!

Ping request:
{"jsonrpc": "2.0", "method": "JSONRPC.Ping", "id": 2}
Response:  {"id": 2, "jsonrpc": "2.0", "result": "pong"}

Next request:
{"jsonrpc": "2.0", "method": "XBMC.GetInfoLabels", "params": {"labels": ["MusicPlayer.Title", "MusicPlayer.Album", "MusicPlayer.Artist", "MusicPlayer.Time"]}, "id": 3}
Response:  {"id": 3, "jsonrpc": "2.0", "result": {"MusicPlayer.Album": "Abbey Road", "MusicPlayer.Artist": "The Beatles", "MusicPlayer.Time": "00:40", "MusicPlayer.Title": "Maxwell's Silver Hammer"}}

Next request:
{"jsonrpc": "2.0", "method": "XBMC.GetInfoLabels", "params": {"labels": ["MusicPlayer.offset(0).Cover"]}, "id": 4}
Response:  {"id": 4, "jsonrpc": "2.0", "result": {"MusicPlayer.offset(0).Cover": "/var/media/Music/iTunes/The Beatles/Abbey Road/Folder.jpg"}}

Isolating returned image:// path
/var/media/Music/iTunes/The Beatles/Abbey Road/Folder.jpg

External URL is nominally:
http://10.0.0.188:8080images/%2Fvar%2Fmedia%2FMusic%2FiTunes%2FThe%20Beatles%2FAbbey%20Road%2FFolder.jpg


... However, files evidently need to be prepared for download!


Next request:
{"jsonrpc": "2.0", "method": "Files.PrepareDownload", "params": {"path": "/var/media/Music/iTunes/The Beatles/Abbey Road/Folder.jpg"}, "id": 5}
Response:  {"id": 5, "jsonrpc": "2.0", "result": {"details": {"path": "vfs/%2fvar%2fmedia%2fMusic%2fiTunes%2fThe%20Beatles%2fAbbey%20Road%2fFolder.jpg"}, "mode": "redirect", "protocol": "http"}}

Try retrieving the following:
http://10.0.0.188:8080/vfs/%2fvar%2fmedia%2fMusic%2fiTunes%2fThe%20Beatles%2fAbbey%20Road%2fFolder.jpg

Cutting and pasting the URL at the bottom into a web browser gets me the fullsize cover! I’ve not played yet with getting just a thumbnail image.

Reading through this Kodi-encoded URL text from the wiki, I was at first expecting fetches to the image/ path to “just work”. Somewhere along the way, though, a Files.PrepareDownload step got added.

I hope the above is useful to someone. You would have to replace the IP address targeted, of course.

If anyone with more experience using Kodi’s JSON-RPC interface wants to suggest any improvements, I’m all ears.

UPDATE: One can just use the MusicPlayer.Cover InfoLabel, rather than what I used above. Parsing of the response would have to be adjusted to matched.

Cheers!