__version__ = (1, 0, 0) # ███╗░░░███╗███████╗░█████╗░██████╗░░█████╗░░██╗░░░░░░░██╗░██████╗░██████╗ # ████╗░████║██╔════╝██╔══██╗██╔══██╗██╔══██╗░██║░░██╗░░██║██╔════╝██╔════╝ # ██╔████╔██║█████╗░░███████║██║░░██║██║░░██║░╚██╗████╗██╔╝╚█████╗░╚█████╗░ # ██║╚██╔╝██║██╔══╝░░██╔══██║██║░░██║██║░░██║░░████╔═████║░░╚═══██╗░╚═══██╗ # ██║░╚═╝░██║███████╗██║░░██║██████╔╝╚█████╔╝░░╚██╔╝░╚██╔╝░██████╔╝██████╔╝ # ╚═╝░░░░░╚═╝╚══════╝╚═╝░░╚═╝╚═════╝░░╚════╝░░░░╚═╝░░░╚═╝░░╚═════╝░╚═════╝░ # © Copyright 2025 # ✈ https://t.me/mead0wssMods # scope: hikka_only # scope: hikka_min 1.3.3 # meta developer: @mead0wssMods import aiohttp from .. import loader, utils @loader.tds class TwitchMod(loader.Module): """Модуль для работы с Twitch""" strings = {"name": "Twitch"} def __init__(self): self.config = loader.ModuleConfig( loader.ConfigValue( "CLIENT_ID", "", lambda: "Client ID из Twitch Dev Console [https://dev.twitch.tv/console/]", validator=loader.validators.Hidden() ), loader.ConfigValue( "ACCESS_TOKEN", "", lambda: "Access Token с scope user:read:follows [https://twitchtokengenerator.com/]", validator=loader.validators.Hidden() ), loader.ConfigValue( "TARGET_USERNAME", "", lambda: "Ваш никнейм пользователя Twitch [https://www.twitch.tv/", validator=loader.validators.Hidden() ), ) self.session = aiohttp.ClientSession() async def client_ready(self, client, db): self._client = client async def get_user_id(self, username=None): """Получаем ID пользователя""" url = "https://api.twitch.tv/helix/users" headers = { "Client-ID": self.config["CLIENT_ID"], "Authorization": f"Bearer {self.config['ACCESS_TOKEN']}" } params = {"login": username or self.config["TARGET_USERNAME"]} async with self.session.get(url, headers=headers, params=params) as resp: data = await resp.json() return data["data"][0]["id"] if data.get("data") else None async def get_all_followed(self, user_id): """Получаем всех подписанных стримеров""" url = "https://api.twitch.tv/helix/channels/followed" headers = { "Client-ID": self.config["CLIENT_ID"], "Authorization": f"Bearer {self.config['ACCESS_TOKEN']}" } params = {"user_id": user_id} async with self.session.get(url, headers=headers, params=params) as resp: data = await resp.json() return data.get("data", []) async def get_live_streams(self, logins=None, game_id=None, limit=100): """Получаем онлайн стримы""" url = "https://api.twitch.tv/helix/streams" headers = { "Client-ID": self.config["CLIENT_ID"], "Authorization": f"Bearer {self.config['ACCESS_TOKEN']}" } params = {"first": limit} if logins: params["user_login"] = logins[:100] if game_id: params["game_id"] = game_id async with self.session.get(url, headers=headers, params=params) as resp: data = await resp.json() return data.get("data", []) async def get_top_games(self, limit=10): """Получаем топ игр""" url = "https://api.twitch.tv/helix/games/top" headers = { "Client-ID": self.config["CLIENT_ID"], "Authorization": f"Bearer {self.config['ACCESS_TOKEN']}" } params = {"first": limit} async with self.session.get(url, headers=headers, params=params) as resp: data = await resp.json() return data.get("data", []) async def search_games(self, query): """Поиск игр по названию""" url = "https://api.twitch.tv/helix/search/categories" headers = { "Client-ID": self.config["CLIENT_ID"], "Authorization": f"Bearer {self.config['ACCESS_TOKEN']}" } params = {"query": query} async with self.session.get(url, headers=headers, params=params) as resp: data = await resp.json() return data.get("data", []) async def get_channel_info(self, broadcaster_id): """Получаем информацию о канале""" url = "https://api.twitch.tv/helix/channels" headers = { "Client-ID": self.config["CLIENT_ID"], "Authorization": f"Bearer {self.config['ACCESS_TOKEN']}" } params = {"broadcaster_id": broadcaster_id} async with self.session.get(url, headers=headers, params=params) as resp: data = await resp.json() return data.get("data", [{}])[0] async def get_channel_followers(self, broadcaster_id): """Получаем количество фолловеров канала""" url = "https://api.twitch.tv/helix/channels/followers" headers = { "Client-ID": self.config["CLIENT_ID"], "Authorization": f"Bearer {self.config['ACCESS_TOKEN']}" } params = {"broadcaster_id": broadcaster_id, "first": 1} async with self.session.get(url, headers=headers, params=params) as resp: data = await resp.json() return data.get("total", 0) @loader.command() async def followed(self, message): """Показать всех подписанных стримеров""" user_id = await self.get_user_id() if not user_id: await utils.answer(message, " Пользователь не найден!") return followed = await self.get_all_followed(user_id) if not followed: await utils.answer(message, "🤷‍♂️ Нет подписок") return text = "🎮 Каналы на которые зафолловлен:\n\n" for channel in followed[:25]: followers_count = await self.get_channel_followers(channel["broadcaster_id"]) text += (f"📷 " f"{channel['broadcaster_name']} [👥 {followers_count} Фолловеров]\n") if len(followed) > 25: text += f"\n...и еще {len(followed) - 25} стримеров" await utils.answer(message, text) @loader.command() async def streams(self, message): """Показать онлайн стримы""" user_id = await self.get_user_id() if not user_id: await utils.answer(message, " Пользователь не найден!") return followed = await self.get_all_followed(user_id) if not followed: await utils.answer(message, "🤷‍♂️ Нет подписок") return logins = [channel["broadcaster_login"] for channel in followed] live_streams = await self.get_live_streams(logins[:100]) if not live_streams: await utils.answer(message, "🔴 Сейчас никто не стримит") return text = "🎮 Стримеры ведущие трансляцию:\n" for stream in live_streams: channel_info = await self.get_channel_info(stream["user_id"]) followers_count = await self.get_channel_followers(stream["user_id"]) text += (f'\n👤 {stream["user_name"]}' f'
🎮 {stream["game_name"]}\n' f'👁 {stream["viewer_count"]} зрителей\n' f'👥 {followers_count} фолловеров\n' f'ℹ️ {stream["title"]}\n
') await utils.answer(message, text) @loader.command() async def streamer(self, message): """Информация о стримере""" args = utils.get_args_raw(message) if not args: await utils.answer(message, " Укажите ник стримера") return user_id = await self.get_user_id(args) if not user_id: await utils.answer(message, f" Стример {args} не найден") return channel_info = await self.get_channel_info(user_id) followers_count = await self.get_channel_followers(user_id) text = (f"🎮 Информация о:\n\n 👤 {args}:\n" f"
👥 Фолловеров: {followers_count}\n" f"ℹ️ Описание стрима (пусто = офф): {channel_info.get('title', 'Нет описания')}\n" f"
🎮 Игра на стриме: {channel_info.get('game_name', 'Не указана')} \n" f"🔗 Ссылка: https://twitch.tv/{args}
") await utils.answer(message, text) @loader.command() async def topgames(self, message): """Топ игр на Twitch""" games = await self.get_top_games(10) if not games: await utils.answer(message, " Не удалось получить список игр") return text = "🎮 Топ игр на Twitch:\n\n" text += "\n".join( f"
{i+1}. {game['name']} (ID: {game['id']})
" for i, game in enumerate(games)) await utils.answer(message, text) @loader.command() async def game(self, message): """Поиск игры и стримы по ней""" args = utils.get_args_raw(message) if not args: await utils.answer(message, " Укажите название игры") return games = await self.search_games(args) if not games: await utils.answer(message, f" Игра '{args}' не найдена") return game = games[0] streams = await self.get_live_streams(game_id=game["id"]) text = (f"🎮 Игра: {game['name']}\n" f"🔗 Изображение: {game['box_art_url'].replace('{width}x{height}', '300x400')}\n\n") if streams: text += f"🎮 Топ стримов ({len(streams)} онлайн):\n\n" for stream in streams[:5]: followers_count = await self.get_channel_followers(stream["user_id"]) text += (f'👤 {stream["user_name"]}\n' f'
👁 {stream["viewer_count"]} зрителей\n' f'👥 {followers_count} фолловеров\n' f'ℹ️{stream["title"]}\n
') else: text += "Сейчас никто не стримит эту игру" await utils.answer(message, text)