mirror of
https://github.com/MuRuLOSE/limoka.git
synced 2026-06-16 14:34:17 +02:00
Compare commits
2 Commits
3128c5d7c1
...
d203b114a8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d203b114a8 | ||
|
|
0e4c07b5b5 |
370
SunnexGB/Heroku-Modules/LiveLyrics.py
Normal file
370
SunnexGB/Heroku-Modules/LiveLyrics.py
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
# meta developer: @SunnexGB
|
||||||
|
# requires: aiohttp
|
||||||
|
# meta pic: https://r2.fakecrime.bio/uploads/6725e5a0-0c9e-48ed-be85-dfd857c2aa5f.jpg
|
||||||
|
# meta banner: https://r2.fakecrime.bio/uploads/6725e5a0-0c9e-48ed-be85-dfd857c2aa5f.jpg
|
||||||
|
# meta fhsdesc: Spotify, YaMusic, music, музыка, Lyrics, слова, текст, трек, песня
|
||||||
|
|
||||||
|
__version__ = (1, 0, 0)
|
||||||
|
|
||||||
|
from herokutl.types import Message
|
||||||
|
from .. import loader, utils
|
||||||
|
from ..types import InlineCall
|
||||||
|
import aiohttp
|
||||||
|
import asyncio
|
||||||
|
import re
|
||||||
|
|
||||||
|
@loader.tds
|
||||||
|
class LiveLyrics(loader.Module):
|
||||||
|
"""life lyrics current song"""
|
||||||
|
|
||||||
|
strings = {
|
||||||
|
"name": "LiveLyrics",
|
||||||
|
"no_spotifymod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod not found,but u can install it. You can also support developer: </b> @ke_mods",
|
||||||
|
"no_yamusic": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod not found,but u can install it. You can also support developer: </b> @codrago_m",
|
||||||
|
"no_auth_spotify": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages.</b>",
|
||||||
|
"no_auth_yamusic": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages and setup token to continue.</b>",
|
||||||
|
"no_spotify": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on Spotify.</b>",
|
||||||
|
"no_ym": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on YaMusic.</b>",
|
||||||
|
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Lyrics not found for:</b> <code>{}</code>",
|
||||||
|
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Lyrics are not synchronized.</i>\n\n",
|
||||||
|
"TrackEnded": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Playback ended or track changed.",
|
||||||
|
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
||||||
|
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Oopsi, looks like we've got a timeout here</b>.",
|
||||||
|
"yamusic_installed": "YaMusic installed!",
|
||||||
|
"spotify_installed": "SpotifyMod installed!",
|
||||||
|
"song_link": "🔗 song.link",
|
||||||
|
"close": "❌ Close",
|
||||||
|
"ok": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_ru = {
|
||||||
|
"_cls_doc": "Лайв слова текущей песни.",
|
||||||
|
"no_spotifymod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod не найден,но его можно установить. Вы также можете поддержать разработчика: </b> @ke_mods",
|
||||||
|
"no_yamusic": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod не найден, но его можно установить. Вы также можете поддержать разработчика: </b> @codrago_m",
|
||||||
|
"no_auth_spotify": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji> <b>Вы не авторизованы в SpotifyMod. Перейдите в Избранное.</b>",
|
||||||
|
"no_auth_yamusic": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> Вы не авторизированы в YaMusicMod, перейдите в Избранное и установите токен для продолжения работы.</b>",
|
||||||
|
"no_spotify": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В Spotify ничего не играет.</b>",
|
||||||
|
"no_ym": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В YaMusic ничего не играет.</b>",
|
||||||
|
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Текст не найден для:</b> <code>{}</code>",
|
||||||
|
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Текст не синхронизирован.</i>\n\n",
|
||||||
|
"TrackEnded": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Воспроизведение завершено или трек сменился.",
|
||||||
|
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
||||||
|
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Упси, похоже кто то словил таймаут.</b>.",
|
||||||
|
"yamusic_installed": "YaMusic Установлен!",
|
||||||
|
"spotify_installed": "SpotifyMod Установлен!",
|
||||||
|
"song_link": "🔗 song.link",
|
||||||
|
"close": "❌ Закрыть",
|
||||||
|
"ok": "OK",
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._active_tasks: dict = {}
|
||||||
|
self.config = loader.ModuleConfig(
|
||||||
|
loader.ConfigValue(
|
||||||
|
"emoji_current",
|
||||||
|
"<tg-emoji emoji-id='5215679757366089921'>🤯</tg-emoji>",
|
||||||
|
"Emoji for the current line",
|
||||||
|
validator=loader.validators.String(),
|
||||||
|
),
|
||||||
|
loader.ConfigValue(
|
||||||
|
"dot",
|
||||||
|
"♪",
|
||||||
|
"instrumental_emoji or text",
|
||||||
|
validator=loader.validators.String(),
|
||||||
|
),
|
||||||
|
loader.ConfigValue(
|
||||||
|
"text_lines",
|
||||||
|
"6",
|
||||||
|
"Count lines in message, with synchronized text",
|
||||||
|
validator=loader.validators.Integer(),
|
||||||
|
),
|
||||||
|
loader.ConfigValue(
|
||||||
|
"lyrics_delay",
|
||||||
|
0.5,
|
||||||
|
"delay in switching to a new timing sector with words",
|
||||||
|
),
|
||||||
|
loader.ConfigValue(
|
||||||
|
"request_timeout",
|
||||||
|
12,
|
||||||
|
"timeout value",
|
||||||
|
validator=loader.validators.Integer(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def install_mod(self, call: InlineCall, heroku_module: str):
|
||||||
|
if heroku_module == "SpotifyMod":
|
||||||
|
download_url = "https://raw.githubusercontent.com/radiocycle/Modules/refs/heads/master/SpotifyMod.py"
|
||||||
|
module_name = "SpotifyMod"
|
||||||
|
installed_btn = self.strings["spotify_installed"]
|
||||||
|
no_auth_str = self.strings["no_auth_spotify"]
|
||||||
|
auth_command = "sauth"
|
||||||
|
else:
|
||||||
|
download_url = "https://raw.githubusercontent.com/coddrago/modules/main/YaMusic.py"
|
||||||
|
module_name = "YaMusic"
|
||||||
|
installed_btn = self.strings["yamusic_installed"]
|
||||||
|
no_auth_str = self.strings["no_auth_yamusic"]
|
||||||
|
auth_command = "yguide"
|
||||||
|
try:
|
||||||
|
m = self.lookup("loader")
|
||||||
|
await m.download_and_install(download_url)
|
||||||
|
await call.answer(installed_btn, show_alert=True)
|
||||||
|
mod = self.lookup(module_name)
|
||||||
|
if heroku_module == "SpotifyMod":
|
||||||
|
authorized = mod and mod.get("acs_tkn")
|
||||||
|
else:
|
||||||
|
authorized = mod and mod.get("__config__")["token"]
|
||||||
|
if not authorized:
|
||||||
|
await self.invoke(auth_command, " ", "me")
|
||||||
|
await call.edit(
|
||||||
|
no_auth_str,
|
||||||
|
reply_markup=[
|
||||||
|
[
|
||||||
|
{"text": self.strings["ok"], "callback": self.close}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await call.delete()
|
||||||
|
except Exception as e:
|
||||||
|
await call.answer(f"Error: {e}", show_alert=True)
|
||||||
|
|
||||||
|
def close(self, call: InlineCall):
|
||||||
|
return call.delete()
|
||||||
|
|
||||||
|
async def get_lyrics(self, artist: str, track: str):
|
||||||
|
ClearTimeSections = re.sub(r"\(.*?\)|\[.*?\]", "", track).strip()
|
||||||
|
try:
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.get(
|
||||||
|
"https://lrclib.net/api/search",
|
||||||
|
params={"track_name": ClearTimeSections, "artist_name": artist},
|
||||||
|
timeout=aiohttp.ClientTimeout(total=self.config["request_timeout"]),
|
||||||
|
) as resp:
|
||||||
|
if resp.status == 200:
|
||||||
|
result = await resp.json()
|
||||||
|
return result[0] if result else None
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
return {"timeout": True}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def parse_synced(self, synced_text: str) -> list:
|
||||||
|
lines = []
|
||||||
|
for line in synced_text.split("\n"):
|
||||||
|
m = re.search(r"\[(\d+):(\d+\.\d+)\](.*)", line)
|
||||||
|
if m:
|
||||||
|
mins, secs, text = m.groups()
|
||||||
|
lines.append({
|
||||||
|
"time": (int(mins) * 60 + float(secs)) * 1000,
|
||||||
|
"text": text.strip(),
|
||||||
|
})
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def build_lyrics(self, artist, track, lines, plain, progress_ms, not_synced_str):
|
||||||
|
header = self.strings["header"].format(
|
||||||
|
utils.escape_html(artist),
|
||||||
|
utils.escape_html(track),
|
||||||
|
)
|
||||||
|
if lines:
|
||||||
|
curr_idx = 0
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if progress_ms >= line["time"]:
|
||||||
|
curr_idx = i
|
||||||
|
l_start = max(0, curr_idx - 1)
|
||||||
|
l_end = min(len(lines), l_start + self.config["text_lines"])
|
||||||
|
rows = []
|
||||||
|
for i in range(l_start, l_end):
|
||||||
|
t = lines[i]["text"] or self.config["dot"]
|
||||||
|
if i == curr_idx:
|
||||||
|
rows.append(f"<b>{self.config['emoji_current']} {utils.escape_html(t)}</b>")
|
||||||
|
else:
|
||||||
|
rows.append(f"<code>{utils.escape_html(t)}</code>")
|
||||||
|
return header + "\n".join(rows)
|
||||||
|
return header + not_synced_str + f"<blockquote expandable>{utils.escape_html((plain or '')[:4000])}</blockquote>"
|
||||||
|
|
||||||
|
def build_keyboard(self, song_url):
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
{"text": self.strings["song_link"], "url": song_url}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"text": self.strings["close"], "callback": self.close_cb}
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
async def close_cb(self, call: InlineCall):
|
||||||
|
for track_id, task in list(self._active_tasks.items()):
|
||||||
|
task.cancel()
|
||||||
|
self._active_tasks.pop(track_id, None)
|
||||||
|
try:
|
||||||
|
await call.answer()
|
||||||
|
await call.delete()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def za_loop_a(self, form, mod, track_id, artist_name, track_name, song_url, lines, plain, not_synced_str, heroku_module: str):
|
||||||
|
buffer_clipboard = ""
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
if heroku_module == "SpotifyMod":
|
||||||
|
pb = mod.sp.current_playback()
|
||||||
|
TrackEnded = not pb or not pb.get("item") or pb["item"]["id"] != track_id
|
||||||
|
else:
|
||||||
|
pb = await mod._YaMusicMod__get_now_playing()
|
||||||
|
TrackEnded = not pb or not pb.get("track") or pb["track"]["track_id"] != track_id
|
||||||
|
if TrackEnded:
|
||||||
|
try:
|
||||||
|
await form.edit(
|
||||||
|
self.strings["TrackEnded"],
|
||||||
|
reply_markup=[[{"text": self.strings["close"], "callback": self.close_cb}]],
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
break
|
||||||
|
prog = pb.get("progress_ms", 0)
|
||||||
|
content = self.build_lyrics(artist_name, track_name, lines, plain, prog, not_synced_str)
|
||||||
|
if content != buffer_clipboard:
|
||||||
|
try:
|
||||||
|
await form.edit(content, reply_markup=self.build_keyboard(song_url))
|
||||||
|
buffer_clipboard = content
|
||||||
|
except Exception:
|
||||||
|
break
|
||||||
|
if not lines:
|
||||||
|
break
|
||||||
|
await asyncio.sleep(self.config["lyrics_delay"])
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
raise
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
self._active_tasks.pop(track_id, None)
|
||||||
|
|
||||||
|
@loader.command(ru_doc="- показать синхронизированный текст песни")
|
||||||
|
async def snowlcmd(self, message: Message):
|
||||||
|
"""- show synchronized lyrics for current track"""
|
||||||
|
mod = self.lookup("SpotifyMod")
|
||||||
|
if not mod:
|
||||||
|
form = await self.inline.form("⏳", message=message)
|
||||||
|
await form.edit(
|
||||||
|
self.strings["no_spotifymod"],
|
||||||
|
reply_markup=[
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"text": self.strings["spotify_installed"],
|
||||||
|
"callback": self.install_mod,
|
||||||
|
"kwargs": {"heroku_module": "SpotifyMod"}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if not mod.get("acs_tkn"):
|
||||||
|
await self.invoke("sauth", " ", "me")
|
||||||
|
form = await self.inline.form("⏳", message=message)
|
||||||
|
await form.edit(
|
||||||
|
self.strings["no_auth_spotify"],
|
||||||
|
reply_markup=[[{"text": self.strings["ok"], "callback": self.close}]],
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
playback = mod.sp.current_playback()
|
||||||
|
if not playback or not playback.get("item"):
|
||||||
|
return await utils.answer(message, self.strings["no_spotify"])
|
||||||
|
track = playback["item"]
|
||||||
|
track_id = track["id"]
|
||||||
|
artist_name = track["artists"][0]["name"]
|
||||||
|
track_name = track["name"]
|
||||||
|
song_url = f"https://song.link/s/{track_id}"
|
||||||
|
|
||||||
|
old = self._active_tasks.pop(track_id, None)
|
||||||
|
if old:
|
||||||
|
old.cancel()
|
||||||
|
|
||||||
|
data = await self.get_lyrics(artist_name, track_name)
|
||||||
|
if data and data.get("timeout"):
|
||||||
|
return await utils.answer(message, self.strings["timeout"])
|
||||||
|
if not data or data.get("instrumental"):
|
||||||
|
return await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings["no_lyrics"].format(f"{utils.escape_html(track_name)} - {utils.escape_html(artist_name)}"),
|
||||||
|
)
|
||||||
|
|
||||||
|
synced_raw = data.get("syncedLyrics")
|
||||||
|
plain = data.get("plainLyrics", "")
|
||||||
|
lines = self.parse_synced(synced_raw) if synced_raw else []
|
||||||
|
not_synced_str = self.strings["not_synced"]
|
||||||
|
form = await self.inline.form(
|
||||||
|
text=self.build_lyrics(artist_name, track_name, lines, plain, playback.get("progress_ms", 0), not_synced_str),
|
||||||
|
message=message,
|
||||||
|
reply_markup=self.build_keyboard(song_url),
|
||||||
|
)
|
||||||
|
|
||||||
|
self._active_tasks[track_id] = asyncio.ensure_future(
|
||||||
|
self.za_loop_a(form, mod, track_id, artist_name, track_name, song_url, lines, plain, not_synced_str, heroku_module="SpotifyMod")
|
||||||
|
)
|
||||||
|
|
||||||
|
@loader.command(ru_doc="- показать синхронизированный текст песни")
|
||||||
|
async def ynowlcmd(self, message: Message):
|
||||||
|
"""- show synchronized lyrics for current track"""
|
||||||
|
mod = self.lookup("YaMusic")
|
||||||
|
if not mod:
|
||||||
|
form = await self.inline.form("⏳", message=message)
|
||||||
|
await form.edit(
|
||||||
|
self.strings["no_yamusic"],
|
||||||
|
reply_markup=[
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"text": "Install YaMusicMod",
|
||||||
|
"callback": self.install_mod,
|
||||||
|
"kwargs": {"heroku_module": "YaMusic"}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return
|
||||||
|
if not mod.get("__config__")["token"]:
|
||||||
|
await self.invoke("yguide", " ", "me")
|
||||||
|
form = await self.inline.form("⏳", message=message)
|
||||||
|
await form.edit(
|
||||||
|
self.strings["no_auth_yamusic"],
|
||||||
|
reply_markup=[[{"text": self.strings["ok"], "callback": self.close}]],
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
playback = await mod._YaMusicMod__get_now_playing()
|
||||||
|
if not playback or not playback.get("track"):
|
||||||
|
return await utils.answer(message, self.strings["no_ym"])
|
||||||
|
track = playback["track"]
|
||||||
|
track_id = track["track_id"]
|
||||||
|
artist_name = ", ".join(track["artist"])
|
||||||
|
track_name = track["title"]
|
||||||
|
song_url = f"https://song.link/s/{track_id}"
|
||||||
|
|
||||||
|
old = self._active_tasks.pop(track_id, None)
|
||||||
|
if old:
|
||||||
|
old.cancel()
|
||||||
|
|
||||||
|
data = await self.get_lyrics(artist_name, track_name)
|
||||||
|
if data and data.get("timeout"):
|
||||||
|
return await utils.answer(message, self.strings["timeout"])
|
||||||
|
if not data or data.get("instrumental"):
|
||||||
|
return await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings["no_lyrics"].format(f"{utils.escape_html(track_name)} - {utils.escape_html(artist_name)}"),
|
||||||
|
)
|
||||||
|
|
||||||
|
synced_raw = data.get("syncedLyrics")
|
||||||
|
plain = data.get("plainLyrics", "")
|
||||||
|
lines = self.parse_synced(synced_raw) if synced_raw else []
|
||||||
|
not_synced_str = self.strings["not_synced"]
|
||||||
|
|
||||||
|
form = await self.inline.form(
|
||||||
|
text=self.build_lyrics(artist_name, track_name, lines, plain, playback.get("progress_ms", 0), not_synced_str),
|
||||||
|
message=message,
|
||||||
|
reply_markup=self.build_keyboard(song_url),
|
||||||
|
)
|
||||||
|
|
||||||
|
self._active_tasks[track_id] = asyncio.ensure_future(
|
||||||
|
self.za_loop_a(form, mod, track_id, artist_name, track_name, song_url, lines, plain, not_synced_str, heroku_module="YaMusic")
|
||||||
|
)
|
||||||
@@ -1,285 +1,241 @@
|
|||||||
# meta developer: @SunnexGB
|
# meta developer: @SunnexGB
|
||||||
# requires: aiohttp
|
|
||||||
# meta pic: https://r2.fakecrime.bio/uploads/f49a9294-36ad-4fc4-801f-48cb049111d6.jpg
|
# meta pic: https://r2.fakecrime.bio/uploads/f49a9294-36ad-4fc4-801f-48cb049111d6.jpg
|
||||||
# meta banner: https://r2.fakecrime.bio/uploads/f49a9294-36ad-4fc4-801f-48cb049111d6.jpg
|
# meta banner: https://r2.fakecrime.bio/uploads/f49a9294-36ad-4fc4-801f-48cb049111d6.jpg
|
||||||
# meta fhsdesc: Spotify, music, музыка, спотифай,Lyrics, слова, текст, трек, песня
|
# meta fhsdesc: Spotify, music, музыка, спотифай,Lyrics, слова, текст, трек, песня
|
||||||
# все же я не знаю трек или сонг, так что пусть будет трек, а не сонг потому что интуитивнее поняттнее,наверное?
|
# все же я не знаю трек или сонг, так что пусть будет трек, а не сонг потому что интуитивнее поняттнее,наверное?
|
||||||
# крутой баннер да?
|
# крутой баннер да?
|
||||||
#current version
|
#current version
|
||||||
__version__ = (1, 1, 2)
|
__version__ = (1, 1, 3)
|
||||||
|
|
||||||
from herokutl.types import Message
|
from herokutl.types import Message
|
||||||
from .. import loader, utils
|
from .. import loader, utils
|
||||||
from ..types import InlineCall
|
from ..types import InlineCall
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class SpotifyLyrics(loader.Module):
|
class SpotifyLyrics(loader.Module):
|
||||||
"""life lyrics current song"""
|
|
||||||
|
|
||||||
strings = {
|
strings = {
|
||||||
"name": "SpotifyLyrics",
|
"name": "migration",
|
||||||
"no_spotifymod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod not found,but u can install it. You can also support developer: </b> @ke_mods",
|
"no_SpotifyLyrics": "u're not use SpotifyLyrics,install my new module.",
|
||||||
"no_auth": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages.</b>",
|
"inline_msg": "if u ready to migration pls click on the button.",
|
||||||
"no_spotify": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on Spotify.</b>",
|
"already": "module already install, u're ready for migration ur db?",
|
||||||
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Lyrics not found for:</b> <code>{}</code>",
|
"restartf": "u ready restart ur ub?",
|
||||||
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Lyrics are not synchronized.</i>\n\n",
|
"restartf_btn": "Ok",
|
||||||
"finished": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Playback ended or track changed.",
|
"done": "migration is done.",
|
||||||
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"confirm": "confirm",
|
||||||
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Oopsi, looks like we've got a timeout here</b>.",
|
"install": "install LiveLyrics",
|
||||||
|
"close": "close",
|
||||||
|
"migrate_db": "Yep"
|
||||||
}
|
}
|
||||||
|
|
||||||
strings_ru = {
|
strings_ru = {
|
||||||
"cls_doc": "Лайв слова текущей песни.",
|
"no_SpotifyLyrics": "ты не юзал SpotifyLyrics,установи новый модуль.",
|
||||||
"no_spotifymod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod не найден,но его можно установить. Вы также можете поддержать разработчика: </b> @ke_mods",
|
"inline_msg": "если вы готовы к миграции нажмите на кнопку ниже.",
|
||||||
"no_auth": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> Вы не авторизированы в SpotifyMod, перейдите в Избранное.</b>",
|
"already": "модуль уже стоиит,готовы к переносу данных?",
|
||||||
"no_spotify": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В Spotify ничего не играет.</b>",
|
"restartf": "вы готовы к перезапуску юб?",
|
||||||
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Текст не найден для:</b> <code>{}</code>",
|
"restartf_btn": "Лан",
|
||||||
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Текст не синхронизирован.</i>\n\n",
|
"done": "миграция завершена.",
|
||||||
"finished": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Воспроизведение завершено или трек сменился.",
|
"confirm": "подтвердить",
|
||||||
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"install": "установить LiveLyrics",
|
||||||
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Упси, похоже кто то словил таймаут.</b>.",
|
"close": "закрыть",
|
||||||
|
"migrate_db": "Ага"
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self):
|
async def install_livelyrics(self, call: InlineCall):
|
||||||
self._active_tasks: dict = {}
|
m = self.lookup("Modules") or self.lookup("loader")
|
||||||
self.config = loader.ModuleConfig(
|
await m.download_and_install("https://raw.githubusercontent.com/SunnexGB/Heroku-Modules/refs/heads/main/LiveLyrics.py")
|
||||||
loader.ConfigValue(
|
await call.delete()
|
||||||
"emoji_current",
|
|
||||||
"<tg-emoji emoji-id='5215679757366089921'>🤯</tg-emoji>",
|
async def confirm(self, call: InlineCall):
|
||||||
"Emoji for current line",
|
config = self.db.get("SpotifyLyrics", "__config__") or {}
|
||||||
validator=loader.validators.String(),
|
self.db.set("LiveLyrics", "__config__", config)
|
||||||
),
|
await asyncio.sleep(1)
|
||||||
loader.ConfigValue(
|
await self.invoke("unloadmod", "-f SpotifyLyrics", "me")
|
||||||
"dot",
|
await call.edit(self.strings["done"])
|
||||||
"♪",
|
await asyncio.sleep(2)
|
||||||
"instrumental_emoji or text",
|
await call.edit(
|
||||||
validator=loader.validators.String(),
|
self.strings["restartf"],
|
||||||
),
|
reply_markup=[
|
||||||
loader.ConfigValue(
|
[{"text": self.strings["restartf_btn"], "callback": self.restartf}],
|
||||||
"lyrics_delay",
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
0.5,
|
],
|
||||||
"delay in switching to a new timing sector with words",
|
)
|
||||||
),
|
|
||||||
loader.ConfigValue(
|
async def migrate_db(self, call: InlineCall):
|
||||||
"request_timeout",
|
await call.edit(
|
||||||
12,
|
self.strings["inline_msg"],
|
||||||
"timeout value",
|
reply_markup=[
|
||||||
),
|
[{"text": self.strings["confirm"], "callback": self.confirm}],
|
||||||
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
async def install_spotifymod(self, call: InlineCall):
|
async def restartf(self, call: InlineCall):
|
||||||
mod_url = "https://raw.githubusercontent.com/radiocycle/Modules/refs/heads/master/SpotifyMod.py"
|
await call.delete()
|
||||||
try:
|
await self.invoke("restart", "-f", "me")
|
||||||
m = self.lookup("Modules") or self.lookup("loader")
|
|
||||||
await m.download_and_install(mod_url)
|
|
||||||
await call.answer("SpotifyMod installed!", show_alert=True)
|
|
||||||
mod = self.lookup("SpotifyMod")
|
|
||||||
acs_tkn = mod.get("acs_tkn") if mod else None
|
|
||||||
if not acs_tkn:
|
|
||||||
await self.invoke("sauth", " ", "me")
|
|
||||||
await call.edit(
|
|
||||||
self.strings("no_auth"),
|
|
||||||
reply_markup=[[{"text": "Хорошо", "callback": self.close}]],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await call.delete()
|
|
||||||
except Exception as e:
|
|
||||||
await call.answer(f"Error! Check logs.\n{e}", show_alert=True)
|
|
||||||
|
|
||||||
def close(self, call: InlineCall):
|
async def close(self, call: InlineCall):
|
||||||
return call.delete()
|
await call.delete()
|
||||||
|
|
||||||
async def _get_lyrics(self, artist: str, track: str):
|
@loader.command()
|
||||||
clean_track = re.sub(r"\(.*?\)|\[.*?\]", "", track).strip()
|
async def snowl(self, message: Message):
|
||||||
try:
|
SL_cfg = self.db.get("SpotifyLyrics", "__config__")
|
||||||
async with aiohttp.ClientSession() as session:
|
if SL_cfg is None:
|
||||||
async with session.get(
|
|
||||||
"https://lrclib.net/api/search",
|
|
||||||
params={"track_name": clean_track, "artist_name": artist},
|
|
||||||
timeout=aiohttp.ClientTimeout(total=(self.config["request_timeout"])),
|
|
||||||
) as resp:
|
|
||||||
if resp.status == 200:
|
|
||||||
res = await resp.json()
|
|
||||||
return res[0] if res else None
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
return {"timeout": True}
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _parse_synced(self, synced_text: str) -> list:
|
|
||||||
lines = []
|
|
||||||
for line in synced_text.split("\n"):
|
|
||||||
m = re.search(r"\[(\d+):(\d+\.\d+)\](.*)", line)
|
|
||||||
if m:
|
|
||||||
mins, secs, text = m.groups()
|
|
||||||
lines.append({
|
|
||||||
"time": (int(mins) * 60 + float(secs)) * 1000,
|
|
||||||
"text": text.strip(),
|
|
||||||
})
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def _build_content(self, artist, track, lines, plain, progress_ms, not_synced_str):
|
|
||||||
header = self.strings("header").format(
|
|
||||||
utils.escape_html(artist),
|
|
||||||
utils.escape_html(track),
|
|
||||||
)
|
|
||||||
if lines:
|
|
||||||
curr_idx = 0
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if progress_ms >= line["time"]:
|
|
||||||
curr_idx = i
|
|
||||||
win_start = max(0, curr_idx - 1)
|
|
||||||
win_end = min(len(lines), curr_idx + 6)
|
|
||||||
rows = []
|
|
||||||
for i in range(win_start, win_end):
|
|
||||||
t = lines[i]["text"] or self.config["dot"]
|
|
||||||
if i == curr_idx:
|
|
||||||
rows.append(
|
|
||||||
f"<b>{self.config['emoji_current']} {utils.escape_html(t)}</b>"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
rows.append(f"<code>{utils.escape_html(t)}</code>")
|
|
||||||
return header + "\n".join(rows)
|
|
||||||
else:
|
|
||||||
return header + not_synced_str + f"<blockquote expandable>{utils.escape_html((plain or '')[:4000])}</blockquote>"
|
|
||||||
|
|
||||||
def _markup(self, song_url):
|
|
||||||
return [
|
|
||||||
[{"text": "🔗 song.link", "url": song_url}],
|
|
||||||
[{"text": "❌ Close", "callback": self._close_cb}],
|
|
||||||
]
|
|
||||||
|
|
||||||
async def _close_cb(self, call):
|
|
||||||
for track_id, task in list(self._active_tasks.items()):
|
|
||||||
task.cancel()
|
|
||||||
self._active_tasks.pop(track_id, None)
|
|
||||||
try:
|
|
||||||
await call.answer()
|
|
||||||
await call.delete()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def run_loop(self, form, mod, track_id, artist_name, track_name, song_url, lines, plain, not_synced_str):
|
|
||||||
last_display = ""
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
pb = mod.sp.current_playback()
|
|
||||||
if not pb or not pb.get("item") or pb["item"]["id"] != track_id:
|
|
||||||
try:
|
|
||||||
await form.edit(
|
|
||||||
self.strings("finished"),
|
|
||||||
reply_markup=[[{"text": "❌ Close", "callback": self._close_cb}]],
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
break
|
|
||||||
|
|
||||||
prog = pb.get("progress_ms", 0)
|
|
||||||
content = self._build_content(
|
|
||||||
artist_name, track_name, lines, plain, prog, not_synced_str
|
|
||||||
)
|
|
||||||
|
|
||||||
if content != last_display:
|
|
||||||
try:
|
|
||||||
await form.edit(content, reply_markup=self._markup(song_url))
|
|
||||||
last_display = content
|
|
||||||
except Exception:
|
|
||||||
break
|
|
||||||
|
|
||||||
if not lines:
|
|
||||||
break
|
|
||||||
|
|
||||||
await asyncio.sleep(self.config["lyrics_delay"])
|
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
self._active_tasks.pop(track_id, None)
|
|
||||||
|
|
||||||
@loader.command(ru_doc="- показать синхронизированный текст песни")
|
|
||||||
async def snowlcmd(self, message: Message):
|
|
||||||
"""- show synchronized lyrics for current Spotify track"""
|
|
||||||
mod = self.lookup("SpotifyMod")
|
|
||||||
if not mod:
|
|
||||||
form = await self.inline.form("⏳", message=message)
|
|
||||||
await form.edit(
|
|
||||||
self.strings("no_spotifymod"),
|
|
||||||
reply_markup=[[{"text": "Install SpotifyMod", "callback": self.install_spotifymod}]],
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
acs_tkn = mod.get("acs_tkn")
|
|
||||||
if not acs_tkn:
|
|
||||||
await self.invoke("sauth", " ", "me")
|
|
||||||
form = await self.inline.form("⏳", message=message)
|
|
||||||
await form.edit(
|
|
||||||
self.strings("no_auth"),
|
|
||||||
reply_markup=[[{"text": "Хорошо", "callback": self.close}]],
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
playback = mod.sp.current_playback()
|
|
||||||
if not playback or not playback.get("item"):
|
|
||||||
return await utils.answer(message, self.strings("no_spotify"))
|
|
||||||
|
|
||||||
track = playback["item"]
|
|
||||||
track_id = track["id"]
|
|
||||||
artist_name = track["artists"][0]["name"]
|
|
||||||
track_name = track["name"]
|
|
||||||
song_url = f"https://song.link/s/{track_id}"
|
|
||||||
|
|
||||||
old = self._active_tasks.pop(track_id, None)
|
|
||||||
if old:
|
|
||||||
old.cancel()
|
|
||||||
|
|
||||||
data = await self._get_lyrics(artist_name, track_name)
|
|
||||||
if data and data.get("timeout"):
|
|
||||||
return utils.answer(
|
|
||||||
message,
|
|
||||||
self.strings["timeout"]
|
|
||||||
)
|
|
||||||
if not data or data.get("instrumental"):
|
|
||||||
track_and_artist = f"{utils.escape_html(track_name)} - {utils.escape_html(artist_name)}"
|
|
||||||
return await utils.answer(
|
return await utils.answer(
|
||||||
message,
|
message,
|
||||||
self.strings("no_lyrics").format(track_and_artist),
|
self.strings["no_SpotifyLyrics"],
|
||||||
|
reply_markup=[
|
||||||
|
[{"text": self.strings["install"], "callback": self.install_livelyrics}],
|
||||||
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
if self.lookup("LiveLyrics"):
|
||||||
synced_raw = data.get("syncedLyrics")
|
return await utils.answer(
|
||||||
plain = data.get("plainLyrics", "")
|
message,
|
||||||
|
"модуль уже стоиит,готовы к переносу данных",
|
||||||
lines = self._parse_synced(synced_raw) if synced_raw else []
|
reply_markup=[
|
||||||
not_synced_str = self.strings("not_synced")
|
[{"text": self.strings["migrate_db"], "callback": self.migrate_db}],
|
||||||
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
prog = playback.get("progress_ms", 0)
|
],
|
||||||
initial_content = self._build_content(
|
|
||||||
artist_name, track_name, lines, plain, prog, not_synced_str
|
|
||||||
)
|
|
||||||
|
|
||||||
form = await self.inline.form(
|
|
||||||
text=initial_content,
|
|
||||||
message=message,
|
|
||||||
reply_markup=self._markup(song_url),
|
|
||||||
)
|
|
||||||
|
|
||||||
task = asyncio.ensure_future(
|
|
||||||
self.run_loop(
|
|
||||||
form=form,
|
|
||||||
mod=mod,
|
|
||||||
track_id=track_id,
|
|
||||||
artist_name=artist_name,
|
|
||||||
track_name=track_name,
|
|
||||||
song_url=song_url,
|
|
||||||
lines=lines,
|
|
||||||
plain=plain,
|
|
||||||
not_synced_str=not_synced_str,
|
|
||||||
)
|
)
|
||||||
|
await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings["inline_msg"],
|
||||||
|
reply_markup=[
|
||||||
|
[{"text": self.strings["confirm"], "callback": self.confirm}],
|
||||||
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
|
],
|
||||||
)
|
)
|
||||||
self._active_tasks[track_id] = task
|
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⠤⠤⣄⠠⠤⣤⠤⢤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠁⠀⠀⠀⣠⠖⠉⣀⡀⣀⣤⠍⢩⣵⡢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠖⠋⠁⠀⠀⠀⠀⢀⣴⠊⠀⣠⠞⣠⠞⠉⢳⣦⠀⡈⠻⣦⠑⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠖⠉⠀⠀⠀⠀⠀⠀⣠⣴⡿⠁⠀⡰⢁⡾⠁⠐⠃⢸⡇⠀⠸⡄⠀⠀⠈⠷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣆⠀⠀⠀⠀⣀⣠⡴⡿⠁⣼⡅⠀⣰⢣⢿⡇⡴⠀⠀⣾⡅⠀⠀⣧⠀⠀⠀⠀⢈⢂⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠻⠿⠿⠷⠒⠒⠋⠁⡏⠸⠁⣸⣿⠇⢀⣧⠏⢸⡿⠁⠀⡼⠙⣧⠀⢀⣿⡄⢀⠠⠀⠘⡄⢡⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠁⣤⣠⣯⢿⠀⢸⣟⡴⡾⣳⣴⣾⡷⢠⠛⢆⣾⣿⡇⡀⠀⣦⠀⡇⠀⢣⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢠⡄⠀⡄⠀⠀⠀⢀⣒⣒⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⢼⠀⣿⡿⣿⢸⠐⣿⣿⣿⣿⡿⣶⡿⢷⣯⣮⣾⢯⡟⣇⡇⣸⡏⢠⣠⠀⠀⢣⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⣿⣿⣿⣦⡄⣤⡾⢿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⢸⢠⣿⣿⣿⣼⣇⡿⣟⠛⠛⠃⠀⠀⠁⠉⣠⣶⣷⣄⣿⣼⣿⡆⣸⣧⡀⠀⠀⢆⠀⠀⠀⠀
|
||||||
|
# ⢸⣿⣿⡿⠛⠋⠉⢩⣍⣉⣻⡇⠀⠀⠀⠀⠀⠀⠀⠀⡇⣼⣿⢹⢿⡝⢿⣇⡈⠃⠀⠀⠀⠀⠀⠀⠛⢿⡏⣿⣿⢿⣿⡱⡸⠁⠈⠢⣀⠘⡆⠀⠀⠀
|
||||||
|
# ⠈⣿⡏⣤⠄⠘⠃⠸⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢰⢱⠻⡇⢸⠸⣷⡀⣿⡁⠀⠀⠀⠀⡀⠀⠀⠀⢀⡼⣯⠁⣾⣿⠁⠀⠀⠀⠀⠈⠑⠃⠀⠀⠀
|
||||||
|
# ⢠⣬⣼⣧⡀⠀⠀⠀⢹⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⣾⣿⡦⠧⠬⣧⡸⣿⣧⠙⢠⡀⠀⠀⠀⠀⣀⡤⠊⠀⣿⣰⢿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢸⣿⣿⣿⡀⢀⡀⠀⣸⣿⣿⡁⠀⠀⠀⠀⠀⠀⣰⣯⠟⠛⠛⠛⢿⣭⣿⣿⠷⣶⣟⣷⣶⣒⡉⠁⠀⠀⠜⢹⣿⡼⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠈⠛⠛⠛⠛⠛⠛⠓⠛⠛⠛⠃⠀⠀⠀⠀⢀⢼⣿⣏⣰⣿⣷⣴⣦⠙⣿⣿⡛⠛⠿⠥⢯⣀⣈⡇⢀⠀⠚⢙⡞⠑⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⢽⣿⣿⢻⣿⣿⣟⣿⣿⢿⣿⢦⣄⠀⣀⣀⠉⠩⠿⣷⣾⣭⠑⠒⠢⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠏⠈⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣧⢽⣯⣁⠀⠀⠀⠀⠒⠗⢺⣿⣭⣤⣄⠙⠢⣀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠏⠀⠀⣿⡟⠈⠻⣿⣿⣻⣿⣿⣟⣡⣴⣿⣿⣷⡞⠒⠒⠶⠶⠶⠤⣽⡿⠽⠦⣄⣀⠑⡄⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠋⠀⢀⣴⣿⡇⠀⠀⠉⠻⣥⣽⠿⠋⠙⠻⣽⣿⣤⠃⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠈⠑⠳⣄⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⣠⠊⣼⣿⡇⠀⠀⠐⢿⡿⠁⠀⠀⠀⢀⣀⣩⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢢⡀⠀⠀
|
||||||
|
# ⠀⠀⣠⠤⢤⣀⣀⡀⠀⠀⠀⠀⢠⠏⢀⡜⠁⢰⠇⣿⣿⠀⠀⠀⣈⡇⠀⠀⠀⠀⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀
|
||||||
|
# ⠀⠀⠳⡀⠀⠀⠀⠉⠉⠙⠓⠒⠳⠤⠯⣄⡀⡞⠀⡿⣡⡴⠞⠋⢙⡇⠀⠀⠀⠀⢟⡛⠀⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀
|
||||||
|
# ⠀⠀⠀⠹⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠁⠈⣯⣉⠀⠀⠀⢸⡇⠀⠀⠀⢰⡶⠀⢠⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣧⠀⢰⠃⠟⢳⣄⠀⣾⡇⠀⠀⠀⠈⠀⣰⣯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡜⠁⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠈⠓⠛⠙⣹⡟⠉⠉⡇⠀⠀⠀⣿⠀⠞⡸⠀⡜⢿⣷⡈⢿⡀⠀⠀⠀⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣠⠤⢆⣴⠉⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⣴⠏⠀⠀⢠⡇⠀⠀⠀⣿⠀⠀⠁⢰⠁⢸⠻⣟⠾⡇⠀⢀⣾⣿⡇⣠⣴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣰⣾⣿⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⣼⠋⠀⠀⠀⢸⡇⠀⠀⠀⠈⠙⠒⠒⠢⠭⣍⠀⢸⠓⢤⠴⠚⣿⡉⠀⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣟⡏⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⡜⡽⠀⠀⠀⠀⢸⡇⠀⠀⠀⢀⣀⣀⣀⡀⠀⢸⠀⠺⠤⠼⢠⣾⡉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⠟⠻⣷⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⣸⢹⡇⠀⠀⠀⠀⢠⠏⠉⠉⠉⠉⠉⠉⠉⡝⢣⠘⡆⢰⣠⠞⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠘⡆⠀⢹⡄⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⢀⡇⣿⡇⠀⠀⠀⡰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⠷⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠃⠀⠸⡄⠸⡇⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⢸⠀⡿⣇⠀⣠⠎⠀⠀⠀⠀⠀⠀⠀⣠⠎⠀⢀⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡆⠈⣧⠀⠱⣸⣇⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⢾⠀⡇⢻⣾⠃⠀⠀⠀⠀⠀⠀⢠⢺⠃⠀⡴⢋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠇⠀⠘⡗⢆⠻⡏⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⢸⠀⡷⢁⠋⠓⠦⡴⠂⠀⠀⠀⣼⠃⢠⠎⠀⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠀⠀⠀⢸⠀⡄⠀⠘⠞⢱⣧⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⣨⣇⢳⡎⢀⡴⠻⠇⠀⠀⠀⠀⠃⢠⠋⠀⠀⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡞⢦⠑⠀⠀⠀⢇⠸⣇⠀⠀⠀
|
||||||
|
# ⠀⢀⢸⠃⠈⣦⣷⣅⡀⢀⡄⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⣇⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡃⠈⠃⠈⠐⠀⠈⢢⡓⢆⠀⠀
|
||||||
|
# ⢠⢃⡏⠀⣰⣿⠀⠉⠉⠉⡇⠀⠀⢀⠀⡞⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢦⡀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⣄⡀⠀⠀⢻⢸⠀⠀
|
||||||
|
# ⡇⢸⣾⢠⠇⢿⡀⠀⠀⠀⡧⠀⢰⡇⢸⠁⢰⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠋⠀⠀⢣⠀⠀⢱⠈⠒⢄⢸⠀⡇⠀
|
||||||
|
# ⠁⢸⢹⡼⠀⠀⠙⠒⢀⢜⡡⢠⠋⡇⡏⠀⢸⠀⠀⠀⠀⠀⠈⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠣⡀⠀⠀⡄⠀⠀⠀⢻⠀⠀⠀⠀⠀⢹⠀⡿⡄
|
||||||
|
# ⠀⠀⠈⠳⣤⢀⣠⠶⠓⢩⡡⠃⠀⢷⠀⠀⣼⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢄⠀⡇⠀⠀⠀⠈⢧⠀⠀⠀⠀⡎⡀⡗⢵
|
||||||
|
# ⠀⠀⠀⠀⠋⠉⠀⢀⡠⠋⠀⠀⠀⡎⠀⠀⠇⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢢⡁⠀⠀⠀⠀⠈⢧⠀⢀⡼⠞⣧⠁⢸
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⢰⠃⠀⠀⡃⠀⠀⠀⠀⠀⠀⠀⠈⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠈⣖⠉⠀⣰⠃⠀⠈
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠘⡄⠖⠁⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⠱⡀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠁⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⡀⡈⡇⠀⠀⠀⠀⠀⢀⡠⠔⠒⠋⠉⠀⠀⠀⢹⢳⠀⠀⠀⠀⠀⢳⡀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡾⠀⠀⠀⠀⣇⣠⡤⠒⠒⠛⠉⠉⠉⠹⡤⠋⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⠀⢀⡠⠖⠋⠉⣧⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠷⢶⣶⠖⠚⠀⡇⠀⠀⠀⠀⠀⠀⠀⠈⠑⠒⠒⠊⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠈⠉⠉⠀⣀⡤⠞⠁⠀⠀⠀
|
||||||
|
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠖⠚⠛⠲⣾⣷⣦⣤⠤⠤⠶⠦⠤⠤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠐⢁⡠⠖⠀⠉⠒⣬⣿⣿⣿⣡⠤⠴⠒⠲⠤⢄⠀⠈⠉⠓⠢⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠎⡴⠋⢀⠤⠒⣩⣿⣿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠓⠒⠽⣶⣾⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠎⠀⠐⠁⢠⣶⡿⠋⠁⠀⠀⠀⠀⠀⠀⣀⡴⠶⠖⠂⠀⠀⠀⣀⠀⠀⠈⠙⣿⣿⣿⠙⡄⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⢠⢞⠿⣯⢳⠀⠀⣼⢆⡀⠀⠀⠀⡸⠋⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⠀⠀⠀⠀⠀⠀⢉⠻⣄⠀⠀⠈⢻⣿⣷⡸⡀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠳⣵⡋⠀⣸⢯⠎⠀⠀⢀⡜⡡⠀⠀⠀⠀⠀⠀⢠⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠙⡆⠀⠀⠀⠹⣿⣏⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠯⠼⣰⡿⠃⠀⠀⢠⣾⢾⠀⠀⠀⠀⠀⠀⡠⢁⡤⠊⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⠀⡇⠸⡄⠀⠀⠱⣹⡿⠇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⣠⡿⡵⠁⠀⠀⠀⡤⠀⡼⣡⠏⠀⠀⠀⢀⠀⠀⠀⠀⢸⠀⠀⠀⠀⢇⢁⢳⠀⠀⠀⢻⡅⡆⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⠀⠀⢀⢞⡟⡼⠁⠀⠀⠀⣰⠁⣼⡿⠁⠀⡰⢡⣦⡏⠀⠀⠀⠀⡼⠀⠀⠀⠀⢼⢸⠸⡄⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠞⠀⠀⢀⠔⠁⡞⣼⢃⡆⠀⠀⢠⠇⣰⡟⠤⢤⢾⣴⡵⣵⣧⠀⠀⠀⠀⡇⠀⠀⠀⡆⡬⠀⡇⡇⠀⠀⠀⢹⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⡠⠘⢁⠔⠁⠀⣠⠂⣸⢰⣿⢸⠀⠀⠀⡜⢀⡟⣠⢔⣵⠿⠋⢀⣾⠆⠀⠀⠀⡼⠀⠀⣀⣸⢁⡇⠀⣿⡇⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⢀⣀⡤⠴⠋⠀⡀⠋⢀⣴⠞⠁⡴⣇⣾⡇⢼⠀⠀⢀⣿⣸⣯⣶⣿⣧⣤⣄⣾⠋⠀⠀⢠⣴⡇⠀⠀⣬⡟⣾⣿⡀⢻⡇⠀⠀⠀⠸⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⣭⢭⡴⢋⡴⠋⢀⠔⢀⣴⡿⠃⢠⢞⡵⣿⣏⣾⢸⣰⡀⠀⢻⢻⡏⣿⣿⣿⣿⠻⣷⠒⠦⠴⠿⣟⣁⣀⣼⣟⡴⠁⠘⡧⣿⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⡔⣡⣴⠎⠀⣠⢃⣴⡿⠋⢀⣴⠷⡏⢀⠙⣟⢼⡄⣿⣇⠀⢸⣾⡇⣽⣬⡽⠋⠀⠀⠀⠀⠀⠀⠀⢨⣿⣿⣿⣤⡀⠀⢳⡿⠀⠀⠀⢸⢠⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⣼⣿⠃⠀⣰⢯⣾⠏⣠⡴⠛⠁⣸⢁⠆⠀⠘⣺⠳⣿⠻⣄⠀⣿⣧⠠⠅⠁⠀⠀⠀⠀⠀⠀⠀⠀⢻⠿⢿⡿⠙⢿⣧⣼⠃⡄⠀⢀⣾⢸⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⣿⡇⠀⢀⣿⣿⣯⠞⠋⠀⠀⢠⢃⠎⠀⢰⢀⡏⢠⣿⣿⣿⡷⢼⣎⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠳⢯⣤⠤⢺⡿⣣⢾⠄⣰⣿⡇⣿⢿⡀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⣿⠀⢸⢸⣿⡿⠁⠀⠀⠀⢀⣯⠏⠀⣰⠃⡸⡀⣼⣿⣿⣿⣿⡄⠉⠀⠀⠀⠀⠀⠀⠀⠀⠂⠀⠀⠀⠀⠂⠀⣤⣿⣾⣿⣯⣾⣿⣿⡼⣿⢿⣿⣄⠀⠀⠀⠀⠀
|
||||||
|
# ⢿⡀⢸⠘⡿⠁⠀⠀⠀⢀⠞⠁⠀⣰⠇⡴⣱⢱⣿⣿⣿⣿⠁⠙⢆⠀⠀⠀⠀⠀⢀⢄⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⢹⡿⠛⡇⢹⠘⣿⡷⢝⣲⡶⠞⠀
|
||||||
|
# ⠓⢷⠼⣧⢳⡀⠀⢀⡴⠋⠀⢀⡼⠃⡼⣵⢣⣿⣿⡿⢿⣿⣧⠀⠀⠑⣄⠀⠀⠀⠀⠈⠀⠀⠀⠀⢀⣤⣾⣿⣿⣿⣿⡿⣿⠀⡇⢸⡇⣸⠀⣿⣿⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠈⢢⡈⢷⣵⣔⡋⠀⠀⣠⠏⣠⢞⣽⣿⣿⣿⣿⢉⣹⣿⣿⣷⣤⠀⠀⠙⢦⡀⢀⣀⣤⣴⠒⠊⠉⠉⠉⠉⠙⠻⣿⣷⠹⣧⢣⣾⠃⡟⢀⣿⠟⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⣩⠦⣵⣯⣭⣵⠞⣡⡾⣣⣾⣿⠟⠛⠉⠸⣏⠀⠚⣿⣿⣿⣿⣷⣠⣤⣭⣿⣿⡟⢿⣦⠀⢀⠀⠀⠀⠀⠀⠀⠙⣷⣯⣯⢎⡼⣡⠞⠁⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢀⡴⠊⢡⠞⢁⡰⢊⣵⡾⠟⠋⠉⢹⣹⠀⠀⠀⠀⠈⠒⣞⠁⣹⠿⡷⣮⣭⣭⣽⢿⢯⡗⠈⢻⣷⡋⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⡻⣍⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠉⠖⢠⠋⣴⡫⡾⠋⠁⠀⠀⠀⠢⣄⣏⡇⠀⠀⠀⠀⠀⠈⠋⠻⣤⢷⣃⣹⣏⣉⡦⠞⠁⢀⠞⠳⡳⡀⠀⠀⠀⠀⠀⠀⠀⢹⠑⠷⣌⠓⢤⡀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⡞⢠⣯⡿⠋⡜⠀⠀⠀⠀⠀⠀⠀⠀⢹⠻⡤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⢀⡴⠀⠀⠀⠱⡑⡄⢀⡠⠤⠤⠤⠤⠬⠧⠤⠬⠷⣦⣈⡓⠦⣀⠀⠀⠀
|
||||||
|
# ⠀⣾⠋⢠⣾⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⢧⠀⠉⠓⠲⠤⣀⣀⠀⠀⠀⠀⠀⠀⡰⠋⠀⠀⠀⣀⠴⢛⣉⡠⠤⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⣿⣧⡈⠙⠢⣄
|
||||||
|
# ⢰⠃⡴⡇⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⡀⠀⠀⠀⠀⠀⠈⠉⠙⠂⠀⠀⠀⠀⠀⢀⡠⣊⠥⠚⠁⣀⡤⠴⠒⠋⠁⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⡇⠀⠘⢦
|
||||||
|
# ⣿⢞⡾⢠⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⢚⣁⣤⠖⠋⣁⡤⣤⡴⠒⠒⠋⠁⢀⣀⣀⣀⡤⡼⣧⡟⢿⠀⠀⠈
|
||||||
|
# ⣏⣼⡇⣿⢧⠀⠀⠀⠀⠀⠀⠐⡄⠀⠀⠀⢸⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢩⣿⣶⣶⣾⣇⠔⣉⣤⡖⠿⣍⣹⣿⣿⣯⣿⡿⠋⢹⡜⣾⡇⠀⠀
|
||||||
|
# ⣿⣿⢹⡇⢸⠀⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠈⡏⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⣾⣿⣿⣿⣿⣿⡉⠉⣿⣿⢄⡀⠀⠈⠉⣳⠀⠀⠀⣾⣷⢸⡇⠀⠀
|
||||||
|
# ⢿⣿⣸⡇⣿⡇⠀⠀⠀⠀⠀⠀⠀⡗⠀⠀⢀⡵⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣸⣿⣿⣿⣿⣿⣿⣧⠀⣏⣋⠀⠀⠀⠀⠀⡇⠀⠀⠀⣿⣿⣿⡇⠀⢸
|
||||||
|
# ⠀⠻⡏⢧⣿⣿⡀⠀⠀⠀⠀⠀⠀⡆⢀⠔⠋⠀⠻⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⡿⠀⣿⡯⢹⣦⣀⣀⣠⠇⠀⠀⢸⣿⣿⣿⠁⢀⣿
|
||||||
|
# ⡀⠀⠙⢼⣿⣿⣧⠀⠀⠀⠀⠀⢠⠗⠁⠀⠀⠀⣰⠅⢺⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣿⣿⣿⣿⣿⠁⢰⣷⢤⡀⠀⠀⠀⠉⡇⠀⠀⢸⣿⡿⠃⢀⣾⠟
|
||||||
|
# ⢽⣆⠙⢆⡙⢿⣿⡆⠀⠀⠀⠀⠈⡶⣄⠀⢠⠞⠁⠀⠀⠉⣵⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⠃⠀⡾⠿⡀⠁⠀⠀⠀⠸⡇⠀⠀⣾⠟⠁⢠⠟⠁⠀
|
||||||
|
# ⠀⠙⢧⠀⠙⣦⣝⢷⠀⠀⠀⠀⠀⣧⠟⡟⠁⠀⠀⠀⢀⣀⣼⠻⣥⣄⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠏⠀⢸⣿⠀⠈⠳⣄⠀⠀⡔⣧⠀⠀⣯⡇⣰⠃⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⡄⠀⠸⣿⣧⣇⠀⠀⠀⠀⢿⠀⠻⣦⠀⠀⡾⣍⠀⠀⠀⠈⠻⣿⣦⡀⠀⠀⠀⠀⠘⣿⣿⡟⠀⢠⣧⡁⠀⠂⠤⢴⡓⠋⠀⡏⠀⠀⣿⠀⡇⠀⠀⠀⠀
|
||||||
|
# ⢧⠀⢠⣇⠀⠀⣿⣿⢻⡄⠀⠀⠀⢸⣄⡀⠈⠳⣦⠿⢛⡷⠀⠠⠖⠉⠀⠙⢿⢢⣀⠀⠀⠀⣿⡿⠀⢀⣞⠏⠈⢦⡀⠀⣴⠃⢀⣾⠃⠀⠀⣿⡀⣇⠀⠀⠀⠀
|
||||||
|
# ⢦⣠⢾⠏⢀⣼⡿⠇⢸⣧⠀⠀⠀⠘⡿⣿⣦⣄⡈⠉⠙⢷⣼⣷⡀⢀⡠⠖⠊⠉⠻⡗⢤⣰⡟⠁⣠⣿⠟⠤⣄⡈⠳⣰⡋⢠⡾⠃⠀⠀⢠⠿⣷⡈⠣⣄⣀⡴
|
||||||
|
# ⡯⠵⡷⠖⠋⣽⠀⠀⣾⣿⡀⠀⠀⠀⠹⣄⠈⠛⠻⠿⠶⣾⣷⣼⣇⢺⣹⣧⠀⠀⣠⠔⠛⠿⣿⣶⠿⠁⠀⠀⠀⣸⣶⣷⠾⠋⠀⠀⠀⢀⡞⠀⠈⠉⠙⠛⠉⠀
|
||||||
|
# ⠀⠀⡇⡀⠀⡏⠀⡸⣿⣿⡇⠀⠀⠀⠀⠙⣦⡀⠀⠀⠀⠀⠀⠀⢨⡉⠁⢸⣷⡎⠀⠀⠀⢠⠃⠈⢳⡀⠀⢀⣴⠛⠉⠁⠀⠀⠀⢀⣴⠙⡆⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⡸⣱⠃⠀⣷⢰⠃⣿⣹⡇⠀⠀⠀⠀⠀⠈⠛⢶⣤⣀⣀⣰⣶⣶⣿⣿⣿⡿⠟⠦⣄⢀⠏⠀⠀⠀⢙⣦⣾⣿⣇⠀⠀⠀⢀⣶⠉⢸⡇⢳⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢰⠃⡏⠀⠀⢿⡏⠀⢻⡳⡇⠀⠀⠀⠀⠀⠀⠀⠀⢸⡉⠉⠛⠛⠛⠉⠉⠀⠀⠀⠀⠈⠉⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⠓⠚⣹⡇⠀⢸⡇⡜⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢸⡈⣷⠀⠀⠘⣿⡀⠀⠙⢻⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠃⢻⣿⣿⣿⣿⠃⠀⢠⡟⠀⢠⡿⣱⠃⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⢀⣀⣀⣀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⠟⠙⣿⣿⣿⣶⣶⣶⡞⠉⠀⡉⠒⢤
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠈⠻⠟⠋⠀⠀⠉⠒⠤⢥⣤⡬
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⠿⢿⣿⣿⠿⢿⣿⡿⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠋⢻⣧⣾⣏⠙⣷⣿⣉⣷⣴⡿⢿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣼⣿⣿⣿⣧⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣾⣿⣿⣿⣷⣶⣶⣶⣤⣤⣀⣀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣿⣿⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⢿⣿⣶⣶
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⡀⣠⠴⠒⠒⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠿⣛⣛⣯⣭⣭⣿⣿⣿⠿⠿⢿⣿⣿⣿⣿⣿⡿⠿⢻⣿⣿⣷⣶⣿⣿⣿⠿⠛⠋
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠈⠓⠮⣙⠢⠶⣿⣿⡿⢿⣻⣿⣿⣿⣶⣶⣶⣾⣿⣿⣿⣿⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣿⣿⣿⣿⣶⣿⣿⣿⣿⣿⡿⠟⠋⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠛⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⠛⠉⠉⠉⠿⠟⢹⣿⣿⣿⣿⣿⣿⣿⣟⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠙⡟⣿⣿⣿⣿⣇⠙⠋⠀⠀⠀⠀⠀⢠⠿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠂⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⢸⣿⣿⣿⣿⣧⡀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⢿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⢿⣿⣿⣿⣿⣿⣷⣦⣤⡴⠚⢑⣿⣿⣿⣿⡿⠙⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡸⠟⠛⢿⣿⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠎⠀⠀⢀⣿⣿⡿⠁⠀⠈⠁⠉⠩⢐⣿⣿⣿⣧⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢤⣤⡂⠀⢴⠞⣿⣿⠏⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⡿⠁⠀⠀⠉⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣋⠀⠀⠉⢳⣾⣾⣿⣿⣦⣀⡀⠀⠀⠀⠀⢸⡛⣿⣿⡇⠀⠀⠀⠀⢸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠤⣤⣄⣀⠀⣠⣤⣴⣷⣾⣿⣿⣷⣦⣄⣚⣉⣙⣛⣛⣛⠛⢳⡀⢀⠴⢦⠤⢭⣙⣿⡛⠒⣠⠆⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⢠⡤⠄⠖⠒⠒⠚⠋⠛⢆⠘⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠑⢋⣬⣥⣄⣀⠀⠰⠾⢿⣿⠟⠓⠒⣓⡄⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠘⢣⡀⢱⠖⢝⠻⡷⠾⠶⠾⡄⢀⡀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣻⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣦⣤⣭⣧⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠹⣶⠂⠂⠁⠛⠂⠒⠤⢽⣿⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⢸⣿⣿⣿⣿⣿⣿⡻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⣟⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⠚⠛⠿⢿⣛⡻⢯⣁⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⡀⠀⣀⡠⠴
|
||||||
|
# ⠀⠀⠀⢹⡀⢐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠓⠀⠠⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢿⣿⣿⣿⣿⣿⣿⣿⡿⣻⢟⡡⢎⡿
|
||||||
|
# ⠀⠀⠀⠘⡇⠘⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⢿⣿⣿⣿⣿⣿⣿⠶⠋⣭⠞⢴⣟
|
||||||
|
# ⠀⠀⠀⠀⠃⠀⠑⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡷⠶⠶⠶⠿⢻⡿⠟⠋⡁⠀⠃⠀⠀⢠⣿
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠣⠑⠂⠀⠀⠀⠀⡀⠋⡠⠅⠈⠀⠠⢨⣿
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⡴⠀⠀⠀⠀⠋⠀⠀⠀⠀⠀⠀⠁⣾⠋
|
||||||
|
# ⠀⠀⠀⠀⠀⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⠄⡀⠀⠄⠀⠔⠁⠀⠀⠀⠀⠀⢰⠃⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⠀⠀⠀⠀⠀⠀⢨⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡎⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⡾⠛⠛⠛⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠁⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⣸⣷⠿⣿⣿⣶⣤⣍⡻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⡎⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡇⠀⠀⠈⠉⠛⠿⣿⣿⣦⣽⣛⣿⣿⣿⣯⣭⣥⣤⣶⣾⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⡰⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠁⠀⠀⠀⠀⠀⠀⠀⠉⠙⣿⣿⣿⠟⠋⠉⠉⠉⠉⠉⠙⠛⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠃⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⢿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠋⠁⠀⠀⠀⠀⠀⠀⠂⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⢰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⢠⡏⢸⠁⠀⠀⠀⠀⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀⠀⠀⠀⠸⡇⡾⠀⠀⠀⠀⠀⠀⠀⠀⢀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢷⣄⣀⣀⣀⣀⣀⠤⢴⣧⣷⣦⣀⠀⠀⠀⠀⠀⢀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠁⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⡈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⡀⠀⠀⢀⣀⣀⠘⣿⣿⣿⣿⣿⣷⣶⣶⣴⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢀⣐⡒⠒⣉⣥⠤⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
|||||||
@@ -1,352 +1,241 @@
|
|||||||
# meta developer: @SunnexGB
|
# meta developer: @SunnexGB
|
||||||
# requires: aiohttp
|
|
||||||
# meta pic: https://r2.fakecrime.bio/uploads/ab42b5e2-91f1-4ed1-8002-51b3184e3839.jpg
|
# meta pic: https://r2.fakecrime.bio/uploads/ab42b5e2-91f1-4ed1-8002-51b3184e3839.jpg
|
||||||
# meta banner: https://r2.fakecrime.bio/uploads/ab42b5e2-91f1-4ed1-8002-51b3184e3839.jpg
|
# meta banner: https://r2.fakecrime.bio/uploads/ab42b5e2-91f1-4ed1-8002-51b3184e3839.jpg
|
||||||
# meta fhsdesc: YaMusic, music, музыка, яндекс музыка,Lyrics, слова, текст, трек, песня
|
# meta fhsdesc: YaMusic, music, музыка, яндекс музыка,Lyrics, слова, текст, трек, песня
|
||||||
# все же я не знаю трек или сонг, так что пусть будет трек, а не сонг потому что интуитивнее поняттнее,наверное?
|
# все же я не знаю трек или сонг, так что пусть будет трек, а не сонг потому что интуитивнее поняттнее,наверное?
|
||||||
# крутой баннер да?
|
# крутой баннер да?
|
||||||
#current version
|
#current version
|
||||||
__version__ = (1, 1, 2)
|
__version__ = (1, 1, 3)
|
||||||
|
|
||||||
from herokutl.types import Message
|
from herokutl.types import Message
|
||||||
from .. import loader, utils
|
from .. import loader, utils
|
||||||
from ..types import InlineCall
|
from ..types import InlineCall
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
@loader.tds
|
@loader.tds
|
||||||
class YandexLyrics(loader.Module):
|
class YandexLyrics(loader.Module):
|
||||||
"""life lyrics current song"""
|
|
||||||
|
|
||||||
strings = {
|
strings = {
|
||||||
"name": "YandexLyrics",
|
"name": "migration",
|
||||||
"no_YaMusicMod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod not found,but u can install it. You can also support developer: </b> @codrago_m",
|
"no_YaMusicMod": "u're not use YaMusicMod,install my new module.",
|
||||||
"no_auth": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages and setup token to continue.</b>",
|
"inline_msg": "if u ready to migration pls click on the button.",
|
||||||
"no_ym": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on YaMusic.</b>",
|
"already": "module already install, u're ready for migration ur db?",
|
||||||
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Lyrics not found for:</b> <code>{}</code>",
|
"restartf": "u ready restart ur ub?",
|
||||||
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Lyrics are not synchronized.</i>\n\n",
|
"restartf_btn": "Ok",
|
||||||
"finished": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Playback ended or track changed.",
|
"done": "migration is done.",
|
||||||
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"confirm": "confirm",
|
||||||
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Oopsi, looks like we've got a timeout here</b>.",
|
"install": "install LiveLyrics",
|
||||||
|
"close": "close",
|
||||||
|
"migrate_db": "Yep"
|
||||||
}
|
}
|
||||||
|
|
||||||
strings_ru = {
|
strings_ru = {
|
||||||
"cls_doc": "Лайв слова текущей песни.",
|
"no_YaMusicMod": "ты не юзал YaMusicMod,установи новый модуль.",
|
||||||
"no_YaMusicMod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod не найден,но его можно установить. Вы также можете поддержать разработчика: </b> @codrago_m",
|
"inline_msg": "если вы готовы к миграции нажмите на кнопку ниже.",
|
||||||
"no_auth": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> Вы не авторизированы в YaMusicMod, перейдите в Избранное и установите токен для продолжения работы.</b>",
|
"already": "модуль уже стоиит,готовы к переносу данных?",
|
||||||
"no_ym": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В YaMusic ничего не играет.</b>",
|
"restartf": "вы готовы к перезапуску юб?",
|
||||||
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Текст не найден для:</b> <code>{}</code>",
|
"restartf_btn": "Лан",
|
||||||
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Текст не синхронизирован.</i>\n\n",
|
"done": "миграция завершена.",
|
||||||
"finished": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Воспроизведение завершено или трек сменился.",
|
"confirm": "подтвердить",
|
||||||
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"install": "установить LiveLyrics",
|
||||||
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Упси, похоже кто то словил таймаут.</b>.",
|
"close": "закрыть",
|
||||||
|
"migrate_db": "Ага"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async def install_livelyrics(self, call: InlineCall):
|
||||||
|
m = self.lookup("Modules") or self.lookup("loader")
|
||||||
|
await m.download_and_install("https://raw.githubusercontent.com/SunnexGB/Heroku-Modules/refs/heads/main/LiveLyrics.py")
|
||||||
|
await call.delete()
|
||||||
|
|
||||||
def __init__(self):
|
async def confirm(self, call: InlineCall):
|
||||||
self._active_tasks: dict = {}
|
config = self.db.get("YaMusicMod", "__config__") or {}
|
||||||
self.config = loader.ModuleConfig(
|
self.db.set("LiveLyrics", "__config__", config)
|
||||||
loader.ConfigValue(
|
await asyncio.sleep(1)
|
||||||
"emoji_current",
|
await self.invoke("unloadmod", "-f YaMusicMod", "me")
|
||||||
"<tg-emoji emoji-id='5215679757366089921'>🤯</tg-emoji>",
|
await call.edit(self.strings["done"])
|
||||||
"Emoji for current line",
|
await asyncio.sleep(2)
|
||||||
validator=loader.validators.String(),
|
await call.edit(
|
||||||
),
|
self.strings["restartf"],
|
||||||
loader.ConfigValue(
|
reply_markup=[
|
||||||
"dot",
|
[{"text": self.strings["restartf_btn"], "callback": self.restartf}],
|
||||||
"♪",
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
"instrumental_emoji or text",
|
],
|
||||||
validator=loader.validators.String(),
|
)
|
||||||
),
|
|
||||||
loader.ConfigValue(
|
async def migrate_db(self, call: InlineCall):
|
||||||
"lyrics_delay",
|
await call.edit(
|
||||||
0.5,
|
self.strings["inline_msg"],
|
||||||
"delay in switching to a new timing sector with words",
|
reply_markup=[
|
||||||
),
|
[{"text": self.strings["confirm"], "callback": self.confirm}],
|
||||||
loader.ConfigValue(
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
"request_timeout",
|
],
|
||||||
12,
|
|
||||||
"timeout value",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def install_yamusic(self, call: InlineCall):
|
async def restartf(self, call: InlineCall):
|
||||||
mod_url = "https://raw.githubusercontent.com/coddrago/modules/main/YaMusic.py"
|
await call.delete()
|
||||||
try:
|
await self.invoke("restart", "-f", "me")
|
||||||
m = self.lookup("Modules") or self.lookup("loader")
|
|
||||||
await m.download_and_install(mod_url)
|
|
||||||
await call.answer("YaMusicMod installed!", show_alert=True)
|
|
||||||
mod = self.lookup("YaMusicMod")
|
|
||||||
acs_tkn = mod.get("__config__")["token"] if mod else "****"
|
|
||||||
if not acs_tkn:
|
|
||||||
await self.invoke("yguide", " ", "me")
|
|
||||||
await call.edit(
|
|
||||||
self.strings("no_auth"),
|
|
||||||
reply_markup=[[{"text": "Хорошо", "callback": self.close}]],
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
await call.delete()
|
|
||||||
except Exception as e:
|
|
||||||
await call.answer(f"Error! Check logs.\n{e}", show_alert=True)
|
|
||||||
|
|
||||||
def close(self, call: InlineCall):
|
async def close(self, call: InlineCall):
|
||||||
return call.delete()
|
await call.delete()
|
||||||
|
|
||||||
async def _get_lyrics(self, artist: str, track: str):
|
@loader.command()
|
||||||
clean_track = re.sub(r"\(.*?\)|\[.*?\]", "", track).strip()
|
async def ynowl(self, message: Message):
|
||||||
try:
|
SL_cfg = self.db.get("YaMusicMod", "__config__")
|
||||||
async with aiohttp.ClientSession() as session:
|
if SL_cfg is None:
|
||||||
async with session.get(
|
|
||||||
"https://lrclib.net/api/search",
|
|
||||||
params={"track_name": clean_track, "artist_name": artist},
|
|
||||||
timeout=aiohttp.ClientTimeout(total=(self.config["request_timeout"])),
|
|
||||||
) as resp:
|
|
||||||
if resp.status == 200:
|
|
||||||
res = await resp.json()
|
|
||||||
return res[0] if res else None
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
return {"timeout": True}
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _parse_synced(self, synced_text: str) -> list:
|
|
||||||
lines = []
|
|
||||||
for line in synced_text.split("\n"):
|
|
||||||
m = re.search(r"\[(\d+):(\d+\.\d+)\](.*)", line)
|
|
||||||
if m:
|
|
||||||
mins, secs, text = m.groups()
|
|
||||||
lines.append({
|
|
||||||
"time": (int(mins) * 60 + float(secs)) * 1000,
|
|
||||||
"text": text.strip(),
|
|
||||||
})
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def _build_content(self, artist, track, lines, plain, progress_ms, not_synced_str):
|
|
||||||
header = self.strings("header").format(
|
|
||||||
utils.escape_html(artist),
|
|
||||||
utils.escape_html(track),
|
|
||||||
)
|
|
||||||
if lines:
|
|
||||||
curr_idx = 0
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if progress_ms >= line["time"]:
|
|
||||||
curr_idx = i
|
|
||||||
win_start = max(0, curr_idx - 1)
|
|
||||||
win_end = min(len(lines), curr_idx + 6)
|
|
||||||
rows = []
|
|
||||||
for i in range(win_start, win_end):
|
|
||||||
t = lines[i]["text"] or self.config["dot"]
|
|
||||||
if i == curr_idx:
|
|
||||||
rows.append(
|
|
||||||
f"<b>{self.config['emoji_current']} {utils.escape_html(t)}</b>"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
rows.append(f"<code>{utils.escape_html(t)}</code>")
|
|
||||||
return header + "\n".join(rows)
|
|
||||||
else:
|
|
||||||
return header + not_synced_str + f"<blockquote expandable>{utils.escape_html((plain or '')[:4000])}</blockquote>"
|
|
||||||
|
|
||||||
def _markup(self, song_url):
|
|
||||||
return [
|
|
||||||
[{"text": "🔗 song.link", "url": song_url}],
|
|
||||||
[{"text": "❌ Close", "callback": self._close_cb}],
|
|
||||||
]
|
|
||||||
|
|
||||||
async def _close_cb(self, call):
|
|
||||||
for track_id, task in list(self._active_tasks.items()):
|
|
||||||
task.cancel()
|
|
||||||
self._active_tasks.pop(track_id, None)
|
|
||||||
try:
|
|
||||||
await call.answer()
|
|
||||||
await call.delete()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def run_loop(self, form, mod, track_id, artist_name, track_name, song_url, lines, plain, not_synced_str):
|
|
||||||
last_display = ""
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
pb = await mod._YaMusicMod__get_now_playing()
|
|
||||||
if not pb or not pb.get("track") or pb["track"]["track_id"] != track_id:
|
|
||||||
try:
|
|
||||||
await form.edit(
|
|
||||||
self.strings("finished"),
|
|
||||||
reply_markup=[[{"text": "❌ Close", "callback": self._close_cb}]],
|
|
||||||
)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
break
|
|
||||||
|
|
||||||
prog = pb.get("progress_ms", 0)
|
|
||||||
content = self._build_content(
|
|
||||||
artist_name, track_name, lines, plain, prog, not_synced_str
|
|
||||||
)
|
|
||||||
|
|
||||||
if content != last_display:
|
|
||||||
try:
|
|
||||||
await form.edit(content, reply_markup=self._markup(song_url))
|
|
||||||
last_display = content
|
|
||||||
except Exception:
|
|
||||||
break
|
|
||||||
|
|
||||||
if not lines:
|
|
||||||
break
|
|
||||||
|
|
||||||
await asyncio.sleep(self.config["lyrics_delay"])
|
|
||||||
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
self._active_tasks.pop(track_id, None)
|
|
||||||
|
|
||||||
@loader.command(ru_doc="- показать синхронизированный текст песни")
|
|
||||||
async def ynowlcmd(self, message: Message):
|
|
||||||
"""- show synchronized lyrics for current YaMusic track"""
|
|
||||||
mod = self.lookup("YaMusic")
|
|
||||||
if not mod:
|
|
||||||
form = await self.inline.form("⏳", message=message)
|
|
||||||
await form.edit(
|
|
||||||
self.strings("no_YaMusicMod"),
|
|
||||||
reply_markup=[[{"text": "Install YaMusic", "callback": self.install_yamusic}]],
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
ya_token = mod.get("__config__")["token"]
|
|
||||||
if not ya_token:
|
|
||||||
await self.invoke("yguide", " ", "me")
|
|
||||||
form = await self.inline.form("⏳", message=message)
|
|
||||||
await form.edit(
|
|
||||||
self.strings("no_auth"),
|
|
||||||
reply_markup=[[{"text": "Хорошо", "callback": self.close}]],
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
playback = await mod._YaMusicMod__get_now_playing()
|
|
||||||
if not playback or not playback.get("track"):
|
|
||||||
return await utils.answer(message, self.strings("no_ym"))
|
|
||||||
|
|
||||||
track = playback["track"]
|
|
||||||
track_id = track["track_id"]
|
|
||||||
artist_name = ", ".join(track["artist"])
|
|
||||||
track_name = track["title"]
|
|
||||||
song_url = f"https://song.link/s/{track_id}"
|
|
||||||
|
|
||||||
old = self._active_tasks.pop(track_id, None)
|
|
||||||
if old:
|
|
||||||
old.cancel()
|
|
||||||
|
|
||||||
data = await self._get_lyrics(artist_name, track_name)
|
|
||||||
if data and data.get("timeout"):
|
|
||||||
return utils.answer(
|
|
||||||
message,
|
|
||||||
self.strings["timeout"]
|
|
||||||
)
|
|
||||||
if not data or data.get("instrumental"):
|
|
||||||
track_and_artist = f"{utils.escape_html(track_name)} - {utils.escape_html(artist_name)}"
|
|
||||||
return await utils.answer(
|
return await utils.answer(
|
||||||
message,
|
message,
|
||||||
self.strings("no_lyrics").format(track_and_artist),
|
self.strings["no_YaMusicMod"],
|
||||||
|
reply_markup=[
|
||||||
|
[{"text": self.strings["install"], "callback": self.install_livelyrics}],
|
||||||
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
if self.lookup("LiveLyrics"):
|
||||||
synced_raw = data.get("syncedLyrics")
|
return await utils.answer(
|
||||||
plain = data.get("plainLyrics", "")
|
message,
|
||||||
|
"модуль уже стоиит,готовы к переносу данных",
|
||||||
lines = self._parse_synced(synced_raw) if synced_raw else []
|
reply_markup=[
|
||||||
not_synced_str = self.strings("not_synced")
|
[{"text": self.strings["migrate_db"], "callback": self.migrate_db}],
|
||||||
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
prog = playback.get("progress_ms", 0)
|
],
|
||||||
initial_content = self._build_content(
|
|
||||||
artist_name, track_name, lines, plain, prog, not_synced_str
|
|
||||||
)
|
|
||||||
|
|
||||||
form = await self.inline.form(
|
|
||||||
text=initial_content,
|
|
||||||
message=message,
|
|
||||||
reply_markup=self._markup(song_url),
|
|
||||||
)
|
|
||||||
|
|
||||||
task = asyncio.create_task(
|
|
||||||
self.run_loop(
|
|
||||||
form=form,
|
|
||||||
mod=mod,
|
|
||||||
track_id=track_id,
|
|
||||||
artist_name=artist_name,
|
|
||||||
track_name=track_name,
|
|
||||||
song_url=song_url,
|
|
||||||
lines=lines,
|
|
||||||
plain=plain,
|
|
||||||
not_synced_str=not_synced_str,
|
|
||||||
)
|
)
|
||||||
|
await utils.answer(
|
||||||
|
message,
|
||||||
|
self.strings["inline_msg"],
|
||||||
|
reply_markup=[
|
||||||
|
[{"text": self.strings["confirm"], "callback": self.confirm}],
|
||||||
|
[{"text": self.strings["close"], "callback": self.close}],
|
||||||
|
],
|
||||||
)
|
)
|
||||||
self._active_tasks[track_id] = task
|
|
||||||
|
|
||||||
# Fan-fantasizing
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⠤⠤⣄⠠⠤⣤⠤⢤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Fa-fa-fa-fantasizing
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠤⠒⠉⠁⠀⠀⠀⣠⠖⠉⣀⡀⣀⣤⠍⢩⣵⡢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# You and I-I-I
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠖⠋⠁⠀⠀⠀⠀⢀⣴⠊⠀⣠⠞⣠⠞⠉⢳⣦⠀⡈⠻⣦⠑⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# When I close my eyes (my eyes)
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠖⠉⠀⠀⠀⠀⠀⠀⣠⣴⡿⠁⠀⡰⢁⡾⠁⠐⠃⢸⡇⠀⠸⡄⠀⠀⠈⠷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Nothings real
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣆⠀⠀⠀⠀⣀⣠⡴⡿⠁⣼⡅⠀⣰⢣⢿⡇⡴⠀⠀⣾⡅⠀⠀⣧⠀⠀⠀⠀⢈⢂⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Fantasizing (fantasizing)
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠻⠿⠿⠷⠒⠒⠋⠁⡏⠸⠁⣸⣿⠇⢀⣧⠏⢸⡿⠁⠀⡼⠙⣧⠀⢀⣿⡄⢀⠠⠀⠘⡄⢡⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Bout you and I
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠁⣤⣠⣯⢿⠀⢸⣟⡴⡾⣳⣴⣾⡷⢠⠛⢆⣾⣿⡇⡀⠀⣦⠀⡇⠀⢣⠀⠀⠀⠀⠀⠀
|
||||||
# Cos you only hit my line
|
# ⢠⡄⠀⡄⠀⠀⠀⢀⣒⣒⣶⡀⠀⠀⠀⠀⠀⠀⠀⠀⢼⠀⣿⡿⣿⢸⠐⣿⣿⣿⣿⡿⣶⡿⢷⣯⣮⣾⢯⡟⣇⡇⣸⡏⢠⣠⠀⠀⢣⠀⠀⠀⠀⠀
|
||||||
# When you wanna waste time
|
# ⠀⣿⣿⣿⣦⡄⣤⡾⢿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⢸⢠⣿⣿⣿⣼⣇⡿⣟⠛⠛⠃⠀⠀⠁⠉⣠⣶⣷⣄⣿⣼⣿⡆⣸⣧⡀⠀⠀⢆⠀⠀⠀⠀
|
||||||
# I know you're so busy
|
# ⢸⣿⣿⡿⠛⠋⠉⢩⣍⣉⣻⡇⠀⠀⠀⠀⠀⠀⠀⠀⡇⣼⣿⢹⢿⡝⢿⣇⡈⠃⠀⠀⠀⠀⠀⠀⠛⢿⡏⣿⣿⢿⣿⡱⡸⠁⠈⠢⣀⠘⡆⠀⠀⠀
|
||||||
# But trust me baby I'm not blind (blind)
|
# ⠈⣿⡏⣤⠄⠘⠃⠸⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢰⢱⠻⡇⢸⠸⣷⡀⣿⡁⠀⠀⠀⠀⡀⠀⠀⠀⢀⡼⣯⠁⣾⣿⠁⠀⠀⠀⠀⠈⠑⠃⠀⠀⠀
|
||||||
# Uh oh, you and I
|
# ⢠⣬⣼⣧⡀⠀⠀⠀⢹⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⣾⣿⡦⠧⠬⣧⡸⣿⣧⠙⢠⡀⠀⠀⠀⠀⣀⡤⠊⠀⣿⣰⢿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# We could never be
|
# ⢸⣿⣿⣿⡀⢀⡀⠀⣸⣿⣿⡁⠀⠀⠀⠀⠀⠀⣰⣯⠟⠛⠛⠛⢿⣭⣿⣿⠷⣶⣟⣷⣶⣒⡉⠁⠀⠀⠜⢹⣿⡼⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Uh oh you and I
|
# ⠈⠛⠛⠛⠛⠛⠛⠓⠛⠛⠛⠃⠀⠀⠀⠀⢀⢼⣿⣏⣰⣿⣷⣴⣦⠙⣿⣿⡛⠛⠿⠥⢯⣀⣈⡇⢀⠀⠚⢙⡞⠑⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Cos we will never be
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⢽⣿⣿⢻⣿⣿⣟⣿⣿⢿⣿⢦⣄⠀⣀⣀⠉⠩⠿⣷⣾⣭⠑⠒⠢⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Uh oh, you and I
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⠏⠈⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣧⢽⣯⣁⠀⠀⠀⠀⠒⠗⢺⣿⣭⣤⣄⠙⠢⣀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# No, we will never be
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠏⠀⠀⣿⡟⠈⠻⣿⣿⣻⣿⣿⣟⣡⣴⣿⣿⣷⡞⠒⠒⠶⠶⠶⠤⣽⡿⠽⠦⣄⣀⠑⡄⠀⠀⠀⠀⠀
|
||||||
# That pretty picture that I painted in my mind (mind)
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠋⠀⢀⣴⣿⡇⠀⠀⠉⠻⣥⣽⠿⠋⠙⠻⣽⣿⣤⠃⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠈⠑⠳⣄⠀⠀⠀⠀
|
||||||
# So tell me what (tell me, tell me)
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⣠⠊⣼⣿⡇⠀⠀⠐⢿⡿⠁⠀⠀⠀⢀⣀⣩⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢢⡀⠀⠀
|
||||||
# The view is like
|
# ⠀⠀⣠⠤⢤⣀⣀⡀⠀⠀⠀⠀⢠⠏⢀⡜⠁⢰⠇⣿⣿⠀⠀⠀⣈⡇⠀⠀⠀⠀⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀
|
||||||
# With your head in the clouds
|
# ⠀⠀⠳⡀⠀⠀⠀⠉⠉⠙⠓⠒⠳⠤⠯⣄⡀⡞⠀⡿⣡⡴⠞⠋⢙⡇⠀⠀⠀⠀⢟⡛⠀⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⠀
|
||||||
# And tell me what (tell me, tell me)
|
# ⠀⠀⠀⠹⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠁⠈⣯⣉⠀⠀⠀⢸⡇⠀⠀⠀⢰⡶⠀⢠⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀
|
||||||
# It feels like to be right all the time
|
# ⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣧⠀⢰⠃⠟⢳⣄⠀⣾⡇⠀⠀⠀⠈⠀⣰⣯⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡜⠁⠀⠀
|
||||||
# You say that you love me
|
# ⠀⠀⠀⠀⠈⠓⠛⠙⣹⡟⠉⠉⡇⠀⠀⠀⣿⠀⠞⡸⠀⡜⢿⣷⡈⢿⡀⠀⠀⠀⣼⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣠⠤⢆⣴⠉⠀⠀⠀⠀
|
||||||
# But you don't even love yourself (no)
|
# ⠀⠀⠀⠀⠀⠀⠀⣴⠏⠀⠀⢠⡇⠀⠀⠀⣿⠀⠀⠁⢰⠁⢸⠻⣟⠾⡇⠀⢀⣾⣿⡇⣠⣴⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣰⣾⣿⠀⠀⠀⠀⠀
|
||||||
# Wanna get in my head
|
# ⠀⠀⠀⠀⠀⠀⣼⠋⠀⠀⠀⢸⡇⠀⠀⠀⠈⠙⠒⠒⠢⠭⣍⠀⢸⠓⢤⠴⠚⣿⡉⠀⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣟⡏⠀⠀⠀⠀⠀
|
||||||
# But I ain't gonna let you close (no)
|
# ⠀⠀⠀⠀⠀⡜⡽⠀⠀⠀⠀⢸⡇⠀⠀⠀⢀⣀⣀⣀⡀⠀⢸⠀⠺⠤⠼⢠⣾⡉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⠟⠻⣷⠀⠀⠀⠀⠀
|
||||||
# Tryna control me
|
# ⠀⠀⠀⠀⣸⢹⡇⠀⠀⠀⠀⢠⠏⠉⠉⠉⠉⠉⠉⠉⡝⢣⠘⡆⢰⣠⠞⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠘⡆⠀⢹⡄⠀⠀⠀⠀
|
||||||
# But I ain't gon' play your game
|
# ⠀⠀⠀⢀⡇⣿⡇⠀⠀⠀⡰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⠷⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠃⠀⠸⡄⠸⡇⠀⠀⠀⠀
|
||||||
# No more
|
# ⠀⠀⠀⢸⠀⡿⣇⠀⣠⠎⠀⠀⠀⠀⠀⠀⠀⣠⠎⠀⢀⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡆⠈⣧⠀⠱⣸⣇⠀⠀⠀⠀
|
||||||
# No I won't
|
# ⠀⠀⠀⢾⠀⡇⢻⣾⠃⠀⠀⠀⠀⠀⠀⢠⢺⠃⠀⡴⢋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠇⠀⠘⡗⢆⠻⡏⠀⠀⠀⠀
|
||||||
# When I close (when I close)
|
# ⠀⠀⠀⢸⠀⡷⢁⠋⠓⠦⡴⠂⠀⠀⠀⣼⠃⢠⠎⠀⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠀⠀⠀⢸⠀⡄⠀⠘⠞⢱⣧⠀⠀⠀⠀
|
||||||
# My eyes (my eyes)
|
# ⠀⠀⠀⣨⣇⢳⡎⢀⡴⠻⠇⠀⠀⠀⠀⠃⢠⠋⠀⠀⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡞⢦⠑⠀⠀⠀⢇⠸⣇⠀⠀⠀
|
||||||
# Nothing's real (no)
|
# ⠀⢀⢸⠃⠈⣦⣷⣅⡀⢀⡄⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⣇⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡃⠈⠃⠈⠐⠀⠈⢢⡓⢆⠀⠀
|
||||||
# Fantasizing (fantasize)
|
# ⢠⢃⡏⠀⣰⣿⠀⠉⠉⠉⡇⠀⠀⢀⠀⡞⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢦⡀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⣄⡀⠀⠀⢻⢸⠀⠀
|
||||||
# bout you-you-you-you-you
|
# ⡇⢸⣾⢠⠇⢿⡀⠀⠀⠀⡧⠀⢰⡇⢸⠁⢰⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠋⠀⠀⢣⠀⠀⢱⠈⠒⢄⢸⠀⡇⠀
|
||||||
# You-you-you-you
|
# ⠁⢸⢹⡼⠀⠀⠙⠒⢀⢜⡡⢠⠋⡇⡏⠀⢸⠀⠀⠀⠀⠀⠈⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠣⡀⠀⠀⡄⠀⠀⠀⢻⠀⠀⠀⠀⠀⢹⠀⡿⡄
|
||||||
# You-you-you-you
|
# ⠀⠀⠈⠳⣤⢀⣠⠶⠓⢩⡡⠃⠀⢷⠀⠀⣼⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢄⠀⡇⠀⠀⠀⠈⢧⠀⠀⠀⠀⡎⡀⡗⢵
|
||||||
# You-you-you
|
# ⠀⠀⠀⠀⠋⠉⠀⢀⡠⠋⠀⠀⠀⡎⠀⠀⠇⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢢⡁⠀⠀⠀⠀⠈⢧⠀⢀⡼⠞⣧⠁⢸
|
||||||
# And I
|
# ⠀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⢰⠃⠀⠀⡃⠀⠀⠀⠀⠀⠀⠀⠈⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠈⣖⠉⠀⣰⠃⠀⠈
|
||||||
# You-you-you-you-you-you-you
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠘⡄⠖⠁⠀⠀⠀
|
||||||
# You-you-you-you-you-you-you
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⠱⡀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠀
|
||||||
# You-you-you-you-you
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠁⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⡀⡈⡇⠀⠀⠀⠀⠀⢀⡠⠔⠒⠋⠉⠀⠀⠀⢹⢳⠀⠀⠀⠀⠀⢳⡀⠀⠀⠀
|
||||||
# And I
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡾⠀⠀⠀⠀⣇⣠⡤⠒⠒⠛⠉⠉⠉⠹⡤⠋⠀⠀⠀⢀⡴⠋⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⠀⢀⡠⠖⠋⠉⣧⠀⠀⠀
|
||||||
# This is the last time I tell you
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⠷⢶⣶⠖⠚⠀⡇⠀⠀⠀⠀⠀⠀⠀⠈⠑⠒⠒⠊⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠈⠉⠉⠀⣀⡤⠞⠁⠀⠀⠀
|
||||||
# Don't come round my way if you're just gon' waste my time
|
|
||||||
# And no, I won't be there for the long run
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⠖⠚⠛⠲⣾⣷⣦⣤⠤⠤⠶⠦⠤⠤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# No, not I
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠐⢁⡠⠖⠀⠉⠒⣬⣿⣿⣿⣡⠤⠴⠒⠲⠤⢄⠀⠈⠉⠓⠢⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# But you never get (never get)
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠎⡴⠋⢀⠤⠒⣩⣿⣿⠟⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠓⠒⠽⣶⣾⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# The message, do you?
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠎⠀⠐⠁⢠⣶⡿⠋⠁⠀⠀⠀⠀⠀⠀⣀⡴⠶⠖⠂⠀⠀⠀⣀⠀⠀⠈⠙⣿⣿⣿⠙⡄⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# You never seem (never seem)
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⢠⢞⠿⣯⢳⠀⠀⣼⢆⡀⠀⠀⠀⡸⠋⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⠀⠀⠀⠀⠀⠀⢉⠻⣄⠀⠀⠈⢻⣿⣷⡸⡀⠀⠀⠀⠀⠀⠀⠀
|
||||||
# To grip an understanding
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠳⣵⡋⠀⣸⢯⠎⠀⠀⢀⡜⡡⠀⠀⠀⠀⠀⠀⢠⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠙⡆⠀⠀⠀⠹⣿⣏⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# That you emulate a ghost
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠯⠼⣰⡿⠃⠀⠀⢠⣾⢾⠀⠀⠀⠀⠀⠀⡠⢁⡤⠊⠀⠀⠀⠀⠀⠀⢠⠀⠀⠀⠀⡇⠸⡄⠀⠀⠱⣹⡿⠇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# I pointed out all of your flaws
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⣠⡿⡵⠁⠀⠀⠀⡤⠀⡼⣡⠏⠀⠀⠀⢀⠀⠀⠀⠀⢸⠀⠀⠀⠀⢇⢁⢳⠀⠀⠀⢻⡅⡆⠀⠀⠀⠀⠀⠀⠀
|
||||||
# But you still came up with excuses for em all
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⠀⠀⢀⢞⡟⡼⠁⠀⠀⠀⣰⠁⣼⡿⠁⠀⡰⢡⣦⡏⠀⠀⠀⠀⡼⠀⠀⠀⠀⢼⢸⠸⡄⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# So typical (so typical)
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠞⠀⠀⢀⠔⠁⡞⣼⢃⡆⠀⠀⢠⠇⣰⡟⠤⢤⢾⣴⡵⣵⣧⠀⠀⠀⠀⡇⠀⠀⠀⡆⡬⠀⡇⡇⠀⠀⠀⢹⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# You know it all
|
# ⠀⠀⠀⠀⠀⠀⠀⡠⠘⢁⠔⠁⠀⣠⠂⣸⢰⣿⢸⠀⠀⠀⡜⢀⡟⣠⢔⣵⠿⠋⢀⣾⠆⠀⠀⠀⡼⠀⠀⣀⣸⢁⡇⠀⣿⡇⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# So of course, I'm the one that's wrong (right?)
|
# ⠀⠀⢀⣀⡤⠴⠋⠀⡀⠋⢀⣴⠞⠁⡴⣇⣾⡇⢼⠀⠀⢀⣿⣸⣯⣶⣿⣧⣤⣄⣾⠋⠀⠀⢠⣴⡇⠀⠀⣬⡟⣾⣿⡀⢻⡇⠀⠀⠀⠸⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# When I close my eyes
|
# ⣭⢭⡴⢋⡴⠋⢀⠔⢀⣴⡿⠃⢠⢞⡵⣿⣏⣾⢸⣰⡀⠀⢻⢻⡏⣿⣿⣿⣿⠻⣷⠒⠦⠴⠿⣟⣁⣀⣼⣟⡴⠁⠘⡧⣿⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Nothings real
|
# ⡔⣡⣴⠎⠀⣠⢃⣴⡿⠋⢀⣴⠷⡏⢀⠙⣟⢼⡄⣿⣇⠀⢸⣾⡇⣽⣬⡽⠋⠀⠀⠀⠀⠀⠀⠀⢨⣿⣿⣿⣤⡀⠀⢳⡿⠀⠀⠀⢸⢠⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Fan- fantasize
|
# ⣼⣿⠃⠀⣰⢯⣾⠏⣠⡴⠛⠁⣸⢁⠆⠀⠘⣺⠳⣿⠻⣄⠀⣿⣧⠠⠅⠁⠀⠀⠀⠀⠀⠀⠀⠀⢻⠿⢿⡿⠙⢿⣧⣼⠃⡄⠀⢀⣾⢸⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
# Fa-fa-fa-fa
|
# ⣿⡇⠀⢀⣿⣿⣯⠞⠋⠀⠀⢠⢃⠎⠀⢰⢀⡏⢠⣿⣿⣿⡷⢼⣎⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠳⢯⣤⠤⢺⡿⣣⢾⠄⣰⣿⡇⣿⢿⡀⠀⠀⠀⠀⠀⠀
|
||||||
# Fantasizing
|
# ⣿⠀⢸⢸⣿⡿⠁⠀⠀⠀⢀⣯⠏⠀⣰⠃⡸⡀⣼⣿⣿⣿⣿⡄⠉⠀⠀⠀⠀⠀⠀⠀⠀⠂⠀⠀⠀⠀⠂⠀⣤⣿⣾⣿⣯⣾⣿⣿⡼⣿⢿⣿⣄⠀⠀⠀⠀⠀
|
||||||
# Fa-fantasizing bout you and I
|
# ⢿⡀⢸⠘⡿⠁⠀⠀⠀⢀⠞⠁⠀⣰⠇⡴⣱⢱⣿⣿⣿⣿⠁⠙⢆⠀⠀⠀⠀⠀⢀⢄⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⢹⡿⠛⡇⢹⠘⣿⡷⢝⣲⡶⠞⠀
|
||||||
|
# ⠓⢷⠼⣧⢳⡀⠀⢀⡴⠋⠀⢀⡼⠃⡼⣵⢣⣿⣿⡿⢿⣿⣧⠀⠀⠑⣄⠀⠀⠀⠀⠈⠀⠀⠀⠀⢀⣤⣾⣿⣿⣿⣿⡿⣿⠀⡇⢸⡇⣸⠀⣿⣿⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠈⢢⡈⢷⣵⣔⡋⠀⠀⣠⠏⣠⢞⣽⣿⣿⣿⣿⢉⣹⣿⣿⣷⣤⠀⠀⠙⢦⡀⢀⣀⣤⣴⠒⠊⠉⠉⠉⠉⠙⠻⣿⣷⠹⣧⢣⣾⠃⡟⢀⣿⠟⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⣩⠦⣵⣯⣭⣵⠞⣡⡾⣣⣾⣿⠟⠛⠉⠸⣏⠀⠚⣿⣿⣿⣿⣷⣠⣤⣭⣿⣿⡟⢿⣦⠀⢀⠀⠀⠀⠀⠀⠀⠙⣷⣯⣯⢎⡼⣡⠞⠁⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢀⡴⠊⢡⠞⢁⡰⢊⣵⡾⠟⠋⠉⢹⣹⠀⠀⠀⠀⠈⠒⣞⠁⣹⠿⡷⣮⣭⣭⣽⢿⢯⡗⠈⢻⣷⡋⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⡻⣍⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠉⠖⢠⠋⣴⡫⡾⠋⠁⠀⠀⠀⠢⣄⣏⡇⠀⠀⠀⠀⠀⠈⠋⠻⣤⢷⣃⣹⣏⣉⡦⠞⠁⢀⠞⠳⡳⡀⠀⠀⠀⠀⠀⠀⠀⢹⠑⠷⣌⠓⢤⡀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⡞⢠⣯⡿⠋⡜⠀⠀⠀⠀⠀⠀⠀⠀⢹⠻⡤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⢀⡴⠀⠀⠀⠱⡑⡄⢀⡠⠤⠤⠤⠤⠬⠧⠤⠬⠷⣦⣈⡓⠦⣀⠀⠀⠀
|
||||||
|
# ⠀⣾⠋⢠⣾⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⢧⠀⠉⠓⠲⠤⣀⣀⠀⠀⠀⠀⠀⠀⡰⠋⠀⠀⠀⣀⠴⢛⣉⡠⠤⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⣿⣧⡈⠙⠢⣄
|
||||||
|
# ⢰⠃⡴⡇⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⡀⠀⠀⠀⠀⠀⠈⠉⠙⠂⠀⠀⠀⠀⠀⢀⡠⣊⠥⠚⠁⣀⡤⠴⠒⠋⠁⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⡇⠀⠘⢦
|
||||||
|
# ⣿⢞⡾⢠⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣻⢚⣁⣤⠖⠋⣁⡤⣤⡴⠒⠒⠋⠁⢀⣀⣀⣀⡤⡼⣧⡟⢿⠀⠀⠈
|
||||||
|
# ⣏⣼⡇⣿⢧⠀⠀⠀⠀⠀⠀⠐⡄⠀⠀⠀⢸⢹⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢩⣿⣶⣶⣾⣇⠔⣉⣤⡖⠿⣍⣹⣿⣿⣯⣿⡿⠋⢹⡜⣾⡇⠀⠀
|
||||||
|
# ⣿⣿⢹⡇⢸⠀⠀⠀⠀⠀⠀⠀⠸⡄⠀⠀⠈⡏⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⣾⣿⣿⣿⣿⣿⡉⠉⣿⣿⢄⡀⠀⠈⠉⣳⠀⠀⠀⣾⣷⢸⡇⠀⠀
|
||||||
|
# ⢿⣿⣸⡇⣿⡇⠀⠀⠀⠀⠀⠀⠀⡗⠀⠀⢀⡵⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣸⣿⣿⣿⣿⣿⣿⣧⠀⣏⣋⠀⠀⠀⠀⠀⡇⠀⠀⠀⣿⣿⣿⡇⠀⢸
|
||||||
|
# ⠀⠻⡏⢧⣿⣿⡀⠀⠀⠀⠀⠀⠀⡆⢀⠔⠋⠀⠻⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⡿⠀⣿⡯⢹⣦⣀⣀⣠⠇⠀⠀⢸⣿⣿⣿⠁⢀⣿
|
||||||
|
# ⡀⠀⠙⢼⣿⣿⣧⠀⠀⠀⠀⠀⢠⠗⠁⠀⠀⠀⣰⠅⢺⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣿⣿⣿⣿⣿⠁⢰⣷⢤⡀⠀⠀⠀⠉⡇⠀⠀⢸⣿⡿⠃⢀⣾⠟
|
||||||
|
# ⢽⣆⠙⢆⡙⢿⣿⡆⠀⠀⠀⠀⠈⡶⣄⠀⢠⠞⠁⠀⠀⠉⣵⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⠃⠀⡾⠿⡀⠁⠀⠀⠀⠸⡇⠀⠀⣾⠟⠁⢠⠟⠁⠀
|
||||||
|
# ⠀⠙⢧⠀⠙⣦⣝⢷⠀⠀⠀⠀⠀⣧⠟⡟⠁⠀⠀⠀⢀⣀⣼⠻⣥⣄⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⠏⠀⢸⣿⠀⠈⠳⣄⠀⠀⡔⣧⠀⠀⣯⡇⣰⠃⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⡄⠀⠸⣿⣧⣇⠀⠀⠀⠀⢿⠀⠻⣦⠀⠀⡾⣍⠀⠀⠀⠈⠻⣿⣦⡀⠀⠀⠀⠀⠘⣿⣿⡟⠀⢠⣧⡁⠀⠂⠤⢴⡓⠋⠀⡏⠀⠀⣿⠀⡇⠀⠀⠀⠀
|
||||||
|
# ⢧⠀⢠⣇⠀⠀⣿⣿⢻⡄⠀⠀⠀⢸⣄⡀⠈⠳⣦⠿⢛⡷⠀⠠⠖⠉⠀⠙⢿⢢⣀⠀⠀⠀⣿⡿⠀⢀⣞⠏⠈⢦⡀⠀⣴⠃⢀⣾⠃⠀⠀⣿⡀⣇⠀⠀⠀⠀
|
||||||
|
# ⢦⣠⢾⠏⢀⣼⡿⠇⢸⣧⠀⠀⠀⠘⡿⣿⣦⣄⡈⠉⠙⢷⣼⣷⡀⢀⡠⠖⠊⠉⠻⡗⢤⣰⡟⠁⣠⣿⠟⠤⣄⡈⠳⣰⡋⢠⡾⠃⠀⠀⢠⠿⣷⡈⠣⣄⣀⡴
|
||||||
|
# ⡯⠵⡷⠖⠋⣽⠀⠀⣾⣿⡀⠀⠀⠀⠹⣄⠈⠛⠻⠿⠶⣾⣷⣼⣇⢺⣹⣧⠀⠀⣠⠔⠛⠿⣿⣶⠿⠁⠀⠀⠀⣸⣶⣷⠾⠋⠀⠀⠀⢀⡞⠀⠈⠉⠙⠛⠉⠀
|
||||||
|
# ⠀⠀⡇⡀⠀⡏⠀⡸⣿⣿⡇⠀⠀⠀⠀⠙⣦⡀⠀⠀⠀⠀⠀⠀⢨⡉⠁⢸⣷⡎⠀⠀⠀⢠⠃⠈⢳⡀⠀⢀⣴⠛⠉⠁⠀⠀⠀⢀⣴⠙⡆⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⡸⣱⠃⠀⣷⢰⠃⣿⣹⡇⠀⠀⠀⠀⠀⠈⠛⢶⣤⣀⣀⣰⣶⣶⣿⣿⣿⡿⠟⠦⣄⢀⠏⠀⠀⠀⢙⣦⣾⣿⣇⠀⠀⠀⢀⣶⠉⢸⡇⢳⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢰⠃⡏⠀⠀⢿⡏⠀⢻⡳⡇⠀⠀⠀⠀⠀⠀⠀⠀⢸⡉⠉⠛⠛⠛⠉⠉⠀⠀⠀⠀⠈⠉⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⠓⠚⣹⡇⠀⢸⡇⡜⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⢸⡈⣷⠀⠀⠘⣿⡀⠀⠙⢻⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠃⢻⣿⣿⣿⣿⠃⠀⢠⡟⠀⢠⡿⣱⠃⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⢀⣀⣀⣀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⠟⠙⣿⣿⣿⣶⣶⣶⡞⠉⠀⡉⠒⢤
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠈⠻⠟⠋⠀⠀⠉⠒⠤⢥⣤⡬
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⠿⢿⣿⣿⠿⢿⣿⡿⢿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⠋⢻⣧⣾⣏⠙⣷⣿⣉⣷⣴⡿⢿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣼⣿⣿⣿⣧⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣾⣿⣿⣿⣷⣶⣶⣶⣤⣤⣀⣀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣿⣿⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⢿⣿⣶⣶
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⡀⣠⠴⠒⠒⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠿⣛⣛⣯⣭⣭⣿⣿⣿⠿⠿⢿⣿⣿⣿⣿⣿⡿⠿⢻⣿⣿⣷⣶⣿⣿⣿⠿⠛⠋
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠈⠓⠮⣙⠢⠶⣿⣿⡿⢿⣻⣿⣿⣿⣶⣶⣶⣾⣿⣿⣿⣿⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣿⣿⣿⣿⣶⣿⣿⣿⣿⣿⡿⠟⠋⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⠛⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⠛⠉⠉⠉⠿⠟⢹⣿⣿⣿⣿⣿⣿⣿⣟⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠙⡟⣿⣿⣿⣿⣇⠙⠋⠀⠀⠀⠀⠀⢠⠿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠂⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠻⢸⣿⣿⣿⣿⣧⡀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⢿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⢿⣿⣿⣿⣿⣿⣷⣦⣤⡴⠚⢑⣿⣿⣿⣿⡿⠙⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⡸⠟⠛⢿⣿⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠎⠀⠀⢀⣿⣿⡿⠁⠀⠈⠁⠉⠩⢐⣿⣿⣿⣧⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢤⣤⡂⠀⢴⠞⣿⣿⠏⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⡿⠁⠀⠀⠉⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣋⠀⠀⠉⢳⣾⣾⣿⣿⣦⣀⡀⠀⠀⠀⠀⢸⡛⣿⣿⡇⠀⠀⠀⠀⢸⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⡤⠤⣤⣄⣀⠀⣠⣤⣴⣷⣾⣿⣿⣷⣦⣄⣚⣉⣙⣛⣛⣛⠛⢳⡀⢀⠴⢦⠤⢭⣙⣿⡛⠒⣠⠆⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⢠⡤⠄⠖⠒⠒⠚⠋⠛⢆⠘⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠑⢋⣬⣥⣄⣀⠀⠰⠾⢿⣿⠟⠓⠒⣓⡄⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠘⢣⡀⢱⠖⢝⠻⡷⠾⠶⠾⡄⢀⡀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣻⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣦⣤⣭⣧⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠹⣶⠂⠂⠁⠛⠂⠒⠤⢽⣿⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⢸⣿⣿⣿⣿⣿⣿⡻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⣟⠀⠀⠀⠀⠀⠀⠀⠀⠈⠑⠚⠛⠿⢿⣛⡻⢯⣁⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⡀⠀⣀⡠⠴
|
||||||
|
# ⠀⠀⠀⢹⡀⢐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠓⠀⠠⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢿⣿⣿⣿⣿⣿⣿⣿⡿⣻⢟⡡⢎⡿
|
||||||
|
# ⠀⠀⠀⠘⡇⠘⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⢿⣿⣿⣿⣿⣿⣿⠶⠋⣭⠞⢴⣟
|
||||||
|
# ⠀⠀⠀⠀⠃⠀⠑⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡷⠶⠶⠶⠿⢻⡿⠟⠋⡁⠀⠃⠀⠀⢠⣿
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠣⠑⠂⠀⠀⠀⠀⡀⠋⡠⠅⠈⠀⠠⢨⣿
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⡴⠀⠀⠀⠀⠋⠀⠀⠀⠀⠀⠀⠁⣾⠋
|
||||||
|
# ⠀⠀⠀⠀⠀⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⠄⡀⠀⠄⠀⠔⠁⠀⠀⠀⠀⠀⢰⠃⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⠀⠀⠀⠀⠀⠀⢨⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡎⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠢⡀⠀⠀⠀⡾⠛⠛⠛⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠁⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⣸⣷⠿⣿⣿⣶⣤⣍⡻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⡎⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⡇⠀⠀⠈⠉⠛⠿⣿⣿⣦⣽⣛⣿⣿⣿⣯⣭⣥⣤⣶⣾⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⡰⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⠁⠀⠀⠀⠀⠀⠀⠀⠉⠙⣿⣿⣿⠟⠋⠉⠉⠉⠉⠉⠙⠛⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠃⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⢿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠋⠁⠀⠀⠀⠀⠀⠀⠂⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⢰⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⢠⡏⢸⠁⠀⠀⠀⠀⠀⠀⠀⠀⢠⠇⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⠸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⡄⠀⠀⠀⠀⠀⠀⠀⠸⡇⡾⠀⠀⠀⠀⠀⠀⠀⠀⢀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢷⣄⣀⣀⣀⣀⣀⠤⢴⣧⣷⣦⣀⠀⠀⠀⠀⠀⢀⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠁⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⡈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⡀⠀⠀⢀⣀⣀⠘⣿⣿⣿⣿⣿⣷⣶⣶⣴⡞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
# ⠀⠀⠀⠀⠀⠀⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢀⣐⡒⠒⣉⣥⠤⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⡼⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
|||||||
190
modules.json
190
modules.json
@@ -471,7 +471,7 @@
|
|||||||
},
|
},
|
||||||
"SunnexGB/Heroku-Modules/SpotifyLyrics.py": {
|
"SunnexGB/Heroku-Modules/SpotifyLyrics.py": {
|
||||||
"name": "SpotifyLyrics",
|
"name": "SpotifyLyrics",
|
||||||
"description": "life lyrics current song",
|
"description": "",
|
||||||
"cls_doc": {},
|
"cls_doc": {},
|
||||||
"meta": {
|
"meta": {
|
||||||
"pic": "https://r2.fakecrime.bio/uploads/f49a9294-36ad-4fc4-801f-48cb049111d6.jpg",
|
"pic": "https://r2.fakecrime.bio/uploads/f49a9294-36ad-4fc4-801f-48cb049111d6.jpg",
|
||||||
@@ -481,16 +481,15 @@
|
|||||||
},
|
},
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"snowl": "- show synchronized lyrics for current Spotify track | (RU) - показать синхронизированный текст песни"
|
"snowl": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"new_commands": [
|
"new_commands": [
|
||||||
{
|
{
|
||||||
"name": "snowl",
|
"name": "snowl",
|
||||||
"original_name": "snowlcmd",
|
"original_name": "snowl",
|
||||||
"description": {
|
"description": {
|
||||||
"default": "- show synchronized lyrics for current Spotify track",
|
"default": ""
|
||||||
"ru": "- показать синхронизированный текст песни"
|
|
||||||
},
|
},
|
||||||
"cmd_names": {},
|
"cmd_names": {},
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
@@ -502,24 +501,27 @@
|
|||||||
],
|
],
|
||||||
"inline_handlers": [],
|
"inline_handlers": [],
|
||||||
"strings": {
|
"strings": {
|
||||||
"name": "SpotifyLyrics",
|
"name": "migration",
|
||||||
"no_spotifymod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod not found,but u can install it. You can also support developer: </b> @ke_mods",
|
"no_SpotifyLyrics": "u're not use SpotifyLyrics,install my new module.",
|
||||||
"no_auth": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages.</b>",
|
"inline_msg": "if u ready to migration pls click on the button.",
|
||||||
"no_spotify": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on Spotify.</b>",
|
"already": "module already install, u're ready for migration ur db?",
|
||||||
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Lyrics not found for:</b> <code>{}</code>",
|
"restartf": "u ready restart ur ub?",
|
||||||
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Lyrics are not synchronized.</i>\n\n",
|
"restartf_btn": "Ok",
|
||||||
"finished": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Playback ended or track changed.",
|
"done": "migration is done.",
|
||||||
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"confirm": "confirm",
|
||||||
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Oopsi, looks like we've got a timeout here</b>.",
|
"install": "install LiveLyrics",
|
||||||
"cls_doc_ru": "Лайв слова текущей песни.",
|
"close": "close",
|
||||||
"no_spotifymod_ru": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod не найден,но его можно установить. Вы также можете поддержать разработчика: </b> @ke_mods",
|
"migrate_db": "Yep",
|
||||||
"no_auth_ru": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> Вы не авторизированы в SpotifyMod, перейдите в Избранное.</b>",
|
"no_SpotifyLyrics_ru": "ты не юзал SpotifyLyrics,установи новый модуль.",
|
||||||
"no_spotify_ru": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В Spotify ничего не играет.</b>",
|
"inline_msg_ru": "если вы готовы к миграции нажмите на кнопку ниже.",
|
||||||
"no_lyrics_ru": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Текст не найден для:</b> <code>{}</code>",
|
"already_ru": "модуль уже стоиит,готовы к переносу данных?",
|
||||||
"not_synced_ru": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Текст не синхронизирован.</i>\n\n",
|
"restartf_ru": "вы готовы к перезапуску юб?",
|
||||||
"finished_ru": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Воспроизведение завершено или трек сменился.",
|
"restartf_btn_ru": "Лан",
|
||||||
"header_ru": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"done_ru": "миграция завершена.",
|
||||||
"timeout_ru": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Упси, похоже кто то словил таймаут.</b>."
|
"confirm_ru": "подтвердить",
|
||||||
|
"install_ru": "установить LiveLyrics",
|
||||||
|
"close_ru": "закрыть",
|
||||||
|
"migrate_db_ru": "Ага"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
@@ -705,6 +707,96 @@
|
|||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
"class_cmd_names": {}
|
"class_cmd_names": {}
|
||||||
},
|
},
|
||||||
|
"SunnexGB/Heroku-Modules/LiveLyrics.py": {
|
||||||
|
"name": "LiveLyrics",
|
||||||
|
"description": "life lyrics current song",
|
||||||
|
"cls_doc": {
|
||||||
|
"ru": "Лайв слова текущей песни."
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"pic": "https://r2.fakecrime.bio/uploads/6725e5a0-0c9e-48ed-be85-dfd857c2aa5f.jpg",
|
||||||
|
"banner": "https://r2.fakecrime.bio/uploads/6725e5a0-0c9e-48ed-be85-dfd857c2aa5f.jpg",
|
||||||
|
"developer": "@SunnexGB",
|
||||||
|
"fhsdesc": "Spotify, YaMusic, music, музыка, Lyrics, слова, текст, трек, песня"
|
||||||
|
},
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"snowl": "- show synchronized lyrics for current track | (RU) - показать синхронизированный текст песни"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ynowl": "- show synchronized lyrics for current track | (RU) - показать синхронизированный текст песни"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"new_commands": [
|
||||||
|
{
|
||||||
|
"name": "snowl",
|
||||||
|
"original_name": "snowlcmd",
|
||||||
|
"description": {
|
||||||
|
"default": "- show synchronized lyrics for current track",
|
||||||
|
"ru": "- показать синхронизированный текст песни"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ynowl",
|
||||||
|
"original_name": "ynowlcmd",
|
||||||
|
"description": {
|
||||||
|
"default": "- show synchronized lyrics for current track",
|
||||||
|
"ru": "- показать синхронизированный текст песни"
|
||||||
|
},
|
||||||
|
"cmd_names": {},
|
||||||
|
"aliases": [],
|
||||||
|
"usage": null,
|
||||||
|
"inline": false,
|
||||||
|
"is_inline_handler": false,
|
||||||
|
"decorators": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inline_handlers": [],
|
||||||
|
"strings": {
|
||||||
|
"name": "LiveLyrics",
|
||||||
|
"no_spotifymod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod not found,but u can install it. You can also support developer: </b> @ke_mods",
|
||||||
|
"no_yamusic": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod not found,but u can install it. You can also support developer: </b> @codrago_m",
|
||||||
|
"no_auth_spotify": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages.</b>",
|
||||||
|
"no_auth_yamusic": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages and setup token to continue.</b>",
|
||||||
|
"no_spotify": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on Spotify.</b>",
|
||||||
|
"no_ym": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on YaMusic.</b>",
|
||||||
|
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Lyrics not found for:</b> <code>{}</code>",
|
||||||
|
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Lyrics are not synchronized.</i>\n\n",
|
||||||
|
"TrackEnded": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Playback ended or track changed.",
|
||||||
|
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
||||||
|
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Oopsi, looks like we've got a timeout here</b>.",
|
||||||
|
"yamusic_installed": "YaMusic installed!",
|
||||||
|
"spotify_installed": "SpotifyMod installed!",
|
||||||
|
"song_link": "🔗 song.link",
|
||||||
|
"close": "❌ Close",
|
||||||
|
"ok": "OK",
|
||||||
|
"no_spotifymod_ru": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>SpotifyMod не найден,но его можно установить. Вы также можете поддержать разработчика: </b> @ke_mods",
|
||||||
|
"no_yamusic_ru": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod не найден, но его можно установить. Вы также можете поддержать разработчика: </b> @codrago_m",
|
||||||
|
"no_auth_spotify_ru": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji> <b>Вы не авторизованы в SpotifyMod. Перейдите в Избранное.</b>",
|
||||||
|
"no_auth_yamusic_ru": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> Вы не авторизированы в YaMusicMod, перейдите в Избранное и установите токен для продолжения работы.</b>",
|
||||||
|
"no_spotify_ru": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В Spotify ничего не играет.</b>",
|
||||||
|
"no_ym_ru": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В YaMusic ничего не играет.</b>",
|
||||||
|
"no_lyrics_ru": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Текст не найден для:</b> <code>{}</code>",
|
||||||
|
"not_synced_ru": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Текст не синхронизирован.</i>\n\n",
|
||||||
|
"TrackEnded_ru": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Воспроизведение завершено или трек сменился.",
|
||||||
|
"header_ru": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
||||||
|
"timeout_ru": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Упси, похоже кто то словил таймаут.</b>.",
|
||||||
|
"yamusic_installed_ru": "YaMusic Установлен!",
|
||||||
|
"spotify_installed_ru": "SpotifyMod Установлен!",
|
||||||
|
"song_link_ru": "🔗 song.link",
|
||||||
|
"close_ru": "❌ Закрыть",
|
||||||
|
"ok_ru": "OK"
|
||||||
|
},
|
||||||
|
"has_on_load": false,
|
||||||
|
"has_on_unload": false,
|
||||||
|
"class_cmd_names": {}
|
||||||
|
},
|
||||||
"SunnexGB/Heroku-Modules/spotify_ph.py": {
|
"SunnexGB/Heroku-Modules/spotify_ph.py": {
|
||||||
"name": "spotifyph",
|
"name": "spotifyph",
|
||||||
"description": "Progress bar current track in spotify",
|
"description": "Progress bar current track in spotify",
|
||||||
@@ -859,7 +951,7 @@
|
|||||||
},
|
},
|
||||||
"SunnexGB/Heroku-Modules/YandexLyrics.py": {
|
"SunnexGB/Heroku-Modules/YandexLyrics.py": {
|
||||||
"name": "YandexLyrics",
|
"name": "YandexLyrics",
|
||||||
"description": "life lyrics current song",
|
"description": "",
|
||||||
"cls_doc": {},
|
"cls_doc": {},
|
||||||
"meta": {
|
"meta": {
|
||||||
"pic": "https://r2.fakecrime.bio/uploads/ab42b5e2-91f1-4ed1-8002-51b3184e3839.jpg",
|
"pic": "https://r2.fakecrime.bio/uploads/ab42b5e2-91f1-4ed1-8002-51b3184e3839.jpg",
|
||||||
@@ -869,16 +961,15 @@
|
|||||||
},
|
},
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"ynowl": "- show synchronized lyrics for current YaMusic track | (RU) - показать синхронизированный текст песни"
|
"ynowl": ""
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"new_commands": [
|
"new_commands": [
|
||||||
{
|
{
|
||||||
"name": "ynowl",
|
"name": "ynowl",
|
||||||
"original_name": "ynowlcmd",
|
"original_name": "ynowl",
|
||||||
"description": {
|
"description": {
|
||||||
"default": "- show synchronized lyrics for current YaMusic track",
|
"default": ""
|
||||||
"ru": "- показать синхронизированный текст песни"
|
|
||||||
},
|
},
|
||||||
"cmd_names": {},
|
"cmd_names": {},
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
@@ -890,24 +981,27 @@
|
|||||||
],
|
],
|
||||||
"inline_handlers": [],
|
"inline_handlers": [],
|
||||||
"strings": {
|
"strings": {
|
||||||
"name": "YandexLyrics",
|
"name": "migration",
|
||||||
"no_YaMusicMod": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod not found,but u can install it. You can also support developer: </b> @codrago_m",
|
"no_YaMusicMod": "u're not use YaMusicMod,install my new module.",
|
||||||
"no_auth": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> You not authorized in SpotifyMod, visit you Saved Messages and setup token to continue.</b>",
|
"inline_msg": "if u ready to migration pls click on the button.",
|
||||||
"no_ym": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>Nothing is playing on YaMusic.</b>",
|
"already": "module already install, u're ready for migration ur db?",
|
||||||
"no_lyrics": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Lyrics not found for:</b> <code>{}</code>",
|
"restartf": "u ready restart ur ub?",
|
||||||
"not_synced": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Lyrics are not synchronized.</i>\n\n",
|
"restartf_btn": "Ok",
|
||||||
"finished": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Playback ended or track changed.",
|
"done": "migration is done.",
|
||||||
"header": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"confirm": "confirm",
|
||||||
"timeout": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Oopsi, looks like we've got a timeout here</b>.",
|
"install": "install LiveLyrics",
|
||||||
"cls_doc_ru": "Лайв слова текущей песни.",
|
"close": "close",
|
||||||
"no_YaMusicMod_ru": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>YaMusicMod не найден,но его можно установить. Вы также можете поддержать разработчика: </b> @codrago_m",
|
"migrate_db": "Yep",
|
||||||
"no_auth_ru": "<tg-emoji emoji-id=5429225166250984904>⁉️</tg-emoji><b> Вы не авторизированы в YaMusicMod, перейдите в Избранное и установите токен для продолжения работы.</b>",
|
"no_YaMusicMod_ru": "ты не юзал YaMusicMod,установи новый модуль.",
|
||||||
"no_ym_ru": "<tg-emoji emoji-id=5429164207780152924>😅</tg-emoji> <b>В YaMusic ничего не играет.</b>",
|
"inline_msg_ru": "если вы готовы к миграции нажмите на кнопку ниже.",
|
||||||
"no_lyrics_ru": "<tg-emoji emoji-id=5431402435497181911>💢</tg-emoji> <b>Текст не найден для:</b> <code>{}</code>",
|
"already_ru": "модуль уже стоиит,готовы к переносу данных?",
|
||||||
"not_synced_ru": "<i><tg-emoji emoji-id=5431445849026611010>⚠️</tg-emoji> Текст не синхронизирован.</i>\n\n",
|
"restartf_ru": "вы готовы к перезапуску юб?",
|
||||||
"finished_ru": "<tg-emoji emoji-id=5429638011392377649>‼️</tg-emoji> Воспроизведение завершено или трек сменился.",
|
"restartf_btn_ru": "Лан",
|
||||||
"header_ru": "<tg-emoji emoji-id=5429413328768224565>🎤</tg-emoji> <b>{} - {}</b>\n\n",
|
"done_ru": "миграция завершена.",
|
||||||
"timeout_ru": "<b><tg-emoji emoji-id=5429455831764584284>⏳</tg-emoji></b><b> Упси, похоже кто то словил таймаут.</b>."
|
"confirm_ru": "подтвердить",
|
||||||
|
"install_ru": "установить LiveLyrics",
|
||||||
|
"close_ru": "закрыть",
|
||||||
|
"migrate_db_ru": "Ага"
|
||||||
},
|
},
|
||||||
"has_on_load": false,
|
"has_on_load": false,
|
||||||
"has_on_unload": false,
|
"has_on_unload": false,
|
||||||
@@ -80016,7 +80110,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"total_modules": 1011,
|
"total_modules": 1012,
|
||||||
"generated_at": "2026-06-12T08:37:15.698186"
|
"generated_at": "2026-06-16T03:26:11.134799"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user