From ca64d54b4eb1a9af0fb4b351a37f7e5d982830b5 Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 1 Nov 2020 16:10:44 +0100 Subject: [PATCH 01/14] Fix freeze: Don't assign multiple sets/collections for a specific movie --- resources/lib/itemtypes/movies.py | 73 +++++++++++++++++-------------- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/resources/lib/itemtypes/movies.py b/resources/lib/itemtypes/movies.py index 1c17f395..67836312 100644 --- a/resources/lib/itemtypes/movies.py +++ b/resources/lib/itemtypes/movies.py @@ -140,39 +140,7 @@ class Movie(ItemBase): self.kodidb.modify_streams(file_id, api.mediastreams(), api.runtime()) self.kodidb.modify_studios(kodi_id, v.KODI_TYPE_MOVIE, api.studios()) tags = [section_name] - if api.collections(): - for plex_set_id, set_name in api.collections(): - set_api = None - tags.append(set_name) - # Add any sets from Plex collection tags - kodi_set_id = self.kodidb.create_collection(set_name) - self.kodidb.assign_collection(kodi_set_id, kodi_id) - if not app.SYNC.artwork: - # Rest below is to get collection artwork - continue - if children is None: - # e.g. when added via websocket - LOG.debug('Costly looking up Plex collection %s: %s', - plex_set_id, set_name) - for index, coll_plex_id in api.collections_match(section_id): - # Get Plex artwork for collections - a pain - if index == plex_set_id: - set_xml = PF.GetPlexMetadata(coll_plex_id) - try: - set_xml.attrib - except AttributeError: - LOG.error('Could not get set metadata %s', - coll_plex_id) - continue - set_api = API(set_xml[0]) - break - elif plex_set_id in children: - # Provided by get_metadata thread - set_api = API(children[plex_set_id][0]) - if set_api: - self.kodidb.modify_artwork(set_api.artwork(), - kodi_set_id, - v.KODI_TYPE_SET) + self._process_collections(api, tags, kodi_id, section_id, children) self.kodidb.modify_tags(kodi_id, v.KODI_TYPE_MOVIE, tags) # Process playstate self.kodidb.set_resume(file_id, @@ -246,3 +214,42 @@ class Movie(ItemBase): db_item['kodi_type'], api.userrating()) return True + + def _process_collections(self, api, tags, kodi_id, section_id, children): + for plex_set_id, set_name in api.collections(): + set_api = None + tags.append(set_name) + # Add any sets from Plex collection tags + kodi_set_id = self.kodidb.create_collection(set_name) + self.kodidb.assign_collection(kodi_set_id, kodi_id) + if not app.SYNC.artwork: + # Rest below is to get collection artwork + # TODO: continue instead of break (see TODO/break below) + break + if children is None: + # e.g. when added via websocket + LOG.debug('Costly looking up Plex collection %s: %s', + plex_set_id, set_name) + for index, coll_plex_id in api.collections_match(section_id): + # Get Plex artwork for collections - a pain + if index == plex_set_id: + set_xml = PF.GetPlexMetadata(coll_plex_id) + try: + set_xml.attrib + except AttributeError: + LOG.error('Could not get set metadata %s', + coll_plex_id) + continue + set_api = API(set_xml[0]) + break + elif plex_set_id in children: + # Provided by get_metadata thread + set_api = API(children[plex_set_id][0]) + if set_api: + self.kodidb.modify_artwork(set_api.artwork(), + kodi_set_id, + v.KODI_TYPE_SET) + # TODO: Once Kodi (19?) supports SEVERAL sets/collections per + # movie, support that. For now, we only take the very first + # collection/set that Plex returns + break From 5d67d4a602079247bdce8fb54e5222fa3abd092a Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 5 Nov 2020 15:47:04 +0100 Subject: [PATCH 02/14] Support metadata provider ids (e.g. IMDB) for new Plex Movie Agent --- resources/lib/itemtypes/common.py | 24 +++++++++ resources/lib/itemtypes/movies.py | 41 ++++++-------- resources/lib/itemtypes/tvshows.py | 85 +++++++++++------------------- resources/lib/plex_api/artwork.py | 4 +- resources/lib/plex_api/base.py | 54 +++++++++---------- resources/lib/widgets.py | 5 +- 6 files changed, 102 insertions(+), 111 deletions(-) diff --git a/resources/lib/itemtypes/common.py b/resources/lib/itemtypes/common.py index 3188a112..e2d9323f 100644 --- a/resources/lib/itemtypes/common.py +++ b/resources/lib/itemtypes/common.py @@ -145,3 +145,27 @@ class ItemBase(object): encountered by PKC """ return section_id in app.SYNC.section_ids + + def update_provider_ids(self, api, kodi_id): + """ + Updates the unique metadata provider ids (such as the IMDB id). Returns + a dict of the Kodi unique ids + """ + # We might have an old provider id stored! + self.kodidb.remove_uniqueid(kodi_id, api.kodi_type) + return self.add_provider_ids(api, kodi_id) + + def add_provider_ids(self, api, kodi_id): + """ + Adds the unique ids for all metadata providers to the Kodi database, + such as IMDB or The Movie Database TMDB. + Returns a dict of the Kodi ids: {: } + """ + kodi_unique_ids = api.guids.copy() + for provider, provider_id in api.guids.iteritems(): + kodi_unique_ids[provider] = self.kodidb.add_uniqueid( + kodi_id, + api.kodi_type, + provider_id, + provider) + return kodi_unique_ids diff --git a/resources/lib/itemtypes/movies.py b/resources/lib/itemtypes/movies.py index 1c17f395..0d3f7cc5 100644 --- a/resources/lib/itemtypes/movies.py +++ b/resources/lib/itemtypes/movies.py @@ -56,19 +56,7 @@ class Movie(ItemBase): "default", api.rating(), api.votecount()) - if api.provider('imdb') is not None: - uniqueid = self.kodidb.update_uniqueid(kodi_id, - v.KODI_TYPE_MOVIE, - 'imdb', - api.provider('imdb')) - elif api.provider('tmdb') is not None: - uniqueid = self.kodidb.update_uniqueid(kodi_id, - v.KODI_TYPE_MOVIE, - 'tmdb', - api.provider('tmdb')) - else: - self.kodidb.remove_uniqueid(kodi_id, v.KODI_TYPE_MOVIE) - uniqueid = -1 + unique_id = self.update_provider_ids(api, kodi_id) self.kodidb.modify_people(kodi_id, v.KODI_TYPE_MOVIE, api.people()) @@ -86,18 +74,7 @@ class Movie(ItemBase): "default", api.rating(), api.votecount()) - if api.provider('imdb') is not None: - uniqueid = self.kodidb.add_uniqueid(kodi_id, - v.KODI_TYPE_MOVIE, - api.provider('imdb'), - "imdb") - elif api.provider('tmdb') is not None: - uniqueid = self.kodidb.add_uniqueid(kodi_id, - v.KODI_TYPE_MOVIE, - api.provider('tmdb'), - "tmdb") - else: - uniqueid = -1 + unique_id = self.add_provider_ids(api, kodi_id) self.kodidb.add_people(kodi_id, v.KODI_TYPE_MOVIE, api.people()) @@ -106,6 +83,8 @@ class Movie(ItemBase): kodi_id, v.KODI_TYPE_MOVIE) + unique_id = self._prioritize_provider_id(unique_id) + # Update Kodi's main entry self.kodidb.add_movie(kodi_id, file_id, @@ -117,7 +96,7 @@ class Movie(ItemBase): rating_id, api.list_to_string(api.writers()), api.year(), - uniqueid, + unique_id, api.sorttitle(), api.runtime(), api.content_rating(), @@ -246,3 +225,13 @@ class Movie(ItemBase): db_item['kodi_type'], api.userrating()) return True + + @staticmethod + def _prioritize_provider_id(unique_ids): + """ + Prioritize which ID ends up in the SHOW table (there can only be 1) + tvdb > imdb > tmdb + """ + return unique_ids.get('imdb', + unique_ids.get('tmdb', + unique_ids.get('tvdb'))) diff --git a/resources/lib/itemtypes/tvshows.py b/resources/lib/itemtypes/tvshows.py index f1b6ca46..632d7f2c 100644 --- a/resources/lib/itemtypes/tvshows.py +++ b/resources/lib/itemtypes/tvshows.py @@ -194,19 +194,8 @@ class Show(TvShowMixin, ItemBase): "default", api.rating(), api.votecount()) - if api.provider('tvdb') is not None: - uniqueid = self.kodidb.update_uniqueid(kodi_id, - v.KODI_TYPE_SHOW, - 'tvdb', - api.provider('tvdb')) - elif api.provider('tmdb') is not None: - uniqueid = self.kodidb.update_uniqueid(kodi_id, - v.KODI_TYPE_SHOW, - 'tmdb', - api.provider('tmdb')) - else: - self.kodidb.remove_uniqueid(kodi_id, v.KODI_TYPE_SHOW) - uniqueid = -1 + unique_id = self._prioritize_provider_id( + self.update_provider_ids(api, kodi_id)) self.kodidb.modify_people(kodi_id, v.KODI_TYPE_SHOW, api.people()) @@ -221,7 +210,7 @@ class Show(TvShowMixin, ItemBase): api.premiere_date(), api.list_to_string(api.genres()), api.title(), - uniqueid, + unique_id, api.content_rating(), api.list_to_string(api.studios()), api.sorttitle(), @@ -236,18 +225,8 @@ class Show(TvShowMixin, ItemBase): "default", api.rating(), api.votecount()) - if api.provider('tvdb'): - uniqueid = self.kodidb.add_uniqueid(kodi_id, - v.KODI_TYPE_SHOW, - api.provider('tvdb'), - 'tvdb') - if api.provider('tmdb'): - uniqueid = self.kodidb.add_uniqueid(kodi_id, - v.KODI_TYPE_SHOW, - api.provider('tmdb'), - 'tmdb') - else: - uniqueid = -1 + unique_id = self._prioritize_provider_id( + self.add_provider_ids(api, kodi_id)) self.kodidb.add_people(kodi_id, v.KODI_TYPE_SHOW, api.people()) @@ -263,7 +242,7 @@ class Show(TvShowMixin, ItemBase): api.premiere_date(), api.list_to_string(api.genres()), api.title(), - uniqueid, + unique_id, api.content_rating(), api.list_to_string(api.studios()), api.sorttitle()) @@ -281,6 +260,15 @@ class Show(TvShowMixin, ItemBase): kodi_pathid=kodi_pathid, last_sync=self.last_sync) + @staticmethod + def _prioritize_provider_id(unique_ids): + """ + Prioritize which ID ends up in the SHOW table (there can only be 1) + tvdb > imdb > tmdb + """ + return unique_ids.get('tvdb', + unique_ids.get('imdb', + unique_ids.get('tmdb'))) class Season(TvShowMixin, ItemBase): def add_update(self, xml, section_name=None, section_id=None, @@ -459,19 +447,8 @@ class Episode(TvShowMixin, ItemBase): "default", api.rating(), api.votecount()) - if api.provider('tvdb'): - uniqueid = self.kodidb.update_uniqueid(kodi_id, - v.KODI_TYPE_EPISODE, - 'tvdb', - api.provider('tvdb')) - elif api.provider('tmdb'): - uniqueid = self.kodidb.update_uniqueid(kodi_id, - v.KODI_TYPE_EPISODE, - 'tmdb', - api.provider('tmdb')) - else: - self.kodidb.remove_uniqueid(kodi_id, v.KODI_TYPE_EPISODE) - uniqueid = -1 + unique_id = self._prioritize_provider_id( + self.update_provider_ids(api, kodi_id)) self.kodidb.modify_people(kodi_id, v.KODI_TYPE_EPISODE, api.people()) @@ -493,7 +470,7 @@ class Episode(TvShowMixin, ItemBase): airs_before_episode, fullpath, kodi_pathid, - uniqueid, + unique_id, kodi_fileid, # and NOT kodi_fileid_2 parent_id, api.userrating(), @@ -539,18 +516,8 @@ class Episode(TvShowMixin, ItemBase): "default", api.rating(), api.votecount()) - if api.provider('tvdb'): - uniqueid = self.kodidb.add_uniqueid(kodi_id, - v.KODI_TYPE_EPISODE, - api.provider('tvdb'), - "tvdb") - elif api.provider('tmdb'): - uniqueid = self.kodidb.add_uniqueid(kodi_id, - v.KODI_TYPE_EPISODE, - api.provider('tmdb'), - "tmdb") - else: - uniqueid = -1 + unique_id = self._prioritize_provider_id( + self.add_provider_ids(api, kodi_id)) self.kodidb.add_people(kodi_id, v.KODI_TYPE_EPISODE, api.people()) @@ -575,7 +542,7 @@ class Episode(TvShowMixin, ItemBase): airs_before_episode, fullpath, kodi_pathid, - uniqueid, + unique_id, parent_id, api.userrating()) self.kodidb.set_resume(kodi_fileid, @@ -605,3 +572,13 @@ class Episode(TvShowMixin, ItemBase): self.kodidb.modify_streams(kodi_fileid, # and NOT kodi_fileid_2 api.mediastreams(), api.runtime()) + + @staticmethod + def _prioritize_provider_id(unique_ids): + """ + Prioritize which ID ends up in the SHOW table (there can only be 1) + tvdb > imdb > tmdb + """ + return unique_ids.get('tvdb', + unique_ids.get('imdb', + unique_ids.get('tmdb'))) diff --git a/resources/lib/plex_api/artwork.py b/resources/lib/plex_api/artwork.py index c5f3d62d..a44be6f3 100644 --- a/resources/lib/plex_api/artwork.py +++ b/resources/lib/plex_api/artwork.py @@ -186,9 +186,9 @@ class Artwork(object): # Always seek collection's ids since not provided by PMS if collection is False: if media_type == v.PLEX_TYPE_MOVIE: - media_id = self.provider('imdb') + media_id = self.guids.get('imdb') elif media_type == v.PLEX_TYPE_SHOW: - media_id = self.provider('tvdb') + media_id = self.guids.get('tvdb') if media_id is not None: return media_id, None, None LOG.info('Plex did not provide ID for IMDB or TVDB. Start ' diff --git a/resources/lib/plex_api/base.py b/resources/lib/plex_api/base.py index ef98f83f..f20178e7 100644 --- a/resources/lib/plex_api/base.py +++ b/resources/lib/plex_api/base.py @@ -13,6 +13,9 @@ from .. import widgets LOG = getLogger('PLEX.api') +METADATA_PROVIDERS = (('imdb', utils.REGEX_IMDB), + ('tvdb', utils.REGEX_TVDB), + ('tmdb', utils.REGEX_TMDB)) class Base(object): """ @@ -40,6 +43,7 @@ class Base(object): self._writers = [] self._producers = [] self._locations = [] + self._guids = {} self._coll_match = None # Plex DB attributes self._section_id = None @@ -131,6 +135,11 @@ class Base(object): self.check_db() return self._fanart_synced + @property + def guids(self): + self._scan_children() + return self._guids + def check_db(self, plexdb=None): """ Check's whether we synched this item to Kodi. If so, then retrieve the @@ -457,6 +466,24 @@ class Base(object): elif child.tag == 'Collection': self._collections.append((cast(int, child.get('id')), child.get('tag'))) + elif child.tag == 'Guid': + guid = child.get('id') + guid = guid.split('://', 1) + self._guids[guid[0]] = guid[1] + # Plex Movie agent (legacy) or "normal" Plex tv show agent + if not self._guids: + guid = self.xml.get('guid') + if not guid: + return + for provider, regex in METADATA_PROVIDERS: + provider_id = regex.findall(guid) + try: + self._guids[provider] = provider_id[0] + except IndexError: + pass + else: + # There will only ever be one entry + break def cast(self): """ @@ -544,33 +571,6 @@ class Base(object): 'writer': [(x, ) for x in self._writers] } - def provider(self, providername=None): - """ - providername: e.g. 'imdb', 'tvdb' - - Return IMDB, e.g. "tt0903624". Returns None if not found - """ - item = self.xml.get('guid') - if not item: - return - if providername == 'imdb': - regex = utils.REGEX_IMDB - elif providername == 'tvdb': - # originally e.g. com.plexapp.agents.thetvdb://276564?lang=en - regex = utils.REGEX_TVDB - elif providername == 'tmdb': - # originally e.g. com.plexapp.agents.themoviedb://603?lang=en - regex = utils.REGEX_TMDB - else: - raise NotImplementedError('Not implemented: %s' % providername) - - provider = regex.findall(item) - try: - provider = provider[0] - except IndexError: - provider = None - return provider - def extras(self): """ Returns an iterator for etree elements for each extra, e.g. trailers diff --git a/resources/lib/widgets.py b/resources/lib/widgets.py index 0252de12..80805f00 100644 --- a/resources/lib/widgets.py +++ b/resources/lib/widgets.py @@ -168,8 +168,9 @@ def _generate_content(api): 'trailer': api.trailer(), 'tvshowtitle': api.show_title(), 'uniqueid': { - 'imdbnumber': api.provider('imdb') or '', - 'tvdb_id': api.provider('tvdb') or '' + 'imdbnumber': api.guids.get('imdb') or '', + 'tvdb_id': api.guids.get('tvdb') or '', + 'tmdb_id': api.guids.get('tmdb') or '' }, 'votes': '0', # [str]! 'writer': api.writers(), # list of [str] From 3f1f41f5b64fd37ec72583052dd5bf89d484b9b5 Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 5 Nov 2020 16:05:58 +0100 Subject: [PATCH 03/14] Beta version bump 2.12.4 --- README.md | 2 +- addon.xml | 8 ++++++-- changelog.txt | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5674063e..1a272e61 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![stable version](https://img.shields.io/badge/stable_version-2.12.3-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-2.12.3-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip) +[![beta version](https://img.shields.io/badge/beta_version-2.12.4-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.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) diff --git a/addon.xml b/addon.xml index 2ebc9724..6c740b56 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.3: + version 2.12.4 (beta only): +- Hopefully fix freeze during sync: Don't assign multiple sets/collections for a specific movie +- Support metadata provider ids (e.g. for IMDB) for the new Plex Movie Agent + +version 2.12.3: - Fix playback failing due to caching of subtitles with non-ascii chars - Fix ValueError: invalid literal for int() with base 10 during show sync - Fix UnboundLocalError when certain Plex sections are deleted or being un-synched diff --git a/changelog.txt b/changelog.txt index 85efdfe0..4be12d87 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +version 2.12.4 (beta only): +- Hopefully fix freeze during sync: Don't assign multiple sets/collections for a specific movie +- Support metadata provider ids (e.g. for IMDB) for the new Plex Movie Agent + version 2.12.3: - Fix playback failing due to caching of subtitles with non-ascii chars - Fix ValueError: invalid literal for int() with base 10 during show sync From e551a9451aae5430ee1c41842708c57c6cac22f2 Mon Sep 17 00:00:00 2001 From: croneter Date: Fri, 6 Nov 2020 15:57:24 +0100 Subject: [PATCH 04/14] Fix TypeError when canceling Plex sync section dialog --- resources/lib/library_sync/sections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lib/library_sync/sections.py b/resources/lib/library_sync/sections.py index 46af7e24..04acbbad 100644 --- a/resources/lib/library_sync/sections.py +++ b/resources/lib/library_sync/sections.py @@ -578,7 +578,7 @@ def _choose_libraries(sections): selectable_sections, preselect=preselected, useDetails=False) - if selectable_sections is None: + if selected_sections is None: LOG.info('User chose not to select which libraries to sync') return False index = 0 From 4c2fe6dd59eecbf9392548bbf6ca0df4a98f5c45 Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 17 Dec 2020 16:59:19 +0100 Subject: [PATCH 05/14] Fix rare playback progress report failing and KeyError: u'containerKey' --- resources/lib/plex_companion.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/resources/lib/plex_companion.py b/resources/lib/plex_companion.py index ad9ae747..e0cbb807 100644 --- a/resources/lib/plex_companion.py +++ b/resources/lib/plex_companion.py @@ -92,6 +92,9 @@ class PlexCompanion(backgroundthread.KillableThread): @staticmethod def _process_alexa(data): + if 'key' not in data or 'containerKey' not in data: + LOG.error('Received malformed Alexa data: %s', data) + return xml = PF.GetPlexMetadata(data['key']) try: xml[0].attrib @@ -147,6 +150,9 @@ class PlexCompanion(backgroundthread.KillableThread): @staticmethod def _process_playlist(data): + if 'containerKey' not in data: + LOG.error('Received malformed playlist data: %s', data) + return # Get the playqueue ID _, container_key, query = PF.ParseContainerKey(data['containerKey']) try: @@ -179,6 +185,9 @@ class PlexCompanion(backgroundthread.KillableThread): """ Plex Companion client adjusted audio or subtitle stream """ + if 'type' not in data: + LOG.error('Received malformed stream data: %s', data) + return playqueue = PQ.get_playqueue_from_type( v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[data['type']]) pos = js.get_position(playqueue.playlistid) @@ -201,6 +210,9 @@ class PlexCompanion(backgroundthread.KillableThread): """ example data: {'playQueueID': '8475', 'commandID': '11'} """ + if 'playQueueID' not in data: + LOG.error('Received malformed refresh data: %s', data) + return xml = PL.get_pms_playqueue(data['playQueueID']) if xml is None: return From 71ebdc1e9074ae618adab05be143529f0fce2cb0 Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 17 Dec 2020 17:05:24 +0100 Subject: [PATCH 06/14] Fix high transcoding resolutions not being available for Win10 --- resources/lib/playback_decision.py | 18 ++++++++---------- resources/settings.xml | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/resources/lib/playback_decision.py b/resources/lib/playback_decision.py index 9fe5ed8e..d2e498a5 100644 --- a/resources/lib/playback_decision.py +++ b/resources/lib/playback_decision.py @@ -265,19 +265,17 @@ def get_resolution(): """ chosen = utils.settings('transcoderVideoQualities') res = { - '0': '420x420', - '1': '576x320', - '2': '720x480', - '3': '1024x768', - '4': '1280x720', - '5': '1280x720', + '0': '720x480', + '1': '1024x768', + '2': '1280x720', + '3': '1280x720', + '4': '1920x1080', + '5': '1920x1080', '6': '1920x1080', '7': '1920x1080', '8': '1920x1080', - '9': '1920x1080', - '10': '1920x1080', - '11': '3840x2160', - '12': '3840x2160' + '9': '3840x2160', + '10': '3840x2160' } return res[chosen] diff --git a/resources/settings.xml b/resources/settings.xml index a8b0cb76..5b143128 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -112,7 +112,7 @@ - + From 1207ab485cf4b4761900808188f68885f3b9c7c3 Mon Sep 17 00:00:00 2001 From: croneter Date: Thu, 17 Dec 2020 17:33:55 +0100 Subject: [PATCH 07/14] Fix rare KeyError: None when trying to sync the playlist --- resources/lib/playlists/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resources/lib/playlists/__init__.py b/resources/lib/playlists/__init__.py index 1e2ff6bc..5e612a4c 100644 --- a/resources/lib/playlists/__init__.py +++ b/resources/lib/playlists/__init__.py @@ -357,6 +357,10 @@ def sync_plex_playlist(playlist=None, xml=None, plex_id=None): if api.playlist_type() == v.PLEX_TYPE_PHOTO_PLAYLIST: # Not supported by Kodi return False + elif api.playlist_type() is None: + # Encountered in logs, seems to be a malformed answer + LOG.error('Playlist type is missing: %s', api.xml.attrib) + return False name = api.title() typus = v.KODI_PLAYLIST_TYPE_FROM_PLEX[api.playlist_type()] if (not app.SYNC.enable_music and typus == v.PLEX_PLAYLIST_TYPE_AUDIO): From c753d97d3f89bef71b5d33a87384cb642b71228d Mon Sep 17 00:00:00 2001 From: croneter Date: Fri, 18 Dec 2020 15:35:20 +0100 Subject: [PATCH 08/14] Greatly improve matching logic for tmdb if Plex does not provide id --- resources/lib/plex_api/artwork.py | 155 +------------------- resources/lib/plex_api/fanart_lookup.py | 182 ++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 149 deletions(-) create mode 100644 resources/lib/plex_api/fanart_lookup.py diff --git a/resources/lib/plex_api/artwork.py b/resources/lib/plex_api/artwork.py index a44be6f3..632d4355 100644 --- a/resources/lib/plex_api/artwork.py +++ b/resources/lib/plex_api/artwork.py @@ -2,12 +2,13 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, unicode_literals from logging import getLogger -from re import sub from ..kodi_db import KodiVideoDB, KodiMusicDB from ..downloadutils import DownloadUtils as DU from .. import utils, variables as v, app +from . import fanart_lookup + LOG = getLogger('PLEX.api') @@ -196,154 +197,10 @@ class Artwork(object): else: LOG.debug('Start movie set/collection lookup on themoviedb with %s', item.get('title', '')) - - api_key = utils.settings('themoviedbAPIKey') - if media_type == v.PLEX_TYPE_SHOW: - media_type = 'tv' - title = self.title() - # if the title has the year in remove it as tmdb cannot deal with it... - # replace e.g. 'The Americans (2015)' with 'The Americans' - title = sub(r'\s*\(\d{4}\)$', '', title, count=1) - url = 'https://api.themoviedb.org/3/search/%s' % media_type - parameters = { - 'api_key': api_key, - 'language': v.KODILANGUAGE, - 'query': title.encode('utf-8') - } - data = DU().downloadUrl(url, - authenticate=False, - parameters=parameters, - timeout=7) - try: - data.get('test') - except AttributeError: - LOG.warning('Could not download data from FanartTV') - return - if not data.get('results'): - LOG.info('No match found on themoviedb for type: %s, title: %s', - media_type, title) - return - - year = item.get('year') - match_found = None - # find year match - if year: - for entry in data['results']: - if year in entry.get('first_air_date', ''): - match_found = entry - break - elif year in entry.get('release_date', ''): - match_found = entry - break - # find exact match based on title, if we haven't found a year match - if match_found is None: - LOG.info('No themoviedb match found using year %s', year) - replacements = ( - ' ', - '-', - '&', - ',', - ':', - ';' - ) - for entry in data['results']: - name = entry.get('name', entry.get('title', '')) - original_name = entry.get('original_name', '') - title_alt = title.lower() - name_alt = name.lower() - org_name_alt = original_name.lower() - for replace_string in replacements: - title_alt = title_alt.replace(replace_string, '') - name_alt = name_alt.replace(replace_string, '') - org_name_alt = org_name_alt.replace(replace_string, '') - if name == title or original_name == title: - # match found for exact title name - match_found = entry - break - elif (name.split(' (')[0] == title or title_alt == name_alt or - title_alt == org_name_alt): - # match found with substituting some stuff - match_found = entry - break - - # if a match was not found, we accept the closest match from TMDB - if match_found is None and data.get('results'): - LOG.info('Using very first match from themoviedb') - match_found = entry = data.get('results')[0] - - if match_found is None: - LOG.info('Still no themoviedb match for type: %s, title: %s, ' - 'year: %s', media_type, title, year) - LOG.debug('themoviedb answer was %s', data['results']) - return - - LOG.info('Found themoviedb match for %s: %s', - item.get('title'), match_found) - - tmdb_id = str(entry.get('id', '')) - if tmdb_id == '': - LOG.error('No themoviedb ID found, aborting') - return - - if media_type == 'multi' and entry.get('media_type'): - media_type = entry.get('media_type') - name = entry.get('name', entry.get('title')) - # lookup external tmdb_id and perform artwork lookup on fanart.tv - parameters = {'api_key': api_key} - if media_type == 'movie': - url = 'https://api.themoviedb.org/3/movie/%s' % tmdb_id - parameters['append_to_response'] = 'videos' - elif media_type == 'tv': - url = 'https://api.themoviedb.org/3/tv/%s' % tmdb_id - parameters['append_to_response'] = 'external_ids,videos' - media_id, poster, background = None, None, None - for language in [v.KODILANGUAGE, 'en']: - parameters['language'] = language - data = DU().downloadUrl(url, - authenticate=False, - parameters=parameters, - timeout=7) - try: - data.get('test') - except AttributeError: - LOG.warning('Could not download %s with parameters %s', - url, parameters) - continue - if collection is False: - if data.get('imdb_id'): - media_id = str(data.get('imdb_id')) - break - if (data.get('external_ids') and - data['external_ids'].get('tvdb_id')): - media_id = str(data['external_ids']['tvdb_id']) - break - else: - if not data.get('belongs_to_collection'): - continue - media_id = data.get('belongs_to_collection').get('id') - if not media_id: - continue - media_id = str(media_id) - LOG.debug('Retrieved collections tmdb id %s for %s', - media_id, title) - url = 'https://api.themoviedb.org/3/collection/%s' % media_id - data = DU().downloadUrl(url, - authenticate=False, - parameters=parameters, - timeout=7) - try: - data.get('poster_path') - except AttributeError: - LOG.debug('Could not find TheMovieDB poster paths for %s' - ' in the language %s', title, language) - continue - if not poster and data.get('poster_path'): - poster = ('https://image.tmdb.org/t/p/original%s' % - data.get('poster_path')) - if not background and data.get('backdrop_path'): - background = ('https://image.tmdb.org/t/p/original%s' % - data.get('backdrop_path')) - return media_id, poster, background + return fanart_lookup.external_item_id(self.title(), + self.year(), + self.plex_type, + collection) def lookup_fanart_tv(self, media_id, artworks): """ diff --git a/resources/lib/plex_api/fanart_lookup.py b/resources/lib/plex_api/fanart_lookup.py new file mode 100644 index 00000000..863a7437 --- /dev/null +++ b/resources/lib/plex_api/fanart_lookup.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, unicode_literals +from logging import getLogger +from re import sub +from string import punctuation + +from ..downloadutils import DownloadUtils as DU +from .. import utils, variables as v + +LOG = getLogger('PLEX.api.fanartlookup') + +API_KEY = utils.settings('themoviedbAPIKey') + +# How far apart can a video's airing date be (in years) +YEARS_APART = 1 +# levenshtein_distance_ratio() returns a value between 0 (no match) and 1 (full +# match). What's the threshold? +LEVENSHTEIN_RATIO_THRESHOLD = 0.95 +# Which character should we ignore when matching video titles? +EXCLUDE_CHARS = set(punctuation) + + +def external_item_id(title, year, plex_type, collection): + LOG.debug('Start identifying %s (%s, %s)', title, year, plex_type) + year = int(year) if year else None + media_type = 'tv' if plex_type == v.PLEX_TYPE_SHOW else plex_type + # if the title has the year in remove it as tmdb cannot deal with it... + # replace e.g. 'The Americans (2015)' with 'The Americans' + title = sub(r'\s*\(\d{4}\)$', '', title, count=1) + url = 'https://api.themoviedb.org/3/search/%s' % media_type + parameters = { + 'api_key': API_KEY, + 'language': v.KODILANGUAGE, + 'query': title.encode('utf-8') + } + data = DU().downloadUrl(url, + authenticate=False, + parameters=parameters, + timeout=7) + try: + data = data['results'] + except (AttributeError, KeyError, TypeError): + LOG.debug('No match found on themoviedb for %s (%s, %s)', + title, year, media_type) + return + LOG.debug('themoviedb returned results: %s', data) + # Some entries don't contain a title or id - get rid of them + data = [x for x in data if 'title' in x and 'id' in x] + # Get rid of all results that do NOT have a matching release year + if year: + data = [x for x in data if __year_almost_matches(year, x)] + if not data: + LOG.debug('Empty results returned by themoviedb for %s (%s, %s)', + title, year, media_type) + return + # Calculate how similar the titles are + title = sanitize_string(title) + for entry in data: + entry['match_score'] = levenshtein_distance_ratio( + sanitize_string(entry['title']), title) + # (one of the possibly many) best match using levenshtein distance ratio + entry = max(data, key=lambda x: x['match_score']) + if entry['match_score'] < LEVENSHTEIN_RATIO_THRESHOLD: + LOG.debug('Best themoviedb match not good enough: %s', entry) + return + + # Check if we got several matches. If so, take the most popular one + best_matches = [x for x in data if + x['match_score'] == entry['match_score'] + and 'popularity' in x] + entry = max(best_matches, key=lambda x: x['popularity']) + LOG.debug('Found themoviedb match: %s', entry) + + # lookup external tmdb_id and perform artwork lookup on fanart.tv + tmdb_id = entry.get('id') + parameters = {'api_key': API_KEY} + if media_type == 'movie': + url = 'https://api.themoviedb.org/3/movie/%s' % tmdb_id + parameters['append_to_response'] = 'videos' + elif media_type == 'tv': + url = 'https://api.themoviedb.org/3/tv/%s' % tmdb_id + parameters['append_to_response'] = 'external_ids,videos' + media_id, poster, background = None, None, None + for language in (v.KODILANGUAGE, 'en'): + parameters['language'] = language + data = DU().downloadUrl(url, + authenticate=False, + parameters=parameters, + timeout=7) + try: + data.get('test') + except AttributeError: + LOG.warning('Could not download %s with parameters %s', + url, parameters) + continue + if collection is False: + if data.get('imdb_id'): + media_id = str(data.get('imdb_id')) + break + if (data.get('external_ids') and + data['external_ids'].get('tvdb_id')): + media_id = str(data['external_ids']['tvdb_id']) + break + else: + if not data.get('belongs_to_collection'): + continue + media_id = data.get('belongs_to_collection').get('id') + if not media_id: + continue + media_id = str(media_id) + LOG.debug('Retrieved collections tmdb id %s for %s', + media_id, title) + url = 'https://api.themoviedb.org/3/collection/%s' % media_id + data = DU().downloadUrl(url, + authenticate=False, + parameters=parameters, + timeout=7) + try: + data.get('poster_path') + except AttributeError: + LOG.debug('Could not find TheMovieDB poster paths for %s' + ' in the language %s', title, language) + continue + if not poster and data.get('poster_path'): + poster = ('https://image.tmdb.org/t/p/original%s' % + data.get('poster_path')) + if not background and data.get('backdrop_path'): + background = ('https://image.tmdb.org/t/p/original%s' % + data.get('backdrop_path')) + return media_id, poster, background + + +def __year_almost_matches(year, entry): + try: + entry_year = int(entry['release_date'][0:4]) + except (KeyError, ValueError): + return True + return abs(year - entry_year) <= YEARS_APART + + +def sanitize_string(s): + s = s.lower().strip() + # Get rid of chars in EXCLUDE_CHARS + s = ''.join(character for character in s if character not in EXCLUDE_CHARS) + # Get rid of multiple spaces + s = ' '.join(s.split()) + return s + + +def levenshtein_distance_ratio(s, t): + """ + Calculates levenshtein distance ratio between two strings. + The more similar the strings, the closer the result will be to 1. + The farther disjunct the string, the closer the result to 0 + + https://www.datacamp.com/community/tutorials/fuzzy-string-python + """ + # Initialize matrix of zeros + rows = len(s) + 1 + cols = len(t) + 1 + distance = [[0 for x in range(cols)] for y in range(rows)] + + # Populate matrix of zeros with the indeces of each character of both strings + for i in range(1, rows): + for k in range(1,cols): + distance[i][0] = i + distance[0][k] = k + + # Iterate over the matrix to compute the cost of deletions,insertions and/or substitutions + for col in range(1, cols): + for row in range(1, rows): + if s[row-1] == t[col-1]: + cost = 0 # If the characters are the same in the two strings in a given position [i,j] then the cost is 0 + else: + # In order to align the results with those of the Python Levenshtein package, if we choose to calculate the ratio + # the cost of a substitution is 2. If we calculate just distance, then the cost of a substitution is 1. + cost = 2 + distance[row][col] = min(distance[row-1][col] + 1, # Cost of deletions + distance[row][col-1] + 1, # Cost of insertions + distance[row-1][col-1] + cost) # Cost of substitutions + return ((len(s)+len(t)) - distance[row][col]) / (len(s)+len(t)) From 4a4aecd6692b4153fe5b24f5b10236327dc087e2 Mon Sep 17 00:00:00 2001 From: croneter Date: Fri, 18 Dec 2020 15:52:02 +0100 Subject: [PATCH 09/14] Beta version bump 2.12.5 --- README.md | 2 +- addon.xml | 11 +++++++++-- changelog.txt | 7 +++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a272e61..4db2df20 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![stable version](https://img.shields.io/badge/stable_version-2.12.3-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-2.12.4-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip) +[![beta version](https://img.shields.io/badge/beta_version-2.12.5-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.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) diff --git a/addon.xml b/addon.xml index 6c740b56..7a162353 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -83,7 +83,14 @@ 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.4 (beta only): + version 2.12.5 (beta only): +- Greatly improve matching logic for The Movie Database if Plex does not provide an appropriate id +- Fix high transcoding resolutions not being available for Win10 +- Fix rare playback progress report failing and KeyError: u'containerKey' +- Fix rare KeyError: None when trying to sync playlists +- Fix TypeError when canceling Plex sync section dialog + +version 2.12.4 (beta only): - Hopefully fix freeze during sync: Don't assign multiple sets/collections for a specific movie - Support metadata provider ids (e.g. for IMDB) for the new Plex Movie Agent diff --git a/changelog.txt b/changelog.txt index 4be12d87..9794d298 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,10 @@ +version 2.12.5 (beta only): +- Greatly improve matching logic for The Movie Database if Plex does not provide an appropriate id +- Fix high transcoding resolutions not being available for Win10 +- Fix rare playback progress report failing and KeyError: u'containerKey' +- Fix rare KeyError: None when trying to sync playlists +- Fix TypeError when canceling Plex sync section dialog + version 2.12.4 (beta only): - Hopefully fix freeze during sync: Don't assign multiple sets/collections for a specific movie - Support metadata provider ids (e.g. for IMDB) for the new Plex Movie Agent From fb53ba3a0a1008f72871834dec5e14c116d5c923 Mon Sep 17 00:00:00 2001 From: croneter Date: Sat, 2 Jan 2021 10:24:07 +0100 Subject: [PATCH 10/14] Update readme --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4db2df20..3851f8ef 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ -[![stable version](https://img.shields.io/badge/stable_version-2.12.3-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-2.12.5-red.svg?maxAge=60&style=flat) ](https://github.com/croneter/binary_repo/raw/master/beta/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.2.zip) +[![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 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) @@ -50,8 +52,7 @@ Some people argue that PKC is 'hacky' because of the way it directly accesses th ### PKC Features -- Kodi 19 Matrix is not yet supported (PKC is written in Python 2) -- Support for Kodi 18 Leia +- Support for Kodi 18 Leia and Kodi 19 Matrix - [Amazon Alexa voice recognition](https://www.plex.tv/apps/streaming-devices/amazon-alexa) - [Cinema Trailers & Extras](https://support.plex.tv/articles/202934883-cinema-trailers-extras/) - [Plex Watch Later / Plex It!](https://support.plex.tv/hc/en-us/sections/200211783-Plex-It-) From a0280fdbd3de5588112baa65a2420b5259960730 Mon Sep 17 00:00:00 2001 From: croneter Date: Wed, 23 Dec 2020 16:25:55 +0100 Subject: [PATCH 11/14] Fix suspension of artwork caching --- resources/lib/artwork.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py index 113d8a32..505b8e2c 100644 --- a/resources/lib/artwork.py +++ b/resources/lib/artwork.py @@ -82,7 +82,7 @@ class ImageCachingThread(backgroundthread.KillableThread): for url in self._url_generator(kind, kodi_type): if self.should_suspend() or self.should_cancel(): return False - cache_url(url) + cache_url(url, self.should_suspend) # Toggles Image caching completed to Yes utils.settings('plex_status_image_caching', value=utils.lang(107)) return True @@ -95,7 +95,7 @@ class ImageCachingThread(backgroundthread.KillableThread): break -def cache_url(url): +def cache_url(url, should_suspend=None): url = double_urlencode(url) sleeptime = 0 while True: @@ -113,11 +113,11 @@ def cache_url(url): # download. All is well break except requests.ConnectionError: - if app.APP.stop_pkc: - # Kodi terminated + if app.APP.stop_pkc or (should_suspend and should_suspend()): break # Server thinks its a DOS attack, ('error 10053') # Wait before trying again + # OR: Kodi refuses Webserver connection (no password set) if sleeptime > 5: LOG.error('Repeatedly got ConnectionError for url %s', double_urldecode(url)) From 089294681e96fc7d9d3d83fd7c336ae88d58bcc7 Mon Sep 17 00:00:00 2001 From: croneter Date: Sat, 2 Jan 2021 11:54:53 +0100 Subject: [PATCH 12/14] Fix rare KeyError when using PKC widgets --- resources/lib/widgets.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/lib/widgets.py b/resources/lib/widgets.py index 80805f00..b9c779a2 100644 --- a/resources/lib/widgets.py +++ b/resources/lib/widgets.py @@ -131,7 +131,11 @@ def _generate_content(api): # Item is synched to the Kodi db - let's use that info # (will thus e.g. include additional artwork or metadata) item = js.item_details(api.kodi_id, api.kodi_type) - else: + + # In rare cases, Kodi's JSON reply does not provide 'title' plus potentially + # other fields - let's use the PMS answer to be safe + # See https://github.com/croneter/PlexKodiConnect/issues/1129 + if not api.kodi_id or 'title' not in item: cast = [{ 'name': x[0], 'thumbnail': x[1], From ddf8637bb6cf1d71996131c170a3cfc3cf5a076a Mon Sep 17 00:00:00 2001 From: croneter Date: Sat, 2 Jan 2021 13:11:24 +0100 Subject: [PATCH 13/14] Update translations --- .../resource.language.cs_CZ/strings.po | 5 ++++ .../resource.language.da_DK/strings.po | 5 ++++ .../resource.language.de_DE/strings.po | 5 ++++ .../resource.language.es_AR/strings.po | 21 +++++++++----- .../resource.language.es_ES/strings.po | 3 +- .../resource.language.es_MX/strings.po | 21 +++++++++----- .../resource.language.fr_CA/strings.po | 5 ++++ .../resource.language.fr_FR/strings.po | 5 ++++ .../resource.language.hu_HU/strings.po | 5 ++++ .../resource.language.it_IT/strings.po | 5 ++++ .../resource.language.lt_LT/strings.po | 5 ++++ .../resource.language.lv_LV/strings.po | 29 +++++++++++-------- .../resource.language.nl_NL/strings.po | 5 ++++ .../resource.language.no_NO/strings.po | 5 ++++ .../resource.language.pt_BR/strings.po | 5 ++++ .../resource.language.pt_PT/strings.po | 5 ++++ .../resource.language.ru_RU/strings.po | 5 ++++ .../resource.language.sv_SE/strings.po | 5 ++++ .../resource.language.uk_UA/strings.po | 7 ++++- .../resource.language.zh_CN/strings.po | 5 ++++ .../resource.language.zh_TW/strings.po | 5 ++++ 21 files changed, 131 insertions(+), 30 deletions(-) diff --git a/resources/language/resource.language.cs_CZ/strings.po b/resources/language/resource.language.cs_CZ/strings.po index 5f083f4e..1880b785 100644 --- a/resources/language/resource.language.cs_CZ/strings.po +++ b/resources/language/resource.language.cs_CZ/strings.po @@ -950,6 +950,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Nahrazovat speciální znaky v cestě (např. z mezery na %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.da_DK/strings.po b/resources/language/resource.language.da_DK/strings.po index c8dd4890..d88a051a 100644 --- a/resources/language/resource.language.da_DK/strings.po +++ b/resources/language/resource.language.da_DK/strings.po @@ -954,6 +954,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Escape special characters in path (e.g. space to %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.de_DE/strings.po b/resources/language/resource.language.de_DE/strings.po index 4a859d1a..20d16036 100644 --- a/resources/language/resource.language.de_DE/strings.po +++ b/resources/language/resource.language.de_DE/strings.po @@ -966,6 +966,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Sonderzeichen im Pfad escapen (z.B. Leerzeichen zu %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "Sichere Zeichen für http(s), dav(s) und (s)ftp urls" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.es_AR/strings.po b/resources/language/resource.language.es_AR/strings.po index 500c8b78..67b15db2 100644 --- a/resources/language/resource.language.es_AR/strings.po +++ b/resources/language/resource.language.es_AR/strings.po @@ -1,6 +1,6 @@ # XBMC Media Center language file # Translators: -# Croneter None , 2019 +# Croneter None , 2020 # msgid "" msgstr "" @@ -8,7 +8,7 @@ msgstr "" "Report-Msgid-Bugs-To: croneter@gmail.com\n" "POT-Creation-Date: 2017-04-15 13:13+0000\n" "PO-Revision-Date: 2017-04-30 08:30+0000\n" -"Last-Translator: Croneter None , 2019\n" +"Last-Translator: Croneter None , 2020\n" "Language-Team: Spanish (Argentina) (https://www.transifex.com/croneter/teams/73837/es_AR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -935,7 +935,7 @@ msgid "" "Kodi cannot locate the file %s. Please verify your PKC settings. Stop " "syncing?" msgstr "" -"Kodi no puede localizer el archive %s. Por favoer verificar sus ajustes de " +"Kodi no puede localizer el archivo %s. Por favor verificar sus ajustes de " "PKC. ¿Detener la sincronización?" # Pop-up on initial sync @@ -964,7 +964,12 @@ msgstr "" # PKC Settings - Customize Paths msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" -msgstr "Escapar caracteres especiales en la ruta (i.e. espacio a %20)" +msgstr "Escapar caracteres especiales en la ruta (p. ej. espacio a %20)" + +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "Caracteres seguros para urls http(s), dav(s) y (s)ftp" # PKC Settings - Customize Paths msgctxt "#39037" @@ -1430,7 +1435,7 @@ msgid "" "The current Kodi version is not supported by PKC. Please consult the Plex " "forum." msgstr "" -"La version actual de Kodi no está soportada por PKC. Por favor consultar el" +"La versión actual de Kodi no está soportada por PKC. Por favor consultar el" " fórum de Plex." msgctxt "#39405" @@ -1474,7 +1479,7 @@ msgstr "Sagas" msgctxt "#39502" msgid "PKC On Deck (faster)" -msgstr "Tablero de PKC (mas rapido)" +msgstr "On Deck de PKC (más rápido)" msgctxt "#39600" msgid "" @@ -1616,8 +1621,8 @@ msgid "" "Do you want to replace your custom user ratings with an indicator of how " "many versions of a media item you posses?" msgstr "" -"¿Quiere reemplazar su valoración personalizada con cuántas versione posee de" -" un elemento de medios?" +"¿Quiere reemplazar su valoración personalizada por cuántas versiones posee " +"de un elemento de medios?" # In PKC Settings under Sync msgctxt "#39719" diff --git a/resources/language/resource.language.es_ES/strings.po b/resources/language/resource.language.es_ES/strings.po index 820ec736..761dd54f 100644 --- a/resources/language/resource.language.es_ES/strings.po +++ b/resources/language/resource.language.es_ES/strings.po @@ -2,6 +2,7 @@ # Translators: # Dani , 2019 # Bartolome Soriano , 2019 +# Croneter None , 2020 # msgid "" msgstr "" @@ -9,7 +10,7 @@ msgstr "" "Report-Msgid-Bugs-To: croneter@gmail.com\n" "POT-Creation-Date: 2017-04-15 13:13+0000\n" "PO-Revision-Date: 2017-04-30 08:30+0000\n" -"Last-Translator: Bartolome Soriano , 2019\n" +"Last-Translator: Croneter None , 2020\n" "Language-Team: Spanish (Spain) (https://www.transifex.com/croneter/teams/73837/es_ES/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/resources/language/resource.language.es_MX/strings.po b/resources/language/resource.language.es_MX/strings.po index f7ec0daa..d934e78e 100644 --- a/resources/language/resource.language.es_MX/strings.po +++ b/resources/language/resource.language.es_MX/strings.po @@ -1,6 +1,6 @@ # XBMC Media Center language file # Translators: -# Croneter None , 2019 +# Croneter None , 2020 # msgid "" msgstr "" @@ -8,7 +8,7 @@ msgstr "" "Report-Msgid-Bugs-To: croneter@gmail.com\n" "POT-Creation-Date: 2017-04-15 13:13+0000\n" "PO-Revision-Date: 2017-04-30 08:30+0000\n" -"Last-Translator: Croneter None , 2019\n" +"Last-Translator: Croneter None , 2020\n" "Language-Team: Spanish (Mexico) (https://www.transifex.com/croneter/teams/73837/es_MX/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -935,7 +935,7 @@ msgid "" "Kodi cannot locate the file %s. Please verify your PKC settings. Stop " "syncing?" msgstr "" -"Kodi no puede localizer el archive %s. Por favoer verificar sus ajustes de " +"Kodi no puede localizer el archivo %s. Por favor verificar sus ajustes de " "PKC. ¿Detener la sincronización?" # Pop-up on initial sync @@ -964,7 +964,12 @@ msgstr "" # PKC Settings - Customize Paths msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" -msgstr "Escapar caracteres especiales en la ruta (i.e. espacio a %20)" +msgstr "Escapar caracteres especiales en la ruta (p. ej. espacio a %20)" + +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "Caracteres seguros para urls http(s), dav(s) y (s)ftp" # PKC Settings - Customize Paths msgctxt "#39037" @@ -1430,7 +1435,7 @@ msgid "" "The current Kodi version is not supported by PKC. Please consult the Plex " "forum." msgstr "" -"La version actual de Kodi no está soportada por PKC. Por favor consultar el" +"La versión actual de Kodi no está soportada por PKC. Por favor consultar el" " fórum de Plex." msgctxt "#39405" @@ -1474,7 +1479,7 @@ msgstr "Sagas" msgctxt "#39502" msgid "PKC On Deck (faster)" -msgstr "Tablero de PKC (mas rapido)" +msgstr "On Deck de PKC (más rápido)" msgctxt "#39600" msgid "" @@ -1616,8 +1621,8 @@ msgid "" "Do you want to replace your custom user ratings with an indicator of how " "many versions of a media item you posses?" msgstr "" -"¿Quiere reemplazar su valoración personalizada con cuántas versione posee de" -" un elemento de medios?" +"¿Quiere reemplazar su valoración personalizada por cuántas versiones posee " +"de un elemento de medios?" # In PKC Settings under Sync msgctxt "#39719" diff --git a/resources/language/resource.language.fr_CA/strings.po b/resources/language/resource.language.fr_CA/strings.po index fe7b8e8a..c8756be2 100644 --- a/resources/language/resource.language.fr_CA/strings.po +++ b/resources/language/resource.language.fr_CA/strings.po @@ -975,6 +975,11 @@ msgstr "" "Echapper les caractères spéciaux dans le chemin (ex: %20 au lieu des " "espaces)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "Caractères sûrs pour les urls http(s), dav(s) et (s)ftp" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.fr_FR/strings.po b/resources/language/resource.language.fr_FR/strings.po index 657a6d9a..fd143ab7 100644 --- a/resources/language/resource.language.fr_FR/strings.po +++ b/resources/language/resource.language.fr_FR/strings.po @@ -979,6 +979,11 @@ msgstr "" "Echapper les caractères spéciaux dans le chemin (ex: %20 au lieu des " "espaces)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "Caractères sûrs pour les urls http(s), dav(s) et (s)ftp" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.hu_HU/strings.po b/resources/language/resource.language.hu_HU/strings.po index ce515630..fbc3b19b 100644 --- a/resources/language/resource.language.hu_HU/strings.po +++ b/resources/language/resource.language.hu_HU/strings.po @@ -968,6 +968,11 @@ msgid "Escape special characters in path (e.g. space to %20)" msgstr "" "A speciális karakterek feloldása az elérési útban (pl. szóköz helyett %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.it_IT/strings.po b/resources/language/resource.language.it_IT/strings.po index f4878be7..f09baa49 100644 --- a/resources/language/resource.language.it_IT/strings.po +++ b/resources/language/resource.language.it_IT/strings.po @@ -967,6 +967,11 @@ msgstr "" "Esegui l'escape dei caratteri speciali nel percorso (es. \"spazio\" " "trasformato in \"%20\")" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.lt_LT/strings.po b/resources/language/resource.language.lt_LT/strings.po index 35921623..3afb20db 100644 --- a/resources/language/resource.language.lt_LT/strings.po +++ b/resources/language/resource.language.lt_LT/strings.po @@ -963,6 +963,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Kaita specialių simbolių kelyje (pvz., tarpas %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.lv_LV/strings.po b/resources/language/resource.language.lv_LV/strings.po index fa561faa..6d18986e 100644 --- a/resources/language/resource.language.lv_LV/strings.po +++ b/resources/language/resource.language.lv_LV/strings.po @@ -946,6 +946,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" @@ -1100,7 +1105,7 @@ msgstr "Uzspiest atjaunošanu Kodi ādiņai apturot atskaņošanu" # PKC Settings - Appearance Tweaks msgctxt "#39066" msgid "Recently Added: Also show already watched movies" -msgstr "" +msgstr "Nesen Pievienots: Rādīt arī jau skatītas filmas" # PKC Settings - Connection msgctxt "#39067" @@ -1110,7 +1115,7 @@ msgstr "Tavs pašreizējais Plex Media Serveris:" # PKC Settings - Connection msgctxt "#39068" msgid "Manually enter Plex Media Server address" -msgstr "" +msgstr "Pats ievadi Plex Media Server adresi" # PKC Settings - Connection msgctxt "#39069" @@ -1173,22 +1178,22 @@ msgstr "" # Button text for choosing PKC mode msgctxt "#39081" msgid "Add-on Paths" -msgstr "" +msgstr "Spraudņu Ceļš" # Button text for choosing PKC mode msgctxt "#39082" msgid "Direct Paths" -msgstr "" +msgstr "Tiešie Ceļi" # Dialog for manually entering PMS msgctxt "#39083" msgid "Enter PMS IP or URL" -msgstr "" +msgstr "Ievadi PMS IP vai URL" # Dialog for manually entering PMS msgctxt "#39084" msgid "Enter PMS port" -msgstr "" +msgstr "Ievadi PMS portu" # PKC settings - Appearance Tweaks msgctxt "#39085" @@ -1291,23 +1296,23 @@ msgstr "Tikai trūkstošo" # Message in the PKC settings if user has not logged in to plex.tv msgctxt "#39226" msgid "Not logged in to plex.tv" -msgstr "" +msgstr "Nav pieteicies plex.tv" # Message in the PKC settings if user is logged in to plex.tv msgctxt "#39227" msgid "Logged in to plex.tv" -msgstr "" +msgstr "Pieteicies plex.tv" # Message in the PKC settings to display the plex.tv username msgctxt "#39228" msgid "Plex admin user" -msgstr "" +msgstr "Plex admin user" # Error message if user could not log in; the actual user name will be # appended at the end of the string msgctxt "#39229" msgid "Login failed with plex.tv for user" -msgstr "" +msgstr "Lietotāja pieteikšanās plex.tv neizdevās" # Message in the PKC settings to display the plex.tv username msgctxt "#39230" @@ -1472,7 +1477,7 @@ msgstr "" # Addon Disclaimer msgctxt "#39705" msgid "Use at your own risk" -msgstr "" +msgstr "Lieto uz savu atbildību" # If user gets prompted to choose between several subtitles to burn in msgctxt "#39706" @@ -1530,7 +1535,7 @@ msgstr "Sinhronizēt" # Shown during sync process msgctxt "#39715" msgid "Synching playlists" -msgstr "" +msgstr "Sinhronizē spēļsarakstus" # Error message if an xml, e.g. advancedsettings.xml cannot be parsed (xml is # screwed up; formated the wrong way). Do NOT replace {0} and {1}! diff --git a/resources/language/resource.language.nl_NL/strings.po b/resources/language/resource.language.nl_NL/strings.po index a04a4de7..0b9dd97b 100644 --- a/resources/language/resource.language.nl_NL/strings.po +++ b/resources/language/resource.language.nl_NL/strings.po @@ -957,6 +957,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Pas speciale tekens aan in pad (b.v. spatie naar %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.no_NO/strings.po b/resources/language/resource.language.no_NO/strings.po index 63af2f7b..bfbf6e49 100644 --- a/resources/language/resource.language.no_NO/strings.po +++ b/resources/language/resource.language.no_NO/strings.po @@ -951,6 +951,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Unngå spesielle tegn i stier (eksempel mellomrom til %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.pt_BR/strings.po b/resources/language/resource.language.pt_BR/strings.po index ad348c63..bf22f716 100644 --- a/resources/language/resource.language.pt_BR/strings.po +++ b/resources/language/resource.language.pt_BR/strings.po @@ -945,6 +945,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.pt_PT/strings.po b/resources/language/resource.language.pt_PT/strings.po index 962c4892..9be29b9d 100644 --- a/resources/language/resource.language.pt_PT/strings.po +++ b/resources/language/resource.language.pt_PT/strings.po @@ -948,6 +948,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.ru_RU/strings.po b/resources/language/resource.language.ru_RU/strings.po index b931642b..b7028460 100644 --- a/resources/language/resource.language.ru_RU/strings.po +++ b/resources/language/resource.language.ru_RU/strings.po @@ -961,6 +961,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Преобразуйте специальные символы в пути. (например пробел в %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.sv_SE/strings.po b/resources/language/resource.language.sv_SE/strings.po index 7a1dedc0..e7318873 100644 --- a/resources/language/resource.language.sv_SE/strings.po +++ b/resources/language/resource.language.sv_SE/strings.po @@ -951,6 +951,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Omkoda specialtecken i sökväg (exempelvis mellanslag som %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.uk_UA/strings.po b/resources/language/resource.language.uk_UA/strings.po index 908db1dd..62487938 100644 --- a/resources/language/resource.language.uk_UA/strings.po +++ b/resources/language/resource.language.uk_UA/strings.po @@ -957,6 +957,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "Замінювати спеціальні символи у шляхах (наприклад, пробіл у %20)" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "Безпечні символи для URL-адрес http(s), dav(s) та (s)ftp" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" @@ -1528,7 +1533,7 @@ msgstr "Використовуйте на свій ризик" # If user gets prompted to choose between several subtitles to burn in msgctxt "#39706" msgid "Don't burn-in any subtitle" -msgstr "" +msgstr "Не виводити жодних субтитрів" # If user gets prompted to choose between several audio/subtitle tracks and # language is unknown diff --git a/resources/language/resource.language.zh_CN/strings.po b/resources/language/resource.language.zh_CN/strings.po index 79e38ae1..398a336f 100644 --- a/resources/language/resource.language.zh_CN/strings.po +++ b/resources/language/resource.language.zh_CN/strings.po @@ -918,6 +918,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" diff --git a/resources/language/resource.language.zh_TW/strings.po b/resources/language/resource.language.zh_TW/strings.po index 3da4691a..6611aeb6 100644 --- a/resources/language/resource.language.zh_TW/strings.po +++ b/resources/language/resource.language.zh_TW/strings.po @@ -916,6 +916,11 @@ msgctxt "#39036" msgid "Escape special characters in path (e.g. space to %20)" msgstr "" +# PKC Settings - Customize Paths +msgctxt "#39090" +msgid "Safe characters for http(s), dav(s) and (s)ftp urls" +msgstr "" + # PKC Settings - Customize Paths msgctxt "#39037" msgid "Original Plex MOVIE path to replace:" From d096854b145e537e28dd54d004142678d04fba98 Mon Sep 17 00:00:00 2001 From: croneter Date: Sat, 2 Jan 2021 12:02:36 +0100 Subject: [PATCH 14/14] Stable and beta version bump 2.12.6 --- addon.xml | 10 ++++++++-- changelog.txt | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/addon.xml b/addon.xml index 7a162353..bea96a8a 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -83,7 +83,13 @@ 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.5 (beta only): + version 2.12.6: +- Fix rare KeyError when using PKC widgets +- Fix suspension of artwork caching and PKC becoming unresponsive +- Update translations +- Versions 2.12.4 and 2.12.5 for everyone + +version 2.12.5 (beta only): - Greatly improve matching logic for The Movie Database if Plex does not provide an appropriate id - Fix high transcoding resolutions not being available for Win10 - Fix rare playback progress report failing and KeyError: u'containerKey' diff --git a/changelog.txt b/changelog.txt index 9794d298..a4500090 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,9 @@ +version 2.12.6: +- Fix rare KeyError when using PKC widgets +- Fix suspension of artwork caching and PKC becoming unresponsive +- Update translations +- Versions 2.12.4 and 2.12.5 for everyone + version 2.12.5 (beta only): - Greatly improve matching logic for The Movie Database if Plex does not provide an appropriate id - Fix high transcoding resolutions not being available for Win10