Help to set "UserRating" in a song using script
#1
Hello everybody! How are you?
I come here to explore an idea I had, and also ask for help.
A while ago I had the idea of ​​creating a script to "auto-rating" songs from the Kodi library.
The idea is to divide the music time into 11 parts, classifying them from "0" to "10". This way the music is being "rated" while it is played.

Why divide the songs in "11" parts?
Because 1/11 part is = "0", 2/11 = "1", 3/11= "2" .... 9/11 = "8", 10/11 = "09", 11/11 = "10"
this way, a song with 4:21 (4 minutes and 21 seconds) has 261 seconds, and each part has almost "24" seconds (24*11 = 264)

This is just the general idea, as I still want to implement a grade summing system. But for that I need this code to work correctly:

Code:

# Execute on Kodi Start-Up and wait for the song be played

import xbmc
import xbmcaddon

ADDON = xbmcaddon.Addon()
ADDON_PATH = ADDON.getAddonInfo('path')

monitor = xbmc.Monitor()
player = xbmc.Player()

def onPlayBackEnded():
    xbmc.executebuiltin("Notification(Song ended, The song has ended)")
    xbmc.executebuiltin("PlayerControl(SetUserRating, %s)" % rating)

player.onPlayBackEnded(onPlayBackEnded)

while not monitor.abortRequested():
    
    if player.isPlaying(): 
        # get all the needed times info from the song
        song = player.getMusicInfoTag()        
        song_length = song.getDuration()        
        time_parts = song_length/11        
        current_time = player.getTime()
        
        # calculate the rating as the music is played
        rating = int(current_time/time_parts)
       
       # Here I need to find out how to set the Rating of the music. 
       # song.setUserRating(rating) and song.setRating(rating) appears not working, because the rating in SongInformation Window not change.
 
        #This notification is only to "see" the script working
        xbmc.executebuiltin("Notification(%s, %s)" % ("Rating",song.getUserRating()))

    # the value of 10 is arbitrary. The ideal would be to use the same value of "time_parts", but I haven't figured out how to bring this variable from within the "if player.isPlaying(): "
    monitor.waitForAbort(10)


edit:
here an image with the script "working"

Image

The notification shows an "8" of rating.
As you can see, the values ​​are calculated correctly, I'm just having difficulty saving the value of "rating" and bringing the value of the variable "time_parts" into "monitor.waitForAbort(time_parts)" Does anyone have this answer? 

Thanks in Advance
Reply
#2
It seem no one get interest. But here some progress:

Code:

# Execute on Kodi Start-Up and wait for the song be played

import xbmc
import xbmcaddon
import json

ADDON = xbmcaddon.Addon()
ADDON_PATH = ADDON.getAddonInfo('path')

monitor = xbmc.Monitor()
player = xbmc.Player()

def onPlayBackEnded():
    xbmc.executebuiltin("Notification(Song ended, The song has ended)")
    xbmc.executebuiltin("PlayerControl(SetUserRating, %s)" % rating)

player.onPlayBackEnded(onPlayBackEnded)

while not monitor.abortRequested():
    
    time_parts = 2
    
    if player.isPlaying(): 
        # get all the needed times info from the song
        song = player.getMusicInfoTag()        
        song_length = song.getDuration()        
        time_parts = song_length/11        
        current_time = player.getTime()
        
        # calculate the rating as the music is played
        rating = int(current_time/time_parts)
       
        # Here I need to find out how to set the Rating of the music. 
        
        # Retrieve the currently playing song
        xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"JSONRPC.Introspect","id":1}')
        result = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":0,"properties":["rating"]},"id":1}')
        song_details = json.loads(result)["result"]["item"]

        # Extract the song ID and rating
        song_id = song_details["id"]
        song_rating = song_details["userrating"]
        
        # Update the rating in the music library
        xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, rating))
        
        #This notification is only to "see" the script working
        xbmc.executebuiltin("Notification(%s, %s)" % ("Rating",rating))

    # the value of 10 is arbitrary. The ideal would be to use the same value of "time_parts", but I haven't figured out how to bring this variable from within the "if player.isPlaying(): "
    monitor.waitForAbort(time_parts)


I've learn how to retrieve and write some data from the "MyMusic82.db" file in Database folder.
This way I cant change the Rating in the music, and work very well.
BUT i don't want to change the Rating, i want to change the USERRATING, or "My Rating" as show in image below: 

Image

But, chaging the line :
"xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, rating))" 
to
xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%f},"id":1}' % (song_id, rating))
simply don't work.

Any ideas?
Reply
#3
Interesting project.  For your userrating issue, I think the problem may be the data type.  According to the JSON RPC schema it is looking for an int value and I believe you are passing a string.   You can also use getMusicInfoTag() calls to get details about something playing vs. JSON RPC calls.  i find it a bit easier.   Here's an example of a service I wrote which may have some useful stuff you can use.  One thing to note is that you are just checking if something is playing vs. ensuring it is a music file playing.  Your addon would likely error out if a video file is playing.  My service checks for the media type.  You can also look at the XBMCPlayer class for some more hints.


Good luck,

Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#4
One thing you might want to do is catch the JSON RPC response to see if it was successful or if you get an error back.


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#5
OH!!! Thanks for the tips @jbinkley60!

I'll check the things you pointed!
Reply
#6
Some progress!!! Now the script check if the media is "AUDIO", and working correctly

New Ideia: Get the new new rating and added to old rating em make a "media" rating (if the song has a Rating 8 and the new rating is 10, the total rating will be 18, but will be divided by 2 (old rating + calculated rating divided by 2 = 9). BUT the check if player has stopped or ended is not working.

i've put some notifications and the coments where working or not. And still can´t get the "UserRating" updated, only "rating" and i triple check to confirm that "calculated_rating = int(current_time/time_parts)" is returning an integer and not a string (maybe a fourth check?)

anyway, here the code

Code:

# Execute on Kodi Start-Up and wait for the song be played

import xbmc
import xbmcaddon
import json

ADDON = xbmcaddon.Addon()
ADDON_PATH = ADDON.getAddonInfo('path')

monitor = xbmc.Monitor()
player = xbmc.Player()

while not monitor.abortRequested():    
    time_parts = 1    
    if player.isPlaying():
        # Get the properties of the currently playing item
        result = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetProperties","params":{"playerid":0, "properties":["type"]},"id":1}')
        media_type = json.loads(result)["result"]["type"]

        # Check if the media type is "audio"
        if media_type == "audio":
            # get all the needed times info from the song
            song = player.getMusicInfoTag()        
            song_length = song.getDuration()        
            time_parts = song_length / 11        
            current_time = player.getTime()
            
            # calculate the rating as the music is played
            calculated_rating = int(current_time/time_parts)
           
            # Retrieve the currently playing song
            xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"JSONRPC.Introspect","id":1}')
            result = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":0,"properties":["rating"]},"id":1}')
            song_details = json.loads(result)["result"]["item"]

            # Extract the song ID and rating
            song_id = song_details["id"]
            song_rating = song_details["rating"]            
            
            #This notification is only to "see" the script working <-- THIS ONE WORKING
            xbmc.executebuiltin("Notification(%s, %s)" % ("Calculated Rating", calculated_rating))
            
            # From here is not working, I can't see notifications after stop the music or music ended
            
            # check if the music has stopped, skipped or ended and the calculated rating has NOT the value 0
            if player.onPlayBackEnded() or player.onPlayBackStopped() and calculated_rating == 0:
                new_rating = song_rating
                # Update the rating in the music library
                xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, new_rating))
                #This notification is only to "see" the script working <-- THIS ONE NOT WORKING
                xbmc.executebuiltin("Notification(%s, %s)" % ("Old Rating",new_rating))
            
            # check if the music has stopped, skipped or ended and the calculated rating has the value 0
            if player.onPlayBackEnded() or player.onPlayBackStopped() and not calculated_rating == 0:
                new_rating = int((song_rating + calculated_rating) / 2)
                xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, new_rating))
                #This notification is only to "see" the script working <-- THIS ONE NOT WORKING
                xbmc.executebuiltin("Notification(%s, %s)" % ("New Rating", new_rating))

    monitor.waitForAbort(time_parts)
Reply
#7
(2023-01-25, 17:04)sagrath Wrote:             if player.onPlayBackEnded() or player.onPlayBackStopped() and not calculated_rating == 0:
                new_rating = int((song_rating + calculated_rating) / 2)
                xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, new_rating))
                #This notification is only to "see" the script working <-- THIS ONE NOT WORKING
                xbmc.executebuiltin("Notification(%s, %s)" % ("New Rating", new_rating))

Here's a quick check to ensure the new rating value is correct vs. this being a JSON RPC issue. 

            if player.onPlayBackEnded() or player.onPlayBackStopped() and not calculated_rating == 0:
                new_rating = int((song_rating + calculated_rating) / 2)
                xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, new_rating))
                #This notification is only to "see" the script working <-- THIS ONE NOT WORKING
                xbmc.log('The new userrating is: ' + str(song_id) + ' ' + str(new_rating), xbmc.LOGINFO)
                xbmc.executebuiltin("Notification(%s, %s)" % ("New Rating", new_rating))


This will write a log message with the song_id and new_rating to ensure they are correct.  This may lend some insight to the issue.

Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#8
I forgot to include in my previous post, that the 
"if player.onPlayBackEnded() or player.onPlayBackStopped() and calculated_rating == 0:" and "if player.onPlayBackEnded() or player.onPlayBackStopped() and not calculated_rating == 0:"  doesn't work too.

for some reason the if's statement doesn't detect if the player has stopped or ended, this way, the notifications never beem trigged

if I simplified the code to this: 

Code:

# Execute on Kodi Start-Up and wait for the song be played

import xbmc
import xbmcaddon
import json

ADDON = xbmcaddon.Addon()
ADDON_PATH = ADDON.getAddonInfo('path')

monitor = xbmc.Monitor()
player = xbmc.Player()

while not monitor.abortRequested():    
    time_parts = 1    
    if player.isPlaying():
        # Get the properties of the currently playing item
        result = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetProperties","params":{"playerid":0, "properties":["type"]},"id":1}')
        media_type = json.loads(result)["result"]["type"]

        # Check if the media type is "audio"
        if media_type == "audio":
            # get all the needed times info from the song
            song = player.getMusicInfoTag()        
            song_length = song.getDuration()        
            time_parts = song_length / 11        
            current_time = player.getTime()
            
            # calculate the rating as the music is played
            calculated_rating = int(current_time/time_parts)
           
            # Retrieve the currently playing song
            xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"JSONRPC.Introspect","id":1}')
            result = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":0,"properties":["userrating"]},"id":1}')
            song_details = json.loads(result)["result"]["item"]

            # Extract the song ID and rating
            song_id = song_details["id"]
            song_rating = song_details["userrating"]            
            
            new_rating = 10.0
            # Update the rating in the music library
            xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%f},"id":1}' % (song_id, new_rating))
            
            # This will write a log message with the song_id and new_rating to ensure they are correct. 
            xbmc.log('The new userrating is: ' + str(song_id) + ' ' + str(new_rating), xbmc.LOGINFO)
            
            #This notification is only to "see" the script working <-- THIS ONE NOT WORKING
            xbmc.executebuiltin("Notification(%s, %s)" % ("Old Rating",new_rating))

    monitor.waitForAbort(time_parts)

note that "new_rating" is now arbitrary "10.0"
the notification gets triggered:

Image

In the log we have the messege that @jbinkley60  tells me to do.

Image

But doesn't update the UserRating (aka "My rating in Kodi)
Image

BUT, if I change the code:

"xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%f},"id":1}' % (song_id, new_rating))"
to
"xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, new_rating))"

This happens:
Image

the notification trigger and as you can see, the "Rating" was updated to 10.0

At first I thought it was because of the dot after the 10 (10.0), but even changing the value of new_rating to just 10 (without the dot and zero) the userrating tag doesn't update.

I don't have a clue why isn't update or why "if player.onPlayBackEnded() or player.onPlayBackStopped()"  doesn't work too.

someone have some idea?

sorry to be annoying.
Reply
#9
What if you try this:

"xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%f},"id":1}' % (song_id, int(new_rating)))"

with the new_rating = 10.0 hard coded just like you have it ?  Does the notification message then look right Note that rating is a float and userrating is an int.




Thanks,

Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#10
(2023-01-25, 20:28)sagrath Wrote: I forgot to include in my previous post, that the 
"if player.onPlayBackEnded() or player.onPlayBackStopped() and calculated_rating == 0:" and "if player.onPlayBackEnded() or player.onPlayBackStopped() and not calculated_rating == 0:"  doesn't work too.

The reason this isn't working is a logic problem.  In your original code you check for is playing then is audio.  Then you check for has playback ended or playback stopped nested under is playing / is audio.  A file can't both be playing and stopped / paused at the same time.  You need to pull the if stopped or if paused out to the same level as is playing.  If you look at my player class in this service program you can se they are all at the same level (lines 23-94).


Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#11
(2023-01-25, 21:46)jbinkley60 Wrote: You need to pull the if stopped or if paused out to the same level as is playing.

All right, first of all, very very thanks for the time you spend. This is very new to me.

 If I understand what you say correctly, and look at your code on your service, the if's need be outside the "if player.isPlaying():" just after my "ADDON_PATH = ADDON.getAddonInfo('path')" right?
this way I'll make a Class:

I'll try to figure out how it's done

thanks!!!


EDIT: Forgot to mention:

this sugestion do not work either:

"xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%f},"id":1}' % (song_id, int(new_rating)))"
Reply
#12
(2023-01-25, 22:21)sagrath Wrote: All right, first of all, very very thanks for the time you spend. This is very new to me.

 If I understand what you say correctly, and look at your code on your service, the if's need be outside the "if player.isPlaying():" just after my "ADDON_PATH = ADDON.getAddonInfo('path')" right?
this way I'll make a Class:

I'll try to figure out how it's done

Try something like this and see if it works how you want.  I didn't test the code but the logic should be right.  When I get a chance I'll try to test the RPC call myself. 

plflag = calculated_rating = 0

while not monitor.abortRequested():    
    time_parts = 1    
    if player.isPlaying():
        # Get the properties of the currently playing item
        result = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetProperties","params":{"playerid":0, "properties":["type"]},"id":1}')
        media_type = json.loads(result)["result"]["type"]

        # Check if the media type is "audio"
        if media_type == "audio":
            plflag = 1
            # get all the needed times info from the song
            song = player.getMusicInfoTag()        
            song_length = song.getDuration()        
            time_parts = song_length / 11        
            current_time = player.getTime()
            
            # calculate the rating as the music is played
            calculated_rating = int(current_time/time_parts)
           
            # Retrieve the currently playing song
            xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"JSONRPC.Introspect","id":1}')
            result = xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":0,"properties":["rating"]},"id":1}')
            song_details = json.loads(result)["result"]["item"]

            # Extract the song ID and rating
            song_id = song_details["id"]
            song_rating = song_details["rating"]            
            
            #This notification is only to "see" the script working <-- THIS ONE WORKING
            xbmc.executebuiltin("Notification(%s, %s)" % ("Calculated Rating", calculated_rating))
            
            # From here is not working, I can't see notifications after stop the music or music ended
            
    # check if the music has stopped, skipped or ended and the calculated rating has NOT the value 0
    if (player.onPlayBackEnded() or player.onPlayBackStopped()) and calculated_rating == 0 and plflag == 1:
        new_rating = song_rating
        # Update the rating in the music library
        xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, new_rating))
        #This notification is only to "see" the script working <-- THIS ONE NOT WORKING
        xbmc.executebuiltin("Notification(%s, %s)" % ("Old Rating",new_rating))
        plflag = calculated_rating = 0
            
    # check if the music has stopped, skipped or ended and the calculated rating has the value 0
    if (player.onPlayBackEnded() or player.onPlayBackStopped()) and not calculated_rating == 0 and plflag == 1:
        new_rating = int((song_rating + calculated_rating) / 2)
        xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "rating":%f},"id":1}' % (song_id, new_rating))
        #This notification is only to "see" the script working <-- THIS ONE NOT WORKING
        xbmc.executebuiltin("Notification(%s, %s)" % ("New Rating", new_rating))
        plflag = calculated_rating = 0



Thanks,

Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#13
(2023-01-25, 23:30)jbinkley60 Wrote: Try something like this and see if it works how you want.  I didn't test the code but the logic should be right.  When I get a chance I'll try to test the RPC call myself. 

Edit:
It works!!!!

now the noficcation is trigged with the new rating!!!!

VERY VERY THANKS!!!
Reply
#14
(2023-01-26, 01:06)sagrath Wrote: Edit:
It works!!!!

now the noficcation is trigged with the new rating!!!!

VERY VERY THANKS!!!


Good to hear.  it is always nice when you have some code lying around you can copy from.  Smile   Is the userrating RPC call working or still broken ?


Thanks,

Jeff
Running with the Mezzmo Kodi addon.  The easier way to share your media with multiple Kodi clients.
Service.autostop , CBC Sports, Kodi Selective Cleaner and Mezzmo Kodi addon author.
Reply
#15
(2023-01-26, 01:26)jbinkley60 Wrote: s the userrating RPC call working or still broken ?

It still broken... unfortunaly. The more strange is the rating tag work very well... bet the userrating no....
Reply

Logout Mark Read Team Forum Stats Members Help
Help to set "UserRating" in a song using script0