From 26b1cbdeb350036084c113323a36bd16fbc9dacf Mon Sep 17 00:00:00 2001 From: Ian Date: Fri, 1 Apr 2011 10:56:51 -0400 Subject: [PATCH] Updated visual studio project with latest .cs file --- .gitignore | 3 +- SubsonicMono/SubsonicAPI/SubsonicAPI.pidb | Bin 11913 -> 13661 bytes SubsonicMono/SubsonicMono/SubsonicPlayer.pidb | Bin 8557 -> 8509 bytes SubsonicPlayer/SubsonicAPI/SubsonicAPI.cs | 576 ++++++++++++++---- 4 files changed, 446 insertions(+), 133 deletions(-) diff --git a/.gitignore b/.gitignore index baf3686..33fb3c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .hg/ .hgignore - +*.userprefs +bin/ diff --git a/SubsonicMono/SubsonicAPI/SubsonicAPI.pidb b/SubsonicMono/SubsonicAPI/SubsonicAPI.pidb index 1e55b11c9daacdc8f3234744aab8fefb6b0aa1fe..80081c7d18a14caa2d0c32b32c48754218cb88c6 100644 GIT binary patch delta 4152 zcmZu!YiwLc6~43fZoJoa9NTf6th4dNsqNU=b>bv$(&D&|>oj)bIIitfBBToI^>uQ? zKAd}Zoj3&9h0-RahNJ^+1LYyLLZ#v%*cPb*L4WX%HsU2wgrF*d2#OE}f%pN!eBbQD z-o>LmbI*L|%sFS~%xiBv_M3}0pAv1iu3z=rt%fdVGnHba5Z+9{6A(=aU=?Gr$b8Ip zQ~zCAS*a+OhS35vq~7#|)#BDoYOt*NcoK-mp4J**jW&><42x$LRaGqFrcNfO?HSuz z)oX`jRqv8|wJcb<+IG~>%8qYyq2rs4I94JX0h&f9`>AT*J#8s+=b{(v*fca4fS|%2 z!em%h(&}1yiy3s~qt*H3Y#K9I-AQ zgBqPG?%h^wdlc|A=rqVwU-32tN;^`6BQYFIW`la)8}#+C>0)FZVoV+K4T{U^nlBhA z429yeAVzcrWU5-=qbOTf{ z-9Aq>J;m&e26AdpHKch|ob#*d+J<0vkvWRPAZDWvWP*?lRO~Rvme2!O-t6DyV{(8KT3iIqfnEcd>WtZRq|^;Hc7fKqA-11boE3}5Al9$GWA=y>>W}8G;uZ5<2pQ`e zAXBwgjuwl*2e=dT11(;v40_yc>g$y+iPzOw)r*+Jzf?UWeyt8xw~F7YGu1oAd+J(s z>!ZJedLi9Wu?w?5aWAv7)Kd<0Fp)`m<1XYn!{H z$#^`Hn3k9A)CHLzvm}B!N={qTauyRM?SxESuq67bJN4VtVqLEVUd|*P>82bj61NlQ zWkkA3e1JJt%CW6Eg6!s4ZaS87WpV~O(MT-TyB8X1C*k&8XN*IogCZ~m!6XOeWh<=q z)OWRz>tzp?kArG(VhpFOxIQ&-uzn)*(fXhWO_drXz#07pz9u`bTtkJ1@r3%(=3enh zB^p9Usl|ELvBv!r7(d-@TttpTdO=x|0p#@V2~a? z>c@dS3p^Ha9}~bpDeNG-1Ty21D+6|FJd(=J{K}^R`X=UGWE*6|;0E zi>89Mc=_nU;0lxG!EEOyEqBHdIRF(egK9rO>kLd6k3p%9itU@AS|t2r+O?zE{gia( zZ)M(X`j`k+ty%|pK$UPhCb`KZA*QtJI+GIVdL0|LB) z2G(_;Gqdnn$bA!5#ED+`9N4ElaxCJw`AsQPNy$f(>~+&P37q*pIc7Q7*KwEoS$C6j zk(fQLH#>K8H0|(_Bj+r~wUY_%YQk=M3ftd~qLTxW9G=k{yQpHjvhRrO?mF1DFK2VV zJQhO`SqD5*7A~bNXTGIx5~e0CCobocX?ZyUKZr0F2g2&zizikj-Y0wWC&*Db!uS!z zL@ojz2r@Z!5r>^ya?+eAok0S;@~_veJB5c1J_n&!#|DP0ls&pNkLr0)6*857d%7k$;({uSPFZrsN<}Z=cK8sF zdJA3UjFXJZH6gjXJ08PWOVcICvnPLc)sieO?;sHJIy705*{gA20LjiR&T&dm; z-!IEClq~?oQB;(A0pLe&02P#5)ks(40;6mL`5r`-H$Mozp?Le|Hm^7a5ufRTH%UJm zo}8!SIiMdv){__lL~kr&H!AIE7);*N!oz4Z7P~5(6oT&z?Q8^0Kj^u}uKrDhQ5+Xfn|7kF9 Sc=3;g3>UqBC#veQ%KrfYXB2q= delta 2861 zcmZuzTWnNS6usxpgL!mlD{U#44t>zl(hg;40n7Uh7O)5vjf!A99bllH!psy}Leiqh zLmmQ~4?YNJQL5tdsUxVm<&q=V=*S2S z!`uchr?V}YS`djulgVhuV_cGA+z)E%lO2L>w zIiQE4;frEgaz{LrA<;;lUS0}*JjZ`1tiENH_cHkt34pJZbB=p$k zm^a$b=~ zo_6Js4c;=?0c}6@j&8$4Qg`fZ_xxy zhAUyX)y~y1>;lYKhwjNpxl}Z{=gsXu566}RiPwP7fou-kn5S}}W_S+dg22-`kPDGx z4!W5JIc~A83%5A@A+Xz&dRE@t4iI+MylNISsMiV=t3D(X4$vbi(P^EsAKLbJE0TRCf z4#^*B73lCTLqIn(Cp~Xusj}`P%1+B360Lw!dUGeJ`*Jq781~ED5_La)Bezpo0Ti8W z1c{9pQ6q2Uzn}tgE2fW;AwRC(y(Q?6`3HD1P@am))>ItlvTl+F?_pjroqnfL*Y?57A$nXkMIGDYfSn=aDxgx zfW)>Q5=$W}#!8-X=#$Z{7pSK-4a#S0ALbYkKwY(T?|iAVtuGeebX-0w?G6Pomn~}& zjS$!1`Ha1v&zslX8f{BNHfNV!JA4unO%QH;<|K^~W-5Sddrvgc2ZtrdL3P@Pq2eUq zeX(z4tUb||=o@;QF3QX3vZamKAXyFE0GzVAtZcj+o^h2Sa1G$yYg`9N{0O+x>#MFP zRU~!QuPaY_Uv;&kc3{+{HCJ|BJ-{5iV`+GMszR6oMx$T`e*P)-LsD+mKGHv{N^aHd zk`>iHSr?k;2{>G3&`c3Ep*nptbX1ivt(?}L_GEWF7U7M8*znfCxF*V;`W96y*Xrk} zI@q9;)O%&>zVE&5V z5qFiN)f5>08^WLhrVKdmhe69s+yKurlqqSSVmVCY3Yzd5#p=(_&TE9T^H9`un2^j2 zF9`B~hi$oTR)fyhJtKW8{D}(ae+DnFTD;2VbI+2Nh9)&zFaBJ^2^a6+N^IU3dD!5W z4UIF)2f-8pYA%evqOmxx4;wfSCZnDN^_|Ai6S%J^CN1#Jhm%CDV zn6PkRbZ27HNMh858aE~^+-Ty$#2;W>7{kWbIg}z2PIA6}_nhy1b8qL)SLaLT%mn1k zPCi1XXfwSN1VKxAnz8{qEVcMpv_l^*iVpDNcQHTx40V$B`v(Sw4|zL-p5QQ0p&v`6 zEEvFpl0#+z*UsXQ)CNBMAi2Pg4!sKoF|6-5C;9=>m|XtuIYmX;V1giSHdKirs;cP8 zv|yP{FS1VhC(=ppAA*kA!-;KBb_0?&)Ze)KEU(C zSSoL`@ceSDnF}Oaa6~r2d7P4)ts~S1Ph6AEobm!L$vfa8Zdamk3GXXa@C-dl7A`5d zFp4&#U42d}&GOI+aN!8$8y4DlRl*%J1BX@M+AjREDMQyw3>{DiW9Wu3jN@A*7Hf*sYa|nEec|9Rk+pFh105Tk z_G*hw(=?Ra*cGJr+S85iMJwFGr`qDo+f+-*{VHvnJrH8h7<)H^pis=+X>>TSiAaA2QJjv>m`1BvKw3N73HZ!6(g_f z85(#Ab%Z)fLD;)TCX5RjiOEg)+TPs)>`*~D&!ZIbP6FvDfwnH<<%$Bw2%VG}$#m6@ z6RDx(I|nBS_EGY+f@XqRN)B-2lN{@43(=(NuCUkds|)%ggZ#;mVJjgUn%VFqkyXPs zTC5tj(;{JL=2P)wq*DaEH>rcjf97UBG;8Ge{~{F7BlxhqSINVT!yd1%X225)nVVMX IawQStU-q=gbpQYW delta 1104 zcmZuwNla5=5PsA4z1Q~&q*zMmlTbjxu*(GvBqAW939En#2+~r7LT#Z7Qe3DjD9Yj_ z#)JbWjqyrCqQMLCVBF%(xFjAps&_AnGc6EACi$i_^L_vKFKu5`{;Zsx0BvsaF+P+t z#6Cd~+OgYGhbH45=*J>sj^?JBc+@@G>!M<744|JxgZRLhr+J7FtGz*gc&mcy^Z12C zUR*O~gAcQnf+Uu1iy`b&vSApfmBO89KYmd1A%MS?3<#oK&4&=ysx}zGb82ByV4E4W z7x0N%loa}(7{%{u{!T;~^Gta=?LCGAred6s6R{9%${VuO6E0#S^ur~523c?!zro(* zD>RKe=JR;MwQi^1;SU21#?hurg$S1DvJ@8Z>?*o+op23TboFo@6ZQ3Q1H1Ku<_-QP zY2xdBF8m>C2?wbuAVlL9>J4Quf#rrwm_(-`bN6kU%fbF$lJ`a>Ya1?iaKVrZQ~26Y zX1z<4sX62f_`L3(ipJx7ihHPu`z*XZ8e7&4Cs?pgjE89qiEY*yqQMcg!mssUZ*Hm5>jXW _children; + + public List 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 SubsonicItemType ItemType; - + 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; + 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 MusicFolder : SubsonicItem - { - #region private vars - - private List _Folders; - private List _Songs; - - #endregion private vars - - #region properties - - public List Folders - { - get { return _Folders; } - set { _Folders = value; } - } - - public List Songs - { - get { return _Songs; } - set { _Songs = value; } - } - - #endregion properties - - public MusicFolder() - { - _Folders = new List(); - _Songs = new List(); - - base.ItemType = SubsonicItemType.Folder; - } - - public MusicFolder(string theName, string theId) - { - _Folders = new List(); - _Songs = new List(); - - 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 string artist; + public string album; + public string title; + 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; - id = theId; - - base.ItemType = SubsonicItemType.Song; + 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; } } @@ -152,15 +198,36 @@ namespace SubsonicAPI /// public static class Subsonic { + private static SubsonicItem _MyLibrary; + + /// + /// Public Property that can be used for auto-retrieving children + /// + 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; - // Version of the REST API implemented + // 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; /// /// Takes parameters for server, username and password to generate an auth header @@ -177,7 +244,13 @@ namespace SubsonicAPI 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); @@ -186,6 +259,8 @@ namespace SubsonicAPI /// TODO: Parse the result and determine if logged in or not + _MyLibrary = new SubsonicItem("LibraryRoot", "-1", SubsonicItem.SubsonicItemType.Library, null); + return result; } @@ -244,13 +319,122 @@ namespace SubsonicAPI return requestURL; } + /// + /// Creates a URL for a command with username and encoded pass in the URL + /// + /// + /// + /// URL for streaming a song or retrieving the results of a call + public static string BuildDirectURL(string method, Dictionary parameters) + { + string callURL = "http://" + server + "/rest/" + method + "?v=" + apiVersion + "&c=" + appName + + "&u=" + username + "&p=enc:" + encPass; + if (parameters != null) + { + foreach (KeyValuePair parameter in parameters) + { + callURL += "&" + parameter.Key + "=" + parameter.Value; + } + } + return callURL; + } + + /// + /// Returns a list of SubsonicItems that fall inside the parent object + /// + /// + /// A + /// + /// + /// A + /// + /// + /// A + /// + public static List GetItemChildren(SubsonicItem parent, string ifModifiedSince) + { + Dictionary parameters = new Dictionary(); + + // 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 children = new List(); + + // 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; + } + /// /// Returns an indexed structure of all artists. /// - /// Required: No; If specified, only return artists in the music folder with the given ID. + /// Required: No; If specified, only return artists in the music folder with the given ID. /// Required: No; If specified, only return a result if the artist collection has changed since the given time. /// Dictionary, Key = Artist and Value = id - public static Dictionary GetIndexes(string musicFolderId = "", string ifModifiedSince = "") + public static List GetIndexes(string musicFolderId, string ifModifiedSince) { // Load the parameters if provided Dictionary parameters = new Dictionary(); @@ -270,8 +454,8 @@ namespace SubsonicAPI XmlDocument myXML = new XmlDocument(); myXML.LoadXml(result); - // Parse the XML document into a Dictionary - Dictionary artists = new Dictionary(); + // Parse the XML document into a List + List artists = new List(); if (myXML.ChildNodes[1].Name == "subsonic-response") { 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 id = myXML.ChildNodes[1].FirstChild.ChildNodes[i].ChildNodes[j].Attributes["id"].Value; - artists.Add(artist, id); + artists.Add(new SubsonicItem(artist, id)); } } } @@ -293,6 +477,16 @@ namespace SubsonicAPI return artists; } + + public static List GetIndexes(string musicFolderId) + { + return GetIndexes(musicFolderId, ""); + } + + public static List GetIndexes() + { + return GetIndexes("", ""); + } /// /// Streams a given music file. (Renamed from request name "stream") @@ -303,7 +497,7 @@ namespace SubsonicAPI /// 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. /// - 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 Dictionary theParameters = new Dictionary(); @@ -317,13 +511,17 @@ namespace SubsonicAPI return theStream; } + public static Stream StreamSong(string id) + { + return StreamSong(id, null); + } /// /// 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. /// /// A string which uniquely identifies the music folder. Obtained by calls to getIndexes or getMusicDirectory. /// MusicFolder object containing info for the specified directory - public static MusicFolder GetMusicDirectory(string id) + public static List GetMusicDirectory(string id) { Dictionary theParameters = new Dictionary(); theParameters.Add("id", id); @@ -336,14 +534,15 @@ namespace SubsonicAPI XmlDocument myXML = new XmlDocument(); myXML.LoadXml(result); - MusicFolder theFolder = new MusicFolder("ArtistFolder", id); + List theContents = new List(); 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; + 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++) @@ -352,32 +551,145 @@ namespace SubsonicAPI 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); + SubsonicItem theItem = new SubsonicItem(title, theId, (isDir ? SubsonicItem.SubsonicItemType.Folder : SubsonicItem.SubsonicItemType.Song), theParent); + theContents.Add(theItem); } } } - return theFolder; + return theContents; } - - /// - /// Returns what is currently being played by all users. Takes no extra parameters. - /// - public static List GetNowPlaying() - { - List nowPlaying = new List(); - - Dictionary theParameters = new Dictionary(); - Stream theStream = MakeGenericRequest("getNowPlaying", theParameters); - StreamReader sr = new StreamReader(theStream); - string result = sr.ReadToEnd(); + + /// + /// Returns what is currently being played by all users. Takes no extra parameters. + /// + public static List GetNowPlaying() + { + List nowPlaying = new List(); + + Dictionary theParameters = new Dictionary(); + Stream theStream = MakeGenericRequest("getNowPlaying", theParameters); + StreamReader sr = new StreamReader(theStream); + string result = sr.ReadToEnd(); - - return nowPlaying; - } + /// TODO: Parse result to list + + return nowPlaying; + } + + /// + /// Performs a search valid for the current version of the subsonic server + /// If version is >= 1.4.0 search2 + /// Else search + /// + /// The Term you want to search for + /// A List of SubsonicItem objects + public static List Search(string query) + { + Dictionary parameters = new Dictionary(); + 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 searchResults = new List(); + + // 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; + } + + /// + /// Returns a list of all playlists on server + /// + public static List GetPlaylists() + { + List playlists = new List(); + + Dictionary theParameters = new Dictionary(); + Stream theStream = MakeGenericRequest("getPlaylists", theParameters); + StreamReader sr = new StreamReader(theStream); + string result = sr.ReadToEnd(); + + /// TODO: Parse result into list + + return playlists; + } + + /// + /// Returns a list of all SubsonicItems in playlist of given ID + /// + /// + /// ID of playlist to be fetched [retreive from GetPlaylists()] + /// + /// + /// Returns list of SubsonicItems + /// + public static List GetPlaylist(string playlistId) + { + List playlist = new List(); + + Dictionary theParameters = new Dictionary(); + 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; + } + + + } -} \ No newline at end of file +}