v19 Translating Kodi paths to filesystem paths (and back again)
#1
I'd like to read the playlist, and see what files are on it. This works charm:

            playList = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
            for s in range(playList.size()):
                path = playList.getPath()
                log(f"{s}: {path}")

The only problem is the paths are inconsistent.

Some are filesystem paths, others are of the format: musicdb://songs/229107.mp3?albumid=31229

In fact I have a gut feel this is just dependent on who added them and how. If I add songs to the playlist using Kodi, or Chorus or Kore then they appear with this musicdb:// path. If I add them in my plug int using: playList.add(url=filename), using a filesystem path then they appear with that ins the playlist.

I'd love to know how to move between the two formats. Convert a musicdb:// path to a filesystem path and ideally the reverse too. Can't see any means in the doc.

I found xbmc.translatePath but that isn't for this type of translation. I'd both like to get a musicdb:// path (from a filesystem path) to add to the playlist, and I'd like to interpret a musicdb:// path as a filesystem path.

The two must translate with 100% reliability one way (musicdb:// to filesystem) and maybe the other way (if the file is in the database).
Reply
#2
You can translate that with jsonrpc calls. eg

json:
 {"jsonrpc": "2.0", "method": "AudioLibrary.GetSongDetails", "params": { "songid": 110 , "properties": ["file"] }, "id": "libSongs"}

or for all the songs off an album

json:
{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongs", "params": { "properties": [ "file"],"filter": { "albumid":31299 } }, "id": "libSongs"}

In both cases, the file property will contain the full filesystem path.
Learning Linux the hard way !!
Reply
#3
Thanks. Seems a tad cumbersome.  But can write a wrapper function. Just have to work the syntax out. If you have quick Python syntax for sending and receiving/parsing the reply, by all means share it. But shouldn't be too hard to find in the docs.

That presumably is one way with id: being the musicdb:// path?

Is it possible to go the other way? Knowing a system file path getting the musicdb:// path?
Reply
#4
musicdb:// paths will only exist for files that have been scanned to the library.
so there's no guarantee you can resolve a file path to a musicdb:// path.

you can use the json-rpc method Files.GetFileDetails to check if a file has a library id.
Do not PM or e-mail Team-Kodi members directly asking for support.
Always read the Forum rules, Kodi online-manual, FAQ, Help and Search the forum before posting.
Reply
#5
@ronie Thanks! Will check that out too. Looks like the JSON RPC provides some features never (not yet) implemented int he Python modules.

Of course it can't return a musicdb:// uRL if there isn't one (already noted that above with "100% reliability one way (musicdb:// to filesystem) and maybe the other way (if the file is in the database)")
Reply
#6
OK technical question. What does

"songid": 110

mean? And where is that documented. I'm struggling to find good RPC documentation alas.

And:

"id": "libSongs"

according to the RPC docs I read is an arbitrary string, anything at all, just returned in the response so you can check that the response is valid for the request. What I'm reading is this:

https://www.jsonrpc.org/specification#request_object
https://kodi.wiki/view/JSON-RPC_API/v12#...ongDetails
Reply
#7
OK not much luck so far. If I do this:
python:

{   
    "jsonrpc": "2.0",
    "method": "AudioLibrary.GetSongDetails",
    "params": {
                "songid": 110 ,
                "properties": ["musicdb://songs/229106.mp3?albumid=31229"]
              },
    "id": "libSongs"
}
I get:
python:

{
    "error": {
        "code": -32602,
        "data": {
            "method": "AudioLibrary.GetSongDetails",
            "stack": {
                "message": "array element at index 0 does not match",
                "name": "Item.Fields.Base",
                "property": {
                    "message": "Received value does not match any of the defined enum values",
                    "type": "string"
                },
                "type": "array"
            }
        },
        "message": "Invalid params."
    },
    "id": "libSongs",
    "jsonrpc": "2.0"
}
An error basically. And I'm hoping to convert the musicdb:// path to a filesystem path.

and if I try this:
python:

{   
    "jsonrpc": "2.0",
    "method": "Files.GetFileDetails",
    "params": { "file": "/media/Audio/T-Rex (and John's Children and Marc Bolan)/1991 The Ultimate Collection/13 - Get It On.mp3" },
    "id": "libSongs"
}
I get this:
python:

{
  "id": "libSongs",
   "jsonrpc": "2.0",
   "result": {
       "filedetails": {
           "label": "13 - Get It On.mp3",
           "type": "unknown"
       }
   }
}
and I'm hoping to get a musicdb:// path somehow.

Feeling a tad stuck and lost with poor RPC documentation :-(. All help appreciated. Will gladly add examples to https://kodi.wiki/view/JSON-RPC_API/Examples when done.
Reply
#8
Hmmm, scanning source code for pointers. But it's slow hard work and not yielding much. What I'd like is a list of the properties that can get asked for with GetFileDetails or GetSongDetails.
Reply
#9
The items you want to return from the db go in properties in your first example. 

json:
{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongdetails", "params": { "songid" :8, "properties": [ "albumid","artist", "duration", "album", "track", "disctitle", "file"] }, "id": "libSongs"}

That will return the albumid, artist, duration etc in the results.  Eg, I get

json:
"result": {
        "id": "libSongs",
        "jsonrpc": "2.0",
        "result": {
          "songdetails": {
            "album": "8 Mile",
            "albumid": 1,
            "artist": [
              "Xzibit"
            ],
            "disctitle": "",
            "duration": 219,
            "file": "/media/sde1/Music/Various Artists/8 Mile/08 Xzibit - Spit Shine.mp3",
            "label": "Spit Shine",
            "songid": 8,
            "track": 8
          }
        }
      }

So the one you want to get from the songid to the filesystem path is 'file'.  You can get the songs for an album from the album id (in your example 31229) like this.

json:
{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongs", "params": { "properties": [ "albumid","artist", "duration", "album", "track", "disctitle", "file"], "filter":{"albumid":1}}, "id": "libSongs"}

where the id of the album goes in the filter bit.  I won't post the full 16 results it gives me but this is the <snipped> response.

json:
"result": {
          "limits": {
            "end": 16,
            "start": 0,
            "total": 16
          },
          "songs": [
            {
              "album": "8 Mile",
              "albumid": 1,
              "artist": [
                "Eminem"
              ],
              "disctitle": "",
              "duration": 320,
              "file": "/media/sde1/Music/Various Artists/8 Mile/01 Eminem - Lose Yourself.mp3",
              "label": "Lose Yourself",
              "songid": 1,
              "track": 1
            },
            {
              "album": "8 Mile",
              "albumid": 1,
              "artist": [
                "Eminem",
                "Obie Trice",
                "50 Cent"
              ],
              "disctitle": "",
              "duration": 270,
              "file": "/media/sde1/Music/Various Artists/8 Mile/02 Eminem feat. Obie Trice & 50 Cent - Love Me.mp3",
              "label": "Love Me",
              "songid": 2,
              "track": 2
            },
            {
              "album": "8 Mile",
              "albumid": 1,
              "artist": [
                "Eminem"
              ],
              "disctitle": "",
              "duration": 360,
              "file": "/media/sde1/Music/Various Artists/8 Mile/03 Eminem - 8 Mile.mp3",
              "label": "8 Mile",
              "songid": 3,
              "track": 3
            },

I don't think its (easily) possible to generate Kodi's internal path(s) from the filesystem path.
Learning Linux the hard way !!
Reply
#10
you can use Files.GetFileDetails like this:
json:
{"jsonrpc": "2.0", "method": "Files.GetFileDetails", "params": {"file": "/path/to/file.mp3", "media":"music", "properties":["albumid"]}, "id": 1}

response:
json:
{"id":1,"jsonrpc":"2.0","result":{"filedetails":{"albumid":590,"id":7315,"label":"Symphony In Blue","type":"song"}}}

now you can reconstruct the musicdb path:// using the id and albumid values from the json response
Do not PM or e-mail Team-Kodi members directly asking for support.
Always read the Forum rules, Kodi online-manual, FAQ, Help and Search the forum before posting.
Reply
#11
Very very much thanks for awesome help! I will soon try this again, for now must move onto something else for the nigth but in the next day or two or sooner I'll give these a better read and try out what I've learned!
Reply
#12
OK, as you were so kind I stayed up way too late and coded this up provisionally:

python:

def KodiPath_2_FilePath(Song):
    m = re.search('musicdb://songs/(\d+)', Song)
    song_id = int(m.group(1))
    GetSongDetails = { "jsonrpc": "2.0",
                       "method": "AudioLibrary.GetSongdetails",
                       "params": { "songid" : song_id,
                                   "properties": [ "albumid",
                                                   "artist",
                                                   "duration",
                                                   "album",
                                                   "track",
                                                   "disctitle",
                                                   "file"
                                                 ]
                                 },
                       "id": 1}

    request = json.dumps(GetSongDetails)
    response = xbmc.executeJSONRPC(request)
    SongDetails = json.loads(response)
    return SongDetails["result"]["songdetails"]["file"]

def FilePath_2_KodiPath(Song):
    GetFileDetails = {  "jsonrpc": "2.0",
                        "method": "Files.GetFileDetails",
                        "params": {
                            "file": f"{Song}",
                            "media": "music",
                            "properties": ["albumid"]
                        },
                        "id": 1
                    }

    request = json.dumps(GetFileDetails)
    response = xbmc.executeJSONRPC(request)
    FileDetails = json.loads(response)
    _, file_ext = os.path.splitext(Song)
    song_id = FileDetails["result"]["filedetails"]["id"]
    album_id = FileDetails["result"]["filedetails"]["albumid"]
    kodi_path = f" musicdb://songs/{song_id}.{file_ext}?albumid={album_id}"
    return kodi_path

def KodiPath(Song):
    if Song.startswith("musicdb://"):
        return Song
    else:
        return FilePath_2_KodiPath(Song)

def FilePath(Song):
    if Song.startswith("musicdb://"):
        return KodiPath_2_FilePath(Song)
    else:
        return Song

it could be made more robust yet, and I will endeavour to document this, but these methods work fine.

On niggle is that I use the file extension from the filename to create a kodi path and I can't help but wonder if that can't be received from the JSON RPC loke the song id and album id.

I am still curious to know where all the available properties are documented or if there's a keyword or symbol or instruction that returns the full complement of possible properties in such a call. I have currently no way of divining what properties are available
Reply
#13
You mean like this ? https://github.com/xbmc/xbmc/blob/master...n#L526L541
Learning Linux the hard way !!
Reply
#14
...or one of the many other options:

1. it's all documented on the wiki:
https://kodi.wiki/view/JSON-RPC_API/v12

2. don't like wikis? you can use kodi's built-in webinterface:
http://127.0.0.1:8080/#lab/api-browser/

3. last but not least, use the introspect method
json:
{"jsonrpc":"2.0", "method":"JSONRPC.Introspect", "params":{"filter":{"id":"Files.GetFileDetails", "type":"method"}}, "id":1}
Do not PM or e-mail Team-Kodi members directly asking for support.
Always read the Forum rules, Kodi online-manual, FAQ, Help and Search the forum before posting.
Reply
#15
Thanks again! I love Wikis. But I want aks about this URL:

http://127.0.0.1:8080/#lab/api-browser/

8080 has Chorus listening on it. Is that a Chorus url? If so, all my Chorus does is show a spinning wheel on that.

I have the RPC listening on 9091. But that just timesout with:

http://127.0.0.1:9091/#lab/api-browser/

and on the off chance of a typo I tried:

http://127.0.0.1:8080/lab/api-browser/

but that prints "File not found" in the broswer window.
Reply

Logout Mark Read Team Forum Stats Members Help
Translating Kodi paths to filesystem paths (and back again)0