質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Discord

Discordは、ゲーマー向けのボイスチャットアプリです。チャット・通話がブラウザ上で利用可能で、個人専用サーバーも開設できます。通話中でも音楽を流したり、PC画面を共有できるなど多機能な点が特徴です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

4574閲覧

discord.pyで音声再生中に新たな入力を受け付けない

GardenTree

総合スコア22

Discord

Discordは、ゲーマー向けのボイスチャットアプリです。チャット・通話がブラウザ上で利用可能で、個人専用サーバーも開設できます。通話中でも音楽を流したり、PC画面を共有できるなど多機能な点が特徴です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/08/13 15:55

編集2021/08/13 15:59

##概要
discord.pyでdiscordのbotを製作していて、テキストチャンネルの発言をボイスチャンネルで読み上げようとしています。読み上げにはVoiceTextのAPIを使用してwaveファイルを取得し、ffmpegPCMAudioで再生しています。
##環境
Windows 10 home 64bit

Python 3.9
discord.py 1.7.3
python-voicetext 0.3.1
##症状
長文を読み上げている最中にテキストチャンネルに新たに発言すると、エラーが発生し、新しい方の発言は読み上げられない。
##コード

python

1import discord 2import datetime 3import time 4import os 5from voicetext import VoiceText 6import wave 7import asyncio 8 9 10TOKEN = '' 11KEY = "" 12 13 14client = discord.Client() 15vt = VoiceText(KEY) 16check_text_channel = None 17 18 19#接続時の処理 20@client.event 21async def on_ready(): 22 dt_now = datetime.datetime.now() 23 print(f"[{dt_now}]Launch complete!") 24 25#メッセージが送られた時 26@client.event 27async def on_message(message): 28 29 #botの発言は無視 30 if message.author.bot: 31 return 32 33 #ボイスチャンネルに接続 34 elif message.content == "yomi.c": 35 if message.author.voice is None: 36 await message.channel.send(f"{message.author.mention}さんはボイスチャンネルに接続していません") 37 dt_now = datetime.datetime.now() 38 print(f"[{dt_now}]{message.author}さんはボイスチャンネルに接続していません") 39 40 else: 41 await message.author.voice.channel.connect() 42 global check_text_channel 43 check_text_channel = message.channel 44 await message.channel.send(f"{message.author.voice.channel.name}に接続しました") 45 dt_now = datetime.datetime.now() 46 print(f"[{dt_now}]{message.author.voice.channel.name}に接続しました") 47 48 49 #ボイスチャンネルから切断 50 elif message.content == "yomi.dc": 51 if message.guild.voice_client is None: 52 await message.channel.send("ボイスチャンネルに接続していません") 53 dt_now = datetime.datetime.now() 54 print(f"[{dt_now}]ボイスチャンネルに接続していません") 55 56 else: 57 await message.guild.voice_client.disconnect() 58 await message.channel.send("切断しました") 59 dt_now = datetime.datetime.now() 60 print(f"[{dt_now}]切断しました") 61 62 #読み上げ 63 elif message.channel == check_text_channel: 64 if message.guild.voice_client is None: 65 await message.channel.send("ボイスチャンネルに接続していません") 66 dt_now = datetime.datetime.now() 67 print(f"[{dt_now}]ボイスチャンネルに接続していません") 68 69 else: 70 #音声ファイル作成 71 ut = time.time() 72 with open(f"{ut}.wav","wb") as f: 73 f.write(vt.speed(150).to_wave(message.content)) 74 75 #音声読み上げ 76 message.guild.voice_client.play(discord.FFmpegPCMAudio(f"{ut}.wav")) 77 78 79 #音声ファイル削除 80 with wave.open(f"{ut}.wav", "rb")as f: 81 wave_length=(f.getnframes() / f.getframerate()) #再生時間 82 print(f"PlayTime:{wave_length}") 83 await asyncio.sleep(wave_length + 5) 84 os.remove(f"{ut}.wav") 85 86client.run(TOKEN)

##エラーメッセージ

ErrorMessage

1PlayTime:7.034013605442177 2Ignoring exception in on_message 3Traceback (most recent call last): 4 File "C:\Users\GardenTree\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\client.py", line 343, in _run_event 5 await coro(*args, **kwargs) 6 File "d:\Desktop\yomi-KAI\yomi-KAI.py", line 76, in on_message 7 message.guild.voice_client.play(discord.FFmpegPCMAudio(f"{ut}.wav")) 8 File "C:\Users\GardenTree\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\voice_client.py", line 558, in play 9 raise ClientException('Already playing audio.') 10discord.errors.ClientException: Already playing audio. 11INFO:discord.player:Preparing to terminate ffmpeg process 35480. 12INFO:discord.player:ffmpeg process 35480 has not terminated. Waiting to terminate... 13INFO:discord.player:ffmpeg process 35480 should have terminated with a return code of 1. 14INFO:discord.player:Preparing to terminate ffmpeg process 7840. 15INFO:discord.player:ffmpeg process 7840 successfully terminated with return code of 0.

##調べたこと

  • ブロッキングが発生している?
  • Queueを使えば良い?

##実現したいこと
長文を読み上げ中に新たなテキストが送られると、長文を読み終わった後に読んでほしい。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

VioceClient.playは、引数afterに指定した関数を音声再生後かエラー発生時に実行することができます。
なのでキューが空になるまでafterで再帰すればいいです。

また、キューはcollections.dequeを使うと良いと思います。
複数のサーバーで運用される場合、キューはサーバーごとに持たないと音声が混ざってしまうのでdictなどに格納するといいでしょう。

ざっくりとですが、イメージとしては、

py

1from collections import defaultdict, deque 2 3queue_dict = defaultdict(deque) 4 5def enqueue(voice_client, guild, source): 6 queue = queue_dict[guild.id] 7 queue.append(source) 8 if not voice_client.is_playing(): 9 play(voice_client, queue) 10 11def play(voice_client, queue): 12 if not queue or voice_client.is_playing(): 13 return 14 source = queue.popleft() 15 voice_client.play(source, after=lambda e:play(voice_client, queue))

のような感じでしょうか。プログラムに合わせて適宜読み替えてください。

投稿2021/08/13 20:41

編集2021/08/14 14:20
kairi003

総合スコア1332

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

GardenTree

2021/08/14 13:16

6行目のstack_dictはqueue_dictのtypoでしょうか? また、読み替えるところを教えていただきたいです。
kairi003

2021/08/14 13:25

Typoです修正しました いや別に読み替えなきゃいけないわけでもないんですけど、あんまり元のコードに合わせて書いてないので、afterにwavの削除を組み込むとか、引数をmessageにするとかしてみてくださいって意味です
GardenTree

2021/08/14 13:46

何度も申し訳ないのですが、playのqueueには何を渡せばよいのでしょうか?
kairi003

2021/08/14 13:50

AudioSource、つまり今回はFFmpegPCMAudioです
GardenTree

2021/08/14 13:59

voice_client.play(source, lambda e:play(voice_client, queue)) TypeError: play() takes 2 positional arguments but 3 were given というエラーメッセージが表示されるのですが、どのようにすればよいのでしょうか?
kairi003

2021/08/14 14:01

すみません、after=が必要でした
GardenTree

2021/08/14 14:09

enqueue(message.guild.voice_client, message.guild, f"{ut}.wav") play(message.guild.voice_client, discord.FFmpegPCMAudio) このように呼び出せばよいのでしょうか?
kairi003

2021/08/14 14:17

すみません、 >>playのqueue から勘違いしてました。 playはenqueueから呼び出しています。 引数queueはそのサーバーのqueue、つまりqueue_dict[guild.id]です。 playを直接呼び出すことはしません。 enuqueueはenqueue(message.guild.voice_client, message.guild, discord.FFmpegPCMAudio(f"{ut}.wav"))です。
GardenTree

2021/08/14 14:27

思ったとおりに動作しました!! ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問