pax_global_header 0000666 0000000 0000000 00000000064 13436457030 0014517 g ustar 00root root 0000000 0000000 52 comment=3863a14eedf17551743a8bbccf0237874d7f4a16
woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/ 0000775 0000000 0000000 00000000000 13436457030 0023644 5 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/ 0000775 0000000 0000000 00000000000 13436457030 0025314 5 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre/ 0000775 0000000 0000000 00000000000 13436457030 0030102 5 ustar 00root root 0000000 0000000 __init__.py 0000664 0000000 0000000 00000001525 13436457030 0032137 0 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre # -*- coding: utf-8 -*-
# Copyright(C) 2014 Bezleputh
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
from .module import AgendadulibreModule
__all__ = ['AgendadulibreModule']
woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre/browser.py0000664 0000000 0000000 00000004001 13436457030 0032132 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2014 Bezleputh
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
from weboob.browser import PagesBrowser, URL
from .pages import EventListPage, EventPage
from datetime import timedelta, date
class AgendadulibreBrowser(PagesBrowser):
event_list_page = URL('events\?start_date=(?P.*)(?P.*)', EventListPage)
event_page = URL('events/(?P<_id>.*)', EventPage)
def __init__(self, website, region, *args, **kwargs):
self.BASEURL = u'%s/' % website
self.region = '®ion=%s' % region if region else ''
PagesBrowser.__init__(self, *args, **kwargs)
def list_events(self, date_from, date_to, city=None, categories=None, max_date=None):
_max_date = date_from + timedelta(days=365)
max_date = date(year=_max_date.year, month=_max_date.month, day=_max_date.day)
return self.event_list_page.go(date_from=date_from.strftime("%Y-%m-%d"),
region=self.region)\
.list_events(date_from=date_from,
date_to=date_to,
city=city,
categories=categories,
max_date=max_date)
def get_event(self, event_id, event=None):
_id = event_id.split('#')[-1]
return self.event_page.go(_id=_id).get_event(obj=event)
calendar.py 0000664 0000000 0000000 00000002145 13436457030 0032150 0 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre # -*- coding: utf-8 -*-
# Copyright(C) 2013 Bezleputh
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
from weboob.capabilities.calendar import BaseCalendarEvent, TRANSP, STATUS, CATEGORIES
class AgendaDuLibreCalendarEvent(BaseCalendarEvent):
def __init__(self):
BaseCalendarEvent.__init__(self)
self.sequence = 1
self.transp = TRANSP.TRANSPARENT
self.status = STATUS.CONFIRMED
self.category = CATEGORIES.CONF
favicon.png 0000664 0000000 0000000 00000003431 13436457030 0032157 0 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre PNG
IHDR @ @ iq gAMA a pHYs od tEXtAuthor Jakub Steiner/ !tEXtSource http://jimmac.musichall.czif^ ItEXtCopyright Public Domain http://creativecommons.org/licenses/publicdomain/Y tEXtSoftware paint.net 4.0.3P IDATx^OIg!TSPKN9TApzA0H uXdo+~X_WV6=̑igO.zz8Ç>|#JHCCCyY"%Hyy:uJ̙3 !2dggKII(ƍjSSSKrE(ZDwQ]]-SyKggtuu%W^+WH~~ܾ}}%=zTPS .4illt"$vGAAr@nn
-{tJ80++DIr1G^kî04iҞ$ZDwA0Pw
F_C]Q 89tw0 999+X?|<"c11;;{ I'C. 9߽{=%I%Z;7G>cftO̹gϔc"v~6lGVVT]ō??/ hݩ90ۙNt7 hݩ90wQ+j hݩ9ɓ' 27"Єݩ9ɝu )?J@`7}( W@$ .?3鄃
D֢hu˃?~,yyyS@kkpH0T\*@/21vMMM|Jɀ| ?֯>R/`[#v$SXؕtBFMVlBM JɌmuV?`ccC%Ev"uA D'p!>Êh`fҳا"#Dg7sqJcm|h;
߿/*پ"=p UMנȲrݤQ{UY^^9u'`phHەlSx*f!?Q 1%?i2*@@
pP7>~,pNd5c2u+N%3RbRׯs)pg %%%6N a?ʇݻw"o߾7oׯeiiIeaaA]/^%*rɓ'*>gffdzzZ6GÇebbB˽{N[wܑ[n͛7nUZrP
@ ,B9̹y ky9|"Tp)XU"M!655)r(녨zeZEBRU!f0{xVd@?b/bb.VRTEI zhmMܓqd!4JxF Myj'
!F5GZ{
%א;QȈ,DL chWY/i*;3NT|Jb$WbOVӸzxޜDNEn,O8Ç>|#G~>scZ IENDB` woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre/module.py 0000664 0000000 0000000 00000014577 13436457030 0031757 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2014 Bezleputh
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
from collections import OrderedDict
from weboob.tools.backend import Module, BackendConfig
from weboob.capabilities.calendar import CapCalendarEvent, CATEGORIES
from weboob.tools.value import Value
from .browser import AgendadulibreBrowser
__all__ = ['AgendadulibreModule']
class AgendadulibreModule(Module, CapCalendarEvent):
NAME = 'agendadulibre'
DESCRIPTION = u'agendadulibre website'
MAINTAINER = u'Bezleputh'
EMAIL = 'carton_ben@yahoo.fr'
LICENSE = 'AGPLv3+'
VERSION = '1.6'
ASSOCIATED_CATEGORIES = [CATEGORIES.CONF]
BROWSER = AgendadulibreBrowser
region_choices = OrderedDict([(k, u'%s (%s)' % (v, k)) for k, v in sorted({
"https://www.agendadulibre.org": u'--France--',
"https://www.agendadulibre.org#3": u'Auvergne-Rhône-Alpes',
"https://www.agendadulibre.org#5": u'Bourgogne-Franche-Comté',
"https://www.agendadulibre.org#6": u'Bretagne',
"https://www.agendadulibre.org#7": u'Centre-Val de Loire',
"https://www.agendadulibre.org#30": u'Collectivité sui generis',
"https://www.agendadulibre.org#29": u'Collectivités d\'outre-mer',
"https://www.agendadulibre.org#9": u'Corse',
"https://www.agendadulibre.org#1": u'Grand Est',
"https://www.agendadulibre.org#23": u'Guadeloupe',
"https://www.agendadulibre.org#24": u'Guyane',
"https://www.agendadulibre.org#17": u'Hauts-de-France',
"https://www.agendadulibre.org#12": u'Île-de-France',
"https://www.agendadulibre.org#31": u'Internet',
"https://www.agendadulibre.org#26": u'La Réunion',
"https://www.agendadulibre.org#25": u'Martinique',
"https://www.agendadulibre.org#28": u'Mayotte',
"https://www.agendadulibre.org#4": u'Normandie',
"https://www.agendadulibre.org#2": u'Nouvelle-Aquitaine',
"https://www.agendadulibre.org#13": u'Occitanie',
"https://www.agendadulibre.org#18": u'Pays de la Loire',
"https://www.agendadulibre.org#21": u'Provence-Alpes-Côte d\'Azur',
"https://www.agendadulibre.be": u'--Belgique--',
"https://www.agendadulibre.be#11": u'Antwerpen',
"https://www.agendadulibre.be#10": u'Brabant wallon',
"https://www.agendadulibre.be#9": u'Bruxelles-Capitale',
"https://www.agendadulibre.be#8": u'Hainaut',
"https://www.agendadulibre.be#7": u'Liege',
"https://www.agendadulibre.be#6": u'Limburg',
"https://www.agendadulibre.be#5": u'Luxembourg',
"https://www.agendadulibre.be#4": u'Namur',
"https://www.agendadulibre.be#3": u'Oost-Vlaanderen',
"https://www.agendadulibre.be#2": u'Vlaams-Brabant',
"https://www.agendadulibre.be#1": u'West-Vlaanderen',
"https://www.agendadulibre.ch": u'--Suisse--',
"https://www.agendadulibre.ch#15": u'Appenzell Rhodes-Extérieures',
"https://www.agendadulibre.ch#16": u'Appenzell Rhodes-Intérieures',
"https://www.agendadulibre.ch#19": u'Argovie',
"https://www.agendadulibre.ch#13": u'Bâle-Campagne',
"https://www.agendadulibre.ch#12": u'Bâle-Ville',
"https://www.agendadulibre.ch#2": u'Berne',
"https://www.agendadulibre.ch#10": u'Fribourg',
"https://www.agendadulibre.ch#25": u'Genève',
"https://www.agendadulibre.ch#8": u'Glaris',
"https://www.agendadulibre.ch#18": u'Grisons',
"https://www.agendadulibre.ch#26": u'Jura',
"https://www.agendadulibre.ch#3": u'Lucerne',
"https://www.agendadulibre.ch#24": u'Neuchâtel',
"https://www.agendadulibre.ch#7": u'Nidwald',
"https://www.agendadulibre.ch#6": u'Obwald',
"https://www.agendadulibre.ch#17": u'Saint-Gall',
"https://www.agendadulibre.ch#14": u'Schaffhouse',
"https://www.agendadulibre.ch#5": u'Schwytz',
"https://www.agendadulibre.ch#11": u'Soleure',
"https://www.agendadulibre.ch#21": u'Tessin',
"https://www.agendadulibre.ch#20": u'Thurgovie',
"https://www.agendadulibre.ch#4": u'Uri',
"https://www.agendadulibre.ch#23": u'Valais',
"https://www.agendadulibre.ch#22": u'Vaud',
"https://www.agendadulibre.ch#9": u'Zoug',
"https://www.agendadulibre.ch#1": u'Zurich',
}.items())])
CONFIG = BackendConfig(Value('region', label=u'Region', choices=region_choices))
def create_default_browser(self):
choice = self.config['region'].get().split('#')
selected_region = '' if len(choice) < 2 else choice[-1]
return self.create_browser(website=choice[0], region=selected_region)
def search_events(self, query):
return self.browser.list_events(query.start_date,
query.end_date,
query.city,
query.categories)
def list_events(self, date_from, date_to=None):
return self.browser.list_events(date_from, date_to)
def get_event(self, event_id):
return self.browser.get_event(event_id)
def fill_obj(self, event, fields):
event = self.browser.get_event(event.id, event)
choice = self.config['region'].get().split('#')
selected_region = '' if len(choice) < 2 else choice[-1]
if selected_region == '23':
event.timezone = 'America/Guadeloupe'
elif selected_region == '24':
event.timezone = 'America/Guyana'
elif selected_region == '26':
event.timezone = 'Indian/Reunion'
elif selected_region == '25':
event.timezone = 'America/Martinique'
else:
event.timezone = 'Europe/Paris'
return event
OBJECTS = {AgendadulibreBrowser: fill_obj}
woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre/pages.py 0000664 0000000 0000000 00000016415 13436457030 0031562 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2014 Bezleputh
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
import re
from datetime import time, datetime, date
from weboob.browser.pages import HTMLPage, pagination
from weboob.browser.elements import ItemElement, ListElement, method
from weboob.browser.filters.standard import Regexp, CleanText, DateTime, Env, Format, BrowserURL
from weboob.browser.filters.html import Link, XPath, CleanHTML
from weboob.tools.date import parse_french_date
from .calendar import AgendaDuLibreCalendarEvent
class EventPage(HTMLPage):
@method
class get_event(ItemElement):
klass = AgendaDuLibreCalendarEvent
obj_id = Env('_id')
obj_url = BrowserURL('event_page', _id=Env('_id'))
obj_summary = Format('%s %s',
CleanText('//meta[@name="geo:placename"]/@content'),
CleanText('//meta[@name="DC:title"]/@content'))
obj_description = CleanHTML('//div[@class="description"]')
obj_location = CleanText('//p[@class="full_address"]/span[1]')
obj_city = CleanText('//meta[@name="geo:placename"]/@content')
def obj_start_date(self):
m = re.findall(r'\w* \w* \d?\d \w* \d{4} \w* \d{2}h\d{2}', CleanText('(//p)[1]')(self), re.UNICODE)
if m:
return DateTime(Regexp(CleanText('(//p)[1]'),
'\w* \w* (\d?\d \w* \d{4}) \w* (\d{2}h\d{2}).*',
'\\1 \\2',
flags=re.UNICODE),
parse_func=parse_french_date)(self)
def obj_end_date(self):
m = re.findall(r'\w* \w* \d?\d \w* \d{4} \w* \d{2}h\d{2}', CleanText('(//p)[1]')(self), re.UNICODE)
if m:
if len(m) == 1:
return DateTime(Regexp(CleanText('(//p)[1]'),
r'\w* \w* (\d?\d \w* \d{4}) \w* \d{2}h\d{2} \w* (\d{2}h\d{2})',
'\\1 \\2',
flags=re.UNICODE),
parse_func=parse_french_date)(self)
else:
return DateTime(Regexp(CleanText('(//p)[1]'),
r'\w* \w* (\d?\d \w* \d{4}) \w* (\d{2}h\d{2})',
'\\1 \\2',
nth=-1,
flags=re.UNICODE),
parse_func=parse_french_date)(self)
class EventListPage(HTMLPage):
@pagination
@method
class list_events(ListElement):
item_xpath = '//td[starts-with(@class, "day")]/ul/li'
def next_page(self):
m = re.match('.*/events\?start_date=(\d{4})-(\d{2})-(\d{2})(®ion=.*)?', self.page.url)
if m:
start = date(year=int(m.group(1)), month=int(m.group(2)), day=1)
region = m.group(4) if m.group(4) else ''
try:
next_month = start.replace(month=start.month + 1)
except ValueError:
if start.month == 12:
next_month = start.replace(year=start.year + 1, month=1)
else:
raise
if (self.env['date_to'] is None and
start < self.env['max_date']) or\
(self.env['date_to'] is not None and
datetime.combine(next_month, time.min) < self.env['date_to']):
return '/events?start_date=%s%s' % (next_month.strftime("%Y-%m-%d"), region)
class item(ItemElement):
klass = AgendaDuLibreCalendarEvent
def condition(self):
return len(XPath('.')(self.el)) > 0 and \
('current-month' in XPath('./ancestor::td/@class')(self.el)[0])
obj_id = Format('%s#%s',
CleanText('./ancestor::td/div[@class="day_number"]'),
Regexp(Link('./a'), '/events/(.*)'))
obj_city = CleanText('./a/strong[@class="city"]')
obj_summary = CleanText('./a')
def obj_start_date(self):
m = re.findall(r'\w* \w* \d?\d \w* \d{4} \w* \d{2}h\d{2}', CleanText('./@title')(self), re.UNICODE)
if m:
return DateTime(Regexp(CleanText('./@title'),
'\w* \w* (\d?\d \w* \d{4}) \w* (\d{2}h\d{2}).*',
'\\1 \\2',
flags=re.UNICODE),
parse_func=parse_french_date)(self)
def obj_end_date(self):
m = re.findall(r'\w* \w* \d?\d \w* \d{4} \w* \d{2}h\d{2}', CleanText('./@title')(self), re.UNICODE)
if m:
if len(m) == 1:
return DateTime(Regexp(CleanText('./@title'),
r'\w* \w* (\d?\d \w* \d{4}) \w* \d{2}h\d{2} \w* (\d{2}h\d{2})',
'\\1 \\2',
flags=re.UNICODE),
parse_func=parse_french_date)(self)
else:
return DateTime(Regexp(CleanText('./@title'),
r'\w* \w* (\d?\d \w* \d{4}) \w* (\d{2}h\d{2})',
'\\1 \\2',
nth=-1,
flags=re.UNICODE),
parse_func=parse_french_date)(self)
def validate(self, obj):
return (self.is_valid_event(obj, self.env['city'], self.env['categories']) and
self.is_event_in_valid_period(obj.start_date, self.env['date_from'], self.env['date_to']))
def is_valid_event(self, event, city, categories):
if city and city != '' and city.upper() != event.city.upper():
return False
if categories and len(categories) > 0 and event.category not in categories:
return False
return True
def is_event_in_valid_period(self, event_date, date_from, date_to):
if event_date >= datetime.combine(date_from, time.min):
if not date_to:
return True
else:
if event_date <= date_to:
return True
return False
woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-agendadulibre/modules/agendadulibre/test.py 0000664 0000000 0000000 00000002532 13436457030 0031435 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2014 Bezleputh
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
from weboob.tools.test import BackendTest
from weboob.tools.value import Value
from datetime import datetime
class AgendadulibreTest(BackendTest):
MODULE = 'agendadulibre'
def setUp(self):
if not self.is_backend_configured():
self.backend.config['region'] = Value(value='https://www.agendadulibre.org')
def test_agendadulibre(self):
l = list(self.backend.list_events(datetime.now()))
assert len(l)
event = self.backend.get_event(l[0].id)
self.assertTrue(event.url, 'URL for event "%s" not found: %s' % (event.id, event.url))