Merge branch 'translations' into l10n_translations

This commit is contained in:
tomkat83 2017-03-09 13:04:43 +01:00
commit 1d424cf547
11 changed files with 476 additions and 316 deletions

View file

@ -1,14 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect" <addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.6.5" provider-name="croneter">
name="PlexKodiConnect"
version="1.6.4"
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" />
</requires> </requires>
<extension point="xbmc.python.pluginsource" <extension point="xbmc.python.pluginsource" library="default.py">
library="default.py">
<provides>video audio image</provides> <provides>video audio image</provides>
</extension> </extension>
<extension point="xbmc.service" library="service.py" start="login"> <extension point="xbmc.service" library="service.py" start="login">
@ -21,6 +17,13 @@
</item> </item>
</extension> </extension>
<extension point="xbmc.addon.metadata"> <extension point="xbmc.addon.metadata">
<platform>all</platform>
<language></language>
<license>GNU GENERAL PUBLIC LICENSE. Version 2, June 1991</license>
<forum>https://forums.plex.tv</forum>
<website>https://github.com/croneter/PlexKodiConnect</website>
<email></email>
<source>https://github.com/croneter/PlexKodiConnect</source>
<summary lang="en">Native Integration of Plex into Kodi</summary> <summary lang="en">Native Integration of Plex into Kodi</summary>
<summary lang="en_gb">Native Integration of Plex into Kodi</summary> <summary lang="en_gb">Native Integration of Plex into Kodi</summary>
<summary lang="en_us">Native Integration of Plex into Kodi</summary> <summary lang="en_us">Native Integration of Plex into Kodi</summary>
@ -37,11 +40,5 @@
<description lang="es">Connect Kodi to your Plex Media Server. This plugin assumes that you manage all your videos with Plex (and none with Kodi). You might lose data already stored in the Kodi video and music databases (as this plugin directly changes them). Use at your own risk!</description> <description lang="es">Connect Kodi to your Plex Media Server. This plugin assumes that you manage all your videos with Plex (and none with Kodi). You might lose data already stored in the Kodi video and music databases (as this plugin directly changes them). Use at your own risk!</description>
<description lang="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="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="nl">Verbind Kodi met je Plex Media Server. Deze plugin gaat ervan uit dat je al je video's met Plex (en niet met Kodi) beheerd. Je kunt gegevens reeds opgeslagen in de databases voor video en muziek van Kodi (deze plugin wijzigt deze gegevens direct) verliezen. Gebruik op eigen risico!</description> <description lang="nl">Verbind Kodi met je Plex Media Server. Deze plugin gaat ervan uit dat je al je video's met Plex (en niet met Kodi) beheerd. Je kunt gegevens reeds opgeslagen in de databases voor video en muziek van Kodi (deze plugin wijzigt deze gegevens direct) verliezen. Gebruik op eigen risico!</description>
<platform>all</platform>
<license>GPL v2.0</license>
<forum>https://forums.plex.tv</forum>
<website>https://github.com/croneter/PlexKodiConnect</website>
<email></email>
<source>https://github.com/croneter/PlexKodiConnect</source>
</extension> </extension>
</addon> </addon>

View file

@ -1,3 +1,9 @@
version 1.6.5 (beta only)
- Plex Channels!
- Browse video nodes by folder/path
- Update Danish translation
- Code optimization
version 1.6.4 (beta only) version 1.6.4 (beta only)
- Amazon Alexa support! Be mindful to check the Alexa forum thread first; there are still many issues completely unrelated to PKC - Amazon Alexa support! Be mindful to check the Alexa forum thread first; there are still many issues completely unrelated to PKC
- Enable skipping for Plex Companion - Enable skipping for Plex Companion

View file

@ -36,13 +36,14 @@ from utils import window, pickl_window, reset, passwordsXML, language as lang,\
dialog dialog
from pickler import unpickle_me from pickler import unpickle_me
from PKC_listitem import convert_PKC_to_listitem from PKC_listitem import convert_PKC_to_listitem
import variables as v
############################################################################### ###############################################################################
import loghandler import loghandler
loghandler.config() loghandler.config()
log = logging.getLogger("PLEX.default") log = logging.getLogger('PLEX.default')
############################################################################### ###############################################################################
@ -50,144 +51,160 @@ HANDLE = int(argv[1])
class Main(): class Main():
# MAIN ENTRY POINT # MAIN ENTRY POINT
# @utils.profiling() # @utils.profiling()
def __init__(self): def __init__(self):
log.debug("Full sys.argv received: %s" % argv) log.debug('Full sys.argv received: %s' % argv)
# Parse parameters # Parse parameters
params = dict(parse_qsl(argv[2][1:])) params = dict(parse_qsl(argv[2][1:]))
try: mode = params.get('mode', '')
mode = params['mode'] itemid = params.get('id', '')
itemid = params.get('id', '')
except:
mode = ""
itemid = ''
if mode == 'play': if mode == 'play':
# Put the request into the "queue" self.play()
while window('plex_play_new_item'):
sleep(50)
window('plex_play_new_item',
value='%s%s' % (mode, argv[2]))
# Wait for the result
while not pickl_window('plex_result'):
sleep(50)
result = unpickle_me()
if result is None:
log.error('Error encountered, aborting')
dialog('notification',
heading='{plex}',
message=lang(30128),
icon='{error}',
time=3000)
setResolvedUrl(HANDLE, False, ListItem())
elif result.listitem:
listitem = convert_PKC_to_listitem(result.listitem)
setResolvedUrl(HANDLE, True, listitem)
return
modes = { elif mode == 'ondeck':
'reset': reset, entrypoint.getOnDeck(itemid,
'resetauth': entrypoint.resetAuth, params.get('type'),
'passwords': passwordsXML, params.get('tagname'),
'getsubfolders': entrypoint.GetSubFolders, int(params.get('limit')))
'nextup': entrypoint.getNextUpEpisodes,
'inprogressepisodes': entrypoint.getInProgressEpisodes,
'recentepisodes': entrypoint.getRecentEpisodes,
'refreshplaylist': entrypoint.refreshPlaylist,
'switchuser': entrypoint.switchPlexUser,
'deviceid': entrypoint.resetDeviceId,
'browseplex': entrypoint.BrowsePlexContent,
'ondeck': entrypoint.getOnDeck,
'chooseServer': entrypoint.chooseServer,
'watchlater': entrypoint.watchlater,
'enterPMS': entrypoint.enterPMS,
'togglePlexTV': entrypoint.togglePlexTV,
'Plex_Node': entrypoint.Plex_Node
}
if "/extrafanart" in argv[0]: elif mode == 'recentepisodes':
plexpath = argv[2][1:] entrypoint.getRecentEpisodes(itemid,
plexid = params.get('id') params.get('type'),
entrypoint.getExtraFanArt(plexid, plexpath) params.get('tagname'),
entrypoint.getVideoFiles(plexid, plexpath) int(params.get('limit')))
return
if mode == 'fanart': elif mode == 'nextup':
entrypoint.getNextUpEpisodes(params['tagname'],
int(params['limit']))
elif mode == 'inprogressepisodes':
entrypoint.getInProgressEpisodes(params['tagname'],
int(params['limit']))
elif mode == 'Plex_Node':
entrypoint.Plex_Node(itemid, params.get('viewOffset'))
elif mode == 'browseplex':
entrypoint.browse_plex(key=params.get('key'),
plex_section_id=params.get('id'))
elif mode == 'getsubfolders':
entrypoint.GetSubFolders(itemid)
elif mode == 'watchlater':
entrypoint.watchlater()
elif mode == 'channels':
entrypoint.channels()
elif mode == 'settings':
executebuiltin('Addon.OpenSettings(%s)' % v.ADDON_ID)
elif mode == 'enterPMS':
entrypoint.enterPMS()
elif mode == 'reset':
reset()
elif mode == 'togglePlexTV':
entrypoint.togglePlexTV()
elif mode == 'resetauth':
entrypoint.resetAuth()
elif mode == 'passwords':
passwordsXML()
elif mode == 'switchuser':
entrypoint.switchPlexUser()
elif mode in ('manualsync', 'repair'):
if window('plex_online') != 'true':
# Server is not online, do not run the sync
dialog('ok',
heading=lang(29999),
message=lang(39205))
log.error('Not connected to a PMS.')
else:
if mode == 'repair':
window('plex_runLibScan', value='repair')
log.info('Requesting repair lib sync')
elif mode == 'manualsync':
log.info('Requesting full library scan')
window('plex_runLibScan', value='full')
elif mode == 'texturecache':
window('plex_runLibScan', value='del_textures')
elif mode == 'chooseServer':
entrypoint.chooseServer()
elif mode == 'refreshplaylist':
log.info('Requesting playlist/nodes refresh')
window('plex_runLibScan', value='views')
elif mode == 'deviceid':
self.deviceid()
elif mode == 'fanart':
log.info('User requested fanarttv refresh') log.info('User requested fanarttv refresh')
window('plex_runLibScan', value='fanart') window('plex_runLibScan', value='fanart')
elif '/extrafanart' in argv[0]:
plexpath = argv[2][1:]
plexid = itemid
entrypoint.getExtraFanArt(plexid, plexpath)
entrypoint.getVideoFiles(plexid, plexpath)
# Called by e.g. 3rd party plugin video extras # Called by e.g. 3rd party plugin video extras
if ("/Extras" in argv[0] or "/VideoFiles" in argv[0] or elif ('/Extras' in argv[0] or '/VideoFiles' in argv[0] or
"/Extras" in argv[2]): '/Extras' in argv[2]):
plexId = params.get('id', None) plexId = itemid or None
entrypoint.getVideoFiles(plexId, params) entrypoint.getVideoFiles(plexId, params)
if modes.get(mode):
# Simple functions
if mode == "play":
dbid = params.get('dbid')
# modes[mode](itemid, dbid)
modes[mode](itemid, dbid)
elif mode in ("nextup", "inprogressepisodes"):
limit = int(params['limit'])
modes[mode](params['tagname'], limit)
elif mode in ("channels","getsubfolders"):
modes[mode](itemid)
elif mode == "browsecontent":
modes[mode](itemid, params.get('type'), params.get('folderid'))
elif mode == 'browseplex':
modes[mode](
itemid,
params.get('type'),
params.get('folderid'))
elif mode in ('ondeck', 'recentepisodes'):
modes[mode](
itemid,
params.get('type'),
params.get('tagname'),
int(params.get('limit')))
elif mode == "channelsfolder":
folderid = params['folderid']
modes[mode](itemid, folderid)
elif mode == "companion":
modes[mode](itemid, params=argv[2])
elif mode == 'Plex_Node':
modes[mode](params.get('id'),
params.get('viewOffset'))
else:
modes[mode]()
else: else:
# Other functions entrypoint.doMainListing()
if mode == "settings":
executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
elif mode in ("manualsync", "repair"):
if window('plex_online') != "true":
# Server is not online, do not run the sync
dialog('ok',
heading=lang(29999),
message=lang(39205))
log.error("Not connected to a PMS.")
else:
if mode == 'repair':
window('plex_runLibScan', value="repair")
log.info("Requesting repair lib sync")
elif mode == 'manualsync':
log.info("Requesting full library scan")
window('plex_runLibScan', value="full")
elif mode == "texturecache":
window('plex_runLibScan', value='del_textures')
else:
entrypoint.doMainListing()
if __name__ == "__main__": def play(self):
log.info('plugin.video.plexkodiconnect started') # Put the request into the 'queue'
while window('plex_play_new_item'):
sleep(50)
window('plex_play_new_item',
value='%s%s' % ('play', argv[2]))
# Wait for the result
while not pickl_window('plex_result'):
sleep(50)
result = unpickle_me()
if result is None:
log.error('Error encountered, aborting')
dialog('notification',
heading='{plex}',
message=lang(30128),
icon='{error}',
time=3000)
setResolvedUrl(HANDLE, False, ListItem())
elif result.listitem:
listitem = convert_PKC_to_listitem(result.listitem)
setResolvedUrl(HANDLE, True, listitem)
def deviceid(self):
deviceId_old = window('plex_client_Id')
from clientinfo import getDeviceId
try:
deviceId = getDeviceId(reset=True)
except Exception as e:
log.error('Failed to generate a new device Id: %s' % e)
dialog('ok', lang(29999), lang(33032))
else:
log.info('Successfully removed old device ID: %s New deviceId:'
'%s' % (deviceId_old, deviceId))
# 'Kodi will now restart to apply the changes'
dialog('ok', lang(29999), lang(33033))
executebuiltin('RestartApp')
if __name__ == '__main__':
log.info('%s started' % v.ADDON_ID)
Main() Main()
log.info('plugin.video.plexkodiconnect stopped') log.info('%s stopped' % v.ADDON_ID)

View file

@ -515,6 +515,5 @@
<string id="39603">Nulstil alle indstillinger for PlexKodiConnect Addon? (dette er normalt ikke anbefalet og unødvendigt!)</string> <string id="39603">Nulstil alle indstillinger for PlexKodiConnect Addon? (dette er normalt ikke anbefalet og unødvendigt!)</string>
<string id="39700">Amazon Alexa (Voice Recognition)</string> <string id="39700">Amazon Alexa (Voice Recognition)</string>
<string id="39701">Activate Alexa</string> <string id="39701">Alexa aktivieren</string>
<string id="39702">Browse by folder</string>
</strings> </strings>

View file

@ -106,7 +106,10 @@ def Plex_Node(url, viewOffset, playdirectly=False, node=True):
log.info('Plex_Node called with url: %s, viewOffset: %s' log.info('Plex_Node called with url: %s, viewOffset: %s'
% (url, viewOffset)) % (url, viewOffset))
# Plex redirect, e.g. watch later. Need to get actual URLs # Plex redirect, e.g. watch later. Need to get actual URLs
xml = downloadutils.DownloadUtils().downloadUrl(url) if url.startswith('http'):
xml = downloadutils.DownloadUtils().downloadUrl(url)
else:
xml = downloadutils.DownloadUtils().downloadUrl('{server}%s' % url)
try: try:
xml[0].attrib xml[0].attrib
except: except:
@ -114,8 +117,7 @@ def Plex_Node(url, viewOffset, playdirectly=False, node=True):
return return
if viewOffset != '0': if viewOffset != '0':
try: try:
viewOffset = int(v.PLEX_TO_KODI_TIMEFACTOR * viewOffset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(viewOffset))
float(viewOffset))
except: except:
pass pass
else: else:
@ -194,6 +196,9 @@ def doMainListing():
# Plex Watch later # Plex Watch later
addDirectoryItem(lang(39211), addDirectoryItem(lang(39211),
"plugin://plugin.video.plexkodiconnect/?mode=watchlater") "plugin://plugin.video.plexkodiconnect/?mode=watchlater")
# Plex Channels
addDirectoryItem(lang(30173),
"plugin://plugin.video.plexkodiconnect/?mode=channels")
# Plex user switch # Plex user switch
addDirectoryItem(lang(39200) + window('plex_username'), addDirectoryItem(lang(39200) + window('plex_username'),
"plugin://plugin.video.plexkodiconnect/" "plugin://plugin.video.plexkodiconnect/"
@ -211,23 +216,6 @@ def doMainListing():
xbmcplugin.endOfDirectory(HANDLE) xbmcplugin.endOfDirectory(HANDLE)
##### Generate a new deviceId
def resetDeviceId():
deviceId_old = window('plex_client_Id')
from clientinfo import getDeviceId
try:
deviceId = getDeviceId(reset=True)
except Exception as e:
log.error("Failed to generate a new device Id: %s" % e)
dialog('ok', lang(29999), lang(33032))
else:
log.info("Successfully removed old deviceId: %s New deviceId: %s"
% (deviceId_old, deviceId))
# "Kodi will now restart to apply the changes"
dialog('ok', lang(29999), lang(33033))
executebuiltin('RestartApp')
def switchPlexUser(): def switchPlexUser():
""" """
Signs out currently logged in user (if applicable). Triggers sign-in of a Signs out currently logged in user (if applicable). Triggers sign-in of a
@ -249,12 +237,6 @@ def switchPlexUser():
__LogIn() __LogIn()
##### REFRESH EMBY PLAYLISTS #####
def refreshPlaylist():
log.info('Requesting playlist/nodes refresh')
window('plex_runLibScan', value="views")
#### SHOW SUBFOLDERS FOR NODE ##### #### SHOW SUBFOLDERS FOR NODE #####
def GetSubFolders(nodeindex): def GetSubFolders(nodeindex):
nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"] nodetypes = ["",".recent",".recentepisodes",".inprogress",".inprogressepisodes",".unwatched",".nextepisodes",".sets",".genres",".random",".recommended"]
@ -661,83 +643,6 @@ def RunLibScan(mode):
window('plex_runLibScan', value='full') window('plex_runLibScan', value='full')
def BrowsePlexContent(viewid, mediatype="", folderid=""):
"""
Browse Plex Photos:
viewid: PMS name of the library
mediatype: mediatype, 'photos'
nodetype: e.g. 'ondeck' (TBD!!)
"""
log.debug("BrowsePlexContent called with viewid: %s, mediatype: "
"%s, folderid: %s" % (viewid, mediatype, folderid))
if not folderid:
# Top-level navigation, so get the content of this section
# Get all sections
xml = GetPlexSectionResults(
viewid,
containerSize=int(settings('limitindex')))
try:
xml.attrib
except AttributeError:
log.error("Error download section %s" % viewid)
return xbmcplugin.endOfDirectory(HANDLE, False)
else:
# folderid was passed so we can directly access the folder
xml = downloadutils.DownloadUtils().downloadUrl(
"{server}%s" % folderid)
try:
xml.attrib
except AttributeError:
log.error("Error downloading %s" % folderid)
return xbmcplugin.endOfDirectory(HANDLE, False)
# Set the folder's name
xbmcplugin.setPluginCategory(HANDLE,
xml.attrib.get('librarySectionTitle'))
# set the correct params for the content type
if mediatype == "photos":
xbmcplugin.setContent(HANDLE, 'photos')
# process the listing
for item in xml:
api = API(item)
if item.tag == 'Directory':
li = ListItem(item.attrib.get('title', 'Missing title'))
# for folders we add an additional browse request, passing the
# folderId
li.setProperty('IsFolder', 'true')
li.setProperty('IsPlayable', 'false')
path = "%s?id=%s&mode=browseplex&type=%s&folderid=%s" \
% (ARGV_0, viewid, mediatype, api.getKey())
api.set_listitem_artwork(li)
xbmcplugin.addDirectoryItem(handle=HANDLE,
url=path,
listitem=li,
isFolder=True)
else:
li = api.CreateListItemFromPlexItem()
api.set_listitem_artwork(li)
xbmcplugin.addDirectoryItem(
handle=HANDLE,
url=li.getProperty("path"),
listitem=li)
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_VIDEO_TITLE)
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_DATE)
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_VIDEO_RATING)
xbmcplugin.addSortMethod(HANDLE,
xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)
xbmcplugin.endOfDirectory(
handle=HANDLE,
cacheToDisc=settings('enableTextureCache') == 'true')
def getOnDeck(viewid, mediatype, tagname, limit): def getOnDeck(viewid, mediatype, tagname, limit):
""" """
Retrieves Plex On Deck items, currently only for TV shows Retrieves Plex On Deck items, currently only for TV shows
@ -905,28 +810,179 @@ def watchlater():
log.info('Displaying watch later plex.tv items') log.info('Displaying watch later plex.tv items')
xbmcplugin.setContent(HANDLE, 'movies') xbmcplugin.setContent(HANDLE, 'movies')
url = "plugin://plugin.video.plexkodiconnect/"
params = {
'mode': "Plex_Node",
}
for item in xml: for item in xml:
api = API(item) __build_item(item)
listitem = api.CreateListItemFromPlexItem()
api.AddStreamInfo(listitem)
api.set_listitem_artwork(listitem)
params['id'] = item.attrib.get('key')
params['viewOffset'] = item.attrib.get('viewOffset', '0')
params['plex_type'] = item.attrib.get('type')
xbmcplugin.addDirectoryItem(
handle=HANDLE,
url="%s?%s" % (url, urlencode(params)),
listitem=listitem)
xbmcplugin.endOfDirectory( xbmcplugin.endOfDirectory(
handle=HANDLE, handle=HANDLE,
cacheToDisc=settings('enableTextureCache') == 'true') cacheToDisc=settings('enableTextureCache') == 'true')
def 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')
try:
xml[0].attrib
except (ValueError, AttributeError, IndexError):
log.error('Could not download Plex Channels')
return xbmcplugin.endOfDirectory(HANDLE, False)
log.info('Displaying Plex Channels')
xbmcplugin.setContent(HANDLE, 'files')
for method in v.SORT_METHODS_DIRECTORY:
xbmcplugin.addSortMethod(HANDLE, getattr(xbmcplugin, method))
for item in xml:
__build_folder(item)
xbmcplugin.endOfDirectory(
handle=HANDLE,
cacheToDisc=settings('enableTextureCache') == 'true')
def browse_plex(key=None, plex_section_id=None):
"""
Lists the content of a Plex folder, e.g. channels. Either pass in key (to
be used directly for PMS url {server}<key>) or the plex_section_id
"""
if key:
xml = downloadutils.DownloadUtils().downloadUrl('{server}%s' % key)
else:
xml = GetPlexSectionResults(
plex_section_id,
containerSize=int(settings('limitindex')))
try:
xml[0].attrib
except (ValueError, AttributeError, IndexError):
log.error('Could not browse to %s' % key)
return xbmcplugin.endOfDirectory(HANDLE, False)
photos = False
movies = False
clips = False
tvshows = False
episodes = False
songs = False
artists = False
albums = False
musicvideos = False
for item in xml:
typus = item.attrib.get('type')
if item.tag == 'Directory':
__build_folder(item, plex_section_id=plex_section_id)
else:
__build_item(item)
if typus == v.PLEX_TYPE_PHOTO:
photos = True
elif typus == v.PLEX_TYPE_MOVIE:
movies = True
elif typus == v.PLEX_TYPE_CLIP:
clips = True
elif typus in (v.PLEX_TYPE_SHOW, v.PLEX_TYPE_SEASON):
tvshows = True
elif typus == v.PLEX_TYPE_EPISODE:
episodes = True
elif typus == v.PLEX_TYPE_SONG:
songs = True
elif typus == v.PLEX_TYPE_ARTIST:
artists = True
elif typus == v.PLEX_TYPE_ALBUM:
albums = True
elif typus == v.PLEX_TYPE_MUSICVIDEO:
musicvideos = True
# Set the correct content type
if movies is True:
xbmcplugin.setContent(HANDLE, 'movies')
sort_methods = v.SORT_METHODS_MOVIES
elif clips is True:
xbmcplugin.setContent(HANDLE, 'movies')
sort_methods = v.SORT_METHODS_CLIPS
elif photos is True:
xbmcplugin.setContent(HANDLE, 'files')
sort_methods = v.SORT_METHODS_PHOTOS
elif tvshows is True:
xbmcplugin.setContent(HANDLE, 'tvshows')
sort_methods = v.SORT_METHOD_TVSHOWS
elif episodes is True:
xbmcplugin.setContent(HANDLE, 'episodes')
sort_methods = v.SORT_METHODS_EPISODES
elif songs is True:
xbmcplugin.setContent(HANDLE, 'songs')
sort_methods = v.SORT_METHODS_SONGS
elif artists is True:
xbmcplugin.setContent(HANDLE, 'artists')
sort_methods = v.SORT_METHODS_ARTISTS
elif albums is True:
xbmcplugin.setContent(HANDLE, 'albums')
sort_methods = v.SORT_METHODS_ALBUMS
elif musicvideos is True:
xbmcplugin.setContent(HANDLE, 'musicvideos')
sort_methods = v.SORT_METHODS_MOVIES
else:
xbmcplugin.setContent(HANDLE, 'files')
sort_methods = v.SORT_METHODS_DIRECTORY
for method in sort_methods:
xbmcplugin.addSortMethod(HANDLE, getattr(xbmcplugin, method))
# Set the Kodi title for this view
title = xml.attrib.get('librarySectionTitle', xml.attrib.get('title1'))
xbmcplugin.setPluginCategory(HANDLE, title)
xbmcplugin.endOfDirectory(
handle=HANDLE,
cacheToDisc=settings('enableTextureCache') == 'true')
def __build_folder(xml_element, plex_section_id=None):
url = "plugin://%s/" % v.ADDON_ID
key = xml_element.attrib.get('fastKey', xml_element.attrib.get('key'))
if not key.startswith('/'):
key = '/library/sections/%s/%s' % (plex_section_id, key)
params = {
'mode': "browseplex",
'key': key,
'id': plex_section_id
}
listitem = ListItem(xml_element.attrib.get('title'))
listitem.setArt({'thumb': xml_element.attrib.get('thumb'),
'poster': xml_element.attrib.get('art')})
xbmcplugin.addDirectoryItem(handle=HANDLE,
url="%s?%s" % (url, urlencode(params)),
isFolder=True,
listitem=listitem)
def __build_item(xml_element):
api = API(xml_element)
listitem = api.CreateListItemFromPlexItem()
api.AddStreamInfo(listitem)
api.set_listitem_artwork(listitem)
if api.getType() == v.PLEX_TYPE_CLIP:
params = {
'mode': "Plex_Node",
'id': xml_element.attrib.get('key'),
'viewOffset': xml_element.attrib.get('viewOffset', '0'),
'plex_type': xml_element.attrib.get('type')
}
else:
params = {
'filename': api.getKey(),
'id': api.getRatingKey(),
'dbid': listitem.getProperty('dbid') or '',
'mode': "play"
}
url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
xbmcplugin.addDirectoryItem(handle=HANDLE,
url=url,
listitem=listitem)
def enterPMS(): def enterPMS():
""" """
Opens dialogs for the user the plug in the PMS details Opens dialogs for the user the plug in the PMS details

View file

@ -260,7 +260,6 @@ def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
except KeyError: except KeyError:
log.error('Could not init Plex playlist') log.error('Could not init Plex playlist')
return return
item.ID = xml[-1].attrib['%sItemID' % playlist.kind]
playlist.items.append(item) playlist.items.append(item)
log.debug('Initialized the playlist on the Plex side: %s' % playlist) log.debug('Initialized the playlist on the Plex side: %s' % playlist)

View file

@ -53,6 +53,8 @@ class Playqueue(Thread):
else: else:
# Currently, only video or audio playqueues available # Currently, only video or audio playqueues available
playqueue.kodi_pl = PlayList(PLAYLIST_VIDEO) playqueue.kodi_pl = PlayList(PLAYLIST_VIDEO)
# Overwrite 'picture' with 'photo'
playqueue.type = v.KODI_TYPE_PHOTO
self.playqueues.append(playqueue) self.playqueues.append(playqueue)
# sort the list by their playlistid, just in case # sort the list by their playlistid, just in case
self.playqueues = sorted( self.playqueues = sorted(

View file

@ -70,19 +70,6 @@ class PlayUtils():
log.info("The playurl is: %s" % playurl) log.info("The playurl is: %s" % playurl)
return playurl return playurl
def httpPlay(self):
# Audio, Video, Photo
itemid = self.item['Id']
mediatype = self.item['MediaType']
if mediatype == "Audio":
playurl = "%s/emby/Audio/%s/stream" % (self.server, itemid)
else:
playurl = "%s/emby/Videos/%s/stream?static=true" % (self.server, itemid)
return playurl
def isDirectPlay(self): def isDirectPlay(self):
""" """
Returns the path/playurl if we can direct play, None otherwise Returns the path/playurl if we can direct play, None otherwise

View file

@ -113,6 +113,7 @@ PLEX_TYPE_AUDIO = 'music'
PLEX_TYPE_SONG = 'track' PLEX_TYPE_SONG = 'track'
PLEX_TYPE_ALBUM = 'album' PLEX_TYPE_ALBUM = 'album'
PLEX_TYPE_ARTIST = 'artist' PLEX_TYPE_ARTIST = 'artist'
PLEX_TYPE_MUSICVIDEO = 'musicvideo'
PLEX_TYPE_PHOTO = 'photo' PLEX_TYPE_PHOTO = 'photo'
@ -131,6 +132,7 @@ KODI_TYPE_AUDIO = 'audio'
KODI_TYPE_SONG = 'song' KODI_TYPE_SONG = 'song'
KODI_TYPE_ALBUM = 'album' KODI_TYPE_ALBUM = 'album'
KODI_TYPE_ARTIST = 'artist' KODI_TYPE_ARTIST = 'artist'
KODI_TYPE_MUSICVIDEO = 'musicvideo'
KODI_TYPE_PHOTO = 'photo' KODI_TYPE_PHOTO = 'photo'
@ -195,7 +197,8 @@ KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE = {
PLEX_TYPE_ARTIST: KODI_TYPE_AUDIO, PLEX_TYPE_ARTIST: KODI_TYPE_AUDIO,
PLEX_TYPE_ALBUM: KODI_TYPE_AUDIO, PLEX_TYPE_ALBUM: KODI_TYPE_AUDIO,
PLEX_TYPE_SONG: KODI_TYPE_AUDIO, PLEX_TYPE_SONG: KODI_TYPE_AUDIO,
PLEX_TYPE_AUDIO: KODI_TYPE_AUDIO PLEX_TYPE_AUDIO: KODI_TYPE_AUDIO,
PLEX_TYPE_PHOTO: KODI_TYPE_PHOTO
} }
@ -266,3 +269,88 @@ ALEXA_TO_COMPANION = {
'queryContainerKey': 'containerKey', 'queryContainerKey': 'containerKey',
'queryToken': 'token', 'queryToken': 'token',
} }
# Kodi sort methods for xbmcplugin.addSortMethod()
SORT_METHODS_DIRECTORY = (
'SORT_METHOD_UNSORTED', # sorted as returned from Plex
'SORT_METHOD_LABEL',
)
SORT_METHODS_PHOTOS = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_LABEL',
'SORT_METHOD_DATE',
'SORT_METHOD_DATEADDED',
)
SORT_METHODS_CLIPS = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_TITLE',
'SORT_METHOD_DURATION',
)
SORT_METHODS_MOVIES = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_TITLE',
'SORT_METHOD_DURATION',
'SORT_METHOD_VIDEO_RATING',
'SORT_METHOD_VIDEO_USER_RATING',
'SORT_METHOD_MPAA_RATING',
'SORT_METHOD_COUNTRY',
'SORT_METHOD_STUDIO',
'SORT_METHOD_GENRE',
)
SORT_METHOD_TVSHOWS = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_TITLE',
'SORT_METHOD_VIDEO_RATING',
'SORT_METHOD_VIDEO_USER_RATING',
'SORT_METHOD_MPAA_RATING',
'SORT_METHOD_COUNTRY',
'SORT_METHOD_GENRE',
)
SORT_METHODS_EPISODES = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_TITLE',
'SORT_METHOD_EPISODE',
'SORT_METHOD_DURATION',
'SORT_METHOD_VIDEO_RATING',
'SORT_METHOD_VIDEO_USER_RATING',
'SORT_METHOD_MPAA_RATING',
'SORT_METHOD_FILE',
'SORT_METHOD_FULLPATH',
)
SORT_METHODS_SONGS = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_TITLE',
'SORT_METHOD_TRACKNUM',
'SORT_METHOD_DURATION',
'SORT_METHOD_ARTIST',
'SORT_METHOD_ARTIST_AND_YEAR',
'SORT_METHOD_ALBUM',
'SORT_METHOD_SONG_RATING',
'SORT_METHOD_SONG_USER_RATING'
)
SORT_METHODS_ARTISTS = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_TITLE',
'SORT_METHOD_TRACKNUM',
'SORT_METHOD_DURATION',
'SORT_METHOD_ARTIST',
'SORT_METHOD_ARTIST_AND_YEAR',
'SORT_METHOD_ALBUM',
)
SORT_METHODS_ALBUMS = (
'SORT_METHOD_UNSORTED',
'SORT_METHOD_TITLE',
'SORT_METHOD_TRACKNUM',
'SORT_METHOD_DURATION',
'SORT_METHOD_ARTIST',
'SORT_METHOD_ARTIST_AND_YEAR',
'SORT_METHOD_ALBUM',
)

View file

@ -102,7 +102,7 @@ class VideoNodes(object):
return return
if mediatype == "photos": if mediatype == "photos":
path = "plugin://plugin.video.plexkodiconnect/?id=%s&mode=getsubfolders" % indexnumber path = "plugin://plugin.video.plexkodiconnect?mode=browseplex&key=/library/sections/%s&id=%s" % (viewid, viewid)
window('Plex.nodes.%s.index' % indexnumber, value=path) window('Plex.nodes.%s.index' % indexnumber, value=path)
@ -131,58 +131,64 @@ class VideoNodes(object):
'9': "genres", '9': "genres",
'10': "random", '10': "random",
'11': "recommended", '11': "recommended",
'12': "ondeck" '12': "ondeck",
'13': 'browsefiles'
} }
mediatypes = { mediatypes = {
# label according to nodetype per mediatype # label according to nodetype per mediatype
'movies': 'movies':
{ {
'1': tagname, '1': tagname,
'2': 30174, '2': 30174,
# '4': 30177, # '4': 30177,
# '6': 30189, # '6': 30189,
'8': 39501, '8': 39501,
'9': 135, '9': 135,
'10': 30227, '10': 30227,
'11': 30230, '11': 30230,
'12': 39500, '12': 39500,
'13': 39702
}, },
'tvshows': 'tvshows':
{ {
'1': tagname, '1': tagname,
# '2': 30170, # '2': 30170,
'3': 30174, '3': 30174,
# '4': 30171, # '4': 30171,
# '5': 30178, # '5': 30178,
# '7': 30179, # '7': 30179,
'9': 135, '9': 135,
'10': 30227, '10': 30227,
# '11': 30230, # '11': 30230,
'12': 39500, '12': 39500,
'13': 39702
}, },
'homevideos': 'homevideos':
{ {
'1': tagname, '1': tagname,
'2': 30251, '2': 30251,
'11': 30253 '11': 30253,
'13': 39702
}, },
'photos': 'photos':
{ {
'1': tagname, '1': tagname,
'2': 30252, '2': 30252,
'8': 30255, '8': 30255,
'11': 30254 '11': 30254,
'13': 39702
}, },
'musicvideos': 'musicvideos':
{ {
'1': tagname, '1': tagname,
'2': 30256, '2': 30256,
'4': 30257, '4': 30257,
'6': 30258 '6': 30258,
'13': 39702
} }
} }
@ -200,6 +206,7 @@ class VideoNodes(object):
'10': '8', # "random", '10': '8', # "random",
'11': '5', # "recommended", '11': '5', # "recommended",
'12': '1', # "ondeck" '12': '1', # "ondeck"
'13': '9' # browse by folder
} }
nodes = mediatypes[mediatype] nodes = mediatypes[mediatype]
@ -244,6 +251,8 @@ class VideoNodes(object):
elif mediatype =="movies": elif mediatype =="movies":
# Reset nodetype; we got the label # Reset nodetype; we got the label
nodetype = 'inprogress' nodetype = 'inprogress'
elif nodetype == 'browsefiles':
path = 'plugin://plugin.video.plexkodiconnect?mode=browseplex&key=/library/sections/%s/folder' % viewid
else: else:
path = "library://video/Plex-%s/%s_%s.xml" % (dirname, viewid, nodetype) path = "library://video/Plex-%s/%s_%s.xml" % (dirname, viewid, nodetype)
@ -285,7 +294,7 @@ class VideoNodes(object):
continue continue
# Create the root # Create the root
if (nodetype in ("nextepisodes", "ondeck", 'recentepisodes') or mediatype == "homevideos"): if (nodetype in ("nextepisodes", "ondeck", 'recentepisodes', 'browsefiles') or mediatype == "homevideos"):
# Folder type with plugin path # Folder type with plugin path
root = self.commonRoot(order=sortorder[node], label=label, tagname=tagname, roottype=2) root = self.commonRoot(order=sortorder[node], label=label, tagname=tagname, roottype=2)
etree.SubElement(root, 'path').text = path etree.SubElement(root, 'path').text = path

View file

@ -96,7 +96,7 @@
<setting id="offerDelete" type="bool" label="30114" default="false" visible="false"/> <setting id="offerDelete" type="bool" label="30114" default="false" visible="false"/>
<setting id="deleteTV" type="bool" label="30115" visible="eq(-1,true)" default="false" subsetting="true" /> <setting id="deleteTV" type="bool" label="30115" visible="eq(-1,true)" default="false" subsetting="true" />
<setting id="deleteMovies" type="bool" label="30116" visible="eq(-2,true)" default="false" subsetting="true" /> <setting id="deleteMovies" type="bool" label="30116" visible="eq(-2,true)" default="false" subsetting="true" />
<setting id="resumeJumpBack" type="slider" label="30521" default="10" range="0,1,120" option="int" /> <setting id="resumeJumpBack" type="slider" label="30521" default="10" range="0,1,120" option="int" visible="false"/>
<setting type="sep" /> <setting type="sep" />
<setting id="playType" type="enum" label="30002" values="Direct Play (default)|Direct Stream|Force Transcode" default="0" /> <setting id="playType" type="enum" label="30002" values="Direct Play (default)|Direct Stream|Force Transcode" default="0" />
<setting id="transcoderVideoQualities" type="enum" label="30160" values="420x420, 320kbps|576x320, 720kbps|720x480, 1.5Mbps|1024x768, 2Mbps|1280x720, 3Mbps|1280x720, 4Mbps|1920x1080, 8Mbps|1920x1080, 10Mbps|1920x1080, 12Mbps|1920x1080, 20Mbps|1920x1080, 40Mbps" default="10" /><!-- Video Quality if Transcoding necessary --> <setting id="transcoderVideoQualities" type="enum" label="30160" values="420x420, 320kbps|576x320, 720kbps|720x480, 1.5Mbps|1024x768, 2Mbps|1280x720, 3Mbps|1280x720, 4Mbps|1920x1080, 8Mbps|1920x1080, 10Mbps|1920x1080, 12Mbps|1920x1080, 20Mbps|1920x1080, 40Mbps" default="10" /><!-- Video Quality if Transcoding necessary -->