はじめに
この記事では、discord.pyのFFmpegPCMAudio
を利用してYouTube動画をボイスチャットで再生するために必要な手順について解説します。
(前回の記事の応用内容です。)
この記事の対象者
- discord.pyでYouTubeの動画をボイスチャットで再生したい
- 前回の記事の応用をしたい
前提知識
- Replitでdiscord.pyのFFmpegPCMAudioを使う の内容(discord.pyで音声を再生する方法)
手順
前回の記事と同じ作業が必要なのでここでは省きます
1. 必要なライブラリをインストールする
YouTubeの動画を参照するため、動画のソースを取得する手段が必要です。ここではpytubeを扱いますが、必要に応じてyoutube_dl等のライブラリで代用することができます。
1. pytubeをpipコマンドでインストールする
以下のコマンドをシェルから実行してください:
pip install -U pytube
2. インストールを確認する
pip show pytube
Name: pytube
Version: 15.0.0
Summary: Python 3 library for downloading YouTube Videos.
Home-page: https://github.com/pytube/pytube
Author: Ronnie Ghose, Taylor Fox Dahlin, Nick Ficano
Author-email: hey@pytube.io
License: The Unlicense (Unlicense)
Location: /xxx/.pythonlibs/lib/python3.10/site-packages
Requires:
Required-by:
この記事の執筆時点では15.0.0
が最新バージョンですが、更新される可能性があります。
2. 実際のコードに組み込む
1. pytubeライブラリの使い方
from pytube import YouTube
# URLの形が不正であるとインスタンスを作成した時点で pytube.exceptions.RegexMatchError が発生します
yt = YouTube("youtu.be/eXaMpLe")
# pytube.YouTubeのインスタンスはstreams属性からpytube.query.StreamQueryのリストを返しますが、
# 動画が利用できない場合(idに合う動画が見つからないなど)は pytube.exceptions.VideoUnavailable が発生します
streams: list = yt.streams
# ストリームを音声のみでフィルターし、音質の良い順に並び替え、最初の項目を取得します
# これにより最高音質のオーディオストリームを取得できます
audio = streams.filter(only_audio=True).order_by('abr').last()
# pytube.query.StreamQueryのurl属性からソースのリンクを取得します
# 音声をダウンロードしてio.BytesIOで再生する方法もありますが、帯域を節約するためにリンクを使います
url = audio.url
2. discord.pyを使って再生する
# discord.FFmpegPCMAudioを使って再生するための音声ソースを作成します
source = discord.FFmpegPCMAudio(url)
# discord.PCMVolumeTransformerを使って音声を調節します(任意)
# volumeの値は音量の倍率を指定し、1の場合はそのままの音量で、0の場合は無音になります
source = discord.PCMVolumeTransformer(source, volume=0.5)
# discord.VoiceClientのplayメソッドを利用して音声ソースを再生します
vc.play(source)
3. 最終的なコードの例
1. pytubeを利用した書き方
shell
pip install -U discord.py[voice] pytube
main.py
import os
import discord
from discord.ext import commands
from pytube import YouTube
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='!', intents=intents)
tree = bot.tree
discord.opus.load_opus('libopus/lib/libopus.so')
@bot.command()
async def play(ctx, url, volume=1.0):
try:
volume = float(volume)
except ValueError:
ctx.send("音量は数字で指定してください")
return
if ctx.guild.voice_client is None:
vc = await ctx.author.voice.channel.connect(self_deaf=True)
else:
vc = ctx.guild.voice_client
try:
yt = YouTube(url)
streams = yt.streams
audio = streams.filter(only_audio=True).order_by('abr').last()
source = discord.FFmpegPCMAudio(audio.url)
source = discord.PCMVolumeTransformer(source, volume=volume)
vc.play(source)
await ctx.send(f'再生開始: {yt.title}, 音量: {volume*100}%')
while vc.is_playing():
await asyncio.sleep(1)
await vc.disconnect()
except Exception as e:
await ctx.send("再生中にエラーが発生しました")
raise e
bot.run(os.environ['TOKEN'])
2. youtube_dlを利用した書き方
shell
pip install -U discord.py[voice] youtube_dl
main.py
import os
import discord
from discord.ext import commands
from youtube_dl import YoutubeDL
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='!', intents=intents)
tree = bot.tree
discord.opus.load_opus('libopus/lib/libopus.so')
@bot.command()
async def play(ctx, url, volume=1.0):
try:
volume = float(volume)
except ValueError:
await ctx.send("音量は数字で指定してください")
return
if ctx.guild.voice_client is None:
vc = await ctx.author.voice.channel.connect()
else:
vc = ctx.guild.voice_client
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegPCMAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
with YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info(url, download=False)
url2 = info_dict['formats'][0]['url']
source = discord.FFmpegPCMAudio(url2)
source = discord.PCMVolumeTransformer(source, volume=volume)
vc.play(source)
await ctx.send(f'再生開始: {info_dict["title"]}, 音量: {volume*100}%')
while vc.is_playing():
await asyncio.sleep(1)
await vc.disconnect()
bot.run(os.environ['TOKEN'])
終わりに
最後まで読んで頂きありがとうございます。不備があればコメントで指摘して下さい。