Merge branch 'master' into develop
This commit is contained in:
commit
98d11ceb2d
25 changed files with 483 additions and 152 deletions
16
README.md
16
README.md
|
@ -55,18 +55,28 @@ Currently these features are working:
|
|||
- Play directly from network paths (e.g. "\\\\server\\Plex\\movie.mkv" on Windows or SMB paths "smb://server/Plex/movie.mkv") instead of slow HTTP (e.g. "192.168.1.1:32400"). You have to setup all your Plex libraries to point to such network paths.
|
||||
|
||||
|
||||
**Known Issues:**
|
||||
**Known "Larger" Issues:**
|
||||
Solutions are unlikely due to the nature of these issues
|
||||
- **Plex Music:** You must have a static IP address for your Plex media server if you plan to use Plex Music features. This is due to the way Kodi works and cannot be helped.
|
||||
- **Plex Music:** Kodi tries to scan every(!) single Plex song on startup. This leads to errors in the Kodi log file and potentially even crashes. (Plex puts each song in a "dedicated folder", e.g. 'http://192.168.1.1:32400/library/parts/749450/'. Kodi unsuccessfully tries to scan these folders)
|
||||
- **Plex updates:** PlexKodiConnect continuously polls the Plex Media Server for changes. If something on the PMS has changed, this change is synced to Kodi. Hence if you rescan your entire library, a long PlexKodiConnect re-sync is triggered.
|
||||
- **Direct Paths:** If you use direct paths, your sync will be slower
|
||||
- **Subtitles**: external Plex subtitles (separate file, e.g. mymovie.srt) can be used, but it is impossible to label them correctly/tell what language they are in
|
||||
- **Direct Paths:** If you use direct paths, your (initial) sync will be slower
|
||||
|
||||
**Known Bugs:**
|
||||
- **Plex Music:** Plex Music for direct paths does not work yet.
|
||||
- **Video Nodes**: some nodes, e.g. "On Deck", are customized/hacked. Hence no access to movie metadata is possible, because Kodi does not know it's a library item
|
||||
|
||||
**What could be in the pipeline?**
|
||||
|
||||
**What could be in the pipeline for future development?**
|
||||
- Watch Later
|
||||
- Playlists
|
||||
- Homevideos
|
||||
- Pictures
|
||||
- Music Videos
|
||||
- Automatic updates
|
||||
- Redesigned background sync process that puts less strain on the PMS
|
||||
- Simultaneously connecting to several PMS
|
||||
- TV Shows Theme Music (ultra-low prio)
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<addon id="plugin.video.plexkodiconnect"
|
||||
name="PlexKodiConnect"
|
||||
version="1.0.14"
|
||||
version="1.0.16"
|
||||
provider-name="croneter">
|
||||
<requires>
|
||||
<import addon="xbmc.python" version="2.1.0"/>
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
version 1.0.16
|
||||
- Kodi profiles up and running; try assigning different Plex users per profile!
|
||||
- Change "Switch User" to "Log Out Plex User: <username>"
|
||||
- TV shows On Deck: append season and episode number in the settings
|
||||
- Shut down PKC correctly (useful for Kodi profiles)
|
||||
- Don't de-authorize if several PMS are present
|
||||
- Relabel to "Full PKC reset" in settings
|
||||
|
||||
version 1.0.15
|
||||
- Enable external Plex subtitles if available
|
||||
- TV On Deck: option to include show name
|
||||
- Playback updates now if an item is resumed
|
||||
- Fix PMS not being informed of playback stop
|
||||
- Fix playback updates for remote PMS
|
||||
- Deactivate info "Gathering information from files"
|
||||
- Updated readme
|
||||
|
||||
version 1.0.14
|
||||
- Fix TV shows rating not showing up
|
||||
- Fix music libraries being scanned twice
|
||||
|
|
|
@ -357,11 +357,10 @@
|
|||
<string id="39014">Please sign in to plex.tv.</string>
|
||||
<string id="39015">Problems connecting to server. Pick another server?</string>
|
||||
<string id="39016">Disable Plex music library?</string>
|
||||
<string id="39017">Would you now like to go to the plugin's settings?
|
||||
(This is hopefully unneccessary ;-))</string>
|
||||
<string id="39017">Would you now like to go to the plugin's settings to fine-tune PKC? You will need to RESTART Kodi!</string>
|
||||
|
||||
<string id="39018">[COLOR yellow]Repair local database (force update all content)[/COLOR]</string>
|
||||
<string id="39019">[COLOR yellow]Perform local database reset (full resync)[/COLOR]</string>
|
||||
<string id="39019">[COLOR red]Partial or full reset of Database and PKC[/COLOR]</string>
|
||||
<string id="39020">[COLOR yellow]Cache all images to Kodi texture cache[/COLOR]</string>
|
||||
<string id="39021">[COLOR yellow]Sync Emby Theme Media to Kodi[/COLOR]</string>
|
||||
<string id="39022"> (local)</string>
|
||||
|
@ -388,8 +387,15 @@
|
|||
<string id="39043">Go a step further and complete replace all original Plex library paths (/volume1/media) with custom SMB paths (smb://NAS/MyStuff)?</string>
|
||||
<string id="39044">Please enter your custom smb paths in the settings under "Sync Options" and then restart Kodi</string>
|
||||
|
||||
<string id="39045">Appearance Tweaks</string>
|
||||
<string id="39046">TV Shows</string>
|
||||
<string id="39047">On Deck: Append show title to episode</string>
|
||||
<string id="39048">On Deck: Append season- and episode-number (e.g. S3E2)</string>
|
||||
<string id="39049">Nothing works? Try a full reset!</string>
|
||||
|
||||
|
||||
<!-- Plex Entrypoint.py -->
|
||||
<string id="39200">Switch Plex Home User</string>
|
||||
<string id="39200">Log-out Plex Home User: </string>
|
||||
<string id="39201">Settings</string>
|
||||
<string id="39202">Network credentials</string>
|
||||
<string id="39203">Refresh Plex playlists/nodes</string>
|
||||
|
|
|
@ -294,10 +294,10 @@
|
|||
<string id="39014">Bitte loggen Sie sich in plex.tv ein.</string>
|
||||
<string id="39015">Beim Verbinden mit dem Server sind Probleme aufgetreten. Mit einem anderen Server versuchen?</string>
|
||||
<string id="39016">Plex Musik Bibliotheken deaktivieren?</string>
|
||||
<string id="39017">Möchten Sie nun die Einstellungen des Plugins öffnen? (Was hoffentlich unnötig ist ;-))"</string>
|
||||
<string id="39017">Möchten Sie nun die Einstellungen des Plugins öffnen? Kodi muss anschliessend neu gestartet werden!</string>
|
||||
|
||||
<string id="39018">[COLOR yellow]Lokale Datenbank reparieren (allen Inhalt aktualisieren)[/COLOR]</string>
|
||||
<string id="39019">[COLOR yellow]Lokale Datenbank zurücksetzen (kompletter Resync nötig)[/COLOR]</string>
|
||||
<string id="39019">[COLOR red]Datenbank und auf Wunsch PKC zurücksetzen[/COLOR]</string>
|
||||
<string id="39020">[COLOR yellow]Alle Plex Bilder in Kodi zwischenspeichern[/COLOR]</string>
|
||||
<string id="39021">[COLOR yellow]Plex Themes zu Kodi synchronisieren[/COLOR]</string>
|
||||
<string id="39022"> (lokal)</string>
|
||||
|
@ -324,8 +324,14 @@
|
|||
<string id="39043">Sollen sogar sämtliche Plex Pfade wie /volume1/Hans/medien durch benutzerdefinierte smb Pfade wie smb://NAS/Filme ersetzt werden?</string>
|
||||
<string id="39044">Bitte geben Sie Ihre benutzerdefinierten SMB Pfade nun in den Einstellungen unter Sync Optionen ein. Starten Sie dann Kodi neu.</string>
|
||||
|
||||
<string id="39045">Erscheinung</string>
|
||||
<string id="39046">TV Serien</string>
|
||||
<string id="39047">"Aktuell": Serien- an Episoden-Titel anfügen</string>
|
||||
<string id="39048">"Aktuell": Staffel und Episode anfügen (z.B. S3E2)</string>
|
||||
<string id="39049">Nichts funktioniert? Setze mal alles zurück!</string>
|
||||
|
||||
<!-- Plex Entrypoint.py -->
|
||||
<string id="39200">Plex Home Benutzer wechseln</string>
|
||||
<string id="39200">Plex Home Benutzer abmelden: </string>
|
||||
<string id="39201">Einstellungen</string>
|
||||
<string id="39202">Netzwerk Credentials</string>
|
||||
<string id="39203">Plex Playlisten und Nodes zurücksetzen</string>
|
||||
|
|
|
@ -51,6 +51,7 @@ from threading import Thread
|
|||
import Queue
|
||||
import traceback
|
||||
import requests
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
import re
|
||||
import json
|
||||
|
@ -58,10 +59,10 @@ from urllib import urlencode, quote_plus, unquote
|
|||
|
||||
from PlexFunctions import PlexToKodiTimefactor, PMSHttpsEnabled
|
||||
|
||||
try:
|
||||
import xml.etree.cElementTree as etree
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
# Disable requests logging
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
|
||||
@utils.logging
|
||||
|
@ -194,12 +195,12 @@ class PlexAPI():
|
|||
# Wait for approx 30 seconds (since the PIN is not visible anymore :-))
|
||||
while count < 30:
|
||||
xml = self.CheckPlexTvSignin(identifier)
|
||||
if xml:
|
||||
if xml is not False:
|
||||
break
|
||||
# Wait for 1 seconds
|
||||
xbmc.sleep(1000)
|
||||
count += 1
|
||||
if not xml:
|
||||
if xml is False:
|
||||
# Could not sign in to plex.tv Try again later
|
||||
dialog.ok(self.addonName, string(39305))
|
||||
return False
|
||||
|
@ -263,7 +264,7 @@ class PlexAPI():
|
|||
identifier = None
|
||||
# Download
|
||||
xml = self.TalkToPlexServer(url, talkType="POST")
|
||||
if not xml:
|
||||
if xml is False:
|
||||
return code, identifier
|
||||
try:
|
||||
code = xml.find('code').text
|
||||
|
@ -648,7 +649,11 @@ class PlexAPI():
|
|||
# Ping to check whether we need HTTPs or HTTP
|
||||
url = (self.getPMSProperty(ATV_udid, uuid_id, 'ip') + ':'
|
||||
+ self.getPMSProperty(ATV_udid, uuid_id, 'port'))
|
||||
if PMSHttpsEnabled(url):
|
||||
https = PMSHttpsEnabled(url)
|
||||
if https is None:
|
||||
# Error contacting url
|
||||
continue
|
||||
elif https:
|
||||
self.updatePMSProperty(ATV_udid, uuid_id, 'scheme', 'https')
|
||||
else:
|
||||
self.updatePMSProperty(ATV_udid, uuid_id, 'scheme', 'http')
|
||||
|
@ -2316,6 +2321,7 @@ class API():
|
|||
utils.window('emby_shouldStop', value="true")
|
||||
playurl = False
|
||||
utils.window('emby_pathverified', value='true')
|
||||
utils.settings('emby_pathverified', value='true')
|
||||
return playurl
|
||||
|
||||
def askToValidate(self, url):
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import threading
|
||||
import traceback
|
||||
import socket
|
||||
import requests
|
||||
|
||||
import xbmc
|
||||
|
||||
|
@ -64,22 +63,19 @@ class PlexCompanion(threading.Thread):
|
|||
message_count = 0
|
||||
is_running = False
|
||||
while not self.threadStopped():
|
||||
while self.threadSuspended():
|
||||
if self.threadStopped():
|
||||
break
|
||||
xbmc.sleep(3000)
|
||||
# If we are not authorized, sleep
|
||||
# Otherwise, we trigger a download which leads to a
|
||||
# re-authorizations
|
||||
if window('emby_serverStatus'):
|
||||
xbmc.sleep(3000)
|
||||
continue
|
||||
while self.threadSuspended() or window('emby_serverStatus'):
|
||||
if self.threadStopped():
|
||||
break
|
||||
xbmc.sleep(1000)
|
||||
try:
|
||||
|
||||
httpd.handle_request()
|
||||
message_count += 1
|
||||
|
||||
if message_count > 30:
|
||||
if message_count > 100:
|
||||
if self.client.check_client_registration():
|
||||
self.logMsg("Client is still registered", 1)
|
||||
else:
|
||||
|
@ -97,13 +93,14 @@ class PlexCompanion(threading.Thread):
|
|||
xbmc.sleep(50)
|
||||
except:
|
||||
self.logMsg("Error in loop, continuing anyway", 1)
|
||||
self.logMsg(traceback.print_exc(), 1)
|
||||
self.logMsg(traceback.format_exc(), 1)
|
||||
xbmc.sleep(50)
|
||||
|
||||
self.client.stop_all()
|
||||
try:
|
||||
httpd.socket.shutdown(socket.SHUT_RDWR)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
httpd.socket.close()
|
||||
requests.dumpConnections()
|
||||
self.logMsg("----===## STOP Plex Companion ##===----", 0)
|
||||
|
|
|
@ -4,12 +4,17 @@ from ast import literal_eval
|
|||
from urlparse import urlparse, parse_qs
|
||||
import re
|
||||
from copy import deepcopy
|
||||
import requests
|
||||
|
||||
from xbmcaddon import Addon
|
||||
|
||||
import downloadutils
|
||||
from utils import logMsg, settings
|
||||
|
||||
# Disable requests logging
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
|
||||
addonName = Addon().getAddonInfo('name')
|
||||
title = "%s %s" % (addonName, __name__)
|
||||
|
@ -394,7 +399,8 @@ def getPlexRepeat(kodiRepeat):
|
|||
|
||||
def PMSHttpsEnabled(url):
|
||||
"""
|
||||
Returns True if the PMS wants to talk https, False otherwise
|
||||
Returns True if the PMS wants to talk https, False otherwise. None if error
|
||||
occured, e.g. the connection timed out
|
||||
|
||||
With with e.g. url=192.168.0.1:32400 (NO http/https)
|
||||
|
||||
|
@ -403,17 +409,37 @@ def PMSHttpsEnabled(url):
|
|||
|
||||
Prefers HTTPS over HTTP
|
||||
"""
|
||||
xml = downloadutils.DownloadUtils().downloadUrl(
|
||||
'https://%s/identity' % url)
|
||||
# True if https, False if http
|
||||
answer = True
|
||||
try:
|
||||
# received a valid XML - https connection is possible
|
||||
xml.attrib
|
||||
logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTPS' % url, 1)
|
||||
return True
|
||||
except:
|
||||
# couldn't get an xml - switch to http traffic
|
||||
logMsg('PMSHttpsEnabled', 'PMS on %s talks HTTPS' % url, 1)
|
||||
return False
|
||||
# Don't use downloadutils here, otherwise we may get un-authorized!
|
||||
res = requests.get('https://%s/identity' % url,
|
||||
headers={},
|
||||
verify=False,
|
||||
timeout=(3, 10))
|
||||
# Don't verify SSL since we can connect for sure then!
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
# Might have SSL deactivated. Try with http
|
||||
try:
|
||||
res = requests.get('http://%s/identity' % url,
|
||||
headers={},
|
||||
timeout=(3, 10))
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
logMsg("Server is offline or cannot be reached. Url: %s, "
|
||||
"Error message: %s" % (url, e), -1)
|
||||
return None
|
||||
except requests.exceptions.ReadTimeout:
|
||||
logMsg("Server timeout reached for Url %s" % url, -1)
|
||||
return None
|
||||
else:
|
||||
answer = False
|
||||
except requests.exceptions.ReadTimeout:
|
||||
logMsg("Server timeout reached for Url %s" % url, -1)
|
||||
return None
|
||||
if res.status_code == requests.codes.ok:
|
||||
return answer
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def scrobble(ratingKey, state):
|
||||
|
|
|
@ -15,6 +15,10 @@ import xbmcvfs
|
|||
import utils
|
||||
import image_cache_thread
|
||||
|
||||
# Disable requests logging
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
# import json
|
||||
import requests
|
||||
import xml.etree.ElementTree as etree
|
||||
# import logging
|
||||
|
||||
# import xbmc
|
||||
|
@ -13,10 +14,6 @@ import utils
|
|||
import clientinfo
|
||||
|
||||
import PlexAPI
|
||||
try:
|
||||
import xml.etree.cElementTree as etree
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -392,7 +389,8 @@ class DownloadUtils():
|
|||
|
||||
elif status not in ("401", "Auth"):
|
||||
# Tell userclient token has been revoked.
|
||||
self.logMsg('Setting emby_serverStatus to 401')
|
||||
self.logMsg('Error 401 contacting %s' % url, 0)
|
||||
self.logMsg('Setting emby_serverStatus to 401', 0)
|
||||
utils.window('emby_serverStatus', value="401")
|
||||
self.logMsg("HTTP Error: %s" % e, 0)
|
||||
xbmcgui.Dialog().notification(
|
||||
|
|
|
@ -81,13 +81,28 @@ def reConnect():
|
|||
utils.logMsg("entrypoint reConnect",
|
||||
"Connection resets requested", 0)
|
||||
dialog = xbmcgui.Dialog()
|
||||
# Resetting, please wait
|
||||
dialog.notification(
|
||||
heading=addonName,
|
||||
message=string(39207),
|
||||
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
|
||||
time=2000,
|
||||
sound=False)
|
||||
# Pause library sync thread - user needs to be auth in order to sync
|
||||
utils.window('suspend_LibraryThread', value='true')
|
||||
# Wait max for 5 seconds for all lib scans to finish
|
||||
counter = 0
|
||||
while utils.window('emby_dbScan') == 'true':
|
||||
if counter > 500:
|
||||
# Failed to reset PMS and plex.tv connects. Try to restart Kodi.
|
||||
dialog.ok(heading=addonName,
|
||||
message=string(39208))
|
||||
# Resuming threads, just in case
|
||||
utils.window('suspend_LibraryThread', clear=True)
|
||||
# Abort reConnection
|
||||
return
|
||||
counter += 1
|
||||
xbmc.sleep(50)
|
||||
|
||||
# Delete plex credentials in settings
|
||||
utils.settings('myplexlogin', value="true")
|
||||
|
@ -97,18 +112,13 @@ def reConnect():
|
|||
utils.settings('plexHomeSize', value="1")
|
||||
utils.settings('plexAvatar', value="")
|
||||
|
||||
# Wait max for 5 seconds for all lib scans to finish
|
||||
counter = 0
|
||||
while utils.window('emby_dbScan') == 'true':
|
||||
if counter > 100:
|
||||
dialog.ok(heading=addonName,
|
||||
message=string(39208))
|
||||
# Resuming threads, just in case
|
||||
utils.window('suspend_LibraryThread', clear=True)
|
||||
# Abort reConnection
|
||||
return
|
||||
counter += 1
|
||||
xbmc.sleep(50)
|
||||
# Reset connection details
|
||||
utils.settings('plex_machineIdentifier', value="")
|
||||
utils.settings('plex_servername', value="")
|
||||
utils.settings('https', value="")
|
||||
utils.settings('ipaddress', value="")
|
||||
utils.settings('port', value="")
|
||||
|
||||
# Log out currently signed in user:
|
||||
utils.window('emby_serverStatus', value="401")
|
||||
|
||||
|
@ -255,7 +265,7 @@ def doMainListing():
|
|||
addDirectoryItem(label, path)
|
||||
|
||||
# Plex user switch
|
||||
addDirectoryItem(string(39200),
|
||||
addDirectoryItem(string(39200) + utils.window('plex_username'),
|
||||
"plugin://plugin.video.plexkodiconnect/"
|
||||
"?mode=switchuser")
|
||||
|
||||
|
@ -1446,6 +1456,19 @@ def getOnDeck(viewid, mediatype, tagname, limit):
|
|||
for episode in episodes:
|
||||
# There will always be only 1 episode ('limit=1')
|
||||
li = createListItem(episode)
|
||||
# Fix some skin shortcomings
|
||||
title = episode.get('title', '')
|
||||
if utils.settings('OnDeckTvAppendSeason') == 'true':
|
||||
seasonid = episode.get('season')
|
||||
episodeid = episode.get('episode')
|
||||
if seasonid and episodeid:
|
||||
title = ('S' + str(seasonid) + 'E' + str(episodeid)
|
||||
+ ' - ' + title)
|
||||
if utils.settings('OnDeckTvAppendShow') == 'true':
|
||||
show = episode.get('showtitle')
|
||||
if show:
|
||||
title = show + ' - ' + title
|
||||
li.setLabel(title)
|
||||
xbmcplugin.addDirectoryItem(
|
||||
handle=int(sys.argv[1]),
|
||||
url=episode['file'],
|
||||
|
|
|
@ -3,6 +3,10 @@ import utils
|
|||
import xbmc
|
||||
import requests
|
||||
|
||||
# Disable requests logging
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
|
||||
@utils.logging
|
||||
class image_cache_thread(threading.Thread):
|
||||
|
|
|
@ -261,8 +261,6 @@ class InitialSetup():
|
|||
dialog.ok(heading=self.addonName,
|
||||
line1=string(39044))
|
||||
goToSettings = True
|
||||
# Don't start anything because we need these paths first!
|
||||
utils.window('emby_serverStatus', value="Stop")
|
||||
|
||||
# Go to network credentials?
|
||||
if dialog.yesno(heading=self.addonName,
|
||||
|
@ -280,8 +278,9 @@ class InitialSetup():
|
|||
xbmc.executebuiltin(
|
||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
else:
|
||||
# Open Settings page now?
|
||||
# Open Settings page now? You will need to restart!
|
||||
if dialog.yesno(heading=self.addonName,
|
||||
line1=string(39017)):
|
||||
utils.window('emby_serverStatus', value="Stop")
|
||||
xbmc.executebuiltin(
|
||||
'Addon.OpenSettings(plugin.video.plexkodiconnect)')
|
||||
|
|
|
@ -2055,17 +2055,18 @@ class Music(Items):
|
|||
if doIndirect:
|
||||
# Plex works a bit differently
|
||||
path = "%s%s" % (self.server, item[0][0].attrib.get('key'))
|
||||
filename = API.addPlexCredentialsToUrl(path)
|
||||
# Keep path empty to not let Kodi scan it
|
||||
path = ""
|
||||
path = API.addPlexCredentialsToUrl(path)
|
||||
filename = path.rsplit('/', 1)[1]
|
||||
path = path.replace(filename, '')
|
||||
|
||||
# UPDATE THE SONG #####
|
||||
if update_item:
|
||||
self.logMsg("UPDATE song itemid: %s - Title: %s with path: %s"
|
||||
% (itemid, title, path), 1)
|
||||
# Update path
|
||||
query = "UPDATE path SET strPath = ? WHERE idPath = ?"
|
||||
kodicursor.execute(query, (path, pathid))
|
||||
# Use dummy strHash '123' for Kodi
|
||||
query = "UPDATE path SET strPath = ?, strHash = ? WHERE idPath = ?"
|
||||
kodicursor.execute(query, (path, '123', pathid))
|
||||
|
||||
# Update the song entry
|
||||
query = ' '.join((
|
||||
|
@ -2087,7 +2088,7 @@ class Music(Items):
|
|||
self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1)
|
||||
|
||||
# Add path
|
||||
pathid = kodi_db.addPath(path)
|
||||
pathid = kodi_db.addPath(path, strHash="123")
|
||||
|
||||
try:
|
||||
# Get the album
|
||||
|
|
|
@ -47,7 +47,7 @@ class Kodidb_Functions():
|
|||
self.clientInfo = clientinfo.ClientInfo()
|
||||
self.artwork = artwork.Artwork()
|
||||
|
||||
def addPath(self, path):
|
||||
def addPath(self, path, strHash=None):
|
||||
# SQL won't return existing paths otherwise
|
||||
if path is None:
|
||||
path = ""
|
||||
|
@ -64,15 +64,26 @@ class Kodidb_Functions():
|
|||
except TypeError:
|
||||
cursor.execute("select coalesce(max(idPath),0) from path")
|
||||
pathid = cursor.fetchone()[0] + 1
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO path(
|
||||
idPath, strPath)
|
||||
if strHash is None:
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO path(
|
||||
idPath, strPath)
|
||||
|
||||
VALUES (?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (pathid, path))
|
||||
VALUES (?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (pathid, path))
|
||||
else:
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO path(
|
||||
idPath, strPath, strHash)
|
||||
|
||||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (pathid, path, strHash))
|
||||
|
||||
return pathid
|
||||
|
||||
|
@ -744,6 +755,88 @@ class Kodidb_Functions():
|
|||
ids.append(row[0])
|
||||
return ids
|
||||
|
||||
def getIdFromTitle(self, itemdetails):
|
||||
"""
|
||||
Returns the Kodi id (e.g. idMovie, idEpisode) from the item's
|
||||
title (c00), if there is exactly ONE found for the itemtype.
|
||||
(False otherwise)
|
||||
|
||||
itemdetails is the data['item'] response from Kodi
|
||||
|
||||
itemdetails for movies:
|
||||
{
|
||||
"title":"Kung Fu Panda",
|
||||
"type":"movie",
|
||||
"year":2008
|
||||
}
|
||||
|
||||
itemdetails for episodes:
|
||||
{
|
||||
"episode":5
|
||||
"season":5,
|
||||
"showtitle":"Girls",
|
||||
"title":"Queen for Two Days",
|
||||
"type":"episode"
|
||||
}
|
||||
"""
|
||||
try:
|
||||
type = itemdetails['type']
|
||||
except:
|
||||
return False
|
||||
|
||||
if type == 'movie':
|
||||
query = ' '.join((
|
||||
"SELECT idMovie",
|
||||
"FROM movie",
|
||||
"WHERE c00 = ?"
|
||||
))
|
||||
try:
|
||||
rows = self.cursor.execute(query, (itemdetails['title'],))
|
||||
except:
|
||||
return False
|
||||
elif type == 'episode':
|
||||
query = ' '.join((
|
||||
"SELECT idShow",
|
||||
"FROM tvshow",
|
||||
"WHERE c00 = ?"
|
||||
))
|
||||
try:
|
||||
rows = self.cursor.execute(query, (itemdetails['showtitle'],))
|
||||
except:
|
||||
return False
|
||||
ids = []
|
||||
for row in rows:
|
||||
ids.append(row[0])
|
||||
if len(ids) > 1:
|
||||
# No unique match possible
|
||||
return False
|
||||
showid = ids[0]
|
||||
|
||||
query = ' '.join((
|
||||
"SELECT idEpisode",
|
||||
"FROM episode",
|
||||
"WHERE c12 = ? AND c13 = ? AND idShow = ?"
|
||||
))
|
||||
try:
|
||||
rows = self.cursor.execute(
|
||||
query,
|
||||
(itemdetails['season'],
|
||||
itemdetails['episode'],
|
||||
showid))
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
ids = []
|
||||
for row in rows:
|
||||
ids.append(row[0])
|
||||
if len(ids) > 1:
|
||||
# No unique match possible
|
||||
return False
|
||||
else:
|
||||
return ids[0]
|
||||
|
||||
def getUnplayedItems(self):
|
||||
"""
|
||||
VIDEOS
|
||||
|
|
|
@ -10,6 +10,7 @@ import xbmcgui
|
|||
|
||||
import downloadutils
|
||||
import embydb_functions as embydb
|
||||
import kodidb_functions as kodidb
|
||||
import playbackutils as pbutils
|
||||
import utils
|
||||
from PlexFunctions import scrobble
|
||||
|
@ -154,11 +155,21 @@ class KodiMonitor(xbmc.Monitor):
|
|||
# Try to get a Kodi ID
|
||||
item = data.get('item')
|
||||
try:
|
||||
kodiid = item['id']
|
||||
type = item['type']
|
||||
except (KeyError, TypeError):
|
||||
log("Item is invalid for Plex playstate update.", 0)
|
||||
except:
|
||||
log("Item is invalid for PMS playstate update.", 0)
|
||||
return
|
||||
try:
|
||||
kodiid = item['id']
|
||||
except (KeyError, TypeError):
|
||||
log('Kodi did not give us a Kodi item id, trying to get from item '
|
||||
'title', 0)
|
||||
# Try to get itemid with the element's title
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
kodiid = kodi_db.getIdFromTitle(item)
|
||||
if kodiid is False:
|
||||
log("Item is invalid for PMS playstate update.", 0)
|
||||
return
|
||||
|
||||
# Get Plex' item id
|
||||
with embydb.GetEmbyDB() as emby_db:
|
||||
|
|
|
@ -4,10 +4,7 @@
|
|||
|
||||
from threading import Thread, Lock
|
||||
import Queue
|
||||
try:
|
||||
import xml.etree.cElementTree as etree
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as etree
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
|
@ -239,6 +236,9 @@ class LibrarySync(Thread):
|
|||
'enableBackgroundSync') == "true" else False
|
||||
self.limitindex = int(utils.settings('limitindex'))
|
||||
|
||||
if utils.settings('emby_pathverified') == 'true':
|
||||
utils.window('emby_pathverified', value='true')
|
||||
|
||||
# Time offset between Kodi and PMS in seconds (=Koditime - PMStime)
|
||||
self.timeoffset = 0
|
||||
# Time in seconds to look into the past when looking for PMS changes
|
||||
|
@ -326,7 +326,7 @@ class LibrarySync(Thread):
|
|||
|
||||
# Get the Plex item's metadata
|
||||
xml = PlexFunctions.GetPlexMetadata(plexId)
|
||||
if not xml:
|
||||
if xml is None:
|
||||
self.logMsg("Could not download metadata, aborting time sync", -1)
|
||||
return
|
||||
libraryId = xml[0].attrib['librarySectionID']
|
||||
|
@ -493,7 +493,7 @@ class LibrarySync(Thread):
|
|||
updatedAt=self.getPMSfromKodiTime(lastSync),
|
||||
containerSize=self.limitindex)
|
||||
# Just skip if something went wrong
|
||||
if not items:
|
||||
if items is None:
|
||||
continue
|
||||
# Get one itemtype, because they're the same in the PMS section
|
||||
try:
|
||||
|
@ -528,7 +528,7 @@ class LibrarySync(Thread):
|
|||
view['id'],
|
||||
lastViewedAt=self.getPMSfromKodiTime(lastSync),
|
||||
containerSize=self.limitindex)
|
||||
if not items:
|
||||
if items is None:
|
||||
continue
|
||||
for item in items:
|
||||
itemId = item.attrib.get('ratingKey')
|
||||
|
@ -635,6 +635,12 @@ class LibrarySync(Thread):
|
|||
# Add sources
|
||||
utils.sourcesXML()
|
||||
|
||||
# Deactivate Kodi popup showing that it's (unsuccessfully) trying to
|
||||
# scan music folders
|
||||
if self.enableMusic:
|
||||
utils.musiclibXML()
|
||||
utils.advancedSettingsXML()
|
||||
|
||||
# Set new timestamp NOW because sync might take a while
|
||||
self.saveLastSync()
|
||||
|
||||
|
@ -1075,7 +1081,7 @@ class LibrarySync(Thread):
|
|||
viewName = view['name']
|
||||
all_plexmovies = PlexFunctions.GetPlexSectionResults(
|
||||
viewId, args=None, containerSize=self.limitindex)
|
||||
if not all_plexmovies:
|
||||
if all_plexmovies is None:
|
||||
self.logMsg("Couldnt get section items, aborting for view.", 1)
|
||||
continue
|
||||
# Populate self.updatelist and self.allPlexElementsId
|
||||
|
@ -1209,7 +1215,7 @@ class LibrarySync(Thread):
|
|||
viewName = view['name']
|
||||
allPlexTvShows = PlexFunctions.GetPlexSectionResults(
|
||||
viewId, containerSize=self.limitindex)
|
||||
if not allPlexTvShows:
|
||||
if allPlexTvShows is None:
|
||||
self.logMsg(
|
||||
"Error downloading show view xml for view %s" % viewId, -1)
|
||||
continue
|
||||
|
@ -1236,7 +1242,7 @@ class LibrarySync(Thread):
|
|||
# Grab all seasons to tvshow from PMS
|
||||
seasons = PlexFunctions.GetAllPlexChildren(
|
||||
tvShowId, containerSize=self.limitindex)
|
||||
if not seasons:
|
||||
if seasons is None:
|
||||
self.logMsg(
|
||||
"Error downloading season xml for show %s" % tvShowId, -1)
|
||||
continue
|
||||
|
@ -1261,7 +1267,7 @@ class LibrarySync(Thread):
|
|||
# Grab all episodes to tvshow from PMS
|
||||
episodes = PlexFunctions.GetAllPlexLeaves(
|
||||
view['id'], containerSize=self.limitindex)
|
||||
if not episodes:
|
||||
if episodes is None:
|
||||
self.logMsg(
|
||||
"Error downloading episod xml for view %s"
|
||||
% view.get('name'), -1)
|
||||
|
@ -1359,7 +1365,7 @@ class LibrarySync(Thread):
|
|||
viewName = view['name']
|
||||
itemsXML = PlexFunctions.GetPlexSectionResults(
|
||||
viewId, args=urlArgs, containerSize=self.limitindex)
|
||||
if not itemsXML:
|
||||
if itemsXML is None:
|
||||
self.logMsg("Error downloading xml for view %s"
|
||||
% viewId, -1)
|
||||
continue
|
||||
|
@ -1401,6 +1407,7 @@ class LibrarySync(Thread):
|
|||
except Exception as e:
|
||||
utils.window('emby_dbScan', clear=True)
|
||||
self.logMsg('LibrarySync thread crashed', -1)
|
||||
self.logMsg('Error message: %s' % e, -1)
|
||||
# Library sync thread has crashed
|
||||
xbmcgui.Dialog().ok(
|
||||
heading=self.addonName,
|
||||
|
|
|
@ -275,9 +275,7 @@ class PlaybackUtils():
|
|||
|
||||
# Append external subtitles to stream
|
||||
playmethod = utils.window('%s.playmethod' % embyitem)
|
||||
# Only for direct stream
|
||||
if playmethod in ("DirectStream"):
|
||||
# Direct play automatically appends external
|
||||
if playmethod in ("DirectStream", "DirectPlay"):
|
||||
subtitles = self.API.externalSubs(playurl)
|
||||
listitem.setSubtitles(subtitles)
|
||||
|
||||
|
|
|
@ -537,6 +537,7 @@ class Player(xbmc.Player):
|
|||
url = "{server}/emby/Items/%s?format=json" % itemid
|
||||
log("Deleting request: %s" % itemid, 1)
|
||||
doUtils(url, type="DELETE")
|
||||
self.stopPlayback(data)
|
||||
|
||||
# Clean the WINDOW properties
|
||||
for filename in self.played_info:
|
||||
|
@ -552,7 +553,6 @@ class Player(xbmc.Player):
|
|||
)
|
||||
for item in cleanup:
|
||||
utils.window(item, clear=True)
|
||||
self.stopPlayback(data)
|
||||
|
||||
# Stop transcoding
|
||||
if playMethod == "Transcode":
|
||||
|
@ -564,7 +564,7 @@ class Player(xbmc.Player):
|
|||
self.played_info.clear()
|
||||
|
||||
def stopPlayback(self, data):
|
||||
self.logMsg("stopPlayback called", 2)
|
||||
self.logMsg("stopPlayback called", 1)
|
||||
|
||||
itemId = data['item_id']
|
||||
playTime = data['currentPosition']
|
||||
|
|
|
@ -32,8 +32,11 @@ import threading
|
|||
import time
|
||||
import urllib2
|
||||
|
||||
import xbmc
|
||||
|
||||
import downloadutils
|
||||
from PlexFunctions import PMSHttpsEnabled
|
||||
from utils import window
|
||||
|
||||
|
||||
class plexgdm:
|
||||
|
@ -119,7 +122,7 @@ class plexgdm:
|
|||
|
||||
self.__printDebug("Sending registration data: HTTP/1.0 200 OK\r\n%s" % (self.client_data), 3)
|
||||
self.client_registered = True
|
||||
time.sleep(0.5)
|
||||
xbmc.sleep(500)
|
||||
|
||||
self.__printDebug("Client Update loop stopped",1)
|
||||
|
||||
|
@ -141,9 +144,15 @@ class plexgdm:
|
|||
return False
|
||||
|
||||
try:
|
||||
media_server=self.server_list[0]['server']
|
||||
media_port=self.server_list[0]['port']
|
||||
scheme = self.server_list[0]['protocol']
|
||||
for server in self.server_list:
|
||||
if server['uuid'] == window('plex_machineIdentifier'):
|
||||
media_server = server['server']
|
||||
media_port = server['port']
|
||||
scheme = server['protocol']
|
||||
break
|
||||
else:
|
||||
self.__printDebug("Did not find our server!", 2)
|
||||
return False
|
||||
|
||||
self.__printDebug("Checking server [%s] on port [%s]" % (media_server, media_port) ,2)
|
||||
client_result = self.download(
|
||||
|
@ -240,13 +249,45 @@ class plexgdm:
|
|||
update['class'] = each.split(':')[1].strip()
|
||||
|
||||
# Quickly test if we need https
|
||||
if PMSHttpsEnabled(
|
||||
'%s:%s' % (update['server'], update['port'])):
|
||||
https = PMSHttpsEnabled(
|
||||
'%s:%s' % (update['server'], update['port']))
|
||||
if https is None:
|
||||
# Error contacting server
|
||||
continue
|
||||
elif https:
|
||||
update['protocol'] = 'https'
|
||||
else:
|
||||
update['protocol'] = 'http'
|
||||
discovered_servers.append(update)
|
||||
|
||||
# Append REMOTE PMS that we haven't found yet; if necessary
|
||||
currServer = window('pms_server')
|
||||
if currServer:
|
||||
currServerProt, currServerIP, currServerPort = \
|
||||
currServer.split(':')
|
||||
currServerIP = currServerIP.replace('/', '')
|
||||
for server in discovered_servers:
|
||||
if server['server'] == currServerIP:
|
||||
break
|
||||
else:
|
||||
# Currently active server was not discovered via GDM; ADD
|
||||
update = {
|
||||
'port': currServerPort,
|
||||
'protocol': currServerProt,
|
||||
'class': None,
|
||||
'content-type': 'plex/media-server',
|
||||
'discovery': 'auto',
|
||||
'master': 1,
|
||||
'owned': '1',
|
||||
'role': 'master',
|
||||
'server': currServerIP,
|
||||
'serverName': window('plex_servername'),
|
||||
'updated': int(time.time()),
|
||||
'uuid': window('plex_machineIdentifier'),
|
||||
'version': 'irrelevant'
|
||||
}
|
||||
discovered_servers.append(update)
|
||||
|
||||
self.server_list = discovered_servers
|
||||
|
||||
if not self.server_list:
|
||||
|
@ -292,7 +333,7 @@ class plexgdm:
|
|||
if discovery_count > self.discovery_interval:
|
||||
self.discover()
|
||||
discovery_count=0
|
||||
time.sleep(1)
|
||||
xbmc.sleep(1000)
|
||||
|
||||
def start_discovery(self, daemon = False):
|
||||
if not self._discovery_is_running:
|
||||
|
@ -326,8 +367,8 @@ if __name__ == '__main__':
|
|||
client.start_all()
|
||||
while not client.discovery_complete:
|
||||
print "Waiting for results"
|
||||
time.sleep(1)
|
||||
time.sleep(20)
|
||||
xbmc.sleep(1000)
|
||||
xbmc.sleep(20000)
|
||||
print client.getServerList()
|
||||
if client.check_client_registration():
|
||||
print "Successfully registered"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import re
|
||||
import threading
|
||||
from xml.dom.minidom import parseString
|
||||
# from xml.dom.minidom import parseString
|
||||
from functions import *
|
||||
from settings import settings
|
||||
from httppersist import requests
|
||||
|
||||
from xbmc import Player
|
||||
import xbmcgui
|
||||
# import xbmcgui
|
||||
import downloadutils
|
||||
from utils import window
|
||||
import PlexFunctions as pf
|
||||
|
@ -67,18 +67,19 @@ class SubscriptionManager:
|
|||
ret += ' />'
|
||||
return ret
|
||||
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
|
||||
# pbmc_server = str(WINDOW.getProperty('plexbmc.nowplaying.server'))
|
||||
# userId = str(WINDOW.getProperty('currUserId'))
|
||||
# pbmc_server = str(WINDOW.getProperty('pms_server'))
|
||||
pbmc_server = None
|
||||
pbmc_server = window('pms_server')
|
||||
if pbmc_server:
|
||||
(self.protocol, self.server, self.port) = \
|
||||
pbmc_server.split(':')
|
||||
self.server = self.server.replace('/', '')
|
||||
keyid = None
|
||||
count = 0
|
||||
while not keyid:
|
||||
if count > 300:
|
||||
break
|
||||
keyid = WINDOW.getProperty('Plex_currently_playing_itemid')
|
||||
keyid = window('Plex_currently_playing_itemid')
|
||||
xbmc.sleep(100)
|
||||
count += 1
|
||||
if keyid:
|
||||
|
@ -87,8 +88,6 @@ class SubscriptionManager:
|
|||
ret += ' location="%s"' % (self.mainlocation)
|
||||
ret += ' key="%s"' % (self.lastkey)
|
||||
ret += ' ratingKey="%s"' % (self.lastratingkey)
|
||||
if pbmc_server:
|
||||
(self.server, self.port) = pbmc_server.split(':')
|
||||
serv = getServerByHost(self.server)
|
||||
if info.get('playQueueID'):
|
||||
self.containerKey = "/playQueues/%s" % info.get('playQueueID')
|
||||
|
|
|
@ -76,8 +76,8 @@ class UserClient(threading.Thread):
|
|||
settings = utils.settings
|
||||
|
||||
# Original host
|
||||
self.machineIdentifier = utils.settings('plex_machineIdentifier')
|
||||
self.servername = utils.settings('plex_servername')
|
||||
self.machineIdentifier = settings('plex_machineIdentifier')
|
||||
self.servername = settings('plex_servername')
|
||||
HTTPS = settings('https') == "true"
|
||||
host = settings('ipaddress')
|
||||
port = settings('port')
|
||||
|
@ -91,14 +91,11 @@ class UserClient(threading.Thread):
|
|||
# If https is true
|
||||
if prefix and HTTPS:
|
||||
server = "https://%s" % server
|
||||
return server
|
||||
# If https is false
|
||||
elif prefix and not HTTPS:
|
||||
server = "http://%s" % server
|
||||
return server
|
||||
# If only the host:port is required
|
||||
elif not prefix:
|
||||
return server
|
||||
self.logMsg('Returning active server: %s' % server)
|
||||
return server
|
||||
|
||||
def getSSLverify(self):
|
||||
# Verify host certificate
|
||||
|
@ -410,6 +407,7 @@ class UserClient(threading.Thread):
|
|||
self.auth = False
|
||||
if self.authenticate():
|
||||
# Successfully authenticated and loaded a user
|
||||
log("Successfully authenticated!", 1)
|
||||
log("Current user: %s" % self.currUser, 1)
|
||||
log("Current userId: %s" % self.currUserId, 1)
|
||||
log("Current accessToken: xxxx", 1)
|
||||
|
|
|
@ -148,7 +148,7 @@ def ThreadMethodsAdditionalStop(windowAttribute):
|
|||
def wrapper(cls):
|
||||
def threadStopped(self):
|
||||
return (self._threadStopped or
|
||||
(window('terminateNow') == "true") or
|
||||
(window('plex_terminateNow') == "true") or
|
||||
window(windowAttribute) == "true")
|
||||
cls.threadStopped = threadStopped
|
||||
return cls
|
||||
|
@ -209,7 +209,7 @@ def ThreadMethods(cls):
|
|||
cls.threadSuspended = threadSuspended
|
||||
|
||||
def threadStopped(self):
|
||||
return self._threadStopped or (window('terminateNow') == 'true')
|
||||
return self._threadStopped or (window('plex_terminateNow') == 'true')
|
||||
cls.threadStopped = threadStopped
|
||||
|
||||
# Return class to render this a decorator
|
||||
|
@ -625,6 +625,85 @@ def indent(elem, level=0):
|
|||
if level and (not elem.tail or not elem.tail.strip()):
|
||||
elem.tail = i
|
||||
|
||||
|
||||
def musiclibXML():
|
||||
"""
|
||||
Deactivates Kodi trying to scan music library on startup
|
||||
|
||||
Changes guisettings.xml in Kodi userdata folder:
|
||||
updateonstartup: set to "false"
|
||||
"""
|
||||
path = xbmc.translatePath("special://profile/").decode('utf-8')
|
||||
xmlpath = "%sguisettings.xml" % path
|
||||
|
||||
try:
|
||||
xmlparse = etree.parse(xmlpath)
|
||||
except:
|
||||
# Document is blank or missing
|
||||
root = etree.Element('settings')
|
||||
else:
|
||||
root = xmlparse.getroot()
|
||||
|
||||
music = root.find('musiclibrary')
|
||||
if music is None:
|
||||
music = etree.SubElement(root, 'musiclibrary')
|
||||
|
||||
startup = music.find('updateonstartup')
|
||||
if startup is None:
|
||||
# Setting does not exist yet; create it
|
||||
startup = etree.SubElement(music,
|
||||
'updateonstartup',
|
||||
attrib={'default': "true"}).text = "false"
|
||||
else:
|
||||
startup.text = "false"
|
||||
|
||||
# Prettify and write to file
|
||||
try:
|
||||
indent(root)
|
||||
except:
|
||||
pass
|
||||
etree.ElementTree(root).write(xmlpath)
|
||||
|
||||
|
||||
def advancedSettingsXML():
|
||||
"""
|
||||
Deactivates Kodi popup for scanning of music library
|
||||
|
||||
Changes advancedsettings.xml, musiclibrary:
|
||||
backgroundupdate set to "true"
|
||||
"""
|
||||
path = xbmc.translatePath("special://profile/").decode('utf-8')
|
||||
xmlpath = "%sadvancedsettings.xml" % path
|
||||
|
||||
try:
|
||||
xmlparse = etree.parse(xmlpath)
|
||||
except:
|
||||
# Document is blank or missing
|
||||
root = etree.Element('advancedsettings')
|
||||
else:
|
||||
root = xmlparse.getroot()
|
||||
|
||||
music = root.find('musiclibrary')
|
||||
if music is None:
|
||||
music = etree.SubElement(root, 'musiclibrary')
|
||||
|
||||
backgroundupdate = music.find('backgroundupdate')
|
||||
if backgroundupdate is None:
|
||||
# Setting does not exist yet; create it
|
||||
backgroundupdate = etree.SubElement(
|
||||
music,
|
||||
'backgroundupdate').text = "true"
|
||||
else:
|
||||
backgroundupdate.text = "true"
|
||||
|
||||
# Prettify and write to file
|
||||
try:
|
||||
indent(root)
|
||||
except:
|
||||
pass
|
||||
etree.ElementTree(root).write(xmlpath)
|
||||
|
||||
|
||||
def sourcesXML():
|
||||
# To make Master lock compatible
|
||||
path = xbmc.translatePath("special://profile/").decode('utf-8')
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
<setting id="enableImportSongRating" type="bool" label="30524" default="true" visible="false"/>
|
||||
<setting id="enableExportSongRating" type="bool" label="30525" default="false" visible="false" />
|
||||
<setting id="enableUpdateSongRating" type="bool" label="30526" default="false" visible="false" />
|
||||
<setting id="emby_pathverified" type="bool" default="false" visible="false" /> <!-- If 'false': one single warning message pops up if PKC cannot verify direct paths -->
|
||||
</category>
|
||||
|
||||
<category label="30516"><!-- Playback -->
|
||||
|
@ -108,13 +109,21 @@
|
|||
<setting id="newmusictime" type="number" label="30533" visible="false" default="2" option="int" subsetting="true" />
|
||||
</category>
|
||||
-->
|
||||
|
||||
<category label="39045"><!-- Appearance Tweaks -->
|
||||
<setting type="lsep" label="39046" />
|
||||
<setting id="OnDeckTvAppendShow" type="bool" label="39047" default="false" /><!--On Deck view: Append show title to episode-->
|
||||
<setting id="OnDeckTvAppendSeason" type="bool" label="39048" default="false" /><!--On Deck view: Append season number to episode-->
|
||||
</category>
|
||||
|
||||
<category label="30022"><!-- Advanced -->
|
||||
<setting id="logLevel" type="enum" label="30004" values="Disabled|Info|Debug" default="1" />
|
||||
<setting id="startupDelay" type="number" label="30529" default="0" option="int" />
|
||||
<setting id="connectMsg" type="bool" label="30249" default="true" />
|
||||
<setting label="39018" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=repair)" option="close" /> <!-- Repair local database (force update all content) -->
|
||||
<setting label="39019" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=reset)" option="close" /> <!-- Perform local database reset (full resync) -->
|
||||
<setting label="39020" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=texturecache)" option="close" /> <!-- Cache all images to Kodi texture cache -->
|
||||
<setting label="39021" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=thememedia)" option="close" visible="false" /> <!-- Sync Plex Theme Media to Kodi -->
|
||||
<setting type="lsep" label="39049" /><!-- Nothing works? Try a full reset -->
|
||||
<setting label="39019" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect/?mode=reset)" option="close" /> <!-- Partial or full reset of Database and PKC -->
|
||||
</category>
|
||||
</settings>
|
||||
|
|
49
service.py
49
service.py
|
@ -28,6 +28,7 @@ import player
|
|||
import utils
|
||||
import videonodes
|
||||
import websocket_client as wsc
|
||||
import downloadutils
|
||||
|
||||
import PlexAPI
|
||||
import PlexCompanion
|
||||
|
@ -80,7 +81,10 @@ class Service():
|
|||
"emby_initialScan", "emby_customplaylist", "emby_playbackProps",
|
||||
"plex_runLibScan", "plex_username", "pms_token", "plex_token",
|
||||
"pms_server", "plex_machineIdentifier", "plex_servername",
|
||||
"plex_authenticated"
|
||||
"plex_authenticated", "EmbyUserImage", "useDirectPaths",
|
||||
"replaceSMB", "remapSMB", "remapSMBmovieOrg", "remapSMBtvOrg",
|
||||
"remapSMBmusicOrg", "remapSMBmovieNew", "remapSMBtvNew",
|
||||
"remapSMBmusicNew", "suspend_LibraryThread", "plex_terminateNow"
|
||||
]
|
||||
for prop in properties:
|
||||
window(prop, clear=True)
|
||||
|
@ -132,12 +136,10 @@ class Service():
|
|||
# 3. User has access to the server
|
||||
|
||||
if window('emby_online') == "true":
|
||||
|
||||
# Emby server is online
|
||||
# Verify if user is set and has access to the server
|
||||
if (user.currUser is not None) and user.HasAccess:
|
||||
|
||||
# If an item is playing
|
||||
# If an item is playing
|
||||
if xplayer.isPlaying():
|
||||
try:
|
||||
# Update and report progress
|
||||
|
@ -190,10 +192,15 @@ class Service():
|
|||
ws.start()
|
||||
# Start the syncing thread
|
||||
if not self.library_running:
|
||||
log('Starting libary sync thread', 1)
|
||||
self.library_running = True
|
||||
library.start()
|
||||
# Start the Plex Companion thread
|
||||
if not self.plexCompanion_running and \
|
||||
self.runPlexCompanion == "true":
|
||||
self.plexCompanion_running = True
|
||||
plexCompanion.start()
|
||||
else:
|
||||
|
||||
if (user.currUser is None) and self.warn_auth:
|
||||
# Alert user is not authenticated and suppress future warning
|
||||
self.warn_auth = False
|
||||
|
@ -213,6 +220,7 @@ class Service():
|
|||
if monitor.waitForAbort(5):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
xbmc.sleep(50)
|
||||
else:
|
||||
# Wait until Emby server is online
|
||||
# or Kodi is shut down.
|
||||
|
@ -235,9 +243,7 @@ class Service():
|
|||
icon="special://home/addons/plugin.video."
|
||||
"plexkodiconnect/icon.png",
|
||||
sound=False)
|
||||
|
||||
self.server_online = False
|
||||
|
||||
else:
|
||||
# Server is online
|
||||
if not self.server_online:
|
||||
|
@ -254,9 +260,8 @@ class Service():
|
|||
"plexkodiconnect/icon.png",
|
||||
time=2000,
|
||||
sound=False)
|
||||
|
||||
self.server_online = True
|
||||
log("Server is online and ready.", 1)
|
||||
log("Server %s is online and ready." % server, 1)
|
||||
window('emby_online', value="true")
|
||||
|
||||
# Start the userclient thread
|
||||
|
@ -264,36 +269,31 @@ class Service():
|
|||
self.userclient_running = True
|
||||
user.start()
|
||||
|
||||
# Start the Plex Companion thread
|
||||
if not self.plexCompanion_running and \
|
||||
self.runPlexCompanion == "true":
|
||||
self.plexCompanion_running = True
|
||||
plexCompanion.start()
|
||||
|
||||
|
||||
break
|
||||
|
||||
if monitor.waitForAbort(1):
|
||||
# Abort was requested while waiting.
|
||||
break
|
||||
xbmc.sleep(50)
|
||||
|
||||
if monitor.waitForAbort(1):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
|
||||
##### Emby thread is terminating. #####
|
||||
# Terminating PlexKodiConnect
|
||||
|
||||
# Tell all threads to terminate
|
||||
utils.window('terminateNow', value='true')
|
||||
# Tell all threads to terminate (e.g. several lib sync threads)
|
||||
utils.window('plex_terminateNow', value='true')
|
||||
|
||||
try:
|
||||
if self.plexCompanion_running:
|
||||
plexCompanion.stopThread()
|
||||
plexCompanion.stopThread()
|
||||
except:
|
||||
xbmc.log('plexCompanion already shut down')
|
||||
|
||||
try:
|
||||
if self.library_running:
|
||||
library.stopThread()
|
||||
library.stopThread()
|
||||
except:
|
||||
xbmc.log('Library sync already shut down')
|
||||
|
||||
|
@ -303,8 +303,7 @@ class Service():
|
|||
xbmc.log('Websocket client already shut down')
|
||||
|
||||
try:
|
||||
if self.userclient_running:
|
||||
user.stopThread()
|
||||
user.stopThread()
|
||||
except:
|
||||
xbmc.log('User client already shut down')
|
||||
|
||||
|
@ -314,8 +313,8 @@ class Service():
|
|||
delay = int(utils.settings('startupDelay'))
|
||||
|
||||
xbmc.log("Delaying Plex startup by: %s sec..." % delay)
|
||||
# Plex: add 3 seconds just for good measure
|
||||
if delay and xbmc.Monitor().waitForAbort(delay+3):
|
||||
# Plex: add 5 seconds just for good measure
|
||||
if delay and xbmc.Monitor().waitForAbort(delay+5):
|
||||
# Start the service
|
||||
xbmc.log("Abort requested while waiting. Emby for kodi not started.")
|
||||
else:
|
||||
|
|
Loading…
Reference in a new issue