Merge pull request #2250 from MediaBrowser/beta

Beta
pull/1154/head
Luke 8 years ago committed by GitHub
commit 367e17826e

@ -245,12 +245,8 @@ namespace MediaBrowser.Api
item.OriginalTitle = string.IsNullOrWhiteSpace(request.OriginalTitle) ? null : request.OriginalTitle;
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
{
hasCriticRating.CriticRating = request.CriticRating;
hasCriticRating.CriticRatingSummary = request.CriticRatingSummary;
}
item.CriticRating = request.CriticRating;
item.CriticRatingSummary = request.CriticRatingSummary;
item.DisplayMediaType = request.DisplayMediaType;
item.CommunityRating = request.CommunityRating;
@ -279,11 +275,7 @@ namespace MediaBrowser.Api
item.Tagline = request.Taglines.FirstOrDefault();
}
var hasShortOverview = item as IHasShortOverview;
if (hasShortOverview != null)
{
hasShortOverview.ShortOverview = request.ShortOverview;
}
item.ShortOverview = request.ShortOverview;
item.Keywords = request.Keywords;

@ -19,6 +19,7 @@ using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Api.Playback.Progressive;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Server.Implementations.LiveTv.EmbyTV;
namespace MediaBrowser.Api.LiveTv
@ -390,6 +391,7 @@ namespace MediaBrowser.Api.LiveTv
public bool? EnableUserData { get; set; }
public string SeriesTimerId { get; set; }
public string LibrarySeriesId { get; set; }
/// <summary>
/// Fields to return within the items, in addition to basic information
@ -990,6 +992,17 @@ namespace MediaBrowser.Api.LiveTv
query.SeriesTimerId = request.SeriesTimerId;
query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (!string.IsNullOrWhiteSpace(request.LibrarySeriesId))
{
query.IsSeries = true;
var series = _libraryManager.GetItemById(request.LibrarySeriesId) as Series;
if (series != null)
{
query.Name = series.Name;
}
}
var result = await _liveTvManager.GetPrograms(query, GetDtoOptions(request), CancellationToken.None).ConfigureAwait(false);
return ToOptimizedResult(result);

@ -317,13 +317,32 @@ namespace MediaBrowser.Api.Playback
}
if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(encodingOptions.VaapiDevice))
{
return GetAvailableEncoder("h264_vaapi", defaultEncoder);
if (IsVaapiSupported(state))
{
return GetAvailableEncoder("h264_vaapi", defaultEncoder);
}
}
}
return defaultEncoder;
}
private bool IsVaapiSupported(StreamState state)
{
var videoStream = state.VideoStream;
if (videoStream != null)
{
// vaapi will throw an error with this input
// [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99.
if (string.Equals(videoStream.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase) && videoStream.Level == -99)
{
return false;
}
}
return true;
}
private string GetAvailableEncoder(string preferredEncoder, string defaultEncoder)
{
if (MediaEncoder.SupportsEncoder(preferredEncoder))

@ -887,7 +887,6 @@ namespace MediaBrowser.Api.Playback.Hls
var mapArgs = state.IsOutputVideo ? GetMapArgs(state) : string.Empty;
var enableSplittingOnNonKeyFrames = state.VideoRequest.EnableSplittingOnNonKeyFrames && string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase);
enableSplittingOnNonKeyFrames = false;
// TODO: check libavformat version for 57 50.100 and use -hls_flags split_by_time
var hlsProtocolSupportsSplittingByTime = false;

@ -125,7 +125,7 @@ namespace MediaBrowser.Api.Playback
SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate,
request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex,
request.SubtitleStreamIndex, request.PlaySessionId, request.UserId);
request.SubtitleStreamIndex, request.MaxAudioChannels, request.PlaySessionId, request.UserId);
}
else
{
@ -167,7 +167,7 @@ namespace MediaBrowser.Api.Playback
{
var mediaSourceId = request.MediaSourceId;
SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.UserId);
SetDeviceSpecificData(request.Id, info, profile, authInfo, request.MaxStreamingBitrate ?? profile.MaxStreamingBitrate, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex, request.MaxAudioChannels, request.UserId);
}
return ToOptimizedResult(info);
@ -230,13 +230,14 @@ namespace MediaBrowser.Api.Playback
string mediaSourceId,
int? audioStreamIndex,
int? subtitleStreamIndex,
int? maxAudioChannels,
string userId)
{
var item = _libraryManager.GetItemById(itemId);
foreach (var mediaSource in result.MediaSources)
{
SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, result.PlaySessionId, userId);
SetDeviceSpecificData(item, mediaSource, profile, auth, maxBitrate, startTimeTicks, mediaSourceId, audioStreamIndex, subtitleStreamIndex, maxAudioChannels, result.PlaySessionId, userId);
}
SortMediaSources(result, maxBitrate);
@ -251,6 +252,7 @@ namespace MediaBrowser.Api.Playback
string mediaSourceId,
int? audioStreamIndex,
int? subtitleStreamIndex,
int? maxAudioChannels,
string playSessionId,
string userId)
{
@ -262,7 +264,8 @@ namespace MediaBrowser.Api.Playback
Context = EncodingContext.Streaming,
DeviceId = auth.DeviceId,
ItemId = item.Id.ToString("N"),
Profile = profile
Profile = profile,
MaxAudioChannels = maxAudioChannels
};
if (string.Equals(mediaSourceId, mediaSource.Id, StringComparison.OrdinalIgnoreCase))

@ -127,7 +127,9 @@ namespace MediaBrowser.Common.Implementations.Logging
{
for (var i = 0; i < paramList.Length; i++)
{
message = message.Replace("{" + i + "}", paramList[i].ToString());
var obj = paramList[i];
message = message.Replace("{" + i + "}", (obj == null ? "null" : obj.ToString()));
}
}

@ -1,8 +0,0 @@
using System;
namespace MediaBrowser.Controller.Dlna
{
public interface ISsdpHandler
{
}
}

@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class BaseItem
/// </summary>
public abstract class BaseItem : IHasProviderIds, ILibraryItem, IHasImages, IHasUserData, IHasMetadata, IHasLookupInfo<ItemLookupInfo>
public abstract class BaseItem : IHasProviderIds, IHasImages, IHasUserData, IHasMetadata, IHasLookupInfo<ItemLookupInfo>
{
protected BaseItem()
{

@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Entities
/// Plugins derive from and export this class to create a folder that will appear in the root along
/// with all the other actual physical folders in the system.
/// </summary>
public abstract class BasePluginFolder : Folder, ICollectionFolder, IByReferenceItem
public abstract class BasePluginFolder : Folder, ICollectionFolder
{
public virtual string CollectionType
{

@ -1,12 +0,0 @@

namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// This is a marker class that tells us that a particular item type may be physically resolved
/// more than once within the library and we need to be sure to resolve them all to the same
/// instance of that item.
/// </summary>
public interface IByReferenceItem
{
}
}

@ -1,20 +0,0 @@
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasCriticRating
/// </summary>
public interface IHasCriticRating
{
/// <summary>
/// Gets or sets the critic rating.
/// </summary>
/// <value>The critic rating.</value>
float? CriticRating { get; set; }
/// <summary>
/// Gets or sets the critic rating summary.
/// </summary>
/// <value>The critic rating summary.</value>
string CriticRatingSummary { get; set; }
}
}

@ -1,12 +0,0 @@

namespace MediaBrowser.Controller.Entities
{
public interface IHasShortOverview
{
/// <summary>
/// Gets or sets the short overview.
/// </summary>
/// <value>The short overview.</value>
string ShortOverview { get; set; }
}
}

@ -1,28 +0,0 @@
using System;
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface ILibraryItem
/// </summary>
public interface ILibraryItem
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
string Name { get; }
/// <summary>
/// Gets the id.
/// </summary>
/// <value>The id.</value>
Guid Id { get; }
/// <summary>
/// Gets the path.
/// </summary>
/// <value>The path.</value>
string Path { get; }
}
}

@ -1,10 +0,0 @@
using System;
namespace MediaBrowser.Controller.Entities
{
public class ImageSourceInfo
{
public Guid ImagePathMD5 { get; set; }
public Guid ImageUrlMD5 { get; set; }
}
}

@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <summary>
/// Class Movie
/// </summary>
public class Movie : Video, IHasCriticRating, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
public class Movie : Video, IHasSpecialFeatures, IHasBudget, IHasTrailers, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
{
public List<Guid> SpecialFeatureIds { get; set; }

@ -36,7 +36,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
return true;
return false;
}
}

@ -10,7 +10,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Class Trailer
/// </summary>
public class Trailer : Video, IHasCriticRating, IHasBudget, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
public class Trailer : Video, IHasBudget, IHasMetascore, IHasOriginalTitle, IHasLookupInfo<TrailerInfo>
{
public Trailer()
{

@ -1668,16 +1668,7 @@ namespace MediaBrowser.Controller.Entities
{
var val = query.MinCriticRating.Value;
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
{
if (!(hasCriticRating.CriticRating.HasValue && hasCriticRating.CriticRating >= val))
{
return false;
}
}
else
if (!(item.CriticRating.HasValue && item.CriticRating >= val))
{
return false;
}

@ -24,7 +24,6 @@ namespace MediaBrowser.Controller.Entities
IHasAspectRatio,
ISupportsPlaceHolders,
IHasMediaSources,
IHasShortOverview,
IThemeMedia
{
[IgnoreDataMember]

@ -78,14 +78,17 @@ namespace MediaBrowser.Controller.LiveTv
protected override string CreateSortName()
{
double number = 0;
if (!string.IsNullOrEmpty(Number))
{
double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number);
double number = 0;
if (double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number))
{
return number.ToString("00000-") + (Name ?? string.Empty);
}
}
return number.ToString("00000-") + (Name ?? string.Empty);
return Number + "-" + (Name ?? string.Empty);
}
[IgnoreDataMember]

@ -111,7 +111,6 @@
<Compile Include="Dlna\IDlnaManager.cs" />
<Compile Include="Dlna\IEventManager.cs" />
<Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
<Compile Include="Dlna\ISsdpHandler.cs" />
<Compile Include="Dlna\IUpnpService.cs" />
<Compile Include="Dlna\SsdpMessageEventArgs.cs" />
<Compile Include="Drawing\IImageProcessor.cs" />
@ -132,10 +131,8 @@
<Compile Include="Entities\Game.cs" />
<Compile Include="Entities\GameGenre.cs" />
<Compile Include="Entities\GameSystem.cs" />
<Compile Include="Entities\IByReferenceItem.cs" />
<Compile Include="Entities\IHasAspectRatio.cs" />
<Compile Include="Entities\IHasBudget.cs" />
<Compile Include="Entities\IHasCriticRating.cs" />
<Compile Include="Entities\IHasDisplayOrder.cs" />
<Compile Include="Entities\IHasId.cs" />
<Compile Include="Entities\IHasImages.cs" />
@ -146,15 +143,12 @@
<Compile Include="Entities\IHasProgramAttributes.cs" />
<Compile Include="Entities\IHasScreenshots.cs" />
<Compile Include="Entities\IHasSeries.cs" />
<Compile Include="Entities\IHasShortOverview.cs" />
<Compile Include="Entities\IHasSpecialFeatures.cs" />
<Compile Include="Entities\IHasStartDate.cs" />
<Compile Include="Entities\IHasTrailers.cs" />
<Compile Include="Entities\IHasUserData.cs" />
<Compile Include="Entities\IHiddenFromDisplay.cs" />
<Compile Include="Entities\IItemByName.cs" />
<Compile Include="Entities\ILibraryItem.cs" />
<Compile Include="Entities\ImageSourceInfo.cs" />
<Compile Include="Entities\IMetadataContainer.cs" />
<Compile Include="Entities\InternalItemsQuery.cs" />
<Compile Include="Entities\InternalPeopleQuery.cs" />

@ -185,14 +185,12 @@ namespace MediaBrowser.Controller.Providers
{
var text = reader.ReadElementContentAsString();
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null && !string.IsNullOrEmpty(text))
if (!string.IsNullOrEmpty(text))
{
float value;
if (float.TryParse(text, NumberStyles.Any, _usCulture, out value))
{
hasCriticRating.CriticRating = value;
item.CriticRating = value;
}
}
@ -292,12 +290,7 @@ namespace MediaBrowser.Controller.Providers
if (!string.IsNullOrWhiteSpace(val))
{
var hasShortOverview = item as IHasShortOverview;
if (hasShortOverview != null)
{
hasShortOverview.ShortOverview = val;
}
item.ShortOverview = val;
}
break;
@ -309,12 +302,7 @@ namespace MediaBrowser.Controller.Providers
if (!string.IsNullOrWhiteSpace(val))
{
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
{
hasCriticRating.CriticRatingSummary = val;
}
item.CriticRatingSummary = val;
}
break;

@ -12,7 +12,6 @@ namespace MediaBrowser.Controller.Providers
public Stream Stream { get; set; }
public ImageFormat Format { get; set; }
public bool HasImage { get; set; }
public string InternalCacheKey { get; set; }
public void SetFormatFromMimeType(string mimeType)
{

@ -69,28 +69,8 @@ namespace MediaBrowser.Controller.Providers
/// <summary>
/// Saves the image.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="source">The source.</param>
/// <param name="mimeType">Type of the MIME.</param>
/// <param name="type">The type.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <param name="internalCacheKey">The internal cache key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken);
/// <summary>
/// Saves the image.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="source">The source.</param>
/// <param name="mimeType">Type of the MIME.</param>
/// <param name="type">The type.</param>
/// <param name="imageIndex">Index of the image.</param>
/// <param name="internalCacheKey">The internal cache key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken);
Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken);
/// <summary>
/// Adds the metadata providers.

@ -585,10 +585,9 @@ namespace MediaBrowser.Dlna.Didl
{
var desc = item.Overview;
var hasShortOverview = item as IHasShortOverview;
if (hasShortOverview != null && !string.IsNullOrEmpty(hasShortOverview.ShortOverview))
if (!string.IsNullOrEmpty(item.ShortOverview))
{
desc = hasShortOverview.ShortOverview;
desc = item.ShortOverview;
}
if (!string.IsNullOrWhiteSpace(desc))
@ -697,16 +696,36 @@ namespace MediaBrowser.Dlna.Didl
private void AddPeople(BaseItem item, XmlElement element)
{
var types = new[] { PersonType.Director, PersonType.Writer, PersonType.Producer, PersonType.Composer, "Creator" };
var types = new[]
{
PersonType.Director,
PersonType.Writer,
PersonType.Producer,
PersonType.Composer,
"Creator"
};
var people = _libraryManager.GetPeople(item);
var index = 0;
// Seeing some LG models locking up due content with large lists of people
// The actual issue might just be due to processing a more metadata than it can handle
var limit = 10;
foreach (var actor in people)
{
var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
?? PersonType.Actor;
AddValue(element, "upnp", type.ToLower(), actor.Name, NS_UPNP);
index++;
if (index >= limit)
{
break;
}
}
}

@ -19,6 +19,7 @@ using System.Net;
using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding;
using Rssdp;
using Rssdp.Infrastructure;
namespace MediaBrowser.Dlna.Main
{
@ -154,8 +155,14 @@ namespace MediaBrowser.Dlna.Main
}
}
private void LogMessage(string msg)
{
//_logger.Debug(msg);
}
private void StartPublishing()
{
SsdpDevicePublisherBase.LogFunction = LogMessage;
_Publisher = new SsdpDevicePublisher();
}
@ -235,48 +242,71 @@ namespace MediaBrowser.Dlna.Main
var addressString = address.ToString();
var udn = (addressString).GetMD5().ToString("N");
var udn = CreateUuid(addressString);
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
_logger.Info("Registering publisher for {0} on {1}", fullService, addressString);
var descriptorUri = "/dlna/" + udn + "/description.xml";
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
var services = new List<string>
var device = new SsdpRootDevice
{
CacheLifetime = TimeSpan.FromSeconds(cacheLength), //How long SSDP clients can cache this info.
Location = uri, // Must point to the URL that serves your devices UPnP description document.
FriendlyName = "Emby Server",
Manufacturer = "Emby",
ModelName = "Emby Server",
Uuid = udn
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
SetProperies(device, fullService);
_Publisher.AddDevice(device);
var embeddedDevices = new List<string>
{
"urn:schemas-upnp-org:device:MediaServer:1",
"urn:schemas-upnp-org:service:ContentDirectory:1",
"urn:schemas-upnp-org:service:ConnectionManager:1",
"urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
};
foreach (var fullService in services)
foreach (var subDevice in embeddedDevices)
{
_logger.Info("Registering publisher for {0} on {1}", fullService, addressString);
var descriptorURI = "/dlna/" + udn + "/description.xml";
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorURI);
var service = fullService.Replace("urn:", string.Empty).Replace(":1", string.Empty);
var serviceParts = service.Split(':');
var deviceTypeNamespace = serviceParts[0].Replace('.', '-');
var device = new SsdpRootDevice
var embeddedDevice = new SsdpEmbeddedDevice
{
CacheLifetime = TimeSpan.FromSeconds(cacheLength), //How long SSDP clients can cache this info.
Location = uri, // Must point to the URL that serves your devices UPnP description document.
DeviceTypeNamespace = deviceTypeNamespace,
DeviceClass = serviceParts[1],
DeviceType = serviceParts[2],
FriendlyName = "Emby Server",
Manufacturer = "Emby",
ModelName = "Emby Server",
FriendlyName = device.FriendlyName,
Manufacturer = device.Manufacturer,
ModelName = device.ModelName,
Uuid = udn
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
_Publisher.AddDevice(device);
SetProperies(embeddedDevice, subDevice);
device.AddDevice(embeddedDevice);
}
}
}
private string CreateUuid(string text)
{
return text.GetMD5().ToString("N");
}
private void SetProperies(SsdpDevice device, string fullDeviceType)
{
var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty);
var serviceParts = service.Split(':');
var deviceTypeNamespace = serviceParts[0].Replace('.', '-');
device.DeviceTypeNamespace = deviceTypeNamespace;
device.DeviceClass = serviceParts[1];
device.DeviceType = serviceParts[2];
}
private readonly object _syncLock = new object();
private void StartPlayToManager()
{

@ -108,7 +108,6 @@
<Compile Include="Profiles\SonyBravia2014Profile.cs" />
<Compile Include="Profiles\SonyPs4Profile.cs" />
<Compile Include="Profiles\VlcProfile.cs" />
<Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
<Compile Include="Ssdp\Extensions.cs" />
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
<Compile Include="PlayTo\PlaybackStoppedEventArgs.cs" />
@ -130,7 +129,6 @@
<Compile Include="Service\BaseService.cs" />
<Compile Include="Service\ControlErrorHandler.cs" />
<Compile Include="Service\ServiceXmlBuilder.cs" />
<Compile Include="Ssdp\Datagram.cs" />
<Compile Include="Server\DescriptionXmlBuilder.cs" />
<Compile Include="Ssdp\DeviceDiscovery.cs" />
<Compile Include="PlayTo\SsdpHttpClient.cs" />
@ -160,8 +158,6 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Server\Headers.cs" />
<Compile Include="Server\UpnpDevice.cs" />
<Compile Include="Ssdp\SsdpMessageBuilder.cs" />
<Compile Include="Ssdp\SsdpHandler.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj">

@ -1,126 +0,0 @@
using MediaBrowser.Model.Logging;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace MediaBrowser.Dlna.Ssdp
{
public class Datagram
{
public EndPoint ToEndPoint { get; private set; }
public EndPoint FromEndPoint { get; private set; }
public string Message { get; private set; }
public bool IsBroadcast { get; private set; }
public bool EnableDebugLogging { get; private set; }
private readonly ILogger _logger;
public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool isBroadcast, bool enableDebugLogging)
{
Message = message;
_logger = logger;
EnableDebugLogging = enableDebugLogging;
IsBroadcast = isBroadcast;
FromEndPoint = fromEndPoint;
ToEndPoint = toEndPoint;
}
public void Send()
{
var msg = Encoding.ASCII.GetBytes(Message);
var socket = CreateSocket();
if (socket == null)
{
return;
}
if (FromEndPoint != null)
{
try
{
socket.Bind(FromEndPoint);
}
catch (Exception ex)
{
if (EnableDebugLogging)
{
_logger.ErrorException("Error binding datagram socket", ex);
}
if (IsBroadcast)
{
CloseSocket(socket, false);
return;
}
}
}
try
{
socket.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
{
try
{
socket.EndSend(result);
}
catch (Exception ex)
{
if (EnableDebugLogging)
{
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
}
}
finally
{
CloseSocket(socket, true);
}
}, null);
}
catch (Exception ex)
{
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
CloseSocket(socket, false);
}
}
private void CloseSocket(Socket socket, bool logError)
{
try
{
socket.Close();
}
catch (Exception ex)
{
if (logError && EnableDebugLogging)
{
_logger.ErrorException("Error closing datagram socket", ex);
}
}
}
private Socket CreateSocket()
{
try
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
if (IsBroadcast)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
}
return socket;
}
catch (Exception ex)
{
_logger.ErrorException("Error creating socket", ex);
return null;
}
}
}
}

@ -1,21 +0,0 @@
using MediaBrowser.Dlna.PlayTo;
using System;
using System.Net;
namespace MediaBrowser.Dlna.Ssdp
{
public class DeviceDiscoveryInfo
{
public Device Device { get; set; }
/// <summary>
/// The server's ip address that the device responded to
/// </summary>
public IPAddress LocalIpAddress { get; set; }
public Uri Uri { get; set; }
public string Usn { get; set; }
public string Nt { get; set; }
}
}

@ -9,30 +9,6 @@ namespace MediaBrowser.Dlna.Ssdp
{
public static class Extensions
{
public static Task<int> ReceiveAsync(this Socket socket, byte[] buffer, int offset, int size)
{
var tcs = new TaskCompletionSource<int>(socket);
var remoteip = new IPEndPoint(IPAddress.Any, 0);
var endpoint = (EndPoint)remoteip;
socket.BeginReceiveFrom(buffer, offset, size, SocketFlags.None, ref endpoint, iar =>
{
var result = (TaskCompletionSource<int>)iar.AsyncState;
var iarSocket = (Socket)result.Task.AsyncState;
try
{
result.TrySetResult(iarSocket.EndReceive(iar));
}
catch (Exception exc)
{
result.TrySetException(exc);
}
}, tcs);
return tcs.Task;
}
public static string GetValue(this XElement container, XName name)
{
var node = container.Element(name);

@ -1,328 +0,0 @@
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Dlna.Server;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace MediaBrowser.Dlna.Ssdp
{
public class SsdpHandler : IDisposable, ISsdpHandler
{
private Socket _multicastSocket;
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
const string SSDPAddr = "239.255.255.250";
const int SSDPPort = 1900;
private readonly string _serverSignature;
private readonly IPAddress _ssdpIp = IPAddress.Parse(SSDPAddr);
private readonly IPEndPoint _ssdpEndp = new IPEndPoint(IPAddress.Parse(SSDPAddr), SSDPPort);
private Timer _notificationTimer;
private bool _isDisposed;
private readonly Dictionary<string, List<UpnpDevice>> _devices = new Dictionary<string, List<UpnpDevice>>();
private readonly IApplicationHost _appHost;
private readonly int _unicastPort = 1901;
private UdpClient _unicastClient;
public SsdpHandler(ILogger logger, IServerConfigurationManager config, IApplicationHost appHost)
{
_logger = logger;
_config = config;
_appHost = appHost;
_config.NamedConfigurationUpdated += _config_ConfigurationUpdated;
_serverSignature = GenerateServerSignature();
}
private string GenerateServerSignature()
{
var os = Environment.OSVersion;
var pstring = os.Platform.ToString();
switch (os.Platform)
{
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
pstring = "WIN";
break;
}
return String.Format(
"{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}",
pstring,
IntPtr.Size * 8,
os.Version.Major,
os.Version.Minor,
_appHost.ApplicationVersion
);
}
void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
{
if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase))
{
ReloadAliveNotifier();
}
}
public IEnumerable<UpnpDevice> RegisteredDevices
{
get
{
lock (_devices)
{
var devices = _devices.ToList();
return devices.SelectMany(i => i.Value).ToList();
}
}
}
public void Start()
{
DisposeSocket();
StopAliveNotifier();
RestartSocketListener();
ReloadAliveNotifier();
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if (e.Mode == PowerModes.Resume)
{
Start();
}
}
public async void SendDatagram(string msg,
EndPoint endpoint,
EndPoint localAddress,
bool isBroadcast,
int sendCount = 3)
{
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog;
for (var i = 0; i < sendCount; i++)
{
if (i > 0)
{
await Task.Delay(500).ConfigureAwait(false);
}
var dgram = new Datagram(endpoint, localAddress, _logger, msg, isBroadcast, enableDebugLogging);
dgram.Send();
}
}
private void RestartSocketListener()
{
if (_isDisposed)
{
return;
}
try
{
_multicastSocket = CreateMulticastSocket();
_logger.Info("MultiCast socket created");
}
catch (Exception ex)
{
_logger.ErrorException("Error creating MultiCast socket", ex);
//StartSocketRetryTimer();
}
}
public void Dispose()
{
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
_isDisposed = true;
DisposeSocket();
StopAliveNotifier();
}
private void DisposeSocket()
{
if (_multicastSocket != null)
{
_multicastSocket.Close();
_multicastSocket.Dispose();
_multicastSocket = null;
}
}
private Socket CreateMulticastSocket()
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(_ssdpIp, 0));
socket.Bind(new IPEndPoint(IPAddress.Any, SSDPPort));
return socket;
}
private void NotifyAll()
{
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLog;
if (enableDebugLogging)
{
_logger.Debug("Sending alive notifications");
}
foreach (var d in RegisteredDevices)
{
NotifyDevice(d, "alive", enableDebugLogging);
}
}
private void NotifyDevice(UpnpDevice dev, string type, bool logMessage)
{
const string header = "NOTIFY * HTTP/1.1";
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
// If needed later for non-server devices, these headers will need to be dynamic
values["HOST"] = "239.255.255.250:1900";
values["CACHE-CONTROL"] = "max-age = 600";
values["LOCATION"] = dev.Descriptor.ToString();
values["SERVER"] = _serverSignature;
values["NTS"] = "ssdp:" + type;
values["NT"] = dev.Type;
values["USN"] = dev.USN;
if (logMessage)
{
_logger.Debug("{0} said {1}", dev.USN, type);
}
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
SendDatagram(msg, _ssdpEndp, new IPEndPoint(dev.Address, 0), true, 2);
//SendUnicastRequest(msg, 1);
}
public void RegisterNotification(string uuid, Uri descriptionUri, IPAddress address, IEnumerable<string> services)
{
lock (_devices)
{
List<UpnpDevice> list;
List<UpnpDevice> dl;
if (_devices.TryGetValue(uuid, out dl))
{
list = dl;
}
else
{
list = new List<UpnpDevice>();
_devices[uuid] = list;
}
list.AddRange(services.Select(i => new UpnpDevice(uuid, i, descriptionUri, address)));
NotifyAll();
_logger.Debug("Registered mount {0} at {1}", uuid, descriptionUri);
}
}
public void UnregisterNotification(string uuid)
{
lock (_devices)
{
List<UpnpDevice> dl;
if (_devices.TryGetValue(uuid, out dl))
{
_devices.Remove(uuid);
foreach (var d in dl.ToList())
{
NotifyDevice(d, "byebye", true);
}
_logger.Debug("Unregistered mount {0}", uuid);
}
}
}
private readonly object _notificationTimerSyncLock = new object();
private int _aliveNotifierIntervalMs;
private void ReloadAliveNotifier()
{
var config = _config.GetDlnaConfiguration();
if (!config.BlastAliveMessages)
{
StopAliveNotifier();
return;
}
var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
{
lock (_notificationTimerSyncLock)
{
if (_notificationTimer == null)
{
_logger.Debug("Starting alive notifier");
const int initialDelayMs = 3000;
_notificationTimer = new Timer(state => NotifyAll(), null, initialDelayMs, intervalMs);
}
else
{
_logger.Debug("Updating alive notifier");
_notificationTimer.Change(intervalMs, intervalMs);
}
_aliveNotifierIntervalMs = intervalMs;
}
}
}
private void StopAliveNotifier()
{
lock (_notificationTimerSyncLock)
{
if (_notificationTimer != null)
{
_logger.Debug("Stopping alive notifier");
_notificationTimer.Dispose();
_notificationTimer = null;
}
}
}
public class UdpState
{
public UdpClient UdpClient;
public IPEndPoint EndPoint;
}
}
}

@ -1,26 +0,0 @@
using System.Collections.Generic;
using System.Text;
namespace MediaBrowser.Dlna.Ssdp
{
public class SsdpMessageBuilder
{
public string BuildMessage(string header, Dictionary<string, string> values)
{
var builder = new StringBuilder();
const string argFormat = "{0}: {1}\r\n";
builder.AppendFormat("{0}\r\n", header);
foreach (var pair in values)
{
builder.AppendFormat(argFormat, pair.Key, pair.Value);
}
builder.Append("\r\n");
return builder.ToString();
}
}
}

@ -258,18 +258,14 @@ namespace MediaBrowser.LocalMetadata.Savers
builder.Append("<Type>" + SecurityElement.Escape(item.DisplayMediaType) + "</Type>");
}
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
if (item.CriticRating.HasValue)
{
if (hasCriticRating.CriticRating.HasValue)
{
builder.Append("<CriticRating>" + SecurityElement.Escape(hasCriticRating.CriticRating.Value.ToString(UsCulture)) + "</CriticRating>");
}
builder.Append("<CriticRating>" + SecurityElement.Escape(item.CriticRating.Value.ToString(UsCulture)) + "</CriticRating>");
}
if (!string.IsNullOrEmpty(hasCriticRating.CriticRatingSummary))
{
builder.Append("<CriticRatingSummary><![CDATA[" + hasCriticRating.CriticRatingSummary + "]]></CriticRatingSummary>");
}
if (!string.IsNullOrEmpty(item.CriticRatingSummary))
{
builder.Append("<CriticRatingSummary><![CDATA[" + item.CriticRatingSummary + "]]></CriticRatingSummary>");
}
if (!string.IsNullOrEmpty(item.Overview))
@ -285,14 +281,10 @@ namespace MediaBrowser.LocalMetadata.Savers
builder.Append("<OriginalTitle>" + SecurityElement.Escape(hasOriginalTitle.OriginalTitle) + "</OriginalTitle>");
}
}
var hasShortOverview = item as IHasShortOverview;
if (hasShortOverview != null)
if (!string.IsNullOrEmpty(item.ShortOverview))
{
if (!string.IsNullOrEmpty(hasShortOverview.ShortOverview))
{
builder.Append("<ShortOverview><![CDATA[" + hasShortOverview.ShortOverview + "]]></ShortOverview>");
}
builder.Append("<ShortOverview><![CDATA[" + item.ShortOverview + "]]></ShortOverview>");
}
if (!string.IsNullOrEmpty(item.CustomRating))

@ -588,13 +588,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(options.VaapiDevice))
{
return GetAvailableEncoder(mediaEncoder, "h264_vaapi", defaultEncoder);
if (IsVaapiSupported(state))
{
return GetAvailableEncoder(mediaEncoder, "h264_vaapi", defaultEncoder);
}
}
}
return defaultEncoder;
}
private static bool IsVaapiSupported(EncodingJob state)
{
var videoStream = state.VideoStream;
if (videoStream != null)
{
// vaapi will throw an error with this input
// [vaapi @ 0x7faed8000960] No VAAPI support for codec mpeg4 profile -99.
if (string.Equals(videoStream.Codec, "mpeg4", StringComparison.OrdinalIgnoreCase) && videoStream.Level == -99)
{
return false;
}
}
return true;
}
internal static bool CanStreamCopyVideo(EncodingJobOptions request, MediaStream videoStream)
{
if (videoStream.IsInterlaced)

@ -31,6 +31,7 @@ namespace MediaBrowser.Model.Dto
public bool RequiresOpening { get; set; }
public string OpenToken { get; set; }
public bool RequiresClosing { get; set; }
public bool SupportsProbing { get; set; }
public string LiveStreamId { get; set; }
public int? BufferMs { get; set; }
@ -63,6 +64,7 @@ namespace MediaBrowser.Model.Dto
SupportsTranscoding = true;
SupportsDirectStream = true;
SupportsDirectPlay = true;
SupportsProbing = true;
}
public int? DefaultAudioStreamIndex { get; set; }

@ -16,6 +16,7 @@ namespace MediaBrowser.Model.LiveTv
public string RecordingEncodingFormat { get; set; }
public bool EnableRecordingSubfolders { get; set; }
public bool EnableOriginalAudioWithEncodedRecordings { get; set; }
public bool EnableOriginalVideoWithEncodedRecordings { get; set; }
public List<TunerHostInfo> TunerHosts { get; set; }
public List<ListingsProviderInfo> ListingProviders { get; set; }

@ -42,6 +42,7 @@ namespace MediaBrowser.Model.LiveTv
/// <value>The user identifier.</value>
public string UserId { get; set; }
public string SeriesTimerId { get; set; }
public string Name { get; set; }
/// <summary>
/// The earliest date for which a program starts to return

@ -11,6 +11,7 @@ namespace MediaBrowser.Model.MediaInfo
public long? StartTimeTicks { get; set; }
public int? AudioStreamIndex { get; set; }
public int? SubtitleStreamIndex { get; set; }
public int? MaxAudioChannels { get; set; }
public string ItemId { get; set; }
public DeviceProfile DeviceProfile { get; set; }
@ -24,6 +25,7 @@ namespace MediaBrowser.Model.MediaInfo
MaxStreamingBitrate = options.MaxBitrate;
ItemId = options.ItemId;
DeviceProfile = options.Profile;
MaxAudioChannels = options.MaxAudioChannels;
VideoOptions videoOptions = options as VideoOptions;
if (videoOptions != null)

@ -16,6 +16,8 @@ namespace MediaBrowser.Model.MediaInfo
public int? SubtitleStreamIndex { get; set; }
public int? MaxAudioChannels { get; set; }
public string MediaSourceId { get; set; }
public string LiveStreamId { get; set; }

@ -100,6 +100,7 @@ namespace MediaBrowser.Model.Net
.ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase);
dict["image/jpg"] = ".jpg";
dict["image/x-png"] = ".png";
return dict;
}

@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Manager
return SaveImage(item, source, mimeType, type, imageIndex, null, cancellationToken);
}
public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(mimeType))
{
@ -109,9 +109,9 @@ namespace MediaBrowser.Providers.Manager
}
}
}
if (!string.IsNullOrEmpty(internalCacheKey))
if (saveLocallyWithMedia.HasValue && !saveLocallyWithMedia.Value)
{
saveLocally = false;
saveLocally = saveLocallyWithMedia.Value;
}
if (!imageIndex.HasValue && item.AllowsMultipleImages(type))
@ -356,6 +356,11 @@ namespace MediaBrowser.Providers.Manager
var season = item as Season;
var extension = MimeTypes.ToExtension(mimeType);
if (string.IsNullOrWhiteSpace(extension))
{
throw new ArgumentException(string.Format("Unable to determine image file extension from mime type {0}", mimeType));
}
if (type == ImageType.Thumb && saveLocally)
{
if (season != null && season.IndexNumber.HasValue)

@ -156,14 +156,14 @@ namespace MediaBrowser.Providers.Manager
var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
}
}
else
{
var mimeType = "image/" + response.Format.ToString().ToLower();
await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
}
downloadedImages.Add(imageType);

@ -353,19 +353,16 @@ namespace MediaBrowser.Providers.Manager
{
var updateType = ItemUpdateType.None;
if (isFullRefresh || currentUpdateType > ItemUpdateType.None)
var folder = item as Folder;
if (folder != null && folder.SupportsDateLastMediaAdded)
{
var folder = item as Folder;
if (folder != null && folder.SupportsDateLastMediaAdded)
{
var items = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).ToList();
var date = items.Count == 0 ? (DateTime?)null : items.Max();
var items = folder.GetRecursiveChildren(i => !i.IsFolder).Select(i => i.DateCreated).ToList();
var date = items.Count == 0 ? (DateTime?)null : items.Max();
if ((!folder.DateLastMediaAdded.HasValue && date.HasValue) || folder.DateLastMediaAdded != date)
{
folder.DateLastMediaAdded = date;
updateType = ItemUpdateType.MetadataEdit;
}
if ((!folder.DateLastMediaAdded.HasValue && date.HasValue) || folder.DateLastMediaAdded != date)
{
folder.DateLastMediaAdded = date;
updateType = ItemUpdateType.MetadataImport;
}
}

@ -140,12 +140,7 @@ namespace MediaBrowser.Providers.Manager
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
}
public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
{
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
}
public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
public Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(source))
{
@ -154,7 +149,7 @@ namespace MediaBrowser.Providers.Manager
var fileStream = _fileSystem.GetFileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, fileStream, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger, _memoryStreamProvider).SaveImage(item, fileStream, mimeType, type, imageIndex, saveLocallyWithMedia, cancellationToken);
}
public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken)

@ -236,15 +236,9 @@ namespace MediaBrowser.Providers.Manager
private static void MergeShortOverview(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
{
var sourceHasShortOverview = source as IHasShortOverview;
var targetHasShortOverview = target as IHasShortOverview;
if (sourceHasShortOverview != null && targetHasShortOverview != null)
if (replaceData || string.IsNullOrEmpty(target.ShortOverview))
{
if (replaceData || string.IsNullOrEmpty(targetHasShortOverview.ShortOverview))
{
targetHasShortOverview.ShortOverview = sourceHasShortOverview.ShortOverview;
}
target.ShortOverview = source.ShortOverview;
}
}
@ -311,20 +305,14 @@ namespace MediaBrowser.Providers.Manager
private static void MergeCriticRating(BaseItem source, BaseItem target, List<MetadataFields> lockedFields, bool replaceData)
{
var sourceCast = source as IHasCriticRating;
var targetCast = target as IHasCriticRating;
if (sourceCast != null && targetCast != null)
if (replaceData || !target.CriticRating.HasValue)
{
if (replaceData || !targetCast.CriticRating.HasValue)
{
targetCast.CriticRating = sourceCast.CriticRating;
}
target.CriticRating = source.CriticRating;
}
if (replaceData || string.IsNullOrEmpty(targetCast.CriticRatingSummary))
{
targetCast.CriticRatingSummary = sourceCast.CriticRatingSummary;
}
if (replaceData || string.IsNullOrEmpty(target.CriticRatingSummary))
{
target.CriticRatingSummary = source.CriticRatingSummary;
}
}

@ -66,28 +66,24 @@ namespace MediaBrowser.Providers.Omdb
item.ProductionYear = year;
}
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
{
// Seeing some bogus RT data on omdb for series, so filter it out here
// RT doesn't even have tv series
int tomatoMeter;
// Seeing some bogus RT data on omdb for series, so filter it out here
// RT doesn't even have tv series
int tomatoMeter;
if (!string.IsNullOrEmpty(result.tomatoMeter)
&& int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
&& tomatoMeter >= 0)
{
hasCriticRating.CriticRating = tomatoMeter;
}
if (!string.IsNullOrEmpty(result.tomatoMeter)
&& int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
&& tomatoMeter >= 0)
{
item.CriticRating = tomatoMeter;
}
if (!string.IsNullOrEmpty(result.tomatoConsensus)
&& !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
{
hasCriticRating.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
}
}
if (!string.IsNullOrEmpty(result.tomatoConsensus)
&& !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
{
item.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
}
int voteCount;
int voteCount;
if (!string.IsNullOrEmpty(result.imdbVotes)
&& int.TryParse(result.imdbVotes, NumberStyles.Number, _usCulture, out voteCount)
@ -167,25 +163,21 @@ namespace MediaBrowser.Providers.Omdb
item.ProductionYear = year;
}
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
{
// Seeing some bogus RT data on omdb for series, so filter it out here
// RT doesn't even have tv series
int tomatoMeter;
// Seeing some bogus RT data on omdb for series, so filter it out here
// RT doesn't even have tv series
int tomatoMeter;
if (!string.IsNullOrEmpty(result.tomatoMeter)
&& int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
&& tomatoMeter >= 0)
{
hasCriticRating.CriticRating = tomatoMeter;
}
if (!string.IsNullOrEmpty(result.tomatoMeter)
&& int.TryParse(result.tomatoMeter, NumberStyles.Integer, _usCulture, out tomatoMeter)
&& tomatoMeter >= 0)
{
item.CriticRating = tomatoMeter;
}
if (!string.IsNullOrEmpty(result.tomatoConsensus)
&& !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
{
hasCriticRating.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
}
if (!string.IsNullOrEmpty(result.tomatoConsensus)
&& !string.Equals(result.tomatoConsensus, "No consensus yet.", StringComparison.OrdinalIgnoreCase))
{
item.CriticRatingSummary = WebUtility.HtmlDecode(result.tomatoConsensus);
}
int voteCount;
@ -420,12 +412,8 @@ namespace MediaBrowser.Providers.Omdb
hasAwards.AwardSummary = WebUtility.HtmlDecode(result.Awards);
}
var hasShortOverview = item as IHasShortOverview;
if (hasShortOverview != null)
{
// Imdb plots are usually pretty short
hasShortOverview.ShortOverview = result.Plot;
}
// Imdb plots are usually pretty short
item.ShortOverview = result.Plot;
//if (!string.IsNullOrWhiteSpace(result.Director))
//{

@ -45,6 +45,11 @@ namespace MediaBrowser.Server.Implementations.IO
private void AddAffectedPath(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentNullException("path");
}
if (!_affectedPaths.Contains(path, StringComparer.Ordinal))
{
_affectedPaths.Add(path);
@ -53,6 +58,11 @@ namespace MediaBrowser.Server.Implementations.IO
public void AddPath(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentNullException("path");
}
lock (_timerLock)
{
AddAffectedPath(path);

@ -2838,9 +2838,13 @@ namespace MediaBrowser.Server.Implementations.Library
private bool ValidateNetworkPath(string path)
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT || !path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase))
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
return Directory.Exists(path);
// We can't validate protocol-based paths, so just allow them
if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
{
return Directory.Exists(path);
}
}
// Without native support for unc, we cannot validate this when running under mono

@ -360,7 +360,6 @@ namespace MediaBrowser.Server.Implementations.Library
public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken)
{
enableAutoClose = false;
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try

@ -207,14 +207,18 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
// Find movies with their own folders
if (args.IsDirectory)
{
var files = args.FileSystemChildren
.Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
.ToList();
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
return null;
return FindMovie<MusicVideo>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
{
return null;
return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
}
if (string.IsNullOrEmpty(collectionType))
@ -222,6 +226,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
// Owned items will be caught by the plain video resolver
if (args.Parent == null)
{
//return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
return null;
}
@ -231,21 +236,13 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
}
{
var files = args.FileSystemChildren
.Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
.ToList();
return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
}
}
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
var files = args.FileSystemChildren
.Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
.ToList();
return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
return FindMovie<Movie>(args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
}
return null;
@ -360,13 +357,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
/// Finds a movie based on a child file system entries
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="path">The path.</param>
/// <param name="parent">The parent.</param>
/// <param name="fileSystemEntries">The file system entries.</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="collectionType">Type of the collection.</param>
/// <returns>Movie.</returns>
private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType)
private T FindMovie<T>(string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool allowFilesAsFolders)
where T : Video, new()
{
var multiDiscFolders = new List<FileSystemMetadata>();
@ -413,23 +405,27 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
}
}
var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
!string.Equals(collectionType, CollectionType.Photos) &&
!string.Equals(collectionType, CollectionType.MusicVideos);
if (allowFilesAsFolders)
{
// TODO: Allow GetMultiDiscMovie in here
var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
!string.Equals(collectionType, CollectionType.Photos) &&
!string.Equals(collectionType, CollectionType.MusicVideos);
var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
if (result.Items.Count == 1)
{
var movie = (T)result.Items[0];
movie.IsInMixedFolder = false;
movie.Name = Path.GetFileName(movie.ContainingFolderPath);
return movie;
}
if (result.Items.Count == 1)
{
var movie = (T)result.Items[0];
movie.IsInMixedFolder = false;
movie.Name = Path.GetFileName(movie.ContainingFolderPath);
return movie;
}
if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
{
return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
if (result.Items.Count == 0 && multiDiscFolders.Count > 0)
{
return GetMultiDiscMovie<T>(multiDiscFolders, directoryService);
}
}
return null;

@ -1021,7 +1021,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var stream = new MediaSourceInfo
{
Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
Id = recordingId,
SupportsDirectPlay = false,
SupportsDirectStream = true,
@ -1854,23 +1854,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
ParentIndexNumber = program.SeasonNumber.Value,
IndexNumber = program.EpisodeNumber.Value,
AncestorIds = seriesIds,
ExcludeLocationTypes = new[] { LocationType.Virtual }
});
if (result.TotalRecordCount > 0)
{
return true;
}
}
if (!string.IsNullOrWhiteSpace(program.EpisodeTitle))
{
var result = _libraryManager.GetItemsResult(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Episode).Name },
Name = program.EpisodeTitle,
AncestorIds = seriesIds,
ExcludeLocationTypes = new[] { LocationType.Virtual }
IsVirtualItem = false
});
if (result.TotalRecordCount > 0)

@ -52,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
{
var format = _liveTvOptions.RecordingEncodingFormat;
if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase))
if (string.Equals(format, "mkv", StringComparison.OrdinalIgnoreCase) || _liveTvOptions.EnableOriginalVideoWithEncodedRecordings)
{
return "mkv";
}
@ -204,6 +204,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
private bool EncodeVideo(MediaSourceInfo mediaSource)
{
if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings)
{
return false;
}
var mediaStreams = mediaSource.MediaStreams ?? new List<MediaStream>();
return !mediaStreams.Any(i => i.Type == MediaStreamType.Video && string.Equals(i.Codec, "h264", StringComparison.OrdinalIgnoreCase) && !i.IsInterlaced);
}

@ -72,7 +72,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
dto.ProgramInfo = _dtoService.GetBaseItemDto(program, new DtoOptions());
dto.ProgramInfo.TimerId = dto.Id;
if (info.Status != RecordingStatus.Cancelled && info.Status != RecordingStatus.Error)
{
dto.ProgramInfo.TimerId = dto.Id;
dto.ProgramInfo.Status = info.Status.ToString();
}
dto.ProgramInfo.SeriesTimerId = dto.SeriesTimerId;
}

@ -877,6 +877,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
SortOrder = query.SortOrder ?? SortOrder.Ascending,
EnableTotalRecordCount = query.EnableTotalRecordCount,
TopParentIds = new[] { topFolder.Id.ToString("N") },
Name = query.Name,
DtoOptions = options
};
@ -1946,7 +1947,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
}
else
{
timers = timers.Where(i => !(i.Item1.Status == RecordingStatus.New));
timers = timers.Where(i => i.Item1.Status != RecordingStatus.New);
}
}
@ -2304,7 +2305,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
info.RecordAnyChannel = true;
info.RecordAnyTime = true;
info.Days = new List<DayOfWeek>
{

@ -140,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
try
{
if (stream.MediaStreams.Any(i => i.Index != -1))
if (!stream.SupportsProbing || stream.MediaStreams.Any(i => i.Index != -1))
{
await AddMediaInfo(stream, isAudio, cancellationToken).ConfigureAwait(false);
}

@ -60,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
//OpenedMediaSource.Path = tempFile;
//OpenedMediaSource.ReadAtNativeFramerate = true;
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
OpenedMediaSource.Protocol = MediaProtocol.Http;
OpenedMediaSource.SupportsDirectPlay = false;
OpenedMediaSource.SupportsDirectStream = true;

@ -13,6 +13,7 @@ using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Serialization;
@ -24,12 +25,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
private readonly IFileSystem _fileSystem;
private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost;
public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient)
public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
: base(config, logger, jsonSerializer, mediaEncoder)
{
_fileSystem = fileSystem;
_httpClient = httpClient;
_appHost = appHost;
}
public override string Type
@ -46,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
protected override async Task<IEnumerable<ChannelInfo>> GetChannelsInternal(TunerHostInfo info, CancellationToken cancellationToken)
{
return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(info.Url, ChannelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
return await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(info.Url, ChannelIdPrefix, info.Id, cancellationToken).ConfigureAwait(false);
}
public Task<List<LiveTvTunerInfo>> GetTunerInfos(CancellationToken cancellationToken)
@ -75,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
public async Task Validate(TunerHostInfo info)
{
using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
using (var stream = await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
{
}

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Logging;
@ -18,12 +19,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost;
public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient)
public M3uParser(ILogger logger, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
{
_logger = logger;
_fileSystem = fileSystem;
_httpClient = httpClient;
_appHost = appHost;
}
public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken)
@ -41,7 +44,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
{
if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
return _httpClient.Get(url, cancellationToken);
return _httpClient.Get(new HttpRequestOptions
{
Url = url,
CancellationToken = cancellationToken,
// Some data providers will require a user agent
UserAgent = _appHost.FriendlyName + "/" + _appHost.ApplicationVersion
});
}
return Task.FromResult(_fileSystem.OpenRead(url));
}
@ -111,15 +120,31 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
channel.Number = "0";
}
channel.ImageUrl = FindProperty("tvg-logo", extInf, null);
channel.Number = FindProperty("channel-id", extInf, channel.Number);
channel.Number = FindProperty("tvg-id", extInf, channel.Number);
channel.Name = FindProperty("tvg-id", extInf, channel.Name);
channel.Name = FindProperty("tvg-name", extInf, channel.Name);
channel.ImageUrl = FindProperty("tvg-logo", extInf);
var name = FindProperty("tvg-name", extInf);
if (string.IsNullOrWhiteSpace(name))
{
name = FindProperty("tvg-id", extInf);
}
channel.Name = name;
var numberString = FindProperty("tvg-id", extInf);
if (string.IsNullOrWhiteSpace(numberString))
{
numberString = FindProperty("channel-id", extInf);
}
if (!string.IsNullOrWhiteSpace(numberString))
{
channel.Number = numberString;
}
return channel;
}
private string FindProperty(string property, string properties, string defaultResult = "")
private string FindProperty(string property, string properties)
{
var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
var matches = reg.Matches(properties);
@ -130,7 +155,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts
return match.Groups[2].Value;
}
}
return defaultResult;
return null;
}
}

@ -8,6 +8,7 @@ using CommonIO;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
@ -25,12 +26,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
{
private readonly IFileSystem _fileSystem;
private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost;
public SatIpHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient)
public SatIpHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost)
: base(config, logger, jsonSerializer, mediaEncoder)
{
_fileSystem = fileSystem;
_httpClient = httpClient;
_appHost = appHost;
}
private const string ChannelIdPrefix = "sat_";
@ -39,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
{
if (!string.IsNullOrWhiteSpace(tuner.M3UUrl))
{
return await new M3uParser(Logger, _fileSystem, _httpClient).Parse(tuner.M3UUrl, ChannelIdPrefix, tuner.Id, cancellationToken).ConfigureAwait(false);
return await new M3uParser(Logger, _fileSystem, _httpClient, _appHost).Parse(tuner.M3UUrl, ChannelIdPrefix, tuner.Id, cancellationToken).ConfigureAwait(false);
}
var channels = await new ChannelScan(Logger).Scan(tuner, cancellationToken).ConfigureAwait(false);

@ -144,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.Photos
return ItemUpdateType.None;
}
await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, Guid.NewGuid().ToString("N"), cancellationToken).ConfigureAwait(false);
await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, false, cancellationToken).ConfigureAwait(false);
return ItemUpdateType.ImageUpdate;
}

@ -22,9 +22,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
private float GetValue(BaseItem x)
{
var hasCriticRating = x as IHasCriticRating;
return hasCriticRating == null ? 0 : hasCriticRating.CriticRating ?? 0;
return x.CriticRating ?? 0;
}
/// <summary>

@ -71,7 +71,7 @@ namespace MediaBrowser.ServerApplication
if (_isRunningAsService)
{
_canRestartService = CanRestartWindowsService();
//_canRestartService = CanRestartWindowsService();
}
var currentProcess = Process.GetCurrentProcess();

@ -986,9 +986,6 @@
<Content Include="dashboard-ui\scripts\userparentalcontrol.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\wizardservice.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\wizardsettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -1034,9 +1031,6 @@
<Content Include="dashboard-ui\wizardlivetvtuner.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\wizardservice.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\wizardsettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

@ -294,14 +294,12 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
var text = reader.ReadElementContentAsString();
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null && !string.IsNullOrEmpty(text))
if (!string.IsNullOrEmpty(text))
{
float value;
if (float.TryParse(text, NumberStyles.Any, _usCulture, out value))
{
hasCriticRating.CriticRating = value;
item.CriticRating = value;
}
}
@ -388,12 +386,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
var hasShortOverview = item as IHasShortOverview;
if (hasShortOverview != null)
{
hasShortOverview.ShortOverview = val;
}
item.ShortOverview = val;
}
break;
}
@ -418,12 +411,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
var hasCriticRating = item as IHasCriticRating;
if (hasCriticRating != null)
{
hasCriticRating.CriticRatingSummary = val;
}
item.CriticRatingSummary = val;
}
break;

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
<version>3.0.663</version>
<version>3.0.665</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.663" />
<dependency id="MediaBrowser.Common" version="3.0.665" />
<dependency id="NLog" version="4.3.8" />
<dependency id="SimpleInjector" version="3.2.2" />
</dependencies>

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
<version>3.0.663</version>
<version>3.0.665</version>
<title>MediaBrowser.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
<version>3.0.663</version>
<version>3.0.665</version>
<title>Media Browser.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.663" />
<dependency id="MediaBrowser.Common" version="3.0.665" />
<dependency id="Interfaces.IO" version="1.0.0.5" />
</dependencies>
</metadata>

Loading…
Cancel
Save