@DaveN thanks for all your help! I really appreciate it. It’s difficult to debug an issue I cannot replicate so your help is invaluable in a situation like this. I hope we did not consume too much of your time.
When you play an album via RoonCommandLine it doesn’t scrobble the tracks to last.fm. Is this expected behaviour?
And now I really am turning in
Bill_Janssen
(Wigwam wool socks now on asymmetrical isolation feet!)
44
Both work for me. Non-Latin-1 characters in the tag names? Actually, since Python 3 is all Unicode, I’d bet there’s a tag name using Windows CP-1252 that doesn’t convert properly to Unicode.
Nice idea, but I’m fairly sure that’s not the case. Also, it wouldn’t explain why roon -l genres also fails (as I’m using Roon’s genres, not my own), nor why roon -l playlists now returns the following:
djn@trinity / % roon -l playlists
No playlists found matching __all__
I was wondering why roon -l playlists only returned the Qobuz playlist and noticed it was the only one that was set to ‘Shared (visible to all profiles)’. I changed a few others and they now show up too.
Unfortunately changing the profile / visibility didn’t work for tags, nor does it have any relevance to genres, but I thought it might spark some ideas for you … maybe there’s something going on with respect to Profiles? That said, I only have one profile, and there’s nothing odd about it that I’ve noticed.
Oh, and I also forced a backup this morning, just to check there isn’t something funky going on with my database. It ran without problems.
@DaveN , good morning. Or afternoon maybe where you are? Good to hear that playlist listing is working. But, tags and genres still need work. Let’s see if debug output from the roonapi Python module will get us any helpful info. Attached is a slightly modified list_tags.py with debug logging enabled. Replace your /usr/local/Roon/api/list_tags.py with this debug version and run the command:
[EDIT]
Oops, forgot to attach. I do not see an attachment feature here.
Tell me there is a better way to do this. Copy and paste the following:
import argparse
import configparser
from os import path
import sys
import logging
config = configparser.ConfigParser()
config.read('/usr/local/Roon/etc/roon_api.ini')
# Set to IP address of your Roon Core
server = config['DEFAULT']['RoonCoreIP']
# Set to Port of your Roon Core
port = config['DEFAULT']['RoonCorePort']
# Name of the file that holds a Roon API token
tokenfile = config['DEFAULT']['TokenFileName']
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--tag", help="tag search term")
parser.add_argument("-z", "--zone", help="zone selection")
args = parser.parse_args()
if args.tag:
searchterm = args.tag
else:
searchterm = config['DEFAULT']['DefaultTag']
if args.zone:
target_zone = args.zone
else:
target_zone = config['DEFAULT']['DefaultZone']
version = config['DEFAULT']['RoonCommandLineVersion']
release = config['DEFAULT']['RoonCommandLineRelease']
fullver = version + "-" + release
from roonapi import RoonApi
logging.getLogger("roonapi").setLevel(logging.DEBUG)
appinfo = {
"extension_id": "roon_command_line",
"display_name": "Python library for Roon",
"display_version": fullver,
"publisher": "RoonCommandLine",
"email": "roon@ronrecord.com",
"website": "https://gitlab.com/doctorfree/RoonCommandLine",
}
# Can be None if you don't yet have a token
if path.exists(tokenfile):
token = open(tokenfile).read()
else:
token = "None"
roonapi = RoonApi(appinfo, token, server, port)
# get target zone output_id
outputs = roonapi.outputs
output_id = None
for (k, v) in outputs.items():
if target_zone in v["display_name"]:
output_id = k
if output_id is None:
err = "No zone found matching " + target_zone
sys.exit(err)
# List matching tags
tags = roonapi.list_media(output_id, ["Library", "Tags", searchterm])
if tags:
print(*tags, sep = "\n")
else:
print("No tags found matching ", searchterm)
# save the token for next time
with open(tokenfile, "w") as f:
f.write(str(roonapi.token))
This is an excellent feature request. I was unaware last.fm scrobbling was not supported via the API. I will verify that and, if indeed API calls do not scrobble as one would expect, I may be able to add this feature to RoonCommandLine utilizing the last.fm API.
@DaveN , yes the backtick was a typo on my part. Thanks for the debug output. I am reviewing it and comparing it with the debug output from my successful tags listing. The difference seems to be that in your tag listing, when searching for Tags it can load the browse service successfully but then when it tries to browse the browse service it fails to find a match and triggers a callback which indicates that there was a state change with key “zones_seek_changed”.
My successful tag listing is able to both load and browse the browse service when searching for Tags, does not trigger the callback indicating zone seek change, and continues to search for __all__.
Some info is provided by debug level logging but insufficient for me to fully grok what is going on. But it may help isolate the issue to something to do with accessing the browse service for Tags and Genres but not Albums etc. I do not yet understand what triggers the callback or what “zones_seek_changed” might mean. I will pursue this.
To verify, you have gone into Roon’s “My Stuff → Tags” and in the “My Tags” dropdown enabled “Shared Tags” and this did not change the behavior. Correct? Also, what type of Roon Core are you running? Do you have Roon, Roon Server or ROCK?
This didn’t make any difference. What’s interesting is that it did work for playlists. It’s also interesting that genres fail too, and they aren’t linked to profiles. I’m not sure why tags and genres and, to a lesser extent, playlists, are different from artists and albums. There’s clearly something odd going on.
I’m running Roon Server on a Mac mini M1 (16GB RAM). I’m also running Roon on the same machine as a client.
You’ve probably already found this thread but, if not, it might be useful.
@DaveN yes, I read that thread. We are handling the callback in the Python Roon API but maybe I did not do it correctly in the list_media method. It’s an area I am looking into.
Can you do another test for me? Play by tag is not yet implemented but play_genre is so I would like to see if you can play a genre in your library even though you cannot list the genres in your library. This will give me a clue as to whether the issue is in my list_media method or not.
If it fails I have a debug version of play_genre.py I can get you. If it succeeds, then the problem may be in the list_media method as the play_media method does the same browse_load then browse_browse to locate the media in your library.
Oh yeah, play_genre.py calls list_media before it calls play_media so this didn’t do me any good. I still have suspicions about the list_media method. Let me go off and get lost in code for a while and I will ping you when I re-emerge. Thanks for the test.
This is an updated roonapi.py in the Python Roon API module. It tries to avoid hitting sections of the code that might throw an exception when attempting to access null objects. It may not resolve the issue we are debugging but it should get us further down the execution path. I hope. I’ve tested it here but since I am not yet able to trigger the issue I don’t see how it handles that. If you have time, here is how to test.
First, make a backup copy of the installed roonapi.py so you can restore it later. Locate the roonapi Python module by running:
python3 -m pip show roonapi
The Location: field will tell you where roonapi is installed. For example, it could be something like Location: /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages
Change directory to the roonapi Python module, in this example:
cd /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/roonapi
Thanks! I will look through this for any more clues. It does what I expected, avoids the exceptions we were seeing earlier, gets to the actual search for tags after loading the browse service successfully, but doesn’t find any tags.
The permissions on your /usr/local/Roon/etc/ directory and contents do not look right. The ./Install command should have been run as the user that will be running Roon. It invokes the ./macInstall command and sets ownership of the etc directory and its contents to that user.
So maybe your RoonCommandLine installation failed in some way.
You can manually correct this permissions/ownership error with the command:
sudo chown -R <username> /usr/local/Roon/etc
Where <username> is the username of your RoonCommandLine user (I think that is djn). Maybe there is a bug in the macInstall script. I will review it.
My bad. I thought I read somewhere that it was better to run ./Install with sudo. I’ve corrected the permissions now and re-ran python3 /usr/local/Roon/api/list_tags.py -t _all … Same output, just without the permissions error.
EDIT:
And I guess the following is to be expected, given the change in roonapi.py
djn@trinity etc % roon -l genres
No genres found matching __all__
I could imagine that there was something amiss with my tags, but I can’t see how genres could have got messed up too … I definitely have a whole bunch of them