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 00000000..03846cae Binary files /dev/null and b/contrib/plugin.video.videoobmc/icon.png differ 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 @@ + + + + + + + + + + +