Added and updated repositories 2026-01-27 01:17:35

This commit is contained in:
github-actions[bot]
2026-01-27 01:17:36 +00:00
parent 7cb3c70695
commit c670c44a7a
70 changed files with 3312 additions and 3198 deletions

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, ai, assistant
from .. import loader, utils
import aiohttp

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, ai, username
# requires: aiohttp
import asyncio

View File

@@ -2,6 +2,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, user, profile
from hikkatl.types import Message
from telethon.tl.functions.account import UpdateProfileRequest

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, calculator, calc
from .. import loader, utils
import math

View File

@@ -1,7 +1,8 @@
# На модуль распространяется лицензия "GNU General Public License v3.0"
# На модуль распространяется лицензия "GNU General Public License v3.0
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @PyModule
# meta fhsdesc: tool, tools, channel, admintools, admin, admintool
from telethon.tl.types import Message
from .. import loader

View File

@@ -1,3 +1,4 @@
# meta fhsdesc: tool, tools, server, admin
from .. import loader, utils
import aiohttp
import asyncio

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, fun, packs
# requires: opencv-python pillow
import os

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: fun, cute, message, love
import random
import re

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, phone, info
# requires: aiohttp cachetools
import asyncio

View File

@@ -3,6 +3,7 @@
# scope: hikka_only
# meta developer: @pymodule
# meta fhsdesc: tool, tools, scanner, domain
# requires: python-whois dnspython requests
import socket

View File

@@ -2,6 +2,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @PyModule
# meta fhsdesc: tool, tools, user, id
from .. import loader, utils
@loader.tds

View File

@@ -11,183 +11,459 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, github, info, inline
from .. import loader, utils
from ..inline import InlineCall
import logging
import json
import re
import asyncio
import urllib.request
import json
from datetime import datetime, timedelta
@loader.tds
class GitHubInfoMod(loader.Module):
"""GitHub user info, recent activity and contribution graph"""
"""GitHub user information"""
strings = {
"name": "GitHubInfo",
"no_username": "❗ Provide a GitHub username.",
"user_not_found": "🚫 User not found: <b>{}</b>",
"profile": "Profile",
"api_error": "⚠ GitHub API error: <b>{msg}</b>",
"no_activity": "🕸 No recent activity from <b>{}</b>",
"no_contrib": "📭 No contribution data for <b>{}</b>",
"info_text": (
"👤 <b>{name}</b> | <a href=\"{url}\">{profile}</a>\n"
"🏢 {company} | 📍 {location}\n"
"📝 {bio}\n\n"
"📦 Repos: <b>{repos}</b> | "
"👥 Followers: <b>{followers}</b> | "
"no_contrib": "📭 No contribution data.",
"no_repos": "📭 No public repositories.",
"no_orgs": "📭 Not a member of any organizations.",
"no_title": "No title",
"no_desc": "No description",
"not_specified": "Not specified",
"more_commits": " ... and {} more\n",
"hireable_yes": "Yes",
"hireable_no": "No",
"menu_text": "Choose a section:",
"btn_activity": "🔥 Activity",
"btn_contrib": "📊 Contributions",
"btn_repos": "📦 Repositories",
"btn_orgs": "🏛 Organizations",
"btn_back": "← Back to profile",
"profile_header": "<b>Profile</b> <a href=\"{url}\">{username}</a>\n\n",
"profile_text": (
"👤 Name: <b>{name}</b>\n"
"🏷 Login: <code>{login}</code>\n"
"📝 Bio: {bio}\n"
"🏢 Company: {company}\n"
"📍 Location: {location}\n"
"📧 Email: {email}\n"
"🔗 Website: {blog}\n"
"🐦 Twitter: {twitter}\n"
"💼 Hireable: {hireable}\n"
"📊 Type: {type}\n"
"📦 Public repos: <b>{repos}</b>\n"
"⭐ Public gists: <b>{gists}</b>\n"
"👥 Followers: <b>{followers}</b>\n"
"👣 Following: <b>{following}</b>\n"
"🕒 Created: <code>{created}</code>"
"🕐 Created: <code>{created}</code>\n"
"🕐 Updated: <code>{updated}</code>"
),
"activity_header": "<b>Recent activity:</b>\n",
"activity_commit": "🔨 {count} commit(s) → <code>{branch}</code> in {repo}",
"activity_create": "✨ Created {ref_type} in {repo}",
"activity_pr": "🔄 {action} PR: {title}",
"activity_issue": "{action} issue: {title}",
"activity_star": "⭐ Starred {repo}",
"activity_fork": "⑂ Forked to {fork}",
"activity_other": "{event} in {repo}",
"contrib_header": "<b>Contribution graph</b> for <a href=\"https://github.com/{username}\">{username}</a>:\n",
"contrib_footer": "⬛ = 0, 🟩 = 1+ contributions",
"activity_header": "<b>Recent activity</b> <a href=\"https://github.com/{username}\">{username}</a>\n\n",
"push_header": "🔨 Pushed to <code>{branch}</code> → <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"push_no_commits": "🔨 Pushed (no details) to <code>{branch}</code> → <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"commit_line": "• <a href=\"{url}\"><code>{sha}</code></a>: {message}\n",
"create_branch": "✨ Created branch <code>{ref}</code> in <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"create_tag": "✨ Created tag <code>{ref}</code> in <a href=\"https://github.com/{repo}/releases/tag/{ref}\">{repo}</a>\n",
"create_repo": "✨ Created repository <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"pr_opened": "🔄 Opened PR <a href=\"{url}\">#{} {title}</a>\n",
"pr_closed": "🔄 Closed PR <a href=\"{url}\">#{} {title}</a>\n",
"pr_merged": "🔄 Merged PR <a href=\"{url}\">#{} {title}</a>\n",
"issue_opened": "❗ Opened issue <a href=\"{url}\">#{} {title}</a>\n",
"issue_closed": "❗ Closed issue <a href=\"{url}\">#{} {title}</a>\n",
"star": "⭐ Starred <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"fork": "⑂ Forked <a href=\"https://github.com/{fork}\">{fork}</a>\n",
"other": "{event} in <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"repos_header": "<b>Top repositories by stars</b> <a href=\"https://github.com/{username}\">{username}</a>\n\n",
"repo_line": "⭐ <b>{stars}</b> | <a href=\"{url}\">{name}</a> — {desc}\nLanguage: {lang} | Forks: {forks}\n\n",
"orgs_header": "<b>Organizations</b> <a href=\"https://github.com/{username}\">{username}</a>\n\n",
"org_line": "• <a href=\"{url}\">{login}</a> — {desc}\n",
"contrib_header": "<b>Contribution graph (last year)</b> <a href=\"https://github.com/{username}\">{username}</a>\n",
"contrib_footer": "\n⬛ = 0, 🟩 = 1+ contributions",
}
strings_ru = {
"no_username": "❗ Укажи имя пользователя GitHub.",
"_cls_doc": "Информация о GitHub-пользователе",
"no_username": "❗ Укажи GitHub username.",
"user_not_found": "🚫 Пользователь не найден: <b>{}</b>",
"profile": "Профиль",
"no_activity": "🕸 Нет активности у <b>{}</b>",
"no_contrib": "📭 Нет данных о вкладах <b>{}</b>",
"info_text": (
"👤 <b>{name}</b> | <a href=\"{url}\">{profile}</a>\n"
"🏢 {company} | 📍 {location}\n"
"📝 {bio}\n\n"
"📦 Репозитории: <b>{repos}</b> | "
"👥 Подписчики: <b>{followers}</b> | "
"api_error": "⚠ Ошибка GitHub API: <b>{msg}</b>",
"no_activity": "🕸 Нет недавней активности у <b>{}</b>",
"no_contrib": "📭 Нет данных о контрибуциях.",
"no_repos": "📭 Нет публичных репозиториев.",
"no_orgs": "📭 Не состоит в организациях.",
"no_title": "Без названия",
"no_desc": "Без описания",
"not_specified": "Не указано",
"more_commits": " ... и ещё {}\n",
"hireable_yes": "Да",
"hireable_no": "Нет",
"menu_text": "Выбери раздел:",
"btn_activity": "🔥 Активность",
"btn_contrib": "📊 Контрибы",
"btn_repos": "📦 Репозитории",
"btn_orgs": "🏛 Организации",
"btn_back": "← Назад к профилю",
"profile_header": "<b>Профиль</b> <a href=\"{url}\">{username}</a>\n\n",
"profile_text": (
"👤 Имя: <b>{name}</b>\n"
"🏷 Логин: <code>{login}</code>\n"
"📝 Био: {bio}\n"
"🏢 Компания: {company}\n"
"📍 Локация: {location}\n"
"📧 Email: {email}\n"
"🔗 Сайт: {blog}\n"
"🐦 Twitter: {twitter}\n"
"💼 Доступен для найма: {hireable}\n"
"📊 Тип аккаунта: {type}\n"
"📦 Публичные репозитории: <b>{repos}</b>\n"
"⭐ Публичные гисты: <b>{gists}</b>\n"
"👥 Подписчики: <b>{followers}</b>\n"
"👣 Подписки: <b>{following}</b>\n"
"🕒 Создан: <code>{created}</code>"
"🕐 Создан: <code>{created}</code>\n"
"🕐 Обновлён: <code>{updated}</code>"
),
"activity_header": "<b>Последняя активность:</b>\n",
"activity_commit": "🔨 {count} коммит(ов) → <code>{branch}</code> в {repo}",
"activity_create": "✨ Создан {ref_type} в {repo}",
"activity_pr": "🔄 {action} PR: {title}",
"activity_issue": "{action} issue: {title}",
"activity_star": "В избранное {repo}",
"activity_fork": "⑂ Форк в {fork}",
"activity_other": "{event} в {repo}",
"contrib_header": "<b>График активности</b> <a href=\"https://github.com/{username}\">{username}</a>:\n",
"contrib_footer": "⬛ = 0, 🟩 = 1+ контрибуций",
"activity_header": "<b>Последняя активность</b> <a href=\"https://github.com/{username}\">{username}</a>\n\n",
"push_header": "🔨 Запушил в <code>{branch}</code> → <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"push_no_commits": "🔨 Запушил (без деталей) в <code>{branch}</code> → <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"commit_line": "• <a href=\"{url}\"><code>{sha}</code></a>: {message}\n",
"create_branch": "✨ Создал ветку <code>{ref}</code> в <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"create_tag": "✨ Создал тег <code>{ref}</code> в <a href=\"https://github.com/{repo}/releases/tag/{ref}\">{repo}</a>\n",
"create_repo": "✨ Создал репозиторий <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"pr_opened": "🔄 Открыл PR <a href=\"{url}\">#{} {title}</a>\n",
"pr_closed": "🔄 Закрыл PR <a href=\"{url}\">#{} {title}</a>\n",
"pr_merged": "🔄 Замержил PR <a href=\"{url}\">#{} {title}</a>\n",
"issue_opened": "❗ Открыл issue <a href=\"{url}\">#{} {title}</a>\n",
"issue_closed": "❗ Закрыл issue <a href=\"{url}\">#{} {title}</a>\n",
"star": "⭐ Добавил в избранное <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"fork": "⑂ Форкнул <a href=\"https://github.com/{fork}\">{fork}</a>\n",
"other": "{event} в <a href=\"https://github.com/{repo}\">{repo}</a>\n",
"repos_header": "<b>Топ репозитории по звёздам</b> <a href=\"https://github.com/{username}\">{username}</a>\n\n",
"repo_line": "⭐ <b>{stars}</b> | <a href=\"{url}\">{name}</a> — {desc}\nЯзык: {lang} | Форков: {forks}\n\n",
"orgs_header": "<b>Организации</b> <a href=\"https://github.com/{username}\">{username}</a>\n\n",
"org_line": "• <a href=\"{url}\">{login}</a> — {desc}\n",
"contrib_header": "<b>График контрибуций (последний год)</b> <a href=\"https://github.com/{username}\">{username}</a>\n",
"contrib_footer": "\n⬛ = 0, 🟩 = 1+ контрибуций",
}
def __init__(self):
self.logger = logging.getLogger(__name__)
def github_api(self, url):
async def github_fetch(self, url, github_api=True):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
"Accept": "application/vnd.github+json" if github_api else "application/json",
"X-GitHub-Api-Version": "2022-11-28",
}
req = urllib.request.Request(url, headers=headers)
try:
with urllib.request.urlopen(url) as resp:
return json.loads(resp.read().decode())
with urllib.request.urlopen(req, timeout=15) as resp:
raw = resp.read().decode("utf-8")
return json.loads(raw) if raw else {}
except Exception as e:
self.logger.warning(f"[GitHub API] {e}")
return None
self.logger.error(f"[GitHub] {e}")
return {"message": str(e)}
def get_username(self, message):
args = message.text.split(maxsplit=1)
return args[1] if len(args) > 1 else None
@loader.command(doc="Show GitHub user info", ru_doc="Информация о пользователе GitHub")
async def gh(self, message):
"""Show GitHub user info"""
username = self.get_username(message)
@loader.command(ru_doc="{username без @} — Информация о GitHub пользователе")
async def github(self, message):
"""{username without @} — GitHub user information"""
username = utils.get_args_raw(message)
if not username:
return await message.edit(self.strings("no_username"))
await utils.answer(message, self.strings("no_username"))
return
data = self.github_api(f"https://api.github.com/users/{username}")
if not data:
return await message.edit(self.strings("user_not_found").format(username))
user_data = await self.github_fetch(f"https://api.github.com/users/{username}")
if "message" in user_data:
await utils.answer(message, self.strings("user_not_found").format(username))
return
await message.edit(self.strings("info_text").format(
name=data.get("name") or username,
url=data["html_url"],
profile=self.strings("profile"),
company=data.get("company", "N/A"),
location=data.get("location", "N/A"),
bio=data.get("bio", "No bio"),
repos=data.get("public_repos", 0),
followers=data.get("followers", 0),
following=data.get("following", 0),
created=data.get("created_at", "")[:10]
))
hireable = self.strings("hireable_yes") if user_data.get("hireable") else self.strings("hireable_no")
@loader.command(doc="Show recent GitHub activity", ru_doc="Последняя активность GitHub")
async def gha(self, message):
"""Show recent GitHub activity"""
username = self.get_username(message)
if not username:
return await message.edit(self.strings("no_username"))
profile_text = (
self.strings("profile_header").format(url=user_data["html_url"], username=username)
+ self.strings("profile_text").format(
name=user_data.get("name") or self.strings("not_specified"),
login=username,
bio=user_data.get("bio") or self.strings("no_desc"),
company=user_data.get("company") or self.strings("not_specified"),
location=user_data.get("location") or self.strings("not_specified"),
email=user_data.get("email") or self.strings("not_specified"),
blog=user_data.get("blog") or self.strings("not_specified"),
twitter=user_data.get("twitter_username") or self.strings("not_specified"),
hireable=hireable,
type=user_data.get("type", "User"),
repos=user_data.get("public_repos", 0),
gists=user_data.get("public_gists", 0),
followers=user_data.get("followers", 0),
following=user_data.get("following", 0),
created=user_data.get("created_at", "")[:10],
updated=user_data.get("updated_at", "")[:10],
)
+ "\n" + self.strings("menu_text")
)
events = self.github_api(f"https://api.github.com/users/{username}/events?per_page=5")
await self.inline.form(
message=message,
text=profile_text,
reply_markup=[
[{"text": self.strings("btn_activity"), "callback": self._activity, "args": (username,)}],
[{"text": self.strings("btn_contrib"), "callback": self._contrib, "args": (username,)}, {"text": self.strings("btn_repos"), "callback": self._repos, "args": (username,)}],
[{"text": self.strings("btn_orgs"), "callback": self._orgs, "args": (username,)}],
],
ttl=10 * 60,
)
async def _profile(self, call: InlineCall, username: str):
# Этот метод теперь используется только для возврата к профилю
data = await self.github_fetch(f"https://api.github.com/users/{username}")
if "message" in data:
await call.edit(self.strings("api_error").format(msg=data["message"]))
return
hireable = self.strings("hireable_yes") if data.get("hireable") else self.strings("hireable_no")
profile_text = (
self.strings("profile_header").format(url=data["html_url"], username=username)
+ self.strings("profile_text").format(
name=data.get("name") or self.strings("not_specified"),
login=username,
bio=data.get("bio") or self.strings("no_desc"),
company=data.get("company") or self.strings("not_specified"),
location=data.get("location") or self.strings("not_specified"),
email=data.get("email") or self.strings("not_specified"),
blog=data.get("blog") or self.strings("not_specified"),
twitter=data.get("twitter_username") or self.strings("not_specified"),
hireable=hireable,
type=data.get("type", "User"),
repos=data.get("public_repos", 0),
gists=data.get("public_gists", 0),
followers=data.get("followers", 0),
following=data.get("following", 0),
created=data.get("created_at", "")[:10],
updated=data.get("updated_at", "")[:10],
)
+ "\n" + self.strings("menu_text")
)
await call.edit(
text=profile_text,
reply_markup=[
[{"text": self.strings("btn_activity"), "callback": self._activity, "args": (username,)}],
[{"text": self.strings("btn_contrib"), "callback": self._contrib, "args": (username,)}, {"text": self.strings("btn_repos"), "callback": self._repos, "args": (username,)}],
[{"text": self.strings("btn_orgs"), "callback": self._orgs, "args": (username,)}],
]
)
async def _activity(self, call: InlineCall, username: str):
events = await self.github_fetch(f"https://api.github.com/users/{username}/events?per_page=40")
if "message" in events:
await call.edit(self.strings("api_error").format(msg=events["message"]), reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]])
return
if not events:
return await message.edit(self.strings("no_activity").format(username))
await call.edit(self.strings("no_activity").format(username=username), reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]])
return
lines = []
for event in events:
lines = [self.strings("activity_header").format(username=username)]
seen_repos = set()
for event in events[:25]:
etype = event["type"]
repo = event["repo"]["name"]
if repo in seen_repos and len(lines) > 20:
continue
payload = event.get("payload", {})
if etype == "PushEvent":
branch = re.sub(r"refs/heads/", "", payload.get("ref", "main"))
count = len(payload.get("commits", []))
lines.append(self.strings("activity_commit").format(count=count, branch=branch, repo=repo))
branch = payload.get("ref", "refs/heads/main").replace("refs/heads/", "")
commits = payload.get("commits", [])
if commits:
lines.append(self.strings("push_header").format(branch=branch, repo=repo))
for commit in commits[:5]:
sha = commit["sha"][:7]
message = commit["message"].split("\n")[0][:100]
if len(commit["message"].split("\n")[0]) > 100:
message += "..."
url = f"https://github.com/{repo}/commit/{commit['sha']}"
lines.append(self.strings("commit_line").format(url=url, sha=sha, message=message))
if len(commits) > 5:
lines.append(self.strings("more_commits").format(len(commits)-5))
else:
lines.append(self.strings("push_no_commits").format(branch=branch, repo=repo))
seen_repos.add(repo)
elif etype == "CreateEvent":
lines.append(self.strings("activity_create").format(ref_type=payload.get("ref_type"), repo=repo))
ref_type = payload.get("ref_type")
ref = payload.get("ref") or ""
if ref_type == "branch":
lines.append(self.strings("create_branch").format(ref=ref, repo=repo))
elif ref_type == "tag":
lines.append(self.strings("create_tag").format(ref=ref, repo=repo))
elif ref_type == "repository":
lines.append(self.strings("create_repo").format(repo=repo))
elif etype == "PullRequestEvent":
pr = payload.get("pull_request", {})
lines.append(self.strings("activity_pr").format(action=payload.get("action"), title=pr.get("title")))
number = pr.get("number", "?")
title = pr.get("title") or self.strings("no_title")
url = pr.get("html_url") or f"https://github.com/{repo}"
action = payload.get("action")
if action == "closed" and pr.get("merged"):
lines.append(self.strings("pr_merged").format(url=url, number=number, title=title))
elif action == "opened":
lines.append(self.strings("pr_opened").format(url=url, number=number, title=title))
elif action == "closed":
lines.append(self.strings("pr_closed").format(url=url, number=number, title=title))
elif etype == "IssuesEvent":
issue = payload.get("issue", {})
lines.append(self.strings("activity_issue").format(action=payload.get("action"), title=issue.get("title")))
number = issue.get("number", "?")
title = issue.get("title") or self.strings("no_title")
url = issue.get("html_url") or f"https://github.com/{repo}"
action = payload.get("action")
if action == "opened":
lines.append(self.strings("issue_opened").format(url=url, number=number, title=title))
elif action == "closed":
lines.append(self.strings("issue_closed").format(url=url, number=number, title=title))
elif etype == "WatchEvent":
lines.append(self.strings("activity_star").format(repo=repo))
lines.append(self.strings("star").format(repo=repo))
elif etype == "ForkEvent":
lines.append(self.strings("activity_fork").format(fork=payload.get("forkee", {}).get("full_name")))
fork = payload.get("forkee", {}).get("full_name", "unknown")
lines.append(self.strings("fork").format(fork=fork))
else:
lines.append(self.strings("activity_other").format(event=etype, repo=repo))
event_name = etype.replace("Event", "")
lines.append(self.strings("other").format(event=event_name, repo=repo))
await message.edit(self.strings("activity_header") + "\n".join(lines))
await call.edit(
text="".join(lines),
reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]]
)
@loader.command(doc="Show GitHub contribution graph", ru_doc="Показать график контрибов GitHub")
async def ghc(self, message):
"""Show GitHub contribution graph"""
username = self.get_username(message)
if not username:
return await message.edit(self.strings("no_username"))
async def _repos(self, call: InlineCall, username: str):
repos = await self.github_fetch(f"https://api.github.com/users/{username}/repos?sort=stars&per_page=10")
if "message" in repos:
await call.edit(self.strings("api_error").format(msg=repos["message"]), reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]])
return
if not repos:
await call.edit(self.strings("no_repos"), reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]])
return
data = self.github_api(f"https://github-contributions-api.deno.dev/{username}.json")
contribs = data.get("contributions") if data else None
lines = [self.strings("repos_header").format(username=username)]
for repo in repos[:10]:
lines.append(self.strings("repo_line").format(
stars=repo.get("stargazers_count", 0),
url=repo["html_url"],
name=repo["name"],
desc=repo.get("description") or self.strings("no_desc"),
lang=repo.get("language") or self.strings("not_specified"),
forks=repo.get("forks_count", 0),
))
if not isinstance(contribs, list):
return await message.edit(self.strings("no_contrib").format(username))
await call.edit(
text="".join(lines),
reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]]
)
async def _orgs(self, call: InlineCall, username: str):
orgs = await self.github_fetch(f"https://api.github.com/users/{username}/orgs")
if "message" in orgs:
await call.edit(self.strings("api_error").format(msg=orgs["message"]), reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]])
return
if not orgs:
await call.edit(self.strings("no_orgs"), reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]])
return
lines = [self.strings("orgs_header").format(username=username)]
for org in orgs:
lines.append(self.strings("org_line").format(
url=f"https://github.com/{org['login']}",
login=org["login"],
desc=org.get("description") or self.strings("no_desc"),
))
await call.edit(
text="".join(lines),
reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]]
)
async def _contrib(self, call: InlineCall, username: str):
data = await self.github_fetch(f"https://github-contributions-api.deno.dev/{username}.json", github_api=False)
if not data or not data.get("contributions"):
await call.edit(self.strings("no_contrib"), reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]])
return
raw_days = []
for week in data.get("contributions", []):
if isinstance(week, list):
raw_days.extend([day for day in week if isinstance(day, dict)])
today = datetime.utcnow().date()
start = today - timedelta(days=90)
matrix = [["" for _ in range(13)] for _ in range(7)]
weeks_count = 53
days_back = weeks_count * 7 + 7
start = today - timedelta(days=days_back)
for entry in contribs:
matrix = [["" for _ in range(weeks_count)] for _ in range(7)]
for entry in raw_days:
date_str = entry.get("date")
if not date_str:
continue
try:
date = datetime.strptime(entry["date"], "%Y-%m-%d").date()
if not (start <= date <= today):
date = datetime.strptime(date_str, "%Y-%m-%d").date()
if date < start or date > today:
continue
day = (date.weekday() + 1) % 7 # Sunday=0
week = (date - start).days // 7
if entry.get("contributionCount", 0) > 0:
matrix[day][week] = "🟩"
except:
count = entry.get("contributionCount") or entry.get("count", 0) or 0
if count > 0:
day_idx = (date.weekday() + 1) % 7
week_idx = (date - start).days // 7
if week_idx < weeks_count:
matrix[day_idx][week_idx] = "🟩"
except Exception:
continue
days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
graph = "\n".join(f"{days[i]} {''.join(matrix[i])}" for i in range(7))
days_labels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
graph = "\n".join(f"{days_labels[i]} {''.join(matrix[i])}" for i in range(7))
await message.edit(
self.strings("contrib_header").format(username=username)
+ f"<pre>{graph}</pre>\n"
+ self.strings("contrib_footer")
await call.edit(
text=self.strings("contrib_header").format(username=username)
+ f"<pre>{graph}</pre>"
+ self.strings("contrib_footer"),
reply_markup=[[{"text": self.strings("btn_back"), "callback": self._profile, "args": (username,)}]]
)

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, auto, restart, heroku, hikka
from hikkatl.types import Message
from .. import loader, utils

View File

@@ -2,6 +2,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @PyModule
# meta fhsdesc: fun, rp, rpgame
# requires: toml
import os
from hikka import loader, utils

View File

@@ -2,6 +2,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @PyModule
# meta fhsdesc: tool, tools, lyrics, music
import requests
from bs4 import BeautifulSoup, Tag, NavigableString
import re

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, minecraft, game
import aiohttp
import base64

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, in heroku
# requires: asyncio
from .. import loader, utils

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, point, auto
from .. import loader, utils

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, qr
from .. import loader, utils
import requests

View File

@@ -3,6 +3,7 @@
# scope: hikka_only
# meta developer: @pymodule
# meta fhsdesc: tool, tools, random
from .. import loader, utils
import random

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, test, speedtest
# requires: speedtest-cli
import speedtest

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, info, sysinfo, system
# requires: psutil
from .. import loader, utils

View File

@@ -11,6 +11,7 @@
# https://github.com/all-licenses/GNU-General-Public-License-v3.0
# meta developer: @pymodule
# meta fhsdesc: tool, tools, admin, tag, alltag, tagall
from .. import loader, utils
from telethon.tl.types import ChannelParticipantsAdmins, UserStatusRecently, UserStatusOnline, Message

View File

@@ -5,6 +5,7 @@
# Name: UserParser
# Description: Данный модуль позволяет копировать ID, Username и Name участников чата при помощи команды .userpars
# meta developer: @PyModule
# meta fhsdesc: tool, tools, id, parser, userparser
from .. import loader, utils
import json

View File

@@ -12,6 +12,7 @@
# meta developer: @pymodule
# requires: aiohttp
# meta fhsdesc: tool, tools, wiki, wikipedia, info, wikiinfo
from .. import loader, utils
from ..inline.types import InlineQuery