Merge branch 'hotfixes' of https://github.com/croneter/PlexKodiConnect into hotfixes
This commit is contained in:
commit
3e9e572e3c
10 changed files with 2203 additions and 135 deletions
|
@ -1,5 +1,5 @@
|
||||||
[![stable version](https://img.shields.io/badge/stable_version-1.8.16-blue.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect/bin/repository.plexkodiconnect/repository.plexkodiconnect-1.0.0.zip)
|
[![stable version](https://img.shields.io/badge/stable_version-1.8.18-blue.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect/bin/repository.plexkodiconnect/repository.plexkodiconnect-1.0.0.zip)
|
||||||
[![beta version](https://img.shields.io/badge/beta_version-1.8.16-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip)
|
[![beta version](https://img.shields.io/badge/beta_version-1.8.18-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip)
|
||||||
|
|
||||||
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
|
[![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)
|
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
||||||
|
|
18
addon.xml
18
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="1.8.16" provider-name="croneter">
|
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.8.18" provider-name="croneter">
|
||||||
<requires>
|
<requires>
|
||||||
<import addon="xbmc.python" version="2.1.0"/>
|
<import addon="xbmc.python" version="2.1.0"/>
|
||||||
<import addon="script.module.requests" version="2.3.0" />
|
<import addon="script.module.requests" version="2.3.0" />
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
<item>
|
<item>
|
||||||
<label>30401</label>
|
<label>30401</label>
|
||||||
<description>30416</description>
|
<description>30416</description>
|
||||||
<visible>[!IsEmpty(ListItem.DBID) + !StringCompare(ListItem.DBID,-1) | !IsEmpty(ListItem.Property(plexid))] + !IsEmpty(Window(10000).Property(plex_context))</visible>
|
<visible>[!IsEmpty(ListItem.DBID) + !StringCompare(ListItem.DBID,-1) | !IsEmpty(ListItem.Property(plexid))]</visible>
|
||||||
</item>
|
</item>
|
||||||
</extension>
|
</extension>
|
||||||
<extension point="xbmc.addon.metadata">
|
<extension point="xbmc.addon.metadata">
|
||||||
|
@ -59,7 +59,19 @@
|
||||||
<summary lang="da_DK">Indbygget Integration af Plex i Kodi</summary>
|
<summary lang="da_DK">Indbygget Integration af Plex i Kodi</summary>
|
||||||
<description lang="da_DK">Tilslut Kodi til din Plex Media Server. Dette plugin forudsætter, at du administrere alle dine videoer med Plex (og ikke med Kodi). Du kan miste data som allerede er gemt i Kodi video og musik-databaser (dette plugin ændrer direkte i dem). Brug på eget ansvar!</description>
|
<description lang="da_DK">Tilslut Kodi til din Plex Media Server. Dette plugin forudsætter, at du administrere alle dine videoer med Plex (og ikke med Kodi). Du kan miste data som allerede er gemt i Kodi video og musik-databaser (dette plugin ændrer direkte i dem). Brug på eget ansvar!</description>
|
||||||
<disclaimer lang="da_DK">Brug på eget ansvar</disclaimer>
|
<disclaimer lang="da_DK">Brug på eget ansvar</disclaimer>
|
||||||
<news>version 1.8.16:
|
<news>version 1.8.18:
|
||||||
|
- Russian translation, thanks @UncleStark, @xom2000, @AlexFreit
|
||||||
|
- Fix Plex context menu not showing up
|
||||||
|
- Deal better with missing stream info (e.g. channels)
|
||||||
|
- Fix AttributeError if Plex key is missing
|
||||||
|
|
||||||
|
version 1.8.17:
|
||||||
|
- Hopefully fix stable repo
|
||||||
|
- Fix subtitles not working or showing up as Unknown
|
||||||
|
- Enable channels for Plex home users
|
||||||
|
- Remove obsolete PKC settings show contextmenu
|
||||||
|
|
||||||
|
version 1.8.16:
|
||||||
- Add premiere dates for movies, thanks @dazedcrazy
|
- Add premiere dates for movies, thanks @dazedcrazy
|
||||||
- Fix items not getting marked as fully watched
|
- Fix items not getting marked as fully watched
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
version 1.8.18:
|
||||||
|
- Russian translation, thanks @UncleStark, @xom2000, @AlexFreit
|
||||||
|
- Fix Plex context menu not showing up
|
||||||
|
- Deal better with missing stream info (e.g. channels)
|
||||||
|
- Fix AttributeError if Plex key is missing
|
||||||
|
|
||||||
|
version 1.8.17:
|
||||||
|
- Hopefully fix stable repo
|
||||||
|
- Fix subtitles not working or showing up as Unknown
|
||||||
|
- Enable channels for Plex home users
|
||||||
|
- Remove obsolete PKC settings show contextmenu
|
||||||
|
|
||||||
version 1.8.16:
|
version 1.8.16:
|
||||||
- Add premiere dates for movies, thanks @dazedcrazy
|
- Add premiere dates for movies, thanks @dazedcrazy
|
||||||
- Fix items not getting marked as fully watched
|
- Fix items not getting marked as fully watched
|
||||||
|
|
2128
resources/language/resource.language.ru_RU/strings.po
Normal file
2128
resources/language/resource.language.ru_RU/strings.po
Normal file
File diff suppressed because it is too large
Load diff
|
@ -57,7 +57,7 @@ import state
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
log = logging.getLogger("PLEX."+__name__)
|
log = logging.getLogger("PLEX." + __name__)
|
||||||
|
|
||||||
REGEX_IMDB = re_compile(r'''/(tt\d+)''')
|
REGEX_IMDB = re_compile(r'''/(tt\d+)''')
|
||||||
REGEX_TVDB = re_compile(r'''thetvdb:\/\/(.+?)\?''')
|
REGEX_TVDB = re_compile(r'''thetvdb:\/\/(.+?)\?''')
|
||||||
|
@ -1177,9 +1177,9 @@ class API():
|
||||||
|
|
||||||
def getKey(self):
|
def getKey(self):
|
||||||
"""
|
"""
|
||||||
Returns the Plex key such as '/library/metadata/246922'
|
Returns the Plex key such as '/library/metadata/246922' or empty string
|
||||||
"""
|
"""
|
||||||
return self.item.attrib.get('key')
|
return self.item.attrib.get('key', '')
|
||||||
|
|
||||||
def getFilePath(self, forceFirstMediaStream=False):
|
def getFilePath(self, forceFirstMediaStream=False):
|
||||||
"""
|
"""
|
||||||
|
@ -1756,61 +1756,56 @@ class API():
|
||||||
subtitlelanguages = []
|
subtitlelanguages = []
|
||||||
try:
|
try:
|
||||||
# Sometimes, aspectratio is on the "toplevel"
|
# Sometimes, aspectratio is on the "toplevel"
|
||||||
aspectratio = self.item[0].attrib.get('aspectRatio', None)
|
aspect = self.item[0].attrib.get('aspectRatio')
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# There is no stream info at all, returning empty
|
# There is no stream info at all, returning empty
|
||||||
return {
|
return {
|
||||||
'video': videotracks,
|
'video': videotracks,
|
||||||
'audio': audiotracks,
|
'audio': audiotracks,
|
||||||
'subtitle': subtitlelanguages
|
'subtitle': subtitlelanguages
|
||||||
}
|
}
|
||||||
# TODO: what if several Media tags exist?!?
|
|
||||||
# Loop over parts
|
# Loop over parts
|
||||||
for child in self.item[0]:
|
for child in self.item[0]:
|
||||||
container = child.attrib.get('container', None)
|
container = child.attrib.get('container')
|
||||||
# Loop over Streams
|
# Loop over Streams
|
||||||
for grandchild in child:
|
for grandchild in child:
|
||||||
mediaStream = grandchild.attrib
|
stream = grandchild.attrib
|
||||||
mediaType = int(mediaStream.get('streamType', 999))
|
media_type = int(stream.get('streamType', 999))
|
||||||
if mediaType == 1: # Video streams
|
track = {}
|
||||||
videotrack = {}
|
if media_type == 1: # Video streams
|
||||||
videotrack['codec'] = mediaStream['codec'].lower()
|
if 'codec' in stream:
|
||||||
if "msmpeg4" in videotrack['codec']:
|
track['codec'] = stream['codec'].lower()
|
||||||
videotrack['codec'] = "divx"
|
if "msmpeg4" in track['codec']:
|
||||||
elif "mpeg4" in videotrack['codec']:
|
track['codec'] = "divx"
|
||||||
# if "simple profile" in profile or profile == "":
|
elif "mpeg4" in track['codec']:
|
||||||
# videotrack['codec'] = "xvid"
|
# if "simple profile" in profile or profile == "":
|
||||||
pass
|
# track['codec'] = "xvid"
|
||||||
elif "h264" in videotrack['codec']:
|
pass
|
||||||
if container in ("mp4", "mov", "m4v"):
|
elif "h264" in track['codec']:
|
||||||
videotrack['codec'] = "avc1"
|
if container in ("mp4", "mov", "m4v"):
|
||||||
videotrack['height'] = mediaStream.get('height', None)
|
track['codec'] = "avc1"
|
||||||
videotrack['width'] = mediaStream.get('width', None)
|
track['height'] = stream.get('height')
|
||||||
# TODO: 3d Movies?!?
|
track['width'] = stream.get('width')
|
||||||
# videotrack['Video3DFormat'] = item.get('Video3DFormat')
|
# track['Video3DFormat'] = item.get('Video3DFormat')
|
||||||
aspectratio = mediaStream.get('aspectRatio', aspectratio)
|
track['aspect'] = stream.get('aspectRatio', aspect)
|
||||||
videotrack['aspect'] = aspectratio
|
track['duration'] = self.getRuntime()[1]
|
||||||
# TODO: Video 3d format
|
track['video3DFormat'] = None
|
||||||
videotrack['video3DFormat'] = None
|
videotracks.append(track)
|
||||||
videotracks.append(videotrack)
|
elif media_type == 2: # Audio streams
|
||||||
|
if 'codec' in stream:
|
||||||
elif mediaType == 2: # Audio streams
|
track['codec'] = stream['codec'].lower()
|
||||||
audiotrack = {}
|
if ("dca" in track['codec'] and
|
||||||
audiotrack['codec'] = mediaStream['codec'].lower()
|
"ma" in stream.get('profile', '').lower()):
|
||||||
if ("dca" in audiotrack['codec'] and
|
track['codec'] = "dtshd_ma"
|
||||||
"ma" in mediaStream.get('profile', '').lower()):
|
track['channels'] = stream.get('channels')
|
||||||
audiotrack['codec'] = "dtshd_ma"
|
|
||||||
audiotrack['channels'] = mediaStream.get('channels')
|
|
||||||
# 'unknown' if we cannot get language
|
# 'unknown' if we cannot get language
|
||||||
audiotrack['language'] = mediaStream.get(
|
track['language'] = stream.get(
|
||||||
'languageCode', lang(39310)).lower()
|
'languageCode', lang(39310)).lower()
|
||||||
audiotracks.append(audiotrack)
|
audiotracks.append(track)
|
||||||
|
elif media_type == 3: # Subtitle streams
|
||||||
elif mediaType == 3: # Subtitle streams
|
|
||||||
# 'unknown' if we cannot get language
|
# 'unknown' if we cannot get language
|
||||||
subtitlelanguages.append(
|
subtitlelanguages.append(
|
||||||
mediaStream.get('languageCode',
|
stream.get('languageCode', lang(39310)).lower())
|
||||||
lang(39310)).lower())
|
|
||||||
return {
|
return {
|
||||||
'video': videotracks,
|
'video': videotracks,
|
||||||
'audio': audiotracks,
|
'audio': audiotracks,
|
||||||
|
@ -2370,14 +2365,10 @@ class API():
|
||||||
if key:
|
if key:
|
||||||
# We do know the language - temporarily download
|
# We do know the language - temporarily download
|
||||||
if stream.attrib.get('languageCode') is not None:
|
if stream.attrib.get('languageCode') is not None:
|
||||||
try:
|
|
||||||
language = v.LANGUAGECODE_TO_LANGUAGE[stream.attrib['languageCode']]
|
|
||||||
except KeyError:
|
|
||||||
language = stream.attrib['languageCode']
|
|
||||||
path = self.download_external_subtitles(
|
path = self.download_external_subtitles(
|
||||||
"{server}%s" % key,
|
"{server}%s" % key,
|
||||||
"subtitle%02d.%s.%s" % (fileindex,
|
"subtitle%02d.%s.%s" % (fileindex,
|
||||||
language,
|
stream.attrib['languageCode'],
|
||||||
stream.attrib['codec']))
|
stream.attrib['codec']))
|
||||||
fileindex += 1
|
fileindex += 1
|
||||||
# We don't know the language - no need to download
|
# We don't know the language - no need to download
|
||||||
|
@ -2567,18 +2558,9 @@ class API():
|
||||||
"""
|
"""
|
||||||
Add media stream information to xbmcgui.ListItem
|
Add media stream information to xbmcgui.ListItem
|
||||||
"""
|
"""
|
||||||
mediastreams = self.getMediaStreams()
|
for key, value in self.getMediaStreams().iteritems():
|
||||||
videostreamFound = False
|
if value:
|
||||||
if mediastreams:
|
listItem.addStreamInfo(key, value)
|
||||||
for key, value in mediastreams.iteritems():
|
|
||||||
if key == "video" and value:
|
|
||||||
videostreamFound = True
|
|
||||||
if value:
|
|
||||||
listItem.addStreamInfo(key, value)
|
|
||||||
if not videostreamFound:
|
|
||||||
# just set empty streamdetails to prevent errors in the logs
|
|
||||||
listItem.addStreamInfo(
|
|
||||||
"video", {'duration': self.getRuntime()[1]})
|
|
||||||
|
|
||||||
def validatePlayurl(self, path, typus, forceCheck=False, folder=False,
|
def validatePlayurl(self, path, typus, forceCheck=False, folder=False,
|
||||||
omitCheck=False):
|
omitCheck=False):
|
||||||
|
|
|
@ -752,10 +752,6 @@ def channels():
|
||||||
"""
|
"""
|
||||||
Listing for Plex Channels
|
Listing for Plex Channels
|
||||||
"""
|
"""
|
||||||
if window('plex_restricteduser') == 'true':
|
|
||||||
log.error('No Plex Channels - restricted user')
|
|
||||||
return xbmcplugin.endOfDirectory(HANDLE, False)
|
|
||||||
|
|
||||||
xml = downloadutils.DownloadUtils().downloadUrl('{server}/channels/all')
|
xml = downloadutils.DownloadUtils().downloadUrl('{server}/channels/all')
|
||||||
try:
|
try:
|
||||||
xml[0].attrib
|
xml[0].attrib
|
||||||
|
|
|
@ -22,7 +22,6 @@ log = getLogger("PLEX."+__name__)
|
||||||
|
|
||||||
# settings: window-variable
|
# settings: window-variable
|
||||||
WINDOW_SETTINGS = {
|
WINDOW_SETTINGS = {
|
||||||
'enableContext': 'plex_context',
|
|
||||||
'plex_restricteduser': 'plex_restricteduser',
|
'plex_restricteduser': 'plex_restricteduser',
|
||||||
'force_transcode_pix': 'plex_force_transcode_pix',
|
'force_transcode_pix': 'plex_force_transcode_pix',
|
||||||
'fetch_pms_item_number': 'fetch_pms_item_number'
|
'fetch_pms_item_number': 'fetch_pms_item_number'
|
||||||
|
|
|
@ -21,66 +21,8 @@ def tryDecode(string, encoding='utf-8'):
|
||||||
string = string.decode()
|
string = string.decode()
|
||||||
return string
|
return string
|
||||||
|
|
||||||
# When does Plex mark a video as completely played?
|
|
||||||
MARK_PLAYED_AT = 0.9
|
MARK_PLAYED_AT = 0.9
|
||||||
|
|
||||||
# Matching table for using Plex XML's stream 'languageCode'
|
|
||||||
LANGUAGECODE_TO_LANGUAGE = {
|
|
||||||
'afr': 'Afrikaans',
|
|
||||||
'ara': 'Arabic',
|
|
||||||
'hye': 'Armenian',
|
|
||||||
'bul': 'Bulgarian',
|
|
||||||
'cat': 'Catala',
|
|
||||||
'chi': 'Mandarin',
|
|
||||||
'hrv': 'Hrvatski',
|
|
||||||
'cze': 'Cesky',
|
|
||||||
'dan': 'Dansk',
|
|
||||||
'dut': 'Nederlands',
|
|
||||||
'eng': 'English',
|
|
||||||
'epo': 'Esperanto',
|
|
||||||
'fin': 'Suomi',
|
|
||||||
'fre': 'Francais',
|
|
||||||
'ger': 'Deutsch',
|
|
||||||
'geo': 'Georgian',
|
|
||||||
'gre': 'Greek',
|
|
||||||
'heb': 'Hebrew',
|
|
||||||
'hin': 'Hindi',
|
|
||||||
'hun': 'Magyar',
|
|
||||||
'ind': 'Bahasa Indonesia',
|
|
||||||
'gle': 'Gaeilge',
|
|
||||||
'ice': 'Islenska',
|
|
||||||
'ita': 'Italiano',
|
|
||||||
'jpn': 'Japanese',
|
|
||||||
'kor': 'Korean',
|
|
||||||
'kur': 'Kurdi',
|
|
||||||
'lat': 'Latin',
|
|
||||||
'mac': 'Macedonian',
|
|
||||||
'may': 'Malay',
|
|
||||||
'mlt': 'Malti',
|
|
||||||
'nep': 'Nepali',
|
|
||||||
'nor': 'Norsk',
|
|
||||||
'per': 'Persian',
|
|
||||||
'pol': 'Polszczyzna',
|
|
||||||
'por': 'Portugues',
|
|
||||||
'rum': 'Romana',
|
|
||||||
'rus': 'Russian',
|
|
||||||
'srp': 'Serbian',
|
|
||||||
'gla': 'Gaidhlig',
|
|
||||||
'slo': 'Slovencina',
|
|
||||||
'slv': 'Slovenski Jezik',
|
|
||||||
'spa': 'Espanol',
|
|
||||||
'swe': 'Svenska',
|
|
||||||
'tam': 'Tamil',
|
|
||||||
'tha': 'Thai',
|
|
||||||
'tur': 'Turkish',
|
|
||||||
'tah': 'Tahitian',
|
|
||||||
'ukr': 'Ukrainian',
|
|
||||||
'uzb': 'Ozbek',
|
|
||||||
'vie': 'Tieng Viet',
|
|
||||||
'wel': 'Cymraeg',
|
|
||||||
'yid': 'Yiddish',
|
|
||||||
}
|
|
||||||
|
|
||||||
_ADDON = Addon()
|
_ADDON = Addon()
|
||||||
ADDON_NAME = 'PlexKodiConnect'
|
ADDON_NAME = 'PlexKodiConnect'
|
||||||
ADDON_ID = 'plugin.video.plexkodiconnect'
|
ADDON_ID = 'plugin.video.plexkodiconnect'
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
<setting type="lsep" label="39700" />
|
<setting type="lsep" label="39700" />
|
||||||
<setting id="enable_alexa" label="39701" type="bool" default="true"/>
|
<setting id="enable_alexa" label="39701" type="bool" default="true"/>
|
||||||
<setting type="lsep" label="" />
|
<setting type="lsep" label="" />
|
||||||
<setting id="enableContext" type="bool" label="30413" default="true" />
|
|
||||||
<setting id="skipContextMenu" type="bool" label="30520" default="false" visible="eq(-1,true)" subsetting="true" />
|
<setting id="skipContextMenu" type="bool" label="30520" default="false" visible="eq(-1,true)" subsetting="true" />
|
||||||
<setting id="plex_restricteduser" type="bool" default="false" visible="false"/>
|
<setting id="plex_restricteduser" type="bool" default="false" visible="false"/>
|
||||||
<setting id="plex_allows_mediaDeletion" type="bool" default="true" visible="false"/>
|
<setting id="plex_allows_mediaDeletion" type="bool" default="true" visible="false"/>
|
||||||
|
|
|
@ -85,8 +85,6 @@ class Service():
|
||||||
|
|
||||||
window('plex_kodiProfile',
|
window('plex_kodiProfile',
|
||||||
value=tryDecode(translatePath("special://profile")))
|
value=tryDecode(translatePath("special://profile")))
|
||||||
window('plex_context',
|
|
||||||
value='true' if settings('enableContext') == "true" else "")
|
|
||||||
window('fetch_pms_item_number',
|
window('fetch_pms_item_number',
|
||||||
value=settings('fetch_pms_item_number'))
|
value=settings('fetch_pms_item_number'))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue