diff --git a/bot.py b/bot.py
index 462f322..c9d3459 100755
--- a/bot.py
+++ b/bot.py
@@ -1,25 +1,29 @@
#!/usr/bin/env python3
import asyncio
-import os
-import json
import glob
-import traceback
import importlib
-import sys
-import re
-import requests
import json
+import os
+import re
+import sys
+import traceback
import urllib.parse
-from nio import (AsyncClient, RoomMessageText, RoomMessageUnknown, JoinError, InviteEvent)
+
+import requests
+from nio import AsyncClient, InviteEvent, JoinError, RoomMessageText
# Couple of custom exceptions
+
+
class CommandRequiresAdmin(Exception):
pass
+
class CommandRequiresOwner(Exception):
pass
+
class Bot:
appid = 'org.vranki.hemppa'
version = '1.1'
@@ -59,11 +63,12 @@ class Bot:
if not self.is_owner(event):
raise CommandRequiresOwner
- # Returns true if event's sender is admin in the room event was sent in, or is bot owner
+ # Returns true if event's sender is admin in the room event was sent in,
+ # or is bot owner
def is_admin(self, room, event):
if self.is_owner(event):
return True
- if not event.sender in room.power_levels.users:
+ if event.sender not in room.power_levels.users:
return False
return room.power_levels.users[event.sender] >= 50
@@ -77,9 +82,9 @@ class Bot:
if "get_settings" in dir(moduleobject):
try:
module_settings[modulename] = moduleobject.get_settings()
- except:
+ except Exception:
traceback.print_exc(file=sys.stderr)
- data = { self.appid: self.version, 'module_settings': module_settings}
+ data = {self.appid: self.version, 'module_settings': module_settings}
self.set_account_data(data)
def load_settings(self, data):
@@ -91,8 +96,9 @@ class Bot:
if data['module_settings'].get(modulename):
if "set_settings" in dir(moduleobject):
try:
- moduleobject.set_settings(data['module_settings'][modulename])
- except:
+ moduleobject.set_settings(
+ data['module_settings'][modulename])
+ except Exception:
traceback.print_exc(file=sys.stderr)
async def message_cb(self, room, event):
@@ -114,7 +120,7 @@ class Bot:
await self.send_text(room, f'Sorry, you need admin power level in this room to run that command.')
except CommandRequiresOwner:
await self.send_text(room, f'Sorry, only bot owner can run that command.')
- except:
+ except Exception:
await self.send_text(room, f'Module {command} experienced difficulty: {sys.exc_info()[0]} - see log for details')
traceback.print_exc(file=sys.stderr)
@@ -124,12 +130,13 @@ class Bot:
result = await self.client.join(room.room_id)
if type(result) == JoinError:
print(f"Error joining room {room.room_id} (attempt %d): %s",
- attempt, result.message,
- )
+ attempt, result.message,
+ )
else:
break
else:
- print(f'Received invite event, but not joining as sender is not owner or bot not configured to join on invite. {event}')
+ print(
+ f'Received invite event, but not joining as sender is not owner or bot not configured to join on invite. {event}')
def load_module(self, modulename):
try:
@@ -157,7 +164,7 @@ class Bot:
if "matrix_poll" in dir(moduleobject):
try:
await moduleobject.matrix_poll(bot, self.pollcount)
- except:
+ except Exception:
traceback.print_exc(file=sys.stderr)
await asyncio.sleep(10)
@@ -178,16 +185,18 @@ class Bot:
response = requests.get(ad_url)
if response.status_code == 200:
return response.json()
- print(f'Getting account data failed: {response} {response.json()} - this is normal if you have not saved any settings yet.')
+ print(
+ f'Getting account data failed: {response} {response.json()} - this is normal if you have not saved any settings yet.')
return None
def init(self):
- self.client = AsyncClient(os.environ['MATRIX_SERVER'], os.environ['MATRIX_USER'])
+ self.client = AsyncClient(
+ os.environ['MATRIX_SERVER'], os.environ['MATRIX_USER'])
self.client.access_token = os.getenv('MATRIX_ACCESS_TOKEN')
self.join_on_invite = os.getenv("JOIN_ON_INVITE") is not None
self.owners = os.environ['BOT_OWNERS'].split(',')
self.get_modules()
-
+
def stop(self):
print(f'Stopping {len(self.modules)} modules..')
for modulename, moduleobject in self.modules.items():
@@ -195,13 +204,14 @@ class Bot:
if "matrix_stop" in dir(moduleobject):
try:
moduleobject.matrix_stop(bot)
- except:
+ except Exception:
traceback.print_exc(file=sys.stderr)
async def run(self):
if not self.client.access_token:
await self.client.login(os.environ['MATRIX_PASSWORD'])
- print("Logged in with password, access token:", self.client.access_token)
+ print("Logged in with password, access token:",
+ self.client.access_token)
await self.client.sync()
@@ -211,7 +221,7 @@ class Bot:
if "matrix_start" in dir(moduleobject):
try:
moduleobject.matrix_start(bot)
- except:
+ except Exception:
traceback.print_exc(file=sys.stderr)
self.poll_task = asyncio.get_event_loop().create_task(self.poll_timer())
diff --git a/modules/cron.py b/modules/cron.py
index 8f0566f..af7fd2b 100644
--- a/modules/cron.py
+++ b/modules/cron.py
@@ -1,13 +1,14 @@
import shlex
from datetime import datetime
+
class MatrixModule:
- daily_commands = dict() # room_id -> command json
+ daily_commands = dict() # room_id -> command json
last_hour = datetime.now().hour
async def matrix_message(self, bot, room, event):
bot.must_be_admin(room, event)
-
+
args = shlex.split(event.body)
args.pop(0)
if len(args) == 3:
@@ -16,7 +17,8 @@ class MatrixModule:
dailycmd = args[2]
if not self.daily_commands.get(room.room_id):
self.daily_commands[room.room_id] = []
- self.daily_commands[room.room_id].append({ 'time': dailytime, 'command': dailycmd })
+ self.daily_commands[room.room_id].append(
+ {'time': dailytime, 'command': dailycmd})
bot.save_settings()
await bot.send_text(room, 'Daily command added.')
elif len(args) == 1:
@@ -31,7 +33,7 @@ class MatrixModule:
return('Runs scheduled commands')
def get_settings(self):
- return { 'daily_commands': self.daily_commands }
+ return {'daily_commands': self.daily_commands}
def set_settings(self, data):
if data.get('daily_commands'):
diff --git a/modules/googlecal.py b/modules/googlecal.py
index 6a37460..45790b5 100644
--- a/modules/googlecal.py
+++ b/modules/googlecal.py
@@ -1,16 +1,13 @@
from __future__ import print_function
-from datetime import datetime
-import datetime
-import pickle
-import os.path
-import time
+
import os
+import os.path
+import pickle
+from datetime import datetime
-from googleapiclient.discovery import build
-from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
-
-
+from google_auth_oauthlib.flow import InstalledAppFlow
+from googleapiclient.discovery import build
#
# Google calendar notifications
@@ -20,18 +17,19 @@ from google.auth.transport.requests import Request
# can be copied to another computer.
#
+
class MatrixModule:
def matrix_start(self, bot):
self.bot = bot
self.SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
self.credentials_file = "credentials.json"
self.service = None
- self.calendar_rooms = dict() # Contains room_id -> [calid, calid] ..
+ self.calendar_rooms = dict() # Contains room_id -> [calid, calid] ..
creds = None
if not os.path.exists(self.credentials_file) or os.path.getsize(self.credentials_file) == 0:
- return # No-op if not set up
+ return # No-op if not set up
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
@@ -45,7 +43,8 @@ class MatrixModule:
else:
flow = InstalledAppFlow.from_client_secrets_file(
self.credentials_file, self.SCOPES)
- creds = flow.run_local_server(port=0) # urn:ietf:wg:oauth:2.0:oob
+ # urn:ietf:wg:oauth:2.0:oob
+ creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
@@ -54,14 +53,15 @@ class MatrixModule:
self.service = build('calendar', 'v3', credentials=creds)
try:
- calendar_list = self.service.calendarList().list().execute()['items']
- print(f'Google calendar set up successfully with access to {len(calendar_list)} calendars:\n')
+ calendar_list = self.service.calendarList().list().execute()[
+ 'items']
+ print(
+ f'Google calendar set up successfully with access to {len(calendar_list)} calendars:\n')
for calendar in calendar_list:
print(calendar['summary'] + ' - ' + calendar['id'])
- except:
+ except Exception:
print('Getting calendar list failed!')
-
async def matrix_message(self, bot, room, event):
if not self.service:
await bot.send_text(room, 'Google calendar not set up for this bot.')
@@ -95,7 +95,8 @@ class MatrixModule:
else:
self.calendar_rooms[room.room_id] = [calid]
- print(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
+ print(
+ f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
@@ -111,7 +112,8 @@ class MatrixModule:
if self.calendar_rooms.get(room.room_id):
self.calendar_rooms[room.room_id].remove(calid)
- print(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
+ print(
+ f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
@@ -141,28 +143,29 @@ class MatrixModule:
startTime = datetime.datetime.utcnow()
now = startTime.isoformat() + 'Z'
events_result = self.service.events().list(calendarId=calid, timeMin=now,
- maxResults=10, singleEvents=True,
- orderBy='startTime').execute()
+ maxResults=10, singleEvents=True,
+ orderBy='startTime').execute()
events = events_result.get('items', [])
return events
def list_today(self, calid):
startTime = datetime.datetime.utcnow()
- startTime = startTime.replace(hour = 0, minute = 0, second = 0, microsecond=0)
+ startTime = startTime.replace(
+ hour=0, minute=0, second=0, microsecond=0)
endTime = startTime + datetime.timedelta(hours=24)
now = startTime.isoformat() + 'Z'
end = endTime.isoformat() + 'Z'
print('Looking for events between', now, end)
events_result = self.service.events().list(calendarId=calid, timeMin=now,
- timeMax=end, maxResults=10, singleEvents=True,
- orderBy='startTime').execute()
+ timeMax=end, maxResults=10, singleEvents=True,
+ orderBy='startTime').execute()
return events_result.get('items', [])
def help(self):
return('Google calendar. Lists 10 next events by default. today = list today\'s events.')
def get_settings(self):
- return { 'calendar_rooms': self.calendar_rooms }
+ return {'calendar_rooms': self.calendar_rooms}
def set_settings(self, data):
if data.get('calendar_rooms'):
diff --git a/modules/ig.py b/modules/ig.py
index 347664a..7ee1cec 100644
--- a/modules/ig.py
+++ b/modules/ig.py
@@ -1,14 +1,17 @@
-from igramscraper.instagram import Instagram
-from igramscraper.exception.instagram_not_found_exception import InstagramNotFoundException
from datetime import datetime, timedelta
from random import randrange
+from igramscraper.exception.instagram_not_found_exception import \
+ InstagramNotFoundException
+from igramscraper.instagram import Instagram
+
+
class MatrixModule:
instagram = Instagram()
known_ids = set()
- account_rooms = dict() # Roomid -> [account, account..]
- next_poll_time = dict() # Roomid -> datetime, None = not polled yet
+ account_rooms = dict() # Roomid -> [account, account..]
+ next_poll_time = dict() # Roomid -> datetime, None = not polled yet
async def matrix_poll(self, bot, pollcount):
if len(self.account_rooms):
@@ -27,7 +30,8 @@ class MatrixModule:
try:
await self.poll_account(bot, account, roomid, send_messages)
except InstagramNotFoundException:
- print('ig error: there is ', account, ' account that does not exist - deleting from room')
+ print('ig error: there is ', account,
+ ' account that does not exist - deleting from room')
self.account_rooms[roomid].remove(account)
bot.save_settings()
@@ -77,7 +81,8 @@ class MatrixModule:
else:
self.account_rooms[room.room_id] = [account]
- print(f'Accounts now for this room {self.account_rooms.get(room.room_id)}')
+ print(
+ f'Accounts now for this room {self.account_rooms.get(room.room_id)}')
try:
await self.poll_account(bot, account, room.room_id, False)
@@ -91,18 +96,20 @@ class MatrixModule:
bot.must_be_admin(room, event)
account = args[2]
- print(f'Removing account {account} from room id {room.room_id}')
+ print(
+ f'Removing account {account} from room id {room.room_id}')
if self.account_rooms.get(room.room_id):
self.account_rooms[room.room_id].remove(account)
- print(f'Accounts now for this room {self.account_rooms.get(room.room_id)}')
+ print(
+ f'Accounts now for this room {self.account_rooms.get(room.room_id)}')
bot.save_settings()
await bot.send_text(room, 'Removed instagram account from this room')
def get_settings(self):
- return { 'account_rooms': self.account_rooms }
+ return {'account_rooms': self.account_rooms}
def set_settings(self, data):
if data.get('account_rooms'):
diff --git a/modules/loc.py b/modules/loc.py
index a7cc85c..cced6af 100644
--- a/modules/loc.py
+++ b/modules/loc.py
@@ -1,8 +1,10 @@
from geopy.geocoders import Nominatim
-from nio import (RoomMessageUnknown)
+from nio import RoomMessageUnknown
+
class MatrixModule:
bot = None
+
def matrix_start(self, bot):
self.bot = bot
bot.client.add_event_callback(self.unknown_cb, RoomMessageUnknown)
@@ -26,8 +28,9 @@ class MatrixModule:
float(latlon[0])
float(latlon[1])
- osm_link = 'https://www.openstreetmap.org/?mlat=' + latlon[0] + "&mlon=" + latlon[1]
-
+ osm_link = 'https://www.openstreetmap.org/?mlat=' + \
+ latlon[0] + "&mlon=" + latlon[1]
+
plain = sender + ' 🚩 ' + osm_link
html = f'{sender} 🚩 {location_text}'
diff --git a/modules/metar.py b/modules/metar.py
index 11f5db9..ad94d15 100644
--- a/modules/metar.py
+++ b/modules/metar.py
@@ -1,13 +1,13 @@
-import subprocess
-import os
import urllib.request
+
class MatrixModule:
async def matrix_message(self, bot, room, event):
args = event.body.split()
if len(args) == 2:
icao = args[1]
- metar_url = "https://tgftp.nws.noaa.gov/data/observations/metar/stations/" + icao.upper() + ".TXT"
+ metar_url = "https://tgftp.nws.noaa.gov/data/observations/metar/stations/" + \
+ icao.upper() + ".TXT"
response = urllib.request.urlopen(metar_url)
lines = response.readlines()
await bot.send_text(room, lines[1].decode("utf-8").strip())
diff --git a/modules/taf.py b/modules/taf.py
index 35d4fe2..5704f77 100644
--- a/modules/taf.py
+++ b/modules/taf.py
@@ -1,6 +1,6 @@
-import os
import urllib.request
+
class MatrixModule:
async def matrix_message(self, bot, room, event):
args = event.body.split()
@@ -16,6 +16,6 @@ class MatrixModule:
await bot.send_text(room, 'Cannot find taf for ' + icao)
else:
await bot.send_text(room, 'Usage: !taf ')
-
+
def help(self):
return('Taf data access (usage: !taf )')
diff --git a/modules/teamup.py b/modules/teamup.py
index 1a68a25..eddfbde 100644
--- a/modules/teamup.py
+++ b/modules/teamup.py
@@ -1,20 +1,22 @@
-from pyteamup import Calendar, Event
-from datetime import datetime
import time
-import os
+from datetime import datetime
+
+from pyteamup import Calendar
#
# TeamUp calendar notifications
#
+
+
class MatrixModule:
api_key = None
- calendar_rooms = dict() # Roomid -> [calid, calid..]
- calendars = dict() # calid -> Calendar
+ calendar_rooms = dict() # Roomid -> [calid, calid..]
+ calendars = dict() # calid -> Calendar
async def matrix_poll(self, bot, pollcount):
if self.api_key:
- if pollcount % (6 * 5) == 0: # Poll every 5 min
- await self.poll_all_calendars(bot)
+ if pollcount % (6 * 5) == 0: # Poll every 5 min
+ await self.poll_all_calendars(bot)
async def matrix_message(self, bot, room, event):
args = event.body.split()
@@ -24,10 +26,14 @@ class MatrixModule:
calendar = self.calendars[calendarid]
events = calendar.get_event_collection()
for event in events:
- s = '' + str(event.start_dt.day) + '.' + str(event.start_dt.month)
+ s = '' + str(event.start_dt.day) + \
+ '.' + str(event.start_dt.month)
if not event.all_day:
- s = s + ' ' + event.start_dt.strftime("%H:%M") + ' (' + str(event.duration) + ' min)'
- s = s + ' ' + event.title + " " + (event.notes or '')
+ s = s + ' ' + \
+ event.start_dt.strftime(
+ "%H:%M") + ' (' + str(event.duration) + ' min)'
+ s = s + ' ' + event.title + \
+ " " + (event.notes or '')
await bot.send_html(room, s, s)
elif len(args) == 2:
if args[1] == 'list':
@@ -51,7 +57,8 @@ class MatrixModule:
else:
self.calendar_rooms[room.room_id] = [calid]
- print(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
+ print(
+ f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
self.setup_calendars()
@@ -65,7 +72,8 @@ class MatrixModule:
if self.calendar_rooms.get(room.room_id):
self.calendar_rooms[room.room_id].remove(calid)
- print(f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
+ print(
+ f'Calendars now for this room {self.calendar_rooms.get(room.room_id)}')
bot.save_settings()
self.setup_calendars()
@@ -85,12 +93,12 @@ class MatrixModule:
for roomid in self.calendar_rooms:
calendars = self.calendar_rooms[roomid]
for calendarid in calendars:
- events, timestamp = self.poll_server(self.calendars[calendarid])
+ events, timestamp = self.poll_server(
+ self.calendars[calendarid])
self.calendars[calendarid].timestamp = timestamp
for event in events:
await bot.send_text(bot.get_room_by_id(roomid), 'Calendar: ' + self.eventToString(event))
-
def poll_server(self, calendar):
events, timestamp = calendar.get_changed_events(calendar.timestamp)
return events, timestamp
@@ -111,9 +119,12 @@ class MatrixModule:
if(event['delete_dt']):
s = event['title'] + ' deleted.'
else:
- s = event['title'] + " " + (event['notes'] or '') + ' ' + str(startdt.day) + '.' + str(startdt.month)
+ s = event['title'] + " " + (event['notes'] or '') + \
+ ' ' + str(startdt.day) + '.' + str(startdt.month)
if not event['all_day']:
- s = s + ' ' + startdt.strftime("%H:%M") + ' (' + str(event['duration']) + ' min)'
+ s = s + ' ' + \
+ startdt.strftime("%H:%M") + \
+ ' (' + str(event['duration']) + ' min)'
return s
def setup_calendars(self):
@@ -126,13 +137,13 @@ class MatrixModule:
self.calendars[calid].timestamp = int(time.time())
def get_settings(self):
- return { 'apikey': self.api_key or '', 'calendar_rooms': self.calendar_rooms }
+ return {'apikey': self.api_key or '', 'calendar_rooms': self.calendar_rooms}
def set_settings(self, data):
if data.get('calendar_rooms'):
self.calendar_rooms = data['calendar_rooms']
if data.get('apikey'):
self.api_key = data['apikey']
- if self.api_key and len(self.api_key)==0:
+ if self.api_key and len(self.api_key) == 0:
self.api_key = None
self.setup_calendars()
diff --git a/modules/uptime.py b/modules/uptime.py
index 4317c82..04495c5 100644
--- a/modules/uptime.py
+++ b/modules/uptime.py
@@ -1,5 +1,6 @@
import time
+
class MatrixModule:
def matrix_start(self, bot):
self.starttime = time.time()