From 3bf9c2518b8aca9c9b474d55593918b662dd904b Mon Sep 17 00:00:00 2001
From: Christophe Benz
Date: Tue, 6 Jul 2010 12:59:06 +0200
Subject: [PATCH] global s/frontends/applications/
---
scripts/boobank | 2 +-
scripts/chatoob | 2 +-
scripts/havesex | 2 +-
scripts/masstransit | 2 +-
scripts/monboob | 2 +-
scripts/qboobmsg | 2 +-
scripts/qhavesex | 2 +-
scripts/qvideoob | 2 +-
scripts/travel | 2 +-
scripts/videoob | 2 +-
scripts/videoob-web-server | 2 +-
scripts/weboob-debug | 2 +-
scripts/weboob-tests | 2 +-
scripts/weboobcfg | 2 +-
scripts/weboorrents | 2 +-
scripts/wetboobs | 2 +-
tools/all_packages.sh | 22 +-
weboob/applications/__init__.py | 1 +
weboob/applications/boobank/__init__.py | 19 ++
weboob/applications/boobank/boobank.py | 70 +++++
weboob/applications/boobank/setup.py | 46 +++
weboob/applications/chatoob/__init__.py | 18 ++
weboob/applications/chatoob/chatoob.py | 61 ++++
weboob/applications/havesex/__init__.py | 19 ++
weboob/applications/havesex/havesex.py | 91 ++++++
weboob/applications/masstransit/__init__.py | 20 ++
.../applications/masstransit/masstransit.py | 239 ++++++++++++++++
weboob/applications/masstransit/setup.py | 46 +++
weboob/applications/monboob/__init__.py | 19 ++
weboob/applications/monboob/monboob.py | 265 ++++++++++++++++++
weboob/applications/monboob/setup.py | 45 +++
weboob/applications/qboobmsg/__init__.py | 1 +
weboob/applications/qboobmsg/main_window.py | 47 ++++
.../applications/qboobmsg/messages_manager.py | 134 +++++++++
weboob/applications/qboobmsg/qboobmsg.py | 34 +++
weboob/applications/qboobmsg/setup.py | 49 ++++
weboob/applications/qboobmsg/ui/Makefile | 13 +
weboob/applications/qboobmsg/ui/__init__.py | 0
.../applications/qboobmsg/ui/main_window.ui | 91 ++++++
.../qboobmsg/ui/messages_manager.ui | 192 +++++++++++++
weboob/applications/qhavesex/__init__.py | 1 +
weboob/applications/qhavesex/contacts.py | 203 ++++++++++++++
weboob/applications/qhavesex/main_window.py | 59 ++++
weboob/applications/qhavesex/qhavesex.py | 35 +++
weboob/applications/qhavesex/setup.py | 50 ++++
weboob/applications/qhavesex/status.py | 102 +++++++
weboob/applications/qhavesex/ui/Makefile | 13 +
weboob/applications/qhavesex/ui/__init__.py | 0
.../qhavesex/ui/contact_thread.ui | 90 ++++++
weboob/applications/qhavesex/ui/contacts.ui | 89 ++++++
.../applications/qhavesex/ui/main_window.ui | 92 ++++++
.../qhavesex/ui/thread_message.ui | 109 +++++++
weboob/applications/qvideoob/__init__.py | 1 +
weboob/applications/qvideoob/main_window.py | 116 ++++++++
weboob/applications/qvideoob/minivideo.py | 62 ++++
weboob/applications/qvideoob/qvideoob.py | 40 +++
weboob/applications/qvideoob/setup.py | 50 ++++
weboob/applications/qvideoob/ui/Makefile | 13 +
weboob/applications/qvideoob/ui/__init__.py | 0
.../applications/qvideoob/ui/main_window.ui | 193 +++++++++++++
weboob/applications/qvideoob/ui/minivideo.ui | 189 +++++++++++++
weboob/applications/qvideoob/ui/video.ui | 224 +++++++++++++++
weboob/applications/qvideoob/video.py | 49 ++++
weboob/applications/travel/__init__.py | 20 ++
weboob/applications/travel/application.py | 44 +++
weboob/applications/travel/setup.py | 46 +++
weboob/applications/videoob/__init__.py | 19 ++
weboob/applications/videoob/setup.py | 46 +++
weboob/applications/videoob/videoob.py | 54 ++++
weboob/applications/videoob_web/__init__.py | 19 ++
.../applications/videoob_web/public/style.css | 5 +
weboob/applications/videoob_web/setup.py | 48 ++++
.../videoob_web/templates/base.mako | 17 ++
.../videoob_web/templates/index.mako | 43 +++
.../applications/videoob_web/videoob_web.py | 110 ++++++++
weboob/applications/weboobcfg/__init__.py | 19 ++
weboob/applications/weboobcfg/weboobcfg.py | 178 ++++++++++++
weboob/applications/weboobdebug/__init__.py | 18 ++
.../applications/weboobdebug/weboobdebug.py | 45 +++
weboob/applications/weboobtests/__init__.py | 18 ++
.../applications/weboobtests/weboobtests.py | 44 +++
weboob/applications/weboorrents/__init__.py | 19 ++
weboob/applications/weboorrents/setup.py | 46 +++
.../applications/weboorrents/weboorrents.py | 71 +++++
weboob/applications/wetboobs/__init__.py | 19 ++
weboob/applications/wetboobs/setup.py | 45 +++
weboob/applications/wetboobs/wetboobs.py | 66 +++++
weboob/tools/application/console.py | 2 +-
88 files changed, 4387 insertions(+), 28 deletions(-)
create mode 100644 weboob/applications/__init__.py
create mode 100644 weboob/applications/boobank/__init__.py
create mode 100644 weboob/applications/boobank/boobank.py
create mode 100755 weboob/applications/boobank/setup.py
create mode 100644 weboob/applications/chatoob/__init__.py
create mode 100644 weboob/applications/chatoob/chatoob.py
create mode 100644 weboob/applications/havesex/__init__.py
create mode 100644 weboob/applications/havesex/havesex.py
create mode 100644 weboob/applications/masstransit/__init__.py
create mode 100644 weboob/applications/masstransit/masstransit.py
create mode 100755 weboob/applications/masstransit/setup.py
create mode 100644 weboob/applications/monboob/__init__.py
create mode 100644 weboob/applications/monboob/monboob.py
create mode 100755 weboob/applications/monboob/setup.py
create mode 100644 weboob/applications/qboobmsg/__init__.py
create mode 100644 weboob/applications/qboobmsg/main_window.py
create mode 100644 weboob/applications/qboobmsg/messages_manager.py
create mode 100644 weboob/applications/qboobmsg/qboobmsg.py
create mode 100755 weboob/applications/qboobmsg/setup.py
create mode 100644 weboob/applications/qboobmsg/ui/Makefile
create mode 100644 weboob/applications/qboobmsg/ui/__init__.py
create mode 100644 weboob/applications/qboobmsg/ui/main_window.ui
create mode 100644 weboob/applications/qboobmsg/ui/messages_manager.ui
create mode 100644 weboob/applications/qhavesex/__init__.py
create mode 100644 weboob/applications/qhavesex/contacts.py
create mode 100644 weboob/applications/qhavesex/main_window.py
create mode 100644 weboob/applications/qhavesex/qhavesex.py
create mode 100755 weboob/applications/qhavesex/setup.py
create mode 100644 weboob/applications/qhavesex/status.py
create mode 100644 weboob/applications/qhavesex/ui/Makefile
create mode 100644 weboob/applications/qhavesex/ui/__init__.py
create mode 100644 weboob/applications/qhavesex/ui/contact_thread.ui
create mode 100644 weboob/applications/qhavesex/ui/contacts.ui
create mode 100644 weboob/applications/qhavesex/ui/main_window.ui
create mode 100644 weboob/applications/qhavesex/ui/thread_message.ui
create mode 100644 weboob/applications/qvideoob/__init__.py
create mode 100644 weboob/applications/qvideoob/main_window.py
create mode 100644 weboob/applications/qvideoob/minivideo.py
create mode 100644 weboob/applications/qvideoob/qvideoob.py
create mode 100755 weboob/applications/qvideoob/setup.py
create mode 100644 weboob/applications/qvideoob/ui/Makefile
create mode 100644 weboob/applications/qvideoob/ui/__init__.py
create mode 100644 weboob/applications/qvideoob/ui/main_window.ui
create mode 100644 weboob/applications/qvideoob/ui/minivideo.ui
create mode 100644 weboob/applications/qvideoob/ui/video.ui
create mode 100644 weboob/applications/qvideoob/video.py
create mode 100644 weboob/applications/travel/__init__.py
create mode 100644 weboob/applications/travel/application.py
create mode 100755 weboob/applications/travel/setup.py
create mode 100644 weboob/applications/videoob/__init__.py
create mode 100755 weboob/applications/videoob/setup.py
create mode 100644 weboob/applications/videoob/videoob.py
create mode 100644 weboob/applications/videoob_web/__init__.py
create mode 100644 weboob/applications/videoob_web/public/style.css
create mode 100755 weboob/applications/videoob_web/setup.py
create mode 100644 weboob/applications/videoob_web/templates/base.mako
create mode 100644 weboob/applications/videoob_web/templates/index.mako
create mode 100644 weboob/applications/videoob_web/videoob_web.py
create mode 100644 weboob/applications/weboobcfg/__init__.py
create mode 100644 weboob/applications/weboobcfg/weboobcfg.py
create mode 100644 weboob/applications/weboobdebug/__init__.py
create mode 100644 weboob/applications/weboobdebug/weboobdebug.py
create mode 100644 weboob/applications/weboobtests/__init__.py
create mode 100644 weboob/applications/weboobtests/weboobtests.py
create mode 100644 weboob/applications/weboorrents/__init__.py
create mode 100755 weboob/applications/weboorrents/setup.py
create mode 100644 weboob/applications/weboorrents/weboorrents.py
create mode 100644 weboob/applications/wetboobs/__init__.py
create mode 100755 weboob/applications/wetboobs/setup.py
create mode 100644 weboob/applications/wetboobs/wetboobs.py
diff --git a/scripts/boobank b/scripts/boobank
index e2f871849c..b208313a31 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 a76a959f6f..b578c01b06 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 c4d7a8a303..a52bd9d1d1 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 915c257ff5..1a545f3c52 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 927fda66c2..31cbcad205 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 9cc2e88bc1..4177e49cca 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 3cadf607b6..ce2c7ade8a 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 28f5726a6f..ea6d48e986 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 32b76c9e99..a09d6ac438 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 51897a5f7a..72fbe7a89e 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 c6e2cab06f..ada312d18c 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 48416ad90f..84425bd15c 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 c79456f5d3..3d698f0b3e 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 a4609f6ec0..c712b7849f 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 75665b365b..ec69235d9d 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 88882e25c6..12fa2b5835 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 4652291981..bdd4bf94cc 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 0000000000..de40ea7ca0
--- /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 0000000000..b6558548d3
--- /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 0000000000..5c3510d76c
--- /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 0000000000..e0287d593b
--- /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 0000000000..e106ea0230
--- /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 0000000000..9262cb7669
--- /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 0000000000..80fb0343e1
--- /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 0000000000..656b44a871
--- /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 0000000000..55b190ebbf
--- /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 0000000000..37d80c1b39
--- /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 0000000000..c9cbda3acb
--- /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 0000000000..ee4a0e9786
--- /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 0000000000..81ed3cfae6
--- /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 0000000000..616e941535
--- /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 0000000000..3db51dd078
--- /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 0000000000..8b7d56af0d
--- /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 0000000000..c3a392d90a
--- /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 0000000000..c9f24205de
--- /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 0000000000..fc0ac9707a
--- /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 0000000000..f0db5154cf
--- /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 0000000000..e69de29bb2
diff --git a/weboob/applications/qboobmsg/ui/main_window.ui b/weboob/applications/qboobmsg/ui/main_window.ui
new file mode 100644
index 0000000000..330e9460dc
--- /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 0000000000..beba8bca75
--- /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 0000000000..e55140d2be
--- /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 0000000000..b6931cd9bf
--- /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 0000000000..803488ecd7
--- /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 0000000000..1a4d3da84c
--- /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 0000000000..3a65ffb982
--- /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 0000000000..27333aa34a
--- /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 0000000000..f0db5154cf
--- /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 0000000000..e69de29bb2
diff --git a/weboob/applications/qhavesex/ui/contact_thread.ui b/weboob/applications/qhavesex/ui/contact_thread.ui
new file mode 100644
index 0000000000..33a482f36a
--- /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 0000000000..a663289802
--- /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 0000000000..6a2b3e4774
--- /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 0000000000..0c55067bc1
--- /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 0000000000..83eea19a9a
--- /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 0000000000..0aff986cc4
--- /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 0000000000..71b3bc6f7a
--- /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 0000000000..490120404d
--- /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 0000000000..c8b1882881
--- /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 0000000000..f0db5154cf
--- /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 0000000000..e69de29bb2
diff --git a/weboob/applications/qvideoob/ui/main_window.ui b/weboob/applications/qvideoob/ui/main_window.ui
new file mode 100644
index 0000000000..2002c0b085
--- /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 0000000000..624e39e5f3
--- /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 0000000000..6d54c9bb4e
--- /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 0000000000..4092d47501
--- /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 0000000000..59de2ae236
--- /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 0000000000..457ea08726
--- /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 0000000000..1a60f68977
--- /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 0000000000..a62cad0937
--- /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 0000000000..f0c7b93ee2
--- /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 0000000000..195260ecf6
--- /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 0000000000..fb8f0ddd46
--- /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 0000000000..1ceedc5ac1
--- /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 0000000000..3368b26161
--- /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 0000000000..6b9c4a61be
--- /dev/null
+++ b/weboob/applications/videoob_web/templates/base.mako
@@ -0,0 +1,17 @@
+## -*- coding: utf-8 -*-
+
+<%def name="title()" filter="trim">
+Videoob Web
+%def>
+
+
+
+
+ ${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 0000000000..a0a1f1353b
--- /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>
+
+<%def name="video_item(item)">
+
+ % 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
+
+%def>
diff --git a/weboob/applications/videoob_web/videoob_web.py b/weboob/applications/videoob_web/videoob_web.py
new file mode 100644
index 0000000000..8b7b28061c
--- /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 0000000000..5c1352775f
--- /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 0000000000..6d623e6012
--- /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 0000000000..e4655d1943
--- /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 0000000000..79a15cbd04
--- /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 0000000000..2833ddee57
--- /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 0000000000..3e6b0148b0
--- /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 0000000000..2757e023ad
--- /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 0000000000..139b3bd977
--- /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 0000000000..6ba3022b1c
--- /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 0000000000..399170184b
--- /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 0000000000..bd675ef903
--- /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 0000000000..840f268b1c
--- /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 9a55b8009f..8ea28bccbb 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)):
--
GitLab