__version__ = (2, 6, 1)
"""
█▀▄▀█ █▀█ █▀█ █ █▀ █ █ █▀▄▀█ █▀▄▀█ █▀▀ █▀█
█ ▀ █ █▄█ █▀▄ █ ▄█ █▄█ █ ▀ █ █ ▀ █ ██▄ █▀▄
Copyright 2022 t.me/morisummermods
Licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
"""
# scope: inline_content
# requires: requests bs4 spotipy
# meta developer: @morisummermods
# meta pic: https://i.imgur.com/pViqDsI.png
# meta banner: https://i.imgur.com/AIjsMoV.jpg
import logging
import re
from urllib.parse import quote_plus
import requests
import spotipy
from aiogram.types import (
InlineKeyboardButton,
InlineKeyboardMarkup,
InlineQueryResultArticle,
InputTextMessageContent,
)
from bs4 import BeautifulSoup
from telethon.tl.functions.channels import JoinChannelRequest
from telethon.tl.types import Message
from .. import loader # noqa
from .. import utils # noqa
from ..inline import GeekInlineQuery, rand # noqa
logger = logging.getLogger(__name__)
api_headers = {
"User-Agent": "CompuServe Classic/1.22",
"Accept": "application/json",
"Host": "api.genius.com",
}
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/99.0.4844.82 Safari/537.36"
)
}
host = "https://api.genius.com"
n = "\n"
def get_lyrics(self, song_url, remove_section_headers=False):
"""Uses BeautifulSoup to scrape song info off of a Genius song URL"""
page = requests.get(song_url, headers=headers)
html = BeautifulSoup(page.text.replace("
", "\n"), "html.parser")
lyrics = "\n".join(
[
p.get_text()
for p in html.find_all("div", attrs={"data-lyrics-container": "true"})
]
)
# Remove [Verse], [Bridge], etc.
lyrics = re.sub(r"(\[.*?\])", "\g<1>", lyrics)
if remove_section_headers:
lyrics = re.sub(r"(\[.*?\])*", "", lyrics)
lyrics = re.sub("\n{2}", "\n", lyrics)
return lyrics or self.strings["noLyrics"]
def search(q):
"""Search documents hosted on Genius"""
req = requests.get(
(
"https://api.genius.com/search"
"?text_format=plain"
f"&q={quote_plus(q)}"
"&access_token=uhYUr-qrBp5V3o46lA8vcaL1DKXTWVs5SDsb_0CDCIcKxKLwtapqeqkdNu8JnA6w"
),
headers=api_headers,
).json()
return [
{
"artists": hit["result"]["artist_names"].replace("\u200b", ""),
"title": hit["result"]["title"].replace("\u200b", ""),
"pic": hit["result"]["header_image_thumbnail_url"],
"url": hit["result"]["url"],
"id": hit["result"]["id"],
}
for hit in req["response"]["hits"]
]
def add_protocol(x):
"""Add https protocol to link"""
return f"https:{x}" if x.startswith("//") else x
@loader.tds
class LyricsMod(loader.Module):
"""Song lyrics from Genius"""
strings = {
"name": "Lyrics",
"type_name": "🚫 Please type name of the song",
"genius": "🎵 Full lyrics on Genius",
"noSpotify": (
"🚫 Please install SpotifyNow module and proceed auth\n"
"🌃 Install: .dlmod https://mods.hikariatama.ru/spotify.py"
),
"notFound": "🚫 No results found",
"couldn'tFind": "We couldn't find what are you looking for",
"sauth": "🚫 Execute .sauth before using this action.",
"SpotifyError": "🚫 Spotify error",
"noResults": "🚫 No results found for {}",
"noLyrics": "🚫 Couldn't find the lyrics",
"lyrics": "Lyrics for {} by {}\n{}",
"loading": "Loading lyrics for {} by {}...\n{}",
}
strings_ru = {
"_cls_doc": "Поиск тексов песен с Genius",
"_cmd_doc_lyrics": "Получить слова песни",
"_cmd_doc_slyrics": (
"Получить слова песни прослушиваемой в Спотифай, "
"для работоспособности требуется модуль SpotifyNow"
),
"_ihandle_doc_lyrics": "Поиск текста песни",
"type_name": "🚫 Пожалуйста, введите имя композиции",
"genius": "🎵 Полный текст на Genius",
"noSpotify": (
"🚫 Пожалуйста установи модуль SpotifyNow и пройди авторизацию.\n"
"🌃 Установка: .dlmod https://mods.hikariatama.ru/spotify.py"
),
"notFound": "🚫 Результаты не найдены",
"couldn'tFind": "К сожалению мы не нашли, что вы искали",
"sauth": "🚫 Выполни .sauth перед этим действием.",
"SpotifyError": "🚫 Ошибка Спотифай",
"noResults": "🚫 Результаты для {} не найдены",
"noLyrics": "🚫 Не удалось найти текст",
"lyrics": "Текст песни {} от {}\n{}",
"loading": "Загрузка текста песни {} от {}...\n{}",
}
async def client_ready(self, client, db) -> None:
if hasattr(self, "hikka"):
self.bot_id = self.inline.bot_id
return
self.db = db
self.client = client
self.bot_id = (await self.inline.bot.get_me()).id
try:
channel = await self.client.get_entity("t.me/morisummermods")
await client(JoinChannelRequest(channel))
except Exception:
logger.info("Can't join morisummermods")
try:
post = (await client.get_messages("@morisummermods", ids=[13]))[0]
await post.react("❤️")
except Exception:
logger.info("Can't react to morisummermods")
async def lyricscmd(self, message: Message):
"""Get lyrics"""
text = utils.get_args_raw(message)
reply = await message.get_reply_message()
if not text:
if reply:
if (
getattr(reply, "media", None)
and getattr(reply.media, "document", None)
and getattr(reply.media.document, "attributes", None)
):
text = reply.media.document.attributes[1].file_name.rsplit(".", 1)[
0
]
else:
try:
e = next(
entity
for entity in reply.entities
if type(entity).__name__ == "MessageEntityCode"
)
text = reply.raw_text[e.offset - 1 : e.offset + e.length]
except Exception:
text = reply.raw_text
else:
await utils.answer(message, self.strings["type_name"])
return
if tracks := search(text):
track = tracks[0]
else:
await utils.answer(message, self.strings["noResults"].format(text))
return
await self.inline.form(
self.strings["lyrics"].format(
track["title"], track["artists"], get_lyrics(self, track["url"])
)[:4092]
+ "",
reply_markup=[[{"text": self.strings["genius"], "url": track["url"]}]],
force_me=False,
message=message,
)
async def lyrics_inline_handler(self, query: GeekInlineQuery) -> None:
"""Search song"""
text = query.args
if not text:
return
tracks = search(text)
if not tracks:
await query.answer(
[
InlineQueryResultArticle(
id="-1",
title=self.strings["notFound"],
description=self.strings["couldn'tFind"],
thumb_url="https://img.icons8.com/stickers/100/000000/nothing-found.png",
input_message_content=InputTextMessageContent(
self.strings["noResults"].format(text),
parse_mode="HTML",
),
)
],
cache_time=0,
)
return
res = [
InlineQueryResultArticle(
id=track["id"],
title=track["title"],
description=track["artists"],
thumb_url=add_protocol(track["pic"]),
input_message_content=InputTextMessageContent(
self.strings["loading"].format(
track["title"], track["artists"], track["url"]
),
parse_mode="HTML",
disable_web_page_preview=True,
),
reply_markup=InlineKeyboardMarkup().add(
InlineKeyboardButton(self.strings["genius"], url=track["url"])
),
)
for track in tracks[:50]
]
await query.answer(res, cache_time=0)
async def slyricscmd(self, message: Message):
"""Get lyrics from your current Spotify playback (Needs SpotifyNow module)"""
check = self.db.get("SpotifyNow", "acs_tkn", "404")
if check == "404":
await utils.answer(message, self.strings["noSpotify"])
return
elif check is None:
await utils.answer(message, self.strings["sauth"])
return
try:
sp = spotipy.Spotify(
auth=self.db.get("SpotifyNow", "acs_tkn")["access_token"]
)
current_playback = sp.current_playback()
except Exception:
await utils.answer(message, self.strings["SpotifyError"])
return
try:
track = current_playback["item"]["name"]
except Exception:
track = None
try:
artists = ", ".join(
[artist["name"] for artist in current_playback["item"]["artists"]]
)
except Exception:
artists = None
text = f"{artists} {track}"
if tracks := search(text):
track = tracks[0]
else:
await utils.answer(message, self.strings["noResults"].format(text))
return
await self.inline.form(
self.strings["lyrics"].format(
track["title"], track["artists"], get_lyrics(self, track["url"])
)[:4092]
+ "",
reply_markup=[[{"text": self.strings["genius"], "url": track["url"]}]],
force_me=False,
message=message,
)
async def watcher(self, message: Message) -> None:
if (
getattr(message, "out", False)
and getattr(message, "via_bot_id", False)
and message.via_bot_id == self.bot_id
and (
"Loading lyrics for" in getattr(message, "raw_text", "")
or "Загрузка текста песни" in getattr(message, "raw_text", "")
)
):
e = message.entities
track = {
"title": message.raw_text[e[0].offset : e[0].offset + e[0].length],
"artists": message.raw_text[e[1].offset : e[1].offset + e[1].length],
"url": message.raw_text.splitlines()[1],
}
await self.inline.form(
self.strings["lyrics"].format(
track["title"], track["artists"], get_lyrics(self, track["url"])
)[:4092]
+ "",
reply_markup=[[{"text": self.strings["genius"], "url": track["url"]}]],
force_me=False,
message=message,
)
return