Téléchargement fonctionnel + création d'agenda google.
This commit is contained in:
parent
510589b375
commit
642c82f7f2
2 changed files with 98 additions and 56 deletions
|
@ -1,5 +1,6 @@
|
||||||
Un script du cancer codé avec les pieds pour aller chercher l'emploi du temps
|
Un script pour aller chercher l'emploi du temps
|
||||||
sur NTNOE.
|
sur NTNOE. Il crée un agenda `ntnoe` dans votre Google agenda pour y
|
||||||
|
synchroniser l'agenda NTNOE.
|
||||||
|
|
||||||
Vous avec besoin d'une clé API google, allez la chercher
|
Vous avec besoin d'une clé API google, allez la chercher
|
||||||
[ici](https://developers.google.com/google-apps/calendar/quickstart/python) et
|
[ici](https://developers.google.com/google-apps/calendar/quickstart/python) et
|
||||||
|
@ -17,6 +18,4 @@ Créez un fichier `ntnoe_credentials` sur le modèle de
|
||||||
python3 main.py
|
python3 main.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Par contre ça gère pas les modifications de cours de façon tip top, donc
|
Après le tout s'automatise bien avec un petit `cron` des familles.
|
||||||
synchronisez pas trop dans le future. Pour modifier ce temps, voir la variable
|
|
||||||
`TIMEDELTA_SYNCHRO`.
|
|
||||||
|
|
145
main.py
145
main.py
|
@ -1,9 +1,38 @@
|
||||||
|
"""
|
||||||
|
NTNOE SYNC is a simple script tha allows you to synchronize your NTNOE diary
|
||||||
|
with Google Calendar.
|
||||||
|
|
||||||
|
It will create a `ntnoe` calendar among your Google calendars and write your
|
||||||
|
NTNOE calendar into. NTNOE_SYNC is availabe under the MIT license.
|
||||||
|
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Hugo LEVY-FALK
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import httplib2
|
import httplib2
|
||||||
import urllib
|
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
import shutil
|
|
||||||
|
|
||||||
from apiclient import discovery
|
from apiclient import discovery
|
||||||
from oauth2client import client
|
from oauth2client import client
|
||||||
|
@ -13,25 +42,29 @@ from oauth2client.file import Storage
|
||||||
import icalendar
|
import icalendar
|
||||||
|
|
||||||
|
|
||||||
TIMEDELTA_SYNCHRO = datetime.timedelta(days=7) # Number of days to look for
|
TIMEDELTA_SYNCHRO = datetime.timedelta(days=15) # Number of days to look for
|
||||||
# for synchronization
|
# for synchronization
|
||||||
with open('ntnoe_credentials') as f:
|
|
||||||
NTNOE_ID,NTNOE_PASS,_ = f.read().split('\n')
|
|
||||||
|
|
||||||
|
with open('ntnoe_credentials') as f:
|
||||||
|
NTNOE_ID, NTNOE_PASS, _ = f.read().split('\n')
|
||||||
|
|
||||||
SCOPES = 'https://www.googleapis.com/auth/calendar'
|
SCOPES = 'https://www.googleapis.com/auth/calendar'
|
||||||
CLIENT_SECRET_FILE = 'client_secret.json'
|
CLIENT_SECRET_FILE = 'client_secret.json'
|
||||||
APPLICATION_NAME = 'Google Calendar API Python Quickstart'
|
APPLICATION_NAME = 'Google Calendar API Python Quickstart'
|
||||||
|
|
||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
|
"""
|
||||||
|
The event class allows a simple convertion between `icalendar.cal.Event`
|
||||||
|
and a formatted `dict` for the google API.
|
||||||
|
"""
|
||||||
|
|
||||||
# ColorId corresponding to course code
|
# ColorId corresponding to course code
|
||||||
EVENT_COLOR = {
|
EVENT_COLOR = {
|
||||||
'9' : '9', # Amphi
|
'9': '9', # Amphi
|
||||||
'11' : '10', # TL
|
'11': '10', # TL
|
||||||
'10' : '6', # TD
|
'10': '6', # TD
|
||||||
'13' : '5', # Autre
|
'13': '5', # Autre
|
||||||
'12' : '3', # Exam
|
'12': '3', # Exam
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,28 +74,31 @@ class Event:
|
||||||
self.start = e.decoded('DTSTART')
|
self.start = e.decoded('DTSTART')
|
||||||
self.end = e.decoded('DTEND')
|
self.end = e.decoded('DTEND')
|
||||||
self.location = e.decoded('LOCATION').decode('utf-8')
|
self.location = e.decoded('LOCATION').decode('utf-8')
|
||||||
self.colorid = self.EVENT_COLOR.get(e.decoded('DESCRIPTION').decode('utf-8'), '1')
|
self.colorid = self.EVENT_COLOR.get(
|
||||||
|
e.decoded('DESCRIPTION').decode('utf-8'), '1')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.as_google())
|
return str(self.as_google())
|
||||||
|
|
||||||
def as_google(self):
|
def as_google(self):
|
||||||
|
"""Returns the event as a formatted `dict` for the google API."""
|
||||||
return {
|
return {
|
||||||
'summary' : self.summary,
|
'summary': self.summary,
|
||||||
'location' : self.location,
|
'location': self.location,
|
||||||
'start' : {
|
'start': {
|
||||||
'dateTime' : self.start.isoformat(),
|
'dateTime': self.start.isoformat(),
|
||||||
'timeZone' : 'Europe/Paris',
|
'timeZone': 'Europe/Paris',
|
||||||
},
|
},
|
||||||
'end' : {
|
'end': {
|
||||||
'dateTime' : self.end.isoformat(),
|
'dateTime': self.end.isoformat(),
|
||||||
'timeZone' : 'Europe/Paris',
|
'timeZone': 'Europe/Paris',
|
||||||
},
|
},
|
||||||
'colorId' : self.colorid,
|
'colorId': self.colorid,
|
||||||
'reminders': {
|
'reminders': {
|
||||||
'useDefault': False,
|
'useDefault': False,
|
||||||
'overrides': [],
|
'overrides': [],
|
||||||
},
|
},
|
||||||
|
'description': 'ntnoe_calendar',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,48 +130,58 @@ def get_credentials():
|
||||||
|
|
||||||
|
|
||||||
def get_ntnoe():
|
def get_ntnoe():
|
||||||
url = "http://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{}.ics"
|
"""Retrieves the calendar on NTNOE."""
|
||||||
url = url.format(NTNOE_ID)
|
r = requests.post(
|
||||||
|
|
||||||
data = {'envoyer':'Utf8_All','submit':'Générer'}
|
|
||||||
|
|
||||||
r = requests.get(
|
|
||||||
"https://ntnoe.metz.supelec.fr/ical/index.php",
|
"https://ntnoe.metz.supelec.fr/ical/index.php",
|
||||||
data=urllib.parse.urlencode(data),
|
data={"envoyer":"Utf8_All","submit":"G%E9n%E9rer"},
|
||||||
auth=(NTNOE_ID, NTNOE_PASS),
|
auth=(NTNOE_ID, NTNOE_PASS),
|
||||||
)
|
)
|
||||||
url = "https://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{id}.ics".format(id=NTNOE_ID)
|
|
||||||
r = requests.get(url, auth=(NTNOE_ID, NTNOE_PASS), stream=True)
|
|
||||||
with open("edt_{}.ics".format(NTNOE_ID), 'wb') as f:
|
|
||||||
f.write(r.content)
|
|
||||||
|
|
||||||
|
url = "https://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{}.ics"
|
||||||
|
url = url.format(NTNOE_ID)
|
||||||
|
r = requests.get(url, auth=(NTNOE_ID, NTNOE_PASS))
|
||||||
|
return r.content
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Get the events on NTNOE the puts them on Google Calendar.
|
"""Get the events on NTNOE the puts them on Google Calendar.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
get_ntnoe()
|
|
||||||
credentials = get_credentials()
|
credentials = get_credentials()
|
||||||
http = credentials.authorize(httplib2.Http())
|
http = credentials.authorize(httplib2.Http())
|
||||||
service = discovery.build('calendar', 'v3', http=http)
|
service = discovery.build('calendar', 'v3', http=http)
|
||||||
|
|
||||||
with open("edt_" + NTNOE_ID + ".ics") as f:
|
ical = icalendar.Calendar.from_ical(get_ntnoe())
|
||||||
c = icalendar.Calendar.from_ical(f.read())
|
|
||||||
|
calendars = service.calendarList().list().execute()
|
||||||
|
ntnoe_calendar_id = None
|
||||||
|
for c in calendars['items']:
|
||||||
|
if c['summary'] == 'ntnoe':
|
||||||
|
ntnoe_calendar_id = c['id']
|
||||||
|
|
||||||
|
if not ntnoe_calendar_id:
|
||||||
|
print("Creating ntnoe calendar...")
|
||||||
|
created = service.calendars().insert(body={
|
||||||
|
'defaultReminders' : [],
|
||||||
|
'selected' : True,
|
||||||
|
'summary' : 'ntnoe',
|
||||||
|
}).execute()
|
||||||
|
ntnoe_calendar_id = created['id']
|
||||||
|
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
then = now + TIMEDELTA_SYNCHRO
|
then = now + TIMEDELTA_SYNCHRO
|
||||||
time_search = datetime.datetime(now.year, now.month, now.day, 1)
|
time_search = datetime.datetime(now.year, now.month, now.day, 1)
|
||||||
response = service.events().list(
|
|
||||||
calendarId='primary',
|
former_ones = service.events().list(
|
||||||
timeMin=time_search.isoformat()+'Z',
|
calendarId=ntnoe_calendar_id,
|
||||||
timeMax=then.isoformat()+'Z',
|
|
||||||
).execute()
|
).execute()
|
||||||
|
|
||||||
existing_events = set()
|
for event in former_ones['items']:
|
||||||
for e in response['items']:
|
print('Deleting event : {}'.format(event['id']))
|
||||||
if 'summary' in e.keys():
|
service.events().delete(
|
||||||
existing_events.add(e['summary'])
|
calendarId=ntnoe_calendar_id,
|
||||||
for e in c.walk('VEVENT'):
|
eventId=event['id']
|
||||||
|
).execute()
|
||||||
|
|
||||||
|
for e in ical.walk('VEVENT'):
|
||||||
event = Event(e)
|
event = Event(e)
|
||||||
t = (
|
t = (
|
||||||
event.summary,
|
event.summary,
|
||||||
|
@ -146,15 +192,12 @@ def main():
|
||||||
if now >= event.end or event.start >= then:
|
if now >= event.end or event.start >= then:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if existing_events.intersection({event.summary}):
|
|
||||||
continue
|
|
||||||
|
|
||||||
event = service.events().insert(
|
event = service.events().insert(
|
||||||
calendarId='primary',
|
calendarId=ntnoe_calendar_id,
|
||||||
body=event.as_google()
|
body=event.as_google()
|
||||||
).execute()
|
).execute()
|
||||||
print("Added event : {}".format(event.get('htmlLink')))
|
print("Adding event : {}".format(event['id']))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue