diff --git a/resources/lib/kodidb_functions.py b/resources/lib/kodidb_functions.py
deleted file mode 100644
index e486250b..00000000
--- a/resources/lib/kodidb_functions.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# -*- coding: utf-8 -*-
-
-##################################################################################################
-
-import logging
-
-import xbmc
-
-import api
-import artwork
-
-#################################################################################################
-
-log = logging.getLogger("EMBY."+__name__)
-
-#################################################################################################
-
-class Kodidb_Functions(object):
-
- kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2])
-
-
- def __init__(self, cursor):
-
- self.cursor = cursor
- self.artwork = artwork.Artwork()
-
- def createTag(self, name):
- # This will create and return the tag_id
- if self.kodiversion in (15, 16, 17):
- # Kodi Isengard, Jarvis, Krypton
- query = ' '.join((
-
- "SELECT tag_id",
- "FROM tag",
- "WHERE name = ?",
- "COLLATE NOCASE"
- ))
- self.cursor.execute(query, (name,))
- try:
- tag_id = self.cursor.fetchone()[0]
-
- except TypeError:
- self.cursor.execute("select coalesce(max(tag_id),0) from tag")
- tag_id = self.cursor.fetchone()[0] + 1
-
- query = "INSERT INTO tag(tag_id, name) values(?, ?)"
- self.cursor.execute(query, (tag_id, name))
- log.debug("Create tag_id: %s name: %s", tag_id, name)
- else:
- # Kodi Helix
- query = ' '.join((
-
- "SELECT idTag",
- "FROM tag",
- "WHERE strTag = ?",
- "COLLATE NOCASE"
- ))
- self.cursor.execute(query, (name,))
- try:
- tag_id = self.cursor.fetchone()[0]
-
- except TypeError:
- self.cursor.execute("select coalesce(max(idTag),0) from tag")
- tag_id = self.cursor.fetchone()[0] + 1
-
- query = "INSERT INTO tag(idTag, strTag) values(?, ?)"
- self.cursor.execute(query, (tag_id, name))
- log.debug("Create idTag: %s name: %s", tag_id, name)
-
- return tag_id
-
- def updateTag(self, oldtag, newtag, kodiid, mediatype):
- # TODO: Move to video nodes eventually
- log.debug("Updating: %s with %s for %s: %s", oldtag, newtag, mediatype, kodiid)
-
- if self.kodiversion in (15, 16, 17):
- # Kodi Isengard, Jarvis, Krypton
- try:
- query = ' '.join((
-
- "UPDATE tag_link",
- "SET tag_id = ?",
- "WHERE media_id = ?",
- "AND media_type = ?",
- "AND tag_id = ?"
- ))
- self.cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
- except Exception:
- # The new tag we are going to apply already exists for this item
- # delete current tag instead
- query = ' '.join((
-
- "DELETE FROM tag_link",
- "WHERE media_id = ?",
- "AND media_type = ?",
- "AND tag_id = ?"
- ))
- self.cursor.execute(query, (kodiid, mediatype, oldtag,))
- else:
- # Kodi Helix
- try:
- query = ' '.join((
-
- "UPDATE taglinks",
- "SET idTag = ?",
- "WHERE idMedia = ?",
- "AND media_type = ?",
- "AND idTag = ?"
- ))
- self.cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
- except Exception:
- # The new tag we are going to apply already exists for this item
- # delete current tag instead
- query = ' '.join((
-
- "DELETE FROM taglinks",
- "WHERE idMedia = ?",
- "AND media_type = ?",
- "AND idTag = ?"
- ))
- self.cursor.execute(query, (kodiid, mediatype, oldtag,))
diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py
index 0dabebe9..8d302a97 100644
--- a/resources/lib/librarysync.py
+++ b/resources/lib/librarysync.py
@@ -17,10 +17,9 @@ import clientinfo
import downloadutils
import itemtypes
import embydb_functions as embydb
-import kodidb_functions as kodidb
import read_embyserver as embyserver
import userclient
-import videonodes
+import views
from objects import Movies, MusicVideos, TVShows, Music
from utils import window, settings, language as lang, should_stop
from ga_client import GoogleAnalytics
@@ -60,7 +59,6 @@ class LibrarySync(threading.Thread):
self.doUtils = downloadutils.DownloadUtils().downloadUrl
self.user = userclient.UserClient()
self.emby = embyserver.Read_EmbyServer()
- self.vnodes = videonodes.VideoNodes()
self.kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
@@ -276,7 +274,9 @@ class LibrarySync(threading.Thread):
starttotal = datetime.now()
# Set views
- self.maintainViews(cursor_emby, cursor_video)
+ views.Views(cursor_emby, cursor_video).maintain()
+ conn_emby.commit()
+ #self.maintainViews(cursor_emby, cursor_video)
# Sync video library
process = {
@@ -362,222 +362,10 @@ class LibrarySync(threading.Thread):
def refreshViews(self):
- with DatabaseConn('emby') as conn_emby, DatabaseConn('video') as conn_video:
+ with DatabaseConn('emby') as conn_emby, DatabaseConn() as conn_video:
with closing(conn_emby.cursor()) as cursor_emby, closing(conn_video.cursor()) as cursor_video:
# Compare views, assign correct tags to items
- self.maintainViews(cursor_emby, cursor_video)
-
-
- def maintainViews(self, embycursor, kodicursor):
-
- # Compare the views to emby
- emby = self.emby
- emby_db = embydb.Embydb_Functions(embycursor)
- kodi_db = kodidb.Kodidb_Functions(kodicursor)
-
- # Get views
- result = self.doUtils("{server}/emby/Users/{UserId}/Views?format=json")
- grouped_views = result['Items'] if 'Items' in result else []
- ordered_views = self.emby.getViews(sortedlist=True)
- all_views = []
- sorted_views = []
- for view in ordered_views:
- all_views.append(view['name'])
- if view['type'] == "music":
- continue
-
- if view['type'] == "mixed":
- sorted_views.append(view['name'])
- sorted_views.append(view['name'])
- log.info("Sorted views: %s" % sorted_views)
-
- # total nodes for window properties
- self.vnodes.clearProperties()
- totalnodes = len(sorted_views) + 0
-
- current_views = emby_db.getViews()
- # Set views for supported media type
- emby_mediatypes = {
-
- 'movies': "Movie",
- 'tvshows': "Series",
- 'musicvideos': "MusicVideo",
- 'homevideos': "Video",
- 'music': "Audio",
- 'photos': "Photo"
- }
- for mediatype in ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos']:
-
- nodes = [] # Prevent duplicate for nodes of the same type
- playlists = [] # Prevent duplicate for playlists of the same type
- # Get media folders from server
- folders = self.emby.getViews(mediatype, root=True)
- for folder in folders:
-
- folderid = folder['id']
- foldername = folder['name']
- viewtype = folder['type']
-
- if foldername not in all_views:
- # Media folders are grouped into userview
- params = {
- 'ParentId': folderid,
- 'Recursive': True,
- 'Limit': 1,
- 'IncludeItemTypes': emby_mediatypes[mediatype]
- } # Get one item from server using the folderid
- url = "{server}/emby/Users/{UserId}/Items?format=json"
- result = self.doUtils(url, parameters=params)
- try:
- verifyitem = result['Items'][0]['Id']
- except (TypeError, IndexError):
- # Something is wrong. Keep the same folder name.
- # Could be the view is empty or the connection
- pass
- else:
- for grouped_view in grouped_views:
- # This is only reserved for the detection of grouped views
- if (grouped_view['Type'] == "UserView" and
- grouped_view.get('CollectionType') == mediatype):
- # Take the userview, and validate the item belong to the view
- if self.emby.verifyView(grouped_view['Id'], verifyitem):
- # Take the name of the userview
- log.info("Found corresponding view: %s %s"
- % (grouped_view['Name'], grouped_view['Id']))
- foldername = grouped_view['Name']
- break
- else:
- # Unable to find a match, add the name to our sorted_view list
- sorted_views.append(foldername)
- log.info("Couldn't find corresponding grouped view: %s" % sorted_views)
-
- # Failsafe
- try:
- sorted_views.index(foldername)
- except ValueError:
- sorted_views.append(foldername)
-
- # Get current media folders from emby database
- view = emby_db.getView_byId(folderid)
- try:
- current_viewname = view[0]
- current_viewtype = view[1]
- current_tagid = view[2]
-
- except TypeError:
- log.info("Creating viewid: %s in Emby database." % folderid)
- tagid = kodi_db.createTag(foldername)
- # Create playlist for the video library
- if (foldername not in playlists and
- mediatype in ('movies', 'tvshows', 'musicvideos')):
- utils.playlistXSP(mediatype, foldername, folderid, viewtype)
- playlists.append(foldername)
- # Create the video node
- if foldername not in nodes and mediatype not in ("musicvideos", "music"):
- self.vnodes.viewNode(sorted_views.index(foldername), foldername, mediatype,
- viewtype, folderid)
- if viewtype == "mixed": # Change the value
- sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
- nodes.append(foldername)
- totalnodes += 1
- # Add view to emby database
- emby_db.addView(folderid, foldername, viewtype, tagid)
-
- else:
- log.debug(' '.join((
-
- "Found viewid: %s" % folderid,
- "viewname: %s" % current_viewname,
- "viewtype: %s" % current_viewtype,
- "tagid: %s" % current_tagid)))
-
- # View is still valid
- try:
- current_views.remove(folderid)
- except ValueError:
- # View was just created, nothing to remove
- pass
-
- # View was modified, update with latest info
- if current_viewname != foldername:
- log.info("viewid: %s new viewname: %s" % (folderid, foldername))
- tagid = kodi_db.createTag(foldername)
-
- # Update view with new info
- emby_db.updateView(foldername, tagid, folderid)
-
- if mediatype != "music":
- if emby_db.getView_byName(current_viewname) is None:
- # The tag could be a combined view. Ensure there's no other tags
- # with the same name before deleting playlist.
- utils.playlistXSP(
- mediatype, current_viewname, folderid, current_viewtype, True)
- # Delete video node
- if mediatype != "musicvideos":
- self.vnodes.viewNode(
- indexnumber=None,
- tagname=current_viewname,
- mediatype=mediatype,
- viewtype=current_viewtype,
- viewid=folderid,
- delete=True)
- # Added new playlist
- if (foldername not in playlists and
- mediatype in ('movies', 'tvshows', 'musicvideos')):
- utils.playlistXSP(mediatype, foldername, folderid, viewtype)
- playlists.append(foldername)
- # Add new video node
- if foldername not in nodes and mediatype != "musicvideos":
- self.vnodes.viewNode(sorted_views.index(foldername), foldername,
- mediatype, viewtype, folderid)
- if viewtype == "mixed": # Change the value
- sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
- nodes.append(foldername)
- totalnodes += 1
-
- # Update items with new tag
- items = emby_db.getItem_byView(folderid)
- for item in items:
- # Remove the "s" from viewtype for tags
- kodi_db.updateTag(
- current_tagid, tagid, item[0], current_viewtype[:-1])
- else:
- # Validate the playlist exists or recreate it
- if mediatype != "music":
- if (foldername not in playlists and
- mediatype in ('movies', 'tvshows', 'musicvideos')):
- utils.playlistXSP(mediatype, foldername, folderid, viewtype)
- playlists.append(foldername)
- # Create the video node if not already exists
- if foldername not in nodes and mediatype != "musicvideos":
- self.vnodes.viewNode(sorted_views.index(foldername), foldername,
- mediatype, viewtype, folderid)
- if viewtype == "mixed": # Change the value
- sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
- nodes.append(foldername)
- totalnodes += 1
- else:
- # Add video nodes listings
- self.vnodes.singleNode(totalnodes, "Favorite movies", "movies", "favourites")
- totalnodes += 1
- self.vnodes.singleNode(totalnodes, "Favorite tvshows", "tvshows", "favourites")
- totalnodes += 1
- self.vnodes.singleNode(totalnodes, "Favorite episodes", "episodes", "favourites")
- totalnodes += 1
- self.vnodes.singleNode(totalnodes, "channels", "movies", "channels")
- totalnodes += 1
- # Save total
- window('Emby.nodes.total', str(totalnodes))
-
- # Remove any old referenced views
- log.info("Removing views: %s" % current_views)
- for view in current_views:
- emby_db.removeView(view)
- # Remove any items that belongs to the old view
- items = emby_db.get_item_by_view(view)
- items = [i[0] for i in items] # Convert list of tuple to list
- self.triage_items("remove", items)
-
+ views.Views(cursor_emby, cursor_video).maintain()
def movies(self, embycursor, kodicursor, pdialog):
diff --git a/resources/lib/player.py b/resources/lib/player.py
index 9505238d..9f196e66 100644
--- a/resources/lib/player.py
+++ b/resources/lib/player.py
@@ -11,7 +11,6 @@ import xbmcgui
import clientinfo
import downloadutils
-import kodidb_functions as kodidb
import websocket_client as wsc
from utils import window, settings, language as lang
from ga_client import GoogleAnalytics, log_error
diff --git a/resources/lib/read_embyserver.py b/resources/lib/read_embyserver.py
index b201e807..3c1718dd 100644
--- a/resources/lib/read_embyserver.py
+++ b/resources/lib/read_embyserver.py
@@ -31,6 +31,9 @@ class Read_EmbyServer():
self.userId = window('emby_currUser')
self.server = window('emby_server%s' % self.userId)
+ def get_emby_url(self, handler):
+ return "{server}/emby/%s" % handler
+
def split_list(self, itemlist, size):
# Split up list in pieces of size. Will generate a list of lists
@@ -589,4 +592,15 @@ class Read_EmbyServer():
data = {'username': username, 'password': hashlib.sha1(password).hexdigest()}
user = self.doUtils(url, postBody=data, action_type="POST", authenticate=False)
- return user
\ No newline at end of file
+ return user
+
+ def get_single_item(self, media_type, parent_id):
+
+ params = {
+ 'ParentId': parent_id,
+ 'Recursive': True,
+ 'Limit': 1,
+ 'IncludeItemTypes': media_type
+ }
+ url = self.get_emby_url('Users/{UserId}/Items?format=json')
+ return self.doUtils(url, parameters=params)
\ No newline at end of file
diff --git a/resources/lib/service_entry.py b/resources/lib/service_entry.py
index f730d8fc..273dce45 100644
--- a/resources/lib/service_entry.py
+++ b/resources/lib/service_entry.py
@@ -16,8 +16,8 @@ import initialsetup
import kodimonitor
import librarysync
import player
-import videonodes
import websocket_client as wsc
+from views import VideoNodes
from utils import window, settings, dialog, language as lang
from ga_client import GoogleAnalytics
import hashlib
@@ -77,7 +77,7 @@ class Service(object):
window(prop, clear=True)
# Clear video nodes properties
- videonodes.VideoNodes().clearProperties()
+ VideoNodes().clearProperties()
# Set the minimum database version
window('emby_minDBVersion', value="1.1.63")
diff --git a/resources/lib/videonodes.py b/resources/lib/videonodes.py
deleted file mode 100644
index 02f2f17e..00000000
--- a/resources/lib/videonodes.py
+++ /dev/null
@@ -1,392 +0,0 @@
-# -*- coding: utf-8 -*-
-
-#################################################################################################
-
-import logging
-import shutil
-import xml.etree.ElementTree as etree
-
-import xbmc
-import xbmcaddon
-import xbmcvfs
-
-import utils
-from utils import window, language as lang
-
-#################################################################################################
-
-log = logging.getLogger("EMBY."+__name__)
-
-#################################################################################################
-
-
-class VideoNodes(object):
-
-
- def __init__(self):
-
- self.kodiversion = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
-
-
- def commonRoot(self, order, label, tagname, roottype=1):
-
- if roottype == 0:
- # Index
- root = etree.Element('node', attrib={'order': "%s" % order})
- elif roottype == 1:
- # Filter
- root = etree.Element('node', attrib={'order': "%s" % order, 'type': "filter"})
- etree.SubElement(root, 'match').text = "all"
- # Add tag rule
- rule = etree.SubElement(root, 'rule', attrib={'field': "tag", 'operator': "is"})
- etree.SubElement(rule, 'value').text = tagname
- else:
- # Folder
- root = etree.Element('node', attrib={'order': "%s" % order, 'type': "folder"})
-
- etree.SubElement(root, 'label').text = label
- etree.SubElement(root, 'icon').text = "special://home/addons/plugin.video.emby/icon.png"
-
- return root
-
- def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
-
- if viewtype == "mixed":
- dirname = "%s - %s" % (viewid, mediatype)
- else:
- dirname = viewid
-
- path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
- nodepath = xbmc.translatePath(
- "special://profile/library/video/emby/%s/" % dirname).decode('utf-8')
-
- # Verify the video directory
- if not xbmcvfs.exists(path):
- try:
- shutil.copytree(
- src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'),
- dst=xbmc.translatePath("special://profile/library/video").decode('utf-8'))
- except Exception as error:
- log.error(error)
-
- xbmcvfs.exists(path)
-
- if delete:
- dirs, files = xbmcvfs.listdir(nodepath)
- for file in files:
- xbmcvfs.delete(nodepath + file)
-
- log.info("Sucessfully removed videonode: %s." % tagname)
- return
- # Create the node directory
- if not xbmcvfs.exists(nodepath) and not mediatype == "photos":
- # We need to copy over the default items
- xbmcvfs.mkdirs(nodepath)
-
- # Create index entry
- nodeXML = "%sindex.xml" % nodepath
- # Set windows property
- path = "library://video/emby/%s/" % dirname
- for i in range(1, indexnumber):
- # Verify to make sure we don't create duplicates
- if window('Emby.nodes.%s.index' % i) == path:
- return
-
- if mediatype == "photos":
- path = "plugin://plugin.video.emby/?id=%s&mode=getsubfolders" % indexnumber
-
- window('Emby.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)
- else:
- root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0)
- try:
- utils.indent(root)
- except: pass
- etree.ElementTree(root).write(nodeXML)
-
- nodetypes = {
-
- '1': "all",
- '2': "recent",
- '3': "recentepisodes",
- '4': "inprogress",
- '5': "inprogressepisodes",
- '6': "unwatched",
- '7': "nextepisodes",
- '8': "sets",
- '9': "genres",
- '10': "random",
- '11': "recommended",
- }
- mediatypes = {
- # label according to nodetype per mediatype
- 'movies':
- {
- '1': tagname,
- '2': 30174,
- '4': 30177,
- '6': 30189,
- '8': 20434,
- '9': 135,
- '10': 30229,
- '11': 30230
- },
-
- 'tvshows':
- {
- '1': tagname,
- '2': 30170,
- '3': 30175,
- '4': 30171,
- '5': 30178,
- '7': 30179,
- '9': 135,
- '10': 30229,
- '11': 30230
- },
-
- 'homevideos':
- {
- '1': tagname,
- '2': 30251,
- '11': 30253
- },
-
- 'photos':
- {
- '1': tagname,
- '2': 30252,
- '8': 30255,
- '11': 30254
- },
-
- 'musicvideos':
- {
- '1': tagname,
- '2': 30256,
- '4': 30257,
- '6': 30258
- }
- }
-
- nodes = mediatypes[mediatype]
- for node in nodes:
-
- nodetype = nodetypes[node]
- nodeXML = "%s%s.xml" % (nodepath, nodetype)
- # Get label
- stringid = nodes[node]
- if node != "1":
- label = lang(stringid)
- if not label:
- label = xbmc.getLocalizedString(stringid)
- else:
- label = stringid
-
- # Set window properties
- if (mediatype == "homevideos" or mediatype == "photos") and nodetype == "all":
- # Custom query
- path = ("plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=%s"
- % (tagname, mediatype))
- elif (mediatype == "homevideos" or mediatype == "photos"):
- # Custom query
- path = ("plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=%s&folderid=%s"
- % (tagname, mediatype, nodetype))
- elif nodetype == "nextepisodes":
- # Custom query
- path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname
- elif self.kodiversion == 14 and nodetype == "recentepisodes":
- # Custom query
- path = "plugin://plugin.video.emby/?id=%s&mode=recentepisodes&limit=25" % tagname
- elif self.kodiversion == 14 and nodetype == "inprogressepisodes":
- # Custom query
- path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25"% tagname
- else:
- path = "library://video/emby/%s/%s.xml" % (viewid, nodetype)
-
- if mediatype == "photos":
- windowpath = "ActivateWindow(Pictures,%s,return)" % path
- else:
- windowpath = "ActivateWindow(Videos,%s,return)" % path
-
- if nodetype == "all":
-
- if viewtype == "mixed":
- templabel = "%s - %s" % (tagname, mediatype)
- else:
- templabel = label
-
- embynode = "Emby.nodes.%s" % indexnumber
- window('%s.title' % embynode, value=templabel)
- window('%s.path' % embynode, value=windowpath)
- window('%s.content' % embynode, value=path)
- window('%s.type' % embynode, value=mediatype)
- else:
- embynode = "Emby.nodes.%s.%s" % (indexnumber, nodetype)
- window('%s.title' % embynode, value=label)
- window('%s.path' % embynode, value=windowpath)
- window('%s.content' % embynode, value=path)
-
- if mediatype == "photos":
- # For photos, we do not create a node in videos but we do want the window props
- # to be created.
- # To do: add our photos nodes to kodi picture sources somehow
- continue
-
- if xbmcvfs.exists(nodeXML):
- # Don't recreate xml if already exists
- continue
-
- # Create the root
- if (nodetype == "nextepisodes" or mediatype == "homevideos" or
- (self.kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
- # Folder type with plugin path
- root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2)
- etree.SubElement(root, 'path').text = path
- etree.SubElement(root, 'content').text = "episodes"
- else:
- root = self.commonRoot(order=node, label=label, tagname=tagname)
- if nodetype in ('recentepisodes', 'inprogressepisodes'):
- etree.SubElement(root, 'content').text = "episodes"
- else:
- etree.SubElement(root, 'content').text = mediatype
-
- limit = "25"
- # Elements per nodetype
- if nodetype == "all":
- etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle"
-
- elif nodetype == "recent":
- etree.SubElement(root, 'order', {'direction': "descending"}).text = "dateadded"
- etree.SubElement(root, 'limit').text = limit
- rule = etree.SubElement(root, 'rule', {'field': "playcount", 'operator': "is"})
- etree.SubElement(rule, 'value').text = "0"
-
- elif nodetype == "inprogress":
- etree.SubElement(root, 'rule', {'field': "inprogress", 'operator': "true"})
- etree.SubElement(root, 'limit').text = limit
-
- elif nodetype == "genres":
- etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle"
- etree.SubElement(root, 'group').text = "genres"
-
- elif nodetype == "unwatched":
- etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle"
- rule = etree.SubElement(root, "rule", {'field': "playcount", 'operator': "is"})
- etree.SubElement(rule, 'value').text = "0"
-
- elif nodetype == "sets":
- etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle"
- etree.SubElement(root, 'group').text = "sets"
-
- elif nodetype == "random":
- etree.SubElement(root, 'order', {'direction': "ascending"}).text = "random"
- etree.SubElement(root, 'limit').text = limit
-
- elif nodetype == "recommended":
- etree.SubElement(root, 'order', {'direction': "descending"}).text = "rating"
- etree.SubElement(root, 'limit').text = limit
- rule = etree.SubElement(root, 'rule', {'field': "playcount", 'operator': "is"})
- etree.SubElement(rule, 'value').text = "0"
- rule2 = etree.SubElement(root, 'rule',
- attrib={'field': "rating", 'operator': "greaterthan"})
- etree.SubElement(rule2, 'value').text = "7"
-
- elif nodetype == "recentepisodes":
- # Kodi Isengard, Jarvis
- etree.SubElement(root, 'order', {'direction': "descending"}).text = "dateadded"
- etree.SubElement(root, 'limit').text = limit
- rule = etree.SubElement(root, 'rule', {'field': "playcount", 'operator': "is"})
- etree.SubElement(rule, 'value').text = "0"
-
- elif nodetype == "inprogressepisodes":
- # Kodi Isengard, Jarvis
- etree.SubElement(root, 'limit').text = "25"
- rule = etree.SubElement(root, 'rule',
- attrib={'field': "inprogress", 'operator':"true"})
-
- try:
- utils.indent(root)
- except: pass
- etree.ElementTree(root).write(nodeXML)
-
- def singleNode(self, indexnumber, tagname, mediatype, itemtype):
-
- tagname = tagname.encode('utf-8')
- cleantagname = utils.normalize_nodes(tagname)
- nodepath = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
- nodeXML = "%semby_%s.xml" % (nodepath, cleantagname)
- path = "library://video/emby_%s.xml" % cleantagname
- windowpath = "ActivateWindow(Videos,%s,return)" % path
-
- # Create the video node directory
- if not xbmcvfs.exists(nodepath):
- # We need to copy over the default items
- shutil.copytree(
- src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'),
- dst=xbmc.translatePath("special://profile/library/video").decode('utf-8'))
- xbmcvfs.exists(path)
-
- labels = {
-
- 'Favorite movies': 30180,
- 'Favorite tvshows': 30181,
- 'Favorite episodes': 30182,
- 'channels': 30173
- }
- label = lang(labels[tagname])
- embynode = "Emby.nodes.%s" % indexnumber
- window('%s.title' % embynode, value=label)
- window('%s.path' % embynode, value=windowpath)
- window('%s.content' % embynode, value=path)
- window('%s.type' % embynode, value=itemtype)
-
- if xbmcvfs.exists(nodeXML):
- # Don't recreate xml if already exists
- return
-
- if itemtype == "channels":
- root = self.commonRoot(order=1, label=label, tagname=tagname, roottype=2)
- etree.SubElement(root, 'path').text = "plugin://plugin.video.emby/?id=0&mode=channels"
- elif itemtype == "favourites" and mediatype == "episodes":
- root = self.commonRoot(order=1, label=label, tagname=tagname, roottype=2)
- etree.SubElement(root, 'path').text = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=%s&folderid=favepisodes" %(tagname, mediatype)
- else:
- root = self.commonRoot(order=1, label=label, tagname=tagname)
- etree.SubElement(root, 'order', {'direction': "ascending"}).text = "sorttitle"
-
- etree.SubElement(root, 'content').text = mediatype
-
- try:
- utils.indent(root)
- except: pass
- etree.ElementTree(root).write(nodeXML)
-
- def clearProperties(self):
-
- log.info("Clearing nodes properties.")
- embyprops = window('Emby.nodes.total')
- propnames = [
-
- "index","path","title","content",
- "inprogress.content","inprogress.title",
- "inprogress.content","inprogress.path",
- "nextepisodes.title","nextepisodes.content",
- "nextepisodes.path","unwatched.title",
- "unwatched.content","unwatched.path",
- "recent.title","recent.content","recent.path",
- "recentepisodes.title","recentepisodes.content",
- "recentepisodes.path","inprogressepisodes.title",
- "inprogressepisodes.content","inprogressepisodes.path"
- ]
-
- if embyprops:
- totalnodes = int(embyprops)
- for i in range(totalnodes):
- for prop in propnames:
- window('Emby.nodes.%s.%s' % (str(i), prop), clear=True)
\ No newline at end of file
diff --git a/resources/lib/views.py b/resources/lib/views.py
index d1c0556d..8a2384dc 100644
--- a/resources/lib/views.py
+++ b/resources/lib/views.py
@@ -13,7 +13,7 @@ import xbmcvfs
import read_embyserver as embyserver
import embydb_functions as embydb
-from utils import window, language as lang
+from utils import window, language as lang, normalize_nodes, indent as xml_indent
#################################################################################################
@@ -30,20 +30,34 @@ class Views(object):
playlists = list()
views = list()
sorted_views = list()
+ grouped_views = list()
+ media_types = {
+
+ 'movies': "Movie",
+ 'tvshows': "Series",
+ 'musicvideos': "MusicVideo",
+ 'homevideos': "Video",
+ 'music': "Audio",
+ 'photos': "Photo"
+ }
def __init__(self, emby_cursor, kodi_cursor):
self.emby_cursor = emby_cursor
self.kodi_cursor = kodi_cursor
self.video_nodes = VideoNodes()
+ self.playlist = Playlist()
self.emby = embyserver.Read_EmbyServer()
- self.emby_db = embydb.Embydb_Functions(embycursor)
+ self.emby_db = embydb.Embydb_Functions(emby_cursor)
def _populate_views(self):
# Will get emby views and views in Kodi
- self.views = self.emby.getViews(sortedlist=True)
- for view in self.views:
+ grouped_views = self.emby.get_views()
+ self.grouped_views = grouped_views['Items'] if "Items" in grouped_views else []
+
+ for view in self.emby.getViews(sortedlist=True):
+ self.views.append(view['name'])
if view['type'] == "music":
continue
@@ -57,178 +71,105 @@ class Views(object):
def maintain(self):
# Compare views to emby
self._populate_views()
- view_list = [view['name'] for view in self.all_views]
- grouped_views = self.emby.get_views()
- current_views = emby_db.getViews()
+ curr_views = self.emby_db.getViews()
# total nodes for window properties
- self.vnodes.clearProperties()
+ self.video_nodes.clearProperties()
- # Set views for supported media type
- emby_mediatypes = {
-
- 'movies': "Movie",
- 'tvshows': "Series",
- 'musicvideos': "MusicVideo",
- 'homevideos': "Video",
- 'music': "Audio",
- 'photos': "Photo"
- }
- for mediatype in ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos']:
+ for media_type in ('movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos'):
self.nodes = list() # Prevent duplicate for nodes of the same type
self.playlists = list() # Prevent duplicate for playlists of the same type
- # Get media folders from server
- for folder in [view for view in ordered if view['type'] == mediatype]:
+ # Get media folders from the ordered
+ for folder in self.emby.getViews(media_type, root=True):
- folderid = folder['id']
- foldername = folder['name']
- viewtype = folder['type']
+ view_id = folder['id']
+ view_name = folder['name']
+ view_type = folder['type']
- if foldername not in view_list:
+ if view_name not in self.views:
# Media folders are grouped into userview
- params = {
- 'ParentId': folderid,
- 'Recursive': True,
- 'Limit': 1,
- 'IncludeItemTypes': emby_mediatypes[mediatype]
- } # Get one item from server using the folderid
- url = "{server}/emby/Users/{UserId}/Items?format=json"
- result = self.doUtils(url, parameters=params)
- try:
- verifyitem = result['Items'][0]['Id']
- except (TypeError, IndexError):
- # Something is wrong. Keep the same folder name.
- # Could be the view is empty or the connection
- pass
- else:
- for grouped_view in grouped_views:
- # This is only reserved for the detection of grouped views
- if (grouped_view['Type'] == "UserView" and
- grouped_view.get('CollectionType') == mediatype):
- # Take the userview, and validate the item belong to the view
- if self.emby.verifyView(grouped_view['Id'], verifyitem):
- # Take the name of the userview
- log.info("Found corresponding view: %s %s"
- % (grouped_view['Name'], grouped_view['Id']))
- foldername = grouped_view['Name']
- break
- else:
- # Unable to find a match, add the name to our sorted_view list
- self.sorted_views.append(foldername)
- log.info("Couldn't find corresponding grouped view: %s" % self.sorted_views)
-
- # Failsafe
- try:
- self.sorted_views.index(foldername)
+ view_name = self._get_grouped_view(media_type, view_id, view_name)
+
+ try: # Make sure the view is in sorted views before proceeding
+ self.sorted_views.index(view_name)
except ValueError:
- self.sorted_views.append(foldername)
+ self.sorted_views.append(view_name)
- # Get current media folders from emby database
- view = emby_db.getView_byId(folderid)
- try:
- current_viewname = view[0]
- current_viewtype = view[1]
- current_tagid = view[2]
+ # Get current media folders from emby database and compare
+ if self.compare_view(media_type, view_id, view_name, view_type):
+ if view_id in curr_views: # View is still valid
+ curr_views.remove(view_id)
- except TypeError:
- self._add_view(mediatype, folderid, foldername, viewtype)
-
- else:
- log.debug(' '.join((
-
- "Found viewid: %s" % folderid,
- "viewname: %s" % current_viewname,
- "viewtype: %s" % current_viewtype,
- "tagid: %s" % current_tagid)))
-
- # View is still valid
- try:
- current_views.remove(folderid)
- except ValueError:
- # View was just created, nothing to remove
- pass
-
- # View was modified, update with latest info
- if current_viewname != foldername:
- log.info("viewid: %s new viewname: %s" % (folderid, foldername))
- tagid = self._get_tag(foldername)
-
- # Update view with new info
- emby_db.updateView(foldername, tagid, folderid)
-
- if mediatype != "music":
- if emby_db.getView_byName(current_viewname) is None:
- # The tag could be a combined view. Ensure there's no other tags
- # with the same name before deleting playlist.
- self._playlist(mediatype, current_viewname, folderid,
- current_viewtype, True)
- # Delete video node
- if mediatype != "musicvideos":
- self.vnodes.viewNode(
- indexnumber=None,
- tagname=current_viewname,
- mediatype=mediatype,
- viewtype=current_viewtype,
- viewid=folderid,
- delete=True)
- # Added new playlist
- self.create_playlist(mediatype, foldername, folderid, viewtype)
- # Add new video node
- self.create_node(mediatype, foldername, folderid, viewtype)
-
- # Update items with new tag
- items = emby_db.getItem_byView(folderid)
- for item in items:
- # Remove the "s" from viewtype for tags
- self._update_tag(
- current_tagid, tagid, item[0], current_viewtype[:-1])
- else:
- # Validate the playlist exists or recreate it
- if mediatype != "music":
- self.create_playlist(mediatype, foldername, folderid, viewtype)
- # Create the video node if not already exists
- self.create_node(mediatype, foldername, folderid, viewtype)
# Add video nodes listings
- self.add_single_node(totalnodes, "Favorite movies", "movies", "favourites")
- self.add_single_node(totalnodes, "Favorite tvshows", "tvshows", "favourites")
- self.add_single_node(totalnodes, "Favorite episodes", "episodes", "favourites")
- self.add_single_node(totalnodes, "channels", "movies", "channels")
+ self.add_single_nodes()
# Save total
window('Emby.nodes.total', str(self.total_nodes))
-
# Remove any old referenced views
- log.info("Removing views: %s", current_views)
- for view in current_views:
+ log.info("Removing views: %s", curr_views)
+ for view in curr_views:
self.remove_view(view)
- def create_node(self, media_type, view_name, view_id, view_type):
+ def _get_grouped_view(self, media_type, view_id, view_name):
+ # Get single item from view to compare
+ result = self.emby.get_single_item(self.media_types[media_type], view_id)
+ try:
+ item = result['Items'][0]['Id']
+ except (TypeError, IndexError):
+ # Something is wrong. Keep the same folder name.
+ # Could be the view is empty or the connection
+ pass
+ else:
+ for view in self.grouped_views:
+ if view['Type'] == "UserView" and view.get('CollectionType') == media_type:
+ # Take the userview, and validate the item belong to the view
+ if self.emby.verifyView(view['Id'], item):
+ log.info("found corresponding view: %s %s", view['Name'], view['Id'])
+ view_name = view['Name']
+ break
+ else: # Unable to find a match, add the name to our sorted_view list
+ log.info("couldn't find corresponding grouped view: %s", self.sorted_views)
- if view_name not in self.nodes and media_type not in ('musicvideos', 'music'):
- index = self.sorted_views.index(view_name)
- self.video_nodes.viewNode(index, view_name, media_type,view_type, view_id)
-
- if view_type == "mixed": # Change the value
- self.sorted_views[index] = "%ss" % view_name
-
- self.nodes.append(view_name)
- self.total_nodes += 1
-
- def add_single_node(self, index, tag, media_type, item_type):
- self.video_nodes.singleNode(index, tag, media_type, item_type)
- self.total_nodes += 1
+ return view_name
def add_view(self, media_type, view_id, view_name, view_type):
# Generate view, playlist and video node
log.info("creating view %s: %s", view_name, view_id)
- tag_id = self._get_tag(view_name)
+ tag_id = self.get_tag(view_name)
- # Create playlist for the video library
- self.create_playlist(media_type, view_name, view_id, view_type)
- # Create the video node
- self.create_node(media_type, view_name, view_id, view_type)
+ self.add_playlist_node(media_type, view_id, view_name, view_type)
# Add view to emby database
self.emby_db.addView(view_id, view_name, view_type, tag_id)
+ def compare_view(self, media_type, view_id, view_name, view_type):
+
+ curr_view = self.emby_db.getView_byId(view_id)
+ try:
+ curr_view_name = curr_view[0]
+ curr_view_type = curr_view[1]
+ curr_tag_id = curr_view[2]
+ except TypeError:
+ self.add_view(media_type, view_id, view_name, view_type)
+ return False
+
+ # View is still valid
+ log.debug("Found viewid: %s viewname: %s viewtype: %s tagid: %s",
+ view_id, curr_view_name, curr_view_type, curr_tag_id)
+
+ if curr_view_name != view_name:
+ # View was modified, update with latest info
+ log.info("viewid: %s new viewname: %s", view_id, view_name)
+ tag_id = self.get_tag(view_name)
+ # Update view with new info
+ self.emby_db.updateView(view_name, tag_id, view_id)
+ # Delete old playlists and video nodes
+ self.delete_playlist_node(media_type, curr_view_name, view_id, curr_view_type)
+ # Update items with new tag
+ self._update_items_tag(curr_view_type[:-1], view_id, curr_tag_id, tag_id)
+
+ # Verify existance of playlist and nodes
+ self.add_playlist_node(media_type, view_id, view_name, view_type)
+ return True
+
def remove_view(self, view):
# Remove any items that belongs to the old view
items = self.emby_db.get_item_by_view(view)
@@ -236,79 +177,13 @@ class Views(object):
# TODO: Triage not accessible from here yet
#self.triage_items("remove", items)
- def create_playlist(self, media_type, view_name, view_id, view_type):
+ def _update_items_tag(self, media_type, view_id, tag, new_tag):
+ items = self.emby_db.getItem_byView(view_id)
+ for item in items:
+ # Remove the "s" from viewtype for tags
+ self._update_tag(tag, new_tag, item[0], media_type)
- if view_name not in self.playlists and media_type in ('movies', 'tvshows', 'musicvideos'):
-
- self._playlist(media_type, view_name, view_id, view_type)
- self.playlists.append(view_name)
-
- @classmethod
- def _add_playlist(cls, tag, playlist_name, path, media_type):
- # Using write process since there's no guarantee the xml declaration works with etree
- special_types = {'homevideos': "movies"}
- log.info("writing playlist to: %s", path)
- try:
- f = xbmcvfs.File(path, 'w')
- except:
- log.info("failed to create playlist: %s", path)
- return False
- else:
- f.write(
- '\n'
- '\n\t'
- 'Emby %s\n\t'
- 'all\n\t'
- '\n\t\t'
- '%s\n\t'
- ''
- ''
- % (special_types.get(media_type, media_type), playlist_name, tag))
- f.close()
- log.info("successfully added playlist: %s" % tag)
- return True
-
- @classmethod
- def _delete_playlist(cls, path):
- xbmcvfs.delete(path)
- log.info("successfully removed playlist: %s", path)
-
- def _playlist(self, media_type, tag, view_id, view_type="", delete=False):
- # Tagname is in unicode - actions: add or delete
- tag = tag.encode('utf-8')
- path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
-
- if view_type == "mixed":
- playlist_name = "%s - %s" % (tag, media_type)
- xsp_path = os.path.join(path, "Emby %s - %s.xsp" % (view_id, media_type))
- else:
- playlist_name = tag
- xsp_path = os.path.join(path, "Emby %s" % view_id)
-
- # Only add the playlist if it doesn't exist
- if xbmcvfs.exists(xsp_path):
- if delete:
- self._delete_playlist(xsp_path)
- return True
-
- elif not xbmcvfs.exists(path):
- log.info("creating directory: %s", path)
- xbmcvfs.mkdirs(path)
-
- return self._add_playlist(tag, playlist_name, xsp_path, media_type)
-
- def _add_tag(self, tag):
-
- self.kodi_cursor.execute("select coalesce(max(tag_id),0) from tag")
- tag_id = self.kodi_cursor.fetchone()[0] + 1
-
- query = "INSERT INTO tag(tag_id, name) values(?, ?)"
- self.kodi_cursor.execute(query, (tag_id, tag))
- log.debug("Create tag_id: %s name: %s", tag_id, tag)
-
- return tag_id
-
- def _get_tag(self, tag):
+ def get_tag(self, tag):
# This will create and return the tag_id
if KODI in (15, 16, 17):
# Kodi Isengard, Jarvis, Krypton
@@ -345,6 +220,17 @@ class Views(object):
return tag_id
+ def _add_tag(self, tag):
+
+ self.kodi_cursor.execute("select coalesce(max(tag_id),0) from tag")
+ tag_id = self.kodi_cursor.fetchone()[0] + 1
+
+ query = "INSERT INTO tag(tag_id, name) values(?, ?)"
+ self.kodi_cursor.execute(query, (tag_id, tag))
+ log.debug("Create tag_id: %s name: %s", tag_id, tag)
+
+ return tag_id
+
def _update_tag(self, tag, new_tag, kodi_id, media_type):
log.debug("Updating: %s with %s for %s: %s", tag, new_tag, media_type, kodi_id)
@@ -395,6 +281,110 @@ class Views(object):
))
self.kodi_cursor.execute(query, (kodi_id, media_type, tag,))
+ def add_playlist_node(self, media_type, view_id, view_name, view_type):
+ # Create playlist for the video library
+ if view_name not in self.playlists and media_type in ('movies', 'tvshows', 'musicvideos'):
+ self.playlist.process_playlist(media_type, view_id, view_name, view_type)
+ self.playlists.append(view_name)
+ # Create the video node
+ self._create_node(media_type, view_id, view_name, view_type)
+
+ def delete_playlist_node(self, media_type, view_id, view_name, view_type):
+
+ if media_type == "music":
+ return
+
+ if self.emby_db.getView_byName(view_name) is None:
+ # The tag could be a combined view. Ensure there's no other tags
+ # with the same name before deleting playlist.
+ self.playlist.process_playlist(media_type, view_id, view_name, view_type, True)
+ # Delete video node
+ if media_type != "musicvideos":
+ self.video_nodes.viewNode(None, view_name, media_type, view_type, view_id, True)
+
+ def _create_node(self, media_type, view_id, view_name, view_type):
+
+ if view_name not in self.nodes and media_type not in ('musicvideos', 'music'):
+ index = self.sorted_views.index(view_name)
+ self.video_nodes.viewNode(index, view_name, media_type,view_type, view_id)
+
+ if view_type == "mixed": # Change the value
+ self.sorted_views[index] = "%ss" % view_name
+
+ self.nodes.append(view_name)
+ self.total_nodes += 1
+
+ def add_single_nodes(self):
+ singles = [
+ ("Favorite movies", "movies", "favourites"),
+ ("Favorite tvshows", "tvshows", "favourites"),
+ ("Favorite episodes", "episodes", "favourites"),
+ ("channels", "movies", "channels")
+ ]
+ for args in singles:
+ self._single_node(self.total_nodes, *args)
+
+ def _single_node(self, index, tag, media_type, view_type):
+ self.video_nodes.singleNode(index, tag, media_type, view_type)
+ self.total_nodes += 1
+
+
+class Playlist(object):
+
+ def __init__(self):
+ pass
+
+ def process_playlist(self, media_type, view_id, view_name, view_type, delete=False):
+ # Tagname is in unicode - actions: add or delete
+ tag = view_name.encode('utf-8')
+ path = xbmc.translatePath("special://profile/playlists/video/").decode('utf-8')
+
+ if view_type == "mixed":
+ playlist_name = "%s - %s" % (tag, media_type)
+ xsp_path = os.path.join(path, "Emby %s - %s.xsp" % (view_id, media_type))
+ else:
+ playlist_name = tag
+ xsp_path = os.path.join(path, "Emby %s" % view_id)
+
+ # Only add the playlist if it doesn't exist
+ if xbmcvfs.exists(xsp_path):
+ if delete:
+ self._delete_playlist(xsp_path)
+ return
+
+ elif not xbmcvfs.exists(path):
+ log.info("creating directory: %s", path)
+ xbmcvfs.mkdirs(path)
+
+ self._add_playlist(tag, playlist_name, xsp_path, media_type)
+
+ def _add_playlist(self, tag, name, path, media_type):
+ # Using write process since there's no guarantee the xml declaration works with etree
+ special_types = {'homevideos': "movies"}
+ log.info("writing playlist to: %s", path)
+ try:
+ f = xbmcvfs.File(path, 'w')
+ except:
+ log.info("failed to create playlist: %s", path)
+ else:
+ f.write(
+ '\n'
+ '\n\t'
+ 'Emby %s\n\t'
+ 'all\n\t'
+ '\n\t\t'
+ '%s\n\t'
+ ''
+ ''
+ % (special_types.get(media_type, media_type), name, tag))
+ f.close()
+ log.info("successfully added playlist: %s" % tag)
+
+ @classmethod
+ def _delete_playlist(cls, path):
+ xbmcvfs.delete(path)
+ log.info("successfully removed playlist: %s", path)
+
class VideoNodes(object):
@@ -402,7 +392,7 @@ class VideoNodes(object):
def __init__(self):
pass
- def commonRoot(self, order, label, tagname, roottype=1):
+ def commonRoot(self, order, label, tagname="", roottype=1):
if roottype == 0:
# Index
@@ -430,29 +420,10 @@ class VideoNodes(object):
else:
dirname = viewid
- path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
+
nodepath = xbmc.translatePath(
"special://profile/library/video/emby/%s/" % dirname).decode('utf-8')
- # Verify the video directory
- if not xbmcvfs.exists(path):
- try:
- shutil.copytree(
- src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'),
- dst=xbmc.translatePath("special://profile/library/video").decode('utf-8'))
- except Exception as error:
- log.error(error)
-
- xbmcvfs.exists(path)
-
- emby_path = xbmc.translatePath("special://profile/library/video/emby/index.xml").decode('utf-8')
- if not emby_path:
- root = self.commonRoot(order=0, label="Emby", roottype=0)
- try:
- utils.indent(root)
- except: pass
- etree.ElementTree(root).write(emby_path)
-
if delete:
dirs, files = xbmcvfs.listdir(nodepath)
for file in files:
@@ -460,10 +431,32 @@ class VideoNodes(object):
log.info("Sucessfully removed videonode: %s." % tagname)
return
+
+ # Verify the video directory
+ path = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
+ if not xbmcvfs.exists(path):
+ try:
+ shutil.copytree(
+ src=xbmc.translatePath("special://xbmc/system/library/video").decode('utf-8'),
+ dst=xbmc.translatePath("special://profile/library/video").decode('utf-8'))
+ except Exception as error:
+ log.error(error)
+
+ xbmcvfs.mkdir(path)
+
+ embypath = xbmc.translatePath("special://profile/library/video/emby/").decode('utf-8')
+ if not xbmcvfs.exists(embypath):
+ xbmcvfs.mkdir(embypath)
+ root = self.commonRoot(order=0, label="Emby", roottype=0)
+ try:
+ xml_indent(root)
+ except: pass
+ etree.ElementTree(root).write(os.path.join(embypath, "index.xml"))
+
# Create the node directory
if not xbmcvfs.exists(nodepath) and not mediatype == "photos":
# We need to copy over the default items
- xbmcvfs.mkdirs(nodepath)
+ xbmcvfs.mkdir(nodepath)
# Create index entry
nodeXML = "%sindex.xml" % nodepath
@@ -487,7 +480,7 @@ class VideoNodes(object):
else:
root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0)
try:
- utils.indent(root)
+ xml_indent(root)
except: pass
etree.ElementTree(root).write(nodeXML)
@@ -582,10 +575,10 @@ class VideoNodes(object):
elif nodetype == "nextepisodes":
# Custom query
path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname
- elif self.kodiversion == 14 and nodetype == "recentepisodes":
+ elif KODI == 14 and nodetype == "recentepisodes":
# Custom query
path = "plugin://plugin.video.emby/?id=%s&mode=recentepisodes&limit=25" % tagname
- elif self.kodiversion == 14 and nodetype == "inprogressepisodes":
+ elif KODI == 14 and nodetype == "inprogressepisodes":
# Custom query
path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25"% tagname
else:
@@ -626,7 +619,7 @@ class VideoNodes(object):
# Create the root
if (nodetype == "nextepisodes" or mediatype == "homevideos" or
- (self.kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
+ (KODI == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
# Folder type with plugin path
root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2)
etree.SubElement(root, 'path').text = path
@@ -693,14 +686,14 @@ class VideoNodes(object):
attrib={'field': "inprogress", 'operator':"true"})
try:
- utils.indent(root)
+ xml_indent(root)
except: pass
etree.ElementTree(root).write(nodeXML)
def singleNode(self, indexnumber, tagname, mediatype, itemtype):
tagname = tagname.encode('utf-8')
- cleantagname = utils.normalize_nodes(tagname)
+ cleantagname = normalize_nodes(tagname)
nodepath = xbmc.translatePath("special://profile/library/video/").decode('utf-8')
nodeXML = "%semby_%s.xml" % (nodepath, cleantagname)
path = "library://video/emby_%s.xml" % cleantagname
@@ -745,6 +738,30 @@ class VideoNodes(object):
etree.SubElement(root, 'content').text = mediatype
try:
- utils.indent(root)
+ xml_indent(root)
except: pass
etree.ElementTree(root).write(nodeXML)
+
+ def clearProperties(self):
+
+ log.info("Clearing nodes properties.")
+ embyprops = window('Emby.nodes.total')
+ propnames = [
+
+ "index","path","title","content",
+ "inprogress.content","inprogress.title",
+ "inprogress.content","inprogress.path",
+ "nextepisodes.title","nextepisodes.content",
+ "nextepisodes.path","unwatched.title",
+ "unwatched.content","unwatched.path",
+ "recent.title","recent.content","recent.path",
+ "recentepisodes.title","recentepisodes.content",
+ "recentepisodes.path","inprogressepisodes.title",
+ "inprogressepisodes.content","inprogressepisodes.path"
+ ]
+
+ if embyprops:
+ totalnodes = int(embyprops)
+ for i in range(totalnodes):
+ for prop in propnames:
+ window('Emby.nodes.%s.%s' % (str(i), prop), clear=True)