Updated visual studio project with latest .cs file

This commit is contained in:
Ian 2011-04-01 10:56:51 -04:00
parent c212660b0f
commit 26b1cbdeb3
4 changed files with 446 additions and 133 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
.hg/ .hg/
.hgignore .hgignore
*.userprefs
bin/

View File

@ -1,4 +1,4 @@
/************************************************************************** /**************************************************************************
Subsonic Csharp Subsonic Csharp
Copyright (C) 2010 Ian Fijolek Copyright (C) 2010 Ian Fijolek
@ -29,118 +29,164 @@ namespace SubsonicAPI
public class SubsonicItem public class SubsonicItem
{ {
public string Name;
public string id;
public enum SubsonicItemType public enum SubsonicItemType
{ {
Folder, Song Folder, Song, Artist, Library, Playlist
} }
public SubsonicItemType ItemType; 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() public override string ToString()
{ {
return Name; 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;
}
} }
} }
public class MusicFolder : SubsonicItem return foundItem;
{
#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 public SubsonicItem GetChildByName(string childName)
{ {
get { return _Songs; } SubsonicItem theItem = null;
set { _Songs = value; }
}
#endregion properties if (_children != null)
public MusicFolder()
{ {
_Folders = new List<MusicFolder>(); theItem = _children.Find(
_Songs = new List<Song>(); delegate(SubsonicItem itm)
base.ItemType = SubsonicItemType.Folder;
}
public MusicFolder(string theName, string theId)
{ {
_Folders = new List<MusicFolder>(); return itm.name == childName ;
_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) return theItem;
{
MusicFolder theFolder = _Folders.Find(
delegate(MusicFolder fldr)
{
return fldr.Name == theFolderName;
}
);
return theFolder;
} }
} }
public class Song : SubsonicItem public class Song : SubsonicItem
{ {
public string artist;
public string album;
public string title;
public Song() public Song()
{ {
base.ItemType = SubsonicItemType.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 theTitle, string theId) public Song(string title,string artist, string album, string id)
{ {
Name = theTitle; this.artist = artist;
id = theId; 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();
}
base.ItemType = SubsonicItemType.Song; 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;
} }
} }
@ -152,16 +198,37 @@ namespace SubsonicAPI
/// </summary> /// </summary>
public static class Subsonic 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 // Should be set from application layer when the application is loaded
public static string appName; public static string appName;
// Version of the REST API implemented // Min version of the REST API implemented
private static string apiVersion = "1.3.0"; private static string apiVersion = "1.3.0";
// Set with the login method // Set with the login method
static string server; static string server;
static string authHeader; static string authHeader;
// Used for generating direct URLS
static string encPass;
static string username;
/// <summary> /// <summary>
/// Takes parameters for server, username and password to generate an auth header /// Takes parameters for server, username and password to generate an auth header
/// and Pings the server /// and Pings the server
@ -178,6 +245,12 @@ namespace SubsonicAPI
authHeader = user + ":" + password; authHeader = user + ":" + password;
authHeader = Convert.ToBase64String(Encoding.Default.GetBytes(authHeader)); 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); Stream theStream = MakeGenericRequest("ping", null);
StreamReader sr = new StreamReader(theStream); StreamReader sr = new StreamReader(theStream);
@ -186,6 +259,8 @@ namespace SubsonicAPI
/// TODO: Parse the result and determine if logged in or not /// TODO: Parse the result and determine if logged in or not
_MyLibrary = new SubsonicItem("LibraryRoot", "-1", SubsonicItem.SubsonicItemType.Library, null);
return result; return result;
} }
@ -244,13 +319,122 @@ namespace SubsonicAPI
return requestURL; 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> /// <summary>
/// Returns an indexed structure of all artists. /// Returns an indexed structure of all artists.
/// </summary> /// </summary>
/// <param name="musicFolderId">Required: No; If specified, only return artists in the music folder with the given ID.</param> /// <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> /// <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> /// <returns>Dictionary, Key = Artist and Value = id</returns>
public static Dictionary<string, string> GetIndexes(string musicFolderId = "", string ifModifiedSince = "") public static List<SubsonicItem> GetIndexes(string musicFolderId, string ifModifiedSince)
{ {
// Load the parameters if provided // Load the parameters if provided
Dictionary<string, string> parameters = new Dictionary<string, string>(); Dictionary<string, string> parameters = new Dictionary<string, string>();
@ -270,8 +454,8 @@ namespace SubsonicAPI
XmlDocument myXML = new XmlDocument(); XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result); myXML.LoadXml(result);
// Parse the XML document into a Dictionary // Parse the XML document into a List
Dictionary<string, string> artists = new Dictionary<string, string>(); List<SubsonicItem> artists = new List<SubsonicItem>();
if (myXML.ChildNodes[1].Name == "subsonic-response") if (myXML.ChildNodes[1].Name == "subsonic-response")
{ {
if (myXML.ChildNodes[1].FirstChild.Name == "indexes") if (myXML.ChildNodes[1].FirstChild.Name == "indexes")
@ -285,7 +469,7 @@ namespace SubsonicAPI
string artist = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["name"].Value; 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; string id = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["id"].Value;
artists.Add(artist, id); artists.Add(new SubsonicItem(artist, id));
} }
} }
} }
@ -294,6 +478,16 @@ namespace SubsonicAPI
return artists; return artists;
} }
public static List<SubsonicItem> GetIndexes(string musicFolderId)
{
return GetIndexes(musicFolderId, "");
}
public static List<SubsonicItem> GetIndexes()
{
return GetIndexes("", "");
}
/// <summary> /// <summary>
/// Streams a given music file. (Renamed from request name "stream") /// Streams a given music file. (Renamed from request name "stream")
/// </summary> /// </summary>
@ -303,7 +497,7 @@ namespace SubsonicAPI
/// limit the bitrate to this value, in kilobits per second. If set to zero, no limit /// 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> /// is imposed. Legal values are: 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 and 320. </param>
/// <returns></returns> /// <returns></returns>
public static Stream StreamSong(string id, int? maxBitRate = null) public static Stream StreamSong(string id, int? maxBitRate)
{ {
// Reades the id of the song and sets it as a parameter // Reades the id of the song and sets it as a parameter
Dictionary<string, string> theParameters = new Dictionary<string,string>(); Dictionary<string, string> theParameters = new Dictionary<string,string>();
@ -317,13 +511,17 @@ namespace SubsonicAPI
return theStream; return theStream;
} }
public static Stream StreamSong(string id)
{
return StreamSong(id, null);
}
/// <summary> /// <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. /// 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> /// </summary>
/// <param name="id">A string which uniquely identifies the music folder. Obtained by calls to getIndexes or getMusicDirectory.</param> /// <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> /// <returns>MusicFolder object containing info for the specified directory</returns>
public static MusicFolder GetMusicDirectory(string id) public static List<SubsonicItem> GetMusicDirectory(string id)
{ {
Dictionary<string, string> theParameters = new Dictionary<string, string>(); Dictionary<string, string> theParameters = new Dictionary<string, string>();
theParameters.Add("id", id); theParameters.Add("id", id);
@ -336,14 +534,15 @@ namespace SubsonicAPI
XmlDocument myXML = new XmlDocument(); XmlDocument myXML = new XmlDocument();
myXML.LoadXml(result); myXML.LoadXml(result);
MusicFolder theFolder = new MusicFolder("ArtistFolder", id); List<SubsonicItem> theContents = new List<SubsonicItem>();
if (myXML.ChildNodes[1].Name == "subsonic-response") if (myXML.ChildNodes[1].Name == "subsonic-response")
{ {
if (myXML.ChildNodes[1].FirstChild.Name == "directory") if (myXML.ChildNodes[1].FirstChild.Name == "directory")
{ {
theFolder.Name = myXML.ChildNodes[1].FirstChild.Attributes["name"].Value; SubsonicItem theParent = new SubsonicItem();
theFolder.id = myXML.ChildNodes[1].FirstChild.Attributes["id"].Value; theParent.name = myXML.ChildNodes[1].FirstChild.Attributes["name"].Value;
theParent.id = myXML.ChildNodes[1].FirstChild.Attributes["id"].Value;
int i = 0; int i = 0;
for (i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++) for (i = 0; i < myXML.ChildNodes[1].FirstChild.ChildNodes.Count; i++)
@ -352,32 +551,145 @@ namespace SubsonicAPI
string title = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["title"].Value; string title = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["title"].Value;
string theId = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["id"].Value; string theId = myXML.ChildNodes[1].FirstChild.ChildNodes[i].Attributes["id"].Value;
if (isDir) SubsonicItem theItem = new SubsonicItem(title, theId, (isDir ? SubsonicItem.SubsonicItemType.Folder : SubsonicItem.SubsonicItemType.Song), theParent);
theFolder.AddFolder(title, theId); theContents.Add(theItem);
else
theFolder.AddSong(title, theId);
} }
} }
} }
return theFolder; return theContents;
} }
/// <summary> /// <summary>
/// Returns what is currently being played by all users. Takes no extra parameters. /// Returns what is currently being played by all users. Takes no extra parameters.
/// </summary> /// </summary>
public static List<Song> GetNowPlaying() public static List<SubsonicItem> GetNowPlaying()
{ {
List<Song> nowPlaying = new List<Song>(); List<SubsonicItem> nowPlaying = new List<SubsonicItem>();
Dictionary<string, string> theParameters = new Dictionary<string, string>(); Dictionary<string, string> theParameters = new Dictionary<string, string>();
Stream theStream = MakeGenericRequest("getNowPlaying", theParameters); Stream theStream = MakeGenericRequest("getNowPlaying", theParameters);
StreamReader sr = new StreamReader(theStream); StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd(); string result = sr.ReadToEnd();
/// TODO: Parse result to list
return nowPlaying; return nowPlaying;
} }
/// <summary>
/// Performs a search valid for the current version of the subsonic server
/// If version is >= 1.4.0 search2
/// Else search
/// </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 = "";
// Use search for the server version
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;
}
/// <summary>
/// Returns a list of all playlists on server
/// </summary>
public static List<SubsonicItem> GetPlaylists()
{
List<SubsonicItem> playlists = new List<SubsonicItem>();
Dictionary<string, string> theParameters = new Dictionary<string, string>();
Stream theStream = MakeGenericRequest("getPlaylists", theParameters);
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
/// TODO: Parse result into list
return playlists;
}
/// <summary>
/// Returns a list of all SubsonicItems in playlist of given ID
/// </summary>
/// <param name="playlistId">
/// ID of playlist to be fetched [retreive from GetPlaylists()]
/// </param>
/// <returns>
/// Returns list of SubsonicItems
/// </returns>
public static List<SubsonicItem> GetPlaylist(string playlistId)
{
List<SubsonicItem> playlist = new List<SubsonicItem>();
Dictionary<string, string> theParameters = new Dictionary<string, string>();
theParameters.Add("id", playlistId);
Stream theStream = MakeGenericRequest("getPlaylist", theParameters);
StreamReader sr = new StreamReader(theStream);
string result = sr.ReadToEnd();
/// TODO: Parse result into list
return playlist;
}
} }
} }