This commit is contained in:
croneter 2018-02-11 12:59:04 +01:00
parent 406c2b9f63
commit ca8ad96a05
19 changed files with 301 additions and 362 deletions

View file

@ -32,7 +32,7 @@ sys_path.append(_base_resource)
############################################################################### ###############################################################################
import entrypoint import entrypoint
from utils import window, reset, passwordsXML, language as lang, dialog, \ from utils import window, reset, passwords_xml, language as lang, dialog, \
plex_command plex_command
from pickler import unpickle_me, pickl_window from pickler import unpickle_me, pickl_window
from PKC_listitem import convert_PKC_to_listitem from PKC_listitem import convert_PKC_to_listitem
@ -115,7 +115,7 @@ class Main():
entrypoint.resetAuth() entrypoint.resetAuth()
elif mode == 'passwords': elif mode == 'passwords':
passwordsXML() passwords_xml()
elif mode == 'switchuser': elif mode == 'switchuser':
entrypoint.switchPlexUser() entrypoint.switchPlexUser()

View file

@ -40,8 +40,8 @@ from xbmcvfs import exists
import clientinfo as client import clientinfo as client
from downloadutils import DownloadUtils as DU from downloadutils import DownloadUtils as DU
from utils import window, settings, language as lang, tryDecode, tryEncode, \ from utils import window, settings, language as lang, try_decode, try_encode, \
DateToKodi, exists_dir, slugify, dialog unix_date_to_kodi, exists_dir, slugify, dialog
import PlexFunctions as PF import PlexFunctions as PF
import plexdb_functions as plexdb import plexdb_functions as plexdb
import variables as v import variables as v
@ -139,7 +139,7 @@ class API():
ans = None ans = None
if ans is not None: if ans is not None:
try: try:
ans = tryDecode(unquote(ans)) ans = try_decode(unquote(ans))
except UnicodeDecodeError: except UnicodeDecodeError:
# Sometimes, Plex seems to have encoded in latin1 # Sometimes, Plex seems to have encoded in latin1
ans = unquote(ans).decode('latin1') ans = unquote(ans).decode('latin1')
@ -167,7 +167,7 @@ class API():
self.item[0][0].attrib['key'])) self.item[0][0].attrib['key']))
# Attach Plex id to url to let it be picked up by our playqueue agent # Attach Plex id to url to let it be picked up by our playqueue agent
# later # later
return tryEncode('%s&plex_id=%s' % (path, self.getRatingKey())) return try_encode('%s&plex_id=%s' % (path, self.getRatingKey()))
def getTVShowPath(self): def getTVShowPath(self):
""" """
@ -194,7 +194,7 @@ class API():
""" """
res = self.item.attrib.get('addedAt') res = self.item.attrib.get('addedAt')
if res is not None: if res is not None:
res = DateToKodi(res) res = unix_date_to_kodi(res)
else: else:
res = '2000-01-01 10:00:00' res = '2000-01-01 10:00:00'
return res return res
@ -231,7 +231,7 @@ class API():
played = True if playcount else False played = True if playcount else False
try: try:
lastPlayedDate = DateToKodi(int(item['lastViewedAt'])) lastPlayedDate = unix_date_to_kodi(int(item['lastViewedAt']))
except (KeyError, ValueError): except (KeyError, ValueError):
lastPlayedDate = None lastPlayedDate = None
@ -884,7 +884,7 @@ class API():
parameters = { parameters = {
'api_key': apiKey, 'api_key': apiKey,
'language': v.KODILANGUAGE, 'language': v.KODILANGUAGE,
'query': tryEncode(title) 'query': try_encode(title)
} }
data = DU().downloadUrl(url, data = DU().downloadUrl(url,
authenticate=False, authenticate=False,
@ -1196,12 +1196,12 @@ class API():
languages.append(stream.attrib['language']) languages.append(stream.attrib['language'])
languages = ', '.join(languages) languages = ', '.join(languages)
if filename: if filename:
option = tryEncode(filename) option = try_encode(filename)
if languages: if languages:
if option: if option:
option = '%s (%s): ' % (option, tryEncode(languages)) option = '%s (%s): ' % (option, try_encode(languages))
else: else:
option = '%s: ' % tryEncode(languages) option = '%s: ' % try_encode(languages)
if 'videoResolution' in entry.attrib: if 'videoResolution' in entry.attrib:
option = '%s%sp ' % (option, option = '%s%sp ' % (option,
entry.attrib.get('videoResolution')) entry.attrib.get('videoResolution'))
@ -1544,7 +1544,7 @@ class API():
# exist() needs a / or \ at the end to work for directories # exist() needs a / or \ at the end to work for directories
if folder is False: if folder is False:
# files # files
check = exists(tryEncode(path)) check = exists(try_encode(path))
else: else:
# directories # directories
if "\\" in path: if "\\" in path:
@ -1640,7 +1640,7 @@ class API():
plexitem = "plex_%s" % playurl plexitem = "plex_%s" % playurl
window('%s.runtime' % plexitem, value=str(userdata['Runtime'])) window('%s.runtime' % plexitem, value=str(userdata['Runtime']))
window('%s.type' % plexitem, value=itemtype) window('%s.type' % plexitem, value=itemtype)
state.PLEX_IDS[tryDecode(playurl)] = self.getRatingKey() state.PLEX_IDS[try_decode(playurl)] = self.getRatingKey()
# window('%s.itemid' % plexitem, value=self.getRatingKey()) # window('%s.itemid' % plexitem, value=self.getRatingKey())
window('%s.playcount' % plexitem, value=str(userdata['PlayCount'])) window('%s.playcount' % plexitem, value=str(userdata['PlayCount']))

View file

@ -11,7 +11,7 @@ from threading import Thread
from xbmc import sleep from xbmc import sleep
from downloadutils import DownloadUtils as DU from downloadutils import DownloadUtils as DU
from utils import settings, tryEncode, tryDecode from utils import settings, try_encode, try_decode
from variables import PLEX_TO_KODI_TIMEFACTOR from variables import PLEX_TO_KODI_TIMEFACTOR
import plex_tv import plex_tv
@ -306,11 +306,11 @@ def _plex_gdm():
} }
for line in response['data'].split('\n'): for line in response['data'].split('\n'):
if 'Content-Type:' in line: if 'Content-Type:' in line:
pms['product'] = tryDecode(line.split(':')[1].strip()) pms['product'] = try_decode(line.split(':')[1].strip())
elif 'Host:' in line: elif 'Host:' in line:
pms['baseURL'] = line.split(':')[1].strip() pms['baseURL'] = line.split(':')[1].strip()
elif 'Name:' in line: elif 'Name:' in line:
pms['name'] = tryDecode(line.split(':')[1].strip()) pms['name'] = try_decode(line.split(':')[1].strip())
elif 'Port:' in line: elif 'Port:' in line:
pms['port'] = line.split(':')[1].strip() pms['port'] = line.split(':')[1].strip()
elif 'Resource-Identifier:' in line: elif 'Resource-Identifier:' in line:
@ -820,7 +820,7 @@ def transcode_image_path(key, AuthToken, path, width, height):
path = 'http://127.0.0.1:32400' + key path = 'http://127.0.0.1:32400' + key
else: # internal path, add-on else: # internal path, add-on
path = 'http://127.0.0.1:32400' + path + '/' + key path = 'http://127.0.0.1:32400' + path + '/' + key
path = tryEncode(path) path = try_encode(path)
# This is bogus (note the extra path component) but ATV is stupid when it # This is bogus (note the extra path component) but ATV is stupid when it
# comes to caching images, it doesn't use querystrings. Fortunately PMS is # comes to caching images, it doesn't use querystrings. Fortunately PMS is
# lenient... # lenient...

View file

@ -12,8 +12,8 @@ import requests
from xbmc import sleep, translatePath from xbmc import sleep, translatePath
from xbmcvfs import exists from xbmcvfs import exists
from utils import window, settings, language as lang, kodiSQL, tryEncode, \ from utils import window, settings, language as lang, kodi_sql, try_encode, \
thread_methods, dialog, exists_dir, tryDecode thread_methods, dialog, exists_dir, try_decode
import state import state
# Disable annoying requests warnings # Disable annoying requests warnings
@ -134,13 +134,13 @@ class Artwork():
if dialog('yesno', "Image Texture Cache", lang(39251)): if dialog('yesno', "Image Texture Cache", lang(39251)):
LOG.info("Resetting all cache data first") LOG.info("Resetting all cache data first")
# Remove all existing textures first # Remove all existing textures first
path = tryDecode(translatePath("special://thumbnails/")) path = try_decode(translatePath("special://thumbnails/"))
if exists_dir(path): if exists_dir(path):
rmtree(path, ignore_errors=True) rmtree(path, ignore_errors=True)
self.restoreCacheDirectories() self.restoreCacheDirectories()
# remove all existing data from texture DB # remove all existing data from texture DB
connection = kodiSQL('texture') connection = kodi_sql('texture')
cursor = connection.cursor() cursor = connection.cursor()
query = 'SELECT tbl_name FROM sqlite_master WHERE type=?' query = 'SELECT tbl_name FROM sqlite_master WHERE type=?'
cursor.execute(query, ('table', )) cursor.execute(query, ('table', ))
@ -153,7 +153,7 @@ class Artwork():
connection.close() connection.close()
# Cache all entries in video DB # Cache all entries in video DB
connection = kodiSQL('video') connection = kodi_sql('video')
cursor = connection.cursor() cursor = connection.cursor()
# dont include actors # dont include actors
query = "SELECT url FROM art WHERE media_type != ?" query = "SELECT url FROM art WHERE media_type != ?"
@ -166,7 +166,7 @@ class Artwork():
for url in result: for url in result:
self.cacheTexture(url[0]) self.cacheTexture(url[0])
# Cache all entries in music DB # Cache all entries in music DB
connection = kodiSQL('music') connection = kodi_sql('music')
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute("SELECT url FROM art") cursor.execute("SELECT url FROM art")
result = cursor.fetchall() result = cursor.fetchall()
@ -179,7 +179,7 @@ class Artwork():
def cacheTexture(self, url): def cacheTexture(self, url):
# Cache a single image url to the texture cache # Cache a single image url to the texture cache
if url and self.enableTextureCache: if url and self.enableTextureCache:
self.queue.put(double_urlencode(tryEncode(url))) self.queue.put(double_urlencode(try_encode(url)))
def addArtwork(self, artwork, kodiId, mediaType, cursor): def addArtwork(self, artwork, kodiId, mediaType, cursor):
# Kodi conversion table # Kodi conversion table
@ -323,7 +323,7 @@ class Artwork():
def deleteCachedArtwork(self, url): def deleteCachedArtwork(self, url):
# Only necessary to remove and apply a new backdrop or poster # Only necessary to remove and apply a new backdrop or poster
connection = kodiSQL('texture') connection = kodi_sql('texture')
cursor = connection.cursor() cursor = connection.cursor()
try: try:
cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", cursor.execute("SELECT cachedurl FROM texture WHERE url = ?",
@ -336,7 +336,7 @@ class Artwork():
path = translatePath("special://thumbnails/%s" % cachedurl) path = translatePath("special://thumbnails/%s" % cachedurl)
LOG.debug("Deleting cached thumbnail: %s" % path) LOG.debug("Deleting cached thumbnail: %s" % path)
if exists(path): if exists(path):
rmtree(tryDecode(path), ignore_errors=True) rmtree(try_decode(path), ignore_errors=True)
cursor.execute("DELETE FROM texture WHERE url = ?", (url,)) cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
connection.commit() connection.commit()
finally: finally:
@ -347,4 +347,4 @@ class Artwork():
LOG.info("Restoring cache directories...") LOG.info("Restoring cache directories...")
paths = ("","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","Video","plex") paths = ("","0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","Video","plex")
for p in paths: for p in paths:
makedirs(tryDecode(translatePath("special://thumbnails/%s" % p))) makedirs(try_decode(translatePath("special://thumbnails/%s" % p)))

View file

@ -11,8 +11,8 @@ import xbmcplugin
from xbmc import sleep, executebuiltin, translatePath from xbmc import sleep, executebuiltin, translatePath
from xbmcgui import ListItem from xbmcgui import ListItem
from utils import window, settings, language as lang, dialog, tryEncode, \ from utils import window, settings, language as lang, dialog, try_encode, \
CatchExceptions, exists_dir, plex_command, tryDecode CatchExceptions, exists_dir, plex_command, try_decode
import downloadutils import downloadutils
from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \ from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \
@ -53,11 +53,11 @@ def chooseServer():
if not __LogOut(): if not __LogOut():
return return
from utils import deletePlaylists, deleteNodes from utils import delete_playlists, delete_nodes
# First remove playlists # First remove playlists
deletePlaylists() delete_playlists()
# Remove video nodes # Remove video nodes
deleteNodes() delete_nodes()
# Log in again # Log in again
__LogIn() __LogIn()
@ -175,10 +175,10 @@ def switchPlexUser():
return return
# First remove playlists of old user # First remove playlists of old user
from utils import deletePlaylists, deleteNodes from utils import delete_playlists, delete_nodes
deletePlaylists() delete_playlists()
# Remove video nodes # Remove video nodes
deleteNodes() delete_nodes()
__LogIn() __LogIn()
@ -455,14 +455,14 @@ def getVideoFiles(plexId, params):
if exists_dir(path): if exists_dir(path):
for root, dirs, files in walk(path): for root, dirs, files in walk(path):
for directory in dirs: for directory in dirs:
item_path = tryEncode(join(root, directory)) item_path = try_encode(join(root, directory))
li = ListItem(item_path, path=item_path) li = ListItem(item_path, path=item_path)
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,
url=item_path, url=item_path,
listitem=li, listitem=li,
isFolder=True) isFolder=True)
for file in files: for file in files:
item_path = tryEncode(join(root, file)) item_path = try_encode(join(root, file))
li = ListItem(item_path, path=item_path) li = ListItem(item_path, path=item_path)
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,
url=file, url=file,
@ -490,7 +490,7 @@ def getExtraFanArt(plexid, plexPath):
# We need to store the images locally for this to work # We need to store the images locally for this to work
# because of the caching system in xbmc # because of the caching system in xbmc
fanartDir = tryDecode(translatePath( fanartDir = try_decode(translatePath(
"special://thumbnails/plex/%s/" % plexid)) "special://thumbnails/plex/%s/" % plexid))
if not exists_dir(fanartDir): if not exists_dir(fanartDir):
# Download the images to the cache directory # Download the images to the cache directory
@ -504,19 +504,19 @@ def getExtraFanArt(plexid, plexPath):
backdrops = api.getAllArtwork()['Backdrop'] backdrops = api.getAllArtwork()['Backdrop']
for count, backdrop in enumerate(backdrops): for count, backdrop in enumerate(backdrops):
# Same ordering as in artwork # Same ordering as in artwork
fanartFile = tryEncode(join(fanartDir, "fanart%.3d.jpg" % count)) fanartFile = try_encode(join(fanartDir, "fanart%.3d.jpg" % count))
li = ListItem("%.3d" % count, path=fanartFile) li = ListItem("%.3d" % count, path=fanartFile)
xbmcplugin.addDirectoryItem( xbmcplugin.addDirectoryItem(
handle=HANDLE, handle=HANDLE,
url=fanartFile, url=fanartFile,
listitem=li) listitem=li)
copyfile(backdrop, tryDecode(fanartFile)) copyfile(backdrop, try_decode(fanartFile))
else: else:
log.info("Found cached backdrop.") log.info("Found cached backdrop.")
# Use existing cached images # Use existing cached images
for root, dirs, files in walk(fanartDir): for root, dirs, files in walk(fanartDir):
for file in files: for file in files:
fanartFile = tryEncode(join(root, file)) fanartFile = try_encode(join(root, file))
li = ListItem(file, path=fanartFile) li = ListItem(file, path=fanartFile)
xbmcplugin.addDirectoryItem(handle=HANDLE, xbmcplugin.addDirectoryItem(handle=HANDLE,
url=fanartFile, url=fanartFile,

View file

@ -6,7 +6,7 @@ import xml.etree.ElementTree as etree
from xbmc import executebuiltin, translatePath from xbmc import executebuiltin, translatePath
from utils import settings, window, language as lang, tryEncode, tryDecode, \ from utils import settings, window, language as lang, try_encode, try_decode, \
XmlKodiSetting, reboot_kodi, dialog XmlKodiSetting, reboot_kodi, dialog
from migration import check_migration from migration import check_migration
from downloadutils import DownloadUtils as DU from downloadutils import DownloadUtils as DU
@ -76,7 +76,7 @@ def reload_pkc():
set_webserver() set_webserver()
# To detect Kodi profile switches # To detect Kodi profile switches
window('plex_kodiProfile', window('plex_kodiProfile',
value=tryDecode(translatePath("special://profile"))) value=try_decode(translatePath("special://profile")))
getDeviceId() getDeviceId()
# Initialize the PKC playqueues # Initialize the PKC playqueues
PQ.init_playqueues() PQ.init_playqueues()
@ -355,7 +355,7 @@ class InitialSetup(object):
dialog('ok', dialog('ok',
lang(29999), lang(29999),
'%s %s' % (lang(39214), '%s %s' % (lang(39214),
tryEncode(server['name']))) try_encode(server['name'])))
return return
else: else:
return return
@ -610,8 +610,8 @@ class InitialSetup(object):
line1=lang(39029), line1=lang(39029),
line2=lang(39030)): line2=lang(39030)):
LOG.debug("Presenting network credentials dialog.") LOG.debug("Presenting network credentials dialog.")
from utils import passwordsXML from utils import passwords_xml
passwordsXML() passwords_xml()
# Disable Plex music? # Disable Plex music?
if dialog('yesno', heading=lang(29999), line1=lang(39016)): if dialog('yesno', heading=lang(29999), line1=lang(39016)):
LOG.debug("User opted to disable Plex music library.") LOG.debug("User opted to disable Plex music library.")

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, kodiSQL, CatchExceptions from utils import window, kodi_sql, CatchExceptions
import plexdb_functions as plexdb import plexdb_functions as plexdb
import kodidb_functions as kodidb import kodidb_functions as kodidb
@ -43,9 +43,9 @@ class Items(object):
""" """
Open DB connections and cursors Open DB connections and cursors
""" """
self.plexconn = kodiSQL('plex') self.plexconn = kodi_sql('plex')
self.plexcursor = self.plexconn.cursor() self.plexcursor = self.plexconn.cursor()
self.kodiconn = kodiSQL('video') self.kodiconn = kodi_sql('video')
self.kodicursor = self.kodiconn.cursor() self.kodicursor = self.kodiconn.cursor()
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor) self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor) self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
@ -1273,10 +1273,10 @@ class Music(Items):
OVERWRITE this method, because we need to open another DB. OVERWRITE this method, because we need to open another DB.
Open DB connections and cursors Open DB connections and cursors
""" """
self.plexconn = kodiSQL('plex') self.plexconn = kodi_sql('plex')
self.plexcursor = self.plexconn.cursor() self.plexcursor = self.plexconn.cursor()
# Here it is, not 'video' but 'music' # Here it is, not 'video' but 'music'
self.kodiconn = kodiSQL('music') self.kodiconn = kodi_sql('music')
self.kodicursor = self.kodiconn.cursor() self.kodicursor = self.kodiconn.cursor()
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor) self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor) self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)

View file

@ -5,7 +5,7 @@ from logging import getLogger
from ntpath import dirname from ntpath import dirname
import artwork import artwork
from utils import kodiSQL from utils import kodi_sql
import variables as v import variables as v
############################################################################### ###############################################################################
@ -30,7 +30,7 @@ class GetKodiDB():
self.db_type = db_type self.db_type = db_type
def __enter__(self): def __enter__(self):
self.kodiconn = kodiSQL(self.db_type) self.kodiconn = kodi_sql(self.db_type)
kodi_db = Kodidb_Functions(self.kodiconn.cursor()) kodi_db = Kodidb_Functions(self.kodiconn.cursor())
return kodi_db return kodi_db

View file

@ -8,10 +8,10 @@ from random import shuffle
import xbmc import xbmc
from xbmcvfs import exists from xbmcvfs import exists
from utils import window, settings, getUnixTimestamp, \ from utils import window, settings, unix_timestamp, thread_methods, \
thread_methods, create_actor_db_index, dialog, LogTime, playlistXSP,\ create_actor_db_index, dialog, LogTime, playlist_xsp, language as lang, \
language as lang, DateToKodi, reset, tryDecode, deletePlaylists, \ unix_date_to_kodi, reset, try_decode, delete_playlists, delete_nodes, \
deleteNodes, tryEncode, compare_version try_encode, compare_version
import downloadutils import downloadutils
import itemtypes import itemtypes
import plexdb_functions as plexdb import plexdb_functions as plexdb
@ -155,7 +155,7 @@ class LibrarySync(Thread):
log.debug('No timestamp; using 0') log.debug('No timestamp; using 0')
# Set the timer # Set the timer
koditime = getUnixTimestamp() koditime = unix_timestamp()
# Toggle watched state # Toggle watched state
scrobble(plexId, 'watched') scrobble(plexId, 'watched')
# Let the PMS process this first! # Let the PMS process this first!
@ -329,7 +329,7 @@ class LibrarySync(Thread):
# Create playlist for the video library # Create playlist for the video library
if (foldername not in playlists and if (foldername not in playlists and
mediatype in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)): mediatype in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)):
playlistXSP(mediatype, foldername, folderid, viewtype) playlist_xsp(mediatype, foldername, folderid, viewtype)
playlists.append(foldername) playlists.append(foldername)
# Create the video node # Create the video node
if (foldername not in nodes and if (foldername not in nodes and
@ -371,7 +371,7 @@ class LibrarySync(Thread):
# The tag could be a combined view. Ensure there's # The tag could be a combined view. Ensure there's
# no other tags with the same name before deleting # no other tags with the same name before deleting
# playlist. # playlist.
playlistXSP(mediatype, playlist_xsp(mediatype,
current_viewname, current_viewname,
folderid, folderid,
current_viewtype, current_viewtype,
@ -388,7 +388,7 @@ class LibrarySync(Thread):
# Added new playlist # Added new playlist
if (foldername not in playlists and mediatype in if (foldername not in playlists and mediatype in
(v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)): (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)):
playlistXSP(mediatype, playlist_xsp(mediatype,
foldername, foldername,
folderid, folderid,
viewtype) viewtype)
@ -414,7 +414,7 @@ class LibrarySync(Thread):
if mediatype != v.PLEX_TYPE_ARTIST: if mediatype != v.PLEX_TYPE_ARTIST:
if (foldername not in playlists and mediatype in if (foldername not in playlists and mediatype in
(v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)): (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)):
playlistXSP(mediatype, playlist_xsp(mediatype,
foldername, foldername,
folderid, folderid,
viewtype) viewtype)
@ -1102,7 +1102,7 @@ class LibrarySync(Thread):
""" """
self.videoLibUpdate = False self.videoLibUpdate = False
self.musicLibUpdate = False self.musicLibUpdate = False
now = getUnixTimestamp() now = unix_timestamp()
deleteListe = [] deleteListe = []
for i, item in enumerate(self.itemsToProcess): for i, item in enumerate(self.itemsToProcess):
if self.thread_stopped() or self.thread_suspended(): if self.thread_stopped() or self.thread_suspended():
@ -1220,7 +1220,7 @@ class LibrarySync(Thread):
'state': status, 'state': status,
'type': typus, 'type': typus,
'ratingKey': str(item['itemID']), 'ratingKey': str(item['itemID']),
'timestamp': getUnixTimestamp(), 'timestamp': unix_timestamp(),
'attempt': 0 'attempt': 0
}) })
elif typus in (v.PLEX_TYPE_MOVIE, elif typus in (v.PLEX_TYPE_MOVIE,
@ -1237,7 +1237,7 @@ class LibrarySync(Thread):
'state': status, 'state': status,
'type': typus, 'type': typus,
'ratingKey': plex_id, 'ratingKey': plex_id,
'timestamp': getUnixTimestamp(), 'timestamp': unix_timestamp(),
'attempt': 0 'attempt': 0
}) })
@ -1276,7 +1276,7 @@ class LibrarySync(Thread):
'state': None, # Don't need a state here 'state': None, # Don't need a state here
'type': kodi_info[5], 'type': kodi_info[5],
'ratingKey': plex_id, 'ratingKey': plex_id,
'timestamp': getUnixTimestamp(), 'timestamp': unix_timestamp(),
'attempt': 0 'attempt': 0
}) })
@ -1386,7 +1386,7 @@ class LibrarySync(Thread):
resume, resume,
session['duration'], session['duration'],
session['file_id'], session['file_id'],
DateToKodi(getUnixTimestamp())) unix_date_to_kodi(unix_timestamp()))
def fanartSync(self, refresh=False): def fanartSync(self, refresh=False):
""" """
@ -1430,9 +1430,9 @@ class LibrarySync(Thread):
window('plex_dbScan', value="true") window('plex_dbScan', value="true")
state.DB_SCAN = True state.DB_SCAN = True
# First remove playlists # First remove playlists
deletePlaylists() delete_playlists()
# Remove video nodes # Remove video nodes
deleteNodes() delete_nodes()
# Kick off refresh # Kick off refresh
if self.maintainViews() is True: if self.maintainViews() is True:
# Ran successfully # Ran successfully
@ -1549,11 +1549,11 @@ class LibrarySync(Thread):
# Also runs when first installed # Also runs when first installed
# Verify the video database can be found # Verify the video database can be found
videoDb = v.DB_VIDEO_PATH videoDb = v.DB_VIDEO_PATH
if not exists(tryEncode(videoDb)): if not exists(try_encode(videoDb)):
# Database does not exists # Database does not exists
log.error("The current Kodi version is incompatible " log.error("The current Kodi version is incompatible "
"to know which Kodi versions are supported.") "to know which Kodi versions are supported.")
log.error('Current Kodi version: %s' % tryDecode( log.error('Current Kodi version: %s' % try_decode(
xbmc.getInfoLabel('System.BuildVersion'))) xbmc.getInfoLabel('System.BuildVersion')))
# "Current Kodi version is unsupported, cancel lib sync" # "Current Kodi version is unsupported, cancel lib sync"
dialog('ok', heading='{plex}', line1=lang(39403)) dialog('ok', heading='{plex}', line1=lang(39403))
@ -1562,10 +1562,10 @@ class LibrarySync(Thread):
state.DB_SCAN = True state.DB_SCAN = True
window('plex_dbScan', value="true") window('plex_dbScan', value="true")
log.info("Db version: %s" % settings('dbCreatedWithVersion')) log.info("Db version: %s" % settings('dbCreatedWithVersion'))
lastTimeSync = getUnixTimestamp() lastTimeSync = unix_timestamp()
# Initialize time offset Kodi - PMS # Initialize time offset Kodi - PMS
self.syncPMStime() self.syncPMStime()
lastSync = getUnixTimestamp() lastSync = unix_timestamp()
if settings('FanartTV') == 'true': if settings('FanartTV') == 'true':
# Start getting additional missing artwork # Start getting additional missing artwork
with plexdb.Get_Plex_DB() as plex_db: with plexdb.Get_Plex_DB() as plex_db:
@ -1579,8 +1579,8 @@ class LibrarySync(Thread):
'refresh': True 'refresh': True
}) })
log.info('Refreshing video nodes and playlists now') log.info('Refreshing video nodes and playlists now')
deletePlaylists() delete_playlists()
deleteNodes() delete_nodes()
log.info("Initial start-up full sync starting") log.info("Initial start-up full sync starting")
librarySync = fullSync() librarySync = fullSync()
window('plex_dbScan', clear=True) window('plex_dbScan', clear=True)
@ -1604,7 +1604,7 @@ class LibrarySync(Thread):
self.triage_lib_scans() self.triage_lib_scans()
self.force_dialog = False self.force_dialog = False
continue continue
now = getUnixTimestamp() now = unix_timestamp()
# Standard syncs - don't force-show dialogs # Standard syncs - don't force-show dialogs
self.force_dialog = False self.force_dialog = False
if (now - lastSync > FULL_SYNC_INTERVALL and if (now - lastSync > FULL_SYNC_INTERVALL and

View file

@ -12,7 +12,7 @@ LEVELS = {
############################################################################### ###############################################################################
def tryEncode(uniString, encoding='utf-8'): def try_encode(uniString, encoding='utf-8'):
""" """
Will try to encode uniString (in unicode) to encoding. This possibly Will try to encode uniString (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
@ -43,5 +43,5 @@ class LogHandler(logging.StreamHandler):
try: try:
xbmc.log(self.format(record), level=LEVELS[record.levelno]) xbmc.log(self.format(record), level=LEVELS[record.levelno])
except UnicodeEncodeError: except UnicodeEncodeError:
xbmc.log(tryEncode(self.format(record)), xbmc.log(try_encode(self.format(record)),
level=LEVELS[record.levelno]) level=LEVELS[record.levelno])

View file

@ -18,7 +18,7 @@ from playutils import PlayUtils
from PKC_listitem import PKC_ListItem from PKC_listitem import PKC_ListItem
from pickler import pickle_me, Playback_Successful from pickler import pickle_me, Playback_Successful
import json_rpc as js import json_rpc as js
from utils import settings, dialog, language as lang, tryEncode from utils import settings, dialog, language as lang, try_encode
from plexbmchelper.subscribers import LOCKER from plexbmchelper.subscribers import LOCKER
import variables as v import variables as v
import state import state
@ -167,7 +167,7 @@ def _prep_playlist_stack(xml):
path = ('plugin://plugin.video.plexkodiconnect?%s' path = ('plugin://plugin.video.plexkodiconnect?%s'
% urlencode(params)) % urlencode(params))
listitem = api.CreateListItemFromPlexItem() listitem = api.CreateListItemFromPlexItem()
listitem.setPath(tryEncode(path)) listitem.setPath(try_encode(path))
else: else:
# Will add directly via the Kodi DB # Will add directly via the Kodi DB
path = None path = None
@ -244,7 +244,7 @@ def conclude_playback(playqueue, pos):
playurl = playutils.getPlayUrl() playurl = playutils.getPlayUrl()
else: else:
playurl = item.file playurl = item.file
listitem.setPath(tryEncode(playurl)) listitem.setPath(try_encode(playurl))
if item.playmethod in ('DirectStream', 'DirectPlay'): if item.playmethod in ('DirectStream', 'DirectPlay'):
listitem.setSubtitles(api.externalSubs()) listitem.setSubtitles(api.externalSubs())
else: else:
@ -322,14 +322,14 @@ def process_indirect(key, offset, resolve=True):
return return
playurl = xml[0].attrib['key'] playurl = xml[0].attrib['key']
item.file = playurl item.file = playurl
listitem.setPath(tryEncode(playurl)) listitem.setPath(try_encode(playurl))
playqueue.items.append(item) playqueue.items.append(item)
if resolve is True: if resolve is True:
result.listitem = listitem result.listitem = listitem
pickle_me(result) pickle_me(result)
else: else:
thread = Thread(target=Player().play, thread = Thread(target=Player().play,
args={'item': tryEncode(playurl), args={'item': try_encode(playurl),
'listitem': listitem}) 'listitem': listitem})
thread.setDaemon(True) thread.setDaemon(True)
LOG.info('Done initializing PKC playback, starting Kodi player') LOG.info('Done initializing PKC playback, starting Kodi player')

View file

@ -8,7 +8,7 @@ from re import compile as re_compile
import plexdb_functions as plexdb import plexdb_functions as plexdb
from downloadutils import DownloadUtils as DU from downloadutils import DownloadUtils as DU
from utils import tryEncode, escape_html from utils import try_encode, escape_html
from PlexAPI import API from PlexAPI import API
from PlexFunctions import GetPlexMetadata from PlexFunctions import GetPlexMetadata
import json_rpc as js import json_rpc as js
@ -60,7 +60,7 @@ class PlaylistObjectBaseclase(object):
continue continue
if isinstance(getattr(self, key), (str, unicode)): if isinstance(getattr(self, key), (str, unicode)):
answ += '\'%s\': \'%s\', ' % (key, answ += '\'%s\': \'%s\', ' % (key,
tryEncode(getattr(self, key))) try_encode(getattr(self, key)))
else: else:
# e.g. int # e.g. int
answ += '\'%s\': %s, ' % (key, str(getattr(self, key))) answ += '\'%s\': %s, ' % (key, str(getattr(self, key)))
@ -168,7 +168,7 @@ class Playlist_Item(object):
continue continue
if isinstance(getattr(self, key), (str, unicode)): if isinstance(getattr(self, key), (str, unicode)):
answ += '\'%s\': \'%s\', ' % (key, answ += '\'%s\': \'%s\', ' % (key,
tryEncode(getattr(self, key))) try_encode(getattr(self, key)))
else: else:
# e.g. int # e.g. int
answ += '\'%s\': %s, ' % (key, str(getattr(self, key))) answ += '\'%s\': %s, ' % (key, str(getattr(self, key)))

View file

@ -4,7 +4,7 @@
from logging import getLogger from logging import getLogger
from downloadutils import DownloadUtils as DU from downloadutils import DownloadUtils as DU
from utils import window, settings, language as lang, dialog, tryEncode from utils import window, settings, language as lang, dialog, try_encode
import variables as v import variables as v
############################################################################### ###############################################################################
@ -274,7 +274,7 @@ class PlayUtils():
codec, codec,
channellayout) channellayout)
audio_streams_list.append(index) audio_streams_list.append(index)
audio_streams.append(tryEncode(track)) audio_streams.append(try_encode(track))
audio_numb += 1 audio_numb += 1
# Subtitles # Subtitles
@ -306,7 +306,7 @@ class PlayUtils():
"%s%s" % (window('pms_server'), "%s%s" % (window('pms_server'),
stream.attrib['key'])) stream.attrib['key']))
downloadable_streams.append(index) downloadable_streams.append(index)
download_subs.append(tryEncode(path)) download_subs.append(try_encode(path))
else: else:
track = "%s (%s)" % (track, lang(39710)) # burn-in track = "%s (%s)" % (track, lang(39710)) # burn-in
if stream.attrib.get('selected') == '1' and downloadable: if stream.attrib.get('selected') == '1' and downloadable:
@ -315,7 +315,7 @@ class PlayUtils():
default_sub = index default_sub = index
subtitle_streams_list.append(index) subtitle_streams_list.append(index)
subtitle_streams.append(tryEncode(track)) subtitle_streams.append(try_encode(track))
sub_num += 1 sub_num += 1
if audio_numb > 1: if audio_numb > 1:

View file

@ -4,7 +4,7 @@ from logging import getLogger
from xbmc import sleep, executebuiltin from xbmc import sleep, executebuiltin
from downloadutils import DownloadUtils as DU from downloadutils import DownloadUtils as DU
from utils import dialog, language as lang, settings, tryEncode from utils import dialog, language as lang, settings, try_encode
import variables as v import variables as v
import state import state
@ -39,7 +39,7 @@ def choose_home_user(token):
username = user['title'] username = user['title']
userlist.append(username) userlist.append(username)
# To take care of non-ASCII usernames # To take care of non-ASCII usernames
userlist_coded.append(tryEncode(username)) userlist_coded.append(try_encode(username))
usernumber = len(userlist) usernumber = len(userlist)
username = '' username = ''
usertoken = '' usertoken = ''

View file

@ -3,7 +3,7 @@
############################################################################### ###############################################################################
from logging import getLogger from logging import getLogger
from utils import kodiSQL from utils import kodi_sql
import variables as v import variables as v
############################################################################### ###############################################################################
@ -22,7 +22,7 @@ class Get_Plex_DB():
and the db gets closed and the db gets closed
""" """
def __enter__(self): def __enter__(self):
self.plexconn = kodiSQL('plex') self.plexconn = kodi_sql('plex')
return Plex_DB_Functions(self.plexconn.cursor()) return Plex_DB_Functions(self.plexconn.cursor())
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):

View file

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
Various functions and decorators for PKC
"""
############################################################################### ###############################################################################
from logging import getLogger from logging import getLogger
from cProfile import Profile from cProfile import Profile
@ -7,7 +9,7 @@ from pstats import Stats
from sqlite3 import connect, OperationalError from sqlite3 import connect, OperationalError
from datetime import datetime, timedelta from datetime import datetime, timedelta
from StringIO import StringIO from StringIO import StringIO
from time import localtime, strftime, strptime from time import localtime, strftime
from unicodedata import normalize from unicodedata import normalize
import xml.etree.ElementTree as etree import xml.etree.ElementTree as etree
from functools import wraps, partial from functools import wraps, partial
@ -21,12 +23,13 @@ import xbmc
import xbmcaddon import xbmcaddon
import xbmcgui import xbmcgui
from xbmcvfs import exists, delete from xbmcvfs import exists, delete
import variables as v import variables as v
import state import state
############################################################################### ###############################################################################
log = getLogger("PLEX."+__name__) LOG = getLogger("PLEX." + __name__)
WINDOW = xbmcgui.Window(10000) WINDOW = xbmcgui.Window(10000)
ADDON = xbmcaddon.Addon(id='plugin.video.plexkodiconnect') ADDON = xbmcaddon.Addon(id='plugin.video.plexkodiconnect')
@ -46,7 +49,8 @@ def reboot_kodi(message=None):
dialog('ok', heading='{plex}', line1=message) dialog('ok', heading='{plex}', line1=message)
xbmc.executebuiltin('RestartApp') xbmc.executebuiltin('RestartApp')
def window(property, value=None, clear=False, windowid=10000):
def window(prop, value=None, clear=False, windowid=10000):
""" """
Get or set window property - thread safe! Get or set window property - thread safe!
@ -60,11 +64,11 @@ def window(property, value=None, clear=False, windowid=10000):
win = WINDOW win = WINDOW
if clear: if clear:
win.clearProperty(property) win.clearProperty(prop)
elif value is not None: elif value is not None:
win.setProperty(tryEncode(property), tryEncode(value)) win.setProperty(try_encode(prop), try_encode(value))
else: else:
return tryDecode(win.getProperty(property)) return try_decode(win.getProperty(prop))
def plex_command(key, value): def plex_command(key, value):
@ -90,10 +94,10 @@ def settings(setting, value=None):
addon = xbmcaddon.Addon(id='plugin.video.plexkodiconnect') addon = xbmcaddon.Addon(id='plugin.video.plexkodiconnect')
if value is not None: if value is not None:
# Takes string or unicode by default! # Takes string or unicode by default!
addon.setSetting(tryEncode(setting), tryEncode(value)) addon.setSetting(try_encode(setting), try_encode(value))
else: else:
# Should return unicode by default, but just in case # Should return unicode by default, but just in case
return tryDecode(addon.getSetting(setting)) return try_decode(addon.getSetting(setting))
def exists_dir(path): def exists_dir(path):
@ -104,24 +108,26 @@ def exists_dir(path):
Feed with encoded string or unicode Feed with encoded string or unicode
""" """
if v.KODIVERSION >= 17: if v.KODIVERSION >= 17:
answ = exists(tryEncode(path)) answ = exists(try_encode(path))
else: else:
dummyfile = join(tryDecode(path), 'dummyfile.txt') dummyfile = join(try_decode(path), 'dummyfile.txt')
try: try:
with open(dummyfile, 'w') as f: with open(dummyfile, 'w') as filer:
f.write('text') filer.write('text')
except IOError: except IOError:
# folder does not exist yet # folder does not exist yet
answ = 0 answ = 0
else: else:
# Folder exists. Delete file again. # Folder exists. Delete file again.
delete(tryEncode(dummyfile)) delete(try_encode(dummyfile))
answ = 1 answ = 1
return answ return answ
def language(stringid): def language(stringid):
# Central string retrieval """
Central string retrieval from strings.po
"""
return ADDON.getLocalizedString(stringid) return ADDON.getLocalizedString(stringid)
@ -236,7 +242,7 @@ def kodi_time_to_millis(time):
return ret return ret
def tryEncode(uniString, encoding='utf-8'): def try_encode(uniString, encoding='utf-8'):
""" """
Will try to encode uniString (in unicode) to encoding. This possibly Will try to encode uniString (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
@ -252,7 +258,7 @@ def tryEncode(uniString, encoding='utf-8'):
return uniString return uniString
def tryDecode(string, encoding='utf-8'): def try_decode(string, encoding='utf-8'):
""" """
Will try to decode string (encoded) using encoding. This possibly Will try to decode string (encoded) using 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
@ -295,7 +301,7 @@ def escape_html(string):
return string return string
def DateToKodi(stamp): def unix_date_to_kodi(stamp):
""" """
converts a Unix time stamp (seconds passed sinceJanuary 1 1970) to a converts a Unix time stamp (seconds passed sinceJanuary 1 1970) to a
propper, human-readable time stamp used by Kodi propper, human-readable time stamp used by Kodi
@ -313,49 +319,42 @@ def DateToKodi(stamp):
return localdate return localdate
def IntFromStr(string): def unix_timestamp(seconds_into_the_future=None):
"""
Returns an int from string or the int 0 if something happened
"""
try:
result = int(string)
except:
result = 0
return result
def getUnixTimestamp(secondsIntoTheFuture=None):
""" """
Returns a Unix time stamp (seconds passed since January 1 1970) for NOW as Returns a Unix time stamp (seconds passed since January 1 1970) for NOW as
an integer. an integer.
Optionally, pass secondsIntoTheFuture: positive int's will result in a Optionally, pass seconds_into_the_future: positive int's will result in a
future timestamp, negative the past future timestamp, negative the past
""" """
if secondsIntoTheFuture: if seconds_into_the_future:
future = datetime.utcnow() + timedelta(seconds=secondsIntoTheFuture) future = datetime.utcnow() + timedelta(seconds=seconds_into_the_future)
else: else:
future = datetime.utcnow() future = datetime.utcnow()
return timegm(future.timetuple()) return timegm(future.timetuple())
def kodiSQL(media_type="video"): def kodi_sql(media_type=None):
"""
Open a connection to the Kodi database.
media_type: 'video' (standard if not passed), 'plex', 'music', 'texture'
"""
if media_type == "plex": if media_type == "plex":
dbPath = v.DB_PLEX_PATH db_path = v.DB_PLEX_PATH
elif media_type == "music": elif media_type == "music":
dbPath = v.DB_MUSIC_PATH db_path = v.DB_MUSIC_PATH
elif media_type == "texture": elif media_type == "texture":
dbPath = v.DB_TEXTURE_PATH db_path = v.DB_TEXTURE_PATH
else: else:
dbPath = v.DB_VIDEO_PATH db_path = v.DB_VIDEO_PATH
return connect(dbPath, timeout=60.0) return connect(db_path, timeout=60.0)
def create_actor_db_index(): def create_actor_db_index():
""" """
Index the "actors" because we got a TON - speed up SELECT and WHEN Index the "actors" because we got a TON - speed up SELECT and WHEN
""" """
conn = kodiSQL('video') conn = kodi_sql('video')
cursor = conn.cursor() cursor = conn.cursor()
try: try:
cursor.execute(""" cursor.execute("""
@ -370,6 +369,10 @@ def create_actor_db_index():
def reset(): def reset():
"""
User navigated to the PKC settings, Advanced, and wants to reset the Kodi
database and possibly PKC entirely
"""
# Are you sure you want to reset your local Kodi database? # Are you sure you want to reset your local Kodi database?
if not dialog('yesno', if not dialog('yesno',
heading='{plex} %s ' % language(30132), heading='{plex} %s ' % language(30132),
@ -380,7 +383,7 @@ def reset():
plex_command('STOP_SYNC', 'True') plex_command('STOP_SYNC', 'True')
count = 10 count = 10
while window('plex_dbScan') == "true": while window('plex_dbScan') == "true":
log.debug("Sync is running, will retry: %s..." % count) LOG.debug("Sync is running, will retry: %s...", count)
count -= 1 count -= 1
if count == 0: if count == 0:
# Could not stop the database from running. Please try again later. # Could not stop the database from running. Please try again later.
@ -391,14 +394,14 @@ def reset():
xbmc.sleep(1000) xbmc.sleep(1000)
# Clean up the playlists # Clean up the playlists
deletePlaylists() delete_playlists()
# Clean up the video nodes # Clean up the video nodes
deleteNodes() delete_nodes()
# Wipe the kodi databases # Wipe the kodi databases
log.info("Resetting the Kodi video database.") LOG.info("Resetting the Kodi video database.")
connection = kodiSQL('video') connection = kodi_sql('video')
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"') cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
rows = cursor.fetchall() rows = cursor.fetchall()
@ -410,8 +413,8 @@ def reset():
cursor.close() cursor.close()
if settings('enableMusic') == "true": if settings('enableMusic') == "true":
log.info("Resetting the Kodi music database.") LOG.info("Resetting the Kodi music database.")
connection = kodiSQL('music') connection = kodi_sql('music')
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"') cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
rows = cursor.fetchall() rows = cursor.fetchall()
@ -423,8 +426,8 @@ def reset():
cursor.close() cursor.close()
# Wipe the Plex database # Wipe the Plex database
log.info("Resetting the Plex database.") LOG.info("Resetting the Plex database.")
connection = kodiSQL('plex') connection = kodi_sql('plex')
cursor = connection.cursor() cursor = connection.cursor()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"') cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
rows = cursor.fetchall() rows = cursor.fetchall()
@ -441,21 +444,21 @@ def reset():
if dialog('yesno', if dialog('yesno',
heading='{plex} %s ' % language(30132), heading='{plex} %s ' % language(30132),
line1=language(39602)): line1=language(39602)):
log.info("Resetting all cached artwork.") LOG.info("Resetting all cached artwork.")
# Remove all existing textures first # Remove all existing textures first
path = xbmc.translatePath("special://thumbnails/") path = xbmc.translatePath("special://thumbnails/")
if exists(path): if exists(path):
rmtree(tryDecode(path), ignore_errors=True) rmtree(try_decode(path), ignore_errors=True)
# remove all existing data from texture DB # remove all existing data from texture DB
connection = kodiSQL('texture') connection = kodi_sql('texture')
cursor = connection.cursor() cursor = connection.cursor()
query = 'SELECT tbl_name FROM sqlite_master WHERE type=?' query = 'SELECT tbl_name FROM sqlite_master WHERE type=?'
cursor.execute(query, ("table", )) cursor.execute(query, ("table", ))
rows = cursor.fetchall() rows = cursor.fetchall()
for row in rows: for row in rows:
tableName = row[0] table_name = row[0]
if(tableName != "version"): if table_name != "version":
cursor.execute("DELETE FROM %s" % tableName) cursor.execute("DELETE FROM %s" % table_name)
connection.commit() connection.commit()
cursor.close() cursor.close()
@ -469,44 +472,36 @@ def reset():
line1=language(39603)): line1=language(39603)):
# Delete the settings # Delete the settings
addon = xbmcaddon.Addon() addon = xbmcaddon.Addon()
addondir = tryDecode(xbmc.translatePath(addon.getAddonInfo('profile'))) addondir = try_decode(xbmc.translatePath(addon.getAddonInfo('profile')))
dataPath = "%ssettings.xml" % addondir LOG.info("Deleting: settings.xml")
log.info("Deleting: settings.xml") remove("%ssettings.xml" % addondir)
remove(dataPath)
reboot_kodi() reboot_kodi()
def profiling(sortby="cumulative"): def profiling(sortby="cumulative"):
# Will print results to Kodi log """
Will print results to Kodi log. Must be enabled in the Python source code
"""
def decorator(func): def decorator(func):
"""
decorator construct
"""
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
"""
pr = Profile() wrapper construct
"""
pr.enable() profile = Profile()
profile.enable()
result = func(*args, **kwargs) result = func(*args, **kwargs)
pr.disable() profile.disable()
string_io = StringIO()
s = StringIO() stats = Stats(profile, stream=string_io).sort_stats(sortby)
ps = Stats(pr, stream=s).sort_stats(sortby) stats.print_stats()
ps.print_stats() LOG.info(string_io.getvalue())
log.info(s.getvalue())
return result return result
return wrapper return wrapper
return decorator return decorator
def convertdate(date):
try:
date = datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ")
except TypeError:
# TypeError: attribute of type 'NoneType' is not callable
# Known Kodi/python error
date = datetime(*(strptime(date, "%Y-%m-%dT%H:%M:%SZ")[0:6]))
return date
def compare_version(current, minimum): def compare_version(current, minimum):
""" """
@ -515,38 +510,36 @@ def compare_version(current, minimum):
Input strings: e.g. "1.2.3"; always with Major, Minor and Patch! Input strings: e.g. "1.2.3"; always with Major, Minor and Patch!
""" """
log.info("current DB: %s minimum DB: %s" % (current, minimum)) LOG.info("current DB: %s minimum DB: %s", current, minimum)
try: try:
currMajor, currMinor, currPatch = current.split(".") curr_major, curr_minor, curr_patch = current.split(".")
except ValueError: except ValueError:
# there WAS no current DB, e.g. deleted. # there WAS no current DB, e.g. deleted.
return True return True
minMajor, minMinor, minPatch = minimum.split(".") min_major, min_minor, min_patch = minimum.split(".")
currMajor = int(currMajor) curr_major = int(curr_major)
currMinor = int(currMinor) curr_minor = int(curr_minor)
currPatch = int(currPatch) curr_patch = int(curr_patch)
minMajor = int(minMajor) min_major = int(min_major)
minMinor = int(minMinor) min_minor = int(min_minor)
minPatch = int(minPatch) min_patch = int(min_patch)
if currMajor > minMajor: if curr_major > min_major:
return True return True
elif currMajor < minMajor: elif curr_major < min_major:
return False return False
if currMinor > minMinor: if curr_minor > min_minor:
return True return True
elif currMinor < minMinor: elif curr_minor < min_minor:
return False
if currPatch >= minPatch:
return True
else:
return False return False
return curr_patch >= min_patch
def normalize_nodes(text): def normalize_nodes(text):
# For video nodes """
For video nodes
"""
text = text.replace(":", "") text = text.replace(":", "")
text = text.replace("/", "-") text = text.replace("/", "-")
text = text.replace("\\", "-") text = text.replace("\\", "-")
@ -561,13 +554,15 @@ def normalize_nodes(text):
# Remove dots from the last character as windows can not have directories # Remove dots from the last character as windows can not have directories
# with dots at the end # with dots at the end
text = text.rstrip('.') text = text.rstrip('.')
text = tryEncode(normalize('NFKD', unicode(text, 'utf-8'))) text = try_encode(normalize('NFKD', unicode(text, 'utf-8')))
return text return text
def normalize_string(text): def normalize_string(text):
# For theme media, do not modify unless """
# modified in TV Tunes For theme media, do not modify unless modified in TV Tunes
"""
text = text.replace(":", "") text = text.replace(":", "")
text = text.replace("/", "-") text = text.replace("/", "-")
text = text.replace("\\", "-") text = text.replace("\\", "-")
@ -580,7 +575,7 @@ def normalize_string(text):
# Remove dots from the last character as windows can not have directories # Remove dots from the last character as windows can not have directories
# with dots at the end # with dots at the end
text = text.rstrip('.') text = text.rstrip('.')
text = tryEncode(normalize('NFKD', unicode(text, 'utf-8'))) text = try_encode(normalize('NFKD', unicode(text, 'utf-8')))
return text return text
@ -595,8 +590,8 @@ def indent(elem, level=0):
elem.text = i + " " elem.text = i + " "
if not elem.tail or not elem.tail.strip(): if not elem.tail or not elem.tail.strip():
elem.tail = i elem.tail = i
for elem in elem: for item in elem:
indent(elem, level+1) indent(item, level+1)
if not elem.tail or not elem.tail.strip(): if not elem.tail or not elem.tail.strip():
elem.tail = i elem.tail = i
else: else:
@ -604,30 +599,6 @@ def indent(elem, level=0):
elem.tail = i elem.tail = i
def guisettingsXML():
"""
Returns special://userdata/guisettings.xml as an etree xml root element
"""
path = tryDecode(xbmc.translatePath("special://profile/"))
xmlpath = "%sguisettings.xml" % path
try:
xmlparse = etree.parse(xmlpath)
except IOError:
# Document is blank or missing
root = etree.Element('settings')
except etree.ParseError:
log.error('Error parsing %s' % xmlpath)
# "Kodi cannot parse {0}. PKC will not function correctly. Please visit
# {1} and correct your file!"
dialog('ok', language(29999), language(39716).format(
'guisettings.xml', 'http://kodi.wiki/view/userdata'))
return
else:
root = xmlparse.getroot()
return root
class XmlKodiSetting(object): class XmlKodiSetting(object):
""" """
Used to load a Kodi XML settings file from special://profile as an etree Used to load a Kodi XML settings file from special://profile as an etree
@ -670,7 +641,7 @@ class XmlKodiSetting(object):
except IOError: except IOError:
# Document is blank or missing # Document is blank or missing
if self.force_create is False: if self.force_create is False:
log.debug('%s does not seem to exist; not creating', self.path) LOG.debug('%s does not seem to exist; not creating', self.path)
# This will abort __enter__ # This will abort __enter__
self.__exit__(IOError, None, None) self.__exit__(IOError, None, None)
# Create topmost xml entry # Create topmost xml entry
@ -678,7 +649,7 @@ class XmlKodiSetting(object):
element=etree.Element(self.top_element)) element=etree.Element(self.top_element))
self.write_xml = True self.write_xml = True
except etree.ParseError: except etree.ParseError:
log.error('Error parsing %s', self.path) LOG.error('Error parsing %s', self.path)
# "Kodi cannot parse {0}. PKC will not function correctly. Please # "Kodi cannot parse {0}. PKC will not function correctly. Please
# visit {1} and correct your file!" # visit {1} and correct your file!"
dialog('ok', language(29999), language(39716).format( dialog('ok', language(29999), language(39716).format(
@ -775,7 +746,7 @@ class XmlKodiSetting(object):
elif old.attrib != attrib: elif old.attrib != attrib:
already_set = False already_set = False
if already_set is True: if already_set is True:
log.debug('Element has already been found') LOG.debug('Element has already been found')
return old return old
# Need to set new setting, indeed # Need to set new setting, indeed
self.write_xml = True self.write_xml = True
@ -790,34 +761,35 @@ class XmlKodiSetting(object):
return element return element
def passwordsXML(): def passwords_xml():
# To add network credentials """
path = tryDecode(xbmc.translatePath("special://userdata/")) To add network credentials to Kodi's password xml
"""
path = try_decode(xbmc.translatePath("special://userdata/"))
xmlpath = "%spasswords.xml" % path xmlpath = "%spasswords.xml" % path
dialog = xbmcgui.Dialog()
try: try:
xmlparse = etree.parse(xmlpath) xmlparse = etree.parse(xmlpath)
except IOError: except IOError:
# Document is blank or missing # Document is blank or missing
root = etree.Element('passwords') root = etree.Element('passwords')
skipFind = True skip_find = True
except etree.ParseError: except etree.ParseError:
log.error('Error parsing %s' % xmlpath) LOG.error('Error parsing %s', xmlpath)
# "Kodi cannot parse {0}. PKC will not function correctly. Please visit # "Kodi cannot parse {0}. PKC will not function correctly. Please visit
# {1} and correct your file!" # {1} and correct your file!"
dialog.ok(language(29999), language(39716).format( dialog('ok', language(29999), language(39716).format(
'passwords.xml', 'http://forum.kodi.tv/')) 'passwords.xml', 'http://forum.kodi.tv/'))
return return
else: else:
root = xmlparse.getroot() root = xmlparse.getroot()
skipFind = False skip_find = False
credentials = settings('networkCreds') credentials = settings('networkCreds')
if credentials: if credentials:
# Present user with options # Present user with options
option = dialog.select( option = dialog('select',
"Modify/Remove network credentials", ["Modify", "Remove"]) "Modify/Remove network credentials",
["Modify", "Remove"])
if option < 0: if option < 0:
# User cancelled dialog # User cancelled dialog
@ -825,76 +797,86 @@ def passwordsXML():
elif option == 1: elif option == 1:
# User selected remove # User selected remove
success = False
for paths in root.getiterator('passwords'): for paths in root.getiterator('passwords'):
for path in paths: for path in paths:
if path.find('.//from').text == "smb://%s/" % credentials: if path.find('.//from').text == "smb://%s/" % credentials:
paths.remove(path) paths.remove(path)
log.info("Successfully removed credentials for: %s" LOG.info("Successfully removed credentials for: %s",
% credentials) credentials)
etree.ElementTree(root).write(xmlpath, etree.ElementTree(root).write(xmlpath,
encoding="UTF-8") encoding="UTF-8")
break success = True
else: if not success:
log.error("Failed to find saved server: %s in passwords.xml" LOG.error("Failed to find saved server: %s in passwords.xml",
% credentials) credentials)
dialog('notification',
heading='{plex}',
message="%s not found" % credentials,
icon='{warning}',
sound=False)
return
settings('networkCreds', value="") settings('networkCreds', value="")
xbmcgui.Dialog().notification( dialog('notification',
heading='PlexKodiConnect', heading='{plex}',
message="%s removed from passwords.xml" % credentials, message="%s removed from passwords.xml" % credentials,
icon="special://home/addons/plugin.video.plexkodiconnect/icon.png", icon='{plex}',
time=1000, sound=False)
sound=False)
return return
elif option == 0: elif option == 0:
# User selected to modify # User selected to modify
server = dialog.input("Modify the computer name or ip address", credentials) server = dialog('input',
"Modify the computer name or ip address",
credentials)
if not server: if not server:
return return
else: else:
# No credentials added # No credentials added
dialog.ok( dialog('ok',
heading="Network credentials", "Network credentials",
line1= ( 'Input the server name or IP address as indicated in your plex '
"Input the server name or IP address as indicated in your plex library paths. " 'library paths. For example, the server name: '
'For example, the server name: \\\\SERVER-PC\\path\\ or smb://SERVER-PC/path is "SERVER-PC".')) '\\\\SERVER-PC\\path\\ or smb://SERVER-PC/path is SERVER-PC')
server = dialog.input("Enter the server name or IP address") server = dialog('input', "Enter the server name or IP address")
if not server: if not server:
return return
server = quote_plus(server) server = quote_plus(server)
# Network username # Network username
user = dialog.input("Enter the network username") user = dialog('input', "Enter the network username")
if not user: if not user:
return return
user = quote_plus(user) user = quote_plus(user)
# Network password # Network password
password = dialog.input("Enter the network password", password = dialog('input',
'', # Default input "Enter the network password",
xbmcgui.INPUT_ALPHANUM, '', # Default input
xbmcgui.ALPHANUM_HIDE_INPUT) type='{alphanum}',
option='{hide}')
# Need to url-encode the password # Need to url-encode the password
password = quote_plus(password) password = quote_plus(password)
# Add elements. Annoying etree bug where findall hangs forever # Add elements. Annoying etree bug where findall hangs forever
if skipFind is False: if skip_find is False:
skipFind = True skip_find = True
for path in root.findall('.//path'): for path in root.findall('.//path'):
if path.find('.//from').text.lower() == "smb://%s/" % server.lower(): if path.find('.//from').text.lower() == "smb://%s/" % server.lower():
# Found the server, rewrite credentials # Found the server, rewrite credentials
path.find('.//to').text = "smb://%s:%s@%s/" % (user, password, server) path.find('.//to').text = ("smb://%s:%s@%s/"
skipFind = False % (user, password, server))
skip_find = False
break break
if skipFind: if skip_find:
# Server not found, add it. # Server not found, add it.
path = etree.SubElement(root, 'path') path = etree.SubElement(root, 'path')
etree.SubElement(path, 'from', attrib={'pathversion': "1"}).text = "smb://%s/" % server etree.SubElement(path, 'from', attrib={'pathversion': "1"}).text = \
"smb://%s/" % server
topath = "smb://%s:%s@%s/" % (user, password, server) topath = "smb://%s:%s@%s/" % (user, password, server)
etree.SubElement(path, 'to', attrib={'pathversion': "1"}).text = topath etree.SubElement(path, 'to', attrib={'pathversion': "1"}).text = topath
# Add credentials # Add credentials
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: try:
indent(root) indent(root)
@ -902,19 +884,12 @@ def passwordsXML():
pass pass
etree.ElementTree(root).write(xmlpath, encoding="UTF-8") etree.ElementTree(root).write(xmlpath, encoding="UTF-8")
# dialog.notification(
# heading="PlexKodiConnect",
# message="Added to passwords.xml",
# icon="special://home/addons/plugin.video.plexkodiconnect/icon.png",
# time=5000,
# sound=False)
def playlist_xsp(mediatype, tagname, viewid, viewtype="", delete=False):
def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
""" """
Feed with tagname as unicode Feed with tagname as unicode
""" """
path = tryDecode(xbmc.translatePath("special://profile/playlists/video/")) path = try_decode(xbmc.translatePath("special://profile/playlists/video/"))
if viewtype == "mixed": if viewtype == "mixed":
plname = "%s - %s" % (tagname, mediatype) plname = "%s - %s" % (tagname, mediatype)
xsppath = "%sPlex %s - %s.xsp" % (path, viewid, mediatype) xsppath = "%sPlex %s - %s.xsp" % (path, viewid, mediatype)
@ -923,16 +898,16 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
xsppath = "%sPlex %s.xsp" % (path, viewid) xsppath = "%sPlex %s.xsp" % (path, viewid)
# Create the playlist directory # Create the playlist directory
if not exists(tryEncode(path)): if not exists(try_encode(path)):
log.info("Creating directory: %s" % path) LOG.info("Creating directory: %s", path)
makedirs(path) makedirs(path)
# Only add the playlist if it doesn't already exists # Only add the playlist if it doesn't already exists
if exists(tryEncode(xsppath)): if exists(try_encode(xsppath)):
log.info('Path %s does exist' % xsppath) LOG.info('Path %s does exist', xsppath)
if delete: if delete:
remove(xsppath) remove(xsppath)
log.info("Successfully removed playlist: %s." % tagname) LOG.info("Successfully removed playlist: %s.", tagname)
return return
# Using write process since there's no guarantee the xml declaration works # Using write process since there's no guarantee the xml declaration works
@ -942,9 +917,9 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
'movie': 'movies', 'movie': 'movies',
'show': 'tvshows' 'show': 'tvshows'
} }
log.info("Writing playlist file to: %s" % xsppath) LOG.info("Writing playlist file to: %s", xsppath)
with open(xsppath, 'wb') as f: with open(xsppath, 'wb') as filer:
f.write(tryEncode( filer.write(try_encode(
'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n' '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
'<smartplaylist type="%s">\n\t' '<smartplaylist type="%s">\n\t'
'<name>Plex %s</name>\n\t' '<name>Plex %s</name>\n\t'
@ -954,20 +929,24 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
'</rule>\n' '</rule>\n'
'</smartplaylist>\n' '</smartplaylist>\n'
% (itemtypes.get(mediatype, mediatype), plname, tagname))) % (itemtypes.get(mediatype, mediatype), plname, tagname)))
log.info("Successfully added playlist: %s" % tagname) LOG.info("Successfully added playlist: %s", tagname)
def deletePlaylists(): def delete_playlists():
# Clean up the playlists """
path = tryDecode(xbmc.translatePath("special://profile/playlists/video/")) Clean up the playlists
"""
path = try_decode(xbmc.translatePath("special://profile/playlists/video/"))
for root, _, files in walk(path): for root, _, files in walk(path):
for file in files: for file in files:
if file.startswith('Plex'): if file.startswith('Plex'):
remove(join(root, file)) remove(join(root, file))
def deleteNodes(): def delete_nodes():
# Clean up video nodes """
path = tryDecode(xbmc.translatePath("special://profile/library/video/")) Clean up video nodes
"""
path = try_decode(xbmc.translatePath("special://profile/library/video/"))
for root, dirs, _ in walk(path): for root, dirs, _ in walk(path):
for directory in dirs: for directory in dirs:
if directory.startswith('Plex-'): if directory.startswith('Plex-'):
@ -993,9 +972,9 @@ def CatchExceptions(warnuser=False):
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except Exception as e: except Exception as e:
log.error('%s has crashed. Error: %s' % (func.__name__, e)) LOG.error('%s has crashed. Error: %s', func.__name__, e)
import traceback import traceback
log.error("Traceback:\n%s" % traceback.format_exc()) LOG.error("Traceback:\n%s", traceback.format_exc())
if warnuser: if warnuser:
window('plex_scancrashed', value='true') window('plex_scancrashed', value='true')
return return
@ -1012,8 +991,8 @@ def LogTime(func):
starttotal = datetime.now() starttotal = datetime.now()
result = func(*args, **kwargs) result = func(*args, **kwargs)
elapsedtotal = datetime.now() - starttotal elapsedtotal = datetime.now() - starttotal
log.info('It took %s to run the function %s' LOG.info('It took %s to run the function %s',
% (elapsedtotal, func.__name__)) elapsedtotal, func.__name__)
return result return result
return wrapper return wrapper
@ -1117,43 +1096,3 @@ class Lock_Function(object):
result = func(*args, **kwargs) result = func(*args, **kwargs)
return result return result
return wrapper return wrapper
###############################################################################
# UNUSED METHODS
# def changePlayState(itemType, kodiId, playCount, lastplayed):
# """
# YET UNUSED
# kodiId: int or str
# playCount: int or str
# lastplayed: str or int unix timestamp
# """
# lastplayed = DateToKodi(lastplayed)
# kodiId = int(kodiId)
# playCount = int(playCount)
# method = {
# 'movie': ' VideoLibrary.SetMovieDetails',
# 'episode': 'VideoLibrary.SetEpisodeDetails',
# 'musicvideo': ' VideoLibrary.SetMusicVideoDetails', # TODO
# 'show': 'VideoLibrary.SetTVShowDetails', # TODO
# '': 'AudioLibrary.SetAlbumDetails', # TODO
# '': 'AudioLibrary.SetArtistDetails', # TODO
# 'track': 'AudioLibrary.SetSongDetails'
# }
# params = {
# 'movie': {
# 'movieid': kodiId,
# 'playcount': playCount,
# 'lastplayed': lastplayed
# },
# 'episode': {
# 'episodeid': kodiId,
# 'playcount': playCount,
# 'lastplayed': lastplayed
# }
# }
# result = jsonrpc(method[itemType]).execute(params[itemType])
# log.debug("JSON result was: %s" % result)

View file

@ -6,7 +6,7 @@ from xbmcaddon import Addon
# For any file operations with KODI function, use encoded strings! # For any file operations with KODI function, use encoded strings!
def tryDecode(string, encoding='utf-8'): def try_decode(string, encoding='utf-8'):
""" """
Will try to decode string (encoded) using encoding. This possibly Will try to decode string (encoded) using 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
@ -37,7 +37,7 @@ ADDON_VERSION = _ADDON.getAddonInfo('version')
KODILANGUAGE = xbmc.getLanguage(xbmc.ISO_639_1) KODILANGUAGE = xbmc.getLanguage(xbmc.ISO_639_1)
KODIVERSION = int(xbmc.getInfoLabel("System.BuildVersion")[:2]) KODIVERSION = int(xbmc.getInfoLabel("System.BuildVersion")[:2])
KODILONGVERSION = xbmc.getInfoLabel('System.BuildVersion') KODILONGVERSION = xbmc.getInfoLabel('System.BuildVersion')
KODI_PROFILE = tryDecode(xbmc.translatePath("special://profile")) KODI_PROFILE = try_decode(xbmc.translatePath("special://profile"))
if xbmc.getCondVisibility('system.platform.osx'): if xbmc.getCondVisibility('system.platform.osx'):
PLATFORM = "MacOSX" PLATFORM = "MacOSX"
@ -56,7 +56,7 @@ elif xbmc.getCondVisibility('system.platform.android'):
else: else:
PLATFORM = "Unknown" PLATFORM = "Unknown"
DEVICENAME = tryDecode(_ADDON.getSetting('deviceName')) DEVICENAME = try_decode(_ADDON.getSetting('deviceName'))
DEVICENAME = DEVICENAME.replace(":", "") DEVICENAME = DEVICENAME.replace(":", "")
DEVICENAME = DEVICENAME.replace("/", "-") DEVICENAME = DEVICENAME.replace("/", "-")
DEVICENAME = DEVICENAME.replace("\\", "-") DEVICENAME = DEVICENAME.replace("\\", "-")
@ -86,7 +86,7 @@ _DB_VIDEO_VERSION = {
17: 107, # Krypton 17: 107, # Krypton
18: 108 # Leia 18: 108 # Leia
} }
DB_VIDEO_PATH = tryDecode(xbmc.translatePath( DB_VIDEO_PATH = try_decode(xbmc.translatePath(
"special://database/MyVideos%s.db" % _DB_VIDEO_VERSION[KODIVERSION])) "special://database/MyVideos%s.db" % _DB_VIDEO_VERSION[KODIVERSION]))
_DB_MUSIC_VERSION = { _DB_MUSIC_VERSION = {
@ -97,7 +97,7 @@ _DB_MUSIC_VERSION = {
17: 60, # Krypton 17: 60, # Krypton
18: 62 # Leia 18: 62 # Leia
} }
DB_MUSIC_PATH = tryDecode(xbmc.translatePath( DB_MUSIC_PATH = try_decode(xbmc.translatePath(
"special://database/MyMusic%s.db" % _DB_MUSIC_VERSION[KODIVERSION])) "special://database/MyMusic%s.db" % _DB_MUSIC_VERSION[KODIVERSION]))
_DB_TEXTURE_VERSION = { _DB_TEXTURE_VERSION = {
@ -108,12 +108,12 @@ _DB_TEXTURE_VERSION = {
17: 13, # Krypton 17: 13, # Krypton
18: 13 # Leia 18: 13 # Leia
} }
DB_TEXTURE_PATH = tryDecode(xbmc.translatePath( DB_TEXTURE_PATH = try_decode(xbmc.translatePath(
"special://database/Textures%s.db" % _DB_TEXTURE_VERSION[KODIVERSION])) "special://database/Textures%s.db" % _DB_TEXTURE_VERSION[KODIVERSION]))
DB_PLEX_PATH = tryDecode(xbmc.translatePath("special://database/plex.db")) DB_PLEX_PATH = try_decode(xbmc.translatePath("special://database/plex.db"))
EXTERNAL_SUBTITLE_TEMP_PATH = tryDecode(xbmc.translatePath( EXTERNAL_SUBTITLE_TEMP_PATH = try_decode(xbmc.translatePath(
"special://profile/addon_data/%s/temp/" % ADDON_ID)) "special://profile/addon_data/%s/temp/" % ADDON_ID))

View file

@ -8,8 +8,8 @@ from os import makedirs
import xbmc import xbmc
from xbmcvfs import exists from xbmcvfs import exists
from utils import window, settings, language as lang, tryEncode, indent, \ from utils import window, settings, language as lang, try_encode, indent, \
normalize_nodes, exists_dir, tryDecode normalize_nodes, exists_dir, try_decode
import variables as v import variables as v
############################################################################### ###############################################################################
@ -62,9 +62,9 @@ class VideoNodes(object):
dirname = viewid dirname = viewid
# Returns strings # Returns strings
path = tryDecode(xbmc.translatePath( path = try_decode(xbmc.translatePath(
"special://profile/library/video/")) "special://profile/library/video/"))
nodepath = tryDecode(xbmc.translatePath( nodepath = try_decode(xbmc.translatePath(
"special://profile/library/video/Plex-%s/" % dirname)) "special://profile/library/video/Plex-%s/" % dirname))
if delete: if delete:
@ -77,9 +77,9 @@ class VideoNodes(object):
# Verify the video directory # Verify the video directory
if not exists_dir(path): if not exists_dir(path):
copytree( copytree(
src=tryDecode(xbmc.translatePath( src=try_decode(xbmc.translatePath(
"special://xbmc/system/library/video")), "special://xbmc/system/library/video")),
dst=tryDecode(xbmc.translatePath( dst=try_decode(xbmc.translatePath(
"special://profile/library/video"))) "special://profile/library/video")))
# Create the node directory # Create the node directory
@ -292,7 +292,7 @@ class VideoNodes(object):
# To do: add our photos nodes to kodi picture sources somehow # To do: add our photos nodes to kodi picture sources somehow
continue continue
if exists(tryEncode(nodeXML)): if exists(try_encode(nodeXML)):
# Don't recreate xml if already exists # Don't recreate xml if already exists
continue continue
@ -378,9 +378,9 @@ class VideoNodes(object):
etree.ElementTree(root).write(nodeXML, encoding="UTF-8") etree.ElementTree(root).write(nodeXML, encoding="UTF-8")
def singleNode(self, indexnumber, tagname, mediatype, itemtype): def singleNode(self, indexnumber, tagname, mediatype, itemtype):
tagname = tryEncode(tagname) tagname = try_encode(tagname)
cleantagname = tryDecode(normalize_nodes(tagname)) cleantagname = try_decode(normalize_nodes(tagname))
nodepath = tryDecode(xbmc.translatePath( nodepath = try_decode(xbmc.translatePath(
"special://profile/library/video/")) "special://profile/library/video/"))
nodeXML = "%splex_%s.xml" % (nodepath, cleantagname) nodeXML = "%splex_%s.xml" % (nodepath, cleantagname)
path = "library://video/plex_%s.xml" % cleantagname path = "library://video/plex_%s.xml" % cleantagname
@ -394,9 +394,9 @@ class VideoNodes(object):
if not exists_dir(nodepath): if not exists_dir(nodepath):
# We need to copy over the default items # We need to copy over the default items
copytree( copytree(
src=tryDecode(xbmc.translatePath( src=try_decode(xbmc.translatePath(
"special://xbmc/system/library/video")), "special://xbmc/system/library/video")),
dst=tryDecode(xbmc.translatePath( dst=try_decode(xbmc.translatePath(
"special://profile/library/video"))) "special://profile/library/video")))
labels = { labels = {
@ -411,7 +411,7 @@ class VideoNodes(object):
window('%s.content' % embynode, value=path) window('%s.content' % embynode, value=path)
window('%s.type' % embynode, value=itemtype) window('%s.type' % embynode, value=itemtype)
if exists(tryEncode(nodeXML)): if exists(try_encode(nodeXML)):
# Don't recreate xml if already exists # Don't recreate xml if already exists
return return

View file

@ -292,7 +292,7 @@ class ABNF(object):
opcode: operation code. please see OPCODE_XXX. opcode: operation code. please see OPCODE_XXX.
""" """
if opcode == ABNF.OPCODE_TEXT and isinstance(data, unicode): if opcode == ABNF.OPCODE_TEXT and isinstance(data, unicode):
data = utils.tryEncode(data) data = utils.try_encode(data)
# mask must be set if send data from client # mask must be set if send data from client
return ABNF(1, 0, 0, 0, opcode, 1, data) return ABNF(1, 0, 0, 0, opcode, 1, data)