Player.Open and plugin:// item
#1
Goal: integrate Yatse (and other remotes) share function with the plugin.
From https://community.yatse.tv/t/send-to-kod...mp/2389/16 I understood that yatse uses Player.Open with params.item.file for everything: videos, music, files, playlists.

Note:
variable plugin_url is url with plugin:// inside, unresolved url

Part 1: Player.Open and xbmcplugin.addDirectoryItems

Let's say that plugin://plugin.audio.example/ creates Folder using following code:

python:
track_list = []
for track in album_source.tracks:
    li = xbmcgui.ListItem(label="title")
    li.setProperty('IsPlayable', 'true')
    plugin_url = self._build_url({'mode': 'stream', 'url': track.file, 'title': title})
    li.setPath(plugin_url)
    items.append((plugin_url, li, False))

xbmcplugin.addDirectoryItems(addon_handle, track_list, len(track_list))
xbmcplugin.setContent(addon_handle, 'songs')
xbmcplugin.endOfDirectory(addon_handle)

JSON-RPC with params.item.file:
json:
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "Player.Open",
    "params": {
        "item": {
            "file": "plugin://plugin.audio.example/?mode=url&url=https://url_to_album_source"
        }
    }
}
Result:
Doesn't work, spins loading wheel few times, maybe crash

Change JSON-RPC with params.item.directory:

json:
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "Player.Open",
    "params": {
        "item": {
            "directory": "plugin://plugin.audio.example/?mode=url&url=https://url_to_album_source"
        }
    }
}

Result:
Works ideally. We could stop there, but Yatse is using params.item.file for everything and devs wouldn't change it only for me.


Part 2: Player.Open and xbmc.Playlist(xbmc.PLAYLIST_MUSIC).add
Let's say that plugin://plugin.audio.example/ creates playlist using following code:

python:
track_list = []
for track in album_source.tracks:
    li = xbmcgui.ListItem(label="title")
    li.setProperty('IsPlayable', 'true')
    plugin_url = self._build_url({'mode': 'stream', 'url': track.file, 'title': title})
    li.setPath(plugin_url)
    items.append((plugin_url, li, False))

playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
for plugin_url, list_item, folder in track_list:
    playlist.add(plugin_url, list_item)

JSON-RPC with params.item.file:

json:
{
    "id": 1,
    "jsonrpc": "2.0",
    "method": "Player.Open",
    "params": {
        "item": {
            "file": "plugin://plugin.audio.example/?mode=url&url=https://url_to_album_source"
        }
    }
}

Result:
Doesn't play anything

add setResolvedUrl:

python:
playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
for plugin_url, list_item, folder in track_list:
    xbmcplugin.setResolvedUrl(addon_handle, True, listitem=list_item)
    playlist.add(plugin_url, list_item)

Result:
Plays, but playlist has only one last item of track_list

Change it a bit, setReslovedUrl only to the first item:

python:
playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
for plugin_url, list_item, folder in track_list:
    playlist.add(plugin_url, list_item)
xbmcplugin.setResolvedUrl(addon_handle, True, listitem=track_list[0][1])

Result:
Plays, but playlist has only one first item of track_list

Then I tried to add new list_item and resolve it:

python:

playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
for plugin_url, list_item, folder in track_list:
    playlist.add(plugin_url, list_item)

new_li = xbmcgui.ListItem(label="new_li")
new_li.setPath(plugin_url)
xbmcplugin.setResolvedUrl(addon_handle, True, listitem=new_li)

Result:
Wow, it works. But first item is item with name "new_li", but all other tracks are in tact. No idea what is the difference there between this and previous approach. Why it does work with temp listitem, but doesn't work with the one that already there?

after browsing forum I find one, where plugin waits after setResolvedUrl and before playlist.add (https://forum.kodi.tv/showthread.php?tid=334889)

python:
playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
xbmcplugin.setResolvedUrl(addon_handle, True, listitem=track_list[0][1])
xbmc.sleep(2000)
## track_list[1:] to avoid duplication
for plugin_url, list_item, folder in track_list[1:]:
    playlist.add(plugin_url, list_item)

Result:
Everything works as it should, as in params.item.directory way. But it looks ugly.

Any thoughts on my findings? Is all that works as expected? Why this is so hard? Ofc params.item.directory works as expected, but I think that we need unique approach.
Reply
#2
(2020-05-25, 17:25)DimaKompot Wrote: ....

Ideally we should have some sort of python API method similar to setResolvedUrl that instead of receiving a single item, would receive the playlist and internally resolve it to the first item on the playlist. The reason it works is because you're resolving the plugin path to a playable item (setResolvUrl) while that item belongs to an item list (playlist). Hence, when the player receives the item it automatically fills the queue.

This is not new, and is basically the "hack" plugin developers use to add playlists to plugins without using xbmc.Player().play().
To avoid the problem with the first item you could try doing something like below (note route is just to make it easy for you to understand the concept - see https://github.com/tamland/kodi-plugin-routing), i.e. create a temporary list with your items, create the playlist, pass the first one to the setResolvedUrl method:

python:


@plugin.route("/play/{id}")
def resolve_single_item(id):
   item = "My individual song"
   item.setPath("xxxxx.mp3")
   xbmcplugin.setResolvedUrl(plugin.handle, True, listitem=item)
   

@plugin.route("/generateplaylistandplay")
def generate_and_resolve_playlist():
    # create your items that point to another route in your addon for playback
    item1 = xbmcgui.ListItem("My song with id 1")
    item1.setProperty("IsPlayable", "true")
    item1.setPath("plugin://plugin.audio.myaddon/play/1")

    item2 = xbmcgui.ListItem("My song with id 2")
    item2.setProperty("IsPlayable", "true")
    item2.setPath("plugin://plugin.audio.myaddon/play/2")

    # create the playlist
    my_items = [item1, item2]
    playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
    for item in my_items:
        playlist.add(item.getPath(), item)
    
    # resolve plugin path to the first item of the playlist
    xbmcplugin.setResolvedUrl(plugin.handle, True, listitem=my_items[0])


Hopefully in the future we may have a cleaner way of doing the same Smile
Reply
#3
How is that different from my:
python:

track_list = []
for track in album_source.tracks:
    li = xbmcgui.ListItem(label="title")
    li.setProperty('IsPlayable', 'true')
    plugin_url = self._build_url({'mode': 'stream', 'url': track.file, 'title': title})
    li.setPath(plugin_url)
    items.append((plugin_url, li, False))

playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
for plugin_url, list_item, folder in track_list:
    playlist.add(plugin_url, list_item)
xbmcplugin.setResolvedUrl(addon_handle, True, listitem=track_list[0][1])

With such configuration only first item is getting played
Reply
#4
Pushed changes with implementation of:
python:
playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
xbmcplugin.setResolvedUrl(addon_handle, True, listitem=track_list[0][1])
xbmc.sleep(2000)
## track_list[1:] to avoid duplication
for plugin_url, list_item, folder in track_list[1:]:
    playlist.add(plugin_url, list_item)
to the repo:
https://github.com/Virusmater/plugin.aud...ult.py#L64
if somebody from kodi team want to look into it - you're welcome. just resolving the url only for 1st item doesn't work for me.
the plugin is possible to install just from a zip archive of the repo.
any questions - you can ask me
Reply

Logout Mark Read Team Forum Stats Members Help
Player.Open and plugin:// item0