Added C# project
parent
94ef313c9e
commit
c756e38f2e
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{9840E711-4380-43B5-89D9-6243E051BCB8}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>MpdDj</RootNamespace>
|
||||
<AssemblyName>MpdDj</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Externalconsole>true</Externalconsole>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Externalconsole>true</Externalconsole>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from djimporter import download_youtube
|
||||
from matrix_client.client import MatrixClient
|
||||
from mpc.mpc import MPCClient
|
||||
from time import time, sleep
|
||||
from queue import Queue
|
||||
import traceback
|
||||
|
||||
|
||||
class CmdListener:
|
||||
rooms = {}
|
||||
mpc = None
|
||||
client = None
|
||||
stream_url = ""
|
||||
cmd_queue = None
|
||||
music_dir = None
|
||||
def __init__(self,config):
|
||||
self.mpc = MPCClient(config["mpc"]["host"],config["mpc"]["port"])
|
||||
self.music_dir = config["mpc"]["music_dir"]
|
||||
self.cmd_queue = Queue()
|
||||
|
||||
try:
|
||||
self.mpc.current()
|
||||
except:
|
||||
raise Exception("An error occured while connecting to the mpd server.")
|
||||
return
|
||||
|
||||
try:
|
||||
self.client = MatrixClient(config["matrix"]["host"])
|
||||
except:
|
||||
raise Exception("An error occured while connecting to the matrix server!")
|
||||
return
|
||||
|
||||
|
||||
self.stream_url = config["mpc"]["streamurl"]
|
||||
try:
|
||||
self.client.login_with_password(config["matrix"]["user"],config["matrix"]["pass"])
|
||||
except MatrixRequestError as e:
|
||||
print(e)
|
||||
if e.code == 403:
|
||||
print("Bad username or password.")
|
||||
sys.exit(4)
|
||||
else:
|
||||
print("Check your sever details are correct.")
|
||||
sys.exit(3)
|
||||
|
||||
MTX_ROOMS = config["matrix"]["rooms"].split(",")
|
||||
|
||||
for sroom in MTX_ROOMS:
|
||||
room = self.client.join_room(sroom)
|
||||
room.add_listener(self.__on_cmd)
|
||||
self.rooms[room.room_id] = room
|
||||
|
||||
def run(self):
|
||||
self.client.start_listener_thread()
|
||||
while True:
|
||||
event = self.cmd_queue.get()
|
||||
if event is None:
|
||||
continue;
|
||||
else:
|
||||
cmd = event['content']['body']
|
||||
body = cmd.lower()
|
||||
if body.startswith('mpddj:') or body.startswith('!mpddj'):
|
||||
self.__parse_command(body[6:],event,cmd[6:])
|
||||
elif body.startswith('mpd dj:'):
|
||||
self.__parse_command(body[7:],event,cmd[7:])
|
||||
|
||||
def __on_cmd(self,event):
|
||||
if event['type'] == "m.room.message" and event['content']['msgtype'] == "m.text":
|
||||
if event['age'] < 5000:
|
||||
self.cmd_queue.put(event)
|
||||
|
||||
def __newfile_play(self,fname,max_attempts=25):
|
||||
# Do update check
|
||||
attempts = 0
|
||||
gotfile = False
|
||||
while attempts < max_attempts and not gotfile:
|
||||
musiclist = self.mpc.listall()
|
||||
gotfile = fname in musiclist
|
||||
if not gotfile:
|
||||
sleep(0.5)
|
||||
attempts += 1
|
||||
if gotfile:
|
||||
self.mpc.add(fname)
|
||||
self.mpc.play()
|
||||
|
||||
def __parse_command(self,cmd,event,cmd_regular):
|
||||
cmd = cmd.strip()
|
||||
parts = cmd.split(" ")
|
||||
room = self.rooms[event['room_id']];
|
||||
if parts[0] == "shuffle":
|
||||
self.mpc.shuffle()
|
||||
elif parts[0] == "prev":
|
||||
self.mpc.next()
|
||||
elif parts[0] == "play":
|
||||
self.mpc.play()
|
||||
elif parts[0] == "next":
|
||||
self.mpc.next()
|
||||
elif parts[0] == "playlist":
|
||||
plist = self.mpc.playlist().split("\n")[:-1][:3]
|
||||
if len(plist) > 0:
|
||||
plist[0] = "▶ " + plist[0]
|
||||
room.send_text("\n".join(plist).replace(".ogg",""))
|
||||
else:
|
||||
room.send_text("The playlist is empty")
|
||||
elif parts[0] == "current":
|
||||
fname = self.mpc.current()
|
||||
fname = fname.replace("_"," ").replace(".ogg","")
|
||||
room.send_text(fname)
|
||||
elif parts[0] == "update":
|
||||
self.mpc.update()
|
||||
elif parts[0] == "help":
|
||||
room.send_text("Commands are: play,prev,next,current,playlist,help,[youtube url],stream url")
|
||||
elif "youtube.com/" in parts[0] or "soundcloud.com/" in parts[0]:
|
||||
pos = 1
|
||||
try:
|
||||
url = cmd_regular.strip().split(" ")[0]
|
||||
pos = len(self.mpc.playlist().split('\n'))-1
|
||||
status,fname = download_youtube(url,self.music_dir,self.__newfile_play)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print(traceback.format_exc())
|
||||
room.send_text("Couldn't download the file :(")
|
||||
return;
|
||||
self.mpc.update(True)
|
||||
|
||||
|
||||
if status:
|
||||
if fname is not False:
|
||||
fi = fname.replace(".ogg","")
|
||||
if pos > 0:
|
||||
room.send_text(fi + " has been queued. It currently at position "+str(pos+1))
|
||||
else:
|
||||
room.send_text(fi + " has begun playing")
|
||||
else:
|
||||
if pos > 1:
|
||||
room.send_text("Your playlist has been queued. It currently at position "+str(pos))
|
||||
else:
|
||||
room.send_text("Your playlist has begun playing")
|
||||
if self.mpc.current() == '':
|
||||
sleep(0.5)# Allow it to breathe
|
||||
self.mpc.play()
|
||||
else:
|
||||
room.send_text("I couldn't play the file. This is probably a bug and should be reported to Half-Shot.")
|
||||
|
||||
elif "stream url" in cmd:
|
||||
room.send_text(self.stream_url)
|
@ -1,53 +0,0 @@
|
||||
#from mutagen.oggvorbis import OggVorbis
|
||||
import youtube_dl
|
||||
from os.path import getctime, basename,exists
|
||||
from glob import iglob
|
||||
from threading import Lock
|
||||
from time import sleep
|
||||
|
||||
yt_mutex = Lock()
|
||||
__yt_callback = None
|
||||
__yt_lastfile = ""
|
||||
def yt_hook(status):
|
||||
global __yt_callback
|
||||
global __yt_lastfile
|
||||
if status['status'] == "finished":
|
||||
print("Finished downloading video")
|
||||
fname = status['filename'].replace(".tmp",".ogg")
|
||||
print("YT Last file:",__yt_lastfile)
|
||||
if __yt_lastfile != "":
|
||||
__yt_callback(__yt_lastfile)
|
||||
__yt_lastfile = basename(fname)
|
||||
|
||||
def download_youtube(url,outputdir,callback):
|
||||
global __yt_callback
|
||||
global __yt_lastfile
|
||||
yt_mutex.acquire()
|
||||
path = False
|
||||
status = False
|
||||
__yt_callback = callback
|
||||
try:
|
||||
ydl_opts = {
|
||||
'format': 'bestaudio/best',
|
||||
'outtmpl': outputdir+'%(title)s.tmp',
|
||||
'add-metadata':True,
|
||||
'postprocessors': [{
|
||||
'key': 'FFmpegExtractAudio',
|
||||
'preferredcodec': 'vorbis',
|
||||
'preferredquality': '192',
|
||||
}],
|
||||
'progress_hooks':[yt_hook]
|
||||
}
|
||||
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
|
||||
|
||||
data = ydl.extract_info(url,False)
|
||||
if 'entries' not in data.keys():
|
||||
path = basename(ydl.prepare_filename(data).replace(".tmp",".ogg"))
|
||||
status = ydl.download([url])
|
||||
print(status)
|
||||
status = (status == 0)
|
||||
__yt_callback(__yt_lastfile)
|
||||
__yt_lastfile = ""
|
||||
finally:
|
||||
yt_mutex.release()
|
||||
return status, path
|
@ -1 +0,0 @@
|
||||
Subproject commit 03a28dcc84e90922165d4719f92d7d53c65345f0
|
@ -1,87 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
""" Matrix MPD DJ """
|
||||
import configparser
|
||||
from os.path import expanduser,exists
|
||||
from cmdlistener import CmdListener
|
||||
from sys import exit
|
||||
# Error Codes:
|
||||
# 1 - Unknown problem has occured
|
||||
# 2 - Could not find the server.
|
||||
# 3 - Bad URL Format.
|
||||
# 4 - Bad username/password.
|
||||
# 11 - Wrong room format.
|
||||
# 12 - Couldn't find room.
|
||||
|
||||
def default_config(path):
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
config["mpc"] = {}
|
||||
config["matrix"] = {}
|
||||
|
||||
config["mpc"]["host"] = "localhost"
|
||||
config["mpc"]["port"] = "6600"
|
||||
config["mpc"]["streamurl"] = "http://localhost:8000"
|
||||
config["mpc"]["music_dir"] = "/var/lib/mpd/music"
|
||||
|
||||
config["matrix"]["host"] = "https://localhost:8448"
|
||||
config["matrix"]["user"] = "username"
|
||||
config["matrix"]["pass"] = "password"
|
||||
config["matrix"]["rooms"] = "#RoomA,#RoomB:localhost,#RoomC"
|
||||
|
||||
with open(path, 'w') as configfile:
|
||||
config.write(configfile)
|
||||
|
||||
def read_config(path):
|
||||
config = configparser.ConfigParser()
|
||||
config.read(path)
|
||||
if "mpc" not in config.keys():
|
||||
print("Error, missing mpc section")
|
||||
return False
|
||||
|
||||
keys = ["host","port","streamurl","music_dir"]
|
||||
for key in keys:
|
||||
if key not in config["mpc"].keys():
|
||||
print("Error, missing",key,"from mpc section")
|
||||
return False
|
||||
|
||||
if "matrix" not in config.keys():
|
||||
print("Error, missing matrix section")
|
||||
return False
|
||||
|
||||
keys = ["host","user","pass","rooms"]
|
||||
for key in keys:
|
||||
if key not in config["matrix"].keys():
|
||||
print("Error, missing",key,"from matrix section")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
#Get config
|
||||
cfgfile = expanduser("~/.config/mpddj.ini")
|
||||
config = None
|
||||
if not exists(cfgfile):
|
||||
print("Config file not found, writing a new one")
|
||||
print("Writing to",cfgfile)
|
||||
config = default_config(cfgfile)
|
||||
else:
|
||||
print("Reading",cfgfile)
|
||||
if read_config(cfgfile):
|
||||
config = configparser.ConfigParser()
|
||||
config.read(cfgfile)
|
||||
else:
|
||||
print("Cannot start, you have errors in your config file")
|
||||
|
||||
try:
|
||||
cmd = CmdListener(config)
|
||||
except Exception as e:
|
||||
print("Failed to connect to one or more services.")
|
||||
print("The message was:",e)
|
||||
exit(2)
|
||||
cmd.run()
|
||||
|
||||
|
||||
MPD_HOST = "localhost"
|
||||
MPD_STREAMURL = "http://half-shot.uk:8000/mpd.ogg"
|
||||
MTX_HOST = "https://souppenguin.com:8448"
|
||||
MTX_USERNAME = "@mpddj:souppenguin.com"
|
||||
MTX_ROOMS = ["#devtest:souppenguin.com","#offtopic:matrix.org"]
|
@ -1 +0,0 @@
|
||||
__version__ = "0.0.1"
|
@ -1,174 +0,0 @@
|
||||
from subprocess import call, check_output
|
||||
import shlex
|
||||
import socket
|
||||
#TODO: Implement the rest
|
||||
|
||||
def onoff(val):
|
||||
if val == True:
|
||||
return "on"
|
||||
else:
|
||||
return "off"
|
||||
|
||||
class MPCClient:
|
||||
def __init__(self,hostname="localhost",port="6600"):
|
||||
self.host = hostname
|
||||
self.port = port
|
||||
|
||||
def __runcmd(self,cmd,output=False,args=[]):
|
||||
c = ["mpc","-h",self.host,"-p",self.port,cmd]
|
||||
if(output):
|
||||
return check_output(c+args).decode()
|
||||
else:
|
||||
return call(c+args)
|
||||
|
||||
def __runtcp(self,cmd,output=False,args=[]):
|
||||
BUFFER = 512
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
s.connect((self.host,int(self.port)))
|
||||
except:
|
||||
raise Exception("Couldn't connect to MPD")
|
||||
|
||||
data = s.recv(BUFFER).decode()
|
||||
if not data.startswith("OK MPD"):
|
||||
s.close()
|
||||
raise Exception("Couldn't connect to MPD")
|
||||
msg = cmd+" "+" ".join(args)+"\n"
|
||||
s.send(msg.encode())
|
||||
data = s.recv(BUFFER)
|
||||
s.close()
|
||||
return True
|
||||
|
||||
def set_crossfade(self,seconds):
|
||||
return self.__runcmd("crossfade",False,[str(seconds)])
|
||||
|
||||
def get_crossfade(self):
|
||||
cfade = self.__runcmd("crossfade",True)
|
||||
if(cfade):
|
||||
cfade = int(cfade[11:])
|
||||
return cfade
|
||||
|
||||
def current(self):
|
||||
return self.__runcmd("current",True)
|
||||
|
||||
def crop(self):
|
||||
return self.__runcmd("crop")
|
||||
|
||||
def clear(self):
|
||||
return self.__runcmd("clear")
|
||||
|
||||
def pause(self):
|
||||
return self.__runcmd("pause")
|
||||
|
||||
def delete(self,songid=0):
|
||||
return self.__runcmd("del",False,[songid])
|
||||
|
||||
def idle(self,filter=None):
|
||||
if filter != None:
|
||||
return self.__runcmd("idle",True,[filter])
|
||||
else:
|
||||
return self.__runcmd("idle",True)
|
||||
|
||||
def play(self,songid=None):
|
||||
if(songid != None):
|
||||
return self.__runcmd("play",False,[songid])
|
||||
else:
|
||||
return self.__runcmd("play",False)
|
||||
|
||||
def listall(self,playlist=None):
|
||||
if playlist != None:
|
||||
return self.__runcmd("listall",True,[playlist]).split("\n")
|
||||
else:
|
||||
return self.__runcmd("listall",True).split("\n")
|
||||
|
||||
def load(self,playlist):
|
||||
return self.__runcmd("load",False,[playlist])
|
||||
|
||||
def ls(self,directory=None):
|
||||
if directory != None:
|
||||
return self.__runcmd("ls",True,[directory])
|
||||
else:
|
||||
return self.__runcmd("ls",True)
|
||||
|
||||
def lsplaylists(self,directory=None):
|
||||
return self.__runcmd("lsplaylists",True)
|
||||
|
||||
def move(self,frm,to):
|
||||
return self.__runcmd("move",False,[frm,to])
|
||||
|
||||
def next(self):
|
||||
return self.__runcmd("next")
|
||||
|
||||
def playlist(self,playlist=None):
|
||||
if playlist != None:
|
||||
return self.__runcmd("playlist",True,[playlist])
|
||||
else:
|
||||
return self.__runcmd("playlist",True)
|
||||
|
||||
def prev(self):
|
||||
return self.__runcmd("prev")
|
||||
|
||||
def random(self,on=None):
|
||||
if on != None:
|
||||
return self.__runcmd("random",False,[onoff(om)])
|
||||
else:
|
||||
return self.__runcmd("random",False)
|
||||
|
||||
def repeat(self,on=None):
|
||||
if on != None:
|
||||
return self.__runcmd("repeat",False,[onoff(om)])
|
||||
else:
|
||||
return self.__runcmd("repeat",False)
|
||||
|
||||
def single(self,on=None):
|
||||
if on != None:
|
||||
return self.__runcmd("single",False,[onoff(om)])
|
||||
else:
|
||||
return self.__runcmd("single",False)
|
||||
|
||||
def consume(self,on=None):
|
||||
if on != None:
|
||||
return self.__runcmd("consume",False,[onoff(om)])
|
||||
else:
|
||||
return self.__runcmd("consume",False)
|
||||
|
||||
def rm(self,playlist):
|
||||
return self.__runcmd("rm",False,[playlist])
|
||||
|
||||
def save(self,playlist):
|
||||
return self.__runcmd("save",False,[playlist])
|
||||
|
||||
def shuffle(self):
|
||||
return self.__runcmd("shuffle")
|
||||
|
||||
def stats(self):
|
||||
return self.__runcmd("stats",True)
|
||||
|
||||
def stop(self):
|
||||
return self.__runcmd("stop")
|
||||
|
||||
def toggle(self):
|
||||
return self.__runcmd("toggle")
|
||||
|
||||
def add(self,file):
|
||||
file = '"'+file+'"'
|
||||
return self.__runtcp("add",False,[file])
|
||||
|
||||
def insert(self,file):
|
||||
file = shlex.quote(file)
|
||||
return self.__runtcp("insert",False,[file])
|
||||
|
||||
def update(self,wait=False,path=None):
|
||||
path = shlex.quote(path)
|
||||
args = []
|
||||
|
||||
if wait:
|
||||
args.append("--wait")
|
||||
|
||||
if path != None:
|
||||
args.append(path)
|
||||
|
||||
return self.__runcmd("update",False,args)
|
||||
|
||||
def version(self):
|
||||
return self.__runcmd("version")
|
Loading…
Reference in New Issue