mirror of
https://github.com/deadcxap/YandexMusicDiscordBot.git
synced 2026-01-12 00:11:39 +03:00
feat: Add explicit settings functionality.
This commit is contained in:
@@ -7,8 +7,9 @@ from discord.ext.commands import Cog
|
|||||||
import yandex_music
|
import yandex_music
|
||||||
import yandex_music.exceptions
|
import yandex_music.exceptions
|
||||||
from yandex_music import ClientAsync as YMClient
|
from yandex_music import ClientAsync as YMClient
|
||||||
|
from yandex_music import Track, Album, Artist, Playlist
|
||||||
|
|
||||||
from MusicBot.database import BaseUsersDatabase
|
from MusicBot.database import BaseUsersDatabase, BaseGuildsDatabase
|
||||||
from MusicBot.cogs.utils.find import (
|
from MusicBot.cogs.utils.find import (
|
||||||
process_album, process_track, process_artist, process_playlist,
|
process_album, process_track, process_artist, process_playlist,
|
||||||
ListenAlbum, ListenTrack, ListenArtist, ListenPlaylist
|
ListenAlbum, ListenTrack, ListenArtist, ListenPlaylist
|
||||||
@@ -22,7 +23,8 @@ class General(Cog):
|
|||||||
|
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self.db = BaseUsersDatabase()
|
self.db = BaseGuildsDatabase()
|
||||||
|
self.users_db = BaseUsersDatabase()
|
||||||
|
|
||||||
account = discord.SlashCommandGroup("account", "Команды, связанные с аккаунтом.")
|
account = discord.SlashCommandGroup("account", "Команды, связанные с аккаунтом.")
|
||||||
|
|
||||||
@@ -84,7 +86,7 @@ class General(Cog):
|
|||||||
"или имеете разрешение управления каналом.\n```/queue clear```\n")
|
"или имеете разрешение управления каналом.\n```/queue clear```\n")
|
||||||
elif command == 'settings':
|
elif command == 'settings':
|
||||||
embed.description += ("Получить текущие настройки.\n```/settings show```\n"
|
embed.description += ("Получить текущие настройки.\n```/settings show```\n"
|
||||||
"Разрешить или запретить воспроизведение Explicit треков.\n```/settings explicit```\n"
|
"Разрешить или запретить воспроизведение Explicit треков и альбомов. Если автор или плейлист содержат Explicit треки, убираются кнопки для доступа к ним.\n```/settings explicit```\n"
|
||||||
"Разрешить или запретить создание меню проигрывателя, даже если в канале больше одного человека.\n```/settings menu```\n"
|
"Разрешить или запретить создание меню проигрывателя, даже если в канале больше одного человека.\n```/settings menu```\n"
|
||||||
"Разрешить или запретить голосование.\n```/settings vote <тип голосования>```\n"
|
"Разрешить или запретить голосование.\n```/settings vote <тип голосования>```\n"
|
||||||
"`Примечание`: Только пользователи с разрешением управления каналом могут менять настройки.")
|
"`Примечание`: Только пользователи с разрешением управления каналом могут менять настройки.")
|
||||||
@@ -115,17 +117,17 @@ class General(Cog):
|
|||||||
about = cast(yandex_music.Status, client.me).to_dict()
|
about = cast(yandex_music.Status, client.me).to_dict()
|
||||||
uid = ctx.author.id
|
uid = ctx.author.id
|
||||||
|
|
||||||
self.db.update(uid, {'ym_token': token})
|
self.users_db.update(uid, {'ym_token': token})
|
||||||
await ctx.respond(f'Привет, {about['account']['first_name']}!', delete_after=15, ephemeral=True)
|
await ctx.respond(f'Привет, {about['account']['first_name']}!', delete_after=15, ephemeral=True)
|
||||||
|
|
||||||
@account.command(description="Удалить токен из датабазы бота.")
|
@account.command(description="Удалить токен из датабазы бота.")
|
||||||
async def remove(self, ctx: discord.ApplicationContext) -> None:
|
async def remove(self, ctx: discord.ApplicationContext) -> None:
|
||||||
self.db.update(ctx.user.id, {'ym_token': None})
|
self.users_db.update(ctx.user.id, {'ym_token': None})
|
||||||
await ctx.respond(f'Токен был удалён.', delete_after=15, ephemeral=True)
|
await ctx.respond(f'Токен был удалён.', delete_after=15, ephemeral=True)
|
||||||
|
|
||||||
@account.command(description="Получить плейлист «Мне нравится»")
|
@account.command(description="Получить плейлист «Мне нравится»")
|
||||||
async def likes(self, ctx: discord.ApplicationContext) -> None:
|
async def likes(self, ctx: discord.ApplicationContext) -> None:
|
||||||
token = self.db.get_ym_token(ctx.user.id)
|
token = self.users_db.get_ym_token(ctx.user.id)
|
||||||
if not token:
|
if not token:
|
||||||
await ctx.respond('❌ Необходимо указать свой токен доступа с помощью команды /login.', delete_after=15, ephemeral=True)
|
await ctx.respond('❌ Необходимо указать свой токен доступа с помощью команды /login.', delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
@@ -145,7 +147,7 @@ class General(Cog):
|
|||||||
|
|
||||||
@account.command(description="Получить ваши плейлисты.")
|
@account.command(description="Получить ваши плейлисты.")
|
||||||
async def playlists(self, ctx: discord.ApplicationContext) -> None:
|
async def playlists(self, ctx: discord.ApplicationContext) -> None:
|
||||||
token = self.db.get_ym_token(ctx.user.id)
|
token = self.users_db.get_ym_token(ctx.user.id)
|
||||||
if not token:
|
if not token:
|
||||||
await ctx.respond('❌ Необходимо указать свой токен доступа с помощью команды /login.', delete_after=15, ephemeral=True)
|
await ctx.respond('❌ Необходимо указать свой токен доступа с помощью команды /login.', delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
@@ -157,7 +159,7 @@ class General(Cog):
|
|||||||
playlists: list[tuple[str, int]] = [
|
playlists: list[tuple[str, int]] = [
|
||||||
(playlist.title if playlist.title else 'Без названия', playlist.track_count if playlist.track_count else 0) for playlist in playlists_list
|
(playlist.title if playlist.title else 'Без названия', playlist.track_count if playlist.track_count else 0) for playlist in playlists_list
|
||||||
]
|
]
|
||||||
self.db.update(ctx.user.id, {'playlists': playlists, 'playlists_page': 0})
|
self.users_db.update(ctx.user.id, {'playlists': playlists, 'playlists_page': 0})
|
||||||
embed = generate_playlist_embed(0, playlists)
|
embed = generate_playlist_embed(0, playlists)
|
||||||
await ctx.respond(embed=embed, view=MyPlalists(ctx), ephemeral=True)
|
await ctx.respond(embed=embed, view=MyPlalists(ctx), ephemeral=True)
|
||||||
|
|
||||||
@@ -184,10 +186,12 @@ class General(Cog):
|
|||||||
await ctx.respond("❌ Недопустимый тип.", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ Недопустимый тип.", delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
token = self.db.get_ym_token(ctx.user.id)
|
guild = self.db.get_guild(ctx.guild_id)
|
||||||
|
token = self.users_db.get_ym_token(ctx.user.id)
|
||||||
if not token:
|
if not token:
|
||||||
await ctx.respond("❌ Необходимо указать свой токен доступа с помощью комманды /login.", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ Необходимо указать свой токен доступа с помощью команды /login.", delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client = await YMClient(token).init()
|
client = await YMClient(token).init()
|
||||||
except yandex_music.exceptions.UnauthorizedError:
|
except yandex_music.exceptions.UnauthorizedError:
|
||||||
@@ -198,41 +202,70 @@ class General(Cog):
|
|||||||
if not client.me or not client.me.account or not client.me.account.uid:
|
if not client.me or not client.me.account or not client.me.account.uid:
|
||||||
await ctx.respond("❌ Не удалось получить информацию о пользователе.", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ Не удалось получить информацию о пользователе.", delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
playlists = await client.users_playlists_list(client.me.account.uid)
|
playlists = await client.users_playlists_list(client.me.account.uid)
|
||||||
result = None
|
result = next((playlist for playlist in playlists if playlist.title == name), None)
|
||||||
for playlist in playlists:
|
if not result:
|
||||||
if playlist.title == name:
|
|
||||||
result = playlist
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
await ctx.respond("❌ Плейлист не найден.", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ Плейлист не найден.", delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
tracks = await result.fetch_tracks_async()
|
||||||
|
if not tracks:
|
||||||
|
await ctx.respond("❌ Плейлист пуст.", delete_after=15, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
for track_short in tracks:
|
||||||
|
track = cast(Track, track_short.track)
|
||||||
|
if (track.explicit or track.content_warning) and not guild['allow_explicit']:
|
||||||
|
await ctx.respond("❌ Explicit контент запрещён на этом сервере.", delete_after=15, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
embed = await process_playlist(result)
|
embed = await process_playlist(result)
|
||||||
await ctx.respond(embed=embed, view=ListenPlaylist(result))
|
await ctx.respond(embed=embed, view=ListenPlaylist(result))
|
||||||
else:
|
else:
|
||||||
result = await client.search(name, True, content_type.lower())
|
result = await client.search(name, True)
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
await ctx.respond("❌ Что-то пошло не так. Повторите попытку позже", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ Что-то пошло не так. Повторите попытку позже", delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
if content_type == 'Album' and result.albums:
|
content_map = {
|
||||||
album = result.albums.results[0]
|
'Album': (result.albums, process_album, ListenAlbum),
|
||||||
embed = await process_album(album)
|
'Track': (result.tracks, process_track, ListenTrack),
|
||||||
await ctx.respond(embed=embed, view=ListenAlbum(album))
|
'Artist': (result.artists, process_artist, ListenArtist),
|
||||||
elif content_type == 'Track' and result.tracks:
|
'Playlist': (result.playlists, process_playlist, ListenPlaylist)
|
||||||
track = result.tracks.results[0]
|
}
|
||||||
album_id = cast(int, track.albums[0].id)
|
|
||||||
embed = await process_track(track)
|
if content_type in content_map:
|
||||||
await ctx.respond(embed=embed, view=ListenTrack(track, album_id))
|
content: Album | Track | Artist | Playlist = content_map[content_type][0].results[0]
|
||||||
elif content_type == 'Artist' and result.artists:
|
embed: discord.Embed = await content_map[content_type][1](content)
|
||||||
artist = result.artists.results[0]
|
view = content_map[content_type][2](content)
|
||||||
embed = await process_artist(artist)
|
|
||||||
await ctx.respond(embed=embed, view=ListenArtist(artist))
|
if isinstance(content, (Track, Album)) and (content.explicit or content.content_warning) and not guild['allow_explicit']:
|
||||||
elif content_type == 'Playlist' and result.playlists:
|
await ctx.respond("❌ Explicit контент запрещён на этом сервере.", delete_after=15, ephemeral=True)
|
||||||
playlist = result.playlists.results[0]
|
return
|
||||||
embed = await process_playlist(playlist)
|
elif isinstance(content, Artist):
|
||||||
await ctx.respond(embed=embed, view=ListenPlaylist(playlist))
|
tracks = await content.get_tracks_async()
|
||||||
|
if not tracks:
|
||||||
|
await ctx.respond("❌ Треки от этого исполнителя не найдены.", delete_after=15, ephemeral=True)
|
||||||
|
return
|
||||||
|
for track in tracks:
|
||||||
|
if (track.explicit or track.content_warning) and not guild['allow_explicit']:
|
||||||
|
view = None
|
||||||
|
embed.set_footer(text="Воспроизведение недоступно, так как у автора присутствуют Explicit треки")
|
||||||
|
break
|
||||||
|
elif isinstance(content, Playlist):
|
||||||
|
tracks = await content.fetch_tracks_async()
|
||||||
|
if not tracks:
|
||||||
|
await ctx.respond("❌ Треки в этом плейлисте не найдены.", delete_after=15, ephemeral=True)
|
||||||
|
return
|
||||||
|
for track_short in content.tracks:
|
||||||
|
track = cast(Track, track_short.track)
|
||||||
|
if (track.explicit or track.content_warning) and not guild['allow_explicit']:
|
||||||
|
view = None
|
||||||
|
embed.set_footer(text="Воспроизведение недоступно, так как у автора присутствуют Explicit треки")
|
||||||
|
break
|
||||||
|
|
||||||
|
await ctx.respond(embed=embed, view=view)
|
||||||
else:
|
else:
|
||||||
await ctx.respond("❌ По запросу ничего не найдено.", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ По запросу ничего не найдено.", delete_after=15, ephemeral=True)
|
||||||
|
|||||||
@@ -139,10 +139,10 @@ class PlayPlaylistButton(Button, VoiceExtension):
|
|||||||
|
|
||||||
class ListenTrack(View):
|
class ListenTrack(View):
|
||||||
|
|
||||||
def __init__(self, track: Track, album_id: int, *items: Item, timeout: float | None = None, disable_on_timeout: bool = False):
|
def __init__(self, track: Track, *items: Item, timeout: float | None = None, disable_on_timeout: bool = False):
|
||||||
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
|
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
|
||||||
link_app = f"yandexmusic://album/{album_id}/track/{track.id}"
|
link_app = f"yandexmusic://album/{track.albums[0].id}/track/{track.id}"
|
||||||
link_web = f"https://music.yandex.ru/album/{album_id}/track/{track.id}"
|
link_web = f"https://music.yandex.ru/album/{track.albums[0].id}/track/{track.id}"
|
||||||
self.button1: Button = Button(label="Слушать в приложении", style=ButtonStyle.gray, url=link_app)
|
self.button1: Button = Button(label="Слушать в приложении", style=ButtonStyle.gray, url=link_app)
|
||||||
self.button2: Button = Button(label="Слушать в браузере", style=ButtonStyle.gray, url=link_web)
|
self.button2: Button = Button(label="Слушать в браузере", style=ButtonStyle.gray, url=link_web)
|
||||||
self.button3: PlayTrackButton = PlayTrackButton(track, label="Слушать в голосовом канале", style=ButtonStyle.gray)
|
self.button3: PlayTrackButton = PlayTrackButton(track, label="Слушать в голосовом канале", style=ButtonStyle.gray)
|
||||||
@@ -180,6 +180,7 @@ class ListenArtist(View):
|
|||||||
self.add_item(self.button3)
|
self.add_item(self.button3)
|
||||||
|
|
||||||
class ListenPlaylist(View):
|
class ListenPlaylist(View):
|
||||||
|
|
||||||
def __init__(self, playlist: Playlist, *items: Item, timeout: float | None = None, disable_on_timeout: bool = False):
|
def __init__(self, playlist: Playlist, *items: Item, timeout: float | None = None, disable_on_timeout: bool = False):
|
||||||
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
|
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
|
||||||
link_app = f"yandexmusic://playlist/{playlist.playlist_uuid}"
|
link_app = f"yandexmusic://playlist/{playlist.playlist_uuid}"
|
||||||
|
|||||||
@@ -458,4 +458,3 @@ class VoiceExtension:
|
|||||||
return None
|
return None
|
||||||
await client.users_likes_tracks_remove(ym_track.id, client.me.account.uid)
|
await client.users_likes_tracks_remove(ym_track.id, client.me.account.uid)
|
||||||
return 'TRACK REMOVED'
|
return 'TRACK REMOVED'
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ class Voice(Cog, VoiceExtension):
|
|||||||
embed = None
|
embed = None
|
||||||
|
|
||||||
if len(channel.members) > 2 and not guild['always_allow_menu']:
|
if len(channel.members) > 2 and not guild['always_allow_menu']:
|
||||||
await ctx.respond("Вы не единственный в голосовом канале.", ephemeral=True)
|
await ctx.respond("❌ Вы не единственный в голосовом канале.", ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
if guild['current_track']:
|
if guild['current_track']:
|
||||||
@@ -159,8 +159,8 @@ class Voice(Cog, VoiceExtension):
|
|||||||
Track.de_json(
|
Track.de_json(
|
||||||
guild['current_track'],
|
guild['current_track'],
|
||||||
client=ClientAsync() # type: ignore # Async client can be used here.
|
client=ClientAsync() # type: ignore # Async client can be used here.
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
vc = await self.get_voice_client(ctx)
|
vc = await self.get_voice_client(ctx)
|
||||||
if vc and vc.is_paused():
|
if vc and vc.is_paused():
|
||||||
embed.set_footer(text='Приостановлено')
|
embed.set_footer(text='Приостановлено')
|
||||||
|
|||||||
Reference in New Issue
Block a user