disnake

Форк
0
/
basic_voice.py 
143 строки · 4.5 Кб
1
# SPDX-License-Identifier: MIT
2

3
"""A basic example showing how to integrate audio from youtube-dl into voice chat."""
4

5
# NOTE: this example requires ffmpeg (https://ffmpeg.org/download.html) to be installed
6
#       and available in your `%PATH%` or `$PATH`
7

8
# pyright: reportUnknownLambdaType=false
9

10
import asyncio
11
import os
12
from typing import Any, Dict, Optional
13

14
import disnake
15
import youtube_dl  # type: ignore
16
from disnake.ext import commands
17

18
# Suppress noise about console usage from errors
19
youtube_dl.utils.bug_reports_message = lambda: ""
20

21

22
ytdl_format_options = {
23
    "format": "bestaudio/best",
24
    "outtmpl": "%(extractor)s-%(id)s-%(title)s.%(ext)s",
25
    "restrictfilenames": True,
26
    "noplaylist": True,
27
    "nocheckcertificate": True,
28
    "ignoreerrors": False,
29
    "logtostderr": False,
30
    "quiet": True,
31
    "no_warnings": True,
32
    "default_search": "auto",
33
    "source_address": "0.0.0.0",  # bind to ipv4 since ipv6 addresses cause issues sometimes
34
}
35

36
ytdl = youtube_dl.YoutubeDL(ytdl_format_options)
37

38

39
class YTDLSource(disnake.PCMVolumeTransformer):
40
    def __init__(self, source: disnake.AudioSource, *, data: Dict[str, Any], volume: float = 0.5):
41
        super().__init__(source, volume)
42

43
        self.title = data.get("title")
44

45
    @classmethod
46
    async def from_url(
47
        cls, url, *, loop: Optional[asyncio.AbstractEventLoop] = None, stream: bool = False
48
    ):
49
        loop = loop or asyncio.get_event_loop()
50
        data: Any = await loop.run_in_executor(
51
            None, lambda: ytdl.extract_info(url, download=not stream)
52
        )
53

54
        if "entries" in data:
55
            # take first item from a playlist
56
            data = data["entries"][0]
57

58
        filename = data["url"] if stream else ytdl.prepare_filename(data)
59

60
        return cls(disnake.FFmpegPCMAudio(filename, options="-vn"), data=data)
61

62

63
class Music(commands.Cog):
64
    def __init__(self, bot: commands.Bot):
65
        self.bot = bot
66

67
    @commands.command()
68
    async def join(self, ctx, *, channel: disnake.VoiceChannel):
69
        """Joins a voice channel"""
70
        if ctx.voice_client is not None:
71
            return await ctx.voice_client.move_to(channel)
72

73
        await channel.connect()
74

75
    @commands.command()
76
    async def play(self, ctx, *, query: str):
77
        """Plays a file from the local filesystem"""
78
        await self.ensure_voice(ctx)
79
        source = disnake.PCMVolumeTransformer(disnake.FFmpegPCMAudio(query))
80
        ctx.voice_client.play(source, after=lambda e: print(f"Player error: {e}") if e else None)
81

82
        await ctx.send(f"Now playing: {query}")
83

84
    @commands.command()
85
    async def yt(self, ctx, *, url: str):
86
        """Plays from a url (almost anything youtube_dl supports)"""
87
        await self._play_url(ctx, url=url, stream=False)
88

89
    @commands.command()
90
    async def stream(self, ctx, *, url: str):
91
        """Streams from a url (same as yt, but doesn't predownload)"""
92
        await self._play_url(ctx, url=url, stream=True)
93

94
    async def _play_url(self, ctx, *, url: str, stream: bool):
95
        await self.ensure_voice(ctx)
96
        async with ctx.typing():
97
            player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=stream)
98
            ctx.voice_client.play(
99
                player, after=lambda e: print(f"Player error: {e}") if e else None
100
            )
101

102
        await ctx.send(f"Now playing: {player.title}")
103

104
    @commands.command()
105
    async def volume(self, ctx, volume: int):
106
        """Changes the player's volume"""
107
        if ctx.voice_client is None:
108
            return await ctx.send("Not connected to a voice channel.")
109

110
        ctx.voice_client.source.volume = volume / 100
111
        await ctx.send(f"Changed volume to {volume}%")
112

113
    @commands.command()
114
    async def stop(self, ctx):
115
        """Stops and disconnects the bot from voice"""
116
        await ctx.voice_client.disconnect()
117

118
    async def ensure_voice(self, ctx):
119
        if ctx.voice_client is None:
120
            if ctx.author.voice:
121
                await ctx.author.voice.channel.connect()
122
            else:
123
                await ctx.send("You are not connected to a voice channel.")
124
                raise commands.CommandError("Author not connected to a voice channel.")
125
        elif ctx.voice_client.is_playing():
126
            ctx.voice_client.stop()
127

128

129
bot = commands.Bot(
130
    command_prefix=commands.when_mentioned,
131
    description="Relatively simple music bot example",
132
)
133

134

135
@bot.event
136
async def on_ready():
137
    print(f"Logged in as {bot.user} (ID: {bot.user.id})\n------")
138

139

140
bot.add_cog(Music(bot))
141

142
if __name__ == "__main__":
143
    bot.run(os.getenv("BOT_TOKEN"))
144

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.