Initial git commit

This commit is contained in:
ianfijolek 2011-02-01 14:59:57 -05:00
commit ab3d1b3472
47 changed files with 3763 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.hg/
.hgignore

View File

@ -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("SubsonicAPI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[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("")]

View File

@ -0,0 +1,648 @@
/**************************************************************************
Subsonic Csharp
Copyright (C) 2010 Ian Fijolek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
namespace SubsonicAPI
{
#region Classes
public class SubsonicItem
{
public enum SubsonicItemType
{
Folder, Song, Artist, Library
}
public string name;
public string id;
public string lastModified;
public string lastAccessed;
public SubsonicItemType itemType;
public SubsonicItem parent;
private List<SubsonicItem> _children;
public List<SubsonicItem> children
{
get
{
if (_children == null)
{
if (this.itemType == SubsonicItemType.Song)
_children = null;
else
_children = Subsonic.GetItemChildren(this, "");
}
return _children;
}
set
{
_children = value;
}
}
public SubsonicItem()
{
this.name = "";
this.id = "";
this.lastAccessed = DateTime.Now.ToString();
}
public SubsonicItem(string name, string id)
{
this.name = name;
this.id = name;
this.lastAccessed = DateTime.Now.ToString();
}
public SubsonicItem(string name, string id, SubsonicItemType itemType, SubsonicItem parent)
{
this.name = name;
this.id = id;
this.itemType = itemType;
this.parent = parent;
this.lastAccessed = DateTime.Now.ToString();
}
public override string ToString()
{
return name;
}
public SubsonicItem FindItemById(string id)
{
SubsonicItem foundItem = null;
// If the current item is the item we are looking for, return it
if (this.id == id)
foundItem = this;
// Otherwise, we check the children if they exist
else if (_children != null)
{
foreach(SubsonicItem child in _children)
{
// If this child is the item we are looking for, return it
if (child.id == id)
{
foundItem = child;
break;
}
else
{
foundItem = child.FindItemById(id);
if (foundItem != null)
break;
}
}
}
return foundItem;
}
public SubsonicItem GetChildByName(string childName)
{
SubsonicItem theItem = null;
if (_children != null)
{
theItem = _children.Find(
delegate(SubsonicItem itm)
{
return itm.name == childName ;
}
);
}
return theItem;
}
}
public class Song : SubsonicItem
{
public string artist;
public string album;
public string title;
public Song()
{
this.artist = "";
this.title = "";
this.album = "";
this.name = "";
this.id = "";
this.itemType = SubsonicItem.SubsonicItemType.Song;
this.parent = null;
this.lastAccessed = DateTime.Now.ToString();
}
public Song(string title,string artist, string album, string id)
{
this.artist = artist;
this.title = title;
this.album = album;
this.name = title;
this.id = id;
this.itemType = SubsonicItem.SubsonicItemType.Song;
this.parent = null;
this.lastAccessed = DateTime.Now.ToString();
}
public Song(string title, string artist, string album, string id, SubsonicItem parent)
{
this.artist = artist;
this.title = title;
this.album = album;
this.name = title;
this.id = id;
this.itemType = SubsonicItem.SubsonicItemType.Song;
this.parent = parent;
this.lastAccessed = DateTime.Now.ToString();
}
public Stream getStream()
{
return Subsonic.StreamSong(this.id);
}
public override string ToString()
{
return artist + " - " + title;
}
}
#endregion Classes
/// <summary>
/// Open Source C# Implementation of the Subsonic API
/// http://www.subsonic.org/pages/api.jsp
/// </summary>
public static class Subsonic
{
private static SubsonicItem _MyLibrary;
/// <summary>
/// Public Property that can be used for auto-retrieving children
/// </summary>
public static SubsonicItem MyLibrary
{
get
{
return _MyLibrary;
}
set
{
_MyLibrary = value;
}
}
// Should be set from application layer when the application is loaded
public static string appName;
// Min version of the REST API implemented
private static string apiVersion = "1.3.0";
// Set with the login method
static string server;
static string authHeader;
// Used for generating direct URLS
static string encPass;
static string username;
/// <summary>
/// Takes parameters for server, username and password to generate an auth header
/// and Pings the server
/// </summary>
/// <param name="theServer"></param>
/// <param name="user"></param>
/// <param name="password"></param>
/// <returns>Resulting XML (Future boolean)</returns>
public static string LogIn(string theServer, string user, string password)
{
string result = "Nothing Happened";
server = theServer;
authHeader = user + ":" + password;
authHeader = Convert.ToBase64String(Encoding.Default.GetBytes(authHeader));
// Store user and encoded password for alternate authentication
username = user;
Byte[] passwordBytes = Encoding.Default.GetBytes(password);
for (int i = 0; i < passwordBytes.Length; i++)
encPass += passwordBytes[i].ToString("x2");
Stream theStream = MakeGenericRequest("ping", null);
StreamReader sr = new StreamReader(theStream);
result = sr.ReadToEnd();
/// TODO: Parse the result and determine if logged in or not
_MyLibrary = new SubsonicItem("LibraryRoot", "-1", SubsonicItem.SubsonicItemType.Library, null);
return result;
}
/// <summary>
/// Uses the Auth Header for logged in user to make an HTTP request to the server
/// with the given Subsonic API method and parameters
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns>Datastream of the server response</returns>
public static Stream MakeGenericRequest(string method, Dictionary<string, string> parameters)
{
// Check to see if Logged In yet
if (string.IsNullOrEmpty(authHeader))
{
// Throw a Not Logged In exception
Exception e = new Exception("No Authorization header. Must Log In first");
return null;
}
else
{
if (!method.EndsWith(".view"))
method += ".view";
string requestURL = BuildRequestURL(method, parameters);
WebRequest theRequest = WebRequest.Create(requestURL);
theRequest.Method = "GET";
theRequest.Headers["Authorization"] = "Basic " + authHeader;
WebResponse response = theRequest.GetResponse();
Stream dataStream = response.GetResponseStream();
return dataStream;
}
}
/// <summary>
/// Creates a URL for a request but does not make the actual request using set login credentials an dmethod and parameters
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns>Proper Subsonic API URL for a request</returns>
public static string BuildRequestURL(string method, Dictionary<string, string> parameters)
{
string requestURL = "http://" + server + "/rest/" + method + "?v=" + apiVersion + "&c=" + appName;
if (parameters != null)
{
foreach (KeyValuePair<string, string> parameter in parameters)
{
requestURL += "&" + parameter.Key + "=" + parameter.Value;
}
}
return requestURL;
}
/// <summary>
/// Creates a URL for a command with username and encoded pass in the URL
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns>URL for streaming a song or retrieving the results of a call</returns>
public static string BuildDirectURL(string method, Dictionary<string, string> parameters)
{
string callURL = "http://" + server + "/rest/" + method + "?v=" + apiVersion + "&c=" + appName
+ "&u=" + username + "&p=enc:" + encPass;
if (parameters != null)
{
foreach (KeyValuePair<string, string> parameter in parameters)
{
callURL += "&" + parameter.Key + "=" + parameter.Value;
}
}
return callURL;
}
/// <summary>
/// Returns a list of SubsonicItems that fall inside the parent object
/// </summary>
/// <param name="parent">
/// A <see cref="SubsonicItem"/>
/// </param>
/// <param name="ifModifiedSince">
/// A <see cref="System.String"/>
/// </param>
/// <returns>
/// A <see cref="List<SubsonicItem>"/>
/// </returns>
public static List<SubsonicItem> GetItemChildren(SubsonicItem parent, string ifModifiedSince)
{
Dictionary<string, string> parameters = new Dictionary<string, string>();
// Generate the proper request for the parent type
string requestType, musicFolderId;
if (parent.itemType == SubsonicItem.SubsonicItemType.Library)
{
requestType = "getIndexes";
if (parent.id != "-1")
parameters.Add("musicFolderId", parent.id);
}
else
{
requestType = "getMusicDirectory";
parameters.Add("id", parent.id);
}
// Load the parameters if provided
if (!string.IsNullOrEmpty(ifModifiedSince))
parameters.Add("ifModifiedSince", ifModifiedSince);
// Make the request
Stream theStream = MakeGenericRequest(requestType, parameters);
// Read the response as a string
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
// Parse the resulting XML string into an XmlDocument
XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result);
List<SubsonicItem> children = new List<SubsonicItem>();
// Parse the artist
if (parent.itemType == SubsonicItem.SubsonicItemType.Library)
{
if (myXML.ChildNodes[1].Name == "subsonic-response")
{
if (myXML.ChildNodes[1].FirstChild.Name == "indexes")
{
for (int i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
{
for (int j = 0; j < myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes.Count; j++)
{
string artist = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["name"].Value;
string id = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["id"].Value;
children.Add(new SubsonicItem(artist, id, SubsonicItem.SubsonicItemType.Folder, parent));
}
}
}
}
}
// Parse the directory
else if (parent.itemType == SubsonicItem.SubsonicItemType.Folder)
{
if (myXML.ChildNodes[1].Name == "subsonic-response")
{
if (myXML.ChildNodes[1].FirstChild.Name == "directory")
{
for (int i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
{
bool isDir = bool.Parse(myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["isDir"].Value);
string title = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["title"].Value;
string id = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["id"].Value;
SubsonicItem theItem = new SubsonicItem(title, id, (isDir ? SubsonicItem.SubsonicItemType.Folder : SubsonicItem.SubsonicItemType.Song), parent);
children.Add(theItem);
}
}
}
}
return children;
}
/// <summary>
/// Returns an indexed structure of all artists.
/// </summary>
/// <param name="parent">Required: No; If specified, only return artists in the music folder with the given ID.</param>
/// <param name="ifModifiedSince">Required: No; If specified, only return a result if the artist collection has changed since the given time.</param>
/// <returns>Dictionary, Key = Artist and Value = id</returns>
public static List<SubsonicItem> GetIndexes(string musicFolderId, string ifModifiedSince)
{
// Load the parameters if provided
Dictionary<string, string> parameters = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(musicFolderId))
parameters.Add("musicFolderId", musicFolderId);
if (!string.IsNullOrEmpty(ifModifiedSince))
parameters.Add("ifModifiedSince", ifModifiedSince);
// Make the request
Stream theStream = MakeGenericRequest("getIndexes", parameters);
// Read the response as a string
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
// Parse the resulting XML string into an XmlDocument
XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result);
// Parse the XML document into a List
List<SubsonicItem> artists = new List<SubsonicItem>();
if (myXML.ChildNodes[1].Name == "subsonic-response")
{
if (myXML.ChildNodes[1].FirstChild.Name == "indexes")
{
int i = 0;
for (i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
{
int j = 0;
for (j = 0; j < myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes.Count; j++)
{
string artist = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["name"].Value;
string id = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["id"].Value;
artists.Add(new SubsonicItem(artist, id));
}
}
}
}
return artists;
}
public static List<SubsonicItem> GetIndexes(string musicFolderId)
{
return GetIndexes(musicFolderId, "");
}
public static List<SubsonicItem> GetIndexes()
{
return GetIndexes("", "");
}
/// <summary>
/// Streams a given music file. (Renamed from request name "stream")
/// </summary>
/// <param name="id">Required: Yes; A string which uniquely identifies the file to stream.
/// Obtained by calls to getMusicDirectory.</param>
/// <param name="maxBitRate">Required: No; If specified, the server will attempt to
/// limit the bitrate to this value, in kilobits per second. If set to zero, no limit
/// is imposed. Legal values are: 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 and 320. </param>
/// <returns></returns>
public static Stream StreamSong(string id, int? maxBitRate)
{
// Reades the id of the song and sets it as a parameter
Dictionary<string, string> theParameters = new Dictionary<string,string>();
theParameters.Add("id", id);
if (maxBitRate.HasValue)
theParameters.Add("maxBitRate", maxBitRate.ToString());
// Makes the request
Stream theStream = MakeGenericRequest("stream", theParameters);
return theStream;
}
public static Stream StreamSong(string id)
{
return StreamSong(id, null);
}
/// <summary>
/// Returns a listing of all files in a music directory. Typically used to get list of albums for an artist, or list of songs for an album.
/// </summary>
/// <param name="id">A string which uniquely identifies the music folder. Obtained by calls to getIndexes or getMusicDirectory.</param>
/// <returns>MusicFolder object containing info for the specified directory</returns>
public static List<SubsonicItem> GetMusicDirectory(string id)
{
Dictionary<string, string> theParameters = new Dictionary<string, string>();
theParameters.Add("id", id);
Stream theStream = MakeGenericRequest("getMusicDirectory", theParameters);
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result);
List<SubsonicItem> theContents = new List<SubsonicItem>();
if (myXML.ChildNodes[1].Name == "subsonic-response")
{
if (myXML.ChildNodes[1].FirstChild.Name == "directory")
{
SubsonicItem theParent = new SubsonicItem();
theParent.name = myXML.ChildNodes[1].FirstChild.Attributes["name"].Value;
theParent.id = myXML.ChildNodes[1].FirstChild.Attributes["id"].Value;
int i = 0;
for (i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
{
bool isDir = bool.Parse(myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["isDir"].Value);
string title = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["title"].Value;
string theId = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["id"].Value;
SubsonicItem theItem = new SubsonicItem(title, theId, (isDir ? SubsonicItem.SubsonicItemType.Folder : SubsonicItem.SubsonicItemType.Song), theParent);
theContents.Add(theItem);
}
}
}
return theContents;
}
/// <summary>
/// Returns what is currently being played by all users. Takes no extra parameters.
/// </summary>
public static List<SubsonicItem> GetNowPlaying()
{
List<SubsonicItem> nowPlaying = new List<SubsonicItem>();
Dictionary<string, string> theParameters = new Dictionary<string, string>();
Stream theStream = MakeGenericRequest("getNowPlaying", theParameters);
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
return nowPlaying;
}
/// <summary>
/// Performs a search valid for the current version of the subsonic server
/// </summary>
/// <param name="query">The Term you want to search for</param>
/// <returns>A List of SubsonicItem objects</returns>
public static List<SubsonicItem> Search(string query)
{
Dictionary<string, string> parameters = new Dictionary<string, string>();
Version apiV = new Version(apiVersion);
Version Search2Min = new Version("1.4.0");
string request = "";
if (apiV >= Search2Min)
{
request = "search2";
parameters.Add("query", query);
}
else
{
request = "search";
parameters.Add("any", query);
}
// Make the request
Stream theStream = MakeGenericRequest(request, parameters);
// Read the response as a string
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
// Parse the resulting XML string into an XmlDocument
XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result);
List<SubsonicItem> searchResults = new List<SubsonicItem>();
// Parse the artist
if (myXML.ChildNodes[1].Name == "subsonic-response")
{
if (myXML.ChildNodes[1].FirstChild.Name == "searchResult")
{
for (int i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
{
bool isDir = bool.Parse(myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["isDir"].Value);
string title = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["title"].Value;
string theId = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["id"].Value;
string artist = "";
string album = "";
if (!isDir)
{
artist = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["artist"].Value;
album = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["album"].Value;
}
SubsonicItem theItem;
if (isDir)
theItem = new SubsonicItem(title, theId, SubsonicItem.SubsonicItemType.Folder, null);
else
theItem = new Song(title, artist, album, theId);
searchResults.Add(theItem);
}
}
}
return searchResults;
}
}
}

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>SubsonicAPI</RootNamespace>
<AssemblyName>SubsonicAPI</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="SubsonicAPI.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

Binary file not shown.

View File

@ -0,0 +1,32 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SubsonicPlayer", "SubsonicMono\SubsonicPlayer.csproj", "{416D955F-4CD9-41C8-BB9D-BF17B59710B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SubsonicAPI", "SubsonicAPI\SubsonicAPI.csproj", "{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SubsonicWeb", "SubsonicWeb\SubsonicWeb.csproj", "{91BB17F9-5F24-4329-BA99-8A96B800416E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{416D955F-4CD9-41C8-BB9D-BF17B59710B8}.Debug|x86.ActiveCfg = Debug|x86
{416D955F-4CD9-41C8-BB9D-BF17B59710B8}.Debug|x86.Build.0 = Debug|x86
{416D955F-4CD9-41C8-BB9D-BF17B59710B8}.Release|x86.ActiveCfg = Release|x86
{416D955F-4CD9-41C8-BB9D-BF17B59710B8}.Release|x86.Build.0 = Release|x86
{91BB17F9-5F24-4329-BA99-8A96B800416E}.Debug|x86.ActiveCfg = Debug|Any CPU
{91BB17F9-5F24-4329-BA99-8A96B800416E}.Debug|x86.Build.0 = Debug|Any CPU
{91BB17F9-5F24-4329-BA99-8A96B800416E}.Release|x86.ActiveCfg = Release|Any CPU
{91BB17F9-5F24-4329-BA99-8A96B800416E}.Release|x86.Build.0 = Release|Any CPU
{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}.Debug|x86.ActiveCfg = Debug|Any CPU
{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}.Debug|x86.Build.0 = Debug|Any CPU
{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}.Release|x86.ActiveCfg = Release|Any CPU
{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = SubsonicMono\SubsonicPlayer.csproj
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,25 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug|x86" ctype="Workspace" />
<MonoDevelop.Ide.Workbench ActiveDocument="SubsonicMono/MainWindow.cs" ctype="Workbench">
<Files>
<File FileName="SubsonicAPI/SubsonicAPI.cs" Line="613" Column="14" />
<File FileName="SubsonicMono/MainWindow.cs" Line="192" Column="56" />
<File FileName="SubsonicMono/Main.cs" Line="13" Column="1" />
<File FileName="SubsonicWeb/Default.aspx" Line="14" Column="11" />
<File FileName="SubsonicWeb/Global.asax.cs" Line="17" Column="4" />
<File FileName="SubsonicWeb/Default.aspx.cs" Line="15" Column="1" />
<File FileName="SubsonicWeb/Library.aspx" Line="12" Column="92" />
<File FileName="SubsonicWeb/Library.aspx.cs" Line="33" Column="2" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore>
<Breakpoint file="/home/ianfijolek/workspace/subsonic-csharp/SubsonicMono/SubsonicWeb/Default.aspx.cs" line="15" />
<Breakpoint file="/home/ianfijolek/workspace/subsonic-csharp/SubsonicMono/SubsonicWeb/Library.aspx.cs" line="20" />
<Breakpoint file="/home/ianfijolek/workspace/subsonic-csharp/SubsonicMono/SubsonicWeb/Library.aspx.cs" line="75" />
<Breakpoint file="/home/ianfijolek/workspace/subsonic-csharp/SubsonicMono/SubsonicAPI/SubsonicAPI.cs" line="578" />
<Breakpoint file="/home/ianfijolek/workspace/subsonic-csharp/SubsonicMono/SubsonicAPI/SubsonicAPI.cs" line="613" />
</BreakpointStore>
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MonoDevelop.Ide.DebuggingService.PinnedWatches ctype="PinnedWatchStore" />
</Properties>

View File

@ -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("SubsonicMono")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[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("")]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,17 @@
using System;
using Gtk;
namespace SubsonicMono
{
class MainClass
{
public static void Main (string[] args)
{
Application.Init ();
MainWindow win = new MainWindow ();
win.Show ();
Application.Run ();
}
}
}

View File

@ -0,0 +1,203 @@
/**************************************************************************
Subsonic Csharp
Copyright (C) 2010 Ian Fijolek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
using System;
using Gtk;
using SubsonicAPI;
using System.Collections.Generic;
using HollyLibrary;
using System.Threading;
public partial class MainWindow : Gtk.Window
{
HTreeView tvLibrary;
HSimpleList slPlaylist;
public MainWindow () : base(Gtk.WindowType.Toplevel)
{
Build ();
Subsonic.appName = "IansCsharpApp";
InitializeTreeView();
InitializePlaylist();
}
private void InitializeTreeView()
{
tvLibrary = new HTreeView();
swLibrary.Add(tvLibrary);
tvLibrary.NodeExpanded += tvLibraryNodeExpanded;
tvLibrary.Editable = false;
tvLibrary.Visible = true;
}
private void InitializePlaylist()
{
slPlaylist = new HSimpleList();
swPlayQueue.Add(slPlaylist);
slPlaylist.Visible = true;
}
void tvLibraryNodeExpanded (object sender, NodeEventArgs args)
{
// Fetch any items inside the node...
HTreeNode thisNode = args.Node;
// Check to see if it has any children
if (thisNode.Nodes.Count == 1 && thisNode.Nodes[0].Text == "")
{
// Node child is a dummy
thisNode.Nodes[0].Text = "Loading...";
// Get path to the selected node to expandsimp
Queue<string> nodePath = GetNodePath(thisNode);
// Dive into library to selected node
SubsonicItem thisItem = Subsonic.MyLibrary;
while (nodePath.Count > 0)
{
thisItem = thisItem.GetChildByName(nodePath.Dequeue());
}
// Should now have the correct selected item
foreach(SubsonicItem child in thisItem.children)
{
HTreeNode childNode = new HTreeNode(child.name);
thisNode.Nodes.Add(childNode);
// Adding a dummy node for any Folders
if (child.itemType == SubsonicItem.SubsonicItemType.Folder)
childNode.Nodes.Add(new HTreeNode(""));
}
// Remove dummy node
thisNode.Nodes.RemoveAt(0);
}
}
private Queue<string> GetNodePath(HTreeNode theNode)
{
// Create a queue that will hold the name of all parent objects
Queue<string> nodePath;
if (theNode.ParentNode != null)
{
// If this node has a parent, then recurse
nodePath = GetNodePath(theNode.ParentNode);
}
else
{
// If the praent, then initialize the path
nodePath = new Queue<string>();
}
// Add enqueue this item in the path
nodePath.Enqueue(theNode.Text);
return nodePath;
}
private SubsonicItem GetNodeItem(HTreeNode theNode)
{
// Get path to the selected node
Queue<string> nodePath = GetNodePath(theNode);
// Dive into library to selected node
SubsonicItem thisItem = Subsonic.MyLibrary;
while (nodePath.Count > 0)
{
thisItem = thisItem.GetChildByName(nodePath.Dequeue());
}
return thisItem;
}
protected void OnDeleteEvent (object sender, DeleteEventArgs a)
{
Application.Quit ();
a.RetVal = true;
}
protected virtual void OnBtnLogin2Clicked (object sender, System.EventArgs e)
{
string server = tbServer.Text;
string user = tbUsername.Text;
string passw0rdd = tbPaassw0rd.Text;
string loginResult = Subsonic.LogIn(server, user, passw0rdd);
Console.WriteLine("Login Result: " + loginResult);
SubsonicItem thisLibrary = Subsonic.MyLibrary;
foreach(SubsonicItem artist in thisLibrary.children)
{
HTreeNode artistNode = new HTreeNode(artist.name);
tvLibrary.Nodes.Add(artistNode);
// Adding a dummy node for the artist
artistNode.Nodes.Add(new HTreeNode(""));
}
}
protected virtual void OnBtnQueueSongClicked (object sender, System.EventArgs e)
{
HTreeNode theNode = tvLibrary.SelectedNode;
// Check if node has children
if (theNode.Nodes.Count > 0)
{
// Will add all children to queue
}
else
{
// Node is a leaf (song)
SubsonicItem theItem = GetNodeItem(theNode);
// Confirm that the item is asong
if (theItem.itemType == SubsonicItem.SubsonicItemType.Song)
{
//slPlaylist.Items.Add(theItem);
Dictionary<string, string> songId = new Dictionary<string, string>();
songId.Add("id", theItem.id);
string streamURL = Subsonic.BuildDirectURL("download.view", songId);
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = "vlc";
proc.StartInfo.Arguments = "--one-instance --playlist-enqueue " + streamURL;
proc.Start();
}
}
}
protected virtual void OnBtnSearchClicked (object sender, System.EventArgs e)
{
string search = tbSearch.Text;
List<SubsonicItem> results = Subsonic.Search(search);
foreach (SubsonicItem si in results)
slPlaylist.Items.Add(si);
}
}

View File

@ -0,0 +1,9 @@
Application: Subsonic Csharp
Author: Ian Fijolek
License: GPLv3
Homepage: http://code.google.com/p/subsonic-csharp/
Please refer to the home page for license information as well
as source code, documentation and compiling instructions
Uses HollyLibrary.dll (LGPL) located at http://code.google.com/p/holly-gtk-widgets/

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{416D955F-4CD9-41C8-BB9D-BF17B59710B8}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>SubsonicMono</RootNamespace>
<AssemblyName>SubsonicMono</AssemblyName>
<TargetFrameworkVersion>v3.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>
<PlatformTarget>x86</PlatformTarget>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
<Package>glib-sharp-2.0</Package>
</Reference>
<Reference Include="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
<Package>glade-sharp-2.0</Package>
</Reference>
<Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
<SpecificVersion>False</SpecificVersion>
<Package>gtk-sharp-2.0</Package>
</Reference>
<Reference Include="Mono.Posix" />
<Reference Include="HollyLibrary, Version=1.0.3209.34427, Culture=neutral, PublicKeyToken=null">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\MonoLibs\HollyLibrary.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="gtk-gui\gui.stetic">
<LogicalName>gui.stetic</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Include="gtk-gui\generated.cs" />
<Compile Include="MainWindow.cs" />
<Compile Include="gtk-gui\MainWindow.cs" />
<Compile Include="Main.cs" />
<Compile Include="AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\SubsonicAPI\SubsonicAPI.csproj">
<Project>{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}</Project>
<Name>SubsonicAPI</Name>
</ProjectReference>
</ItemGroup>
</Project>

Binary file not shown.

View File

@ -0,0 +1,192 @@
// This file has been generated by the GUI designer. Do not modify.
public partial class MainWindow
{
private global::Gtk.Fixed frMain;
private global::Gtk.Label lblTitle;
private global::Gtk.Entry tbServer;
private global::Gtk.Label lbServer;
private global::Gtk.Label lblUsername;
private global::Gtk.Entry tbUsername;
private global::Gtk.Label lbPassw00rd;
private global::Gtk.Entry tbPaassw0rd;
private global::Gtk.ScrolledWindow swLibrary;
private global::Gtk.Button btnLogin2;
private global::Gtk.ScrolledWindow swPlayQueue;
private global::Gtk.Button btnQueueSong;
private global::Gtk.Button btnSearch;
private global::Gtk.Entry tbSearch;
private global::Gtk.Label label1;
protected virtual void Build ()
{
global::Stetic.Gui.Initialize (this);
// Widget MainWindow
this.Name = "MainWindow";
this.Title = global::Mono.Unix.Catalog.GetString ("MainWindow");
this.WindowPosition = ((global::Gtk.WindowPosition)(4));
// Container child MainWindow.Gtk.Container+ContainerChild
this.frMain = new global::Gtk.Fixed ();
this.frMain.Name = "frMain";
this.frMain.HasWindow = false;
// Container child frMain.Gtk.Fixed+FixedChild
this.lblTitle = new global::Gtk.Label ();
this.lblTitle.Name = "lblTitle";
this.lblTitle.LabelProp = global::Mono.Unix.Catalog.GetString ("Subsonic");
this.frMain.Add (this.lblTitle);
global::Gtk.Fixed.FixedChild w1 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.lblTitle]));
w1.X = 9;
w1.Y = 10;
// Container child frMain.Gtk.Fixed+FixedChild
this.tbServer = new global::Gtk.Entry ();
this.tbServer.CanFocus = true;
this.tbServer.Name = "tbServer";
this.tbServer.IsEditable = true;
this.tbServer.InvisibleChar = '•';
this.frMain.Add (this.tbServer);
global::Gtk.Fixed.FixedChild w2 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.tbServer]));
w2.X = 9;
w2.Y = 71;
// Container child frMain.Gtk.Fixed+FixedChild
this.lbServer = new global::Gtk.Label ();
this.lbServer.Name = "lbServer";
this.lbServer.LabelProp = global::Mono.Unix.Catalog.GetString ("Server URL:");
this.frMain.Add (this.lbServer);
global::Gtk.Fixed.FixedChild w3 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.lbServer]));
w3.X = 13;
w3.Y = 46;
// Container child frMain.Gtk.Fixed+FixedChild
this.lblUsername = new global::Gtk.Label ();
this.lblUsername.Name = "lblUsername";
this.lblUsername.LabelProp = global::Mono.Unix.Catalog.GetString ("Username:");
this.frMain.Add (this.lblUsername);
global::Gtk.Fixed.FixedChild w4 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.lblUsername]));
w4.X = 15;
w4.Y = 110;
// Container child frMain.Gtk.Fixed+FixedChild
this.tbUsername = new global::Gtk.Entry ();
this.tbUsername.CanFocus = true;
this.tbUsername.Name = "tbUsername";
this.tbUsername.IsEditable = true;
this.tbUsername.InvisibleChar = '•';
this.frMain.Add (this.tbUsername);
global::Gtk.Fixed.FixedChild w5 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.tbUsername]));
w5.X = 11;
w5.Y = 138;
// Container child frMain.Gtk.Fixed+FixedChild
this.lbPassw00rd = new global::Gtk.Label ();
this.lbPassw00rd.Name = "lbPassw00rd";
this.lbPassw00rd.LabelProp = global::Mono.Unix.Catalog.GetString ("Password:");
this.frMain.Add (this.lbPassw00rd);
global::Gtk.Fixed.FixedChild w6 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.lbPassw00rd]));
w6.X = 13;
w6.Y = 176;
// Container child frMain.Gtk.Fixed+FixedChild
this.tbPaassw0rd = new global::Gtk.Entry ();
this.tbPaassw0rd.CanFocus = true;
this.tbPaassw0rd.Name = "tbPaassw0rd";
this.tbPaassw0rd.IsEditable = true;
this.tbPaassw0rd.Visibility = false;
this.tbPaassw0rd.InvisibleChar = '•';
this.frMain.Add (this.tbPaassw0rd);
global::Gtk.Fixed.FixedChild w7 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.tbPaassw0rd]));
w7.X = 13;
w7.Y = 199;
// Container child frMain.Gtk.Fixed+FixedChild
this.swLibrary = new global::Gtk.ScrolledWindow ();
this.swLibrary.WidthRequest = 262;
this.swLibrary.HeightRequest = 348;
this.swLibrary.CanFocus = true;
this.swLibrary.Name = "swLibrary";
this.swLibrary.ShadowType = ((global::Gtk.ShadowType)(1));
this.frMain.Add (this.swLibrary);
global::Gtk.Fixed.FixedChild w8 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.swLibrary]));
w8.X = 10;
w8.Y = 295;
// Container child frMain.Gtk.Fixed+FixedChild
this.btnLogin2 = new global::Gtk.Button ();
this.btnLogin2.CanFocus = true;
this.btnLogin2.Name = "btnLogin2";
this.btnLogin2.UseUnderline = true;
this.btnLogin2.Label = global::Mono.Unix.Catalog.GetString ("Login2");
this.frMain.Add (this.btnLogin2);
global::Gtk.Fixed.FixedChild w9 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.btnLogin2]));
w9.X = 14;
w9.Y = 241;
// Container child frMain.Gtk.Fixed+FixedChild
this.swPlayQueue = new global::Gtk.ScrolledWindow ();
this.swPlayQueue.WidthRequest = 208;
this.swPlayQueue.HeightRequest = 338;
this.swPlayQueue.CanFocus = true;
this.swPlayQueue.Name = "swPlayQueue";
this.swPlayQueue.ShadowType = ((global::Gtk.ShadowType)(1));
this.frMain.Add (this.swPlayQueue);
global::Gtk.Fixed.FixedChild w10 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.swPlayQueue]));
w10.X = 315;
w10.Y = 296;
// Container child frMain.Gtk.Fixed+FixedChild
this.btnQueueSong = new global::Gtk.Button ();
this.btnQueueSong.CanFocus = true;
this.btnQueueSong.Name = "btnQueueSong";
this.btnQueueSong.UseUnderline = true;
this.btnQueueSong.Label = global::Mono.Unix.Catalog.GetString (">");
this.frMain.Add (this.btnQueueSong);
global::Gtk.Fixed.FixedChild w11 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.btnQueueSong]));
w11.X = 280;
w11.Y = 425;
// Container child frMain.Gtk.Fixed+FixedChild
this.btnSearch = new global::Gtk.Button ();
this.btnSearch.CanFocus = true;
this.btnSearch.Name = "btnSearch";
this.btnSearch.UseUnderline = true;
this.btnSearch.Label = global::Mono.Unix.Catalog.GetString ("Search");
this.frMain.Add (this.btnSearch);
global::Gtk.Fixed.FixedChild w12 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.btnSearch]));
w12.X = 323;
w12.Y = 247;
// Container child frMain.Gtk.Fixed+FixedChild
this.tbSearch = new global::Gtk.Entry ();
this.tbSearch.CanFocus = true;
this.tbSearch.Name = "tbSearch";
this.tbSearch.IsEditable = true;
this.tbSearch.InvisibleChar = '•';
this.frMain.Add (this.tbSearch);
global::Gtk.Fixed.FixedChild w13 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.tbSearch]));
w13.X = 315;
w13.Y = 213;
// Container child frMain.Gtk.Fixed+FixedChild
this.label1 = new global::Gtk.Label ();
this.label1.Name = "label1";
this.label1.LabelProp = global::Mono.Unix.Catalog.GetString ("Search");
this.frMain.Add (this.label1);
global::Gtk.Fixed.FixedChild w14 = ((global::Gtk.Fixed.FixedChild)(this.frMain[this.label1]));
w14.X = 318;
w14.Y = 179;
this.Add (this.frMain);
if ((this.Child != null)) {
this.Child.ShowAll ();
}
this.DefaultWidth = 836;
this.DefaultHeight = 684;
this.Show ();
this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent);
this.btnLogin2.Clicked += new global::System.EventHandler (this.OnBtnLogin2Clicked);
this.btnQueueSong.Clicked += new global::System.EventHandler (this.OnBtnQueueSongClicked);
this.btnSearch.Clicked += new global::System.EventHandler (this.OnBtnSearchClicked);
}
}

View File

@ -0,0 +1,29 @@
// This file has been generated by the GUI designer. Do not modify.
namespace Stetic
{
internal class Gui
{
private static bool initialized;
static internal void Initialize (Gtk.Widget iconRenderer)
{
if ((Stetic.Gui.initialized == false)) {
Stetic.Gui.initialized = true;
}
}
}
internal class ActionGroups
{
public static Gtk.ActionGroup GetActionGroup (System.Type type)
{
return Stetic.ActionGroups.GetActionGroup (type.FullName);
}
public static Gtk.ActionGroup GetActionGroup (string name)
{
return null;
}
}
}

View File

@ -0,0 +1,215 @@
<?xml version="1.0" encoding="utf-8"?>
<stetic-interface>
<configuration>
<images-root-path>..</images-root-path>
<target-gtk-version>2.12</target-gtk-version>
</configuration>
<import>
<widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
<widget-library name="../../../../MonoLibs/HollyLibrary.dll" />
<widget-library name="../bin/Debug/SubsonicMono.exe" internal="true" />
</import>
<widget class="Gtk.Window" id="MainWindow" design-size="836 684">
<property name="MemberName" />
<property name="Title" translatable="yes">MainWindow</property>
<property name="WindowPosition">CenterOnParent</property>
<signal name="DeleteEvent" handler="OnDeleteEvent" />
<child>
<widget class="Gtk.Fixed" id="frMain">
<property name="MemberName" />
<property name="HasWindow">False</property>
<child>
<widget class="Gtk.Label" id="lblTitle">
<property name="MemberName" />
<property name="LabelProp" translatable="yes">Subsonic</property>
</widget>
<packing>
<property name="X">9</property>
<property name="Y">10</property>
</packing>
</child>
<child>
<widget class="Gtk.Entry" id="tbServer">
<property name="MemberName" />
<property name="CanFocus">True</property>
<property name="IsEditable">True</property>
<property name="InvisibleChar">•</property>
</widget>
<packing>
<property name="X">9</property>
<property name="Y">71</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="lbServer">
<property name="MemberName" />
<property name="LabelProp" translatable="yes">Server URL:</property>
</widget>
<packing>
<property name="X">13</property>
<property name="Y">46</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="lblUsername">
<property name="MemberName" />
<property name="LabelProp" translatable="yes">Username:</property>
</widget>
<packing>
<property name="X">15</property>
<property name="Y">110</property>
</packing>
</child>
<child>
<widget class="Gtk.Entry" id="tbUsername">
<property name="MemberName" />
<property name="CanFocus">True</property>
<property name="IsEditable">True</property>
<property name="InvisibleChar">•</property>
</widget>
<packing>
<property name="X">11</property>
<property name="Y">138</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="lbPassw00rd">
<property name="MemberName" />
<property name="LabelProp" translatable="yes">Password:</property>
</widget>
<packing>
<property name="X">13</property>
<property name="Y">176</property>
</packing>
</child>
<child>
<widget class="Gtk.Entry" id="tbPaassw0rd">
<property name="MemberName" />
<property name="CanFocus">True</property>
<property name="IsEditable">True</property>
<property name="Visibility">False</property>
<property name="InvisibleChar">•</property>
</widget>
<packing>
<property name="X">13</property>
<property name="Y">199</property>
</packing>
</child>
<child>
<placeholder />
</child>
<child>
<placeholder />
</child>
<child>
<widget class="Gtk.ScrolledWindow" id="swLibrary">
<property name="MemberName" />
<property name="WidthRequest">262</property>
<property name="HeightRequest">348</property>
<property name="CanFocus">True</property>
<property name="ShadowType">In</property>
<child>
<widget class="Gtk.Viewport" id="GtkViewport">
<property name="MemberName" />
<property name="ShadowType">None</property>
<child>
<placeholder />
</child>
</widget>
</child>
</widget>
<packing>
<property name="X">10</property>
<property name="Y">295</property>
</packing>
</child>
<child>
<widget class="Gtk.Button" id="btnLogin2">
<property name="MemberName" />
<property name="CanFocus">True</property>
<property name="Type">TextOnly</property>
<property name="Label" translatable="yes">Login2</property>
<property name="UseUnderline">True</property>
<signal name="Clicked" handler="OnBtnLogin2Clicked" />
</widget>
<packing>
<property name="X">14</property>
<property name="Y">241</property>
</packing>
</child>
<child>
<widget class="Gtk.ScrolledWindow" id="swPlayQueue">
<property name="MemberName" />
<property name="WidthRequest">208</property>
<property name="HeightRequest">338</property>
<property name="CanFocus">True</property>
<property name="ShadowType">In</property>
<child>
<widget class="Gtk.Viewport" id="GtkViewport1">
<property name="MemberName" />
<property name="ShadowType">None</property>
<child>
<placeholder />
</child>
</widget>
</child>
</widget>
<packing>
<property name="X">315</property>
<property name="Y">296</property>
</packing>
</child>
<child>
<widget class="Gtk.Button" id="btnQueueSong">
<property name="MemberName" />
<property name="CanFocus">True</property>
<property name="Type">TextOnly</property>
<property name="Label" translatable="yes">&gt;</property>
<property name="UseUnderline">True</property>
<signal name="Clicked" handler="OnBtnQueueSongClicked" />
</widget>
<packing>
<property name="X">280</property>
<property name="Y">425</property>
</packing>
</child>
<child>
<widget class="Gtk.Button" id="btnSearch">
<property name="MemberName" />
<property name="CanFocus">True</property>
<property name="Type">TextOnly</property>
<property name="Label" translatable="yes">Search</property>
<property name="UseUnderline">True</property>
<signal name="Clicked" handler="OnBtnSearchClicked" />
</widget>
<packing>
<property name="X">323</property>
<property name="Y">247</property>
</packing>
</child>
<child>
<widget class="Gtk.Entry" id="tbSearch">
<property name="MemberName" />
<property name="CanFocus">True</property>
<property name="IsEditable">True</property>
<property name="InvisibleChar">•</property>
</widget>
<packing>
<property name="X">315</property>
<property name="Y">213</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="label1">
<property name="MemberName" />
<property name="LabelProp" translatable="yes">Search</property>
</widget>
<packing>
<property name="X">318</property>
<property name="Y">179</property>
</packing>
</child>
</widget>
</child>
</widget>
</stetic-interface>

View File

@ -0,0 +1,25 @@
<%@ Page Language="C#" Inherits="SubsonicWeb.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head runat="server">
<title>Default</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Panel id="pnlLogin" runat="server">
<div>
<asp:Label id="lblUsername" runat="server" AssociatedControlID="tbUsername">Username</asp:Label>
<br />
<asp:TextBox id="tbUsername" runat="server" />
<br />
<br />
<asp:Label id="lblPassword" runat="server" AssociatedControlID="tbPassword">Password</asp:Label>
<br />
<asp:TextBox id="tbPassword" runat="server" TextMode="Password" />
<br />
<asp:Button id="btnLogIn" runat="server" OnClick="btnLogIn_Click" Text="Login" />
</div>
</asp:Panel>
</form>
</body>
</html>

View File

@ -0,0 +1,29 @@
using System;
using System.Web;
using System.Web.UI;
using SubsonicAPI;
namespace SubsonicWeb
{
public partial class Default : System.Web.UI.Page
{
protected void btnLogIn_Click (object sender, System.EventArgs e)
{
string server = "thefij.kicks-ass.net:4040";
string username = tbUsername.Text;
string password = tbPassword.Text;
Subsonic.appName = "IansWebApp";
string results = Subsonic.LogIn(server, username, password);
if (results != "")
Response.Redirect("Library.aspx");
}
}
}

View File

@ -0,0 +1,30 @@
// ------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Mono Runtime Version: 2.0.50727.1433
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
// ------------------------------------------------------------------------------
namespace SubsonicWeb {
public partial class Default {
protected System.Web.UI.HtmlControls.HtmlForm form1;
protected System.Web.UI.WebControls.Panel pnlLogin;
protected System.Web.UI.WebControls.Label lblUsername;
protected System.Web.UI.WebControls.TextBox tbUsername;
protected System.Web.UI.WebControls.Label lblPassword;
protected System.Web.UI.WebControls.TextBox tbPassword;
protected System.Web.UI.WebControls.Button btnLogIn;
}
}

View File

@ -0,0 +1 @@
<%@ Application Inherits="SubsonicWeb.Global" %>

View File

@ -0,0 +1,49 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.SessionState;
namespace SubsonicWeb
{
public class Global : System.Web.HttpApplication
{
protected virtual void Application_Start (Object sender, EventArgs e)
{
}
protected virtual void Session_Start (Object sender, EventArgs e)
{
}
protected virtual void Application_BeginRequest (Object sender, EventArgs e)
{
}
protected virtual void Application_EndRequest (Object sender, EventArgs e)
{
}
protected virtual void Application_AuthenticateRequest (Object sender, EventArgs e)
{
}
protected virtual void Application_Error (Object sender, EventArgs e)
{
}
protected virtual void Session_End (Object sender, EventArgs e)
{
}
protected virtual void Application_End (Object sender, EventArgs e)
{
}
}
}

View File

@ -0,0 +1,32 @@
<%@ Page Language="C#" Inherits="SubsonicWeb.Library" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head runat="server">
<title>Library</title>
</head>
<body>
<form id="form1" runat="server">
<table>
<tr>
<td>
<asp:Repeater id="rptArtists" runat="server" OnItemDataBound="rptArtists_ItemDataBound">
<ItemTemplate>
<asp:LinkButton id="lbtnArtist" runat="server" />
<asp:HyperLink id="hlnkArtist" runat="server" />
<br />
</ItemTemplate>
</asp:Repeater>
</td>
<td>
<asp:Label id="lblSelArtist" runat="server">Select an Artist</asp:Label>
<asp:Repeater id="rptItems" runat="server">
<ItemTemplate>
</ItemTemplate>
</asp:Repeater>
</td>
</tr>
</table>
</form>
</body>
</html>

View File

@ -0,0 +1,82 @@
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using SubsonicAPI;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using Mono.Data.Sqlite;
namespace SubsonicWeb
{
public partial class Library : System.Web.UI.Page
{
protected override void OnLoad (EventArgs e)
{
base.OnLoad (e);
DataTable dtArtists = new DataTable();
#region fetch data for artists
Mono.Data.Sqlite.SqliteConnection cn = new Mono.Data.Sqlite.SqliteConnection("library.sqlite");
Mono.Data.Sqlite.SqliteCommand comm = new Mono.Data.Sqlite.SqliteCommand(cn);
Mono.Data.Sqlite.SqliteDataAdapter adapter = new Mono.Data.Sqlite.SqliteDataAdapter(comm);
comm.CommandText = @"
SELECT name, id, fetched
FROM artists
";
adapter.Fill(dtArtists);
#endregion
if (dtArtists.Rows.Count == 0)
{
List<SubsonicItem> artists = Subsonic.GetIndexes();
foreach (SubsonicItem artist in artists)
{
DataRow dr = dtArtists.NewRow();
dr["name"] = artist.name;
dr["id"] = artist.id;
dr["feteched"] = DateTime.Now.ToString();
dtArtists.Rows.Add(dr);
comm = new Mono.Data.Sqlite.SqliteCommand(cn);
comm.CommandText = @"
INSERT INTO artists (name, id, fetched)
VALUES(@name, @id, @fetched);
";
comm.Parameters.AddWithValue("@name", artist.name);
comm.Parameters.AddWithValue("@id", artist.id);
comm.Parameters.AddWithValue("@fetched", DateTime.Now.ToString());
if (cn.State != ConnectionState.Open)
cn.Open();
comm.ExecuteNonQuery();
}
if (cn.State != ConnectionState.Closed)
cn.Close();
}
rptArtists.DataSource = dtArtists;
rptArtists.DataBind();
}
protected void rptArtists_ItemDataBound (object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
HyperLink hlnkArtist = (HyperLink)e.Item.FindControl("hlnkArtist");
}
}
}
}

View File

@ -0,0 +1,28 @@
// ------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Mono Runtime Version: 2.0.50727.1433
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
// ------------------------------------------------------------------------------
namespace SubsonicWeb {
public partial class Library {
protected System.Web.UI.HtmlControls.HtmlForm form1;
protected System.Web.UI.WebControls.Repeater rptArtists;
protected System.Web.UI.WebControls.LinkButton lbtnArtist;
protected System.Web.UI.WebControls.HyperLink hlnkArtist;
protected System.Web.UI.WebControls.Label lblSelArtist;
protected System.Web.UI.WebControls.Repeater rptItems;
}
}

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProductVersion>9.0.21022</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{91BB17F9-5F24-4329-BA99-8A96B800416E}</ProjectGuid> <ProjectTypeGuids>{349C5851-65DF-11DA-9384-00065B846F21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <OutputType>Library</OutputType> <RootNamespace>SubsonicWeb</RootNamespace> <AssemblyName>SubsonicWeb</AssemblyName> <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin</OutputPath> <DefineConstants>DEBUG</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <ConsolePause>false</ConsolePause> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>none</DebugType> <Optimize>false</Optimize> <OutputPath>bin</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <ConsolePause>false</ConsolePause> </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Web" /> <Reference Include="System.Xml" /> <Reference Include="System.Web.Services" /> <Reference Include="Mono.Data" /> <Reference Include="System.Data" /> <Reference Include="Mono.Data.Sqlite" /> <Reference Include="Mono.Data.SqliteClient" /> </ItemGroup> <ItemGroup> <Content Include="Global.asax" /> <Content Include="web.config" /> <Content Include="Default.aspx" /> <Content Include="Library.aspx" /> </ItemGroup> <ItemGroup> <Compile Include="Global.asax.cs"> <DependentUpon>Global.asax</DependentUpon> </Compile> <Compile Include="Default.aspx.cs"> <DependentUpon>Default.aspx</DependentUpon> </Compile> <Compile Include="Default.aspx.designer.cs"> <DependentUpon>Default.aspx</DependentUpon> </Compile> <Compile Include="Library.aspx.cs"> <DependentUpon>Library.aspx</DependentUpon> </Compile> <Compile Include="Library.aspx.designer.cs"> <DependentUpon>Library.aspx</DependentUpon> </Compile> </ItemGroup> <ItemGroup> <ProjectReference Include="..\SubsonicAPI\SubsonicAPI.csproj"> <Project>{AD32EC84-3CE8-4E20-934E-6B4F40A9BC08}</Project> <Name>SubsonicAPI</Name> </ProjectReference> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" /> <ProjectExtensions> <MonoDevelop> <Properties VerifyCodeBehindFields="true" VerifyCodeBehindEvents="true" xmlns=""> <XspParameters Port="8080" Address="127.0.0.1" SslMode="None" SslProtocol="Default" KeyType="None" CertFile="" KeyFile="" PasswordOptions="None" Password="" Verbose="true" /> </Properties> </MonoDevelop> </ProjectExtensions> </Project>

Binary file not shown.

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<!--
Web.config file for SubsonicWeb.
The settings that can be used in this file are documented at
http://www.mono-project.com/Config_system.web and
http://msdn2.microsoft.com/en-us/library/b5ysx397.aspx
-->
<configuration>
<system.web>
<compilation defaultLanguage="C#" debug="true">
<assemblies>
<add assembly="Mono.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
<add assembly="Mono.Data.Sqlite, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
<add assembly="Mono.Data.SqliteClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
</assemblies>
</compilation>
<customErrors mode="RemoteOnly">
</customErrors>
<authentication mode="None">
</authentication>
<authorization>
<allow users="*" />
</authorization>
<httpHandlers>
</httpHandlers>
<trace enabled="false" localOnly="true" pageOutput="false" requestLimit="10" traceMode="SortByTime" />
<sessionState mode="InProc" cookieless="false" timeout="20" />
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
<pages>
</pages>
</system.web>
</configuration>

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SubsonicAPI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("IBM")]
[assembly: AssemblyProduct("SubsonicAPI")]
[assembly: AssemblyCopyright("Copyright © IBM 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("cfc7a286-1cf6-4b0d-a011-fb2a3abcbb9a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,383 @@
/**************************************************************************
Subsonic Csharp
Copyright (C) 2010 Ian Fijolek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
namespace SubsonicAPI
{
#region Classes
public class SubsonicItem
{
public string Name;
public string id;
public enum SubsonicItemType
{
Folder, Song
}
public SubsonicItemType ItemType;
public override string ToString()
{
return Name;
}
}
public class MusicFolder : SubsonicItem
{
#region private vars
private List<MusicFolder> _Folders;
private List<Song> _Songs;
#endregion private vars
#region properties
public List<MusicFolder> Folders
{
get { return _Folders; }
set { _Folders = value; }
}
public List<Song> Songs
{
get { return _Songs; }
set { _Songs = value; }
}
#endregion properties
public MusicFolder()
{
_Folders = new List<MusicFolder>();
_Songs = new List<Song>();
base.ItemType = SubsonicItemType.Folder;
}
public MusicFolder(string theName, string theId)
{
_Folders = new List<MusicFolder>();
_Songs = new List<Song>();
base.Name = theName;
base.id = theId;
base.ItemType = SubsonicItemType.Folder;
}
~MusicFolder() { }
public void AddSong(string title, string id)
{
Song newSong = new Song(title, id);
_Songs.Add(newSong);
}
public void AddFolder(string name, string id)
{
MusicFolder newFolder = new MusicFolder(name, id);
_Folders.Add(newFolder);
}
public Song FindSong(string theTitle)
{
Song theSong = _Songs.Find(
delegate(Song sng)
{
return sng.Name == theTitle;
}
);
return theSong;
}
public MusicFolder FindFolder(string theFolderName)
{
MusicFolder theFolder = _Folders.Find(
delegate(MusicFolder fldr)
{
return fldr.Name == theFolderName;
}
);
return theFolder;
}
}
public class Song : SubsonicItem
{
public Song()
{
base.ItemType = SubsonicItemType.Song;
}
public Song(string theTitle, string theId)
{
Name = theTitle;
id = theId;
base.ItemType = SubsonicItemType.Song;
}
}
#endregion Classes
/// <summary>
/// Open Source C# Implementation of the Subsonic API
/// http://www.subsonic.org/pages/api.jsp
/// </summary>
public static class Subsonic
{
// Should be set from application layer when the application is loaded
public static string appName;
// Version of the REST API implemented
private static string apiVersion = "1.3.0";
// Set with the login method
static string server;
static string authHeader;
/// <summary>
/// Takes parameters for server, username and password to generate an auth header
/// and Pings the server
/// </summary>
/// <param name="theServer"></param>
/// <param name="user"></param>
/// <param name="password"></param>
/// <returns>Resulting XML (Future boolean)</returns>
public static string LogIn(string theServer, string user, string password)
{
string result = "Nothing Happened";
server = theServer;
authHeader = user + ":" + password;
authHeader = Convert.ToBase64String(Encoding.Default.GetBytes(authHeader));
Stream theStream = MakeGenericRequest("ping", null);
StreamReader sr = new StreamReader(theStream);
result = sr.ReadToEnd();
/// TODO: Parse the result and determine if logged in or not
return result;
}
/// <summary>
/// Uses the Auth Header for logged in user to make an HTTP request to the server
/// with the given Subsonic API method and parameters
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns>Datastream of the server response</returns>
public static Stream MakeGenericRequest(string method, Dictionary<string, string> parameters)
{
// Check to see if Logged In yet
if (string.IsNullOrEmpty(authHeader))
{
// Throw a Not Logged In exception
Exception e = new Exception("No Authorization header. Must Log In first");
return null;
}
else
{
if (!method.EndsWith(".view"))
method += ".view";
string requestURL = BuildRequestURL(method, parameters);
WebRequest theRequest = WebRequest.Create(requestURL);
theRequest.Method = "GET";
theRequest.Headers["Authorization"] = "Basic " + authHeader;
WebResponse response = theRequest.GetResponse();
Stream dataStream = response.GetResponseStream();
return dataStream;
}
}
/// <summary>
/// Creates a URL for a request but does not make the actual request using set login credentials an dmethod and parameters
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns>Proper Subsonic API URL for a request</returns>
public static string BuildRequestURL(string method, Dictionary<string, string> parameters)
{
string requestURL = "http://" + server + "/rest/" + method + "?v=" + apiVersion + "&c=" + appName;
if (parameters != null)
{
foreach (KeyValuePair<string, string> parameter in parameters)
{
requestURL += "&" + parameter.Key + "=" + parameter.Value;
}
}
return requestURL;
}
/// <summary>
/// Returns an indexed structure of all artists.
/// </summary>
/// <param name="musicFolderId">Required: No; If specified, only return artists in the music folder with the given ID.</param>
/// <param name="ifModifiedSince">Required: No; If specified, only return a result if the artist collection has changed since the given time.</param>
/// <returns>Dictionary, Key = Artist and Value = id</returns>
public static Dictionary<string, string> GetIndexes(string musicFolderId = "", string ifModifiedSince = "")
{
// Load the parameters if provided
Dictionary<string, string> parameters = new Dictionary<string, string>();
if (!string.IsNullOrEmpty(musicFolderId))
parameters.Add("musicFolderId", musicFolderId);
if (!string.IsNullOrEmpty(ifModifiedSince))
parameters.Add("ifModifiedSince", ifModifiedSince);
// Make the request
Stream theStream = MakeGenericRequest("getIndexes", parameters);
// Read the response as a string
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
// Parse the resulting XML string into an XmlDocument
XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result);
// Parse the XML document into a Dictionary
Dictionary<string, string> artists = new Dictionary<string, string>();
if (myXML.ChildNodes[1].Name == "subsonic-response")
{
if (myXML.ChildNodes[1].FirstChild.Name == "indexes")
{
int i = 0;
for (i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
{
int j = 0;
for (j = 0; j < myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes.Count; j++)
{
string artist = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["name"].Value;
string id = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["id"].Value;
artists.Add(artist, id);
}
}
}
}
return artists;
}
/// <summary>
/// Streams a given music file. (Renamed from request name "stream")
/// </summary>
/// <param name="id">Required: Yes; A string which uniquely identifies the file to stream.
/// Obtained by calls to getMusicDirectory.</param>
/// <param name="maxBitRate">Required: No; If specified, the server will attempt to
/// limit the bitrate to this value, in kilobits per second. If set to zero, no limit
/// is imposed. Legal values are: 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 and 320. </param>
/// <returns></returns>
public static Stream StreamSong(string id, int? maxBitRate = null)
{
// Reades the id of the song and sets it as a parameter
Dictionary<string, string> theParameters = new Dictionary<string,string>();
theParameters.Add("id", id);
if (maxBitRate.HasValue)
theParameters.Add("maxBitRate", maxBitRate.ToString());
// Makes the request
Stream theStream = MakeGenericRequest("stream", theParameters);
return theStream;
}
/// <summary>
/// Returns a listing of all files in a music directory. Typically used to get list of albums for an artist, or list of songs for an album.
/// </summary>
/// <param name="id">A string which uniquely identifies the music folder. Obtained by calls to getIndexes or getMusicDirectory.</param>
/// <returns>MusicFolder object containing info for the specified directory</returns>
public static MusicFolder GetMusicDirectory(string id)
{
Dictionary<string, string> theParameters = new Dictionary<string, string>();
theParameters.Add("id", id);
Stream theStream = MakeGenericRequest("getMusicDirectory", theParameters);
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result);
MusicFolder theFolder = new MusicFolder("ArtistFolder", id);
if (myXML.ChildNodes[1].Name == "subsonic-response")
{
if (myXML.ChildNodes[1].FirstChild.Name == "directory")
{
theFolder.Name = myXML.ChildNodes[1].FirstChild.Attributes["name"].Value;
theFolder.id = myXML.ChildNodes[1].FirstChild.Attributes["id"].Value;
int i = 0;
for (i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
{
bool isDir = bool.Parse(myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["isDir"].Value);
string title = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["title"].Value;
string theId = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["id"].Value;
if (isDir)
theFolder.AddFolder(title, theId);
else
theFolder.AddSong(title, theId);
}
}
}
return theFolder;
}
/// <summary>
/// Returns what is currently being played by all users. Takes no extra parameters.
/// </summary>
public static List<Song> GetNowPlaying()
{
List<Song> nowPlaying = new List<Song>();
Dictionary<string, string> theParameters = new Dictionary<string, string>();
Stream theStream = MakeGenericRequest("getNowPlaying", theParameters);
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
return nowPlaying;
}
}
}

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SubsonicAPI</RootNamespace>
<AssemblyName>SubsonicAPI</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SubsonicAPI.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Binary file not shown.

View File

@ -0,0 +1,42 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual C# Express 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SubsonicPlayer", "SubsonicPlayer\SubsonicPlayer.csproj", "{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SubsonicAPI", "SubsonicAPI\SubsonicAPI.csproj", "{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Debug|Any CPU.ActiveCfg = Debug|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Debug|Mixed Platforms.Build.0 = Debug|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Debug|x86.ActiveCfg = Debug|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Debug|x86.Build.0 = Debug|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Release|Any CPU.ActiveCfg = Release|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Release|Mixed Platforms.ActiveCfg = Release|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Release|Mixed Platforms.Build.0 = Release|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Release|x86.ActiveCfg = Release|x86
{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}.Release|x86.Build.0 = Release|x86
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Debug|x86.ActiveCfg = Debug|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Release|Any CPU.Build.0 = Release|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Binary file not shown.

View File

@ -0,0 +1,13 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" ctype="Workspace" />
<MonoDevelop.Ide.Workbench ActiveDocument="SubsonicPlayer/PlayerForm.cs" ctype="Workbench">
<Files>
<File FileName="SubsonicPlayer/Program.cs" Line="1" Column="1" />
<File FileName="SubsonicPlayer/PlayerForm.cs" Line="203" Column="36" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MonoDevelop.Ide.DebuggingService.PinnedWatches ctype="PinnedWatchStore" />
</Properties>

View File

@ -0,0 +1,285 @@
namespace WindowsFormsApplication1
{
partial class PlayerForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.tbServer = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.tbPassword = new System.Windows.Forms.TextBox();
this.tbUser = new System.Windows.Forms.TextBox();
this.btnLogIn = new System.Windows.Forms.Button();
this.tbResults = new System.Windows.Forms.RichTextBox();
this.btnGetSongs = new System.Windows.Forms.Button();
this.tvArtists = new System.Windows.Forms.TreeView();
this.label5 = new System.Windows.Forms.Label();
this.lbAlbums = new System.Windows.Forms.ListBox();
this.label6 = new System.Windows.Forms.Label();
this.button1 = new System.Windows.Forms.Button();
this.lbPlaylist = new System.Windows.Forms.ListBox();
this.label7 = new System.Windows.Forms.Label();
this.pbSongProgress = new System.Windows.Forms.ProgressBar();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// tbServer
//
this.tbServer.Location = new System.Drawing.Point(82, 35);
this.tbServer.Name = "tbServer";
this.tbServer.Size = new System.Drawing.Size(100, 20);
this.tbServer.TabIndex = 0;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(13, 13);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(82, 13);
this.label1.TabIndex = 1;
this.label1.Text = "SubSonic Login";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(20, 42);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(41, 13);
this.label2.TabIndex = 2;
this.label2.Text = "Server:";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(20, 78);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(32, 13);
this.label3.TabIndex = 3;
this.label3.Text = "User:";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(20, 114);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(56, 13);
this.label4.TabIndex = 4;
this.label4.Text = "Password:";
//
// tbPassword
//
this.tbPassword.Location = new System.Drawing.Point(82, 107);
this.tbPassword.Name = "tbPassword";
this.tbPassword.PasswordChar = '*';
this.tbPassword.Size = new System.Drawing.Size(100, 20);
this.tbPassword.TabIndex = 2;
//
// tbUser
//
this.tbUser.Location = new System.Drawing.Point(82, 75);
this.tbUser.Name = "tbUser";
this.tbUser.Size = new System.Drawing.Size(100, 20);
this.tbUser.TabIndex = 1;
//
// btnLogIn
//
this.btnLogIn.Location = new System.Drawing.Point(23, 150);
this.btnLogIn.Name = "btnLogIn";
this.btnLogIn.Size = new System.Drawing.Size(75, 23);
this.btnLogIn.TabIndex = 3;
this.btnLogIn.Text = "Log In";
this.btnLogIn.UseVisualStyleBackColor = true;
this.btnLogIn.Click += new System.EventHandler(this.btnLogIn_Click);
//
// tbResults
//
this.tbResults.Location = new System.Drawing.Point(23, 499);
this.tbResults.Name = "tbResults";
this.tbResults.Size = new System.Drawing.Size(278, 131);
this.tbResults.TabIndex = 99;
this.tbResults.Text = "";
//
// btnGetSongs
//
this.btnGetSongs.Enabled = false;
this.btnGetSongs.Location = new System.Drawing.Point(107, 150);
this.btnGetSongs.Name = "btnGetSongs";
this.btnGetSongs.Size = new System.Drawing.Size(75, 23);
this.btnGetSongs.TabIndex = 4;
this.btnGetSongs.Text = "Get Songs";
this.btnGetSongs.UseVisualStyleBackColor = true;
this.btnGetSongs.Click += new System.EventHandler(this.btnGetSongs_Click);
//
// tvArtists
//
this.tvArtists.Location = new System.Drawing.Point(16, 200);
this.tvArtists.Name = "tvArtists";
this.tvArtists.Size = new System.Drawing.Size(281, 248);
this.tvArtists.TabIndex = 101;
this.tvArtists.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.tvArtists_AfterSelect);
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(13, 183);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(35, 13);
this.label5.TabIndex = 102;
this.label5.Text = "Artists";
//
// lbAlbums
//
this.lbAlbums.FormattingEnabled = true;
this.lbAlbums.Location = new System.Drawing.Point(303, 200);
this.lbAlbums.Name = "lbAlbums";
this.lbAlbums.Size = new System.Drawing.Size(212, 251);
this.lbAlbums.TabIndex = 103;
this.lbAlbums.SelectedIndexChanged += new System.EventHandler(this.lbAlbums_SelectedIndexChanged);
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(307, 186);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(41, 13);
this.label6.TabIndex = 104;
this.label6.Text = "Albums";
//
// button1
//
this.button1.Location = new System.Drawing.Point(188, 150);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 105;
this.button1.Text = "Pause";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// lbPlaylist
//
this.lbPlaylist.FormattingEnabled = true;
this.lbPlaylist.Location = new System.Drawing.Point(522, 200);
this.lbPlaylist.Name = "lbPlaylist";
this.lbPlaylist.Size = new System.Drawing.Size(154, 251);
this.lbPlaylist.TabIndex = 106;
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(524, 186);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(39, 13);
this.label7.TabIndex = 107;
this.label7.Text = "Playlist";
//
// pbSongProgress
//
this.pbSongProgress.Location = new System.Drawing.Point(373, 149);
this.pbSongProgress.Name = "pbSongProgress";
this.pbSongProgress.Size = new System.Drawing.Size(289, 23);
this.pbSongProgress.TabIndex = 108;
//
// button2
//
this.button2.Location = new System.Drawing.Point(270, 149);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 109;
this.button2.Text = "Skip";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(270, 120);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(75, 23);
this.button3.TabIndex = 110;
this.button3.Text = "Stop";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// PlayerForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(688, 633);
this.Controls.Add(this.button3);
this.Controls.Add(this.button2);
this.Controls.Add(this.pbSongProgress);
this.Controls.Add(this.label7);
this.Controls.Add(this.lbPlaylist);
this.Controls.Add(this.button1);
this.Controls.Add(this.label6);
this.Controls.Add(this.lbAlbums);
this.Controls.Add(this.label5);
this.Controls.Add(this.tvArtists);
this.Controls.Add(this.btnGetSongs);
this.Controls.Add(this.tbResults);
this.Controls.Add(this.btnLogIn);
this.Controls.Add(this.tbUser);
this.Controls.Add(this.tbPassword);
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.tbServer);
this.Name = "PlayerForm";
this.Text = "Subsonic";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox tbServer;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox tbPassword;
private System.Windows.Forms.TextBox tbUser;
private System.Windows.Forms.Button btnLogIn;
private System.Windows.Forms.RichTextBox tbResults;
private System.Windows.Forms.Button btnGetSongs;
private System.Windows.Forms.TreeView tvArtists;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.ListBox lbAlbums;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.ListBox lbPlaylist;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.ProgressBar pbSongProgress;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;
}
}

View File

@ -0,0 +1,574 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Media;
using System.IO;
using NAudio.Wave;
using System.Threading;
using SubsonicAPI;
namespace WindowsFormsApplication1
{
public partial class PlayerForm : Form
{
public PlayerForm()
{
InitializeComponent();
Subsonic.appName = "IansCsharpApp";
}
private void btnLogIn_Click(object sender, EventArgs e)
{
string server = tbServer.Text;
string user = tbUser.Text;
string password = tbPassword.Text;
string result = Subsonic.LogIn(server, user, password);
tbResults.Text = result;
btnGetSongs.Enabled = true;
}
Dictionary<string, string> artists;
private void btnGetSongs_Click(object sender, EventArgs e)
{
artists = Subsonic.GetIndexes();
tvArtists.BeginUpdate();
string firstLetter = "";
int treeIndex = -1;
foreach (KeyValuePair<string, string> kvp in artists)
{
string thisFirstLetter = GetFirstLetter(kvp.Key);
if (thisFirstLetter != firstLetter)
{
firstLetter = thisFirstLetter;
tvArtists.Nodes.Add(firstLetter);
treeIndex++;
}
tvArtists.Nodes[treeIndex].Nodes.Add(kvp.Key);
}
tvArtists.EndUpdate();
}
private string GetFirstLetter(string name)
{
name = name.ToUpper();
string theFirstLetter = "";
if (name.StartsWith("THE "))
theFirstLetter = name.Substring(4, 1);
else if (name.StartsWith("LOS "))
theFirstLetter = name.Substring(4, 1);
else if (name.StartsWith("LAS "))
theFirstLetter = name.Substring(4, 1);
else if (name.StartsWith("LA "))
theFirstLetter = name.Substring(3, 1);
else
theFirstLetter = name.Substring(0, 1); // No leading word
return theFirstLetter.ToUpper();
}
private void tvArtists_AfterSelect(object sender, TreeViewEventArgs e)
{
string theArtist = tvArtists.SelectedNode.Text;
if (artists.ContainsKey(theArtist))
{
string theID = artists[theArtist];
UpdateAlbumListView(theID);
}
}
Stack<string> _AlbumListHistory;
public Stack<string> AlbumListHistory
{
get
{
if (_AlbumListHistory == null)
{
_AlbumListHistory = new Stack<string>();
_AlbumListHistory.Push("Root");
}
return _AlbumListHistory;
}
set
{
_AlbumListHistory = value;
}
}
string _LastAlbumId;
public string LastAlbumId
{
get
{
if (string.IsNullOrEmpty(_LastAlbumId))
_LastAlbumId = "Root";
return _LastAlbumId;
}
set
{
_LastAlbumId = value;
}
}
private void UpdateAlbumListView(string theID)
{
LastAlbumId = theID;
MusicFolder FolderContents = Subsonic.GetMusicDirectory(theID);
lbAlbums.BeginUpdate();
lbAlbums.Items.Clear();
if (AlbumListHistory.Peek() != "Root")
lbAlbums.Items.Add(new MusicFolder("..", AlbumListHistory.Peek()));
foreach (MusicFolder mf in FolderContents.Folders)
{
lbAlbums.Items.Add(mf);
}
foreach (Song sg in FolderContents.Songs)
{
lbAlbums.Items.Add(sg);
}
lbAlbums.EndUpdate();
}
MusicPlayer _thePlayer;
private MusicPlayer thePlayer
{
get
{
if (_thePlayer == null)
_thePlayer = new MusicPlayer(this);
return _thePlayer;
}
set
{
_thePlayer = value;
}
}
private void lbAlbums_SelectedIndexChanged(object sender, EventArgs e)
{
SubsonicItem theItem = (SubsonicItem)lbAlbums.SelectedItem;
if (theItem.ItemType == SubsonicItem.SubsonicItemType.Folder)
{
if (theItem.Name == "..")
AlbumListHistory.Pop();
else
AlbumListHistory.Push(LastAlbumId);
UpdateAlbumListView(theItem.id);
}
else if (theItem.ItemType == SubsonicItem.SubsonicItemType.Song)
{
thePlayer.addToPlaylist((Song)theItem);
thePlayer.play();
}
}
private void button1_Click(object sender, EventArgs e)
{
thePlayer.pause();
}
public void updatePlaylist(Queue<Song> playlist)
{
lbPlaylist.BeginUpdate();
lbPlaylist.Items.Clear();
foreach (Song sng in playlist)
{
lbPlaylist.Items.Add(sng);
}
lbPlaylist.EndUpdate();
}
public void updateSongProgress(int progress)
{
if (progress > 100)
progress = 100;
pbSongProgress.Value = progress;
}
private void button2_Click(object sender, EventArgs e)
{
thePlayer.skipSong();
}
private void button3_Click(object sender, EventArgs e)
{
thePlayer.stop();
}
}
public class MusicPlayer
{
private Song currentSong;
private Queue<Song> playlist;
private BackgroundWorker playerThread;
public PlaybackState playState;
private PlayerForm mainForm;
public MusicPlayer()
{
}
public MusicPlayer(PlayerForm theMainForm)
{
mainForm = theMainForm;
}
/// <summary>
/// Public method called by the main view to start playing the playlist
/// </summary>
public void play()
{
// If there is no backgroundworker initialized, do that
if (playerThread == null)
{
playerThread = new BackgroundWorker();
playerThread.DoWork += new DoWorkEventHandler(playerThread_DoWork);
playerThread.ProgressChanged += new ProgressChangedEventHandler(playerThread_ProgressChanged);
playerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(playerThread_RunWorkerCompleted);
playerThread.WorkerReportsProgress = true;
}
// Set state to playing
this.playState = PlaybackState.Playing;
// start playing the entire queue
playQueue();
}
private void playQueue()
{
if (playlist.Count > 0 && this.playState == PlaybackState.Playing)
{
currentSong = playlist.Peek();
if (waveOut == null || waveOut.PlaybackState != PlaybackState.Playing)
NewPlaySong();
// If the player is not busy yet then start it
if (!playerThread.IsBusy)
playerThread.RunWorkerAsync();
}
else
{
this.playState = PlaybackState.Stopped;
}
}
IWavePlayer waveOut;
WaveStream mainOutputStream;
WaveChannel32 volumeStream;
private void NewPlaySong()
{
if (waveOut != null)
{
if (waveOut.PlaybackState == PlaybackState.Playing)
{
return;
}
else if (waveOut.PlaybackState == PlaybackState.Paused)
{
waveOut.Play();
return;
}
}
else
{
CreateWaveOut();
mainOutputStream = CreateInputStream();
//trackBarPosition.Maximum = (int)mainOutputStream.TotalTime.TotalSeconds;
//labelTotalTime.Text = String.Format("{0:00}:{1:00}", (int)mainOutputStream.TotalTime.TotalMinutes,
// mainOutputStream.TotalTime.Seconds);
//trackBarPosition.TickFrequency = trackBarPosition.Maximum / 30;
waveOut.Init(mainOutputStream);
volumeStream.Volume = 15; //volumeSlider1.Volume;
waveOut.Play();
}
}
private WaveStream CreateInputStream()
{
WaveChannel32 inputStream;
Stream stream = Subsonic.StreamSong(currentSong.id);
// Try to move this filling of memory stream into the background...
Stream ms = new MemoryStream();
byte[] buffer = new byte[32768];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
playerThread.ReportProgress(50);
ms.Write(buffer, 0, read);
}
ms.Position = 0;
WaveStream mp3Reader = new Mp3FileReader(ms);
WaveStream pcmStream = WaveFormatConversionStream.CreatePcmStream(mp3Reader);
WaveStream blockAlignedStream = new BlockAlignReductionStream(pcmStream);
inputStream = new WaveChannel32(blockAlignedStream);
// we are not going into a mixer so we don't need to zero pad
//((WaveChannel32)inputStream).PadWithZeroes = false;
volumeStream = inputStream;
//var meteringStream = new MeteringStream(inputStream, inputStream.WaveFormat.SampleRate / 10);
//meteringStream.StreamVolume += new EventHandler<StreamVolumeEventArgs>(meteringStream_StreamVolume);
return volumeStream;
}
private void CreateWaveOut()
{
CloseWaveOut();
if (true)
{
WaveCallbackInfo callbackInfo = WaveCallbackInfo.FunctionCallback();
WaveOut outputDevice = new WaveOut(callbackInfo);
//outputDevice.NumberOfBuffers = 1;
//outputDevice.DesiredLatency = latency;
waveOut = outputDevice;
}
}
private void CloseWaveOut()
{
if (waveOut != null)
{
waveOut.Stop();
}
if (mainOutputStream != null)
{
// this one really closes the file and ACM conversion
volumeStream.Close();
volumeStream = null;
// this one does the metering stream
mainOutputStream.Close();
mainOutputStream = null;
}
if (waveOut != null)
{
waveOut.Dispose();
waveOut = null;
}
}
/// <summary>
/// Defines what should be done when the playerThread starts working
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void playerThread_DoWork(object sender, DoWorkEventArgs e)
{
//playSong();
TrackPlayer();
}
/// <summary>
/// Updates the main thread on the progress of the player thread
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void playerThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
mainForm.updateSongProgress(e.ProgressPercentage);
}
/// <summary>
/// Defines what should be done when the player thread finishes working
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void playerThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
SongFinished();
}
private void SongFinished()
{
// Remove the top song from the playlist
currentSong = playlist.Dequeue();
// Update the mainform playlist
mainForm.updatePlaylist(playlist);
// Start playing the next song
if (playState == PlaybackState.Playing)
playQueue();
}
private void TrackPlayer()
{
while (waveOut != null && waveOut.PlaybackState != PlaybackState.Stopped)
{
int progress = (int)((double)mainOutputStream.CurrentTime.TotalSeconds * 100.0 / (double)mainOutputStream.TotalTime.TotalSeconds);
playerThread.ReportProgress(progress);
Thread.Sleep(100);
}
}
/// <summary>
/// Public method to add a song to the playlist
/// </summary>
/// <param name="theSong"></param>
public void addToPlaylist(Song theSong)
{
if (playlist == null)
playlist = new Queue<Song>();
playlist.Enqueue(theSong);
// Update the playlist on the main form
mainForm.updatePlaylist(playlist);
}
bool skipThis;
/// <summary>
/// Method that plays whatever the current song is
/// </summary>
private void playSong()
{
skipThis = false;
Stream stream = Subsonic.StreamSong(currentSong.id);
// Try to move this filling of memory stream into the background...
Stream ms = new MemoryStream();
byte[] buffer = new byte[32768];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
playerThread.ReportProgress(50);
ms.Write(buffer, 0, read);
}
ms.Position = 0;
Mp3FileReader mp3Reader = new Mp3FileReader(ms);
WaveStream blockAlignedStream =
new BlockAlignReductionStream(
WaveFormatConversionStream.CreatePcmStream(mp3Reader));
WaveOut waveOut;
waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback());
waveOut.Init(blockAlignedStream);
waveOut.Play();
playState = PlaybackState.Playing;
bool songEnd = false;
while (playState != PlaybackState.Stopped && !songEnd && !skipThis)
{
if (waveOut.PlaybackState == PlaybackState.Stopped)
songEnd = true;
else
{
switch (playState)
{
case PlaybackState.Paused:
waveOut.Pause();
break;
case PlaybackState.Playing:
if (waveOut.PlaybackState != PlaybackState.Playing)
waveOut.Play();
else
{
int progress = (int)(100.0 * mp3Reader.CurrentTime.TotalSeconds / mp3Reader.TotalTime.TotalSeconds);
playerThread.ReportProgress(progress);
Thread.Sleep(100);
}
break;
default:
break;
}
}
}
//if (playState == PlaybackState.Stopped)
waveOut.Stop();
//waveOut.Dispose();
}
internal void pause()
{
//if (playState == PlaybackState.Playing)
// playState = PlaybackState.Paused;
//else if (playState == PlaybackState.Paused)
// playState = PlaybackState.Playing;
if (waveOut != null)
{
if (waveOut.PlaybackState == PlaybackState.Playing)
{
playState = PlaybackState.Paused;
waveOut.Pause();
}
else if (waveOut.PlaybackState == PlaybackState.Paused)
{
playState = PlaybackState.Playing;
waveOut.Play();
}
}
}
internal void skipSong()
{
if (waveOut != null)
{
if (waveOut.PlaybackState == PlaybackState.Playing)
{
waveOut.Stop();
}
else if (waveOut.PlaybackState == PlaybackState.Paused)
{
waveOut.Stop();
}
}
}
internal void stop()
{
playState = PlaybackState.Stopped;
if (waveOut != null)
{
if (waveOut.PlaybackState == PlaybackState.Playing)
{
waveOut.Stop();
}
else if (waveOut.PlaybackState == PlaybackState.Paused)
{
waveOut.Stop();
}
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new PlayerForm());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WindowsFormsApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("IBM")]
[assembly: AssemblyProduct("WindowsFormsApplication1")]
[assembly: AssemblyCopyright("Copyright © IBM 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("52c76658-dc37-4f9e-8b61-3ff686aad7b4")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WindowsFormsApplication1.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WindowsFormsApplication1.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WindowsFormsApplication1.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{DCD7B803-6052-4B77-8DF5-91B0BBA2CA19}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WindowsFormsApplication1</RootNamespace>
<AssemblyName>SubsonicPlayer</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="NAudio, Version=1.3.8.0, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\NAudio.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="PlayerForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="PlayerForm.Designer.cs">
<DependentUpon>PlayerForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="PlayerForm.resx">
<DependentUpon>PlayerForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<COMReference Include="WMPLib">
<Guid>{6BF52A50-394A-11D3-B153-00C04F79FAA6}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SubsonicAPI\SubsonicAPI.csproj">
<Project>{8EFE676D-0D2D-466A-B6D3-91F93FE71ADC}</Project>
<Name>SubsonicAPI</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

Binary file not shown.