commit
88150e461c
|
@ -819,10 +819,10 @@ namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
if (state.PlayableStreamFileNames.Count > 0)
|
if (state.PlayableStreamFileNames.Count > 0)
|
||||||
{
|
{
|
||||||
return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
|
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -45,6 +45,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _virtual children
|
/// The _virtual children
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -17,6 +17,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
|
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
|
||||||
{
|
{
|
||||||
|
public List<string> AlbumArtists { get; set; }
|
||||||
|
public List<string> Artists { get; set; }
|
||||||
|
|
||||||
public MusicAlbum()
|
public MusicAlbum()
|
||||||
{
|
{
|
||||||
Artists = new List<string>();
|
Artists = new List<string>();
|
||||||
|
@ -48,6 +51,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public override bool SupportsCumulativeRunTimeTicks
|
public override bool SupportsCumulativeRunTimeTicks
|
||||||
{
|
{
|
||||||
|
@ -83,8 +95,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
get { return false; }
|
get { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> AlbumArtists { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the tracks.
|
/// Gets the tracks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -103,8 +113,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
return Tracks;
|
return Tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> Artists { get; set; }
|
|
||||||
|
|
||||||
public override List<string> GetUserDataKeys()
|
public override List<string> GetUserDataKeys()
|
||||||
{
|
{
|
||||||
var list = base.GetUserDataKeys();
|
var list = base.GetUserDataKeys();
|
||||||
|
|
|
@ -48,6 +48,15 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
get { return true; }
|
get { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool CanDelete()
|
public override bool CanDelete()
|
||||||
{
|
{
|
||||||
return !IsAccessedByName;
|
return !IsAccessedByName;
|
||||||
|
|
|
@ -129,6 +129,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
get { return false; }
|
get { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public virtual bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool DetectIsInMixedFolder()
|
public bool DetectIsInMixedFolder()
|
||||||
{
|
{
|
||||||
if (SupportsIsInMixedFolderDetection)
|
if (SupportsIsInMixedFolderDetection)
|
||||||
|
|
|
@ -38,6 +38,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool CanDelete()
|
public override bool CanDelete()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -61,6 +61,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
get { return false; }
|
get { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this instance is folder.
|
/// Gets a value indicating whether this instance is folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -26,6 +26,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the game system.
|
/// Gets or sets the game system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -20,5 +20,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
|
Task FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user);
|
||||||
|
|
||||||
bool EnableRememberingTrackSelections { get; }
|
bool EnableRememberingTrackSelections { get; }
|
||||||
|
|
||||||
|
bool SupportsPlayedStatus { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,13 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Album;
|
return AlbumEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public PhotoAlbum Album
|
public PhotoAlbum AlbumEntity
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool GetBlockUnratedValue(UserPolicy config)
|
protected override bool GetBlockUnratedValue(UserPolicy config)
|
||||||
{
|
{
|
||||||
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
return config.BlockUnratedItems.Contains(UnratedItem.Other);
|
||||||
|
|
|
@ -33,6 +33,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ClearCache()
|
private void ClearCache()
|
||||||
{
|
{
|
||||||
lock (_childIdsLock)
|
lock (_childIdsLock)
|
||||||
|
|
|
@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override int GetChildCount(User user)
|
public override int GetChildCount(User user)
|
||||||
{
|
{
|
||||||
return GetChildren(user, true).Count();
|
return GetChildren(user, true).Count();
|
||||||
|
|
|
@ -44,6 +44,15 @@ namespace MediaBrowser.Controller.Entities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override string CreatePresentationUniqueKey()
|
public override string CreatePresentationUniqueKey()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
|
if (!string.IsNullOrWhiteSpace(PrimaryVersionId))
|
||||||
|
|
|
@ -54,6 +54,15 @@ namespace MediaBrowser.Controller.LiveTv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Status == RecordingStatus.Completed && base.SupportsPlayedStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public override LocationType LocationType
|
public override LocationType LocationType
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="protocol">The protocol.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol);
|
string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the input argument.
|
/// Gets the input argument.
|
||||||
|
|
|
@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
public IIsoMount MountedIso { get; set; }
|
public IIsoMount MountedIso { get; set; }
|
||||||
public VideoType VideoType { get; set; }
|
public VideoType VideoType { get; set; }
|
||||||
public List<string> PlayableStreamFileNames { get; set; }
|
public List<string> PlayableStreamFileNames { get; set; }
|
||||||
|
public int AnalyzeDurationSections { get; set; }
|
||||||
|
|
||||||
public MediaInfoRequest()
|
public MediaInfoRequest()
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,15 @@ namespace MediaBrowser.Controller.Playlists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public override bool SupportsPlayedStatus
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return string.Equals(MediaType, "Video", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public override bool AlwaysScanInternalMetadataPath
|
public override bool AlwaysScanInternalMetadataPath
|
||||||
{
|
{
|
||||||
|
|
|
@ -431,10 +431,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
if (state.PlayableStreamFileNames.Count > 0)
|
if (state.PlayableStreamFileNames.Count > 0)
|
||||||
{
|
{
|
||||||
return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol);
|
return MediaEncoder.GetProbeSizeAndAnalyzeDurationArgument(new[] { state.MediaPath }, state.InputProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -26,6 +26,12 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
return string.Format("\"{0}\"", url);
|
return string.Format("\"{0}\"", url);
|
||||||
}
|
}
|
||||||
|
if (protocol == MediaProtocol.Udp)
|
||||||
|
{
|
||||||
|
var url = inputFiles.First();
|
||||||
|
|
||||||
|
return string.Format("\"{0}\"", url);
|
||||||
|
}
|
||||||
|
|
||||||
return GetConcatInputArgument(inputFiles);
|
return GetConcatInputArgument(inputFiles);
|
||||||
}
|
}
|
||||||
|
@ -74,9 +80,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return path.Replace("\"", "\\\"");
|
return path.Replace("\"", "\\\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetProbeSizeArgument(bool isDvd)
|
public static string GetProbeSizeArgument(int numInputFiles)
|
||||||
{
|
{
|
||||||
return isDvd ? "-probesize 1G -analyzeduration 200M" : "";
|
return numInputFiles > 1 ? "-probesize 1G" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetAnalyzeDurationArgument(int numInputFiles)
|
||||||
|
{
|
||||||
|
return numInputFiles > 1 ? "-analyzeduration 200M" : "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,10 +426,24 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
|
var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames);
|
||||||
|
|
||||||
var probeSizeArgument = GetProbeSizeArgument(inputFiles, request.Protocol);
|
var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
|
||||||
|
string analyzeDuration;
|
||||||
|
|
||||||
|
if (request.AnalyzeDurationSections > 0)
|
||||||
|
{
|
||||||
|
analyzeDuration = "-analyzeduration " +
|
||||||
|
(request.AnalyzeDurationSections*1000000).ToString(CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
probeSize = probeSize + " " + analyzeDuration;
|
||||||
|
probeSize = probeSize.Trim();
|
||||||
|
|
||||||
return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
|
return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters,
|
||||||
probeSizeArgument, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
|
probeSize, request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -450,9 +464,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
/// <param name="inputFiles">The input files.</param>
|
/// <param name="inputFiles">The input files.</param>
|
||||||
/// <param name="protocol">The protocol.</param>
|
/// <param name="protocol">The protocol.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
public string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol)
|
public string GetProbeSizeAndAnalyzeDurationArgument(string[] inputFiles, MediaProtocol protocol)
|
||||||
{
|
{
|
||||||
return EncodingUtils.GetProbeSizeArgument(inputFiles.Length > 1);
|
var results = new List<string>();
|
||||||
|
|
||||||
|
var probeSize = EncodingUtils.GetProbeSizeArgument(inputFiles.Length);
|
||||||
|
var analyzeDuration = EncodingUtils.GetAnalyzeDurationArgument(inputFiles.Length);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(probeSize))
|
||||||
|
{
|
||||||
|
results.Add(probeSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(analyzeDuration))
|
||||||
|
{
|
||||||
|
results.Add(analyzeDuration);
|
||||||
|
}
|
||||||
|
return string.Join(" ", results.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -871,7 +899,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
|
var args = useIFrame ? string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}{4}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, thumbnail) :
|
||||||
string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
|
string.Format("-i {0}{3} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg);
|
||||||
|
|
||||||
var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol);
|
var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputPath }, protocol);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(probeSize))
|
if (!string.IsNullOrEmpty(probeSize))
|
||||||
{
|
{
|
||||||
|
@ -982,7 +1010,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
|
var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf);
|
||||||
|
|
||||||
var probeSize = GetProbeSizeArgument(new[] { inputArgument }, protocol);
|
var probeSize = GetProbeSizeAndAnalyzeDurationArgument(new[] { inputArgument }, protocol);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(probeSize))
|
if (!string.IsNullOrEmpty(probeSize))
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace MediaBrowser.Model.MediaInfo
|
||||||
File = 0,
|
File = 0,
|
||||||
Http = 1,
|
Http = 1,
|
||||||
Rtmp = 2,
|
Rtmp = 2,
|
||||||
Rtsp = 3
|
Rtsp = 3,
|
||||||
|
Udp = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -598,7 +598,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
dto.Altitude = item.Altitude;
|
dto.Altitude = item.Altitude;
|
||||||
dto.IsoSpeedRating = item.IsoSpeedRating;
|
dto.IsoSpeedRating = item.IsoSpeedRating;
|
||||||
|
|
||||||
var album = item.Album;
|
var album = item.AlbumEntity;
|
||||||
|
|
||||||
if (album != null)
|
if (album != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -269,9 +269,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
positionTicks = 0;
|
positionTicks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is Audio)
|
if (!item.SupportsPlayedStatus)
|
||||||
{
|
{
|
||||||
positionTicks = 0;
|
positionTicks = 0;
|
||||||
|
data.Played = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.PlaybackPositionTicks = positionTicks;
|
data.PlaybackPositionTicks = positionTicks;
|
||||||
|
|
|
@ -27,6 +27,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using CommonIO;
|
using CommonIO;
|
||||||
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
@ -59,8 +60,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
public static EmbyTV Current;
|
public static EmbyTV Current;
|
||||||
|
|
||||||
public event EventHandler DataSourceChanged { add { } remove { } }
|
public event EventHandler DataSourceChanged;
|
||||||
public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged { add { } remove { } }
|
public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
|
private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
|
||||||
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
|
new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
@ -1009,7 +1010,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
|
public async Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(string recordingId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ActiveRecordingInfo info;
|
ActiveRecordingInfo info;
|
||||||
|
|
||||||
|
@ -1017,9 +1018,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
if (_activeRecordings.TryGetValue(recordingId, out info))
|
if (_activeRecordings.TryGetValue(recordingId, out info))
|
||||||
{
|
{
|
||||||
return Task.FromResult(new List<MediaSourceInfo>
|
var stream = new MediaSourceInfo
|
||||||
{
|
|
||||||
new MediaSourceInfo
|
|
||||||
{
|
{
|
||||||
Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
|
Path = _appHost.GetLocalApiUrl("localhost") + "/LiveTv/LiveRecordings/" + recordingId + "/stream",
|
||||||
Id = recordingId,
|
Id = recordingId,
|
||||||
|
@ -1031,8 +1030,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
RequiresClosing = false,
|
RequiresClosing = false,
|
||||||
Protocol = Model.MediaInfo.MediaProtocol.Http,
|
Protocol = Model.MediaInfo.MediaProtocol.Http,
|
||||||
BufferMs = 0
|
BufferMs = 0
|
||||||
}
|
};
|
||||||
});
|
|
||||||
|
var isAudio = false;
|
||||||
|
await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return new List<MediaSourceInfo>
|
||||||
|
{
|
||||||
|
stream
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
|
@ -1258,6 +1264,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
|
|
||||||
string liveStreamId = null;
|
string liveStreamId = null;
|
||||||
|
|
||||||
|
OnRecordingStatusChanged();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
|
var allMediaSources = await GetChannelStreamMediaSources(timer.ChannelId, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
@ -1353,6 +1361,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
|
||||||
{
|
{
|
||||||
_timerProvider.Delete(timer);
|
_timerProvider.Delete(timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnRecordingStatusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRecordingStatusChanged()
|
||||||
|
{
|
||||||
|
EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
}, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void EnforceKeepUpTo(TimerInfo timer)
|
private async void EnforceKeepUpTo(TimerInfo timer)
|
||||||
|
|
110
MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs
Normal file
110
MediaBrowser.Server.Implementations/LiveTv/LiveStreamHelper.cs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
|
{
|
||||||
|
public class LiveStreamHelper
|
||||||
|
{
|
||||||
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public LiveStreamHelper(IMediaEncoder mediaEncoder, ILogger logger)
|
||||||
|
{
|
||||||
|
_mediaEncoder = mediaEncoder;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var originalRuntime = mediaSource.RunTimeTicks;
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
|
||||||
|
{
|
||||||
|
InputPath = mediaSource.Path,
|
||||||
|
Protocol = mediaSource.Protocol,
|
||||||
|
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
|
||||||
|
ExtractChapters = false,
|
||||||
|
AnalyzeDurationSections = 2
|
||||||
|
|
||||||
|
}, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
_logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
|
mediaSource.Bitrate = info.Bitrate;
|
||||||
|
mediaSource.Container = info.Container;
|
||||||
|
mediaSource.Formats = info.Formats;
|
||||||
|
mediaSource.MediaStreams = info.MediaStreams;
|
||||||
|
mediaSource.RunTimeTicks = info.RunTimeTicks;
|
||||||
|
mediaSource.Size = info.Size;
|
||||||
|
mediaSource.Timestamp = info.Timestamp;
|
||||||
|
mediaSource.Video3DFormat = info.Video3DFormat;
|
||||||
|
mediaSource.VideoType = info.VideoType;
|
||||||
|
|
||||||
|
mediaSource.DefaultSubtitleStreamIndex = null;
|
||||||
|
|
||||||
|
// Null this out so that it will be treated like a live stream
|
||||||
|
if (!originalRuntime.HasValue)
|
||||||
|
{
|
||||||
|
mediaSource.RunTimeTicks = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
|
||||||
|
|
||||||
|
if (audioStream == null || audioStream.Index == -1)
|
||||||
|
{
|
||||||
|
mediaSource.DefaultAudioStreamIndex = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mediaSource.DefaultAudioStreamIndex = audioStream.Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
|
||||||
|
if (videoStream != null)
|
||||||
|
{
|
||||||
|
if (!videoStream.BitRate.HasValue)
|
||||||
|
{
|
||||||
|
var width = videoStream.Width ?? 1920;
|
||||||
|
|
||||||
|
if (width >= 1900)
|
||||||
|
{
|
||||||
|
videoStream.BitRate = 8000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (width >= 1260)
|
||||||
|
{
|
||||||
|
videoStream.BitRate = 3000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (width >= 700)
|
||||||
|
{
|
||||||
|
videoStream.BitRate = 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is coming up false and preventing stream copy
|
||||||
|
videoStream.IsAVC = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to estimate this
|
||||||
|
if (!mediaSource.Bitrate.HasValue)
|
||||||
|
{
|
||||||
|
var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
|
||||||
|
|
||||||
|
if (total > 0)
|
||||||
|
{
|
||||||
|
mediaSource.Bitrate = total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,9 +121,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
foreach (var service in _services)
|
foreach (var service in _services)
|
||||||
{
|
{
|
||||||
service.DataSourceChanged += service_DataSourceChanged;
|
service.DataSourceChanged += service_DataSourceChanged;
|
||||||
|
service.RecordingStatusChanged += Service_RecordingStatusChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Service_RecordingStatusChanged(object sender, RecordingStatusChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_lastRecordingRefreshTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
public List<ITunerHost> TunerHosts
|
public List<ITunerHost> TunerHosts
|
||||||
{
|
{
|
||||||
get { return _tunerHosts; }
|
get { return _tunerHosts; }
|
||||||
|
@ -2299,6 +2305,19 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
|
|
||||||
var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
|
var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
|
||||||
|
|
||||||
|
info.RecordAnyChannel = true;
|
||||||
|
info.RecordAnyTime = true;
|
||||||
|
info.Days = new List<DayOfWeek>
|
||||||
|
{
|
||||||
|
DayOfWeek.Sunday,
|
||||||
|
DayOfWeek.Monday,
|
||||||
|
DayOfWeek.Tuesday,
|
||||||
|
DayOfWeek.Wednesday,
|
||||||
|
DayOfWeek.Thursday,
|
||||||
|
DayOfWeek.Friday,
|
||||||
|
DayOfWeek.Saturday
|
||||||
|
};
|
||||||
|
|
||||||
info.Id = null;
|
info.Id = null;
|
||||||
|
|
||||||
return new Tuple<SeriesTimerInfo, ILiveTvService>(info, service);
|
return new Tuple<SeriesTimerInfo, ILiveTvService>(info, service);
|
||||||
|
|
|
@ -146,7 +146,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
|
await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -216,92 +216,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var originalRuntime = mediaSource.RunTimeTicks;
|
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
|
|
||||||
{
|
|
||||||
InputPath = mediaSource.Path,
|
|
||||||
Protocol = mediaSource.Protocol,
|
|
||||||
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
|
|
||||||
ExtractChapters = false
|
|
||||||
|
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.Info("Live tv media info probe took {0} seconds", (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture));
|
|
||||||
|
|
||||||
mediaSource.Bitrate = info.Bitrate;
|
|
||||||
mediaSource.Container = info.Container;
|
|
||||||
mediaSource.Formats = info.Formats;
|
|
||||||
mediaSource.MediaStreams = info.MediaStreams;
|
|
||||||
mediaSource.RunTimeTicks = info.RunTimeTicks;
|
|
||||||
mediaSource.Size = info.Size;
|
|
||||||
mediaSource.Timestamp = info.Timestamp;
|
|
||||||
mediaSource.Video3DFormat = info.Video3DFormat;
|
|
||||||
mediaSource.VideoType = info.VideoType;
|
|
||||||
|
|
||||||
mediaSource.DefaultSubtitleStreamIndex = null;
|
|
||||||
|
|
||||||
// Null this out so that it will be treated like a live stream
|
|
||||||
if (!originalRuntime.HasValue)
|
|
||||||
{
|
|
||||||
mediaSource.RunTimeTicks = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
|
|
||||||
|
|
||||||
if (audioStream == null || audioStream.Index == -1)
|
|
||||||
{
|
|
||||||
mediaSource.DefaultAudioStreamIndex = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mediaSource.DefaultAudioStreamIndex = audioStream.Index;
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Video);
|
|
||||||
if (videoStream != null)
|
|
||||||
{
|
|
||||||
if (!videoStream.BitRate.HasValue)
|
|
||||||
{
|
|
||||||
var width = videoStream.Width ?? 1920;
|
|
||||||
|
|
||||||
if (width >= 1900)
|
|
||||||
{
|
|
||||||
videoStream.BitRate = 8000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (width >= 1260)
|
|
||||||
{
|
|
||||||
videoStream.BitRate = 3000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (width >= 700)
|
|
||||||
{
|
|
||||||
videoStream.BitRate = 1000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is coming up false and preventing stream copy
|
|
||||||
videoStream.IsAVC = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to estimate this
|
|
||||||
if (!mediaSource.Bitrate.HasValue)
|
|
||||||
{
|
|
||||||
var total = mediaSource.MediaStreams.Select(i => i.BitRate ?? 0).Sum();
|
|
||||||
|
|
||||||
if (total > 0)
|
|
||||||
{
|
|
||||||
mediaSource.Bitrate = total;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Task CloseMediaSource(string liveStreamId)
|
public Task CloseMediaSource(string liveStreamId)
|
||||||
{
|
{
|
||||||
return _liveTvManager.CloseLiveStream(liveStreamId);
|
return _liveTvManager.CloseLiveStream(liveStreamId);
|
||||||
|
|
|
@ -234,6 +234,7 @@
|
||||||
<Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
|
<Compile Include="LiveTv\EmbyTV\TimerManager.cs" />
|
||||||
<Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
|
<Compile Include="LiveTv\Listings\SchedulesDirect.cs" />
|
||||||
<Compile Include="LiveTv\Listings\XmlTvListingsProvider.cs" />
|
<Compile Include="LiveTv\Listings\XmlTvListingsProvider.cs" />
|
||||||
|
<Compile Include="LiveTv\LiveStreamHelper.cs" />
|
||||||
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
|
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
|
||||||
<Compile Include="LiveTv\LiveTvDtoService.cs" />
|
<Compile Include="LiveTv\LiveTvDtoService.cs" />
|
||||||
<Compile Include="LiveTv\LiveTvManager.cs" />
|
<Compile Include="LiveTv\LiveTvManager.cs" />
|
||||||
|
|
|
@ -633,10 +633,14 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
data.PlayCount++;
|
data.PlayCount++;
|
||||||
data.LastPlayedDate = DateTime.UtcNow;
|
data.LastPlayedDate = DateTime.UtcNow;
|
||||||
|
|
||||||
if (!(item is Video))
|
if (!(item is Video) && item.SupportsPlayedStatus)
|
||||||
{
|
{
|
||||||
data.Played = true;
|
data.Played = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.Played = false;
|
||||||
|
}
|
||||||
|
|
||||||
await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
|
await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -851,7 +855,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
{
|
{
|
||||||
// If the client isn't able to report this, then we'll just have to make an assumption
|
// If the client isn't able to report this, then we'll just have to make an assumption
|
||||||
data.PlayCount++;
|
data.PlayCount++;
|
||||||
data.Played = true;
|
data.Played = item.SupportsPlayedStatus;
|
||||||
data.PlaybackPositionTicks = 0;
|
data.PlaybackPositionTicks = 0;
|
||||||
playedToCompletion = true;
|
playedToCompletion = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -704,7 +704,7 @@ namespace MediaBrowser.ServerApplication
|
||||||
WindowStyle = ProcessWindowStyle.Hidden,
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
Verb = "runas",
|
Verb = "runas",
|
||||||
ErrorDialog = false,
|
ErrorDialog = false,
|
||||||
Arguments = String.Format("/c sc stop {0} & sc start {0}", BackgroundService.GetExistingServiceName())
|
Arguments = String.Format("/c sc stop {0} & sc start {0} & sc start {0}", BackgroundService.GetExistingServiceName())
|
||||||
};
|
};
|
||||||
Process.Start(startInfo);
|
Process.Start(startInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common.Internal</id>
|
<id>MediaBrowser.Common.Internal</id>
|
||||||
<version>3.0.661</version>
|
<version>3.0.662</version>
|
||||||
<title>MediaBrowser.Common.Internal</title>
|
<title>MediaBrowser.Common.Internal</title>
|
||||||
<authors>Luke</authors>
|
<authors>Luke</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<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>
|
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
|
||||||
<copyright>Copyright © Emby 2013</copyright>
|
<copyright>Copyright © Emby 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.661" />
|
<dependency id="MediaBrowser.Common" version="3.0.662" />
|
||||||
<dependency id="NLog" version="4.3.8" />
|
<dependency id="NLog" version="4.3.8" />
|
||||||
<dependency id="SimpleInjector" version="3.2.2" />
|
<dependency id="SimpleInjector" version="3.2.2" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Common</id>
|
<id>MediaBrowser.Common</id>
|
||||||
<version>3.0.661</version>
|
<version>3.0.662</version>
|
||||||
<title>MediaBrowser.Common</title>
|
<title>MediaBrowser.Common</title>
|
||||||
<authors>Emby Team</authors>
|
<authors>Emby Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>MediaBrowser.Server.Core</id>
|
<id>MediaBrowser.Server.Core</id>
|
||||||
<version>3.0.661</version>
|
<version>3.0.662</version>
|
||||||
<title>Media Browser.Server.Core</title>
|
<title>Media Browser.Server.Core</title>
|
||||||
<authors>Emby Team</authors>
|
<authors>Emby Team</authors>
|
||||||
<owners>ebr,Luke,scottisafool</owners>
|
<owners>ebr,Luke,scottisafool</owners>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<description>Contains core components required to build plugins for Emby Server.</description>
|
<description>Contains core components required to build plugins for Emby Server.</description>
|
||||||
<copyright>Copyright © Emby 2013</copyright>
|
<copyright>Copyright © Emby 2013</copyright>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.661" />
|
<dependency id="MediaBrowser.Common" version="3.0.662" />
|
||||||
<dependency id="Interfaces.IO" version="1.0.0.5" />
|
<dependency id="Interfaces.IO" version="1.0.0.5" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user