Open mxdalchau opened 1 year ago
Could you be a bit more specific in what you're looking for? The "how to use" section is step by step on how to get things running. I'm more than happy to add additional information, but I'm not sure what exactly you're looking for
He might mean weather you are going to publish it on DockerHub? This might make it easier for people to implement. Just guessing here, and following this project with great interest!
Hey, sorry my english is no t so good...
If i use docker-compose with docker file.. which file i should edit?
so the docker-compose is running http://xxx.xxx.xxx.xxx:3333/wsdl
there is only a white site
could i see a log ... to analyze whats the problem
I think a more detailed how-to might help. I am struggling with quite a few point:
Since I couldnt find it I tried via docker-compose
docker-compose refers to node-docker but that cannot be found or installed.
audiobookshelf-sonos Error
Error response from daemon: pull access denied for node-docker, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
The "ABS_TOKEN=" likely stands for the audiobookshelf user token, that can be found when logging in as root and clicking on settings -> users -> specific username
ABS_LIBRARY_ID= is not clear. Does it expect a ID (likely numeric) or the name of the library?
are the modifications of config.js and sonos.wsdl also necessary when running via docker compose? if yes how does docker compose know which files to take - the only volumne defined there is sonos.wsdl?
I've spent a bit of time looking at this and have a few answers to the above.
docker build -t node-docker:latest
, the command will run and it should work. Anyway, I've tried all these, and still not working.
@jmt-gh, what sort of response should we be getting from the URLs: https://soap.server.com/wsdl or https://soap.server.com/manifest?
I get a 200 response but 0 bytes return from the /wsdl, and this response from the /manifest:
{
"schemaVersion": "1.0",
"endpoints": [
{
"type": "reporting",
"uri": "https://soap.server.com/wsdl/playback/v2.1/report"
}
]
}
Seems like there should be a bit more in the wsdl response at least.
By the way, if I use this for the env variable in the docker-compose:
- SOAP_URI="https://soap.server.com/wsdl"
The return from the manifest shows this:
"uri": '"https://soap.server.com/wsdl"/playback/v2.1/report'
When I remove the "", it displays correctly.
should the abs uri only a http or could be https?
i get {"schemaVersion":"1.0","endpoints":[{"type":"reporting","uri":"https://soabs.xxxx.de/wsdl/playback/v2.1/report"}]} what is right, but i can´t access in sonos
should the abs uri only a http or could be https?
I'd have thought whatever you have set up. Mine is https, so that's what I've put in.
ok me too.. but the sonos app can´t read the libary
Mine can't either, I get a connection error. There's no feedback on the log of the container, so it's quite hard to debug it.
schade eigentlich wirkte das Projekt vielversprechend
@jt196 did you ever get this working?
@jt196 did you ever get this working?
Hacked away at it for half a day but never got it to work. I could add the service to Sonos by unchecking "Support Manifest File", that's about as far as I got. There were no logs on the Docker container when I tried to access it in Sonos, and Sonos itself have disabled a lot of the log checking functions in their speakers. I went a little through their docs, but had little success I'm afraid.
Hi!
I set this up in a docker container on Unraid, Trial and error but it's running except cant find a way to access the library in the sonosapp.
The docker log gives me this error: [getLibraryItems] Error caught. Error: Request failed with status code 404
@eendenhart no idea, but maybe post how you got so far here so maybe we can get a solution together?
404 is just a not found error, so likely you've entered the audiobookshelf URL incorrectly.
I think the url is correct; I checked many times. I got a connection in audiobookshelf: when i typ the wrong token he gives in the logs of audiobookshelf an error.
What i did:
docker build /mnt/user/appdata/audiobookshelf-sonos
docker tag 'containerid' node-docker
https://hub.docker.com/r/eendenhart/audiobookshelf-sonos/
80:3333
I got the error [getLibraryItems] Error caught. Error: Request failed with status code 404
when i hit the services in sonos
@jt196 did you ever get this working?
Hacked away at it for half a day but never got it to work. I could add the service to Sonos by unchecking "Support Manifest File", that's about as far as I got. There were no logs on the Docker container when I tried to access it in Sonos, and Sonos itself have disabled a lot of the log checking functions in their speakers. I went a little through their docs, but had little success I'm afraid.
I've put a bit of time into this today and got a little further but still not working.
First of all I turned on debugging in the servert.js file by uncommenting line 37. Now we can see incoming requests and how the SOAP server responds.
Now for what I had been doing wrong:
The first few requests go through and seem to make it to audiobookshelf, however I'm hitting a wall with the error:
TypeError: Cannot read properties of undefined (reading 'id')
Edit: A bit more digging and I got there. Comment out lines: 104, 105, 106, 107, 108, 139, 140, 141, 142, 144, 145 in utils.js. It seems if you have any book metadata missing (author, narrator, album art etc) it causes the wrong data to be returned. after commenting out these lines Sonos finally connects to audio book shelf and shows my library.
However, it still does not play any of the books, saying Sonos is unable to connect. I suspect the function getMediaMetadata on line 16 of sonos-service.js needs completing.
@robwalster I've played around a little bit and made no progress at all. Some pointers that might be useful.
FROM node:16-alpine
ENV NODE_ENV=production
WORKDIR /app
COPY ["package.json", "package-lock.json", "./"]
RUN npm install --production && npm install -g nodemon
COPY . .
CMD ["nodemon", "server.js"]
async function buildLibraryMetadataResult(res) { if (!res || !res.results) { return null; } let libraryItems = res.results; let count = res.total; let total = count; let mediaMetadata = []; for (const libraryItem of libraryItems) { if (!libraryItem || !libraryItem.media || !libraryItem.media.audioFiles || !libraryItem.media.audioFiles[0]) { continue; } let authorId = libraryItem.media.metadata && libraryItem.media.metadata.authors && libraryItem.media.metadata.authors[0] ? libraryItem.media.metadata.authors[0].id : null; let authorName = authorId ? libraryItem.media.metadata.authors[0].name : null; let narratorId = libraryItem.media.metadata && libraryItem.media.metadata.narrators && libraryItem.media.metadata.narrators[0] ? libraryItem.media.metadata.narrators[0].id : null; let narratorName = narratorId ? libraryItem.media.metadata.narrators[0].name : null; var mediaMetadataEntry = { itemType: "audiobook", id: libraryItem.id, mimeType: libraryItem.media.audioFiles[0].mimeType, canPlay: true, canResume: true, title: libraryItem.media.metadata ? libraryItem.media.metadata.title : null, summary: libraryItem.media.metadata ? libraryItem.media.metadata.description : null, authorId: authorId, author: authorName, narratorId: narratorId, narrator: narratorName, albumArtURI: `${ABS_URI}${libraryItem.media.coverPath}?token=${ABS_TOKEN}`, }; mediaMetadata.push(mediaMetadataEntry); } return { getMetadataResult: { count: count, total: total, index: 0, mediaCollection: mediaMetadata, }, }; } async function buildAudiobookTrackList(libraryItem, progressData) { if (!libraryItem || !libraryItem.media || !libraryItem.media.audioFiles) { return null; } let tracks = libraryItem.media.audioFiles; let icount = tracks.length; let itotal = tracks.length; let imediaMetadata = []; for (const track of tracks) { let authorId = libraryItem.media.metadata && libraryItem.media.metadata.authors && libraryItem.media.metadata.authors[0] ? libraryItem.media.metadata.authors[0].id : null; let authorName = authorId ? libraryItem.media.metadata.authors[0].name : null; let narratorId = libraryItem.media.metadata && libraryItem.media.metadata.narrators && libraryItem.media.metadata.narrators[0] ? libraryItem.media.metadata.narrators[0].id : null; let narratorName = narratorId ? libraryItem.media.metadata.narrators[0].name : null; var mediaMetadataEntry = { id: `${libraryItem.id}/${track.metadata.filename}`, itemType: "track", title: track.metadata.filename, mimeType: track.mimeType, trackMetadata: { authorId: authorId, author: authorName, narratorId: narratorId, narrator: narratorName, duration: track.duration, book: libraryItem.media.metadata ? libraryItem.media.metadata.title : null, albumArtURI: `${ABS_URI}${libraryItem.media.coverPath}?token=${ABS_TOKEN}`, canPlay: true, canAddToFavorites: false, }, }; imediaMetadata.push(mediaMetadataEntry); } let positionInformation = {}; if (progressData) { positionInformation = { id: `${libraryItem.id}/${progressData.partName}`, index: 0, offsetMillis: Math.round(progressData.relativeTimeForPart * 1000), }; } return { getMetadataResult: { count: icount, total: itotal, index: 0, positionInformation: positionInformation, mediaMetadata: imediaMetadata, }, }; }
Edit, 'scuse the crappy formating, didn't want to paste the whole lot here but the details tags don't play well with code.
OK it appears to be an issue with the buildLibraryMetadata function.
This is an object being fed into the loop:
{
id: '70edd71c-0088-49b8-8ea5-210c8049ce09',
ino: '370123',
oldLibraryItemId: 'ab_vm3xuee9z2z7krgw7q',
libraryId: '96cfd553-cc4e-4a9b-9f67-866838eb62d7',
folderId: '92fb9312-b5e2-4aae-b1d4-96fd7e521299',
path: '/audiobooks/C.S. Forester/The Good Shepherd',
relPath: 'C.S. Forester/The Good Shepherd',
isFile: false,
mtimeMs: 1594763569000,
ctimeMs: 1641490864998,
birthtimeMs: 1641490864998,
addedAt: 1646732242162,
updatedAt: 1646820362213,
isMissing: false,
isInvalid: false,
mediaType: 'book',
media: {
id: '43c51480-1e3c-4b50-88b7-b7f045065474',
metadata: {
title: 'The Good Shepherd',
titleIgnorePrefix: 'Good Shepherd, The',
subtitle: null,
authorName: 'C.S. Forester',
authorNameLF: 'Forester, C.S.',
narratorName: 'Edoardo Ballerini',
seriesName: '',
genres: [Array],
publishedYear: '2020',
publishedDate: null,
publisher: 'Podium Audio',
description: 'The Good Shepherd is now a major motion picture, Greyhound , scripted by and starring Tom Hanks, directed by Aaron Schneider, and produced by Gary Goetzman. A convoy of 37 merchant ships is ploughing through icy, submarine-infested North Atlantic seas during the most critical days of World War II, when the German submarines had the upper hand and Allied shipping was suffering heavy losses. In charge is Commander George Krause, an untested veteran of the US Navy. Hounded by a wolf pack of German U-boats, he faces 48 hours of desperate peril trapped the bridge of the ship. Exhausted beyond measure, he must make countless and terrible decisions as he leads his small fighting force against the relentless U-boats.',
isbn: null,
asin: '1774244152',
language: 'English',
explicit: false,
abridged: false
},
coverPath: '/audiobooks/C.S. Forester/The Good Shepherd/The Good Shepherd - 001.mp3',
tags: [],
numTracks: 17,
numAudioFiles: 17,
numChapters: 33,
numMissingParts: 0,
numInvalidAudioFiles: 0,
duration: 28401.437333,
size: 454976356,
ebookFormat: null
},
numFiles: 17,
size: 454976356
}
The function expects:
None of these exist in the object, so no wonder it's not returning any results.
According to the API docs, these should be returned in library > library item > book
But for some reason, it's not doing that.
The reason I can see, looks like expected behaviour, getting library items will not retrieve the expected data. The audioFiles and the metadata.authors, metadata.narrators simply aren't there.
With the data logging, this amended function will return a soap style object in the console:
async function buildLibraryMetadataResult(res) {
if (!res || !res.results) {
return null;
}
let libraryItems = res.results;
let total = count;
let mediaMetadata = [];
for (const libraryItem of libraryItems) {
var mediaMetadataEntry = {
itemType: "audiobook",
id: libraryItem.id,
canPlay: true,
canResume: true,
title: libraryItem.media.metadata
? libraryItem.media.metadata.title
: null,
summary: libraryItem.media.metadata
? libraryItem.media.metadata.description
: null,
author: libraryItem.media.metadata.authorName,
narrator: libraryItem.media.metadata.narratorName,
albumArtURI: `${ABS_URI}${libraryItem.media.coverPath}?token=${ABS_TOKEN}`,
};
mediaMetadata.push(mediaMetadataEntry);
}
return {
getMetadataResult: {
count: count,
total: total,
index: 0,
mediaCollection: mediaMetadata,
},
};
}
But I still can't get it to show the items...
I've tried a bunch of stuff and still can't get it to work.
The soap server is working correctly, and returning a correct response, with a properly structured soap xml. I've tested this on SoapUI - even to the point where I'm using the stock responses in the docs here and they still don't work.
I'm wondering at this point whether the customsd form is being filled incorrectly. It's polling the server and SoapUI, but not happy with the result.
Maybe unchecking the "Support Manifest File" is causing the issue? I can't add the service if I don't do this.
I've put the updated/worked on files in a new repo. They should maybe get some folks a bit further along the line.
I've also added notes about testing, debugging etc. Still can't get it working though!
:wave: Hello all. Sorry for not being particularly active on this project. I can't commit to helping resolve everything here, but I'll try and get things up and running locally again and see if there are any glaring issues I find.
A few things to note:
tl;dr: I was able to get things up easily still, but not necessairly fully funcitonal and running. The latter due to API changes in ABS.
OK, made some progress debugging. A few things:
Some initial things I had to change to make some progress:
It was crashing all over buildLibraryMetadataResults
The "new" version of mediaMetadataEntry:
for (const libraryItem of libraryItems) {
// https://developer.sonos.com/build/content-service-add-features/save-resume-playback/
var mediaMetadataEntry = {
itemType: "audiobook",
id: libraryItem.id,
//mimeType: libraryItem.media.audioFiles[0].mimeType,
canPlay: true,
canResume: true,
title: libraryItem.media.metadata.title,
summary: libraryItem.media.metadata.description,
//authorId: libraryItem.media.metadata.authors[0].id,
//author: libraryItem.media.metadata.authors[0].name,
//narratorId: libraryItem.media.metadata.narrators[0].id,
//narrator: libraryItem.media.metadata.narrators[0].name,
//albumArtURI: `${ABS_URI}${libraryItem.media.coverPath}?token=${ABS_TOKEN}`,
};
mediaMetadata.push(mediaMetadataEntry);
}
I'll keep poking around, as well as update this repo with the new "debugging support" I've added to a few of thes methods to help. My gut is telling me there's a decent chunk of work that needs to be done here to get it working though, or at least working to the level it was prior. That said, the initial issues that were had in this issue definitely weren't related to this, and were most likely just environmental set up issues.
Some more progress:
Had to comment out some more due-to-API-changes fields:
async function buildAudiobookTrackList(libraryItem, progressData) {
let tracks = libraryItem.media.audioFiles;
let icount = tracks.length;
let itotal = tracks.length;
let imediaMetadata = [];
for (const track of tracks) {
var mediaMetadataEntry = {
id: `${libraryItem.id}/${track.metadata.filename}`,
itemType: "track",
title: track.metadata.filename,
mimeType: track.mimeType,
trackMetadata: {
authorId: libraryItem.media.metadata.authors[0].id,
author: libraryItem.media.metadata.authors[0].name,
//narratorId: libraryItem.media.metadata.narrators[0].id,
//narrator: libraryItem.media.metadata.narrators[0].name,
duration: track.duration,
book: libraryItem.media.metadata.title,
albumArtURI: `${ABS_URI}${libraryItem.media.coverPath}?token=${ABS_TOKEN}`,
canPlay: true,
canAddToFavorites: false,
},
};
imediaMetadata.push(mediaMetadataEntry);
}
This brings SONOS to actually trying to play the file, but throws an error modal in the app that says "Part01.mp3 is no longer available on audiobookshelf" which is interesting. Though the soap part of the server is actively running and participating at this point, as indicated by these messages in the docker output:
audiobookshelf-sonos | getMediaURI called
audiobookshelf-sonos | [soapServer] /playback/v2.1/report/timePlayed called
audiobookshelf-sonos | [soapServer] /playback/v2.1/report/timePlayed called
audiobookshelf-sonos | oh it got called?
which is great
ABS API reference: https://api.audiobookshelf.org
OK. More progress.
I have audio streaming to the speakers again.
This is the function that actually generates the URL telling the speaker where to fetch the audio from. As with the other breakages, this is no longer valid, in a variety of ways.
async function buildMediaURI(id) {
let path = `${ABS_URI}/s/item/${id}?token=${ABS_TOKEN}`;
return {
getMediaURIResult: path,
};
}
The path needed now resembles something like: <ABS_URI>/api/items/<library_id>/file/<file_id>?token=<auth_token>
. Hardcoding path to be the appropriate URL using an auth token from a web session, and the audio starts playing.
This brings up a couple things:
Number 3 doesn't need to happen. It's available in the libraryItem as the ino
field already
I've got everything working right now aside from getting progress and setting new progress (you can browse the library, select an audiobook, it will play, you can seek in the file, and seek to other files, etc. it just always starts from the first file in the book) It's definitely possible, just requires some mucking around. I'll look to get to it later this weekend
just reread through most of the comments.
@eendenhart , your 404 is indicative of the ABS API changes. It should be resolved once I push the next update.
@jt196 , there shouldn't be any issues with this running in docker. My debugging session tonight was on a different machine than I initially developed this on leveraging the container. If you've found specific issues with it, let me know, but ideally all troubleshooting is done within the container so we can eliminate variables. As well, the compose file will automatically build the latest local audiobookshelf-sonos/ folder (and can rebuild with docker-compose up --build
), which should make it easier for both development and running "production"
@jmt-gh thanks for dropping in. Appreciate folks don't always have the time to devote to these projects!
Do you want to update the repo with your working code, that would be helpful.
Couple of points.
I couldn't get my set up to work with a URL, it just doesn't poll the backend, well it does but only getLastUpdate function - which it requests and receives a correct response. My settings are:
http://soap.my_url.com/wsdl
https://soap.my_url.com/wsdl
https://soap.my_url.com/manifest
If I use the IP address for the service:
http://192.168.1.xx:3333/wsdl
http://192.168.1.xx:3333/wsdl
The response with the library data logs to the console.
It looks like this:
[replied] <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://www.sonos.com/Services/1.1"><soap:Body><getMetadataResponse xmlns="http://www.sonos.com/Services/1.1"><getMetadataResult><count>85</count><total>85</total><index>0</index><mediaCollection><itemType>audiobook</itemType><id>74162736-8a64-4b10-a0fc-4c431b398e47</id><canPlay>true</canPlay><canResume>true</canResume><title>Live At the Purple Onion</title><summary xsi:nil="true"></summary></mediaCollection><mediaCollection><itemType>audiobook</itemType><id>59a84934-7a93-48c1-a4f9-837c23e78d24</id><canPlay>true</canPlay><canResume>true</canResume><title>Derek and Clive - Ad Nauseam</title><summary xsi:nil="true"></summary></mediaCollection><mediaCollection><itemType>audiobook</itemType><id>6741e0a4-2468-45be-ac7c-6bce300621b5</id><canPlay>true</canPlay><canResume>true</canResume><title>No Reason To Complain</title><summary xsi:nil="true"></summary></mediaCollection>
Concatenated here, but it looks correctly formed.
Port number: I wonder whether the port number should be different. In my config I have HTTP_PORT: 80 - which is the internal port for the docker container, external being 3333.
mediaCollection vs mediaMetadata. In the buildLibraryMetadataResult function, you're returning this object:
return {
getMetadataResult: {
count: count,
total: total,
index: 0,
mediaCollection: mediaMetadata,
},
};
From reading the Sonos docs, it looks more appropriate to just use mediaMetadata: mediaMetadata
, as this fits in with a list of all the tracks/audiobooks, rather than a collection of media (genres, artists etc).
I can get the response working, but still no library display. All in all, quite frustrating!
For me to get the Playback working i had to change the beginning of buildAudiobookTracklist
to:
async function buildAudiobookTrackList(libraryItem, progressData) {
console.log("MEDIA");
console.log(libraryItem)
let tracks = libraryItem.media.audioFiles;
let icount = tracks.length;
let itotal = tracks.length;
let imediaMetadata = [];
for (const track of tracks) {
var mediaMetadataEntry = {
id: `${libraryItem.media.libraryItemId}/file/${track.ino}`,
and buildMEdiaURI
to:
async function buildMediaURI(id) {
let path = `${ABS_URI}/api/items/${id}?token=${ABS_TOKEN}`;
return {
getMediaURIResult: path,
};
}
Hellooooo. I recognize I never pushed up the update I had mentioned. Sorry about that.
I'm actively working on getting things back to a fully working state. Currently the only thing not working is having progress updated on ABS when listening on Sonos. From my last update, getting progress down from ABS was broken as well. That's been updated with a patch that looks something like this diff:
@@ -151,13 +157,19 @@ async function buildAudiobookTrackList(libraryItem, progressData) {
let positionInformation = {};
if (progressData) {
+ try {
+ console.log(`[buildAudiobookTrackList] There was progressData!`)
positionInformation = {
- id: `${libraryItem.id}/${progressData.partName}`, // li_{string}/Part##.mp3
+ id: `${libraryItem.id}/file/${progressData.partName}`, // UUID-ITEM-ID/12345
index: 0,
// 1) Sonos gets upset if there are too many decimals
// 2) ABS returns everything in seconds, so multiple by 1000 for milliseconds for sonos
offsetMillis: Math.round(progressData.relativeTimeForPart * 1000),
};
Current issue with getting updates back up to ABS is that the sonos side of things just doesn't seem to be trying to reach out to the update endpoint in server.js
. I see it reaching out to /manifest
, but nothing beyond that.
progress!
I added some logging to server.js
, to track every endpoint trying to be hit, be it existing or not:
diff --git a/server.js b/server.js
index 89b49ed..f97e9f3 100644
--- a/server.js
+++ b/server.js
@@ -14,6 +14,10 @@ const SONOS_WSDL_FILE = config.SONOS_WSDL_FILE;
/**********/
EXPRESS_APP.use(express.json()); // express.json allows for native body parsing
+EXPRESS_APP.use((req, res, next) => {
+ console.log(`Received request: ${req.method} ${req.url}`);
+ next();
+});
and noticed this requests for progress updates:
audiobookshelf-sonos | Received request: POST /wsdl
audiobookshelf-sonos | Received request: POST /wsdl/playback/v2.1/report/timePlayed
audiobookshelf-sonos | Received request: POST /wsdl
audiobookshelf-sonos | Received request: POST /wsdl/playback/v2.1/report/timePlayed
specifically the /wsdl/
part at the beginning of POST /wsdl/playback/v2.1/report/timePlayed
stood out, as I didn't have that on the routes defined in server.js
.
Adding this diff, and I'm not starting ot see progress requests hitting properly, and further code getting processed now:
+ EXPRESS_APP.post(`${SOAP_ENDPOINT}/playback/v2.1/report`, (req, res) => {
console.log("[soapServer] /playback/v2.1/report called");
});
+
- EXPRESS_APP.post("/playback/v2.1/report/timePlayed", (req, res) => {
+ EXPRESS_APP.post(`${SOAP_ENDPOINT}/playback/v2.1/report/timePlayed`, (req, res) => {
console.log("[soapServer] /playback/v2.1/report/timePlayed called");
Still looking in to making sure ABS updates the progress properly.
Andddd I think this is the last of it. Similar to a lot of the other changes, it just needed to be moved from the old file name syntax to the new UUID/file-ino syntax.
async function buildProgress(libraryItem, updateObject) {
- let partId = updateObject.libraryItemIdAndFileName.split("/")[1]; // li_{string}/Part##.mp3
+ //let partId = updateObject.libraryItemIdAndFileName.split("/")[1]; // li_{string}/Part##.mp3
+ let partId = updateObject.libraryItemIdAndFileName.split("/")[2]; // ITEM-UUID/file/12345 -> 12345
+ console.log(`[buildProgress] partId: ${partId}`)
let audioFiles = libraryItem.media.audioFiles;
+ console.log(`[buildProgress] audioFiles: ${JSON.stringify(audioFiles, null, 2)}`)
+
let res = {
progress: updateObject.positionMillis / 1000, // abs tracks progress in seconds
bookDuration: audioFiles
.map((audioFile) => audioFile.duration)
.reduce((result, item) => result + item),
};
+ console.log(`[buildProgress] res: ${JSON.stringify(res, null, 2)}`)
for (const audioFile of audioFiles) {
- let filename = audioFile.metadata.filename;
+ let filename = audioFile.ino;
if (filename == partId) {
// only grab as much duration as up to the part we are currently at
I've merged all of the fixes I have right now in to the main branch. I still need to update the README, and add more appropriate logging / logging levels.
README has been updated. It focuses now on configuring the docker-compose.yml file, rather than the conflicting compose file + config file which was confusing before.
Anddd improved logging has been put in place. At least in the sense that there should now be some level of logging for most things -- if they are useful or not.. that's a different story haha.
Please feel free to give all of this with the new readme a shot, and let me know how things go.
hey nice.. step by step... if i want to open audiobookservice in sonos ... i get the message:
Durchsuchen der Musikdateien nicht möglich
but the logs... generate a information from my audiobookshelf
This occurs when the Custom Service Descriptor is set up properly, but the app doesn't received anything when you browse to it.
Most likely either the configuration in the docker-compose file is incorrect, or your speakers are unable to communicate with the server / application.
If you post the log output here it could potentially help diagnose the issue. You'll want the full log output of you opening the app, clicking the ABS entry in the sonos app, etc.
I would also double check the environment configurations are correct in the docker-compose.yml file. The values should not be wrapped in quotes, and you need to ensure the ABS library ID and API key are accurate
OK dude, just retrying this.
FYI The git clone
command currently in the Readme is erroring out, I changed the url to https://github.com/jmt-gh/audiobookshelf-sonos.git
and it clones fine. Assume the given URL (git@github.com:jmt-gh/audiobookshelf-sonos.git
) might be for the owner of the repo/require credentials?
As per @mxdalchau and my previous experience, I'm getting an "Unable to browse music" message. I've tested this now on a smaller library as well as a test one with just 4 items. Neither works.
The logs produce a list of library items. Here's my logs:
[2024-01-22T11:14:23.852Z] [DEBUG] [Unknown - Unknown:Unknown] Received request: GET /manifest
[2024-01-22T11:14:23.853Z] [INFO] [Unknown - Unknown:Unknown] /manifest endpoint hit
[2024-01-22T11:14:28.222Z] [DEBUG] [Unknown - Unknown:Unknown] Received request: POST /wsdl
[2024-01-22T11:14:28.233Z] [DEBUG] [Unknown - Unknown:Unknown] Received request: POST /wsdl
[2024-01-22T11:14:28.237Z] [DEBUG] [getMetadata - /app/sonos-service.js:8] getMetadata sonos-service called with args {"id":"root","index":0,"count":100}
[2024-01-22T11:14:28.238Z] [INFO] [getLibraryItems - /app/utils.js:17] Fetching library item at: "https://audiobooks.domain.com/api/libraries/<library_id>/items"
[2024-01-22T11:14:28.305Z] [DEBUG] [buildLibraryMetadataResult - /app/utils.js:116] libraryItem for mediaMetadataEntry: {"id":"022f5ead-e66e-4592-a6bc-bea084ae4f01","ino":"369861","oldLibraryItemId":null,"libraryId":"571b1e8a-e2ac-47fb-b0a1-f0f8d7ec15e3","folderId":"1c6a556e-623a-4e53-bb86-29a32c849558","path":"/audiobooks/Alan Partridge/From the Oasthouse The Alan Partridge Podcast","relPath":"From the Oasthouse The Alan Partridge Podcast","isFile":false,"mtimeMs":1601981799000,"ctimeMs":1694594837580,"birthtimeMs":1694594837580,"addedAt":1705921897649,"updatedAt":1705921897649,"isMissing":false,"isInvalid":false,"mediaType":"book","media":{"id":"a1fedd4d-3533-45cb-9151-9dfd257bc4a2","metadata":{"title":"From the Oasthouse: The Alan Partridge Podcast: An Audible Original","titleIgnorePrefix":"From the Oasthouse: The Alan Partridge Podcast: An Audible Original","subtitle":null,"authorName":"Alan Partridge","authorNameLF":"Partridge, Alan","narratorName":"Alan Partridge","seriesName":"","genres":["Comedy, Podcast"],"publishedYear":"2020","publishedDate":null,"publisher":null,"description":"Broadcaster, writer, philanthroper and one of the first public figures to suggest high-visibility clothing for people manning temporary car parks, the public Alan Partridge is a cherished institution. But what of the unseen Alan? For the first time, this","isbn":null,"asin":null,"language":null,"explicit":false,"abridged":false},"coverPath":"/audiobooks/Alan Partridge/From the Oasthouse The Alan Partridge Podcast/From the Oasthouse The Alan Partridge Podcast An Audible Original.jpg","tags":[],"numTracks":1,"numAudioFiles":1,"numChapters":17,"numMissingParts":0,"numInvalidAudioFiles":0,"duration":24274.279909,"size":385577371},"numFiles":3,"size":385894072}
... the rest of the library below
I can also confirm that if I make a Postman GET request to the ABS url with the login credentials, it returns a list of library items.
So the request for information is producing a list of metadata, but that for whatever reason isn't displaying in the Sonos app.
Incidentally, I finally ran the Sonos v2 upgrade, thinking this might be the culprit. It seems to have helped adding the service with the "support manifest file" checked, but still producing this error.
I've also played around with changing the SOAP_URI variable, but adding /wsdl to the end doesn't seem to solve it. Incidentally, the list of library items is produced regardless of whether the SOAP_URI is entered correctly, but the getMetadata
and getLibraryItems
aren't logged if it's incorrect.
Here's my docker compose settings if you notice any glaring errors. No quotes have been used here:
version: "3.8"
services:
audiobookshelf-sonos:
build:
context: .
dockerfile: Dockerfile
container_name: audiobookshelf-sonos
environment:
- SOAP_URI=https://soap.domain.com # also tried with /wsdl
- ABS_URI=https://audiobooks.domain.com
- ABS_LIBRARY_ID=<my_library_id>
- ABS_TOKEN=<redacted>
- LOG_LEVEL=debug # set to debug, info, warn, error
ports:
- 3333:80
volumes:
- ./sonos.wsdl:/app/sonos.wsdl
sonos.wsdl:
<wsdl:service name="Sonos">
<wsdl:port name="SonosSoap" binding="tns:SonosSoap">
<soap:address location="https://soap.domain.com"/> <!-- UPDATE WITH SOAP_URI -->
</wsdl:port>
</wsdl:service>
Note, also changing this to https://soap.domain.com/wsdl
doesn't fix anything.
/customsd.htm
Secure endpoint URL: https://soap.domain.com/wsdl
Polling interval: 10
Authentication SOAP header policy: Anonymous
Manifest:
version: 1
URI: https://soap.domain.com/manifest
Support manifest file: checked
Playback event logging during track play: checked
Playback duration logging at track end: checked
This adds to the Sonos services without erroring out.
As it's working on your set up, I have a feeling it's likely something like a config error.
I don't know whether this helps but here's some results to GET requests to the soap URIs.
/manifest:
{
"schemaVersion": "1.0",
"endpoints": [
{
"type": "reporting",
"uri": "https://soap.jamestorr.com/playback/v2.1/report"
}
]
}
/wsdl: 200 response, empty. /playback/v2.1/report: 404 response (just doing that as the endpoint above points to this)
If I make a POST request with the body:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:son="http://www.sonos.com/Services/1.1">
<soapenv:Header/>
<soapenv:Body>
<son:getMetadata>
<son:id>root</son:id>
<son:index>0</son:index>
<son:count>100</son:count>
</son:getMetadata>
</soapenv:Body>
</soapenv:Envelope>
To the URL: https://soap.domain.com/wsdl
, with content type XML, I successfully receive a response with the correct metadata. Here's what the response looks like:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://www.sonos.com/Services/1.1">
<soap:Body>
<getMetadataResponse xmlns="http://www.sonos.com/Services/1.1">
<getMetadataResult>
<count>85</count>
<total>85</total>
<index>0</index>
<mediaCollection>
<itemType>audiobook</itemType>
<id>74162736-8a64-4b10-a0fc-4c431b398e47</id>
<canPlay>true</canPlay>
<canResume>true</canResume>
<title>Live At the Purple Onion</title>
<summary xsi:nil="true"></summary>
</mediaCollection>
--- continues for the rest of the library ---
</getMetadataResult>
</getMetadataResponse>
</soap:Body>
</soap:Envelope>
Lots of info here, hope it helps. What might be useful would be:
OK dude, just retrying this.
FYI The
git clone
command currently in the Readme is erroring out, I changed the url tohttps://github.com/jmt-gh/audiobookshelf-sonos.git
and it clones fine. Assume the given URL (git@github.com:jmt-gh/audiobookshelf-sonos.git
) might be for the owner of the repo/require credentials?As per @mxdalchau and my previous experience, I'm getting an "Unable to browse music" message. I've tested this now on a smaller library as well as a test one with just 4 items. Neither works.
The logs produce a list of library items. Here's my logs:
[2024-01-22T11:14:23.852Z] [DEBUG] [Unknown - Unknown:Unknown] Received request: GET /manifest [2024-01-22T11:14:23.853Z] [INFO] [Unknown - Unknown:Unknown] /manifest endpoint hit [2024-01-22T11:14:28.222Z] [DEBUG] [Unknown - Unknown:Unknown] Received request: POST /wsdl [2024-01-22T11:14:28.233Z] [DEBUG] [Unknown - Unknown:Unknown] Received request: POST /wsdl [2024-01-22T11:14:28.237Z] [DEBUG] [getMetadata - /app/sonos-service.js:8] getMetadata sonos-service called with args {"id":"root","index":0,"count":100} [2024-01-22T11:14:28.238Z] [INFO] [getLibraryItems - /app/utils.js:17] Fetching library item at: "https://audiobooks.domain.com/api/libraries/<library_id>/items" [2024-01-22T11:14:28.305Z] [DEBUG] [buildLibraryMetadataResult - /app/utils.js:116] libraryItem for mediaMetadataEntry: {"id":"022f5ead-e66e-4592-a6bc-bea084ae4f01","ino":"369861","oldLibraryItemId":null,"libraryId":"571b1e8a-e2ac-47fb-b0a1-f0f8d7ec15e3","folderId":"1c6a556e-623a-4e53-bb86-29a32c849558","path":"/audiobooks/Alan Partridge/From the Oasthouse The Alan Partridge Podcast","relPath":"From the Oasthouse The Alan Partridge Podcast","isFile":false,"mtimeMs":1601981799000,"ctimeMs":1694594837580,"birthtimeMs":1694594837580,"addedAt":1705921897649,"updatedAt":1705921897649,"isMissing":false,"isInvalid":false,"mediaType":"book","media":{"id":"a1fedd4d-3533-45cb-9151-9dfd257bc4a2","metadata":{"title":"From the Oasthouse: The Alan Partridge Podcast: An Audible Original","titleIgnorePrefix":"From the Oasthouse: The Alan Partridge Podcast: An Audible Original","subtitle":null,"authorName":"Alan Partridge","authorNameLF":"Partridge, Alan","narratorName":"Alan Partridge","seriesName":"","genres":["Comedy, Podcast"],"publishedYear":"2020","publishedDate":null,"publisher":null,"description":"Broadcaster, writer, philanthroper and one of the first public figures to suggest high-visibility clothing for people manning temporary car parks, the public Alan Partridge is a cherished institution. But what of the unseen Alan? For the first time, this","isbn":null,"asin":null,"language":null,"explicit":false,"abridged":false},"coverPath":"/audiobooks/Alan Partridge/From the Oasthouse The Alan Partridge Podcast/From the Oasthouse The Alan Partridge Podcast An Audible Original.jpg","tags":[],"numTracks":1,"numAudioFiles":1,"numChapters":17,"numMissingParts":0,"numInvalidAudioFiles":0,"duration":24274.279909,"size":385577371},"numFiles":3,"size":385894072} ... the rest of the library below
I can also confirm that if I make a Postman GET request to the ABS url with the login credentials, it returns a list of library items.
So the request for information is producing a list of metadata, but that for whatever reason isn't displaying in the Sonos app.
Incidentally, I finally ran the Sonos v2 upgrade, thinking this might be the culprit. It seems to have helped adding the service with the "support manifest file" checked, but still producing this error.
I've also played around with changing the SOAP_URI variable, but adding /wsdl to the end doesn't seem to solve it. Incidentally, the list of library items is produced regardless of whether the SOAP_URI is entered correctly, but the
getMetadata
andgetLibraryItems
aren't logged if it's incorrect.Here's my docker compose settings if you notice any glaring errors. No quotes have been used here:
version: "3.8" services: audiobookshelf-sonos: build: context: . dockerfile: Dockerfile container_name: audiobookshelf-sonos environment: - SOAP_URI=https://soap.domain.com # also tried with /wsdl - ABS_URI=https://audiobooks.domain.com - ABS_LIBRARY_ID=<my_library_id> - ABS_TOKEN=<redacted> - LOG_LEVEL=debug # set to debug, info, warn, error ports: - 3333:80 volumes: - ./sonos.wsdl:/app/sonos.wsdl
sonos.wsdl:
<wsdl:service name="Sonos"> <wsdl:port name="SonosSoap" binding="tns:SonosSoap"> <soap:address location="https://soap.domain.com"/> <!-- UPDATE WITH SOAP_URI --> </wsdl:port> </wsdl:service>
Note, also changing this to
https://soap.domain.com/wsdl
doesn't fix anything./customsd.htm
Secure endpoint URL: https://soap.domain.com/wsdl Polling interval: 10 Authentication SOAP header policy: Anonymous Manifest: version: 1 URI: https://soap.domain.com/manifest Support manifest file: checked Playback event logging during track play: checked Playback duration logging at track end: checked
This adds to the Sonos services without erroring out.
As it's working on your set up, I have a feeling it's likely something like a config error.
I don't know whether this helps but here's some results to GET requests to the soap URIs.
/manifest:
{ "schemaVersion": "1.0", "endpoints": [ { "type": "reporting", "uri": "https://soap.jamestorr.com/playback/v2.1/report" } ] }
/wsdl: 200 response, empty. /playback/v2.1/report: 404 response (just doing that as the endpoint above points to this)
If I make a POST request with the body:
<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:son="http://www.sonos.com/Services/1.1"> <soapenv:Header/> <soapenv:Body> <son:getMetadata> <son:id>root</son:id> <son:index>0</son:index> <son:count>100</son:count> </son:getMetadata> </soapenv:Body> </soapenv:Envelope>
To the URL:
https://soap.domain.com/wsdl
, with content type XML, I successfully receive a response with the correct metadata. Here's what the response looks like:<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://www.sonos.com/Services/1.1"> <soap:Body> <getMetadataResponse xmlns="http://www.sonos.com/Services/1.1"> <getMetadataResult> <count>85</count> <total>85</total> <index>0</index> <mediaCollection> <itemType>audiobook</itemType> <id>74162736-8a64-4b10-a0fc-4c431b398e47</id> <canPlay>true</canPlay> <canResume>true</canResume> <title>Live At the Purple Onion</title> <summary xsi:nil="true"></summary> </mediaCollection> --- continues for the rest of the library --- </getMetadataResult> </getMetadataResponse> </soap:Body> </soap:Envelope>
Lots of info here, hope it helps. What might be useful would be:
1. A redacted version of your working config/docker-compose file settings as above. 2. For you to check POST/GET on your soap server, so we can check our set up.
Thought I'm gonna tell you how exactly I got this running pretty quickly, maybe it helps.
Current issue with getting updates back up to ABS is that the sonos side of things just doesn't seem to be trying to reach out to the update endpoint in
server.js
. I see it reaching out to/manifest
, but nothing beyond that.
Was there any solution to this? Doesn't seem like it is doing for me either.
Current issue with getting updates back up to ABS is that the sonos side of things just doesn't seem to be trying to reach out to the update endpoint in
server.js
. I see it reaching out to/manifest
, but nothing beyond that.Was there any solution to this? Doesn't seem like it is doing for me either.
I solved this by converting to /playback without any prefix.
I solved this by converting to /playback without any prefix.
What exactly do you mean here?
I solved this by converting to /playback without any prefix.
What exactly do you mean here?
There is EXPRESS_APP.post(`${SOAP_ENDPOINT}/playback... in the server.js source file. I removed the SOAP_ENDPOINT part as the calls were not registering for me otherwise
@fayeinmay , glad to hear you've got it working, and thanks for sharing the steps you took. Definetly makes me feel like I've got a bit of a sanity check that things work outside of my environment haha. The reason you've needed to make those changes is because you didn't register the secure URL in the same way it's laid out in the README:
Input the following information:
Service Name: audiobookshelf
Secure Endpoint URL: https://<the_url_you_defined_for_this_server_above>/wsdl
Polling interval: 10
Authentication SOAP header policy: Anonymous
Manifest
In the end, you end up with the same result, but repo currently assuming you defined the URL with appended with the /wsdl
path, so puts that in a few places (though maybe we should just look at doing it without for simplicity)
@fayeinmay , glad to hear you've got it working, and thanks for sharing the steps you took. Definetly makes me feel like I've got a bit of a sanity check that things work outside of my environment haha. The reason you've needed to make those changes is because you didn't register the secure URL in the same way it's laid out in the README:
Input the following information: Service Name: audiobookshelf Secure Endpoint URL: https://<the_url_you_defined_for_this_server_above>/wsdl Polling interval: 10 Authentication SOAP header policy: Anonymous Manifest
In the end, you end up with the same result, but repo currently assuming you defined the URL with appended with the
/wsdl
path, so puts that in a few places (though maybe we should just look at doing it without for simplicity)
I'd say you're right, because I did redo the setup step twice and could've forgotten to append /wsdl, but I only needed to change the path on the http calls, not on the soap calls. Except you say for soap sonos does auto apply /wsdl as a suffix.
Hey,
could you write a more detailed instruction please?
thanks :)