123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- using MediaBrowser.Common.Extensions;
- using MediaBrowser.Common.Net;
- using MediaBrowser.Controller.Channels;
- using MediaBrowser.Controller.Configuration;
- using MediaBrowser.Controller.Dlna;
- using MediaBrowser.Controller.Providers;
- using MediaBrowser.Dlna.ContentDirectory;
- using MediaBrowser.Dlna.PlayTo;
- using MediaBrowser.Dlna.Ssdp;
- using MediaBrowser.Model.Channels;
- using MediaBrowser.Model.Entities;
- using MediaBrowser.Model.Logging;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- namespace MediaBrowser.Dlna.Channels
- {
- public class DlnaChannelFactory : IChannelFactory, IDisposable
- {
- private readonly IServerConfigurationManager _config;
- private readonly ILogger _logger;
- private readonly IHttpClient _httpClient;
- private readonly IDeviceDiscovery _deviceDiscovery;
- private readonly SemaphoreSlim _syncLock = new SemaphoreSlim(1, 1);
- private List<Device> _servers = new List<Device>();
- public static DlnaChannelFactory Instance;
- private Func<List<string>> _localServersLookup;
- public DlnaChannelFactory(IServerConfigurationManager config, IHttpClient httpClient, ILogger logger, IDeviceDiscovery deviceDiscovery)
- {
- _config = config;
- _httpClient = httpClient;
- _logger = logger;
- _deviceDiscovery = deviceDiscovery;
- Instance = this;
- }
- internal void Start(Func<List<string>> localServersLookup)
- {
- _localServersLookup = localServersLookup;
- //deviceDiscovery.DeviceDiscovered += deviceDiscovery_DeviceDiscovered;
- _deviceDiscovery.DeviceLeft += deviceDiscovery_DeviceLeft;
- }
- async void deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
- {
- string usn;
- if (!e.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
- string nt;
- if (!e.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
- string location;
- if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
- if (!IsValid(nt, usn))
- {
- return;
- }
- if (_localServersLookup != null)
- {
- if (_localServersLookup().Any(i => usn.IndexOf(i, StringComparison.OrdinalIgnoreCase) != -1))
- {
- // Don't add the local Dlna server to this
- return;
- }
- }
- if (GetExistingServers(usn).Any())
- {
- return;
- }
- await _syncLock.WaitAsync().ConfigureAwait(false);
- try
- {
- if (GetExistingServers(usn).Any())
- {
- return;
- }
- var device = await Device.CreateuPnpDeviceAsync(new Uri(location), _httpClient, _config, _logger)
- .ConfigureAwait(false);
- if (!_servers.Any(i => string.Equals(i.Properties.UUID, device.Properties.UUID, StringComparison.OrdinalIgnoreCase)))
- {
- _servers.Add(device);
- }
- }
- catch (Exception ex)
- {
- }
- finally
- {
- _syncLock.Release();
- }
- }
- async void deviceDiscovery_DeviceLeft(object sender, SsdpMessageEventArgs e)
- {
- string usn;
- if (!e.Headers.TryGetValue("USN", out usn)) usn = String.Empty;
- string nt;
- if (!e.Headers.TryGetValue("NT", out nt)) nt = String.Empty;
- if (!IsValid(nt, usn))
- {
- return;
- }
- if (!GetExistingServers(usn).Any())
- {
- return;
- }
- await _syncLock.WaitAsync().ConfigureAwait(false);
- try
- {
- var list = _servers.ToList();
- foreach (var device in GetExistingServers(usn).ToList())
- {
- list.Remove(device);
- }
- _servers = list;
- }
- finally
- {
- _syncLock.Release();
- }
- }
- private bool IsValid(string nt, string usn)
- {
- // It has to report that it's a media renderer
- if (usn.IndexOf("ContentDirectory:", StringComparison.OrdinalIgnoreCase) == -1 &&
- nt.IndexOf("ContentDirectory:", StringComparison.OrdinalIgnoreCase) == -1 &&
- usn.IndexOf("MediaServer:", StringComparison.OrdinalIgnoreCase) == -1 &&
- nt.IndexOf("MediaServer:", StringComparison.OrdinalIgnoreCase) == -1)
- {
- return false;
- }
- return true;
- }
- private IEnumerable<Device> GetExistingServers(string usn)
- {
- return _servers
- .Where(i => usn.IndexOf(i.Properties.UUID, StringComparison.OrdinalIgnoreCase) != -1);
- }
- public IEnumerable<IChannel> GetChannels()
- {
- //if (_servers.Count > 0)
- //{
- // var service = _servers[0].Properties.Services
- // .FirstOrDefault(i => string.Equals(i.ServiceType, "urn:schemas-upnp-org:service:ContentDirectory:1", StringComparison.OrdinalIgnoreCase));
- // var controlUrl = service == null ? null : (_servers[0].Properties.BaseUrl.TrimEnd('/') + "/" + service.ControlUrl.TrimStart('/'));
- // if (!string.IsNullOrEmpty(controlUrl))
- // {
- // return new List<IChannel>
- // {
- // new ServerChannel(_servers.ToList(), _httpClient, _logger, controlUrl)
- // };
- // }
- //}
- return new List<IChannel>();
- }
- public void Dispose()
- {
- if (_deviceDiscovery != null)
- {
- _deviceDiscovery.DeviceDiscovered -= deviceDiscovery_DeviceDiscovered;
- _deviceDiscovery.DeviceLeft -= deviceDiscovery_DeviceLeft;
- }
- }
- }
- public class ServerChannel : IChannel, IFactoryChannel
- {
- private readonly IHttpClient _httpClient;
- private readonly ILogger _logger;
- public string ControlUrl { get; set; }
- public List<Device> Servers { get; set; }
- public ServerChannel(IHttpClient httpClient, ILogger logger)
- {
- _httpClient = httpClient;
- _logger = logger;
- Servers = new List<Device>();
- }
- public string Name
- {
- get { return "Devices"; }
- }
- public string Description
- {
- get { return string.Empty; }
- }
- public string DataVersion
- {
- get { return DateTime.UtcNow.Ticks.ToString(); }
- }
- public string HomePageUrl
- {
- get { return string.Empty; }
- }
- public ChannelParentalRating ParentalRating
- {
- get { return ChannelParentalRating.GeneralAudience; }
- }
- public InternalChannelFeatures GetChannelFeatures()
- {
- return new InternalChannelFeatures
- {
- ContentTypes = new List<ChannelMediaContentType>
- {
- ChannelMediaContentType.Song,
- ChannelMediaContentType.Clip
- },
- MediaTypes = new List<ChannelMediaType>
- {
- ChannelMediaType.Audio,
- ChannelMediaType.Video,
- ChannelMediaType.Photo
- }
- };
- }
- public bool IsEnabledFor(string userId)
- {
- return true;
- }
- public async Task<ChannelItemResult> GetChannelItems(InternalChannelItemQuery query, CancellationToken cancellationToken)
- {
- IEnumerable<ChannelItemInfo> items;
- if (string.IsNullOrWhiteSpace(query.FolderId))
- {
- items = Servers.Select(i => new ChannelItemInfo
- {
- FolderType = ChannelFolderType.Container,
- Id = GetServerId(i),
- Name = i.Properties.Name,
- Overview = i.Properties.ModelDescription,
- Type = ChannelItemType.Folder
- });
- }
- else
- {
- var idParts = query.FolderId.Split('|');
- var folderId = idParts.Length == 2 ? idParts[1] : null;
- var result = await new ContentDirectoryBrowser(_httpClient, _logger).Browse(new ContentDirectoryBrowseRequest
- {
- Limit = query.Limit,
- StartIndex = query.StartIndex,
- ParentId = folderId,
- ContentDirectoryUrl = ControlUrl
- }, cancellationToken).ConfigureAwait(false);
- items = result.Items.ToList();
- }
- var list = items.ToList();
- var count = list.Count;
- list = ApplyPaging(list, query).ToList();
- return new ChannelItemResult
- {
- Items = list,
- TotalRecordCount = count
- };
- }
- private string GetServerId(Device device)
- {
- return device.Properties.UUID.GetMD5().ToString("N");
- }
- private IEnumerable<T> ApplyPaging<T>(IEnumerable<T> items, InternalChannelItemQuery query)
- {
- if (query.StartIndex.HasValue)
- {
- items = items.Skip(query.StartIndex.Value);
- }
- if (query.Limit.HasValue)
- {
- items = items.Take(query.Limit.Value);
- }
- return items;
- }
- public Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken)
- {
- // TODO: Implement
- return Task.FromResult(new DynamicImageResponse
- {
- HasImage = false
- });
- }
- public IEnumerable<ImageType> GetSupportedChannelImages()
- {
- return new List<ImageType>
- {
- ImageType.Primary
- };
- }
- }
- }
|