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

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

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

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

並列処理

複数の計算が同時に実行される手法

YouTube

YouTubeとはユーザーがビデオをアップロード・共有・閲覧できるビデオ共有ウェブサイトです。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Python

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

Q&A

解決済

1回答

1117閲覧

実行可能な処理が残っているのにも関わらず処理が終了する

saba0592

総合スコア3

Discord

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

並列処理

複数の計算が同時に実行される手法

YouTube

YouTubeとはユーザーがビデオをアップロード・共有・閲覧できるビデオ共有ウェブサイトです。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Python

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

0グッド

0クリップ

投稿2021/12/22 16:14

編集2021/12/22 22:59

前提・実現したいこと

Musicクラスのplay()、もしくはloop()を実行した際にYTDLSource.from_url()以降を処理したい。

発生している問題・エラーメッセージ

Musicクラスのplay()、もしくはloop()を実行するとYTDLSource.from_url()を実行する行で処理が終了し、次以降を処理してくれない。

該当のソースコード

Python

1import asyncio 2 3import discord 4from discord.ext import commands 5import traceback 6import youtube_dl 7import os 8import urllib.request 9import re 10 11 12# Suppress noise about console usage from errors 13youtube_dl.utils.bug_reports_message = lambda: '' 14 15prefix = os.getenv('DISCORD_BOT_PREFIX', default='>') 16lang = os.getenv('DISCORD_BOT_LANG', default='ja') 17token = 'token' 18 19 20ytdl_format_options = { 21 'format': 'bestaudio/best', 22 'outtmpl': '%(extractor)s-%(id)s-%(title)s.mp3', 23 'restrictfilenames': True, 24 'noplaylist': True, 25 'nocheckcertificate': True, 26 'ignoreerrors': False, 27 'logtostderr': False, 28 'quiet': True, 29 'no_warnings': True, 30 'postprocessors': [{ 31 'key': 'FFmpegExtractAudio', 32 'preferredcodec': 'mp3', 33 'preferredquality': '192', 34 }], 35 'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes: True 36} 37 38ffmpeg_options = { 39 'options': '-vn' 40} 41 42ytdl = youtube_dl.YoutubeDL(ytdl_format_options) 43 44 45class YTDLSource(discord.PCMVolumeTransformer): 46 def __init__(self, source, *, data, volume=0.2): 47 super().__init__(source, volume) 48 49 self.data = data 50 51 self.title = data.get('title') 52 self.url = data.get('url') 53 54 @classmethod 55 async def from_url(cls, url, *, loop=None): 56 loop = loop or asyncio.get_event_loop() 57 data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=False)) 58 59 if 'entries' in data: 60 # take first item from a playlist 61 data = data['entries'][0] 62 63 filename = data['url'] 64 ytdl.prepare_filename(data) 65 return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data) 66 67 68class AudioQueue(asyncio.Queue): 69 def __init__(self): 70 super().__init__(100) 71 72 def __getitem__(self, idx): 73 return self._queue[idx] 74 75 def to_list(self): 76 return list(self._queue) 77 78 def remove(self, idx): 79 del self._queue[idx] 80 81 def reset(self): 82 self._queue.clear() 83 84 85class AudioStatus: 86 def __init__(self, ctx: commands.Context, vc: discord.VoiceClient): 87 self.vc: discord.VoiceClient = vc 88 self.ctx: commands.Context = ctx 89 self.queue = AudioQueue() 90 self.playing = asyncio.Event() 91 self.loopMode = False 92 asyncio.create_task(self.playing_task()) 93 94 async def add_audio(self, title, path): 95 await self.queue.put([title, path]) 96 97 def get_list(self): 98 return self.queue.to_list() 99 100 def remove(self, idx): 101 self.queue.remove(idx) 102 103 def reset(self): 104 self.queue.reset() 105 106 async def playing_task(self): 107 while True: 108 self.playing.clear() 109 if self.loopMode: 110 title, player = self.queue[0] 111 else: 112 title, player = await self.queue.get() 113 self.vc.play(player, after=self.play_next) 114 if not self.loopMode: 115 await self.ctx.send(f'{title}を再生します。') 116 await self.playing.wait() 117 118 def play_next(self, err=None): 119 self.playing.set() 120 121 async def leave(self): 122 self.queue.reset() 123 if self.vc: 124 await self.vc.disconnect() 125 self.vc = None 126 127 @property 128 def is_playing(self): 129 return self.vc.is_playing() 130 131 def resume(self): 132 self.vc.stop() 133 134 def pause(self): 135 self.vc.stop() 136 137 def stop(self): 138 self.vc.stop() 139 140 141class Music(commands.Cog): 142 def __init__(self, bot): 143 self.bot = bot 144 self.audio_statuses = "" 145 146 # command to connect to voice channel 147 @commands.command(aliases=["s"]) 148 async def start(self, ctx): 149 """Joins a voice channel""" 150 151 if ctx.author.voice is None: 152 await ctx.send('先にボイスチャンネルに接続してください…。') 153 else: 154 if ctx.guild.voice_client: 155 if ctx.author.voice.channel == ctx.guild.voice_client.channel: 156 await ctx.send('既に接続済みです…。') 157 else: 158 await ctx.voice_client.disconnect() 159 await asyncio.sleep(0.5) 160 vc = await ctx.author.voice.channel.connect() 161 self.audio_statuses = AudioStatus(ctx, vc) 162 await ctx.send('ボイスチャンネルを変更しました。') 163 else: 164 vc = await ctx.author.voice.channel.connect() 165 self.audio_statuses = AudioStatus(ctx, vc) 166 await ctx.send('ボイスチャンネルに接続しました。') 167 168 # command to play sound from a youtube URL or add to queue 169 @commands.command(aliases=["pl"]) 170 async def play(self, ctx, *, entry): 171 """Play music""" 172 173 status = self.audio_statuses 174 status.loopMode = False 175 queue = status.get_list 176 177 player = await Music.get_player(ctx, entry) 178 if len(queue) != 0: 179 await ctx.send(f'`{player.title}`を追加しました。') 180 await status.add_audio(player.title, player) 181 182 # command to loop play sound from a youtube URL 183 @commands.command(aliases=["l"]) 184 async def loop(self, ctx, *, entry): 185 """Loop play music""" 186 187 status = self.audio_statuses 188 status.loopMode = True 189 190 player = await Music.get_player(ctx, entry) 191 await status.reset() 192 await ctx.send(f'`{player.title}`を追加しました。') 193 await status.add_audio(player.title, player) 194 195 @classmethod 196 async def get_player(self, ctx, entry): 197 if entry.startswith('http') is True: 198 url = entry 199 else: 200 search_keyword = entry.replace(" ", "+") 201 regex = r'[^\x00-\x7F]' 202 matchedList = re.findall(regex, search_keyword) 203 for m in matchedList: 204 search_keyword = search_keyword.replace(m, urllib.parse.quote_plus(m, encoding="utf-8")) 205 html = urllib.request.urlopen("https://www.youtube.com/results?search_query=" + search_keyword) 206 video_ids = re.findall(r"watch?v=(\S{11})", html.read().decode()) 207 url = "https://www.youtube.com/watch?v=" + video_ids[0] 208 async with ctx.typing(): 209 return await YTDLSource.from_url(url, loop=self.bot.loop) 210 211 212bot = commands.Bot(command_prefix=prefix, 213 description='Relatively simple music bot example') 214 215 216@bot.event 217async def on_ready(): 218 print('Logged in as {0} ({0.id})'.format(bot.user)) 219 print('------') 220 await bot.change_presence(activity=discord.Game(name=f'{prefix}hでコマンド一覧', type=1)) 221 222 223@bot.event 224async def on_command_error(ctx, error): 225 if isinstance(error, commands.errors.CommandNotFound): 226 await ctx.send('存在しないコマンドです…。') 227 elif isinstance(error, commands.errors.MissingRequiredArgument): 228 await ctx.send('引数が足りません…。') 229 elif isinstance(error, commands.CommandError): 230 pass 231 else: 232 orig_error = getattr(error, 'original', error) 233 error_msg = ''.join(traceback.TracebackException.from_exception(orig_error).format()) 234 await ctx.send("不明なエラーが発生…。") 235 await bot.get_channel(チャンネルID).send(error_msg) 236 print(error_msg) 237 238bot.add_cog(Music(bot)) 239bot.run(token)

試したこと

①get_player()を削除して該当処理をplay()の中で処理してみた。→YTDLSource.from_url()の行までは進んだが、そこで処理が終了。
②get_player()の次の行にprint()を記述→実行されたがprint()以降は実行されず。
③デバッグしてみた。→YTDLSource.from_url()の行までは進んだが、そこでステップインを行うと処理が終了。
④YTDLSource.from_url()をコメントアウトし、別の戻り値を設定。→同じ箇所で処理が終了する。
⑤YTDLSource.from_url()だけをplay()の中で実行→③と同じ
⑥スタックトレースを確認→出力なし

補足情報(FW/ツールのバージョンなど)

Python 3.9.5
youtube-dl 2021/12/17
ffmpeg 4.4

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

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

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

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

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

guest

回答1

0

自己解決

複数箇所に問題がありました。
・status.get_list()の()を書き忘れていた。そのためif len(queue)でエラーが発生していた。
・get_player()の処理の中でself.botを使用しているが、Musicオブジェクトにbot属性がない。get_player()の引数にbotを追加することで解決。
・loop()を起動すると、playing_task()のself.queue[0]でIndexError。未解決ですが、自力でなんとかします。

今回難航する原因となった、「on_command_error()を定義しているのにStackTraceが出力されない」件は私には分かりません。ひとまずすべてのメソッドにtry exceptを追加し、raise Exceptionすることで対処します。

投稿2021/12/23 14:19

編集2021/12/23 14:21
saba0592

総合スコア3

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問