INTERACT FORUM

Please login or register.

Login with username, password and session length
Advanced search  
Pages: [1]   Go Down

Author Topic: JRiver Conky Integration (1st Attempt, Try at your own risk)  (Read 4616 times)

mwillems

  • MC Beta Team
  • Citizen of the Universe
  • *****
  • Posts: 5242
  • "Linux Merit Badge" Recipient

I'm a big fan of Conky (for the unfamiliar, it's a lightweight highly customizable system monitoring/scriptable display tool for linux). People have integrated weather apps, system upgrade notifications, rss feeds, and almost anything else you can think of into Conky, basically turning it into a replacement sytem tray/notification system for X11 desktops.  Conky also has integration with several Linux music players, most notably mpd.  Conky has built in support to show all kinds of metadata from mpd and a few other players, so I decided to do some work to try and get basic "homemade" conky integration with JRiver using MCWS.



You can see what my "first draft" looks like on the right side of the desktop.  I'm still trying to work out a few issues with how it interacts with my normal conky (on the left hand side of the screen), but that's kind of a side issue.  I've got it fetching and displaying the currently playing Artist, Album, Track Title, Duration, and the Cover Art in real time.  I also managed to script some "intelligent" scrolling  so that the text entries scroll only when they're longer than will fit in the available space.  That said, Conky's built in scroll feature is a little "dumb" (lots of white space between scrolls), but it works in a basic way.

I'm going to post the code below with the following caveats:  

1) You'll need to tweak this based on the size of your display, your window manager, and about a half dozen other things.  There's really no such thing as a "drop in" conky configuration.
2) These scripts will not be winning any awards for beauty, efficiency, or code correctness.  They mostly work, but do a few things that are frowned on by professionals (like using regex to parse XML strings, which I have on good authority will result in ponies eating your face).  For that reason, it's not likely to be super portable, or a good fit for low-powered devices (like a Pi).
3) I tried to avoid doing anything that seemed obviously dangerous, and built in one or two data validation features (more to come), *BUT* this code is provided as is for informational purposes without any guarantee of safety, suitability, etc.  If you have an album with a fork bomb for a name, you're on your own.  If you don't know what any of this does, don't run it.

The scripts all assume that they'll be in a directory named ".MCWS" in the home directory of the user who is running conky.  Feel free to put them wherever you like, but remember to change the scripts

The main script (Fetcher) fetches an XML file using MCWS that has general info about what's playing, as well as fetching the album art, and performing a data validation step.
Code: [Select]
#!/bin/bash
#Fetch the xml
wget -q localhost\:52199/MCWS/v1/Playback/Info\?Zone\=\-1 -O ~/.MCWS/Info    
#Lift out the image URL
URL=$(sed -n 's:.*<Item Name="ImageURL">\(.*\)</Item>.*:\1:p' ~/.MCWS/Info)
#Fetch the Image
wget localhost:52199/$URL -O ~/.MCWS/img.jpg
#Fix ampersands
sed -- 's/\&amp;/\&/g' ~/.MCWS/Info > ~/.MCWS/Info2
mv ~/.MCWS/Info2 ~/.MCWS/Info

Then (because Conky only really handles one line at a time) we have separate scripts for each of the data elements we're pulling.  For example, the Artist script looks like this:
Code: [Select]
#!/bin/bash
~/.MCWS/Fetcher
ARTIST=$(sed -n 's:.*<Item Name="Artist">\(.*\)</Item>.*:\1:p' ~/.MCWS/Info)
echo $ARTIST

The Album, Name, ElapsedTimeDisplay, and TotalTimeDisplay scripts are identical except for replacing Artist with the appropriate term in all instances.

The relevant part of the final conky configuration file (under the TEXT header in the .conkyrc) is set up like this on a 1920x1080 screen:
Code: [Select]
${goto 1250}${color} JRiver
${goto 1252}${color} Artist: ${if_match "35" <= "${exec  ~/.MCWS/Artist | wc -m}"} ${alignr 265}${scroll 33 ${execi 1 ~/.MCWS/Artist}} ${else} ${alignr 265}${execi 1 ~/.MCWS/Artist}${endif}
${goto 1252}${color} Album:  ${if_match "35" <= "${exec  ~/.MCWS/Album | wc -m}"} ${alignr 265}${scroll 33 ${execi 1 ~/.MCWS/Album}} ${else} ${alignr 265}${execi 1 ~/.MCWS/Album}${endif}
${goto 1252}${color} Track:  ${if_match "35" <= "${exec  ~/.MCWS/Track | wc -m}"} ${alignr 265}${scroll 33 ${execi 1 ~/.MCWS/Track}} ${else} ${alignr 265}${execi 1 ~/.MCWS/Track}${endif}
${goto 1252}${color} Time:  ${alignr 265}${execi 1 ~/.MCWS/Elapsed_Time} / ${execi 1 ~/.MCWS/Total_Time}
${image ~/.MCWS/img.jpg -p 1255,550 -s 400x400 -f 2}

I'm sure that looks like an unholy mess, but unfortunately Conky treats white space as actual white space, so every space you add affects the final spacing.  One of my first improvement steps will be trying to find ways to clean this up without messing up the design.  Hopefully this is helpful for someone (or at least some people who know bash and regex much better than me will offer constructive criticism  ;D )

 
Logged

mattkhan

  • MC Beta Team
  • Citizen of the Universe
  • *****
  • Posts: 4276
Re: JRiver Conky Integration (1st Attempt, Try at your own risk)
« Reply #1 on: June 20, 2015, 11:31:29 am »

You could use xmllint --xpath if you want to keep the ponies at bay. This is an easy way to execute adhoc xpath expressions in a script to select element/attribute values without losing your marbles when regex'ing it :)

Logged

mwillems

  • MC Beta Team
  • Citizen of the Universe
  • *****
  • Posts: 5242
  • "Linux Merit Badge" Recipient
Re: JRiver Conky Integration (1st Attempt, Try at your own risk)
« Reply #2 on: June 20, 2015, 02:41:24 pm »

I'm looking at that right now actually, thanks for the tip.

Given that I'm really just trying to lift a readily identifiable string out of relatively fixed xml document (rather than trying to truly parse it), I may be able to get away with my abominable seds, but there's got to be a more efficent/prettier way.  I also need to figure out what kind of performance hit running all those shell scripts is causing.  The Conky docs recommend patching in anything you care about using C, and note that iterative shell calls are very resource intensive.  I'm not sure exactly how intensive they mean; I tested it on a 4790K, so I don't see conky cracking 2% CPU at worst, but I bet all those sub-shells would be pretty rough on a Raspi.  I could always just have it poll less often than once a second, especially if I changed the playtime entry to a bar instead of a number.
Logged

mattkhan

  • MC Beta Team
  • Citizen of the Universe
  • *****
  • Posts: 4276
Re: JRiver Conky Integration (1st Attempt, Try at your own risk)
« Reply #3 on: June 21, 2015, 05:47:39 am »

Generally speaking it gets punishing, performance wise, when you have subshells forking in a loop or if polling repeatedly. The cost of all those forks can add up. At that point, you want to work out how to collapse the forks into one process. This may entail moving the functionality out of bash and into some other language (perl, ruby etc). I imagine they recommend C as you would normally be accessing the host system itself in a conky plugin. Something like Ruby is probably a better fit for this sort of operation though if you poll every second then that is not much overhead.

The optimisations that stand out are probably

- cache the IMG rather than fetching each time
- read the xml once dump out the contents per field of interest rather than read it n times, awk would be the obvious drop in replacement for that though http://stackoverflow.com/questions/2957684/awk-access-captured-group-from-line-pattern says capturing the regex group value is not obvious (but doable). You'd certainly save on the forks there but if the doc is small (I suppose it is) then I imagine the actual speedup might be quite trivial, one for benchmarking (e.g. time it on a loop of a few 000s runs).

For a low powered client, i would think the best optimisation is doing no work, ie get the server to push the required content from the xml, inc the img, to client
Logged

mwillems

  • MC Beta Team
  • Citizen of the Universe
  • *****
  • Posts: 5242
  • "Linux Merit Badge" Recipient
Re: JRiver Conky Integration (1st Attempt, Try at your own risk)
« Reply #4 on: June 21, 2015, 09:46:06 am »

Generally speaking it gets punishing, performance wise, when you have subshells forking in a loop or if polling repeatedly. The cost of all those forks can add up. At that point, you want to work out how to collapse the forks into one process. This may entail moving the functionality out of bash and into some other language (perl, ruby etc). I imagine they recommend C as you would normally be accessing the host system itself in a conky plugin. Something like Ruby is probably a better fit for this sort of operation though if you poll every second then that is not much overhead.

This is all good advice, and I'll look into it.  I was inclining towards C just because I already know it (admittedly 10 year old knowledge, but it was fairly deep at the time), whereas I know nothing at all about perl or ruby.  But they seem popular, and it might be an excuse to learn something new.

Quote
The optimisations that stand out are probably

- cache the IMG rather than fetching each time

That's a good idea, and I've added it to my to do list

Quote
- read the xml once dump out the contents per field of interest rather than read it n times, awk would be the obvious drop in replacement for that though http://stackoverflow.com/questions/2957684/awk-access-captured-group-from-line-pattern says capturing the regex group value is not obvious (but doable). You'd certainly save on the forks there but if the doc is small (I suppose it is) then I imagine the actual speedup might be quite trivial, one for benchmarking (e.g. time it on a loop of a few 000s runs).

I actually looked at awking it because I'm better with awk than with sed, but the way the xml is structured, the awk "fields" split in the wrong places for parsing, and there's no single character that could be defined as a delimiter that would produce guaranteed correct results.  I'd need to pre-process it (possibly with sed again) and then re-awk it to get the fields I want.  That might still be faster than reading the file umpteen times.  

Really the final answer is to get everything into a single script/program so I can keep the info in memory, it's just hard to consolidate given that conky formats text based on literal location in the config file, but there has to be a way around that.

Quote
For a low powered client, i would think the best optimisation is doing no work, ie get the server to push the required content from the xml, inc the img, to client

That's a good idea if someone wants to take it up.  In my case, I don't use any of my Pi's for direct interactive use (they're all functioning as headless boxes), so I wouldn't want to use this myself on Pis anyway, but for anyone who might, that's a good answer.
Logged
Pages: [1]   Go Up