global s/frontends/applications/
This commit is contained in:
parent
423bc10f33
commit
3bf9c2518b
88 changed files with 4387 additions and 28 deletions
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
# 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__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@ COMMAND="$1"
|
||||||
SETUP_PY_LIST="
|
SETUP_PY_LIST="
|
||||||
weboob/setup.py
|
weboob/setup.py
|
||||||
weboob/backends/setup.py
|
weboob/backends/setup.py
|
||||||
weboob/frontends/boobank/setup.py
|
weboob/applications/boobank/setup.py
|
||||||
weboob/frontends/masstransit/setup.py
|
weboob/applications/masstransit/setup.py
|
||||||
weboob/frontends/monboob/setup.py
|
weboob/applications/monboob/setup.py
|
||||||
weboob/frontends/qboobmsg/setup.py
|
weboob/applications/qboobmsg/setup.py
|
||||||
weboob/frontends/qhavesex/setup.py
|
weboob/applications/qhavesex/setup.py
|
||||||
weboob/frontends/qvideoob/setup.py
|
weboob/applications/qvideoob/setup.py
|
||||||
weboob/frontends/travel/setup.py
|
weboob/applications/travel/setup.py
|
||||||
weboob/frontends/videoob/setup.py
|
weboob/applications/videoob/setup.py
|
||||||
weboob/frontends/videoob_web/setup.py
|
weboob/applications/videoob_web/setup.py
|
||||||
weboob/frontends/weboorrents/setup.py
|
weboob/applications/weboorrents/setup.py
|
||||||
weboob/frontends/wetboobs/setup.py
|
weboob/applications/wetboobs/setup.py
|
||||||
"
|
"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
1
weboob/applications/__init__.py
Normal file
1
weboob/applications/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
__import__('pkg_resources').declare_namespace(__name__)
|
||||||
19
weboob/applications/boobank/__init__.py
Normal file
19
weboob/applications/boobank/__init__.py
Normal file
|
|
@ -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
|
||||||
70
weboob/applications/boobank/boobank.py
Normal file
70
weboob/applications/boobank/boobank.py
Normal file
|
|
@ -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))
|
||||||
46
weboob/applications/boobank/setup.py
Executable file
46
weboob/applications/boobank/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
18
weboob/applications/chatoob/__init__.py
Normal file
18
weboob/applications/chatoob/__init__.py
Normal file
|
|
@ -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
|
||||||
61
weboob/applications/chatoob/chatoob.py
Normal file
61
weboob/applications/chatoob/chatoob.py
Normal file
|
|
@ -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))
|
||||||
19
weboob/applications/havesex/__init__.py
Normal file
19
weboob/applications/havesex/__init__.py
Normal file
|
|
@ -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
|
||||||
91
weboob/applications/havesex/havesex.py
Normal file
91
weboob/applications/havesex/havesex.py
Normal file
|
|
@ -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)
|
||||||
20
weboob/applications/masstransit/__init__.py
Normal file
20
weboob/applications/masstransit/__init__.py
Normal file
|
|
@ -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
|
||||||
239
weboob/applications/masstransit/masstransit.py
Normal file
239
weboob/applications/masstransit/masstransit.py
Normal file
|
|
@ -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()
|
||||||
46
weboob/applications/masstransit/setup.py
Executable file
46
weboob/applications/masstransit/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
19
weboob/applications/monboob/__init__.py
Normal file
19
weboob/applications/monboob/__init__.py
Normal file
|
|
@ -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
|
||||||
265
weboob/applications/monboob/monboob.py
Normal file
265
weboob/applications/monboob/monboob.py
Normal file
|
|
@ -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'<p>-- <br />%s</p>' % 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']
|
||||||
45
weboob/applications/monboob/setup.py
Executable file
45
weboob/applications/monboob/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
1
weboob/applications/qboobmsg/__init__.py
Normal file
1
weboob/applications/qboobmsg/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from .qboobmsg import QBoobMsg
|
||||||
47
weboob/applications/qboobmsg/main_window.py
Normal file
47
weboob/applications/qboobmsg/main_window.py
Normal file
|
|
@ -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()
|
||||||
134
weboob/applications/qboobmsg/messages_manager.py
Normal file
134
weboob/applications/qboobmsg/messages_manager.py
Normal file
|
|
@ -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("<h1>%s</h1>"
|
||||||
|
"<b>Date</b>: %s<br />"
|
||||||
|
"<b>From</b>: %s<br />"
|
||||||
|
"<p>%s</p>"
|
||||||
|
% (message.title, str(message.date), message.sender, message.content))
|
||||||
34
weboob/applications/qboobmsg/qboobmsg.py
Normal file
34
weboob/applications/qboobmsg/qboobmsg.py
Normal file
|
|
@ -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()
|
||||||
49
weboob/applications/qboobmsg/setup.py
Executable file
49
weboob/applications/qboobmsg/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
13
weboob/applications/qboobmsg/ui/Makefile
Normal file
13
weboob/applications/qboobmsg/ui/Makefile
Normal file
|
|
@ -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)
|
||||||
|
|
||||||
0
weboob/applications/qboobmsg/ui/__init__.py
Normal file
0
weboob/applications/qboobmsg/ui/__init__.py
Normal file
91
weboob/applications/qboobmsg/ui/main_window.ui
Normal file
91
weboob/applications/qboobmsg/ui/main_window.ui
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>763</width>
|
||||||
|
<height>580</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>QBoobMsg</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>763</width>
|
||||||
|
<height>24</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionModules"/>
|
||||||
|
<addaction name="actionRefresh"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionQuit"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<widget class="QToolBar" name="toolBar">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>toolBar</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionModules"/>
|
||||||
|
<addaction name="actionRefresh"/>
|
||||||
|
</widget>
|
||||||
|
<action name="actionModules">
|
||||||
|
<property name="text">
|
||||||
|
<string>Modules</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionQuit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRefresh">
|
||||||
|
<property name="text">
|
||||||
|
<string>Refresh</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>actionQuit</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>close()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>381</x>
|
||||||
|
<y>289</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
192
weboob/applications/qboobmsg/ui/messages_manager.ui
Normal file
192
weboob/applications/qboobmsg/ui/messages_manager.ui
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MessagesManager</class>
|
||||||
|
<widget class="QWidget" name="MessagesManager">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>767</width>
|
||||||
|
<height>591</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QListWidget" name="backendsList">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>2</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QTreeWidget" name="messagesTree">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="tabKeyNavigation">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="animated">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="headerHidden">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="headerDefaultSectionSize">
|
||||||
|
<number>100</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerShowSortIndicator" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerDefaultSectionSize">
|
||||||
|
<number>100</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerShowSortIndicator" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="headerStretchLastSection">
|
||||||
|
<bool>true</bool>
|
||||||
|
</attribute>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Date</string>
|
||||||
|
</property>
|
||||||
|
<property name="textAlignment">
|
||||||
|
<set>AlignLeft|AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>From</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Title</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTextEdit" name="messageBody">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="expandButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>+</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="collapseButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>−</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>expandButton</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>messagesTree</receiver>
|
||||||
|
<slot>expandAll()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>733</x>
|
||||||
|
<y>31</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>527</x>
|
||||||
|
<y>150</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>collapseButton</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>messagesTree</receiver>
|
||||||
|
<slot>collapseAll()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>733</x>
|
||||||
|
<y>60</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>527</x>
|
||||||
|
<y>150</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
1
weboob/applications/qhavesex/__init__.py
Normal file
1
weboob/applications/qhavesex/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from .qhavesex import QHaveSex
|
||||||
203
weboob/applications/qhavesex/contacts.py
Normal file
203
weboob/applications/qhavesex/contacts.py
Normal file
|
|
@ -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', '<br />')
|
||||||
|
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('<h2>%s</h2><font color="#%06X">%s</font><br /><i>%s</i>' % (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'))
|
||||||
59
weboob/applications/qhavesex/main_window.py
Normal file
59
weboob/applications/qhavesex/main_window.py
Normal file
|
|
@ -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
|
||||||
35
weboob/applications/qhavesex/qhavesex.py
Normal file
35
weboob/applications/qhavesex/qhavesex.py
Normal file
|
|
@ -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()
|
||||||
50
weboob/applications/qhavesex/setup.py
Executable file
50
weboob/applications/qhavesex/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
102
weboob/applications/qhavesex/status.py
Normal file
102
weboob/applications/qhavesex/status.py
Normal file
|
|
@ -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'<h1>%s — %s</h1>' % (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 += '</p>'
|
||||||
|
body += '<p>%s</p>' % value
|
||||||
|
in_p = False
|
||||||
|
else:
|
||||||
|
if not in_p:
|
||||||
|
body += "<p>"
|
||||||
|
in_p = True
|
||||||
|
else:
|
||||||
|
body += "<br />"
|
||||||
|
|
||||||
|
body += '<b>%s</b>: %s' % (field.label, field.value)
|
||||||
|
if in_p:
|
||||||
|
body += "</p>"
|
||||||
|
|
||||||
|
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()
|
||||||
13
weboob/applications/qhavesex/ui/Makefile
Normal file
13
weboob/applications/qhavesex/ui/Makefile
Normal file
|
|
@ -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)
|
||||||
|
|
||||||
0
weboob/applications/qhavesex/ui/__init__.py
Normal file
0
weboob/applications/qhavesex/ui/__init__.py
Normal file
90
weboob/applications/qhavesex/ui/contact_thread.ui
Normal file
90
weboob/applications/qhavesex/ui/contact_thread.ui
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ContactThread</class>
|
||||||
|
<widget class="QWidget" name="ContactThread">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>578</width>
|
||||||
|
<height>429</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaContent">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>556</width>
|
||||||
|
<height>187</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QWidget#scrollAreaContent {
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="textEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="sendButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Send</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
89
weboob/applications/qhavesex/ui/contacts.ui
Normal file
89
weboob/applications/qhavesex/ui/contacts.ui
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Contacts</class>
|
||||||
|
<widget class="QWidget" name="Contacts">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>482</width>
|
||||||
|
<height>320</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="groupBox"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="refreshButton">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>../../../../../../../../usr/share/icons/oxygen/16x16/actions/view-refresh.png</normaloff>../../../../../../../../usr/share/icons/oxygen/16x16/actions/view-refresh.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="contactList">
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>120</width>
|
||||||
|
<height>120</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionRectVisible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
92
weboob/applications/qhavesex/ui/main_window.ui
Normal file
92
weboob/applications/qhavesex/ui/main_window.ui
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>763</width>
|
||||||
|
<height>580</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>QHaveSex</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>763</width>
|
||||||
|
<height>24</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionModules"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionQuit"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<widget class="QToolBar" name="toolBar">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>toolBar</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionModules"/>
|
||||||
|
</widget>
|
||||||
|
<action name="actionModules">
|
||||||
|
<property name="text">
|
||||||
|
<string>Modules</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionQuit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>actionQuit</sender>
|
||||||
|
<signal>triggered()</signal>
|
||||||
|
<receiver>MainWindow</receiver>
|
||||||
|
<slot>close()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>-1</x>
|
||||||
|
<y>-1</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>381</x>
|
||||||
|
<y>289</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
109
weboob/applications/qhavesex/ui/thread_message.ui
Normal file
109
weboob/applications/qhavesex/ui/thread_message.ui
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ThreadMessage</class>
|
||||||
|
<widget class="QFrame" name="ThreadMessage">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>552</width>
|
||||||
|
<height>76</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Frame</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="imageLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="nameLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>1</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="widget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="headerLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="contentLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="textInteractionFlags">
|
||||||
|
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>1</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
1
weboob/applications/qvideoob/__init__.py
Normal file
1
weboob/applications/qvideoob/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from .qvideoob import QVideoob
|
||||||
116
weboob/applications/qvideoob/main_window.py
Normal file
116
weboob/applications/qvideoob/main_window.py
Normal file
|
|
@ -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()
|
||||||
62
weboob/applications/qvideoob/minivideo.py
Normal file
62
weboob/applications/qvideoob/minivideo.py
Normal file
|
|
@ -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()
|
||||||
40
weboob/applications/qvideoob/qvideoob.py
Normal file
40
weboob/applications/qvideoob/qvideoob.py
Normal file
|
|
@ -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()
|
||||||
50
weboob/applications/qvideoob/setup.py
Executable file
50
weboob/applications/qvideoob/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
13
weboob/applications/qvideoob/ui/Makefile
Normal file
13
weboob/applications/qvideoob/ui/Makefile
Normal file
|
|
@ -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)
|
||||||
|
|
||||||
0
weboob/applications/qvideoob/ui/__init__.py
Normal file
0
weboob/applications/qvideoob/ui/__init__.py
Normal file
193
weboob/applications/qvideoob/ui/main_window.ui
Normal file
193
weboob/applications/qvideoob/ui/main_window.ui
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>785</width>
|
||||||
|
<height>594</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>QVideoob</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_2">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Search: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="searchEdit"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="sortbyEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Relevance</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rating</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Duration</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Date</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="backendEdit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Display:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="sfwCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>SFW</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="nsfwCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>NSFW</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaContent">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>763</width>
|
||||||
|
<height>391</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QWidget#scrollAreaContent {
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_3">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>URL: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="urlEdit"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>785</width>
|
||||||
|
<height>25</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
189
weboob/applications/qvideoob/ui/minivideo.ui
Normal file
189
weboob/applications/qvideoob/ui/minivideo.ui
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MiniVideo</class>
|
||||||
|
<widget class="QFrame" name="MiniVideo">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>464</width>
|
||||||
|
<height>132</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="imageLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Title</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="titleLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>50</weight>
|
||||||
|
<italic>true</italic>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Duration</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="durationLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Author</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="authorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Date</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="dateLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rating</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLabel" name="ratingLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Where</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLabel" name="backendLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
224
weboob/applications/qvideoob/ui/video.ui
Normal file
224
weboob/applications/qvideoob/ui/video.ui
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Video</class>
|
||||||
|
<widget class="QDialog" name="Video">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>647</width>
|
||||||
|
<height>404</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Video</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="titleLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::Box</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background-color: rgb(255, 255, 255);</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Sunken</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="Phonon::VideoPlayer" name="videoPlayer">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Phonon::SeekSlider" name="seekSlider">
|
||||||
|
<property name="iconVisible">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tracking">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_2">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>URL</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="urlEdit">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="cursor">
|
||||||
|
<cursorShape>ArrowCursor</cursorShape>
|
||||||
|
</property>
|
||||||
|
<property name="mouseTracking">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="autoFillBackground">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Duration</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="durationLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Author</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="authorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Date</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="dateLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rating</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLabel" name="ratingLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Phonon::VideoPlayer</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">phonon/videoplayer.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>Phonon::SeekSlider</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">phonon/seekslider.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
49
weboob/applications/qvideoob/video.py
Normal file
49
weboob/applications/qvideoob/video.py
Normal file
|
|
@ -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()
|
||||||
20
weboob/applications/travel/__init__.py
Normal file
20
weboob/applications/travel/__init__.py
Normal file
|
|
@ -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
|
||||||
44
weboob/applications/travel/application.py
Normal file
44
weboob/applications/travel/application.py
Normal file
|
|
@ -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)
|
||||||
46
weboob/applications/travel/setup.py
Executable file
46
weboob/applications/travel/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
19
weboob/applications/videoob/__init__.py
Normal file
19
weboob/applications/videoob/__init__.py
Normal file
|
|
@ -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
|
||||||
46
weboob/applications/videoob/setup.py
Executable file
46
weboob/applications/videoob/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
54
weboob/applications/videoob/videoob.py
Normal file
54
weboob/applications/videoob/videoob.py
Normal file
|
|
@ -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)
|
||||||
19
weboob/applications/videoob_web/__init__.py
Normal file
19
weboob/applications/videoob_web/__init__.py
Normal file
|
|
@ -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
|
||||||
5
weboob/applications/videoob_web/public/style.css
Normal file
5
weboob/applications/videoob_web/public/style.css
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.video-item
|
||||||
|
{
|
||||||
|
margin-bottom: 5ex;
|
||||||
|
margin-left: 2em;
|
||||||
|
}
|
||||||
48
weboob/applications/videoob_web/setup.py
Executable file
48
weboob/applications/videoob_web/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
17
weboob/applications/videoob_web/templates/base.mako
Normal file
17
weboob/applications/videoob_web/templates/base.mako
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
## -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
<%def name="title()" filter="trim">
|
||||||
|
Videoob Web
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>${self.title()}</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
${next.css()}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
${next.body()}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
43
weboob/applications/videoob_web/templates/index.mako
Normal file
43
weboob/applications/videoob_web/templates/index.mako
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
## -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
<%inherit file="base.mako"/>
|
||||||
|
|
||||||
|
<%def name="css()" filter="trim">
|
||||||
|
<link rel="stylesheet" type="text/css" href="style.css"/>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="video_item(item)">
|
||||||
|
<div class="video-item">
|
||||||
|
<a href="${item['page_url']}">
|
||||||
|
<img src="${item['thumbnail_url']}" alt="${item['title']}"/>
|
||||||
|
<br/>
|
||||||
|
${item['title']}
|
||||||
|
</a>
|
||||||
|
## (<a href="${item['url']}"><em>download</em></a>)
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<%def name="body()">
|
||||||
|
<h1>Videoob Web</h1>
|
||||||
|
<div id="search">
|
||||||
|
<form action="/" method="get">
|
||||||
|
<label for="q">Search pattern:</label>
|
||||||
|
<input id="q" type="text" name="q" value="${form_data['q']}" />
|
||||||
|
<input type="submit" value="Search" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="results">
|
||||||
|
% if merge:
|
||||||
|
% for item in results:
|
||||||
|
${video_item(item)}
|
||||||
|
% endfor
|
||||||
|
% else:
|
||||||
|
% for backend, items in sorted(results.iteritems()):
|
||||||
|
<h2>${backend}</h2>
|
||||||
|
% for item in items:
|
||||||
|
${video_item(item)}
|
||||||
|
% endfor
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
</div>
|
||||||
|
</%def>
|
||||||
110
weboob/applications/videoob_web/videoob_web.py
Normal file
110
weboob/applications/videoob_web/videoob_web.py
Normal file
|
|
@ -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()
|
||||||
19
weboob/applications/weboobcfg/__init__.py
Normal file
19
weboob/applications/weboobcfg/__init__.py
Normal file
|
|
@ -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
|
||||||
178
weboob/applications/weboobcfg/weboobcfg.py
Normal file
178
weboob/applications/weboobcfg/weboobcfg.py
Normal file
|
|
@ -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])
|
||||||
18
weboob/applications/weboobdebug/__init__.py
Normal file
18
weboob/applications/weboobdebug/__init__.py
Normal file
|
|
@ -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
|
||||||
45
weboob/applications/weboobdebug/weboobdebug.py
Normal file
45
weboob/applications/weboobdebug/weboobdebug.py
Normal file
|
|
@ -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={})
|
||||||
18
weboob/applications/weboobtests/__init__.py
Normal file
18
weboob/applications/weboobtests/__init__.py
Normal file
|
|
@ -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
|
||||||
44
weboob/applications/weboobtests/weboobtests.py
Normal file
44
weboob/applications/weboobtests/weboobtests.py
Normal file
|
|
@ -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)
|
||||||
19
weboob/applications/weboorrents/__init__.py
Normal file
19
weboob/applications/weboorrents/__init__.py
Normal file
|
|
@ -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
|
||||||
46
weboob/applications/weboorrents/setup.py
Executable file
46
weboob/applications/weboorrents/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
71
weboob/applications/weboorrents/weboorrents.py
Normal file
71
weboob/applications/weboorrents/weboorrents.py
Normal file
|
|
@ -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)
|
||||||
19
weboob/applications/wetboobs/__init__.py
Normal file
19
weboob/applications/wetboobs/__init__.py
Normal file
|
|
@ -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
|
||||||
45
weboob/applications/wetboobs/setup.py
Executable file
45
weboob/applications/wetboobs/setup.py
Executable file
|
|
@ -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',
|
||||||
|
],
|
||||||
|
)
|
||||||
66
weboob/applications/wetboobs/wetboobs.py
Normal file
66
weboob/applications/wetboobs/wetboobs.py
Normal file
|
|
@ -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
|
||||||
|
|
@ -216,7 +216,7 @@ class ConsoleApplication(BaseApplication):
|
||||||
loaded_backends = BaseApplication.load_backends(self, caps, names, *args, **kwargs)
|
loaded_backends = BaseApplication.load_backends(self, caps, names, *args, **kwargs)
|
||||||
if not loaded_backends:
|
if not loaded_backends:
|
||||||
logging.error(u'Cannot start application: no configured backend was found.\nHere is a list of all available 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()
|
weboobcfg = WeboobCfg()
|
||||||
if caps is not None:
|
if caps is not None:
|
||||||
if not isinstance(caps, (list, tuple, set)):
|
if not isinstance(caps, (list, tuple, set)):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue