Added C# project

rr/dockerize
Will Hunt 8 years ago
parent 94ef313c9e
commit c756e38f2e

316
.gitignore vendored

@ -1,62 +1,262 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
#User Specific
*.userprefs
*.usertasks
#Mono Project Files
*.pidb
*.resources
test-results/
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# Sphinx documentation
docs/_build/
# FAKE - F# Make
.fake/
# PyBuilder
target/
# JetBrains Rider
.idea/
*.sln.iml
#Ipython Notebook
.ipynb_checkpoints

@ -0,0 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MpdDj", "MpdDj\MpdDj.csproj", "{9840E711-4380-43B5-89D9-6243E051BCB8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9840E711-4380-43B5-89D9-6243E051BCB8}.Debug|x86.ActiveCfg = Debug|x86
{9840E711-4380-43B5-89D9-6243E051BCB8}.Debug|x86.Build.0 = Debug|x86
{9840E711-4380-43B5-89D9-6243E051BCB8}.Release|x86.ActiveCfg = Release|x86
{9840E711-4380-43B5-89D9-6243E051BCB8}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal

@ -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>

@ -0,0 +1,12 @@
using System;
namespace MpdDj
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
}
}
}

@ -0,0 +1,27 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle ("MpdDj")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("")]
[assembly: AssemblyProduct ("")]
[assembly: AssemblyCopyright ("will")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion ("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

@ -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…
Cancel
Save