diff --git a/vibr/bot.py b/vibr/bot.py index c73566b..52ca3a3 100644 --- a/vibr/bot.py +++ b/vibr/bot.py @@ -6,7 +6,7 @@ from os import environ, getenv from pathlib import Path from typing import TYPE_CHECKING - +from ytmusicapi import YTMusic import async_spotify import yaml from async_spotify import SpotifyApiClient @@ -39,6 +39,7 @@ from .exts.playing._errors import LyricsNotFound, SongNotProvided from .player import Player +ytmusic = YTMusic() if TYPE_CHECKING: from typing import TypedDict @@ -470,48 +471,43 @@ async def can_connect( return False return True - async def lyrics(self, inter: Inter, query: str | None = None) -> None: + async def lyrics(self, inter: Inter, song: str | None = None) -> None: player: Player = inter.guild.voice_client - if not query: + if not song: if player is None or player.current is None: raise SongNotProvided + assert player.current.title is not None if "-" in player.current.title: q = player.current.title - else: - q = player.current.title, player.current.author + else: + q =f"{player.current.title} {player.current.author}" else: - q = query + q = song await inter.response.defer() - url_search = f"https://api.flowery.pw/v1/lyrics/search?query={q}" - - async with inter.client.session.get(url_search) as resp: - result = await resp.json() + searchresult = ytmusic.search(query=q,filter="songs",limit=1) try: - isrc = result["tracks"][0]["external"]["isrc"] - spotify_id = result["tracks"][0]["external"]["spotify_id"] - except KeyError as e: - raise LyricsNotFound from e - - url_lyrics = f"https://api.flowery.pw/v1/lyrics?isrc={isrc}&spotify_id={spotify_id}&query={q}" - - async with inter.client.session.get(url_lyrics) as res: - lyrics = await res.json() - + song = ytmusic.get_watch_playlist(searchresult[0]["videoId"]) + except IndexError: + raise LyricsNotFound + lyrics_id = song['lyrics'] try: - lyrics_text = lyrics["lyrics"]["text"] - title = lyrics["track"]["title"] - artist = lyrics["track"]["artist"] - thumbnail = lyrics["track"]["media"]["artwork"] - except KeyError as e: - raise LyricsNotFound from e + lyrics_req = ytmusic.get_lyrics(browseId=lyrics_id) + except Exception: + raise LyricsNotFound + lyrics = lyrics_req['lyrics'] + source = lyrics_req['source'] + title = song['tracks'][0]['title'] + thumbnail = song['tracks'][0]['thumbnail'][1]['url'] + artist = song['tracks'][0]['artists'][0]['name'] - lyrics_text = truncate(lyrics_text, length=4096) + lyrics_text = truncate(lyrics, length=4096) embed = Embed(title=title, description=lyrics_text, timestamp=utcnow()) embed.set_author(name=artist) embed.set_thumbnail(url=thumbnail) + embed.set_footer(text=source) await inter.send(embed=embed, ephemeral=True) diff --git a/vibr/exts/lyrics.py b/vibr/exts/lyrics.py index 2d0712e..48453c4 100644 --- a/vibr/exts/lyrics.py +++ b/vibr/exts/lyrics.py @@ -13,7 +13,7 @@ class Lyrics(CogBase[Vibr]): - @slash_command(dm_permission=False) + @slash_command() @voted async def lyrics(self, inter: Inter, query: str | None = None) -> None: """Get a song's lyrics @@ -22,7 +22,7 @@ async def lyrics(self, inter: Inter, query: str | None = None) -> None: The song to search lyrics for, leave blank if you want the current song. """ - await self.bot.lyrics(inter=inter, query=query) + await self.bot.lyrics(inter=inter, song=query) def setup(bot: Vibr) -> None: diff --git a/vibr/poetry.lock b/vibr/poetry.lock index e8fe7d1..cfc4813 100644 --- a/vibr/poetry.lock +++ b/vibr/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiodns" version = "3.0.0" description = "Simple DNS resolver for asyncio" -category = "main" optional = false python-versions = "*" files = [ @@ -19,7 +18,6 @@ pycares = ">=4.0.0" name = "aiohttp" version = "3.8.4" description = "Async http client/server framework (asyncio)" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -130,7 +128,6 @@ speedups = ["Brotli", "aiodns", "cchardet"] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -145,7 +142,6 @@ frozenlist = ">=1.1.0" name = "async-spotify" version = "0.4.4" description = "An async spotify api client" -category = "main" optional = false python-versions = ">=3.6" files = [] @@ -166,7 +162,6 @@ subdirectory = "src" name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -178,7 +173,6 @@ files = [ name = "asyncache" version = "0.3.1" description = "Helpers to use cachetools with async code." -category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -193,7 +187,6 @@ cachetools = ">=5.2.0,<6.0.0" name = "asyncpg" version = "0.27.0" description = "An asyncio PostgreSQL driver" -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -244,7 +237,6 @@ test = ["flake8 (>=5.0.4,<5.1.0)", "uvloop (>=0.15.3)"] name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -263,7 +255,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte name = "black" version = "23.3.0" description = "The uncompromising code formatter." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -312,7 +303,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "brotli" version = "1.0.9" description = "Python bindings for the Brotli compression library" -category = "main" optional = false python-versions = "*" files = [ @@ -404,7 +394,6 @@ files = [ name = "cachetools" version = "5.3.0" description = "Extensible memoizing collections and decorators" -category = "main" optional = false python-versions = "~=3.7" files = [ @@ -416,7 +405,6 @@ files = [ name = "certifi" version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -428,7 +416,6 @@ files = [ name = "cffi" version = "1.15.1" description = "Foreign Function Interface for Python calling C code." -category = "main" optional = false python-versions = "*" files = [ @@ -505,7 +492,6 @@ pycparser = "*" name = "charset-normalizer" version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -590,7 +576,6 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -605,7 +590,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -617,7 +601,6 @@ files = [ name = "delarva" version = "0.1.0" description = "A slash-based debug cog for nextcord." -category = "main" optional = false python-versions = "^3.8" files = [] @@ -639,7 +622,6 @@ resolved_reference = "0391e396cc399fc8bcbb158dae544f3b81fac489" name = "dnspython" version = "2.3.0" description = "DNS toolkit" -category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -660,7 +642,6 @@ wmi = ["wmi (>=1.5.1,<2.0.0)"] name = "docker" version = "6.1.2" description = "A Python library for the Docker Engine API." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -682,7 +663,6 @@ ssh = ["paramiko (>=2.4.3)"] name = "docstring-parser" version = "0.15" description = "Parse Python docstrings in reST, Google and Numpydoc format" -category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -694,7 +674,6 @@ files = [ name = "email-validator" version = "2.0.0.post2" description = "A robust email address syntax and deliverability validation library." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -710,7 +689,6 @@ idna = ">=2.0.0" name = "frozenlist" version = "1.3.3" description = "A list-like structure which implements collections.abc.MutableSequence" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -794,7 +772,6 @@ files = [ name = "hiredis" version = "2.2.3" description = "Python wrapper for hiredis" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -893,7 +870,6 @@ files = [ name = "humanfriendly" version = "10.0" description = "Human friendly output for text interfaces using Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -908,7 +884,6 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -920,7 +895,6 @@ files = [ name = "inflection" version = "0.5.1" description = "A port of Ruby on Rails inflector to Python" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -932,7 +906,6 @@ files = [ name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -950,7 +923,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -968,7 +940,6 @@ i18n = ["Babel (>=2.7)"] name = "mafic" version = "2.9.2" description = "A properly typehinted lavalink client for discord.py, nextcord, disnake and py-cord." -category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -987,7 +958,6 @@ speedups = ["orjson (>=3.8.0,<4.0.0)"] name = "markupsafe" version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1047,7 +1017,6 @@ files = [ name = "mslex" version = "0.3.0" description = "shlex for windows" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1059,7 +1028,6 @@ files = [ name = "multidict" version = "6.0.4" description = "multidict implementation" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1143,7 +1111,6 @@ files = [ name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1155,7 +1122,6 @@ files = [ name = "nextcord" version = "2.4.2" description = "A Python wrapper for the Discord API forked from discord.py" -category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -1179,7 +1145,6 @@ voice = ["PyNaCl (>=1.3.0,<1.5)"] name = "nextcord-ext-menus" version = "1.5.6" description = "An extension module to make reaction and button component menus with nextcord" -category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -1194,7 +1159,6 @@ docs = ["sphinx", "sphinx-book-theme (==0.3.3)", "sphinxcontrib-trio"] name = "ooliver-botbase" version = "2.0.3" description = "A personal nextcord bot base package for bots." -category = "main" optional = false python-versions = "^3.8" files = [] @@ -1203,24 +1167,23 @@ develop = false [package.dependencies] nextcord = "^2.0.0" nextcord-ext-menus = "^1.5.2" -piccolo = {version = "^0.111.1", extras = ["orjson", "postgres", "uvloop"], optional = true} +piccolo = {version = ">=0.111.1,<0.118.0", extras = ["orjson", "postgres", "uvloop"], optional = true} psutil = "^5.9.0" python-dotenv = ">=0.16.0,<1.1.0" [package.extras] -db = ["piccolo[orjson,postgres,uvloop] (>=0.111.1,<0.112.0)"] +db = ["piccolo[orjson,postgres,uvloop] (>=0.111.1,<0.118.0)"] [package.source] type = "git" url = "https://github.com/ooliver1/botbase" reference = "master" -resolved_reference = "b72c501f647a90bbff855eec3c24da8ac50abcd9" +resolved_reference = "ae5e173cb9ac099ec1e6d16c6b343eafb36dbb65" [[package]] name = "orjson" version = "3.8.14" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1276,7 +1239,6 @@ files = [ name = "packaging" version = "23.1" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1288,7 +1250,6 @@ files = [ name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1300,7 +1261,6 @@ files = [ name = "piccolo" version = "0.111.1" description = "A fast, user friendly ORM and query builder which supports asyncio." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1332,7 +1292,6 @@ uvloop = ["uvloop (>=0.12.0)"] name = "platformdirs" version = "3.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1348,7 +1307,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest- name = "prometheus-async" version = "22.2.0" description = "Async helpers for prometheus_client." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1372,7 +1330,6 @@ twisted = ["twisted"] name = "prometheus-client" version = "0.17.0" description = "Python client for the Prometheus monitoring system." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1387,7 +1344,6 @@ twisted = ["twisted"] name = "psutil" version = "5.9.5" description = "Cross-platform lib for process and system monitoring in Python." -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1414,7 +1370,6 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] name = "pycares" version = "4.3.0" description = "Python interface for c-ares" -category = "main" optional = false python-versions = "*" files = [ @@ -1482,7 +1437,6 @@ idna = ["idna (>=2.1)"] name = "pycparser" version = "2.21" description = "C parser in Python" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -1494,7 +1448,6 @@ files = [ name = "pydantic" version = "1.10.8" description = "Data validation and settings management using python type hints" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1548,7 +1501,6 @@ email = ["email-validator (>=1.0.3)"] name = "pyreadline3" version = "3.4.1" description = "A python implementation of GNU readline." -category = "main" optional = false python-versions = "*" files = [ @@ -1560,7 +1512,6 @@ files = [ name = "python-dotenv" version = "1.0.0" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1575,7 +1526,6 @@ cli = ["click (>=5.0)"] name = "pywin32" version = "306" description = "Python for Window Extensions" -category = "main" optional = false python-versions = "*" files = [ @@ -1599,7 +1549,6 @@ files = [ name = "pyyaml" version = "6.0" description = "YAML parser and emitter for Python" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1649,7 +1598,6 @@ files = [ name = "redis" version = "4.5.5" description = "Python client for Redis database and key-value store" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1669,7 +1617,6 @@ ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)" name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1691,7 +1638,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "ruff" version = "0.0.270" description = "An extremely fast Python linter, written in Rust." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1718,7 +1664,6 @@ files = [ name = "targ" version = "0.3.8" description = "Build a Python CLI for your app, just using type hints and docstrings." -category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -1727,14 +1672,13 @@ files = [ ] [package.dependencies] -colorama = ">=0.4.0,<0.5.0" +colorama = "==0.4.*" docstring-parser = ">=0.12" [[package]] name = "taskipy" version = "1.11.0" description = "tasks runner for python projects" -category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -1752,7 +1696,6 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version >= \"3.7\" and py name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1764,7 +1707,6 @@ files = [ name = "typing-extensions" version = "4.6.1" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1776,7 +1718,6 @@ files = [ name = "urllib3" version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1794,7 +1735,6 @@ zstd = ["zstandard (>=0.18.0)"] name = "uvloop" version = "0.17.0" description = "Fast implementation of asyncio event loop on top of libuv" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1839,7 +1779,6 @@ test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "my name = "websocket-client" version = "1.5.2" description = "WebSocket client for Python with low level API options" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1856,7 +1795,6 @@ test = ["websockets"] name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -1941,7 +1879,6 @@ files = [ name = "yarl" version = "1.9.2" description = "Yet another URL library" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -2025,7 +1962,24 @@ files = [ idna = ">=2.0" multidict = ">=4.0" +[[package]] +name = "ytmusicapi" +version = "1.1.1" +description = "Unofficial API for YouTube Music" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ytmusicapi-1.1.1-py3-none-any.whl", hash = "sha256:0c154a052c8f8e2310a51b1f391aa2ed1a2f6693a7ec343cc47b822de5e95783"}, + {file = "ytmusicapi-1.1.1.tar.gz", hash = "sha256:50258db9bd0512b766177906488265a4870a74f65d3f3279cbccb1f593c1525c"}, +] + +[package.dependencies] +requests = ">=2.22" + +[package.extras] +dev = ["coverage", "flake8", "pre-commit", "sphinx", "sphinx-rtd-theme", "yapf"] + [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "e1986b4559f7c7704b807c503cce58e9541c86a4a0e9011f23e7ca730d3843a7" +content-hash = "7fd902d82e2b7348b573737853ad6df5d05d3ecc84cc0bec0d86398f0219467f" diff --git a/vibr/pyproject.toml b/vibr/pyproject.toml index 708dde8..f8cf816 100644 --- a/vibr/pyproject.toml +++ b/vibr/pyproject.toml @@ -23,6 +23,7 @@ humanfriendly = "^10.0" redis = { version = "^4.5.5", extras = ["hiredis"] } prometheus-async = "^22.2.0" prometheus-client = "^0.17.0" +ytmusicapi = "^1.1.1" [tool.poetry.group.dev.dependencies] black = "^23.3.0"