From d1839bfcd45d9b65b5b8933269c7cbc6125fe096 Mon Sep 17 00:00:00 2001 From: Bezleputh Date: Tue, 2 Sep 2014 16:48:17 +0200 Subject: [PATCH] [contrib] add a xbmc plugin that interracts with videoob --- contrib/plugin.video.videoobmc/addon.xml | 22 +++ contrib/plugin.video.videoobmc/changelog.txt | 8 + contrib/plugin.video.videoobmc/default.py | 31 ++++ .../plugin.video.videoobmc/default_test.py | 20 +++ contrib/plugin.video.videoobmc/icon.png | Bin 0 -> 7959 bytes .../resources/language/english/strings.xml | 23 +++ .../resources/language/french/strings.xml | 23 +++ .../resources/lib/__init__.py | 1 + .../resources/lib/actions.py | 108 ++++++++++++ .../resources/lib/base/__init__.py | 1 + .../resources/lib/base/actions.py | 16 ++ .../resources/lib/base/common_xbmc.py | 157 ++++++++++++++++++ .../resources/lib/base/menu.py | 40 +++++ .../resources/lib/base/weboobmc.py | 62 +++++++ .../resources/lib/base/weboobmc2.py | 80 +++++++++ .../resources/lib/constants.py | 10 ++ .../resources/lib/menu.py | 72 ++++++++ .../resources/lib/test/__init__.py | 1 + .../resources/lib/test/common_test.py | 110 ++++++++++++ .../resources/lib/videoobmc.py | 94 +++++++++++ .../resources/lib/videoobmc.py | 93 +++++++++++ .../resources/lib/videoobmc2.py | 53 ++++++ .../resources/settings.xml | 11 ++ 23 files changed, 1036 insertions(+) create mode 100644 contrib/plugin.video.videoobmc/addon.xml create mode 100644 contrib/plugin.video.videoobmc/changelog.txt create mode 100644 contrib/plugin.video.videoobmc/default.py create mode 100755 contrib/plugin.video.videoobmc/default_test.py create mode 100644 contrib/plugin.video.videoobmc/icon.png create mode 100644 contrib/plugin.video.videoobmc/resources/language/english/strings.xml create mode 100644 contrib/plugin.video.videoobmc/resources/language/french/strings.xml create mode 100644 contrib/plugin.video.videoobmc/resources/lib/__init__.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/actions.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/base/__init__.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/base/actions.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/base/common_xbmc.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/base/menu.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/base/weboobmc.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/base/weboobmc2.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/constants.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/menu.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/test/__init__.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/test/common_test.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/videoobmc.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/videoobmc.py create mode 100644 contrib/plugin.video.videoobmc/resources/lib/videoobmc2.py create mode 100644 contrib/plugin.video.videoobmc/resources/settings.xml diff --git a/contrib/plugin.video.videoobmc/addon.xml b/contrib/plugin.video.videoobmc/addon.xml new file mode 100644 index 00000000..820a844c --- /dev/null +++ b/contrib/plugin.video.videoobmc/addon.xml @@ -0,0 +1,22 @@ + + + + + + + video + + + linux + + Plugin for Videoob + + [B]Videoob[/B] is an application able to handle videos on supported websites. More information available on http://videoob.org/. + + [B]Videoob[/B] est une application qui permet de récupérer des vidéos depuis divers sites. Pour plus d'informations à ce sujet, n'hésitez pas à visiter le site : http://videoob.org/ + + + diff --git a/contrib/plugin.video.videoobmc/changelog.txt b/contrib/plugin.video.videoobmc/changelog.txt new file mode 100644 index 00000000..f70f3cc5 --- /dev/null +++ b/contrib/plugin.video.videoobmc/changelog.txt @@ -0,0 +1,8 @@ +[B]Dependance :[B] +- weboob (http://weboob.org/install) + +[B]Version 0.1.0[/B] +-Call weboob directly + +[B]Version 0.0.1[/B] +-First try diff --git a/contrib/plugin.video.videoobmc/default.py b/contrib/plugin.video.videoobmc/default.py new file mode 100644 index 00000000..de04e623 --- /dev/null +++ b/contrib/plugin.video.videoobmc/default.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +import sys +import resources.lib.base.common_xbmc as common_xbmc +import resources.lib.constants as constants +from resources.lib.actions import actions + +# Plugin constants +version = "0.1.0" +plugin = "videoobmc" + version +addon_id = "plugin.video.videoobmc" +author = "Bezleputh" +mail = "carton_ben@yahoo.fr" + +#import lxml.html import Element +#print Element.__file__ + +#TODO gestion du logger, gestion des modules via XBMC (activation/desactivation) + +#Bug encodge des categories +#corriger version 1 pour que v2 et v1 donctionnent + +if (__name__ == "__main__"): + if not (sys.argv[2]): + actions[constants.DISPLAY_MENU]()._do() + else: + params = common_xbmc.parse_params(sys.argv[2]) + action = params.get("action") + if (action): + actions[action]()._do(params) + else: + common_xbmc.display_error(" ARGV Nothing done.. verify params " + repr(params)) diff --git a/contrib/plugin.video.videoobmc/default_test.py b/contrib/plugin.video.videoobmc/default_test.py new file mode 100755 index 00000000..f045c825 --- /dev/null +++ b/contrib/plugin.video.videoobmc/default_test.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import sys +import resources.lib.test.common_test as common_xbmc +import resources.lib.constants as constants + +from resources.lib.actions import actions + +print sys.argv +if len(sys.argv) < 2: + actions[constants.DISPLAY_MENU]()._do() +else: + params = common_xbmc.parse_params(sys.argv[1]) + #print params + action = params.get("action") + if (action): + actions[action]()._do(params) + else: + common_xbmc.display_error(" ARGV Nothing done.. verify params " + repr(params)) diff --git a/contrib/plugin.video.videoobmc/icon.png b/contrib/plugin.video.videoobmc/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..03846cae16f8bb8ee039e16d3285958bb137c9e5 GIT binary patch literal 7959 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 N002ovPDHLkV1gMjb&>!8 literal 0 HcmV?d00001 diff --git a/contrib/plugin.video.videoobmc/resources/language/english/strings.xml b/contrib/plugin.video.videoobmc/resources/language/english/strings.xml new file mode 100644 index 00000000..f5f6e83a --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/language/english/strings.xml @@ -0,0 +1,23 @@ + + + + Search + Search: + + Download + Information + + Error! + + Information + Download started + Download succeed + + Download folder: + Number of videos per backends: + Display Non Safe For Work videos: + Enable debug mode: + Update weboob backends + Start updating weboob backends + Weboob backends successfully updated + diff --git a/contrib/plugin.video.videoobmc/resources/language/french/strings.xml b/contrib/plugin.video.videoobmc/resources/language/french/strings.xml new file mode 100644 index 00000000..09c8d746 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/language/french/strings.xml @@ -0,0 +1,23 @@ + + + + Recherche + Recherche: + + Télécharger + Information + + Erreur! + + Information + Lancement du téléchargement + Fichier téléchargé avec succès + + Répertoire de Téléchargement: + Nombre de vidéos par backends: + Afficher les vidéos interdites aux moins de 18 ans : + Enable debug mode : + Mise à jour des modules weboob + Debut de la mise à jour + Weboob est maintenant à jour + diff --git a/contrib/plugin.video.videoobmc/resources/lib/__init__.py b/contrib/plugin.video.videoobmc/resources/lib/__init__.py new file mode 100644 index 00000000..ee074ac5 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/__init__.py @@ -0,0 +1 @@ +# Dummy file to make this directory a package. diff --git a/contrib/plugin.video.videoobmc/resources/lib/actions.py b/contrib/plugin.video.videoobmc/resources/lib/actions.py new file mode 100644 index 00000000..4cb029ba --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/actions.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +import sys +import constants + +from base.actions import BaseAction +from menu import MenuItem, MenuItemVideo, MenuItemPath +from threading import Thread +from videoobmc2 import Videoobmc + +if hasattr(sys.modules["__main__"], "common_xbmc"): + common_xbmc = sys.modules["__main__"].common_xbmc +else: + import common_xbmc + + +class VideoobBaseAction(BaseAction): + def __init__(self): + count = common_xbmc.get_settings('nbVideoPerBackend') + numbers = ["10", "25", "50", "100"] + self.videoobmc = Videoobmc(count=numbers[int(count)], nsfw=common_xbmc.get_settings('nsfw')) + + +class DisplayMenuAction(VideoobBaseAction): + def _do(self, param={}): + backends = self.videoobmc.backends + if backends: + MenuItem(common_xbmc.get_translation('30000'), constants.SEARCH).add_to_menu() + for backend in backends: + icon = self.videoobmc.get_backend_icon(backend) + MenuItem(backend, constants.DISPLAY_BACKENDS, backend=backend, iconimage=icon).add_to_menu() + common_xbmc.end_of_directory(False) + else: + common_xbmc.display_error(" Please install and configure weboob") + + +class DisplayCollectionMenuAction(VideoobBaseAction): + def _do(self, param={}): + path = param.get('path') if 'path' in param.keys() else '' + collections, videos = self.videoobmc.ls(param.get('backend'), path=path) + threads = [] + + for col in collections: + MenuItemPath(col).add_to_menu() + for video in videos: + aThread = Thread(target=self.add_videos, args=(video, video.backend)) + threads.append(aThread) + aThread.start() + + for t in threads: + t.join() + + common_xbmc.end_of_directory(False) + + def add_videos(self, _video, backend): + print _video + video = self.videoobmc.get_video(_video, backend) + if video: + MenuItemVideo(video).add_to_menu() + + +class DownloadAction(VideoobBaseAction): + def _do(self, param={}): + _id = param.get('id') + backend = param.get('backend') + if _id: + aThread = Thread(target=self.download, args=(_id, backend)) + aThread.start() + common_xbmc.display_info(common_xbmc.get_translation('30301')) + common_xbmc.end_of_directory(False) + + def download(self, _id, backend): + dl_dir = common_xbmc.get_settings('downloadPath') + self.videoobmc.download(_id, dl_dir if dl_dir else common_xbmc.get_addon_dir(), backend) + common_xbmc.display_info(common_xbmc.get_translation('30302')) + + +class SearchAction(VideoobBaseAction): + def _do(self, param={}): + pattern = common_xbmc.ask_user('', common_xbmc.get_translation('30001')) + if pattern: + for video in self.videoobmc.search(pattern, param.get('backend')): + MenuItemVideo(video).add_to_menu() + common_xbmc.end_of_directory(False) + + +class DisplayBackendsAction(VideoobBaseAction): + def _do(self, param={}): + backend = param.get('backend') + if backend: + MenuItem('Search', constants.SEARCH, backend=backend).add_to_menu() + DisplayCollectionMenuAction()._do(param) + else: + common_xbmc.end_of_directory(False) + + +class UpdateWeboobAction(VideoobBaseAction): + def _do(self, param={}): + common_xbmc.display_info(common_xbmc.get_translation('30551')) + self.videoobmc.update() + common_xbmc.display_info(common_xbmc.get_translation('30552')) + + +actions = {constants.DISPLAY_MENU: DisplayMenuAction, + constants.DISPLAY_COLLECTION_MENU: DisplayCollectionMenuAction, + constants.SEARCH: SearchAction, + constants.DOWNLOAD: DownloadAction, + constants.DISPLAY_BACKENDS: DisplayBackendsAction, + constants.UPDATE: UpdateWeboobAction} diff --git a/contrib/plugin.video.videoobmc/resources/lib/base/__init__.py b/contrib/plugin.video.videoobmc/resources/lib/base/__init__.py new file mode 100644 index 00000000..ee074ac5 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/base/__init__.py @@ -0,0 +1 @@ +# Dummy file to make this directory a package. diff --git a/contrib/plugin.video.videoobmc/resources/lib/base/actions.py b/contrib/plugin.video.videoobmc/resources/lib/base/actions.py new file mode 100644 index 00000000..470da7d3 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/base/actions.py @@ -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 = {} diff --git a/contrib/plugin.video.videoobmc/resources/lib/base/common_xbmc.py b/contrib/plugin.video.videoobmc/resources/lib/base/common_xbmc.py new file mode 100644 index 00000000..1835ca75 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/base/common_xbmc.py @@ -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) diff --git a/contrib/plugin.video.videoobmc/resources/lib/base/menu.py b/contrib/plugin.video.videoobmc/resources/lib/base/menu.py new file mode 100644 index 00000000..4add6315 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/base/menu.py @@ -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) diff --git a/contrib/plugin.video.videoobmc/resources/lib/base/weboobmc.py b/contrib/plugin.video.videoobmc/resources/lib/base/weboobmc.py new file mode 100644 index 00000000..d1247594 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/base/weboobmc.py @@ -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() diff --git a/contrib/plugin.video.videoobmc/resources/lib/base/weboobmc2.py b/contrib/plugin.video.videoobmc/resources/lib/base/weboobmc2.py new file mode 100644 index 00000000..4ec65fb1 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/base/weboobmc2.py @@ -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) diff --git a/contrib/plugin.video.videoobmc/resources/lib/constants.py b/contrib/plugin.video.videoobmc/resources/lib/constants.py new file mode 100644 index 00000000..f74b91cf --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/constants.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- + +DISPLAY_MENU = "display_menu" +DISPLAY_COLLECTION_MENU = "display_collection_menu" +DISPLAY_BACKENDS = "display_backends" + +SEARCH = "search" +VIDEO = "video" +DOWNLOAD = "download" +UPDATE = "update" diff --git a/contrib/plugin.video.videoobmc/resources/lib/menu.py b/contrib/plugin.video.videoobmc/resources/lib/menu.py new file mode 100644 index 00000000..8f3d3e5c --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/menu.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +import sys +import constants + +from datetime import datetime, timedelta +from base.menu import BaseMenuItem, BaseMenuLink + +if hasattr(sys.modules["__main__"], "common_xbmc"): + common_xbmc = sys.modules["__main__"].common_xbmc +else: + import common_xbmc + + +class MenuItem(BaseMenuItem): + params = {} + + def __init__(self, name, action, iconimage="DefaultFolder.png", backend=''): + BaseMenuItem.__init__(self, name, action, iconimage) + self.params['backend'] = backend + + +class MenuItemPath(MenuItem): + + def __init__(self, collection, action=constants.DISPLAY_COLLECTION_MENU, iconimage="DefaultFolder.png"): + MenuItem.__init__(self, collection.title, action, iconimage, collection.fullid.split('@')[-1]) + self.params["path"] = '/'.join(collection.split_path) + + +class MenuItemVideo(BaseMenuLink): + def __init__(self, video, iconimage="DefaultFolder.png"): + name = '[%s] %s' % (video.backend, video.title) + BaseMenuLink.__init__(self, name, video.url, constants.VIDEO, + video.thumbnail.url if video.thumbnail.url else iconimage) + self.video = video + self.params["id"] = self.video.id + + def createVideoContextMenu(self): + cm = [] + + #Information + cm.append((common_xbmc.get_translation('30110'), "XBMC.Action(Info)")) + + #Téléchargement + url = "%s?action=%s&id=%s&backend=%s" % (sys.argv[0], constants.DOWNLOAD, self.video.id, self.video.backend) + cm.append((common_xbmc.get_translation('30100'), "XBMC.PlayMedia(%s)" % (url))) + + return cm + + def create_info_labels(self): + date, year = self.format_date(self.video.date) + + duration = 0 + if self.video.duration: + duration = u'%s' % str(self.video.duration.total_seconds()/60) if isinstance(self.video.duration, timedelta) else self.video.duration + + description = u'%s' % self.video.description + + return {"Title": self.video.title, + "Year": year, + "Plot": description, + "PlotOutline": description[0:30] if len(description) > 30 else description, + "Director": self.video.author if self.video.author else 'Unknown', + "Duration": duration, + "Date": date} + + def format_date(self, video_date): + date = datetime.now().strftime("%d/%m/%Y") + if video_date: + date = video_date.strftime("%d/%m/%Y") + + year = date.split('/')[-1] + return date, year diff --git a/contrib/plugin.video.videoobmc/resources/lib/test/__init__.py b/contrib/plugin.video.videoobmc/resources/lib/test/__init__.py new file mode 100644 index 00000000..ee074ac5 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/test/__init__.py @@ -0,0 +1 @@ +# Dummy file to make this directory a package. diff --git a/contrib/plugin.video.videoobmc/resources/lib/test/common_test.py b/contrib/plugin.video.videoobmc/resources/lib/test/common_test.py new file mode 100644 index 00000000..112cc496 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/test/common_test.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- + +import urllib + + +def get_addon(): + pass + + +def get_translation(key): + translation = {'30000': 'Recherche', + '30001': 'Recherche :', + '30100': 'Télécharger', + '30110': 'Information', + '30200': 'Erreur!', + '30300': 'Information', + '30301': 'Lancement du téléchargement', + '30302': 'Fichier téléchargé avec succès', + '30551': 'Debut de la mise à jour', + '30552': 'Weboob est maintenant à jour'} + return translation.get(key) + + +def get_addon_dir(): + return '/home/benjamin' + + +def get_settings(key): + settings = {'downloadPath': get_addon_dir(), + 'nbVideoPerBackend': '0', + 'nsfw': 'False'} + return settings.get(key) + + +def display_error(error): + print "%s: %s" % ("ERROR", error) + + +def display_info(msg): + print "%s: %s" % ("INFO", msg) + + +def parse_params(paramStr): + + paramDic = {} + # Parameters are on the 3rd arg passed to the script + if len(paramStr) > 1: + paramStr = paramStr.replace('?', '') + + # Ignore last char if it is a '/' + if paramStr[len(paramStr) - 1] == '/': + paramStr = paramStr[0:len(paramStr) - 2] + + # Processing each parameter splited on '&' + for param in paramStr.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 + paramDic[key] = value + return paramDic + + +def ask_user(content, title): + return raw_input(title) + + +def create_param_url(paramsDic, quote_plus=False): + + #url = sys.argv[0] + url = '' + sep = '?' + + try: + for param in paramsDic: + if quote_plus: + url = url + sep + urllib.quote_plus(param) + '=' + urllib.quote_plus(paramsDic[param]) + else: + url = "%s%s%s=%s" % (url, sep, param, paramsDic[param]) + + sep = '&' + except Exception, msg: + display_error("create_param_url %s" % msg) + url = None + return url + + +def add_menu_item(params={}): + print '%s => "%s"' % (params.get('name'), create_param_url(params)) + + +def add_menu_link(params={}): + print '[%s] %s (%s)' % (params.get('id'), params.get('name'), params.get('url')) + #print params.get('itemInfoLabels') + #print params.get('c_items') + + +def end_of_directory(update=False): + print '******************************************************' + + +def download_video(url, name, dir='./'): + print 'Downlaod a video %s from %s' % (name, url) diff --git a/contrib/plugin.video.videoobmc/resources/lib/videoobmc.py b/contrib/plugin.video.videoobmc/resources/lib/videoobmc.py new file mode 100644 index 00000000..da5c995b --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/videoobmc.py @@ -0,0 +1,94 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import time + +from datetime import timedelta, datetime +from .base.weboobmc import Weboobmc +from weboob.capabilities.video import BaseVideo +from weboob.capabilities.image import BaseImage +from weboob.capabilities.collection import Collection + +class Videoobmc(Weboobmc): + def __init__(self, count=10, nsfw=False): + Weboobmc.__init__(self, count=count) + self.backends =list(self.get_loaded_backends('CapVideo')) + _nsfw = 'on' if nsfw else 'off' + self._call_weboob('videoob', 'nsfw', argument=_nsfw) + + def search(self, pattern, backend=''): + #videoob search pattern -f json + options = {'--select': 'id,title,date,description,author,duration,thumbnail,url'} + if backend: + options['-b'] = backend + _videos = self._json_call_weboob('videoob', 'search', argument=pattern, options=options) + if _videos: + for _video in _videos: + yield self.create_video_from_json(_video) + + def create_video_from_json(self, _video): + video = BaseVideo() + video.id = u'%s' % _video['id'] + video.backend = u'%s' % _video['id'].split('@')[-1] + + if 'url' in _video.keys(): + video.url = u'%s' % _video['url'] + + if 'thumbnail' in _video.keys() and _video['thumbnail'] and 'url' in _video['thumbnail'].keys(): + video.thumbnail = BaseImage() + video.thumbnail.url = u'%s' % _video['thumbnail']['url'] + else: + video.thumbnail.url = u'' + video.title = u'%s' % _video['title'] + + if _video['date']: + + try: + datetime.strptime(_video['date'].split('.')[0], '%Y-%m-%d %H:%M:%S') + except TypeError: + datetime(*(time.strptime(_video['date'].split('.')[0], '%Y-%m-%d %H:%M:%S')[0:6])) + + video.description = u'%s' % _video['description'] + video.author = u'%s' % _video['author'] + + if _video['duration']: + _duration = _video['duration'].split(':') + video.duration = timedelta(hours=int(_duration[0]), minutes=int(_duration[1]), seconds=int(_duration[2])) + + return video + + def get_video(self, video, backend): + #videoob info _id -f json + _video = self._json_call_weboob('videoob', 'info', argument=video.id) + if _video and len(_video) > 0: + return self.create_video_from_json(_video[0]) + + def ls(self, backend, path=''): + options = {'-b': backend} + result = self._json_call_weboob('videoob', 'ls', options=options, argument=path) + return self.separate_collections_and_videos(result) + + def separate_collections_and_videos(self, objs): + videos = [] + categories = [] + for obj in objs: + if self.is_category(obj): + categories.append(self.create_category_from_json(obj)) + else: + video = BaseVideo() + video.id = obj['id'].split('@')[0] + video.backend = obj['id'].split('@')[-1] + videos.append(video) + return categories, videos + + def create_category_from_json(self, obj): + collection = Collection(obj['split_path'].split('/')) + collection.title = obj['title'] + collection.id = obj['id'].split('@')[0] + collection.backend = obj['id'].split('@')[1] + return collection + + def download(self, _id, path, backend): + #videoob download _id path + options = {'-b': backend} + self._call_weboob('videoob', 'download', options=options, argument=u'%s %s' % (_id, path)) diff --git a/contrib/plugin.video.videoobmc/resources/lib/videoobmc.py b/contrib/plugin.video.videoobmc/resources/lib/videoobmc.py new file mode 100644 index 00000000..73fcfd15 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/videoobmc.py @@ -0,0 +1,93 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import time + +from datetime import timedelta, datetime +from .base.weboobmc import Weboobmc +from weboob.capabilities.video import BaseVideo +from weboob.capabilities.image import BaseImage +from weboob.capabilities.collection import Collection + +class Videoobmc(Weboobmc): + def __init__(self, count=10, nsfw=False): + Weboobmc.__init__(self, count=count) + self.backends =list(self.get_loaded_backends('CapVideo')) + _nsfw = 'on' if nsfw else 'off' + self._call_weboob('videoob', 'nsfw', argument=_nsfw) + + def search(self, pattern, backend=''): + #videoob search pattern -f json + options = {'--select': 'id,title,date,description,author,duration,thumbnail,url'} + if backend: + options['-b'] = backend + _videos = self._json_call_weboob('videoob', 'search', argument=pattern, options=options) + if _videos: + for _video in _videos: + yield self.create_video_from_json(_video) + + def create_video_from_json(self, _video): + video = BaseVideo() + video.id = u'%s' % _video['id'] + print video.id + print _video['id'] + video.backend = u'%s' % _video['id'].split('@')[-1] + + if 'url' in _video.keys(): + video.url = u'%s' % _video['url'] + + if 'thumbnail' in _video.keys() and _video['thumbnail'] and 'url' in _video['thumbnail'].keys(): + video.thumbnail = BaseImage() + video.thumbnail.url = u'%s' % _video['thumbnail']['url'] + else: + video.thumbnail.url = u'' + video.title = u'%s' % _video['title'] + + if _video['date']: + + try: + video.date = datetime.strptime(_video['date'].split('.')[0], '%Y-%m-%d %H:%M:%S') + except TypeError: + video.date = datetime(*(time.strptime(_video['date'].split('.')[0], '%Y-%m-%d %H:%M:%S')[0:6])) + + video.description = u'%s' % _video['description'] + video.author = u'%s' % _video['author'] + + if _video['duration']: + _duration = _video['duration'].split(':') + video.duration = timedelta(hours=int(_duration[0]), minutes=int(_duration[1]), seconds=int(_duration[2])) + + return video + + def get_video(self, _id, backend): + #videoob info _id -f json + _video = self._json_call_weboob('videoob', 'info', argument=_id) + if _video and len(_video) > 0: + return self.create_video_from_json(_video[0]) + + def ls(self, backend, path=''): + options = {'-b': backend} + result = self._json_call_weboob('videoob', 'ls', options=options, argument=path) + return self.separate_collections_and_videos(result) + + def separate_collections_and_videos(self, objs): + videos = [] + categories = [] + for obj in objs: + if self.is_category(obj): + categories.append(self.create_category_from_json(obj)) + else: + #videos.append(self.get_video(obj['id'])) + videos.append(self.create_video_from_json(obj)) + return categories, videos + + def create_category_from_json(self, obj): + collection = Collection(obj['split_path'].split('/')) + collection.title = obj['title'] + collection.id = obj['id'].split('@')[0] + collection.backend = obj['id'].split('@')[1] + return collection + + def download(self, _id, path): + #videoob download _id path + self._call_weboob('videoob', 'download', argument=u'%s %s' % (_id, path)) diff --git a/contrib/plugin.video.videoobmc/resources/lib/videoobmc2.py b/contrib/plugin.video.videoobmc/resources/lib/videoobmc2.py new file mode 100644 index 00000000..1f98ff76 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/lib/videoobmc2.py @@ -0,0 +1,53 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from .base.weboobmc2 import Weboobmc +from weboob.capabilities.video import BaseVideo, CapVideo +from weboob.capabilities.collection import CapCollection, Collection + + +class Videoobmc(Weboobmc): + def __init__(self, count=10, nsfw=False): + Weboobmc.__init__(self, count=count) + self.backends = self.weboob.load_backends(CapVideo) + self.nsfw = nsfw + + def search(self, pattern, backend=''): + kwargs = {'pattern': pattern, + 'nsfw': self.nsfw, + 'backends': backend} + + fields = ['id', 'title', 'date', 'description', 'author', 'duration', 'thumbnail', 'url'] + try: + for _backend, video in self.weboob.do(self._do_complete, self.count, fields, 'search_videos', **kwargs): + yield video + except Exception as e: + print e + + def get_video(self, video, _backend): + backend = self.weboob.get_backend(_backend) + fields = ['id', 'title', 'date', 'description', 'author', 'duration', 'thumbnail', 'url'] + return backend.fillobj(video, fields) + + def ls(self, backend, path=''): + kwargs = {'split_path': path.split('/') if path else [], + 'caps': CapCollection, + 'objs': (BaseVideo, ), + 'backends': backend} + fields = [] # ['id', 'title', 'date', 'description', 'author', 'duration', 'thumbnail', 'url'] + result = self.weboob.do(self._do_complete, self.count, fields, 'iter_resources', **kwargs) + return self.separate_collections_and_videos(result) + + def separate_collections_and_videos(self, objs): + videos = [] + categories = [] + for backend, obj in objs: + if isinstance(obj, Collection): + categories.append(obj) + else: + videos.append(obj) + return categories, videos + + def download(self, _id, dest, backend): + for backend, _video in self.weboob.do('get_video', _id, backends=backend): + self.download_obj(_video, dest) diff --git a/contrib/plugin.video.videoobmc/resources/settings.xml b/contrib/plugin.video.videoobmc/resources/settings.xml new file mode 100644 index 00000000..8a760d36 --- /dev/null +++ b/contrib/plugin.video.videoobmc/resources/settings.xml @@ -0,0 +1,11 @@ + + + + + + + + + + +