|  |  | @ -29,6 +29,7 @@ if config.get('storage'): | 
			
		
	
		
		
			
				
					
					|  |  |  | notify_chat = config['config']['notify_chat'] |  |  |  | notify_chat = config['config']['notify_chat'] | 
			
		
	
		
		
			
				
					
					|  |  |  | wait_seconds = config['config']['wait_seconds'] |  |  |  | wait_seconds = config['config']['wait_seconds'] | 
			
		
	
		
		
			
				
					
					|  |  |  | channels = config['config']['channels'] |  |  |  | channels = config['config']['channels'] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | invidious_instances = config['config'].get('invidious_instances', []) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | live_regex = re.compile(r'error: (?:ytnotifier:([0-9]+) )?(this live event will begin|premieres) in (.+)', re.I) |  |  |  | live_regex = re.compile(r'error: (?:ytnotifier:([0-9]+) )?(this live event will begin|premieres) in (.+)', re.I) | 
			
		
	
		
		
			
				
					
					|  |  |  | strip_date = re.compile(r' \d{4}-\d{2}-\d{2} \d{2}:\d{2}$') |  |  |  | strip_date = re.compile(r' \d{4}-\d{2}-\d{2} \d{2}:\d{2}$') | 
			
		
	
	
		
		
			
				
					|  |  | @ -97,7 +98,7 @@ async def _handle_video(video_id, video_title): | 
			
		
	
		
		
			
				
					
					|  |  |  |                     elif not last_was_few_moments: |  |  |  |                     elif not last_was_few_moments: | 
			
		
	
		
		
			
				
					
					|  |  |  |                         await client.send_message(notify_chat, f'<b>{"Premiere" if is_premiere else "Live event"} starting in {human_end_schedule_time}:</b> <a href="{video_url}">{html.escape(video_title)}</a>') |  |  |  |                         await client.send_message(notify_chat, f'<b>{"Premiere" if is_premiere else "Live event"} starting in {human_end_schedule_time}:</b> <a href="{video_url}">{html.escape(video_title)}</a>') | 
			
		
	
		
		
			
				
					
					|  |  |  |                 elif not last_was_few_moments: |  |  |  |                 elif not last_was_few_moments: | 
			
		
	
		
		
			
				
					
					|  |  |  |                     await client.send_message(notify_chat, f'<b>{"Premiere" if is_premeire else "Live event"} starting in {human_end_schedule_time}:</b> <a href="{video_url}">{html.escape(video_title)}</a>') |  |  |  |                     await client.send_message(notify_chat, f'<b>{"Premiere" if is_premiere else "Live event"} starting in {human_end_schedule_time}:</b> <a href="{video_url}">{html.escape(video_title)}</a>') | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 last_was_few_moments = 'moment' in human_end_schedule_time.lower() |  |  |  |                 last_was_few_moments = 'moment' in human_end_schedule_time.lower() | 
			
		
	
		
		
			
				
					
					|  |  |  |             await asyncio.sleep(wait_time) |  |  |  |             await asyncio.sleep(wait_time) | 
			
		
	
		
		
			
				
					
					|  |  |  |         else: |  |  |  |         else: | 
			
		
	
	
		
		
			
				
					|  |  | @ -123,6 +124,20 @@ async def handle_video(video_id, video_title): | 
			
		
	
		
		
			
				
					
					|  |  |  |     finally: |  |  |  |     finally: | 
			
		
	
		
		
			
				
					
					|  |  |  |         tmp_handled_videos.discard(video_id) |  |  |  |         tmp_handled_videos.discard(video_id) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | async def get_video_list(session, channel_id): | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     for i in invidious_instances: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         try: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             async with session.get(f'{i}/api/v1/channels/{channel_id}/latest?fields=title,videoId&a={time.time()}', headers={'Cache-Control': 'no-store, max-age=0'}) as resp: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if resp.status != 200: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     logging.error('Invidious instance %s returned %s', i, str(resp.status)) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     continue | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 return list(map(lambda i: (i['videoId'], i['title']), await resp.json())) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         except BaseException: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             logging.exception('Invidious instance %s raised exception', i) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     async with session.get(f'https://www.youtube.com/feeds/videos.xml?channel_id={channel_id}&a={time.time()}', headers={'Cache-Control': 'no-store, max-age=0'}) as resp: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         d = feedparser.parse(await resp.text()) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return list(map(lambda i: (i['yt_videoid'], i['title']), d['entries'])) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | async def main(): |  |  |  | async def main(): | 
			
		
	
		
		
			
				
					
					|  |  |  |     await client.start(bot_token=bot_token) |  |  |  |     await client.start(bot_token=bot_token) | 
			
		
	
		
		
			
				
					
					|  |  |  |     if storage_chat_id and storage_message_id: |  |  |  |     if storage_chat_id and storage_message_id: | 
			
		
	
	
		
		
			
				
					|  |  | @ -149,11 +164,7 @@ async def main(): | 
			
		
	
		
		
			
				
					
					|  |  |  |         while True: |  |  |  |         while True: | 
			
		
	
		
		
			
				
					
					|  |  |  |             for i in channels: |  |  |  |             for i in channels: | 
			
		
	
		
		
			
				
					
					|  |  |  |                 logging.info('Checking %s', i) |  |  |  |                 logging.info('Checking %s', i) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 async with session.get(f'https://www.youtube.com/feeds/videos.xml?channel_id={i}&a={time.time()}', headers={'Cache-Control': 'no-store, max-age=0'}) as resp: |  |  |  |                 for video_id, video_title in await get_video_list(session, i): | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                     d = feedparser.parse(await resp.text()) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 for e in d['entries']: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     video_id = e['yt_videoid'] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     video_title = e['title'] |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                     if video_id not in seen_videos and video_id not in tmp_handled_videos: |  |  |  |                     if video_id not in seen_videos and video_id not in tmp_handled_videos: | 
			
		
	
		
		
			
				
					
					|  |  |  |                         tmp_handled_videos.add(video_id) |  |  |  |                         tmp_handled_videos.add(video_id) | 
			
		
	
		
		
			
				
					
					|  |  |  |                         if loadmode: |  |  |  |                         if loadmode: | 
			
		
	
	
		
		
			
				
					|  |  | 
 |