Playing first item in .pls instead of treating like a folder
#1
Music 
I'm working on giving my addon, Digitally Imported, a much needed overhaul and making it less dependent on regex parsing the sites html.

The current version opens each .pls and extracts the first stream from it, but the optimal solution would of course be to play the first track from the .pls and let the player automatically switch to the next track/stream in case the first one fails.

The current behavior when I add a .pls to the interface using the addDirectoryItem with isFolder=False, is that when I click it, it get's downloaded and opened like a folder, displaying each stream as a seperate item in the menu.

I've tried playing around with the mimetype of the item I'm adding, but it does have the wished effect.

Here's my current WIP version of the addItem() function, hoping someone can point out my stupidity.
Code:
# Adds item to XBMC itemlist
    def addItem(self, channelTitle, streamUrl, streamDescription, streamBitrate, icon, isNewChannel, totalItems):
        if isNewChannel == True: # tart it up a bit if it's a new channel
            li = xbmcgui.ListItem(label="[COLOR FF007EFF]" + channelTitle + "[/COLOR]", thumbnailImage=icon)
            xbmc.log("New channel found: " + channelTitle, xbmc.LOGERROR)
        else:
            li = xbmcgui.ListItem(label=channelTitle, thumbnailImage=icon)

        li.setProperty("mimetype", 'audio/x-scpls')
        li.setInfo(type="Music", infoLabels={"label": channelTitle, "Genre": channelTitle, "Comment": streamDescription,
                                             "Size": (streamBitrate * 1024)})
        li.setProperty("IsPlayable", "true")
        li.setProperty("IsLive", "true")

        player = xbmc.Player(xbmc.PLAYER_CORE_PAPLAYER)

        #li.addContextMenuItems('Play', player.play(streamUrl))

        xbmcplugin.addDirectoryItem(handle=HANDLE, url=streamUrl, listitem=li, isFolder=False, totalItems=totalItems)

        return True

Any help or suggestions would be appreciated.
Reply
#2
If your going to set "IsPlayable", "true" the url you pass to addDirectoryItem needs to be a plugin url e.g. sys.argv[0] + '?url=streamUrl'
Then when the plugin is called when the item is selected you get the url from sys.argv[2] and use setResolvedUrl .

Even then I don't think it will have the desired effect. I'm thinking* that anytime you send the player a .pls it's going to open a playlist window. You may* be able to parse the .pls in to a xbmc.Playlist then use the builtin xbmc.executebuiltin('playlist.playoffset(video,0)')
Reply
#3
I had the same problem with my Radio add-on: A playlist is "a playlist" ;-) for xbmc, not a single playable stream. So we have two solutions:

1. "isPlayable=False; isFolder=True" because its a playlist = a folder
2. "isPlayable=True; isFolder=False" and parse the list yourself to get a single playable stream.

In Radio I use the second method but picking a random stream-url if there are multiple. This has the advantage that the user may try it again if the stream did not work.

Feel free to be inspired of my solution (of copy it ;-)):
PHP Code:
# This resolves M3U, PLS, ASX and a radio-specific XML playlist format
    
def __resolve_playlist(selfstation):
        
self.log('__resolve_playlist started with station=%s'
                 
station['id'])
        
servers = []
        
stream_url station['streamURL']
        if 
stream_url.lower().endswith('m3u'):
            
response self.__urlopen(stream_url)
            
self.log('__resolve_playlist found .m3u file')
            
servers = [
                
for l in response.splitlines()
                if 
l.strip() and not l.strip().startswith('#')
            ]
        
elif stream_url.lower().endswith('pls'):
            
response self.__urlopen(stream_url)
            
self.log('__resolve_playlist found .pls file')
            
servers = [
                
l.split('=')[1] for l in response.splitlines()
                if 
l.lower().startswith('file')
            ]
        
elif stream_url.lower().endswith('asx'):
            
response self.__urlopen(stream_url)
            
self.log('__resolve_playlist found .asx file')
            
servers = [
                
l.split('href="')[1].split('"')[0]
                for 
l in response.splitlines() if 'href' in l
            
]
        
elif stream_url.lower().endswith('xml'):
            
self.log('__resolve_playlist found .xml file')
            
servers = [
                
stream_url['streamUrl']
                for 
stream_url in station.get('streamUrls', [])
                if 
'streamUrl' in stream_url
            
]
        if 
servers:
            
self.log('__resolve_playlist found %d servers' len(servers))
            return 
random.choice(servers)
        return 
stream_url 

See here for full code.

Regards,
sphere
My GitHub. My Add-ons:
Image
Reply
#4
(2013-12-16, 00:42)sphere Wrote: I had the same problem with my Radio add-on: A playlist is "a playlist" ;-) for xbmc, not a single playable stream. So we have two solutions:

1. "isPlayable=False; isFolder=True" because its a playlist = a folder
2. "isPlayable=True; isFolder=False" and parse the list yourself to get a single playable stream.

I chose option 2 also for iHeartRadio. Then when resolving the url do a head request to make sure the stream is active.

Thinking about it more now, parsing the playlist into a stack:// url may be a better solution.
Reply
#5
(2013-12-16, 12:26)divingmule Wrote: ...
Then when resolving the url do a head request to make sure the stream is active.
...
Thinking about it more now, parsing the playlist into a stack:// url may be a better solution.

I also tried HEAD-requests but it wasn't worth the code (it was no indication if streaming works).

stack-URL is a good idea, please report if that works well Wink
My GitHub. My Add-ons:
Image
Reply
#6
Hi guys, thanks for the suggestion and sorry for the delayed response.
I'll be looking into revamping both my DI.fm and Sky.fm plugins with your suggestions over Christmas.

Merry Christmas Smile
Reply
#7
I suspect the stack trick won't work with audio unfortunately.

It seems like a better solution would be a way for you to say "play this playlist URL as it is - don't treat it like a playlist" ?

I'm not sure what the best plan to do that would be though. Protocol option?
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#8
(2013-12-22, 21:28)jmarshall Wrote: I suspect the stack trick won't work with audio unfortunately.

It seems like a better solution would be a way for you to say "play this playlist URL as it is - don't treat it like a playlist" ?

I'm not sure what the best plan to do that would be though. Protocol option?

IMO it would be best like this:

- ListItem with "isPlayable=True" and a playlist file as URL: XBMC should automatically choose the server (changed behavior. Currently "it simply does not work Wink")
- ListItem with "isPlayable=False" and a playlist file as URL: XBMC should interpret the playlist as folder (the current behavior).

Another protocol option would be redundant to "isPlayable".

If you want to work on PR for this I could create a small demo plugin for you.

regards,
sphere
My GitHub. My Add-ons:
Image
Reply

Logout Mark Read Team Forum Stats Members Help
Playing first item in .pls instead of treating like a folder0