From a12e07da6a2ca92fd838db8f241b7cb6cf65a747 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 24 Feb 2021 15:21:07 +0100 Subject: [PATCH 1/9] Fix rare TypeError: expected string or buffer on playback start --- resources/lib/kodimonitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py index 8580ec75..6807a38a 100644 --- a/resources/lib/kodimonitor.py +++ b/resources/lib/kodimonitor.py @@ -289,7 +289,7 @@ class KodiMonitor(xbmc.Monitor): LOG.debug('Detected different path') try: tmp_plex_id = int(utils.REGEX_PLEX_ID.findall(path)[0]) - except IndexError: + except (IndexError, TypeError): LOG.debug('No Plex id in path, need to init playqueue') initialize = True else: From 9150e168f633677c4b6349b8cfb470d8bd5ab35f Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 24 Feb 2021 17:20:37 +0100 Subject: [PATCH 2/9] Sync name and user rating of a TV show season to Kodi --- resources/lib/itemtypes/tvshows.py | 18 ++++++++++++++---- resources/lib/kodi_db/video.py | 23 ++++++++++++++++++++--- resources/lib/plex_api/base.py | 6 ++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/resources/lib/itemtypes/tvshows.py b/resources/lib/itemtypes/tvshows.py index 632d7f2c..d983f5ce 100644 --- a/resources/lib/itemtypes/tvshows.py +++ b/resources/lib/itemtypes/tvshows.py @@ -270,6 +270,7 @@ class Show(TvShowMixin, ItemBase): unique_ids.get('imdb', unique_ids.get('tmdb'))) + class Season(TvShowMixin, ItemBase): def add_update(self, xml, section_name=None, section_id=None, children=None): @@ -279,7 +280,7 @@ class Season(TvShowMixin, ItemBase): api = API(xml) if not self.sync_this_item(section_id or api.library_section_id()): LOG.debug('Skipping sync of %s %s: %s - section %s not synched to ' - 'Kodi', api.plex_type, api.plex_id, api.title(), + 'Kodi', api.plex_type, api.plex_id, api.season_name(), section_id or api.library_section_id()) return plex_id = api.plex_id @@ -317,15 +318,24 @@ class Season(TvShowMixin, ItemBase): if key in artwork and artwork[key] == parent_artwork[key]: del artwork[key] if update_item: - LOG.info('UPDATE season plex_id %s - %s', plex_id, api.title()) + LOG.info('UPDATE season plex_id %s - %s', + plex_id, api.season_name()) kodi_id = season['kodi_id'] + self.kodidb.update_season(kodi_id, + parent_id, + api.index(), + api.season_name(), + api.userrating() or None) if app.SYNC.artwork: self.kodidb.modify_artwork(artwork, kodi_id, v.KODI_TYPE_SEASON) else: - LOG.info('ADD season plex_id %s - %s', plex_id, api.title()) - kodi_id = self.kodidb.add_season(parent_id, api.index()) + LOG.info('ADD season plex_id %s - %s', plex_id, api.season_name()) + kodi_id = self.kodidb.add_season(parent_id, + api.index(), + api.season_name(), + api.userrating() or None) if app.SYNC.artwork: self.kodidb.add_artwork(artwork, kodi_id, diff --git a/resources/lib/kodi_db/video.py b/resources/lib/kodi_db/video.py index 2466e5e3..6a349150 100644 --- a/resources/lib/kodi_db/video.py +++ b/resources/lib/kodi_db/video.py @@ -718,15 +718,32 @@ class KodiVideoDB(common.KodiDBBase): self.cursor.execute('DELETE FROM sets WHERE idSet = ?', (set_id,)) @db.catch_operationalerrors - def add_season(self, showid, seasonnumber): + def add_season(self, showid, seasonnumber, name, userrating): """ Adds a TV show season to the Kodi video DB or simply returns the ID, if there already is an entry in the DB """ - self.cursor.execute('INSERT INTO seasons(idShow, season) VALUES (?, ?)', - (showid, seasonnumber)) + self.cursor.execute(''' + INSERT INTO seasons( + idShow, season, name, userrating) + VALUES (?, ?, ?, ?) + ''', (showid, seasonnumber, name, userrating)) return self.cursor.lastrowid + @db.catch_operationalerrors + def update_season(self, seasonid, showid, seasonnumber, name, userrating): + """ + Updates a TV show season with a certain seasonid + """ + self.cursor.execute(''' + UPDATE seasons + SET idShow = ?, + season = ?, + name = ?, + userrating = ? + WHERE idSeason = ? + ''', (showid, seasonnumber, name, userrating, seasonid)) + @db.catch_operationalerrors def add_uniqueid(self, *args): """ diff --git a/resources/lib/plex_api/base.py b/resources/lib/plex_api/base.py index 9a749a60..60a0739a 100644 --- a/resources/lib/plex_api/base.py +++ b/resources/lib/plex_api/base.py @@ -398,6 +398,12 @@ class Base(object): """ return self.parent_index() + def season_name(self): + """ + Returns the season's name/title or None + """ + return self.xml.get('title') + def artist_name(self): """ Returns the artist name for an album: first it attempts to return From 12587a985cf527986e16020c9ca8013f0df48c74 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 24 Feb 2021 17:38:30 +0100 Subject: [PATCH 3/9] Beta version bump 2.12.17 --- addon.xml | 8 ++++++-- changelog.txt | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/addon.xml b/addon.xml index cd9e1f46..6b170242 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -83,7 +83,11 @@ Natūralioji „Plex“ integracija į „Kodi“ Prijunkite „Kodi“ prie „Plex Medija Serverio“. Šiame papildinyje daroma prielaida, kad valdote visus savo vaizdo įrašus naudodami „Plex“ (ir nė vieno su „Kodi“). Galite prarasti jau saugomus „Kodi“ vaizdo įrašų ir muzikos duomenų bazių duomenis (kadangi šis papildinys juos tiesiogiai pakeičia). Naudokite savo pačių rizika! Naudokite savo pačių rizika - version 2.12.16: + version 2.12.17 (beta only): +- Sync name and user rating of a TV show season to Kodi +- Fix rare TypeError: expected string or buffer on playback start + +version 2.12.16: - versions 2.12.14 and 2.12.15 for everyone version 2.12.15 (beta only): diff --git a/changelog.txt b/changelog.txt index ff075196..bb26304f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +version 2.12.17 (beta only): +- Sync name and user rating of a TV show season to Kodi +- Fix rare TypeError: expected string or buffer on playback start + version 2.12.16: - versions 2.12.14 and 2.12.15 for everyone From f134266efcfca31501e99d36dc18b6dc3cd8c0b4 Mon Sep 17 00:00:00 2001 From: croneter Date: Mon, 1 Mar 2021 10:48:12 +0100 Subject: [PATCH 4/9] Improve logging for websocket JSON loads --- resources/lib/websocket_client.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/lib/websocket_client.py b/resources/lib/websocket_client.py index b0468617..f50bbbd0 100644 --- a/resources/lib/websocket_client.py +++ b/resources/lib/websocket_client.py @@ -177,9 +177,9 @@ class PMS_Websocket(WebSocket): try: message = loads(message) - except ValueError: - LOG.error('%s: Error decoding message from websocket', - self.__class__.__name__) + except ValueError as err: + LOG.error('%s: Error decoding message from websocket: %s', + self.__class__.__name__, err) LOG.error(message) return try: From bb7b2de44bf5a4d9cc82bedbdb2450489bed034a Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 7 Mar 2021 15:16:23 +0100 Subject: [PATCH 5/9] Sync recently watched items individually before synching every playstate --- resources/lib/library_sync/full_sync.py | 61 +++++++++++++++++++------ 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/resources/lib/library_sync/full_sync.py b/resources/lib/library_sync/full_sync.py index cdb85e30..75c5c69f 100644 --- a/resources/lib/library_sync/full_sync.py +++ b/resources/lib/library_sync/full_sync.py @@ -137,7 +137,7 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread): LOG.error('Could not entirely process section %s', section) self.successful = False - def threaded_get_generators(self, kinds, section_queue, all_items): + def threaded_get_generators(self, kinds, section_queue, items): """ Getting iterators is costly, so let's do it in a dedicated thread """ @@ -154,17 +154,28 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread): continue section = sections.get_sync_section(section, plex_type=kind[0]) - if self.repair or all_items: + timestamp = section.last_sync - UPDATED_AT_SAFETY \ + if section.last_sync else None + if items == 'all': updated_at = None - else: - updated_at = section.last_sync - UPDATED_AT_SAFETY \ - if section.last_sync else None + last_viewed_at = None + elif items == 'watched': + if not timestamp: + # No need to sync playstate updates since section + # has not yet been synched + continue + else: + updated_at = None + last_viewed_at = timestamp + elif items == 'updated': + updated_at = timestamp + last_viewed_at = None try: section.iterator = PF.get_section_iterator( section.section_id, plex_type=section.plex_type, updated_at=updated_at, - last_viewed_at=None) + last_viewed_at=last_viewed_at) except RuntimeError: LOG.error('Sync at least partially unsuccessful!') LOG.error('Error getting section iterator %s', section) @@ -195,19 +206,42 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread): (v.PLEX_TYPE_ARTIST, v.PLEX_TYPE_ARTIST), (v.PLEX_TYPE_ALBUM, v.PLEX_TYPE_ARTIST), ]) + # ADD NEW ITEMS # We need to enforce syncing e.g. show before season before episode bg.FunctionAsTask(self.threaded_get_generators, None, - kinds, section_queue, False).start() + kinds, + section_queue, + items='all' if self.repair else 'updated').start() # Do the heavy lifting self.process_new_and_changed_items(section_queue, processing_queue) common.update_kodi_library(video=True, music=True) if self.should_cancel() or not self.successful: return + # In order to not delete all your songs again for playstate synch + if app.SYNC.enable_music: + kinds.extend([ + (v.PLEX_TYPE_SONG, v.PLEX_TYPE_ARTIST), + ]) + + # Update playstate progress since last sync - especially useful for + # users of very large libraries since this step is very fast + # These playstates will be synched twice + LOG.debug('Start synching playstate for last watched items') + bg.FunctionAsTask(self.threaded_get_generators, + None, + kinds, + section_queue, + items='watched').start() + self.processing_loop_playstates(section_queue) + if self.should_cancel() or not self.successful: + return + # Sync Plex playlists to Kodi and vice-versa if common.PLAYLIST_SYNC_ENABLED: + LOG.debug('Start playlist sync') if self.show_dialog: if self.dialog: self.dialog.close() @@ -218,14 +252,9 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread): return # SYNC PLAYSTATE of ALL items (otherwise we won't pick up on items that - # were set to unwatched). Also mark all items on the PMS to be able - # to delete the ones still in Kodi + # were set to unwatched or changed user ratings). Also mark all items on + # the PMS to be able to delete the ones still in Kodi LOG.debug('Start synching playstate and userdata for every item') - if app.SYNC.enable_music: - # In order to not delete all your songs again - kinds.extend([ - (v.PLEX_TYPE_SONG, v.PLEX_TYPE_ARTIST), - ]) # Make sure we're not showing an item's title in the sync dialog if not self.show_dialog_userdata and self.dialog: # Close the progress indicator dialog @@ -233,7 +262,9 @@ class FullSync(common.LibrarySyncMixin, bg.KillableThread): self.dialog = None bg.FunctionAsTask(self.threaded_get_generators, None, - kinds, section_queue, True).start() + kinds, + section_queue, + items='all').start() self.processing_loop_playstates(section_queue) if self.should_cancel() or not self.successful: return From 1885d3fc947a2666653ebe45ed4e1e048d437e4a Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 7 Mar 2021 17:17:37 +0100 Subject: [PATCH 6/9] Beta version bump 2.12.18 --- addon.xml | 8 ++++++-- changelog.txt | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/addon.xml b/addon.xml index 6b170242..033c321c 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -83,7 +83,11 @@ Natūralioji „Plex“ integracija į „Kodi“ Prijunkite „Kodi“ prie „Plex Medija Serverio“. Šiame papildinyje daroma prielaida, kad valdote visus savo vaizdo įrašus naudodami „Plex“ (ir nė vieno su „Kodi“). Galite prarasti jau saugomus „Kodi“ vaizdo įrašų ir muzikos duomenų bazių duomenis (kadangi šis papildinys juos tiesiogiai pakeičia). Naudokite savo pačių rizika! Naudokite savo pačių rizika - version 2.12.17 (beta only): + version 2.12.18 (beta only): +- Quickly sync recently watched items before synching the playstates of the entire Plex library +- Improve logging for websocket JSON loads + +version 2.12.17 (beta only): - Sync name and user rating of a TV show season to Kodi - Fix rare TypeError: expected string or buffer on playback start diff --git a/changelog.txt b/changelog.txt index bb26304f..0af460f2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +version 2.12.18 (beta only): +- Quickly sync recently watched items before synching the playstates of the entire Plex library +- Improve logging for websocket JSON loads + version 2.12.17 (beta only): - Sync name and user rating of a TV show season to Kodi - Fix rare TypeError: expected string or buffer on playback start From f6c2a7c08f786f430d763e71bfde0736f9bb7fef Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 14 Mar 2021 14:18:02 +0100 Subject: [PATCH 7/9] Beta and stable version bump 2.12.19 --- addon.xml | 8 ++++++-- changelog.txt | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/addon.xml b/addon.xml index 033c321c..688b82c2 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -83,7 +83,11 @@ Natūralioji „Plex“ integracija į „Kodi“ Prijunkite „Kodi“ prie „Plex Medija Serverio“. Šiame papildinyje daroma prielaida, kad valdote visus savo vaizdo įrašus naudodami „Plex“ (ir nė vieno su „Kodi“). Galite prarasti jau saugomus „Kodi“ vaizdo įrašų ir muzikos duomenų bazių duomenis (kadangi šis papildinys juos tiesiogiai pakeičia). Naudokite savo pačių rizika! Naudokite savo pačių rizika - version 2.12.18 (beta only): + version 2.12.19: +- 2.12.17 and 2.12.18 for everyone +- Rename skip intro skin file + +version 2.12.18 (beta only): - Quickly sync recently watched items before synching the playstates of the entire Plex library - Improve logging for websocket JSON loads diff --git a/changelog.txt b/changelog.txt index 0af460f2..41f3ceb0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +version 2.12.19: +- 2.12.17 and 2.12.18 for everyone +- Rename skip intro skin file + version 2.12.18 (beta only): - Quickly sync recently watched items before synching the playstates of the entire Plex library - Improve logging for websocket JSON loads From 886d2e5df78458f7f1091b956ad9f36606588aae Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 14 Mar 2021 12:55:51 +0100 Subject: [PATCH 8/9] Rename skip intro skin file --- resources/lib/skip_plex_intro.py | 2 +- .../1080i/{skip_intro.xml => script-plex-skip_intro.xml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename resources/skins/default/1080i/{skip_intro.xml => script-plex-skip_intro.xml} (100%) diff --git a/resources/lib/skip_plex_intro.py b/resources/lib/skip_plex_intro.py index ada9e1b9..b82f6dae 100644 --- a/resources/lib/skip_plex_intro.py +++ b/resources/lib/skip_plex_intro.py @@ -16,7 +16,7 @@ def skip_intro(intros): if start <= progress < end: in_intro = True if in_intro and app.APP.skip_intro_dialog is None: - app.APP.skip_intro_dialog = SkipIntroDialog('skip_intro.xml', + app.APP.skip_intro_dialog = SkipIntroDialog('script-plex-skip_intro.xml', v.ADDON_PATH, 'default', '1080i', diff --git a/resources/skins/default/1080i/skip_intro.xml b/resources/skins/default/1080i/script-plex-skip_intro.xml similarity index 100% rename from resources/skins/default/1080i/skip_intro.xml rename to resources/skins/default/1080i/script-plex-skip_intro.xml From 0a1edcd24a4061ec9bfed42e391274b71487c9cf Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 14 Mar 2021 14:25:27 +0100 Subject: [PATCH 9/9] Update readme --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 10d7f274..89d53c56 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ [![Kodi Leia stable version](https://img.shields.io/badge/Kodi_Leia_STABLE-latest-blue.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Leia.STABLE.zip) [![Kodi Leia beta version](https://img.shields.io/badge/Kodi_Leia_BETA-latest-red.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Leia.BETA.zip) +[![Kodi Matrix stable version](https://img.shields.io/badge/Kodi_Matrix_STABLE-latest-blue.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Matrix.STABLE.zip) [![Kodi Matrix beta version](https://img.shields.io/badge/Kodi_Matrix_BETA-latest-red.svg?maxAge=60&style=flat) ](https://croneter.github.io/pkc-source/repository.plexkodiconnect.Kodi-Matrix.BETA.zip) - [![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation) [![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq) [![Forum](https://img.shields.io/badge/forum-plex-orange.svg?maxAge=60&style=flat)](https://forums.plex.tv/discussion/210023/plexkodiconnect-let-kodi-talk-to-your-plex) @@ -39,11 +39,7 @@ Unfortunately, the PKC Kodi repository had to move because it stopped working (t ### Download and Installation -Install PKC via the PlexKodiConnect Kodi repository download button just below (do NOT use the standard GitHub download!). Alternatively, add [https://croneter.github.io/pkc-source](https://croneter.github.io/pkc-source) as a new Kodi `Web server directory (HTTPS)` source. See the [github wiki installation manual](https://github.com/croneter/PlexKodiConnect/wiki/Installation) for a detailed guide. Please use the stable version except if you really know what you're doing. Kodi will update PKC automatically. - -| Stable version | Beta version | -|----------------|--------------| -| [![stable version](https://img.shields.io/badge/stable_version-latest-blue.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/stable/repository.plexkodiconnect/repository.plexkodiconnect-1.0.2.zip) | [![beta version](https://img.shields.io/badge/beta_version-latest-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip) | +Using the Kodi file manager, add [https://croneter.github.io/pkc-source](https://croneter.github.io/pkc-source) as a new Kodi `Web server directory (HTTPS)` source, then install the PlexKodiConnect repository from this new source "from ZIP file". See the [github wiki installation manual](https://github.com/croneter/PlexKodiConnect/wiki/Installation) for a detailed guide. Kodi will update PKC automatically. ### Warning Use at your own risk! This plugin assumes that you manage all your videos with Plex (and none with Kodi). You might lose data already stored in the Kodi video and music databases as this plugin directly changes them. Don't worry if you want Plex to manage all your media (like you should ;-)).