mirror of
https://github.com/ViViDboarder/subsonic-csharp.git
synced 2024-11-22 00:46:31 +00:00
Initial git commit
This commit is contained in:
commit
ab3d1b3472
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.hg/
|
||||||
|
.hgignore
|
||||||
|
|
27
SubsonicMono/SubsonicAPI/AssemblyInfo.cs
Normal file
27
SubsonicMono/SubsonicAPI/AssemblyInfo.cs
Normal 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("")]
|
||||||
|
|
648
SubsonicMono/SubsonicAPI/SubsonicAPI.cs
Normal file
648
SubsonicMono/SubsonicAPI/SubsonicAPI.cs
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
SubsonicMono/SubsonicAPI/SubsonicAPI.csproj
Normal file
41
SubsonicMono/SubsonicAPI/SubsonicAPI.csproj
Normal 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>
|
BIN
SubsonicMono/SubsonicAPI/SubsonicAPI.pidb
Normal file
BIN
SubsonicMono/SubsonicAPI/SubsonicAPI.pidb
Normal file
Binary file not shown.
32
SubsonicMono/SubsonicMono.sln
Normal file
32
SubsonicMono/SubsonicMono.sln
Normal 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
|
25
SubsonicMono/SubsonicMono.userprefs
Normal file
25
SubsonicMono/SubsonicMono.userprefs
Normal 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>
|
27
SubsonicMono/SubsonicMono/AssemblyInfo.cs
Normal file
27
SubsonicMono/SubsonicMono/AssemblyInfo.cs
Normal 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("")]
|
||||||
|
|
BIN
SubsonicMono/SubsonicMono/ItemLoad.gif
Normal file
BIN
SubsonicMono/SubsonicMono/ItemLoad.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
17
SubsonicMono/SubsonicMono/Main.cs
Normal file
17
SubsonicMono/SubsonicMono/Main.cs
Normal 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 ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
203
SubsonicMono/SubsonicMono/MainWindow.cs
Normal file
203
SubsonicMono/SubsonicMono/MainWindow.cs
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
9
SubsonicMono/SubsonicMono/README
Normal file
9
SubsonicMono/SubsonicMono/README
Normal 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/
|
85
SubsonicMono/SubsonicMono/SubsonicPlayer.csproj
Normal file
85
SubsonicMono/SubsonicMono/SubsonicPlayer.csproj
Normal 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>
|
BIN
SubsonicMono/SubsonicMono/SubsonicPlayer.pidb
Normal file
BIN
SubsonicMono/SubsonicMono/SubsonicPlayer.pidb
Normal file
Binary file not shown.
192
SubsonicMono/SubsonicMono/gtk-gui/MainWindow.cs
Normal file
192
SubsonicMono/SubsonicMono/gtk-gui/MainWindow.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
29
SubsonicMono/SubsonicMono/gtk-gui/generated.cs
Normal file
29
SubsonicMono/SubsonicMono/gtk-gui/generated.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
215
SubsonicMono/SubsonicMono/gtk-gui/gui.stetic
Normal file
215
SubsonicMono/SubsonicMono/gtk-gui/gui.stetic
Normal 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">></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>
|
25
SubsonicMono/SubsonicWeb/Default.aspx
Normal file
25
SubsonicMono/SubsonicWeb/Default.aspx
Normal 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>
|
29
SubsonicMono/SubsonicWeb/Default.aspx.cs
Normal file
29
SubsonicMono/SubsonicWeb/Default.aspx.cs
Normal 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
30
SubsonicMono/SubsonicWeb/Default.aspx.designer.cs
generated
Normal file
30
SubsonicMono/SubsonicWeb/Default.aspx.designer.cs
generated
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
1
SubsonicMono/SubsonicWeb/Global.asax
Normal file
1
SubsonicMono/SubsonicWeb/Global.asax
Normal file
@ -0,0 +1 @@
|
|||||||
|
<%@ Application Inherits="SubsonicWeb.Global" %>
|
49
SubsonicMono/SubsonicWeb/Global.asax.cs
Normal file
49
SubsonicMono/SubsonicWeb/Global.asax.cs
Normal 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
32
SubsonicMono/SubsonicWeb/Library.aspx
Normal file
32
SubsonicMono/SubsonicWeb/Library.aspx
Normal 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>
|
82
SubsonicMono/SubsonicWeb/Library.aspx.cs
Normal file
82
SubsonicMono/SubsonicWeb/Library.aspx.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
28
SubsonicMono/SubsonicWeb/Library.aspx.designer.cs
generated
Normal file
28
SubsonicMono/SubsonicWeb/Library.aspx.designer.cs
generated
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
1
SubsonicMono/SubsonicWeb/SubsonicWeb.csproj
Normal file
1
SubsonicMono/SubsonicWeb/SubsonicWeb.csproj
Normal 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>
|
BIN
SubsonicMono/SubsonicWeb/library.sqlite
Normal file
BIN
SubsonicMono/SubsonicWeb/library.sqlite
Normal file
Binary file not shown.
33
SubsonicMono/SubsonicWeb/web.config
Normal file
33
SubsonicMono/SubsonicWeb/web.config
Normal 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>
|
36
SubsonicPlayer/SubsonicAPI/Properties/AssemblyInfo.cs
Normal file
36
SubsonicPlayer/SubsonicAPI/Properties/AssemblyInfo.cs
Normal 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")]
|
383
SubsonicPlayer/SubsonicAPI/SubsonicAPI.cs
Normal file
383
SubsonicPlayer/SubsonicAPI/SubsonicAPI.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
SubsonicPlayer/SubsonicAPI/SubsonicAPI.csproj
Normal file
54
SubsonicPlayer/SubsonicAPI/SubsonicAPI.csproj
Normal 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>
|
BIN
SubsonicPlayer/SubsonicAPI/SubsonicAPI.pidb
Normal file
BIN
SubsonicPlayer/SubsonicAPI/SubsonicAPI.pidb
Normal file
Binary file not shown.
42
SubsonicPlayer/SubsonicPlayer.sln
Normal file
42
SubsonicPlayer/SubsonicPlayer.sln
Normal 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
|
BIN
SubsonicPlayer/SubsonicPlayer.suo
Normal file
BIN
SubsonicPlayer/SubsonicPlayer.suo
Normal file
Binary file not shown.
13
SubsonicPlayer/SubsonicPlayer.userprefs
Normal file
13
SubsonicPlayer/SubsonicPlayer.userprefs
Normal 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>
|
285
SubsonicPlayer/SubsonicPlayer/PlayerForm.Designer.cs
generated
Normal file
285
SubsonicPlayer/SubsonicPlayer/PlayerForm.Designer.cs
generated
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
574
SubsonicPlayer/SubsonicPlayer/PlayerForm.cs
Normal file
574
SubsonicPlayer/SubsonicPlayer/PlayerForm.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
SubsonicPlayer/SubsonicPlayer/PlayerForm.resx
Normal file
120
SubsonicPlayer/SubsonicPlayer/PlayerForm.resx
Normal 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>
|
21
SubsonicPlayer/SubsonicPlayer/Program.cs
Normal file
21
SubsonicPlayer/SubsonicPlayer/Program.cs
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
SubsonicPlayer/SubsonicPlayer/Properties/AssemblyInfo.cs
Normal file
36
SubsonicPlayer/SubsonicPlayer/Properties/AssemblyInfo.cs
Normal 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")]
|
71
SubsonicPlayer/SubsonicPlayer/Properties/Resources.Designer.cs
generated
Normal file
71
SubsonicPlayer/SubsonicPlayer/Properties/Resources.Designer.cs
generated
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
SubsonicPlayer/SubsonicPlayer/Properties/Resources.resx
Normal file
117
SubsonicPlayer/SubsonicPlayer/Properties/Resources.resx
Normal 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>
|
30
SubsonicPlayer/SubsonicPlayer/Properties/Settings.Designer.cs
generated
Normal file
30
SubsonicPlayer/SubsonicPlayer/Properties/Settings.Designer.cs
generated
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
108
SubsonicPlayer/SubsonicPlayer/SubsonicPlayer.csproj
Normal file
108
SubsonicPlayer/SubsonicPlayer/SubsonicPlayer.csproj
Normal 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>
|
3
SubsonicPlayer/SubsonicPlayer/SubsonicPlayer.csproj.user
Normal file
3
SubsonicPlayer/SubsonicPlayer/SubsonicPlayer.csproj.user
Normal 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>
|
BIN
SubsonicPlayer/SubsonicPlayer/SubsonicPlayer.pidb
Normal file
BIN
SubsonicPlayer/SubsonicPlayer/SubsonicPlayer.pidb
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user