Skip to content

Instantly share code, notes, and snippets.

@jbeluch
Created December 17, 2012 19:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbeluch/4321270 to your computer and use it in GitHub Desktop.
Save jbeluch/4321270 to your computer and use it in GitHub Desktop.
'''
redditmusic.resources.lib.playlists
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module contains an xbmcswift2.Module for handling the playlists
interaction for the addon.
:copyright: (c) 2012 by Jonathan Beluch
:license: GPLv3, see LICENSE.txt for more details.
'''
import functools
import xbmcswift2
#from xbmcswift2 import module, xbmc, xbmcgui, adding_items
from xbmcswift2 import module, xbmc, xbmcgui
''' Example usage
from xbmcswift2 import Plugin
import xbcmswift2_playlists
plugin = Plugin()
lists = xbmcswift2_playlists.Playlists(plugin)
@plugin.route('/')
def index():
items = [...]
items.append(lists.get_show_playlists_item())
'''
def _run(plugin, endpoint, **items):
'''Returns a RunPlugin string for use in a context menu.
#:param endpoint: The endpoint to be used with playlists.url_for().
#:param **items: Any keyword args to be passed to playlists.url_for().
'''
return 'XBMC.RunPlugin(%s)' % plugin.url_for(endpoint, **items)
class Playlists(object):
def __init__(self, plugin, playlists_storage='my_playlists', temp_item_storage='temp_items'):
self.plugin = plugin
self.playlist_storage = 'my_playlists'
self.temp_item_storage = 'temp_items'
self._run = functools.partial(_run, self.plugin)
self.init_plugin()
def init_plugin(self):
self.init_routes()
# register a callback to process all playable list items
callback = functools.partial(self.add_ctx_to_playable_items, self)
# TODO: Build signals into xbmcswift2?
#adding_items.connect(callback, self.plugin)
def add_ctx_to_playable_items(self, sender, items, **extra):
my_playlists = self.plugin.get_storage(self.playlists_storage)
for item in items:
ctx = []
for name in my_playlists.keys():
label = 'Add to %s playlist' % name
action = self._run('add_to_playlist', playlist=name, url=item['path'])
ctx.append((label, action))
item['context_menu'] = ctx
return items
def _add(self, url_ptn, meth, name=None):
if not name:
name = meth.__name__
self.plugin.add_url_rule(url_ptn, meth, name)
def init_routes(self):
self._add('/playlists/', self.show_playlists)
self._add('/playlists/create/', self.create_playlist)
self._add('/playlists/delete/<playlist>/', self.remove_playlist)
self._add('/playlists/show/<name>/', self.show_playlist)
self._add('/playlists/removeitem/<playlist>/<url>/', self.remove_from_playlist)
self._add('/playlists/additem/<playlist>/<url>/', self.add_to_playlist)
def show_playlists(self):
'''Displays the 'Create Playlist' item as well as items for any
playlists the user has created.
'''
my_playlists = self.plugin.get_storage(self.playlist_storage)
import random
one_time_code = random.int()
create = {
'label': 'Create Playlist',
'path': self.plugin.url_for('create_playlist', code=one_time_code),
}
items = [{
'label': name,
'path': self.plugin.url_for('show_playlist', name=name),
'context_menu': [('Delete this playlist',
self._run('remove_playlist', playlist=name)), ]
} for name in sorted(my_playlists.keys())]
return [create] + items
def create_playlist(self, code):
codes = self.plugin.get_storage('codes')
if code not in codes.keys():
xbmc.executebuiltin(_run('create_playlist_ajax'))
codes[code] = True
return self.plugin.finish(self.show_playlists(), update_listing=True)
def create_playlist_ajax(self):
'''Creates a new empty user named playlist. User's can add playlist items
from the context menu of playable items elsewhere in the addon.
'''
# Remove when xbmcswift2 adds xbmc.keyboard in CLI mode
if xbmcswift2.CLI_MODE:
name = raw_input('Enter playlist name')
else:
name = self.plugin.keyboard(heading='Enter playlist name')
my_playlists = self.plugin.get_storage('my_playlists')
if name and name not in my_playlists.keys():
my_playlists[name] = []
def remove_playlist(self, playlist):
'''Deletes a user specified playlist. If the playlist is not empty, the
user will be presented with a yes/no confirmation dialog before deletion.
'''
my_playlists = self.plugin.get_storage('my_playlists')
num_items = len(my_playlists[playlist])
delete = True
if num_items > 0:
dialog = xbmcgui.Dialog()
delete = dialog.yesno(self.plugin.name, 'Are you sure you wish to delete?')
if delete:
del my_playlists[playlist]
my_playlists.sync()
xbmc.executebuiltin('Container.Refresh')
def show_playlist(self, name):
'''Displays a user's custom playlist. The playlist items are persisted via
plugin storage.
'''
my_playlists = self.plugin.get_storage(self.playlist_storage)
items = my_playlists[name]
# Augment the existing list items with a context menu item to 'Remove from
# Playlist'.
for item in items:
ctx_items = [
('Remove this item from playlist',
self._run('remove_from_playlist', playlist=name, url=item['path']))
]
item['context_menu'] = ctx_items
return items
def remove_from_playlist(self, playlist, url):
'''Deletes an item from the given playlist whose url matches the provided
url.
'''
# We don't have the full item in temp_items, so have to iterate over items
# in the list and match on url
my_playlists = self.plugin.get_storage('my_playlists')
try:
match = (item for item in my_playlists[playlist]
if item['path'] == url).next()
my_playlists[playlist].remove(match)
my_playlists.sync()
xbmc.executebuiltin('Container.Refresh')
except StopIteration:
pass
def add_to_playlist(self, playlist, url):
'''Adds an item to the given playlist. The list item added will be pulled
from temp_items storage and matched on the provided url.
'''
temp_items = self.plugin.get_storage('temp_items')
item = temp_items[url]
my_playlists = self.plugin.get_storage('my_playlists')
my_playlists[playlist].append(item)
my_playlists.sync()
def get_show_playlists_item(self):
return {
'label': 'Show Playlists',
'path': self.plugin.url_for('show_playlists'),
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment