Here, I ulpload to my private github!
Song Auto rating Girthub
Continuing my saga, here are some thoughts:
When I came up with this script, I thought of certain details:
Well, for the script to work 100% and have accurate evaluations, the situation must occur as follows:
When starting the song, the evaluation calculations start and two variants are taken into account:
Variant A: If the music has original empty note or equal to Zero, the script will divide the music in 11 parts and calculate the note being the part 1/11 = rating 0, 2/11 = rating 1, 3/11 = rating 2.... 10/11 = rating 9 and 11/11 = rating 10.
Variant B: If the song already has some rating, the script will calculate the same as variant A, and will calculate the initial rating, plus the calculated rating and divide by 2, thus making an average note.
And I thought of the following five scenarios in which music is evaluated:
Scenario A: The music plays to the end and the player stops.
Occurs when the song is the only or last song in the playlist, and the repeat function is disabled.
Scenario B: Music is stopped by user action:
Occurs when the user presses the STOP button, and the player stops, regardless of which position the music is in.
Scenario C: The song plays until the end and the next song starts:
Occurs when the song is not the only or last song in the playlist, or when the repeat function is activated.
Scenario D: The song is skipped by the user, either to the next one in the playlist, or the previous one:
Occurs when the user presses the skip-forward or skip-backwards buttons, causing the current song to be stopped, but without the player stopping.
Scenario E: The music ends and then starts:
It happens when the song is the only one in the playlist and the repeat function is activated.
While writing the code, I noticed that scenario A was easily solved with:
else:
monitor.onPlayBackStopped()
which calls the function "def onPlayBackStopped(self):" and it's good.
The scenario B uses the same funcion as scenario A, so it's good too!
scenario C is possible as long as the evaluation of the music occurs in real time, because in this way, regardless of the user's action, the music will receive the note along which it is played, but it will not take into account empty notes or zero notes , because as soon as it receives a score of 1 (that is, the second 1/11 of the song) the calculation will change to a song with a score != of zero or empty.
That is, either it is possible to evaluate in real time with automatic evaluation of the next song in the playlist, or it is possible to evaluate the music according to its current score, which would be current score plus calculated score divided by 2.
complicated right?
Scenario E is the same as scenario C, the difference is that the song will be re-evaluated at each execution.
As for scenario D, I really couldn't run it at all. By the way, I even managed it, because if I use scenario C, when skipping the song, there will be an evaluation of the next or previous one.
Does anyone have any ideas on how to check when the user skips the song?
I did some tests over the week, and managed to find a logic where I got scenarios A and B and C taking into account zero and non-zero grades. In other words, only scenario D was missing.
I'm going crazy already looking for a solution. Who told me to get into programming hahahahaha!
by the way here's the code: (not in github, because there I keep the last of @
jbinkley60 show me.
python:
import xbmc
import xbmcaddon
import json
import time
class Monitor(xbmc.Monitor):
def __init__(self):
self.is_library_song = False
pass
def status_check(self):
# perform monitor status check
pass
def onPlayBackStarted(self):
self.is_library_song = True
# When the song ends, either by user action, or when the song is
# the last in the playlist and the "repeat" function is disabled.
def onPlayBackStopped(self):
if self.is_library_song and current_time > 5:
# If the song has no rating yet, or the rating is "0", this will be its new rating.
if song_rating == 0:
new_rating = int(current_time/song_parts)
# If the song already has a rating, here the current rating value will
# be added to the new rating calculation, to obtain an average rating.
elif song_rating != 0:
new_rating = (song_rating + calculated_rating) / 2
# Saving the new rating as the song stops.
xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%d},"id":1}' % (song_id, new_rating))
xbmc.executebuiltin("Notification(%s, %s)" % ("New Rating", new_rating))
self.is_library_song = False
def calculate_zero_rating(calculated_rating):
# 2 seconds before music ends, the calculation
# will be the the value in "calculated_rating"
if (current_time - 2) >= song_length:
new_rating = int(current_time/song_parts)
xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%d},"id":1}' % (song_id, new_rating))
xbmc.executebuiltin("Notification(%s, %s, time=2000)" % ("New 0 Rating", new_rating))
else:
xbmc.executebuiltin("Notification(%s, %s, time=2000)" % ('{} Waiting:'.format(song_title), 'Seconds: {}'.format(current_time - 2)))
def calculate_positive_rating(calculated_rating):
# 2 seconds before music ends, the calculation
# will be the current song rating, plus the calculated_rating
# divided by 2, to get an average ratings
if (current_time - 2) >= song_length:
new_rating = int((song_rating + calculated_rating) / 2)
xbmc.executeJSONRPC('{"jsonrpc":"2.0","method":"AudioLibrary.SetSongDetails","params":{"songid": %d, "userrating":%d},"id":1}' % (song_id, new_rating))
xbmc.executebuiltin("Notification(%s, %s, time=2000)" % ("New Positive Rating", new_rating))
else:
xbmc.executebuiltin("Notification(%s, %s, time=2000)" % ('{} Waiting:'.format(song_title), 'Seconds: {}'.format(current_time - 2)))
monitor = Monitor()
player = xbmc.Player()
calculated_rating = 0
while not monitor.abortRequested():
try:
while True:
if xbmc.Player().isPlayingAudio():
# 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}')
# Extract the song ID and rating
song_details = json.loads(result)["result"]["item"]
# Ensure music file exists in Kodi database
if "id" in song_details:
song_id = song_details["id"]
song_rating = song_details["userrating"]
# To have all the necessary time calculations.
song = player.getMusicInfoTag()
song_title = song.getTitle()
song_length = song.getDuration()
song_parts = int(song_length / 11)
current_time = int(player.getTime())
# To avoid an error where the calculation would be divided by zero
if current_time > 0:
# here is the calculation of the current playing ratings
calculated_rating = int(current_time / song_parts)
# When music starts, "self.is_library_song" is set to True
monitor.onPlayBackStarted()
# If song has rating empty or zero, the calculations
# will be made in "def calculate_zero_rating()"
if song_rating == 0:
calculate_zero_rating(calculated_rating)
# If song already has a non-zero rating, the calculations
# will be made in "def calculate_positive_rating()"
if song_rating > 0:
calculate_positive_rating(calculated_rating)
else:
# when the song ends, with or
# without user intervention.
monitor.onPlayBackStopped()
monitor.status_check()
# Sleep/wait for abort for 1 second
if monitor.waitForAbort(1):
# Abort was requested while waiting. Exit the while loop.
break
except Exception as e:
xbmc.executebuiltin("Notification(%s, %s)" % ("An error occurred: ", e))
In this logic, I do not use the sugestion of @
jbinkley60 to use new variable called original_rating = 0, because now the song only wil be rating 2 seconds before has stopped or ended.
But as i said above, I can't get to scenario D, because I can't find a logic to increment within that scope. I also can't find in the Kodi documentation how to identify when the user triggers skip-forward/backward.
Does anyone have a suggestion or opinion?