umbrellaplug / umbrellaplug.github.io

Umbrella Kodi Addon Official
111 stars 17 forks source link

[FEATURE] Set watched in Kodi library when watched in Umbrella #372

Open CnC-ode opened 1 week ago

CnC-ode commented 1 week ago

Feature

Hello,

My problem is the following:

I would much appreciate it if you would consider implementing this feature on Umbrella because it is the only thing that is missing for it to be the perfect player for me.

Cheers!

adamosborne83 commented 1 week ago

Download the Trakt addon, this will then sync between your library and Umbrella. In settings of the trakt addon you will see sync. So then when new movies are added to library it will all sync.

CnC-ode commented 1 week ago

@adamosborne83 Yes I have all that setup...

That's not really the problem. As I mentioned, if I force a Trakt sync, the item in the library will be marked as watched.

The idea of the feature is to do that automatically when play ends. This happens if the item is played directly from the library (using Umbrella as a player) but its not happening if it is played from an Umbrella list inside the addon.

adamosborne83 commented 1 week ago

@adamosborne83 Yes I have all that setup...

That's not really the problem. As I mentioned, if I force a Trakt sync, the item in the library will be marked as watched.

The idea of the feature is to do that automatically when play ends. This happens if the item is played directly from the library (using Umbrella as a player) but its not happening if it is played from an Umbrella list inside the addon.

But, what I'm saying is that the trakt addon does this. Watch Ghosbusters in Umbrella, then the trakt addon will mark it as watched in library.

CnC-ode commented 1 week ago

@adamosborne83

It will, but not when the play ends...

I have to force a Trakt sync for it to actually mark it as watched in kodi library

umbrellaplug commented 1 week ago

@adamosborne83

It will, but not when the play ends...

I have to force a Trakt sync for it to actually mark it as watched in kodi library

Kodi library should be marked as watched when completed, the playcount in the kodi database is increased whenever an item is watched.

Couple of things.

  1. Can you turn logging on and watch something and duplicate the not being marked as watched then attach the log here?
  2. Can you provide me the exact steps I would need to take to duplicate/ re-create the issue on my system so I can look into what may be happening?
CnC-ode commented 1 week ago
  1. I actually thought that wasn't supposed to happen. I've now digged into the logs to find a little bit more, and maybe I found the issue:

umbrella.log

[2024-06-23 01:20:48] [ plugin.video.umbrella: DEBUG ]: Sending Episode to be marked as watched. IMDB: tt1266020 TVDB: 84912 Season: 4 Episode: 22 Title: Parks and Recreation Watch Percentage Used: 85 Current Percentage: 85.01763826244158

kodi.log

2024-06-23 01:20:48.577 T:13281    info <general>: metahandler: b'Loading sqlite3 as DB engine version: 3.39.4' (ENCODED)
2024-06-23 01:20:49.625 T:13281   error <general>: metahandler: b'************* Error inserting to cache table: UNIQUE constraint failed: episode_meta.imdb_id, episode_meta.tvdb_id, episode_meta.episode_id, episode_meta.title ' (ENCODED)
  1. The steps are very easy:
CnC-ode commented 6 days ago

Hello again,

I've been digging a little further on this, mainly by reading player.py code. It is my understanding that Umbrella is behaving as expected, in other words, Umbrella will mark items as watched on Kodi library only if the play action was invoked from the library item itself:

  1. This is the function where jsonrpc is invoked in order to increase playcount:
    def libForPlayback(self):
        if self.DBID is None: return
        try:
            if self.media_type == 'movie':
                rpc = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": {"movieid": %s, "playcount": 1 }, "id": 1 }' % str(self.DBID)
            elif self.media_type == 'episode':
                rpc = '{"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": {"episodeid": %s, "playcount": 1 }, "id": 1 }' % str(self.DBID)
            control.jsonrpc(rpc)
        except: log_utils.error()
  1. However, DBID is set on the getMeta() function, but only if the action originated from videodb and not from plugin:
    def getMeta(self, meta):
        try:
            if not meta or ('videodb' in control.infoLabel('ListItem.FolderPath')): raise Exception()
    ...
            if 'plugin' not in control.infoLabel('Container.PluginName'):
                self.DBID = meta.get('movieid')
    ...
            if 'plugin' not in control.infoLabel('Container.PluginName'):
                self.DBID = meta.get('episodeid')
    ...

I've then messed around a bit to check if I could implement the feature I'm requesting myself xD and... I did manage to do it, like this:

  1. On getMeta() I'm calling a function to try and get the DBID:
    def getMeta(self, meta):
        try:
            if not meta or ('videodb' in control.infoLabel('ListItem.FolderPath')): raise Exception()
...
            #try to get kody library DBID
            self.DBID = self.getDBID(meta)
            return (poster, thumb, season_poster, fanart, banner, clearart, clearlogo, discart, meta)
...
  1. getDBID() is basically a copy/paste from the code within getMeta() used to assert DBID when play originates from videodb:
    def getDBID(self, meta):
        try:
            if self.media_type == 'movie':
                meta = control.jsonrpc('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": {"filter":{"or": [{"field": "year", "operator": "is", "value": "%s"}, {"field": "year", "operator": "is", "value": "%s"}, {"field": "year", "operator": "is", "value": "%s"}]}, "properties" : ["title", "originaltitle", "uniqueid", "year", "premiered", "genre", "studio", "country", "runtime", "rating", "votes", "mpaa", "director", "writer", "cast", "plot", "plotoutline", "tagline", "thumbnail", "art", "file"]}, "id": 1}' % (self.year, str(int(self.year) + 1), str(int(self.year) - 1)))
                meta = jsloads(meta)['result']['movies']
                try:
                    meta = [i for i in meta if (i.get('uniqueid', []).get('imdb', '') == self.imdb) or (i.get('uniqueid', []).get('unknown', '') == self.imdb)] # scraper now using "unknown"
                except:
                    if self.debuglog:
                        log_utils.log('Get Meta Failed in getMeta: %s' % str(meta), level=log_utils.LOGDEBUG)
                    meta = None
                if meta: meta = meta[0]
                else: raise Exception()
                return meta.get('movieid')
            if self.media_type == 'episode':
                show_meta = control.jsonrpc('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": {"filter":{"or": [{"field": "year", "operator": "is", "value": "%s"}, {"field": "year", "operator": "is", "value": "%s"}, {"field": "year", "operator": "is", "value": "%s"}]}, "properties" : ["title", "originaltitle", "uniqueid", "mpaa", "year", "genre", "runtime", "thumbnail", "file"]}, "id": 1}' % (self.year, str(int(self.year)+1), str(int(self.year)-1)))
                show_meta = jsloads(show_meta)['result']['tvshows']
                show_meta = [i for i in show_meta if i['uniqueid']['imdb'] == self.imdb]
                show_meta = [i for i in show_meta if (i.get('uniqueid', []).get('imdb', '') == self.imdb) or (i.get('uniqueid', []).get('unknown', '') == self.imdb)] # scraper now using "unknown"
                if show_meta: show_meta = show_meta[0]
                else: raise Exception()
                tvshowid = show_meta['tvshowid']
                meta = control.jsonrpc('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params":{"tvshowid": %d, "filter":{"and": [{"field": "season", "operator": "is", "value": "%s"}, {"field": "episode", "operator": "is", "value": "%s"}]}, "properties": ["showtitle", "title", "season", "episode", "firstaired", "runtime", "rating", "director", "writer", "cast", "plot", "thumbnail", "art", "file"]}, "id": 1}' % (tvshowid, self.season, self.episode))
                meta = jsloads(meta)['result']['episodes']
                if meta: meta = meta[0]
                else: raise Exception()
                return meta.get('episodeid')
        except:
            log_utils.error()
            return ''