Plex Companien (Plexbmc helper) version 0.1
This commit is contained in:
parent
e859a807bc
commit
48ba7f0869
16 changed files with 274 additions and 86 deletions
21
default.py
21
default.py
|
@ -8,7 +8,6 @@ import urlparse
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcaddon
|
import xbmcaddon
|
||||||
import xbmcgui
|
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
@ -22,9 +21,6 @@ sys.path.append(base_resource)
|
||||||
import entrypoint
|
import entrypoint
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
import PlexAPI
|
|
||||||
import userclient
|
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
enableProfiling = False
|
enableProfiling = False
|
||||||
|
@ -34,8 +30,8 @@ class Main:
|
||||||
|
|
||||||
# MAIN ENTRY POINT
|
# MAIN ENTRY POINT
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
plx = PlexAPI.PlexAPI()
|
|
||||||
# Parse parameters
|
# Parse parameters
|
||||||
|
xbmc.log("Full sys.argv received: %s" % sys.argv)
|
||||||
base_url = sys.argv[0]
|
base_url = sys.argv[0]
|
||||||
addon_handle = int(sys.argv[1])
|
addon_handle = int(sys.argv[1])
|
||||||
params = urlparse.parse_qs(sys.argv[2][1:])
|
params = urlparse.parse_qs(sys.argv[2][1:])
|
||||||
|
@ -44,11 +40,15 @@ class Main:
|
||||||
mode = params['mode'][0]
|
mode = params['mode'][0]
|
||||||
itemid = params.get('id')
|
itemid = params.get('id')
|
||||||
if itemid:
|
if itemid:
|
||||||
itemid = itemid[0]
|
try:
|
||||||
|
itemid = itemid[0]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
except:
|
except:
|
||||||
params = {}
|
params = {}
|
||||||
mode = ""
|
mode = ""
|
||||||
|
xbmc.log("mode: %s, itemid: %s, base_url: %s, addon_handle: %s"
|
||||||
|
% (mode, itemid, base_url, addon_handle), 2)
|
||||||
|
|
||||||
modes = {
|
modes = {
|
||||||
|
|
||||||
|
@ -65,7 +65,8 @@ class Main:
|
||||||
'nextup': entrypoint.getNextUpEpisodes,
|
'nextup': entrypoint.getNextUpEpisodes,
|
||||||
'inprogressepisodes': entrypoint.getInProgressEpisodes,
|
'inprogressepisodes': entrypoint.getInProgressEpisodes,
|
||||||
'recentepisodes': entrypoint.getRecentEpisodes,
|
'recentepisodes': entrypoint.getRecentEpisodes,
|
||||||
'refreshplaylist': entrypoint.refreshPlaylist
|
'refreshplaylist': entrypoint.refreshPlaylist,
|
||||||
|
'companion': entrypoint.plexCompanion
|
||||||
}
|
}
|
||||||
|
|
||||||
if "extrafanart" in sys.argv[0]:
|
if "extrafanart" in sys.argv[0]:
|
||||||
|
@ -90,7 +91,9 @@ class Main:
|
||||||
elif mode == "channelsfolder":
|
elif mode == "channelsfolder":
|
||||||
folderid = params['folderid'][0]
|
folderid = params['folderid'][0]
|
||||||
modes[mode](itemid, folderid)
|
modes[mode](itemid, folderid)
|
||||||
|
elif mode == "companion":
|
||||||
|
resume = params.get('resume', '')
|
||||||
|
modes[mode](itemid, resume=resume)
|
||||||
else:
|
else:
|
||||||
modes[mode]()
|
modes[mode]()
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -53,15 +53,13 @@ import requests
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
import uuid
|
from urllib import urlencode, quote_plus
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import xml.etree.cElementTree as etree
|
import xml.etree.cElementTree as etree
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import xml.etree.ElementTree as etree
|
import xml.etree.ElementTree as etree
|
||||||
|
|
||||||
from urllib import urlencode, quote_plus
|
|
||||||
|
|
||||||
# from Version import __VERSION__
|
# from Version import __VERSION__
|
||||||
# from Debug import * # dprint(), prettyXML()
|
# from Debug import * # dprint(), prettyXML()
|
||||||
|
|
||||||
|
@ -1499,6 +1497,7 @@ class PlexAPI():
|
||||||
xml = self.doUtils.downloadUrl(url, headerOptions=headerOptions)
|
xml = self.doUtils.downloadUrl(url, headerOptions=headerOptions)
|
||||||
if not xml:
|
if not xml:
|
||||||
self.logMsg("Error retrieving metadata for %s" % url, -1)
|
self.logMsg("Error retrieving metadata for %s" % url, -1)
|
||||||
|
xml = None
|
||||||
return xml
|
return xml
|
||||||
|
|
||||||
|
|
||||||
|
|
111
resources/lib/PlexCompanion.py
Normal file
111
resources/lib/PlexCompanion.py
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import threading
|
||||||
|
import traceback
|
||||||
|
import socket
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import xbmc
|
||||||
|
|
||||||
|
import clientinfo
|
||||||
|
import utils
|
||||||
|
from plexbmchelper import listener, plexgdm, subscribers
|
||||||
|
from plexbmchelper.settings import settings
|
||||||
|
|
||||||
|
|
||||||
|
class PlexCompanion(threading.Thread):
|
||||||
|
def __init__(self):
|
||||||
|
self._shouldStop = threading.Event()
|
||||||
|
self.port = int(utils.settings('companionPort'))
|
||||||
|
ci = clientinfo.ClientInfo()
|
||||||
|
self.addonName = ci.getAddonName()
|
||||||
|
self.clientId = ci.getDeviceId()
|
||||||
|
self.deviceName = ci.getDeviceName()
|
||||||
|
self.logMsg("----===## Starting PlexBMC Helper ##===----", 1)
|
||||||
|
|
||||||
|
# Start GDM for server/client discovery
|
||||||
|
self.client = plexgdm.plexgdm(debug=settings['gdm_debug'])
|
||||||
|
self.client.clientDetails(self.clientId, # UUID
|
||||||
|
self.deviceName, # clientName
|
||||||
|
self.port,
|
||||||
|
self.addonName,
|
||||||
|
'1.0') # Version
|
||||||
|
self.logMsg("Registration string is: %s "
|
||||||
|
% self.client.getClientDetails(), 1)
|
||||||
|
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
|
def logMsg(self, msg, lvl=1):
|
||||||
|
className = self.__class__.__name__
|
||||||
|
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
|
||||||
|
|
||||||
|
def stopClient(self):
|
||||||
|
# When emby for kodi terminates
|
||||||
|
self._shouldStop.set()
|
||||||
|
|
||||||
|
def stopped(self):
|
||||||
|
return self._shouldStop.isSet()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
start_count = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
httpd = listener.ThreadedHTTPServer(
|
||||||
|
('', self.port),
|
||||||
|
listener.MyHandler)
|
||||||
|
httpd.timeout = 0.95
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
self.logMsg("Unable to start PlexCompanion. Traceback:", -1)
|
||||||
|
self.logMsg(traceback.print_exc(), -1)
|
||||||
|
|
||||||
|
xbmc.sleep(3000)
|
||||||
|
|
||||||
|
if start_count == 3:
|
||||||
|
self.logMsg("Error: Unable to start web helper.", -1)
|
||||||
|
httpd = False
|
||||||
|
break
|
||||||
|
|
||||||
|
start_count += 1
|
||||||
|
|
||||||
|
if not httpd:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.client.start_all()
|
||||||
|
message_count = 0
|
||||||
|
is_running = False
|
||||||
|
while not self.stopped():
|
||||||
|
try:
|
||||||
|
|
||||||
|
httpd.handle_request()
|
||||||
|
message_count += 1
|
||||||
|
|
||||||
|
if message_count > 30:
|
||||||
|
if self.stopped():
|
||||||
|
break
|
||||||
|
if self.client.check_client_registration():
|
||||||
|
self.logMsg("Client is still registered", 1)
|
||||||
|
else:
|
||||||
|
self.logMsg("Client is no longer registered",
|
||||||
|
1)
|
||||||
|
self.logMsg("PlexBMC Helper still running on "
|
||||||
|
"port %s" % self.port, 1)
|
||||||
|
message_count = 0
|
||||||
|
|
||||||
|
if not is_running:
|
||||||
|
self.logMsg("PleXBMC Helper has started", 0)
|
||||||
|
|
||||||
|
is_running = True
|
||||||
|
if message_count % 1 == 0:
|
||||||
|
subscribers.subMgr.notify()
|
||||||
|
settings['serverList'] = self.client.getServerList()
|
||||||
|
except:
|
||||||
|
self.logMsg("Error in loop, continuing anyway", 1)
|
||||||
|
self.logMsg(traceback.print_exc(), 1)
|
||||||
|
|
||||||
|
self.client.stop_all()
|
||||||
|
try:
|
||||||
|
httpd.socket.shutdown(socket.SHUT_RDWR)
|
||||||
|
finally:
|
||||||
|
httpd.socket.close()
|
||||||
|
requests.dumpConnections()
|
||||||
|
self.logMsg("----===## STOP PlexBMC Helper ##===----", 0)
|
|
@ -218,6 +218,9 @@ class DownloadUtils():
|
||||||
r = s.delete(url, json=postBody, timeout=timeout, headers=header)
|
r = s.delete(url, json=postBody, timeout=timeout, headers=header)
|
||||||
elif type == "OPTIONS":
|
elif type == "OPTIONS":
|
||||||
r = s.options(url, json=postBody, timeout=timeout, headers=header)
|
r = s.options(url, json=postBody, timeout=timeout, headers=header)
|
||||||
|
# For Plex Companion
|
||||||
|
elif type == "POSTXML":
|
||||||
|
r = s.post(url, postBody, timeout=timeout, headers=header)
|
||||||
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# request session does not exists
|
# request session does not exists
|
||||||
|
|
|
@ -6,6 +6,7 @@ import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import urlparse
|
import urlparse
|
||||||
|
import re
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcaddon
|
import xbmcaddon
|
||||||
|
@ -26,10 +27,33 @@ import playutils
|
||||||
import api
|
import api
|
||||||
|
|
||||||
import PlexAPI
|
import PlexAPI
|
||||||
|
import embydb_functions
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def plexCompanion(fullurl, resume=""):
|
||||||
|
regex = re.compile(r'''/(\d+)$''')
|
||||||
|
itemid = regex.findall(fullurl)
|
||||||
|
try:
|
||||||
|
itemid = itemid[0]
|
||||||
|
except IndexError:
|
||||||
|
# No matches found, url not like:
|
||||||
|
# http://192.168.0.2:32400/library/metadata/243480
|
||||||
|
return False
|
||||||
|
# TODO: direct play an URL
|
||||||
|
# Initialize embydb
|
||||||
|
embyconn = utils.kodiSQL('emby')
|
||||||
|
embycursor = embyconn.cursor()
|
||||||
|
emby = embydb_functions.Embydb_Functions(embycursor)
|
||||||
|
# Get dbid using itemid
|
||||||
|
dbid = emby.getItem_byId(itemid)[0]
|
||||||
|
embyconn.close()
|
||||||
|
# Start playing
|
||||||
|
item = PlexAPI.PlexAPI().GetPlexMetadata(itemid)
|
||||||
|
pbutils.PlaybackUtils(item).play(itemid, dbid)
|
||||||
|
|
||||||
|
|
||||||
def doPlayback(itemid, dbid):
|
def doPlayback(itemid, dbid):
|
||||||
# Get a first XML to get the librarySectionUUID
|
# Get a first XML to get the librarySectionUUID
|
||||||
item = PlexAPI.PlexAPI().GetPlexMetadata(itemid)
|
item = PlexAPI.PlexAPI().GetPlexMetadata(itemid)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
import Queue
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
|
@ -21,7 +22,6 @@ import userclient
|
||||||
import videonodes
|
import videonodes
|
||||||
|
|
||||||
import PlexAPI
|
import PlexAPI
|
||||||
import Queue
|
|
||||||
|
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
|
||||||
|
@ -46,14 +46,9 @@ class ThreadedGetMetadata(threading.Thread):
|
||||||
self.lock = lock
|
self.lock = lock
|
||||||
self.userStop = userStop
|
self.userStop = userStop
|
||||||
self._shouldstop = threading.Event()
|
self._shouldstop = threading.Event()
|
||||||
self.addonName = clientinfo.ClientInfo().getAddonName()
|
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
def logMsg(self, msg, lvl=1):
|
def run(self):
|
||||||
className = self.__class__.__name__
|
|
||||||
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
|
|
||||||
|
|
||||||
def run_internal(self):
|
|
||||||
plx = PlexAPI.PlexAPI()
|
plx = PlexAPI.PlexAPI()
|
||||||
global getMetadataCount
|
global getMetadataCount
|
||||||
while self.stopped() is False:
|
while self.stopped() is False:
|
||||||
|
@ -68,25 +63,22 @@ class ThreadedGetMetadata(threading.Thread):
|
||||||
plexXML = plx.GetPlexMetadata(updateItem['itemId'])
|
plexXML = plx.GetPlexMetadata(updateItem['itemId'])
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
updateItem['XML'] = plexXML
|
# check whether valid XML
|
||||||
# place item into out queue
|
try:
|
||||||
self.out_queue.put(updateItem)
|
# .tag works for XML
|
||||||
|
plexXML.tag
|
||||||
|
updateItem['XML'] = plexXML
|
||||||
|
# place item into out queue
|
||||||
|
self.out_queue.put(updateItem)
|
||||||
|
# If we don't have a valid XML, don't put that into the queue
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
# Keep track of where we are at
|
# Keep track of where we are at
|
||||||
with self.lock:
|
with self.lock:
|
||||||
getMetadataCount += 1
|
getMetadataCount += 1
|
||||||
# signals to queue job is done
|
# signals to queue job is done
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
|
||||||
def run(self):
|
|
||||||
try:
|
|
||||||
self.run_internal()
|
|
||||||
except Exception as e:
|
|
||||||
xbmcgui.Dialog().ok(self.addonName,
|
|
||||||
"A sync thread has exited! "
|
|
||||||
"You should restart Kodi now. "
|
|
||||||
"Please report this on the forum.")
|
|
||||||
raise
|
|
||||||
|
|
||||||
def stopThread(self):
|
def stopThread(self):
|
||||||
self._shouldstop.set()
|
self._shouldstop.set()
|
||||||
|
|
||||||
|
@ -113,14 +105,9 @@ class ThreadedProcessMetadata(threading.Thread):
|
||||||
self.itemType = itemType
|
self.itemType = itemType
|
||||||
self.userStop = userStop
|
self.userStop = userStop
|
||||||
self._shouldstop = threading.Event()
|
self._shouldstop = threading.Event()
|
||||||
self.addonName = clientinfo.ClientInfo().getAddonName()
|
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
def logMsg(self, msg, lvl=1):
|
def run(self):
|
||||||
className = self.__class__.__name__
|
|
||||||
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
|
|
||||||
|
|
||||||
def run_internal(self):
|
|
||||||
# Constructs the method name, e.g. itemtypes.Movies
|
# Constructs the method name, e.g. itemtypes.Movies
|
||||||
itemFkt = getattr(itemtypes, self.itemType)
|
itemFkt = getattr(itemtypes, self.itemType)
|
||||||
global processMetadataCount
|
global processMetadataCount
|
||||||
|
@ -152,16 +139,6 @@ class ThreadedProcessMetadata(threading.Thread):
|
||||||
# signals to queue job is done
|
# signals to queue job is done
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
|
||||||
def run(self):
|
|
||||||
try:
|
|
||||||
self.run_internal()
|
|
||||||
except Exception as e:
|
|
||||||
xbmcgui.Dialog().ok(self.addonName,
|
|
||||||
"A sync thread has exited! "
|
|
||||||
"You should restart Kodi now. "
|
|
||||||
"Please report this on the forum.")
|
|
||||||
raise
|
|
||||||
|
|
||||||
def stopThread(self):
|
def stopThread(self):
|
||||||
self._shouldstop.set()
|
self._shouldstop.set()
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,9 @@ def jsonrpc(action, arguments = {}):
|
||||||
elif action.lower() == "playmedia":
|
elif action.lower() == "playmedia":
|
||||||
fullurl=arguments[0]
|
fullurl=arguments[0]
|
||||||
resume=arguments[1]
|
resume=arguments[1]
|
||||||
xbmc.Player().play("plugin://plugin.video.plexbmc/?mode=5&force="+resume+"&url="+fullurl)
|
xbmc.Player().play("plugin://plugin.video.plexkodiconnect/"
|
||||||
|
"?mode=companion&resume=%s&id=%s"
|
||||||
|
% (resume, fullurl))
|
||||||
return True
|
return True
|
||||||
elif arguments:
|
elif arguments:
|
||||||
request=json.dumps({ "id" : 1,
|
request=json.dumps({ "id" : 1,
|
||||||
|
@ -127,7 +129,7 @@ def getPlexHeaders():
|
||||||
"X-Plex-Version": settings['version'],
|
"X-Plex-Version": settings['version'],
|
||||||
"X-Plex-Client-Identifier": settings['uuid'],
|
"X-Plex-Client-Identifier": settings['uuid'],
|
||||||
"X-Plex-Provides": "player",
|
"X-Plex-Provides": "player",
|
||||||
"X-Plex-Product": "PleXBMC",
|
"X-Plex-Product": "PlexKodiConnect",
|
||||||
"X-Plex-Device-Name": settings['client_name'],
|
"X-Plex-Device-Name": settings['client_name'],
|
||||||
"X-Plex-Platform": "XBMC",
|
"X-Plex-Platform": "XBMC",
|
||||||
"X-Plex-Model": getPlatform(),
|
"X-Plex-Model": getPlatform(),
|
|
@ -74,7 +74,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
resp += ' protocolVersion="1"'
|
resp += ' protocolVersion="1"'
|
||||||
resp += ' protocolCapabilities="navigation,playback,timeline"'
|
resp += ' protocolCapabilities="navigation,playback,timeline"'
|
||||||
resp += ' machineIdentifier="%s"' % settings['uuid']
|
resp += ' machineIdentifier="%s"' % settings['uuid']
|
||||||
resp += ' product="PleXBMC"'
|
resp += ' product="PlexKodiConnect"'
|
||||||
resp += ' platform="%s"' % getPlatform()
|
resp += ' platform="%s"' % getPlatform()
|
||||||
resp += ' platformVersion="%s"' % settings['plexbmc_version']
|
resp += ' platformVersion="%s"' % settings['plexbmc_version']
|
||||||
resp += ' deviceClass="pc"'
|
resp += ' deviceClass="pc"'
|
|
@ -31,6 +31,7 @@ import re
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import urllib2
|
import urllib2
|
||||||
|
import downloadutils
|
||||||
|
|
||||||
class plexgdm:
|
class plexgdm:
|
||||||
|
|
||||||
|
@ -140,9 +141,11 @@ class plexgdm:
|
||||||
media_port=self.server_list[0]['port']
|
media_port=self.server_list[0]['port']
|
||||||
|
|
||||||
self.__printDebug("Checking server [%s] on port [%s]" % (media_server, media_port) ,2)
|
self.__printDebug("Checking server [%s] on port [%s]" % (media_server, media_port) ,2)
|
||||||
f = urllib2.urlopen('http://%s:%s/clients' % (media_server, media_port))
|
client_result = downloadutils.DownloadUtils().downloadUrl(
|
||||||
client_result = f.read()
|
'http://%s:%s/clients' % (media_server, media_port))
|
||||||
if self.client_id in client_result:
|
# f = urllib2.urlopen('http://%s:%s/clients' % (media_server, media_port))
|
||||||
|
# client_result = f.read()
|
||||||
|
if self.client_id in str(client_result):
|
||||||
self.__printDebug("Client registration successful",1)
|
self.__printDebug("Client registration successful",1)
|
||||||
self.__printDebug("Client data is: %s" % client_result, 3)
|
self.__printDebug("Client data is: %s" % client_result, 3)
|
||||||
return True
|
return True
|
|
@ -7,7 +7,7 @@ settings = {}
|
||||||
try:
|
try:
|
||||||
guidoc = parse(xbmc.translatePath('special://userdata/guisettings.xml'))
|
guidoc = parse(xbmc.translatePath('special://userdata/guisettings.xml'))
|
||||||
except:
|
except:
|
||||||
print "Unable to read XBMC's guisettings.xml"
|
print "Unable to read XBMC's guisettings.xml"
|
||||||
|
|
||||||
def getGUI(name):
|
def getGUI(name):
|
||||||
global guidoc
|
global guidoc
|
||||||
|
@ -19,24 +19,28 @@ def getGUI(name):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
addon = xbmcaddon.Addon()
|
addon = xbmcaddon.Addon()
|
||||||
plexbmc = xbmcaddon.Addon('plugin.video.plexbmc')
|
plexbmc = xbmcaddon.Addon('plugin.video.plexkodiconnect')
|
||||||
|
|
||||||
settings['debug'] = addon.getSetting('debug') == "true"
|
if plexbmc.getSetting('logLevel') == '2' or \
|
||||||
settings['gdm_debug'] = addon.getSetting('gdm_debug') == "true"
|
plexbmc.getSetting('logLevel') == '1':
|
||||||
if addon.getSetting('use_xbmc_name') == "true":
|
settings['debug'] = 'true'
|
||||||
settings['client_name'] = getGUI('devicename')
|
settings['gdm_debug'] = 'true'
|
||||||
else:
|
else:
|
||||||
settings['client_name'] = addon.getSetting('c_name')
|
settings['debug'] = 'false'
|
||||||
|
settings['gdm_debug'] = 'false'
|
||||||
|
|
||||||
|
settings['client_name'] = plexbmc.getSetting('deviceName')
|
||||||
|
|
||||||
# XBMC web server settings
|
# XBMC web server settings
|
||||||
settings['webserver_enabled'] = (getGUI('webserver') == "true")
|
settings['webserver_enabled'] = (getGUI('webserver') == "true")
|
||||||
settings['port'] = int(getGUI('webserverport'))
|
settings['port'] = int(getGUI('webserverport'))
|
||||||
settings['user'] = getGUI('webserverusername')
|
settings['user'] = getGUI('webserverusername')
|
||||||
settings['passwd'] = getGUI('webserverpassword')
|
settings['passwd'] = getGUI('webserverpassword')
|
||||||
|
|
||||||
settings['uuid'] = str(addon.getSetting('uuid')) or str(uuid.uuid4())
|
settings['uuid'] = plexbmc.getSetting('plex_client_Id')
|
||||||
addon.setSetting('uuid', settings['uuid'])
|
|
||||||
settings['version'] = addon.getAddonInfo('version')
|
settings['version'] = plexbmc.getAddonInfo('version')
|
||||||
settings['plexbmc_version'] = plexbmc.getAddonInfo('version')
|
settings['plexbmc_version'] = plexbmc.getAddonInfo('version')
|
||||||
settings['myplex_user'] = plexbmc.getSetting('myplex_user')
|
settings['myplex_user'] = plexbmc.getSetting('username')
|
||||||
settings['serverList'] = []
|
settings['serverList'] = []
|
||||||
settings['myport'] = 3005
|
settings['myport'] = addon.getSetting('companionPort')
|
|
@ -5,6 +5,7 @@ from xml.dom.minidom import parseString
|
||||||
from functions import *
|
from functions import *
|
||||||
from settings import settings
|
from settings import settings
|
||||||
from httppersist import requests
|
from httppersist import requests
|
||||||
|
import downloadutils
|
||||||
|
|
||||||
class SubscriptionManager:
|
class SubscriptionManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -19,6 +20,7 @@ class SubscriptionManager:
|
||||||
self.port = ""
|
self.port = ""
|
||||||
self.playerprops = {}
|
self.playerprops = {}
|
||||||
self.sentstopped = True
|
self.sentstopped = True
|
||||||
|
self.download = downloadutils.DownloadUtils()
|
||||||
|
|
||||||
def getVolume(self):
|
def getVolume(self):
|
||||||
self.volume = getVolume()
|
self.volume = getVolume()
|
||||||
|
@ -113,7 +115,11 @@ class SubscriptionManager:
|
||||||
params['time'] = info['time']
|
params['time'] = info['time']
|
||||||
params['duration'] = info['duration']
|
params['duration'] = info['duration']
|
||||||
serv = getServerByHost(self.server)
|
serv = getServerByHost(self.server)
|
||||||
requests.getwithparams(serv.get('server', 'localhost'), serv.get('port', 32400), "/:/timeline", params, getPlexHeaders(), serv.get('protocol', 'http'))
|
url = serv.get('protocol', 'http') + '://' \
|
||||||
|
+ serv.get('server', 'localhost') + ':' \
|
||||||
|
+ serv.get('port', 32400) + "/:/timeline"
|
||||||
|
self.download.downloadUrl(url, type="GET", parameters=params)
|
||||||
|
# requests.getwithparams(serv.get('server', 'localhost'), serv.get('port', 32400), "/:/timeline", params, getPlexHeaders(), serv.get('protocol', 'http'))
|
||||||
printDebug("sent server notification with state = %s" % params['state'])
|
printDebug("sent server notification with state = %s" % params['state'])
|
||||||
WINDOW = xbmcgui.Window(10000)
|
WINDOW = xbmcgui.Window(10000)
|
||||||
WINDOW.setProperty('plexbmc.nowplaying.sent', '1')
|
WINDOW.setProperty('plexbmc.nowplaying.sent', '1')
|
||||||
|
@ -175,6 +181,7 @@ class Subscriber:
|
||||||
self.commandID = int(commandID) or 0
|
self.commandID = int(commandID) or 0
|
||||||
self.navlocationsent = False
|
self.navlocationsent = False
|
||||||
self.age = 0
|
self.age = 0
|
||||||
|
self.download = downloadutils.DownloadUtils()
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.uuid == other.uuid
|
return self.uuid == other.uuid
|
||||||
def tostr(self):
|
def tostr(self):
|
||||||
|
@ -191,7 +198,14 @@ class Subscriber:
|
||||||
self.navlocationsent = True
|
self.navlocationsent = True
|
||||||
msg = re.sub(r"INSERTCOMMANDID", str(self.commandID), msg)
|
msg = re.sub(r"INSERTCOMMANDID", str(self.commandID), msg)
|
||||||
printDebug("sending xml to subscriber %s: %s" % (self.tostr(), msg))
|
printDebug("sending xml to subscriber %s: %s" % (self.tostr(), msg))
|
||||||
if not requests.post(self.host, self.port, "/:/timeline", msg, getPlexHeaders(), self.protocol):
|
url = self.protocol + '://' + self.host + ':' + self.port \
|
||||||
|
+ "/:/timeline"
|
||||||
|
response = self.download.downloadUrl(url,
|
||||||
|
postBody=msg,
|
||||||
|
type="POSTXML")
|
||||||
|
# if not requests.post(self.host, self.port, "/:/timeline", msg, getPlexHeaders(), self.protocol):
|
||||||
|
# subMgr.removeSubscriber(self.uuid)
|
||||||
|
if response in [False, 401]:
|
||||||
subMgr.removeSubscriber(self.uuid)
|
subMgr.removeSubscriber(self.uuid)
|
||||||
|
|
||||||
subMgr = SubscriptionManager()
|
subMgr = SubscriptionManager()
|
|
@ -15,9 +15,39 @@ import xbmcaddon
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
import xbmcvfs
|
import xbmcvfs
|
||||||
|
|
||||||
|
import clientinfo
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
class logDecor(object):
|
||||||
|
"""
|
||||||
|
A decorator adding logging capabilities.
|
||||||
|
|
||||||
|
Syntax: self.logMsg(message, loglevel)
|
||||||
|
|
||||||
|
Loglevel: -2 (Error) to 2 (DB debug)
|
||||||
|
"""
|
||||||
|
def __init__(self, f):
|
||||||
|
"""
|
||||||
|
If there are no decorator arguments, the function to be decorated is
|
||||||
|
passed to the constructor.
|
||||||
|
"""
|
||||||
|
self.f = f
|
||||||
|
self.addonName = clientinfo.ClientInfo().getAddonName()
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
The __call__ method is not called until the
|
||||||
|
decorated function is called.
|
||||||
|
"""
|
||||||
|
def decorLog(self, msg, lvl=1):
|
||||||
|
className = self.__class__.__name__
|
||||||
|
logMsg("%s %s" % (self.addonName, className), msg, lvl)
|
||||||
|
# The function itself:
|
||||||
|
self.f(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def logMsg(title, msg, level=1):
|
def logMsg(title, msg, level=1):
|
||||||
|
|
||||||
# Get the logLevel set in UserClient
|
# Get the logLevel set in UserClient
|
||||||
|
|
|
@ -75,4 +75,8 @@
|
||||||
<setting label="30239" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=reset)" option="close" />
|
<setting label="30239" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=reset)" option="close" />
|
||||||
<setting id="syncThreadNumber" type="number" label="Number of parallel threads while syncing" default="10" option="int"/>
|
<setting id="syncThreadNumber" type="number" label="Number of parallel threads while syncing" default="10" option="int"/>
|
||||||
</category>
|
</category>
|
||||||
|
<category label="Plex Companion">
|
||||||
|
<setting id="plexCompanion" label="Enable Plex Companion" type="bool" default="true" />
|
||||||
|
<setting id="companionPort" label="Plex Companion Port" type="number" default="3005" option="int" visible="eq(-1,true)"/>
|
||||||
|
</category>
|
||||||
</settings>
|
</settings>
|
||||||
|
|
50
service.py
50
service.py
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
# import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcaddon
|
import xbmcaddon
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
import xbmcvfs
|
# import xbmcvfs
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
@ -29,9 +29,10 @@ import librarysync
|
||||||
import player
|
import player
|
||||||
import utils
|
import utils
|
||||||
import videonodes
|
import videonodes
|
||||||
import websocket_client as wsc
|
# import websocket_client as wsc
|
||||||
|
|
||||||
import PlexAPI
|
import PlexAPI
|
||||||
|
import PlexCompanion
|
||||||
|
|
||||||
#################################################################################################
|
#################################################################################################
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ class Service():
|
||||||
websocket_running = False
|
websocket_running = False
|
||||||
library_running = False
|
library_running = False
|
||||||
kodimonitor_running = False
|
kodimonitor_running = False
|
||||||
|
plexCompanion_running = False
|
||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -106,6 +108,9 @@ class Service():
|
||||||
# ws = wsc.WebSocket_Client()
|
# ws = wsc.WebSocket_Client()
|
||||||
library = librarysync.LibrarySync()
|
library = librarysync.LibrarySync()
|
||||||
kplayer = player.Player()
|
kplayer = player.Player()
|
||||||
|
plx = PlexAPI.PlexAPI()
|
||||||
|
plexCompanion = PlexCompanion.PlexCompanion()
|
||||||
|
plexCompanionDesired = utils.settings('plexCompanion')
|
||||||
# Sync and progress report
|
# Sync and progress report
|
||||||
lastProgressUpdate = datetime.today()
|
lastProgressUpdate = datetime.today()
|
||||||
|
|
||||||
|
@ -223,10 +228,7 @@ class Service():
|
||||||
# No server info set in add-on settings
|
# No server info set in add-on settings
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif PlexAPI.PlexAPI().CheckConnection(
|
elif plx.CheckConnection(server, plexToken) != 200:
|
||||||
server,
|
|
||||||
plexToken
|
|
||||||
) != 200:
|
|
||||||
# Server is offline.
|
# Server is offline.
|
||||||
# Alert the user and suppress future warning
|
# Alert the user and suppress future warning
|
||||||
if self.server_online:
|
if self.server_online:
|
||||||
|
@ -234,10 +236,12 @@ class Service():
|
||||||
utils.window('emby_online', value="false")
|
utils.window('emby_online', value="false")
|
||||||
|
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading="Error connecting",
|
heading="Error connecting",
|
||||||
message="%s Server is unreachable." % self.addonName,
|
message="%s Server is unreachable."
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
% self.addonName,
|
||||||
sound=False)
|
icon="special://home/addons/plugin.video."
|
||||||
|
"plexkodiconnect/icon.png",
|
||||||
|
sound=False)
|
||||||
|
|
||||||
self.server_online = False
|
self.server_online = False
|
||||||
|
|
||||||
|
@ -251,11 +255,12 @@ class Service():
|
||||||
break
|
break
|
||||||
# Alert the user that server is online.
|
# Alert the user that server is online.
|
||||||
xbmcgui.Dialog().notification(
|
xbmcgui.Dialog().notification(
|
||||||
heading="Emby server",
|
heading="Emby server",
|
||||||
message="Server is online.",
|
message="Server is online.",
|
||||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
icon="special://home/addons/plugin.video."
|
||||||
time=2000,
|
"plexkodiconnect/icon.png",
|
||||||
sound=False)
|
time=2000,
|
||||||
|
sound=False)
|
||||||
|
|
||||||
self.server_online = True
|
self.server_online = True
|
||||||
self.logMsg("Server is online and ready.", 1)
|
self.logMsg("Server is online and ready.", 1)
|
||||||
|
@ -266,6 +271,12 @@ class Service():
|
||||||
self.userclient_running = True
|
self.userclient_running = True
|
||||||
user.start()
|
user.start()
|
||||||
|
|
||||||
|
# Start the Plex Companion thread
|
||||||
|
if not self.plexCompanion_running and \
|
||||||
|
plexCompanionDesired == "true":
|
||||||
|
self.plexCompanion_running = True
|
||||||
|
plexCompanion.start()
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if monitor.waitForAbort(1):
|
if monitor.waitForAbort(1):
|
||||||
|
@ -278,11 +289,14 @@ class Service():
|
||||||
|
|
||||||
##### Emby thread is terminating. #####
|
##### Emby thread is terminating. #####
|
||||||
|
|
||||||
|
if self.plexCompanion_running:
|
||||||
|
plexCompanion.stopClient()
|
||||||
|
|
||||||
if self.library_running:
|
if self.library_running:
|
||||||
library.stopThread()
|
library.stopThread()
|
||||||
|
|
||||||
if self.websocket_running:
|
# if self.websocket_running:
|
||||||
ws.stopClient()
|
# ws.stopClient()
|
||||||
|
|
||||||
if self.userclient_running:
|
if self.userclient_running:
|
||||||
user.stopClient()
|
user.stopClient()
|
||||||
|
|
Loading…
Reference in a new issue