Merge branch 'develop' into translations
This commit is contained in:
commit
0f292c2799
12 changed files with 156 additions and 19 deletions
|
@ -1,5 +1,5 @@
|
|||
[![stable version](https://img.shields.io/badge/stable_version-1.8.0-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.0-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip)
|
||||
[![stable version](https://img.shields.io/badge/stable_version-1.8.1-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.1-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)
|
||||
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)
|
||||
|
|
10
addon.xml
10
addon.xml
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.8.0" provider-name="croneter">
|
||||
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.8.1" provider-name="croneter">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="2.1.0"/>
|
||||
<import addon="script.module.requests" version="2.3.0" />
|
||||
|
@ -44,7 +44,13 @@
|
|||
<disclaimer lang="nl_NL">Gebruik op eigen risico</disclaimer>
|
||||
<disclaimer lang="zh_TW">使用風險由您自己承擔</disclaimer>
|
||||
<disclaimer lang="es_ES">Usar a su propio riesgo</disclaimer>
|
||||
<news>version 1.8.0
|
||||
<news>version 1.8.1:
|
||||
- Fix library sync crash due to UnicodeDecodeError
|
||||
- Fix fanart for collections
|
||||
- Comply with themoviedb.org terms of use
|
||||
- Add some translations
|
||||
|
||||
version 1.8.0
|
||||
Featuring:
|
||||
- Major music overhaul: Direct Paths should now work! Many thanks @Memesa for the pointers! Don't forget to reset your database
|
||||
- Big transcoding overhaul
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
version 1.8.1:
|
||||
- Fix library sync crash due to UnicodeDecodeError
|
||||
- Fix fanart for collections
|
||||
- Comply with themoviedb.org terms of use
|
||||
- Add some translations
|
||||
|
||||
version 1.8.0
|
||||
Featuring:
|
||||
- Major music overhaul: Direct Paths should now work! Many thanks @Memesa for the pointers! Don't forget to reset your database
|
||||
|
|
|
@ -1944,3 +1944,13 @@ msgstr ""
|
|||
msgctxt "#39717"
|
||||
msgid "PKC uses free additional artwork from www.themoviedb.org. Many thanks!"
|
||||
msgstr ""
|
||||
|
||||
# Shown during very first PKC setup only
|
||||
msgctxt "#39718"
|
||||
msgid "Do you want to replace your custom user ratings with an indicator of how many versions of a media item you posses?"
|
||||
msgstr ""
|
||||
|
||||
# In PKC Settings under Sync
|
||||
msgctxt "#39719"
|
||||
msgid "Replace user ratings with number of media versions"
|
||||
msgstr ""
|
||||
|
|
|
@ -1288,10 +1288,17 @@ class API():
|
|||
except (KeyError, ValueError):
|
||||
lastPlayedDate = None
|
||||
|
||||
try:
|
||||
userrating = int(float(item['userRating']))
|
||||
except (KeyError, ValueError):
|
||||
if state.INDICATE_MEDIA_VERSIONS is True:
|
||||
userrating = 0
|
||||
for entry in self.item.findall('./Media'):
|
||||
userrating += 1
|
||||
# Don't show a value of '1'
|
||||
userrating = 0 if userrating == 1 else userrating
|
||||
else:
|
||||
try:
|
||||
userrating = int(float(item['userRating']))
|
||||
except (KeyError, ValueError):
|
||||
userrating = 0
|
||||
|
||||
try:
|
||||
rating = float(item['audienceRating'])
|
||||
|
@ -1881,7 +1888,8 @@ class API():
|
|||
|
||||
If not found in item's Plex metadata, check themovidedb.org
|
||||
|
||||
collection=True will try to return the collection's ID
|
||||
collection=True will try to return the three-tuple:
|
||||
collection ID, poster-path, background-path
|
||||
|
||||
None is returned if unsuccessful
|
||||
"""
|
||||
|
@ -1900,7 +1908,8 @@ class API():
|
|||
log.info('Plex did not provide ID for IMDB or TVDB. Start '
|
||||
'lookup process')
|
||||
else:
|
||||
log.info('Start movie set/collection lookup on themoviedb')
|
||||
log.info('Start movie set/collection lookup on themoviedb using %s'
|
||||
% item.get('title', ''))
|
||||
|
||||
apiKey = settings('themoviedbAPIKey')
|
||||
if media_type == v.PLEX_TYPE_SHOW:
|
||||
|
@ -1909,7 +1918,7 @@ class API():
|
|||
# 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 = 'http://api.themoviedb.org/3/search/%s' % media_type
|
||||
url = 'https://api.themoviedb.org/3/search/%s' % media_type
|
||||
parameters = {
|
||||
'api_key': apiKey,
|
||||
'language': v.KODILANGUAGE,
|
||||
|
@ -2001,10 +2010,10 @@ class API():
|
|||
for language in [v.KODILANGUAGE, "en"]:
|
||||
parameters['language'] = language
|
||||
if media_type == "movie":
|
||||
url = 'http://api.themoviedb.org/3/movie/%s' % tmdbId
|
||||
url = 'https://api.themoviedb.org/3/movie/%s' % tmdbId
|
||||
parameters['append_to_response'] = 'videos'
|
||||
elif media_type == "tv":
|
||||
url = 'http://api.themoviedb.org/3/tv/%s' % tmdbId
|
||||
url = 'https://api.themoviedb.org/3/tv/%s' % tmdbId
|
||||
parameters['append_to_response'] = 'external_ids,videos'
|
||||
data = DownloadUtils().downloadUrl(
|
||||
url,
|
||||
|
@ -2025,9 +2034,28 @@ class API():
|
|||
mediaId = str(data["external_ids"].get("tvdb_id"))
|
||||
break
|
||||
else:
|
||||
if data.get("belongs_to_collection") is not None:
|
||||
mediaId = str(data.get("belongs_to_collection").get("id"))
|
||||
log.debug('Retrieved collections tmdb id %s' % mediaId)
|
||||
if data.get("belongs_to_collection") is None:
|
||||
continue
|
||||
mediaId = str(data.get("belongs_to_collection").get("id"))
|
||||
log.debug('Retrieved collections tmdb id %s for %s'
|
||||
% (mediaId, title))
|
||||
url = 'https://api.themoviedb.org/3/collection/%s' % mediaId
|
||||
data = DownloadUtils().downloadUrl(
|
||||
url,
|
||||
authenticate=False,
|
||||
parameters=parameters,
|
||||
timeout=7)
|
||||
try:
|
||||
data.get('poster_path')
|
||||
except AttributeError:
|
||||
log.info('Could not find TheMovieDB poster paths for %s in'
|
||||
'the language %s' % (title, language))
|
||||
continue
|
||||
else:
|
||||
poster = 'https://image.tmdb.org/t/p/original%s' % data.get('poster_path')
|
||||
background = 'https://image.tmdb.org/t/p/original%s' % data.get('backdrop_path')
|
||||
mediaId = mediaId, poster, background
|
||||
break
|
||||
return mediaId
|
||||
|
||||
def getFanartTVArt(self, mediaId, allartworks, setInfo=False):
|
||||
|
@ -2158,7 +2186,18 @@ class API():
|
|||
# fanart tv only for movie or tv show
|
||||
externalId = self.getExternalItemId(collection=True)
|
||||
if externalId is not None:
|
||||
try:
|
||||
externalId, poster, background = externalId
|
||||
except TypeError:
|
||||
poster, background = None, None
|
||||
if poster is not None:
|
||||
allartworks['Primary'] = poster
|
||||
if background is not None:
|
||||
allartworks['Backdrop'].append(background)
|
||||
allartworks = self.getFanartTVArt(externalId, allartworks, True)
|
||||
else:
|
||||
log.info('Did not find a set/collection ID on TheMovieDB using %s.'
|
||||
' Artwork will be missing.' % self.getTitle()[0])
|
||||
return allartworks
|
||||
|
||||
def shouldStream(self):
|
||||
|
|
|
@ -12,6 +12,7 @@ from plexbmchelper import listener, plexgdm, subscribers, functions, \
|
|||
httppersist, plexsettings
|
||||
from PlexFunctions import ParseContainerKey, GetPlexMetadata
|
||||
from PlexAPI import API
|
||||
from playlist_func import get_pms_playqueue, get_plextype_from_xml
|
||||
import player
|
||||
import variables as v
|
||||
import state
|
||||
|
@ -149,6 +150,26 @@ class PlexCompanion(Thread):
|
|||
offset=data.get('offset'))
|
||||
playqueue.plex_transient_token = token
|
||||
|
||||
elif task['action'] == 'refreshPlayQueue':
|
||||
# example data: {'playQueueID': '8475', 'commandID': '11'}
|
||||
xml = get_pms_playqueue(data['playQueueID'])
|
||||
if xml is None:
|
||||
return
|
||||
if len(xml) == 0:
|
||||
log.debug('Empty playqueue received - clearing playqueue')
|
||||
plex_type = get_plextype_from_xml(xml)
|
||||
if plex_type is None:
|
||||
return
|
||||
playqueue = self.mgr.playqueue.get_playqueue_from_type(
|
||||
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type])
|
||||
playqueue.clear()
|
||||
return
|
||||
playqueue = self.mgr.playqueue.get_playqueue_from_type(
|
||||
v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[xml[0].attrib['type']])
|
||||
self.mgr.playqueue.update_playqueue_from_PMS(
|
||||
playqueue,
|
||||
data['playQueueID'])
|
||||
|
||||
def run(self):
|
||||
# Ensure that sockets will be closed no matter what
|
||||
try:
|
||||
|
|
|
@ -110,11 +110,19 @@ def process_command(request_path, params, queue=None):
|
|||
'data': params
|
||||
})
|
||||
|
||||
elif request_path == 'player/playback/refreshPlayQueue':
|
||||
queue.put({
|
||||
'action': 'refreshPlayQueue',
|
||||
'data': params
|
||||
})
|
||||
|
||||
elif request_path == "player/playback/setParameters":
|
||||
if 'volume' in params:
|
||||
volume = int(params['volume'])
|
||||
log.debug("Adjusting the volume to %s" % volume)
|
||||
JSONRPC('Application.SetVolume').execute({"volume": volume})
|
||||
else:
|
||||
log.error('Unknown parameters: %s' % params)
|
||||
|
||||
elif request_path == "player/playback/play":
|
||||
for playerid in getPlayerIds():
|
||||
|
|
|
@ -488,10 +488,16 @@ class InitialSetup():
|
|||
if dialog.yesno(heading=lang(29999), line1=lang(39061)):
|
||||
log.debug("User opted to use FanArtTV")
|
||||
settings('FanartTV', value="true")
|
||||
# Do you want to replace your custom user ratings with an indicator of
|
||||
# how many versions of a media item you posses?
|
||||
if dialog.yesno(heading=lang(29999), line1=lang(39718)):
|
||||
log.debug("User opted to replace user ratings with version number")
|
||||
settings('indicate_media_versions', value="true")
|
||||
|
||||
# If you use several Plex libraries of one kind, e.g. "Kids Movies" and
|
||||
# "Parents Movies", be sure to check https://goo.gl/JFtQV9
|
||||
dialog.ok(heading=lang(29999), line1=lang(39076))
|
||||
|
||||
# Need to tell about our image source for collections: themoviedb.org
|
||||
dialog.ok(heading=lang(29999), line1=lang(39717))
|
||||
# Make sure that we only ask these questions upon first installation
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
import logging
|
||||
from urllib import quote
|
||||
from urlparse import parse_qsl, urlsplit
|
||||
from re import compile as re_compile
|
||||
|
||||
import plexdb_functions as plexdb
|
||||
from downloadutils import DownloadUtils as DU
|
||||
from utils import JSONRPC, tryEncode, escape_html
|
||||
from PlexAPI import API
|
||||
from PlexFunctions import GetPlexMetadata
|
||||
|
||||
###############################################################################
|
||||
|
||||
log = logging.getLogger("PLEX."+__name__)
|
||||
|
||||
REGEX = re_compile(r'''metadata%2F(\d+)''')
|
||||
###############################################################################
|
||||
|
||||
# kodi_item dict:
|
||||
|
@ -63,9 +66,6 @@ class Playlist_Object_Baseclase(object):
|
|||
self.plex_transient_token = None
|
||||
log.debug('Playlist cleared: %s' % self)
|
||||
|
||||
def log_Kodi_playlist(self):
|
||||
log.debug('Current Kodi playlist: %s' % get_kodi_playlist_items(self))
|
||||
|
||||
|
||||
class Playlist_Object(Playlist_Object_Baseclase):
|
||||
kind = 'playList'
|
||||
|
@ -566,3 +566,39 @@ def remove_from_Kodi_playlist(playlist, pos):
|
|||
del playlist.items[pos]
|
||||
except IndexError:
|
||||
log.error('Cannot delete position %s for %s' % (pos, playlist))
|
||||
|
||||
|
||||
def get_pms_playqueue(playqueue_id):
|
||||
"""
|
||||
Returns the Plex playqueue as an etree XML or None if unsuccessful
|
||||
"""
|
||||
xml = DU().downloadUrl(
|
||||
"{server}/playQueues/%s" % playqueue_id,
|
||||
headerOptions={'Accept': 'application/xml'})
|
||||
try:
|
||||
xml.attrib
|
||||
except AttributeError:
|
||||
log.error('Could not download Plex playqueue %s' % playqueue_id)
|
||||
xml = None
|
||||
return xml
|
||||
|
||||
|
||||
def get_plextype_from_xml(xml):
|
||||
"""
|
||||
Needed if PMS returns an empty playqueue. Will get the Plex type from the
|
||||
empty playlist playQueueSourceURI. Feed with (empty) etree xml
|
||||
|
||||
returns None if unsuccessful
|
||||
"""
|
||||
try:
|
||||
plex_id = REGEX.findall(xml.attrib['playQueueSourceURI'])[0]
|
||||
except IndexError:
|
||||
log.error('Could not get plex_id from xml: %s' % xml.attrib)
|
||||
return
|
||||
new_xml = GetPlexMetadata(plex_id)
|
||||
try:
|
||||
new_xml[0].attrib
|
||||
except (TypeError, IndexError, AttributeError):
|
||||
log.error('Could not get plex metadata for plex id %s' % plex_id)
|
||||
return
|
||||
return new_xml[0].attrib.get('type')
|
||||
|
|
|
@ -22,6 +22,8 @@ RESTRICTED_USER = False
|
|||
# Direct Paths (True) or Addon Paths (False)? Along with
|
||||
# window('useDirectPaths')
|
||||
DIRECT_PATHS = False
|
||||
# Shall we replace custom user ratings with the number of versions available?
|
||||
INDICATE_MEDIA_VERSIONS = False
|
||||
|
||||
# Along with window('plex_authenticated')
|
||||
AUTHENTICATED = False
|
||||
|
|
|
@ -165,6 +165,8 @@ class UserClient(threading.Thread):
|
|||
if settings('useDirectPaths') == "1" else 'false')
|
||||
state.DIRECT_PATHS = True if settings('useDirectPaths') == "1" \
|
||||
else False
|
||||
state.INDICATE_MEDIA_VERSIONS = True \
|
||||
if settings('indicate_media_versions') == "true" else False
|
||||
window('plex_force_transcode_pix', value='true'
|
||||
if settings('force_transcode_pix') == "1" else 'false')
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
<setting id="dbSyncScreensaver" type="bool" label="39062" default="false" /><!--Sync when screensaver is deactivated-->
|
||||
|
||||
<setting type="lsep" label="30538" /><!-- Complete Re-Sync necessary -->
|
||||
<setting id="indicate_media_versions" type="bool" label="39719" default="false" /><!-- Replace user ratings with number of versions -->
|
||||
<setting id="enableMusic" type="bool" label="30509" default="true" />
|
||||
<setting id="useDirectPaths" type="enum" label="30511" values="Addon(Default)|Native(Direct paths)" default="0" visible="true"/> <!-- Playback mode -->
|
||||
|
||||
|
|
Loading…
Reference in a new issue