2014-12-05, 04:12
I recently implemented a web site on my home network to augment my Kodi based entertainment system. Currently, the system can:
The documentation for the json-rpc is impressive, yet lacking. It should not be too offensive to say that despite the impressive documentation I struggled to implement a few of these features. Favourites, for example, is mentioned in the documentation (as far as I can tell) only in the namespace section the json-rpc. I had to dig through the C++ code to figure out the field names for favourites so that I could requests them as the defaults are not useful.
I began this project on Sunday. I am certain that by Wednesday night I had reached double digits of world wide google bandwidth...
What I found most useful was examples. The examples take what's in the documentation and make it real. We all need this because reading the documentation is just not enough. This mapping between the problem space and solution space needed to effectively program is beautifully described in Peter Naur's essay, "Programming as Theory Building." (http://pages.cs.wisc.edu/~remzi/Naur.pdf)
So I thought I would offer a summary of every call I implement in the hope that it might help others doing similar work. As usual, your mileage may vary and the API may change but here's what I did and few of the gotchas I ran into:
Helpful Links:
The API: http://kodi.wiki/view/JSON-RPC_API/v6
Some useful query/filter examples using json-rpc: https://github.com/KODeKarnage/script.la...service.py
Window Ids: http://kodi.wiki/view/Window_IDs
Windows and Dialogs: http://kodi.wiki/view/Opening_Windows_and_Dialogs and the enums: http://kodi.wiki/view/JSON-RPC_API/v6#GUI.Window
The skinning guide has a list of built in funtions from which I was able to infer some helpful info: http://kodi.wiki/view/Skinning_Manual#Ap..._Functions
These calls all worked for me:
Some commands have to be done in sequences. For example, to issue a play/pause, you need to find the active play and tell it to pause:
Play/Pause:
(the answer comes back with an array of playerid and I take the first)
(put the int from the GetActivePlayers into the value for playerid before calling)
ZoomIn:ZoomOut: Stop:
Change "zoom level" or "view mode" as it's called in Confluence. It cycles through all available. This took me forever to figure out because the documentation shows zoomlevel1...zoomlevel9 and I could not make those do anything. This is the command I wanted all along:
GUI.ShowNotification:
I tied this to Tasker on my Android phone and now have SMS messages showing up on my TV with no third party software. Works great:
This brings up the progress bar and player controls:
Brings up the video settings screen:
To get a random unwatched episode of a particular TV show I needed to:
Taking the tvshowid out of those results (234), I then "get a list of all episodes for that tv show filtered by 'playcount is 0' for tvshowid 234":
After selecting a random entry out of the array of episodes, use the episode.file property (refered to in this example as "smb://userid:password/server/novaepisode.avi") to open the file:
Favourites.GetFavourites() - This works to retrieve the current favourites.
Had to track down the fields to list in the "properties" array here: https://github.com/xbmc/xbmc/blob/master...ations.cpp:
On my network, I found the performance is fine to query favourites each time I need them.
I've only implemented two types of favourites, type="media" and type="window"
For type="media" I do a Player.Open command. (see above)
For type="window" I do a GUI.ActivateWindow. But there's a catch. You need to take the "windowparameter" property and pass it to GUI.ActivateWindow in it's parameters array, but it MUST be quoted or commas in your file paths will cause the command to fail.
Here's an example of opening a window to a directory. Note: the parameters value has been quoted using a json escaped quote (\"). Thanks to @ironic_monkey for helping me debug this:
I hope this is helpful to someone else.
Scott
- Start our Christmas Music in PartyMode
- Launch NPR [for morning news and traffic]
- <girlfriend's-favourite-tv-show> (rando) [This function looks up all the unwatched episodes of her fav tv show, then launches a random episode]
- Jump straight to the Snap Judgement podcast
- Play/Pause | Stop | Prev | Next | Fullscreen
- Home | Videos | Movies | Music | TV
- Displays a recent history of activities (last 10 actions, a log shows the full history) [This function was added because my gf wanted to know *what* random episode she had been watching.]
- Lists all the current Favourites as Button-Links [Click to launch]
- All functions work across multiple devices.
The documentation for the json-rpc is impressive, yet lacking. It should not be too offensive to say that despite the impressive documentation I struggled to implement a few of these features. Favourites, for example, is mentioned in the documentation (as far as I can tell) only in the namespace section the json-rpc. I had to dig through the C++ code to figure out the field names for favourites so that I could requests them as the defaults are not useful.
I began this project on Sunday. I am certain that by Wednesday night I had reached double digits of world wide google bandwidth...
What I found most useful was examples. The examples take what's in the documentation and make it real. We all need this because reading the documentation is just not enough. This mapping between the problem space and solution space needed to effectively program is beautifully described in Peter Naur's essay, "Programming as Theory Building." (http://pages.cs.wisc.edu/~remzi/Naur.pdf)
So I thought I would offer a summary of every call I implement in the hope that it might help others doing similar work. As usual, your mileage may vary and the API may change but here's what I did and few of the gotchas I ran into:
Helpful Links:
The API: http://kodi.wiki/view/JSON-RPC_API/v6
Some useful query/filter examples using json-rpc: https://github.com/KODeKarnage/script.la...service.py
Window Ids: http://kodi.wiki/view/Window_IDs
Windows and Dialogs: http://kodi.wiki/view/Opening_Windows_and_Dialogs and the enums: http://kodi.wiki/view/JSON-RPC_API/v6#GUI.Window
The skinning guide has a list of built in funtions from which I was able to infer some helpful info: http://kodi.wiki/view/Skinning_Manual#Ap..._Functions
These calls all worked for me:
Some commands have to be done in sequences. For example, to issue a play/pause, you need to find the active play and tell it to pause:
Play/Pause:
Code:
{"jsonrpc":"2.0","method":"Player.GetActivePlayers","id":1,"params":{}}
Code:
{"jsonrpc":"2.0","method":"Player.PlayPause","id":1,"params":{"playerid":0}}
ZoomIn:
Code:
{ "jsonrpc": "2.0", "method": "Input.ExecuteAction", "params": { "action": "zoomin" }, "id": 1 }
Code:
{ "jsonrpc": "2.0", "method": "Input.ExecuteAction", "params": { "action": "zoomout" }, "id": 1 }
Code:
{ "jsonrpc": "2.0", "method": "Input.ExecuteAction", "params": { "action": "stop" }, "id": 1 }
Change "zoom level" or "view mode" as it's called in Confluence. It cycles through all available. This took me forever to figure out because the documentation shows zoomlevel1...zoomlevel9 and I could not make those do anything. This is the command I wanted all along:
Code:
{ "jsonrpc": "2.0", "method": "Input.ExecuteAction", "params": { "action": "aspectratio" }, "id": 1 }
GUI.ShowNotification:
I tied this to Tasker on my Android phone and now have SMS messages showing up on my TV with no third party software. Works great:
Code:
{ "jsonrpc": "2.0", "method": "GUI.ShowNotification", "params": { "title": "Scott's Message", "message": "I should save this movie." }, "id": 1 }
This brings up the progress bar and player controls:
Code:
{ "jsonrpc": "2.0", "method": "Input.ShowOSD", "id": 1 }
Brings up the video settings screen:
Code:
{ "jsonrpc": "2.0", "method": "GUI.ActivateWindow", "params": { "window": "osdvideosettings" },"id": 1 }
To get a random unwatched episode of a particular TV show I needed to:
- Lookup the tvshowid using the title of the TV show.
- Get a list of all episodes for that tv show filtered by "playcount is 0".
- Randomly pull one entry out of the filtered list.
- Launch the file associated with that episode.
Code:
{"jsonrpc":"2.0","method":"VideoLibrary.GetTVShows","id":1,"params":{"filter":{"field":"title", "operator":"is","value":"NOVA"},"properties":["lastplayed","playcount"],"sort":{"order":"descending","method":"lastplayed"}}}
Taking the tvshowid out of those results (234), I then "get a list of all episodes for that tv show filtered by 'playcount is 0' for tvshowid 234":
Code:
{"jsonrpc":"2.0","method":"VideoLibrary.GetEpisodes","id":1,"params":{"filter":{"field":"playcount", "operator":"is","value":"0"},"properties":["season","episode","runtime","resume","playcount","tvshowid","lastplayed","file"],"tvshowid":234,"sort":{"order":"descending","method":"lastplayed"}}}
After selecting a random entry out of the array of episodes, use the episode.file property (refered to in this example as "smb://userid:password/server/novaepisode.avi") to open the file:
Code:
{"jsonrpc":"2.0","method":"Player.Open","id":1,"params":{"item":{"file":"smb://userid:password/server/novaepisode.avi"}}}
Favourites.GetFavourites() - This works to retrieve the current favourites.
Had to track down the fields to list in the "properties" array here: https://github.com/xbmc/xbmc/blob/master...ations.cpp:
Code:
{ "jsonrpc": "2.0", "method": "Favourites.GetFavourites", "params": { "properties": ["window","path","thumbnail","windowparameter"] }, "id": 1 }
On my network, I found the performance is fine to query favourites each time I need them.
I've only implemented two types of favourites, type="media" and type="window"
For type="media" I do a Player.Open command. (see above)
For type="window" I do a GUI.ActivateWindow. But there's a catch. You need to take the "windowparameter" property and pass it to GUI.ActivateWindow in it's parameters array, but it MUST be quoted or commas in your file paths will cause the command to fail.
Here's an example of opening a window to a directory. Note: the parameters value has been quoted using a json escaped quote (\"). Thanks to @ironic_monkey for helping me debug this:
Code:
{"jsonrpc":"2.0","method":"GUI.ActivateWindow","id":1,"params":{"window":"videos","parameters": ["\"smb://myusername:mypassword@myserver/my-path-to-content/\""]}}
I hope this is helpful to someone else.
Scott