├── OpenSonos.LocalMusicServer.Test.Unit
├── packages.config
├── Browsing
│ ├── SonosIdentifierTests.cs
│ └── GuidProviderTests.cs
├── Bootstrapping
│ └── ServerConfigurationTests.cs
├── MusicDatabase
│ └── PhysicalResourceTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── OpenSonos.LocalMusicServer.Test.Unit.csproj
└── Smapi
│ └── ResponseFormattingExtensionsTests.cs
├── OpenSonos.LocalMusicServer
├── Browsing
│ ├── IRepresentAResource.cs
│ ├── IIdentityProvider.cs
│ ├── MusicRepositories
│ │ ├── ISearchProvider.cs
│ │ ├── IMonitorTheFileSystemForChanges.cs
│ │ ├── TopLevelDirectorySearchProvider.cs
│ │ ├── ChangeMonitor.cs
│ │ └── FlatFileMusicRepository.cs
│ ├── Container.cs
│ ├── MusicFile.cs
│ ├── IMusicRepository.cs
│ ├── ResourceCollection.cs
│ ├── ConvertPathsToSha1.cs
│ ├── SonosIdentifier.cs
│ ├── PhysicalResource.cs
│ └── IdentityProvider.cs
├── App.config
├── Bootstrapping
│ ├── ServerConfiguration.cs
│ ├── ServerConfigurationFactory.cs
│ ├── SimpleServicesToNinject.cs
│ └── Bindings.cs
├── packages.config
├── Smapi
│ ├── SmapiSoapControllerDependencies.cs
│ ├── ResponseFormattingExtensions.cs
│ └── SmapiSoapController.cs
├── SmapiService.cs
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── ServerRegistrationService.cs
├── DiscoveryAndRegistration
│ └── PlayerWebInterface.cs
└── OpenSonos.LocalMusicServer.csproj
├── OpenSonos
├── packages.config
├── SonosPlayer.cs
├── SonosServer
│ ├── ISonosMetadataApi.cs
│ ├── Metadata
│ │ ├── Presentation.cs
│ │ └── PresentationMap.cs
│ ├── ServerBase.cs
│ └── ISonosApi.cs
├── Properties
│ └── AssemblyInfo.cs
├── LocalMusicServerFactory.cs
├── Players.cs
└── OpenSonos.csproj
├── OpenSonos.Test.Unit
├── Properties
│ └── AssemblyInfo.cs
└── OpenSonos.Test.Unit.csproj
├── OpenSonos.sln
├── .gitignore
├── README.md
├── LICENSE
└── Sonos.wsdl
/OpenSonos.LocalMusicServer.Test.Unit/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/IRepresentAResource.cs:
--------------------------------------------------------------------------------
1 | namespace OpenSonos.LocalMusicServer.Browsing
2 | {
3 | public interface IRepresentAResource
4 | {
5 | SonosIdentifier Identifier { get; }
6 | string DisplayName { get; }
7 | }
8 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/IIdentityProvider.cs:
--------------------------------------------------------------------------------
1 | namespace OpenSonos.LocalMusicServer.Browsing
2 | {
3 | public interface IIdentityProvider
4 | {
5 | SonosIdentifier IdFor(string path);
6 | SonosIdentifier FromRequestId(string requestedId);
7 | }
8 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/MusicRepositories/ISearchProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace OpenSonos.LocalMusicServer.Browsing.MusicRepositories
4 | {
5 | public interface ISearchProvider
6 | {
7 | List Search(string query);
8 | }
9 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/MusicRepositories/IMonitorTheFileSystemForChanges.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OpenSonos.LocalMusicServer.Browsing.MusicRepositories
4 | {
5 | public interface IMonitorTheFileSystemForChanges
6 | {
7 | void StartMonitoring(string path, Action onChange);
8 | }
9 | }
--------------------------------------------------------------------------------
/OpenSonos/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/Container.cs:
--------------------------------------------------------------------------------
1 | namespace OpenSonos.LocalMusicServer.Browsing
2 | {
3 | public class Container : PhysicalResource
4 | {
5 | public Container()
6 | {
7 | }
8 |
9 | public Container(SonosIdentifier path) : base(path)
10 | {
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/MusicFile.cs:
--------------------------------------------------------------------------------
1 | namespace OpenSonos.LocalMusicServer.Browsing
2 | {
3 | public class MusicFile : PhysicalResource
4 | {
5 | public MusicFile()
6 | {
7 | }
8 |
9 | public MusicFile(SonosIdentifier path) : base(path)
10 | {
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/IMusicRepository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OpenSonos.LocalMusicServer.Browsing
4 | {
5 | public interface IMusicRepository
6 | {
7 | DateTime LastUpdate { get; }
8 |
9 | ResourceCollection GetResources(string identifier);
10 | ResourceCollection Search(string query);
11 | }
12 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/OpenSonos/SonosPlayer.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 |
3 | namespace OpenSonos
4 | {
5 | public class SonosPlayer
6 | {
7 | public IPAddress Address { get; set; }
8 |
9 | public SonosPlayer(string address)
10 | {
11 | Address = IPAddress.Parse(address);
12 | }
13 |
14 | private static readonly SonosPlayer NoPlayer = new SonosPlayer("0.0.0.0");
15 | public static SonosPlayer None { get { return NoPlayer; } }
16 | }
17 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Bootstrapping/ServerConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 |
3 | namespace OpenSonos.LocalMusicServer.Bootstrapping
4 | {
5 | public class ServerConfiguration
6 | {
7 | public string BaseUrl { get; set; }
8 | public string BasePort { get; set; }
9 | public string MusicShare { get; set; }
10 | public IPAddress ServerIp { get; set; }
11 |
12 | public string ServerRoot { get { return "http://" + ServerIp + ":" + BasePort; } }
13 |
14 | }
15 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/OpenSonos/SonosServer/ISonosMetadataApi.cs:
--------------------------------------------------------------------------------
1 | using System.ServiceModel;
2 | using System.ServiceModel.Web;
3 | using OpenSonos.SonosServer.Metadata;
4 |
5 | namespace OpenSonos.SonosServer
6 | {
7 | [ServiceContract]
8 | [XmlSerializerFormat]
9 | public interface ISonosMetadataApi
10 | {
11 | [OperationContract]
12 | [WebGet(UriTemplate = "presentation-maps", BodyStyle = WebMessageBodyStyle.Bare)]
13 | [ServiceKnownType(typeof(PresentationMap))]
14 | Presentation GetPresentationMaps();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/ResourceCollection.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace OpenSonos.LocalMusicServer.Browsing
4 | {
5 | public class ResourceCollection : List
6 | {
7 | public SonosIdentifier Identifier { get; set; }
8 |
9 | public ResourceCollection(SonosIdentifier identifier, IEnumerable enumerable)
10 | : this(identifier)
11 | {
12 | AddRange(enumerable);
13 | }
14 |
15 | public ResourceCollection(SonosIdentifier identifier)
16 | {
17 | Identifier = identifier;
18 | }
19 |
20 | public ResourceCollection()
21 | {
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer.Test.Unit/Browsing/SonosIdentifierTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 | using OpenSonos.LocalMusicServer.Browsing;
3 |
4 | namespace OpenSonos.LocalMusicServer.Test.Unit.Browsing
5 | {
6 | [TestFixture]
7 | public class SonosIdentifierTests
8 | {
9 | [TestCase("\\\\some\\path", true)]
10 | [TestCase("\\\\some\\path\\file.mp3", false)]
11 | public void CreatedWithAPath_IsDirectoryIsAccurate(string path, bool isDirectory)
12 | {
13 | var si = new SonosIdentifier {Path = path};
14 |
15 | Assert.That(si.IsDirectory, Is.EqualTo(isDirectory));
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/ConvertPathsToSha1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 | using System.Text;
4 |
5 | namespace OpenSonos.LocalMusicServer.Browsing
6 | {
7 | public class ConvertPathsToSha1
8 | {
9 | private readonly SHA1CryptoServiceProvider _sha;
10 |
11 | public ConvertPathsToSha1()
12 | {
13 | _sha = new SHA1CryptoServiceProvider();
14 | }
15 |
16 | public string IdentifierFor(string path)
17 | {
18 | var bytes = _sha.ComputeHash(Encoding.ASCII.GetBytes(path));
19 | return BitConverter.ToString(bytes).Replace("-", "").ToLower();
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Smapi/SmapiSoapControllerDependencies.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using OpenSonos.LocalMusicServer.Browsing;
3 |
4 | namespace OpenSonos.LocalMusicServer.Smapi
5 | {
6 | public class SmapiSoapControllerDependencies
7 | {
8 | public Guid Id { get; set; }
9 | public IMusicRepository MusicRepository { get; set; }
10 | public IIdentityProvider IdentityProvider { get; set; }
11 |
12 | public SmapiSoapControllerDependencies(IMusicRepository musicRepository, IIdentityProvider identityProvider)
13 | {
14 | Id = Guid.NewGuid();
15 | MusicRepository = musicRepository;
16 | IdentityProvider = identityProvider;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/OpenSonos/SonosServer/Metadata/Presentation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Xml.Serialization;
4 |
5 | namespace OpenSonos.SonosServer.Metadata
6 | {
7 | [Serializable]
8 | [XmlRoot("Presentation")]
9 | public class Presentation
10 | {
11 | [XmlElement("PresentationMap")]
12 | public List PresentationMaps;
13 |
14 | public Presentation()
15 | {
16 | }
17 |
18 | public Presentation(PresentationMap singleMap)
19 | {
20 | PresentationMaps = new List
21 | {
22 | PresentationMap.DefaultSonosSearch()
23 | };
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer.Test.Unit/Bootstrapping/ServerConfigurationTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using NUnit.Framework;
3 | using OpenSonos.LocalMusicServer.Bootstrapping;
4 |
5 | namespace OpenSonos.LocalMusicServer.Test.Unit.Bootstrapping
6 | {
7 | [TestFixture]
8 | public class ServerConfigurationTests
9 | {
10 | [Test]
11 | public void ServerRoot_CalculatedBaseOnServerIpAndPort()
12 | {
13 | var sc = new ServerConfiguration
14 | {
15 | ServerIp = IPAddress.Parse("127.0.0.1"),
16 | BasePort = "80"
17 | };
18 |
19 | Assert.That(sc.ServerRoot, Is.EqualTo("http://127.0.0.1:80"));
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Bootstrapping/ServerConfigurationFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Net;
3 | using System.Net.Sockets;
4 |
5 | namespace OpenSonos.LocalMusicServer.Bootstrapping
6 | {
7 | public static class ServerConfigurationFactory
8 | {
9 | public static ServerConfiguration LoadConfiguration()
10 | {
11 | var appSetting = new System.Configuration.Abstractions.ConfigurationManager();
12 | var cfg = appSetting.AppSettings.Map();
13 | cfg.ServerIp = GetIp();
14 | return cfg;
15 | }
16 |
17 | private static IPAddress GetIp()
18 | {
19 | var host = Dns.GetHostEntry(Dns.GetHostName());
20 | return host.AddressList.First(x => x.AddressFamily == AddressFamily.InterNetwork);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/SonosIdentifier.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace OpenSonos.LocalMusicServer.Browsing
4 | {
5 | public class SonosIdentifier
6 | {
7 | public string Id { get; set; }
8 | public string Path { get; set; }
9 |
10 | public bool IsDirectory
11 | {
12 | get { return Path == null || !Path.EndsWith(".mp3"); }
13 | }
14 |
15 | public string Uri
16 | {
17 | get { return "x-file-cifs:" + Path.Replace("\\", "/"); }
18 | }
19 |
20 | public SonosIdentifier()
21 | {
22 | Id = string.Empty;
23 | Path = string.Empty;
24 | }
25 |
26 | public static SonosIdentifier Default(string rootPath)
27 | {
28 | return new SonosIdentifier {Id = Guid.Empty.ToString(), Path = rootPath};
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Browsing/PhysicalResource.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 |
3 | namespace OpenSonos.LocalMusicServer.Browsing
4 | {
5 | public abstract class PhysicalResource : IRepresentAResource
6 | {
7 | public SonosIdentifier Identifier { get; set; }
8 | public string DisplayName { get { return Identifier.Path.Split('\\').Last(); } }
9 |
10 | public PhysicalResource()
11 | {
12 | }
13 |
14 | protected PhysicalResource(SonosIdentifier identifier)
15 | {
16 | Identifier = identifier;
17 | }
18 |
19 | public static PhysicalResource FromId(SonosIdentifier identifier)
20 | {
21 | return identifier.IsDirectory
22 | ? (PhysicalResource) new Container(identifier)
23 | : new MusicFile(identifier);
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/SmapiService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ServiceModel;
3 | using OpenSonos.LocalMusicServer.Bootstrapping;
4 | using SimpleServices;
5 |
6 | namespace OpenSonos.LocalMusicServer
7 | {
8 | public class SmapiService : IWindowsService
9 | {
10 | public ApplicationContext AppContext { get; set; }
11 |
12 | private readonly ServiceHost _server;
13 |
14 | public SmapiService(LocalMusicServerFactory localMusicServerFactory, ServerConfiguration config)
15 | {
16 | _server = localMusicServerFactory.HostedAt(new Uri(config.BaseUrl + ":" + config.BasePort));
17 | }
18 |
19 | public void Start(string[] args)
20 | {
21 | _server.Open();
22 | }
23 |
24 | public void Stop()
25 | {
26 | _server.Close(new TimeSpan(0, 0, 0, 10));
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/OpenSonos.LocalMusicServer/Bootstrapping/SimpleServicesToNinject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Ninject;
4 | using SimpleServices;
5 |
6 | namespace OpenSonos.LocalMusicServer.Bootstrapping
7 | {
8 | public class SimpleServicesToNinject : IIocContainer
9 | {
10 | private readonly IKernel _kernel;
11 |
12 | public SimpleServicesToNinject(IKernel kernel)
13 | {
14 | _kernel = kernel;
15 | }
16 |
17 | public T GetType()
18 | {
19 | return _kernel.Get();
20 | }
21 |
22 | public IEnumerable GetAll()
23 | {
24 | return _kernel.GetAll();
25 | }
26 |
27 | public object Get(Type t)
28 | {
29 | return _kernel.Get(t);
30 | }
31 |
32 | public IEnumerable