parent
60759ba625
commit
b2cd6e1156
9 changed files with 181 additions and 246 deletions
|
@ -39,11 +39,11 @@ import xml.etree.ElementTree as etree
|
|||
from re import compile as re_compile, sub
|
||||
from json import dumps
|
||||
from urllib import urlencode, quote_plus, unquote
|
||||
from os import path as os_path
|
||||
from os.path import basename, join, exists
|
||||
from os import makedirs
|
||||
|
||||
import xbmcgui
|
||||
from xbmc import sleep, executebuiltin
|
||||
from xbmcvfs import exists, mkdirs
|
||||
|
||||
import clientinfo as client
|
||||
from downloadutils import DownloadUtils
|
||||
|
@ -2113,11 +2113,14 @@ class API():
|
|||
if fanarttvimage not in data:
|
||||
continue
|
||||
for entry in data[fanarttvimage]:
|
||||
if fanartcount < maxfanarts:
|
||||
if exists(entry.get("url")):
|
||||
allartworks['Backdrop'].append(
|
||||
entry.get("url", "").replace(' ', '%20'))
|
||||
fanartcount += 1
|
||||
if entry.get("url") is None:
|
||||
continue
|
||||
if fanartcount > maxfanarts:
|
||||
break
|
||||
if exists(tryEncode(entry['url'])):
|
||||
allartworks['Backdrop'].append(
|
||||
entry['url'].replace(' ', '%20'))
|
||||
fanartcount += 1
|
||||
return allartworks
|
||||
|
||||
def getSetArtwork(self, parentInfo=False):
|
||||
|
@ -2184,7 +2187,7 @@ class API():
|
|||
# Get additional info (filename / languages)
|
||||
filename = None
|
||||
if 'file' in entry[0].attrib:
|
||||
filename = os_path.basename(entry[0].attrib['file'])
|
||||
filename = basename(entry[0].attrib['file'])
|
||||
# Languages of audio streams
|
||||
languages = []
|
||||
for stream in entry[0]:
|
||||
|
@ -2339,8 +2342,8 @@ class API():
|
|||
Returns the path to the downloaded subtitle or None
|
||||
"""
|
||||
if not exists(v.EXTERNAL_SUBTITLE_TEMP_PATH):
|
||||
mkdirs(v.EXTERNAL_SUBTITLE_TEMP_PATH)
|
||||
path = os_path.join(v.EXTERNAL_SUBTITLE_TEMP_PATH, filename)
|
||||
makedirs(v.EXTERNAL_SUBTITLE_TEMP_PATH)
|
||||
path = join(v.EXTERNAL_SUBTITLE_TEMP_PATH, filename)
|
||||
r = DownloadUtils().downloadUrl(url, return_response=True)
|
||||
try:
|
||||
r.status_code
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
import logging
|
||||
from json import dumps, loads
|
||||
import requests
|
||||
from os import path as os_path
|
||||
from os.path import exists
|
||||
from shutil import rmtree
|
||||
from urllib import quote_plus, unquote
|
||||
from threading import Thread
|
||||
from Queue import Queue, Empty
|
||||
|
||||
from xbmc import executeJSONRPC, sleep, translatePath
|
||||
from xbmcvfs import listdir, delete
|
||||
|
||||
from utils import window, settings, language as lang, kodiSQL, tryEncode, \
|
||||
tryDecode, IfExists, ThreadMethods, ThreadMethodsAdditionalStop, dialog
|
||||
ThreadMethods, ThreadMethodsAdditionalStop, dialog
|
||||
|
||||
# Disable annoying requests warnings
|
||||
import requests.packages.urllib3
|
||||
|
@ -228,30 +228,21 @@ class Artwork():
|
|||
if dialog('yesno', "Image Texture Cache", lang(39251)):
|
||||
log.info("Resetting all cache data first")
|
||||
# Remove all existing textures first
|
||||
path = tryDecode(translatePath("special://thumbnails/"))
|
||||
if IfExists(path):
|
||||
allDirs, allFiles = listdir(path)
|
||||
for dir in allDirs:
|
||||
allDirs, allFiles = listdir(path+dir)
|
||||
for file in allFiles:
|
||||
if os_path.supports_unicode_filenames:
|
||||
delete(os_path.join(
|
||||
path + tryDecode(dir),
|
||||
tryDecode(file)))
|
||||
else:
|
||||
delete(os_path.join(
|
||||
tryEncode(path) + dir,
|
||||
file))
|
||||
path = translatePath("special://thumbnails/")
|
||||
if exists(path):
|
||||
rmtree(path, ignore_errors=True)
|
||||
|
||||
# remove all existing data from texture DB
|
||||
connection = kodiSQL('texture')
|
||||
cursor = connection.cursor()
|
||||
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
|
||||
query = 'SELECT tbl_name FROM sqlite_master WHERE type=?'
|
||||
cursor.execute(query, ('table', ))
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
tableName = row[0]
|
||||
if tableName != "version":
|
||||
cursor.execute("DELETE FROM " + tableName)
|
||||
query = "DELETE FROM ?"
|
||||
cursor.execute(query, (tableName,))
|
||||
connection.commit()
|
||||
connection.close()
|
||||
|
||||
|
@ -259,7 +250,8 @@ class Artwork():
|
|||
connection = kodiSQL('video')
|
||||
cursor = connection.cursor()
|
||||
# dont include actors
|
||||
cursor.execute("SELECT url FROM art WHERE media_type != 'actor'")
|
||||
query = "SELECT url FROM art WHERE media_type != ?"
|
||||
cursor.execute(query, ('actor', ))
|
||||
result = cursor.fetchall()
|
||||
total = len(result)
|
||||
log.info("Image cache sync about to process %s video images" % total)
|
||||
|
@ -286,7 +278,6 @@ class Artwork():
|
|||
def addArtwork(self, artwork, kodiId, mediaType, cursor):
|
||||
# Kodi conversion table
|
||||
kodiart = {
|
||||
|
||||
'Primary': ["thumb", "poster"],
|
||||
'Banner': "banner",
|
||||
'Logo': "clearlogo",
|
||||
|
@ -307,7 +298,6 @@ class Artwork():
|
|||
backdropsNumber = len(backdrops)
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT url",
|
||||
"FROM art",
|
||||
"WHERE media_id = ?",
|
||||
|
@ -320,7 +310,6 @@ class Artwork():
|
|||
if len(rows) > backdropsNumber:
|
||||
# More backdrops in database. Delete extra fanart.
|
||||
query = ' '.join((
|
||||
|
||||
"DELETE FROM art",
|
||||
"WHERE media_id = ?",
|
||||
"AND media_type = ?",
|
||||
|
@ -339,7 +328,7 @@ class Artwork():
|
|||
cursor=cursor)
|
||||
|
||||
if backdropsNumber > 1:
|
||||
try: # Will only fail on the first try, str to int.
|
||||
try: # Will only fail on the first try, str to int.
|
||||
index += 1
|
||||
except TypeError:
|
||||
index = 1
|
||||
|
@ -438,14 +427,10 @@ class Artwork():
|
|||
log.info("Could not find cached url.")
|
||||
else:
|
||||
# Delete thumbnail as well as the entry
|
||||
thumbnails = tryDecode(
|
||||
translatePath("special://thumbnails/%s" % cachedurl))
|
||||
log.debug("Deleting cached thumbnail: %s" % thumbnails)
|
||||
try:
|
||||
delete(thumbnails)
|
||||
except Exception as e:
|
||||
log.error('Could not delete cached artwork %s. Error: %s'
|
||||
% (thumbnails, e))
|
||||
path = translatePath("special://thumbnails/%s" % cachedurl)
|
||||
log.debug("Deleting cached thumbnail: %s" % path)
|
||||
if exists(path):
|
||||
rmtree(path, ignore_errors=True)
|
||||
cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
|
||||
connection.commit()
|
||||
finally:
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###############################################################################
|
||||
import logging
|
||||
from os import path as os_path
|
||||
from shutil import copyfile
|
||||
from os import walk, makedirs
|
||||
from os.path import basename, join, exists
|
||||
from sys import argv
|
||||
from urllib import urlencode
|
||||
|
||||
|
@ -9,8 +11,8 @@ import xbmcplugin
|
|||
from xbmc import sleep, executebuiltin, translatePath
|
||||
from xbmcgui import ListItem
|
||||
|
||||
from utils import window, settings, language as lang, dialog, tryDecode,\
|
||||
tryEncode, CatchExceptions, JSONRPC
|
||||
from utils import window, settings, language as lang, dialog, tryEncode, \
|
||||
CatchExceptions, JSONRPC
|
||||
import downloadutils
|
||||
|
||||
from PlexFunctions import GetPlexMetadata, GetPlexSectionResults, \
|
||||
|
@ -486,6 +488,7 @@ def getVideoFiles(plexId, params):
|
|||
except:
|
||||
log.error('Could not get file path for item %s' % plexId)
|
||||
return xbmcplugin.endOfDirectory(HANDLE)
|
||||
path = tryEncode(path)
|
||||
# Assign network protocol
|
||||
if path.startswith('\\\\'):
|
||||
path = path.replace('\\\\', 'smb://')
|
||||
|
@ -493,28 +496,25 @@ def getVideoFiles(plexId, params):
|
|||
# Plex returns Windows paths as e.g. 'c:\slfkjelf\slfje\file.mkv'
|
||||
elif '\\' in path:
|
||||
path = path.replace('\\', '\\\\')
|
||||
# Directory only, get rid of filename (!! exists() needs / or \ at end)
|
||||
path = path.replace(os_path.basename(path), '')
|
||||
# Only proceed if we can access this folder
|
||||
import xbmcvfs
|
||||
if xbmcvfs.exists(path):
|
||||
# Careful, returns encoded strings!
|
||||
dirs, files = xbmcvfs.listdir(path)
|
||||
for file in files:
|
||||
file = path + tryDecode(file)
|
||||
li = ListItem(file, path=file)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=tryEncode(file),
|
||||
listitem=li)
|
||||
for dir in dirs:
|
||||
dir = path + tryDecode(dir)
|
||||
li = ListItem(dir, path=dir)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=tryEncode(dir),
|
||||
listitem=li,
|
||||
isFolder=True)
|
||||
# Directory only, get rid of filename
|
||||
path = path.replace(basename(path), '')
|
||||
if exists(path):
|
||||
for root, dirs, files in walk(path):
|
||||
for directory in dirs:
|
||||
item_path = join(root, directory)
|
||||
li = ListItem(item_path, path=item_path)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=item_path,
|
||||
listitem=li,
|
||||
isFolder=True)
|
||||
for file in files:
|
||||
item_path = join(root, file)
|
||||
li = ListItem(item_path, path=item_path)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=file,
|
||||
listitem=li)
|
||||
else:
|
||||
log.warn('Kodi cannot access folder %s' % path)
|
||||
log.error('Kodi cannot access folder %s' % path)
|
||||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
|
||||
|
@ -525,7 +525,6 @@ def getExtraFanArt(plexid, plexPath):
|
|||
will be called by skinhelper script to get the extrafanart
|
||||
for tvshows we get the plexid just from the path
|
||||
"""
|
||||
import xbmcvfs
|
||||
log.debug('Called with plexid: %s, plexPath: %s' % (plexid, plexPath))
|
||||
if not plexid:
|
||||
if "plugin.video.plexkodiconnect" in plexPath:
|
||||
|
@ -536,11 +535,10 @@ def getExtraFanArt(plexid, plexPath):
|
|||
|
||||
# We need to store the images locally for this to work
|
||||
# because of the caching system in xbmc
|
||||
fanartDir = tryDecode(translatePath(
|
||||
"special://thumbnails/plex/%s/" % plexid))
|
||||
if not xbmcvfs.exists(fanartDir):
|
||||
fanartDir = translatePath("special://thumbnails/plex/%s/" % plexid)
|
||||
if not exists(fanartDir):
|
||||
# Download the images to the cache directory
|
||||
xbmcvfs.mkdirs(tryEncode(fanartDir))
|
||||
makedirs(fanartDir)
|
||||
xml = GetPlexMetadata(plexid)
|
||||
if xml is None:
|
||||
log.error('Could not download metadata for %s' % plexid)
|
||||
|
@ -550,29 +548,23 @@ def getExtraFanArt(plexid, plexPath):
|
|||
backdrops = api.getAllArtwork()['Backdrop']
|
||||
for count, backdrop in enumerate(backdrops):
|
||||
# Same ordering as in artwork
|
||||
if os_path.supports_unicode_filenames:
|
||||
fanartFile = os_path.join(fanartDir,
|
||||
"fanart%.3d.jpg" % count)
|
||||
else:
|
||||
fanartFile = os_path.join(
|
||||
tryEncode(fanartDir),
|
||||
tryEncode("fanart%.3d.jpg" % count))
|
||||
fanartFile = join(fanartDir, "fanart%.3d.jpg" % count)
|
||||
li = ListItem("%.3d" % count, path=fanartFile)
|
||||
xbmcplugin.addDirectoryItem(
|
||||
handle=HANDLE,
|
||||
url=fanartFile,
|
||||
listitem=li)
|
||||
xbmcvfs.copy(backdrop, fanartFile)
|
||||
copyfile(backdrop, fanartFile)
|
||||
else:
|
||||
log.info("Found cached backdrop.")
|
||||
# Use existing cached images
|
||||
dirs, files = xbmcvfs.listdir(fanartDir)
|
||||
for file in files:
|
||||
fanartFile = os_path.join(fanartDir, tryDecode(file))
|
||||
li = ListItem(file, path=fanartFile)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=fanartFile,
|
||||
listitem=li)
|
||||
for root, dirs, files in walk(fanartDir):
|
||||
for file in files:
|
||||
fanartFile = join(root, file)
|
||||
li = ListItem(file, path=fanartFile)
|
||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||
url=fanartFile,
|
||||
listitem=li)
|
||||
xbmcplugin.endOfDirectory(HANDLE)
|
||||
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
###############################################################################
|
||||
|
||||
import logging
|
||||
from threading import Thread
|
||||
import Queue
|
||||
from random import shuffle
|
||||
from os.path import exists
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcvfs
|
||||
|
||||
from utils import window, settings, getUnixTimestamp, sourcesXML,\
|
||||
ThreadMethods, ThreadMethodsAdditionalStop, LogTime, getScreensaver,\
|
||||
|
@ -1505,7 +1503,7 @@ class LibrarySync(Thread):
|
|||
# Also runs when first installed
|
||||
# Verify the video database can be found
|
||||
videoDb = v.DB_VIDEO_PATH
|
||||
if not xbmcvfs.exists(videoDb):
|
||||
if not exists(videoDb):
|
||||
# Database does not exists
|
||||
log.error("The current Kodi version is incompatible "
|
||||
"to know which Kodi versions are supported.")
|
||||
|
|
|
@ -3,14 +3,15 @@
|
|||
###############################################################################
|
||||
import logging
|
||||
import threading
|
||||
from os.path import exists
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
import xbmcvfs
|
||||
|
||||
|
||||
from utils import window, settings, language as lang, ThreadMethods, \
|
||||
tryDecode, ThreadMethodsAdditionalSuspend
|
||||
ThreadMethodsAdditionalSuspend
|
||||
import downloadutils
|
||||
|
||||
import PlexAPI
|
||||
|
@ -209,9 +210,8 @@ class UserClient(threading.Thread):
|
|||
return False
|
||||
|
||||
# Get /profile/addon_data
|
||||
addondir = tryDecode(xbmc.translatePath(
|
||||
self.addon.getAddonInfo('profile')))
|
||||
hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)
|
||||
addondir = xbmc.translatePath(self.addon.getAddonInfo('profile'))
|
||||
hasSettings = exists("%ssettings.xml" % addondir)
|
||||
|
||||
# If there's no settings.xml
|
||||
if not hasSettings:
|
||||
|
|
|
@ -13,12 +13,13 @@ from unicodedata import normalize
|
|||
import xml.etree.ElementTree as etree
|
||||
from functools import wraps
|
||||
from calendar import timegm
|
||||
from os import path as os_path
|
||||
from os.path import exists, join
|
||||
from os import remove, makedirs, walk
|
||||
from shutil import rmtree
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
import xbmcvfs
|
||||
|
||||
from variables import DB_VIDEO_PATH, DB_MUSIC_PATH, DB_TEXTURE_PATH, \
|
||||
DB_PLEX_PATH
|
||||
|
@ -198,27 +199,6 @@ def DateToKodi(stamp):
|
|||
return localdate
|
||||
|
||||
|
||||
def IfExists(path):
|
||||
"""
|
||||
Kodi's xbmcvfs.exists is broken - it caches the results for directories.
|
||||
|
||||
path: path to a directory (with a slash at the end)
|
||||
|
||||
Returns True if path exists, else false
|
||||
"""
|
||||
dummyfile = tryEncode(os_path.join(path, 'dummyfile.txt'))
|
||||
try:
|
||||
etree.ElementTree(etree.Element('test')).write(dummyfile)
|
||||
except:
|
||||
# folder does not exist yet
|
||||
answer = False
|
||||
else:
|
||||
# Folder exists. Delete file again.
|
||||
xbmcvfs.delete(dummyfile)
|
||||
answer = True
|
||||
return answer
|
||||
|
||||
|
||||
def IntFromStr(string):
|
||||
"""
|
||||
Returns an int from string or the int 0 if something happened
|
||||
|
@ -362,24 +342,14 @@ def reset():
|
|||
line1=language(39602)):
|
||||
log.info("Resetting all cached artwork.")
|
||||
# Remove all existing textures first
|
||||
path = tryDecode(xbmc.translatePath("special://thumbnails/"))
|
||||
if xbmcvfs.exists(path):
|
||||
allDirs, allFiles = xbmcvfs.listdir(path)
|
||||
for dir in allDirs:
|
||||
allDirs, allFiles = xbmcvfs.listdir(path+dir)
|
||||
for file in allFiles:
|
||||
if os_path.supports_unicode_filenames:
|
||||
xbmcvfs.delete(os_path.join(
|
||||
path + tryDecode(dir),
|
||||
tryDecode(file)))
|
||||
else:
|
||||
xbmcvfs.delete(os_path.join(
|
||||
tryEncode(path) + dir,
|
||||
file))
|
||||
path = xbmc.translatePath("special://thumbnails/")
|
||||
if exists(path):
|
||||
rmtree(path, ignore_errors=True)
|
||||
# remove all existing data from texture DB
|
||||
connection = kodiSQL('texture')
|
||||
cursor = connection.cursor()
|
||||
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
|
||||
query = 'SELECT tbl_name FROM sqlite_master WHERE type=?'
|
||||
cursor.execute(query, ("table", ))
|
||||
rows = cursor.fetchall()
|
||||
for row in rows:
|
||||
tableName = row[0]
|
||||
|
@ -398,10 +368,10 @@ def reset():
|
|||
line1=language(39603)):
|
||||
# Delete the settings
|
||||
addon = xbmcaddon.Addon()
|
||||
addondir = tryDecode(xbmc.translatePath(addon.getAddonInfo('profile')))
|
||||
addondir = xbmc.translatePath(addon.getAddonInfo('profile'))
|
||||
dataPath = "%ssettings.xml" % addondir
|
||||
log.info("Deleting: settings.xml")
|
||||
xbmcvfs.delete(tryEncode(dataPath))
|
||||
remove(dataPath)
|
||||
|
||||
# Kodi will now restart to apply the changes.
|
||||
dialog('ok',
|
||||
|
@ -664,12 +634,13 @@ def sourcesXML():
|
|||
|
||||
def passwordsXML():
|
||||
# To add network credentials
|
||||
path = tryDecode(xbmc.translatePath("special://userdata/"))
|
||||
path = xbmc.translatePath("special://userdata/")
|
||||
xmlpath = "%spasswords.xml" % path
|
||||
|
||||
try:
|
||||
xmlparse = etree.parse(xmlpath)
|
||||
except: # Document is blank or missing
|
||||
except:
|
||||
# Document is blank or missing
|
||||
root = etree.Element('passwords')
|
||||
skipFind = True
|
||||
else:
|
||||
|
@ -753,8 +724,6 @@ def passwordsXML():
|
|||
etree.SubElement(path, 'from', attrib={'pathversion': "1"}).text = "smb://%s/" % server
|
||||
topath = "smb://%s:%s@%s/" % (user, password, server)
|
||||
etree.SubElement(path, 'to', attrib={'pathversion': "1"}).text = topath
|
||||
# Force Kodi to see the credentials without restarting
|
||||
xbmcvfs.exists(topath)
|
||||
|
||||
# Add credentials
|
||||
settings('networkCreds', value="%s" % server)
|
||||
|
@ -762,7 +731,8 @@ def passwordsXML():
|
|||
# Prettify and write to file
|
||||
try:
|
||||
indent(root)
|
||||
except: pass
|
||||
except:
|
||||
pass
|
||||
etree.ElementTree(root).write(xmlpath)
|
||||
|
||||
# dialog.notification(
|
||||
|
@ -776,7 +746,7 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
|
|||
"""
|
||||
Feed with tagname as unicode
|
||||
"""
|
||||
path = tryDecode(xbmc.translatePath("special://profile/playlists/video/"))
|
||||
path = xbmc.translatePath("special://profile/playlists/video/")
|
||||
if viewtype == "mixed":
|
||||
plname = "%s - %s" % (tagname, mediatype)
|
||||
xsppath = "%sPlex %s - %s.xsp" % (path, viewid, mediatype)
|
||||
|
@ -785,20 +755,20 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
|
|||
xsppath = "%sPlex %s.xsp" % (path, viewid)
|
||||
|
||||
# Create the playlist directory
|
||||
if not xbmcvfs.exists(tryEncode(path)):
|
||||
if not exists(path):
|
||||
log.info("Creating directory: %s" % path)
|
||||
xbmcvfs.mkdirs(tryEncode(path))
|
||||
makedirs(path)
|
||||
|
||||
# Only add the playlist if it doesn't already exists
|
||||
if xbmcvfs.exists(tryEncode(xsppath)):
|
||||
if exists(xsppath):
|
||||
log.info('Path %s does exist' % xsppath)
|
||||
if delete:
|
||||
xbmcvfs.delete(tryEncode(xsppath))
|
||||
remove(xsppath)
|
||||
log.info("Successfully removed playlist: %s." % tagname)
|
||||
|
||||
return
|
||||
|
||||
# Using write process since there's no guarantee the xml declaration works with etree
|
||||
# Using write process since there's no guarantee the xml declaration works
|
||||
# with etree
|
||||
itemtypes = {
|
||||
'homevideos': 'movies',
|
||||
'movie': 'movies',
|
||||
|
@ -806,51 +776,39 @@ def playlistXSP(mediatype, tagname, viewid, viewtype="", delete=False):
|
|||
}
|
||||
log.info("Writing playlist file to: %s" % xsppath)
|
||||
try:
|
||||
f = xbmcvfs.File(tryEncode(xsppath), 'wb')
|
||||
except:
|
||||
with open(xsppath, 'wb'):
|
||||
tryEncode(
|
||||
'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
|
||||
'<smartplaylist type="%s">\n\t'
|
||||
'<name>Plex %s</name>\n\t'
|
||||
'<match>all</match>\n\t'
|
||||
'<rule field="tag" operator="is">\n\t\t'
|
||||
'<value>%s</value>\n\t'
|
||||
'</rule>\n'
|
||||
'</smartplaylist>\n'
|
||||
% (itemtypes.get(mediatype, mediatype), plname, tagname))
|
||||
except Exception as e:
|
||||
log.error("Failed to create playlist: %s" % xsppath)
|
||||
log.error(e)
|
||||
return
|
||||
else:
|
||||
f.write(tryEncode(
|
||||
'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n'
|
||||
'<smartplaylist type="%s">\n\t'
|
||||
'<name>Plex %s</name>\n\t'
|
||||
'<match>all</match>\n\t'
|
||||
'<rule field="tag" operator="is">\n\t\t'
|
||||
'<value>%s</value>\n\t'
|
||||
'</rule>\n'
|
||||
'</smartplaylist>\n'
|
||||
% (itemtypes.get(mediatype, mediatype), plname, tagname)))
|
||||
f.close()
|
||||
log.info("Successfully added playlist: %s" % tagname)
|
||||
|
||||
def deletePlaylists():
|
||||
|
||||
# Clean up the playlists
|
||||
path = tryDecode(xbmc.translatePath("special://profile/playlists/video/"))
|
||||
dirs, files = xbmcvfs.listdir(tryEncode(path))
|
||||
for file in files:
|
||||
if tryDecode(file).startswith('Plex'):
|
||||
xbmcvfs.delete(tryEncode("%s%s" % (path, tryDecode(file))))
|
||||
path = xbmc.translatePath("special://profile/playlists/video/")
|
||||
for root, _, files in walk(path):
|
||||
for file in files:
|
||||
if file.startswith('Plex'):
|
||||
remove(join(root, file))
|
||||
|
||||
def deleteNodes():
|
||||
|
||||
# Clean up video nodes
|
||||
import shutil
|
||||
path = tryDecode(xbmc.translatePath("special://profile/library/video/"))
|
||||
dirs, files = xbmcvfs.listdir(tryEncode(path))
|
||||
for dir in dirs:
|
||||
if tryDecode(dir).startswith('Plex'):
|
||||
try:
|
||||
shutil.rmtree("%s%s" % (path, tryDecode(dir)))
|
||||
except:
|
||||
log.error("Failed to delete directory: %s" % tryDecode(dir))
|
||||
for file in files:
|
||||
if tryDecode(file).startswith('plex'):
|
||||
try:
|
||||
xbmcvfs.delete(tryEncode("%s%s" % (path, tryDecode(file))))
|
||||
except:
|
||||
log.error("Failed to file: %s" % tryDecode(file))
|
||||
path = xbmc.translatePath("special://profile/library/video/")
|
||||
for root, dirs, _ in walk(path):
|
||||
for directory in dirs:
|
||||
if directory.startswith('Plex-'):
|
||||
rmtree(join(root, directory))
|
||||
break
|
||||
|
||||
|
||||
###############################################################################
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
import xbmc
|
||||
from xbmcaddon import Addon
|
||||
|
||||
# Paths are in string, not unicode!
|
||||
|
||||
|
||||
def tryDecode(string, encoding='utf-8'):
|
||||
"""
|
||||
|
@ -27,7 +29,7 @@ ADDON_VERSION = _ADDON.getAddonInfo('version')
|
|||
KODILANGUAGE = xbmc.getLanguage(xbmc.ISO_639_1)
|
||||
KODIVERSION = int(xbmc.getInfoLabel("System.BuildVersion")[:2])
|
||||
KODILONGVERSION = xbmc.getInfoLabel('System.BuildVersion')
|
||||
KODI_PROFILE = tryDecode(xbmc.translatePath("special://profile"))
|
||||
KODI_PROFILE = xbmc.translatePath("special://profile")
|
||||
|
||||
if xbmc.getCondVisibility('system.platform.osx'):
|
||||
PLATFORM = "MacOSX"
|
||||
|
@ -68,8 +70,8 @@ _DB_VIDEO_VERSION = {
|
|||
17: 107, # Krypton
|
||||
18: 107 # Leia
|
||||
}
|
||||
DB_VIDEO_PATH = tryDecode(xbmc.translatePath(
|
||||
"special://database/MyVideos%s.db" % _DB_VIDEO_VERSION[KODIVERSION]))
|
||||
DB_VIDEO_PATH = xbmc.translatePath(
|
||||
"special://database/MyVideos%s.db" % _DB_VIDEO_VERSION[KODIVERSION])
|
||||
|
||||
_DB_MUSIC_VERSION = {
|
||||
13: 46, # Gotham
|
||||
|
@ -79,8 +81,8 @@ _DB_MUSIC_VERSION = {
|
|||
17: 60, # Krypton
|
||||
18: 60 # Leia
|
||||
}
|
||||
DB_MUSIC_PATH = tryDecode(xbmc.translatePath(
|
||||
"special://database/MyMusic%s.db" % _DB_MUSIC_VERSION[KODIVERSION]))
|
||||
DB_MUSIC_PATH = xbmc.translatePath(
|
||||
"special://database/MyMusic%s.db" % _DB_MUSIC_VERSION[KODIVERSION])
|
||||
|
||||
_DB_TEXTURE_VERSION = {
|
||||
13: 13, # Gotham
|
||||
|
@ -90,13 +92,13 @@ _DB_TEXTURE_VERSION = {
|
|||
17: 13, # Krypton
|
||||
18: 13 # Leia
|
||||
}
|
||||
DB_TEXTURE_PATH = tryDecode(xbmc.translatePath(
|
||||
"special://database/Textures%s.db" % _DB_TEXTURE_VERSION[KODIVERSION]))
|
||||
DB_TEXTURE_PATH = xbmc.translatePath(
|
||||
"special://database/Textures%s.db" % _DB_TEXTURE_VERSION[KODIVERSION])
|
||||
|
||||
DB_PLEX_PATH = tryDecode(xbmc.translatePath("special://database/plex.db"))
|
||||
DB_PLEX_PATH = xbmc.translatePath("special://database/plex.db")
|
||||
|
||||
EXTERNAL_SUBTITLE_TEMP_PATH = tryDecode(xbmc.translatePath(
|
||||
"special://profile/addon_data/%s/temp/" % ADDON_ID))
|
||||
EXTERNAL_SUBTITLE_TEMP_PATH = xbmc.translatePath(
|
||||
"special://profile/addon_data/%s/temp/" % ADDON_ID)
|
||||
|
||||
|
||||
# Multiply Plex time by this factor to receive Kodi time
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
###############################################################################
|
||||
|
||||
import logging
|
||||
import shutil
|
||||
from shutil import copytree
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
import xbmc
|
||||
import xbmcvfs
|
||||
from os import remove, makedirs, listdir
|
||||
from os.path import exists, isfile, join
|
||||
|
||||
from utils import window, settings, language as lang, IfExists, tryDecode, \
|
||||
tryEncode, indent, normalize_nodes
|
||||
from utils import window, settings, language as lang, tryEncode, indent, \
|
||||
normalize_nodes
|
||||
import variables as v
|
||||
|
||||
###############################################################################
|
||||
|
@ -18,6 +17,7 @@ import variables as v
|
|||
log = logging.getLogger("PLEX."+__name__)
|
||||
|
||||
###############################################################################
|
||||
# Paths are strings, NOT unicode!
|
||||
|
||||
|
||||
class VideoNodes(object):
|
||||
|
@ -61,36 +61,30 @@ class VideoNodes(object):
|
|||
else:
|
||||
dirname = viewid
|
||||
|
||||
path = tryDecode(xbmc.translatePath(
|
||||
"special://profile/library/video/"))
|
||||
nodepath = tryDecode(xbmc.translatePath(
|
||||
"special://profile/library/video/Plex-%s/" % dirname))
|
||||
# Returns strings
|
||||
path = xbmc.translatePath("special://profile/library/video/")
|
||||
nodepath = xbmc.translatePath(
|
||||
"special://profile/library/video/Plex-%s/" % dirname)
|
||||
|
||||
if delete:
|
||||
dirs, files = xbmcvfs.listdir(tryEncode(nodepath))
|
||||
files = [f for f in listdir(nodepath) if isfile(join(nodepath, f))]
|
||||
for file in files:
|
||||
xbmcvfs.delete(tryEncode(
|
||||
(nodepath + tryDecode(file))))
|
||||
remove(nodepath + file)
|
||||
log.info("Sucessfully removed videonode: %s." % tagname)
|
||||
return
|
||||
|
||||
# Verify the video directory
|
||||
# KODI BUG
|
||||
# Kodi caches the result of exists for directories
|
||||
# so try creating a file
|
||||
if IfExists(path) is False:
|
||||
shutil.copytree(
|
||||
src=tryDecode(xbmc.translatePath(
|
||||
"special://xbmc/system/library/video")),
|
||||
dst=tryDecode(xbmc.translatePath(
|
||||
"special://profile/library/video")))
|
||||
if exists(path) is False:
|
||||
copytree(
|
||||
src=xbmc.translatePath("special://xbmc/system/library/video"),
|
||||
dst=xbmc.translatePath("special://profile/library/video"))
|
||||
|
||||
# Create the node directory
|
||||
if mediatype != "photos":
|
||||
if IfExists(nodepath) is False:
|
||||
if exists(nodepath) is False:
|
||||
# folder does not exist yet
|
||||
log.debug('Creating folder %s' % nodepath)
|
||||
xbmcvfs.mkdirs(tryEncode(nodepath))
|
||||
makedirs(nodepath)
|
||||
|
||||
# Create index entry
|
||||
nodeXML = "%sindex.xml" % nodepath
|
||||
|
@ -103,23 +97,29 @@ class VideoNodes(object):
|
|||
|
||||
if mediatype == "photos":
|
||||
path = "plugin://plugin.video.plexkodiconnect?mode=browseplex&key=/library/sections/%s&id=%s" % (viewid, viewid)
|
||||
|
||||
|
||||
window('Plex.nodes.%s.index' % indexnumber, value=path)
|
||||
|
||||
|
||||
# Root
|
||||
if not mediatype == "photos":
|
||||
if viewtype == "mixed":
|
||||
specialtag = "%s-%s" % (tagname, mediatype)
|
||||
root = self.commonRoot(order=0, label=specialtag, tagname=tagname, roottype=0)
|
||||
root = self.commonRoot(order=0,
|
||||
label=specialtag,
|
||||
tagname=tagname,
|
||||
roottype=0)
|
||||
else:
|
||||
root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0)
|
||||
root = self.commonRoot(order=0,
|
||||
label=tagname,
|
||||
tagname=tagname,
|
||||
roottype=0)
|
||||
try:
|
||||
indent(root)
|
||||
except: pass
|
||||
except:
|
||||
pass
|
||||
etree.ElementTree(root).write(nodeXML)
|
||||
|
||||
nodetypes = {
|
||||
|
||||
'1': "all",
|
||||
'2': "recent",
|
||||
'3': "recentepisodes",
|
||||
|
@ -255,7 +255,7 @@ class VideoNodes(object):
|
|||
path = 'plugin://plugin.video.plexkodiconnect?mode=browseplex&key=/library/sections/%s/folder' % viewid
|
||||
else:
|
||||
path = "library://video/Plex-%s/%s_%s.xml" % (dirname, viewid, nodetype)
|
||||
|
||||
|
||||
if mediatype == "photos":
|
||||
windowpath = "ActivateWindow(Pictures,%s,return)" % path
|
||||
else:
|
||||
|
@ -264,7 +264,7 @@ class VideoNodes(object):
|
|||
windowpath = "ActivateWindow(Videos,%s,return)" % path
|
||||
else:
|
||||
windowpath = "ActivateWindow(Video,%s,return)" % path
|
||||
|
||||
|
||||
if nodetype == "all":
|
||||
|
||||
if viewtype == "mixed":
|
||||
|
@ -288,8 +288,8 @@ class VideoNodes(object):
|
|||
# to be created.
|
||||
# To do: add our photos nodes to kodi picture sources somehow
|
||||
continue
|
||||
|
||||
if xbmcvfs.exists(tryEncode(nodeXML)):
|
||||
|
||||
if exists(nodeXML):
|
||||
# Don't recreate xml if already exists
|
||||
continue
|
||||
|
||||
|
@ -370,15 +370,14 @@ class VideoNodes(object):
|
|||
|
||||
try:
|
||||
indent(root)
|
||||
except: pass
|
||||
except:
|
||||
pass
|
||||
etree.ElementTree(root).write(nodeXML)
|
||||
|
||||
def singleNode(self, indexnumber, tagname, mediatype, itemtype):
|
||||
|
||||
tagname = tryEncode(tagname)
|
||||
cleantagname = normalize_nodes(tagname)
|
||||
nodepath = tryDecode(xbmc.translatePath(
|
||||
"special://profile/library/video/"))
|
||||
nodepath = xbmc.translatePath("special://profile/library/video/")
|
||||
nodeXML = "%splex_%s.xml" % (nodepath, cleantagname)
|
||||
path = "library://video/plex_%s.xml" % cleantagname
|
||||
if v.KODIVERSION >= 17:
|
||||
|
@ -388,17 +387,13 @@ class VideoNodes(object):
|
|||
windowpath = "ActivateWindow(Video,%s,return)" % path
|
||||
|
||||
# Create the video node directory
|
||||
if not xbmcvfs.exists(nodepath):
|
||||
if not exists(nodepath):
|
||||
# We need to copy over the default items
|
||||
shutil.copytree(
|
||||
src=tryDecode(xbmc.translatePath(
|
||||
"special://xbmc/system/library/video")),
|
||||
dst=tryDecode(xbmc.translatePath(
|
||||
"special://profile/library/video")))
|
||||
xbmcvfs.exists(path)
|
||||
copytree(
|
||||
src=xbmc.translatePath("special://xbmc/system/library/video"),
|
||||
dst=xbmc.translatePath("special://profile/library/video"))
|
||||
|
||||
labels = {
|
||||
|
||||
'Favorite movies': 30180,
|
||||
'Favorite tvshows': 30181,
|
||||
'channels': 30173
|
||||
|
@ -410,12 +405,15 @@ class VideoNodes(object):
|
|||
window('%s.content' % embynode, value=path)
|
||||
window('%s.type' % embynode, value=itemtype)
|
||||
|
||||
if xbmcvfs.exists(nodeXML):
|
||||
if exists(nodeXML):
|
||||
# Don't recreate xml if already exists
|
||||
return
|
||||
|
||||
if itemtype == "channels":
|
||||
root = self.commonRoot(order=1, label=label, tagname=tagname, roottype=2)
|
||||
root = self.commonRoot(order=1,
|
||||
label=label,
|
||||
tagname=tagname,
|
||||
roottype=2)
|
||||
etree.SubElement(root, 'path').text = "plugin://plugin.video.plexkodiconnect/?id=0&mode=channels"
|
||||
else:
|
||||
root = self.commonRoot(order=1, label=label, tagname=tagname)
|
||||
|
@ -425,7 +423,8 @@ class VideoNodes(object):
|
|||
|
||||
try:
|
||||
indent(root)
|
||||
except: pass
|
||||
except:
|
||||
pass
|
||||
etree.ElementTree(root).write(nodeXML)
|
||||
|
||||
def clearProperties(self):
|
||||
|
@ -433,7 +432,6 @@ class VideoNodes(object):
|
|||
log.info("Clearing nodes properties.")
|
||||
plexprops = window('Plex.nodes.total')
|
||||
propnames = [
|
||||
|
||||
"index","path","title","content",
|
||||
"inprogress.content","inprogress.title",
|
||||
"inprogress.content","inprogress.path",
|
||||
|
|
|
@ -164,12 +164,11 @@ class Service():
|
|||
counter = 0
|
||||
while not monitor.abortRequested():
|
||||
|
||||
if tryDecode(window('plex_kodiProfile')) != kodiProfile:
|
||||
if window('plex_kodiProfile') != kodiProfile:
|
||||
# Profile change happened, terminate this thread and others
|
||||
log.warn("Kodi profile was: %s and changed to: %s. "
|
||||
"Terminating old PlexKodiConnect thread."
|
||||
% (kodiProfile,
|
||||
tryDecode(window('plex_kodiProfile'))))
|
||||
% (kodiProfile, window('plex_kodiProfile')))
|
||||
break
|
||||
|
||||
# Before proceeding, need to make sure:
|
||||
|
|
Loading…
Reference in a new issue