[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