v19 Filter movies by actor and list them in the GUI
#1
What I try to accomplish is, I search my videodb for all movies with a specific actor and want to display those movies. But only by an API call.

The best idea I had was to use GUI.ActivateWindow and pass a list of movieid's as parameters:

json:
{ "jsonrpc": "2.0", "method": "GUI.ActivateWindow", "params": { "window":"videos", "parameters": [ LIST_OF_MOVIEID] }, "id": "1"} }

but I guess this isn't possible this way?!?

Or since there is a built in filter in Kodi where I can filter by actors, is there a way to do the same just by using the API?

Any ideas are welcome, thanks in advance.
Reply
#2
Your best bet would be to create smart playlists and add a rule. Limit to "Actor" and for the condition "contains" and then the name of the actor you are searching for.

You could try adding playlists via API or modify them:

https://kodi.wiki/view/JSON-RPC_API/v12#Playlist.Add
Reply
#3
It turns out that I was wrong

xbmc.executeJSONRPC('{"jsonrpc":"2.0", "method":"GUI.ActivateWindow", "params":{"window": "videos", "parameters":["videodb://movies/actors/<place_id_here>", "return"]}, "id":1}')

Should do what you want. You just have to know the actor-ID.

Spoke to @ronie and he told me that this should be possible this way. Haven't tried myself yet, but I would not doubt him Wink
Reply
#4
First, thanks for your and @ronie 's help !

Your hint with the smart playlist was a good start, I wrote a little python script to ssh into Kodi and echo a smart playlist with the desire actor and open it with GUI.ActivateWindow.
This works but its a bit ugly using ssh therefore...

So I was glad to hear that it should be possible with those parameters 
json:
"parameters":["videodb://movies/actors/<place_id_here>", "return"]
but unfortunately it doesn't work. As far as I read, Kodi is using as actor-id the full name, so I tried 
json:
"parameters":["videodb://movies/actors/Vin Diesel", "return"]
I also tried with %20 or + because of the spaces but the list keeps empty.

I also couldn't found anything else related to a cast or actor id in the json-rpc docs.

Edit:
Okay, I just did take a look into the database, there are actor_id's and with those id's it does work. But now the question is, can I get those id's with the json rpc somehow?  Otherwise I guess I have to query the database directly, since I use python it shouldn't be to hard and still cleaner then using ssh and echo Big Grin
Reply
#5
The "ID" is number, not a name.

I played a bit with the command and unforunately we do not have anything to get a current list of actor names and their respective IDs. What I've done so far is to check my "MyVideo119.db" file (with some SQL-viewer) and inside that I found a list of actors with their IDs. Making this possible via "VideoLibrary.GetActors" would make a nice feature request Wink . It could probably be pretty similar to "VideoLibrary.GetMovies". I will have a look if I can get this managed and PR it. I'm not dev myself, but maybe it's only a bit of copy and paste and changing some values.

The 2nd unfortunate thing is, that those IDs are not the same on different Kodi installation each with their own libraries. That might be different in case you are using a MySQL centralized database. For me, as I don't use a MySQL DB, I checked on my main HTPC and on my laptop and those IDs for the actors differ. So you have to check for yourself which ID will match. the command I used is:

curl -X POST -H "content-type:application/json" http://192.168.1.162:8080/jsonrpc -u kodi:1234 -d '{"jsonrpc":"2.0","id":1,"method":"GUI.ActivateWindow","params":{"window":"videos", "parameters":["videodb://movies/actors/1"]}}'

You have to replace the IP and the username:passwort ofc Wink
For me and my current installtion, the ID "1" shows movies of "Paul Walker". That might be different for you.
 
(2021-12-24, 13:03)corus Wrote: This works but its a bit ugly using ssh therefore...
Regarding the playlists....as said, you can use JSON for that as well. There's no need to use SSH. But in the end it's up to you what fits your needs Wink
Reply
#6
I guess this could be a nice feature since I read a couple of threads about a similar question.
Yes I do use a centralized MySQL database and I think for now I will query the id with python directly from the database, should be the cleanest way until we can use the json rpc.

Thanks again for your help and merry Christmas Smile
Reply
#7
Same to you and glad I could help Wink
Reply
#8
In case someone else want to do something similar:

python:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import requests
import json
#pip3 install pymysql
import pymysql.cursors

class ShowMoviesWithActor:
    def __init__(self, actor):
        self.kodi_ip = "KODI_IP"
        self.kodi_port = 8080
        self.sql_user = "USER"
        self.sql_password = "PASSWORD"
        self.sql_ip = "MYSQL_IP"

        actor_id = self.getActorId(actor)
        if actor_id:
            self.sendKodiRequest("GUI.ActivateWindow", {"window": "videos", "parameters": ["videodb://movies/actors/%s" % actor_id]})
        else:
            print("No movies found with %s" % actor)

    def getActorId(self, actor):
        connection = pymysql.connect(host=self.sql_ip,
                                     user=self.sql_user,
                                     password=self.sql_password,
                                     database='MyVideos119',
                                     cursorclass=pymysql.cursors.DictCursor)
        with connection:
            with connection.cursor() as cursor:
                sql = "SELECT * FROM actor;"
                cursor.execute(sql)
                result = cursor.fetchall()

        if result:
            for info in result:
                if info.get("name").lower() == actor.lower():
                    return info.get("actor_id")

        return None

    def sendKodiRequest(self, method, params=dict()):
        payload = {"jsonrpc": "2.0", "id":1}

        payload.update({"method": method, "params": params})
        url = "http://%s:%s/jsonrpc" % (self.kodi_ip, self.kodi_port)
        try:
            r = requests.post(url, data=json.dumps(payload))
            if r.status_code == 200:
                return r.json()
        except Exception as e:
            print("Connection Error")
        return False

ShowMoviesWithActor("Ryan Reynolds")
Reply
#9
Nice 👍
Reply
#10
hi, even if a fetching of actor db id is a bit cumbersome it's may not needed for your wished 'action' (show movies by actor x)

i am just at the beginning by learning python, but this method / source is maybe helpfull.

It queries the lib using the filter param.
So , that you can check against in the json result tuple (may search/find/split : ' "total":* ' )
( thats the part which i cannot provide and need to learn , but i am sure you can and know how to do it)

And than using activate window using encoded xsp append if total result is greater than 0

A important thing to note is the diff betweeen movie,tvshow,episode (actor id wise, and path wise).
Hope it helps even if my python skill is pretty low.


Sources
python:

### infos,using virtual xsp - see https://forum.kodi.tv/showthread.php?tid=341640
# encode lib paths - using 'Christian Bale', spaces dont need to be encoded
# movie_path = 'videodb://movies/titles/?xsp=
%7B%22rules%22%3A%7B%22and%22%3A%5B%7B%22field%22%3A%22actor%22%2C%22operator%22%3A%22contains%22%2C%22value%22%3A%5B%22Christian Bale%22%5D%7D%5D%7D%2C%22type%22%3A%22movies%22%7D'
# tvshow_path = 'videodb://tvshows/titles/?xsp=
%7B%22rules%22%3A%7B%22and%22%3A%5B%7B%22field%22%3A%22actor%22%2C%22operator%22%3A%22contains%22%2C%22value%22%3A%5B%22Christian Bale%22%5D%7D%5D%7D%2C%22type%22%3A%22tvshows%22%7D'
# episode_path = 'videodb://tvshows/titles/-1/-1/?xsp=
%7B%22rules%22%3A%7B%22and%22%3A%5B%7B%22field%22%3A%22actor%22%2C%22operator%22%3A%22contains%22%2C%22value%22%3A%5B%22Christian Bale%22%5D%7D%5D%7D%2C%22type%22%3A%22episodes%22%7D'

decoded lib paths - using 'Christian Bale', cannot be used for activatewindow
# movie_path = 'videodb://movies/titles/? xsp={"rules":{"and":[{"field":"actor","operator":"contains","value":["Christian Bale"]}]},"type":"movies"}'
# tvshow_path = 'videodb://tvshows/titles/? xsp={"rules":{"and":[{"field":"actor","operator":"contains","value":["Christian Bale"]}]},"type":"tvshows"}'
# episode_path = 'videodb://tvshows/titles/-1/-1/? xsp={"rules":{"and":[{"field":"actor","operator":"contains","value":["Christian Bale"]}]},"type":"episodes"}'

# when id could be fetched it'll easier to use this path
# videodb://movies/actors/<actor_movie_dbid>/

python:

# -*- coding: utf-8 -*-
import xbmc

def main():
    actor_name_id = 'Christian Bale'
    
    # may like to get some (more) item props for the query -  more_movie_properties = '"title", "lastplayed", "studio", "cast", "plot", "writer", "director", "fanart", "runtime", "mpaa", "thumbnail", "file", "year", "genre", "tag", "trailer"'
    movie_properties = '"title"'
    
    # query lib using filter by actor is equal to check against via find?
    result_getitems_by_actor = xbmc.executeJSONRPC(' {"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties": [ %s ], "sort": { "order": "ascending", "method": "year", "ignorearticle": true }, "filter": { "actor": "%s" } }, "id": "libMovies" }' % (movie_properties,actor_name_id))
    
    # ... need code to extract ' "total":=*'  = from result_getitems_by_actor tuple and set to variable name : cast_movie_items
    
    # something like ?
    # if result_getitems_by_actor.find('method') == -1:
        # cast_movie_items = 0
    # else:
        # cast_movie_items = 2
    
    # for compensate my lack in aknowledge ,force true by any int > 0
    cast_movie_items = 2
    
    # build the lib url using xsp methods
    if cast_movie_items > 0:
        # i dont no other way escaping py-variable (%s) inside the encoded url,therefore split
        movie_split_suffix = 'videodb://movies/titles/?xsp=%7B%22rules%22%3A%7B%22and%22%3A%5B%7B%22field%22%3A%22actor%22%2C%22operator%22%3A%22contains%22%2C%22value%22%3A%5B%22'
        movie_split_postfix = '%22%5D%7D%5D%7D%2C%22type%22%3A%22movies%22%7D'
        
        movie_path = movie_split_suffix + actor_name_id + movie_split_postfix
        
        result_goto_items_by_actor = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "GUI.ActivateWindow", "params": { "window": "videos", "parameters": [ "%s" ] }, "id": 1}' % movie_path)

if __name__ == '__main__':
    main()        
 



EDIT: the python code box
auto convert itself, after put in into
syntax=python
so
the variables in the python code above should look this way

movie_split_suffix = 'videodb://movies/titles/?xsp=%7B%22rules%22%3A%7B%22and%22%3A%5B%7B%22field%22%3A%22actor%22%2C%22operator%22%3A%22contains%22%2C%22value%22%3A%5B%22'

        movie_split_postfix = '%22%5D%7D%5D%7D%2C%22type%22%3A%22movies%22%7D'
Skins |  Titan M O D   •   S W A N (WIP)
Reply
#11
@corus , i learned more, got it workin this way....

json rpc used

query lib to check for existing actor_name_id in movie and/or tvshow library using the filter param :
   - https://kodi.wiki/view/JSON-RPC_API/v12#....GetMovies
   - https://kodi.wiki/view/JSON-RPC_API/v12#...GetTVShows

activate window using virtual xsp in path:
   - https://kodi.wiki/view/JSON-RPC_API/v12#...vateWindow

notify popup when no actor_name_id found :
   - https://kodi.wiki/view/JSON-RPC_API/v12#...tification -


unsure if faster than the the other way...

python:

# -*- coding: utf-8 -*-
import xbmc
# https://docs.python.org/3/library/urllib...arse.quote
import urllib.parse

def main():
    # parse container_content as args either (movies,tvshows,episodes)
    container_content = sys.argv[1]
    actor_name_id = 'liam neeson'
    
    # check exist, check for 0 to be true = not -1 in json.result tuple
    exist_results = xbmc.executeJSONRPC(' {"jsonrpc": "2.0", "method": "VideoLibrary.Get%s", "params": { "sort": { "order": "ascending", "method": "year", "ignorearticle": true }, "filter": { "actor": "%s" } }, "id": "lib%s" }' % (container_content,actor_name_id,container_content)).find('"total":0')
    
    if exist_results == -1:
        if container_content == 'movies':
            db_url_root_path = 'videodb://movies/titles/?xsp='
        elif container_content == 'tvshows':
            db_url_root_path = 'videodb://tvshows/titles/?xsp='
        elif container_content == 'episodes':
            db_url_root_path = 'videodb://tvshows/titles/-1/-1/?xsp='
        # encode xsp and create path
        # xsp example syntax {"group":{"mixed":false,"type":"none"},"order":{"direction":"ascending","ignorefolders":0,"method":"year"},"rules":{"and":[{"field":"actor","operator":"is","value":["christian bale"]}]},"type":"movies"}
        decoded_xsp = '{"rules":{"and":[{"field":"actor","operator":"is","value":["%s"]}]},"type":"%s"}' % (actor_name_id,container_content)
        encoded_xsp = urllib.parse.quote(decoded_xsp.encode())
        
        url = db_url_root_path + encoded_xsp
        
        xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "GUI.ActivateWindow", "params": { "window": "videos", "parameters": [ "%s" ] }, "id": 1}' % url)
    else:
        xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "GUI.ShowNotification", "params": { "title": "sorry... ", "message": "no %s Items with %s found" }, "id": 1}' % (container_content,actor_name_id))

if __name__ == '__main__':
    main()
Skins |  Titan M O D   •   S W A N (WIP)
Reply
#12
Hi @mardukL, very nice !
I guess this is what @DaVu  had in mind with using a smart playlist but I didn't find anything to create a "virtual xsp" so I gave up this idea very quickly...

But so as you, I learned more again and realized how powerful Kodi can be in terms of customization Big Grin
Thank you very much for your input too!

Here an updated version of my script with @mardukL solution:

python:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import requests
import json
import urllib.parse

class ShowContentWithActor:
    def __init__(self, actor, content):
        self.kodi_ip = "KODI_IP"
        self.kodi_port = 8080

        params = {"sort": {"order": "ascending", "method": "year", "ignorearticle": True},
                  "filter": {"actor": "%s" % actor}}

        if content == "movies":
            result = self.sendKodiRequest("VideoLibrary.GetMovies", params)
            video_db = "videodb://movies/titles/?xsp="

        if content == "tvshows" or content == "episodes":
            result = self.sendKodiRequest("VideoLibrary.GetTvshows", params)
            if content == "tvshows":
                video_db = "videodb://tvshows/titles/?xsp="
            else:
                content = "tvshows"
                video_db = "videodb://tvshows/titles/-1/-1/?xsp="

        actor_result = result.get("result")
        if actor_result.get(content):
            decoded_xsp = '{"rules":{"and":[{"field":"actor","operator":"is","value":["%s"]}]},"type":"%s"}' % (actor, content)
            url = video_db + urllib.parse.quote(decoded_xsp.encode())
            self.sendKodiRequest("GUI.ActivateWindow", {"window": "videos", "parameters": ["%s" % url]})

        else:
            self.sendKodiRequest("GUI.ShowNotification", {"title": "sorry...", "message": "no %s Items with %s found" % (content, actor)})

    def sendKodiRequest(self, method, params=dict()):
        payload = {"jsonrpc": "2.0", "id":1}
        payload.update({"method": method, "params": params})
        url = "http://%s:%s/jsonrpc" % (self.kodi_ip, self.kodi_port)
        try:
            r = requests.post(url, data=json.dumps(payload))
            if r.status_code == 200:
                return r.json()
        except Exception as e:
            print("Connection Error")
        return False

ShowContentWithActor("kat dennings", "tvshows")
Reply
#13
(2021-12-28, 19:41)corus Wrote: Hi @mardukL, very nice !
I guess this is what @DaVu  had in mind with using a smart playlist but I didn't find anything to create a "virtual xsp" so I gave up this idea very quickly...

But so as you, I learned more again and realized how powerful Kodi can be in terms of customization Big Grin
Thank you very much for your input too!

Here an updated version of my script with @mardukL solution:

python:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import requests
import json
import urllib.parse

class ShowContentWithActor:
    def __init__(self, actor, content):
        self.kodi_ip = "KODI_IP"
        self.kodi_port = 8080

        params = {"sort": {"order": "ascending", "method": "year", "ignorearticle": True},
                  "filter": {"actor": "%s" % actor}}

        if content == "movies":
            result = self.sendKodiRequest("VideoLibrary.GetMovies", params)
            video_db = "videodb://movies/titles/?xsp="

        if content == "tvshows" or content == "episodes":
            result = self.sendKodiRequest("VideoLibrary.GetTvshows", params)
            if content == "tvshows":
                video_db = "videodb://tvshows/titles/?xsp="
            else:
                content = "tvshows"
                video_db = "videodb://tvshows/titles/-1/-1/?xsp="

        actor_result = result.get("result")
        if actor_result.get(content):
            decoded_xsp = '{"rules":{"and":[{"field":"actor","operator":"is","value":["%s"]}]},"type":"%s"}' % (actor, content)
            url = video_db + urllib.parse.quote(decoded_xsp.encode())
            self.sendKodiRequest("GUI.ActivateWindow", {"window": "videos", "parameters": ["%s" % url]})

        else:
            self.sendKodiRequest("GUI.ShowNotification", {"title": "sorry...", "message": "no %s Items with %s found" % (content, actor)})

    def sendKodiRequest(self, method, params=dict()):
        payload = {"jsonrpc": "2.0", "id":1}
        payload.update({"method": method, "params": params})
        url = "http://%s:%s/jsonrpc" % (self.kodi_ip, self.kodi_port)
        try:
            r = requests.post(url, data=json.dumps(payload))
            if r.status_code == 200:
                return r.json()
        except Exception as e:
            print("Connection Error")
        return False

ShowContentWithActor("kat dennings", "tvshows")
Nice, espeacially for remote it.

And thanks and problem, i also liked to learn a little bit more about py and using json rpc recently.

The xsp method is not my idea, just found it here ( skinning related )
- https://forum.kodi.tv/showthread.php?tid=341640

So i just had to figure out how can encode/decode via python.

Terms 'virtual' xsp:
kodi folderpath s can make use of xsp appended 'url' s
- you can test them by

1.
create a smart playlist and navigate into it
or
create a custom library node and navigate to

or
just navigate to
library://videos/ and go into any path startig at this root dir

2.
than return the Container FolderPath

maybe
via Container.FolderPath ( for the container itself ) or listitem.folderpath ( for a specific item )
e.g.
- xbmc.getInfoLabel('Container.FolderPath')
or
via json : https://kodi.wiki/view/JSON-RPC_API/v12#...InfoLabels

3.
you 'll notice that you get an 'percent' encoded url.

as that is for sure not really readable by humans,
url - decode them to take a look at the syntax ( dict?) and for sure using it as "template" for creating a definition for a script using
those 'virtual' nodes. ( as it can be customiced without provide a file, just encode it and send it to kodi).

EDIT: @corus

you can ommit the optional "sort" param

python:
"sort": { "order": "ascending", "method": "year", "ignorearticle": true }

as it just use for the exist check, i forget it too
python:

params = {"filter": {"actor": "%s" % actor}}
should be enough

edit again:
overread at first look, and
unsure if typo on your end, but another thing to note is that episodes can have cast members, which arent part of the tv shost cast and vice versa.

so even if episodes share root url with tv shows, the check exist for episode castmembers has to excluded from tv shows query
use VideoLibrary.GetEpisodes instead.

also for the xsp/smartplaylist , its important to differ the content type between shows n episodes.

the show 'the simpsons' is a good example to test ( if you got it stored, liam neeson, william dafoe, woody harrelson and more can be found in episodes but will not return results on tvshow.)
so , best is test any show you got ,where you can imagine an 'cameo' actor for an episode which is not part of the show itself.

exist_results = xbmc.executeJSONRPC(' {"jsonrpc": "2.0", "method": "VideoLibrary.Get%s", "params": { "sort": { "order": "ascending", "method": "year", "ignorearticle": true }, "filter": { "actor": "%s" } }, "id": "lib%s" }' % (container_content,actor_name_id,container_content)).find('"total":0')

from
python:

if content == "movies":
result = self.sendKodiRequest("VideoLibrary.GetMovies", params)
video_db = "videodb://movies/titles/?xsp="

if content == "tvshows" or content == "episodes":
result = self.sendKodiRequest("VideoLibrary.GetTvshows", params)
if content == "tvshows":
video_db = "videodb://tvshows/titles/?xsp="
else:
content = "tvshows"
video_db = "videodb://tvshows/titles/-1/-1/?xsp="


to something like
python:

result = self.sendKodiRequest("VideoLibrary.Get%s" % content, params)
if content == "movies" or content == "tvshows":
video_db = "videodb://%s/titles/?xsp=" % content
else:
video_db = "videodb://tvshows/titles/-1/-1/?xsp="
Skins |  Titan M O D   •   S W A N (WIP)
Reply
#14
Quote:overread at first look, and
unsure if typo on your end, but another thing to note is that episodes can have cast members, which arent part of the tv shost cast and vice versa.

so even if episodes share root url with tv shows, the check exist for episode castmembers has to excluded from tv shows query
use VideoLibrary.GetEpisodes instead.

No it's not a typo, but (and please correct me if I'm wrong), you can't query VideoLibrary.GetEpisodes without a tvshowid parameter what you won't get unless you query the TvShow first.
Quote:the show 'the simpsons' is a good example to test ( if you got it stored, liam neeson, william dafoe, woody harrelson and more can be found in episodes but will not return results on tvshow.)
so , best is test any show you got ,where you can imagine an 'cameo' actor for an episode which is not part of the show itself.
It's a good point, and I tested it, you are right with a VideoLibrary.GetTvshows query I don't get those actors. But to be honest it's not this important. I just thought last week, wouldn't it be nice if I could just ask my smart speaker "show me all movies with Ryan Reynolds", and thanks to you this is working now in a clean way without any SSH or MySQL queries Big Grin
Reply
#15
In case of filters, those have to be done differently:

For example: 

{"jsonrpc":"2.0","id":1,"method":"VideoLibrary.GetMovies", "params":{"filter":{"field":"actor","operator":"is","value":"Sigourney Weaver"}}}

This is also documented on our wiki: https://kodi.wiki/view/JSON-RPC_API/Examples

In that case you are able to use the name instead of the actorID. Unfortunately you can't combine "GUI.ActivateWindow" with filters like that. 

I'm currently working on a JSON method "VideoLibrary.GetActor". Not as trivial as I thought, but I guess I can get some help from Team members. Might be helpful for scripts where you can store values in variables and create individual calls.
Reply

Logout Mark Read Team Forum Stats Members Help
Filter movies by actor and list them in the GUI0