<commit_before>"""
Dogbot owner only music extension.
"""

import asyncio
import logging
import random

import discord
import youtube_dl
from discord.ext import commands

from dog import Cog
from dog.core import utils, checks

logger = logging.getLogger(__name__)

YTDL_OPTS = {
    'format': 'webm[abr>0]/bestaudio/best',
    'prefer_ffmpeg': True
}

SEARCHING_TEXT = (
    'Beep boop...',
    'Travelling the interwebs...',
    'Hold up...',
    'Searching...',
    'Just a sec...'
)


class YouTubeDLSource(discord.FFmpegPCMAudio):
    def __init__(self, url):
        ytdl = youtube_dl.YoutubeDL(YTDL_OPTS)
        info = ytdl.extract_info(url, download=False)

        if '_type' in info and info['_type'] == 'playlist':
            info = info['entries'][0]

        self.url = url
        self.info = info

        super().__init__(info['url'])


async def youtube_search(bot, query: str) -> 'List[Dict[Any, Any]]':
    """
    Searches YouTube for videos. Returns a list of :class:`YouTubeResult`.
    """
    def search():
        ytdl = youtube_dl.YouTubeDL(YTDL_OPTS)
        info = ytdl.extract_info('ytsearch:' + query, download=False)
        return info
    return await bot.loop.run_in_executor(None, search)


async def must_be_in_voice(ctx: commands.Context):
    return ctx.guild.voice_client is not None


async def cannot_be_playing(ctx: commands.Context):
    return not ctx.guild.voice_client.is_playing()


async def is_whitelisted(bot, guild: discord.Guild):
    async with bot.pgpool.acquire() as conn:
        record = await conn.fetchrow('SELECT * FROM music_guilds WHERE guild_id = $1', guild.id)
        return record is not None


async def can_use_music(ctx: commands.Context):
    return await ctx.bot.is_owner(ctx.author) or (False if not ctx.guild else await is_whitelisted(ctx.bot, ctx.guild))


def required_votes(number_of_people: int) -> int:
    return max(round(number_of_people / 2.5), 1)


class Music(Cog):
    def __init__(self, bot):
        super().__init__(bot)

        self.queues = {}
        self.skip_votes = {}

    @commands.group(aliases=['m', 'mus'])
    async def music(self, ctx):
        """ Music. Beep boop! """
        pass

    @music.command()
    @commands.is_owner()
    async def status(self, ctx):
        """ Views the status of Opus. """
        await ctx.send(f'Opus status: {discord.opus.is_loaded()}')

    @music.command(aliases=['summon'])
    async def join(self, ctx):
        """ Summons the bot to your voice channel. """
        msg = await ctx.send('\N{RUNNER} Connecting to voice...')
        if ctx.guild.voice_client is not None and ctx.guild.voice_client.is_connected():
            return await msg.edit(content='\N{CONFUSED FACE} I\'m already connected!')
        if ctx.author.voice is None:
            return await msg.edit(content='\N{CONFUSED FACE} I can\'t join you if you aren\'t in a voice channel!')
        await ctx.author.voice.channel.connect()
        await msg.edit(content='\N{OK HAND SIGN} Connected!')

    @music.command()
    @commands.check(must_be_in_voice)
    async def skip(self, ctx):
        """
        Votes to skip this song.

        40% of users in the voice channel must skip in order for the song to be skipped.
        If someone leaves the voice channel, just rerun this command to recalculate the amount
        of votes needed.

        If you are a Dogbot Moderator, the song is skipped instantly.
        """

        if not ctx.guild.voice_client.is_playing():
            return await ctx.send('I\'m not playing anything at the moment.')

        async def insta_skip():
            # clear voteskips
            self.skip_votes[ctx.guild.id] = []

            # get the next song, say it
            queue = self.queues.get(ctx.guild.id, [])
            if queue:
                await ctx.send('Skipping...! I\'ll play **{0.info[title]}** next.'.format(queue[0].original))
            else:
                await ctx.send('Skipping!')

            # stop!!!
            ctx.guild.voice_client.stop()

        if checks.is_dogbot_moderator(ctx):
            logger.debug('Instantly skipping.')
            await insta_skip()
        else:
            existing_votes = self.skip_votes.get(ctx.guild.id, [])  # votes we already have
            voice_members = len(ctx.guild.voice_client.channel.members)  # how many people in the channel?
            votes_with_this_one = len(existing_votes) + 1  # votes with this one counted
            required = required_votes(voice_members)  # how many votes do we need?

            # recalculate amount of users it takes to vote
            if len(existing_votes) >= required:
                logger.debug('Voteskip: Recalculated. Skipping. %d/%d', len(existing_votes), required)
                return await insta_skip()

            # check if they already voted
            if ctx.author.id in existing_votes:
                return await ctx.send('You already voted to skip. **{}** more vote(s) needed to skip.'.format(required -
                                      len(existing_votes)))

            # ok, their vote counts. now check if we surpass required votes with their votes too!
            if votes_with_this_one >= required:
                logger.debug('Voteskip: Fresh vote! Skipping. %d/%d', votes_with_this_one, required)
                return await insta_skip()<commit_msg>[Music] Improve comments<commit_after>"""
Dogbot owner only music extension.
"""

import asyncio
import logging
import random

import discord
import youtube_dl
from discord.ext import commands

from dog import Cog
from dog.core import utils, checks

logger = logging.getLogger(__name__)

YTDL_OPTS = {
    'format': 'webm[abr>0]/bestaudio/best',
    'prefer_ffmpeg': True
}

SEARCHING_TEXT = (
    'Beep boop...',
    'Travelling the interwebs...',
    'Hold up...',
    'Searching...',
    'Just a sec...'
)


class YouTubeDLSource(discord.FFmpegPCMAudio):
    def __init__(self, url):
        ytdl = youtube_dl.YoutubeDL(YTDL_OPTS)
        info = ytdl.extract_info(url, download=False)

        if '_type' in info and info['_type'] == 'playlist':
            info = info['entries'][0]

        self.url = url
        self.info = info

        super().__init__(info['url'])


async def youtube_search(bot, query: str) -> 'List[Dict[Any, Any]]':
    """
    Searches YouTube for videos. Returns a list of :class:`YouTubeResult`.
    """
    def search():
        ytdl = youtube_dl.YouTubeDL(YTDL_OPTS)
        info = ytdl.extract_info('ytsearch:' + query, download=False)
        return info
    return await bot.loop.run_in_executor(None, search)


async def must_be_in_voice(ctx: commands.Context):
    return ctx.guild.voice_client is not None


async def cannot_be_playing(ctx: commands.Context):
    return not ctx.guild.voice_client.is_playing()


async def is_whitelisted(bot, guild: discord.Guild):
    async with bot.pgpool.acquire() as conn:
        record = await conn.fetchrow('SELECT * FROM music_guilds WHERE guild_id = $1', guild.id)
        return record is not None


async def can_use_music(ctx: commands.Context):
    return await ctx.bot.is_owner(ctx.author) or (False if not ctx.guild else await is_whitelisted(ctx.bot, ctx.guild))


def required_votes(number_of_people: int) -> int:
    return max(round(number_of_people / 2.5), 1)


class Music(Cog):
    def __init__(self, bot):
        super().__init__(bot)

        self.queues = {}
        self.skip_votes = {}

    @commands.group(aliases=['m', 'mus'])
    async def music(self, ctx):
        """ Music. Beep boop! """
        pass

    @music.command()
    @commands.is_owner()
    async def status(self, ctx):
        """ Views the status of Opus. """
        await ctx.send(f'Opus status: {discord.opus.is_loaded()}')

    @music.command(aliases=['summon'])
    async def join(self, ctx):
        """ Summons the bot to your voice channel. """
        msg = await ctx.send('\N{RUNNER} Connecting to voice...')
        if ctx.guild.voice_client is not None and ctx.guild.voice_client.is_connected():
            return await msg.edit(content='\N{CONFUSED FACE} I\'m already connected!')
        if ctx.author.voice is None:
            return await msg.edit(content='\N{CONFUSED FACE} I can\'t join you if you aren\'t in a voice channel!')
        await ctx.author.voice.channel.connect()
        await msg.edit(content='\N{OK HAND SIGN} Connected!')

    @music.command()
    @commands.check(must_be_in_voice)
    async def skip(self, ctx):
        """
        Votes to skip this song.

        40% of users in the voice channel must skip in order for the song to be skipped.
        If someone leaves the voice channel, just rerun this command to recalculate the amount
        of votes needed.

        If you are a Dogbot Moderator, the song is skipped instantly.
        """

        if not ctx.guild.voice_client.is_playing():
            return await ctx.send('I\'m not playing anything at the moment.')

        async def insta_skip():
            # clear voteskips
            self.skip_votes[ctx.guild.id] = []

            # get the next song, say it
            queue = self.queues.get(ctx.guild.id, [])
            if queue:
                await ctx.send('Skipping...! I\'ll play **{0.info[title]}** next.'.format(queue[0].original))
            else:
                await ctx.send('Skipping!')

            # stop!!!
            ctx.guild.voice_client.stop()

        if checks.is_dogbot_moderator(ctx):
            logger.debug('Instantly skipping.')
            await insta_skip()
        else:
            existing_votes = self.skip_votes.get(ctx.guild.id, [])  # votes we already have
            voice_members = len(ctx.guild.voice_client.channel.members)  # how many people in the channel?
            votes_with_this_one = len(existing_votes) + 1  # votes with this one counted
            required = required_votes(voice_members)  # how many votes do we need?

            # recalculate amount of users it takes to vote, not counting this vote.
            # (just in case someone left the channel)
            if len(existing_votes) >= required:
                logger.debug('Voteskip: Recalculated. Skipping. %d/%d', len(existing_votes), required)
                return await insta_skip()

            # check if they already voted
            if ctx.author.id in existing_votes:
                return await ctx.send('You already voted to skip. **{}** more vote(s) needed to skip.'.format(required -
                                      len(existing_votes)))

            # ok, their vote counts. now check if we surpass required votes with this vote!
            if votes_with_this_one >= required:
                logger.debug('Voteskip: Fresh vote! Skipping. %d/%d', votes_with_this_one, required)
                return await insta_skip()
{'fraction_non_alphanumeric': 0.11397670549084858, 'fraction_numerical': 0.0020336476243298205, 'mean_word_length': 2.459865685960985, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3168610', 'n_tokens_mistral': 3397, 'n_tokens_neox': 3268, 'n_words': 929}