ffmpeg:加载共享库时出错:libvpx.so.6:无法打开共享对象文件:没有这样的文件或目录

问题描述

我正在用 Python 重写构建一个多工具 discord bot。

所以我决定也添加音乐。当我完成机器人并在我的本地电脑上尝试它时,它运行良好。但是,当我上传到 Heroku 时,我遇到了一些 ffmpeg 错误

最初我认为 Heroku 是基于 Linux 的,所以我下载了适用于 Linux 的 ffmpeg。还是没用。然后我添加一个 apt buildpack 并以这种方式下载。但是现在它起作用了,但出现了不同的错误。它找到了 ffmpeg 但歌曲没有播放,这显示在控制台中:

[ffmpeg:加载共享库时出错:libvpx.so.6:不能 打开共享对象文件:没有那个文件或目录]

我该如何解决这个问题?

完整代码如下:

import discord
from discord.ext import commands

import asyncio
import itertools
import sys
import traceback
from async_timeout import timeout
from functools import partial
from youtube_dl import YoutubedL
import ctypes
import ctypes.util

@commands.Cog.listener()
async def on_ready(self):

    print("ctypes - Find opus:")
    a = ctypes.util.find_library('opus')
    print(a)
    
    print("discord - Load Opus:")
    b = discord.opus.load_opus(a)
    print(b)
    
    print("discord - Is loaded:")
    c = discord.opus.is_loaded()
    print(c)



ytdlopts = {
    'format': 'bestaudio/best','outtmpl': 'downloads/%(extractor)s-%(id)s-%(title)s.%(ext)s','restrictfilenames': True,'noplaylist': True,'nocheckcertificate': True,'ignoreerrors': False,'logtostderr': False,'quiet': True,'no_warnings': True,'default_search': 'auto','source_address': '0.0.0.0'
}

ffmpegopts = {
    'before_options': '-nostdin','options': '-vn'
}

ytdl = YoutubedL(ytdlopts)


class VoiceConnectionError(commands.CommandError):


class InvalidVoiceChannel(VoiceConnectionError):



class YTDLSource(discord.PCMVolumeTransformer):

    def __init__(self,source,*,data,requester):
        super().__init__(source)
        self.requester = requester

        self.title = data.get('title')
        self.web_url = data.get('webpage_url')


    def __getitem__(self,item: str):
        return self.__getattribute__(item)

    @classmethod
    async def create_source(cls,ctx,search: str,loop,download=False):
        loop = loop or asyncio.get_event_loop()

        to_run = partial(ytdl.extract_info,url=search,download=download)
        data = await loop.run_in_executor(None,to_run)

        if 'entries' in data:
            data = data['entries'][0]

        await ctx.send(f'```ini\n[Added {data["title"]} to the Queue.]\n```')

        if download:
            source = ytdl.prepare_filename(data)
        else:
            return {'webpage_url': data['webpage_url'],'requester': ctx.author,'title': data['title']}

        return cls(discord.FFmpegPCMAudio(source),data=data,requester=ctx.author)

    @classmethod
    async def regather_stream(cls,loop):
        """Used for preparing a stream,instead of downloading.
        Since Youtube Streaming links expire."""
        loop = loop or asyncio.get_event_loop()
        requester = data['requester']

        to_run = partial(ytdl.extract_info,url=data['webpage_url'],download=False)
        data = await loop.run_in_executor(None,to_run)

        return cls(discord.FFmpegPCMAudio(data['url']),requester=requester)


class MusicPlayer(commands.Cog):

    __slots__ = ('bot','_guild','_channel','_cog','queue','next','current','np','volume')

    def __init__(self,ctx):
        self.bot = ctx.bot
        self._guild = ctx.guild
        self._channel = ctx.channel
        self._cog = ctx.cog

        self.queue = asyncio.Queue()
        self.next = asyncio.Event()

        self.np = None
        self.volume = .5
        self.current = None

        ctx.bot.loop.create_task(self.player_loop())

    async def player_loop(self):
        """Our main player loop."""
        await self.bot.wait_until_ready()

        while not self.bot.is_closed():
            self.next.clear()

            try:
                    source = await self.queue.get()
            except asyncio.TimeoutError:
                return self.destroy(self._guild)

            if not isinstance(source,YTDLSource):
                try:
                    source = await YTDLSource.regather_stream(source,loop=self.bot.loop)
                except Exception as e:
                    await self._channel.send(f'There was an error processing your song.\n'
                                             f'```css\n[{e}]\n```')
                    continue

            source.volume = self.volume
            self.current = source

            self._guild.voice_client.play(source,after=lambda _: self.bot.loop.call_soon_threadsafe(self.next.set))
            self.np = await self._channel.send(f'**Now Playing:** `{source.title}` requested by '
                                               f'`{source.requester}`')
            await self.next.wait()

            source.cleanup()
            self.current = None

            try:
                await self.np.delete()
            except discord.HTTPException:
                pass

    def destroy(self,guild):
        """disconnect and cleanup the player."""
        return self.bot.loop.create_task(self._cog.cleanup(guild))


class Music(commands.Cog):
    """Music related commands."""

    __slots__ = ('bot','players')

    def __init__(self,bot):
        self.bot = bot
        self.players = {}

    async def cleanup(self,guild):
        try:
            await guild.voice_client.disconnect()
        except AttributeError:
            pass

        try:
            del self.players[guild.id]
        except KeyError:
            pass

    async def __local_check(self,ctx):
        """A local check which applies to all commands in this cog."""
        if not ctx.guild:
            raise commands.noprivateMessage
        return True

    async def __error(self,error):
        """A local error handler for all errors arising from commands in this cog."""
        if isinstance(error,commands.noprivateMessage):
            try:
                return await ctx.send('This command can not be used in Private Messages.')
            except discord.HTTPException:
                pass
        elif isinstance(error,InvalidVoiceChannel):
            await ctx.send('Error connecting to Voice Channel. '
                           'Please make sure you are in a valid channel or provide me with one')

        print('Ignoring exception in command {}:'.format(ctx.command),file=sys.stderr)
        traceback.print_exception(type(error),error,error.__traceback__,file=sys.stderr)

    def get_player(self,ctx):
        """Retrieve the guild player,or generate one."""
        try:
            player = self.players[ctx.guild.id]
        except KeyError:
            player = MusicPlayer(ctx)
            self.players[ctx.guild.id] = player

        return player

    @commands.command(name='connect',aliases=['join'])
    async def connect_(self,ctx):
        try:
            channel = ctx.author.voice.channel
        except AttributeError:
            raise InvalidVoiceChannel('No channel to join.')

        vc = ctx.voice_client

        if vc:
            if vc.channel.id == channel.id:
                return
            try:
                await vc.move_to(channel)
            except asyncio.TimeoutError:
                raise VoiceConnectionError(f'Moving to channel: <{channel}> timed out.')
        else:
            try:
                await channel.connect()
            except asyncio.TimeoutError:
                raise VoiceConnectionError(f'Connecting to channel: <{channel}> timed out.')

        await ctx.send(f'Connected to: **{channel}**',)

    @commands.command(name='play',aliases=['sing'])
    async def play_(self,search: str):
        await ctx.trigger_typing()

        vc = ctx.voice_client

        if not vc:
            await ctx.invoke(self.connect_)

        player = self.get_player(ctx)
        source = await YTDLSource.create_source(ctx,search,loop=self.bot.loop,download=False)

        await player.queue.put(source)

    @commands.command(name='pause')
    async def pause_(self,ctx):
        """Pause the currently playing song."""
        vc = ctx.voice_client

        if not vc or not vc.is_playing():
            return await ctx.send('I am not currently playing anything!')
        elif vc.is_paused():
            return

        vc.pause()
        await ctx.send(f'**`{ctx.author}`**: Paused the song!')

    @commands.command(name='resume')
    async def resume_(self,ctx):
        """Resume the currently paused song."""
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            return await ctx.send('I am not currently playing anything!',)
        elif not vc.is_paused():
            return

        vc.resume()
        await ctx.send(f'**`{ctx.author}`**: Resumed the song!')

    @commands.command(name='skip')
    async def skip_(self,ctx):
        """Skip the song."""
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            return await ctx.send('I am not currently playing anything!')

        if vc.is_paused():
            pass
        elif not vc.is_playing():
            return

        vc.stop()
        await ctx.send(f'**`{ctx.author}`**: Skipped the song!')

    @commands.command(name='queue',aliases=['q','playlist'])
    async def queue_info(self,ctx):
        """Retrieve a basic queue of upcoming songs."""
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            return await ctx.send('I am not currently connected to voice!')

        player = self.get_player(ctx)
        if player.queue.empty():
            return await ctx.send('There are currently no more queued songs.')

        upcoming = list(itertools.islice(player.queue._queue,5))

        fmt = '\n'.join(f'**`{_["title"]}`**' for _ in upcoming)
        embed = discord.Embed(title=f'Upcoming - Next {len(upcoming)}',description=fmt)

        await ctx.send(embed=embed)

    @commands.command(name='Now_playing',aliases=['np','currentsong','playing'])
    async def Now_playing_(self,ctx):
        """display information about the currently playing song."""
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            return await ctx.send('I am not currently connected to voice!',)

        player = self.get_player(ctx)
        if not player.current:
            return await ctx.send('I am not currently playing anything!')

        try:
            await player.np.delete()
        except discord.HTTPException:
            pass

        player.np = await ctx.send(f'**Now Playing:** `{vc.source.title}` '
                                   f'requested by `{vc.source.requester}`')

    @commands.command(name='volume',aliases=['vol'])
    async def change_volume(self,vol: float):
        """Change the player volume.
        Parameters
        ------------
        volume: float or int [required]
            The volume to set the player to in percentage. This must be between 1 and 100.
        """
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            return await ctx.send('I am not currently connected to voice!',)

        if not 0 < vol < 101:
            return await ctx.send('Please enter a value between 1 and 100.')

        player = self.get_player(ctx)

        if vc.source:
            vc.source.volume = vol / 100

        player.volume = vol / 100
        await ctx.send(f'**`{ctx.author}`**: Set the volume to **{vol}%**')

    @commands.command(name='stop',aliases=['leave'])
    async def stop_(self,ctx):
        vc = ctx.voice_client

        if not vc or not vc.is_connected():
            return await ctx.send('I am not currently playing anything!')

        await self.cleanup(ctx.guild)


def setup(client):
    client.add_cog(Music(client))

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)