[boobcoming] add new application boobcoming
This commit is contained in:
parent
b766065ec5
commit
d5e92e414e
3 changed files with 355 additions and 0 deletions
25
scripts/boobcoming
Executable file
25
scripts/boobcoming
Executable file
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- 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.applications.boobcoming import Boobcoming
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
Boobcoming.run()
|
||||||
23
weboob/applications/boobcoming/__init__.py
Normal file
23
weboob/applications/boobcoming/__init__.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
# -*- 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 .boobcoming import Boobcoming
|
||||||
|
|
||||||
|
__all__ = ['Boobcoming']
|
||||||
307
weboob/applications/boobcoming/boobcoming.py
Normal file
307
weboob/applications/boobcoming/boobcoming.py
Normal file
|
|
@ -0,0 +1,307 @@
|
||||||
|
# -*- 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
|
||||||
|
import sys
|
||||||
|
from datetime import date, timedelta, time, datetime
|
||||||
|
|
||||||
|
from weboob.tools.application.formatters.iformatter import IFormatter, PrettyFormatter
|
||||||
|
from weboob.capabilities.base import empty
|
||||||
|
from weboob.capabilities.calendar import ICapCalendarEvent
|
||||||
|
from weboob.tools.application.repl import ReplApplication, defaultcount
|
||||||
|
|
||||||
|
__all__ = ['Boobcoming']
|
||||||
|
|
||||||
|
|
||||||
|
class ICalFormatter(IFormatter):
|
||||||
|
MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary')
|
||||||
|
|
||||||
|
def start_format(self, **kwargs):
|
||||||
|
self.output(u'BEGIN:VCALENDAR')
|
||||||
|
self.output(u'VERSION:2.0')
|
||||||
|
self.output(u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN')
|
||||||
|
|
||||||
|
def format_obj(self, obj, alias):
|
||||||
|
result = u'BEGIN:VEVENT\n'
|
||||||
|
result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
result += u'SUMMARY:%s\n' % obj.summary
|
||||||
|
if hasattr(obj, 'location') and not empty(obj.location):
|
||||||
|
result += u'LOCATION:%s\n' % obj.location
|
||||||
|
|
||||||
|
if hasattr(obj, 'categories') and not empty(obj.categories):
|
||||||
|
result += u'CATEGORIES:%s\n' % obj.categories
|
||||||
|
|
||||||
|
if hasattr(obj, 'status') and not empty(obj.status):
|
||||||
|
result += u'STATUS:%s\n' % obj.status
|
||||||
|
|
||||||
|
if hasattr(obj, 'description') and not empty(obj.description):
|
||||||
|
result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n')
|
||||||
|
|
||||||
|
if hasattr(obj, 'transp') and not empty(obj.transp):
|
||||||
|
result += u'TRANSP:%s\n' % obj.transp
|
||||||
|
|
||||||
|
if hasattr(obj, 'sequence') and not empty(obj.sequence):
|
||||||
|
result += u'SEQUENCE:%s\n' % obj.sequence
|
||||||
|
|
||||||
|
if hasattr(obj, 'url') and not empty(obj.url):
|
||||||
|
result += u'URL:%s\n' % obj.url
|
||||||
|
|
||||||
|
result += u'END:VEVENT'
|
||||||
|
return result
|
||||||
|
|
||||||
|
def flush(self, **kwargs):
|
||||||
|
self.output(u'END:VCALENDAR')
|
||||||
|
|
||||||
|
|
||||||
|
class UpcomingListFormatter(PrettyFormatter):
|
||||||
|
MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category')
|
||||||
|
|
||||||
|
def get_title(self, obj):
|
||||||
|
return ' %s - %s ' % (obj.category, obj.summary)
|
||||||
|
|
||||||
|
def get_description(self, obj):
|
||||||
|
result = u''
|
||||||
|
result += u'\tDate: %s\n' % obj.start_date.strftime('%A %d %B %Y')
|
||||||
|
result += u'\tHour: %s - %s \n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M'))
|
||||||
|
return result.strip('\n\t')
|
||||||
|
|
||||||
|
|
||||||
|
class UpcomingFormatter(IFormatter):
|
||||||
|
MANDATORY_FIELDS = ('id', 'start_date', 'end_date', 'summary', 'category')
|
||||||
|
|
||||||
|
def format_obj(self, obj, alias):
|
||||||
|
result = u'%s%s - %s%s\n' % (self.BOLD, obj.category, obj.summary, self.NC)
|
||||||
|
result += u'Date: %s\n' % obj.start_date.strftime('%A %d %B %Y')
|
||||||
|
result += u'Hour: %s - %s\n' % (obj.start_date.strftime('%H:%M'), obj.end_date.strftime('%H:%M'))
|
||||||
|
|
||||||
|
if hasattr(obj, 'location') and not empty(obj.location):
|
||||||
|
result += u'Location: %s\n' % obj.location
|
||||||
|
|
||||||
|
if hasattr(obj, 'description') and not empty(obj.description):
|
||||||
|
result += u'Description:\n %s\n\n' % obj.description
|
||||||
|
|
||||||
|
if hasattr(obj, 'price') and not empty(obj.price):
|
||||||
|
result += u'Price: %s\n' % obj.price
|
||||||
|
|
||||||
|
if hasattr(obj, 'url') and not empty(obj.url):
|
||||||
|
result += u'url: %s\n' % obj.url
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class Boobcoming(ReplApplication):
|
||||||
|
APPNAME = 'boobcoming'
|
||||||
|
VERSION = '0.h'
|
||||||
|
COPYRIGHT = 'Copyright(C) 2012 Bezleputh'
|
||||||
|
DESCRIPTION = "Console application to see upcoming events."
|
||||||
|
SHORT_DESCRIPTION = "see upcoming events"
|
||||||
|
CAPS = ICapCalendarEvent
|
||||||
|
EXTRA_FORMATTERS = {'upcoming_list': UpcomingListFormatter,
|
||||||
|
'upcoming': UpcomingFormatter,
|
||||||
|
#'ical_formatter': ICalFormatter,
|
||||||
|
}
|
||||||
|
COMMANDS_FORMATTERS = {'list': 'upcoming_list',
|
||||||
|
'info': 'upcoming',
|
||||||
|
#'export': 'ical_formatter',
|
||||||
|
}
|
||||||
|
|
||||||
|
WEEK = {'MONDAY': 0,
|
||||||
|
'TUESDAY': 1,
|
||||||
|
'WEDNESDAY': 2,
|
||||||
|
'THURSDAY': 3,
|
||||||
|
'FRIDAY': 4,
|
||||||
|
'SATURDAY': 5,
|
||||||
|
'SUNDAY': 6,
|
||||||
|
'LUNDI': 0,
|
||||||
|
'MARDI': 1,
|
||||||
|
'MERCREDI': 2,
|
||||||
|
'JEUDI': 3,
|
||||||
|
'VENDREDI': 4,
|
||||||
|
'SAMEDI': 5,
|
||||||
|
'DIMANCHE': 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
@defaultcount(10)
|
||||||
|
def do_list(self, line):
|
||||||
|
"""
|
||||||
|
list [PATTERN]
|
||||||
|
List upcoming events, pattern can be an english or french week day, 'today' or a date
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.change_path([u'events'])
|
||||||
|
if line:
|
||||||
|
_date = self.parse_date(line)
|
||||||
|
if not _date:
|
||||||
|
print >>sys.stderr, 'Invalid argument: %s' % self.get_command_help('list', short=True)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
date_from = datetime.combine(_date, time.min)
|
||||||
|
date_to = datetime.combine(_date, time.max)
|
||||||
|
else:
|
||||||
|
date_from = datetime.now()
|
||||||
|
date_to = None
|
||||||
|
|
||||||
|
for backend, event in self.do('list_events', date_from, date_to):
|
||||||
|
self.cached_format(event)
|
||||||
|
|
||||||
|
def complete_info(self, text, line, *ignored):
|
||||||
|
args = line.split(' ')
|
||||||
|
if len(args) == 2:
|
||||||
|
return self._complete_object()
|
||||||
|
|
||||||
|
def do_info(self, _id):
|
||||||
|
"""
|
||||||
|
info ID
|
||||||
|
|
||||||
|
Get information about an event.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not _id:
|
||||||
|
print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('info', short=True)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
event = self.get_object(_id, 'get_event')
|
||||||
|
|
||||||
|
if not event:
|
||||||
|
print >>sys.stderr, 'Upcoming event not found: %s' % _id
|
||||||
|
return 3
|
||||||
|
|
||||||
|
self.start_format()
|
||||||
|
self.format(event)
|
||||||
|
|
||||||
|
def start_format(self, **kwargs):
|
||||||
|
result = u'BEGIN:VCALENDAR\n'
|
||||||
|
result += u'VERSION:2.0\n'
|
||||||
|
result += u'PRODID:-//hacksw/handcal//NONSGML v1.0//EN\n'
|
||||||
|
return result
|
||||||
|
|
||||||
|
def format_event(self, obj):
|
||||||
|
result = u'BEGIN:VEVENT\n'
|
||||||
|
result += u'DTSTART:%s\n' % obj.start_date.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
result += u'DTEND:%s\n' % obj.end_date.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
result += u'SUMMARY:%s\n' % obj.summary
|
||||||
|
if hasattr(obj, 'location') and not empty(obj.location):
|
||||||
|
result += u'LOCATION:%s\n' % obj.location
|
||||||
|
|
||||||
|
if hasattr(obj, 'categories') and not empty(obj.categories):
|
||||||
|
result += u'CATEGORIES:%s\n' % obj.categories
|
||||||
|
|
||||||
|
if hasattr(obj, 'status') and not empty(obj.status):
|
||||||
|
result += u'STATUS:%s\n' % obj.status
|
||||||
|
|
||||||
|
if hasattr(obj, 'description') and not empty(obj.description):
|
||||||
|
result += u'DESCRIPTION:%s\n' % obj.description.replace('\r\n', '\\n')
|
||||||
|
|
||||||
|
if hasattr(obj, 'transp') and not empty(obj.transp):
|
||||||
|
result += u'TRANSP:%s\n' % obj.transp
|
||||||
|
|
||||||
|
if hasattr(obj, 'sequence') and not empty(obj.sequence):
|
||||||
|
result += u'SEQUENCE:%s\n' % obj.sequence
|
||||||
|
|
||||||
|
if hasattr(obj, 'url') and not empty(obj.url):
|
||||||
|
result += u'URL:%s\n' % obj.url
|
||||||
|
|
||||||
|
result += u'END:VEVENT\n'
|
||||||
|
return result
|
||||||
|
|
||||||
|
def end_format(self):
|
||||||
|
return u'END:VCALENDAR'
|
||||||
|
|
||||||
|
def do_export(self, line):
|
||||||
|
"""
|
||||||
|
export FILENAME ID1 [ID2 ID3 ...]
|
||||||
|
|
||||||
|
id is the identifier of the event
|
||||||
|
FILENAME is where to write the file. If FILENAME is '-', the file is written to stdout.
|
||||||
|
|
||||||
|
Export event in ICALENDAR format
|
||||||
|
"""
|
||||||
|
if not line:
|
||||||
|
print >>sys.stderr, 'This command takes two arguments: %s' % self.get_command_help('export')
|
||||||
|
return 2
|
||||||
|
|
||||||
|
_file, args = self.parse_command_args(line, 2, req_n=1)
|
||||||
|
|
||||||
|
if not args:
|
||||||
|
print >>sys.stderr, 'This command takes two arguments: %s' % self.get_command_help('export')
|
||||||
|
return 2
|
||||||
|
|
||||||
|
_ids = args.strip().split(' ')
|
||||||
|
|
||||||
|
buff = self.start_format()
|
||||||
|
|
||||||
|
for _id in _ids:
|
||||||
|
event = self.get_object(_id, 'get_event')
|
||||||
|
|
||||||
|
if not event:
|
||||||
|
print >>sys.stderr, 'Upcoming event not found: %s' % _id
|
||||||
|
return 3
|
||||||
|
|
||||||
|
buff += self.format_event(event)
|
||||||
|
|
||||||
|
buff += self.end_format()
|
||||||
|
|
||||||
|
if _file == "-":
|
||||||
|
print buff
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
dest = self.check_file_ext(_file)
|
||||||
|
with open(dest, 'w') as f:
|
||||||
|
f.write(buff.encode('ascii', 'ignore'))
|
||||||
|
except IOError as e:
|
||||||
|
print >>sys.stderr, 'Unable to write bill in "%s": %s' % (dest, e)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def check_file_ext(self, _file):
|
||||||
|
splitted_file = _file.split('.')
|
||||||
|
if splitted_file[-1] != 'ics':
|
||||||
|
return "%s.ics" % _file
|
||||||
|
else:
|
||||||
|
return _file
|
||||||
|
|
||||||
|
def get_date_from_day(self, day):
|
||||||
|
today = date.today()
|
||||||
|
today_day_number = today.weekday()
|
||||||
|
|
||||||
|
requested_day_number = self.WEEK[day.upper()]
|
||||||
|
|
||||||
|
if today_day_number < requested_day_number:
|
||||||
|
day_to_go = requested_day_number - today_day_number
|
||||||
|
else:
|
||||||
|
day_to_go = 7 - today_day_number + requested_day_number
|
||||||
|
|
||||||
|
requested_date = today + timedelta(day_to_go)
|
||||||
|
return date(requested_date.year, requested_date.month, requested_date.day)
|
||||||
|
|
||||||
|
def parse_date(self, string):
|
||||||
|
matches = re.search('\s*([012]?[0-9]|3[01])\s*/\s*(0?[1-9]|1[012])\s*/?(\d{2}|\d{4})?$', string)
|
||||||
|
if matches:
|
||||||
|
year = matches.group(3)
|
||||||
|
if not year:
|
||||||
|
year = date.today().year
|
||||||
|
elif len(year) == 2:
|
||||||
|
year = 2000 + int(year)
|
||||||
|
return date(int(year), int(matches.group(2)), int(matches.group(1)))
|
||||||
|
|
||||||
|
elif string.upper() in self.WEEK.keys():
|
||||||
|
return self.get_date_from_day(string)
|
||||||
|
|
||||||
|
elif string.upper() == "TODAY":
|
||||||
|
return date.today()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue