mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-16 14:34:17 +02:00
Added and updated repositories 2026-02-05 01:22:45
This commit is contained in:
214
radiocycle/Modules/LastFm.py
Normal file
214
radiocycle/Modules/LastFm.py
Normal file
@@ -0,0 +1,214 @@
|
||||
# =======================================
|
||||
# _ __ __ __ _
|
||||
# | |/ /___ | \/ | ___ __| |___
|
||||
# | ' // _ \ | |\/| |/ _ \ / _` / __|
|
||||
# | . \ __/ | | | | (_) | (_| \__ \
|
||||
# |_|\_\___| |_| |_|\___/ \__,_|___/
|
||||
# @ke_mods
|
||||
# =======================================
|
||||
#
|
||||
# LICENSE: CC BY-ND 4.0 (Attribution-NoDerivatives 4.0 International)
|
||||
# --------------------------------------
|
||||
# https://creativecommons.org/licenses/by-nd/4.0/legalcode
|
||||
# =======================================
|
||||
|
||||
# meta developer: @ke_mods
|
||||
|
||||
from .. import loader, utils
|
||||
import requests
|
||||
import io
|
||||
import textwrap
|
||||
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont, ImageOps
|
||||
|
||||
class Banners:
|
||||
def __init__(
|
||||
self,
|
||||
title: str,
|
||||
artists: list,
|
||||
track_cover: bytes,
|
||||
font
|
||||
):
|
||||
self.title = title
|
||||
self.artists = ", ".join(artists) if isinstance(artists, list) else artists
|
||||
self.track_cover = track_cover
|
||||
self.font_url = font
|
||||
|
||||
def _get_font(self, size, font_bytes):
|
||||
return ImageFont.truetype(io.BytesIO(font_bytes), size)
|
||||
|
||||
def _prepare_cover(self, size, radius):
|
||||
cover = Image.open(io.BytesIO(self.track_cover)).convert("RGBA")
|
||||
cover = cover.resize((size, size), Image.Resampling.LANCZOS)
|
||||
|
||||
mask = Image.new("L", (size, size), 0)
|
||||
draw = ImageDraw.Draw(mask)
|
||||
draw.rounded_rectangle((0, 0, size, size), radius=radius, fill=255)
|
||||
|
||||
output = Image.new("RGBA", (size, size), (0, 0, 0, 0))
|
||||
output.paste(cover, (0, 0), mask=mask)
|
||||
return output
|
||||
|
||||
def _prepare_background(self, w, h):
|
||||
bg = Image.open(io.BytesIO(self.track_cover)).convert("RGBA")
|
||||
bg = bg.resize((w, h), Image.Resampling.BICUBIC)
|
||||
bg = bg.filter(ImageFilter.GaussianBlur(radius=20))
|
||||
bg = ImageEnhance.Brightness(bg).enhance(0.4)
|
||||
return bg
|
||||
|
||||
def horizontal(self):
|
||||
W, H = 1500, 600
|
||||
padding = 60
|
||||
cover_size = 480
|
||||
|
||||
font_bytes = requests.get(self.font_url).content
|
||||
title_font = self._get_font(55, font_bytes)
|
||||
artist_font = self._get_font(45, font_bytes)
|
||||
lfm_font = self._get_font(35, font_bytes)
|
||||
|
||||
img = self._prepare_background(W, H)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
cover = self._prepare_cover(cover_size, 30)
|
||||
img.paste(cover, (padding, (H - cover_size) // 2), cover)
|
||||
|
||||
text_x = padding + cover_size + 60
|
||||
text_y_start = 100
|
||||
text_width_limit = W - text_x - padding
|
||||
|
||||
display_title = self.title
|
||||
while title_font.getlength(display_title) > text_width_limit and len(display_title) > 0:
|
||||
display_title = display_title[:-1]
|
||||
if len(display_title) < len(self.title): display_title += "…"
|
||||
|
||||
display_artist = self.artists
|
||||
while artist_font.getlength(display_artist) > text_width_limit and len(display_artist) > 0:
|
||||
display_artist = display_artist[:-1]
|
||||
if len(display_artist) < len(self.artists): display_artist += "…"
|
||||
|
||||
draw.text((text_x, text_y_start), display_title, font=title_font, fill="white")
|
||||
draw.text((text_x, text_y_start + 70), display_artist, font=artist_font, fill="#B3B3B3")
|
||||
|
||||
bar_y = 480
|
||||
draw.text((text_x, bar_y), "last.fm", font=lfm_font, fill="white")
|
||||
|
||||
by = io.BytesIO()
|
||||
img.save(by, format="PNG")
|
||||
by.seek(0)
|
||||
by.name = "banner.png"
|
||||
return by
|
||||
|
||||
def vertical(self):
|
||||
W, H = 1000, 1500
|
||||
padding = 80
|
||||
cover_size = 800
|
||||
|
||||
font_bytes = requests.get(self.font_url).content
|
||||
title_font = self._get_font(60, font_bytes)
|
||||
artist_font = self._get_font(45, font_bytes)
|
||||
lfm_font = self._get_font(35, font_bytes)
|
||||
|
||||
img = self._prepare_background(W, H)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
cover = self._prepare_cover(cover_size, 40)
|
||||
cover_x = (W - cover_size) // 2
|
||||
cover_y = 120
|
||||
img.paste(cover, (cover_x, cover_y), cover)
|
||||
|
||||
text_area_y = cover_y + cover_size + 120
|
||||
text_width_limit = W - (padding * 2)
|
||||
|
||||
display_title = self.title
|
||||
while title_font.getlength(display_title) > text_width_limit and len(display_title) > 0:
|
||||
display_title = display_title[:-1]
|
||||
if len(display_title) < len(self.title): display_title += "…"
|
||||
|
||||
display_artist = self.artists
|
||||
while artist_font.getlength(display_artist) > text_width_limit and len(display_artist) > 0:
|
||||
display_artist = display_artist[:-1]
|
||||
if len(display_artist) < len(self.artists): display_artist += "…"
|
||||
|
||||
title_w = title_font.getlength(display_title)
|
||||
draw.text(((W - title_w) / 2, text_area_y), display_title, font=title_font, fill="white")
|
||||
|
||||
artist_w = artist_font.getlength(display_artist)
|
||||
draw.text(((W - artist_w) / 2, text_area_y + 75), display_artist, font=artist_font, fill="#B3B3B3")
|
||||
|
||||
bar_y = text_area_y + 260
|
||||
|
||||
lfm_w = lfm_font.getlength("last.fm")
|
||||
draw.text(((W - lfm_w) / 2, bar_y), "last.fm", font=lfm_font, fill="white")
|
||||
|
||||
by = io.BytesIO()
|
||||
img.save(by, format="PNG")
|
||||
by.seek(0)
|
||||
by.name = "banner.png"
|
||||
return by
|
||||
|
||||
@loader.tds
|
||||
class lastfmmod(loader.Module):
|
||||
"""Module for music from different services"""
|
||||
|
||||
strings = {
|
||||
"name": "LastFm",
|
||||
"no_track": "<emoji document_id=5465665476971471368>❌</emoji> <b>No track is currently playing</b>",
|
||||
"_doc_text": "The text that will be written next to the file",
|
||||
"_doc_username": "Your username from last.fm",
|
||||
"nick_error": "<emoji document_id=5465665476971471368>❌</emoji> <b>Put your nickname from last.fm</b>",
|
||||
"uploading": "<emoji document_id=5841359499146825803>🕔</emoji> <i>Uploading banner...</i>",
|
||||
}
|
||||
strings_ru = {
|
||||
"name": "LastFm",
|
||||
"no_track": "<emoji document_id=5465665476971471368>❌</emoji> <b>Сейчас ничего не играет</b>",
|
||||
"_doc_text": "Текст, который будет написан рядом с файлом",
|
||||
"_doc_username": "Ваш username с last.fm",
|
||||
"nick_error": "<emoji document_id=5465665476971471368>❌</emoji> <b>Укажите ваш никнейм с last.fm</b>",
|
||||
"uploading": "<emoji document_id=5841359499146825803>🕔</emoji> <i>Загрузка баннера...</i>",
|
||||
}
|
||||
strings_jp = {
|
||||
"name": "LastFm",
|
||||
"no_track": "<emoji document_id=5465665476971471368>❌</emoji> <b>現在再生中のトラックはありません</b>",
|
||||
"_doc_text": "ファイルの横に表示されるテキスト",
|
||||
"_doc_username": "Last.fmのユーザー名",
|
||||
"nick_error": "<emoji document_id=5465665476971471368>❌</emoji> <b>Last.fmのニックネームを入力してください</b>",
|
||||
"uploading": "<emoji document_id=5841359499146825803>🕔</emoji> <i>バナーをアップロード中...</i>",
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue("username", None, lambda: self.strings["_doc_username"]),
|
||||
loader.ConfigValue("custom_text", "<emoji document_id=5413612466208799435>🤩</emoji> <b>{song_name}</b> — <b>{song_artist}</b>", lambda: self.strings["_doc_text"]),
|
||||
loader.ConfigValue("font", "https://raw.githubusercontent.com/kamekuro/assets/master/fonts/Onest-Bold.ttf", "Custom font URL (ttf)"),
|
||||
loader.ConfigValue("banner_version", "horizontal", lambda: "Banner version", validator=loader.validators.Choice(["horizontal", "vertical"])),
|
||||
)
|
||||
|
||||
@loader.command(alias="np")
|
||||
async def nowplay(self, message):
|
||||
"""| send playing track info"""
|
||||
user = self.config["username"]
|
||||
if not user:
|
||||
await self.invoke("config", "lastfm", message=message)
|
||||
return await utils.answer(message, self.strings["nick_error"])
|
||||
|
||||
try:
|
||||
url = f'http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&nowplaying=true&user={user}&api_key=460cda35be2fbf4f28e8ea7a38580730&format=json'
|
||||
data = requests.get(url).json()
|
||||
track = next((t for t in data.get('recenttracks', {}).get('track', []) if t.get('@attr', {}).get('nowplaying')), None)
|
||||
if not track:
|
||||
return await utils.answer(message, self.strings["no_track"])
|
||||
name = track.get('name', 'Unknown')
|
||||
artist = track.get('artist', {}).get('#text', 'Unknown')
|
||||
caption = self.config["custom_text"].format(song_artist=artist, song_name=name)
|
||||
imgs = track.get('image', [])
|
||||
cov_url = next((i['#text'] for i in imgs if i['size'] == 'extralarge'), imgs[-1]['#text'] if imgs else None)
|
||||
|
||||
if not cov_url:
|
||||
return await utils.answer(message, caption)
|
||||
msg = await utils.answer(message, self.strings["uploading"])
|
||||
cov_bytes = await utils.run_sync(requests.get, cov_url)
|
||||
banners = Banners(name, artist, cov_bytes.content, self.config["font"])
|
||||
file = await utils.run_sync(getattr(banners, self.config["banner_version"]))
|
||||
await utils.answer(msg, caption, file=file)
|
||||
|
||||
except Exception as e:
|
||||
await utils.answer(message, f"<pre><code class='language-python'>{e}</code></pre>")
|
||||
48
radiocycle/Modules/Neofetch.py
Normal file
48
radiocycle/Modules/Neofetch.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# =======================================
|
||||
# _ __ __ __ _
|
||||
# | |/ /___ | \/ | ___ __| |___
|
||||
# | ' // _ \ | |\/| |/ _ \ / _` / __|
|
||||
# | . \ __/ | | | | (_) | (_| \__ \
|
||||
# |_|\_\___| |_| |_|\___/ \__,_|___/
|
||||
# @ke_mods
|
||||
# =======================================
|
||||
#
|
||||
# LICENSE: CC BY-ND 4.0 (Attribution-NoDerivatives 4.0 International)
|
||||
# --------------------------------------
|
||||
# https://creativecommons.org/licenses/by-nd/4.0/legalcode
|
||||
# =======================================
|
||||
|
||||
# meta developer: @ke_mods
|
||||
|
||||
import subprocess
|
||||
from .. import loader, utils
|
||||
|
||||
@loader.tds
|
||||
class NeofetchMod(loader.Module):
|
||||
strings = {
|
||||
"name": "Neofetch",
|
||||
"not_installed": "<b>Please, install</b> <i>Neofetch</i> <b>package</b>",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"not_installed": "<b>Пожалуйста, установите пакет</b> <i>Neofetch</i>",
|
||||
}
|
||||
|
||||
strings_ua = {
|
||||
"not_installed": "<b>Будь ласка, встановіть пакет<b> <i>Neofetch</i>",
|
||||
}
|
||||
|
||||
@loader.command(
|
||||
ru_doc="- запустить команду neofetch",
|
||||
ua_doc="- запустити команду neofetch",
|
||||
)
|
||||
async def neofetchcmd(self, message):
|
||||
"""- run neofetch command"""
|
||||
try:
|
||||
result = subprocess.run(["neofetch", "--stdout"], capture_output=True, text=True)
|
||||
output = result.stdout
|
||||
await utils.answer(message, f"<pre>{utils.escape_html(output)}</pre>")
|
||||
|
||||
except FileNotFoundError:
|
||||
await utils.answer(message, self.strings("not_installed"))
|
||||
|
||||
211
radiocycle/Modules/PicToStories.py
Normal file
211
radiocycle/Modules/PicToStories.py
Normal file
@@ -0,0 +1,211 @@
|
||||
# =======================================
|
||||
# _ __ __ __ _
|
||||
# | |/ /___ | \/ | ___ __| |___
|
||||
# | ' // _ \ | |\/| |/ _ \ / _` / __|
|
||||
# | . \ __/ | | | | (_) | (_| \__ \
|
||||
# |_|\_\___| |_| |_|\___/ \__,_|___/
|
||||
# @ke_mods
|
||||
# =======================================
|
||||
#
|
||||
# LICENSE: CC BY-ND 4.0 (Attribution-NoDerivatives 4.0 International)
|
||||
# --------------------------------------
|
||||
# https://creativecommons.org/licenses/by-nd/4.0/legalcode
|
||||
# =======================================
|
||||
|
||||
# meta developer: @ke_mods
|
||||
# requires: pillow
|
||||
|
||||
import io
|
||||
import asyncio
|
||||
|
||||
from telethon import functions, types
|
||||
from PIL import Image
|
||||
|
||||
from .. import loader, utils
|
||||
|
||||
|
||||
@loader.tds
|
||||
class PicToStoriesMod(loader.Module):
|
||||
"""Grid for stories"""
|
||||
|
||||
strings = {
|
||||
"name": "PicToStories",
|
||||
"no_rep": (
|
||||
"<emoji document_id=5879813604068298387>❗️</emoji> "
|
||||
"<b>Reply to photo!</b>"
|
||||
),
|
||||
"work": (
|
||||
"<emoji document_id=5841359499146825803>🕔</emoji> "
|
||||
"<b>Processing...</b>"
|
||||
),
|
||||
"done": (
|
||||
"<emoji document_id=5776375003280838798>✅</emoji> "
|
||||
"<b>Done! Check your profile.</b>"
|
||||
),
|
||||
"err": (
|
||||
"<emoji document_id=5778527486270770928>❌</emoji> "
|
||||
"<b>Error:</b> {}"
|
||||
),
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"no_rep": (
|
||||
"<emoji document_id=5879813604068298387>❗️</emoji> "
|
||||
"<b>Реплай на фото!</b>"
|
||||
),
|
||||
"work": (
|
||||
"<emoji document_id=5841359499146825803>🕔</emoji> "
|
||||
"<b>Обрабатываю...</b>"
|
||||
),
|
||||
"done": (
|
||||
"<emoji document_id=5776375003280838798>✅</emoji> "
|
||||
"<b>Готово! Проверяй профиль.</b>"
|
||||
),
|
||||
"err": (
|
||||
"<emoji document_id=5778527486270770928>❌</emoji> "
|
||||
"<b>Ошибка:</b> {}"
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.config = loader.ModuleConfig(
|
||||
loader.ConfigValue(
|
||||
"period",
|
||||
48,
|
||||
lambda: "Visibility period in hours",
|
||||
validator=loader.validators.Integer(),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"blacklist",
|
||||
[],
|
||||
lambda: "Blacklisted user IDs",
|
||||
validator=loader.validators.Series(loader.validators.Integer()),
|
||||
),
|
||||
loader.ConfigValue(
|
||||
"cooldown",
|
||||
0,
|
||||
lambda: "Cooldown between stories in seconds",
|
||||
validator=loader.validators.Integer(minimum=0),
|
||||
),
|
||||
)
|
||||
|
||||
@loader.command(ru_doc="<реплай на фото> [название альбома] - сделать сетку")
|
||||
async def ptscmd(self, message):
|
||||
"""<reply to photo> [album name] - make grid"""
|
||||
args = utils.get_args_raw(message)
|
||||
reply = await message.get_reply_message()
|
||||
if not reply or not reply.media:
|
||||
await utils.answer(message, self.strings("no_rep"))
|
||||
return
|
||||
|
||||
try:
|
||||
image_bytes = await reply.download_media(file=bytes)
|
||||
img = Image.open(io.BytesIO(image_bytes))
|
||||
except Exception as e:
|
||||
await utils.answer(message, self.strings("err").format(e))
|
||||
return
|
||||
|
||||
await utils.answer(message, self.strings("work"))
|
||||
|
||||
w, h = img.size
|
||||
curr_ratio = w / h
|
||||
variants = [
|
||||
(5 / 4, 2),
|
||||
(4 / 5, 3),
|
||||
(3 / 5, 4),
|
||||
(9 / 16, 5)
|
||||
]
|
||||
best_ratio, rows = min(variants, key=lambda x: abs(curr_ratio - x[0]))
|
||||
|
||||
new_h = int(w / best_ratio)
|
||||
img = img.resize((w, new_h), Image.LANCZOS)
|
||||
w, h = img.size
|
||||
|
||||
parts = []
|
||||
pw, ph = w // 3, h // rows
|
||||
for r in range(rows):
|
||||
for c in range(3):
|
||||
x, y = c * pw, r * ph
|
||||
parts.append(img.crop((x, y, x + pw, y + ph)))
|
||||
|
||||
parts.reverse()
|
||||
|
||||
privacy = [types.InputPrivacyValueAllowAll()]
|
||||
if self.config["blacklist"]:
|
||||
entities = []
|
||||
for uid in self.config["blacklist"]:
|
||||
try:
|
||||
entities.append(await self.client.get_input_entity(uid))
|
||||
except Exception:
|
||||
continue
|
||||
if entities:
|
||||
privacy.append(types.InputPrivacyValueDisallowUsers(users=entities))
|
||||
|
||||
story_ids = []
|
||||
for i, p in enumerate(parts):
|
||||
out = io.BytesIO()
|
||||
p.save(out, "JPEG", quality=95)
|
||||
out.seek(0)
|
||||
|
||||
uploaded_file = await self.client.upload_file(out, file_name="s.jpg")
|
||||
res = await self.client(
|
||||
functions.stories.SendStoryRequest(
|
||||
peer=types.InputPeerSelf(),
|
||||
media=types.InputMediaUploadedPhoto(uploaded_file),
|
||||
privacy_rules=privacy,
|
||||
period=self.config["period"] * 3600,
|
||||
)
|
||||
)
|
||||
|
||||
sid = next(
|
||||
(
|
||||
u.story_id if hasattr(u, "story_id") else u.id
|
||||
for u in res.updates
|
||||
if hasattr(u, "story_id") or hasattr(u, "id")
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
if sid:
|
||||
story_ids.append(sid)
|
||||
|
||||
if self.config["cooldown"] > 0 and i < len(parts) - 1:
|
||||
await asyncio.sleep(self.config["cooldown"])
|
||||
|
||||
if not story_ids:
|
||||
return
|
||||
|
||||
if args:
|
||||
all_albums = await self.client(
|
||||
functions.stories.GetAlbumsRequest(peer=types.InputPeerSelf(), hash=0)
|
||||
)
|
||||
|
||||
target = next(
|
||||
(a for a in all_albums.albums if getattr(a, 'title', '') == args),
|
||||
None
|
||||
)
|
||||
|
||||
if target:
|
||||
await self.client(
|
||||
functions.stories.UpdateAlbumRequest(
|
||||
peer=types.InputPeerSelf(),
|
||||
album_id=target.album_id,
|
||||
add_stories=story_ids,
|
||||
)
|
||||
)
|
||||
else:
|
||||
await self.client(
|
||||
functions.stories.CreateAlbumRequest(
|
||||
peer=types.InputPeerSelf(),
|
||||
stories=story_ids,
|
||||
title=args,
|
||||
)
|
||||
)
|
||||
else:
|
||||
await self.client(
|
||||
functions.stories.TogglePinnedRequest(
|
||||
peer=types.InputPeerSelf(), id=story_ids, pinned=True
|
||||
)
|
||||
)
|
||||
|
||||
await utils.answer(message, self.strings("done"))
|
||||
1436
radiocycle/Modules/SpotifyMod.py
Normal file
1436
radiocycle/Modules/SpotifyMod.py
Normal file
File diff suppressed because it is too large
Load Diff
74
radiocycle/Modules/UnbanAll.py
Normal file
74
radiocycle/Modules/UnbanAll.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# =======================================
|
||||
# _ __ __ __ _
|
||||
# | |/ /___ | \/ | ___ __| |___
|
||||
# | ' // _ \ | |\/| |/ _ \ / _` / __|
|
||||
# | . \ __/ | | | | (_) | (_| \__ \
|
||||
# |_|\_\___| |_| |_|\___/ \__,_|___/
|
||||
# @ke_mods
|
||||
# =======================================
|
||||
#
|
||||
# LICENSE: CC BY-ND 4.0 (Attribution-NoDerivatives 4.0 International)
|
||||
# --------------------------------------
|
||||
# https://creativecommons.org/licenses/by-nd/4.0/legalcode
|
||||
# =======================================
|
||||
|
||||
# meta developer: @ke_mods
|
||||
|
||||
from .. import loader, utils
|
||||
from telethon.tl.types import ChatBannedRights
|
||||
from telethon.tl.functions.channels import EditBannedRequest
|
||||
from telethon.tl.types import ChannelParticipantsKicked
|
||||
|
||||
@loader.tds
|
||||
class UnbanAllMod(loader.Module):
|
||||
strings = {
|
||||
"name": "UnbanAll",
|
||||
"no_rights": "<b>❌ I don't have administrator rights to remove restrictions.</b>",
|
||||
"success": "<b>✅ All banned chat members have been unbanned.</b>",
|
||||
"unban_in_process": "<b>👀 Unbanning users...</b>",
|
||||
"no_banned": "<b>ℹ️ There are no banned members in this chat.</b>",
|
||||
"error_occured": "<b>💢 An error occurred while unbanning user <code>{}</code>:</b>\n<code>{}</code>",
|
||||
}
|
||||
strings_ru = {
|
||||
"no_rights": "<b>❌ У меня нет прав администратора для снятия ограничений.</b>",
|
||||
"success": "<b>✅ Все забаненные участники чата были разблокированы.</b>",
|
||||
"unban_in_process": "<b>👀 Разбаниваю пользователей...</b>",
|
||||
"no_banned": "<b>ℹ️ В этом чате нет забаненных участников.</b>",
|
||||
"error_occured": "<b>💢 Произошла ошибка при разблокировке пользователя <code>{}</code>:</b>\n<code>{}</code>",
|
||||
}
|
||||
|
||||
@loader.command(ru_doc="- Разбанить всех забаненных пользователей")
|
||||
async def unbanallcmd(self, message):
|
||||
"""- Unban all banned users"""
|
||||
chat = await message.get_chat()
|
||||
|
||||
if not chat.admin_rights and not chat.creator:
|
||||
await utils.answer(message, self.strings("no_rights"))
|
||||
return
|
||||
|
||||
await utils.answer(message, self.strings("unban_in_process"))
|
||||
|
||||
no_banned = True
|
||||
|
||||
async for user in self.client.iter_participants(
|
||||
message.chat_id, filter=ChannelParticipantsKicked
|
||||
):
|
||||
|
||||
no_banned = False
|
||||
|
||||
try:
|
||||
await self.client(EditBannedRequest(
|
||||
message.chat_id,
|
||||
user.id,
|
||||
ChatBannedRights(until_date=0)
|
||||
))
|
||||
|
||||
except Exception as e:
|
||||
await utils.answer(message, self.strings("error_occured").format(user.id, e))
|
||||
pass
|
||||
|
||||
if no_banned:
|
||||
await utils.answer(message, self.strings("no_banned"))
|
||||
return
|
||||
|
||||
await utils.answer(message, self.strings("success"))
|
||||
7
radiocycle/Modules/full.txt
Normal file
7
radiocycle/Modules/full.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Neofetch
|
||||
randomanimepic
|
||||
SpotifyMod
|
||||
UnbanAll
|
||||
voicetotext
|
||||
LastFm
|
||||
PicToStories
|
||||
65
radiocycle/Modules/randomanimepic.py
Normal file
65
radiocycle/Modules/randomanimepic.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# =======================================
|
||||
# _ __ __ __ _
|
||||
# | |/ /___ | \/ | ___ __| |___
|
||||
# | ' // _ \ | |\/| |/ _ \ / _` / __|
|
||||
# | . \ __/ | | | | (_) | (_| \__ \
|
||||
# |_|\_\___| |_| |_|\___/ \__,_|___/
|
||||
# @ke_mods
|
||||
# =======================================
|
||||
#
|
||||
# LICENSE: CC BY-ND 4.0 (Attribution-NoDerivatives 4.0 International)
|
||||
# --------------------------------------
|
||||
# https://creativecommons.org/licenses/by-nd/4.0/legalcode
|
||||
# =======================================
|
||||
|
||||
# meta developer: @ke_mods
|
||||
|
||||
import requests
|
||||
import asyncio
|
||||
import logging
|
||||
import traceback
|
||||
from logging import basicConfig
|
||||
from .. import loader, utils
|
||||
|
||||
basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@loader.tds
|
||||
class RandomAnimePicMod(loader.Module):
|
||||
strings = {
|
||||
"name": "RandomAnimePic",
|
||||
"img": "<emoji document_id=4916036072560919511>✅</emoji> <b>Your anime pic</b>\n<emoji document_id=5877465816030515018>🔗</emoji> <b>URL:</b> {}",
|
||||
"loading": "<emoji document_id=4911241630633165627>✨</emoji> <b>Loading image...</b>",
|
||||
"error": "<emoji document_id=5116151848855667552>🚫</emoji> <b>An unexpected error occurred...</b>",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"img": "<emoji document_id=4916036072560919511>✅</emoji> <b>Ваша аниме-картинка</b>\n<emoji document_id=5877465816030515018>🔗</emoji> <b>Ссылка:</b> {}",
|
||||
"loading": "<emoji document_id=4911241630633165627>✨</emoji> <b>Загрузка изображения...</b>",
|
||||
"error": "<emoji document_id=5116151848855667552>🚫</emoji> <b>Произошла непредвиденная ошибка...</b>",
|
||||
}
|
||||
|
||||
@loader.command(
|
||||
ru_doc="- получить рандомную аниме-картинку 👀"
|
||||
)
|
||||
async def rapiccmd(self, message):
|
||||
"""- fetch random anime-pic 👀"""
|
||||
|
||||
await utils.answer(message, self.strings("loading"))
|
||||
|
||||
try:
|
||||
res = requests.get("https://api.nekosia.cat/api/v1/images/cute?count=1")
|
||||
res.raise_for_status()
|
||||
data = res.json()
|
||||
image_url = data['image']['original']['url']
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
await utils.answer(message, self.strings("img").format(image_url), file=image_url, reply_to=message.reply_to_msg_id)
|
||||
|
||||
except Exception:
|
||||
logger.error("Error fetching random anime pic: %s", traceback.format_exc())
|
||||
|
||||
await utils.answer(message, self.strings("error"))
|
||||
|
||||
await asyncio.sleep(5)
|
||||
77
radiocycle/Modules/voicetotext.py
Normal file
77
radiocycle/Modules/voicetotext.py
Normal file
@@ -0,0 +1,77 @@
|
||||
# =======================================
|
||||
# _ __ __ __ _
|
||||
# | |/ /___ | \/ | ___ __| |___
|
||||
# | ' // _ \ | |\/| |/ _ \ / _` / __|
|
||||
# | . \ __/ | | | | (_) | (_| \__ \
|
||||
# |_|\_\___| |_| |_|\___/ \__,_|___/
|
||||
# @ke_mods
|
||||
# =======================================
|
||||
#
|
||||
# LICENSE: CC BY-ND 4.0 (Attribution-NoDerivatives 4.0 International)
|
||||
# --------------------------------------
|
||||
# https://creativecommons.org/licenses/by-nd/4.0/legalcode
|
||||
# =======================================
|
||||
|
||||
# meta developer: @ke_mods
|
||||
# scope: ffmpeg
|
||||
# requires: pydub SpeechRecognition
|
||||
|
||||
from .. import loader, utils
|
||||
import os
|
||||
import speech_recognition as sr
|
||||
from pydub import AudioSegment
|
||||
|
||||
@loader.tds
|
||||
class VoiceToTextMod(loader.Module):
|
||||
strings = {
|
||||
"name": "VoiceToText",
|
||||
"process_text": "<emoji document_id=4911241630633165627>✨</emoji> <b>Recognizing the message text...</b>",
|
||||
"vtt_success": "<emoji document_id=5116110535565247270>🔥</emoji> <b>Recognized text:</b>\n<blockquote expandable>{}</blockquote>",
|
||||
"vtt_failure": "<emoji document_id=5116151848855667552>🚫</emoji> <b>Failed to recognize the message.</b>",
|
||||
"vtt_request_error": "<emoji document_id=5116151848855667552>🚫</emoji> <b>Error when contacting the recognition service:</b>\n<code>{}</code>",
|
||||
"vtt_invalid": "<emoji document_id=5116151848855667552>🚫</emoji> <b>Please reply to a voice or video message with the command</b> <code>{}vtt</code>",
|
||||
"vtt_successful": "<emoji document_id=4916036072560919511>✅</emoji> <b>Text recognized successfully</b>",
|
||||
}
|
||||
|
||||
strings_ru = {
|
||||
"process_text": "<emoji document_id=4911241630633165627>✨</emoji> <b>Распознаю текст сообщения...</b>",
|
||||
"vtt_success": "<emoji document_id=5116110535565247270>🔥</emoji> <b>Распознанный текст:</b>\n<blockquote expandable>{}</blockquote>",
|
||||
"vtt_failure": "<emoji document_id=5116151848855667552>🚫</emoji> <b>Не удалось распознать сообщение.</b>",
|
||||
"vtt_request_error": "<emoji document_id=5116151848855667552>🚫</emoji> <b>Ошибка при обращении к сервису распознавания:</b>\n<code>{}</code>",
|
||||
"vtt_invalid": "<emoji document_id=5116151848855667552>🚫</emoji> <b>Пожалуйста, ответьте на голосовое или видеосообщение командой</b> <code>{}vtt</code>",
|
||||
"vtt_successful": "<emoji document_id=4916036072560919511>✅</emoji> <b>Текст успешно распознан</b>",
|
||||
}
|
||||
|
||||
@loader.command(
|
||||
ru_doc="- распознает текст из голосового или видеосообщения.",
|
||||
)
|
||||
async def vttcmd(self, message):
|
||||
"""- recognizes text from voice or video messages."""
|
||||
reply = await message.get_reply_message()
|
||||
|
||||
if not reply or not (reply.voice or reply.video_note):
|
||||
await utils.answer(message, self.strings["vtt_invalid"].format(self.get_prefix()))
|
||||
return
|
||||
|
||||
msg = await utils.answer(
|
||||
message, self.strings["process_text"], reply_to=message.id
|
||||
)
|
||||
|
||||
media_file = await reply.download_media()
|
||||
wav_file = media_file.replace('.mp4', '.wav') if reply.video_note else media_file.replace('.oga', '.wav')
|
||||
|
||||
try:
|
||||
AudioSegment.from_file(media_file).export(wav_file, format='wav')
|
||||
recognizer = sr.Recognizer()
|
||||
with sr.AudioFile(wav_file) as source:
|
||||
audio_data = recognizer.record(source)
|
||||
try:
|
||||
text = recognizer.recognize_google(audio_data, language='ru-RU')
|
||||
await utils.answer(msg, self.strings["vtt_success"].format(text))
|
||||
except sr.UnknownValueError:
|
||||
await utils.answer(msg, self.strings["vtt_failure"])
|
||||
except sr.RequestError as e:
|
||||
await utils.answer(msg, self.strings["vtt_request_error"].format(e))
|
||||
finally:
|
||||
os.remove(media_file)
|
||||
os.remove(wav_file)
|
||||
Reference in New Issue
Block a user