This commit is contained in:
croneter 2018-02-11 13:24:00 +01:00
parent ca8ad96a05
commit ca11528593
6 changed files with 82 additions and 58 deletions

View file

@ -12,7 +12,7 @@ from xbmc import sleep, executebuiltin, translatePath
from xbmcgui import ListItem from xbmcgui import ListItem
from utils import window, settings, language as lang, dialog, try_encode, \ from utils import window, settings, language as lang, dialog, try_encode, \
CatchExceptions, exists_dir, plex_command, try_decode catch_exceptions, exists_dir, plex_command, try_decode
import downloadutils import downloadutils
from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \ from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \
@ -473,7 +473,7 @@ def getVideoFiles(plexId, params):
xbmcplugin.endOfDirectory(HANDLE) xbmcplugin.endOfDirectory(HANDLE)
@CatchExceptions(warnuser=False) @catch_exceptions(warnuser=False)
def getExtraFanArt(plexid, plexPath): def getExtraFanArt(plexid, plexPath):
""" """
Get extrafanart for listitem Get extrafanart for listitem

View file

@ -6,7 +6,7 @@ from ntpath import dirname
from datetime import datetime from datetime import datetime
from artwork import Artwork from artwork import Artwork
from utils import window, kodi_sql, CatchExceptions from utils import window, kodi_sql, catch_exceptions
import plexdb_functions as plexdb import plexdb_functions as plexdb
import kodidb_functions as kodidb import kodidb_functions as kodidb
@ -61,7 +61,7 @@ class Items(object):
self.kodiconn.close() self.kodiconn.close()
return self return self
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def getfanart(self, plex_id, refresh=False): def getfanart(self, plex_id, refresh=False):
""" """
Tries to get additional fanart for movies (+sets) and TV shows. Tries to get additional fanart for movies (+sets) and TV shows.
@ -177,7 +177,7 @@ class Movies(Items):
""" """
Used for plex library-type movies Used for plex library-type movies
""" """
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def add_update(self, item, viewtag=None, viewid=None): def add_update(self, item, viewtag=None, viewid=None):
""" """
Process single movie Process single movie
@ -509,7 +509,7 @@ class TVShows(Items):
""" """
For Plex library-type TV shows For Plex library-type TV shows
""" """
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def add_update(self, item, viewtag=None, viewid=None): def add_update(self, item, viewtag=None, viewid=None):
""" """
Process a single show Process a single show
@ -742,7 +742,7 @@ class TVShows(Items):
tags.extend(collections) tags.extend(collections)
self.kodi_db.addTags(showid, tags, "tvshow") self.kodi_db.addTags(showid, tags, "tvshow")
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def add_updateSeason(self, item, viewtag=None, viewid=None): def add_updateSeason(self, item, viewtag=None, viewid=None):
""" """
Process a single season of a certain tv show Process a single season of a certain tv show
@ -790,7 +790,7 @@ class TVShows(Items):
view_id=viewid, view_id=viewid,
checksum=checksum) checksum=checksum)
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def add_updateEpisode(self, item, viewtag=None, viewid=None): def add_updateEpisode(self, item, viewtag=None, viewid=None):
""" """
Process single episode Process single episode
@ -1282,7 +1282,7 @@ class Music(Items):
self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor) self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
return self return self
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def add_updateArtist(self, item, viewtag=None, viewid=None): def add_updateArtist(self, item, viewtag=None, viewid=None):
""" """
Adds a single artist Adds a single artist
@ -1368,7 +1368,7 @@ class Music(Items):
# Update artwork # Update artwork
artwork.addArtwork(artworks, artistid, v.KODI_TYPE_ARTIST, kodicursor) artwork.addArtwork(artworks, artistid, v.KODI_TYPE_ARTIST, kodicursor)
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def add_updateAlbum(self, item, viewtag=None, viewid=None, children=None, def add_updateAlbum(self, item, viewtag=None, viewid=None, children=None,
scan_children=True): scan_children=True):
""" """
@ -1565,7 +1565,7 @@ class Music(Items):
for child in children: for child in children:
self.add_updateSong(child, viewtag, viewid) self.add_updateSong(child, viewtag, viewid)
@CatchExceptions(warnuser=True) @catch_exceptions(warnuser=True)
def add_updateSong(self, item, viewtag=None, viewid=None): def add_updateSong(self, item, viewtag=None, viewid=None):
""" """
Process single song Process single song

View file

@ -9,7 +9,7 @@ import xbmc
from xbmcvfs import exists from xbmcvfs import exists
from utils import window, settings, unix_timestamp, thread_methods, \ from utils import window, settings, unix_timestamp, thread_methods, \
create_actor_db_index, dialog, LogTime, playlist_xsp, language as lang, \ create_actor_db_index, dialog, log_time, playlist_xsp, language as lang, \
unix_date_to_kodi, reset, try_decode, delete_playlists, delete_nodes, \ unix_date_to_kodi, reset, try_decode, delete_playlists, delete_nodes, \
try_encode, compare_version try_encode, compare_version
import downloadutils import downloadutils
@ -218,7 +218,7 @@ class LibrarySync(Thread):
# Create an index for actors to speed up sync # Create an index for actors to speed up sync
create_actor_db_index() create_actor_db_index()
@LogTime @log_time
def fullSync(self, repair=False): def fullSync(self, repair=False):
""" """
repair=True: force sync EVERY item repair=True: force sync EVERY item
@ -727,7 +727,7 @@ class LibrarySync(Thread):
}) })
self.updatelist = [] self.updatelist = []
@LogTime @log_time
def PlexMovies(self): def PlexMovies(self):
# Initialize # Initialize
self.allPlexElementsId = {} self.allPlexElementsId = {}
@ -819,7 +819,7 @@ class LibrarySync(Thread):
with itemMth() as method: with itemMth() as method:
method.updateUserdata(xml) method.updateUserdata(xml)
@LogTime @log_time
def PlexTVShows(self): def PlexTVShows(self):
# Initialize # Initialize
self.allPlexElementsId = {} self.allPlexElementsId = {}
@ -949,7 +949,7 @@ class LibrarySync(Thread):
log.info("%s sync is finished." % itemType) log.info("%s sync is finished." % itemType)
return True return True
@LogTime @log_time
def PlexMusic(self): def PlexMusic(self):
itemType = 'Music' itemType = 'Music'

View file

@ -6,7 +6,7 @@ from logging import getLogger
from threading import Thread, RLock from threading import Thread, RLock
from downloadutils import DownloadUtils as DU from downloadutils import DownloadUtils as DU
from utils import window, kodi_time_to_millis, Lock_Function from utils import window, kodi_time_to_millis, LockFunction
import state import state
import variables as v import variables as v
import json_rpc as js import json_rpc as js
@ -17,7 +17,7 @@ import playqueue as PQ
LOG = getLogger("PLEX." + __name__) LOG = getLogger("PLEX." + __name__)
# Need to lock all methods and functions messing with subscribers or state # Need to lock all methods and functions messing with subscribers or state
LOCK = RLock() LOCK = RLock()
LOCKER = Lock_Function(LOCK) LOCKER = LockFunction(LOCK)
############################################################################### ###############################################################################

View file

@ -242,20 +242,20 @@ def kodi_time_to_millis(time):
return ret return ret
def try_encode(uniString, encoding='utf-8'): def try_encode(input_str, encoding='utf-8'):
""" """
Will try to encode uniString (in unicode) to encoding. This possibly Will try to encode input_str (in unicode) to encoding. This possibly
fails with e.g. Android TV's Python, which does not accept arguments for fails with e.g. Android TV's Python, which does not accept arguments for
string.encode() string.encode()
""" """
if isinstance(uniString, str): if isinstance(input_str, str):
# already encoded # already encoded
return uniString return input_str
try: try:
uniString = uniString.encode(encoding, "ignore") input_str = input_str.encode(encoding, "ignore")
except TypeError: except TypeError:
uniString = uniString.encode() input_str = input_str.encode()
return uniString return input_str
def try_decode(string, encoding='utf-8'): def try_decode(string, encoding='utf-8'):
@ -878,10 +878,7 @@ def passwords_xml():
settings('networkCreds', value="%s" % server) settings('networkCreds', value="%s" % server)
LOG.info("Added server: %s to passwords.xml", server) LOG.info("Added server: %s to passwords.xml", server)
# Prettify and write to file # Prettify and write to file
try: indent(root)
indent(root)
except:
pass
etree.ElementTree(root).write(xmlpath, encoding="UTF-8") etree.ElementTree(root).write(xmlpath, encoding="UTF-8")
@ -957,7 +954,7 @@ def delete_nodes():
############################################################################### ###############################################################################
# WRAPPERS # WRAPPERS
def CatchExceptions(warnuser=False): def catch_exceptions(warnuser=False):
""" """
Decorator for methods to catch exceptions and log them. Useful for e.g. Decorator for methods to catch exceptions and log them. Useful for e.g.
librarysync threads using itemtypes.py, because otherwise we would not librarysync threads using itemtypes.py, because otherwise we would not
@ -967,12 +964,18 @@ def CatchExceptions(warnuser=False):
which will trigger a Kodi infobox to inform user which will trigger a Kodi infobox to inform user
""" """
def decorate(func): def decorate(func):
"""
Decorator construct
"""
@wraps(func) @wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
"""
Wrapper construct
"""
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except Exception as e: except Exception as err:
LOG.error('%s has crashed. Error: %s', func.__name__, e) LOG.error('%s has crashed. Error: %s', func.__name__, err)
import traceback import traceback
LOG.error("Traceback:\n%s", traceback.format_exc()) LOG.error("Traceback:\n%s", traceback.format_exc())
if warnuser: if warnuser:
@ -982,7 +985,7 @@ def CatchExceptions(warnuser=False):
return decorate return decorate
def LogTime(func): def log_time(func):
""" """
Decorator for functions and methods to log the time it took to run the code Decorator for functions and methods to log the time it took to run the code
""" """
@ -1010,10 +1013,10 @@ def thread_methods(cls=None, add_stops=None, add_suspends=None):
ALSO returns True if PKC should exit ALSO returns True if PKC should exit
Also adds the following class attributes: Also adds the following class attributes:
__thread_stopped thread_stopped
__thread_suspended thread_suspended
__stops stops
__suspends suspends
invoke with either invoke with either
@Newthread_methods @Newthread_methods
@ -1030,41 +1033,56 @@ def thread_methods(cls=None, add_stops=None, add_suspends=None):
add_suspends=add_suspends) add_suspends=add_suspends)
# Because we need a reference, not a copy of the immutable objects in # Because we need a reference, not a copy of the immutable objects in
# state, we need to look up state every time explicitly # state, we need to look up state every time explicitly
cls.__stops = ['STOP_PKC'] cls.stops = ['STOP_PKC']
if add_stops is not None: if add_stops is not None:
cls.__stops.extend(add_stops) cls.stops.extend(add_stops)
cls.__suspends = add_suspends or [] cls.suspends = add_suspends or []
# Attach new attributes to class # Attach new attributes to class
cls.__thread_stopped = False cls.thread_stopped = False
cls.__thread_suspended = False cls.thread_suspended = False
# Define new class methods and attach them to class # Define new class methods and attach them to class
def stop_thread(self): def stop_thread(self):
self.__thread_stopped = True """
Call to stop this thread
"""
self.thread_stopped = True
cls.stop_thread = stop_thread cls.stop_thread = stop_thread
def suspend_thread(self): def suspend_thread(self):
self.__thread_suspended = True """
Call to suspend this thread
"""
self.thread_suspended = True
cls.suspend_thread = suspend_thread cls.suspend_thread = suspend_thread
def resume_thread(self): def resume_thread(self):
self.__thread_suspended = False """
Call to revive a suspended thread back to life
"""
self.thread_suspended = False
cls.resume_thread = resume_thread cls.resume_thread = resume_thread
def thread_suspended(self): def thread_suspended(self):
if self.__thread_suspended is True: """
Returns True if the thread is suspended
"""
if self.thread_suspended is True:
return True return True
for suspend in self.__suspends: for suspend in self.suspends:
if getattr(state, suspend): if getattr(state, suspend):
return True return True
return False return False
cls.thread_suspended = thread_suspended cls.thread_suspended = thread_suspended
def thread_stopped(self): def thread_stopped(self):
if self.__thread_stopped is True: """
Returns True if the thread is stopped
"""
if self.thread_stopped is True:
return True return True
for stop in self.__stops: for stop in self.stops:
if getattr(state, stop): if getattr(state, stop):
return True return True
return False return False
@ -1074,12 +1092,12 @@ def thread_methods(cls=None, add_stops=None, add_suspends=None):
return cls return cls
class Lock_Function(object): class LockFunction(object):
""" """
Decorator for class methods and functions to lock them with lock. Decorator for class methods and functions to lock them with lock.
Initialize this class first Initialize this class first
lockfunction = Lock_Function(lock), where lock is a threading.Lock() object lockfunction = LockFunction(lock), where lock is a threading.Lock() object
To then lock a function or method: To then lock a function or method:
@ -1090,8 +1108,14 @@ class Lock_Function(object):
self.lock = lock self.lock = lock
def lockthis(self, func): def lockthis(self, func):
"""
Use this method to actually lock a function or method
"""
@wraps(func) @wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
"""
Wrapper construct
"""
with self.lock: with self.lock:
result = func(*args, **kwargs) result = func(*args, **kwargs)
return result return result

View file

@ -213,8 +213,8 @@ class Alexa_Websocket(WebSocket):
Can't use thread_methods! Can't use thread_methods!
""" """
__thread_stopped = False thread_stopped = False
__thread_suspended = False thread_suspended = False
def getUri(self): def getUri(self):
uri = ('wss://pubsub.plex.tv/sub/websockets/%s/%s?X-Plex-Token=%s' uri = ('wss://pubsub.plex.tv/sub/websockets/%s/%s?X-Plex-Token=%s'
@ -256,16 +256,16 @@ class Alexa_Websocket(WebSocket):
# Path in thread_methods # Path in thread_methods
def stop_thread(self): def stop_thread(self):
self.__thread_stopped = True self.thread_stopped = True
def suspend_thread(self): def suspend_thread(self):
self.__thread_suspended = True self.thread_suspended = True
def resume_thread(self): def resume_thread(self):
self.__thread_suspended = False self.thread_suspended = False
def thread_stopped(self): def thread_stopped(self):
if self.__thread_stopped is True: if self.thread_stopped is True:
return True return True
if state.STOP_PKC: if state.STOP_PKC:
return True return True
@ -276,7 +276,7 @@ class Alexa_Websocket(WebSocket):
""" """
Overwrite method since we need to check for plex token Overwrite method since we need to check for plex token
""" """
if self.__thread_suspended is True: if self.thread_suspended is True:
return True return True
if not state.PLEX_TOKEN: if not state.PLEX_TOKEN:
return True return True