[Biplan] Add a new module to manage www.lebiplan.org

This commit is contained in:
Bezleputh 2013-10-30 19:29:23 +01:00 committed by Florent
commit 2ce5b4d0d4
6 changed files with 345 additions and 0 deletions

View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.
from .backend import BiplanBackend
__all__ = ['BiplanBackend']

53
modules/biplan/backend.py Normal file
View file

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.tools.backend import BaseBackend
from weboob.capabilities.calendar import ICapCalendarEvent
import itertools
from .browser import BiplanBrowser
from.calendar import BiplanCalendarEvent
__all__ = ['BiplanBackend']
class BiplanBackend(BaseBackend, ICapCalendarEvent):
NAME = 'biplan'
DESCRIPTION = u'lebiplan.org website'
MAINTAINER = u'Bezleputh'
EMAIL = 'carton_ben@yahoo.fr'
LICENSE = 'AGPLv3+'
VERSION = '0.h'
BROWSER = BiplanBrowser
def list_events(self, date_from, date_to=None):
with self.browser:
return itertools.chain(self.browser.list_events_concert(date_from, date_to),
self.browser.list_events_theatre(date_from, date_to))
def get_event(self, _id, event=None):
with self.browser:
return self.browser.get_event(_id, event)
def fill_obj(self, event, fields):
self.get_event(event.id, event)
OBJECTS = {BiplanCalendarEvent: fill_obj}

55
modules/biplan/browser.py Normal file
View file

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.tools.browser import BaseBrowser
from weboob.tools.browser.decorators import id2url
from .pages import ProgramPage, EventPage
from .calendar import BiplanCalendarEvent
__all__ = ['BiplanBrowser']
class BiplanBrowser(BaseBrowser):
PROTOCOL = 'http'
DOMAIN = 'www.lebiplan.org'
ENCODING = None
PAGES = {
#'%s://%s/fr/biplan-prog-concert.php' % (PROTOCOL, DOMAIN): ProgramPage,
'%s://%s/fr/biplan-prog(.*?).php' % (PROTOCOL, DOMAIN): ProgramPage,
'%s://%s/(.*?)' % (PROTOCOL, DOMAIN): EventPage,
}
def list_events_concert(self, date_from, date_to=None):
self.location('%s://%s/fr/biplan-prog-concert.php' % (self.PROTOCOL, self.DOMAIN))
assert self.is_on_page(ProgramPage)
return self.page.list_events(date_from, date_to, is_concert=True)
def list_events_theatre(self, date_from, date_to=None):
self.location('%s://%s/fr/biplan-prog-theatre.php' % (self.PROTOCOL, self.DOMAIN))
assert self.is_on_page(ProgramPage)
return self.page.list_events(date_from, date_to, is_concert=False)
@id2url(BiplanCalendarEvent.id2url)
def get_event(self, url, event=None):
self.location(url)
assert self.is_on_page(EventPage)
return self.page.get_event(url, event)

View file

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.capabilities.calendar import BaseCalendarEvent, TRANSP, STATUS, CATEGORIES
class BiplanCalendarEvent(BaseCalendarEvent):
location = '19, rue Colbert - 59000 LILLE'
sequence = 1
transp = TRANSP.TRANSPARENT
status = STATUS.CONFIRMED
@classmethod
def id2url(cls, _id):
return 'http://www.lebiplan.org/%s.html' % _id
class BiplanCalendarEventConcert(BiplanCalendarEvent):
category = CATEGORIES.CONCERT
class BiplanCalendarEventTheatre(BiplanCalendarEvent):
category = CATEGORIES.THEATRE

141
modules/biplan/pages.py Normal file
View file

@ -0,0 +1,141 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.
import re
from datetime import datetime, time
import weboob.tools.date as date_util
from weboob.tools.browser import BasePage
from .calendar import BiplanCalendarEventConcert, BiplanCalendarEventTheatre
__all__ = ['ProgramPage', 'EventPage']
def parse_b(b):
to_return = []
for item in b.replace('\n', '\t').replace(' ', '\t').split('\t'):
if not (item is None or item == ''):
to_return.append(u'%s' % item)
return to_return
class ProgramPage(BasePage):
def list_events(self, date_from, date_to=None, is_concert=None):
divs = self.document.getroot().xpath("//div[@class='ligne']")
for i in range(1, len(divs)):
event = self.create_event(divs[i], date_from, date_to, is_concert)
if event:
yield event
def create_event(self, div, date_from, date_to, is_concert):
re_id = re.compile('/(.*?).html', re.DOTALL)
a_id = self.parser.select(div, "div/a", 1, method='xpath')
b = self.parser.select(div, "div/div/b", 2, method='xpath')
_id = re_id.search(a_id.attrib['href']).group(1)
date = self.parse_date(b[0].text_content())
if _id and self.is_event_in_valid_period(date, date_from, date_to):
if is_concert:
event = BiplanCalendarEventConcert(_id)
else:
event = BiplanCalendarEventTheatre(_id)
time_price = parse_b(b[1].text_content())
start_time = self.parse_start_time(time_price)
event.start_date = datetime.combine(date, start_time)
event.end_date = datetime.combine(event.start_date, time.max)
price = time_price[time_price.index('-') + 1:]
event.price = " ".join(price)
event.summary = u'%s' % self.parser.select(div, "div/div/div/a/strong", 1, method='xpath').text
return event
def is_event_in_valid_period(self, event_date, date_from, date_to):
if event_date >= date_from:
if not date_to:
return True
else:
if event_date <= date_to:
return True
return False
def parse_start_time(self, time_price):
start_time = "".join(time_price[:time_price.index('-')]).split('h')
time_hour = start_time[0]
time_minutes = 0
if len(start_time) > 1 and start_time[1]:
time_minutes = start_time[1]
return time(int(time_hour), int(time_minutes))
def parse_date(self, b):
content = parse_b(b)
a_date = content[1:content.index('-')]
for fr, en in date_util.DATE_TRANSLATE_FR:
a_date[1] = fr.sub(en, a_date[1])
if (datetime.now().month > datetime.strptime(a_date[1], "%B").month):
a_date.append(u'%i' % (datetime.now().year + 1))
else:
a_date.append(u'%i' % (datetime.now().year))
return date_util.parse_french_date(" ".join(a_date))
class EventPage(BasePage):
def get_event(self, url, event=None):
div = self.document.getroot().xpath("//div[@id='popup']")[0]
if not event:
re_id = re.compile('http://www.lebiplan.org/(.*?).html', re.DOTALL)
_id = re_id.search(url).group(1)
if div.attrib['class'] == 'theatre-popup':
event = BiplanCalendarEventTheatre(_id)
else:
event = BiplanCalendarEventConcert(_id)
b = self.parser.select(div, "div/b", 1, method='xpath').text_content()
splitted_b = b.split('-')
event.price = u'%s' % " ".join(parse_b(splitted_b[-1]))
_date = date_util.parse_french_date(" ".join(parse_b(splitted_b[0])))
start_time = self.parse_start_time("".join(parse_b(splitted_b[2])))
event.start_date = datetime.combine(_date, start_time)
event.end_date = datetime.combine(_date, time.max)
event.url = url
event.summary = u'%s' % self.parser.select(div, "div/div/span", 1, method='xpath').text_content()
event.description = u'%s' % self.parser.select(div,
"div/div[@class='presentation-popup']",
1,
method='xpath').text_content().strip()
return event
def parse_start_time(self, _time):
start_time = _time.split('h')
time_hour = start_time[0]
time_minutes = 0
if len(start_time) > 1 and start_time[1]:
time_minutes = start_time[1]
return time(int(time_hour), int(time_minutes))

32
modules/biplan/test.py Normal file
View file

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Bezleputh
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.tools.test import BackendTest
from datetime import datetime
class BiplanTest(BackendTest):
BACKEND = 'biplan'
def test_biplan_list(self):
l = list(self.backend.list_events(datetime.now()))
assert len(l)
event = self.backend.get_event(l[0].id, None)
self.assertTrue(event.url, 'URL for event "%s" not found: %s' % (event.id, event.url))