[contrib] add a xbmc plugin that interracts with videoob
This commit is contained in:
parent
d479a86c4d
commit
d1839bfcd4
23 changed files with 1036 additions and 0 deletions
|
|
@ -0,0 +1 @@
|
|||
# Dummy file to make this directory a package.
|
||||
16
contrib/plugin.video.videoobmc/resources/lib/base/actions.py
Normal file
16
contrib/plugin.video.videoobmc/resources/lib/base/actions.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class BaseAction():
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def _do(self, param=None):
|
||||
"""
|
||||
Overload this method in application type subclass
|
||||
if you want to associate an action to the menu
|
||||
"""
|
||||
pass
|
||||
|
||||
actions = {}
|
||||
157
contrib/plugin.video.videoobmc/resources/lib/base/common_xbmc.py
Normal file
157
contrib/plugin.video.videoobmc/resources/lib/base/common_xbmc.py
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcplugin
|
||||
import xbmcaddon
|
||||
|
||||
import urllib
|
||||
import sys
|
||||
|
||||
from traceback import print_exc
|
||||
|
||||
|
||||
def get_addon():
|
||||
if hasattr(sys.modules["__main__"], "addon_id"):
|
||||
_id = sys.modules["__main__"].addon_id
|
||||
return xbmcaddon.Addon(id=_id)
|
||||
|
||||
|
||||
def get_translation(key):
|
||||
addon = get_addon()
|
||||
if addon:
|
||||
return addon.getLocalizedString(int(key))
|
||||
|
||||
|
||||
def get_settings(key):
|
||||
addon = get_addon()
|
||||
if addon:
|
||||
return addon.getSetting(key)
|
||||
|
||||
|
||||
def get_addon_dir():
|
||||
addon = get_addon()
|
||||
if addon:
|
||||
addonDir = addon.getAddonInfo("path")
|
||||
else:
|
||||
addonDir = xbmc.translatePath("special://profile/addon_data/")
|
||||
|
||||
return addonDir
|
||||
|
||||
|
||||
def display_error(msg):
|
||||
xbmc.executebuiltin("XBMC.Notification(%s, %s)" % (get_translation('30200').decode('utf-8'), msg))
|
||||
print msg
|
||||
print_exc(msg)
|
||||
|
||||
|
||||
def display_info(msg):
|
||||
xbmc.executebuiltin("XBMC.Notification(%s, %s, 3000, DefaultFolder.png)" % (get_translation('30300').encode('utf-8'),
|
||||
msg.encode('utf-8')))
|
||||
#print msg
|
||||
print_exc()
|
||||
|
||||
|
||||
def parse_params(param_str):
|
||||
param_dic = {}
|
||||
# Parameters are on the 3rd arg passed to the script
|
||||
param_str = sys.argv[2]
|
||||
if len(param_str) > 1:
|
||||
param_str = param_str.replace('?', '')
|
||||
|
||||
# Ignore last char if it is a '/'
|
||||
if param_str[len(param_str) - 1] == '/':
|
||||
param_str = param_str[0:len(param_str) - 2]
|
||||
|
||||
# Processing each parameter splited on '&'
|
||||
for param in param_str.split('&'):
|
||||
try:
|
||||
# Spliting couple key/value
|
||||
key, value = param.split('=')
|
||||
except:
|
||||
key = param
|
||||
value = ''
|
||||
|
||||
key = urllib.unquote_plus(key)
|
||||
value = urllib.unquote_plus(value)
|
||||
|
||||
# Filling dictionnary
|
||||
param_dic[key] = value
|
||||
|
||||
return param_dic
|
||||
|
||||
|
||||
def ask_user(content, title):
|
||||
keyboard = xbmc.Keyboard(content, title)
|
||||
keyboard.doModal()
|
||||
if keyboard.isConfirmed() and keyboard.getText():
|
||||
return keyboard.getText()
|
||||
return ""
|
||||
|
||||
|
||||
def create_param_url(param_dic, quote_plus=False):
|
||||
"""
|
||||
Create an plugin URL based on the key/value passed in a dictionary
|
||||
"""
|
||||
url = sys.argv[0]
|
||||
sep = '?'
|
||||
|
||||
try:
|
||||
for param in param_dic:
|
||||
if quote_plus:
|
||||
url = url + sep + urllib.quote_plus(param) + '=' + urllib.quote_plus(param_dic[param])
|
||||
else:
|
||||
url = "%s%s%s=%s" % (url, sep, param, param_dic[param])
|
||||
|
||||
sep = '&'
|
||||
except Exception, msg:
|
||||
display_error("create_param_url %s" % msg)
|
||||
url = None
|
||||
return url
|
||||
|
||||
|
||||
def create_list_item(name, itemInfoType="Video", itemInfoLabels=None, iconimage="DefaultFolder.png",
|
||||
c_items=None, isPlayable=False):
|
||||
lstItem = xbmcgui.ListItem(label=name, iconImage=iconimage, thumbnailImage=iconimage)
|
||||
|
||||
if c_items:
|
||||
lstItem.addContextMenuItems(c_items, replaceItems=True)
|
||||
|
||||
if itemInfoLabels:
|
||||
iLabels = itemInfoLabels
|
||||
else:
|
||||
iLabels = {"Title": name, }
|
||||
|
||||
lstItem.setInfo(type=itemInfoType, infoLabels=iLabels)
|
||||
if isPlayable:
|
||||
lstItem.setProperty('IsPlayable', "true")
|
||||
|
||||
return lstItem
|
||||
|
||||
|
||||
def add_menu_item(params={}):
|
||||
url = create_param_url(params)
|
||||
if params.get('name'):
|
||||
if params.get('iconimage'):
|
||||
lstItem = create_list_item(params.get('name'), iconimage=params.get('iconimage'))
|
||||
else:
|
||||
lstItem = create_list_item(params.get('name'))
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=lstItem, isFolder=True)
|
||||
else:
|
||||
display_error('add_menu_item : Fail to add item to menu')
|
||||
|
||||
|
||||
def add_menu_link(params={}):
|
||||
if params.get('name') and params.get('iconimage') and params.get('url') and \
|
||||
params.get('itemInfoLabels') and params.get('c_items'):
|
||||
url = params.get('url')
|
||||
lstItem = create_list_item(params.get('name'), iconimage=params.get('iconimage'),
|
||||
itemInfoLabels=params.get('itemInfoLabels'), c_items=params.get('c_items'),
|
||||
isPlayable=True)
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=lstItem)
|
||||
else:
|
||||
display_error('add_menu_link : Fail to add item to menu')
|
||||
|
||||
|
||||
def end_of_directory(update=False):
|
||||
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=True, updateListing=update) # , cacheToDisc=True)
|
||||
40
contrib/plugin.video.videoobmc/resources/lib/base/menu.py
Normal file
40
contrib/plugin.video.videoobmc/resources/lib/base/menu.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
|
||||
if hasattr(sys.modules["__main__"], "common_xbmc"):
|
||||
common_xbmc = sys.modules["__main__"].common_xbmc
|
||||
else:
|
||||
import common_xbmc
|
||||
|
||||
|
||||
class BaseMenuItem():
|
||||
|
||||
def __init__(self, name, action, iconimage="DefaultFolder.png"):
|
||||
self.params = {}
|
||||
self.params['name'] = name
|
||||
self.params['action'] = action
|
||||
self.params['iconimage'] = iconimage
|
||||
|
||||
def get(self, element):
|
||||
return self.params[element]
|
||||
|
||||
def add_to_menu(self):
|
||||
common_xbmc.add_menu_item(self.params)
|
||||
|
||||
|
||||
class BaseMenuLink(BaseMenuItem):
|
||||
|
||||
def __init__(self, name, url, action, iconimage="DefaultFolder.png"):
|
||||
BaseMenuItem.__init__(self, name, action, iconimage)
|
||||
self.params["url"] = url
|
||||
|
||||
def createVideoContextMenu(self):
|
||||
return ""
|
||||
|
||||
def create_info_labels(self):
|
||||
return ""
|
||||
|
||||
def add_to_menu(self):
|
||||
self.params["itemInfoLabels"] = self.create_info_labels()
|
||||
self.params["c_items"] = self.createVideoContextMenu()
|
||||
common_xbmc.add_menu_link(self.params)
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import simplejson as json
|
||||
|
||||
if hasattr(sys.modules["__main__"], "common_xbmc"):
|
||||
common_xbmc = sys.modules["__main__"].common_xbmc
|
||||
else:
|
||||
import common_xbmc
|
||||
|
||||
|
||||
class Weboobmc():
|
||||
def __init__(self, count=10):
|
||||
self.count = count
|
||||
|
||||
def update(self):
|
||||
#weboob-config update
|
||||
self._call_weboob('weboob-config', 'update')
|
||||
|
||||
def _call_weboob(self, application, command, options={}, argument=""):
|
||||
options['-n'] = self.count
|
||||
_opt = " ".join(["%s %s " % (k, v) for k, v in options.items()])
|
||||
_cmd = "%s %s %s %s" % (application, _opt, command, argument)
|
||||
#print _cmd.encode('utf-8')
|
||||
return subprocess.check_output(_cmd, shell=True)
|
||||
|
||||
def _json_call_weboob(self, application, command, options={}, argument=""):
|
||||
options['-f'] = 'json'
|
||||
try:
|
||||
result = self._call_weboob(application, command, options, argument)
|
||||
m = re.search(r"(\[{.+\}])", result)
|
||||
if m:
|
||||
result = u'%s' % m.group(1)
|
||||
#print result
|
||||
return json.loads(result) if result else []
|
||||
except subprocess.CalledProcessError as e:
|
||||
common_xbmc.display_error(" Error while calling weboob : %s " % e)
|
||||
|
||||
def get_loaded_backends(self, caps):
|
||||
#weboob-config list ICapVideo -f json
|
||||
backends = self._json_call_weboob('weboob-config', 'list', argument=caps)
|
||||
for backend in backends:
|
||||
if "_enabled=0" not in backend['Configuration']:
|
||||
yield backend['Name'] # , self.get_backend_icon(backend['Module'])
|
||||
|
||||
def get_backend_icon(self, module):
|
||||
if 'WEBOOB_WORKDIR' in os.environ:
|
||||
datadir = os.environ.get('WEBOOB_WORKDIR')
|
||||
else:
|
||||
datadir = os.path.join(os.environ.get('XDG_DATA_HOME',
|
||||
os.path.join(os.path.expanduser('~'), '.local', 'share')
|
||||
), 'weboob')
|
||||
icons_dir = os.path.join(datadir, 'icons')
|
||||
|
||||
return os.path.join(icons_dir, '%s.png' % module)
|
||||
|
||||
def is_category(self, obj):
|
||||
return 'split_path' in obj.keys()
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from weboob.tools.application.base import BaseApplication
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
|
||||
class Weboobmc(BaseApplication):
|
||||
def __init__(self, count=10):
|
||||
BaseApplication.__init__(self)
|
||||
self.count = int(count)
|
||||
self._is_default_count = False
|
||||
|
||||
def update(self):
|
||||
self.weboob.update()
|
||||
|
||||
def get_backend_icon(self, module):
|
||||
minfo = self.weboob.repositories.get_module_info(module)
|
||||
return self.weboob.repositories.get_module_icon_path(minfo)
|
||||
|
||||
def obj_to_filename(self, obj, dest=None, default=None):
|
||||
"""
|
||||
This method can be used to get a filename from an object, using a mask
|
||||
filled by information of this object.
|
||||
All patterns are braces-enclosed, and are name of available fields in
|
||||
the object.
|
||||
:param obj: object type obj: BaseObject param dest: dest given by user (default None)
|
||||
type dest: str param default: default file mask (if not given, this is
|
||||
:'{id}-{title}.{ext}') type default: str rtype: str
|
||||
"""
|
||||
|
||||
if default is None:
|
||||
default = '{id}-{title}.{ext}'
|
||||
if dest is None:
|
||||
dest = '.'
|
||||
if os.path.isdir(dest):
|
||||
dest = os.path.join(dest, default)
|
||||
|
||||
def repl(m):
|
||||
field = m.group(1)
|
||||
if hasattr(obj, field):
|
||||
return re.sub('[?:/]', '-', '%s' % getattr(obj, field))
|
||||
else:
|
||||
return m.group(0)
|
||||
|
||||
return re.sub(r'\{(.+?)\}', repl, dest)
|
||||
|
||||
def download_obj(self, obj, dest):
|
||||
|
||||
def check_exec(executable):
|
||||
with open('/dev/null', 'w') as devnull:
|
||||
process = subprocess.Popen(['which', executable], stdout=devnull)
|
||||
if process.wait() != 0:
|
||||
print 'Please install "%s"' % executable
|
||||
return False
|
||||
return True
|
||||
|
||||
dest = self.obj_to_filename(obj, dest)
|
||||
if obj.url.startswith('rtmp'):
|
||||
if not check_exec('rtmpdump'):
|
||||
return 1
|
||||
args = ('rtmpdump', '-e', '-r', obj.url, '-o', dest)
|
||||
elif obj.url.startswith('mms'):
|
||||
if not check_exec('mimms'):
|
||||
return 1
|
||||
args = ('mimms', '-r', obj.url, dest)
|
||||
elif u'm3u8' == obj.ext:
|
||||
_dest, _ = os.path.splitext(dest)
|
||||
dest = u'%s.%s' % (_dest, 'mp4')
|
||||
args = ('wget',) + tuple(line for line in self.read_url(obj.url) if not line.startswith('#')) + ('-O', dest)
|
||||
else:
|
||||
if check_exec('wget'):
|
||||
args = ('wget', '-c', obj.url, '-O', dest)
|
||||
elif check_exec('curl'):
|
||||
args = ('curl', '-C', '-', obj.url, '-o', dest)
|
||||
else:
|
||||
return 1
|
||||
os.spawnlp(os.P_WAIT, args[0], *args)
|
||||
Loading…
Add table
Add a link
Reference in a new issue