diff --git a/addon.xml b/addon.xml index 21330134..d0846823 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -91,7 +91,16 @@ Plex를 Kodi에 기본 통합 Kodi를 Plex Media Server에 연결합니다. 이 플러그인은 Plex로 모든 비디오를 관리하고 Kodi로는 관리하지 않는다고 가정합니다. Kodi 비디오 및 음악 데이터베이스에 이미 저장된 데이터가 손실 될 수 있습니다 (이 플러그인이 직접 변경하므로). 자신의 책임하에 사용하십시오! 자신의 책임하에 사용 - version 3.5.0: + version 3.5.2: +- version 3.5.1 for everyone + +version 3.5.1 (beta only): +- Refactor stream code and fix Kodi not activating subtitle when it should +- Direct Paths: Fix TypeError: "element indices must be integers" on playback startup +- Android: Fix broken Python multiprocessing module (a Kodi 19.2 bug) +- Fix logging if fanart.tv lookup fails: be less verbose + +version 3.5.0: - versions 3.4.5-3.4.7 for everyone version 3.4.7 (beta only): diff --git a/changelog.txt b/changelog.txt index ba380ba2..b3db9478 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,12 @@ +version 3.5.2: +- version 3.5.1 for everyone + +version 3.5.1 (beta only): +- Refactor stream code and fix Kodi not activating subtitle when it should +- Direct Paths: Fix TypeError: "element indices must be integers" on playback startup +- Android: Fix broken Python multiprocessing module (a Kodi 19.2 bug) +- Fix logging if fanart.tv lookup fails: be less verbose + version 3.5.0: - versions 3.4.5-3.4.7 for everyone diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py index 4914016a..aec4efcd 100644 --- a/resources/lib/downloadutils.py +++ b/resources/lib/downloadutils.py @@ -223,7 +223,11 @@ class DownloadUtils(object): if r.status_code != 401: self.count_unauthorized = 0 - if r.status_code == 204: + if return_response is True: + # return the entire response object + return r + + elif r.status_code == 204: # No body in the response # But read (empty) content to release connection back to pool # (see requests: keep-alive documentation) @@ -257,9 +261,6 @@ class DownloadUtils(object): elif r.status_code in (200, 201): # 200: OK # 201: Created - if return_response is True: - # return the entire response object - return r try: # xml response r = utils.etree.fromstring(r.content) diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py index de88a3c0..40633d46 100644 --- a/resources/lib/kodimonitor.py +++ b/resources/lib/kodimonitor.py @@ -382,72 +382,17 @@ class KodiMonitor(xbmc.Monitor): if not playerid == v.KODI_VIDEO_PLAYER_ID: # We're just messing with Kodi's videoplayer return - if not self._switched_to_plex_streams: - # We need to switch to the Plex streams ONCE upon playback start - # after onavchange has been fired - self.switch_to_plex_streams() - self._switched_to_plex_streams = True - else: - item = app.PLAYSTATE.item - if item is None: - # Player might've quit - return - kodi_audio_stream = js.get_current_audio_stream_index(playerid) - sub_enabled = js.get_subtitle_enabled(playerid) - kodi_sub_stream = js.get_current_subtitle_stream_index(playerid) - # Audio - if kodi_audio_stream != item.current_kodi_audio_stream: - item.on_kodi_audio_stream_change(kodi_audio_stream) - # Subtitles - CURRENTLY BROKEN ON THE KODI SIDE! - # current_kodi_sub_stream may also be zero - subs_off = (None, False) - if ((sub_enabled and item.current_kodi_sub_stream in subs_off) - or (not sub_enabled and item.current_kodi_sub_stream not in subs_off) - or (kodi_sub_stream is not None - and kodi_sub_stream != item.current_kodi_sub_stream)): - item.on_kodi_subtitle_stream_change(kodi_sub_stream, - sub_enabled) - - @staticmethod - def switch_to_plex_streams(): - """ - Override Kodi audio and subtitle streams with Plex PMS' selection - """ item = app.PLAYSTATE.item if item is None: # Player might've quit return - for typus in ('audio', 'subtitle'): - try: - plex_index, language_tag = item.active_plex_stream_index(typus) - except TypeError: - LOG.debug('Deactivating Kodi subtitles because the PMS ' - 'told us to not show any subtitles') - app.APP.player.showSubtitles(False) - item.current_kodi_sub_stream = False - continue - LOG.debug('The PMS wants to display %s stream with Plex id %s and ' - 'languageTag %s', - typus, plex_index, language_tag) - kodi_index = item.kodi_stream_index(plex_index, typus) - if kodi_index is None: - LOG.debug('Leaving Kodi %s stream settings untouched since we ' - 'could not parse Plex %s stream with id %s to a Kodi' - ' index', typus, typus, plex_index) - else: - LOG.debug('Switching to Kodi %s stream number %s because the ' - 'PMS told us to show stream with Plex id %s', - typus, kodi_index, plex_index) - # If we're choosing an "illegal" index, this function does - # need seem to fail nor log any errors - if typus == 'audio': - app.APP.player.setAudioStream(kodi_index) - else: - app.APP.player.setSubtitleStream(kodi_index) - if typus == 'audio': - item.current_kodi_audio_stream = kodi_index - else: - item.current_kodi_sub_stream = kodi_index + if not self._switched_to_plex_streams: + # We need to switch to the Plex streams ONCE upon playback start + # after onavchange has been fired + item.switch_to_plex_streams() + self._switched_to_plex_streams = True + else: + item.on_av_change(playerid) def _playback_cleanup(ended=False): diff --git a/resources/lib/playlist_func.py b/resources/lib/playlist_func.py index 153b0aed..c548dea0 100644 --- a/resources/lib/playlist_func.py +++ b/resources/lib/playlist_func.py @@ -324,6 +324,58 @@ class PlaylistItem(object): PF.change_audio_stream(plex_stream_index, self.api.part_id()) self.current_kodi_audio_stream = kodi_stream_index + def switch_to_plex_streams(self): + self.switch_to_plex_stream('audio') + self.switch_to_plex_stream('subtitle') + + def switch_to_plex_stream(self, typus): + try: + plex_index, language_tag = self.active_plex_stream_index(typus) + except TypeError: + LOG.debug('Deactivating Kodi subtitles because the PMS ' + 'told us to not show any subtitles') + app.APP.player.showSubtitles(False) + self.current_kodi_sub_stream = False + return + LOG.debug('The PMS wants to display %s stream with Plex id %s and ' + 'languageTag %s', typus, plex_index, language_tag) + kodi_index = self.kodi_stream_index(plex_index, typus) + if kodi_index is None: + LOG.debug('Leaving Kodi %s stream settings untouched since we ' + 'could not parse Plex %s stream with id %s to a Kodi' + ' index', typus, typus, plex_index) + else: + LOG.debug('Switching to Kodi %s stream number %s because the ' + 'PMS told us to show stream with Plex id %s', + typus, kodi_index, plex_index) + # If we're choosing an "illegal" index, this function does + # need seem to fail nor log any errors + if typus == 'audio': + app.APP.player.setAudioStream(kodi_index) + else: + app.APP.player.setSubtitleStream(kodi_index) + app.APP.player.showSubtitles(True) + if typus == 'audio': + self.current_kodi_audio_stream = kodi_index + else: + self.current_kodi_sub_stream = kodi_index + + def on_av_change(self, playerid): + kodi_audio_stream = js.get_current_audio_stream_index(playerid) + sub_enabled = js.get_subtitle_enabled(playerid) + kodi_sub_stream = js.get_current_subtitle_stream_index(playerid) + # Audio + if kodi_audio_stream != self.current_kodi_audio_stream: + self.on_kodi_audio_stream_change(kodi_audio_stream) + # Subtitles - CURRENTLY BROKEN ON THE KODI SIDE! + # current_kodi_sub_stream may also be zero + subs_off = (None, False) + if ((sub_enabled and self.current_kodi_sub_stream in subs_off) + or (not sub_enabled and self.current_kodi_sub_stream not in subs_off) + or (kodi_sub_stream is not None + and kodi_sub_stream != self.current_kodi_sub_stream)): + self.on_kodi_subtitle_stream_change(kodi_sub_stream, sub_enabled) + def playlist_item_from_kodi(kodi_item): """ diff --git a/resources/lib/plex_api/artwork.py b/resources/lib/plex_api/artwork.py index 8e354084..f8b351f8 100644 --- a/resources/lib/plex_api/artwork.py +++ b/resources/lib/plex_api/artwork.py @@ -220,12 +220,14 @@ class Artwork(object): else: # Not supported artwork return artworks - data = DU().downloadUrl(url, authenticate=False, timeout=15) - try: - data.get('test') - except AttributeError: - LOG.error('Could not download data from FanartTV') + data = DU().downloadUrl(url, + authenticate=False, + timeout=15, + return_response=True) + if not data.ok: + LOG.debug('Could not download data from FanartTV') return artworks + data = data.json() fanart_tv_types = list(v.FANART_TV_TO_KODI_TYPE) diff --git a/resources/lib/plex_api/base.py b/resources/lib/plex_api/base.py index c26d820f..4f5540d8 100644 --- a/resources/lib/plex_api/base.py +++ b/resources/lib/plex_api/base.py @@ -16,12 +16,15 @@ METADATA_PROVIDERS = (('imdb', utils.REGEX_IMDB), ('tvdb', utils.REGEX_TVDB), ('tmdb', utils.REGEX_TMDB), ('anidb', utils.REGEX_ANIDB)) + + class Base(object): """ Processes a Plex media server's XML response xml: xml.etree.ElementTree element """ + def __init__(self, xml): self.xml = xml # which media part in the XML response shall we look at if several @@ -260,13 +263,21 @@ class Base(object): Returns the media streams directly from the PMS xml. Mind to set self.mediastream and self.part before calling this method! """ - return self.xml[self.mediastream][self.part] + try: + return self.xml[self.mediastream][self.part] + except TypeError: + # Direct Paths when we don't set mediastream and part + return self.xml[0][0] def part_id(self): """ Returns the unique id of the currently active part [int] """ - return int(self.xml[self.mediastream][self.part].attrib['id']) + try: + return int(self.xml[self.mediastream][self.part].attrib['id']) + except TypeError: + # Direct Paths when we don't set mediastream and part + return int(self.xml[0][0].attrib['id']) def plot(self): """ diff --git a/resources/lib/plex_api/media.py b/resources/lib/plex_api/media.py index 1a828dbd..1b3b7f35 100644 --- a/resources/lib/plex_api/media.py +++ b/resources/lib/plex_api/media.py @@ -357,16 +357,15 @@ class Media(object): filename, extension) response = DU().downloadUrl(url, return_response=True) - try: - response.status_code - except AttributeError: + if not response.ok: LOG.error('Could not temporarily download subtitle %s', url) + LOG.error('HTTP status: %s, message: %s', + response.status_code, response.text) return - else: - LOG.debug('Writing temp subtitle to %s', path) - with open(path, 'wb') as f: - f.write(response.content) - return path + LOG.debug('Writing temp subtitle to %s', path) + with open(path, 'wb') as f: + f.write(response.content) + return path def validate_playurl(self, path, typus, force_check=False, folder=False, omit_check=False): diff --git a/resources/lib/utils.py b/resources/lib/utils.py index 3c663661..d7eea96a 100644 --- a/resources/lib/utils.py +++ b/resources/lib/utils.py @@ -23,6 +23,11 @@ import re import gc try: from multiprocessing.pool import ThreadPool + # Annyoing Kodi bug on Android, introduced with + # https://github.com/xbmc/xbmc/pull/20034 + # See https://github.com/croneter/PlexKodiConnect/issues/1641 + with ThreadPool(): + pass SUPPORTS_POOL = True except Exception: SUPPORTS_POOL = False @@ -867,13 +872,12 @@ def process_method_on_list(method_to_run, items): all_items = [] if SUPPORTS_POOL: pool = ThreadPool() - try: - all_items = pool.map(method_to_run, items) - except Exception: - # catch exception to prevent threadpool running forever - ERROR(notify=True) - pool.close() - pool.join() + with ThreadPool() as pool: + try: + all_items = pool.map(method_to_run, items) + except Exception: + # catch exception to prevent threadpool running forever + ERROR(notify=True) else: all_items = [method_to_run(item) for item in items] all_items = [_f for _f in all_items if _f]