2018-07-13 02:46:02 +10:00
|
|
|
#!/usr/bin/env python
|
2015-12-25 07:07:00 +11:00
|
|
|
# -*- coding: utf-8 -*-
|
2018-07-13 02:46:02 +10:00
|
|
|
"""
|
|
|
|
Loads of different functions called in SEPARATE Python instances through
|
|
|
|
e.g. plugin://... calls. Hence be careful to only rely on window variables.
|
|
|
|
"""
|
|
|
|
from __future__ import absolute_import, division, unicode_literals
|
2017-12-10 00:35:08 +11:00
|
|
|
from logging import getLogger
|
2017-01-25 05:59:38 +11:00
|
|
|
from sys import argv
|
|
|
|
from urllib import urlencode
|
2015-12-25 07:07:00 +11:00
|
|
|
import xbmcplugin
|
2018-11-21 02:58:25 +11:00
|
|
|
from xbmc import sleep
|
2017-01-25 05:59:38 +11:00
|
|
|
from xbmcgui import ListItem
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2018-06-22 03:24:37 +10:00
|
|
|
from . import utils
|
2018-06-24 02:25:18 +10:00
|
|
|
from . import path_ops
|
2018-06-22 03:24:37 +10:00
|
|
|
from .downloadutils import DownloadUtils as DU
|
|
|
|
from .plex_api import API
|
|
|
|
from . import plex_functions as PF
|
|
|
|
from . import json_rpc as js
|
|
|
|
from . import variables as v
|
2018-11-19 00:59:17 +11:00
|
|
|
# Be careful - your using app in another Python instance!
|
|
|
|
from . import app
|
2016-01-02 00:40:40 +11:00
|
|
|
|
2016-02-20 06:03:06 +11:00
|
|
|
###############################################################################
|
2018-06-22 03:24:37 +10:00
|
|
|
LOG = getLogger('PLEX.entrypoint')
|
2016-08-30 23:51:11 +10:00
|
|
|
|
|
|
|
###############################################################################
|
2016-01-30 06:07:21 +11:00
|
|
|
|
|
|
|
|
2018-06-15 21:44:46 +10:00
|
|
|
def choose_pms_server():
|
2016-03-24 22:34:39 +11:00
|
|
|
"""
|
2016-05-30 00:52:00 +10:00
|
|
|
Lets user choose from list of PMS
|
2016-03-24 22:34:39 +11:00
|
|
|
"""
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.info("Choosing PMS server requested, starting")
|
2018-11-19 00:59:17 +11:00
|
|
|
utils.plex_command('choose_pms_server')
|
2016-03-24 02:07:09 +11:00
|
|
|
|
2016-03-24 22:34:39 +11:00
|
|
|
|
2018-06-15 21:44:46 +10:00
|
|
|
def toggle_plex_tv_sign_in():
|
|
|
|
"""
|
|
|
|
Signs out of Plex.tv if there was a token saved and thus deletes the token.
|
|
|
|
Or signs in to plex.tv if the user was not logged in before.
|
|
|
|
"""
|
2018-11-19 00:59:17 +11:00
|
|
|
LOG.info('Toggle of Plex.tv sign-in requested')
|
|
|
|
utils.plex_command('toggle_plex_tv_sign_in')
|
2016-08-30 23:51:11 +10:00
|
|
|
|
|
|
|
|
2018-06-15 21:47:22 +10:00
|
|
|
def directory_item(label, path, folder=True):
|
|
|
|
"""
|
|
|
|
Adds a xbmcplugin.addDirectoryItem() directory itemlistitem
|
|
|
|
"""
|
|
|
|
listitem = ListItem(label, path=path)
|
|
|
|
listitem.setThumbnailImage(
|
|
|
|
"special://home/addons/plugin.video.plexkodiconnect/icon.png")
|
|
|
|
listitem.setArt(
|
|
|
|
{"fanart": "special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
|
|
|
|
listitem.setArt(
|
|
|
|
{"landscape":"special://home/addons/plugin.video.plexkodiconnect/fanart.jpg"})
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2018-06-15 21:47:22 +10:00
|
|
|
url=path,
|
|
|
|
listitem=listitem,
|
|
|
|
isFolder=folder)
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-08-30 23:51:11 +10:00
|
|
|
|
2018-06-15 21:49:18 +10:00
|
|
|
def show_main_menu(content_type=None):
|
|
|
|
"""
|
|
|
|
Shows the main PKC menu listing with all libraries, Channel, settings, etc.
|
|
|
|
"""
|
2018-06-15 22:15:39 +10:00
|
|
|
LOG.debug('Do main listing with content_type: %s', content_type)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'files')
|
2015-12-25 07:07:00 +11:00
|
|
|
# Get emby nodes from the window props
|
2018-06-22 03:24:37 +10:00
|
|
|
plexprops = utils.window('Plex.nodes.total')
|
2016-05-31 16:06:42 +10:00
|
|
|
if plexprops:
|
|
|
|
totalnodes = int(plexprops)
|
2015-12-25 07:07:00 +11:00
|
|
|
for i in range(totalnodes):
|
2018-06-22 03:24:37 +10:00
|
|
|
path = utils.window('Plex.nodes.%s.index' % i)
|
2015-12-25 07:07:00 +11:00
|
|
|
if not path:
|
2018-06-22 03:24:37 +10:00
|
|
|
path = utils.window('Plex.nodes.%s.content' % i)
|
2017-03-20 00:32:01 +11:00
|
|
|
if not path:
|
|
|
|
continue
|
2018-06-22 03:24:37 +10:00
|
|
|
label = utils.window('Plex.nodes.%s.title' % i)
|
|
|
|
node_type = utils.window('Plex.nodes.%s.type' % i)
|
2017-03-20 00:32:01 +11:00
|
|
|
# because we do not use seperate entrypoints for each content type,
|
|
|
|
# we need to figure out which items to show in each listing. for
|
|
|
|
# now we just only show picture nodes in the picture library video
|
|
|
|
# nodes in the video library and all nodes in any other window
|
|
|
|
if node_type == 'photos' and content_type == 'image':
|
2018-06-15 21:47:22 +10:00
|
|
|
directory_item(label, path)
|
2018-07-19 23:02:21 +10:00
|
|
|
elif node_type == 'albums' and content_type == 'audio':
|
|
|
|
directory_item(label, path)
|
|
|
|
elif node_type in ('movies',
|
|
|
|
'tvshows',
|
|
|
|
'homevideos',
|
|
|
|
'musicvideos') and content_type == 'video':
|
2018-06-15 21:47:22 +10:00
|
|
|
directory_item(label, path)
|
2018-07-30 21:20:40 +10:00
|
|
|
# Playlists
|
|
|
|
if content_type != 'image':
|
|
|
|
directory_item(utils.lang(136),
|
|
|
|
('plugin://%s?mode=playlists&content_type=%s'
|
|
|
|
% (v.ADDON_ID, content_type)))
|
2018-07-28 00:01:05 +10:00
|
|
|
# Plex Hub
|
|
|
|
directory_item('Plex Hub',
|
|
|
|
'plugin://%s?mode=hub&type=%s' % (v.ADDON_ID, content_type))
|
2016-04-17 21:36:41 +10:00
|
|
|
# Plex Watch later
|
2017-03-20 00:32:01 +11:00
|
|
|
if content_type not in ('image', 'audio'):
|
2018-06-22 03:24:37 +10:00
|
|
|
directory_item(utils.lang(39211),
|
2018-06-15 21:49:18 +10:00
|
|
|
"plugin://%s?mode=watchlater" % v.ADDON_ID)
|
2017-03-08 02:37:36 +11:00
|
|
|
# Plex Channels
|
2018-06-22 03:24:37 +10:00
|
|
|
directory_item(utils.lang(30173), "plugin://%s?mode=channels" % v.ADDON_ID)
|
2016-03-11 02:04:01 +11:00
|
|
|
# Plex user switch
|
2018-06-22 03:24:37 +10:00
|
|
|
directory_item('%s%s' % (utils.lang(39200), utils.settings('username')),
|
2018-06-15 21:49:18 +10:00
|
|
|
"plugin://%s?mode=switchuser" % v.ADDON_ID)
|
2017-03-20 00:32:01 +11:00
|
|
|
|
|
|
|
# some extra entries for settings and stuff
|
2018-06-22 03:24:37 +10:00
|
|
|
directory_item(utils.lang(39201), "plugin://%s?mode=settings" % v.ADDON_ID)
|
|
|
|
directory_item(utils.lang(39204),
|
2018-06-15 21:49:18 +10:00
|
|
|
"plugin://%s?mode=manualsync" % v.ADDON_ID)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(int(argv[1]))
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-02-29 16:20:59 +11:00
|
|
|
|
2018-06-15 21:50:04 +10:00
|
|
|
def switch_plex_user():
|
2016-01-25 20:36:24 +11:00
|
|
|
"""
|
|
|
|
Signs out currently logged in user (if applicable). Triggers sign-in of a
|
|
|
|
new user
|
|
|
|
"""
|
|
|
|
# Guess these user avatars are a future feature. Skipping for now
|
|
|
|
# Delete any userimages. Since there's always only 1 user: position = 0
|
|
|
|
# position = 0
|
2018-06-22 03:24:37 +10:00
|
|
|
# utils.window('EmbyAdditionalUserImage.%s' % position, clear=True)
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.info("Plex home user switch requested")
|
2018-11-19 00:59:17 +11:00
|
|
|
utils.plex_command('switch_plex_user')
|
2016-01-25 20:36:24 +11:00
|
|
|
|
|
|
|
|
2018-06-15 21:55:32 +10:00
|
|
|
def create_listitem(item, append_show_title=False, append_sxxexx=False):
|
|
|
|
"""
|
|
|
|
Feed with a Kodi json item response to get a xbmcgui.ListItem() with
|
|
|
|
everything set and ready.
|
|
|
|
"""
|
2015-12-25 07:07:00 +11:00
|
|
|
title = item['title']
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem = ListItem(title)
|
|
|
|
listitem.setProperty('IsPlayable', 'true')
|
2016-04-27 18:37:24 +10:00
|
|
|
metadata = {
|
2018-06-15 21:55:32 +10:00
|
|
|
'duration': str(item['runtime'] / 60),
|
2015-12-25 07:07:00 +11:00
|
|
|
'Plot': item['plot'],
|
|
|
|
'Playcount': item['playcount']
|
|
|
|
}
|
2018-04-04 00:53:59 +10:00
|
|
|
if 'episode' in item:
|
2015-12-25 07:07:00 +11:00
|
|
|
episode = item['episode']
|
|
|
|
metadata['Episode'] = episode
|
2018-04-04 00:53:59 +10:00
|
|
|
if 'season' in item:
|
2015-12-25 07:07:00 +11:00
|
|
|
season = item['season']
|
|
|
|
metadata['Season'] = season
|
|
|
|
if season and episode:
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem.setProperty('episodeno', 's%.2de%.2d' % (season, episode))
|
2018-02-12 00:42:49 +11:00
|
|
|
if append_sxxexx is True:
|
2018-04-04 00:53:59 +10:00
|
|
|
title = 'S%.2dE%.2d - %s' % (season, episode, title)
|
|
|
|
if 'firstaired' in item:
|
2015-12-25 07:07:00 +11:00
|
|
|
metadata['Premiered'] = item['firstaired']
|
2018-04-04 00:53:59 +10:00
|
|
|
if 'showtitle' in item:
|
2015-12-25 07:07:00 +11:00
|
|
|
metadata['TVshowTitle'] = item['showtitle']
|
2018-02-12 00:42:49 +11:00
|
|
|
if append_show_title is True:
|
2016-04-27 18:37:24 +10:00
|
|
|
title = item['showtitle'] + ' - ' + title
|
2018-04-04 00:53:59 +10:00
|
|
|
if 'rating' in item:
|
|
|
|
metadata['Rating'] = str(round(float(item['rating']), 1))
|
|
|
|
if 'director' in item:
|
|
|
|
metadata['Director'] = item['director']
|
|
|
|
if 'writer' in item:
|
|
|
|
metadata['Writer'] = item['writer']
|
|
|
|
if 'cast' in item:
|
2015-12-25 07:07:00 +11:00
|
|
|
cast = []
|
|
|
|
castandrole = []
|
|
|
|
for person in item['cast']:
|
|
|
|
name = person['name']
|
|
|
|
cast.append(name)
|
|
|
|
castandrole.append((name, person['role']))
|
|
|
|
metadata['Cast'] = cast
|
|
|
|
metadata['CastAndRole'] = castandrole
|
|
|
|
|
2016-04-27 18:37:24 +10:00
|
|
|
metadata['Title'] = title
|
2018-04-04 00:53:59 +10:00
|
|
|
metadata['mediatype'] = 'episode'
|
|
|
|
metadata['dbid'] = str(item['episodeid'])
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem.setLabel(title)
|
|
|
|
listitem.setInfo(type='Video', infoLabels=metadata)
|
|
|
|
|
|
|
|
listitem.setProperty('resumetime', str(item['resume']['position']))
|
|
|
|
listitem.setProperty('totaltime', str(item['resume']['total']))
|
|
|
|
listitem.setArt(item['art'])
|
|
|
|
listitem.setThumbnailImage(item['art'].get('thumb', ''))
|
|
|
|
listitem.setArt({'icon': 'DefaultTVShows.png'})
|
|
|
|
listitem.setProperty('fanart_image', item['art'].get('tvshow.fanart', ''))
|
2017-08-03 02:54:05 +10:00
|
|
|
try:
|
2018-06-22 03:24:37 +10:00
|
|
|
listitem.addContextMenuItems([(utils.lang(30032),
|
|
|
|
'XBMC.Action(Info)',)])
|
2017-08-03 02:54:05 +10:00
|
|
|
except TypeError:
|
|
|
|
# Kodi fuck-up
|
|
|
|
pass
|
2015-12-25 07:07:00 +11:00
|
|
|
for key, value in item['streamdetails'].iteritems():
|
|
|
|
for stream in value:
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem.addStreamInfo(key, stream)
|
|
|
|
return listitem
|
|
|
|
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2018-06-15 21:57:33 +10:00
|
|
|
def next_up_episodes(tagname, limit):
|
|
|
|
"""
|
|
|
|
List the next up episodes for tagname.
|
|
|
|
"""
|
2015-12-25 07:07:00 +11:00
|
|
|
count = 0
|
|
|
|
# if the addon is called with nextup parameter,
|
|
|
|
# we return the nextepisodes list of the given tagname
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'episodes')
|
2015-12-25 07:07:00 +11:00
|
|
|
# First we get a list of all the TV shows - filtered by tag
|
2017-01-25 05:59:38 +11:00
|
|
|
params = {
|
|
|
|
'sort': {'order': "descending", 'method': "lastplayed"},
|
|
|
|
'filter': {
|
|
|
|
'and': [
|
|
|
|
{'operator': "true", 'field': "inprogress", 'value': ""},
|
|
|
|
{'operator': "is", 'field': "tag", 'value': "%s" % tagname}
|
|
|
|
]},
|
|
|
|
'properties': ['title', 'studio', 'mpaa', 'file', 'art']
|
2015-12-25 07:07:00 +11:00
|
|
|
}
|
2017-12-09 05:43:06 +11:00
|
|
|
for item in js.get_tv_shows(params):
|
2018-06-22 03:24:37 +10:00
|
|
|
if utils.settings('ignoreSpecialsNextEpisodes') == "true":
|
2017-12-09 05:43:06 +11:00
|
|
|
params = {
|
|
|
|
'tvshowid': item['tvshowid'],
|
|
|
|
'sort': {'method': "episode"},
|
|
|
|
'filter': {
|
|
|
|
'and': [
|
|
|
|
{'operator': "lessthan",
|
|
|
|
'field': "playcount",
|
|
|
|
'value': "1"},
|
|
|
|
{'operator': "greaterthan",
|
|
|
|
'field': "season",
|
|
|
|
'value': "0"}]},
|
|
|
|
'properties': [
|
|
|
|
"title", "playcount", "season", "episode", "showtitle",
|
|
|
|
"plot", "file", "rating", "resume", "tvshowid", "art",
|
|
|
|
"streamdetails", "firstaired", "runtime", "writer",
|
|
|
|
"dateadded", "lastplayed"
|
|
|
|
],
|
|
|
|
'limits': {"end": 1}
|
|
|
|
}
|
|
|
|
else:
|
|
|
|
params = {
|
|
|
|
'tvshowid': item['tvshowid'],
|
|
|
|
'sort': {'method': "episode"},
|
|
|
|
'filter': {
|
|
|
|
'operator': "lessthan",
|
|
|
|
'field': "playcount",
|
|
|
|
'value': "1"},
|
|
|
|
'properties': [
|
|
|
|
"title", "playcount", "season", "episode", "showtitle",
|
|
|
|
"plot", "file", "rating", "resume", "tvshowid", "art",
|
|
|
|
"streamdetails", "firstaired", "runtime", "writer",
|
|
|
|
"dateadded", "lastplayed"
|
|
|
|
],
|
|
|
|
'limits': {"end": 1}
|
|
|
|
}
|
|
|
|
for episode in js.get_episodes(params):
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2017-12-09 05:43:06 +11:00
|
|
|
url=episode['file'],
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem=create_listitem(episode))
|
2017-12-09 05:43:06 +11:00
|
|
|
count += 1
|
|
|
|
if count == limit:
|
|
|
|
break
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(handle=int(argv[1]))
|
2017-01-25 05:59:38 +11:00
|
|
|
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2018-06-15 21:58:39 +10:00
|
|
|
def in_progress_episodes(tagname, limit):
|
|
|
|
"""
|
|
|
|
List the episodes that are in progress for tagname
|
|
|
|
"""
|
2015-12-25 07:07:00 +11:00
|
|
|
count = 0
|
|
|
|
# if the addon is called with inprogressepisodes parameter,
|
|
|
|
# we return the inprogressepisodes list of the given tagname
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'episodes')
|
2015-12-25 07:07:00 +11:00
|
|
|
# First we get a list of all the in-progress TV shows - filtered by tag
|
2017-01-25 05:59:38 +11:00
|
|
|
params = {
|
|
|
|
'sort': {'order': "descending", 'method': "lastplayed"},
|
|
|
|
'filter': {
|
|
|
|
'and': [
|
|
|
|
{'operator': "true", 'field': "inprogress", 'value': ""},
|
|
|
|
{'operator': "is", 'field': "tag", 'value': "%s" % tagname}
|
|
|
|
]},
|
|
|
|
'properties': ['title', 'studio', 'mpaa', 'file', 'art']
|
2015-12-25 07:07:00 +11:00
|
|
|
}
|
2017-12-09 05:43:06 +11:00
|
|
|
for item in js.get_tv_shows(params):
|
|
|
|
params = {
|
|
|
|
'tvshowid': item['tvshowid'],
|
|
|
|
'sort': {'method': "episode"},
|
|
|
|
'filter': {
|
|
|
|
'operator': "true",
|
|
|
|
'field': "inprogress",
|
|
|
|
'value': ""},
|
|
|
|
'properties': ["title", "playcount", "season", "episode",
|
2018-06-15 22:00:12 +10:00
|
|
|
"showtitle", "plot", "file", "rating", "resume",
|
|
|
|
"tvshowid", "art", "cast", "streamdetails",
|
|
|
|
"firstaired", "runtime", "writer", "dateadded",
|
|
|
|
"lastplayed"]
|
2017-12-09 05:43:06 +11:00
|
|
|
}
|
|
|
|
for episode in js.get_episodes(params):
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2017-12-09 05:43:06 +11:00
|
|
|
url=episode['file'],
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem=create_listitem(episode))
|
2017-12-09 05:43:06 +11:00
|
|
|
count += 1
|
|
|
|
if count == limit:
|
|
|
|
break
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(handle=int(argv[1]))
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2018-06-15 22:00:12 +10:00
|
|
|
|
2018-06-15 22:01:09 +10:00
|
|
|
def recent_episodes(mediatype, tagname, limit):
|
2018-06-15 22:00:12 +10:00
|
|
|
"""
|
|
|
|
List the recently added episodes for tagname
|
|
|
|
"""
|
2015-12-25 07:07:00 +11:00
|
|
|
count = 0
|
|
|
|
# if the addon is called with recentepisodes parameter,
|
|
|
|
# we return the recentepisodes list of the given tagname
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'episodes')
|
2018-06-22 03:24:37 +10:00
|
|
|
append_show_title = utils.settings('RecentTvAppendShow') == 'true'
|
|
|
|
append_sxxexx = utils.settings('RecentTvAppendSeason') == 'true'
|
2015-12-25 07:07:00 +11:00
|
|
|
# First we get a list of all the TV shows - filtered by tag
|
2018-06-15 22:05:48 +10:00
|
|
|
show_ids = set()
|
2017-01-25 05:59:38 +11:00
|
|
|
params = {
|
|
|
|
'sort': {'order': "descending", 'method': "dateadded"},
|
|
|
|
'filter': {'operator': "is", 'field': "tag", 'value': "%s" % tagname},
|
2015-12-25 07:07:00 +11:00
|
|
|
}
|
2017-12-09 05:43:06 +11:00
|
|
|
for tv_show in js.get_tv_shows(params):
|
2018-06-15 22:05:48 +10:00
|
|
|
show_ids.add(tv_show['tvshowid'])
|
2017-01-25 05:59:38 +11:00
|
|
|
params = {
|
|
|
|
'sort': {'order': "descending", 'method': "dateadded"},
|
|
|
|
'properties': ["title", "playcount", "season", "episode", "showtitle",
|
|
|
|
"plot", "file", "rating", "resume", "tvshowid", "art",
|
|
|
|
"streamdetails", "firstaired", "runtime", "cast", "writer",
|
|
|
|
"dateadded", "lastplayed"],
|
|
|
|
"limits": {"end": limit}
|
2016-03-16 00:19:56 +11:00
|
|
|
}
|
2018-06-22 03:24:37 +10:00
|
|
|
if utils.settings('TVShowWatched') == 'false':
|
2017-01-25 05:59:38 +11:00
|
|
|
params['filter'] = {
|
2016-05-16 01:24:44 +10:00
|
|
|
'operator': "lessthan",
|
|
|
|
'field': "playcount",
|
|
|
|
'value': "1"
|
|
|
|
}
|
2017-12-09 05:43:06 +11:00
|
|
|
for episode in js.get_episodes(params):
|
2018-06-15 22:05:48 +10:00
|
|
|
if episode['tvshowid'] in show_ids:
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem = create_listitem(episode,
|
|
|
|
append_show_title=append_show_title,
|
|
|
|
append_sxxexx=append_sxxexx)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2018-06-15 21:55:32 +10:00
|
|
|
url=episode['file'],
|
|
|
|
listitem=listitem)
|
2017-12-09 05:43:06 +11:00
|
|
|
count += 1
|
|
|
|
if count == limit:
|
|
|
|
break
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(handle=int(argv[1]))
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-04-09 23:46:51 +10:00
|
|
|
|
2018-06-15 22:05:48 +10:00
|
|
|
def get_video_files(plex_id, params):
|
2016-04-09 23:46:51 +10:00
|
|
|
"""
|
|
|
|
GET VIDEO EXTRAS FOR LISTITEM
|
|
|
|
|
|
|
|
returns the video files for the item as plugin listing, can be used for
|
|
|
|
browsing the actual files or videoextras etc.
|
|
|
|
"""
|
2018-06-15 22:05:48 +10:00
|
|
|
if plex_id is None:
|
2016-04-09 23:46:51 +10:00
|
|
|
filename = params.get('filename')
|
|
|
|
if filename is not None:
|
|
|
|
filename = filename[0]
|
|
|
|
import re
|
|
|
|
regex = re.compile(r'''library/metadata/(\d+)''')
|
|
|
|
filename = regex.findall(filename)
|
|
|
|
try:
|
2018-06-15 22:05:48 +10:00
|
|
|
plex_id = filename[0]
|
2016-04-09 23:46:51 +10:00
|
|
|
except IndexError:
|
|
|
|
pass
|
|
|
|
|
2018-06-15 22:05:48 +10:00
|
|
|
if plex_id is None:
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.info('No Plex ID found, abort getting Extras')
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]))
|
2018-11-26 17:19:34 +11:00
|
|
|
app.init(entrypoint=True)
|
2018-06-22 03:24:37 +10:00
|
|
|
item = PF.GetPlexMetadata(plex_id)
|
2016-04-09 23:46:51 +10:00
|
|
|
try:
|
2018-06-24 02:25:18 +10:00
|
|
|
path = utils.try_decode(item[0][0][0].attrib['file'])
|
2018-06-15 22:05:48 +10:00
|
|
|
except (TypeError, IndexError, AttributeError, KeyError):
|
2018-06-15 22:15:39 +10:00
|
|
|
LOG.error('Could not get file path for item %s', plex_id)
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]))
|
2016-04-09 23:46:51 +10:00
|
|
|
# Assign network protocol
|
|
|
|
if path.startswith('\\\\'):
|
|
|
|
path = path.replace('\\\\', 'smb://')
|
|
|
|
path = path.replace('\\', '/')
|
|
|
|
# Plex returns Windows paths as e.g. 'c:\slfkjelf\slfje\file.mkv'
|
|
|
|
elif '\\' in path:
|
|
|
|
path = path.replace('\\', '\\\\')
|
2017-05-04 04:30:33 +10:00
|
|
|
# Directory only, get rid of filename
|
2018-06-24 02:25:18 +10:00
|
|
|
path = path.replace(path_ops.path.basename(path), '')
|
|
|
|
if path_ops.exists(path):
|
|
|
|
for root, dirs, files in path_ops.walk(path):
|
2017-05-04 04:30:33 +10:00
|
|
|
for directory in dirs:
|
2018-06-24 02:25:18 +10:00
|
|
|
item_path = utils.try_encode(path_ops.path.join(root,
|
|
|
|
directory))
|
2018-06-15 22:05:48 +10:00
|
|
|
listitem = ListItem(item_path, path=item_path)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2017-05-04 04:30:33 +10:00
|
|
|
url=item_path,
|
2018-06-15 22:05:48 +10:00
|
|
|
listitem=listitem,
|
2017-05-04 04:30:33 +10:00
|
|
|
isFolder=True)
|
|
|
|
for file in files:
|
2018-06-24 02:25:18 +10:00
|
|
|
item_path = utils.try_encode(path_ops.path.join(root, file))
|
2018-06-15 22:05:48 +10:00
|
|
|
listitem = ListItem(item_path, path=item_path)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2017-05-04 04:30:33 +10:00
|
|
|
url=file,
|
2018-06-15 22:05:48 +10:00
|
|
|
listitem=listitem)
|
2017-05-12 03:26:13 +10:00
|
|
|
break
|
2016-04-09 23:51:30 +10:00
|
|
|
else:
|
2018-06-15 22:15:39 +10:00
|
|
|
LOG.error('Kodi cannot access folder %s', path)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(int(argv[1]))
|
2016-04-09 23:46:51 +10:00
|
|
|
|
|
|
|
|
2018-06-22 03:24:37 +10:00
|
|
|
@utils.catch_exceptions(warnuser=False)
|
2018-06-15 22:05:48 +10:00
|
|
|
def extra_fanart(plex_id, plex_path):
|
2016-06-20 00:42:44 +10:00
|
|
|
"""
|
|
|
|
Get extrafanart for listitem
|
|
|
|
will be called by skinhelper script to get the extrafanart
|
2018-06-15 22:05:48 +10:00
|
|
|
for tvshows we get the plex_id just from the path
|
2016-06-20 00:42:44 +10:00
|
|
|
"""
|
2018-06-15 22:05:48 +10:00
|
|
|
LOG.debug('Called with plex_id: %s, plex_path: %s', plex_id, plex_path)
|
|
|
|
if not plex_id:
|
|
|
|
if "plugin.video.plexkodiconnect" in plex_path:
|
|
|
|
plex_id = plex_path.split("/")[-2]
|
|
|
|
if not plex_id:
|
|
|
|
LOG.error('Could not get a plex_id, aborting')
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]))
|
2016-06-20 00:42:44 +10:00
|
|
|
|
2016-07-23 00:55:57 +10:00
|
|
|
# We need to store the images locally for this to work
|
|
|
|
# because of the caching system in xbmc
|
2018-06-24 02:25:18 +10:00
|
|
|
fanart_dir = path_ops.translate_path("special://thumbnails/plex/%s/"
|
|
|
|
% plex_id)
|
|
|
|
if not path_ops.exists(fanart_dir):
|
2016-07-23 00:55:57 +10:00
|
|
|
# Download the images to the cache directory
|
2018-06-24 02:25:18 +10:00
|
|
|
path_ops.makedirs(fanart_dir)
|
2018-11-26 17:19:34 +11:00
|
|
|
app.init(entrypoint=True)
|
2018-06-22 03:24:37 +10:00
|
|
|
xml = PF.GetPlexMetadata(plex_id)
|
2016-07-23 00:55:57 +10:00
|
|
|
if xml is None:
|
2018-06-15 22:05:48 +10:00
|
|
|
LOG.error('Could not download metadata for %s', plex_id)
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]))
|
2016-06-20 00:42:44 +10:00
|
|
|
|
2017-01-25 05:59:38 +11:00
|
|
|
api = API(xml[0])
|
2018-02-12 00:42:49 +11:00
|
|
|
backdrops = api.artwork()['Backdrop']
|
2016-07-23 00:55:57 +10:00
|
|
|
for count, backdrop in enumerate(backdrops):
|
|
|
|
# Same ordering as in artwork
|
2018-06-24 02:25:18 +10:00
|
|
|
art_file = utils.try_encode(path_ops.path.join(
|
|
|
|
fanart_dir, "fanart%.3d.jpg" % count))
|
2018-06-15 22:08:43 +10:00
|
|
|
listitem = ListItem("%.3d" % count, path=art_file)
|
2016-07-23 00:55:57 +10:00
|
|
|
xbmcplugin.addDirectoryItem(
|
2018-06-24 18:04:30 +10:00
|
|
|
handle=int(argv[1]),
|
2018-06-15 22:07:53 +10:00
|
|
|
url=art_file,
|
2018-06-15 22:08:43 +10:00
|
|
|
listitem=listitem)
|
2018-06-24 02:25:18 +10:00
|
|
|
path_ops.copyfile(backdrop, utils.try_decode(art_file))
|
2016-07-23 00:55:57 +10:00
|
|
|
else:
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.info("Found cached backdrop.")
|
2016-07-23 00:55:57 +10:00
|
|
|
# Use existing cached images
|
2018-06-24 02:25:18 +10:00
|
|
|
fanart_dir = utils.try_decode(fanart_dir)
|
|
|
|
for root, _, files in path_ops.walk(fanart_dir):
|
|
|
|
root = utils.decode_path(root)
|
2017-05-04 04:30:33 +10:00
|
|
|
for file in files:
|
2018-06-24 02:25:18 +10:00
|
|
|
file = utils.decode_path(file)
|
|
|
|
art_file = utils.try_encode(path_ops.path.join(root, file))
|
2018-06-15 22:08:43 +10:00
|
|
|
listitem = ListItem(file, path=art_file)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2018-06-15 22:07:53 +10:00
|
|
|
url=art_file,
|
2018-06-15 22:08:43 +10:00
|
|
|
listitem=listitem)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(int(argv[1]))
|
2016-03-04 00:00:48 +11:00
|
|
|
|
|
|
|
|
2018-07-17 21:48:09 +10:00
|
|
|
def _wait_for_auth():
|
|
|
|
"""
|
|
|
|
Call to be sure that PKC is authenticated, e.g. for widgets on Kodi
|
|
|
|
startup. Will wait for at most 30s, then fail if not authenticated.
|
|
|
|
|
|
|
|
Will set xbmcplugin.endOfDirectory(int(argv[1]), False) if failed
|
|
|
|
"""
|
|
|
|
counter = 0
|
|
|
|
while utils.window('plex_authenticated') != 'true':
|
|
|
|
counter += 1
|
|
|
|
if counter == 300:
|
|
|
|
LOG.error('Aborting view, we were not authenticated for PMS')
|
|
|
|
xbmcplugin.endOfDirectory(int(argv[1]), False)
|
|
|
|
return False
|
|
|
|
sleep(100)
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2018-06-15 22:11:17 +10:00
|
|
|
def on_deck_episodes(viewid, tagname, limit):
|
2016-03-15 23:09:51 +11:00
|
|
|
"""
|
|
|
|
Retrieves Plex On Deck items, currently only for TV shows
|
|
|
|
|
|
|
|
Input:
|
|
|
|
viewid: Plex id of the library section, e.g. '1'
|
|
|
|
tagname: Name of the Plex library, e.g. "My Movies"
|
2016-03-16 00:19:56 +11:00
|
|
|
limit: Max. number of items to retrieve, e.g. 50
|
2016-03-15 23:09:51 +11:00
|
|
|
"""
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'episodes')
|
2018-06-22 03:24:37 +10:00
|
|
|
append_show_title = utils.settings('OnDeckTvAppendShow') == 'true'
|
|
|
|
append_sxxexx = utils.settings('OnDeckTvAppendSeason') == 'true'
|
|
|
|
if utils.settings('OnDeckTVextended') == 'false':
|
2016-04-18 19:23:05 +10:00
|
|
|
# Chances are that this view is used on Kodi startup
|
|
|
|
# Wait till we've connected to a PMS. At most 30s
|
2018-07-17 21:48:09 +10:00
|
|
|
if not _wait_for_auth():
|
|
|
|
return
|
2018-11-26 17:19:34 +11:00
|
|
|
# We're using another python instance - need to load some vars
|
|
|
|
app.init(entrypoint=True)
|
2018-06-22 03:24:37 +10:00
|
|
|
xml = DU().downloadUrl('{server}/library/sections/%s/onDeck' % viewid)
|
2016-04-18 19:23:05 +10:00
|
|
|
if xml in (None, 401):
|
2018-06-15 22:15:39 +10:00
|
|
|
LOG.error('Could not download PMS xml for view %s', viewid)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(int(argv[1]), False)
|
2018-06-08 00:27:41 +10:00
|
|
|
return
|
|
|
|
counter = 0
|
2016-04-22 18:26:40 +10:00
|
|
|
for item in xml:
|
2017-01-25 05:59:38 +11:00
|
|
|
api = API(item)
|
2018-02-12 00:42:49 +11:00
|
|
|
listitem = api.create_listitem(
|
|
|
|
append_show_title=append_show_title,
|
|
|
|
append_sxxexx=append_sxxexx)
|
2018-06-08 00:27:41 +10:00
|
|
|
if api.resume_point():
|
|
|
|
listitem.setProperty('resumetime', str(api.resume_point()))
|
2018-07-08 21:24:25 +10:00
|
|
|
path = api.path(force_first_media=True)
|
2016-04-22 18:26:40 +10:00
|
|
|
xbmcplugin.addDirectoryItem(
|
2018-06-24 18:04:30 +10:00
|
|
|
handle=int(argv[1]),
|
2018-06-08 00:27:41 +10:00
|
|
|
url=path,
|
2016-04-22 18:26:40 +10:00
|
|
|
listitem=listitem)
|
2018-06-08 00:27:41 +10:00
|
|
|
counter += 1
|
|
|
|
if counter == limit:
|
2017-02-03 06:31:58 +11:00
|
|
|
break
|
2018-06-08 00:27:41 +10:00
|
|
|
xbmcplugin.endOfDirectory(
|
2018-06-24 18:04:30 +10:00
|
|
|
handle=int(argv[1]),
|
2018-06-22 03:24:37 +10:00
|
|
|
cacheToDisc=utils.settings('enableTextureCache') == 'true')
|
2018-06-08 00:27:41 +10:00
|
|
|
return
|
2016-04-18 19:23:05 +10:00
|
|
|
|
2016-03-15 23:09:51 +11:00
|
|
|
# if the addon is called with nextup parameter,
|
|
|
|
# we return the nextepisodes list of the given tagname
|
|
|
|
# First we get a list of all the TV shows - filtered by tag
|
2017-01-25 05:59:38 +11:00
|
|
|
params = {
|
|
|
|
'sort': {'order': "descending", 'method': "lastplayed"},
|
|
|
|
'filter': {
|
|
|
|
'and': [
|
|
|
|
{'operator': "true", 'field': "inprogress", 'value': ""},
|
|
|
|
{'operator': "is", 'field': "tag", 'value': "%s" % tagname}
|
|
|
|
]}
|
2016-03-15 23:09:51 +11:00
|
|
|
}
|
2018-02-07 07:00:32 +11:00
|
|
|
items = js.get_tv_shows(params)
|
|
|
|
if not items:
|
|
|
|
# Now items retrieved - empty directory
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(handle=int(argv[1]))
|
2018-02-07 07:00:32 +11:00
|
|
|
return
|
|
|
|
|
2017-01-25 05:59:38 +11:00
|
|
|
params = {
|
|
|
|
'sort': {'method': "episode"},
|
|
|
|
'limits': {"end": 1},
|
|
|
|
'properties': [
|
|
|
|
"title", "playcount", "season", "episode", "showtitle",
|
|
|
|
"plot", "file", "rating", "resume", "tvshowid", "art",
|
|
|
|
"streamdetails", "firstaired", "runtime", "cast", "writer",
|
|
|
|
"dateadded", "lastplayed"
|
|
|
|
],
|
2016-03-15 23:09:51 +11:00
|
|
|
}
|
2018-06-22 03:24:37 +10:00
|
|
|
if utils.settings('ignoreSpecialsNextEpisodes') == "true":
|
2017-01-25 05:59:38 +11:00
|
|
|
params['filter'] = {
|
2016-03-15 23:09:51 +11:00
|
|
|
'and': [
|
|
|
|
{'operator': "lessthan", 'field': "playcount", 'value': "1"},
|
|
|
|
{'operator': "greaterthan", 'field': "season", 'value': "0"}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
else:
|
2017-01-25 05:59:38 +11:00
|
|
|
params['filter'] = {
|
2016-03-15 23:09:51 +11:00
|
|
|
'or': [
|
|
|
|
{'operator': "lessthan", 'field': "playcount", 'value': "1"},
|
|
|
|
{'operator': "true", 'field': "inprogress", 'value': ""}
|
|
|
|
]
|
|
|
|
}
|
2018-02-07 07:00:32 +11:00
|
|
|
|
2016-03-15 23:09:51 +11:00
|
|
|
# Are there any episodes still in progress/not yet finished watching?!?
|
|
|
|
# Then we should show this episode, NOT the "next up"
|
2017-01-25 05:59:38 +11:00
|
|
|
inprog_params = {
|
|
|
|
'sort': {'method': "episode"},
|
|
|
|
'filter': {'operator': "true", 'field': "inprogress", 'value': ""},
|
|
|
|
'properties': params['properties']
|
2016-03-15 23:09:51 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
count = 0
|
2018-02-07 07:00:32 +11:00
|
|
|
for item in items:
|
2017-01-25 05:59:38 +11:00
|
|
|
inprog_params['tvshowid'] = item['tvshowid']
|
2017-12-09 05:43:06 +11:00
|
|
|
episodes = js.get_episodes(inprog_params)
|
|
|
|
if not episodes:
|
2016-03-15 23:09:51 +11:00
|
|
|
# No, there are no episodes not yet finished. Get "next up"
|
2017-01-25 05:59:38 +11:00
|
|
|
params['tvshowid'] = item['tvshowid']
|
2017-12-09 05:43:06 +11:00
|
|
|
episodes = js.get_episodes(params)
|
2018-02-07 07:00:32 +11:00
|
|
|
if not episodes:
|
|
|
|
# Also no episodes currently coming up
|
|
|
|
continue
|
2016-03-15 23:09:51 +11:00
|
|
|
for episode in episodes:
|
|
|
|
# There will always be only 1 episode ('limit=1')
|
2018-06-15 21:55:32 +10:00
|
|
|
listitem = create_listitem(episode,
|
|
|
|
append_show_title=append_show_title,
|
|
|
|
append_sxxexx=append_sxxexx)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2018-02-07 07:00:32 +11:00
|
|
|
url=episode['file'],
|
|
|
|
listitem=listitem,
|
|
|
|
isFolder=False)
|
2016-03-15 23:09:51 +11:00
|
|
|
count += 1
|
|
|
|
if count >= limit:
|
|
|
|
break
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(handle=int(argv[1]))
|
2016-04-17 21:36:41 +10:00
|
|
|
|
|
|
|
|
2018-07-30 21:20:40 +10:00
|
|
|
def playlists(content_type):
|
2018-07-17 21:48:09 +10:00
|
|
|
"""
|
2018-07-19 22:53:16 +10:00
|
|
|
Lists all Plex playlists of the media type plex_playlist_type
|
2018-07-30 21:20:40 +10:00
|
|
|
content_type: 'audio', 'video'
|
2018-07-17 21:48:09 +10:00
|
|
|
"""
|
2018-07-30 21:20:40 +10:00
|
|
|
LOG.debug('Listing Plex %s playlists', content_type)
|
2018-07-17 21:48:09 +10:00
|
|
|
if not _wait_for_auth():
|
|
|
|
return
|
|
|
|
xbmcplugin.setContent(int(argv[1]), 'files')
|
2018-11-26 17:19:34 +11:00
|
|
|
app.init(entrypoint=True)
|
2018-07-17 21:48:09 +10:00
|
|
|
from .playlists.pms import all_playlists
|
|
|
|
xml = all_playlists()
|
|
|
|
if xml is None:
|
|
|
|
return
|
|
|
|
for item in xml:
|
|
|
|
api = API(item)
|
2018-07-30 21:20:40 +10:00
|
|
|
if not api.playlist_type() == content_type:
|
2018-07-17 21:48:09 +10:00
|
|
|
continue
|
|
|
|
listitem = ListItem(api.title())
|
2018-07-19 22:54:46 +10:00
|
|
|
listitem.setArt({'thumb': api.one_artwork('composite')})
|
2018-07-17 21:48:09 +10:00
|
|
|
url = "plugin://%s/" % v.ADDON_ID
|
|
|
|
key = api.path_and_plex_id()
|
|
|
|
params = {
|
|
|
|
'mode': "browseplex",
|
|
|
|
'key': key,
|
|
|
|
}
|
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
|
|
|
url="%s?%s" % (url, urlencode(params)),
|
|
|
|
isFolder=True,
|
|
|
|
listitem=listitem)
|
|
|
|
xbmcplugin.endOfDirectory(
|
|
|
|
handle=int(argv[1]),
|
|
|
|
cacheToDisc=utils.settings('enableTextureCache') == 'true')
|
|
|
|
|
|
|
|
|
2018-07-28 00:01:05 +10:00
|
|
|
def hub(content_type):
|
|
|
|
"""
|
|
|
|
Plus hub endpoint pms:port/hubs. Need to separate Kodi types with
|
|
|
|
content_type:
|
|
|
|
audio, video, image
|
|
|
|
"""
|
2018-11-26 17:19:34 +11:00
|
|
|
app.init(entrypoint=True)
|
2018-07-28 00:01:05 +10:00
|
|
|
xml = PF.get_plex_hub()
|
|
|
|
try:
|
|
|
|
xml.attrib
|
|
|
|
except AttributeError:
|
|
|
|
LOG.error('Could not get Plex hub listing')
|
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]), False)
|
|
|
|
for entry in xml:
|
|
|
|
api = API(entry)
|
|
|
|
if content_type == 'video' and api.plex_type() in v.PLEX_VIDEOTYPES:
|
|
|
|
__build_folder(entry)
|
|
|
|
elif content_type == 'audio' and api.plex_type() in v.PLEX_AUDIOTYPES:
|
|
|
|
__build_folder(entry)
|
|
|
|
elif content_type == 'image' and api.plex_type() == v.PLEX_TYPE_PHOTO:
|
|
|
|
__build_folder(entry)
|
2019-01-01 23:19:26 +11:00
|
|
|
else:
|
|
|
|
# Needed for widgets, where no content_type is provided
|
|
|
|
__build_folder(entry)
|
2018-07-28 00:01:05 +10:00
|
|
|
xbmcplugin.endOfDirectory(
|
|
|
|
handle=int(argv[1]),
|
|
|
|
cacheToDisc=utils.settings('enableTextureCache') == 'true')
|
|
|
|
|
|
|
|
|
2016-04-17 21:36:41 +10:00
|
|
|
def watchlater():
|
|
|
|
"""
|
|
|
|
Listing for plex.tv Watch Later section (if signed in to plex.tv)
|
|
|
|
"""
|
2018-06-22 03:24:37 +10:00
|
|
|
if utils.window('plex_token') == '':
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.error('No watch later - not signed in to plex.tv')
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]), False)
|
2018-06-22 03:24:37 +10:00
|
|
|
if utils.window('plex_restricteduser') == 'true':
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.error('No watch later - restricted user')
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]), False)
|
2016-04-17 21:36:41 +10:00
|
|
|
|
2018-06-22 03:24:37 +10:00
|
|
|
xml = DU().downloadUrl('https://plex.tv/pms/playlists/queue/all',
|
|
|
|
authenticate=False,
|
|
|
|
headerOptions={'X-Plex-Token': utils.window('plex_token')})
|
2016-04-17 21:36:41 +10:00
|
|
|
if xml in (None, 401):
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.error('Could not download watch later list from plex.tv')
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]), False)
|
2016-04-17 21:36:41 +10:00
|
|
|
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.info('Displaying watch later plex.tv items')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'movies')
|
2018-06-22 03:24:37 +10:00
|
|
|
direct_paths = utils.settings('useDirectPaths') == '1'
|
2016-04-17 21:36:41 +10:00
|
|
|
for item in xml:
|
2018-06-08 00:27:41 +10:00
|
|
|
__build_item(item, direct_paths)
|
2016-04-17 21:36:41 +10:00
|
|
|
xbmcplugin.endOfDirectory(
|
2018-06-24 18:04:30 +10:00
|
|
|
handle=int(argv[1]),
|
2018-06-22 03:24:37 +10:00
|
|
|
cacheToDisc=utils.settings('enableTextureCache') == 'true')
|
2016-05-30 00:52:00 +10:00
|
|
|
|
|
|
|
|
2017-03-08 02:37:36 +11:00
|
|
|
def channels():
|
|
|
|
"""
|
|
|
|
Listing for Plex Channels
|
|
|
|
"""
|
2018-06-22 03:24:37 +10:00
|
|
|
xml = DU().downloadUrl('{server}/channels/all')
|
2017-03-08 02:37:36 +11:00
|
|
|
try:
|
|
|
|
xml[0].attrib
|
2017-05-01 01:07:56 +10:00
|
|
|
except (ValueError, AttributeError, IndexError, TypeError):
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.error('Could not download Plex Channels')
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]), False)
|
2017-03-08 02:37:36 +11:00
|
|
|
|
2018-06-15 21:40:25 +10:00
|
|
|
LOG.info('Displaying Plex Channels')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'files')
|
2017-03-09 02:21:00 +11:00
|
|
|
for method in v.SORT_METHODS_DIRECTORY:
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addSortMethod(int(argv[1]), getattr(xbmcplugin, method))
|
2017-03-08 02:37:36 +11:00
|
|
|
for item in xml:
|
|
|
|
__build_folder(item)
|
|
|
|
xbmcplugin.endOfDirectory(
|
2018-06-24 18:04:30 +10:00
|
|
|
handle=int(argv[1]),
|
2018-06-22 03:24:37 +10:00
|
|
|
cacheToDisc=utils.settings('enableTextureCache') == 'true')
|
2017-03-08 02:37:36 +11:00
|
|
|
|
|
|
|
|
2017-03-09 02:21:00 +11:00
|
|
|
def browse_plex(key=None, plex_section_id=None):
|
2017-03-08 02:37:36 +11:00
|
|
|
"""
|
2017-03-09 02:21:00 +11:00
|
|
|
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
|
2017-03-08 02:37:36 +11:00
|
|
|
"""
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Browsing to key %s, section %s', key, plex_section_id)
|
2018-11-26 17:19:34 +11:00
|
|
|
app.init(entrypoint=True)
|
2017-03-09 02:21:00 +11:00
|
|
|
if key:
|
2018-06-22 03:24:37 +10:00
|
|
|
xml = DU().downloadUrl('{server}%s' % key)
|
2017-03-09 02:21:00 +11:00
|
|
|
else:
|
2018-06-22 03:24:37 +10:00
|
|
|
xml = PF.GetPlexSectionResults(plex_section_id)
|
2017-03-08 02:37:36 +11:00
|
|
|
try:
|
2018-07-28 00:01:05 +10:00
|
|
|
xml.attrib
|
|
|
|
except AttributeError:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.error('Could not browse to key %s, section %s',
|
|
|
|
key, plex_section_id)
|
2018-06-24 18:04:30 +10:00
|
|
|
return xbmcplugin.endOfDirectory(int(argv[1]), False)
|
2017-03-09 02:21:00 +11:00
|
|
|
|
|
|
|
photos = False
|
|
|
|
movies = False
|
|
|
|
clips = False
|
|
|
|
tvshows = False
|
|
|
|
episodes = False
|
|
|
|
songs = False
|
|
|
|
artists = False
|
|
|
|
albums = False
|
|
|
|
musicvideos = False
|
2018-06-22 03:24:37 +10:00
|
|
|
direct_paths = utils.settings('useDirectPaths') == '1'
|
2017-03-08 02:37:36 +11:00
|
|
|
for item in xml:
|
|
|
|
if item.tag == 'Directory':
|
2017-03-09 03:53:43 +11:00
|
|
|
__build_folder(item, plex_section_id=plex_section_id)
|
2017-03-08 02:37:36 +11:00
|
|
|
else:
|
2017-03-19 22:14:16 +11:00
|
|
|
typus = item.attrib.get('type')
|
2018-06-08 00:27:41 +10:00
|
|
|
__build_item(item, direct_paths)
|
2017-03-09 02:21:00 +11:00
|
|
|
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
|
2017-03-09 03:02:26 +11:00
|
|
|
if movies is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to movies')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'movies')
|
2017-03-09 03:02:26 +11:00
|
|
|
sort_methods = v.SORT_METHODS_MOVIES
|
2017-03-09 02:21:00 +11:00
|
|
|
elif clips is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Clips -> Setting view to movies')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'movies')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHODS_CLIPS
|
2017-03-09 03:02:26 +11:00
|
|
|
elif photos is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to images')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'images')
|
2017-03-09 03:02:26 +11:00
|
|
|
sort_methods = v.SORT_METHODS_PHOTOS
|
2017-03-09 02:21:00 +11:00
|
|
|
elif tvshows is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to tvshows')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'tvshows')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHOD_TVSHOWS
|
|
|
|
elif episodes is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to episodes')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'episodes')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHODS_EPISODES
|
|
|
|
elif songs is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to songs')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'songs')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHODS_SONGS
|
|
|
|
elif artists is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to artists')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'artists')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHODS_ARTISTS
|
|
|
|
elif albums is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to albums')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'albums')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHODS_ALBUMS
|
|
|
|
elif musicvideos is True:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to musicvideos')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'musicvideos')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHODS_MOVIES
|
|
|
|
else:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Setting view to files')
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'files')
|
2017-03-09 02:21:00 +11:00
|
|
|
sort_methods = v.SORT_METHODS_DIRECTORY
|
|
|
|
|
|
|
|
for method in sort_methods:
|
2018-07-19 23:07:08 +10:00
|
|
|
LOG.debug('Adding Kodi sort method %s', method)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addSortMethod(int(argv[1]), getattr(xbmcplugin, method))
|
2017-03-09 02:21:00 +11:00
|
|
|
|
|
|
|
# Set the Kodi title for this view
|
|
|
|
title = xml.attrib.get('librarySectionTitle', xml.attrib.get('title1'))
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setPluginCategory(int(argv[1]), title)
|
2017-03-09 02:21:00 +11:00
|
|
|
|
2017-03-08 02:37:36 +11:00
|
|
|
xbmcplugin.endOfDirectory(
|
2018-06-24 18:04:30 +10:00
|
|
|
handle=int(argv[1]),
|
2018-06-22 03:24:37 +10:00
|
|
|
cacheToDisc=utils.settings('enableTextureCache') == 'true')
|
2017-03-08 02:37:36 +11:00
|
|
|
|
|
|
|
|
2017-03-09 03:53:43 +11:00
|
|
|
def __build_folder(xml_element, plex_section_id=None):
|
2017-03-08 20:51:21 +11:00
|
|
|
url = "plugin://%s/" % v.ADDON_ID
|
2018-07-28 00:01:05 +10:00
|
|
|
key = xml_element.get('fastKey', xml_element.get('key'))
|
2017-03-09 03:53:43 +11:00
|
|
|
if not key.startswith('/'):
|
|
|
|
key = '/library/sections/%s/%s' % (plex_section_id, key)
|
2017-03-08 02:37:36 +11:00
|
|
|
params = {
|
2017-03-09 02:21:00 +11:00
|
|
|
'mode': "browseplex",
|
2017-03-09 03:53:43 +11:00
|
|
|
'key': key,
|
2017-03-08 02:37:36 +11:00
|
|
|
}
|
2018-07-28 00:01:05 +10:00
|
|
|
if plex_section_id:
|
|
|
|
params['id'] = plex_section_id
|
|
|
|
listitem = ListItem(xml_element.get('title'))
|
|
|
|
thumb = xml_element.get('thumb') or \
|
|
|
|
'special://home/addons/%s/icon.png' % v.ADDON_ID
|
|
|
|
art = xml_element.get('art') or \
|
|
|
|
'special://home/addons/%s/fanart.jpg' % v.ADDON_ID
|
|
|
|
listitem.setThumbnailImage(thumb)
|
|
|
|
listitem.setArt({'fanart': art, 'landscape': art})
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2017-03-08 20:51:21 +11:00
|
|
|
url="%s?%s" % (url, urlencode(params)),
|
|
|
|
isFolder=True,
|
|
|
|
listitem=listitem)
|
2017-03-08 02:37:36 +11:00
|
|
|
|
|
|
|
|
2018-06-08 00:27:41 +10:00
|
|
|
def __build_item(xml_element, direct_paths):
|
2017-03-08 02:37:36 +11:00
|
|
|
api = API(xml_element)
|
2018-02-12 00:42:49 +11:00
|
|
|
listitem = api.create_listitem()
|
|
|
|
resume = api.resume_point()
|
2018-01-29 03:28:02 +11:00
|
|
|
if resume:
|
|
|
|
listitem.setProperty('resumetime', str(resume))
|
2018-02-12 00:42:49 +11:00
|
|
|
if (api.path_and_plex_id().startswith('/system/services') or
|
|
|
|
api.path_and_plex_id().startswith('http')):
|
2017-03-09 04:24:50 +11:00
|
|
|
params = {
|
2017-03-14 07:39:07 +11:00
|
|
|
'mode': 'plex_node',
|
2018-02-12 19:22:39 +11:00
|
|
|
'key': xml_element.attrib.get('key'),
|
2018-01-29 03:21:28 +11:00
|
|
|
'offset': xml_element.attrib.get('viewOffset', '0'),
|
2017-03-09 04:24:50 +11:00
|
|
|
}
|
2017-03-19 22:14:16 +11:00
|
|
|
url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
|
2018-02-12 00:42:49 +11:00
|
|
|
elif api.plex_type() == v.PLEX_TYPE_PHOTO:
|
2017-03-19 22:14:16 +11:00
|
|
|
url = api.get_picture_path()
|
2017-03-09 04:24:50 +11:00
|
|
|
else:
|
2018-06-08 00:27:41 +10:00
|
|
|
url = api.path(direct_paths=direct_paths)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2017-03-09 04:24:50 +11:00
|
|
|
url=url,
|
2017-03-08 20:51:21 +11:00
|
|
|
listitem=listitem)
|
2017-03-08 02:37:36 +11:00
|
|
|
|
|
|
|
|
2018-05-05 03:03:27 +10:00
|
|
|
def extras(plex_id):
|
|
|
|
"""
|
|
|
|
Lists all extras for plex_id
|
|
|
|
"""
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.setContent(int(argv[1]), 'movies')
|
2018-11-26 17:19:34 +11:00
|
|
|
app.init(entrypoint=True)
|
2018-06-22 03:24:37 +10:00
|
|
|
xml = PF.GetPlexMetadata(plex_id)
|
2018-05-05 03:03:27 +10:00
|
|
|
try:
|
|
|
|
xml[0].attrib
|
|
|
|
except (TypeError, IndexError, KeyError):
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(int(argv[1]))
|
2018-05-05 03:03:27 +10:00
|
|
|
return
|
|
|
|
for item in API(xml[0]).extras():
|
|
|
|
api = API(item)
|
|
|
|
listitem = api.create_listitem()
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.addDirectoryItem(handle=int(argv[1]),
|
2018-05-05 03:03:27 +10:00
|
|
|
url=api.path(),
|
|
|
|
listitem=listitem)
|
2018-06-24 18:04:30 +10:00
|
|
|
xbmcplugin.endOfDirectory(int(argv[1]))
|
2018-05-05 03:03:27 +10:00
|
|
|
|
|
|
|
|
2018-06-15 22:13:46 +10:00
|
|
|
def create_new_pms():
|
2016-05-30 00:52:00 +10:00
|
|
|
"""
|
|
|
|
Opens dialogs for the user the plug in the PMS details
|
|
|
|
"""
|
2018-11-19 00:59:17 +11:00
|
|
|
LOG.info('Request to manually enter new PMS address')
|
|
|
|
utils.plex_command('enter_new_pms_address')
|