diff --git a/scripts/boobank b/scripts/boobank index e2f871849c267355c6aab73ff0fb1c8f38d15372..b208313a3149aa174ad514f90ccb970402bc366a 100755 --- a/scripts/boobank +++ b/scripts/boobank @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.boobank import Boobank +from weboob.applications.boobank import Boobank if __name__ == '__main__': diff --git a/scripts/chatoob b/scripts/chatoob index a76a959f6f720f6cac8234ca22cd9777c0dd7687..b578c01b064bc30a2e932599401bf8195f9a3776 100755 --- a/scripts/chatoob +++ b/scripts/chatoob @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.chatoob import Chatoob +from weboob.applications.chatoob import Chatoob if __name__ == '__main__': diff --git a/scripts/havesex b/scripts/havesex index c4d7a8a303fbde4ae2faa178810898f56ed96d47..a52bd9d1d1783b4e45be352a6c1bc39e44f6e5ee 100755 --- a/scripts/havesex +++ b/scripts/havesex @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.havesex import HaveSex +from weboob.applications.havesex import HaveSex if __name__ == '__main__': diff --git a/scripts/masstransit b/scripts/masstransit index 915c257ff5b7fc24cce775fdf1423134e16ad553..1a545f3c52ed92c9884b761abf3c25283e06351e 100755 --- a/scripts/masstransit +++ b/scripts/masstransit @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.masstransit import Masstransit +from weboob.applications.masstransit import Masstransit if __name__ == '__main__': diff --git a/scripts/monboob b/scripts/monboob index 927fda66c2bc5da5a853d8315469370b2c7ce23c..31cbcad20558f26481533d21378b0b43d4d5e800 100755 --- a/scripts/monboob +++ b/scripts/monboob @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.monboob import Monboob +from weboob.applications.monboob import Monboob if __name__ == '__main__': diff --git a/scripts/qboobmsg b/scripts/qboobmsg index 9cc2e88bc1acacfcd76ee60f45b815497dbc8a31..4177e49ccab23e90173efca93793d9ebcd9cd9e3 100755 --- a/scripts/qboobmsg +++ b/scripts/qboobmsg @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.qboobmsg import QBoobMsg +from weboob.applications.qboobmsg import QBoobMsg if __name__ == '__main__': diff --git a/scripts/qhavesex b/scripts/qhavesex index 3cadf607b6776ad4b3c07bb587c6f5485df97980..ce2c7ade8a670f753d0e012368997ea3f049bfbb 100755 --- a/scripts/qhavesex +++ b/scripts/qhavesex @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.qhavesex import QHaveSex +from weboob.applications.qhavesex import QHaveSex if __name__ == '__main__': diff --git a/scripts/qvideoob b/scripts/qvideoob index 28f5726a6ff0f374a16b54f6575295c27396cb19..ea6d48e98688364ed11e18dd51d5d7b923f8817e 100755 --- a/scripts/qvideoob +++ b/scripts/qvideoob @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.qvideoob import QVideoob +from weboob.applications.qvideoob import QVideoob if __name__ == '__main__': diff --git a/scripts/travel b/scripts/travel index 32b76c9e99c80a3d5e731fa70bf7dcd24310f9ee..a09d6ac43859a1bd73826a68638b1d9d8d8d825a 100755 --- a/scripts/travel +++ b/scripts/travel @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.travel import Travel +from weboob.applications.travel import Travel if __name__ == '__main__': diff --git a/scripts/videoob b/scripts/videoob index 51897a5f7aa9cfdfab909b05844413569ef5ca1b..72fbe7a89e8d40f98264934cdde09f5e45331496 100755 --- a/scripts/videoob +++ b/scripts/videoob @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.videoob import Videoob +from weboob.applications.videoob import Videoob if __name__ == '__main__': diff --git a/scripts/videoob-web-server b/scripts/videoob-web-server index c6e2cab06fe7925c26e9be45d40985a73e648924..ada312d18ce7a92fe2b05851d7b889514230bacd 100755 --- a/scripts/videoob-web-server +++ b/scripts/videoob-web-server @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.videoob_web import VideoobWeb +from weboob.applications.videoob_web import VideoobWeb if __name__ == '__main__': diff --git a/scripts/weboob-debug b/scripts/weboob-debug index 48416ad90f2dd402433aebe24cc214e079f1eb70..84425bd15cabcfd24bbb49aead9de996d127606f 100755 --- a/scripts/weboob-debug +++ b/scripts/weboob-debug @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.weboobdebug import WeboobDebug +from weboob.applications.weboobdebug import WeboobDebug if __name__ == '__main__': diff --git a/scripts/weboob-tests b/scripts/weboob-tests index c79456f5d3b279f6cc2e156d472d330396dcf00c..3d698f0b3eef5e3303aa82fd10b6d016b4d31e30 100755 --- a/scripts/weboob-tests +++ b/scripts/weboob-tests @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.weboobtests import WeboobTests +from weboob.applications.weboobtests import WeboobTests if __name__ == '__main__': diff --git a/scripts/weboobcfg b/scripts/weboobcfg index a4609f6ec08b073dc1d8d2626f27f415238890c2..c712b7849fde2321a183eed3b112c15ab21924cb 100755 --- a/scripts/weboobcfg +++ b/scripts/weboobcfg @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.weboobcfg import WeboobCfg +from weboob.applications.weboobcfg import WeboobCfg if __name__ == '__main__': diff --git a/scripts/weboorrents b/scripts/weboorrents index 75665b365b877807bc63d1590c60bfda620a1b8d..ec69235d9de644c22331bbfcc4db92338d37a333 100755 --- a/scripts/weboorrents +++ b/scripts/weboorrents @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.weboorrents import Weboorrents +from weboob.applications.weboorrents import Weboorrents if __name__ == '__main__': diff --git a/scripts/wetboobs b/scripts/wetboobs index 88882e25c6955b1f01f6101b138cb4a3fc73dfa7..12fa2b583548cdec1ceec557469d29776a5acdcd 100755 --- a/scripts/wetboobs +++ b/scripts/wetboobs @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -from weboob.frontends.wetboobs import WetBoobs +from weboob.applications.wetboobs import WetBoobs if __name__ == '__main__': diff --git a/tools/all_packages.sh b/tools/all_packages.sh index 46522919819537c38a3d8018ceaec70f648fee8a..bdd4bf94cc0d3b76944b3c1a3c8c38285ac74de9 100755 --- a/tools/all_packages.sh +++ b/tools/all_packages.sh @@ -5,17 +5,17 @@ COMMAND="$1" SETUP_PY_LIST=" weboob/setup.py weboob/backends/setup.py -weboob/frontends/boobank/setup.py -weboob/frontends/masstransit/setup.py -weboob/frontends/monboob/setup.py -weboob/frontends/qboobmsg/setup.py -weboob/frontends/qhavesex/setup.py -weboob/frontends/qvideoob/setup.py -weboob/frontends/travel/setup.py -weboob/frontends/videoob/setup.py -weboob/frontends/videoob_web/setup.py -weboob/frontends/weboorrents/setup.py -weboob/frontends/wetboobs/setup.py +weboob/applications/boobank/setup.py +weboob/applications/masstransit/setup.py +weboob/applications/monboob/setup.py +weboob/applications/qboobmsg/setup.py +weboob/applications/qhavesex/setup.py +weboob/applications/qvideoob/setup.py +weboob/applications/travel/setup.py +weboob/applications/videoob/setup.py +weboob/applications/videoob_web/setup.py +weboob/applications/weboorrents/setup.py +weboob/applications/wetboobs/setup.py " diff --git a/weboob/applications/__init__.py b/weboob/applications/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..de40ea7ca058e07a399acf61529d418c07eeee61 --- /dev/null +++ b/weboob/applications/__init__.py @@ -0,0 +1 @@ +__import__('pkg_resources').declare_namespace(__name__) diff --git a/weboob/applications/boobank/__init__.py b/weboob/applications/boobank/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..b6558548d3e6f7d86645ead683f27dd813dc1078 --- /dev/null +++ b/weboob/applications/boobank/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .boobank import Boobank diff --git a/weboob/applications/boobank/boobank.py b/weboob/applications/boobank/boobank.py new file mode 100644 index 0000000000000000000000000000000000000000..5c3510d76c491b9e5663d4be163d4e2337adaee4 --- /dev/null +++ b/weboob/applications/boobank/boobank.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# vim: ft=python et softtabstop=4 cinoptions=4 shiftwidth=4 ts=4 ai + +# Copyright(C) 2009-2010 Romain Bignon, Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from __future__ import with_statement + +import logging + +import weboob +from weboob.capabilities.bank import ICapBank, AccountNotFound +from weboob.tools.application import ConsoleApplication + + +__all__ = ['Boobank'] + + +class Boobank(ConsoleApplication): + APPNAME = 'boobank' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + + def main(self, argv): + self.load_backends(ICapBank) + return self.process_command(*argv[1:]) + + @ConsoleApplication.command('List every available accounts') + def command_list(self): + try: + for backend, account in self.weboob.do('iter_accounts'): + self.format(account, backend.name) + except weboob.CallErrors, errors: + for backend, error, backtrace in errors: + if isinstance(error, weboob.tools.browser.BrowserIncorrectPassword): + logging.error(u'Error: Incorrect password for backend %s' % backend.name) + else: + logging.error(u'Error[%s]: %s\n%s' % (backend.name, error, backtrace)) + + @ConsoleApplication.command('Display all future operations') + def command_coming(self, id): + total = 0.0 + + def do(backend): + account = backend.get_account(id) + return backend.iter_operations(account) + + try: + for backend, operation in self.weboob.do(do): + self.format(operation, backend.name) + total += operation.amount + except weboob.CallErrors, errors: + for backend, error, backtrace in errors: + if isinstance(error, AccountNotFound): + logging.error(u'Error: account %s not found' % id) + else: + logging.error(u'Error[%s]: %s\n%s' % (backend.name, error, backtrace)) diff --git a/weboob/applications/boobank/setup.py b/weboob/applications/boobank/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..e0287d593b49ddaf13b04dd8b82dcb81959d5826 --- /dev/null +++ b/weboob/applications/boobank/setup.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-boobank', + version='0.1', + description='Boobank, the Weboob bank-accounts swiss-knife', + long_description='List your bank accounts and get info about them', + author='Christophe Benz, Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/Boobank', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.boobank', + ], + scripts=[ + 'scripts/boobank', + ], + install_requires=[ + 'weboob-bank-backends', + ], +) diff --git a/weboob/applications/chatoob/__init__.py b/weboob/applications/chatoob/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e106ea0230c2758268b778b7ddc66c0931a58309 --- /dev/null +++ b/weboob/applications/chatoob/__init__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from .chatoob import Chatoob diff --git a/weboob/applications/chatoob/chatoob.py b/weboob/applications/chatoob/chatoob.py new file mode 100644 index 0000000000000000000000000000000000000000..9262cb76696b39835839bb48b3ef902949d29ac4 --- /dev/null +++ b/weboob/applications/chatoob/chatoob.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +import logging + +from weboob.tools.application import ConsoleApplication +from weboob.capabilities.chat import ICapChat +from weboob.capabilities.contact import ICapContact, Contact + + +__all__ = ['Chatoob'] + + +class Chatoob(ConsoleApplication): + APPNAME = 'chatoob' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Christophe Benz' + + def main(self, argv): + self.load_backends(ICapChat) + #for backend, result in self.weboob.do('start_chat_polling', self.on_new_chat_message): + #logging.info(u'Polling chat messages for backend %s' % backend) + return self.process_command(*argv[1:]) + + def on_new_chat_message(self, message): + print 'on_new_chat_message: %s' % message + + @ConsoleApplication.command('exit program') + def command_exit(self): + self.weboob.want_stop() + + @ConsoleApplication.command('list online contacts') + def command_list(self): + for backend, contact in self.weboob.do_caps(ICapContact, 'iter_contacts', status=Contact.STATUS_ONLINE): + self.format(contact, backend.name) + + @ConsoleApplication.command('get messages') + def command_messages(self): + for backend, message in self.weboob.do('iter_chat_messages'): + self.format(message, backend.name) + + @ConsoleApplication.command('send message to contact') + def command_send(self, _id, message): + for backend, result in self.weboob.do('send_chat_message', _id, message): + if not result: + logging.error(u'Failed to send message to contact id="%s" on backend "%s"' % (_id, backend.name)) diff --git a/weboob/applications/havesex/__init__.py b/weboob/applications/havesex/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..80fb0343e1c79e410b06b153e265e87ac78327f6 --- /dev/null +++ b/weboob/applications/havesex/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .havesex import HaveSex diff --git a/weboob/applications/havesex/havesex.py b/weboob/applications/havesex/havesex.py new file mode 100644 index 0000000000000000000000000000000000000000..656b44a871f569710b0388815b793d31a0dddc43 --- /dev/null +++ b/weboob/applications/havesex/havesex.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from __future__ import with_statement + +import sys + +import weboob +from weboob.tools.application import PromptApplication +from weboob.capabilities.dating import ICapDating, OptimizationNotFound + + +__all__ = ['HaveSex'] + + +class HaveSex(PromptApplication): + APPNAME = 'havesex' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + STORAGE_FILENAME = 'dating.storage' + CONFIG = {'optimizations': ''} + + def main(self, argv): + self.load_config() + self.load_backends(ICapDating, storage=self.create_storage(self.STORAGE_FILENAME)) + + self.weboob.do('init_optimizations').wait() + + self.optims('Starting', 'start_optimization', self.config.get('optimizations').split(' ')) + + return self.loop() + + @PromptApplication.command("exit program") + def command_exit(self): + print 'Returning in real-life...' + self.weboob.want_stop() + + @PromptApplication.command("show a profile") + def command_profile(self, id): + _id, backend_name = self.parse_id(id) + + found = 0 + for backend, profile in self.weboob.do_backends(backend_name, 'get_profile', _id): + if profile: + print profile.get_profile_text() + found = 1 + + if not found: + print >>sys.stderr, 'Profile not found' + + return True + + def service(self, action, function, *params): + sys.stdout.write('%s:' % action) + for backend, result in self.weboob.do(function, *params): + if result: + sys.stdout.write(' ' + backend.name) + sys.stdout.flush() + sys.stdout.write('.\n') + + def optims(self, action, function, optims): + for optim in optims: + try: + self.service('Starting %s' % optim, 'start_optimization', optim) + except weboob.CallErrors, errors: + for backend, error, backtrace in errors: + if isinstance(error, OptimizationNotFound): + print 'Optimization "%s" not found' % optim + + @PromptApplication.command("start optimizations") + def command_start(self, *optims): + self.optims('Starting', 'start_optimization', optims) + + @PromptApplication.command("stop optimizations") + def command_stop(self, *optims): + self.optims('Stopping', 'stop_optimization', optims) diff --git a/weboob/applications/masstransit/__init__.py b/weboob/applications/masstransit/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..55b190ebbf765112c26b22b7fbeb2b6b157b23b2 --- /dev/null +++ b/weboob/applications/masstransit/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# vim: ft=python et softtabstop=4 cinoptions=4 shiftwidth=4 ts=4 ai + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .masstransit import Masstransit diff --git a/weboob/applications/masstransit/masstransit.py b/weboob/applications/masstransit/masstransit.py new file mode 100644 index 0000000000000000000000000000000000000000..37d80c1b39e7f797e7effbd5fc7af135bb05a915 --- /dev/null +++ b/weboob/applications/masstransit/masstransit.py @@ -0,0 +1,239 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Julien Hébert +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from weboob.capabilities.travel import ICapTravel +from weboob.tools.application import BaseApplication + +import conic +import gtk +import hildon +from logging import debug + + +__all__ = ['Masstransit'] + + +class MasstransitHildon(): + "hildon interface" + + def connect_event(self, connection, event=None, c=None, d=None): + debug("DBUS-DEBUG a: %s, b:%s, c:%s,d: %s" % (connection, event, c, d)) + status = event.get_status() + if status == conic.STATUS_CONNECTED: + self.connected = True + if self.touch_selector_entry_filled == False: + debug("connected, now fill") + self.fill_touch_selector_entry() + if self.refresh_in_progress: + self.refresh() + elif status == conic.STATUS_DISCONNECTED: + self.connected = False + + def __init__(self, weboob): + self.touch_selector_entry_filled = False + self.refresh_in_progress = False + self.connected = False + self.weboob = weboob + self.connection = conic.Connection() + self.connection.connect("connection-event", self.connect_event) + self.connection.set_property("automatic-connection-events", True) + self.connection.request_connection(conic.CONNECT_FLAG_NONE) + + main_window = hildon.Window() + main_window.set_title("Horaires des Prochains Trains") + main_window.connect("destroy", self.on_main_window_destroy) + + self.refresh_button = hildon.Button( + gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, + hildon.BUTTON_ARRANGEMENT_HORIZONTAL, + "Actualiser" + ) + + self.refresh_button.set_sensitive(False) + self.refresh_button.connect("clicked", self.on_refresh_button_clicked) + + self.retour_button = hildon.Button( + gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, + hildon.BUTTON_ARRANGEMENT_HORIZONTAL, + "Retour" + ) + + self.retour_button.set_sensitive(False) + self.retour_button.connect("clicked", self.on_retour_button_clicked) + + self.treestore = gtk.TreeStore(str, str, str, str, str) + treeview = gtk.TreeView(self.treestore) + + + treeview.append_column( + gtk.TreeViewColumn( + 'Train', + gtk.CellRendererText(), + text=0 + )) + + treeview.append_column( + gtk.TreeViewColumn( + 'Horaire', + gtk.CellRendererText(), + text=1 + )) + + treeview.append_column( + gtk.TreeViewColumn( + 'Destination', + gtk.CellRendererText(), + text=2 + )) + treeview.append_column( + gtk.TreeViewColumn( + 'Voie', + gtk.CellRendererText(), + text=3 + )) + + treeview.append_column( + gtk.TreeViewColumn( + 'Information', + gtk.CellRendererText(), + text=4 + )) + + + self.combo_source = hildon.TouchSelectorEntry(text=True) + self.combo_dest = hildon.TouchSelectorEntry(text=True) + + self.picker_button_source = hildon.PickerButton( + gtk.HILDON_SIZE_AUTO, + hildon.BUTTON_ARRANGEMENT_VERTICAL) + + self.picker_button_dest = hildon.PickerButton( + gtk.HILDON_SIZE_AUTO, + hildon.BUTTON_ARRANGEMENT_VERTICAL + ) + + self.picker_button_source.set_sensitive(False) + self.picker_button_dest.set_sensitive(False) + + self.picker_button_source.set_title("Gare de Depart") + self.picker_button_dest.set_title("Gare d'arrivee") + + self.picker_button_source.set_selector(self.combo_source) + self.picker_button_dest.set_selector(self.combo_dest) + + vertical_box = gtk.VBox() + horizontal_box = gtk.HBox() + vertical_box.pack_start(horizontal_box) + horizontal_box.pack_start(self.picker_button_source) + horizontal_box.pack_start(self.picker_button_dest) + horizontal_box.pack_start(self.retour_button) + vertical_box.pack_start(treeview) + vertical_box.pack_start(self.refresh_button) + + main_window.add(vertical_box) + main_window.show_all() + + self.picker_button_source.connect("value-changed", + self.check_station_input, + self.picker_button_source) + self.picker_button_dest.connect("value-changed", + self.check_station_input, + self.picker_button_dest) + + def fill_touch_selector_entry(self): + liste = [] + + for backend in self.weboob.iter_backends(): + for station in backend.iter_station_search(""): + liste.append(station.name.capitalize()) + + liste.sort() + + for station in liste: + self.combo_source.append_text(station) + self.combo_dest.append_text(station) + + self.touch_selector_entry_filled = True + self.picker_button_source.set_sensitive(True) + + def on_main_window_destroy(self, widget): + "exit application at the window close" + gtk.main_quit() + + def on_main_window_show(self, param): + self.fill_touch_selector_entry() + + def on_retour_button_clicked(self, widget): + "the button is clicked" + self.refresh_in_progress = True + col_source = self.combo_source.get_active(0) + col_dest = self.combo_dest.get_active(0) + self.combo_source.set_active(0, col_dest) + self.combo_dest.set_active(0, col_source) + self.refresh() + + def on_refresh_button_clicked(self, widget): + "the refresh button is clicked" + self.refresh_in_progress = True + self.connection.request_connection(conic.CONNECT_FLAG_NONE) + + def check_station_input(self, widget, user_data): + if self.combo_source.get_current_text() is None : + self.picker_button_dest.set_sensitive(False) + self.refresh_button.set_sensitive(False) + self.retour_button.set_sensitive(False) + else: + self.picker_button_dest.set_sensitive(True) + if self.combo_dest.get_current_text() is None: + self.refresh_button.set_sensitive(False) + self.retour_button.set_sensitive(False) + else: + self.refresh_button.set_sensitive(True) + self.retour_button.set_sensitive(True) + + def refresh(self): + "update departures" + self.treestore.clear() + for backend in self.weboob.iter_backends(): + for station in \ + backend.iter_station_search(self.combo_source.get_current_text()): + for arrival in \ + backend.iter_station_search(self.combo_dest.get_current_text()): + for departure in \ + backend.iter_station_departures(station.id, arrival.id): + self.treestore.append(None, + [departure.type, + departure.time, + departure.arrival_station, + departure.plateform, + departure.information]) + + self.refresh_in_progress = False + + +class Masstransit(BaseApplication): + "Application Class" + APPNAME = 'masstransit' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Julien Hébert' + + def main(self, argv): + "main fonction" + self.load_modules(ICapTravel) + MasstransitHildon(self.weboob) + gtk.main() diff --git a/weboob/applications/masstransit/setup.py b/weboob/applications/masstransit/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..c9cbda3acb8a619dc04594a477ac0000c24b3e5e --- /dev/null +++ b/weboob/applications/masstransit/setup.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-masstransit', + version='0.1', + description='Masstransit, the Weboob travel swiss-knife, Hildon version (Maemo OS)', + long_description='Search for train stations and departure timegrids', + author='Julien Hébert', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/Masstransit', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.masstransit', + ], + scripts=[ + 'scripts/masstransit', + ], + install_requires=[ + 'weboob-travel-backends', + ], +) diff --git a/weboob/applications/monboob/__init__.py b/weboob/applications/monboob/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ee4a0e9786c8ebab8f27536ba1d67f27c024dc6b --- /dev/null +++ b/weboob/applications/monboob/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# vim: ft=python et softtabstop=4 cinoptions=4 shiftwidth=4 ts=4 ai + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from .monboob import Monboob diff --git a/weboob/applications/monboob/monboob.py b/weboob/applications/monboob/monboob.py new file mode 100644 index 0000000000000000000000000000000000000000..81ed3cfae68a6dd4959495644bee1769ac2fdeb7 --- /dev/null +++ b/weboob/applications/monboob/monboob.py @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2009-2010 Romain Bignon, Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from email.mime.text import MIMEText +from smtplib import SMTP +from email.Header import Header, decode_header +from email.Utils import parseaddr, formataddr, formatdate +from email import message_from_file, message_from_string +from smtpd import SMTPServer +import time +import re +import sys +import logging +import asyncore + +from weboob.core.engine import Weboob +from weboob.core.scheduler import Scheduler +from weboob.capabilities.messages import ICapMessages, ICapMessagesReply, Message +from weboob.tools.application import ConsoleApplication +from weboob.tools.misc import html2text, get_backtrace, utc2local + + +__all__ = ['Monboob'] + +class FakeSMTPD(SMTPServer): + def __init__(self, app, bindaddr, port): + SMTPServer.__init__(self, (bindaddr, port), None) + self.app = app + + def process_message(self, peer, mailfrom, rcpttos, data): + msg = message_from_string(data) + self.app.process_incoming_mail(msg) + +class MonboobScheduler(Scheduler): + def __init__(self, app): + Scheduler.__init__(self) + self.app = app + + def run(self): + if self.app.options.smtpd: + if ':' in self.app.options.smtpd: + host, port = self.app.options.smtpd.split(':', 1) + else: + host = '127.0.0.1' + port = self.app.options.smtpd + FakeSMTPD(self.app, host, int(port)) + + # XXX Fuck, we shouldn't copy this piece of code from + # weboob.scheduler.Scheduler.run(). + try: + while 1: + self.stop_event.wait(0.1) + if self.app.options.smtpd: + asyncore.loop(timeout=0.1, count=1) + except KeyboardInterrupt: + self._wait_to_stop() + raise + else: + self._wait_to_stop() + return True + + +class Monboob(ConsoleApplication): + APPNAME = 'monboob' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + CONFIG = {'interval': 15, + 'domain': 'weboob.example.org', + 'recipient': 'weboob@example.org', + 'smtp': 'localhost', + 'html': 0} + + def add_application_options(self, group): + group.add_option('-S', '--smtpd', help='run a fake smtpd server and set the port') + + def create_weboob(self): + return Weboob(scheduler=MonboobScheduler(self)) + + def main(self, argv): + self.load_config() + self.load_backends(ICapMessages, storage=self.create_storage()) + + return self.process_command(*argv[1:]) + + def get_email_address_ident(self, msg, header): + s = msg.get(header) + m = re.match('.*<(.*)@(.*)>', s) + if m: + return m.group(1) + else: + try: + return s.split('@')[0] + except IndexError: + return s + + @ConsoleApplication.command("pipe with a mail to post message") + def command_post(self): + msg = message_from_file(sys.stdin) + return self.process_incoming_mail(msg) + + def process_incoming_mail(self, msg): + to = self.get_email_address_ident(msg, 'To') + reply_to = self.get_email_address_ident(msg, 'In-Reply-To') + if not reply_to: + print >>sys.stderr, 'This is not a reply (no Reply-To field)' + return 1 + + title = msg.get('Subject') + if title: + new_title = u'' + for part in decode_header(title): + if part[1]: + new_title += unicode(part[0], part[1]) + else: + new_title += unicode(part[0]) + title = new_title + + content = u'' + for part in msg.walk(): + if part.get_content_type() == 'text/plain': + s = part.get_payload(decode=True) + charsets = part.get_charsets() + msg.get_charsets() + for charset in charsets: + try: + content += unicode(s, charset) + except: + continue + else: + break + + # remove signature + content = content.split(u'\n-- \n')[0] + + bname, id = reply_to.split('.', 1) + + # Default use the To header field to know the backend to use. + if to and bname != to: + bname = to + + try: + backend = self.weboob.backends[bname] + except KeyError: + print >>sys.stderr, 'Backend %s not found' % bname + return 1 + + if not backend.has_caps(ICapMessagesReply): + print >>sys.stderr, 'The backend %s does not implement ICapMessagesReply' % bname + return 1 + + thread_id, msg_id = id.rsplit('.', 1) + try: + backend.post_reply(thread_id, msg_id, title, content) + except Exception, e: + content = u'Unable to send message to %s:\n' % thread_id + content += '\n\t%s\n' % e + if logging.root.level == logging.DEBUG: + content += '\n%s\n' % get_backtrace(e) + self.send_email(backend, Message(thread_id, + 0, + title='Unable to send message', + sender='Monboob', + reply_id=msg_id, + content=content)) + + @ConsoleApplication.command("run daemon") + def command_run(self): + self.weboob.repeat(int(self.config.get('interval')), self.process) + self.weboob.loop() + + def process(self): + for backend, message in self.weboob.do('iter_new_messages'): + self.send_email(backend, message) + + def send_email(self, backend, mail): + domain = self.config.get('domain') + recipient = self.config.get('recipient') + + reply_id = '' + if mail.get_reply_id(): + reply_id = u'<%s.%s@%s>' % (backend.name, mail.get_full_reply_id(), domain) + subject = mail.get_title() + sender = u'"%s" <%s@%s>' % (mail.get_from().replace('"', '""'), backend.name, domain) + + # assume that get_date() returns an UTC datetime + date = formatdate(time.mktime(utc2local(mail.get_date()).timetuple()), localtime=True) + msg_id = u'<%s.%s@%s>' % (backend.name, mail.get_full_id(), domain) + + if int(self.config.get('html')) and mail.is_html: + body = mail.get_content() + content_type = 'html' + else: + if mail.is_html: + body = html2text(mail.get_content()) + else: + body = mail.get_content() + content_type = 'plain' + + if mail.get_signature(): + if int(self.config.get('html')) and mail.is_html: + body += u'

--
%s

' % mail.get_signature() + else: + body += u'\n\n-- \n' + if mail.is_html: + body += html2text(mail.get_signature()) + else: + body += mail.get_signature() + + # Header class is smart enough to try US-ASCII, then the charset we + # provide, then fall back to UTF-8. + header_charset = 'ISO-8859-1' + + # We must choose the body charset manually + for body_charset in 'US-ASCII', 'ISO-8859-1', 'UTF-8': + try: + body.encode(body_charset) + except UnicodeError: + pass + else: + break + + # Split real name (which is optional) and email address parts + sender_name, sender_addr = parseaddr(sender) + recipient_name, recipient_addr = parseaddr(recipient) + + # We must always pass Unicode strings to Header, otherwise it will + # use RFC 2047 encoding even on plain ASCII strings. + sender_name = str(Header(unicode(sender_name), header_charset)) + recipient_name = str(Header(unicode(recipient_name), header_charset)) + + # Make sure email addresses do not contain non-ASCII characters + sender_addr = sender_addr.encode('ascii') + recipient_addr = recipient_addr.encode('ascii') + + # Create the message ('plain' stands for Content-Type: text/plain) + msg = MIMEText(body.encode(body_charset), content_type, body_charset) + msg['From'] = formataddr((sender_name, sender_addr)) + msg['To'] = formataddr((recipient_name, recipient_addr)) + msg['Subject'] = Header(unicode(subject), header_charset) + msg['Message-Id'] = msg_id + msg['Date'] = date + if reply_id: + msg['In-Reply-To'] = reply_id + + # Send the message via SMTP to localhost:25 + smtp = SMTP(self.config.get('smtp')) + print 'Send mail from <%s> to <%s>' % (sender, recipient) + smtp.sendmail(sender, recipient, msg.as_string()) + smtp.quit() + + return msg['Message-Id'] diff --git a/weboob/applications/monboob/setup.py b/weboob/applications/monboob/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..616e941535b25725decf2c5308f5800d8ba086ac --- /dev/null +++ b/weboob/applications/monboob/setup.py @@ -0,0 +1,45 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-monboob', + version='0.1', + description='Monboob, the Weboob e-mail swiss-knife', + author='Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/Monboob', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.monboob', + ], + scripts=[ + 'scripts/monboob', + ], + install_requires=[ + 'weboob-messages-backends', + ], +) diff --git a/weboob/applications/qboobmsg/__init__.py b/weboob/applications/qboobmsg/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3db51dd0782c59096c3d555c0ab94b742ee814a3 --- /dev/null +++ b/weboob/applications/qboobmsg/__init__.py @@ -0,0 +1 @@ +from .qboobmsg import QBoobMsg diff --git a/weboob/applications/qboobmsg/main_window.py b/weboob/applications/qboobmsg/main_window.py new file mode 100644 index 0000000000000000000000000000000000000000..8b7d56af0d5a2b75fd969705aa947c4c6d11bbfd --- /dev/null +++ b/weboob/applications/qboobmsg/main_window.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from PyQt4.QtCore import SIGNAL + +from weboob.tools.application.qt import QtMainWindow +from weboob.tools.application.qt.backendcfg import BackendCfg +from weboob.capabilities.messages import ICapMessages + +from .ui.main_window_ui import Ui_MainWindow +from .messages_manager import MessagesManager + +class MainWindow(QtMainWindow): + def __init__(self, config, weboob, parent=None): + QtMainWindow.__init__(self, parent) + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + + self.config = config + self.weboob = weboob + self.manager = MessagesManager(weboob, self) + + self.setCentralWidget(self.manager) + + self.connect(self.ui.actionModules, SIGNAL("triggered()"), self.modulesConfig) + self.connect(self.ui.actionRefresh, SIGNAL("triggered()"), self.refresh) + + def modulesConfig(self): + bckndcfg = BackendCfg(self.weboob, (ICapMessages,), self) + bckndcfg.show() + + def refresh(self): + self.centralWidget().refresh() diff --git a/weboob/applications/qboobmsg/messages_manager.py b/weboob/applications/qboobmsg/messages_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..c3a392d90ae1c8f0fe0efd8110f1baa0c267e0f8 --- /dev/null +++ b/weboob/applications/qboobmsg/messages_manager.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import time + +from PyQt4.QtGui import QWidget, QTreeWidgetItem, QListWidgetItem +from PyQt4.QtCore import SIGNAL, Qt + +from weboob.capabilities.messages import ICapMessages +from weboob.tools.application.qt import QtDo + +from .ui.messages_manager_ui import Ui_MessagesManager + +class MessagesManager(QWidget): + def __init__(self, weboob, parent=None): + QWidget.__init__(self, parent) + self.ui = Ui_MessagesManager() + self.ui.setupUi(self) + + self.weboob = weboob + + self.ui.backendsList.addItem('(All)') + for backend in self.weboob.iter_backends(): + if not backend.has_caps(ICapMessages): + continue + + item = QListWidgetItem(backend.name.capitalize()) + item.setData(Qt.UserRole, backend) + self.ui.backendsList.addItem(item) + + self.ui.backendsList.setCurrentRow(0) + self.backend = None + + self.connect(self.ui.backendsList, SIGNAL('itemSelectionChanged()'), self._backendChanged) + self.connect(self.ui.messagesTree, SIGNAL('itemClicked(QTreeWidgetItem *, int)'), self._messageSelected) + self.connect(self.ui.messagesTree, SIGNAL('itemActivated(QTreeWidgetItem *, int)'), self._messageSelected) + self.connect(self, SIGNAL('gotMessage'), self._gotMessage) + + def load(self): + self.refresh() + + def _backendChanged(self): + selection = self.ui.backendsList.selectedItems() + if not selection: + self.backend = None + return + + self.backend = selection[0].data(Qt.UserRole).toPyObject() + + self.ui.messagesTree.clear() + self.refresh() + + def refresh(self): + if self.ui.messagesTree.topLevelItemCount() > 0: + command = 'iter_new_messages' + else: + command = 'iter_messages' + + self.ui.backendsList.setEnabled(False) + + self.process = QtDo(self.weboob, self._gotMessage) + + if self.backend: + self.process.do_backends(self.backend.name, command) + else: + self.process.do_caps(ICapMessages, command) + + def _gotMessage(self, backend, message): + if message is None: + self.ui.backendsList.setEnabled(True) + return + + item = QTreeWidgetItem(None, [time.strftime('%Y-%m-%d %H:%M:%S', message.get_date().timetuple()), + message.sender, message.title]) + item.setData(0, Qt.UserRole, message) + + root = self.ui.messagesTree.invisibleRootItem() + + # try to find a message which would be my parent. + # if no one is found, insert it on top level. + if not self._insertMessage(root, item): + self.ui.messagesTree.addTopLevelItem(item) + + # Check orphaned items which are child of this new one to put + # in. + to_remove = [] + for i in xrange(root.childCount()): + sub = root.child(i) + sub_message = sub.data(0, Qt.UserRole).toPyObject() + if sub_message.thread_id == message.thread_id and sub_message.reply_id == message.id: + # do not remove it now because childCount() would change. + to_remove.append(sub) + + for sub in to_remove: + root.removeChild(sub) + item.addChild(sub) + + def _insertMessage(self, top, item): + top_message = top.data(0, Qt.UserRole).toPyObject() + item_message = item.data(0, Qt.UserRole).toPyObject() + + if top_message and top_message.thread_id == item_message.thread_id and top_message.id == item_message.reply_id: + # it's my parent + top.addChild(item) + return True + else: + # check the children + for i in xrange(top.childCount()): + sub = top.child(i) + if self._insertMessage(sub, item): + return True + return False + + def _messageSelected(self, item, column): + message = item.data(0, Qt.UserRole).toPyObject() + self.ui.messageBody.setText("

%s

" + "Date: %s
" + "From: %s
" + "

%s

" + % (message.title, str(message.date), message.sender, message.content)) diff --git a/weboob/applications/qboobmsg/qboobmsg.py b/weboob/applications/qboobmsg/qboobmsg.py new file mode 100644 index 0000000000000000000000000000000000000000..c9f24205dec4f26574159c952ee061212d9a4118 --- /dev/null +++ b/weboob/applications/qboobmsg/qboobmsg.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from weboob.capabilities.messages import ICapMessages +from weboob.tools.application import QtApplication + +from .main_window import MainWindow + +class QBoobMsg(QtApplication): + APPNAME = 'qboobmsg' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + + def main(self, argv): + self.load_backends(ICapMessages, storage=self.create_storage()) + + self.main_window = MainWindow(self.config, self.weboob) + self.main_window.show() + return self.weboob.loop() diff --git a/weboob/applications/qboobmsg/setup.py b/weboob/applications/qboobmsg/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..fc0ac9707a8c6ee410f9b80bf9d7650401abe687 --- /dev/null +++ b/weboob/applications/qboobmsg/setup.py @@ -0,0 +1,49 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +os.system('make -C %s/ui' % os.path.dirname(__file__)) + +setup( + name='weboob-qboobmsg', + version='0.1', + description='QBoobMsg, the Weboob e-mail swiss-knife, Qt version', + author='Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/QBoobMsg', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.qboobmsg', + 'weboob.frontends.qboobmsg.ui', + ], + scripts=[ + 'scripts/qboobmsg', + ], + install_requires=[ + 'weboob-core-qt', + 'weboob-messages-backends', + ], +) diff --git a/weboob/applications/qboobmsg/ui/Makefile b/weboob/applications/qboobmsg/ui/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f0db5154cf49182632325b99b1c6d1875e938bff --- /dev/null +++ b/weboob/applications/qboobmsg/ui/Makefile @@ -0,0 +1,13 @@ +UI_FILES = $(wildcard *.ui) +UI_PY_FILES = $(UI_FILES:%.ui=%_ui.py) +PYUIC = pyuic4 + +all: $(UI_PY_FILES) + +%_ui.py: %.ui + $(PYUIC) -o $@ $^ + +clean: + rm -f *.pyc + rm -f $(UI_PY_FILES) + diff --git a/weboob/applications/qboobmsg/ui/__init__.py b/weboob/applications/qboobmsg/ui/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/weboob/applications/qboobmsg/ui/main_window.ui b/weboob/applications/qboobmsg/ui/main_window.ui new file mode 100644 index 0000000000000000000000000000000000000000..330e9460dcfd557badbec1203dc3ae5a688b4b44 --- /dev/null +++ b/weboob/applications/qboobmsg/ui/main_window.ui @@ -0,0 +1,91 @@ + + + MainWindow + + + + 0 + 0 + 763 + 580 + + + + QBoobMsg + + + + + + + + 0 + 0 + 763 + 24 + + + + + File + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + Modules + + + + + Quit + + + Quit + + + + + Refresh + + + + + + + actionQuit + triggered() + MainWindow + close() + + + -1 + -1 + + + 381 + 289 + + + + + diff --git a/weboob/applications/qboobmsg/ui/messages_manager.ui b/weboob/applications/qboobmsg/ui/messages_manager.ui new file mode 100644 index 0000000000000000000000000000000000000000..beba8bca75b54dd467bcb017f14e115d345149c0 --- /dev/null +++ b/weboob/applications/qboobmsg/ui/messages_manager.ui @@ -0,0 +1,192 @@ + + + MessagesManager + + + + 0 + 0 + 767 + 591 + + + + + + + + + + Qt::Horizontal + + + + + 0 + 0 + + + + + + + 2 + 0 + + + + Qt::Vertical + + + + QAbstractItemView::NoEditTriggers + + + true + + + true + + + true + + + false + + + 100 + + + true + + + true + + + 100 + + + true + + + true + + + + Date + + + AlignLeft|AlignVCenter + + + + + From + + + + + Title + + + + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + expandButton + clicked() + messagesTree + expandAll() + + + 733 + 31 + + + 527 + 150 + + + + + collapseButton + clicked() + messagesTree + collapseAll() + + + 733 + 60 + + + 527 + 150 + + + + + diff --git a/weboob/applications/qhavesex/__init__.py b/weboob/applications/qhavesex/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e55140d2bebd1cb1705497e1b5e1c0e9330724bf --- /dev/null +++ b/weboob/applications/qhavesex/__init__.py @@ -0,0 +1 @@ +from .qhavesex import QHaveSex diff --git a/weboob/applications/qhavesex/contacts.py b/weboob/applications/qhavesex/contacts.py new file mode 100644 index 0000000000000000000000000000000000000000..b6931cd9bf701489175709edad90a9948c679dfb --- /dev/null +++ b/weboob/applications/qhavesex/contacts.py @@ -0,0 +1,203 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import urllib2 +import time +import logging +from PyQt4.QtGui import QWidget, QListWidgetItem, QImage, QIcon, QPixmap, QFrame, QMessageBox +from PyQt4.QtCore import SIGNAL, Qt + +from weboob.tools.application.qt import QtDo, HTMLDelegate +from weboob.capabilities.contact import ICapContact, Contact +from weboob.capabilities.chat import ICapChat +from weboob.capabilities.messages import ICapMessages + +from .ui.contacts_ui import Ui_Contacts +from .ui.contact_thread_ui import Ui_ContactThread +from .ui.thread_message_ui import Ui_ThreadMessage + +class ThreadMessage(QFrame): + def __init__(self, message, parent=None): + QFrame.__init__(self, parent) + self.ui = Ui_ThreadMessage() + self.ui.setupUi(self) + + self.date = message.get_date() + + self.ui.nameLabel.setText(message.sender) + self.ui.headerLabel.setText(time.strftime('%Y-%m-%d %H:%M:%S', message.get_date().timetuple())) + if message.is_html: + content = message.content + else: + content = message.content.replace('&', '&').replace('<', '<').replace('>', '>').replace('\n', '
') + self.ui.contentLabel.setText(content) + +class ContactThread(QWidget): + def __init__(self, weboob, contact, parent=None): + QWidget.__init__(self, parent) + self.ui = Ui_ContactThread() + self.ui.setupUi(self) + + self.weboob = weboob + self.contact = contact + self.messages = [] + + self.connect(self.ui.sendButton, SIGNAL('clicked()'), self.postReply) + + self.refreshMessages() + + def refreshMessages(self): + if self.ui.scrollAreaContent.layout().count() > 0: + command = 'iter_new_messages' + else: + command = 'iter_messages' + + self.process = QtDo(self.weboob, self.gotMessage) + self.process.do_backends(self.contact.backend, command, thread=self.contact.id) + + def gotMessage(self, backend, message): + if not message: + v = self.ui.scrollArea.verticalScrollBar() + print v.minimum(), v.value(), v.maximum(), v.sliderPosition() + self.ui.scrollArea.verticalScrollBar().setValue(self.ui.scrollArea.verticalScrollBar().maximum()) + return + + widget = ThreadMessage(message) + for i, m in enumerate(self.messages): + if widget.date < m.date: + self.ui.scrollAreaContent.layout().insertWidget(i, widget) + self.messages.insert(i, widget) + return + + self.ui.scrollAreaContent.layout().addWidget(widget) + self.messages.append(widget) + + def postReply(self): + text = unicode(self.ui.textEdit.toPlainText()) + self.ui.textEdit.setEnabled(False) + self.ui.sendButton.setEnabled(False) + self.process = QtDo(self.weboob, self.replyPosted, self.replyNotPosted) + self.process.do_backends(self.contact.backend, 'post_reply', self.contact.id, 0, '', text) + + def replyPosted(self, backend, ignored): + self.ui.textEdit.clear() + self.ui.textEdit.setEnabled(True) + self.ui.sendButton.setEnabled(True) + self.refreshMessages() + + def replyNotPosted(self, backend, error, backtrace): + content = unicode(self.tr('Unable to send message:\n%s\n')) % error + if logging.root.level == logging.DEBUG: + content += '\n%s\n' % backtrace + QMessageBox.critical(self, self.tr('Error while posting reply'), + content, QMessageBox.Ok) + + +class IGroup(object): + def __init__(self, weboob, id, name): + self.id = id + self.name = name + self.weboob = weboob + + def iter_contacts(self, cb): + raise NotImplementedError() + +class MetaGroup(IGroup): + def iter_contacts(self, cb): + if self.id == 'online': + status = Contact.STATUS_ONLINE + elif self.id == 'offline': + status = Contact.STATUS_OFFLINE + else: + status = Contact.STATUS_ALL + + self.process = QtDo(self.weboob, lambda b, d: self.cb(cb, b, d)) + self.process.do_caps(ICapContact, 'iter_contacts', status) + + def cb(self, cb, backend, contact): + if contact: + contact.backend = backend + cb(contact) + +class ContactsWidget(QWidget): + def __init__(self, weboob, parent=None): + QWidget.__init__(self, parent) + self.ui = Ui_Contacts() + self.ui.setupUi(self) + + self.weboob = weboob + self.contact = None + self.ui.contactList.setItemDelegate(HTMLDelegate()) + + self.ui.groupBox.addItem('All', MetaGroup(self.weboob, 'all', self.tr('All'))) + self.ui.groupBox.addItem('Onlines', MetaGroup(self.weboob, 'online', self.tr('Online'))) + self.ui.groupBox.addItem('Offlines', MetaGroup(self.weboob, 'offline', self.tr('Offline'))) + + self.connect(self.ui.groupBox, SIGNAL('currentIndexChanged(int)'), self.groupChanged) + self.connect(self.ui.contactList, SIGNAL('currentItemChanged(QListWidgetItem*, QListWidgetItem*)'), self.contactChanged) + self.connect(self.ui.refreshButton, SIGNAL('clicked()'), self.refreshContactList) + + def load(self): + self.ui.groupBox.setCurrentIndex(1) + + def groupChanged(self, i): + self.refreshContactList() + + def refreshContactList(self): + self.ui.contactList.clear() + i = self.ui.groupBox.currentIndex() + group = self.ui.groupBox.itemData(i).toPyObject() + group.iter_contacts(self.addContact) + + def addContact(self, contact): + if not contact: + return + + data = urllib2.urlopen(contact.thumbnail_url).read() + img = QImage.fromData(data) + + status = '' + if contact.status == Contact.STATUS_ONLINE: + status = 'Online' + status_color = 0x00aa00 + elif contact.status == Contact.STATUS_OFFLINE: + status = 'Offline' + status_color = 0xff0000 + + item = QListWidgetItem() + item.setText('

%s

%s
%s' % (contact.name, status_color, status, contact.backend.name)) + item.setIcon(QIcon(QPixmap.fromImage(img))) + item.setData(Qt.UserRole, contact) + + self.ui.contactList.addItem(item) + + def contactChanged(self, current, previous): + self.ui.tabWidget.clear() + self.contact = None + + if not current: + return + + self.contact = current.data(Qt.UserRole).toPyObject() + + self.ui.tabWidget.addTab(QWidget(), self.tr('Profile')) + if self.contact.backend.has_caps(ICapMessages): + self.ui.tabWidget.addTab(ContactThread(self.weboob, self.contact), self.tr('Messages')) + if self.contact.backend.has_caps(ICapChat): + self.ui.tabWidget.addTab(QWidget(), self.tr('Chat')) + self.ui.tabWidget.addTab(QWidget(), self.tr('Calendar')) + self.ui.tabWidget.addTab(QWidget(), self.tr('Notes')) diff --git a/weboob/applications/qhavesex/main_window.py b/weboob/applications/qhavesex/main_window.py new file mode 100644 index 0000000000000000000000000000000000000000..803488ecd7065459c965058b746f9e3e3a3cef0d --- /dev/null +++ b/weboob/applications/qhavesex/main_window.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from PyQt4.QtGui import QWidget +from PyQt4.QtCore import SIGNAL + +from weboob.tools.application.qt import QtMainWindow +from weboob.tools.application.qt.backendcfg import BackendCfg +from weboob.capabilities.dating import ICapDating + +from weboob.frontends.qboobmsg.messages_manager import MessagesManager + +from .ui.main_window_ui import Ui_MainWindow +from .status import AccountsStatus +from .contacts import ContactsWidget + +class MainWindow(QtMainWindow): + def __init__(self, config, weboob, parent=None): + QtMainWindow.__init__(self, parent) + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + + self.config = config + self.weboob = weboob + + self.loaded_tabs = {} + + self.ui.tabWidget.addTab(AccountsStatus(self.weboob), self.tr('Status')) + self.ui.tabWidget.addTab(MessagesManager(self.weboob), self.tr('Messages')) + self.ui.tabWidget.addTab(ContactsWidget(self.weboob), self.tr('Contacts')) + self.ui.tabWidget.addTab(QWidget(), self.tr('Calendar')) + + self.connect(self.ui.actionModules, SIGNAL("triggered()"), self.modulesConfig) + self.connect(self.ui.tabWidget, SIGNAL('currentChanged(int)'), self.tabChanged) + + def modulesConfig(self): + bckndcfg = BackendCfg(self.weboob, (ICapDating,), self) + bckndcfg.show() + + def tabChanged(self, i): + widget = self.ui.tabWidget.currentWidget() + + if hasattr(widget, 'load') and not i in self.loaded_tabs: + widget.load() + self.loaded_tabs[i] = True diff --git a/weboob/applications/qhavesex/qhavesex.py b/weboob/applications/qhavesex/qhavesex.py new file mode 100644 index 0000000000000000000000000000000000000000..1a4d3da84cfae32ef4b7bc2591ed879c6c8c979f --- /dev/null +++ b/weboob/applications/qhavesex/qhavesex.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from weboob.capabilities.dating import ICapDating +from weboob.tools.application import QtApplication + +from .main_window import MainWindow + +class QHaveSex(QtApplication): + APPNAME = 'qhavesex' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + STORAGE_FILENAME = 'dating.storage' + + def main(self, argv): + self.load_backends(ICapDating, storage=self.create_storage()) + + self.main_window = MainWindow(self.config, self.weboob) + self.main_window.show() + return self.weboob.loop() diff --git a/weboob/applications/qhavesex/setup.py b/weboob/applications/qhavesex/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..3a65ffb9828c9cdc3a5fbb2d9b436ce0e5fb910f --- /dev/null +++ b/weboob/applications/qhavesex/setup.py @@ -0,0 +1,50 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +os.system('make -C %s/ui' % os.path.dirname(__file__)) + +setup( + name='weboob-qhavesex', + version='0.1', + description='QHaveSex, the Weboob sexual life swiss-knife, Qt version', + long_description='Optimize your probabilities to have sex on dating websites', + author='Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/QHaveSex', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.qhavesex', + 'weboob.frontends.qhavesex.ui', + ], + scripts=[ + 'scripts/qhavesex', + ], + install_requires=[ + 'weboob-core-qt', + 'weboob-dating-backends', + ], +) diff --git a/weboob/applications/qhavesex/status.py b/weboob/applications/qhavesex/status.py new file mode 100644 index 0000000000000000000000000000000000000000..27333aa34ae4e792e522f942faa3e9460b5de0f2 --- /dev/null +++ b/weboob/applications/qhavesex/status.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from __future__ import with_statement + +from PyQt4.QtGui import QWidget, QHBoxLayout, QVBoxLayout, QFrame, QLabel, QImage, QPixmap +from PyQt4.QtCore import SIGNAL, QTimer + +from weboob.capabilities.dating import StatusField + +class Account(QFrame): + def __init__(self, backend, parent=None): + QFrame.__init__(self, parent) + + self.setFrameShape(QFrame.StyledPanel) + self.setFrameShadow(QFrame.Raised) + + self.backend = backend + self.setLayout(QVBoxLayout()) + + head = QHBoxLayout() + headw = QWidget() + headw.setLayout(head) + + self.title = QLabel(u'

%s — %s

' % (backend.name, backend.DESCRIPTION)) + + if backend.ICON: + self.icon = QLabel() + img = QImage(backend.ICON) + self.icon.setPixmap(QPixmap.fromImage(img)) + head.addWidget(self.icon) + + head.addWidget(self.title) + head.addStretch() + + self.body = QLabel() + + self.layout().addWidget(headw) + self.layout().addWidget(self.body) + + self.timer = QTimer() + self.timer.setSingleShot(False) + self.timer.setInterval(60) + self.connect(self.timer, SIGNAL('timeout()'), self.updateStats) + + self.updateStats() + + def updateStats(self): + with self.backend: + body = u'' + in_p = False + for field in self.backend.get_status(): + if field.flags & StatusField.FIELD_HTML: + value = field.value.replace('&', '&').replace('<', '<').replace('>', '>') + else: + value = '%s' % field.value + + if field.flags & StatusField.FIELD_TEXT: + if in_p: + body += '

' + body += '

%s

' % value + in_p = False + else: + if not in_p: + body += "

" + in_p = True + else: + body += "
" + + body += '%s: %s' % (field.label, field.value) + if in_p: + body += "

" + + self.body.setText(body) + +class AccountsStatus(QWidget): + def __init__(self, weboob, parent=None): + QWidget.__init__(self, parent) + + self.weboob = weboob + + self.setLayout(QVBoxLayout()) + + for backend in self.weboob.iter_backends(): + account = Account(backend) + self.layout().addWidget(account) + + self.layout().addStretch() diff --git a/weboob/applications/qhavesex/ui/Makefile b/weboob/applications/qhavesex/ui/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f0db5154cf49182632325b99b1c6d1875e938bff --- /dev/null +++ b/weboob/applications/qhavesex/ui/Makefile @@ -0,0 +1,13 @@ +UI_FILES = $(wildcard *.ui) +UI_PY_FILES = $(UI_FILES:%.ui=%_ui.py) +PYUIC = pyuic4 + +all: $(UI_PY_FILES) + +%_ui.py: %.ui + $(PYUIC) -o $@ $^ + +clean: + rm -f *.pyc + rm -f $(UI_PY_FILES) + diff --git a/weboob/applications/qhavesex/ui/__init__.py b/weboob/applications/qhavesex/ui/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/weboob/applications/qhavesex/ui/contact_thread.ui b/weboob/applications/qhavesex/ui/contact_thread.ui new file mode 100644 index 0000000000000000000000000000000000000000..33a482f36a23b6c1433d178635676b3414470982 --- /dev/null +++ b/weboob/applications/qhavesex/ui/contact_thread.ui @@ -0,0 +1,90 @@ + + + ContactThread + + + + 0 + 0 + 578 + 429 + + + + Form + + + + + + Qt::Vertical + + + + + 0 + 1 + + + + + + + Qt::ScrollBarAsNeeded + + + true + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 0 + 0 + 556 + 187 + + + + QWidget#scrollAreaContent { + background-color: rgb(255, 255, 255); +} + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + 0 + 0 + + + + Send + + + + + + + + + + + + diff --git a/weboob/applications/qhavesex/ui/contacts.ui b/weboob/applications/qhavesex/ui/contacts.ui new file mode 100644 index 0000000000000000000000000000000000000000..a663289802e9e401bff760f002e2d8bd94f832ee --- /dev/null +++ b/weboob/applications/qhavesex/ui/contacts.ui @@ -0,0 +1,89 @@ + + + Contacts + + + + 0 + 0 + 482 + 320 + + + + Form + + + + + + Qt::Horizontal + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + ../../../../../../../../usr/share/icons/oxygen/16x16/actions/view-refresh.png../../../../../../../../usr/share/icons/oxygen/16x16/actions/view-refresh.png + + + + + + + + + + 120 + 120 + + + + 1 + + + true + + + false + + + + + + + + + 1 + 0 + + + + + + + + + + diff --git a/weboob/applications/qhavesex/ui/main_window.ui b/weboob/applications/qhavesex/ui/main_window.ui new file mode 100644 index 0000000000000000000000000000000000000000..6a2b3e4774f600e3619d128279c331884e6c85fd --- /dev/null +++ b/weboob/applications/qhavesex/ui/main_window.ui @@ -0,0 +1,92 @@ + + + MainWindow + + + + 0 + 0 + 763 + 580 + + + + QHaveSex + + + + + + + -1 + + + + + + + + + 0 + 0 + 763 + 24 + + + + + File + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + Modules + + + + + Quit + + + Quit + + + + + + + actionQuit + triggered() + MainWindow + close() + + + -1 + -1 + + + 381 + 289 + + + + + diff --git a/weboob/applications/qhavesex/ui/thread_message.ui b/weboob/applications/qhavesex/ui/thread_message.ui new file mode 100644 index 0000000000000000000000000000000000000000..0c55067bc136bb8cae5e70489781b52fadc25ec9 --- /dev/null +++ b/weboob/applications/qhavesex/ui/thread_message.ui @@ -0,0 +1,109 @@ + + + ThreadMessage + + + + 0 + 0 + 552 + 76 + + + + Frame + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + + + 0 + 0 + + + + + + + + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + + + + diff --git a/weboob/applications/qvideoob/__init__.py b/weboob/applications/qvideoob/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..83eea19a9a9eeec840df3c246b1441fb358df1ba --- /dev/null +++ b/weboob/applications/qvideoob/__init__.py @@ -0,0 +1 @@ +from .qvideoob import QVideoob diff --git a/weboob/applications/qvideoob/main_window.py b/weboob/applications/qvideoob/main_window.py new file mode 100644 index 0000000000000000000000000000000000000000..0aff986cc4f4965d69c740ab96fd4d90559d5843 --- /dev/null +++ b/weboob/applications/qvideoob/main_window.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from PyQt4.QtCore import SIGNAL + +from weboob.tools.application.qt import QtMainWindow, QtDo + +from weboob.frontends.qvideoob.ui.main_window_ui import Ui_MainWindow + +from .video import Video +from .minivideo import MiniVideo + +class MainWindow(QtMainWindow): + def __init__(self, config, weboob, parent=None): + QtMainWindow.__init__(self, parent) + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + + self.config = config + self.weboob = weboob + self.minivideos = [] + + self.ui.backendEdit.addItem('All backends', '') + for i, backend in enumerate(self.weboob.iter_backends()): + self.ui.backendEdit.addItem(backend.name, backend.name) + if backend.name == self.config.get('settings', 'backend'): + self.ui.backendEdit.setCurrentIndex(i+1) + self.ui.sortbyEdit.setCurrentIndex(int(self.config.get('settings', 'sortby'))) + self.ui.nsfwCheckBox.setChecked(int(self.config.get('settings', 'nsfw'))) + self.ui.sfwCheckBox.setChecked(int(self.config.get('settings', 'sfw'))) + + self.connect(self.ui.searchEdit, SIGNAL("returnPressed()"), self.search) + self.connect(self.ui.urlEdit, SIGNAL("returnPressed()"), self.openURL) + self.connect(self.ui.nsfwCheckBox, SIGNAL("stateChanged(int)"), self.nsfwChanged) + self.connect(self.ui.sfwCheckBox, SIGNAL("stateChanged(int)"), self.sfwChanged) + + def nsfwChanged(self, state): + self.config.set('settings', 'nsfw', int(self.ui.nsfwCheckBox.isChecked())) + self.updateVideosDisplay() + + def sfwChanged(self, state): + self.config.set('settings', 'sfw', int(self.ui.sfwCheckBox.isChecked())) + self.updateVideosDisplay() + + def updateVideosDisplay(self): + for minivideo in self.minivideos: + if (minivideo.video.nsfw and self.ui.nsfwCheckBox.isChecked() or + not minivideo.video.nsfw and self.ui.sfwCheckBox.isChecked()): + minivideo.show() + else: + minivideo.hide() + + def search(self): + pattern = unicode(self.ui.searchEdit.text()) + if not pattern: + return + + for minivideo in self.minivideos: + self.ui.scrollAreaContent.layout().removeWidget(minivideo) + minivideo.hide() + + self.minivideos = [] + self.ui.searchEdit.setEnabled(False) + + backend_name = str(self.ui.backendEdit.itemData(self.ui.backendEdit.currentIndex()).toString()) + + self.process = QtDo(self.weboob, self.addVideo) + if backend_name: + self.process.do_backends(backend_name, 'iter_search_results', pattern, self.ui.sortbyEdit.currentIndex(), nsfw=True) + else: + self.process.do('iter_search_results', pattern, self.ui.sortbyEdit.currentIndex(), nsfw=True) + + def addVideo(self, backend, video): + if not backend: + self.ui.searchEdit.setEnabled(True) + return + minivideo = MiniVideo(backend, video) + self.ui.scrollAreaContent.layout().addWidget(minivideo) + self.minivideos.append(minivideo) + if (video.nsfw and not self.ui.nsfwCheckBox.isChecked() or + not video.nsfw and not self.ui.sfwCheckBox.isChecked()): + minivideo.hide() + + def openURL(self): + url = unicode(self.ui.urlEdit.text()) + if not url: + return + + for backend in self.weboob.iter_backends(): + video = backend.get_video(url) + if video: + video_widget = Video(video, self) + video_widget.show() + + self.ui.urlEdit.clear() + + def closeEvent(self, ev): + self.config.set('settings', 'backend', str(self.ui.backendEdit.itemData(self.ui.backendEdit.currentIndex()).toString())) + self.config.set('settings', 'sortby', self.ui.sortbyEdit.currentIndex()) + self.config.save() + ev.accept() diff --git a/weboob/applications/qvideoob/minivideo.py b/weboob/applications/qvideoob/minivideo.py new file mode 100644 index 0000000000000000000000000000000000000000..71b3bc6f7a33b4e01b5c1427e13a4851faea462d --- /dev/null +++ b/weboob/applications/qvideoob/minivideo.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +import urllib2 +from PyQt4.QtGui import QFrame, QImage, QPixmap + +from weboob.frontends.qvideoob.ui.minivideo_ui import Ui_MiniVideo +from .video import Video + +class MiniVideo(QFrame): + def __init__(self, backend, video, parent=None): + QFrame.__init__(self, parent) + self.ui = Ui_MiniVideo() + self.ui.setupUi(self) + + self.backend = backend + self.video = video + self.ui.titleLabel.setText(video.title) + self.ui.backendLabel.setText(backend.name) + self.ui.durationLabel.setText('%d:%02d:%02d' % (video.duration/3600, (video.duration%3600)/60, video.duration%60)) + self.ui.authorLabel.setText(unicode(video.author)) + self.ui.dateLabel.setText(video.date and unicode(video.date) or '') + if video.rating_max: + self.ui.ratingLabel.setText('%s / %s' % (video.rating, video.rating_max)) + else: + self.ui.ratingLabel.setText('%s' % video.rating) + + if video.thumbnail_url: + data = urllib2.urlopen(video.thumbnail_url).read() + img = QImage.fromData(data) + self.ui.imageLabel.setPixmap(QPixmap.fromImage(img)) + + def enterEvent(self, event): + self.setFrameShadow(self.Sunken) + QFrame.enterEvent(self, event) + + def leaveEvent(self, event): + self.setFrameShadow(self.Raised) + QFrame.leaveEvent(self, event) + + def mousePressEvent(self, event): + QFrame.mousePressEvent(self, event) + + video = self.backend.get_video(self.video.id) + if video: + video_widget = Video(video, self) + video_widget.show() diff --git a/weboob/applications/qvideoob/qvideoob.py b/weboob/applications/qvideoob/qvideoob.py new file mode 100644 index 0000000000000000000000000000000000000000..490120404d9ac8270fd57577b171739f3692030a --- /dev/null +++ b/weboob/applications/qvideoob/qvideoob.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from weboob.capabilities.video import ICapVideo +from weboob.tools.application import QtApplication + +from .main_window import MainWindow + +class QVideoob(QtApplication): + APPNAME = 'qvideoob' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + CONFIG = {'settings': {'nsfw': 1, + 'sfw': 1, + 'sortby': 0, + 'backend': '' + } + } + def main(self, argv): + self.load_modules(ICapVideo) + self.load_config() + + self.main_window = MainWindow(self.config, self.weboob) + self.main_window.show() + return self.weboob.loop() diff --git a/weboob/applications/qvideoob/setup.py b/weboob/applications/qvideoob/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..c8b18828817a9fedad743befca6e82031ff0203c --- /dev/null +++ b/weboob/applications/qvideoob/setup.py @@ -0,0 +1,50 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +os.system('make -C %s/ui' % os.path.dirname(__file__)) + +setup( + name='weboob-qvideoob', + version='0.1', + description='QVideoob, the Weboob video swiss-knife, Qt version', + long_description='Search for videos on many websites, and get info about them', + author='Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/QVideoob', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.qvideoob', + 'weboob.frontends.qvideoob.ui', + ], + scripts=[ + 'scripts/qvideoob', + ], + install_requires=[ + 'weboob-core-qt', + 'weboob-video-backends', + ], +) diff --git a/weboob/applications/qvideoob/ui/Makefile b/weboob/applications/qvideoob/ui/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f0db5154cf49182632325b99b1c6d1875e938bff --- /dev/null +++ b/weboob/applications/qvideoob/ui/Makefile @@ -0,0 +1,13 @@ +UI_FILES = $(wildcard *.ui) +UI_PY_FILES = $(UI_FILES:%.ui=%_ui.py) +PYUIC = pyuic4 + +all: $(UI_PY_FILES) + +%_ui.py: %.ui + $(PYUIC) -o $@ $^ + +clean: + rm -f *.pyc + rm -f $(UI_PY_FILES) + diff --git a/weboob/applications/qvideoob/ui/__init__.py b/weboob/applications/qvideoob/ui/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/weboob/applications/qvideoob/ui/main_window.ui b/weboob/applications/qvideoob/ui/main_window.ui new file mode 100644 index 0000000000000000000000000000000000000000..2002c0b0853d5ee87b7b2bc2fab49b3b1a127dfd --- /dev/null +++ b/weboob/applications/qvideoob/ui/main_window.ui @@ -0,0 +1,193 @@ + + + MainWindow + + + + 0 + 0 + 785 + 594 + + + + QVideoob + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Search: + + + + + + + + + + + 0 + 0 + + + + + Relevance + + + + + Rating + + + + + Duration + + + + + Date + + + + + + + + + + + + + + 10 + + + 0 + + + + + + 0 + 0 + + + + Display: + + + + + + + SFW + + + true + + + + + + + NSFW + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + true + + + + + 0 + 0 + 763 + 391 + + + + QWidget#scrollAreaContent { + background-color: rgb(255, 255, 255); +} + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + URL: + + + + + + + + + + + + + + + 0 + 0 + 785 + 25 + + + + + + + + diff --git a/weboob/applications/qvideoob/ui/minivideo.ui b/weboob/applications/qvideoob/ui/minivideo.ui new file mode 100644 index 0000000000000000000000000000000000000000..624e39e5f36ef3b1c8c35fed9cb8453f84ec5ff9 --- /dev/null +++ b/weboob/applications/qvideoob/ui/minivideo.ui @@ -0,0 +1,189 @@ + + + MiniVideo + + + + 0 + 0 + 464 + 132 + + + + Form + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 9 + + + 5 + + + 5 + + + + + + 0 + 0 + + + + + + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + + 75 + true + + + + Title + + + + + + + + 0 + 0 + + + + + 50 + true + false + + + + TextLabel + + + + + + + + 75 + true + + + + Duration + + + + + + + TextLabel + + + + + + + + 75 + true + + + + Author + + + + + + + TextLabel + + + + + + + + 75 + true + + + + Date + + + + + + + TextLabel + + + + + + + + 75 + true + + + + Rating + + + + + + + TextLabel + + + + + + + + 75 + true + + + + Where + + + + + + + TextLabel + + + + + + + + + + diff --git a/weboob/applications/qvideoob/ui/video.ui b/weboob/applications/qvideoob/ui/video.ui new file mode 100644 index 0000000000000000000000000000000000000000..6d54c9bb4e1f6b192587dce9155dcbc6af1bc1ee --- /dev/null +++ b/weboob/applications/qvideoob/ui/video.ui @@ -0,0 +1,224 @@ + + + Video + + + + 0 + 0 + 647 + 404 + + + + Video + + + + + + + 12 + 75 + true + + + + QFrame::Box + + + QFrame::Raised + + + TextLabel + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + background-color: rgb(255, 255, 255); + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + 0 + 0 + + + + + + + + true + + + true + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + QFormLayout::ExpandingFieldsGrow + + + + + + 75 + true + + + + URL + + + + + + + true + + + ArrowCursor + + + true + + + false + + + true + + + + + + + + 75 + true + + + + Duration + + + + + + + TextLabel + + + + + + + + 75 + true + + + + Author + + + + + + + TextLabel + + + + + + + + 75 + true + + + + Date + + + + + + + TextLabel + + + + + + + + 75 + true + + + + Rating + + + + + + + TextLabel + + + + + + + + + + + Phonon::VideoPlayer + QWidget +
phonon/videoplayer.h
+
+ + Phonon::SeekSlider + QWidget +
phonon/seekslider.h
+
+
+ + +
diff --git a/weboob/applications/qvideoob/video.py b/weboob/applications/qvideoob/video.py new file mode 100644 index 0000000000000000000000000000000000000000..4092d4750181ac0b3052abe74cd66950fa7c394d --- /dev/null +++ b/weboob/applications/qvideoob/video.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from PyQt4.QtCore import QUrl +from PyQt4.QtGui import QDialog +from PyQt4.phonon import Phonon + +from weboob.frontends.qvideoob.ui.video_ui import Ui_Video + +class Video(QDialog): + def __init__(self, video, parent=None): + QDialog.__init__(self, parent) + self.ui = Ui_Video() + self.ui.setupUi(self) + + self.video = video + self.setWindowTitle("Video - %s" % video.title) + self.ui.urlEdit.setText(video.url) + self.ui.titleLabel.setText(video.title) + self.ui.durationLabel.setText('%d:%02d:%02d' % (video.duration/3600, (video.duration%3600)/60, video.duration%60)) + self.ui.authorLabel.setText(unicode(video.author)) + self.ui.dateLabel.setText(unicode(video.date)) + if video.rating_max: + self.ui.ratingLabel.setText('%s / %s' % (video.rating, video.rating_max)) + else: + self.ui.ratingLabel.setText('%s' % video.rating) + + self.ui.seekSlider.setMediaObject(self.ui.videoPlayer.mediaObject()) + self.ui.videoPlayer.load(Phonon.MediaSource(QUrl(video.url))) + self.ui.videoPlayer.play() + + def closeEvent(self, event): + self.ui.videoPlayer.stop() + event.accept() diff --git a/weboob/applications/travel/__init__.py b/weboob/applications/travel/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..59de2ae2369a576ce1e7fbdb0f2bae6bf30a468f --- /dev/null +++ b/weboob/applications/travel/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# vim: ft=python et softtabstop=4 cinoptions=4 shiftwidth=4 ts=4 ai + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .application import Travel diff --git a/weboob/applications/travel/application.py b/weboob/applications/travel/application.py new file mode 100644 index 0000000000000000000000000000000000000000..457ea0872629ef698e3f82e90177025435a6aa84 --- /dev/null +++ b/weboob/applications/travel/application.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon, Julien Hébert +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from weboob.capabilities.travel import ICapTravel +from weboob.tools.application import ConsoleApplication + + +__all__ = ['Travel'] + + +class Travel(ConsoleApplication): + APPNAME = 'travel' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + + def main(self, argv): + self.load_modules(ICapTravel) + + return self.process_command(*argv[1:]) + + @ConsoleApplication.command('Search stations') + def command_stations(self, pattern): + for backend, station in self.weboob.do('iter_station_search', pattern): + self.format(station, backend.name) + + @ConsoleApplication.command('List all departures for a given station') + def command_departures(self, station, arrival=None): + for backend, departure in self.weboob.do('iter_station_departures', station, arrival): + self.format(departure, backend.name) diff --git a/weboob/applications/travel/setup.py b/weboob/applications/travel/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..1a60f6897799dadad62dbcc84d8c07576aefe46a --- /dev/null +++ b/weboob/applications/travel/setup.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-travel', + version='0.1', + description='The Weboob travel swiss-knife', + long_description='Search for train stations and departure timegrids', + author='Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/Travel', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.travel', + ], + scripts=[ + 'scripts/travel', + ], + install_requires=[ + 'weboob-travel-backends', + ], +) diff --git a/weboob/applications/videoob/__init__.py b/weboob/applications/videoob/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a62cad0937df5ab5163492c6e062dbf5245ca0e4 --- /dev/null +++ b/weboob/applications/videoob/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .videoob import Videoob diff --git a/weboob/applications/videoob/setup.py b/weboob/applications/videoob/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..f0c7b93ee259bb098e85fa64c3de0ee155cbaeb4 --- /dev/null +++ b/weboob/applications/videoob/setup.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-videoob', + version='0.1', + description='Videoob, the Weboob video swiss-knife', + long_description='Search for videos on many websites, and get info about them', + author='Christophe Benz', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/Videoob', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.videoob', + ], + scripts=[ + 'scripts/videoob', + ], + install_requires=[ + 'weboob-video-backends', + ], +) diff --git a/weboob/applications/videoob/videoob.py b/weboob/applications/videoob/videoob.py new file mode 100644 index 0000000000000000000000000000000000000000..195260ecf6b444d97925aa68d392ec1c8c65b384 --- /dev/null +++ b/weboob/applications/videoob/videoob.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + + +# Copyright(C) 2010 Christophe Benz, Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from weboob.capabilities.video import ICapVideo +from weboob.tools.application import ConsoleApplication + + +__all__ = ['Videoob'] + + +class Videoob(ConsoleApplication): + APPNAME = 'videoob' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Christophe Benz, Romain Bignon' + CONFIG = {} + + def add_application_options(self, group): + group.add_option('--nsfw', action='store_true', help='enable non-suitable for work videos') + + def main(self, argv): + return self.process_command(*argv[1:]) + + @ConsoleApplication.command('Get video information (accept ID or URL)') + def command_info(self, _id): + _id, backend_name = self.parse_id(_id) + names = (backend_name,) if backend_name is not None else None + self.load_modules(ICapVideo, names=names) + for backend, video in self.weboob.do('get_video', _id): + if video is None: + continue + self.format(video, backend.name) + + @ConsoleApplication.command('Search videos') + def command_search(self, pattern=None): + self.load_modules(ICapVideo) + self.set_header(u'Search pattern: %s' % pattern if pattern else u'Last videos') + for backend, video in self.weboob.do('iter_search_results', pattern=pattern, nsfw=self.options.nsfw): + self.format(video, backend.name) diff --git a/weboob/applications/videoob_web/__init__.py b/weboob/applications/videoob_web/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..fb8f0ddd461a855ed2e224e3d7e1c88f08d9adfa --- /dev/null +++ b/weboob/applications/videoob_web/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .videoob_web import VideoobWeb diff --git a/weboob/applications/videoob_web/public/style.css b/weboob/applications/videoob_web/public/style.css new file mode 100644 index 0000000000000000000000000000000000000000..1ceedc5ac1db0dbbfece1dbae53b46f155b60716 --- /dev/null +++ b/weboob/applications/videoob_web/public/style.css @@ -0,0 +1,5 @@ +.video-item +{ + margin-bottom: 5ex; + margin-left: 2em; +} diff --git a/weboob/applications/videoob_web/setup.py b/weboob/applications/videoob_web/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..3368b26161666abba2b131a1eafd51124061f6a9 --- /dev/null +++ b/weboob/applications/videoob_web/setup.py @@ -0,0 +1,48 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-videoob-web', + version='0.1', + description='Videoob-web, the Weboob video swiss-knife, web server version', + long_description='Search for videos on many websites, and get info about them', + author='Christophe Benz', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/VideoobWeb', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.videoob_web', + 'weboob.frontends.videoob_web.public', + 'weboob.frontends.videoob_web.templates', + ], + scripts=[ + 'scripts/videoob-web-server', + ], + install_requires=[ + 'weboob-video-backends', + ], +) diff --git a/weboob/applications/videoob_web/templates/base.mako b/weboob/applications/videoob_web/templates/base.mako new file mode 100644 index 0000000000000000000000000000000000000000..6b9c4a61be895a65385b41e4b5b342912a22f3d6 --- /dev/null +++ b/weboob/applications/videoob_web/templates/base.mako @@ -0,0 +1,17 @@ +## -*- coding: utf-8 -*- + +<%def name="title()" filter="trim"> +Videoob Web + + + + + + ${self.title()} + + ${next.css()} + + + ${next.body()} + + diff --git a/weboob/applications/videoob_web/templates/index.mako b/weboob/applications/videoob_web/templates/index.mako new file mode 100644 index 0000000000000000000000000000000000000000..a0a1f1353b73f9a4a56597e5e0abd7751cfe9548 --- /dev/null +++ b/weboob/applications/videoob_web/templates/index.mako @@ -0,0 +1,43 @@ +## -*- coding: utf-8 -*- + +<%inherit file="base.mako"/> + +<%def name="css()" filter="trim"> + + + +<%def name="video_item(item)"> +
+ + ${item['title']} +
+ ${item['title']} +
+ ## (download) +
+ + +<%def name="body()"> +

Videoob Web

+ +
+ % if merge: + % for item in results: + ${video_item(item)} + % endfor + % else: + % for backend, items in sorted(results.iteritems()): +

${backend}

+ % for item in items: + ${video_item(item)} + % endfor + % endfor + % endif +
+ diff --git a/weboob/applications/videoob_web/videoob_web.py b/weboob/applications/videoob_web/videoob_web.py new file mode 100644 index 0000000000000000000000000000000000000000..8b7b28061c6cc0f4893e5b23e05a0c3674f73f79 --- /dev/null +++ b/weboob/applications/videoob_web/videoob_web.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +import os + +from mako.lookup import TemplateLookup +from mako.runtime import Context +from routes import Mapper +from StringIO import StringIO +from webob.dec import wsgify +from webob import exc +from wsgiref.simple_server import make_server + +from weboob.capabilities.video import ICapVideo +from weboob.tools.application import BaseApplication + + +__all__ = ['VideoobWeb'] + + +template_lookup = TemplateLookup(directories=[os.path.join(os.path.dirname(__file__), 'templates')], + output_encoding='utf-8', encoding_errors='replace') + + +class VideoobWeb(BaseApplication): + APPNAME = 'videoob-web' + CONFIG = dict(host='localhost', port=8080) + + @wsgify + def make_app(self, req): + map = Mapper() + map.connect('index', '/', method='index') + + results = map.routematch(environ=req.environ) + if results: + match, route = results + req.urlvars = ((), match) + kwargs = match.copy() + method = kwargs.pop('method') + return getattr(self, method)(req, **kwargs) + else: + public_path = os.path.join(os.path.dirname(__file__), 'public') + if not os.path.exists(public_path): + return exc.HTTPNotFound() + path = req.path + if path.startswith('/'): + path = path[1:] + public_file_path = os.path.join(public_path, path) + if os.path.exists(public_file_path): + if path.endswith('.css'): + req.response.content_type = 'text/css' + elif path.endswith('.js'): + req.response.content_type = 'text/javascript' + return open(public_file_path, 'r').read().strip() + else: + return exc.HTTPNotFound() + + def main(self, argv): + self.load_config() + self.weboob.load_modules(ICapVideo) + print 'Web server created. Listening on http://%s:%s' % ( + self.config.get('host'), int(self.config.get('port'))) + srv = make_server(self.config.get('host'), int(self.config.get('port')), self.make_app) + srv.serve_forever() + + def index(self, req): + c = {} + nsfw = req.params.get('nsfw') + nsfw = False if not nsfw or nsfw == '0' else True + q = req.params.get('q', u'') + merge = req.params.get('merge') + merge = False if not merge or merge == '0' else True + c['merge'] = merge + c['form_data'] = dict(q=q) + c['results'] = [] if merge else {} + if q: + for backend in self.weboob.iter_backends(): + videos = [dict(title=video.title, + page_url=video.page_url, + url=video.url if video.url else '/download?id=%s' % video.id, + thumbnail_url=video.thumbnail_url, + ) \ + for video in backend.iter_search_results(pattern=q, nsfw=nsfw)] + if videos: + if merge: + c['results'].extend(videos) + else: + c['results'][backend.name] = videos + if merge: + c['results'] = sorted(c['results'], key=lambda video: video['title'].lower()) + template = template_lookup.get_template('index.mako') + buf = StringIO() + ctx = Context(buf, **c) + template.render_context(ctx) + return buf.getvalue().strip() diff --git a/weboob/applications/weboobcfg/__init__.py b/weboob/applications/weboobcfg/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5c1352775f189781b8d23bbbf8bd98925b8cdf8d --- /dev/null +++ b/weboob/applications/weboobcfg/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .weboobcfg import WeboobCfg diff --git a/weboob/applications/weboobcfg/weboobcfg.py b/weboob/applications/weboobcfg/weboobcfg.py new file mode 100644 index 0000000000000000000000000000000000000000..6d623e60128eaf5f8f8451481209a53ea0dd9670 --- /dev/null +++ b/weboob/applications/weboobcfg/weboobcfg.py @@ -0,0 +1,178 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon, Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import ConfigParser +import logging +import os +import subprocess +import re + +from weboob.tools.application import ConsoleApplication + + +__all__ = ['WeboobCfg'] + + +class WeboobCfg(ConsoleApplication): + APPNAME = 'weboobcfg' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + + def main(self, argv): + return self.process_command(*argv[1:]) + + def caps_included(self, modcaps, caps): + modcaps = [x.__name__ for x in modcaps] + for cap in caps: + if not cap in modcaps: + return False + return True + + @ConsoleApplication.command('List modules') + def command_modules(self, *caps): + print ' Name Capabilities Description ' + print '+--------------+----------------------+----------------------------------------+' + self.weboob.modules_loader.load() + for name, module in self.weboob.modules_loader.modules.iteritems(): + if caps and not self.caps_included(module.iter_caps(), caps): + continue + + first_line = True + for cap in module.iter_caps(): + if first_line: + print ' %-14s %-21s %s' % (name, cap.__name__, module.get_description()) + first_line = False + else: + print ' %s' % cap.__name__ + + @ConsoleApplication.command('List applications') + def command_applications(self, *caps): + import weboob.frontends + path = weboob.frontends.__path__[0] + frontends = [] + regexp = re.compile('^%s/([\w\d_]+)$' % path) + for root, dirs, files in os.walk(path): + m = regexp.match(root) + if m and '__init__.py' in files: + frontends.append(m.group(1)) + + print ' '.join(frontends) + + @ConsoleApplication.command('Display a module') + def command_modinfo(self, name): + try: + module = self.weboob.modules_loader.get_or_load_module(name) + except KeyError: + logging.error('No such module: %s' % name) + return 1 + + print '.------------------------------------------------------------------------------.' + print '| Module %-69s |' % module.get_name() + print "+-----------------.------------------------------------------------------------'" + print '| Version | %s' % module.get_version() + print '| Maintainer | %s' % module.get_maintainer() + print '| License | %s' % module.get_license() + print '| Description | %s' % module.get_description() + print '| Capabilities | %s' % ', '.join([cap.__name__ for cap in module.iter_caps()]) + first = True + for key, field in module.get_config().iteritems(): + value = field.description + if not field.default is None: + value += ' (default: %s)' % field.default + if first: + print '| | ' + print '| Configuration | %s: %s' % (key, value) + first = False + else: + print '| | %s: %s' % (key, value) + print "'-----------------' " + + + @ConsoleApplication.command('Add a configured backend') + def command_add(self, name, *options): + self.weboob.modules_loader.load() + if name not in [module_name for module_name, module in self.weboob.modules_loader.modules.iteritems()]: + logging.error(u'Backend "%s" does not exist.' % name) + return 1 + + params = {} + # set backend params from command-line arguments + for option in options: + try: + key, value = option.split('=', 1) + except ValueError: + logging.error(u'Parameters have to be formatted "key=value"') + return 1 + params[key] = value + # ask for params non-specified on command-line arguments + module = self.weboob.modules_loader.get_or_load_module(name) + asked_config = False + for key, value in module.get_config().iteritems(): + if not asked_config: + asked_config = True + print u'Configuration of backend' + print u'------------------------' + if key not in params: + params[key] = self.ask(' [%s] %s' % (key, value.description), + default=value.default, + masked=value.is_masked, + regexp=value.regexp) + else: + print u' [%s] %s: %s' % (key, value.description, '(masked)' if value.is_masked else params[key]) + if asked_config: + print u'------------------------' + + try: + self.weboob.backends_config.add_backend(name, name, params) + print u'Backend "%s" successfully added to file "%s".\n'\ + 'Please check configuration parameters values with "weboobcfg edit".' % ( + name, self.weboob.backends_config.confpath) + except ConfigParser.DuplicateSectionError: + print u'Backend "%s" is already configured in file "%s"' % (name, self.weboob.backends_config.confpath) + response = raw_input(u'Add new instance of "%s" backend? [yN] ' % name) + if response.lower() == 'y': + while True: + new_name = raw_input(u'Please give new instance name (could be "%s_1"): ' % name) + if not new_name: + continue + try: + self.weboob.backends_config.add_backend(new_name, name, params) + print u'Backend "%s" successfully added to file "%s".\n'\ + 'Please check configuration parameters values with "weboobcfg edit".' % ( + name, self.weboob.backends_config.confpath) + break + except ConfigParser.DuplicateSectionError: + print u'Instance "%s" already exists for backend "%s".' % (new_name, name) + + @ConsoleApplication.command('List backends') + def command_list(self): + print ' Instance Name Name Params ' + print '+---------------+--------------+------------------------------------------------+' + for instance_name, name, params in self.weboob.backends_config.iter_backends(): + print ' %-15s %-14s %-47s' % (instance_name, name, ', '.join('%s=%s' % (key, value) for key, value in params.iteritems())) + + @ConsoleApplication.command('Remove a backend') + def command_remove(self, instance_name): + try: + self.weboob.backends_config.remove_backend(instance_name) + except ConfigParser.NoSectionError: + logging.error("Backend '%s' does not exist" % instance_name) + return 1 + + @ConsoleApplication.command('Edit configuration file') + def command_edit(self): + subprocess.call([os.environ.get('EDITOR', 'vi'), self.weboob.backends_config.confpath]) diff --git a/weboob/applications/weboobdebug/__init__.py b/weboob/applications/weboobdebug/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e4655d1943dc41032c1f47b596b5215f418856ef --- /dev/null +++ b/weboob/applications/weboobdebug/__init__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from .weboobdebug import WeboobDebug diff --git a/weboob/applications/weboobdebug/weboobdebug.py b/weboob/applications/weboobdebug/weboobdebug.py new file mode 100644 index 0000000000000000000000000000000000000000..79a15cbd04c13abe2facaa67a62af5118e3c1ba5 --- /dev/null +++ b/weboob/applications/weboobdebug/weboobdebug.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +import logging + +from weboob.tools.application import ConsoleApplication + + +class WeboobDebug(ConsoleApplication): + APPNAME = 'weboobdebug' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Christophe Benz' + + def main(self, argv): + return self.process_command(*argv[1:]) + + @ConsoleApplication.command('Debug backend') + def command_shell(self, backend_name): + try: + backend = self.weboob.load_modules(names=[backend_name])[backend_name] + except KeyError: + logging.error(u'Unable to load backend "%s"' % backend_name) + return 1 + browser = backend.browser + from IPython.Shell import IPShellEmbed + shell = IPShellEmbed(argv=[]) + locs = dict(backend=backend, browser=browser, frontend=self, weboob=self.weboob) + banner = 'Weboob debug shell\nBackend "%s" loaded.\nAvailable variables: %s' % (backend_name, locs) + shell.set_banner(shell.IP.BANNER + '\n\n' + banner) + shell(local_ns=locs, global_ns={}) diff --git a/weboob/applications/weboobtests/__init__.py b/weboob/applications/weboobtests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2833ddee5703c1abe80c40033a9c699d13e50d36 --- /dev/null +++ b/weboob/applications/weboobtests/__init__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from .weboobtests import WeboobTests diff --git a/weboob/applications/weboobtests/weboobtests.py b/weboob/applications/weboobtests/weboobtests.py new file mode 100644 index 0000000000000000000000000000000000000000..3e6b0148b0970173aa6e002ef6110d1ce9113188 --- /dev/null +++ b/weboob/applications/weboobtests/weboobtests.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from nose import run + +from weboob.tools.application import ConsoleApplication + +__all__ = ['WeboobTests'] + + +class WeboobTests(ConsoleApplication): + APPNAME = 'weboobtests' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + + def main(self, argv): + return self.process_command(*argv[1:]) + + @ConsoleApplication.command('Run tests') + def command_run(self): + self.load_modules() + self.load_backends() + + suite = [] + for backend in self.weboob.iter_backends(): + t = backend.get_test() + if t: + suite.append(t) + + return run(suite=suite) diff --git a/weboob/applications/weboorrents/__init__.py b/weboob/applications/weboorrents/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2757e023ad1bfb731e9e98bacf19323ebbcad508 --- /dev/null +++ b/weboob/applications/weboorrents/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .weboorrents import Weboorrents diff --git a/weboob/applications/weboorrents/setup.py b/weboob/applications/weboorrents/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..139b3bd97783ac50b6c3e0361ac2c418fead1f98 --- /dev/null +++ b/weboob/applications/weboorrents/setup.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-weboorrents', + version='0.1', + description='Weboorrents, the Weboob bittorrent swiss-knife', + long_description='Search for torrents on many websites, and get info about them', + author='Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/Weboorrents', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.weboorrents', + ], + scripts=[ + 'scripts/weboorrents', + ], + install_requires=[ + 'weboob-torrent-backends', + ], +) diff --git a/weboob/applications/weboorrents/weboorrents.py b/weboob/applications/weboorrents/weboorrents.py new file mode 100644 index 0000000000000000000000000000000000000000..6ba3022b1cf9b624fe61ba48063d546687025e95 --- /dev/null +++ b/weboob/applications/weboorrents/weboorrents.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +from __future__ import with_statement + +import sys + +from weboob.capabilities.torrent import ICapTorrent +from weboob.tools.application import ConsoleApplication + + +__all__ = ['Weboorrents'] + + +class Weboorrents(ConsoleApplication): + APPNAME = 'weboorrents' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + CONFIG = {} + + def main(self, argv): + self.load_backends(ICapTorrent) + return self.process_command(*argv[1:]) + + @ConsoleApplication.command('Get information about a torrent') + def command_info(self, id): + _id, backend_name = self.parse_id(id) + + found = 0 + for backend, torrent in self.weboob.do_backends(backend_name, 'get_torrent', _id): + if torrent: + self.format(torrent, backend.name) + found = 1 + + if not found: + print >>sys.stderr, 'Torrent "%s" not found' % id + + @ConsoleApplication.command('Get the torrent file') + def command_getfile(self, id, dest): + _id, backend_name = self.parse_id(id) + + for backend, buf in self.weboob.do_backends(backend_name, 'get_torrent_file', _id): + if buf: + if dest == '-': + print buf + else: + with open(dest, 'w') as f: + f.write(buf) + return + + print >>sys.stderr, 'Torrent "%s" not found' % id + + @ConsoleApplication.command('Search torrents') + def command_search(self, pattern=None): + self.set_header(u'Search pattern: %s' % pattern if pattern else u'Last torrents') + for backend, torrent in self.weboob.do('iter_torrents', pattern=pattern): + self.format(torrent, backend.name) diff --git a/weboob/applications/wetboobs/__init__.py b/weboob/applications/wetboobs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..399170184b69c81264f61d4bbba8d02e49c828be --- /dev/null +++ b/weboob/applications/wetboobs/__init__.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from .wetboobs import WetBoobs diff --git a/weboob/applications/wetboobs/setup.py b/weboob/applications/wetboobs/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..bd675ef903dbe99398dce414dcbf00e9356bfd51 --- /dev/null +++ b/weboob/applications/wetboobs/setup.py @@ -0,0 +1,45 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Christophe Benz +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +from setuptools import setup + +import os + + +setup( + name='weboob-wetboobs', + version='0.1', + description='Wetboobs, the Weboob weather forecast swiss-knife', + author='Romain Bignon', + author_email='weboob@lists.symlink.me', + license='GPLv3', + url='http://weboob.org/Wetboobs', + namespace_packages = ['weboob', 'weboob.frontends'], + packages=[ + 'weboob', + 'weboob.frontends', + 'weboob.frontends.wetboobs', + ], + scripts=[ + 'scripts/wetboobs', + ], + install_requires=[ + 'weboob-weather-backends', + ], +) diff --git a/weboob/applications/wetboobs/wetboobs.py b/weboob/applications/wetboobs/wetboobs.py new file mode 100644 index 0000000000000000000000000000000000000000..840f268b1c094e77eda9e68ba585e2a0a106e365 --- /dev/null +++ b/weboob/applications/wetboobs/wetboobs.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010 Romain Bignon +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +import logging + +from weboob.core import CallErrors +from weboob.capabilities.weather import ICapWeather, CityNotFound +from weboob.tools.application import ConsoleApplication + + +__all__ = ['WetBoobs'] + + +class WetBoobs(ConsoleApplication): + APPNAME = 'wetboobs' + VERSION = '0.1' + COPYRIGHT = 'Copyright(C) 2010 Romain Bignon' + + def main(self, argv): + self.load_modules(ICapWeather) + + return self.process_command(*argv[1:]) + + @ConsoleApplication.command('search cities') + def command_search(self, pattern): + for backend, city in self.weboob.do('iter_city_search', pattern): + self.format(city, backend.name) + + @ConsoleApplication.command('get current weather') + def command_current(self, city): + try: + for backend, current in self.weboob.do('get_current', city): + self.format(current, backend.name) + except CallErrors, e: + for error in e: + if isinstance(error, CityNotFound): + logging.error('City "%s" not found' % city) + else: + raise error + + @ConsoleApplication.command('get forecasts') + def command_forecasts(self, city): + try: + for backend, forecast in self.weboob.do('iter_forecast', city): + self.format(forecast, backend.name) + except CallErrors, e: + for error in e: + if isinstance(error, CityNotFound): + logging.error('City "%s" not found' % city) + else: + raise error diff --git a/weboob/tools/application/console.py b/weboob/tools/application/console.py index 9a55b8009f7e1231b8fae687d949fa053f5ce408..8ea28bccbb8aba6d0879c27bf98fd3887aa74d3e 100644 --- a/weboob/tools/application/console.py +++ b/weboob/tools/application/console.py @@ -216,7 +216,7 @@ def load_backends(self, caps=None, names=None, *args, **kwargs): loaded_backends = BaseApplication.load_backends(self, caps, names, *args, **kwargs) if not loaded_backends: logging.error(u'Cannot start application: no configured backend was found.\nHere is a list of all available backends:') - from weboob.frontends.weboobcfg import WeboobCfg + from weboob.applications.weboobcfg import WeboobCfg weboobcfg = WeboobCfg() if caps is not None: if not isinstance(caps, (list, tuple, set)):