Merge pull request #1648 from croneter/python3-beta
Bump Python 3 master
This commit is contained in:
commit
2d636d8e08
9 changed files with 122 additions and 90 deletions
13
addon.xml
13
addon.xml
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="3.5.0" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="3.5.2" provider-name="croneter">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="3.0.0"/>
|
<import addon="xbmc.python" version="3.0.0"/>
|
||||||
<import addon="script.module.requests" version="2.22.0+matrix.1" />
|
<import addon="script.module.requests" version="2.22.0+matrix.1" />
|
||||||
|
@ -91,7 +91,16 @@
|
||||||
<summary lang="ko_KR">Plex를 Kodi에 기본 통합</summary>
|
<summary lang="ko_KR">Plex를 Kodi에 기본 통합</summary>
|
||||||
<description lang="ko_KR">Kodi를 Plex Media Server에 연결합니다. 이 플러그인은 Plex로 모든 비디오를 관리하고 Kodi로는 관리하지 않는다고 가정합니다. Kodi 비디오 및 음악 데이터베이스에 이미 저장된 데이터가 손실 될 수 있습니다 (이 플러그인이 직접 변경하므로). 자신의 책임하에 사용하십시오!</description>
|
<description lang="ko_KR">Kodi를 Plex Media Server에 연결합니다. 이 플러그인은 Plex로 모든 비디오를 관리하고 Kodi로는 관리하지 않는다고 가정합니다. Kodi 비디오 및 음악 데이터베이스에 이미 저장된 데이터가 손실 될 수 있습니다 (이 플러그인이 직접 변경하므로). 자신의 책임하에 사용하십시오!</description>
|
||||||
<disclaimer lang="ko_KR">자신의 책임하에 사용</disclaimer>
|
<disclaimer lang="ko_KR">자신의 책임하에 사용</disclaimer>
|
||||||
<news>version 3.5.0:
|
<news>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
|
- versions 3.4.5-3.4.7 for everyone
|
||||||
|
|
||||||
version 3.4.7 (beta only):
|
version 3.4.7 (beta only):
|
||||||
|
|
|
@ -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:
|
version 3.5.0:
|
||||||
- versions 3.4.5-3.4.7 for everyone
|
- versions 3.4.5-3.4.7 for everyone
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,11 @@ class DownloadUtils(object):
|
||||||
if r.status_code != 401:
|
if r.status_code != 401:
|
||||||
self.count_unauthorized = 0
|
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
|
# No body in the response
|
||||||
# But read (empty) content to release connection back to pool
|
# But read (empty) content to release connection back to pool
|
||||||
# (see requests: keep-alive documentation)
|
# (see requests: keep-alive documentation)
|
||||||
|
@ -257,9 +261,6 @@ class DownloadUtils(object):
|
||||||
elif r.status_code in (200, 201):
|
elif r.status_code in (200, 201):
|
||||||
# 200: OK
|
# 200: OK
|
||||||
# 201: Created
|
# 201: Created
|
||||||
if return_response is True:
|
|
||||||
# return the entire response object
|
|
||||||
return r
|
|
||||||
try:
|
try:
|
||||||
# xml response
|
# xml response
|
||||||
r = utils.etree.fromstring(r.content)
|
r = utils.etree.fromstring(r.content)
|
||||||
|
|
|
@ -382,72 +382,17 @@ class KodiMonitor(xbmc.Monitor):
|
||||||
if not playerid == v.KODI_VIDEO_PLAYER_ID:
|
if not playerid == v.KODI_VIDEO_PLAYER_ID:
|
||||||
# We're just messing with Kodi's videoplayer
|
# We're just messing with Kodi's videoplayer
|
||||||
return
|
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
|
item = app.PLAYSTATE.item
|
||||||
if item is None:
|
if item is None:
|
||||||
# Player might've quit
|
# Player might've quit
|
||||||
return
|
return
|
||||||
for typus in ('audio', 'subtitle'):
|
if not self._switched_to_plex_streams:
|
||||||
try:
|
# We need to switch to the Plex streams ONCE upon playback start
|
||||||
plex_index, language_tag = item.active_plex_stream_index(typus)
|
# after onavchange has been fired
|
||||||
except TypeError:
|
item.switch_to_plex_streams()
|
||||||
LOG.debug('Deactivating Kodi subtitles because the PMS '
|
self._switched_to_plex_streams = True
|
||||||
'told us to not show any subtitles')
|
else:
|
||||||
app.APP.player.showSubtitles(False)
|
item.on_av_change(playerid)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def _playback_cleanup(ended=False):
|
def _playback_cleanup(ended=False):
|
||||||
|
|
|
@ -324,6 +324,58 @@ class PlaylistItem(object):
|
||||||
PF.change_audio_stream(plex_stream_index, self.api.part_id())
|
PF.change_audio_stream(plex_stream_index, self.api.part_id())
|
||||||
self.current_kodi_audio_stream = kodi_stream_index
|
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):
|
def playlist_item_from_kodi(kodi_item):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -220,12 +220,14 @@ class Artwork(object):
|
||||||
else:
|
else:
|
||||||
# Not supported artwork
|
# Not supported artwork
|
||||||
return artworks
|
return artworks
|
||||||
data = DU().downloadUrl(url, authenticate=False, timeout=15)
|
data = DU().downloadUrl(url,
|
||||||
try:
|
authenticate=False,
|
||||||
data.get('test')
|
timeout=15,
|
||||||
except AttributeError:
|
return_response=True)
|
||||||
LOG.error('Could not download data from FanartTV')
|
if not data.ok:
|
||||||
|
LOG.debug('Could not download data from FanartTV')
|
||||||
return artworks
|
return artworks
|
||||||
|
data = data.json()
|
||||||
|
|
||||||
fanart_tv_types = list(v.FANART_TV_TO_KODI_TYPE)
|
fanart_tv_types = list(v.FANART_TV_TO_KODI_TYPE)
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,15 @@ METADATA_PROVIDERS = (('imdb', utils.REGEX_IMDB),
|
||||||
('tvdb', utils.REGEX_TVDB),
|
('tvdb', utils.REGEX_TVDB),
|
||||||
('tmdb', utils.REGEX_TMDB),
|
('tmdb', utils.REGEX_TMDB),
|
||||||
('anidb', utils.REGEX_ANIDB))
|
('anidb', utils.REGEX_ANIDB))
|
||||||
|
|
||||||
|
|
||||||
class Base(object):
|
class Base(object):
|
||||||
"""
|
"""
|
||||||
Processes a Plex media server's XML response
|
Processes a Plex media server's XML response
|
||||||
|
|
||||||
xml: xml.etree.ElementTree element
|
xml: xml.etree.ElementTree element
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, xml):
|
def __init__(self, xml):
|
||||||
self.xml = xml
|
self.xml = xml
|
||||||
# which media part in the XML response shall we look at if several
|
# 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.
|
Returns the media streams directly from the PMS xml.
|
||||||
Mind to set self.mediastream and self.part before calling this method!
|
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):
|
def part_id(self):
|
||||||
"""
|
"""
|
||||||
Returns the unique id of the currently active part [int]
|
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):
|
def plot(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -357,16 +357,15 @@ class Media(object):
|
||||||
filename,
|
filename,
|
||||||
extension)
|
extension)
|
||||||
response = DU().downloadUrl(url, return_response=True)
|
response = DU().downloadUrl(url, return_response=True)
|
||||||
try:
|
if not response.ok:
|
||||||
response.status_code
|
|
||||||
except AttributeError:
|
|
||||||
LOG.error('Could not temporarily download subtitle %s', url)
|
LOG.error('Could not temporarily download subtitle %s', url)
|
||||||
|
LOG.error('HTTP status: %s, message: %s',
|
||||||
|
response.status_code, response.text)
|
||||||
return
|
return
|
||||||
else:
|
LOG.debug('Writing temp subtitle to %s', path)
|
||||||
LOG.debug('Writing temp subtitle to %s', path)
|
with open(path, 'wb') as f:
|
||||||
with open(path, 'wb') as f:
|
f.write(response.content)
|
||||||
f.write(response.content)
|
return path
|
||||||
return path
|
|
||||||
|
|
||||||
def validate_playurl(self, path, typus, force_check=False, folder=False,
|
def validate_playurl(self, path, typus, force_check=False, folder=False,
|
||||||
omit_check=False):
|
omit_check=False):
|
||||||
|
|
|
@ -23,6 +23,11 @@ import re
|
||||||
import gc
|
import gc
|
||||||
try:
|
try:
|
||||||
from multiprocessing.pool import ThreadPool
|
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
|
SUPPORTS_POOL = True
|
||||||
except Exception:
|
except Exception:
|
||||||
SUPPORTS_POOL = False
|
SUPPORTS_POOL = False
|
||||||
|
@ -867,13 +872,12 @@ def process_method_on_list(method_to_run, items):
|
||||||
all_items = []
|
all_items = []
|
||||||
if SUPPORTS_POOL:
|
if SUPPORTS_POOL:
|
||||||
pool = ThreadPool()
|
pool = ThreadPool()
|
||||||
try:
|
with ThreadPool() as pool:
|
||||||
all_items = pool.map(method_to_run, items)
|
try:
|
||||||
except Exception:
|
all_items = pool.map(method_to_run, items)
|
||||||
# catch exception to prevent threadpool running forever
|
except Exception:
|
||||||
ERROR(notify=True)
|
# catch exception to prevent threadpool running forever
|
||||||
pool.close()
|
ERROR(notify=True)
|
||||||
pool.join()
|
|
||||||
else:
|
else:
|
||||||
all_items = [method_to_run(item) for item in items]
|
all_items = [method_to_run(item) for item in items]
|
||||||
all_items = [_f for _f in all_items if _f]
|
all_items = [_f for _f in all_items if _f]
|
||||||
|
|
Loading…
Reference in a new issue