Merge branch 'hotfixes'

This commit is contained in:
croneter 2017-08-19 18:05:46 +02:00
commit 473bf6f5ed
15 changed files with 120 additions and 99 deletions

View file

@ -1,5 +1,5 @@
[![stable version](https://img.shields.io/badge/stable_version-1.8.9-blue.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect/bin/repository.plexkodiconnect/repository.plexkodiconnect-1.0.0.zip)
[![beta version](https://img.shields.io/badge/beta_version-1.8.9-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip)
[![beta version](https://img.shields.io/badge/beta_version-1.8.10-red.svg?maxAge=60&style=flat) ](https://dl.bintray.com/croneter/PlexKodiConnect_BETA/bin-BETA/repository.plexkodiconnectbeta/repository.plexkodiconnectbeta-1.0.0.zip)
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/Installation)
[![FAQ](https://img.shields.io/badge/wiki-FAQ-brightgreen.svg?maxAge=60&style=flat)](https://github.com/croneter/PlexKodiConnect/wiki/faq)

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.8.9" provider-name="croneter">
<addon id="plugin.video.plexkodiconnect" name="PlexKodiConnect" version="1.8.10" provider-name="croneter">
<requires>
<import addon="xbmc.python" version="2.1.0"/>
<import addon="script.module.requests" version="2.3.0" />
@ -59,7 +59,18 @@
<summary lang="da_DK">Indbygget Integration af Plex i Kodi</summary>
<description lang="da_DK">Tilslut Kodi til din Plex Media Server. Dette plugin forudsætter, at du administrere alle dine videoer med Plex (og ikke med Kodi). Du kan miste data som allerede er gemt i Kodi video og musik-databaser (dette plugin ændrer direkte i dem). Brug på eget ansvar!</description>
<disclaimer lang="da_DK">Brug på eget ansvar</disclaimer>
<news>version 1.8.9
<news>version 1.8.10 (beta only):
- Vastly improve sync speed for music
- Never show library sync dialog if media is playing
- Improvements to sync dialog
- Fix stop synching if path not found
- Resume aborted sync on PKC settings change
- Don't quit library sync if failed repeatedly
- Verify path for every Plex library on install sync
- More descriptive downloadable subtitles
- More code fixes and optimization
version 1.8.9
- Fix playback not starting in some circumstances
- Deactivate some annoying popups on install

View file

@ -1,3 +1,14 @@
version 1.8.10 (beta only):
- Vastly improve sync speed for music
- Never show library sync dialog if media is playing
- Improvements to sync dialog
- Fix stop synching if path not found
- Resume aborted sync on PKC settings change
- Don't quit library sync if failed repeatedly
- Verify path for every Plex library on install sync
- More descriptive downloadable subtitles
- More code fixes and optimization
version 1.8.9
- Fix playback not starting in some circumstances
- Deactivate some annoying popups on install

View file

@ -2357,11 +2357,11 @@ class API():
# ext = stream.attrib.get('format')
if key:
# We do know the language - temporarily download
if stream.attrib.get('languageCode') is not None:
if stream.attrib.get('language') is not None:
path = self.download_external_subtitles(
"{server}%s" % key,
"subtitle%02d.%s.%s" % (fileindex,
stream.attrib['languageCode'],
stream.attrib['language'],
stream.attrib['codec']))
fileindex += 1
# We don't know the language - no need to download
@ -2589,7 +2589,7 @@ class API():
elif window('replaceSMB') == 'true':
if path.startswith('\\\\'):
path = 'smb:' + path.replace('\\', '/')
if ((window('plex_pathverified') == 'true' and forceCheck is False) or
if ((state.PATH_VERIFIED and forceCheck is False) or
omitCheck is True):
return path
@ -2617,12 +2617,12 @@ class API():
if self.askToValidate(path):
state.STOP_SYNC = True
path = None
window('plex_pathverified', value='true')
state.PATH_VERIFIED = True
else:
path = None
elif forceCheck is False:
if window('plex_pathverified') != 'true':
window('plex_pathverified', value='true')
# Only set the flag if we were not force-checking the path
state.PATH_VERIFIED = True
return path
def askToValidate(self, url):

View file

@ -126,8 +126,9 @@ def double_urldecode(text):
return unquote(unquote(text))
@thread_methods(add_stops=['STOP_SYNC'],
add_suspends=['SUSPEND_LIBRARY_THREAD', 'DB_SCAN'])
@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD',
'DB_SCAN',
'STOP_SYNC'])
class Image_Cache_Thread(Thread):
xbmc_host = 'localhost'
xbmc_port, xbmc_username, xbmc_password = setKodiWebServerDetails()

View file

@ -1729,7 +1729,7 @@ class Music(Items):
if album is None or album == 401:
log.error('Could not download album, abort')
return
self.add_updateAlbum(album[0])
self.add_updateAlbum(album[0], children=[item])
plex_dbalbum = plex_db.getItem_byId(plex_albumId)
try:
albumid = plex_dbalbum[0]

View file

@ -47,6 +47,11 @@ class KodiMonitor(Monitor):
"""
Monitor the PKC settings for changes made by the user
"""
log.debug('PKC settings change detected')
# Assume that the user changed the settings so that we can now find the
# path to all media files
state.STOP_SYNC = False
state.PATH_VERIFIED = False
# settings: window-variable
items = {
'logLevel': 'plex_logLevel',

View file

@ -17,8 +17,9 @@ log = getLogger("PLEX."+__name__)
###############################################################################
@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD', 'DB_SCAN'],
add_stops=['STOP_SYNC'])
@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD',
'DB_SCAN',
'STOP_SYNC'])
class Process_Fanart_Thread(Thread):
"""
Threaded download of additional fanart in the background

View file

@ -16,7 +16,7 @@ log = getLogger("PLEX."+__name__)
###############################################################################
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD'])
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD', 'STOP_SYNC'])
class Threaded_Get_Metadata(Thread):
"""
Threaded download of Plex XML metadata for a certain library item.
@ -115,17 +115,9 @@ class Threaded_Get_Metadata(Thread):
except (TypeError, IndexError, AttributeError):
log.error('Could not get children for Plex id %s'
% item['itemId'])
else:
item['children'] = []
for child in children_xml:
child_xml = GetPlexMetadata(child.attrib['ratingKey'])
try:
child_xml[0].attrib
except (TypeError, IndexError, AttributeError):
log.error('Could not get child for Plex id %s'
% child.attrib['ratingKey'])
else:
item['children'].append(child_xml[0])
else:
item['children'] = children_xml
# place item into out queue
out_queue.put(item)

View file

@ -15,7 +15,7 @@ log = getLogger("PLEX."+__name__)
###############################################################################
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD'])
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD', 'STOP_SYNC'])
class Threaded_Process_Metadata(Thread):
"""
Not yet implemented for more than 1 thread - if ever. Only to be called by

View file

@ -2,7 +2,8 @@
from logging import getLogger
from threading import Thread, Lock
from xbmc import sleep
from xbmc import sleep, Player
from xbmcgui import DialogProgressBG
from utils import thread_methods, language as lang
@ -18,18 +19,17 @@ LOCK = Lock()
###############################################################################
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD'])
@thread_methods(add_stops=['SUSPEND_LIBRARY_THREAD', 'STOP_SYNC'])
class Threaded_Show_Sync_Info(Thread):
"""
Threaded class to show the Kodi statusbar of the metadata download.
Input:
dialog xbmcgui.DialogProgressBG() object to show progress
total: Total number of items to get
item_type:
"""
def __init__(self, dialog, total, item_type):
def __init__(self, total, item_type):
self.total = total
self.dialog = dialog
self.item_type = item_type
Thread.__init__(self)
@ -51,14 +51,15 @@ class Threaded_Show_Sync_Info(Thread):
log.debug('Show sync info thread started')
# cache local variables because it's faster
total = self.total
dialog = self.dialog
dialog = DialogProgressBG('dialoglogProgressBG')
thread_stopped = self.thread_stopped
dialog.create("%s %s: %s %s"
% (lang(39714), self.item_type, str(total), lang(39715)))
player = Player()
total = 2 * total
totalProgress = 0
while thread_stopped() is False:
while thread_stopped() is False and not player.isPlaying():
with LOCK:
get_progress = GET_METADATA_COUNT
process_progress = PROCESS_METADATA_COUNT

View file

@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
###############################################################################
import logging
from logging import getLogger
from threading import Thread
import Queue
from random import shuffle
import xbmc
import xbmcgui
from xbmcvfs import exists
from utils import window, settings, getUnixTimestamp, sourcesXML,\
@ -33,13 +32,12 @@ import state
###############################################################################
log = logging.getLogger("PLEX."+__name__)
log = getLogger("PLEX."+__name__)
###############################################################################
@thread_methods(add_stops=['STOP_SYNC'],
add_suspends=['SUSPEND_LIBRARY_THREAD'])
@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD', 'STOP_SYNC'])
class LibrarySync(Thread):
"""
"""
@ -63,7 +61,7 @@ class LibrarySync(Thread):
self.user = userclient.UserClient()
self.vnodes = videonodes.VideoNodes()
self.dialog = xbmcgui.Dialog()
self.xbmcplayer = xbmc.Player()
self.syncThreadNumber = int(settings('syncThreadNumber'))
self.installSyncDone = settings('SyncInstallRunDone') == 'true'
@ -94,23 +92,23 @@ class LibrarySync(Thread):
forced: always show popup, even if user setting to off
"""
if settings('dbSyncIndicator') != 'true':
if self.xbmcplayer.isPlaying():
# Don't show any dialog if media is playing
return
if window('dbSyncIndicator') != 'true':
if not forced:
return
if icon == "plex":
self.dialog.notification(
lang(29999),
message,
"special://home/addons/plugin.video.plexkodiconnect/icon.png",
5000,
False)
dialog('notification',
heading='{plex}',
message=message,
icon='{plex}',
sound=False)
elif icon == "error":
self.dialog.notification(
lang(29999),
message,
xbmcgui.NOTIFICATION_ERROR,
7000,
True)
dialog('notification',
heading='{plex}',
message=message,
type='{error}')
def syncPMStime(self):
"""
@ -298,11 +296,9 @@ class LibrarySync(Thread):
# Do the processing
for itemtype in process:
if self.thread_stopped():
xbmc.executebuiltin('InhibitIdleShutdown(false)')
setScreensaver(value=screensaver)
return False
if not process[itemtype]():
if (self.thread_stopped() or
self.thread_suspended() or
not process[itemtype]()):
xbmc.executebuiltin('InhibitIdleShutdown(false)')
setScreensaver(value=screensaver)
return False
@ -317,13 +313,13 @@ class LibrarySync(Thread):
setScreensaver(value=screensaver)
if window('plex_scancrashed') == 'true':
# Show warning if itemtypes.py crashed at some point
self.dialog.ok(lang(29999), lang(39408))
dialog('ok', heading='{plex}', line1=lang(39408))
window('plex_scancrashed', clear=True)
elif window('plex_scancrashed') == '401':
window('plex_scancrashed', clear=True)
if state.PMS_STATUS not in ('401', 'Auth'):
# Plex server had too much and returned ERROR
self.dialog.ok(lang(29999), lang(39409))
dialog('ok', heading='{plex}', line1=lang(39409))
# Path hack, so Kodis Information screen works
with kodidb.GetKodiDB('video') as kodi_db:
@ -477,7 +473,7 @@ class LibrarySync(Thread):
log.info('Detected new Music library - restarting now')
# 'New Plex music library detected. Sorry, but we need to
# restart Kodi now due to the changes made.'
dialog('ok', lang(29999), lang(39711))
dialog('ok', heading='{plex}', line1=lang(39711))
from xbmc import executebuiltin
executebuiltin('RestartApp')
return False
@ -740,11 +736,7 @@ class LibrarySync(Thread):
threads.append(thread)
# Start one thread to show sync progress ONLY for new PMS items
if self.new_items_only is True and window('dbSyncIndicator') == 'true':
dialog = xbmcgui.DialogProgressBG()
thread = sync_info.Threaded_Show_Sync_Info(
dialog,
itemNumber,
itemType)
thread = sync_info.Threaded_Show_Sync_Info(itemNumber, itemType)
thread.setDaemon(True)
thread.start()
threads.append(thread)
@ -803,7 +795,9 @@ class LibrarySync(Thread):
# PROCESS MOVIES #####
self.updatelist = []
for view in views:
if self.thread_stopped():
if self.installSyncDone is not True:
state.PATH_VERIFIED = False
if self.thread_stopped() or self.thread_suspended():
return False
# Get items per view
viewId = view['id']
@ -821,10 +815,9 @@ class LibrarySync(Thread):
viewName,
viewId)
self.GetAndProcessXMLs(itemType)
log.info("Processed view")
# Update viewstate for EVERY item
for view in views:
if self.thread_stopped():
if self.thread_stopped() or self.thread_suspended():
return False
self.PlexUpdateWatched(view['id'], itemType)
@ -896,7 +889,9 @@ class LibrarySync(Thread):
# PROCESS TV Shows #####
self.updatelist = []
for view in views:
if self.thread_stopped():
if self.installSyncDone is not True:
state.PATH_VERIFIED = False
if self.thread_stopped() or self.thread_suspended():
return False
# Get items per view
viewId = view['id']
@ -925,7 +920,7 @@ class LibrarySync(Thread):
# PROCESS TV Seasons #####
# Cycle through tv shows
for tvShowId in allPlexTvShowsId:
if self.thread_stopped():
if self.thread_stopped() or self.thread_suspended():
return False
# Grab all seasons to tvshow from PMS
seasons = GetAllPlexChildren(tvShowId)
@ -950,7 +945,7 @@ class LibrarySync(Thread):
# PROCESS TV Episodes #####
# Cycle through tv shows
for view in views:
if self.thread_stopped():
if self.thread_stopped() or self.thread_suspended():
return False
# Grab all episodes to tvshow from PMS
episodes = GetAllPlexLeaves(view['id'])
@ -985,7 +980,7 @@ class LibrarySync(Thread):
# Update viewstate:
for view in views:
if self.thread_stopped():
if self.thread_stopped() or self.thread_suspended():
return False
self.PlexUpdateWatched(view['id'], itemType)
@ -1022,7 +1017,7 @@ class LibrarySync(Thread):
for kind in (v.PLEX_TYPE_ARTIST,
v.PLEX_TYPE_ALBUM,
v.PLEX_TYPE_SONG):
if self.thread_stopped():
if self.thread_stopped() or self.thread_suspended():
return False
log.debug("Start processing music %s" % kind)
self.allKodiElementsId = {}
@ -1039,7 +1034,7 @@ class LibrarySync(Thread):
# Update viewstate for EVERY item
for view in views:
if self.thread_stopped():
if self.thread_stopped() or self.thread_suspended():
return False
self.PlexUpdateWatched(view['id'], itemType)
@ -1064,7 +1059,9 @@ class LibrarySync(Thread):
except ValueError:
pass
for view in views:
if self.thread_stopped():
if self.installSyncDone is not True:
state.PATH_VERIFIED = False
if self.thread_stopped() or self.thread_suspended():
return False
# Get items per view
itemsXML = GetPlexSectionResults(view['id'], args=urlArgs)
@ -1139,7 +1136,7 @@ class LibrarySync(Thread):
now = getUnixTimestamp()
deleteListe = []
for i, item in enumerate(self.itemsToProcess):
if self.thread_stopped():
if self.thread_stopped() or self.thread_suspended():
# Chances are that Kodi gets shut down
break
if item['state'] == 9:
@ -1404,7 +1401,7 @@ class LibrarySync(Thread):
import traceback
log.error("Traceback:\n%s" % traceback.format_exc())
# Library sync thread has crashed
self.dialog.ok(lang(29999), lang(39400))
dialog('ok', heading='{plex}', line1=lang(39400))
raise
def run_internal(self):
@ -1422,14 +1419,11 @@ class LibrarySync(Thread):
lastProcessing = 0
oneDay = 60*60*24
xbmcplayer = xbmc.Player()
# Link to Websocket queue
queue = self.mgr.ws.queue
startupComplete = False
self.views = []
errorcount = 0
log.info("---===### Starting LibrarySync ###===---")
@ -1459,13 +1453,15 @@ class LibrarySync(Thread):
log.warn("Db version out of date: %s minimum version "
"required: %s" % (currentVersion, minVersion))
# DB out of date. Proceed to recreate?
resp = self.dialog.yesno(heading=lang(29999),
line1=lang(39401))
resp = dialog('yesno',
heading=lang(29999),
line1=lang(39401))
if not resp:
log.warn("Db version out of date! USER IGNORED!")
# PKC may not work correctly until reset
self.dialog.ok(heading=lang(29999),
line1=(lang(29999) + lang(39402)))
dialog('ok',
heading='{plex}',
line1=lang(29999) + lang(39402))
else:
reset()
break
@ -1483,7 +1479,7 @@ class LibrarySync(Thread):
log.error('Current Kodi version: %s' % tryDecode(
xbmc.getInfoLabel('System.BuildVersion')))
# "Current Kodi version is unsupported, cancel lib sync"
self.dialog.ok(heading=lang(29999), line1=lang(39403))
dialog('ok', heading='{plex}', line1=lang(39403))
break
# Run start up sync
state.DB_SCAN = True
@ -1520,14 +1516,6 @@ class LibrarySync(Thread):
installSyncDone = True
else:
log.error("Initial start-up full sync unsuccessful")
errorcount += 1
if errorcount > 2:
log.error("Startup full sync failed. Stopping sync")
# "Startup syncing process failed repeatedly"
# "Please restart"
self.dialog.ok(heading=lang(29999),
line1=lang(39404))
break
# Currently no db scan, so we can start a new scan
elif state.DB_SCAN is False:
@ -1544,7 +1532,7 @@ class LibrarySync(Thread):
window('plex_dbScan', clear=True)
state.DB_SCAN = False
# Full library sync finished
self.showKodiNote(lang(39407), forced=False)
self.showKodiNote(lang(39407), forced=True)
# Reset views was requested from somewhere else
elif window('plex_runLibScan') == "views":
log.info('Refresh playlist and nodes requested, starting')
@ -1575,8 +1563,9 @@ class LibrarySync(Thread):
window('plex_runLibScan', clear=True)
# Only look for missing fanart (No)
# or refresh all fanart (Yes)
self.fanartSync(refresh=self.dialog.yesno(
heading=lang(29999),
self.fanartSync(refresh=dialog(
'yesno',
heading='{plex}',
line1=lang(39223),
nolabel=lang(39224),
yeslabel=lang(39225)))
@ -1591,7 +1580,7 @@ class LibrarySync(Thread):
else:
now = getUnixTimestamp()
if (now - lastSync > fullSyncInterval and
not xbmcplayer.isPlaying()):
not self.xbmcplayer.isPlaying()):
lastSync = now
log.info('Doing scheduled full library scan')
state.DB_SCAN = True

View file

@ -10,6 +10,8 @@ STOP_PKC = False
SUSPEND_LIBRARY_THREAD = False
# Set if user decided to cancel sync
STOP_SYNC = False
# Could we access the paths?
PATH_VERIFIED = False
# Set if a Plex-Kodi DB sync is being done - along with
# window('plex_dbScan') set to 'true'
DB_SCAN = False

View file

@ -140,6 +140,15 @@ def dialog(typus, *args, **kwargs):
Displays xbmcgui Dialog. Pass a string as typus:
'yesno', 'ok', 'notification', 'input', 'select', 'numeric'
kwargs:
heading='{plex}' title bar (here PlexKodiConnect)
message=lang(30128), Actual dialog content. Don't use with OK
line1=str(), For 'OK' and 'yesno' dialogs use line1...line3!
time=5000,
sound=True,
nolabel=str(), For 'yesno' dialogs
yeslabel=str(), For 'yesno' dialogs
Icons:
icon='{plex}' Display Plex standard icon
icon='{info}' xbmcgui.NOTIFICATION_INFO

View file

@ -30,8 +30,7 @@ sys_path.append(_base_resource)
###############################################################################
from utils import settings, window, language as lang, dialog, tryEncode, \
tryDecode
from utils import settings, window, language as lang, dialog, tryDecode
from userclient import UserClient
import initialsetup
from kodimonitor import KodiMonitor