Jump to content

Feature request (nextgen 8.x.x) - Window properties for skins


OpenHT

Recommended Posts

Hi!

As already discussed in another thread, it would be nice to get the window properties back, so that skin developers can fully integrate Emby on the home screen. As far as I know, the old emby plugin used addon paths,  the new addon can use the much faster library nodes directly.

I just drafted a small technical summary, hope it helps a little bit:

for every emby node:
        xbmcgui.Window(10000).setProperty(key, value)

        # Homemenu
        'Emby.Nodes.[INDEX].title' = [NODE NAME]      e.g. Action Movies
        'Emby.Nodes.[INDEX].type'  = [CONTENT TYPE]   e.g. movies, tvshows, ...
        'Emby.Nodes.[INDEX].index' = [LIBRARY PATH]   e.g. ActivateWindow(videos, library://video/emby_tvshows_[NODE NAME], return)
        'Emby.Nodes.[INDEX].path'  = [LIBRARY PATH]   e.g. ActivateWindow(videos, library://video/emby_tvshows_[NODE NAME]/all.xml, return)

        # Widgets
        ( actors.xml, all.xml, genres.xml, inprogressepisodes.xml, inprogress.xml, nextepisodes.xml, random.xml, recentlyaddedepisodes.xml, recentlyadded.xml, ...)

        'Emby.Nodes.[INDEX].index.content'                  = [LIBRARY PATH]   e.g. 'library://video/emby_tvshows_[NODE NAME]'

        'Emby.Nodes.[INDEX].recentlyaddedepisodes.content'  = [LIBRARY PATH]   e.g. 'library://video/emby_tvshows_[NODE NAME]/recentlyaddedepisodes.xml'
        'Emby.Nodes.[INDEX].recentlyadded.content'          = [LIBRARY PATH]   e.g. 'library://video/emby_tvshows_[NODE NAME]/recentlyadded.xml'
        'Emby.Nodes.[INDEX].random.content'                 = [LIBRARY PATH]   e.g. 'library://video/emby_tvshows_[NODE NAME]/random.xml'
        ... and so on ...

        # Add special nodes after other nodes
        emby_Favorite_tvshows.xml
        emby_Favorite_episodes.xml
        emby_Favorite_movies.xml
        emby_Favorite_musicvideos.xml

 

 

@quickmic

Vielen Dank!

Link to comment
Share on other sites

quickmic

With the following code, you have full control over all (synced) nodes and do whatever you like. Set properties whatever...

The beauty is, you are not bind to any code of the plugin. Also the plugin generates synced nodes for music genres on the fly (workaround due to poor Kodi performance) and you can cover that as well.

Dynamic nodes are not covered yet, but in one of the next versions I'll add link for dynamic nodes as well.

fyi, the code can still be improved, it's just a template and not optimized.

e.g. The code can be trigger as a service of your skin...

import os
import xbmc
import xbmcvfs

def get_embynodes():
    SearchFolders = ['special://profile/library/music/', 'special://profile/library/video/']
    EmbyNodes = []
    NodeIndex = 0
    isSubfolder = False
    FolderIndex = 0

    for SearchFolder in SearchFolders:
        Folders, Files = listDir(SearchFolder)

        # root files
        EmbyNodes.append({f"IndexLabel": "root", f"IndexPath": SearchFolder, "Nodes": []})

        for File in Files:
            if File.startswith("emby_"):
                NodePath = os.path.join(SearchFolder, File)
                NodeData = readFileBinary(NodePath)
                NodeLabel = NodeData.decode("utf-8").split("<label>")
                NodeLabel = NodeLabel[1].split("</label>")
                NodeLabel = NodeLabel[0]
                EmbyNodes[FolderIndex]["Nodes"].append({"NodeLabel": NodeLabel, "NodePath": NodePath})

        FolderIndex += 1

        # Subfolders
        while Folders:
            Folders, NodeIndex, FolderIndex = search_embynodes(NodeIndex, EmbyNodes, SearchFolder, Folders, isSubfolder, FolderIndex)
            isSubfolder = True

    # Final Nodes
    for EmbyNode in EmbyNodes:
        xbmc.log(f"EMBY NODES: index: {EmbyNode['IndexLabel']} / {EmbyNode['IndexPath']}", 1) # LOGINFO

        for EmbyNodeData in EmbyNode["Nodes"]:
            xbmc.log(f"EMBY NODES: node: {EmbyNodeData}", 1) # LOGINFO

def search_embynodes(NodeIndex, EmbyNodes, SearchFolder, Folders, isSubfolder, FolderIndex):
    Subfolders = []

    for Folder in Folders:
        if Folder.startswith("emby_") or isSubfolder:
            NodeSubPath = os.path.join(SearchFolder, Folder)
            IndexFilePath = os.path.join(NodeSubPath, "index.xml")
            IndexFileData = readFileBinary(IndexFilePath)

            if IndexFileData:
                NodeIndexFileLabel = IndexFileData.decode("utf-8").split("<label>")
                NodeIndexFileLabel = NodeIndexFileLabel[1].split("</label>")
                NodeIndexFileLabel = NodeIndexFileLabel[0]
            else:
                continue

            FolderIndexCurrent = FolderIndex
            EmbyNodes.append({f"IndexLabel": NodeIndexFileLabel, f"IndexPath": IndexFilePath, "Nodes": []})
            FolderIndex += 1
            FoundFolders, EmbyFiles = listDir(NodeSubPath)

            for FoundFolder in FoundFolders:
                Subfolders.append(os.path.join(Folder, FoundFolder))

            for EmbyFile in EmbyFiles:
                if EmbyFile == "index.xml":
                    continue
                
                NodePath = os.path.join(NodeSubPath, EmbyFile)
                NodeData = readFileBinary(NodePath)
                NodeLabel = NodeData.decode("utf-8").split("<label>")
                NodeLabel = NodeLabel[1].split("</label>")
                NodeLabel = NodeLabel[0]
                EmbyNodes[FolderIndexCurrent]["Nodes"].append({"NodeLabel": NodeLabel, "NodePath": NodePath})
                NodeIndex += 1

    return Subfolders, NodeIndex, FolderIndex

def readFileBinary(Path):
    Path = translatePath(Path)

    if os.path.isfile(Path):
        with open(Path, "rb") as infile:
            data = infile.read()

        return data

    return b""

def listDir(Path):
    Files = ()
    Folders = ()
    Path = translatePath(Path)

    if os.path.isdir(Path):
        for FilesFolders in os.listdir(Path):
            FilesFoldersPath = os.path.join(Path, FilesFolders)

            if os.path.isdir(FilesFoldersPath):
                FilesFolders = os.path.join(FilesFolders, b"")  # add trailing / or \
                Folders += (FilesFolders.decode('utf-8'),)
            else:
                Files += (FilesFolders.decode('utf-8'),)

    return Folders, Files

def translatePath(Data):
    Path = xbmcvfs.translatePath(Data)
    Path = Path.encode('utf-8')
    return Path

 

Edited by quickmic
Link to comment
Share on other sites

Thanks for the code, I really appreciate it!

I'm just curious, is there a reason why you don't want to implement it directly into the addon? It seems to me that it would be the "cleaner" solution because you are already going through the nodes/subnodes anyway, so setting the window properties there would make more sense than parsing/splitting/joining the library nodes in a separate skin python script. I might be biased here, but I'm not a big fan of adding an additional skin python script for handling an already running python addon.

Either way, thanks for your support and time!

Link to comment
Share on other sites

quickmic
3 minutes ago, OpenHT said:

Thanks for the code, I really appreciate it!

I'm just curious, is there a reason why you don't want to implement it directly into the addon? It seems to me that it would be the "cleaner" solution because you are already going through the nodes/subnodes anyway, so setting the window properties there would make more sense than parsing/splitting/joining the library nodes in a separate skin python script. I might be biased here, but I'm not a big fan of adding an additional skin python script for handling an already running python addon.

Either way, thanks for your support and time!

Mostly, I don't want to maintain it.

Plugins/Skins should capable to run standalone and not be related to any code added into 3rd party plugins.

Link to comment
Share on other sites

Fair enough. Personally, I would consider this information should be part of the addon itself (like in any other addon which provides home screen information e.g. weather) but I also kind of understand your argument. 

I'm going to experiment with both solutions.

 

Thanks again!

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...