Red-DiscordBot/cogs/audio.py
2016-02-24 18:14:09 +01:00

789 lines
33 KiB
Python

import discord
from discord.ext import commands
import asyncio
import threading
import youtube_dl
import os
from random import choice as rndchoice
from random import shuffle
from .utils.dataIO import fileIO
from .utils import checks
from __main__ import send_cmd_help
import glob
import re
import aiohttp
from bs4 import BeautifulSoup
import json
import time
if not discord.opus.is_loaded():
discord.opus.load_opus('libopus-0.dll')
youtube_dl_options = {
'format': 'bestaudio/best',
'extractaudio': True,
'audioformat': "mp3",
'outtmpl': '%(id)s',
'noplaylist': True,
'nocheckcertificate': True,
'ignoreerrors': True,
'quiet': True,
'no_warnings': True,
'outtmpl': "data/audio/cache/%(id)s"}
class Audio:
"""Music streaming."""
def __init__(self, bot):
self.bot = bot
self.music_player = EmptyPlayer()
self.settings = fileIO("data/audio/settings.json", "load")
self.queue_mode = False
self.queue = []
self.playlist = []
self.current = -1 #current track index in self.playlist
self.downloader = {"DONE" : False, "TITLE" : False, "ID" : False, "URL" : False, "DURATION" : False, "DOWNLOADING" : False}
self.skip_votes = []
self.cleanup_timer = int(time.perf_counter())
self.past_titles = [] # This is to prevent the audio module from setting the status to None if a status other than a track's title gets set
self.sing = ["https://www.youtube.com/watch?v=zGTkAVsrfg8", "https://www.youtube.com/watch?v=cGMWL8cOeAU",
"https://www.youtube.com/watch?v=vFrjMq4aL-g", "https://www.youtube.com/watch?v=WROI5WYBU_A",
"https://www.youtube.com/watch?v=41tIUr_ex3g", "https://www.youtube.com/watch?v=f9O2Rjn1azc"]
@commands.command(pass_context=True, no_pm=True)
async def play(self, ctx, link : str):
"""Plays link
"""
if self.downloader["DOWNLOADING"]:
await self.bot.say("I'm already downloading a track.")
return
msg = ctx.message
if await self.check_voice(msg.author, msg):
if self.is_playlist_valid([link]): # reusing a function
if await self.is_alone_or_admin(msg.author):
self.queue = []
self.current = -1
self.playlist = []
self.queue.append(link)
self.music_player.paused = False
self.music_player.stop()
else:
self.playlist = []
self.current = -1
if not self.queue: await self.bot.say("The link has been put into queue.")
self.queue.append(link)
else:
await self.bot.say("That link is not allowed.")
@commands.command(aliases=["title"])
async def song(self):
"""Shows song title
"""
if self.downloader["TITLE"] and "localtracks" not in self.downloader["TITLE"]:
url = ""
if self.downloader["URL"]: url = 'Link : "' + self.downloader["URL"] + '"'
await self.bot.say(self.downloader["TITLE"] + "\n" + url)
else:
await self.bot.say("No title available.")
@commands.command(name="playlist", pass_context=True, no_pm=True)
async def _playlist(self, ctx, name : str): #some checks here
"""Plays saved playlist
"""
await self.start_playlist(ctx, name, random=False)
@commands.command(pass_context=True, no_pm=True)
async def mix(self, ctx, name : str): #some checks here
"""Plays saved playlist (shuffled)
"""
await self.start_playlist(ctx, name, random=True)
async def start_playlist(self, ctx, name, random=None):
if self.downloader["DOWNLOADING"]:
await self.bot.say("I'm already downloading a track.")
return
msg = ctx.message
name += ".txt"
if await self.check_voice(msg.author, msg):
if os.path.isfile("data/audio/playlists/" + name):
self.queue = []
self.current = -1
self.playlist = fileIO("data/audio/playlists/" + name, "load")["playlist"]
if random: shuffle(self.playlist)
self.music_player.paused = False
self.music_player.stop()
@commands.command(pass_context=True, aliases=["next"], no_pm=True)
async def skip(self, ctx):
"""Skips song
"""
msg = ctx.message
if self.music_player.is_playing():
if await self.is_alone_or_admin(msg.author):
self.music_player.paused = False
self.music_player.stop()
else:
await self.vote_skip(msg)
async def vote_skip(self, msg):
v_channel = msg.server.me.voice_channel
if msg.author.voice_channel.id == v_channel.id:
if msg.author.id in self.skip_votes:
await self.bot.say("You already voted.")
return
self.skip_votes.append(msg.author.id)
if msg.server.me.id not in self.skip_votes: self.skip_votes.append(msg.server.me.id)
current_users = []
for m in v_channel.voice_members:
current_users.append(m.id)
clean_skip_votes = [] #Removes votes of people no longer in the channel
for m_id in self.skip_votes:
if m_id in current_users:
clean_skip_votes.append(m_id)
self.skip_votes = clean_skip_votes
votes_needed = int((len(current_users)-1) / 2)
if len(self.skip_votes)-1 >= votes_needed:
self.music_player.paused = False
self.music_player.stop()
self.skip_votes = []
return
await self.bot.say("You voted to skip. Votes: [{0}/{1}]".format(str(len(self.skip_votes)-1), str(votes_needed)))
@commands.command(pass_context=True, no_pm=True)
async def local(self, ctx, name : str):
"""Plays a local playlist"""
if self.downloader["DOWNLOADING"]:
await self.bot.say("I'm already downloading a track.")
return
msg = ctx.message
localplaylists = self.get_local_playlists()
if localplaylists and ("data/audio/localtracks/" not in name and "\\" not in name):
if name in localplaylists:
files = []
if glob.glob("data/audio/localtracks/" + name + "/*.mp3"):
files.extend(glob.glob("data/audio/localtracks/" + name + "/*.mp3"))
if glob.glob("data/audio/localtracks/" + name + "/*.flac"):
files.extend(glob.glob("data/audio/localtracks/" + name + "/*.flac"))
if await self.is_alone_or_admin(msg.author):
if await self.check_voice(msg.author, ctx.message):
self.queue = []
self.current = -1
self.playlist = files
self.music_player.paused = False
self.music_player.stop()
else:
await self.bot.say("I'm in queue mode. Controls are disabled if you're in a room with multiple people.")
else:
await self.bot.say("There is no local playlist with that name.")
else:
await self.bot.say(message.channel, "There are no valid playlists in the localtracks folder.")
@commands.command(pass_context=True, no_pm=True)
async def loop(self, ctx):
"""Loops single song
"""
msg = ctx.message
if self.music_player.is_playing():
if await self.is_alone_or_admin(msg.author):
self.current = -1
self.playlist = [self.downloader["URL"]]
await self.bot.say("I will play this song on repeat.")
else:
await self.bot.say("I'm in queue mode. Controls are disabled if you're in a room with multiple people.")
@commands.command(pass_context=True, no_pm=True)
async def shuffle(self, ctx):
"""Shuffle playlist
"""
msg = ctx.message
if self.music_player.is_playing():
if await self.is_alone_or_admin(msg.author):
if self.playlist:
shuffle(self.playlist)
await self.bot.say("The order of this playlist has been mixed")
else:
await self.bot.say("I'm in queue mode. Controls are disabled if you're in a room with multiple people.")
@commands.command(pass_context=True, aliases=["previous"], no_pm=True) #TODO, PLAYLISTS
async def prev(self, ctx):
"""Previous song
"""
msg = ctx.message
if self.music_player.is_playing() and self.playlist:
if await self.is_alone_or_admin(msg.author):
self.current -= 2
if self.current == -1:
self.current = len(self.playlist) -3
elif self.current == -2:
self.current = len(self.playlist) -2
self.music_player.paused = False
self.music_player.stop()
@commands.command(pass_context=True, no_pm=True)
async def stop(self, ctx):
"""Stops audio activity
"""
msg = ctx.message
if self.music_player.is_playing():
if await self.is_alone_or_admin(msg.author):
await self.close_audio()
else:
await self.bot.say("You can't stop music when there are other people in the channel! Vote to skip instead.")
else:
await self.close_audio()
async def close_audio(self):
self.queue = []
self.playlist = []
self.current = -1
self.music_player.stop()
await asyncio.sleep(1)
if self.bot.voice: await self.bot.voice.disconnect()
@commands.command(name="queue", pass_context=True, no_pm=True) #check that author is in the same channel as the bot
async def _queue(self, ctx, link : str=None):
"""Add link to queue
Shows queue list if no links are provided.
"""
if not link:
queue_list = await self.queue_titles()
await self.bot.say("Videos in queue: \n" + queue_list + "\n\nType queue <link> to add a link to the queue.")
elif await self.check_voice(ctx.message.author, ctx.message) and self.is_playlist_valid([link]):
if not self.playlist:
self.queue.append(link)
msg = ctx.message
result = await self.get_song_metadata(link)
try: # In case of invalid SOUNDCLOUD ID
if result["title"] != []:
await self.bot.say("{} has been put into the queue by {}.".format(result["title"], msg.author))
else:
await self.bot.say("The song has been put into the queue by {}, however it may error.".format(msg.author))
except:
await self.bot.say("A song has been put into the queue by {}.".format(msg.author))
else:
await self.bot.say("I'm already playing a playlist.")
else:
await self.bot.say("That link is now allowed.")
async def is_alone_or_admin(self, author): #Direct control. fix everything
if not self.settings["QUEUE_MODE"]:
return True
elif author.id == checks.settings["OWNER"]:
return True
elif discord.utils.get(author.roles, name=checks.settings["ADMIN_ROLE"]) is not None:
return True
elif discord.utils.get(author.roles, name=checks.settings["MOD_ROLE"]) is not None:
return True
elif len(author.voice_channel.voice_members) in (1, 2):
return True
else:
return False
@commands.command(name="sing", pass_context=True, no_pm=True)
async def _sing(self, ctx):
"""Makes Red sing"""
if self.downloader["DOWNLOADING"]:
await self.bot.say("I'm already downloading a track.")
return
msg = ctx.message
if await self.check_voice(msg.author, msg):
if not self.music_player.is_playing():
self.queue = []
await self.play_video(rndchoice(self.sing))
else:
if await self.is_alone_or_admin(msg.author):
self.queue = []
await self.play_video(rndchoice(self.sing))
else:
await self.bot.say("I'm already playing music for someone else at the moment.")
@commands.command()
async def pause(self):
"""Pauses the current song"""
if self.music_player.is_playing():
self.music_player.paused = True
self.music_player.pause()
await self.bot.say("Song paused.")
@commands.command()
async def resume(self):
"""Resumes paused song."""
if not self.music_player.is_playing():
self.music_player.paused = False
self.music_player.resume()
await self.bot.say("Resuming song.")
@commands.group(name="list", pass_context=True)
async def _list(self, ctx):
"""Lists playlists"""
if ctx.invoked_subcommand is None:
await send_cmd_help(ctx)
@_list.command(name="playlist", pass_context=True)
async def list_playlist(self, ctx):
msg = "Available playlists: \n\n```"
files = os.listdir("data/audio/playlists/")
if files:
for i, f in enumerate(files):
if f.endswith(".txt"):
if i % 4 == 0 and i != 0:
msg = msg + f.replace(".txt", "") + "\n"
else:
msg = msg + f.replace(".txt", "") + "\t"
msg += "```"
await self.bot.send_message(ctx.message.author, msg)
else:
await self.bot.say("There are no playlists.")
@_list.command(name="local", pass_context=True)
async def list_local(self, ctx):
msg = "Available local playlists: \n\n```"
dirs = self.get_local_playlists()
if dirs:
for i, d in enumerate(dirs):
if i % 4 == 0 and i != 0:
msg = msg + d + "\n"
else:
msg = msg + d + "\t"
msg += "```"
await self.bot.send_message(ctx.message.author, msg)
else:
await self.bot.say("There are no local playlists.")
@_list.command(name="queue", pass_context=True)
async def list_queue(self, ctx):
queue_list = await self.queue_titles()
await self.bot.say("Videos in queue: \n" + queue_list)
async def queue_titles(self):
song_names = []
song_names.append(self.downloader["TITLE"])
if len(self.queue) > 0:
for song_url in self.queue:
try:
result = await self.get_song_metadata(song_url)
if result["title"] != []:
song_names.append(result["title"])
else:
song_names.append("Could not get song title")
except:
song_names.append("Could not get song title")
song_list = "\n".join(["{}: {}".format(str(i+1), s) for i, s in enumerate(song_names)])
elif self.music_player.is_playing():
song_list = "1: {}".format(song_names[0])
else:
song_list = "None"
return song_list
@commands.group(pass_context=True)
@checks.mod_or_permissions()
async def audioset(self, ctx):
"""Changes audio module settings"""
if ctx.invoked_subcommand is None:
await send_cmd_help(ctx)
msg = "```"
for k, v in self.settings.items():
msg += str(k) + ": " + str(v) + "\n"
msg += "```"
await self.bot.say(msg)
@audioset.command(name="queue")
async def queueset(self):
"""Enables/disables forced queue"""
self.settings["QUEUE_MODE"] = not self.settings["QUEUE_MODE"]
if self.settings["QUEUE_MODE"]:
await self.bot.say("Queue mode is now on.")
else:
await self.bot.say("Queue mode is now off.")
fileIO("data/audio/settings.json", "save", self.settings)
@audioset.command(name="status")
async def songstatus(self):
"""Enables/disables songs' titles as status"""
self.settings["TITLE_STATUS"] = not self.settings["TITLE_STATUS"]
if self.settings["TITLE_STATUS"]:
await self.bot.say("Songs' titles will show up as status.")
else:
await self.bot.say("Songs' titles will no longer show up as status.")
fileIO("data/audio/settings.json", "save", self.settings)
@audioset.command()
async def maxlength(self, length : int):
"""Maximum track length (seconds) for requested links"""
self.settings["MAX_LENGTH"] = length
await self.bot.say("Maximum length is now " + str(length) + " seconds.")
fileIO("data/audio/settings.json", "save", self.settings)
@audioset.command()
async def volume(self, level : float):
"""Sets the volume (0-1)"""
if level >= 0 and level <= 1:
self.settings["VOLUME"] = level
await self.bot.say("Volume is now set at " + str(level) + ". It will take effect after the current track.")
fileIO("data/audio/settings.json", "save", self.settings)
else:
await self.bot.say("Volume must be between 0 and 1. Example: 0.40")
@audioset.command()
@checks.is_owner()
async def maxcache(self, size : int):
"""Sets the maximum audio cache size (megabytes)
If set to 0, auto cleanup is disabled."""
self.settings["MAX_CACHE"] = size
fileIO("data/audio/settings.json", "save", self.settings)
if not size:
await self.bot.say("Auto audio cache cleanup disabled.")
else:
await self.bot.say("Maximum audio cache size has been set to " + str(size) + "MB.")
@audioset.command()
@checks.is_owner()
async def soundcloud(self, ID : str=None):
"""Sets the SoundCloud Client ID
"""
self.settings["SOUNDCLOUD_CLIENT_ID"] = ID
fileIO("data/audio/settings.json", "save", self.settings)
if not ID:
await self.bot.say("SoundCloud API intergration has been disabled")
else:
await self.bot.say("SoundCloud Client ID has been set")
@commands.group(pass_context=True)
@checks.is_owner()
async def cache(self, ctx):
"""Audio cache management"""
if ctx.invoked_subcommand is None:
await self.bot.say("Current audio cache size: " + str(self.cache_size()) + "MB" )
@cache.command(name="empty")
async def cache_delete(self):
"""Empties audio cache"""
self.empty_cache()
await self.bot.say("Cache emptied.")
def empty_cache(self):
files = os.listdir("data/audio/cache")
for f in files:
try:
os.unlink("data/audio/cache/" + f)
except PermissionError: # In case it tries to delete the file that it's currently playing
pass
def cache_size(self):
total = [os.path.getsize("data/audio/cache/" + f) for f in os.listdir("data/audio/cache")]
size = 0
for f in total:
size += f
return int(size / (1024*1024.0))
async def play_video(self, link):
self.downloader = {"DONE" : False, "TITLE" : False, "ID" : False, "URL": False, "DURATION" : False, "DOWNLOADING" : False}
if "https://" in link or "http://" in link:
path = "data/audio/cache/"
t = threading.Thread(target=self.get_video, args=(link,self,))
t.start()
else: #local
path = ""
self.downloader = {"DONE" : True, "TITLE" : link, "ID" : link, "URL": False, "DURATION" : False, "DOWNLOADING" : False}
while not self.downloader["DONE"]:
await asyncio.sleep(1)
if self.downloader["ID"]:
try:
self.music_player.stop()
self.music_player = self.bot.voice.create_ffmpeg_player(path + self.downloader["ID"], options='''-filter:a "volume={}"'''.format(self.settings["VOLUME"]))
self.music_player.paused = False
self.music_player.start()
if path != "" and self.settings["TITLE_STATUS"]:
self.past_titles.append(self.downloader["TITLE"])
await self.bot.change_status(discord.Game(name=self.downloader["TITLE"]))
except discord.errors.ClientException:
print("Error: I can't play music without ffmpeg. Install it.")
self.downloader = {"DONE" : False, "TITLE" : False, "ID" : False, "URL": False, "DURATION" : False, "DOWNLOADING" : False}
self.queue = []
self.playlist = []
except Exception as e:
print(e)
else:
pass
async def check_voice(self, author, message):
if self.bot.is_voice_connected():
v_channel = message.server.me.voice_channel
if author.voice_channel == v_channel:
return True
elif len(v_channel.voice_members) == 1:
if author.voice_channel:
if author.voice_channel.permissions_for(message.server.me).connect:
wait = await self.close_audio()
await self.bot.join_voice_channel(author.voice_channel)
return True
else:
await self.bot.say("I need permissions to join that voice channel.")
return False
else:
await self.bot.say("You need to be in a voice channel.")
return False
else:
if not self.playlist and not self.queue:
return True
else:
await self.bot.say("I'm already playing music for other people.")
return False
elif author.voice_channel:
if author.voice_channel.permissions_for(message.server.me).connect:
await self.bot.join_voice_channel(author.voice_channel)
return True
else:
await self.bot.say("I need permissions to join that voice channel.")
return False
else:
await self.bot.say("You need to be in a voice channel.")
return False
async def queue_manager(self):
while "Audio" in self.bot.cogs:
if not self.music_player.paused:
if self.queue and not self.music_player.is_playing():
new_link = self.queue[0]
self.queue.pop(0)
self.skip_votes = []
await self.play_video(new_link)
elif self.playlist and not self.music_player.is_playing():
if not self.current == len(self.playlist)-1:
self.current += 1
else:
self.current = 0
new_link = self.playlist[self.current]
self.skip_votes = []
await self.play_video(new_link)
await asyncio.sleep(1)
def get_video(self, url, audio):
try:
self.downloader["DOWNLOADING"] = True
yt = youtube_dl.YoutubeDL(youtube_dl_options)
v = yt.extract_info(url, download=False)
if v["duration"] > self.settings["MAX_LENGTH"]: raise MaximumLength("Track exceeded maximum length. See help audioset maxlength")
if not os.path.isfile("data/audio/cache/" + v["id"]):
v = yt.extract_info(url, download=True)
audio.downloader = {"DONE" : True, "TITLE" : v["title"], "ID" : v["id"], "URL" : url, "DURATION" : v["duration"], "DOWNLOADING" : False} #Errors out here if invalid link
except Exception as e:
print(e) # TODO
audio.downloader = {"DONE" : True, "TITLE" : False, "ID" : False, "URL" : False, "DOWNLOADING" : False}
async def incoming_messages(self, msg): # Workaround, need to fix
if msg.author.id != self.bot.user.id:
if self.settings["MAX_CACHE"] != 0:
if abs(self.cleanup_timer - int(time.perf_counter())) >= 900: # checks cache's size every 15 minutes
self.cleanup_timer = int(time.perf_counter())
if self.cache_size() >= self.settings["MAX_CACHE"]:
self.empty_cache()
print("Cache emptied.")
if msg.channel.is_private and msg.attachments != []:
await self.transfer_playlist(msg)
if not msg.channel.is_private:
if not self.playlist and not self.queue and not self.music_player.is_playing() and str(msg.server.me.game) in self.past_titles:
self.past_titles = []
await self.bot.change_status(None)
def get_local_playlists(self):
dirs = []
files = os.listdir("data/audio/localtracks/")
for f in files:
if os.path.isdir("data/audio/localtracks/" + f) and " " not in f:
if glob.glob("data/audio/localtracks/" + f + "/*.mp3") != []:
dirs.append(f)
elif glob.glob("data/audio/localtracks/" + f + "/*.flac") != []:
dirs.append(f)
if dirs != []:
return dirs
else:
return False
@commands.command(pass_context=True, no_pm=True)
async def addplaylist(self, ctx, name : str, link : str): #CHANGE COMMAND NAME
"""Adds tracks from youtube playlist link"""
if self.is_playlist_name_valid(name) and len(name) < 25 and self.is_playlist_link_valid(link):
if fileIO("playlists/" + name + ".txt", "check"):
await self.bot.say("`A playlist with that name already exists.`")
return False
links = await self.parse_yt_playlist(link)
if links:
data = { "author" : ctx.message.author.id,
"playlist": links,
"link" : link}
fileIO("data/audio/playlists/" + name + ".txt", "save", data)
await self.bot.say("Playlist added. Name: {}".format(name))
else:
await self.bot.say("Something went wrong. Either the link was incorrect or I was unable to retrieve the page.")
else:
await self.bot.say("Something is wrong with the playlist's link or its filename. Remember, the name must be with only numbers, letters and underscores. Link must be this format: https://www.youtube.com/playlist?list=PLe8jmEHFkvsaDOOWcREvkgFoj6MD0pXXX")
async def transfer_playlist(self, message):
msg = message.attachments[0]
if msg["filename"].endswith(".txt"):
if not fileIO("data/audio/playlists/" + msg["filename"], "check"): #returns false if file already exists
r = await aiohttp.get(msg["url"])
r = await r.text()
data = r.replace("\r", "")
data = data.split()
if self.is_playlist_valid(data) and self.is_playlist_name_valid(msg["filename"].replace(".txt", "")):
data = { "author" : message.author.id,
"playlist": data,
"link" : False}
fileIO("data/audio/playlists/" + msg["filename"], "save", data)
await self.bot.send_message(message.channel, "Playlist added. Name: {}".format(msg["filename"].replace(".txt", "")))
else:
await self.bot.send_message(message.channel, "Something is wrong with the playlist or its filename.") # Add formatting info
else:
await self.bot.send_message(message.channel, "A playlist with that name already exists. Change the filename and resubmit it.")
def is_playlist_valid(self, data):
data = [y for y in data if y != ""] # removes all empty elements
data = [y for y in data if y != "\n"]
pattern = "|".join(fileIO("data/audio/accepted_links.json", "load"))
for link in data:
rr = re.search(pattern, link, re.I | re.U)
if rr == None:
return False
return True
def is_playlist_link_valid(self, link):
pattern = "^https:\/\/www.youtube.com\/playlist\?list=(.[^:/]*)"
rr = re.search(pattern, link, re.I | re.U)
if not rr == None:
return rr.group(1)
else:
return False
def is_playlist_name_valid(self, name):
for l in name:
if l.isdigit() or l.isalpha() or l == "_":
pass
else:
return False
return True
async def parse_yt_playlist(self, url):
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
try:
page = await aiohttp.post(url, headers=headers)
page = await page.text()
soup = BeautifulSoup(page, 'html.parser')
tags = soup.find_all("tr", class_="pl-video yt-uix-tile ")
links = []
for tag in tags:
links.append("https://www.youtube.com/watch?v=" + tag['data-video-id'])
if links != []:
return links
else:
return False
except:
return False
async def get_json(self, url):
"""
Returns the JSON from an URL.
Expects the url to be valid and return a JSON object.
"""
async with aiohttp.get(url) as r:
result = await r.json()
return result
async def get_song_metadata(self, song_url):
"""
Returns JSON object containing metadata about the song.
Expects song_url to be valid url and in acepted_list
"""
youtube_regex = (
r'(https?://)?(www\.)?'
'(youtube|youtu|youtube-nocookie)\.(com|be)/'
'(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})')
soundcloud_regex = "^(https:\\/\\/soundcloud\\.com\\/.*)"
is_youtube_link = re.match(youtube_regex, song_url)
is_soundcloud_link = re.match(soundcloud_regex, song_url)
if is_youtube_link:
url = "http://www.youtube.com/oembed?url={0}&format=json".format(song_url)
result = await self.get_json(url)
elif is_soundcloud_link and (self.settings["SOUNDCLOUD_CLIENT_ID"] is not None):
url = "http://api.soundcloud.com/resolve.json?url={0}&client_id={1}".format(song_url, self.settings["SOUNDCLOUD_CLIENT_ID"])
result = await self.get_json(url)
else:
result = {"title": "A song "}
return result
class EmptyPlayer(): #dummy player
def __init__(self):
self.paused = False
def stop(self):
pass
def is_playing(self):
return False
class MaximumLength(Exception):
def __init__(self, m):
self.message = m
def __str__(self):
return self.message
def check_folders():
folders = ("data/audio", "data/audio/cache", "data/audio/playlists", "data/audio/localtracks")
for folder in folders:
if not os.path.exists(folder):
print("Creating " + folder + " folder...")
os.makedirs(folder)
def check_files():
default = {"VOLUME" : 0.5, "MAX_LENGTH" : 3700, "QUEUE_MODE" : True, "MAX_CACHE" : 0, "SOUNDCLOUD_CLIENT_ID": None, "TITLE_STATUS" : True}
settings_path = "data/audio/settings.json"
if not os.path.isfile(settings_path):
print("Creating default audio settings.json...")
fileIO(settings_path, "save", default)
else: #consistency check
current = fileIO(settings_path, "load")
if current.keys() != default.keys():
for key in default.keys():
if key not in current.keys():
current[key] = default[key]
print("Adding " + str(key) + " field to audio settings.json")
fileIO(settings_path, "save", current)
allowed = ["^(https:\/\/www\\.youtube\\.com\/watch\\?v=...........*)", "^(https:\/\/youtu.be\/...........*)",
"^(https:\/\/youtube\\.com\/watch\\?v=...........*)", "^(https:\/\/soundcloud\\.com\/.*)"]
if not os.path.isfile("data/audio/accepted_links.json"):
print("Creating accepted_links.json...")
fileIO("data/audio/accepted_links.json", "save", allowed)
def setup(bot):
check_folders()
check_files()
loop = asyncio.get_event_loop()
n = Audio(bot)
loop.create_task(n.queue_manager())
bot.add_listener(n.incoming_messages, "on_message")
bot.add_cog(n)