A powerful Lavalink library for Discord.py.

Overview

logo.png?raw=true

https://api.codacy.com/project/badge/Grade/d020ed97fd2a46fcb1f42bd3bc397e63

A robust and powerful Lavalink wrapper for Discord.py!

Documentation

Official Documentation.

Support

For support using WaveLink, please join the official support server on Discord.

Discord

Installation

The following commands are currently the valid ways of installing WaveLink.

WaveLink requires Python 3.7+

Windows

py -3.7 -m pip install Wavelink

Linux

python3.7 -m pip install Wavelink

Getting Started

A quick and easy bot example:

import discord
import wavelink
from discord.ext import commands


class Bot(commands.Bot):

    def __init__(self):
        super(Bot, self).__init__(command_prefix=['audio ', 'wave ','aw '])

        self.add_cog(Music(self))

    async def on_ready(self):
        print(f'Logged in as {self.user.name} | {self.user.id}')


class Music(commands.Cog):

    def __init__(self, bot):
        self.bot = bot

        if not hasattr(bot, 'wavelink'):
            self.bot.wavelink = wavelink.Client(bot=self.bot)

        self.bot.loop.create_task(self.start_nodes())

    async def start_nodes(self):
        await self.bot.wait_until_ready()

        # Initiate our nodes. For this example we will use one server.
        # Region should be a discord.py guild.region e.g sydney or us_central (Though this is not technically required)
        await self.bot.wavelink.initiate_node(host='127.0.0.1',
                                              port=2333,
                                              rest_uri='http://127.0.0.1:2333',
                                              password='youshallnotpass',
                                              identifier='TEST',
                                              region='us_central')

    @commands.command(name='connect')
    async def connect_(self, ctx, *, channel: discord.VoiceChannel=None):
        if not channel:
            try:
                channel = ctx.author.voice.channel
            except AttributeError:
                raise discord.DiscordException('No channel to join. Please either specify a valid channel or join one.')

        player = self.bot.wavelink.get_player(ctx.guild.id)
        await ctx.send(f'Connecting to **`{channel.name}`**')
        await player.connect(channel.id)

    @commands.command()
    async def play(self, ctx, *, query: str):
        tracks = await self.bot.wavelink.get_tracks(f'ytsearch:{query}')

        if not tracks:
            return await ctx.send('Could not find any songs with that query.')

        player = self.bot.wavelink.get_player(ctx.guild.id)
        if not player.is_connected:
            await ctx.invoke(self.connect_)

        await ctx.send(f'Added {str(tracks[0])} to the queue.')
        await player.play(tracks[0])


bot = Bot()
bot.run('TOKEN')
Comments
  • TypeError: 'coroutine' object is not callable

    TypeError: 'coroutine' object is not callable

    I'm getting this error when I try and play music on using my discord bot.

    Task exception was never retrieved future: <Task finished name='Task-32' coro=<Websocket.process_data() done, defined at C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\websocket.py:137> exception=TypeError("'coroutine' object is not callable")> Traceback (most recent call last): File "C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\websocket.py", line 156, in process_data event, payload = await self._get_event_payload(data['type'], data) File "C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\websocket.py", line 184, in get_event_payload track = await self.node.build_track(cls=wavelink.Track, identifier=base64) File "C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\pool.py", line 294, in build_track return cls(identifier, data) TypeError: 'coroutine' object is not callable Task exception was never retrieved future: <Task finished name='Task-39' coro=<Websocket.process_data() done, defined at C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\websocket.py:137> exception=TypeError("'coroutine' object is not callable")> Traceback (most recent call last): File "C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\websocket.py", line 156, in process_data event, payload = await self._get_event_payload(data['type'], data) File "C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\websocket.py", line 184, in get_event_payload track = await self.node.build_track(cls=wavelink.Track, identifier=base64) File "C:\Users\icep2\AppData\Local\Programs\Python\Python39\lib\site-packages\wavelink\pool.py", line 294, in build_track return cls(identifier, data) TypeError: 'coroutine' object is not callable

    Not a Bug 
    opened by Kaz213 15
  • Player.is_playing always returns False after track replace

    Player.is_playing always returns False after track replace

    Was broken in this commit: https://github.com/PythonistaGuild/Wavelink/commit/f126755662cdf17199b7814dbe4abcb5f038966b After first track has been replaced with Player.play(track), track_end event triggered after Player.play done. So, after first track replaced, Player._source is always None and Player.is_playing() always returns False.

    Consider changing code from commit above to something like this:

    if event == 'track_end' and payload.get('reason') == 'FINISHED':
        player._source = None
    
    opened by wladbelsky 7
  • Add support for

    Add support for "Session resuming" & "session data queueing".

    This PR is Implemented in #66

    Added New attributes

    • resume_session: bool
    • resume_timeout: float
    • resume_key: str (Best left None)
    • payload_timeout: float This is basically how recent requests shall be sent to the server
    • Websocket.reset() method.

    What are the new features?

    Websocket queueing.

    • Websocket._send() method now queues any data that is requested to be sent while the WS is disconnected.
    • New method Websocket.send_queue() which is called when connecting, and sends queue only when a session is resumed and Websocket is connected.
    • New exception NodeSessionClosedError raised when node closes a session or doesn't resume the old session. Handled within _connect method.

    Resuming

    • example of use of new features
    import string
    import secret
    class key:
        def __init__(self, len, first_key="NoSnoopingOnMyLava"):
            self.len = len
            self.persistent = first_key
    
        def __str__(self):
            return self.persistent
    
        def __repr__(self):
            """This should generate a key and shall make it persistent """
            self.persistent = SomeSecurePasswordGenerator(self.len)
            return self.persistent
    
    ---------------
    
     async def start_nodes(self) -> None:
        """Connect and intiate nodes."""
        nodes = {'MAIN': {'host': 'lavaserver.badhost.com',
                          'port': 80,
                          'rest_uri': 'http://lavaserver.badhost.com',
                          'password': "verytrivialpassword",
                          'identifier': 'MAIN',
                          'region': 'us_central',
                          'heartbeat': 40.0, # ping the server every 40s
                          'resume_session': True,
                          'resume_timeout': 90.0,
                          'resume_key': key(10) # or "Astring"
                          'payload_timeout': 40.0
                          }}
    
        for n in nodes.values():
            await self.bot.wavelink.initiate_node(**n)
    
    • or simply by setting 'resume_session': True
     async def start_nodes(self) -> None:
        """Connect and intiate nodes."""
        nodes = {'MAIN': {'host': 'lavaserver.badhost.com',
                          'port': 80,
                          'rest_uri': 'http://lavaserver.badhost.com',
                          'password': "verytrivialpassword",
                          'identifier': 'MAIN',
                          'region': 'us_central',
                          'resume_session': True
                          }}
    
        for n in nodes.values():
            await self.bot.wavelink.initiate_node(**n)
    

    Though the former has more use cases by using a Key Object we can:

    • Make the key persistent across Clusters
    • log the events, since __str__ is called when configuring the server, while __repr__ is called when the Node's session is closed to generate a new key.
    • To Generate a more secure password
    • Increase length of the password (The default is 32 characters)
    • Use

    How does resuming work?

    When the bot disconnects from the node (eg: 1006) then the lavalink server keeps on playing the music until session timeout, this allows the bot to reconnect and take control of the session. This PR implements this lavalink feature. The changes are not breaking, assuming no-one initializes Node instances directly.

    How does Queueing work?

    After the Node disconnects, we try to reconnect twice before timeout. during this time the requests to the node are queued in an asyncio.Queue subclass whose payload expires after some time. This could be useful when you have an higher timeout but want to only send recent requests

    opened by WizzyGeek 7
  • Add /decodetracks endpoint support

    Add /decodetracks endpoint support

    In addition to the Client/Node.build_track method, this adds the corresponding POST to /decodetracks to batch decode track identifiers. Useful if there are a large number of tracks that need to be decoded.

    The definition of the endpoint can be found here: https://github.com/Frederikam/Lavalink/blob/18ee6778674b7f9a817893b676a91a9b96e642f3/LavalinkServer/src/main/java/lavalink/server/player/AudioLoaderRestHandler.java#L140

    opened by james7132 6
  • AttributeError: '_MissingSentinel' object has no attribute 'guild'

    AttributeError: '_MissingSentinel' object has no attribute 'guild'

    Hi I am trying to make a setvolume command but I keep getting this error: AttributeError: '_MissingSentinel' object has no attribute 'guild'

    Code:

    @bot.command()
    async def setVolume(ctx, *, volume: float):
        vc = ctx.voice_client
        custom_player = CustomPlayer()
    
        if not vc:
            await ctx.send("I ain't in a vc bro")
        else:
            await custom_player.set_volume(volume=volume)
    opened by Necrosis000 5
  • Is there a better way to play a local file?

    Is there a better way to play a local file?

    I've finally got playing a local file (to lavalink) from the bot. (No more ffmpeg)

    I'm Just throwing this out here as a general question:

    is there a better way to search for a Local Track? I see SearchableTrack, having a return_first=true. Just trying to get my head around the API. Any help is apperciated?

    @slash_command(name="lplay", description="Play some local music or SFX") async def lplay(self, inter: Interaction, search): path = "/media/" + search
        search = wavelink.PartialTrack(query=path, cls=wavelink.LocalTrack)
    
        if inter.user.voice is None:
            return await inter.send(f'You are not connected to any voice channel!')
    
        # If the bot isn't in a voice channel
        if not inter.guild.voice_client:
            vc: wavelink.Player = await inter.user.voice.channel.connect(cls=wavelink.Player)
        else:
          #See if the bot is in another channel
          if inter.guild.voice_client.channel != inter.user.voice.channel:
            await inter.guild.voice_client.move_to(inter.user.voice.channel) 
            await inter.send(f'Connected to {inter.user.voice.channel}.')
            
        vc: wavelink.Player = inter.guild.voice_client
       
        try: 
           await vc.play(search)
           await inter.send(f'Playing {search.title}')
        except:
           await inter.send(f'{path} Not found!') 
    
    opened by Mudpuppy12 4
  • queue error please help

    queue error please help

    @bot.event async def on_wavelink_track_end(player: wavelink.Player, track: wavelink.Track, reason): ctx = player.ctx vc: player = ctx.voice_client if vc.loop: return await vc.play(track) next_song = vc.queue.get() await vc.play(next_song) await ctx.send(f"Now playing {next_song.title}")

    • File "/home/container/discord-bot/main.py", line 118, in on_wavelink_track_end next_song = vc.queue.get() File "/home/container/.local/lib/python3.10/site-packages/wavelink/queue.py", line 212, in get raise QueueEmpty("No items in the queue.") wavelink.errors.QueueEmpty: No items in the queue.
    opened by slefgameRz 4
  • wavelink.Player.connect incompatibility with Discord.py 2.0

    wavelink.Player.connect incompatibility with Discord.py 2.0

    Discord.py 2.0 introduced a new self_deaf and self_mute parameter to the connect method. This causes TypeError: Player.connect() got an unexpected keyword argument 'self_deaf'

    opened by Luc1412 4
  • module 'wavelink' has no attribute 'client'

    module 'wavelink' has no attribute 'client'

    Traceback (most recent call last): File "/Users/admin/Desktop/Cogs/music1.py", line 272, in bot = Bot() File "/Users/admin/Desktop/Cogs/music1.py", line 22, in init self.add_cog(Music(self)) File "/Users/admin/Desktop/Cogs/music1.py", line 69, in init self.bot.wavelink = wavelink.Client(bot=self.bot) AttributeError: module 'wavelink' has no attribute 'Client'

    opened by sanjaysanooj22 4
  • v1.2.0 No Longer Supports Python Version 3.8

    v1.2.0 No Longer Supports Python Version 3.8

    In the newest version (v1.2.0), the implementation of the YouTube Playlist searching has removed support for Python Version 3.8. The use of the method .removeprefix() is a python 3.9+ feature.

    The line in question: https://github.com/PythonistaGuild/Wavelink/blob/8a4fb12404a5e908bd7a22ecba1ace7dc950d73f/wavelink/tracks.py#L187

    PEP 616: String methods to remove prefixes and suffixes https://www.python.org/dev/peps/pep-0616/

    If this is intentional to remove Python 3.8 version, then please can the documentation be updated. Otherwise, an implementation to get around this could be:

    def removePrefix(url, prefix):
        if string.startswith(prefix):
            return string[len(prefix):]
        else:
            return string
    
    opened by TwoSails 4
  • [Suggestion] Advanced exmple

    [Suggestion] Advanced exmple

    Hello, Wavelink is working good but in my opinion there a a few missing things:

    • loop song & queue
    • lyrics command
    • pitch (1.00 standard 5.00 max)
    • option to keep the bot into the voicechannel even if nothing is playing.
    opened by FeelsBadMan1 4
  • Add payload_args optional argument to the play method in player.py

    Add payload_args optional argument to the play method in player.py

    This argument allows the user to pass arguments which will be directly sent to Lavalink in the play method. This gives the ability to interact with Lavalink plugins

    opened by Rajdave69 0
  • getting this error on 2.0

    getting this error on 2.0

    File "/home/subrata/Wavelink/wavelink/node.py", line 106, in <genexpr>
        version_tuple = tuple(int(v) for v in version.split('.'))
    ValueError: invalid literal for int() with base 10: 'c597fb10d9d323a174b69efa66fcebd616fb3f1e-SNAPSHOT_Unofficial'
    
    bug 2.0 
    opened by Subrata2402 0
  • Update pool.py

    Update pool.py

    Fixed bug with 'wavelink.NodePool.get_node(region="rotterdam")' raise ZeroConnectedNodes(f "No Nodes for region <{region}> exist on this pool."), although there is at least one node with this region.

    opened by Marco12223 1
  • Player running endless (without sound)

    Player running endless (without sound)

    I currently play an MP3 on the lavalink server in a loop. The loop has been accomplished by following code.

    @commands.Cog.listener(name="on_wavelink_track_end")
        async def _on_track_end(self, player: RadioPlayer, track: wavelink.Track, reason: str):
            if reason != 'FINISHED':
                return
            await player.play(track)
    

    This transition works fine so far. I also added on_wavelink_track_exception and on_wavelink_track_stuck for debug reasons, but both won't get triggered.

    I experience that the player randomly stops playing. The client is still connected. The player got is_connected() and is_playing() set to True. But when checking the position it got an inappropriate high number set.

    My track is about an hour long, but postion is set to 21h in seconds.

    Pausing and resuming resumes the playback.

    opened by Luc1412 0
  • cant search for youtube playlist

    cant search for youtube playlist

    I try to use wavelink.YouTubePlaylist to search for youtubeplaylist and I get error

    code @commands.command(aliases=['P', 'PLAY', 'Play','p']) async def play(self,ctx: commands.Context, *, search:wavelink.YouTubePlaylist): print(search)

    error Ignoring exception in on_message Traceback (most recent call last): File "C:\Python3.10\lib\site-packages\discord\ext\commands\core.py", line 456, in _actual_conversion ret = await method(ctx, argument) File "C:\Python3.10\lib\site-packages\wavelink\tracks.py", line 218, in convert return results[0] TypeError: 'YouTubePlaylist' object is not subscriptable

    Did i miss something?

    and also sorry for my bad English

    opened by tunwit 2
Releases(v1.3.4)
  • v1.3.4(Dec 22, 2022)

  • v1.3.3(Oct 4, 2022)

  • v1.3.2(Jul 10, 2022)

  • v1.3.1(Jun 6, 2022)

  • v1.3.0(Jun 6, 2022)

    Implemented Lavalink Filters, some documentation can be found here: https://wavelink.readthedocs.io/en/latest/wavelink.html#filters This is still a WIP.

    Fixed an issue with YouTubePlaylist converter failing. Bumped aiohttp inline with discord.py

    Source code(tar.gz)
    Source code(zip)
  • v1.2.5(Apr 22, 2022)

  • v1.2.4(Mar 21, 2022)

  • v1.2.3(Mar 21, 2022)

  • v1.2.2(Mar 13, 2022)

  • v1.2.1(Mar 10, 2022)

  • v1.2.0(Mar 7, 2022)

  • v1.1.1(Feb 8, 2022)

  • v1.1.0(Feb 4, 2022)

  • v1.0.2(Jan 24, 2022)

  • v1.0.1(Jan 24, 2022)

  • v1.0.0(Jan 24, 2022)

    Wavelink 1.0.0

    This release is a whole rewrite of the library. It supports discord.py 2.0 and some derivatives.

    See the documentaion for more info and examples. Documentation

    If the documentation is still displaying as the old version, please clear your cache.

    Source code(tar.gz)
    Source code(zip)
  • v0.9.10(Jul 13, 2021)

  • v0.9.9(Mar 8, 2021)

  • v0.9.8(Feb 25, 2021)

    Add force keyword argument to Node.destroy() and Player.destroy()/disconnect(). This prevents a bug from occuring when a player is being destroyed, and the bot is no longer apart of the Guild the player was associated with.

    Source code(tar.gz)
    Source code(zip)
  • v0.9.7(Feb 23, 2021)

  • v0.9.6(Sep 9, 2020)

    Fix a bug in player setting current track to None on TrackStuck and TrackException.

    Since Lavalink sends two events on Exceptions, an End and Exception event this causes a possible race condition in the player, setting the current Track to None when one is actually playing.

    Source code(tar.gz)
    Source code(zip)
  • v0.9.5(Sep 5, 2020)

    Added Exponential Backoff attempts to get_tracks. Retrieving tracks will now by default retry on failure up to a maximum of 5 attempts with an Exponential Backoff. You can set this to False with the kwarg retry_on_failure=False, which will only attempt to retrieve tracks once.

    Added support for custom JSON Encoders.

    Changed YouTube's Track Image to hqdefault, in place of maxresdefault.

    Source code(tar.gz)
    Source code(zip)
  • v0.9.4(Aug 5, 2020)

    Changes to Equalizer which allow for construction without the build() classmethod.

    Added name parameters to the build() classmethod and Equalizer constructor to allow setting a custom name.

    Added a name property to Equalizer. Setting the name should be done by constrcutor or the build() classmethod

    Added __str__ and __repr__ to Equalizer.

    Fixed a bug where set_eq was setting a blank Equalizer class on the player.

    Source code(tar.gz)
    Source code(zip)
  • v0.9.3(Jul 30, 2020)

  • v0.9.2(Jun 20, 2020)

    Add heartbeat to node and websocket.

    This stabilizes connection to Nodes hosted on a VPS with a router or any such intermediate process that closes the connection if it remains idle. Which puts the bot in a "reconnection" loop.

    Source code(tar.gz)
    Source code(zip)
  • v0.9.1(Jun 20, 2020)

  • v0.9.0(Jun 8, 2020)

    Added wavelink.WavelinkMixin to be used in conjunction with a discord.py commands.Cog. This class allows for the registration of the new wavelink listeners:

    on_node_ready on_track_start on_track_end on_track_stuck on_track_exception on_websocket_closed

    All listeners must be decorated with the wavelink.WavelinkMixin.listener() decorator. All listeners must be in a wavelink.WavelinkMixin class. Listeners can be stacked.

    Docs

    Event Payloads WavelinkMixin

    Example

    class Music(commands.Cog, wavelink.WavelinkMixin):
        
        @wavelink.WavelinkMixin.listener()
        async def on_node_ready(self, node):
            print(f'Node {node.identifier} is ready!')
    
    Source code(tar.gz)
    Source code(zip)
  • v0.8.0(May 18, 2020)

  • v0.7.2(May 16, 2020)

  • v0.7.1(May 2, 2020)

Owner
Pythonista
Organisation for the Pythonista Guild
Pythonista
An API wrapper for Discord written in Python.

HCord A fork of discord.py project. HCord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord written in Python. Key Featu

HCord 0 Jul 30, 2022
Fully automated Chegg Discord bot for "homework help"

cheggbog Fully automated Chegg Discord bot for "homework help". Working Sept 15, 2021 Overview Recently, Chegg has made it extremely difficult to auto

Bryce Hackel 8 Dec 23, 2022
Mark Sullivan 66 Dec 13, 2022
A Telegram robot can clone medias from any chat to your own chat.

Clonebot A Telegram robot can clone medias from any chat to your own chat. Read the documentation to know how to use the bot Deploy Developer Document

Renjith Mangal 224 Dec 30, 2022
Python wrapper for Gmailnator

Python wrapper for Gmailnator

h0nda 11 Mar 19, 2022
Hassium Server Manager For Python

Hassium Server Manager This is meant to be a tool for mostly internal use. I decided that I would make it open souce in case anyone wanted to use it.

0 Nov 24, 2022
Nyon-stream - A python script that uses webtorrent to stream nyaa videos directly to mpv

nyon-stream A rather shitty script that uses webtorrent to stream nyaa videos di

18 Feb 08, 2022
A tool that ensures consistent string quotes in your Python code.

pyquotes Single quotes are superior. And if you disagree, there's an option for this as well. In any case, quotes should be consistent throughout the

Adrian 9 Sep 13, 2022
An Anime Themed Fast And Safe Group Managing Bot.

Ξ L I N Λ 👸 A Powerful, Smart And Simple Group Manager bot Avaiilable a latest version as Ξ L I N Λ 👸 on Telegram Self-hosting (For Devs) vps # Inst

7 Nov 12, 2022
Python client for the iNaturalist APIs

pyinaturalist Introduction iNaturalist is a community science platform that helps people get involved in the natural world by observing and identifyin

Nicolas Noé 79 Dec 22, 2022
A bot that connects your guild chat to a Discord channel, written in Python.

Guild Chat Bot A bot that connects your guild chat to a discord channel. Uses discord.py and pyCraft Deploy on Railway Railway is a cloud development

Evernote 10 Sep 25, 2022
A Python Instagram Scraper for Downloading Profile's Posts, stories, ProfilePic and See the Details of Particular Instagram Profile.

✔ ✔ InstAstra ⚡ ⚡ ⁜ Description ~ A Python Instagram Scraper for Downloading Profile's Posts, stories, ProfilePic and See the Details of Particular In

12 Jun 23, 2022
This is a okay that is okay that means none is okay

Owner: Masterolic 🇮🇳 CatUB A Powerful, Smart And Simple Userbot In Telethon. Credits This is A Remix Bot Of Many UserBot. DARKCOBRA FridayUserBot Ja

Masterolic 1 Nov 28, 2021
Manage Proxmox KVM Virtual Machines via Slack bot.

proxmox-slack-bot Create KVM Virtual Machines on Proxmox, the easy way. Not much works works here yet... Setup dev environment Setup fully editable st

Plenus Pyramis 3 Mar 20, 2022
Spodcast is a caching Spotify podcast to RSS proxy

Spodcast Spodcast is a caching Spotify podcast to RSS proxy. Using Spodcast you can follow Spotify-hosted netcasts/podcasts using any player which sup

Frank de Lange 260 Jan 01, 2023
inventory replenishment for a hospital.

Inventory-Replenishment Inventory-Replenishment for a hospital that would like to explore how advanced anlytics may help automate their decision proce

1 Jan 09, 2022
AWS Quick Start Team

EKS CDK Quick Start (in Python) DEVELOPER PREVIEW NOTE: Thise project is currently available as a preview and should not be considered for production

AWS Quick Start 83 Sep 18, 2022
A simple Python API wrapper for Cloudflare Stream's API.

python-cloudflare-stream A basic Python API wrapper for working with Cloudflare Stream. Arbington.com started off using Cloudflare Stream. We used the

Arbington 3 Sep 08, 2022
Just a simple discord bot a create for try

WAIFU MATERIAL DISCORD BOT! French ver. here HOW TO LAUNCH First, clone this rep

1 Jan 08, 2022
This Discord bot is to give timely notifications to Students in the Lakehead CS 2021 Guild

Discord-Bot Goal of Project The purpose of this Discord bot is to give timely notifications to Students in the Lakehead CS 2021 Guild. How can I contr

8 Jan 30, 2022