diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 5b18a2b7c2..a6fa187d4c 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -860,55 +860,35 @@ namespace Emby.Dlna.Didl { AddCommonFields(item, itemStubType, context, writer, filter); - var audio = item as Audio; + var hasArtists = item as IHasArtist; + var hasAlbumArtists = item as IHasAlbumArtist; - if (audio != null) + if (hasArtists != null) { - foreach (var artist in audio.Artists) + foreach (var artist in hasArtists.Artists) { AddValue(writer, "upnp", "artist", artist, NS_UPNP); - } + AddValue(writer, "dc", "creator", artist, NS_DC); - if (!string.IsNullOrEmpty(audio.Album)) - { - AddValue(writer, "upnp", "album", audio.Album, NS_UPNP); - } - - foreach (var artist in audio.AlbumArtists) - { - AddAlbumArtist(writer, artist); + // If it doesn't support album artists (musicvideo), then tag as both + if (hasAlbumArtists == null) + { + AddAlbumArtist(writer, artist); + } } } - var album = item as MusicAlbum; - - if (album != null) + if (hasAlbumArtists != null) { - foreach (var artist in album.AlbumArtists) + foreach (var albumArtist in hasAlbumArtists.AlbumArtists) { - AddAlbumArtist(writer, artist); - AddValue(writer, "upnp", "artist", artist, NS_UPNP); - } - foreach (var artist in album.Artists) - { - AddValue(writer, "upnp", "artist", artist, NS_UPNP); + AddAlbumArtist(writer, albumArtist); } } - var musicVideo = item as MusicVideo; - - if (musicVideo != null) + if (!string.IsNullOrWhiteSpace(item.Album)) { - foreach (var artist in musicVideo.Artists) - { - AddValue(writer, "upnp", "artist", artist, NS_UPNP); - AddAlbumArtist(writer, artist); - } - - if (!string.IsNullOrEmpty(musicVideo.Album)) - { - AddValue(writer, "upnp", "album", musicVideo.Album, NS_UPNP); - } + AddValue(writer, "upnp", "album", item.Album, NS_UPNP); } if (item.IndexNumber.HasValue) diff --git a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs index 4a33012529..0208183614 100644 --- a/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs +++ b/Emby.Server.Implementations/Channels/RefreshChannelsScheduledTask.cs @@ -9,7 +9,7 @@ using MediaBrowser.Model.Tasks; namespace Emby.Server.Implementations.Channels { - class RefreshChannelsScheduledTask : IScheduledTask + class RefreshChannelsScheduledTask : IScheduledTask, IConfigurableScheduledTask { private readonly IChannelManager _channelManager; private readonly IUserManager _userManager; @@ -39,6 +39,21 @@ namespace Emby.Server.Implementations.Channels get { return "Internet Channels"; } } + public bool IsHidden + { + get { return ((ChannelManager)_channelManager).Channels.Length == 0; } + } + + public bool IsEnabled + { + get { return true; } + } + + public bool IsLogged + { + get { return true; } + } + public async Task Execute(System.Threading.CancellationToken cancellationToken, IProgress progress) { var manager = (ChannelManager)_channelManager; @@ -65,15 +80,5 @@ namespace Emby.Server.Implementations.Channels { get { return "RefreshInternetChannels"; } } - - public bool IsHidden - { - get { return false; } - } - - public bool IsEnabled - { - get { return true; } - } } } diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index ef95b47c38..cd7c98dc85 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -124,18 +124,6 @@ namespace Emby.Server.Implementations.HttpClientManager } } - private void AddIpv4Option(HttpWebRequest request, HttpRequestOptions options) - { - request.ServicePoint.BindIPEndPointDelegate = (servicePount, remoteEndPoint, retryCount) => - { - if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) - { - return new IPEndPoint(IPAddress.Any, 0); - } - throw new InvalidOperationException("no IPv4 address"); - }; - } - private WebRequest GetRequest(HttpRequestOptions options, string method) { var url = options.Url; @@ -153,11 +141,6 @@ namespace Emby.Server.Implementations.HttpClientManager if (httpWebRequest != null) { - if (options.PreferIpv4) - { - AddIpv4Option(httpWebRequest, options); - } - AddRequestHeaders(httpWebRequest, options); if (options.EnableHttpCompression) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index cac1cb3b4b..bd8a095503 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -506,7 +506,7 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException("type"); } - if (ConfigurationManager.Configuration.EnableLocalizedGuids && key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath)) + if (key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath)) { // Try to normalize paths located underneath program-data in an attempt to make them more portable key = key.Substring(ConfigurationManager.ApplicationPaths.ProgramDataPath.Length) diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index b3c7ecc9f3..e210e2224e 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -653,6 +653,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings // Schedules direct requires that the client support compression and will return a 400 response without it options.EnableHttpCompression = true; + // On windows 7 under .net core, this header is not getting added +#if NETSTANDARD2_0 + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + options.RequestHeaders["Accept-Encoding"] = "deflate"; + } +#endif + try { return await _httpClient.Post(options).ConfigureAwait(false); @@ -684,6 +692,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings // Schedules direct requires that the client support compression and will return a 400 response without it options.EnableHttpCompression = true; + // On windows 7 under .net core, this header is not getting added +#if NETSTANDARD2_0 + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + options.RequestHeaders["Accept-Encoding"] = "deflate"; + } +#endif + try { return await _httpClient.SendAsync(options, "GET").ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index 66b2cba39b..72d0154aa5 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -103,7 +103,10 @@ namespace Emby.Server.Implementations.Networking } return endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("127.0.0.1", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase) || + endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || IsInPrivateAddressSpaceAndLocalSubnet(endpoint); } @@ -111,46 +114,42 @@ namespace Emby.Server.Implementations.Networking { var endpointFirstPart = endpoint.Split('.')[0]; - string subnet_Match = ""; - if ( - endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) || - endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase) - ) + if (endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase)) { - foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces()) - foreach (UnicastIPAddressInformation unicastIPAddressInformation in adapter.GetIPProperties().UnicastAddresses) - if (unicastIPAddressInformation.Address.AddressFamily == AddressFamily.InterNetwork && endpointFirstPart == unicastIPAddressInformation.Address.ToString().Split('.')[0]) - { - int subnet_Test = 0; - foreach (string part in unicastIPAddressInformation.IPv4Mask.ToString().Split('.')) - { - if (part.Equals("0")) break; - subnet_Test++; - } + var subnets = GetSubnets(endpointFirstPart); - subnet_Match = String.Join(".", unicastIPAddressInformation.Address.ToString().Split('.').Take(subnet_Test).ToArray()); - } + foreach (var subnet_Match in subnets) + { + //Logger.Debug("subnet_Match:" + subnet_Match); + + if (endpoint.StartsWith(subnet_Match + ".", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } } - return endpoint.StartsWith(subnet_Match + ".", StringComparison.OrdinalIgnoreCase); + return false; } - private Dictionary _subnetLookup = new Dictionary(StringComparer.Ordinal); - private string GetSubnet(string endpointFirstPart) + private Dictionary> _subnetLookup = new Dictionary>(StringComparer.Ordinal); + private List GetSubnets(string endpointFirstPart) { - string subnet_Match = ""; + List subnets; lock (_subnetLookup) { - if (_subnetLookup.TryGetValue(endpointFirstPart, out subnet_Match)) + if (_subnetLookup.TryGetValue(endpointFirstPart, out subnets)) { - return subnet_Match; + return subnets; } + subnets = new List(); + foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces()) + { foreach (UnicastIPAddressInformation unicastIPAddressInformation in adapter.GetIPProperties().UnicastAddresses) + { if (unicastIPAddressInformation.Address.AddressFamily == AddressFamily.InterNetwork && endpointFirstPart == unicastIPAddressInformation.Address.ToString().Split('.')[0]) { int subnet_Test = 0; @@ -160,16 +159,21 @@ namespace Emby.Server.Implementations.Networking subnet_Test++; } - subnet_Match = String.Join(".", unicastIPAddressInformation.Address.ToString().Split('.').Take(subnet_Test).ToArray()); + var subnet_Match = String.Join(".", unicastIPAddressInformation.Address.ToString().Split('.').Take(subnet_Test).ToArray()); + + // TODO: Is this check necessary? + if (adapter.OperationalStatus == OperationalStatus.Up) + { + subnets.Add(subnet_Match); + } } - - if (!string.IsNullOrWhiteSpace(subnet_Match)) - { - _subnetLookup[endpointFirstPart] = subnet_Match; + } } - } - return subnet_Match; + _subnetLookup[endpointFirstPart] = subnets; + + return subnets; + } } private bool Is172AddressPrivate(string endpoint) diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 52a5e444f3..1ccb683204 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -91,7 +91,6 @@ namespace MediaBrowser.Api { config.EnableCaseSensitiveItemIds = true; config.SkipDeserializationForBasicTypes = true; - config.EnableLocalizedGuids = true; config.EnableSimpleArtistDetection = true; config.EnableNormalizedItemByNameIds = true; config.DisableLiveTvChannelUserDataName = true; diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs index 51859ecdb5..0a279fa9cc 100644 --- a/MediaBrowser.Common/Net/HttpRequestOptions.cs +++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs @@ -101,7 +101,6 @@ namespace MediaBrowser.Common.Net public TimeSpan CacheLength { get; set; } public int TimeoutMs { get; set; } - public bool PreferIpv4 { get; set; } public bool EnableDefaultUserAgent { get; set; } public bool AppendCharsetToMimeType { get; set; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ce7145a791..12183aec2f 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1266,7 +1266,7 @@ namespace MediaBrowser.Controller.Entities var childOwner = child.IsOwnedItem ? (child.GetOwner() ?? child) : child; - if (childOwner != null) + if (childOwner != null && !(child is IItemByName)) { var childLocationType = childOwner.LocationType; if (childLocationType == LocationType.Remote || childLocationType == LocationType.Virtual) diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 65b054b0c7..f2c3b7cc8a 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -46,7 +46,6 @@ namespace MediaBrowser.Model.Configuration /// /// true if [use HTTPS]; otherwise, false. public bool EnableHttps { get; set; } - public bool EnableLocalizedGuids { get; set; } public bool EnableNormalizedItemByNameIds { get; set; } /// @@ -198,7 +197,6 @@ namespace MediaBrowser.Model.Configuration LocalNetworkAddresses = new string[] { }; CodecsUsed = new string[] { }; ImageExtractionTimeoutMs = 0; - EnableLocalizedGuids = true; PathSubstitutions = new PathSubstitution[] { }; EnableSimpleArtistDetection = true; diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index a11c886974..20de247a6a 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -1099,15 +1099,6 @@ namespace MediaBrowser.Model.Dlna { string audioCodec = audioStream.Codec; - if (string.IsNullOrEmpty(audioCodec)) - { - _logger.Info("Profile: {0}, DirectPlay=false. Reason=Unknown audio codec. Path: {1}", - profile.Name ?? "Unknown Profile", - mediaSource.Path ?? "Unknown path"); - - return new Tuple>(null, new List { TranscodeReason.UnknownAudioStreamInfo }); - } - conditions = new List(); bool? isSecondaryAudio = audioStream == null ? null : mediaSource.IsSecondaryAudio(audioStream); diff --git a/MediaBrowser.Model/Providers/RemoteSearchResult.cs b/MediaBrowser.Model/Providers/RemoteSearchResult.cs index 72b6632e4c..fdff7ba462 100644 --- a/MediaBrowser.Model/Providers/RemoteSearchResult.cs +++ b/MediaBrowser.Model/Providers/RemoteSearchResult.cs @@ -34,6 +34,8 @@ namespace MediaBrowser.Model.Providers public string GameSystem { get; set; } public string Overview { get; set; } + public RemoteSearchResult AlbumArtist { get; set; } + public RemoteSearchResult() { ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 9dd5052dae..cdef42771a 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -948,7 +948,8 @@ namespace MediaBrowser.Providers.Manager } else { - throw new Exception(string.Format("Refresh for item {0} {1} is not in progress", item.GetType().Name, item.Id.ToString("N"))); + // TODO: Need to hunt down the conditions for this happening + //throw new Exception(string.Format("Refresh for item {0} {1} is not in progress", item.GetType().Name, item.Id.ToString("N"))); } } } diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index b54d14935e..3befca4289 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -117,6 +117,17 @@ namespace MediaBrowser.Providers.Music ProductionYear = i.Year }; + if (i.Artists.Count > 0) + { + result.AlbumArtist = new RemoteSearchResult + { + SearchProviderName = Name, + Name = i.Artists[0].Item1 + }; + + result.AlbumArtist.SetProviderId(MetadataProviders.MusicBrainzArtist, i.Artists[0].Item2); + } + if (!string.IsNullOrWhiteSpace(i.ReleaseId)) { result.SetProviderId(MetadataProviders.MusicBrainzAlbum, i.ReleaseId); @@ -285,6 +296,8 @@ namespace MediaBrowser.Providers.Music public string Overview; public int? Year; + public List> Artists = new List>(); + public static List Parse(XmlReader reader) { reader.MoveToContent(); @@ -417,6 +430,32 @@ namespace MediaBrowser.Providers.Music { result.ReleaseGroupId = reader.GetAttribute("id"); reader.Skip(); + break; + } + case "artist-credit": + { + // TODO + + /* + * + + +SARCASTIC+ZOOKEEPER +SARCASTIC+ZOOKEEPER + + + + */ + using (var subReader = reader.ReadSubtree()) + { + var artist = ParseArtistCredit(subReader); + + if (artist != null) + { + result.Artists.Add(artist); + } + } + break; } default: @@ -436,6 +475,130 @@ namespace MediaBrowser.Providers.Music } } + private static Tuple ParseArtistCredit(XmlReader reader) + { + reader.MoveToContent(); + reader.Read(); + + // http://stackoverflow.com/questions/2299632/why-does-xmlreader-skip-every-other-element-if-there-is-no-whitespace-separator + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "name-credit": + { + using (var subReader = reader.ReadSubtree()) + { + return ParseArtistNameCredit(subReader); + } + } + default: + { + reader.Skip(); + break; + } + } + } + else + { + reader.Read(); + } + } + + return null; + } + + private static Tuple ParseArtistNameCredit(XmlReader reader) + { + reader.MoveToContent(); + reader.Read(); + + string name = null; + + // http://stackoverflow.com/questions/2299632/why-does-xmlreader-skip-every-other-element-if-there-is-no-whitespace-separator + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "artist": + { + var id = reader.GetAttribute("id"); + using (var subReader = reader.ReadSubtree()) + { + return ParseArtistArtistCredit(subReader, id); + } + } + default: + { + reader.Skip(); + break; + } + } + } + else + { + reader.Read(); + } + } + + if (string.IsNullOrWhiteSpace(name)) + { + return null; + } + + return new Tuple(name, null); + } + + private static Tuple ParseArtistArtistCredit(XmlReader reader, string artistId) + { + reader.MoveToContent(); + reader.Read(); + + string name = null; + + // http://stackoverflow.com/questions/2299632/why-does-xmlreader-skip-every-other-element-if-there-is-no-whitespace-separator + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "name": + { + name = reader.ReadElementContentAsString(); + break; + } + default: + { + reader.Skip(); + break; + } + } + } + else + { + reader.Read(); + } + } + + if (string.IsNullOrWhiteSpace(name)) + { + return null; + } + + return new Tuple(name, artistId); + } + private async Task GetReleaseIdFromReleaseGroupId(string releaseGroupId, CancellationToken cancellationToken) { var url = string.Format("/ws/2/release?release-group={0}", releaseGroupId);