|  |  |  | @ -4,6 +4,8 @@ import requests | 
		
	
		
			
				|  |  |  |  | import re | 
		
	
		
			
				|  |  |  |  | from bs4 import BeautifulSoup | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | import asyncio | 
		
	
		
			
				|  |  |  |  | from nio import ClientConfig, AsyncClient, LoginResponse, InviteEvent | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | def get_accesstoken_from_file(accesstoken_path): | 
		
	
	
		
			
				
					|  |  |  | @ -12,6 +14,11 @@ def get_accesstoken_from_file(accesstoken_path): | 
		
	
		
			
				|  |  |  |  |     accesstoken_file.close() | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return single_accesstoken | 
		
	
		
			
				|  |  |  |  | async def on_event(room, event): | 
		
	
		
			
				|  |  |  |  |     if hasattr(event, 'membership'): | 
		
	
		
			
				|  |  |  |  |         if event.membership == 'invite': | 
		
	
		
			
				|  |  |  |  |             # automatically join invites | 
		
	
		
			
				|  |  |  |  |             await matrix[event.source['state_key']].join(room.room_id) | 
		
	
		
			
				|  |  |  |  | def get_blog(): | 
		
	
		
			
				|  |  |  |  |     url = 'https://news.blizzard.com/en-us/' | 
		
	
		
			
				|  |  |  |  |     html = requests.get(url).text | 
		
	
	
		
			
				
					|  |  |  | @ -57,7 +64,7 @@ def get_blog(): | 
		
	
		
			
				|  |  |  |  | def get_body(post): | 
		
	
		
			
				|  |  |  |  |     body = post['title']+"\n" | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if post['description'] != '': | 
		
	
		
			
				|  |  |  |  |     if post['description']: | 
		
	
		
			
				|  |  |  |  |         body += post['description']+"\n" | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     body += post['url'] | 
		
	
	
		
			
				
					|  |  |  | @ -68,22 +75,95 @@ def get_formatted_body(post): | 
		
	
		
			
				|  |  |  |  |     formatted_body += '<h5>'+post['title']+'</h5>' | 
		
	
		
			
				|  |  |  |  |     formatted_body += '</a>' | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if post['description'] != '': | 
		
	
		
			
				|  |  |  |  |     if post['description']: | 
		
	
		
			
				|  |  |  |  |         formatted_body += '<p>'+post['description']+'</p>' | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     formatted_body += post['url'] | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     return formatted_body | 
		
	
		
			
				|  |  |  |  | async def main(): | 
		
	
		
			
				|  |  |  |  |     next_batch = {} | 
		
	
		
			
				|  |  |  |  |     for game in device: | 
		
	
		
			
				|  |  |  |  |         # initialize new client | 
		
	
		
			
				|  |  |  |  |         mxid = '@'+mxid_prefix+game+':'+homeserver_name | 
		
	
		
			
				|  |  |  |  |         config = ClientConfig(store_sync_tokens=True) | 
		
	
		
			
				|  |  |  |  |         matrix[mxid] = AsyncClient(homeserver_url, | 
		
	
		
			
				|  |  |  |  |                                   config=config) | 
		
	
		
			
				|  |  |  |  |          | 
		
	
		
			
				|  |  |  |  |         # login | 
		
	
		
			
				|  |  |  |  |         login_response = LoginResponse(mxid, | 
		
	
		
			
				|  |  |  |  |                                        device[game]['id'], | 
		
	
		
			
				|  |  |  |  |                                        device[game]['accesstoken']) | 
		
	
		
			
				|  |  |  |  |         await matrix[mxid].receive_response(login_response) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         matrix[mxid].add_event_callback(on_event, InviteEvent) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |         # do a first sync | 
		
	
		
			
				|  |  |  |  |         sync_filter = { | 
		
	
		
			
				|  |  |  |  |             'room': { | 
		
	
		
			
				|  |  |  |  |                 'state': { | 
		
	
		
			
				|  |  |  |  |                     'types': ['m.room.member'], | 
		
	
		
			
				|  |  |  |  |                     'lazy_load_members': True | 
		
	
		
			
				|  |  |  |  |                 }, | 
		
	
		
			
				|  |  |  |  |                 'timeline': { | 
		
	
		
			
				|  |  |  |  |                     'types': ['invalid'] | 
		
	
		
			
				|  |  |  |  |                 }, | 
		
	
		
			
				|  |  |  |  |                 'ephemeral': { | 
		
	
		
			
				|  |  |  |  |                     'types': ['invalid'] | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         next_batch_state = await matrix[mxid].room_get_state_event(admin_room, | 
		
	
		
			
				|  |  |  |  |                                                                    event_type, | 
		
	
		
			
				|  |  |  |  |                                                                    mxid) | 
		
	
		
			
				|  |  |  |  |         if 'token' in next_batch_state.content: | 
		
	
		
			
				|  |  |  |  |             try: | 
		
	
		
			
				|  |  |  |  |                 sync = await matrix[mxid].sync(timeout=30000, | 
		
	
		
			
				|  |  |  |  |                                                sync_filter=sync_filter, | 
		
	
		
			
				|  |  |  |  |                                                since=next_batch_state.content['token']) | 
		
	
		
			
				|  |  |  |  |                 next_batch[mxid] = sync.next_batch | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |                 continue | 
		
	
		
			
				|  |  |  |  |             except: | 
		
	
		
			
				|  |  |  |  |                 pass | 
		
	
		
			
				|  |  |  |  |         # when there is no next_batch token or first sync threw an error, | 
		
	
		
			
				|  |  |  |  |         # then do a first sync without next_batch | 
		
	
		
			
				|  |  |  |  |         sync = await matrix[mxid].sync(timeout=30000, | 
		
	
		
			
				|  |  |  |  |                                        sync_filter=sync_filter) | 
		
	
		
			
				|  |  |  |  |         next_batch[mxid] = sync.next_batch | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     while True: | 
		
	
		
			
				|  |  |  |  |         for mxid in next_batch: | 
		
	
		
			
				|  |  |  |  |             sync = await matrix[mxid].sync(timeout=30000, | 
		
	
		
			
				|  |  |  |  |                                            sync_filter=sync_filter, | 
		
	
		
			
				|  |  |  |  |                                            since=next_batch[mxid]) | 
		
	
		
			
				|  |  |  |  |             next_batch[mxid] = sync.next_batch | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |             await matrix[mxid].room_put_state(room_id=admin_room, | 
		
	
		
			
				|  |  |  |  |                                               event_type=event_type, | 
		
	
		
			
				|  |  |  |  |                                               state_key=mxid, | 
		
	
		
			
				|  |  |  |  |                                               content={'token': next_batch[mxid]}) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | homeserver = environ['HOMESERVER_URL'] | 
		
	
		
			
				|  |  |  |  | mxid = environ['MXID_PREFIX'] | 
		
	
		
			
				|  |  |  |  | homeserver_name = environ['HOMESERVER_NAME'] | 
		
	
		
			
				|  |  |  |  | homeserver_url = environ['HOMESERVER_URL'] | 
		
	
		
			
				|  |  |  |  | mxid_prefix = environ['MXID_PREFIX'] | 
		
	
		
			
				|  |  |  |  | admin_room = environ['ADMIN_ROOM'] | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | accesstoken = {} | 
		
	
		
			
				|  |  |  |  | for key in environ: | 
		
	
		
			
				|  |  |  |  |     if (game := re.match('^ACCESSTOKEN_([A-Z]*)_FILE$', key)) is not None: | 
		
	
		
			
				|  |  |  |  |         accesstoken[game[1].lower()] = get_accesstoken_from_file(environ[key]) | 
		
	
		
			
				|  |  |  |  | device = {} | 
		
	
		
			
				|  |  |  |  | for var in environ: | 
		
	
		
			
				|  |  |  |  |     if (game := re.match('^DEVICEID_([A-Z]*)$', var)) is not None: | 
		
	
		
			
				|  |  |  |  |         device[game[1].lower()] = {'id': environ[var]} | 
		
	
		
			
				|  |  |  |  | for var in environ: | 
		
	
		
			
				|  |  |  |  |     if (game := re.match('^ACCESSTOKEN_([A-Z]*)_FILE$', var)) is not None: | 
		
	
		
			
				|  |  |  |  |         device[game[1].lower()]['accesstoken'] = get_accesstoken_from_file(environ[var]) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | event_type = 'de.lubiland.snowstorm-matrix.next_batch' | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | matrix = {} | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | asyncio.run(main()) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | blog = get_blog() | 
		
	
	
		
			
				
					|  |  |  | 
 |