# # YouTube video info command # # Copyright © 2023 by luk3yx # # This program 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. # # This program 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 this program. If not, see . # import math, requests, random, time, traceback # Default values so that the command still works if api.invidious.io is down cache_expiry = -math.inf instances = ['yewtu.be'] api_instances = ['i.psf.lt'] def fetch_instances(irc, args): global cache_expiry, instances, api_instances # Refresh the cache at most once per day if time.monotonic() >= cache_expiry or not instances or not api_instances: try: resp = requests.get('https://api.invidious.io/instances.json') resp.raise_for_status() new_instances = [] new_api_instances = [] for _, info in resp.json(): if (info['type'] != 'https' or not info.get('stats') or not info['stats'].get('openRegistrations')): continue new_instances.append(info['uri']) if info['api']: new_api_instances.append(info['uri']) if new_instances and new_api_instances: cache_expiry = time.monotonic() + 86400 instances = new_instances api_instances = new_api_instances except (requests.RequestException, IndexError, ValueError) as exc: # This is okay, just use the cache for now traceback.print_exc() irc.notice(args[0], f'{exc.__class__.__name__} when fetching ' f'Invidious instance list, using cache.') return instances, api_instances RED = '\x0304' GREEN = '\x0303' def get_url_and_metadata(irc, args, video_id): instances, api_instances = fetch_instances(irc, args) api_url = f'{random.choice(api_instances)}' res = requests.get(f'{api_url}/api/v1/videos/{video_id}', params={ 'fields': 'title,liveNow,lengthSeconds,author,publishedText,error' }) return f'{random.choice(instances)}/watch?v={video_id}', res.json() def format_length(seconds): minutes = seconds // 60 seconds %= 60 if minutes < 60: return f'{minutes}:{seconds:02}' return f'{minutes // 60}:{minutes % 60:02}:{seconds % 60:02}' def num(n): precision = 0 for prefix in ('', ' K', ' M'): if n < 1000: return f'\x02{n:.{precision}f}{prefix}\x02' n /= 1000 precision = 1 return f'\x02{n:.{precision}f} B\x02' @register_command('yt', 'youtube') def youtube(irc, hostmask, is_admin, args): video_url = args[1] if 'v=' in video_url: video_id = video_url.split('v=', 1)[1] elif '/shorts/' in video_url: video_id = video_url.split('/shorts/', 1)[1] elif video_url.startswith(('youtu.be/', 'https://youtu.be/', 'http://youtu.be/')): video_id = video_url.split('youtu.be/', 1)[1] else: irc.msg(args[0], 'Usage: .yt