Merge branch 'develop'

This commit is contained in:
tomkat83 2016-03-10 10:47:41 +01:00
commit 3d4e51e587
10 changed files with 199 additions and 47 deletions

View file

@ -7,13 +7,13 @@
**Installation in Kodi**
1. You might want to uninstall everything else Plex related first, e.g. PlexBMC and PlexBMC Helper. Starting with a fresh Kodi install might be a good idea. Be sure to use a "normal", unmodded Skin in Kodi.
If you're updating, you might also want to do a complete reset of the plugin: Settings -> Advanced -> "Performe full DB reset". Choose "Yes" for everything.
If you're updating, you might also want to do a complete reset of the plugin: Settings -> Advanced -> "Perform full DB reset". Choose "Yes" for all questions.
2. Simply fire up Kodi and Install from ZIP from here on.
3. Install the 2 needed dependencies first (be sure to NOT download the sources but the additional release files): https://github.com/croneter/plugin.video.plexkodiconnect.tvshows/releases/tag/1.0.0 and https://github.com/croneter/plugin.video.plexkodiconnect.movies/releases/tag/1.0.0
3. Install the 2 needed dependencies first (be sure to NOT download the sources but the additional release files): https://github.com/croneter/plugin.video.plexkodiconnect.tvshows/releases/ and https://github.com/croneter/plugin.video.plexkodiconnect.movies/releases/
5. Then install PlexKodiConnect, again the additional release file from here: https://github.com/croneter/PlexKodiConnect/releases/
6. Within a few seconds you should be prompted to log into plex.tv. This is mandatory for Plex Home, otherwise you can skip. If nothing happens, try to restart Kodi
7. Once you're succesfully authenticated to your Plex server, the initial sync will start.
8. The first sync of the Plex server to local Kodi database may take a LONG time. With my setup (~400 movies, ~600 episodes, couple of Test music albums and a very powerful NAS), sync take approximately 5 minutes.
8. The first sync of the Plex server to local Kodi database may take a LONG time. With my setup (~400 movies, ~600 episodes, couple of Test music albums and a very powerful NAS), sync takes approximately 5 minutes.
9. Once the full sync is done, you can browse your media in Kodi, syncs will be automatically done in the background.
10. Restart!
@ -62,6 +62,8 @@ Guess what, this is BETA. Currently these features are working:
- Pictures
- Watch Later
- Music Videos
- Playlists
- Play directly from SMB paths ("\\\\server\\Plex\\movie.mkv" on Windows) instead of HTTP ("192.168.1.1:32400")
- TV Shows Theme Music (ultra-low prio)

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect"
name="PlexKodiConnect"
version="1.0.5"
version="1.0.6"
provider-name="croneter">
<requires>
<import addon="xbmc.python" version="2.1.0"/>

View file

@ -1,3 +1,10 @@
version 1.0.6
- Enable traceback and dump XMLs of failed PMS items in the log for lib sync
- Optimize notifications for library syncs
- Manually trigger full library scan from settings
- Merge with MediaBrowser/master up until db4cb448b0e4fd82662f8b82a800d8da8ea33688
version 1.0.5
- Catch exceptions in itemtypes and log them
- Slightly increased download timeouts

View file

@ -51,6 +51,7 @@ if __name__ == '__main__':
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
item = emby_db.getItem_byKodiId(itemid, itemtype)
embycursor.close()
if item: embyid = item[0]
logMsg("Contextmenu opened for embyid: %s - itemtype: %s" %(embyid,itemtype))

View file

@ -8,6 +8,7 @@ import urlparse
import xbmc
import xbmcaddon
import xbmcgui
#################################################################################################
@ -66,7 +67,8 @@ class Main:
'companion': entrypoint.plexCompanion,
'switchuser': entrypoint.switchPlexUser,
'deviceid': entrypoint.resetDeviceId,
'reConnect': entrypoint.reConnect
'reConnect': entrypoint.reConnect,
'delete': entrypoint.deleteItem
}
if "/extrafanart" in sys.argv[0]:
@ -108,7 +110,18 @@ class Main:
if mode == "settings":
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
elif mode in ("manualsync", "repair"):
entrypoint.RunLibScan(mode)
if utils.window('emby_online') != "true":
# Server is not online, do not run the sync
xbmcgui.Dialog().ok(heading="PlexKodiConnect",
line1=("Unable to run the sync, the add-on is not "
"connected to the Emby server."))
utils.logMsg("PLEX", "Not connected to the emby server.", 1)
return
else:
utils.logMsg("PLEX", "Requesting full library scan", 1)
utils.window('plex_runLibScan', value="full")
elif mode == "texturecache":
import artwork
artwork.Artwork().FullTextureCacheSync()

View file

@ -405,5 +405,7 @@
<string id="39404">Startup syncing process failed repeatedly. Try restarting Kodi. Stopping Sync for now.</string>
<string id="39405">Plex playlists/nodes refreshed</string>
<string id="39406">Plex playlists/nodes refresh failed</string>
<string id="39407">Full library sync finished</string>
<string id="39408">Sync had to skip some items because they could not be processed. Please post your Kodi logs to the Plex forum.</string>
</strings>

View file

@ -337,5 +337,7 @@
<string id="39404">Der Startup Synchronisations-Prozess der Plex Bibliotheken ist mehrmals fehlgeschlagen. Bitte Kodi neu starten. Synch wird jetzt gestoppt.</string>
<string id="39405">Plex Playlisten/Nodes aktualisiert</string>
<string id="39406">Plex Playlisten/Nodes Aktualisierung fehlgeschlagen</string>
<string id="39407">Plex Bibliotheken aktualisiert</string>
<string id="39408">Einige Plex Einträge mussten übersprungen werden, da sie nicht verarbeitet werden konnten. Bitte teilen Sie Ihr Kodi log im Plex Forum.</string>
</strings>

View file

@ -285,6 +285,56 @@ def resetDeviceId():
line1=language(33033))
xbmc.executebuiltin('RestartApp')
##### Delete Item
def deleteItem():
# Serves as a keymap action
if xbmc.getInfoLabel('ListItem.Property(embyid)'): # If we already have the embyid
embyid = xbmc.getInfoLabel('ListItem.Property(embyid)')
else:
dbid = xbmc.getInfoLabel('ListItem.DBID')
itemtype = xbmc.getInfoLabel('ListItem.DBTYPE')
if not itemtype:
if xbmc.getCondVisibility('Container.Content(albums)'):
itemtype = "album"
elif xbmc.getCondVisibility('Container.Content(artists)'):
itemtype = "artist"
elif xbmc.getCondVisibility('Container.Content(songs)'):
itemtype = "song"
elif xbmc.getCondVisibility('Container.Content(pictures)'):
itemtype = "picture"
else:
utils.logMsg("EMBY delete", "Unknown type, unable to proceed.", 1)
return
embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
item = emby_db.getItem_byKodiId(dbid, itemtype)
embycursor.close()
try:
embyid = item[0]
except TypeError:
utils.logMsg("EMBY delete", "Unknown embyId, unable to proceed.", 1)
return
if utils.settings('skipContextMenu') != "true":
resp = xbmcgui.Dialog().yesno(
heading="Confirm delete",
line1=("Delete file from Emby Server? This will "
"also delete the file(s) from disk!"))
if not resp:
utils.logMsg("EMBY delete", "User skipped deletion for: %s." % embyid, 1)
return
doUtils = downloadutils.DownloadUtils()
url = "{server}/emby/Items/%s?format=json" % embyid
utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0)
doUtils.downloadUrl(url, type="DELETE")
##### ADD ADDITIONAL USERS #####
def addUser():

View file

@ -287,10 +287,18 @@ class Movies(Items):
try:
self.run_add_update(item, viewtag, viewid)
except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for movies has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now
return
@ -920,10 +928,18 @@ class TVShows(Items):
try:
self.run_add_update(item, viewtag, viewid)
except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for tv show has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now
return
@ -1117,10 +1133,18 @@ class TVShows(Items):
try:
self.run_add_updateSeason(item, viewtag, viewid)
except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for tv seasons has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now
return
@ -1162,10 +1186,18 @@ class TVShows(Items):
try:
self.run_add_updateEpisode(item, viewtag, viewid)
except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for tv episode has crashed for item %s. '
'Error:' % item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now
return
@ -1642,11 +1674,19 @@ class Music(Items):
try:
self.run_add_updateArtist(item, viewtag, viewid, artisttype)
except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for music artist has crashed for '
'item %s. Error:'
% item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now
return
@ -1738,11 +1778,19 @@ class Music(Items):
try:
self.run_add_updateAlbum(item, viewtag, viewid)
except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for music album has crashed for '
'item %s. Error:'
% item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now
return
@ -1936,11 +1984,19 @@ class Music(Items):
try:
self.run_add_updateSong(item, viewtag, viewid)
except Exception as e:
utils.window('emby_dbScan', clear=True)
self.logMsg('itemtypes.py for music song has crashed for '
'item %s. Error:'
% item.attrib.get('ratingKey', None), -1)
self.logMsg(e, -1)
import traceback
self.logMsg("Traceback:\n%s" % traceback.format_exc(), 0)
self.logMsg('The item xml is:', -1)
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
etree.dump(item)
utils.window('plex_scancrashed', value='true')
# skip this item for now
return
@ -2275,4 +2331,4 @@ class Music(Items):
artwork = self.artwork
artwork.deleteArtwork(kodiid, "artist", kodicursor)
kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiid,))
kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiid,))

View file

@ -70,7 +70,7 @@ class ThreadedGetMetadata(Thread):
# Did not receive a valid XML - skip that item for now
self.logMsg("Could not get metadata for %s. "
"Skipping that item for now"
% updateItem['itemId'], -1)
% updateItem['itemId'], 0)
# Increase BOTH counters - since metadata won't be processed
with lock:
getMetadataCount += 1
@ -223,8 +223,8 @@ class LibrarySync(Thread):
self.user = userclient.UserClient()
self.emby = embyserver.Read_EmbyServer()
self.vnodes = videonodes.VideoNodes()
self.syncThreadNumber = int(utils.settings('syncThreadNumber'))
self.syncThreadNumber = int(utils.settings('syncThreadNumber'))
self.installSyncDone = True if \
utils.settings('SyncInstallRunDone') == 'true' else False
self.showDbSync = True if \
@ -236,18 +236,30 @@ class LibrarySync(Thread):
Thread.__init__(self)
def showKodiNote(self, message, forced=False):
def showKodiNote(self, message, forced=False, icon="plex"):
"""
Shows a Kodi popup, if user selected to do so. Pass message in unicode
or string
icon: "plex": shows Plex icon
"error": shows Kodi error icon
"""
if not (self.showDbSync or forced):
return
xbmcgui.Dialog().notification(
heading=self.addonName,
message=message,
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
sound=False)
if icon == "plex":
xbmcgui.Dialog().notification(
heading=self.addonName,
message=message,
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
time=5000,
sound=False)
elif icon == "error":
xbmcgui.Dialog().notification(
heading=self.addonName,
message=message,
icon=xbmcgui.NOTIFICATION_ERROR,
time=7000,
sound=True)
def fastSync(self):
"""
@ -307,7 +319,8 @@ class LibrarySync(Thread):
elif self.updatelist[0]['itemType'] == 'Music':
self.updateKodiMusicLib = True
self.GetAndProcessXMLs(
PlexFunctions.GetItemClassFromType(plexType))
PlexFunctions.GetItemClassFromType(plexType),
showProgress=False)
self.updatelist = []
# Update userdata
@ -327,6 +340,10 @@ class LibrarySync(Thread):
# Reset and return
self.allPlexElementsId = {}
# Show warning if itemtypes.py crashed at some point
if utils.window('plex_scancrashed') == 'true':
xbmcgui.Dialog().ok(self.addonName, self.__language__(39408))
utils.window('plex_scancrashed', clear=True)
return True
def saveLastSync(self):
@ -400,6 +417,10 @@ class LibrarySync(Thread):
utils.window('emby_initialScan', clear=True)
xbmc.executebuiltin('InhibitIdleShutdown(false)')
utils.setScreensaver(value=screensaver)
# Show warning if itemtypes.py crashed at some point
if utils.window('plex_scancrashed') == 'true':
xbmcgui.Dialog().ok(self.addonName, self.__language__(39408))
utils.window('plex_scancrashed', clear=True)
return True
def processView(self, folderItem, kodi_db, emby_db, totalnodes):
@ -698,7 +719,7 @@ class LibrarySync(Thread):
'viewId': viewId,
'title': title})
def GetAndProcessXMLs(self, itemType):
def GetAndProcessXMLs(self, itemType, showProgress=True):
"""
Downloads all XMLs for itemType (e.g. Movies, TV-Shows). Processes them
by then calling itemtypes.<itemType>()
@ -706,6 +727,7 @@ class LibrarySync(Thread):
Input:
itemType: 'Movies', 'TVShows', ...
self.updatelist
showProgress If False, NEVER shows sync progress
"""
# Some logging, just in case.
self.logMsg("self.updatelist: %s" % self.updatelist, 2)
@ -750,17 +772,18 @@ class LibrarySync(Thread):
threads.append(thread)
self.logMsg("Processing thread spawned", 1)
# Start one thread to show sync progress
if self.showDbSync:
dialog = xbmcgui.DialogProgressBG()
thread = ThreadedShowSyncInfo(
dialog,
[getMetadataLock, processMetadataLock],
itemNumber,
itemType)
thread.setDaemon(True)
thread.start()
threads.append(thread)
self.logMsg("Kodi Infobox thread spawned", 1)
if showProgress:
if self.showDbSync:
dialog = xbmcgui.DialogProgressBG()
thread = ThreadedShowSyncInfo(
dialog,
[getMetadataLock, processMetadataLock],
itemNumber,
itemType)
thread.setDaemon(True)
thread.start()
threads.append(thread)
self.logMsg("Kodi Infobox thread spawned", 1)
# Wait until finished
getMetadataQueue.join()
@ -1229,6 +1252,8 @@ class LibrarySync(Thread):
fullSync(manualrun=True)
window('emby_dbScan', clear=True)
count = 0
# Full library sync finished
self.showKodiNote(string(39407), forced=True)
# Reset views was requested from somewhere else
elif window('plex_runLibScan') == "views":
log('Refresh playlist and nodes requested, starting', 0)
@ -1244,22 +1269,14 @@ class LibrarySync(Thread):
# Ran successfully
log("Refresh playlists/nodes completed", 0)
# "Plex playlists/nodes refreshed"
dialog.notification(
heading=self.addonName,
message=string(39405),
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
time=3000,
sound=True)
self.showKodiNote(string(39405), forced=True)
else:
# Failed
log("Refresh playlists/nodes failed", -1)
# "Plex playlists/nodes refresh failed"
dialog.notification(
heading=self.addonName,
message=string(39406),
icon=xbmcgui.NOTIFICATION_ERROR,
time=3000,
sound=True)
self.showKodiNote(string(39406),
forced=True,
icon="error")
window('emby_dbScan', clear=True)
elif enableBackgroundSync:
# Run full lib scan approx every 30min
@ -1269,6 +1286,8 @@ class LibrarySync(Thread):
log('Running background full lib scan', 0)
fullSync(manualrun=True)
window('emby_dbScan', clear=True)
# Full library sync finished
self.showKodiNote(string(39407), forced=False)
# Run fast sync otherwise (ever second or so)
else:
window('emby_dbScan', value="true")