Merge pull request #2847 from MediaBrowser/beta

Beta
This commit is contained in:
Luke 2017-08-27 13:34:55 -04:00 committed by GitHub
commit f3ee129bd9
354 changed files with 2650 additions and 3116 deletions

View File

@ -10,7 +10,6 @@ using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.TV; using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
@ -129,9 +128,20 @@ namespace Emby.Dlna.ContentDirectory
} }
} }
// No configuration so it's going to be pretty arbitrary foreach (var user in _userManager.Users)
return _userManager.Users.FirstOrDefault(i => i.Policy.IsAdministrator) ?? {
_userManager.Users.First(); if (user.Policy.IsAdministrator)
{
return user;
}
}
foreach (var user in _userManager.Users)
{
return user;
}
return null;
} }
public void Dispose() public void Dispose()

View File

@ -487,6 +487,11 @@ namespace Emby.Dlna.ContentDirectory
return GetMusicArtistItems(item, null, user, sort, startIndex, limit); return GetMusicArtistItems(item, null, user, sort, startIndex, limit);
} }
if (item is Genre)
{
return GetGenreItems(item, null, user, sort, startIndex, limit);
}
var collectionFolder = item as ICollectionFolder; var collectionFolder = item as ICollectionFolder;
if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) if (collectionFolder != null && string.Equals(CollectionType.Music, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
{ {
@ -503,23 +508,6 @@ namespace Emby.Dlna.ContentDirectory
if (stubType.HasValue) if (stubType.HasValue)
{ {
if (stubType.Value == StubType.People)
{
var items = _libraryManager.GetPeopleItems(new InternalPeopleQuery
{
ItemId = item.Id
});
var result = new QueryResult<ServerItem>
{
Items = items.Select(i => new ServerItem(i)).ToArray(items.Count),
TotalRecordCount = items.Count
};
return ApplyPaging(result, startIndex, limit);
}
var person = item as Person; var person = item as Person;
if (person != null) if (person != null)
{ {
@ -1173,6 +1161,26 @@ namespace Emby.Dlna.ContentDirectory
return ToResult(result); return ToResult(result);
} }
private QueryResult<ServerItem> GetGenreItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
{
var query = new InternalItemsQuery(user)
{
Recursive = true,
ParentId = parentId,
GenreIds = new[] { item.Id.ToString("N") },
IncludeItemTypes = new[] { typeof(Movie).Name, typeof(Series).Name },
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions()
};
SetSorting(query, sort, false);
var result = _libraryManager.GetItemsResult(query);
return ToResult(result);
}
private QueryResult<ServerItem> GetMusicGenreItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit) private QueryResult<ServerItem> GetMusicGenreItems(BaseItem item, Guid? parentId, User user, SortCriteria sort, int? startIndex, int? limit)
{ {
var query = new InternalItemsQuery(user) var query = new InternalItemsQuery(user)
@ -1331,7 +1339,6 @@ namespace Emby.Dlna.ContentDirectory
public enum StubType public enum StubType
{ {
Folder = 0, Folder = 0,
People = 1,
Latest = 2, Latest = 2,
Playlists = 3, Playlists = 3,
Albums = 4, Albums = 4,

View File

@ -198,7 +198,7 @@ namespace Emby.Dlna.Didl
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions
{ {
ItemId = GetClientId(video), ItemId = GetClientId(video),
MediaSources = sources, MediaSources = sources.ToArray(sources.Count),
Profile = _profile, Profile = _profile,
DeviceId = deviceId, DeviceId = deviceId,
MaxBitrate = _profile.MaxStreamingBitrate MaxBitrate = _profile.MaxStreamingBitrate
@ -236,7 +236,7 @@ namespace Emby.Dlna.Didl
AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo); AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
} }
var subtitleProfiles = streamInfo.GetSubtitleProfiles(false, _serverAddress, _accessToken) var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken)
.Where(subtitle => subtitle.DeliveryMethod == SubtitleDeliveryMethod.External) .Where(subtitle => subtitle.DeliveryMethod == SubtitleDeliveryMethod.External)
.ToList(); .ToList();
@ -391,14 +391,6 @@ namespace Emby.Dlna.Didl
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context) private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
{ {
if (itemStubType.HasValue && itemStubType.Value == StubType.People)
{
if (item is Video)
{
return _localization.GetLocalizedString("HeaderCastCrew");
}
return _localization.GetLocalizedString("HeaderPeople");
}
if (itemStubType.HasValue && itemStubType.Value == StubType.Latest) if (itemStubType.HasValue && itemStubType.Value == StubType.Latest)
{ {
return _localization.GetLocalizedString("ViewTypeMusicLatest"); return _localization.GetLocalizedString("ViewTypeMusicLatest");
@ -513,7 +505,7 @@ namespace Emby.Dlna.Didl
streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions
{ {
ItemId = GetClientId(audio), ItemId = GetClientId(audio),
MediaSources = sources, MediaSources = sources.ToArray(sources.Count),
Profile = _profile, Profile = _profile,
DeviceId = deviceId DeviceId = deviceId
}); });
@ -961,12 +953,6 @@ namespace Emby.Dlna.Didl
private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer) private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer)
{ {
if (stubType.HasValue && stubType.Value == StubType.People)
{
AddEmbeddedImageAsCover("people", writer);
return;
}
ImageDownloadInfo imageInfo = null; ImageDownloadInfo imageInfo = null;
if (context is UserView) if (context is UserView)

View File

@ -1,13 +1,12 @@
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace Emby.Dlna.Didl namespace Emby.Dlna.Didl
{ {
public class Filter public class Filter
{ {
private readonly List<string> _fields; private readonly string[] _fields;
private readonly bool _all; private readonly bool _all;
public Filter() public Filter()
@ -20,9 +19,7 @@ namespace Emby.Dlna.Didl
{ {
_all = StringHelper.EqualsIgnoreCase(filter, "*"); _all = StringHelper.EqualsIgnoreCase(filter, "*");
var list = (filter ?? string.Empty).Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList(); _fields = (filter ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
_fields = list;
} }
public bool Contains(string field) public bool Contains(string field)

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;

View File

@ -13,13 +13,13 @@ using MediaBrowser.Model.System;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Extensions;
namespace Emby.Dlna.PlayTo namespace Emby.Dlna.PlayTo
{ {
@ -48,7 +48,7 @@ namespace Emby.Dlna.PlayTo
{ {
get get
{ {
var lastDateKnownActivity = new[] { _creationTime, _device.DateLastActivity }.Max(); var lastDateKnownActivity = _creationTime > _device.DateLastActivity ? _creationTime : _device.DateLastActivity;
if (DateTime.UtcNow >= lastDateKnownActivity.AddSeconds(120)) if (DateTime.UtcNow >= lastDateKnownActivity.AddSeconds(120))
{ {
@ -564,7 +564,7 @@ namespace Emby.Dlna.PlayTo
streamInfo.TargetVideoCodecTag, streamInfo.TargetVideoCodecTag,
streamInfo.IsTargetAVC); streamInfo.IsTargetAVC);
return list.FirstOrDefault(); return list.Count == 0 ? null : list[0];
} }
return null; return null;
@ -589,7 +589,7 @@ namespace Emby.Dlna.PlayTo
StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions
{ {
ItemId = item.Id.ToString("N"), ItemId = item.Id.ToString("N"),
MediaSources = mediaSources, MediaSources = mediaSources.ToArray(mediaSources.Count),
Profile = profile, Profile = profile,
DeviceId = deviceId, DeviceId = deviceId,
MaxBitrate = profile.MaxStreamingBitrate, MaxBitrate = profile.MaxStreamingBitrate,
@ -609,7 +609,7 @@ namespace Emby.Dlna.PlayTo
StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions
{ {
ItemId = item.Id.ToString("N"), ItemId = item.Id.ToString("N"),
MediaSources = mediaSources, MediaSources = mediaSources.ToArray(mediaSources.Count),
Profile = profile, Profile = profile,
DeviceId = deviceId, DeviceId = deviceId,
MaxBitrate = profile.MaxStreamingBitrate, MaxBitrate = profile.MaxStreamingBitrate,

View File

@ -182,7 +182,7 @@ namespace Emby.Dlna.PlayTo
{ {
PlayableMediaTypes = profile.GetSupportedMediaTypes(), PlayableMediaTypes = profile.GetSupportedMediaTypes(),
SupportedCommands = new List<string> SupportedCommands = new string[]
{ {
GeneralCommandType.VolumeDown.ToString(), GeneralCommandType.VolumeDown.ToString(),
GeneralCommandType.VolumeUp.ToString(), GeneralCommandType.VolumeUp.ToString(),

View File

@ -16,14 +16,14 @@ namespace Emby.Dlna.Profiles
Manufacturer = "Panasonic", Manufacturer = "Panasonic",
Headers = new[] Headers = new[]
{ {
new HttpHeaderInfo new HttpHeaderInfo
{ {
Name = "User-Agent", Name = "User-Agent",
Value = "Panasonic MIL DLNA", Value = "Panasonic MIL DLNA",
Match = HeaderMatchType.Substring Match = HeaderMatchType.Substring
} }
} }
}; };
AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/"); AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/");
@ -31,105 +31,105 @@ namespace Emby.Dlna.Profiles
TimelineOffsetSeconds = 10; TimelineOffsetSeconds = 10;
TranscodingProfiles = new[] TranscodingProfiles = new[]
{ {
new TranscodingProfile new TranscodingProfile
{ {
Container = "mp3", Container = "mp3",
AudioCodec = "mp3", AudioCodec = "mp3",
Type = DlnaProfileType.Audio Type = DlnaProfileType.Audio
}, },
new TranscodingProfile new TranscodingProfile
{ {
Container = "ts", Container = "ts",
AudioCodec = "ac3", AudioCodec = "ac3",
VideoCodec = "h264", VideoCodec = "h264",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new TranscodingProfile new TranscodingProfile
{ {
Container = "jpeg", Container = "jpeg",
Type = DlnaProfileType.Photo Type = DlnaProfileType.Photo
} }
}; };
DirectPlayProfiles = new[] DirectPlayProfiles = new[]
{ {
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mpeg,mpg", Container = "mpeg,mpg",
VideoCodec = "mpeg2video,mpeg4", VideoCodec = "mpeg2video,mpeg4",
AudioCodec = "ac3,mp3,pcm_dvd", AudioCodec = "ac3,mp3,pcm_dvd",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mkv", Container = "mkv",
VideoCodec = "h264,mpeg2video", VideoCodec = "h264,mpeg2video",
AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts", AudioCodec = "aac,ac3,dca,mp3,mp2,pcm,dts",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "ts", Container = "ts",
VideoCodec = "h264,mpeg2video", VideoCodec = "h264,mpeg2video",
AudioCodec = "aac,mp3,mp2", AudioCodec = "aac,mp3,mp2",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mp4,m4v", Container = "mp4,m4v",
VideoCodec = "h264", VideoCodec = "h264",
AudioCodec = "aac,ac3,mp3,pcm", AudioCodec = "aac,ac3,mp3,pcm",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mov", Container = "mov",
VideoCodec = "h264", VideoCodec = "h264",
AudioCodec = "aac,pcm", AudioCodec = "aac,pcm",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "avi", Container = "avi",
VideoCodec = "mpeg4", VideoCodec = "mpeg4",
AudioCodec = "pcm", AudioCodec = "pcm",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "flv", Container = "flv",
VideoCodec = "h264", VideoCodec = "h264",
AudioCodec = "aac", AudioCodec = "aac",
Type = DlnaProfileType.Video Type = DlnaProfileType.Video
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mp3", Container = "mp3",
AudioCodec = "mp3", AudioCodec = "mp3",
Type = DlnaProfileType.Audio Type = DlnaProfileType.Audio
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "mp4", Container = "mp4",
AudioCodec = "aac", AudioCodec = "aac",
Type = DlnaProfileType.Audio Type = DlnaProfileType.Audio
}, },
new DirectPlayProfile new DirectPlayProfile
{ {
Container = "jpeg", Container = "jpeg",
Type = DlnaProfileType.Photo Type = DlnaProfileType.Photo
} }
}; };
ContainerProfiles = new[] ContainerProfiles = new[]
{ {
@ -156,35 +156,35 @@ namespace Emby.Dlna.Profiles
}; };
CodecProfiles = new[] CodecProfiles = new[]
{ {
new CodecProfile new CodecProfile
{ {
Type = CodecType.Video, Type = CodecType.Video,
Conditions = new[] Conditions = new[]
{ {
new ProfileCondition new ProfileCondition
{ {
Condition = ProfileConditionType.LessThanEqual, Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Width, Property = ProfileConditionValue.Width,
Value = "1920" Value = "1920"
}, },
new ProfileCondition new ProfileCondition
{ {
Condition = ProfileConditionType.LessThanEqual, Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.Height, Property = ProfileConditionValue.Height,
Value = "1080" Value = "1080"
}, },
new ProfileCondition new ProfileCondition
{ {
Condition = ProfileConditionType.LessThanEqual, Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoBitDepth, Property = ProfileConditionValue.VideoBitDepth,
Value = "8", Value = "8",
IsRequired = false IsRequired = false
} }
} }
} }
}; };
SubtitleProfiles = new[] SubtitleProfiles = new[]
{ {

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
@ -24,10 +23,12 @@ namespace Emby.Dlna.Ssdp
public static string GetDescendantValue(this XElement container, XName name) public static string GetDescendantValue(this XElement container, XName name)
{ {
var node = container.Descendants(name) foreach (var node in container.Descendants(name))
.FirstOrDefault(); {
return node.Value;
}
return node == null ? null : node.Value; return null;
} }
} }
} }

View File

@ -6,13 +6,13 @@ namespace Emby.Drawing.ImageMagick
{ {
internal static class ImageHelpers internal static class ImageHelpers
{ {
internal static List<string> ProjectPaths(List<string> paths, int count) internal static List<string> ProjectPaths(string[] paths, int count)
{ {
if (count <= 0) if (count <= 0)
{ {
throw new ArgumentOutOfRangeException("count"); throw new ArgumentOutOfRangeException("count");
} }
if (paths.Count == 0) if (paths.Length == 0)
{ {
throw new ArgumentOutOfRangeException("paths"); throw new ArgumentOutOfRangeException("paths");
} }
@ -24,7 +24,7 @@ namespace Emby.Drawing.ImageMagick
return list.Take(count).ToList(); return list.Take(count).ToList();
} }
private static void AddToList(List<string> list, List<string> paths, int count) private static void AddToList(List<string> list, string[] paths, int count)
{ {
while (list.Count < count) while (list.Count < count)
{ {

View File

@ -7,7 +7,6 @@ using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.System; using MediaBrowser.Model.System;
@ -306,15 +305,15 @@ namespace Emby.Drawing.ImageMagick
if (ratio >= 1.4) if (ratio >= 1.4)
{ {
new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height); new StripCollageBuilder(_appPaths, _fileSystem).BuildThumbCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
} }
else if (ratio >= .9) else if (ratio >= .9)
{ {
new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height); new StripCollageBuilder(_appPaths, _fileSystem).BuildSquareCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
} }
else else
{ {
new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths.ToList(), options.OutputPath, options.Width, options.Height); new StripCollageBuilder(_appPaths, _fileSystem).BuildPosterCollage(options.InputPaths, options.OutputPath, options.Width, options.Height);
} }
} }

View File

@ -19,7 +19,7 @@ namespace Emby.Drawing.ImageMagick
_fileSystem = fileSystem; _fileSystem = fileSystem;
} }
public void BuildPosterCollage(List<string> paths, string outputPath, int width, int height) public void BuildPosterCollage(string[] paths, string outputPath, int width, int height)
{ {
using (var wand = BuildPosterCollageWand(paths, width, height)) using (var wand = BuildPosterCollageWand(paths, width, height))
{ {
@ -27,7 +27,7 @@ namespace Emby.Drawing.ImageMagick
} }
} }
public void BuildSquareCollage(List<string> paths, string outputPath, int width, int height) public void BuildSquareCollage(string[] paths, string outputPath, int width, int height)
{ {
using (var wand = BuildSquareCollageWand(paths, width, height)) using (var wand = BuildSquareCollageWand(paths, width, height))
{ {
@ -35,7 +35,7 @@ namespace Emby.Drawing.ImageMagick
} }
} }
public void BuildThumbCollage(List<string> paths, string outputPath, int width, int height) public void BuildThumbCollage(string[] paths, string outputPath, int width, int height)
{ {
using (var wand = BuildThumbCollageWand(paths, width, height)) using (var wand = BuildThumbCollageWand(paths, width, height))
{ {
@ -43,7 +43,7 @@ namespace Emby.Drawing.ImageMagick
} }
} }
private MagickWand BuildPosterCollageWand(List<string> paths, int width, int height) private MagickWand BuildPosterCollageWand(string[] paths, int width, int height)
{ {
var inputPaths = ImageHelpers.ProjectPaths(paths, 3); var inputPaths = ImageHelpers.ProjectPaths(paths, 3);
using (var wandImages = new MagickWand(inputPaths.ToArray())) using (var wandImages = new MagickWand(inputPaths.ToArray()))
@ -108,7 +108,7 @@ namespace Emby.Drawing.ImageMagick
} }
} }
private MagickWand BuildThumbCollageWand(List<string> paths, int width, int height) private MagickWand BuildThumbCollageWand(string[] paths, int width, int height)
{ {
var inputPaths = ImageHelpers.ProjectPaths(paths, 4); var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
using (var wandImages = new MagickWand(inputPaths.ToArray())) using (var wandImages = new MagickWand(inputPaths.ToArray()))
@ -173,7 +173,7 @@ namespace Emby.Drawing.ImageMagick
} }
} }
private MagickWand BuildSquareCollageWand(List<string> paths, int width, int height) private MagickWand BuildSquareCollageWand(string[] paths, int width, int height)
{ {
var inputPaths = ImageHelpers.ProjectPaths(paths, 4); var inputPaths = ImageHelpers.ProjectPaths(paths, 4);
var outputWand = new MagickWand(width, height, new PixelWand("none", 1)); var outputWand = new MagickWand(width, height, new PixelWand("none", 1));

View File

@ -18,6 +18,7 @@ using System.Threading.Tasks;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using Emby.Drawing.Common; using Emby.Drawing.Common;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading; using MediaBrowser.Model.Threading;
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
@ -44,7 +45,7 @@ namespace Emby.Drawing
/// Image processors are specialized metadata providers that run after the normal ones /// Image processors are specialized metadata providers that run after the normal ones
/// </summary> /// </summary>
/// <value>The image enhancers.</value> /// <value>The image enhancers.</value>
public IEnumerable<IImageEnhancer> ImageEnhancers { get; private set; } public IImageEnhancer[] ImageEnhancers { get; private set; }
/// <summary> /// <summary>
/// The _logger /// The _logger
@ -56,22 +57,24 @@ namespace Emby.Drawing
private readonly IServerApplicationPaths _appPaths; private readonly IServerApplicationPaths _appPaths;
private IImageEncoder _imageEncoder; private IImageEncoder _imageEncoder;
private readonly Func<ILibraryManager> _libraryManager; private readonly Func<ILibraryManager> _libraryManager;
private readonly Func<IMediaEncoder> _mediaEncoder;
public ImageProcessor(ILogger logger, public ImageProcessor(ILogger logger,
IServerApplicationPaths appPaths, IServerApplicationPaths appPaths,
IFileSystem fileSystem, IFileSystem fileSystem,
IJsonSerializer jsonSerializer, IJsonSerializer jsonSerializer,
IImageEncoder imageEncoder, IImageEncoder imageEncoder,
Func<ILibraryManager> libraryManager, ITimerFactory timerFactory) Func<ILibraryManager> libraryManager, ITimerFactory timerFactory, Func<IMediaEncoder> mediaEncoder)
{ {
_logger = logger; _logger = logger;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_jsonSerializer = jsonSerializer; _jsonSerializer = jsonSerializer;
_imageEncoder = imageEncoder; _imageEncoder = imageEncoder;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_mediaEncoder = mediaEncoder;
_appPaths = appPaths; _appPaths = appPaths;
ImageEnhancers = new List<IImageEnhancer>(); ImageEnhancers = new IImageEnhancer[] { };
_saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite); _saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
ImageHelper.ImageProcessor = this; ImageHelper.ImageProcessor = this;
@ -120,7 +123,36 @@ namespace Emby.Drawing
{ {
get get
{ {
return _imageEncoder.SupportedInputFormats; return new string[]
{
"tiff",
"jpeg",
"jpg",
"png",
"aiff",
"cr2",
"crw",
"dng",
// Remove until supported
//"nef",
"orf",
"pef",
"arw",
"webp",
"gif",
"bmp",
"erf",
"raf",
"rw2",
"nrw",
"dng",
"ico",
"astc",
"ktx",
"pkm",
"wbmp"
};
} }
} }
@ -203,6 +235,10 @@ namespace Emby.Drawing
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
} }
var supportedImageInfo = await GetSupportedImage(originalImagePath, dateModified).ConfigureAwait(false);
originalImagePath = supportedImageInfo.Item1;
dateModified = supportedImageInfo.Item2;
if (options.Enhancers.Count > 0) if (options.Enhancers.Count > 0)
{ {
if (item == null) if (item == null)
@ -618,7 +654,7 @@ namespace Emby.Drawing
var supportedEnhancers = GetSupportedEnhancers(item, image.Type); var supportedEnhancers = GetSupportedEnhancers(item, image.Type);
return GetImageCacheTag(item, image, supportedEnhancers.ToList()); return GetImageCacheTag(item, image, supportedEnhancers);
} }
/// <summary> /// <summary>
@ -663,6 +699,42 @@ namespace Emby.Drawing
return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N"); return string.Join("|", cacheKeys.ToArray(cacheKeys.Count)).GetMD5().ToString("N");
} }
private async Task<Tuple<string, DateTime>> GetSupportedImage(string originalImagePath, DateTime dateModified)
{
var inputFormat = (Path.GetExtension(originalImagePath) ?? string.Empty)
.TrimStart('.')
.Replace("jpeg", "jpg", StringComparison.OrdinalIgnoreCase);
if (!_imageEncoder.SupportedInputFormats.Contains(inputFormat, StringComparer.OrdinalIgnoreCase))
{
try
{
var filename = (originalImagePath + dateModified.Ticks.ToString(UsCulture)).GetMD5().ToString("N");
var outputPath = Path.Combine(_appPaths.ImageCachePath, "converted-images", filename + ".webp");
var file = _fileSystem.GetFileInfo(outputPath);
if (!file.Exists)
{
await _mediaEncoder().ConvertImage(originalImagePath, outputPath).ConfigureAwait(false);
dateModified = _fileSystem.GetLastWriteTimeUtc(outputPath);
}
else
{
dateModified = file.LastWriteTimeUtc;
}
originalImagePath = outputPath;
}
catch (Exception ex)
{
_logger.ErrorException("Image conversion failed for {0}", ex, originalImagePath);
}
}
return new Tuple<string, DateTime>(originalImagePath, dateModified);
}
/// <summary> /// <summary>
/// Gets the enhanced image. /// Gets the enhanced image.
/// </summary> /// </summary>
@ -672,7 +744,7 @@ namespace Emby.Drawing
/// <returns>Task{System.String}.</returns> /// <returns>Task{System.String}.</returns>
public async Task<string> GetEnhancedImage(IHasMetadata item, ImageType imageType, int imageIndex) public async Task<string> GetEnhancedImage(IHasMetadata item, ImageType imageType, int imageIndex)
{ {
var enhancers = GetSupportedEnhancers(item, imageType).ToList(); var enhancers = GetSupportedEnhancers(item, imageType);
var imageInfo = item.GetImageInfo(imageType, imageIndex); var imageInfo = item.GetImageInfo(imageType, imageIndex);
@ -866,21 +938,25 @@ namespace Emby.Drawing
_logger.Info("Completed creation of image collage and saved to {0}", options.OutputPath); _logger.Info("Completed creation of image collage and saved to {0}", options.OutputPath);
} }
public IEnumerable<IImageEnhancer> GetSupportedEnhancers(IHasMetadata item, ImageType imageType) public List<IImageEnhancer> GetSupportedEnhancers(IHasMetadata item, ImageType imageType)
{ {
return ImageEnhancers.Where(i => var list = new List<IImageEnhancer>();
foreach (var i in ImageEnhancers)
{ {
try try
{ {
return i.Supports(item, imageType); if (i.Supports(item, imageType))
{
list.Add(i);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name); _logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
return false;
} }
}); }
return list;
} }
private bool _disposed; private bool _disposed;

View File

@ -444,11 +444,11 @@ namespace Emby.Server.Implementations.Activity
} }
} }
private async void CreateLogEntry(ActivityLogEntry entry) private void CreateLogEntry(ActivityLogEntry entry)
{ {
try try
{ {
await _activityManager.Create(entry).ConfigureAwait(false); _activityManager.Create(entry);
} }
catch catch
{ {

View File

@ -25,12 +25,12 @@ namespace Emby.Server.Implementations.Activity
_userManager = userManager; _userManager = userManager;
} }
public async Task Create(ActivityLogEntry entry) public void Create(ActivityLogEntry entry)
{ {
entry.Id = Guid.NewGuid().ToString("N"); entry.Id = Guid.NewGuid().ToString("N");
entry.Date = DateTime.UtcNow; entry.Date = DateTime.UtcNow;
await _repo.Create(entry).ConfigureAwait(false); _repo.Create(entry);
EventHelper.FireEventIfNotNull(EntryCreated, this, new GenericEventArgs<ActivityLogEntry>(entry), _logger); EventHelper.FireEventIfNotNull(EntryCreated, this, new GenericEventArgs<ActivityLogEntry>(entry), _logger);
} }

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Data;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.Activity; using MediaBrowser.Model.Activity;
@ -41,12 +40,12 @@ namespace Emby.Server.Implementations.Activity
private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLogEntries"; private const string BaseActivitySelectText = "select Id, Name, Overview, ShortOverview, Type, ItemId, UserId, DateCreated, LogSeverity from ActivityLogEntries";
public Task Create(ActivityLogEntry entry) public void Create(ActivityLogEntry entry)
{ {
return Update(entry); Update(entry);
} }
public async Task Update(ActivityLogEntry entry) public void Update(ActivityLogEntry entry)
{ {
if (entry == null) if (entry == null)
{ {

View File

@ -227,6 +227,8 @@ namespace Emby.Server.Implementations
protected IEnvironmentInfo EnvironmentInfo { get; set; } protected IEnvironmentInfo EnvironmentInfo { get; set; }
private IBlurayExaminer BlurayExaminer { get; set; }
public PackageVersionClass SystemUpdateLevel public PackageVersionClass SystemUpdateLevel
{ {
get get
@ -424,11 +426,6 @@ namespace Emby.Server.Implementations
SetBaseExceptionMessage(); SetBaseExceptionMessage();
if (environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
{
fileSystem.AddShortcutHandler(new LnkShortcutHandler());
}
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem)); fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
} }
@ -866,7 +863,7 @@ namespace Emby.Server.Implementations
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager, CryptographyProvider); SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager, CryptographyProvider);
RegisterSingleInstance(SecurityManager); RegisterSingleInstance(SecurityManager);
InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider); InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider, PackageRuntime);
RegisterSingleInstance(InstallationManager); RegisterSingleInstance(InstallationManager);
ZipClient = new ZipClient(FileSystemManager); ZipClient = new ZipClient(FileSystemManager);
@ -889,7 +886,8 @@ namespace Emby.Server.Implementations
ITextEncoding textEncoding = new TextEncoding.TextEncoding(FileSystemManager, LogManager.GetLogger("TextEncoding"), JsonSerializer); ITextEncoding textEncoding = new TextEncoding.TextEncoding(FileSystemManager, LogManager.GetLogger("TextEncoding"), JsonSerializer);
RegisterSingleInstance(textEncoding); RegisterSingleInstance(textEncoding);
Utilities.EncodingHelper = textEncoding; Utilities.EncodingHelper = textEncoding;
RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer(FileSystemManager, textEncoding)); BlurayExaminer = new BdInfoExaminer(FileSystemManager, textEncoding);
RegisterSingleInstance(BlurayExaminer);
RegisterSingleInstance<IXmlReaderSettingsFactory>(new XmlReaderSettingsFactory()); RegisterSingleInstance<IXmlReaderSettingsFactory>(new XmlReaderSettingsFactory());
@ -1050,7 +1048,15 @@ namespace Emby.Server.Implementations
SetStaticProperties(); SetStaticProperties();
await ((UserManager)UserManager).Initialize().ConfigureAwait(false); ((UserManager)UserManager).Initialize();
}
protected virtual string PackageRuntime
{
get
{
return "netframework";
}
} }
public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup) public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup)
@ -1199,7 +1205,7 @@ namespace Emby.Server.Implementations
private IImageProcessor GetImageProcessor() private IImageProcessor GetImageProcessor()
{ {
return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory); return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory, () => MediaEncoder);
} }
protected virtual FFMpegInstallInfo GetFfmpegInstallInfo() protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
@ -1332,7 +1338,8 @@ namespace Emby.Server.Implementations
ProcessFactory, ProcessFactory,
(Environment.ProcessorCount > 2 ? 14000 : 40000), (Environment.ProcessorCount > 2 ? 14000 : 40000),
EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows, EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows,
EnvironmentInfo); EnvironmentInfo,
BlurayExaminer);
MediaEncoder = mediaEncoder; MediaEncoder = mediaEncoder;
RegisterSingleInstance(MediaEncoder); RegisterSingleInstance(MediaEncoder);
@ -1858,9 +1865,9 @@ namespace Emby.Server.Implementations
HasPendingRestart = HasPendingRestart, HasPendingRestart = HasPendingRestart,
Version = ApplicationVersion.ToString(), Version = ApplicationVersion.ToString(),
WebSocketPortNumber = HttpPort, WebSocketPortNumber = HttpPort,
FailedPluginAssemblies = FailedAssemblies.ToList(), FailedPluginAssemblies = FailedAssemblies.ToArray(),
InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToList(), InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToArray(),
CompletedInstallations = InstallationManager.CompletedInstallations.ToList(), CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
Id = SystemId, Id = SystemId,
ProgramDataPath = ApplicationPaths.ProgramDataPath, ProgramDataPath = ApplicationPaths.ProgramDataPath,
LogPath = ApplicationPaths.LogDirectoryPath, LogPath = ApplicationPaths.LogDirectoryPath,

View File

@ -182,10 +182,8 @@ namespace Emby.Server.Implementations.Channels
{ {
}; };
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user) var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnItems = returnList
.ToArray(returnList.Count);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
@ -431,7 +429,7 @@ namespace Emby.Server.Implementations.Channels
if (isNew) if (isNew)
{ {
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); _libraryManager.CreateItem(item, cancellationToken);
} }
else if (forceUpdate) else if (forceUpdate)
{ {
@ -464,14 +462,14 @@ namespace Emby.Server.Implementations.Channels
return _libraryManager.GetItemById(id) as Channel; return _libraryManager.GetItemById(id) as Channel;
} }
public IEnumerable<ChannelFeatures> GetAllChannelFeatures() public ChannelFeatures[] GetAllChannelFeatures()
{ {
return _libraryManager.GetItemIds(new InternalItemsQuery return _libraryManager.GetItemIds(new InternalItemsQuery
{ {
IncludeItemTypes = new[] { typeof(Channel).Name }, IncludeItemTypes = new[] { typeof(Channel).Name },
SortBy = new[] { ItemSortBy.SortName } SortBy = new[] { ItemSortBy.SortName }
}).Select(i => GetChannelFeatures(i.ToString("N"))); }).Select(i => GetChannelFeatures(i.ToString("N"))).ToArray();
} }
public ChannelFeatures GetChannelFeatures(string id) public ChannelFeatures GetChannelFeatures(string id)
@ -511,10 +509,10 @@ namespace Emby.Server.Implementations.Channels
{ {
CanFilter = !features.MaxPageSize.HasValue, CanFilter = !features.MaxPageSize.HasValue,
CanSearch = provider is ISearchableChannel, CanSearch = provider is ISearchableChannel,
ContentTypes = features.ContentTypes, ContentTypes = features.ContentTypes.ToArray(),
DefaultSortFields = features.DefaultSortFields, DefaultSortFields = features.DefaultSortFields.ToArray(),
MaxPageSize = features.MaxPageSize, MaxPageSize = features.MaxPageSize,
MediaTypes = features.MediaTypes, MediaTypes = features.MediaTypes.ToArray(),
SupportsSortOrderToggle = features.SupportsSortOrderToggle, SupportsSortOrderToggle = features.SupportsSortOrderToggle,
SupportsLatestMedia = supportsLatest, SupportsLatestMedia = supportsLatest,
Name = channel.Name, Name = channel.Name,
@ -566,12 +564,10 @@ namespace Emby.Server.Implementations.Channels
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
{ {
Fields = query.Fields.ToList() Fields = query.Fields
}; };
var returnList = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false)); var returnItems = (await _dtoService.GetBaseItemDtos(items, dtoOptions, user).ConfigureAwait(false));
var returnItems = returnList
.ToArray(returnList.Count);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
@ -833,13 +829,11 @@ namespace Emby.Server.Implementations.Channels
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
{ {
Fields = query.Fields.ToList() Fields = query.Fields
}; };
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user) var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnItems = returnList
.ToArray(returnList.Count);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
@ -987,13 +981,11 @@ namespace Emby.Server.Implementations.Channels
var dtoOptions = new DtoOptions() var dtoOptions = new DtoOptions()
{ {
Fields = query.Fields.ToList() Fields = query.Fields
}; };
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user) var returnItems = (await _dtoService.GetBaseItemDtos(internalResult.Items, dtoOptions, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnItems = returnList
.ToArray(returnList.Count);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
@ -1338,7 +1330,7 @@ namespace Emby.Server.Implementations.Channels
var hasArtists = item as IHasArtist; var hasArtists = item as IHasArtist;
if (hasArtists != null) if (hasArtists != null)
{ {
hasArtists.Artists = info.Artists; hasArtists.Artists = info.Artists.ToArray();
} }
var hasAlbumArtists = item as IHasAlbumArtist; var hasAlbumArtists = item as IHasAlbumArtist;
@ -1396,11 +1388,11 @@ namespace Emby.Server.Implementations.Channels
if (isNew) if (isNew)
{ {
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); _libraryManager.CreateItem(item, cancellationToken);
if (info.People != null && info.People.Count > 0) if (info.People != null && info.People.Count > 0)
{ {
await _libraryManager.UpdatePeople(item, info.People ?? new List<PersonInfo>()).ConfigureAwait(false); _libraryManager.UpdatePeople(item, info.People ?? new List<PersonInfo>());
} }
} }
else if (forceUpdate) else if (forceUpdate)

View File

@ -84,15 +84,15 @@ namespace Emby.Server.Implementations.Collections
ProviderIds = options.ProviderIds, ProviderIds = options.ProviderIds,
Shares = options.UserIds.Select(i => new Share Shares = options.UserIds.Select(i => new Share
{ {
UserId = i.ToString("N"), UserId = i,
CanEdit = true CanEdit = true
}).ToList() }).ToList()
}; };
await parentFolder.AddChild(collection, CancellationToken.None).ConfigureAwait(false); parentFolder.AddChild(collection, CancellationToken.None);
if (options.ItemIdList.Count > 0) if (options.ItemIdList.Length > 0)
{ {
await AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(_fileSystem) await AddToCollection(collection.Id, options.ItemIdList, false, new MetadataRefreshOptions(_fileSystem)
{ {
@ -149,12 +149,17 @@ namespace Emby.Server.Implementations.Collections
return GetCollectionsFolder(string.Empty); return GetCollectionsFolder(string.Empty);
} }
public Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids) public Task AddToCollection(Guid collectionId, IEnumerable<string> ids)
{ {
return AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(_fileSystem)); return AddToCollection(collectionId, ids, true, new MetadataRefreshOptions(_fileSystem));
} }
private async Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions) public Task AddToCollection(Guid collectionId, IEnumerable<Guid> ids)
{
return AddToCollection(collectionId, ids.Select(i => i.ToString("N")), true, new MetadataRefreshOptions(_fileSystem));
}
private async Task AddToCollection(Guid collectionId, IEnumerable<string> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
{ {
var collection = _libraryManager.GetItemById(collectionId) as BoxSet; var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
@ -165,11 +170,12 @@ namespace Emby.Server.Implementations.Collections
var list = new List<LinkedChild>(); var list = new List<LinkedChild>();
var itemList = new List<BaseItem>(); var itemList = new List<BaseItem>();
var currentLinkedChildren = collection.GetLinkedChildren().ToList(); var currentLinkedChildrenIds = collection.GetLinkedChildren().Select(i => i.Id).ToList();
foreach (var itemId in ids) foreach (var id in ids)
{ {
var item = _libraryManager.GetItemById(itemId); var guidId = new Guid(id);
var item = _libraryManager.GetItemById(guidId);
if (string.IsNullOrWhiteSpace(item.Path)) if (string.IsNullOrWhiteSpace(item.Path))
{ {
@ -183,7 +189,7 @@ namespace Emby.Server.Implementations.Collections
itemList.Add(item); itemList.Add(item);
if (currentLinkedChildren.All(i => i.Id != itemId)) if (!currentLinkedChildrenIds.Contains(guidId))
{ {
list.Add(LinkedChild.Create(item)); list.Add(LinkedChild.Create(item));
} }
@ -213,6 +219,11 @@ namespace Emby.Server.Implementations.Collections
} }
} }
public Task RemoveFromCollection(Guid collectionId, IEnumerable<string> itemIds)
{
return RemoveFromCollection(collectionId, itemIds.Select(i => new Guid(i)));
}
public async Task RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds) public async Task RemoveFromCollection(Guid collectionId, IEnumerable<Guid> itemIds)
{ {
var collection = _libraryManager.GetItemById(collectionId) as BoxSet; var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
@ -225,11 +236,11 @@ namespace Emby.Server.Implementations.Collections
var list = new List<LinkedChild>(); var list = new List<LinkedChild>();
var itemList = new List<BaseItem>(); var itemList = new List<BaseItem>();
foreach (var itemId in itemIds) foreach (var guidId in itemIds)
{ {
var childItem = _libraryManager.GetItemById(itemId); var childItem = _libraryManager.GetItemById(guidId);
var child = collection.LinkedChildren.FirstOrDefault(i => (i.ItemId.HasValue && i.ItemId.Value == itemId) || (childItem != null && string.Equals(childItem.Path, i.Path, StringComparison.OrdinalIgnoreCase))); var child = collection.LinkedChildren.FirstOrDefault(i => (i.ItemId.HasValue && i.ItemId.Value == guidId) || (childItem != null && string.Equals(childItem.Path, i.Path, StringComparison.OrdinalIgnoreCase)));
if (child == null) if (child == null)
{ {

View File

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
@ -75,7 +74,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">item</exception> /// <exception cref="System.ArgumentNullException">item</exception>
public async Task SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken) public void SaveDisplayPreferences(DisplayPreferences displayPreferences, Guid userId, string client, CancellationToken cancellationToken)
{ {
if (displayPreferences == null) if (displayPreferences == null)
{ {
@ -123,7 +122,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">item</exception> /// <exception cref="System.ArgumentNullException">item</exception>
public async Task SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId, CancellationToken cancellationToken) public void SaveAllDisplayPreferences(IEnumerable<DisplayPreferences> displayPreferences, Guid userId, CancellationToken cancellationToken)
{ {
if (displayPreferences == null) if (displayPreferences == null)
{ {
@ -226,9 +225,9 @@ namespace Emby.Server.Implementations.Data
} }
} }
public Task SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken) public void SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken)
{ {
return SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken); SaveDisplayPreferences(displayPreferences, new Guid(userId), client, cancellationToken);
} }
public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client) public DisplayPreferences GetDisplayPreferences(string displayPreferencesId, string userId, string client)

View File

@ -132,8 +132,7 @@ namespace Emby.Server.Implementations.Data
/// <summary> /// <summary>
/// Opens the connection to the database /// Opens the connection to the database
/// </summary> /// </summary>
/// <returns>Task.</returns> public void Initialize(SqliteUserDataRepository userDataRepo)
public async Task Initialize(SqliteUserDataRepository userDataRepo)
{ {
using (var connection = CreateConnection()) using (var connection = CreateConnection())
{ {
@ -149,7 +148,7 @@ namespace Emby.Server.Implementations.Data
"create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, AncestorIdText TEXT, PRIMARY KEY (ItemId, AncestorId))", "create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, AncestorIdText TEXT, PRIMARY KEY (ItemId, AncestorId))",
"create index if not exists idx_AncestorIds1 on AncestorIds(AncestorId)", "create index if not exists idx_AncestorIds1 on AncestorIds(AncestorId)",
"create index if not exists idx_AncestorIds2 on AncestorIds(AncestorIdText)", "create index if not exists idx_AncestorIds5 on AncestorIds(AncestorIdText,ItemId)",
"create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT, CleanValue TEXT)", "create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT, CleanValue TEXT)",
@ -308,6 +307,7 @@ namespace Emby.Server.Implementations.Data
"drop index if exists idx_TypeSeriesPresentationUniqueKey2", "drop index if exists idx_TypeSeriesPresentationUniqueKey2",
"drop index if exists idx_AncestorIds3", "drop index if exists idx_AncestorIds3",
"drop index if exists idx_AncestorIds4", "drop index if exists idx_AncestorIds4",
"drop index if exists idx_AncestorIds2",
"create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)", "create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)",
"create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)", "create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)",
@ -599,16 +599,15 @@ namespace Emby.Server.Implementations.Data
/// </summary> /// </summary>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">item</exception> /// <exception cref="System.ArgumentNullException">item</exception>
public Task SaveItem(BaseItem item, CancellationToken cancellationToken) public void SaveItem(BaseItem item, CancellationToken cancellationToken)
{ {
if (item == null) if (item == null)
{ {
throw new ArgumentNullException("item"); throw new ArgumentNullException("item");
} }
return SaveItems(new List<BaseItem> { item }, cancellationToken); SaveItems(new List<BaseItem> { item }, cancellationToken);
} }
/// <summary> /// <summary>
@ -616,13 +615,12 @@ namespace Emby.Server.Implementations.Data
/// </summary> /// </summary>
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException"> /// <exception cref="System.ArgumentNullException">
/// items /// items
/// or /// or
/// cancellationToken /// cancellationToken
/// </exception> /// </exception>
public async Task SaveItems(List<BaseItem> items, CancellationToken cancellationToken) public void SaveItems(List<BaseItem> items, CancellationToken cancellationToken)
{ {
if (items == null) if (items == null)
{ {
@ -1027,9 +1025,9 @@ namespace Emby.Server.Implementations.Data
var hasArtists = item as IHasArtist; var hasArtists = item as IHasArtist;
if (hasArtists != null) if (hasArtists != null)
{ {
if (hasArtists.Artists.Count > 0) if (hasArtists.Artists.Length > 0)
{ {
artists = string.Join("|", hasArtists.Artists.ToArray()); artists = string.Join("|", hasArtists.Artists);
} }
} }
saveItemStatement.TryBind("@Artists", artists); saveItemStatement.TryBind("@Artists", artists);
@ -1907,7 +1905,7 @@ namespace Emby.Server.Implementations.Data
var hasArtists = item as IHasArtist; var hasArtists = item as IHasArtist;
if (hasArtists != null && !reader.IsDBNull(index)) if (hasArtists != null && !reader.IsDBNull(index))
{ {
hasArtists.Artists = reader.GetString(index).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); hasArtists.Artists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
} }
index++; index++;
@ -1958,22 +1956,18 @@ namespace Emby.Server.Implementations.Data
/// Gets the critic reviews. /// Gets the critic reviews.
/// </summary> /// </summary>
/// <param name="itemId">The item id.</param> /// <param name="itemId">The item id.</param>
/// <returns>Task{IEnumerable{ItemReview}}.</returns>
public List<ItemReview> GetCriticReviews(Guid itemId) public List<ItemReview> GetCriticReviews(Guid itemId)
{ {
return new List<ItemReview>(); return new List<ItemReview>();
} }
private readonly Task _cachedTask = Task.FromResult(true);
/// <summary> /// <summary>
/// Saves the critic reviews. /// Saves the critic reviews.
/// </summary> /// </summary>
/// <param name="itemId">The item id.</param> /// <param name="itemId">The item id.</param>
/// <param name="criticReviews">The critic reviews.</param> /// <param name="criticReviews">The critic reviews.</param>
/// <returns>Task.</returns> public void SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews)
public Task SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews)
{ {
return _cachedTask;
} }
/// <summary> /// <summary>
@ -2078,7 +2072,7 @@ namespace Emby.Server.Implementations.Data
/// <summary> /// <summary>
/// Saves the chapters. /// Saves the chapters.
/// </summary> /// </summary>
public async Task SaveChapters(Guid id, List<ChapterInfo> chapters) public void SaveChapters(Guid id, List<ChapterInfo> chapters)
{ {
CheckDisposed(); CheckDisposed();
@ -4653,12 +4647,12 @@ namespace Emby.Server.Implementations.Data
typeof(AggregateFolder) typeof(AggregateFolder)
}; };
public async Task UpdateInheritedValues(CancellationToken cancellationToken) public void UpdateInheritedValues(CancellationToken cancellationToken)
{ {
await UpdateInheritedTags(cancellationToken).ConfigureAwait(false); UpdateInheritedTags(cancellationToken);
} }
private async Task UpdateInheritedTags(CancellationToken cancellationToken) private void UpdateInheritedTags(CancellationToken cancellationToken)
{ {
var newValues = new List<Tuple<Guid, string[]>>(); var newValues = new List<Tuple<Guid, string[]>>();
@ -4753,7 +4747,7 @@ limit 100";
return new[] { value }.Where(IsValidType); return new[] { value }.Where(IsValidType);
} }
public async Task DeleteItem(Guid id, CancellationToken cancellationToken) public void DeleteItem(Guid id, CancellationToken cancellationToken)
{ {
if (id == Guid.Empty) if (id == Guid.Empty)
{ {
@ -5484,7 +5478,7 @@ limit 100";
} }
} }
public async Task UpdatePeople(Guid itemId, List<PersonInfo> people) public void UpdatePeople(Guid itemId, List<PersonInfo> people)
{ {
if (itemId == Guid.Empty) if (itemId == Guid.Empty)
{ {
@ -5614,7 +5608,7 @@ limit 100";
} }
} }
public async Task SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken) public void SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken)
{ {
CheckDisposed(); CheckDisposed();

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
@ -153,7 +152,7 @@ namespace Emby.Server.Implementations.Data
/// userId /// userId
/// or /// or
/// userDataId</exception> /// userDataId</exception>
public Task SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken) public void SaveUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
{ {
if (userData == null) if (userData == null)
{ {
@ -168,10 +167,10 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("key"); throw new ArgumentNullException("key");
} }
return PersistUserData(userId, key, userData, cancellationToken); PersistUserData(userId, key, userData, cancellationToken);
} }
public Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken) public void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken)
{ {
if (userData == null) if (userData == null)
{ {
@ -182,7 +181,7 @@ namespace Emby.Server.Implementations.Data
throw new ArgumentNullException("userId"); throw new ArgumentNullException("userId");
} }
return PersistAllUserData(userId, userData.ToList(), cancellationToken); PersistAllUserData(userId, userData, cancellationToken);
} }
/// <summary> /// <summary>
@ -193,7 +192,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="userData">The user data.</param> /// <param name="userData">The user data.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
public async Task PersistUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken) public void PersistUserData(Guid userId, string key, UserItemData userData, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -264,7 +263,7 @@ namespace Emby.Server.Implementations.Data
/// <summary> /// <summary>
/// Persist all user data for the specified user /// Persist all user data for the specified user
/// </summary> /// </summary>
private async Task PersistAllUserData(Guid userId, List<UserItemData> userDataList, CancellationToken cancellationToken) private void PersistAllUserData(Guid userId, UserItemData[] userDataList, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -349,7 +348,7 @@ namespace Emby.Server.Implementations.Data
/// </summary> /// </summary>
/// <param name="userId"></param> /// <param name="userId"></param>
/// <returns></returns> /// <returns></returns>
public IEnumerable<UserItemData> GetAllUserData(Guid userId) public List<UserItemData> GetAllUserData(Guid userId)
{ {
if (userId == Guid.Empty) if (userId == Guid.Empty)
{ {

View File

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
@ -72,7 +71,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">user</exception> /// <exception cref="System.ArgumentNullException">user</exception>
public async Task SaveUser(User user, CancellationToken cancellationToken) public void SaveUser(User user, CancellationToken cancellationToken)
{ {
if (user == null) if (user == null)
{ {
@ -139,7 +138,7 @@ namespace Emby.Server.Implementations.Data
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="System.ArgumentNullException">user</exception> /// <exception cref="System.ArgumentNullException">user</exception>
public async Task DeleteUser(User user, CancellationToken cancellationToken) public void DeleteUser(User user, CancellationToken cancellationToken)
{ {
if (user == null) if (user == null)
{ {

View File

@ -11,6 +11,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session; using MediaBrowser.Model.Session;
using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Devices namespace Emby.Server.Implementations.Devices
{ {
@ -199,7 +200,10 @@ namespace Emby.Server.Implementations.Devices
} }
history.DeviceId = deviceId; history.DeviceId = deviceId;
history.FilesUploaded.Add(file);
var list = history.FilesUploaded.ToList();
list.Add(file);
history.FilesUploaded = list.ToArray(list.Count);
_json.SerializeToFile(history, path); _json.SerializeToFile(history, path);
} }

View File

@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Dto
/// <param name="owner">The owner.</param> /// <param name="owner">The owner.</param>
/// <returns>Task{DtoBaseItem}.</returns> /// <returns>Task{DtoBaseItem}.</returns>
/// <exception cref="System.ArgumentNullException">item</exception> /// <exception cref="System.ArgumentNullException">item</exception>
public BaseItemDto GetBaseItemDto(BaseItem item, List<ItemFields> fields, User user = null, BaseItem owner = null) public BaseItemDto GetBaseItemDto(BaseItem item, ItemFields[] fields, User user = null, BaseItem owner = null)
{ {
var options = new DtoOptions var options = new DtoOptions
{ {
@ -87,7 +87,17 @@ namespace Emby.Server.Implementations.Dto
return GetBaseItemDto(item, options, user, owner); return GetBaseItemDto(item, options, user, owner);
} }
public async Task<List<BaseItemDto>> GetBaseItemDtos(IEnumerable<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null) public Task<BaseItemDto[]> GetBaseItemDtos(List<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null)
{
return GetBaseItemDtos(items, items.Count, options, user, owner);
}
public Task<BaseItemDto[]> GetBaseItemDtos(BaseItem[] items, DtoOptions options, User user = null, BaseItem owner = null)
{
return GetBaseItemDtos(items, items.Length, options, user, owner);
}
public async Task<BaseItemDto[]> GetBaseItemDtos(IEnumerable<BaseItem> items, int itemCount, DtoOptions options, User user = null, BaseItem owner = null)
{ {
if (items == null) if (items == null)
{ {
@ -101,17 +111,14 @@ namespace Emby.Server.Implementations.Dto
var syncDictionary = GetSyncedItemProgress(options); var syncDictionary = GetSyncedItemProgress(options);
var list = new List<BaseItemDto>(); var returnItems = new BaseItemDto[itemCount];
var programTuples = new List<Tuple<BaseItem, BaseItemDto>>(); var programTuples = new List<Tuple<BaseItem, BaseItemDto>>();
var channelTuples = new List<Tuple<BaseItemDto, LiveTvChannel>>(); var channelTuples = new List<Tuple<BaseItemDto, LiveTvChannel>>();
var refreshQueue = options.Fields.Contains(ItemFields.RefreshState) var index = 0;
? _providerManager.GetRefreshQueue()
: null;
foreach (var item in items) foreach (var item in items)
{ {
var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user, owner); var dto = GetBaseItemDtoInternal(item, options, user, owner);
var tvChannel = item as LiveTvChannel; var tvChannel = item as LiveTvChannel;
if (tvChannel != null) if (tvChannel != null)
@ -144,7 +151,8 @@ namespace Emby.Server.Implementations.Dto
FillSyncInfo(dto, item, options, user, syncDictionary); FillSyncInfo(dto, item, options, user, syncDictionary);
list.Add(dto); returnItems[index] = dto;
index++;
} }
if (programTuples.Count > 0) if (programTuples.Count > 0)
@ -157,18 +165,14 @@ namespace Emby.Server.Implementations.Dto
await _livetvManager().AddChannelInfo(channelTuples, options, user).ConfigureAwait(false); await _livetvManager().AddChannelInfo(channelTuples, options, user).ConfigureAwait(false);
} }
return list; return returnItems;
} }
public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null) public BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
{ {
var syncDictionary = GetSyncedItemProgress(options); var syncDictionary = GetSyncedItemProgress(options);
var refreshQueue = options.Fields.Contains(ItemFields.RefreshState) var dto = GetBaseItemDtoInternal(item, options, user, owner);
? _providerManager.GetRefreshQueue()
: null;
var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user, owner);
var tvChannel = item as LiveTvChannel; var tvChannel = item as LiveTvChannel;
if (tvChannel != null) if (tvChannel != null)
{ {
@ -300,7 +304,7 @@ namespace Emby.Server.Implementations.Dto
} }
} }
private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Dictionary<Guid, Guid> currentRefreshQueue, User user = null, BaseItem owner = null) private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null)
{ {
var fields = options.Fields; var fields = options.Fields;
@ -365,6 +369,8 @@ namespace Emby.Server.Implementations.Dto
{ {
dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user); dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user);
} }
NormalizeMediaSourceContainers(dto);
} }
} }
@ -400,25 +406,72 @@ namespace Emby.Server.Implementations.Dto
dto.Etag = item.GetEtag(user); dto.Etag = item.GetEtag(user);
} }
if (currentRefreshQueue != null) var liveTvManager = _livetvManager();
{
//dto.RefreshState = item.GetRefreshState(currentRefreshQueue);
}
if (item is ILiveTvRecording) if (item is ILiveTvRecording)
{ {
_livetvManager().AddInfoToRecordingDto(item, dto, user); liveTvManager.AddInfoToRecordingDto(item, dto, user);
}
else
{
var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path);
if (activeRecording != null)
{
dto.Type = "Recording";
dto.CanDownload = false;
if (!string.IsNullOrWhiteSpace(dto.SeriesName))
{
dto.EpisodeTitle = dto.Name;
dto.Name = dto.SeriesName;
}
liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user);
}
} }
return dto; return dto;
} }
private void NormalizeMediaSourceContainers(BaseItemDto dto)
{
foreach (var mediaSource in dto.MediaSources)
{
var container = mediaSource.Container;
if (string.IsNullOrWhiteSpace(container))
{
continue;
}
var containers = container.Split(new[] { ',' });
if (containers.Length < 2)
{
continue;
}
var path = mediaSource.Path;
string fileExtensionContainer = null;
if (!string.IsNullOrWhiteSpace(path))
{
path = Path.GetExtension(path);
if (!string.IsNullOrWhiteSpace(path))
{
path = Path.GetExtension(path);
if (!string.IsNullOrWhiteSpace(path))
{
path = path.TrimStart('.');
}
if (!string.IsNullOrWhiteSpace(path) && containers.Contains(path, StringComparer.OrdinalIgnoreCase))
{
fileExtensionContainer = path;
}
}
}
mediaSource.Container = fileExtensionContainer ?? containers[0];
}
}
public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, Dictionary<string, SyncedItemProgress> syncProgress, User user = null) public BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, Dictionary<string, SyncedItemProgress> syncProgress, User user = null)
{ {
var refreshQueue = options.Fields.Contains(ItemFields.RefreshState) var dto = GetBaseItemDtoInternal(item, options, user);
? _providerManager.GetRefreshQueue()
: null;
var dto = GetBaseItemDtoInternal(item, options, refreshQueue, user);
if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts)) if (taggedItems != null && options.Fields.Contains(ItemFields.ItemCounts))
{ {
@ -992,7 +1045,7 @@ namespace Emby.Server.Implementations.Dto
{ {
dto.RemoteTrailers = hasTrailers != null ? dto.RemoteTrailers = hasTrailers != null ?
hasTrailers.RemoteTrailers : hasTrailers.RemoteTrailers :
new MediaUrl[] {}; new MediaUrl[] { };
} }
dto.Name = item.Name; dto.Name = item.Name;
@ -1053,7 +1106,7 @@ namespace Emby.Server.Implementations.Dto
if (dto.Taglines == null) if (dto.Taglines == null)
{ {
dto.Taglines = new string[]{}; dto.Taglines = new string[] { };
} }
} }
@ -1243,17 +1296,17 @@ namespace Emby.Server.Implementations.Dto
if (iHasMediaSources != null) if (iHasMediaSources != null)
{ {
List<MediaStream> mediaStreams; MediaStream[] mediaStreams;
if (dto.MediaSources != null && dto.MediaSources.Count > 0) if (dto.MediaSources != null && dto.MediaSources.Count > 0)
{ {
mediaStreams = dto.MediaSources.Where(i => new Guid(i.Id) == item.Id) mediaStreams = dto.MediaSources.Where(i => new Guid(i.Id) == item.Id)
.SelectMany(i => i.MediaStreams) .SelectMany(i => i.MediaStreams)
.ToList(); .ToArray();
} }
else else
{ {
mediaStreams = _mediaSourceManager().GetStaticMediaSources(iHasMediaSources, true).First().MediaStreams; mediaStreams = _mediaSourceManager().GetStaticMediaSources(iHasMediaSources, true).First().MediaStreams.ToArray();
} }
dto.MediaStreams = mediaStreams; dto.MediaStreams = mediaStreams;
@ -1564,7 +1617,7 @@ namespace Emby.Server.Implementations.Dto
return null; return null;
} }
var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary).ToList(); var supportedEnhancers = _imageProcessor.GetSupportedEnhancers(item, ImageType.Primary);
ImageSize size; ImageSize size;

View File

@ -133,7 +133,6 @@
<Compile Include="IO\FileRefresher.cs" /> <Compile Include="IO\FileRefresher.cs" />
<Compile Include="IO\IsoManager.cs" /> <Compile Include="IO\IsoManager.cs" />
<Compile Include="IO\LibraryMonitor.cs" /> <Compile Include="IO\LibraryMonitor.cs" />
<Compile Include="IO\LnkShortcutHandler.cs" />
<Compile Include="IO\ManagedFileSystem.cs" /> <Compile Include="IO\ManagedFileSystem.cs" />
<Compile Include="IO\MbLinkShortcutHandler.cs" /> <Compile Include="IO\MbLinkShortcutHandler.cs" />
<Compile Include="IO\MemoryStreamProvider.cs" /> <Compile Include="IO\MemoryStreamProvider.cs" />
@ -662,8 +661,9 @@
<Reference Include="Emby.XmlTv, Version=1.0.6387.29335, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Emby.XmlTv, Version=1.0.6387.29335, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Emby.XmlTv.1.0.10\lib\portable-net45+netstandard2.0+win8\Emby.XmlTv.dll</HintPath> <HintPath>..\packages\Emby.XmlTv.1.0.10\lib\portable-net45+netstandard2.0+win8\Emby.XmlTv.dll</HintPath>
</Reference> </Reference>
<Reference Include="MediaBrowser.Naming, Version=1.0.6437.24226, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="MediaBrowser.Naming, Version=1.0.6447.2217, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\MediaBrowser.Naming.1.0.6\lib\portable-net45+netstandard2.0+win8\MediaBrowser.Naming.dll</HintPath> <HintPath>..\packages\MediaBrowser.Naming.1.0.7\lib\portable-net45+netstandard2.0+win8\MediaBrowser.Naming.dll</HintPath>
<Private>True</Private>
</Reference> </Reference>
<Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="ServiceStack.Text, Version=4.5.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath> <HintPath>..\packages\ServiceStack.Text.4.5.8\lib\net45\ServiceStack.Text.dll</HintPath>
@ -699,7 +699,6 @@
<EmbeddedResource Include="Localization\Core\ar.json" /> <EmbeddedResource Include="Localization\Core\ar.json" />
<EmbeddedResource Include="Localization\Core\bg-BG.json" /> <EmbeddedResource Include="Localization\Core\bg-BG.json" />
<EmbeddedResource Include="Localization\Core\ca.json" /> <EmbeddedResource Include="Localization\Core\ca.json" />
<EmbeddedResource Include="Localization\Core\core.json" />
<EmbeddedResource Include="Localization\Core\cs.json" /> <EmbeddedResource Include="Localization\Core\cs.json" />
<EmbeddedResource Include="Localization\Core\da.json" /> <EmbeddedResource Include="Localization\Core\da.json" />
<EmbeddedResource Include="Localization\Core\de.json" /> <EmbeddedResource Include="Localization\Core\de.json" />

View File

@ -367,15 +367,15 @@ namespace Emby.Server.Implementations.EntryPoints
return new LibraryUpdateInfo return new LibraryUpdateInfo
{ {
ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(), ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(), ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N")).Distinct().ToList(), ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList(), FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToList() FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray()
}; };
} }

View File

@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.EntryPoints
dto.ItemId = i.Id.ToString("N"); dto.ItemId = i.Id.ToString("N");
return dto; return dto;
}) })
.ToList(); .ToArray();
var info = new UserDataChangeInfo var info = new UserDataChangeInfo
{ {

View File

@ -162,7 +162,7 @@ namespace Emby.Server.Implementations.HttpServer
return serviceType; return serviceType;
} }
public void AddServiceInfo(Type serviceType, Type requestType, Type responseType) public void AddServiceInfo(Type serviceType, Type requestType)
{ {
ServiceOperationsMap[requestType] = serviceType; ServiceOperationsMap[requestType] = serviceType;
} }

View File

@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.IO
/// <summary> /// <summary>
/// Any file name ending in any of these will be ignored by the watchers /// Any file name ending in any of these will be ignored by the watchers
/// </summary> /// </summary>
private readonly IReadOnlyList<string> _alwaysIgnoreFiles = new List<string> private readonly string[] _alwaysIgnoreFiles = new string[]
{ {
"small.jpg", "small.jpg",
"albumart.jpg", "albumart.jpg",
@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.IO
"TempSBE" "TempSBE"
}; };
private readonly IReadOnlyList<string> _alwaysIgnoreSubstrings = new List<string> private readonly string[] _alwaysIgnoreSubstrings = new string[]
{ {
// Synology // Synology
"eaDir", "eaDir",
@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.IO
".actors" ".actors"
}; };
private readonly IReadOnlyList<string> _alwaysIgnoreExtensions = new List<string> private readonly string[] _alwaysIgnoreExtensions = new string[]
{ {
// thumbs.db // thumbs.db
".db", ".db",
@ -85,6 +85,8 @@ namespace Emby.Server.Implementations.IO
public bool IsPathLocked(string path) public bool IsPathLocked(string path)
{ {
// This method is not used by the core but it used by auto-organize
var lockedPaths = _tempIgnoredPaths.Keys.ToList(); var lockedPaths = _tempIgnoredPaths.Keys.ToList();
return lockedPaths.Any(i => _fileSystem.AreEqual(i, path) || _fileSystem.ContainsSubPath(i, path)); return lockedPaths.Any(i => _fileSystem.AreEqual(i, path) || _fileSystem.ContainsSubPath(i, path));
} }

View File

@ -353,7 +353,7 @@ namespace Emby.Server.Implementations.Library
} }
else else
{ {
if (item is Photo) if (!(item is Video))
{ {
return; return;
} }
@ -461,10 +461,10 @@ namespace Emby.Server.Implementations.Library
parent.RemoveChild(item); parent.RemoveChild(item);
} }
await ItemRepository.DeleteItem(item.Id, CancellationToken.None).ConfigureAwait(false); ItemRepository.DeleteItem(item.Id, CancellationToken.None);
foreach (var child in children) foreach (var child in children)
{ {
await ItemRepository.DeleteItem(child.Id, CancellationToken.None).ConfigureAwait(false); ItemRepository.DeleteItem(child.Id, CancellationToken.None);
} }
BaseItem removed; BaseItem removed;
@ -599,18 +599,16 @@ namespace Emby.Server.Implementations.Library
// When resolving the root, we need it's grandchildren (children of user views) // When resolving the root, we need it's grandchildren (children of user views)
var flattenFolderDepth = isPhysicalRoot ? 2 : 0; var flattenFolderDepth = isPhysicalRoot ? 2 : 0;
var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf); var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, _fileSystem, _logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf);
// Need to remove subpaths that may have been resolved from shortcuts // Need to remove subpaths that may have been resolved from shortcuts
// Example: if \\server\movies exists, then strip out \\server\movies\action // Example: if \\server\movies exists, then strip out \\server\movies\action
if (isPhysicalRoot) if (isPhysicalRoot)
{ {
var paths = NormalizeRootPathList(fileSystemDictionary.Values); files = NormalizeRootPathList(files).ToArray();
fileSystemDictionary = paths.ToDictionary(i => i.FullName);
} }
args.FileSystemDictionary = fileSystemDictionary; args.FileSystemChildren = files;
} }
// Check to see if we should resolve based on our contents // Check to see if we should resolve based on our contents
@ -656,7 +654,7 @@ namespace Emby.Server.Implementations.Library
return false; return false;
} }
public IEnumerable<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths) public List<FileSystemMetadata> NormalizeRootPathList(IEnumerable<FileSystemMetadata> paths)
{ {
var originalList = paths.ToList(); var originalList = paths.ToList();
@ -999,8 +997,7 @@ namespace Emby.Server.Implementations.Library
Path = path Path = path
}; };
var task = CreateItem(item, CancellationToken.None); CreateItem(item, CancellationToken.None);
Task.WaitAll(task);
} }
return item; return item;
@ -1172,7 +1169,7 @@ namespace Emby.Server.Implementations.Library
progress.Report(percent * 100); progress.Report(percent * 100);
} }
await ItemRepository.UpdateInheritedValues(cancellationToken).ConfigureAwait(false); ItemRepository.UpdateInheritedValues(cancellationToken);
progress.Report(100); progress.Report(100);
} }
@ -1208,7 +1205,7 @@ namespace Emby.Server.Implementations.Library
.Where(i => string.Equals(ShortcutFileExtension, Path.GetExtension(i), StringComparison.OrdinalIgnoreCase)) .Where(i => string.Equals(ShortcutFileExtension, Path.GetExtension(i), StringComparison.OrdinalIgnoreCase))
.Select(_fileSystem.ResolveShortcut) .Select(_fileSystem.ResolveShortcut)
.OrderBy(i => i) .OrderBy(i => i)
.ToList(), .ToArray(),
CollectionType = GetCollectionType(dir) CollectionType = GetCollectionType(dir)
}; };
@ -1554,7 +1551,7 @@ namespace Emby.Server.Implementations.Library
IncludeHidden = true, IncludeHidden = true,
IncludeExternalContent = allowExternalContent IncludeExternalContent = allowExternalContent
}, CancellationToken.None).Result.ToList(); }, CancellationToken.None).Result;
query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).Select(i => i.ToString("N")).ToArray(); query.TopParentIds = userViews.SelectMany(i => GetTopParentIdsForQuery(i, user)).Select(i => i.ToString("N")).ToArray();
} }
@ -1814,9 +1811,9 @@ namespace Emby.Server.Implementations.Library
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
public Task CreateItem(BaseItem item, CancellationToken cancellationToken) public void CreateItem(BaseItem item, CancellationToken cancellationToken)
{ {
return CreateItems(new[] { item }, cancellationToken); CreateItems(new[] { item }, cancellationToken);
} }
/// <summary> /// <summary>
@ -1825,11 +1822,11 @@ namespace Emby.Server.Implementations.Library
/// <param name="items">The items.</param> /// <param name="items">The items.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
public async Task CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken) public void CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
{ {
var list = items.ToList(); var list = items.ToList();
await ItemRepository.SaveItems(list, cancellationToken).ConfigureAwait(false); ItemRepository.SaveItems(list, cancellationToken);
foreach (var item in list) foreach (var item in list)
{ {
@ -1872,7 +1869,7 @@ namespace Emby.Server.Implementations.Library
var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name; var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name;
_logger.Debug("Saving {0} to database.", logName); _logger.Debug("Saving {0} to database.", logName);
await ItemRepository.SaveItem(item, cancellationToken).ConfigureAwait(false); ItemRepository.SaveItem(item, cancellationToken);
RegisterItem(item); RegisterItem(item);
@ -2069,7 +2066,7 @@ namespace Emby.Server.Implementations.Library
private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
//private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1); //private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1);
public Task<UserView> GetNamedView(User user, public UserView GetNamedView(User user,
string name, string name,
string viewType, string viewType,
string sortName, string sortName,
@ -2107,7 +2104,7 @@ namespace Emby.Server.Implementations.Library
ForcedSortName = sortName ForcedSortName = sortName
}; };
await CreateItem(item, cancellationToken).ConfigureAwait(false); CreateItem(item, cancellationToken);
refresh = true; refresh = true;
} }
@ -2138,7 +2135,7 @@ namespace Emby.Server.Implementations.Library
return item; return item;
} }
public async Task<UserView> GetNamedView(User user, public UserView GetNamedView(User user,
string name, string name,
string parentId, string parentId,
string viewType, string viewType,
@ -2175,7 +2172,7 @@ namespace Emby.Server.Implementations.Library
item.DisplayParentId = new Guid(parentId); item.DisplayParentId = new Guid(parentId);
} }
await CreateItem(item, cancellationToken).ConfigureAwait(false); CreateItem(item, cancellationToken);
isNew = true; isNew = true;
} }
@ -2201,7 +2198,7 @@ namespace Emby.Server.Implementations.Library
return item; return item;
} }
public async Task<UserView> GetShadowView(BaseItem parent, public UserView GetShadowView(BaseItem parent,
string viewType, string viewType,
string sortName, string sortName,
CancellationToken cancellationToken) CancellationToken cancellationToken)
@ -2240,7 +2237,7 @@ namespace Emby.Server.Implementations.Library
item.DisplayParentId = parentId; item.DisplayParentId = parentId;
await CreateItem(item, cancellationToken).ConfigureAwait(false); CreateItem(item, cancellationToken);
isNew = true; isNew = true;
} }
@ -2311,7 +2308,7 @@ namespace Emby.Server.Implementations.Library
item.DisplayParentId = new Guid(parentId); item.DisplayParentId = new Guid(parentId);
} }
await CreateItem(item, cancellationToken).ConfigureAwait(false); CreateItem(item, cancellationToken);
isNew = true; isNew = true;
} }
@ -2825,14 +2822,14 @@ namespace Emby.Server.Implementations.Library
return ItemRepository.GetPeopleNames(query); return ItemRepository.GetPeopleNames(query);
} }
public Task UpdatePeople(BaseItem item, List<PersonInfo> people) public void UpdatePeople(BaseItem item, List<PersonInfo> people)
{ {
if (!item.SupportsPeople) if (!item.SupportsPeople)
{ {
return Task.FromResult(true); return;
} }
return ItemRepository.UpdatePeople(item.Id, people); ItemRepository.UpdatePeople(item.Id, people);
} }
public async Task<ItemImageInfo> ConvertImageToLocal(IHasMetadata item, ItemImageInfo image, int imageIndex) public async Task<ItemImageInfo> ConvertImageToLocal(IHasMetadata item, ItemImageInfo image, int imageIndex)
@ -3061,7 +3058,7 @@ namespace Emby.Server.Implementations.Library
var topLibraryFolders = GetUserRootFolder().Children.ToList(); var topLibraryFolders = GetUserRootFolder().Children.ToList();
var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders, null); var info = GetVirtualFolderInfo(virtualFolderPath, topLibraryFolders, null);
if (info.Locations.Count > 0 && info.Locations.Count != options.PathInfos.Length) if (info.Locations.Length > 0 && info.Locations.Length != options.PathInfos.Length)
{ {
var list = options.PathInfos.ToList(); var list = options.PathInfos.ToList();

View File

@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
return new CollectionFolder return new CollectionFolder
{ {
CollectionType = GetCollectionType(args), CollectionType = GetCollectionType(args),
PhysicalLocationsList = args.PhysicalLocations.ToList() PhysicalLocationsList = args.PhysicalLocations
}; };
} }
} }

View File

@ -1,6 +1,8 @@
using MediaBrowser.Controller.Configuration; using System.Globalization;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Naming.Common; using MediaBrowser.Naming.Common;
using MediaBrowser.Naming.TV; using MediaBrowser.Naming.TV;
@ -17,15 +19,18 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
private readonly ILocalizationManager _localization;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SeasonResolver"/> class. /// Initializes a new instance of the <see cref="SeasonResolver"/> class.
/// </summary> /// </summary>
/// <param name="config">The config.</param> /// <param name="config">The config.</param>
public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager) public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
{ {
_config = config; _config = config;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_localization = localization;
} }
/// <summary> /// <summary>
@ -47,9 +52,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
SeriesName = series.Name SeriesName = series.Name
}; };
if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0) if (season.IndexNumber.HasValue)
{ {
season.Name = _config.Configuration.SeasonZeroDisplayName; var seasonNumber = season.IndexNumber.Value;
season.Name = seasonNumber == 0 ?
_config.Configuration.SeasonZeroDisplayName :
string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.ToString(UsCulture));
} }
return season; return season;

View File

@ -181,7 +181,7 @@ namespace Emby.Server.Implementations.Library
DtoOptions = new DtoOptions DtoOptions = new DtoOptions
{ {
Fields = new List<ItemFields> Fields = new ItemFields[]
{ {
ItemFields.AirTime, ItemFields.AirTime,
ItemFields.DateCreated, ItemFields.DateCreated,

View File

@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.Library
/// <value>The repository.</value> /// <value>The repository.</value>
public IUserDataRepository Repository { get; set; } public IUserDataRepository Repository { get; set; }
public async Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken) public void SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken)
{ {
if (userData == null) if (userData == null)
{ {
@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Library
foreach (var key in keys) foreach (var key in keys)
{ {
await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false); Repository.SaveUserData(userId, key, userData, cancellationToken);
} }
var cacheKey = GetCacheKey(userId, item.Id); var cacheKey = GetCacheKey(userId, item.Id);
@ -86,7 +86,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="userData"></param> /// <param name="userData"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public async Task SaveAllUserData(Guid userId, IEnumerable<UserItemData> userData, CancellationToken cancellationToken) public void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken)
{ {
if (userData == null) if (userData == null)
{ {
@ -99,7 +99,7 @@ namespace Emby.Server.Implementations.Library
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
await Repository.SaveAllUserData(userId, userData, cancellationToken).ConfigureAwait(false); Repository.SaveAllUserData(userId, userData, cancellationToken);
} }
/// <summary> /// <summary>
@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Library
/// </summary> /// </summary>
/// <param name="userId"></param> /// <param name="userId"></param>
/// <returns></returns> /// <returns></returns>
public IEnumerable<UserItemData> GetAllUserData(Guid userId) public List<UserItemData> GetAllUserData(Guid userId)
{ {
if (userId == Guid.Empty) if (userId == Guid.Empty)
{ {
@ -187,11 +187,11 @@ namespace Emby.Server.Implementations.Library
var userData = GetUserData(user.Id, item); var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData); var dto = GetUserItemDataDto(userData);
item.FillUserDataDtoValues(dto, userData, null, user, new List<ItemFields>()); item.FillUserDataDtoValues(dto, userData, null, user, new ItemFields[] { });
return dto; return dto;
} }
public UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, List<ItemFields> fields) public UserItemDataDto GetUserDataDto(IHasUserData item, BaseItemDto itemDto, User user, ItemFields[] fields)
{ {
var userData = GetUserData(user.Id, item); var userData = GetUserData(user.Id, item);
var dto = GetUserItemDataDto(userData); var dto = GetUserItemDataDto(userData);

View File

@ -160,9 +160,9 @@ namespace Emby.Server.Implementations.Library
return Users.FirstOrDefault(u => string.Equals(u.Name, name, StringComparison.OrdinalIgnoreCase)); return Users.FirstOrDefault(u => string.Equals(u.Name, name, StringComparison.OrdinalIgnoreCase));
} }
public async Task Initialize() public void Initialize()
{ {
Users = await LoadUsers().ConfigureAwait(false); Users = LoadUsers();
var users = Users.ToList(); var users = Users.ToList();
@ -174,7 +174,7 @@ namespace Emby.Server.Implementations.Library
if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value == UserLinkType.LinkedUser) if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value == UserLinkType.LinkedUser)
{ {
user.Policy.IsAdministrator = true; user.Policy.IsAdministrator = true;
await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); UpdateUserPolicy(user, user.Policy, false);
} }
} }
} }
@ -294,12 +294,12 @@ namespace Emby.Server.Implementations.Library
if (success) if (success)
{ {
user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow; user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
await UpdateUser(user).ConfigureAwait(false); UpdateUser(user);
await UpdateInvalidLoginAttemptCount(user, 0).ConfigureAwait(false); UpdateInvalidLoginAttemptCount(user, 0);
} }
else else
{ {
await UpdateInvalidLoginAttemptCount(user, user.Policy.InvalidLoginAttemptCount + 1).ConfigureAwait(false); UpdateInvalidLoginAttemptCount(user, user.Policy.InvalidLoginAttemptCount + 1);
} }
_logger.Info("Authentication request for {0} {1}.", user.Name, success ? "has succeeded" : "has been denied"); _logger.Info("Authentication request for {0} {1}.", user.Name, success ? "has succeeded" : "has been denied");
@ -307,7 +307,7 @@ namespace Emby.Server.Implementations.Library
return success ? user : null; return success ? user : null;
} }
private async Task UpdateInvalidLoginAttemptCount(User user, int newValue) private void UpdateInvalidLoginAttemptCount(User user, int newValue)
{ {
if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0) if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0)
{ {
@ -327,7 +327,7 @@ namespace Emby.Server.Implementations.Library
//fireLockout = true; //fireLockout = true;
} }
await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); UpdateUserPolicy(user, user.Policy, false);
if (fireLockout) if (fireLockout)
{ {
@ -372,7 +372,7 @@ namespace Emby.Server.Implementations.Library
/// Loads the users from the repository /// Loads the users from the repository
/// </summary> /// </summary>
/// <returns>IEnumerable{User}.</returns> /// <returns>IEnumerable{User}.</returns>
private async Task<IEnumerable<User>> LoadUsers() private List<User> LoadUsers()
{ {
var users = UserRepository.RetrieveAllUsers().ToList(); var users = UserRepository.RetrieveAllUsers().ToList();
@ -385,14 +385,14 @@ namespace Emby.Server.Implementations.Library
user.DateLastSaved = DateTime.UtcNow; user.DateLastSaved = DateTime.UtcNow;
await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); UserRepository.SaveUser(user, CancellationToken.None);
users.Add(user); users.Add(user);
user.Policy.IsAdministrator = true; user.Policy.IsAdministrator = true;
user.Policy.EnableContentDeletion = true; user.Policy.EnableContentDeletion = true;
user.Policy.EnableRemoteControlOfOtherUsers = true; user.Policy.EnableRemoteControlOfOtherUsers = true;
await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); UpdateUserPolicy(user, user.Policy, false);
} }
return users; return users;
@ -539,7 +539,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="user">The user.</param> /// <param name="user">The user.</param>
/// <exception cref="System.ArgumentNullException">user</exception> /// <exception cref="System.ArgumentNullException">user</exception>
/// <exception cref="System.ArgumentException"></exception> /// <exception cref="System.ArgumentException"></exception>
public async Task UpdateUser(User user) public void UpdateUser(User user)
{ {
if (user == null) if (user == null)
{ {
@ -554,7 +554,7 @@ namespace Emby.Server.Implementations.Library
user.DateModified = DateTime.UtcNow; user.DateModified = DateTime.UtcNow;
user.DateLastSaved = DateTime.UtcNow; user.DateLastSaved = DateTime.UtcNow;
await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); UserRepository.SaveUser(user, CancellationToken.None);
OnUserUpdated(user); OnUserUpdated(user);
} }
@ -599,7 +599,7 @@ namespace Emby.Server.Implementations.Library
user.DateLastSaved = DateTime.UtcNow; user.DateLastSaved = DateTime.UtcNow;
await UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); UserRepository.SaveUser(user, CancellationToken.None);
EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User> { Argument = user }, _logger); EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User> { Argument = user }, _logger);
@ -653,7 +653,7 @@ namespace Emby.Server.Implementations.Library
{ {
var configPath = GetConfigurationFilePath(user); var configPath = GetConfigurationFilePath(user);
await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false); UserRepository.DeleteUser(user, CancellationToken.None);
try try
{ {
@ -667,7 +667,7 @@ namespace Emby.Server.Implementations.Library
DeleteUserPolicy(user); DeleteUserPolicy(user);
// Force this to be lazy loaded again // Force this to be lazy loaded again
Users = await LoadUsers().ConfigureAwait(false); Users = LoadUsers();
OnUserDeleted(user); OnUserDeleted(user);
} }
@ -681,17 +681,17 @@ namespace Emby.Server.Implementations.Library
/// Resets the password by clearing it. /// Resets the password by clearing it.
/// </summary> /// </summary>
/// <returns>Task.</returns> /// <returns>Task.</returns>
public Task ResetPassword(User user) public void ResetPassword(User user)
{ {
return ChangePassword(user, GetSha1String(string.Empty)); ChangePassword(user, GetSha1String(string.Empty));
} }
public Task ResetEasyPassword(User user) public void ResetEasyPassword(User user)
{ {
return ChangeEasyPassword(user, GetSha1String(string.Empty)); ChangeEasyPassword(user, GetSha1String(string.Empty));
} }
public async Task ChangePassword(User user, string newPasswordSha1) public void ChangePassword(User user, string newPasswordSha1)
{ {
if (user == null) if (user == null)
{ {
@ -709,12 +709,12 @@ namespace Emby.Server.Implementations.Library
user.Password = newPasswordSha1; user.Password = newPasswordSha1;
await UpdateUser(user).ConfigureAwait(false); UpdateUser(user);
EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger); EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger);
} }
public async Task ChangeEasyPassword(User user, string newPasswordSha1) public void ChangeEasyPassword(User user, string newPasswordSha1)
{ {
if (user == null) if (user == null)
{ {
@ -727,7 +727,7 @@ namespace Emby.Server.Implementations.Library
user.EasyPassword = newPasswordSha1; user.EasyPassword = newPasswordSha1;
await UpdateUser(user).ConfigureAwait(false); UpdateUser(user);
EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger); EventHelper.FireEventIfNotNull(UserPasswordChanged, this, new GenericEventArgs<User>(user), _logger);
} }
@ -842,7 +842,7 @@ namespace Emby.Server.Implementations.Library
}; };
} }
public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin) public PinRedeemResult RedeemPasswordResetPin(string pin)
{ {
DeletePinFile(); DeletePinFile();
@ -863,12 +863,12 @@ namespace Emby.Server.Implementations.Library
foreach (var user in users) foreach (var user in users)
{ {
await ResetPassword(user).ConfigureAwait(false); ResetPassword(user);
if (user.Policy.IsDisabled) if (user.Policy.IsDisabled)
{ {
user.Policy.IsDisabled = false; user.Policy.IsDisabled = false;
await UpdateUserPolicy(user, user.Policy, true).ConfigureAwait(false); UpdateUserPolicy(user, user.Policy, true);
} }
usersReset.Add(user.Name); usersReset.Add(user.Name);
} }
@ -945,13 +945,13 @@ namespace Emby.Server.Implementations.Library
} }
private readonly object _policySyncLock = new object(); private readonly object _policySyncLock = new object();
public Task UpdateUserPolicy(string userId, UserPolicy userPolicy) public void UpdateUserPolicy(string userId, UserPolicy userPolicy)
{ {
var user = GetUserById(userId); var user = GetUserById(userId);
return UpdateUserPolicy(user, userPolicy, true); UpdateUserPolicy(user, userPolicy, true);
} }
private async Task UpdateUserPolicy(User user, UserPolicy userPolicy, bool fireEvent) private void UpdateUserPolicy(User user, UserPolicy userPolicy, bool fireEvent)
{ {
// The xml serializer will output differently if the type is not exact // The xml serializer will output differently if the type is not exact
if (userPolicy.GetType() != typeof(UserPolicy)) if (userPolicy.GetType() != typeof(UserPolicy))
@ -970,7 +970,7 @@ namespace Emby.Server.Implementations.Library
user.Policy = userPolicy; user.Policy = userPolicy;
} }
await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); UpdateConfiguration(user, user.Configuration, true);
} }
private void DeleteUserPolicy(User user) private void DeleteUserPolicy(User user)
@ -1032,13 +1032,13 @@ namespace Emby.Server.Implementations.Library
} }
private readonly object _configSyncLock = new object(); private readonly object _configSyncLock = new object();
public Task UpdateConfiguration(string userId, UserConfiguration config) public void UpdateConfiguration(string userId, UserConfiguration config)
{ {
var user = GetUserById(userId); var user = GetUserById(userId);
return UpdateConfiguration(user, config, true); UpdateConfiguration(user, config, true);
} }
private async Task UpdateConfiguration(User user, UserConfiguration config, bool fireEvent) private void UpdateConfiguration(User user, UserConfiguration config, bool fireEvent)
{ {
var path = GetConfigurationFilePath(user); var path = GetConfigurationFilePath(user);

View File

@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.Library
_config = config; _config = config;
} }
public async Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken) public async Task<Folder[]> GetUserViews(UserViewQuery query, CancellationToken cancellationToken)
{ {
var user = _userManager.GetUserById(query.UserId); var user = _userManager.GetUserById(query.UserId);
@ -68,7 +68,7 @@ namespace Emby.Server.Implementations.Library
if (UserView.IsUserSpecific(folder)) if (UserView.IsUserSpecific(folder))
{ {
list.Add(await _libraryManager.GetNamedView(user, folder.Name, folder.Id.ToString("N"), folderViewType, null, cancellationToken).ConfigureAwait(false)); list.Add(_libraryManager.GetNamedView(user, folder.Name, folder.Id.ToString("N"), folderViewType, null, cancellationToken));
continue; continue;
} }
@ -80,7 +80,7 @@ namespace Emby.Server.Implementations.Library
if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) if (query.PresetViews.Contains(folderViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{ {
list.Add(await GetUserView(folder, folderViewType, string.Empty, cancellationToken).ConfigureAwait(false)); list.Add(GetUserView(folder, folderViewType, string.Empty, cancellationToken));
} }
else else
{ {
@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.Library
if (parents.Count > 0) if (parents.Count > 0)
{ {
list.Add(await GetUserView(parents, viewType, string.Empty, user, query.PresetViews, cancellationToken).ConfigureAwait(false)); list.Add(GetUserView(parents, viewType, string.Empty, user, query.PresetViews, cancellationToken));
} }
} }
@ -154,7 +154,8 @@ namespace Emby.Server.Implementations.Library
return index == -1 ? int.MaxValue : index; return index == -1 ? int.MaxValue : index;
}) })
.ThenBy(sorted.IndexOf) .ThenBy(sorted.IndexOf)
.ThenBy(i => i.SortName); .ThenBy(i => i.SortName)
.ToArray();
} }
public Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken) public Task<UserView> GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken)
@ -171,7 +172,7 @@ namespace Emby.Server.Implementations.Library
return GetUserSubView(name, parentId, type, sortName, cancellationToken); return GetUserSubView(name, parentId, type, sortName, cancellationToken);
} }
private async Task<Folder> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, string[] presetViews, CancellationToken cancellationToken) private Folder GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, string[] presetViews, CancellationToken cancellationToken)
{ {
if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase))) if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
{ {
@ -180,14 +181,14 @@ namespace Emby.Server.Implementations.Library
return (Folder)parents[0]; return (Folder)parents[0];
} }
return await GetUserView((Folder)parents[0], viewType, string.Empty, cancellationToken).ConfigureAwait(false); return GetUserView((Folder)parents[0], viewType, string.Empty, cancellationToken);
} }
var name = _localizationManager.GetLocalizedString("ViewType" + viewType); var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false); return _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken);
} }
public Task<UserView> GetUserView(Folder parent, string viewType, string sortName, CancellationToken cancellationToken) public UserView GetUserView(Folder parent, string viewType, string sortName, CancellationToken cancellationToken)
{ {
return _libraryManager.GetShadowView(parent, viewType, sortName, cancellationToken); return _libraryManager.GetShadowView(parent, viewType, sortName, cancellationToken);
} }

View File

@ -208,7 +208,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
continue; continue;
} }
if (virtualFolder.Locations.Count == 1) if (virtualFolder.Locations.Length == 1)
{ {
// remove entire virtual folder // remove entire virtual folder
try try
@ -458,7 +458,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return GetEpgChannelFromTunerChannel(info, tunerChannel, epgChannels); return GetEpgChannelFromTunerChannel(info, tunerChannel, epgChannels);
} }
private string GetMappedChannel(string channelId, List<NameValuePair> mappings) private string GetMappedChannel(string channelId, NameValuePair[] mappings)
{ {
foreach (NameValuePair mapping in mappings) foreach (NameValuePair mapping in mappings)
{ {
@ -472,10 +472,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private ChannelInfo GetEpgChannelFromTunerChannel(ListingsProviderInfo info, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels) private ChannelInfo GetEpgChannelFromTunerChannel(ListingsProviderInfo info, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
{ {
return GetEpgChannelFromTunerChannel(info.ChannelMappings.ToList(), tunerChannel, epgChannels); return GetEpgChannelFromTunerChannel(info.ChannelMappings, tunerChannel, epgChannels);
} }
public ChannelInfo GetEpgChannelFromTunerChannel(List<NameValuePair> mappings, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels) public ChannelInfo GetEpgChannelFromTunerChannel(NameValuePair[] mappings, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
{ {
if (!string.IsNullOrWhiteSpace(tunerChannel.Id)) if (!string.IsNullOrWhiteSpace(tunerChannel.Id))
{ {
@ -607,13 +607,14 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var timer = _timerProvider.GetTimer(timerId); var timer = _timerProvider.GetTimer(timerId);
if (timer != null) if (timer != null)
{ {
timer.Status = RecordingStatus.Cancelled;
if (string.IsNullOrWhiteSpace(timer.SeriesTimerId) || isSeriesCancelled) if (string.IsNullOrWhiteSpace(timer.SeriesTimerId) || isSeriesCancelled)
{ {
_timerProvider.Delete(timer); _timerProvider.Delete(timer);
} }
else else
{ {
timer.Status = RecordingStatus.Cancelled;
_timerProvider.AddOrUpdate(timer, false); _timerProvider.AddOrUpdate(timer, false);
} }
} }
@ -621,6 +622,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
if (_activeRecordings.TryGetValue(timerId, out activeRecordingInfo)) if (_activeRecordings.TryGetValue(timerId, out activeRecordingInfo))
{ {
activeRecordingInfo.Timer = timer;
activeRecordingInfo.CancellationTokenSource.Cancel(); activeRecordingInfo.CancellationTokenSource.Cancel();
} }
} }
@ -830,6 +832,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
existingTimer.IsKids = updatedTimer.IsKids; existingTimer.IsKids = updatedTimer.IsKids;
existingTimer.IsNews = updatedTimer.IsNews; existingTimer.IsNews = updatedTimer.IsNews;
existingTimer.IsMovie = updatedTimer.IsMovie; existingTimer.IsMovie = updatedTimer.IsMovie;
existingTimer.IsSeries = updatedTimer.IsSeries;
existingTimer.IsLive = updatedTimer.IsLive;
existingTimer.IsPremiere = updatedTimer.IsPremiere;
existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries; existingTimer.IsProgramSeries = updatedTimer.IsProgramSeries;
existingTimer.IsRepeat = updatedTimer.IsRepeat; existingTimer.IsRepeat = updatedTimer.IsRepeat;
existingTimer.IsSports = updatedTimer.IsSports; existingTimer.IsSports = updatedTimer.IsSports;
@ -861,7 +866,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken) public async Task<IEnumerable<RecordingInfo>> GetRecordingsAsync(CancellationToken cancellationToken)
{ {
return _activeRecordings.Values.ToList().Select(GetRecordingInfo).ToList(); return new List<RecordingInfo>();
} }
public string GetActiveRecordingPath(string id) public string GetActiveRecordingPath(string id)
@ -875,49 +880,31 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return null; return null;
} }
private RecordingInfo GetRecordingInfo(ActiveRecordingInfo info) public IEnumerable<ActiveRecordingInfo> GetAllActiveRecordings()
{ {
var timer = info.Timer; return _activeRecordings.Values.Where(i => i.Timer.Status == RecordingStatus.InProgress && !i.CancellationTokenSource.IsCancellationRequested);
var program = info.Program; }
var result = new RecordingInfo public ActiveRecordingInfo GetActiveRecordingInfo(string path)
{
if (string.IsNullOrWhiteSpace(path))
{ {
ChannelId = timer.ChannelId, return null;
CommunityRating = timer.CommunityRating,
DateLastUpdated = DateTime.UtcNow,
EndDate = timer.EndDate,
EpisodeTitle = timer.EpisodeTitle,
Genres = timer.Genres,
Id = "recording" + timer.Id,
IsKids = timer.IsKids,
IsMovie = timer.IsMovie,
IsNews = timer.IsNews,
IsRepeat = timer.IsRepeat,
IsSeries = timer.IsProgramSeries,
IsSports = timer.IsSports,
Name = timer.Name,
OfficialRating = timer.OfficialRating,
OriginalAirDate = timer.OriginalAirDate,
Overview = timer.Overview,
ProgramId = timer.ProgramId,
SeriesTimerId = timer.SeriesTimerId,
StartDate = timer.StartDate,
Status = RecordingStatus.InProgress,
TimerId = timer.Id
};
if (program != null)
{
result.Audio = program.Audio;
result.ImagePath = program.ImagePath;
result.ImageUrl = program.ImageUrl;
result.IsHD = program.IsHD;
result.IsLive = program.IsLive;
result.IsPremiere = program.IsPremiere;
result.ShowId = program.ShowId;
} }
return result; foreach (var recording in _activeRecordings.Values)
{
if (string.Equals(recording.Path, path, StringComparison.Ordinal) && !recording.CancellationTokenSource.IsCancellationRequested)
{
var timer = recording.Timer;
if (timer.Status != RecordingStatus.InProgress)
{
return null;
}
return recording;
}
}
return null;
} }
public Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken) public Task<IEnumerable<TimerInfo>> GetTimersAsync(CancellationToken cancellationToken)
@ -1245,6 +1232,33 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
throw new FileNotFoundException(); throw new FileNotFoundException();
} }
public async Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(ActiveRecordingInfo info, CancellationToken cancellationToken)
{
var stream = new MediaSourceInfo
{
Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveRecordings/" + info.Id + "/stream",
Id = info.Id,
SupportsDirectPlay = false,
SupportsDirectStream = true,
SupportsTranscoding = true,
IsInfiniteStream = true,
RequiresOpening = false,
RequiresClosing = false,
Protocol = MediaBrowser.Model.MediaInfo.MediaProtocol.Http,
BufferMs = 0,
IgnoreDts = true,
IgnoreIndex = true
};
var isAudio = false;
await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
return new List<MediaSourceInfo>
{
stream
};
}
public async Task CloseLiveStream(string id, CancellationToken cancellationToken) public async Task CloseLiveStream(string id, CancellationToken cancellationToken)
{ {
// Ignore the consumer id // Ignore the consumer id
@ -1327,7 +1341,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var activeRecordingInfo = new ActiveRecordingInfo var activeRecordingInfo = new ActiveRecordingInfo
{ {
CancellationTokenSource = new CancellationTokenSource(), CancellationTokenSource = new CancellationTokenSource(),
Timer = timer Timer = timer,
Id = timer.Id
}; };
if (_activeRecordings.TryAdd(timer.Id, activeRecordingInfo)) if (_activeRecordings.TryAdd(timer.Id, activeRecordingInfo))
@ -1493,7 +1508,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath); recordPath = recorder.GetOutputPath(mediaStreamInfo, recordPath);
recordPath = EnsureFileUnique(recordPath, timer.Id); recordPath = EnsureFileUnique(recordPath, timer.Id);
_libraryManager.RegisterIgnoredPath(recordPath);
_libraryMonitor.ReportFileSystemChangeBeginning(recordPath); _libraryMonitor.ReportFileSystemChangeBeginning(recordPath);
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(recordPath)); _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(recordPath));
activeRecordingInfo.Path = recordPath; activeRecordingInfo.Path = recordPath;
@ -1512,6 +1526,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_timerProvider.AddOrUpdate(timer, false); _timerProvider.AddOrUpdate(timer, false);
SaveRecordingMetadata(timer, recordPath, seriesPath); SaveRecordingMetadata(timer, recordPath, seriesPath);
TriggerRefresh(recordPath);
EnforceKeepUpTo(timer, seriesPath); EnforceKeepUpTo(timer, seriesPath);
}; };
@ -1543,7 +1558,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
} }
} }
_libraryManager.UnRegisterIgnoredPath(recordPath); TriggerRefresh(recordPath);
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, true); _libraryMonitor.ReportFileSystemChangeComplete(recordPath, true);
ActiveRecordingInfo removed; ActiveRecordingInfo removed;
@ -1574,6 +1589,44 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
OnRecordingStatusChanged(); OnRecordingStatusChanged();
} }
private void TriggerRefresh(string path)
{
var item = GetAffectedBaseItem(_fileSystem.GetDirectoryName(path));
if (item != null)
{
item.ChangedExternally();
}
}
private BaseItem GetAffectedBaseItem(string path)
{
BaseItem item = null;
while (item == null && !string.IsNullOrEmpty(path))
{
item = _libraryManager.FindByPath(path, null);
path = _fileSystem.GetDirectoryName(path);
}
if (item != null)
{
// If the item has been deleted find the first valid parent that still exists
while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path))
{
item = item.GetParent();
if (item == null)
{
break;
}
}
}
return item;
}
private void OnRecordingStatusChanged() private void OnRecordingStatusChanged()
{ {
EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs EventHelper.FireEventIfNotNull(RecordingStatusChanged, this, new RecordingStatusChangedEventArgs
@ -2591,7 +2644,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
list.Add(new VirtualFolderInfo list.Add(new VirtualFolderInfo
{ {
Locations = new List<string> { defaultFolder }, Locations = new string[] { defaultFolder },
Name = defaultName Name = defaultName
}); });
} }
@ -2601,7 +2654,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
list.Add(new VirtualFolderInfo list.Add(new VirtualFolderInfo
{ {
Locations = new List<string> { customPath }, Locations = new string[] { customPath },
Name = "Recorded Movies", Name = "Recorded Movies",
CollectionType = CollectionType.Movies CollectionType = CollectionType.Movies
}); });
@ -2612,7 +2665,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{ {
list.Add(new VirtualFolderInfo list.Add(new VirtualFolderInfo
{ {
Locations = new List<string> { customPath }, Locations = new string[] { customPath },
Name = "Recorded Shows", Name = "Recorded Shows",
CollectionType = CollectionType.TvShows CollectionType = CollectionType.TvShows
}); });
@ -2621,14 +2674,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return list; return list;
} }
class ActiveRecordingInfo
{
public string Path { get; set; }
public TimerInfo Timer { get; set; }
public ProgramInfo Program { get; set; }
public CancellationTokenSource CancellationTokenSource { get; set; }
}
private const int TunerDiscoveryDurationMs = 3000; private const int TunerDiscoveryDurationMs = 3000;
public async Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken) public async Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken)

View File

@ -58,6 +58,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
timerInfo.OriginalAirDate = programInfo.OriginalAirDate; timerInfo.OriginalAirDate = programInfo.OriginalAirDate;
timerInfo.IsProgramSeries = programInfo.IsSeries; timerInfo.IsProgramSeries = programInfo.IsSeries;
timerInfo.IsSeries = programInfo.IsSeries;
timerInfo.IsLive = programInfo.IsLive;
timerInfo.IsPremiere = programInfo.IsPremiere;
timerInfo.HomePageUrl = programInfo.HomePageUrl; timerInfo.HomePageUrl = programInfo.HomePageUrl;
timerInfo.CommunityRating = programInfo.CommunityRating; timerInfo.CommunityRating = programInfo.CommunityRating;
timerInfo.Overview = programInfo.Overview; timerInfo.Overview = programInfo.Overview;

View File

@ -247,7 +247,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings
ProgramAudio audioType = ProgramAudio.Stereo; ProgramAudio audioType = ProgramAudio.Stereo;
bool repeat = programInfo.@new == null; bool repeat = programInfo.@new == null;
string newID = programInfo.programID + "T" + startAt.Ticks + "C" + channelId;
var programId = programInfo.programID ?? string.Empty;
string newID = programId + "T" + startAt.Ticks + "C" + channelId;
if (programInfo.audioProperties != null) if (programInfo.audioProperties != null)
{ {
@ -300,7 +303,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
Etag = programInfo.md5 Etag = programInfo.md5
}; };
var showId = programInfo.programID ?? string.Empty; var showId = programId;
if (!info.IsSeries) if (!info.IsSeries)
{ {
@ -339,11 +342,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (details.descriptions != null) if (details.descriptions != null)
{ {
if (details.descriptions.description1000 != null) if (details.descriptions.description1000 != null && details.descriptions.description1000.Count > 0)
{ {
info.Overview = details.descriptions.description1000[0].description; info.Overview = details.descriptions.description1000[0].description;
} }
else if (details.descriptions.description100 != null) else if (details.descriptions.description100 != null && details.descriptions.description100.Count > 0)
{ {
info.Overview = details.descriptions.description100[0].description; info.Overview = details.descriptions.description100[0].description;
} }
@ -351,16 +354,24 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (info.IsSeries) if (info.IsSeries)
{ {
info.SeriesId = programInfo.programID.Substring(0, 10); info.SeriesId = programId.Substring(0, 10);
if (details.metadata != null) if (details.metadata != null)
{ {
var gracenote = details.metadata.Find(x => x.Gracenote != null).Gracenote; foreach (var metadataProgram in details.metadata)
info.SeasonNumber = gracenote.season;
if (gracenote.episode > 0)
{ {
info.EpisodeNumber = gracenote.episode; var gracenote = metadataProgram.Gracenote;
if (gracenote != null)
{
info.SeasonNumber = gracenote.season;
if (gracenote.episode > 0)
{
info.EpisodeNumber = gracenote.episode;
}
break;
}
} }
} }
} }

View File

@ -15,6 +15,8 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.LiveTv namespace Emby.Server.Implementations.LiveTv
{ {
@ -110,7 +112,7 @@ namespace Emby.Server.Implementations.LiveTv
PostPaddingSeconds = info.PostPaddingSeconds, PostPaddingSeconds = info.PostPaddingSeconds,
IsPostPaddingRequired = info.IsPostPaddingRequired, IsPostPaddingRequired = info.IsPostPaddingRequired,
IsPrePaddingRequired = info.IsPrePaddingRequired, IsPrePaddingRequired = info.IsPrePaddingRequired,
Days = info.Days, Days = info.Days.ToArray(),
Priority = info.Priority, Priority = info.Priority,
RecordAnyChannel = info.RecordAnyChannel, RecordAnyChannel = info.RecordAnyChannel,
RecordAnyTime = info.RecordAnyTime, RecordAnyTime = info.RecordAnyTime,
@ -135,7 +137,7 @@ namespace Emby.Server.Implementations.LiveTv
dto.ProgramId = GetInternalProgramId(service.Name, info.ProgramId).ToString("N"); dto.ProgramId = GetInternalProgramId(service.Name, info.ProgramId).ToString("N");
} }
dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days); dto.DayPattern = info.Days == null ? null : GetDayPattern(info.Days.ToArray(info.Days.Count));
FillImages(dto, info.Name, info.SeriesId); FillImages(dto, info.Name, info.SeriesId);
@ -150,10 +152,7 @@ namespace Emby.Server.Implementations.LiveTv
Name = seriesName, Name = seriesName,
Limit = 1, Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb }, ImageTypes = new ImageType[] { ImageType.Thumb },
DtoOptions = new DtoOptions DtoOptions = new DtoOptions(false)
{
Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
}
}).FirstOrDefault(); }).FirstOrDefault();
@ -196,10 +195,7 @@ namespace Emby.Server.Implementations.LiveTv
ExternalSeriesId = programSeriesId, ExternalSeriesId = programSeriesId,
Limit = 1, Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary }, ImageTypes = new ImageType[] { ImageType.Primary },
DtoOptions = new DtoOptions DtoOptions = new DtoOptions(false)
{
Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
}
}).FirstOrDefault(); }).FirstOrDefault();
@ -248,10 +244,7 @@ namespace Emby.Server.Implementations.LiveTv
Name = seriesName, Name = seriesName,
Limit = 1, Limit = 1,
ImageTypes = new ImageType[] { ImageType.Thumb }, ImageTypes = new ImageType[] { ImageType.Thumb },
DtoOptions = new DtoOptions DtoOptions = new DtoOptions(false)
{
Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
}
}).FirstOrDefault(); }).FirstOrDefault();
@ -274,7 +267,7 @@ namespace Emby.Server.Implementations.LiveTv
{ {
try try
{ {
dto.ParentBackdropImageTags = new List<string> dto.ParentBackdropImageTags = new string[]
{ {
_imageProcessor.GetImageCacheTag(librarySeries, image) _imageProcessor.GetImageCacheTag(librarySeries, image)
}; };
@ -294,10 +287,7 @@ namespace Emby.Server.Implementations.LiveTv
Name = seriesName, Name = seriesName,
Limit = 1, Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary }, ImageTypes = new ImageType[] { ImageType.Primary },
DtoOptions = new DtoOptions DtoOptions = new DtoOptions(false)
{
Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
}
}).FirstOrDefault() ?? _libraryManager.GetItemList(new InternalItemsQuery }).FirstOrDefault() ?? _libraryManager.GetItemList(new InternalItemsQuery
{ {
@ -305,10 +295,7 @@ namespace Emby.Server.Implementations.LiveTv
ExternalSeriesId = programSeriesId, ExternalSeriesId = programSeriesId,
Limit = 1, Limit = 1,
ImageTypes = new ImageType[] { ImageType.Primary }, ImageTypes = new ImageType[] { ImageType.Primary },
DtoOptions = new DtoOptions DtoOptions = new DtoOptions(false)
{
Fields = new List<MediaBrowser.Model.Querying.ItemFields>()
}
}).FirstOrDefault(); }).FirstOrDefault();
@ -327,14 +314,14 @@ namespace Emby.Server.Implementations.LiveTv
} }
} }
if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Count == 0) if (dto.ParentBackdropImageTags == null || dto.ParentBackdropImageTags.Length == 0)
{ {
image = program.GetImageInfo(ImageType.Backdrop, 0); image = program.GetImageInfo(ImageType.Backdrop, 0);
if (image != null) if (image != null)
{ {
try try
{ {
dto.ParentBackdropImageTags = new List<string> dto.ParentBackdropImageTags = new string[]
{ {
_imageProcessor.GetImageCacheTag(program, image) _imageProcessor.GetImageCacheTag(program, image)
}; };
@ -349,24 +336,24 @@ namespace Emby.Server.Implementations.LiveTv
} }
} }
public DayPattern? GetDayPattern(List<DayOfWeek> days) public DayPattern? GetDayPattern(DayOfWeek[] days)
{ {
DayPattern? pattern = null; DayPattern? pattern = null;
if (days.Count > 0) if (days.Length > 0)
{ {
if (days.Count == 7) if (days.Length == 7)
{ {
pattern = DayPattern.Daily; pattern = DayPattern.Daily;
} }
else if (days.Count == 2) else if (days.Length == 2)
{ {
if (days.Contains(DayOfWeek.Saturday) && days.Contains(DayOfWeek.Sunday)) if (days.Contains(DayOfWeek.Saturday) && days.Contains(DayOfWeek.Sunday))
{ {
pattern = DayPattern.Weekends; pattern = DayPattern.Weekends;
} }
} }
else if (days.Count == 5) else if (days.Length == 5)
{ {
if (days.Contains(DayOfWeek.Monday) && days.Contains(DayOfWeek.Tuesday) && days.Contains(DayOfWeek.Wednesday) && days.Contains(DayOfWeek.Thursday) && days.Contains(DayOfWeek.Friday)) if (days.Contains(DayOfWeek.Monday) && days.Contains(DayOfWeek.Tuesday) && days.Contains(DayOfWeek.Wednesday) && days.Contains(DayOfWeek.Thursday) && days.Contains(DayOfWeek.Friday))
{ {
@ -384,7 +371,7 @@ namespace Emby.Server.Implementations.LiveTv
{ {
Name = info.Name, Name = info.Name,
Id = info.Id, Id = info.Id,
Clients = info.Clients, Clients = info.Clients.ToArray(),
ProgramName = info.ProgramName, ProgramName = info.ProgramName,
SourceType = info.SourceType, SourceType = info.SourceType,
Status = info.Status, Status = info.Status,
@ -543,7 +530,7 @@ namespace Emby.Server.Implementations.LiveTv
PostPaddingSeconds = dto.PostPaddingSeconds, PostPaddingSeconds = dto.PostPaddingSeconds,
IsPostPaddingRequired = dto.IsPostPaddingRequired, IsPostPaddingRequired = dto.IsPostPaddingRequired,
IsPrePaddingRequired = dto.IsPrePaddingRequired, IsPrePaddingRequired = dto.IsPrePaddingRequired,
Days = dto.Days, Days = dto.Days.ToList(),
Priority = dto.Priority, Priority = dto.Priority,
RecordAnyChannel = dto.RecordAnyChannel, RecordAnyChannel = dto.RecordAnyChannel,
RecordAnyTime = dto.RecordAnyTime, RecordAnyTime = dto.RecordAnyTime,

View File

@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.LiveTv
private readonly LiveTvDtoService _tvDtoService; private readonly LiveTvDtoService _tvDtoService;
private readonly List<ILiveTvService> _services = new List<ILiveTvService>(); private ILiveTvService[] _services = new ILiveTvService[] { };
private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _refreshRecordingsLock = new SemaphoreSlim(1, 1);
@ -124,7 +124,7 @@ namespace Emby.Server.Implementations.LiveTv
/// <param name="listingProviders">The listing providers.</param> /// <param name="listingProviders">The listing providers.</param>
public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders) public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders)
{ {
_services.AddRange(services); _services = services.ToArray();
_tunerHosts.AddRange(tunerHosts); _tunerHosts.AddRange(tunerHosts);
_listingProviders.AddRange(listingProviders); _listingProviders.AddRange(listingProviders);
@ -558,7 +558,7 @@ namespace Emby.Server.Implementations.LiveTv
if (isNew) if (isNew)
{ {
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); _libraryManager.CreateItem(item, cancellationToken);
} }
else if (forceUpdate) else if (forceUpdate)
{ {
@ -875,7 +875,7 @@ namespace Emby.Server.Implementations.LiveTv
if (isNew) if (isNew)
{ {
await _libraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); _libraryManager.CreateItem(item, cancellationToken);
} }
else if (dataChanged || info.DateLastUpdated > recording.DateLastSaved || statusChanged) else if (dataChanged || info.DateLastUpdated > recording.DateLastSaved || statusChanged)
{ {
@ -985,9 +985,8 @@ namespace Emby.Server.Implementations.LiveTv
var queryResult = _libraryManager.QueryItems(internalQuery); var queryResult = _libraryManager.QueryItems(internalQuery);
var returnList = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user) var returnArray = (await _dtoService.GetBaseItemDtos(queryResult.Items, options, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnArray = returnList.ToArray(returnList.Count);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
@ -998,7 +997,7 @@ namespace Emby.Server.Implementations.LiveTv
return result; return result;
} }
public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken) public async Task<QueryResult<BaseItem>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken)
{ {
var user = _userManager.GetUserById(query.UserId); var user = _userManager.GetUserById(query.UserId);
@ -1036,10 +1035,10 @@ namespace Emby.Server.Implementations.LiveTv
} }
} }
var programList = _libraryManager.QueryItems(internalQuery).Items.Cast<LiveTvProgram>().ToList(); var programList = _libraryManager.QueryItems(internalQuery).Items;
var totalCount = programList.Count; var totalCount = programList.Length;
IOrderedEnumerable<LiveTvProgram> orderedPrograms = programList.OrderBy(i => i.StartDate.Date); IOrderedEnumerable<LiveTvProgram> orderedPrograms = programList.Cast<LiveTvProgram>().OrderBy(i => i.StartDate.Date);
if (query.IsAiring ?? false) if (query.IsAiring ?? false)
{ {
@ -1047,14 +1046,14 @@ namespace Emby.Server.Implementations.LiveTv
.ThenByDescending(i => GetRecommendationScore(i, user.Id, true)); .ThenByDescending(i => GetRecommendationScore(i, user.Id, true));
} }
IEnumerable<LiveTvProgram> programs = orderedPrograms; IEnumerable<BaseItem> programs = orderedPrograms;
if (query.Limit.HasValue) if (query.Limit.HasValue)
{ {
programs = programs.Take(query.Limit.Value); programs = programs.Take(query.Limit.Value);
} }
var result = new QueryResult<LiveTvProgram> var result = new QueryResult<BaseItem>
{ {
Items = programs.ToArray(), Items = programs.ToArray(),
TotalRecordCount = totalCount TotalRecordCount = totalCount
@ -1071,9 +1070,8 @@ namespace Emby.Server.Implementations.LiveTv
var user = _userManager.GetUserById(query.UserId); var user = _userManager.GetUserById(query.UserId);
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnArray = returnList.ToArray(returnList.Count);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
@ -1223,9 +1221,9 @@ namespace Emby.Server.Implementations.LiveTv
await EmbyTV.EmbyTV.Current.ScanForTunerDeviceChanges(cancellationToken).ConfigureAwait(false); await EmbyTV.EmbyTV.Current.ScanForTunerDeviceChanges(cancellationToken).ConfigureAwait(false);
var numComplete = 0; var numComplete = 0;
double progressPerService = _services.Count == 0 double progressPerService = _services.Length == 0
? 0 ? 0
: 1 / _services.Count; : 1 / _services.Length;
var newChannelIdList = new List<Guid>(); var newChannelIdList = new List<Guid>();
var newProgramIdList = new List<Guid>(); var newProgramIdList = new List<Guid>();
@ -1257,13 +1255,13 @@ namespace Emby.Server.Implementations.LiveTv
numComplete++; numComplete++;
double percent = numComplete; double percent = numComplete;
percent /= _services.Count; percent /= _services.Length;
progress.Report(100 * percent); progress.Report(100 * percent);
} }
await CleanDatabaseInternal(newChannelIdList, new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false); await CleanDatabaseInternal(newChannelIdList.ToArray(), new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false);
await CleanDatabaseInternal(newProgramIdList, new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false); await CleanDatabaseInternal(newProgramIdList.ToArray(), new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false);
var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault(); var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault();
@ -1275,8 +1273,11 @@ namespace Emby.Server.Implementations.LiveTv
// Load these now which will prefetch metadata // Load these now which will prefetch metadata
var dtoOptions = new DtoOptions(); var dtoOptions = new DtoOptions();
dtoOptions.Fields.Remove(ItemFields.SyncInfo); var fields = dtoOptions.Fields.ToList();
dtoOptions.Fields.Remove(ItemFields.BasicSyncInfo); fields.Remove(ItemFields.SyncInfo);
fields.Remove(ItemFields.BasicSyncInfo);
dtoOptions.Fields = fields.ToArray(fields.Count);
await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false); await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false);
progress.Report(100); progress.Report(100);
@ -1409,7 +1410,7 @@ namespace Emby.Server.Implementations.LiveTv
if (newPrograms.Count > 0) if (newPrograms.Count > 0)
{ {
await _libraryManager.CreateItems(newPrograms, cancellationToken).ConfigureAwait(false); _libraryManager.CreateItems(newPrograms, cancellationToken);
} }
// TODO: Do this in bulk // TODO: Do this in bulk
@ -1446,14 +1447,14 @@ namespace Emby.Server.Implementations.LiveTv
return new Tuple<List<Guid>, List<Guid>>(channels, programs); return new Tuple<List<Guid>, List<Guid>>(channels, programs);
} }
private async Task CleanDatabaseInternal(List<Guid> currentIdList, string[] validTypes, IProgress<double> progress, CancellationToken cancellationToken) private async Task CleanDatabaseInternal(Guid[] currentIdList, string[] validTypes, IProgress<double> progress, CancellationToken cancellationToken)
{ {
var list = _itemRepo.GetItemIdsList(new InternalItemsQuery var list = _itemRepo.GetItemIdsList(new InternalItemsQuery
{ {
IncludeItemTypes = validTypes, IncludeItemTypes = validTypes,
DtoOptions = new DtoOptions(false) DtoOptions = new DtoOptions(false)
}).ToList(); });
var numComplete = 0; var numComplete = 0;
@ -1543,7 +1544,7 @@ namespace Emby.Server.Implementations.LiveTv
var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false); var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false);
await CleanDatabaseInternal(idList.ToList(), new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false); await CleanDatabaseInternal(idList, new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false);
_lastRecordingRefreshTime = DateTime.UtcNow; _lastRecordingRefreshTime = DateTime.UtcNow;
} }
@ -1560,11 +1561,6 @@ namespace Emby.Server.Implementations.LiveTv
return new QueryResult<BaseItem>(); return new QueryResult<BaseItem>();
} }
if ((query.IsInProgress ?? false))
{
return new QueryResult<BaseItem>();
}
var folderIds = EmbyTV.EmbyTV.Current.GetRecordingFolders() var folderIds = EmbyTV.EmbyTV.Current.GetRecordingFolders()
.SelectMany(i => i.Locations) .SelectMany(i => i.Locations)
.Distinct(StringComparer.OrdinalIgnoreCase) .Distinct(StringComparer.OrdinalIgnoreCase)
@ -1576,13 +1572,10 @@ namespace Emby.Server.Implementations.LiveTv
var excludeItemTypes = new List<string>(); var excludeItemTypes = new List<string>();
if (!query.IsInProgress.HasValue) folderIds.Add(internalLiveTvFolderId);
{
folderIds.Add(internalLiveTvFolderId);
excludeItemTypes.Add(typeof(LiveTvChannel).Name); excludeItemTypes.Add(typeof(LiveTvChannel).Name);
excludeItemTypes.Add(typeof(LiveTvProgram).Name); excludeItemTypes.Add(typeof(LiveTvProgram).Name);
}
if (folderIds.Count == 0) if (folderIds.Count == 0)
{ {
@ -1631,6 +1624,19 @@ namespace Emby.Server.Implementations.LiveTv
} }
} }
if ((query.IsInProgress ?? false))
{
// TODO: filter
var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
return new QueryResult<BaseItem>
{
Items = items,
TotalRecordCount = items.Length
};
}
return _libraryManager.GetItemsResult(new InternalItemsQuery(user) return _libraryManager.GetItemsResult(new InternalItemsQuery(user)
{ {
MediaTypes = new[] { MediaType.Video }, MediaTypes = new[] { MediaType.Video },
@ -1658,11 +1664,6 @@ namespace Emby.Server.Implementations.LiveTv
return new QueryResult<BaseItemDto>(); return new QueryResult<BaseItemDto>();
} }
if (_services.Count > 1)
{
return new QueryResult<BaseItemDto>();
}
if (user == null || (query.IsInProgress ?? false)) if (user == null || (query.IsInProgress ?? false))
{ {
return new QueryResult<BaseItemDto>(); return new QueryResult<BaseItemDto>();
@ -1701,11 +1702,9 @@ namespace Emby.Server.Implementations.LiveTv
DtoOptions = options DtoOptions = options
}); });
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnArray = returnList.ToArray(returnList.Count);
return new QueryResult<BaseItemDto> return new QueryResult<BaseItemDto>
{ {
Items = returnArray, Items = returnArray,
@ -1723,13 +1722,9 @@ namespace Emby.Server.Implementations.LiveTv
var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false);
if (_services.Count == 1 && (!query.IsInProgress.HasValue || !query.IsInProgress.Value) && (!query.IsLibraryItem.HasValue || query.IsLibraryItem.Value)) // TODO: Figure out how to merge emby recordings + service recordings
if (_services.Length == 1)
{ {
if (!query.IsInProgress.HasValue)
{
await RefreshRecordings(folder.Id, cancellationToken).ConfigureAwait(false);
}
return GetEmbyRecordings(query, options, folder.Id, user); return GetEmbyRecordings(query, options, folder.Id, user);
} }
@ -1841,7 +1836,7 @@ namespace Emby.Server.Implementations.LiveTv
}; };
} }
public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, List<ItemFields> fields, User user = null) public async Task AddInfoToProgramDto(List<Tuple<BaseItem, BaseItemDto>> tuples, ItemFields[] fields, User user = null)
{ {
var programTuples = new List<Tuple<BaseItemDto, string, string, string>>(); var programTuples = new List<Tuple<BaseItemDto, string, string, string>>();
var hasChannelImage = fields.Contains(ItemFields.ChannelImage); var hasChannelImage = fields.Contains(ItemFields.ChannelImage);
@ -1921,6 +1916,11 @@ namespace Emby.Server.Implementations.LiveTv
await AddRecordingInfo(programTuples, CancellationToken.None).ConfigureAwait(false); await AddRecordingInfo(programTuples, CancellationToken.None).ConfigureAwait(false);
} }
public ActiveRecordingInfo GetActiveRecordingInfo(string path)
{
return EmbyTV.EmbyTV.Current.GetActiveRecordingInfo(path);
}
public void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, User user = null) public void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, User user = null)
{ {
var recording = (ILiveTvRecording)item; var recording = (ILiveTvRecording)item;
@ -1950,20 +1950,6 @@ namespace Emby.Server.Implementations.LiveTv
dto.IsKids = info.IsKids; dto.IsKids = info.IsKids;
dto.IsPremiere = info.IsPremiere; dto.IsPremiere = info.IsPremiere;
dto.CanDelete = user == null
? recording.CanDelete()
: recording.CanDelete(user);
if (dto.MediaSources == null)
{
dto.MediaSources = recording.GetMediaSources(true);
}
if (dto.MediaStreams == null)
{
dto.MediaStreams = dto.MediaSources.SelectMany(i => i.MediaStreams).ToList();
}
if (info.Status == RecordingStatus.InProgress && info.EndDate.HasValue) if (info.Status == RecordingStatus.InProgress && info.EndDate.HasValue)
{ {
var now = DateTime.UtcNow.Ticks; var now = DateTime.UtcNow.Ticks;
@ -1987,6 +1973,65 @@ namespace Emby.Server.Implementations.LiveTv
} }
} }
public void AddInfoToRecordingDto(BaseItem item, BaseItemDto dto, ActiveRecordingInfo activeRecordingInfo, User user = null)
{
var service = EmbyTV.EmbyTV.Current;
var info = activeRecordingInfo.Timer;
var channel = string.IsNullOrWhiteSpace(info.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, info.ChannelId));
dto.SeriesTimerId = string.IsNullOrEmpty(info.SeriesTimerId)
? null
: _tvDtoService.GetInternalSeriesTimerId(service.Name, info.SeriesTimerId).ToString("N");
dto.TimerId = string.IsNullOrEmpty(info.Id)
? null
: _tvDtoService.GetInternalTimerId(service.Name, info.Id).ToString("N");
var startDate = info.StartDate;
var endDate = info.EndDate;
dto.StartDate = startDate;
dto.EndDate = endDate;
dto.Status = info.Status.ToString();
dto.IsRepeat = info.IsRepeat;
dto.EpisodeTitle = info.EpisodeTitle;
dto.IsMovie = info.IsMovie;
dto.IsSeries = info.IsSeries;
dto.IsSports = info.IsSports;
dto.IsLive = info.IsLive;
dto.IsNews = info.IsNews;
dto.IsKids = info.IsKids;
dto.IsPremiere = info.IsPremiere;
if (info.Status == RecordingStatus.InProgress)
{
startDate = info.StartDate.AddSeconds(0 - info.PrePaddingSeconds);
endDate = info.EndDate.AddSeconds(info.PostPaddingSeconds);
var now = DateTime.UtcNow.Ticks;
var start = startDate.Ticks;
var end = endDate.Ticks;
var pct = now - start;
pct /= end;
pct *= 100;
dto.CompletionPercentage = pct;
}
if (channel != null)
{
dto.ChannelName = channel.Name;
if (channel.HasImage(ImageType.Primary))
{
dto.ChannelPrimaryImageTag = _tvDtoService.GetImageTag(channel);
}
}
}
public async Task<QueryResult<BaseItemDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken) public async Task<QueryResult<BaseItemDto>> GetRecordings(RecordingQuery query, DtoOptions options, CancellationToken cancellationToken)
{ {
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@ -1995,9 +2040,8 @@ namespace Emby.Server.Implementations.LiveTv
var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false); var internalResult = await GetInternalRecordings(query, options, cancellationToken).ConfigureAwait(false);
var returnList = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user) var returnArray = (await _dtoService.GetBaseItemDtos(internalResult.Items, options, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnArray = returnList.ToArray(returnList.Count);
return new QueryResult<BaseItemDto> return new QueryResult<BaseItemDto>
{ {
@ -2100,7 +2144,6 @@ namespace Emby.Server.Implementations.LiveTv
if (service is EmbyTV.EmbyTV) if (service is EmbyTV.EmbyTV)
{ {
// We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says
return service.DeleteRecordingAsync(GetItemExternalId(recording), CancellationToken.None); return service.DeleteRecordingAsync(GetItemExternalId(recording), CancellationToken.None);
} }
@ -2350,7 +2393,6 @@ namespace Emby.Server.Implementations.LiveTv
var currentChannelsDict = new Dictionary<string, BaseItemDto>(); var currentChannelsDict = new Dictionary<string, BaseItemDto>();
var addCurrentProgram = options.AddCurrentProgram; var addCurrentProgram = options.AddCurrentProgram;
var addMediaSources = options.Fields.Contains(ItemFields.MediaSources);
var addServiceName = options.Fields.Contains(ItemFields.ServiceName); var addServiceName = options.Fields.Contains(ItemFields.ServiceName);
foreach (var tuple in tuples) foreach (var tuple in tuples)
@ -2369,11 +2411,6 @@ namespace Emby.Server.Implementations.LiveTv
currentChannelsDict[dto.Id] = dto; currentChannelsDict[dto.Id] = dto;
if (addMediaSources)
{
dto.MediaSources = channel.GetMediaSources(true);
}
if (addCurrentProgram) if (addCurrentProgram)
{ {
var channelIdString = channel.Id.ToString("N"); var channelIdString = channel.Id.ToString("N");
@ -2479,7 +2516,7 @@ namespace Emby.Server.Implementations.LiveTv
var defaults = await GetNewTimerDefaultsInternal(cancellationToken, program).ConfigureAwait(false); var defaults = await GetNewTimerDefaultsInternal(cancellationToken, program).ConfigureAwait(false);
var info = _tvDtoService.GetSeriesTimerInfoDto(defaults.Item1, defaults.Item2, null); var info = _tvDtoService.GetSeriesTimerInfoDto(defaults.Item1, defaults.Item2, null);
info.Days = defaults.Item1.Days; info.Days = defaults.Item1.Days.ToArray();
info.DayPattern = _tvDtoService.GetDayPattern(info.Days); info.DayPattern = _tvDtoService.GetDayPattern(info.Days);
@ -2656,8 +2693,7 @@ namespace Emby.Server.Implementations.LiveTv
var series = recordings var series = recordings
.Where(i => i.IsSeries) .Where(i => i.IsSeries)
.ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase) .ToLookup(i => i.Name, StringComparer.OrdinalIgnoreCase);
.ToList();
groups.AddRange(series.OrderByString(i => i.Key).Select(i => new BaseItemDto groups.AddRange(series.OrderByString(i => i.Key).Select(i => new BaseItemDto
{ {
@ -2762,7 +2798,7 @@ namespace Emby.Server.Implementations.LiveTv
} }
} }
private async Task<IEnumerable<LiveTvServiceInfo>> GetServiceInfos(CancellationToken cancellationToken) private async Task<LiveTvServiceInfo[]> GetServiceInfos(CancellationToken cancellationToken)
{ {
var tasks = Services.Select(i => GetServiceInfo(i, cancellationToken)); var tasks = Services.Select(i => GetServiceInfo(i, cancellationToken));
@ -2806,7 +2842,7 @@ namespace Emby.Server.Implementations.LiveTv
return dto; return dto;
}).ToList(); }).ToArray();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -2822,25 +2858,24 @@ namespace Emby.Server.Implementations.LiveTv
public async Task<LiveTvInfo> GetLiveTvInfo(CancellationToken cancellationToken) public async Task<LiveTvInfo> GetLiveTvInfo(CancellationToken cancellationToken)
{ {
var services = await GetServiceInfos(CancellationToken.None).ConfigureAwait(false); var services = await GetServiceInfos(CancellationToken.None).ConfigureAwait(false);
var servicesList = services.ToList();
var info = new LiveTvInfo var info = new LiveTvInfo
{ {
Services = servicesList.ToList(), Services = services,
IsEnabled = servicesList.Count > 0 IsEnabled = services.Length > 0
}; };
info.EnabledUsers = _userManager.Users info.EnabledUsers = _userManager.Users
.Where(IsLiveTvEnabled) .Where(IsLiveTvEnabled)
.Select(i => i.Id.ToString("N")) .Select(i => i.Id.ToString("N"))
.ToList(); .ToArray();
return info; return info;
} }
private bool IsLiveTvEnabled(User user) private bool IsLiveTvEnabled(User user)
{ {
return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Count > 0); return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
} }
public IEnumerable<User> GetEnabledUsers() public IEnumerable<User> GetEnabledUsers()
@ -2880,10 +2915,13 @@ namespace Emby.Server.Implementations.LiveTv
private void RemoveFields(DtoOptions options) private void RemoveFields(DtoOptions options)
{ {
options.Fields.Remove(ItemFields.CanDelete); var fields = options.Fields.ToList();
options.Fields.Remove(ItemFields.CanDownload);
options.Fields.Remove(ItemFields.DisplayPreferencesId); fields.Remove(ItemFields.CanDelete);
options.Fields.Remove(ItemFields.Etag); fields.Remove(ItemFields.CanDownload);
fields.Remove(ItemFields.DisplayPreferencesId);
fields.Remove(ItemFields.Etag);
options.Fields = fields.ToArray(fields.Count);
} }
public async Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken) public async Task<Folder> GetInternalLiveTvFolder(CancellationToken cancellationToken)
@ -2911,12 +2949,14 @@ namespace Emby.Server.Implementations.LiveTv
var config = GetConfiguration(); var config = GetConfiguration();
var index = config.TunerHosts.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); var list = config.TunerHosts.ToList();
var index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{ {
info.Id = Guid.NewGuid().ToString("N"); info.Id = Guid.NewGuid().ToString("N");
config.TunerHosts.Add(info); list.Add(info);
config.TunerHosts = list.ToArray(list.Count);
} }
else else
{ {
@ -2948,12 +2988,14 @@ namespace Emby.Server.Implementations.LiveTv
var config = GetConfiguration(); var config = GetConfiguration();
var index = config.ListingProviders.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); var list = config.ListingProviders.ToList();
var index = list.FindIndex(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase));
if (index == -1 || string.IsNullOrWhiteSpace(info.Id)) if (index == -1 || string.IsNullOrWhiteSpace(info.Id))
{ {
info.Id = Guid.NewGuid().ToString("N"); info.Id = Guid.NewGuid().ToString("N");
config.ListingProviders.Add(info); list.Add(info);
config.ListingProviders = list.ToArray(list.Count);
info.EnableNewProgramIds = true; info.EnableNewProgramIds = true;
} }
else else
@ -2972,7 +3014,7 @@ namespace Emby.Server.Implementations.LiveTv
{ {
var config = GetConfiguration(); var config = GetConfiguration();
config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList(); config.ListingProviders = config.ListingProviders.Where(i => !string.Equals(id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
_config.SaveConfiguration("livetv", config); _config.SaveConfiguration("livetv", config);
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
@ -3004,7 +3046,7 @@ namespace Emby.Server.Implementations.LiveTv
var providerChannels = await GetChannelsFromListingsProviderData(providerId, CancellationToken.None) var providerChannels = await GetChannelsFromListingsProviderData(providerId, CancellationToken.None)
.ConfigureAwait(false); .ConfigureAwait(false);
var mappings = listingsProviderInfo.ChannelMappings.ToList(); var mappings = listingsProviderInfo.ChannelMappings;
var tunerChannelMappings = var tunerChannelMappings =
tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList(); tunerChannels.Select(i => GetTunerChannelMapping(i, mappings, providerChannels)).ToList();
@ -3014,7 +3056,7 @@ namespace Emby.Server.Implementations.LiveTv
return tunerChannelMappings.First(i => string.Equals(i.Id, tunerChannelId, StringComparison.OrdinalIgnoreCase)); return tunerChannelMappings.First(i => string.Equals(i.Id, tunerChannelId, StringComparison.OrdinalIgnoreCase));
} }
public TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, List<NameValuePair> mappings, List<ChannelInfo> epgChannels) public TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, NameValuePair[] mappings, List<ChannelInfo> epgChannels)
{ {
var result = new TunerChannelMapping var result = new TunerChannelMapping
{ {
@ -3078,7 +3120,7 @@ namespace Emby.Server.Implementations.LiveTv
if (string.Equals(feature, "dvr-l", StringComparison.OrdinalIgnoreCase)) if (string.Equals(feature, "dvr-l", StringComparison.OrdinalIgnoreCase))
{ {
var config = GetConfiguration(); var config = GetConfiguration();
if (config.TunerHosts.Count > 0 && if (config.TunerHosts.Length > 0 &&
config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0) config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
{ {
return Task.FromResult(new MBRegistrationRecord return Task.FromResult(new MBRegistrationRecord

View File

@ -43,9 +43,11 @@ namespace Emby.Server.Implementations.LiveTv
if (baseItem.SourceType == SourceType.LiveTV) if (baseItem.SourceType == SourceType.LiveTV)
{ {
if (string.IsNullOrWhiteSpace(baseItem.Path)) var activeRecordingInfo = _liveTvManager.GetActiveRecordingInfo(item.Path);
if (string.IsNullOrWhiteSpace(baseItem.Path) || activeRecordingInfo != null)
{ {
return GetMediaSourcesInternal(item, cancellationToken); return GetMediaSourcesInternal(item, activeRecordingInfo, cancellationToken);
} }
} }
@ -56,7 +58,7 @@ namespace Emby.Server.Implementations.LiveTv
private const char StreamIdDelimeter = '_'; private const char StreamIdDelimeter = '_';
private const string StreamIdDelimeterString = "_"; private const string StreamIdDelimeterString = "_";
private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(IHasMediaSources item, CancellationToken cancellationToken) private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(IHasMediaSources item, ActiveRecordingInfo activeRecordingInfo, CancellationToken cancellationToken)
{ {
IEnumerable<MediaSourceInfo> sources; IEnumerable<MediaSourceInfo> sources;
@ -67,12 +69,20 @@ namespace Emby.Server.Implementations.LiveTv
if (item is ILiveTvRecording) if (item is ILiveTvRecording)
{ {
sources = await _liveTvManager.GetRecordingMediaSources(item, cancellationToken) sources = await _liveTvManager.GetRecordingMediaSources(item, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
else else
{ {
sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken) if (activeRecordingInfo != null)
.ConfigureAwait(false); {
sources = await EmbyTV.EmbyTV.Current.GetRecordingStreamMediaSources(activeRecordingInfo, cancellationToken)
.ConfigureAwait(false);
}
else
{
sources = await _liveTvManager.GetChannelMediaSources(item, cancellationToken)
.ConfigureAwait(false);
}
} }
} }
catch (NotImplementedException) catch (NotImplementedException)

View File

@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.LiveTv
public bool IsHidden public bool IsHidden
{ {
get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Count == 0; } get { return _liveTvManager.Services.Count == 1 && GetConfiguration().TunerHosts.Length == 0; }
} }
public bool IsEnabled public bool IsEnabled

View File

@ -25,12 +25,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
private readonly IServerApplicationHost _appHost; private readonly IServerApplicationHost _appHost;
private readonly IEnvironmentInfo _environment; private readonly IEnvironmentInfo _environment;
private readonly INetworkManager _networkManager;
public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost, IEnvironmentInfo environment) : base(config, logger, jsonSerializer, mediaEncoder, fileSystem) public M3UTunerHost(IServerConfigurationManager config, ILogger logger, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IHttpClient httpClient, IServerApplicationHost appHost, IEnvironmentInfo environment, INetworkManager networkManager) : base(config, logger, jsonSerializer, mediaEncoder, fileSystem)
{ {
_httpClient = httpClient; _httpClient = httpClient;
_appHost = appHost; _appHost = appHost;
_environment = environment; _environment = environment;
_networkManager = networkManager;
} }
public override string Type public override string Type
@ -38,7 +40,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
get { return "m3u"; } get { return "m3u"; }
} }
public string Name public virtual string Name
{ {
get { return "M3U Tuner"; } get { return "M3U Tuner"; }
} }
@ -99,74 +101,86 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false); var channels = await GetChannels(info, true, cancellationToken).ConfigureAwait(false);
var m3uchannels = channels.Cast<M3UChannel>(); var channel = channels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
var channel = m3uchannels.FirstOrDefault(c => string.Equals(c.Id, channelId, StringComparison.OrdinalIgnoreCase));
if (channel != null) if (channel != null)
{ {
var path = channel.Path; return new List<MediaSourceInfo> { CreateMediaSourceInfo(info, channel) };
MediaProtocol protocol = MediaProtocol.File;
if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Http;
}
else if (path.StartsWith("rtmp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Rtmp;
}
else if (path.StartsWith("rtsp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Rtsp;
}
else if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Udp;
}
else if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Rtmp;
}
var mediaSource = new MediaSourceInfo
{
Path = channel.Path,
Protocol = protocol,
MediaStreams = new List<MediaStream>
{
new MediaStream
{
Type = MediaStreamType.Video,
// Set the index to -1 because we don't know the exact index of the video stream within the container
Index = -1,
IsInterlaced = true
},
new MediaStream
{
Type = MediaStreamType.Audio,
// Set the index to -1 because we don't know the exact index of the audio stream within the container
Index = -1
}
},
RequiresOpening = true,
RequiresClosing = true,
RequiresLooping = info.EnableStreamLooping,
ReadAtNativeFramerate = false,
Id = channel.Path.GetMD5().ToString("N"),
IsInfiniteStream = true,
IsRemote = true,
IgnoreDts = true
};
mediaSource.InferTotalBitrate();
return new List<MediaSourceInfo> { mediaSource };
} }
return new List<MediaSourceInfo>(); return new List<MediaSourceInfo>();
} }
protected virtual MediaSourceInfo CreateMediaSourceInfo(TunerHostInfo info, ChannelInfo channel)
{
var path = channel.Path;
MediaProtocol protocol = MediaProtocol.File;
if (path.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Http;
}
else if (path.StartsWith("rtmp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Rtmp;
}
else if (path.StartsWith("rtsp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Rtsp;
}
else if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Udp;
}
else if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase))
{
protocol = MediaProtocol.Rtmp;
}
Uri uri;
var isRemote = true;
if (Uri.TryCreate(path, UriKind.Absolute, out uri))
{
isRemote = !_networkManager.IsInLocalNetwork(uri.Host);
}
var mediaSource = new MediaSourceInfo
{
Path = path,
Protocol = protocol,
MediaStreams = new List<MediaStream>
{
new MediaStream
{
Type = MediaStreamType.Video,
// Set the index to -1 because we don't know the exact index of the video stream within the container
Index = -1,
IsInterlaced = true
},
new MediaStream
{
Type = MediaStreamType.Audio,
// Set the index to -1 because we don't know the exact index of the audio stream within the container
Index = -1
}
},
RequiresOpening = true,
RequiresClosing = true,
RequiresLooping = info.EnableStreamLooping,
EnableMpDecimate = info.EnableMpDecimate,
ReadAtNativeFramerate = false,
Id = channel.Path.GetMD5().ToString("N"),
IsInfiniteStream = true,
IsRemote = isRemote,
IgnoreDts = true
};
mediaSource.InferTotalBitrate();
return mediaSource;
}
protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken) protected override Task<bool> IsAvailableInternal(TunerHostInfo tuner, string channelId, CancellationToken cancellationToken)
{ {
return Task.FromResult(true); return Task.FromResult(true);

View File

@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
_appHost = appHost; _appHost = appHost;
} }
public async Task<List<M3UChannel>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken) public async Task<List<ChannelInfo>> Parse(string url, string channelIdPrefix, string tunerHostId, CancellationToken cancellationToken)
{ {
// Read the file and display it line by line. // Read the file and display it line by line.
using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false))) using (var reader = new StreamReader(await GetListingsStream(url, cancellationToken).ConfigureAwait(false)))
@ -41,7 +41,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
} }
public List<M3UChannel> ParseString(string text, string channelIdPrefix, string tunerHostId) public List<ChannelInfo> ParseString(string text, string channelIdPrefix, string tunerHostId)
{ {
// Read the file and display it line by line. // Read the file and display it line by line.
using (var reader = new StringReader(text)) using (var reader = new StringReader(text))
@ -66,9 +66,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
} }
const string ExtInfPrefix = "#EXTINF:"; const string ExtInfPrefix = "#EXTINF:";
private List<M3UChannel> GetChannels(TextReader reader, string channelIdPrefix, string tunerHostId) private List<ChannelInfo> GetChannels(TextReader reader, string channelIdPrefix, string tunerHostId)
{ {
var channels = new List<M3UChannel>(); var channels = new List<ChannelInfo>();
string line; string line;
string extInf = ""; string extInf = "";
@ -111,9 +111,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return channels; return channels;
} }
private M3UChannel GetChannelnfo(string extInf, string tunerHostId, string mediaUrl) private ChannelInfo GetChannelnfo(string extInf, string tunerHostId, string mediaUrl)
{ {
var channel = new M3UChannel(); var channel = new ChannelInfo();
channel.TunerHostId = tunerHostId; channel.TunerHostId = tunerHostId;
extInf = extInf.Trim(); extInf = extInf.Trim();
@ -335,10 +335,4 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return dict; return dict;
} }
} }
public class M3UChannel : ChannelInfo
{
public string Path { get; set; }
}
} }

View File

@ -24,8 +24,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public async Task CopyUntilCancelled(Stream source, Action onStarted, CancellationToken cancellationToken) public async Task CopyUntilCancelled(Stream source, Action onStarted, CancellationToken cancellationToken)
{ {
byte[] buffer = new byte[BufferSize];
if (source == null) if (source == null)
{ {
throw new ArgumentNullException("source"); throw new ArgumentNullException("source");
@ -35,25 +33,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
byte[] buffer = new byte[BufferSize];
var bytesRead = source.Read(buffer, 0, buffer.Length); var bytesRead = source.Read(buffer, 0, buffer.Length);
if (bytesRead > 0) if (bytesRead > 0)
{ {
var allStreams = _outputStreams.ToList(); foreach (var stream in _outputStreams)
//if (allStreams.Count == 1)
//{
// allStreams[0].Value.Write(buffer, 0, bytesRead);
//}
//else
{ {
byte[] copy = new byte[bytesRead]; stream.Value.Queue(buffer, 0, bytesRead);
Buffer.BlockCopy(buffer, 0, copy, 0, bytesRead);
foreach (var stream in allStreams)
{
stream.Value.Queue(copy, 0, copy.Length);
}
} }
if (onStarted != null) if (onStarted != null)
@ -73,27 +61,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public Task CopyToAsync(Stream stream, CancellationToken cancellationToken) public Task CopyToAsync(Stream stream, CancellationToken cancellationToken)
{ {
var result = new QueueStream(stream, _logger) var queueStream = new QueueStream(stream, _logger);
_outputStreams.TryAdd(queueStream.Id, queueStream);
try
{ {
OnFinished = OnFinished queueStream.Start(cancellationToken);
}; }
finally
{
_outputStreams.TryRemove(queueStream.Id, out queueStream);
GC.Collect();
}
_outputStreams.TryAdd(result.Id, result); return Task.FromResult(true);
result.Start(cancellationToken);
return result.TaskCompletion.Task;
}
public void RemoveOutputStream(QueueStream stream)
{
QueueStream removed;
_outputStreams.TryRemove(stream.Id, out removed);
}
private void OnFinished(QueueStream queueStream)
{
RemoveOutputStream(queueStream);
} }
} }
} }

View File

@ -13,10 +13,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
public class QueueStream public class QueueStream
{ {
private readonly Stream _outputStream; private readonly Stream _outputStream;
private readonly ConcurrentQueue<Tuple<byte[], int, int>> _queue = new ConcurrentQueue<Tuple<byte[], int, int>>(); private readonly BlockingCollection<Tuple<byte[], int, int>> _queue = new BlockingCollection<Tuple<byte[], int, int>>();
public TaskCompletionSource<bool> TaskCompletion { get; private set; }
public Action<QueueStream> OnFinished { get; set; }
private readonly ILogger _logger; private readonly ILogger _logger;
public Guid Id = Guid.NewGuid(); public Guid Id = Guid.NewGuid();
@ -24,94 +22,24 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{ {
_outputStream = outputStream; _outputStream = outputStream;
_logger = logger; _logger = logger;
TaskCompletion = new TaskCompletionSource<bool>();
} }
public void Queue(byte[] bytes, int offset, int count) public void Queue(byte[] bytes, int offset, int count)
{ {
_queue.Enqueue(new Tuple<byte[], int, int>(bytes, offset, count)); _queue.Add(new Tuple<byte[], int, int>(bytes, offset, count));
} }
public void Start(CancellationToken cancellationToken) public void Start(CancellationToken cancellationToken)
{ {
Task.Run(() => StartInternal(cancellationToken)); while (true)
}
private Tuple<byte[], int, int> Dequeue()
{
Tuple<byte[], int, int> result;
if (_queue.TryDequeue(out result))
{ {
return result; foreach (var result in _queue.GetConsumingEnumerable())
}
return null;
}
private void OnClosed()
{
GC.Collect();
if (OnFinished != null)
{
OnFinished(this);
}
}
public void Write(byte[] bytes, int offset, int count)
{
//return _outputStream.WriteAsync(bytes, offset, count, cancellationToken);
try
{
_outputStream.Write(bytes, offset, count);
}
catch (OperationCanceledException)
{
_logger.Debug("QueueStream cancelled");
TaskCompletion.TrySetCanceled();
OnClosed();
}
catch (Exception ex)
{
_logger.ErrorException("Error in QueueStream", ex);
TaskCompletion.TrySetException(ex);
OnClosed();
}
}
private async Task StartInternal(CancellationToken cancellationToken)
{
try
{
while (true)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var result = Dequeue(); _outputStream.Write(result.Item1, result.Item2, result.Item3);
if (result != null)
{
_outputStream.Write(result.Item1, result.Item2, result.Item3);
}
else
{
await Task.Delay(50, cancellationToken).ConfigureAwait(false);
}
} }
} }
catch (OperationCanceledException)
{
_logger.Debug("QueueStream cancelled");
TaskCompletion.TrySetCanceled();
}
catch (Exception ex)
{
_logger.ErrorException("Error in QueueStream", ex);
TaskCompletion.TrySetException(ex);
}
finally
{
OnClosed();
}
} }
} }
} }

View File

@ -1,179 +0,0 @@
{
"AppDeviceValues": "App: {0}, Device: {1}",
"UserDownloadingItemWithValues": "{0} is downloading {1}",
"FolderTypeMixed": "Mixed content",
"FolderTypeMovies": "Movies",
"FolderTypeMusic": "Music",
"FolderTypeAdultVideos": "Adult videos",
"FolderTypePhotos": "Photos",
"FolderTypeMusicVideos": "Music videos",
"FolderTypeHomeVideos": "Home videos",
"FolderTypeGames": "Games",
"FolderTypeBooks": "Books",
"FolderTypeTvShows": "TV",
"FolderTypeInherit": "Inherit",
"HeaderCastCrew": "Cast & Crew",
"HeaderPeople": "People",
"ValueSpecialEpisodeName": "Special - {0}",
"LabelChapterName": "Chapter {0}",
"NameSeasonNumber": "Season {0}",
"LabelExit": "Exit",
"LabelVisitCommunity": "Visit Community",
"LabelGithub": "Github",
"LabelApiDocumentation": "Api Documentation",
"LabelDeveloperResources": "Developer Resources",
"LabelBrowseLibrary": "Browse Library",
"LabelConfigureServer": "Configure Emby",
"LabelRestartServer": "Restart Server",
"CategorySync": "Sync",
"CategoryUser": "User",
"CategorySystem": "System",
"CategoryApplication": "Application",
"CategoryPlugin": "Plugin",
"NotificationOptionPluginError": "Plugin failure",
"NotificationOptionApplicationUpdateAvailable": "Application update available",
"NotificationOptionApplicationUpdateInstalled": "Application update installed",
"NotificationOptionPluginUpdateInstalled": "Plugin update installed",
"NotificationOptionPluginInstalled": "Plugin installed",
"NotificationOptionPluginUninstalled": "Plugin uninstalled",
"NotificationOptionVideoPlayback": "Video playback started",
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionGamePlayback": "Game playback started",
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
"NotificationOptionTaskFailed": "Scheduled task failure",
"NotificationOptionInstallationFailed": "Installation failure",
"NotificationOptionNewLibraryContent": "New content added",
"NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
"NotificationOptionUserLockedOut": "User locked out",
"NotificationOptionServerRestartRequired": "Server restart required",
"ViewTypePlaylists": "Playlists",
"ViewTypeMovies": "Movies",
"ViewTypeTvShows": "TV",
"ViewTypeGames": "Games",
"ViewTypeMusic": "Music",
"ViewTypeMusicGenres": "Genres",
"ViewTypeMusicArtists": "Artists",
"ViewTypeBoxSets": "Collections",
"ViewTypeChannels": "Channels",
"ViewTypeLiveTV": "Live TV",
"ViewTypeLiveTvNowPlaying": "Now Airing",
"ViewTypeLatestGames": "Latest Games",
"ViewTypeRecentlyPlayedGames": "Recently Played",
"ViewTypeGameFavorites": "Favorites",
"ViewTypeGameSystems": "Game Systems",
"ViewTypeGameGenres": "Genres",
"ViewTypeTvResume": "Resume",
"ViewTypeTvNextUp": "Next Up",
"ViewTypeTvLatest": "Latest",
"ViewTypeTvShowSeries": "Series",
"ViewTypeTvGenres": "Genres",
"ViewTypeTvFavoriteSeries": "Favorite Series",
"ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
"ViewTypeMovieResume": "Resume",
"ViewTypeMovieLatest": "Latest",
"ViewTypeMovieMovies": "Movies",
"ViewTypeMovieCollections": "Collections",
"ViewTypeMovieFavorites": "Favorites",
"ViewTypeMovieGenres": "Genres",
"ViewTypeMusicLatest": "Latest",
"ViewTypeMusicPlaylists": "Playlists",
"ViewTypeMusicAlbums": "Albums",
"ViewTypeMusicAlbumArtists": "Album Artists",
"HeaderOtherDisplaySettings": "Display Settings",
"ViewTypeMusicSongs": "Songs",
"ViewTypeMusicFavorites": "Favorites",
"ViewTypeMusicFavoriteAlbums": "Favorite Albums",
"ViewTypeMusicFavoriteArtists": "Favorite Artists",
"ViewTypeMusicFavoriteSongs": "Favorite Songs",
"ViewTypeFolders": "Folders",
"ViewTypeLiveTvRecordingGroups": "Recordings",
"ViewTypeLiveTvChannels": "Channels",
"ScheduledTaskFailedWithName": "{0} failed",
"LabelRunningTimeValue": "Running time: {0}",
"ScheduledTaskStartedWithName": "{0} started",
"VersionNumber": "Version {0}",
"PluginInstalledWithName": "{0} was installed",
"PluginUpdatedWithName": "{0} was updated",
"PluginUninstalledWithName": "{0} was uninstalled",
"ItemAddedWithName": "{0} was added to the library",
"ItemRemovedWithName": "{0} was removed from the library",
"LabelIpAddressValue": "Ip address: {0}",
"DeviceOnlineWithName": "{0} is connected",
"UserOnlineFromDevice": "{0} is online from {1}",
"ProviderValue": "Provider: {0}",
"SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
"UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
"UserCreatedWithName": "User {0} has been created",
"UserPasswordChangedWithName": "Password has been changed for user {0}",
"UserDeletedWithName": "User {0} has been deleted",
"MessageServerConfigurationUpdated": "Server configuration has been updated",
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
"MessageApplicationUpdated": "Emby Server has been updated",
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
"AuthenticationSucceededWithUserName": "{0} successfully authenticated",
"DeviceOfflineWithName": "{0} has disconnected",
"UserLockedOutWithName": "User {0} has been locked out",
"UserOfflineFromDevice": "{0} has disconnected from {1}",
"UserStartedPlayingItemWithValues": "{0} has started playing {1}",
"UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
"SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
"HeaderUnidentified": "Unidentified",
"HeaderImagePrimary": "Primary",
"HeaderImageBackdrop": "Backdrop",
"HeaderImageLogo": "Logo",
"HeaderUserPrimaryImage": "User Image",
"HeaderOverview": "Overview",
"HeaderShortOverview": "Short Overview",
"HeaderType": "Type",
"HeaderSeverity": "Severity",
"HeaderUser": "User",
"HeaderName": "Name",
"HeaderDate": "Date",
"HeaderPremiereDate": "Premiere Date",
"HeaderDateAdded": "Date Added",
"HeaderReleaseDate": "Release date",
"HeaderRuntime": "Runtime",
"HeaderPlayCount": "Play Count",
"HeaderSeason": "Season",
"HeaderSeasonNumber": "Season number",
"HeaderSeries": "Series:",
"HeaderNetwork": "Network",
"HeaderYear": "Year:",
"HeaderYears": "Years:",
"HeaderParentalRating": "Parental Rating",
"HeaderCommunityRating": "Community rating",
"HeaderTrailers": "Trailers",
"HeaderSpecials": "Specials",
"HeaderGameSystems": "Game Systems",
"HeaderPlayers": "Players:",
"HeaderAlbumArtists": "Album Artists",
"HeaderAlbums": "Albums",
"HeaderDisc": "Disc",
"HeaderTrack": "Track",
"HeaderAudio": "Audio",
"HeaderVideo": "Video",
"HeaderEmbeddedImage": "Embedded image",
"HeaderResolution": "Resolution",
"HeaderSubtitles": "Subtitles",
"HeaderGenres": "Genres",
"HeaderCountries": "Countries",
"HeaderStatus": "Status",
"HeaderTracks": "Tracks",
"HeaderMusicArtist": "Music artist",
"HeaderLocked": "Locked",
"HeaderStudios": "Studios",
"HeaderActor": "Actors",
"HeaderComposer": "Composers",
"HeaderDirector": "Directors",
"HeaderGuestStar": "Guest star",
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
"HeaderCommunityRatings": "Community ratings",
"StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly.",
"DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete."
}

View File

@ -1,5 +1,4 @@
{ {
"DbUpgradeMessage": "Please wait while your Emby Server database is upgraded. {0}% complete.",
"AppDeviceValues": "App: {0}, Device: {1}", "AppDeviceValues": "App: {0}, Device: {1}",
"UserDownloadingItemWithValues": "{0} is downloading {1}", "UserDownloadingItemWithValues": "{0} is downloading {1}",
"FolderTypeMixed": "Mixed content", "FolderTypeMixed": "Mixed content",
@ -13,15 +12,12 @@
"FolderTypeBooks": "Books", "FolderTypeBooks": "Books",
"FolderTypeTvShows": "TV", "FolderTypeTvShows": "TV",
"FolderTypeInherit": "Inherit", "FolderTypeInherit": "Inherit",
"HeaderCastCrew": "Cast & Crew",
"HeaderPeople": "People",
"ValueSpecialEpisodeName": "Special - {0}", "ValueSpecialEpisodeName": "Special - {0}",
"LabelChapterName": "Chapter {0}", "LabelChapterName": "Chapter {0}",
"NameSeasonUnknown": "Season Unknown", "NameSeasonUnknown": "Season Unknown",
"NameSeasonNumber": "Season {0}", "NameSeasonNumber": "Season {0}",
"LabelExit": "Exit", "LabelExit": "Exit",
"LabelVisitCommunity": "Visit Community", "LabelVisitCommunity": "Visit Community",
"LabelGithub": "Github",
"LabelApiDocumentation": "Api Documentation", "LabelApiDocumentation": "Api Documentation",
"LabelDeveloperResources": "Developer Resources", "LabelDeveloperResources": "Developer Resources",
"LabelBrowseLibrary": "Browse Library", "LabelBrowseLibrary": "Browse Library",
@ -164,15 +160,5 @@
"HeaderStatus": "Status", "HeaderStatus": "Status",
"HeaderTracks": "Tracks", "HeaderTracks": "Tracks",
"HeaderMusicArtist": "Music artist", "HeaderMusicArtist": "Music artist",
"HeaderLocked": "Locked",
"HeaderStudios": "Studios",
"HeaderActor": "Actors",
"HeaderComposer": "Composers",
"HeaderDirector": "Directors",
"HeaderGuestStar": "Guest star",
"HeaderProducer": "Producers",
"HeaderWriter": "Writers",
"HeaderParentalRatings": "Parental Ratings",
"HeaderCommunityRatings": "Community ratings",
"StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly." "StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly."
} }

View File

@ -132,7 +132,7 @@ namespace Emby.Server.Implementations.Localization
/// Gets the cultures. /// Gets the cultures.
/// </summary> /// </summary>
/// <returns>IEnumerable{CultureDto}.</returns> /// <returns>IEnumerable{CultureDto}.</returns>
public List<CultureDto> GetCultures() public CultureDto[] GetCultures()
{ {
var type = GetType(); var type = GetType();
var path = type.Namespace + ".iso6392.txt"; var path = type.Namespace + ".iso6392.txt";
@ -169,21 +169,21 @@ namespace Emby.Server.Implementations.Localization
return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) && return list.Where(i => !string.IsNullOrWhiteSpace(i.Name) &&
!string.IsNullOrWhiteSpace(i.DisplayName) && !string.IsNullOrWhiteSpace(i.DisplayName) &&
!string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) && !string.IsNullOrWhiteSpace(i.ThreeLetterISOLanguageName) &&
!string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToList(); !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToArray();
} }
/// <summary> /// <summary>
/// Gets the countries. /// Gets the countries.
/// </summary> /// </summary>
/// <returns>IEnumerable{CountryInfo}.</returns> /// <returns>IEnumerable{CountryInfo}.</returns>
public List<CountryInfo> GetCountries() public CountryInfo[] GetCountries()
{ {
var type = GetType(); var type = GetType();
var path = type.Namespace + ".countries.json"; var path = type.Namespace + ".countries.json";
using (var stream = _assemblyInfo.GetManifestResourceStream(type, path)) using (var stream = _assemblyInfo.GetManifestResourceStream(type, path))
{ {
return _jsonSerializer.DeserializeFromStream<List<CountryInfo>>(stream); return _jsonSerializer.DeserializeFromStream<CountryInfo[]>(stream);
} }
} }
@ -191,9 +191,9 @@ namespace Emby.Server.Implementations.Localization
/// Gets the parental ratings. /// Gets the parental ratings.
/// </summary> /// </summary>
/// <returns>IEnumerable{ParentalRating}.</returns> /// <returns>IEnumerable{ParentalRating}.</returns>
public IEnumerable<ParentalRating> GetParentalRatings() public ParentalRating[] GetParentalRatings()
{ {
return GetParentalRatingsDictionary().Values.ToList(); return GetParentalRatingsDictionary().Values.ToArray();
} }
/// <summary> /// <summary>
@ -335,7 +335,7 @@ namespace Emby.Server.Implementations.Localization
const string prefix = "Core"; const string prefix = "Core";
var key = prefix + culture; var key = prefix + culture;
return _dictionaries.GetOrAdd(key, k => GetDictionary(prefix, culture, "core.json")); return _dictionaries.GetOrAdd(key, k => GetDictionary(prefix, culture, "en-US.json"));
} }
private Dictionary<string, string> GetDictionary(string prefix, string culture, string baseFilename) private Dictionary<string, string> GetDictionary(string prefix, string culture, string baseFilename)
@ -382,9 +382,9 @@ namespace Emby.Server.Implementations.Localization
return culture + ".json"; return culture + ".json";
} }
public IEnumerable<LocalizatonOption> GetLocalizationOptions() public LocalizatonOption[] GetLocalizationOptions()
{ {
return new List<LocalizatonOption> return new LocalizatonOption[]
{ {
new LocalizatonOption{ Name="Arabic", Value="ar"}, new LocalizatonOption{ Name="Arabic", Value="ar"},
new LocalizatonOption{ Name="Bulgarian (Bulgaria)", Value="bg-BG"}, new LocalizatonOption{ Name="Bulgarian (Bulgaria)", Value="bg-BG"},
@ -421,7 +421,7 @@ namespace Emby.Server.Implementations.Localization
new LocalizatonOption{ Name="Ukrainian", Value="uk"}, new LocalizatonOption{ Name="Ukrainian", Value="uk"},
new LocalizatonOption{ Name="Vietnamese", Value="vi"} new LocalizatonOption{ Name="Vietnamese", Value="vi"}
}.OrderBy(i => i.Name); };
} }
} }

View File

@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.Logging
public class FileLogger : IDisposable public class FileLogger : IDisposable
{ {
private readonly Stream _fileStream; private readonly FileStream _fileStream;
private bool _disposed; private bool _disposed;
private readonly CancellationTokenSource _cancellationTokenSource; private readonly CancellationTokenSource _cancellationTokenSource;
@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.Logging
{ {
Directory.CreateDirectory(Path.GetDirectoryName(path)); Directory.CreateDirectory(Path.GetDirectoryName(path));
_fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); _fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, 32768);
_cancellationTokenSource = new CancellationTokenSource(); _cancellationTokenSource = new CancellationTokenSource();
Task.Factory.StartNew(LogInternal, _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default); Task.Factory.StartNew(LogInternal, _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
@ -134,19 +134,12 @@ namespace Emby.Server.Implementations.Logging
{ {
try try
{ {
var any = false;
foreach (var message in _queue.GetConsumingEnumerable()) foreach (var message in _queue.GetConsumingEnumerable())
{ {
var bytes = Encoding.UTF8.GetBytes(message + Environment.NewLine); var bytes = Encoding.UTF8.GetBytes(message + Environment.NewLine);
_fileStream.Write(bytes, 0, bytes.Length); _fileStream.Write(bytes, 0, bytes.Length);
any = true; _fileStream.Flush(true);
}
if (any)
{
_fileStream.Flush();
} }
} }
catch catch

View File

@ -75,6 +75,11 @@ namespace Emby.Server.Implementations.MediaEncoder
return false; return false;
} }
if (!video.IsCompleteMedia)
{
return false;
}
// Can't extract images if there are no video streams // Can't extract images if there are no video streams
return video.DefaultVideoStreamIndex.HasValue; return video.DefaultVideoStreamIndex.HasValue;
} }
@ -129,7 +134,7 @@ namespace Emby.Server.Implementations.MediaEncoder
var protocol = MediaProtocol.File; var protocol = MediaProtocol.File;
var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, new List<string>()); var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, new string[] { });
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path));
@ -174,7 +179,7 @@ namespace Emby.Server.Implementations.MediaEncoder
if (saveChapters && changesMade) if (saveChapters && changesMade)
{ {
await _chapterManager.SaveChapters(video.Id.ToString(), chapters).ConfigureAwait(false); _chapterManager.SaveChapters(video.Id.ToString(), chapters);
} }
DeleteDeadImages(currentImages, chapters); DeleteDeadImages(currentImages, chapters);

View File

@ -28,21 +28,21 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.ApplicationUpdateInstalled.ToString(), Type = NotificationType.ApplicationUpdateInstalled.ToString(),
DefaultDescription = "{ReleaseNotes}", DefaultDescription = "{ReleaseNotes}",
DefaultTitle = "A new version of Emby Server has been installed.", DefaultTitle = "A new version of Emby Server has been installed.",
Variables = new List<string>{"Version"} Variables = new string[]{"Version"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.InstallationFailed.ToString(), Type = NotificationType.InstallationFailed.ToString(),
DefaultTitle = "{Name} installation failed.", DefaultTitle = "{Name} installation failed.",
Variables = new List<string>{"Name", "Version"} Variables = new string[]{"Name", "Version"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.PluginInstalled.ToString(), Type = NotificationType.PluginInstalled.ToString(),
DefaultTitle = "{Name} was installed.", DefaultTitle = "{Name} was installed.",
Variables = new List<string>{"Name", "Version"} Variables = new string[]{"Name", "Version"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
@ -50,14 +50,14 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.PluginError.ToString(), Type = NotificationType.PluginError.ToString(),
DefaultTitle = "{Name} has encountered an error.", DefaultTitle = "{Name} has encountered an error.",
DefaultDescription = "{ErrorMessage}", DefaultDescription = "{ErrorMessage}",
Variables = new List<string>{"Name", "ErrorMessage"} Variables = new string[]{"Name", "ErrorMessage"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.PluginUninstalled.ToString(), Type = NotificationType.PluginUninstalled.ToString(),
DefaultTitle = "{Name} was uninstalled.", DefaultTitle = "{Name} was uninstalled.",
Variables = new List<string>{"Name", "Version"} Variables = new string[]{"Name", "Version"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
@ -65,7 +65,7 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.PluginUpdateInstalled.ToString(), Type = NotificationType.PluginUpdateInstalled.ToString(),
DefaultTitle = "{Name} was updated.", DefaultTitle = "{Name} was updated.",
DefaultDescription = "{ReleaseNotes}", DefaultDescription = "{ReleaseNotes}",
Variables = new List<string>{"Name", "ReleaseNotes", "Version"} Variables = new string[]{"Name", "ReleaseNotes", "Version"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
@ -79,70 +79,70 @@ namespace Emby.Server.Implementations.Notifications
Type = NotificationType.TaskFailed.ToString(), Type = NotificationType.TaskFailed.ToString(),
DefaultTitle = "{Name} failed.", DefaultTitle = "{Name} failed.",
DefaultDescription = "{ErrorMessage}", DefaultDescription = "{ErrorMessage}",
Variables = new List<string>{"Name", "ErrorMessage"} Variables = new string[]{"Name", "ErrorMessage"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.NewLibraryContent.ToString(), Type = NotificationType.NewLibraryContent.ToString(),
DefaultTitle = "{Name} has been added to your media library.", DefaultTitle = "{Name} has been added to your media library.",
Variables = new List<string>{"Name"} Variables = new string[]{"Name"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.AudioPlayback.ToString(), Type = NotificationType.AudioPlayback.ToString(),
DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.", DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.",
Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"} Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.GamePlayback.ToString(), Type = NotificationType.GamePlayback.ToString(),
DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.", DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.",
Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"} Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.VideoPlayback.ToString(), Type = NotificationType.VideoPlayback.ToString(),
DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.", DefaultTitle = "{UserName} is playing {ItemName} on {DeviceName}.",
Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"} Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.AudioPlaybackStopped.ToString(), Type = NotificationType.AudioPlaybackStopped.ToString(),
DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.", DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.",
Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"} Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.GamePlaybackStopped.ToString(), Type = NotificationType.GamePlaybackStopped.ToString(),
DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.", DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.",
Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"} Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.VideoPlaybackStopped.ToString(), Type = NotificationType.VideoPlaybackStopped.ToString(),
DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.", DefaultTitle = "{UserName} has finished playing {ItemName} on {DeviceName}.",
Variables = new List<string>{"UserName", "ItemName", "DeviceName", "AppName"} Variables = new string[]{"UserName", "ItemName", "DeviceName", "AppName"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.CameraImageUploaded.ToString(), Type = NotificationType.CameraImageUploaded.ToString(),
DefaultTitle = "A new camera image has been uploaded from {DeviceName}.", DefaultTitle = "A new camera image has been uploaded from {DeviceName}.",
Variables = new List<string>{"DeviceName"} Variables = new string[]{"DeviceName"}
}, },
new NotificationTypeInfo new NotificationTypeInfo
{ {
Type = NotificationType.UserLockedOut.ToString(), Type = NotificationType.UserLockedOut.ToString(),
DefaultTitle = "{UserName} has been locked out.", DefaultTitle = "{UserName} has been locked out.",
Variables = new List<string>{"UserName"} Variables = new string[]{"UserName"}
} }
}; };

View File

@ -251,7 +251,7 @@ namespace Emby.Server.Implementations.Notifications
_typeFactories = notificationTypeFactories.ToArray(); _typeFactories = notificationTypeFactories.ToArray();
} }
public IEnumerable<NotificationTypeInfo> GetNotificationTypes() public List<NotificationTypeInfo> GetNotificationTypes()
{ {
var list = _typeFactories.Select(i => var list = _typeFactories.Select(i =>
{ {

View File

@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.Notifications
{ {
var artists = hasArtist.AllArtists; var artists = hasArtist.AllArtists;
if (artists.Count > 0) if (artists.Length > 0)
{ {
name = hasArtist.AllArtists[0] + " - " + name; name = hasArtist.AllArtists[0] + " - " + name;
} }
@ -440,7 +440,7 @@ namespace Emby.Server.Implementations.Notifications
name = item.SeriesName + " - " + name; name = item.SeriesName + " - " + name;
} }
if (item.Artists != null && item.Artists.Count > 0) if (item.Artists != null && item.Artists.Length > 0)
{ {
name = item.Artists[0] + " - " + name; name = item.Artists[0] + " - " + name;
} }

View File

@ -128,12 +128,12 @@ namespace Emby.Server.Implementations.Playlists
playlist.SetMediaType(options.MediaType); playlist.SetMediaType(options.MediaType);
await parentFolder.AddChild(playlist, CancellationToken.None).ConfigureAwait(false); parentFolder.AddChild(playlist, CancellationToken.None);
await playlist.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { ForceSave = true }, CancellationToken.None) await playlist.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) { ForceSave = true }, CancellationToken.None)
.ConfigureAwait(false); .ConfigureAwait(false);
if (options.ItemIdList.Count > 0) if (options.ItemIdList.Length > 0)
{ {
await AddToPlaylistInternal(playlist.Id.ToString("N"), options.ItemIdList, user, new DtoOptions(false) await AddToPlaylistInternal(playlist.Id.ToString("N"), options.ItemIdList, user, new DtoOptions(false)
{ {

View File

@ -4,7 +4,6 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Data;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Security;
@ -51,14 +50,14 @@ namespace Emby.Server.Implementations.Security
} }
} }
public Task Create(AuthenticationInfo info, CancellationToken cancellationToken) public void Create(AuthenticationInfo info, CancellationToken cancellationToken)
{ {
info.Id = Guid.NewGuid().ToString("N"); info.Id = Guid.NewGuid().ToString("N");
return Update(info, cancellationToken); Update(info, cancellationToken);
} }
public async Task Update(AuthenticationInfo info, CancellationToken cancellationToken) public void Update(AuthenticationInfo info, CancellationToken cancellationToken)
{ {
if (info == null) if (info == null)
{ {

View File

@ -29,13 +29,6 @@ namespace Emby.Server.Implementations.Services
} }
} }
private Type[] GetGenericArguments(Type type)
{
return type.GetTypeInfo().IsGenericTypeDefinition
? type.GetTypeInfo().GenericTypeParameters
: type.GetTypeInfo().GenericTypeArguments;
}
public void RegisterService(HttpListenerHost appHost, Type serviceType) public void RegisterService(HttpListenerHost appHost, Type serviceType)
{ {
var processedReqs = new HashSet<Type>(); var processedReqs = new HashSet<Type>();
@ -50,38 +43,19 @@ namespace Emby.Server.Implementations.Services
ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions); ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>)); //var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
var responseType = returnMarker != null ? //var responseType = returnMarker != null ?
GetGenericArguments(returnMarker)[0] // GetGenericArguments(returnMarker)[0]
: mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ? // : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
mi.ReturnType // mi.ReturnType
: Type.GetType(requestType.FullName + "Response"); // : Type.GetType(requestType.FullName + "Response");
RegisterRestPaths(appHost, requestType); RegisterRestPaths(appHost, requestType);
appHost.AddServiceInfo(serviceType, requestType, responseType); appHost.AddServiceInfo(serviceType, requestType);
} }
} }
private static Type GetTypeWithGenericTypeDefinitionOf(Type type, Type genericTypeDefinition)
{
foreach (var t in type.GetTypeInfo().ImplementedInterfaces)
{
if (t.GetTypeInfo().IsGenericType && t.GetGenericTypeDefinition() == genericTypeDefinition)
{
return t;
}
}
var genericType = FirstGenericType(type);
if (genericType != null && genericType.GetGenericTypeDefinition() == genericTypeDefinition)
{
return genericType;
}
return null;
}
public static Type FirstGenericType(Type type) public static Type FirstGenericType(Type type)
{ {
while (type != null) while (type != null)

View File

@ -215,13 +215,13 @@ namespace Emby.Server.Implementations.Services
if (name == null) continue; //thank you ASP.NET if (name == null) continue; //thank you ASP.NET
var values = request.QueryString.GetValues(name); var values = request.QueryString.GetValues(name);
if (values.Length == 1) if (values.Count == 1)
{ {
map[name] = values[0]; map[name] = values[0];
} }
else else
{ {
for (var i = 0; i < values.Length; i++) for (var i = 0; i < values.Count; i++)
{ {
map[name + (i == 0 ? "" : "#" + i)] = values[i]; map[name + (i == 0 ? "" : "#" + i)] = values[i];
} }
@ -235,13 +235,13 @@ namespace Emby.Server.Implementations.Services
if (name == null) continue; //thank you ASP.NET if (name == null) continue; //thank you ASP.NET
var values = request.FormData.GetValues(name); var values = request.FormData.GetValues(name);
if (values.Length == 1) if (values.Count == 1)
{ {
map[name] = values[0]; map[name] = values[0];
} }
else else
{ {
for (var i = 0; i < values.Length; i++) for (var i = 0; i < values.Count; i++)
{ {
map[name + (i == 0 ? "" : "#" + i)] = values[i]; map[name + (i == 0 ? "" : "#" + i)] = values[i];
} }

View File

@ -6,11 +6,8 @@ using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session; using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Devices; using MediaBrowser.Model.Devices;
@ -253,7 +250,7 @@ namespace Emby.Server.Implementations.Session
{ {
try try
{ {
await _userManager.UpdateUser(user).ConfigureAwait(false); _userManager.UpdateUser(user);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -468,7 +465,7 @@ namespace Emby.Server.Implementations.Session
if (!userId.HasValue) if (!userId.HasValue)
{ {
sessionInfo.AdditionalUsers.Clear(); sessionInfo.AdditionalUsers = new SessionUserInfo[] { };
} }
if (sessionInfo.SessionController == null) if (sessionInfo.SessionController == null)
@ -622,7 +619,7 @@ namespace Emby.Server.Implementations.Session
{ {
foreach (var user in users) foreach (var user in users)
{ {
await OnPlaybackStart(user.Id, libraryItem).ConfigureAwait(false); OnPlaybackStart(user.Id, libraryItem);
} }
} }
@ -650,8 +647,7 @@ namespace Emby.Server.Implementations.Session
/// </summary> /// </summary>
/// <param name="userId">The user identifier.</param> /// <param name="userId">The user identifier.</param>
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <returns>Task.</returns> private void OnPlaybackStart(Guid userId, IHasUserData item)
private async Task OnPlaybackStart(Guid userId, IHasUserData item)
{ {
var data = _userDataManager.GetUserData(userId, item); var data = _userDataManager.GetUserData(userId, item);
@ -670,7 +666,7 @@ namespace Emby.Server.Implementations.Session
data.Played = false; data.Played = false;
} }
await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None).ConfigureAwait(false); _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackStart, CancellationToken.None);
} }
public Task OnPlaybackProgress(PlaybackProgressInfo info) public Task OnPlaybackProgress(PlaybackProgressInfo info)
@ -702,7 +698,7 @@ namespace Emby.Server.Implementations.Session
{ {
foreach (var user in users) foreach (var user in users)
{ {
await OnPlaybackProgress(user, libraryItem, info).ConfigureAwait(false); OnPlaybackProgress(user, libraryItem, info);
} }
} }
@ -730,7 +726,7 @@ namespace Emby.Server.Implementations.Session
StartIdleCheckTimer(); StartIdleCheckTimer();
} }
private async Task OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info) private void OnPlaybackProgress(User user, BaseItem item, PlaybackProgressInfo info)
{ {
var data = _userDataManager.GetUserData(user.Id, item); var data = _userDataManager.GetUserData(user.Id, item);
@ -742,7 +738,7 @@ namespace Emby.Server.Implementations.Session
UpdatePlaybackSettings(user, info, data); UpdatePlaybackSettings(user, info, data);
await _userDataManager.SaveUserData(user.Id, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); _userDataManager.SaveUserData(user.Id, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None);
} }
} }
@ -842,7 +838,7 @@ namespace Emby.Server.Implementations.Session
{ {
foreach (var user in users) foreach (var user in users)
{ {
playedToCompletion = await OnPlaybackStopped(user.Id, libraryItem, info.PositionTicks, info.Failed).ConfigureAwait(false); playedToCompletion = OnPlaybackStopped(user.Id, libraryItem, info.PositionTicks, info.Failed);
} }
} }
@ -875,7 +871,7 @@ namespace Emby.Server.Implementations.Session
await SendPlaybackStoppedNotification(session, CancellationToken.None).ConfigureAwait(false); await SendPlaybackStoppedNotification(session, CancellationToken.None).ConfigureAwait(false);
} }
private async Task<bool> OnPlaybackStopped(Guid userId, BaseItem item, long? positionTicks, bool playbackFailed) private bool OnPlaybackStopped(Guid userId, BaseItem item, long? positionTicks, bool playbackFailed)
{ {
bool playedToCompletion = false; bool playedToCompletion = false;
@ -896,7 +892,7 @@ namespace Emby.Server.Implementations.Session
playedToCompletion = true; playedToCompletion = true;
} }
await _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None).ConfigureAwait(false); _userDataManager.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackFinished, CancellationToken.None);
} }
return playedToCompletion; return playedToCompletion;
@ -1074,7 +1070,7 @@ namespace Emby.Server.Implementations.Session
DtoOptions = new DtoOptions(false) DtoOptions = new DtoOptions(false)
{ {
EnableImages = false, EnableImages = false,
Fields = new List<ItemFields> Fields = new ItemFields[]
{ {
ItemFields.SortName ItemFields.SortName
} }
@ -1097,7 +1093,7 @@ namespace Emby.Server.Implementations.Session
DtoOptions = new DtoOptions(false) DtoOptions = new DtoOptions(false)
{ {
EnableImages = false, EnableImages = false,
Fields = new List<ItemFields> Fields = new ItemFields[]
{ {
ItemFields.SortName ItemFields.SortName
} }
@ -1340,11 +1336,15 @@ namespace Emby.Server.Implementations.Session
{ {
var user = _userManager.GetUserById(userId); var user = _userManager.GetUserById(userId);
session.AdditionalUsers.Add(new SessionUserInfo var list = session.AdditionalUsers.ToList();
list.Add(new SessionUserInfo
{ {
UserId = userId, UserId = userId,
UserName = user.Name UserName = user.Name
}); });
session.AdditionalUsers = list.ToArray(list.Count);
} }
} }
@ -1368,7 +1368,10 @@ namespace Emby.Server.Implementations.Session
if (user != null) if (user != null)
{ {
session.AdditionalUsers.Remove(user); var list = session.AdditionalUsers.ToList();
list.Remove(user);
session.AdditionalUsers = list.ToArray(list.Count);
} }
} }
@ -1425,7 +1428,7 @@ namespace Emby.Server.Implementations.Session
user = result; user = result;
} }
var token = await GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.AppVersion, request.DeviceName).ConfigureAwait(false); var token = GetAuthorizationToken(user.Id.ToString("N"), request.DeviceId, request.App, request.AppVersion, request.DeviceName);
EventHelper.FireEventIfNotNull(AuthenticationSucceeded, this, new GenericEventArgs<AuthenticationRequest>(request), _logger); EventHelper.FireEventIfNotNull(AuthenticationSucceeded, this, new GenericEventArgs<AuthenticationRequest>(request), _logger);
@ -1447,7 +1450,7 @@ namespace Emby.Server.Implementations.Session
} }
private async Task<string> GetAuthorizationToken(string userId, string deviceId, string app, string appVersion, string deviceName) private string GetAuthorizationToken(string userId, string deviceId, string app, string appVersion, string deviceName)
{ {
var existing = _authRepo.Get(new AuthenticationInfoQuery var existing = _authRepo.Get(new AuthenticationInfoQuery
{ {
@ -1477,12 +1480,12 @@ namespace Emby.Server.Implementations.Session
}; };
_logger.Info("Creating new access token for user {0}", userId); _logger.Info("Creating new access token for user {0}", userId);
await _authRepo.Create(newToken, CancellationToken.None).ConfigureAwait(false); _authRepo.Create(newToken, CancellationToken.None);
return newToken.AccessToken; return newToken.AccessToken;
} }
public async Task Logout(string accessToken) public void Logout(string accessToken)
{ {
if (string.IsNullOrWhiteSpace(accessToken)) if (string.IsNullOrWhiteSpace(accessToken))
{ {
@ -1502,7 +1505,7 @@ namespace Emby.Server.Implementations.Session
{ {
existing.IsActive = false; existing.IsActive = false;
await _authRepo.Update(existing, CancellationToken.None).ConfigureAwait(false); _authRepo.Update(existing, CancellationToken.None);
var sessions = Sessions var sessions = Sessions
.Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase)) .Where(i => string.Equals(i.DeviceId, existing.DeviceId, StringComparison.OrdinalIgnoreCase))
@ -1522,7 +1525,7 @@ namespace Emby.Server.Implementations.Session
} }
} }
public async Task RevokeUserTokens(string userId, string currentAccessToken) public void RevokeUserTokens(string userId, string currentAccessToken)
{ {
var existing = _authRepo.Get(new AuthenticationInfoQuery var existing = _authRepo.Get(new AuthenticationInfoQuery
{ {
@ -1534,14 +1537,14 @@ namespace Emby.Server.Implementations.Session
{ {
if (!string.Equals(currentAccessToken, info.AccessToken, StringComparison.OrdinalIgnoreCase)) if (!string.Equals(currentAccessToken, info.AccessToken, StringComparison.OrdinalIgnoreCase))
{ {
await Logout(info.AccessToken).ConfigureAwait(false); Logout(info.AccessToken);
} }
} }
} }
public Task RevokeToken(string token) public void RevokeToken(string token)
{ {
return Logout(token); Logout(token);
} }
/// <summary> /// <summary>
@ -1661,35 +1664,39 @@ namespace Emby.Server.Implementations.Session
AddProgramRecordingInfo = false AddProgramRecordingInfo = false
}; };
dtoOptions.Fields.Remove(ItemFields.BasicSyncInfo); var fields = dtoOptions.Fields.ToList();
dtoOptions.Fields.Remove(ItemFields.SyncInfo);
dtoOptions.Fields.Remove(ItemFields.CanDelete); fields.Remove(ItemFields.BasicSyncInfo);
dtoOptions.Fields.Remove(ItemFields.CanDownload); fields.Remove(ItemFields.SyncInfo);
dtoOptions.Fields.Remove(ItemFields.ChildCount); fields.Remove(ItemFields.CanDelete);
dtoOptions.Fields.Remove(ItemFields.CustomRating); fields.Remove(ItemFields.CanDownload);
dtoOptions.Fields.Remove(ItemFields.DateLastMediaAdded); fields.Remove(ItemFields.ChildCount);
dtoOptions.Fields.Remove(ItemFields.DateLastRefreshed); fields.Remove(ItemFields.CustomRating);
dtoOptions.Fields.Remove(ItemFields.DateLastSaved); fields.Remove(ItemFields.DateLastMediaAdded);
dtoOptions.Fields.Remove(ItemFields.DisplayPreferencesId); fields.Remove(ItemFields.DateLastRefreshed);
dtoOptions.Fields.Remove(ItemFields.Etag); fields.Remove(ItemFields.DateLastSaved);
dtoOptions.Fields.Remove(ItemFields.ExternalEtag); fields.Remove(ItemFields.DisplayPreferencesId);
dtoOptions.Fields.Remove(ItemFields.InheritedParentalRatingValue); fields.Remove(ItemFields.Etag);
dtoOptions.Fields.Remove(ItemFields.ItemCounts); fields.Remove(ItemFields.ExternalEtag);
dtoOptions.Fields.Remove(ItemFields.MediaSourceCount); fields.Remove(ItemFields.InheritedParentalRatingValue);
dtoOptions.Fields.Remove(ItemFields.MediaStreams); fields.Remove(ItemFields.ItemCounts);
dtoOptions.Fields.Remove(ItemFields.MediaSources); fields.Remove(ItemFields.MediaSourceCount);
dtoOptions.Fields.Remove(ItemFields.People); fields.Remove(ItemFields.MediaStreams);
dtoOptions.Fields.Remove(ItemFields.PlayAccess); fields.Remove(ItemFields.MediaSources);
dtoOptions.Fields.Remove(ItemFields.People); fields.Remove(ItemFields.People);
dtoOptions.Fields.Remove(ItemFields.ProductionLocations); fields.Remove(ItemFields.PlayAccess);
dtoOptions.Fields.Remove(ItemFields.RecursiveItemCount); fields.Remove(ItemFields.People);
dtoOptions.Fields.Remove(ItemFields.RemoteTrailers); fields.Remove(ItemFields.ProductionLocations);
dtoOptions.Fields.Remove(ItemFields.SeasonUserData); fields.Remove(ItemFields.RecursiveItemCount);
dtoOptions.Fields.Remove(ItemFields.Settings); fields.Remove(ItemFields.RemoteTrailers);
dtoOptions.Fields.Remove(ItemFields.SortName); fields.Remove(ItemFields.SeasonUserData);
dtoOptions.Fields.Remove(ItemFields.Tags); fields.Remove(ItemFields.Settings);
dtoOptions.Fields.Remove(ItemFields.ThemeSongIds); fields.Remove(ItemFields.SortName);
dtoOptions.Fields.Remove(ItemFields.ThemeVideoIds); fields.Remove(ItemFields.Tags);
fields.Remove(ItemFields.ThemeSongIds);
fields.Remove(ItemFields.ThemeVideoIds);
dtoOptions.Fields = fields.ToArray(fields.Count);
_itemInfoDtoOptions = dtoOptions; _itemInfoDtoOptions = dtoOptions;
} }
@ -1698,7 +1705,7 @@ namespace Emby.Server.Implementations.Session
if (mediaSource != null) if (mediaSource != null)
{ {
info.MediaStreams = mediaSource.MediaStreams; info.MediaStreams = mediaSource.MediaStreams.ToArray();
} }
return info; return info;

View File

@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Social
AddShareInfo(info, externalUrl); AddShareInfo(info, externalUrl);
await _repository.CreateShare(info).ConfigureAwait(false); _repository.CreateShare(info);
return info; return info;
} }
@ -92,9 +92,9 @@ namespace Emby.Server.Implementations.Social
} }
} }
public Task DeleteShare(string id) public void DeleteShare(string id)
{ {
return _repository.DeleteShare(id); _repository.DeleteShare(id);
} }
} }
} }

View File

@ -1,8 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Data;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
@ -42,7 +40,7 @@ namespace Emby.Server.Implementations.Social
} }
} }
public async Task CreateShare(SocialShareInfo info) public void CreateShare(SocialShareInfo info)
{ {
if (info == null) if (info == null)
{ {
@ -109,7 +107,7 @@ namespace Emby.Server.Implementations.Social
return info; return info;
} }
public async Task DeleteShare(string id) public void DeleteShare(string id)
{ {
} }

View File

@ -36,7 +36,7 @@ namespace Emby.Server.Implementations.Sorting
return string.Empty; return string.Empty;
} }
return audio.Artists.Count == 0 ? null : audio.Artists[0]; return audio.Artists.Length == 0 ? null : audio.Artists[0];
} }
/// <summary> /// <summary>

View File

@ -72,7 +72,7 @@ namespace Emby.Server.Implementations.TV
Recursive = true, Recursive = true,
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
{ {
Fields = new List<ItemFields> Fields = new ItemFields[]
{ {
ItemFields.SeriesPresentationUniqueKey ItemFields.SeriesPresentationUniqueKey
} }
@ -128,7 +128,7 @@ namespace Emby.Server.Implementations.TV
Limit = limit, Limit = limit,
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
{ {
Fields = new List<ItemFields> Fields = new ItemFields[]
{ {
ItemFields.SeriesPresentationUniqueKey ItemFields.SeriesPresentationUniqueKey
}, },
@ -207,7 +207,7 @@ namespace Emby.Server.Implementations.TV
ParentIndexNumberNotEquals = 0, ParentIndexNumberNotEquals = 0,
DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions DtoOptions = new MediaBrowser.Controller.Dto.DtoOptions
{ {
Fields = new List<ItemFields> Fields = new ItemFields[]
{ {
ItemFields.SortName ItemFields.SortName
}, },

View File

@ -122,7 +122,10 @@ namespace Emby.Server.Implementations.Updates
private readonly ICryptoProvider _cryptographyProvider; private readonly ICryptoProvider _cryptographyProvider;
public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config, IFileSystem fileSystem, ICryptoProvider cryptographyProvider) // netframework or netcore
private readonly string _packageRuntime;
public InstallationManager(ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, IHttpClient httpClient, IJsonSerializer jsonSerializer, ISecurityManager securityManager, IConfigurationManager config, IFileSystem fileSystem, ICryptoProvider cryptographyProvider, string packageRuntime)
{ {
if (logger == null) if (logger == null)
{ {
@ -140,6 +143,7 @@ namespace Emby.Server.Implementations.Updates
_config = config; _config = config;
_fileSystem = fileSystem; _fileSystem = fileSystem;
_cryptographyProvider = cryptographyProvider; _cryptographyProvider = cryptographyProvider;
_packageRuntime = packageRuntime;
_logger = logger; _logger = logger;
} }
@ -157,7 +161,7 @@ namespace Emby.Server.Implementations.Updates
/// Gets all available packages. /// Gets all available packages.
/// </summary> /// </summary>
/// <returns>Task{List{PackageInfo}}.</returns> /// <returns>Task{List{PackageInfo}}.</returns>
public async Task<IEnumerable<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken, public async Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken,
bool withRegistration = true, bool withRegistration = true,
string packageType = null, string packageType = null,
Version applicationVersion = null) Version applicationVersion = null)
@ -171,11 +175,11 @@ namespace Emby.Server.Implementations.Updates
{ "systemid", _applicationHost.SystemId } { "systemid", _applicationHost.SystemId }
}; };
using (var json = await _httpClient.Post("https://www.mb3admin.com/admin/service/package/retrieveall", data, cancellationToken).ConfigureAwait(false)) using (var json = await _httpClient.Post("https://www.mb3admin.com/admin/service/package/retrieveall?includeAllRuntimes=true", data, cancellationToken).ConfigureAwait(false))
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(json).ToList(); var packages = _jsonSerializer.DeserializeFromStream<PackageInfo[]>(json);
return FilterPackages(packages, packageType, applicationVersion); return FilterPackages(packages, packageType, applicationVersion);
} }
@ -184,7 +188,7 @@ namespace Emby.Server.Implementations.Updates
{ {
var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
return FilterPackages(packages.ToList(), packageType, applicationVersion); return FilterPackages(packages, packageType, applicationVersion);
} }
} }
@ -195,21 +199,21 @@ namespace Emby.Server.Implementations.Updates
/// </summary> /// </summary>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{List{PackageInfo}}.</returns> /// <returns>Task{List{PackageInfo}}.</returns>
public async Task<IEnumerable<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken) public async Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken)
{ {
_logger.Info("Opening {0}", PackageCachePath); _logger.Info("Opening {0}", PackageCachePath);
try try
{ {
using (var stream = _fileSystem.OpenRead(PackageCachePath)) using (var stream = _fileSystem.OpenRead(PackageCachePath))
{ {
var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(stream).ToList(); var packages = _jsonSerializer.DeserializeFromStream<PackageInfo[]>(stream);
if (DateTime.UtcNow - _lastPackageUpdateTime > GetCacheLength()) if (DateTime.UtcNow - _lastPackageUpdateTime > GetCacheLength())
{ {
UpdateCachedPackages(CancellationToken.None, false); UpdateCachedPackages(CancellationToken.None, false);
} }
return packages; return FilterPackages(packages);
} }
} }
catch (Exception) catch (Exception)
@ -221,7 +225,7 @@ namespace Emby.Server.Implementations.Updates
await UpdateCachedPackages(cancellationToken, true).ConfigureAwait(false); await UpdateCachedPackages(cancellationToken, true).ConfigureAwait(false);
using (var stream = _fileSystem.OpenRead(PackageCachePath)) using (var stream = _fileSystem.OpenRead(PackageCachePath))
{ {
return _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(stream).ToList(); return FilterPackages(_jsonSerializer.DeserializeFromStream<PackageInfo[]>(stream));
} }
} }
@ -244,7 +248,7 @@ namespace Emby.Server.Implementations.Updates
var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
{ {
Url = "https://www.mb3admin.com/admin/service/MB3Packages.json", Url = "https://www.mb3admin.com/admin/service/EmbyPackages.json",
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
Progress = new SimpleProgress<Double>() Progress = new SimpleProgress<Double>()
@ -277,57 +281,77 @@ namespace Emby.Server.Implementations.Updates
private TimeSpan GetCacheLength() private TimeSpan GetCacheLength()
{ {
switch (GetSystemUpdateLevel()) return TimeSpan.FromMinutes(3);
{
case PackageVersionClass.Beta:
return TimeSpan.FromMinutes(30);
case PackageVersionClass.Dev:
return TimeSpan.FromMinutes(3);
default:
return TimeSpan.FromHours(24);
}
} }
protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages) protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages)
{ {
var list = new List<PackageInfo>();
foreach (var package in packages) foreach (var package in packages)
{ {
package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl)) var versions = new List<PackageVersionInfo>();
.OrderByDescending(GetPackageVersion).ToList(); foreach (var version in package.versions)
}
// Remove packages with no versions
packages = packages.Where(p => p.versions.Any()).ToList();
return packages;
}
protected IEnumerable<PackageInfo> FilterPackages(List<PackageInfo> packages, string packageType, Version applicationVersion)
{
foreach (var package in packages)
{
package.versions = package.versions.Where(v => !string.IsNullOrWhiteSpace(v.sourceUrl))
.OrderByDescending(GetPackageVersion).ToList();
}
if (!string.IsNullOrWhiteSpace(packageType))
{
packages = packages.Where(p => string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase)).ToList();
}
// If an app version was supplied, filter the versions for each package to only include supported versions
if (applicationVersion != null)
{
foreach (var package in packages)
{ {
package.versions = package.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToList(); if (string.IsNullOrWhiteSpace(version.sourceUrl))
{
continue;
}
if (string.IsNullOrWhiteSpace(version.runtimes) || version.runtimes.IndexOf(_packageRuntime, StringComparison.OrdinalIgnoreCase) == -1)
{
continue;
}
versions.Add(version);
} }
package.versions = versions
.OrderByDescending(GetPackageVersion)
.ToArray();
if (package.versions.Length == 0)
{
continue;
}
list.Add(package);
} }
// Remove packages with no versions // Remove packages with no versions
packages = packages.Where(p => p.versions.Any()).ToList(); return list;
}
return packages; protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages, string packageType, Version applicationVersion)
{
var packagesList = FilterPackages(packages);
var returnList = new List<PackageInfo>();
var filterOnPackageType = !string.IsNullOrWhiteSpace(packageType);
foreach (var p in packagesList)
{
if (filterOnPackageType && !string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase))
{
continue;
}
// If an app version was supplied, filter the versions for each package to only include supported versions
if (applicationVersion != null)
{
p.versions = p.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToArray();
}
if (p.versions.Length == 0)
{
continue;
}
returnList.Add(p);
}
return returnList;
} }
/// <summary> /// <summary>
@ -418,30 +442,24 @@ namespace Emby.Server.Implementations.Updates
/// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns> /// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns>
public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken) public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken)
{ {
var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); if (!_config.CommonConfiguration.EnableAutoUpdate)
var plugins = _applicationHost.Plugins.ToList();
if (withAutoUpdateEnabled)
{ {
plugins = plugins return new PackageVersionInfo[] { };
.Where(p => _config.CommonConfiguration.EnableAutoUpdate)
.ToList();
} }
var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false);
var systemUpdateLevel = GetSystemUpdateLevel(); var systemUpdateLevel = GetSystemUpdateLevel();
// Figure out what needs to be installed // Figure out what needs to be installed
var packages = plugins.Select(p => return _applicationHost.Plugins.Select(p =>
{ {
var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, systemUpdateLevel); var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, systemUpdateLevel);
return latestPluginInfo != null && GetPackageVersion(latestPluginInfo) > p.Version ? latestPluginInfo : null; return latestPluginInfo != null && GetPackageVersion(latestPluginInfo) > p.Version ? latestPluginInfo : null;
}).Where(i => i != null).ToList(); }).Where(i => i != null)
.Where(p => !string.IsNullOrWhiteSpace(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
return packages
.Where(p => !string.IsNullOrWhiteSpace(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase)));
} }
/// <summary> /// <summary>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Emby.XmlTv" version="1.0.10" targetFramework="net46" /> <package id="Emby.XmlTv" version="1.0.10" targetFramework="net46" />
<package id="MediaBrowser.Naming" version="1.0.6" targetFramework="net46" /> <package id="MediaBrowser.Naming" version="1.0.7" targetFramework="net46" />
<package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" /> <package id="ServiceStack.Text" version="4.5.8" targetFramework="net46" />
<package id="SharpCompress" version="0.14.0" targetFramework="net46" /> <package id="SharpCompress" version="0.14.0" targetFramework="net46" />
<package id="SimpleInjector" version="4.0.8" targetFramework="net46" /> <package id="SimpleInjector" version="4.0.8" targetFramework="net46" />

View File

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Api namespace MediaBrowser.Api
{ {
@ -54,6 +55,17 @@ namespace MediaBrowser.Api
return Request.Headers[name]; return Request.Headers[name];
} }
private static readonly string[] EmptyStringArray = new string[] { };
public static string[] SplitValue(string value, char delim)
{
if (string.IsNullOrWhiteSpace(value))
{
return EmptyStringArray;
}
return value.Split(new[] { delim }, StringSplitOptions.RemoveEmptyEntries);
}
/// <summary> /// <summary>
/// To the optimized result. /// To the optimized result.
/// </summary> /// </summary>
@ -128,7 +140,7 @@ namespace MediaBrowser.Api
var hasFields = request as IHasItemFields; var hasFields = request as IHasItemFields;
if (hasFields != null) if (hasFields != null)
{ {
options.Fields = hasFields.GetItemFields().ToList(); options.Fields = hasFields.GetItemFields();
} }
var client = authInfo.Client ?? string.Empty; var client = authInfo.Client ?? string.Empty;
@ -137,7 +149,9 @@ namespace MediaBrowser.Api
client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 || client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1) client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1)
{ {
options.Fields.Add(Model.Querying.ItemFields.RecursiveItemCount); var list = options.Fields.ToList();
list.Add(Model.Querying.ItemFields.RecursiveItemCount);
options.Fields = list.ToArray(list.Count);
} }
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 || if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
@ -148,7 +162,9 @@ namespace MediaBrowser.Api
client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1 || client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1 ||
client.IndexOf("androidtv", StringComparison.OrdinalIgnoreCase) != -1) client.IndexOf("androidtv", StringComparison.OrdinalIgnoreCase) != -1)
{ {
options.Fields.Add(Model.Querying.ItemFields.ChildCount); var list = options.Fields.ToList();
list.Add(Model.Querying.ItemFields.ChildCount);
options.Fields = list.ToArray(list.Count);
} }
var hasDtoOptions = request as IHasDtoOptions; var hasDtoOptions = request as IHasDtoOptions;
@ -167,7 +183,7 @@ namespace MediaBrowser.Api
if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes)) if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
{ {
options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList(); options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToArray();
} }
} }

View File

@ -55,7 +55,7 @@ namespace MediaBrowser.Api
} }
[Route("/Channels/Features", "GET", Summary = "Gets features for a channel")] [Route("/Channels/Features", "GET", Summary = "Gets features for a channel")]
public class GetAllChannelFeatures : IReturn<List<ChannelFeatures>> public class GetAllChannelFeatures : IReturn<ChannelFeatures[]>
{ {
} }
@ -187,7 +187,7 @@ namespace MediaBrowser.Api
public object Get(GetAllChannelFeatures request) public object Get(GetAllChannelFeatures request)
{ {
var result = _channelManager.GetAllChannelFeatures().ToList(); var result = _channelManager.GetAllChannelFeatures();
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
@ -231,7 +231,7 @@ namespace MediaBrowser.Api
SortOrder = request.SortOrder, SortOrder = request.SortOrder,
SortBy = (request.SortBy ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(), SortBy = (request.SortBy ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
Filters = request.GetFilters().ToArray(), Filters = request.GetFilters().ToArray(),
Fields = request.GetItemFields().ToArray() Fields = request.GetItemFields()
}, CancellationToken.None).ConfigureAwait(false); }, CancellationToken.None).ConfigureAwait(false);
@ -247,7 +247,7 @@ namespace MediaBrowser.Api
ChannelIds = (request.ChannelIds ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(), ChannelIds = (request.ChannelIds ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(),
UserId = request.UserId, UserId = request.UserId,
Filters = request.GetFilters().ToArray(), Filters = request.GetFilters().ToArray(),
Fields = request.GetItemFields().ToList() Fields = request.GetItemFields()
}, CancellationToken.None).ConfigureAwait(false); }, CancellationToken.None).ConfigureAwait(false);

View File

@ -6,7 +6,6 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;
@ -62,7 +61,7 @@ namespace MediaBrowser.Api
[Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")] [Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")]
[Authenticated(Roles = "Admin")] [Authenticated(Roles = "Admin")]
public class GetMetadataPlugins : IReturn<List<MetadataPluginSummary>> public class GetMetadataPlugins : IReturn<MetadataPluginSummary[]>
{ {
} }
@ -170,7 +169,7 @@ namespace MediaBrowser.Api
public object Get(GetMetadataPlugins request) public object Get(GetMetadataPlugins request)
{ {
return ToOptimizedSerializedResultUsingCache(_providerManager.GetAllMetadataPlugins().ToList()); return ToOptimizedSerializedResultUsingCache(_providerManager.GetAllMetadataPlugins());
} }
} }
} }

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Linq;
using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Devices; using MediaBrowser.Model.Devices;
@ -143,7 +142,7 @@ namespace MediaBrowser.Api.Devices
} }
else else
{ {
var file = Request.Files.First(); var file = Request.Files.Length == 0 ? null : Request.Files[0];
var task = _deviceManager.AcceptCameraUpload(deviceId, file.InputStream, new LocalFileInfo var task = _deviceManager.AcceptCameraUpload(deviceId, file.InputStream, new LocalFileInfo
{ {

View File

@ -88,9 +88,7 @@ namespace MediaBrowser.Api
// Serialize to json and then back so that the core doesn't see the request dto type // Serialize to json and then back so that the core doesn't see the request dto type
var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request)); var displayPreferences = _jsonSerializer.DeserializeFromString<DisplayPreferences>(_jsonSerializer.SerializeToString(request));
var task = _displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None); _displayPreferencesManager.SaveDisplayPreferences(displayPreferences, request.UserId, request.Client, CancellationToken.None);
Task.WaitAll(task);
} }
} }
} }

View File

@ -3,7 +3,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.IO; using MediaBrowser.Controller.IO;

View File

@ -1,14 +1,13 @@
using MediaBrowser.Controller.Dlna; using System.Linq;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
namespace MediaBrowser.Api.Dlna namespace MediaBrowser.Api.Dlna
{ {
[Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")] [Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")]
public class GetProfileInfos : IReturn<List<DeviceProfileInfo>> public class GetProfileInfos : IReturn<DeviceProfileInfo[]>
{ {
} }
@ -53,7 +52,7 @@ namespace MediaBrowser.Api.Dlna
public object Get(GetProfileInfos request) public object Get(GetProfileInfos request)
{ {
var result = _dlnaManager.GetProfileInfos().ToList(); var result = _dlnaManager.GetProfileInfos().ToArray();
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }

View File

@ -226,7 +226,7 @@ namespace MediaBrowser.Api
return ToOptimizedSerializedResultUsingCache(GetNetworkShares(path).OrderBy(i => i.Path).ToList()); return ToOptimizedSerializedResultUsingCache(GetNetworkShares(path).OrderBy(i => i.Path).ToList());
} }
return ToOptimizedSerializedResultUsingCache(GetFileSystemEntries(request).OrderBy(i => i.Path).ToList()); return ToOptimizedSerializedResultUsingCache(GetFileSystemEntries(request).ToList());
} }
public object Get(GetNetworkShares request) public object Get(GetNetworkShares request)
@ -271,9 +271,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public object Get(GetNetworkDevices request) public object Get(GetNetworkDevices request)
{ {
var result = _networkManager.GetNetworkDevices() var result = _networkManager.GetNetworkDevices().ToList();
.OrderBy(i => i.Path)
.ToList();
return ToOptimizedSerializedResultUsingCache(result); return ToOptimizedSerializedResultUsingCache(result);
} }
@ -300,7 +298,6 @@ namespace MediaBrowser.Api
/// <returns>IEnumerable{FileSystemEntryInfo}.</returns> /// <returns>IEnumerable{FileSystemEntryInfo}.</returns>
private IEnumerable<FileSystemEntryInfo> GetFileSystemEntries(GetDirectoryContents request) private IEnumerable<FileSystemEntryInfo> GetFileSystemEntries(GetDirectoryContents request)
{ {
// using EnumerateFileSystemInfos doesn't handle reparse points (symlinks)
var entries = _fileSystem.GetFileSystemEntries(request.Path).Where(i => var entries = _fileSystem.GetFileSystemEntries(request.Path).Where(i =>
{ {
if (!request.IncludeHidden && i.IsHidden) if (!request.IncludeHidden && i.IsHidden)
@ -329,7 +326,7 @@ namespace MediaBrowser.Api
Path = f.FullName, Path = f.FullName,
Type = f.IsDirectory ? FileSystemEntryType.Directory : FileSystemEntryType.File Type = f.IsDirectory ? FileSystemEntryType.Directory : FileSystemEntryType.File
}).ToList(); });
} }
public object Get(GetParentPath request) public object Get(GetParentPath request)

View File

@ -108,7 +108,7 @@ namespace MediaBrowser.Api
EnableTotalRecordCount = false, EnableTotalRecordCount = false,
DtoOptions = new Controller.Dto.DtoOptions DtoOptions = new Controller.Dto.DtoOptions
{ {
Fields = new List<ItemFields> { ItemFields.Genres, ItemFields.Tags }, Fields = new ItemFields[] { ItemFields.Genres, ItemFields.Tags },
EnableImages = false, EnableImages = false,
EnableUserData = false EnableUserData = false
} }

View File

@ -28,21 +28,7 @@ namespace MediaBrowser.Api
/// Class GetGameSystemSummaries /// Class GetGameSystemSummaries
/// </summary> /// </summary>
[Route("/Games/SystemSummaries", "GET", Summary = "Finds games similar to a given game.")] [Route("/Games/SystemSummaries", "GET", Summary = "Finds games similar to a given game.")]
public class GetGameSystemSummaries : IReturn<List<GameSystemSummary>> public class GetGameSystemSummaries : IReturn<GameSystemSummary[]>
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "Optional. Filter by user id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
}
/// <summary>
/// Class GetGameSystemSummaries
/// </summary>
[Route("/Games/PlayerIndex", "GET", Summary = "Gets an index of players (1-x) and the number of games listed under each")]
public class GetPlayerIndex : IReturn<List<ItemIndex>>
{ {
/// <summary> /// <summary>
/// Gets or sets the user id. /// Gets or sets the user id.
@ -117,47 +103,17 @@ namespace MediaBrowser.Api
EnableImages = false EnableImages = false
} }
}; };
var gameSystems = _libraryManager.GetItemList(query)
.Cast<GameSystem>()
.ToList();
var result = gameSystems var result = _libraryManager.GetItemList(query)
.Cast<GameSystem>()
.Select(i => GetSummary(i, user)) .Select(i => GetSummary(i, user))
.ToList(); .ToArray();
return ToOptimizedSerializedResultUsingCache(result); return ToOptimizedSerializedResultUsingCache(result);
} }
private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
public object Get(GetPlayerIndex request)
{
var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId);
var query = new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Game).Name },
DtoOptions = new DtoOptions(false)
{
EnableImages = false
}
};
var games = _libraryManager.GetItemList(query)
.Cast<Game>()
.ToList();
var lookup = games
.ToLookup(i => i.PlayersSupported ?? -1)
.OrderBy(i => i.Key)
.Select(i => new ItemIndex
{
ItemCount = i.Count(),
Name = i.Key == -1 ? string.Empty : i.Key.ToString(UsCulture)
})
.ToList();
return ToOptimizedSerializedResultUsingCache(lookup);
}
/// <summary> /// <summary>
/// Gets the summary. /// Gets the summary.
/// </summary> /// </summary>
@ -183,15 +139,15 @@ namespace MediaBrowser.Api
} }
}); });
var games = items.Cast<Game>().ToList(); var games = items.Cast<Game>().ToArray();
summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder); summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder);
summary.GameCount = games.Count; summary.GameCount = games.Length;
summary.GameFileExtensions = games.Where(i => !i.IsPlaceHolder).Select(i => Path.GetExtension(i.Path)) summary.GameFileExtensions = games.Where(i => !i.IsPlaceHolder).Select(i => Path.GetExtension(i.Path))
.Distinct(StringComparer.OrdinalIgnoreCase) .Distinct(StringComparer.OrdinalIgnoreCase)
.ToList(); .ToArray();
return summary; return summary;
} }
@ -234,7 +190,7 @@ namespace MediaBrowser.Api
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
Items = returnList.ToArray(returnList.Count), Items = returnList,
TotalRecordCount = itemsResult.Count TotalRecordCount = itemsResult.Count
}; };

View File

@ -27,7 +27,7 @@ namespace MediaBrowser.Api
/// </summary> /// </summary>
/// <param name="request">The request.</param> /// <param name="request">The request.</param>
/// <returns>IEnumerable{ItemFields}.</returns> /// <returns>IEnumerable{ItemFields}.</returns>
public static IEnumerable<ItemFields> GetItemFields(this IHasItemFields request) public static ItemFields[] GetItemFields(this IHasItemFields request)
{ {
var val = request.Fields; var val = request.Fields;
@ -46,7 +46,7 @@ namespace MediaBrowser.Api
} }
return null; return null;
}).Where(i => i.HasValue).Select(i => i.Value); }).Where(i => i.HasValue).Select(i => i.Value).ToArray();
} }
} }
} }

View File

@ -556,20 +556,7 @@ namespace MediaBrowser.Api.Images
throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type)); throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type));
} }
var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.ImageEnhancers.Where(i => var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.GetSupportedEnhancers(item, request.Type) : new List<IImageEnhancer>();
{
try
{
return i.Supports(item, request.Type);
}
catch (Exception ex)
{
Logger.ErrorException("Error in image enhancer: {0}", ex, i.GetType().Name);
return false;
}
}).ToList() : new List<IImageEnhancer>();
var cropwhitespace = request.Type == ImageType.Logo || var cropwhitespace = request.Type == ImageType.Logo ||
request.Type == ImageType.Art request.Type == ImageType.Art

View File

@ -150,7 +150,7 @@ namespace MediaBrowser.Api.Images
}, CancellationToken.None).ConfigureAwait(false); }, CancellationToken.None).ConfigureAwait(false);
var imagesList = images.ToList(); var imagesList = images.ToArray();
var allProviders = _providerManager.GetRemoteImageProviderInfo(item); var allProviders = _providerManager.GetRemoteImageProviderInfo(item);
@ -161,22 +161,22 @@ namespace MediaBrowser.Api.Images
var result = new RemoteImageResult var result = new RemoteImageResult
{ {
TotalRecordCount = imagesList.Count, TotalRecordCount = imagesList.Length,
Providers = allProviders.Select(i => i.Name) Providers = allProviders.Select(i => i.Name)
.Distinct(StringComparer.OrdinalIgnoreCase) .Distinct(StringComparer.OrdinalIgnoreCase)
.ToList() .ToArray()
}; };
if (request.StartIndex.HasValue) if (request.StartIndex.HasValue)
{ {
imagesList = imagesList.Skip(request.StartIndex.Value) imagesList = imagesList.Skip(request.StartIndex.Value)
.ToList(); .ToArray();
} }
if (request.Limit.HasValue) if (request.Limit.HasValue)
{ {
imagesList = imagesList.Take(request.Limit.Value) imagesList = imagesList.Take(request.Limit.Value)
.ToList(); .ToArray();
} }
result.Images = imagesList; result.Images = imagesList;

View File

@ -64,8 +64,8 @@ namespace MediaBrowser.Api
var info = new MetadataEditorInfo var info = new MetadataEditorInfo
{ {
ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(), ParentalRatingOptions = _localizationManager.GetParentalRatings(),
ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(), ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToArray(),
Countries = _localizationManager.GetCountries(), Countries = _localizationManager.GetCountries(),
Cultures = _localizationManager.GetCultures() Cultures = _localizationManager.GetCultures()
}; };
@ -78,14 +78,14 @@ namespace MediaBrowser.Api
if (string.IsNullOrWhiteSpace(inheritedContentType) || !string.IsNullOrWhiteSpace(configuredContentType)) if (string.IsNullOrWhiteSpace(inheritedContentType) || !string.IsNullOrWhiteSpace(configuredContentType))
{ {
info.ContentTypeOptions = GetContentTypeOptions(true); info.ContentTypeOptions = GetContentTypeOptions(true).ToArray();
info.ContentType = configuredContentType; info.ContentType = configuredContentType;
if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) if (string.IsNullOrWhiteSpace(inheritedContentType) || string.Equals(inheritedContentType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{ {
info.ContentTypeOptions = info.ContentTypeOptions info.ContentTypeOptions = info.ContentTypeOptions
.Where(i => string.IsNullOrWhiteSpace(i.Value) || string.Equals(i.Value, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) .Where(i => string.IsNullOrWhiteSpace(i.Value) || string.Equals(i.Value, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
.ToList(); .ToArray();
} }
} }
} }
@ -209,7 +209,7 @@ namespace MediaBrowser.Api
// Do this first so that metadata savers can pull the updates from the database. // Do this first so that metadata savers can pull the updates from the database.
if (request.People != null) if (request.People != null)
{ {
await _libraryManager.UpdatePeople(item, request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList()); _libraryManager.UpdatePeople(item, request.People.Select(x => new PersonInfo { Name = x.Name, Role = x.Role, Type = x.Type }).ToList());
} }
UpdateItem(request, item); UpdateItem(request, item);
@ -352,7 +352,7 @@ namespace MediaBrowser.Api
hasArtists.Artists = request hasArtists.Artists = request
.ArtistItems .ArtistItems
.Select(i => i.Name) .Select(i => i.Name)
.ToList(); .ToArray();
} }
} }

View File

@ -227,7 +227,7 @@ namespace MediaBrowser.Api.Library
[Route("/Library/MediaFolders", "GET", Summary = "Gets all user media folders.")] [Route("/Library/MediaFolders", "GET", Summary = "Gets all user media folders.")]
[Authenticated] [Authenticated]
public class GetMediaFolders : IReturn<ItemsResult> public class GetMediaFolders : IReturn<QueryResult<BaseItemDto>>
{ {
[ApiMember(Name = "IsHidden", Description = "Optional. Filter by folders that are marked hidden, or not.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "IsHidden", Description = "Optional. Filter by folders that are marked hidden, or not.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? IsHidden { get; set; } public bool? IsHidden { get; set; }
@ -400,7 +400,7 @@ namespace MediaBrowser.Api.Library
}); });
} }
return new ItemsResult(); return new QueryResult<BaseItemDto>();
} }
public object Get(GetMediaFolders request) public object Get(GetMediaFolders request)
@ -416,7 +416,7 @@ namespace MediaBrowser.Api.Library
var dtoOptions = GetDtoOptions(_authContext, request); var dtoOptions = GetDtoOptions(_authContext, request);
var result = new ItemsResult var result = new QueryResult<BaseItemDto>
{ {
TotalRecordCount = items.Count, TotalRecordCount = items.Count,
@ -525,18 +525,18 @@ namespace MediaBrowser.Api.Library
}); });
} }
private async void LogDownload(BaseItem item, User user, AuthorizationInfo auth) private void LogDownload(BaseItem item, User user, AuthorizationInfo auth)
{ {
try try
{ {
await _activityManager.Create(new ActivityLogEntry _activityManager.Create(new ActivityLogEntry
{ {
Name = string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name), Name = string.Format(_localization.GetLocalizedString("UserDownloadingItemWithValues"), user.Name, item.Name),
Type = "UserDownloadingContent", Type = "UserDownloadingContent",
ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device), ShortOverview = string.Format(_localization.GetLocalizedString("AppDeviceValues"), auth.Client, auth.Device),
UserId = auth.UserId UserId = auth.UserId
}).ConfigureAwait(false); });
} }
catch catch
{ {
@ -615,7 +615,7 @@ namespace MediaBrowser.Api.Library
parent = parent.GetParent(); parent = parent.GetParent();
} }
return baseItemDtos.ToList(); return baseItemDtos;
} }
private BaseItem TranslateParentItem(BaseItem item, User user) private BaseItem TranslateParentItem(BaseItem item, User user)

View File

@ -648,7 +648,7 @@ namespace MediaBrowser.Api.LiveTv
{ {
public List<TunerChannelMapping> TunerChannels { get; set; } public List<TunerChannelMapping> TunerChannels { get; set; }
public List<NameIdPair> ProviderChannels { get; set; } public List<NameIdPair> ProviderChannels { get; set; }
public List<NameValuePair> Mappings { get; set; } public NameValuePair[] Mappings { get; set; }
public string ProviderName { get; set; } public string ProviderName { get; set; }
} }
@ -789,7 +789,7 @@ namespace MediaBrowser.Api.LiveTv
var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None) var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None)
.ConfigureAwait(false); .ConfigureAwait(false);
var mappings = listingsProviderInfo.ChannelMappings.ToList(); var mappings = listingsProviderInfo.ChannelMappings;
var result = new ChannelMappingOptions var result = new ChannelMappingOptions
{ {
@ -862,7 +862,7 @@ namespace MediaBrowser.Api.LiveTv
{ {
var config = GetConfiguration(); var config = GetConfiguration();
config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToList(); config.TunerHosts = config.TunerHosts.Where(i => !string.Equals(request.Id, i.Id, StringComparison.OrdinalIgnoreCase)).ToArray();
_config.SaveConfiguration("livetv", config); _config.SaveConfiguration("livetv", config);
} }
@ -922,9 +922,8 @@ namespace MediaBrowser.Api.LiveTv
options.AddCurrentProgram = request.AddCurrentProgram; options.AddCurrentProgram = request.AddCurrentProgram;
var returnList = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user) var returnArray = (await _dtoService.GetBaseItemDtos(channelResult.Items, options, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var returnArray = returnList.ToArray(returnList.Count);
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
@ -937,10 +936,13 @@ namespace MediaBrowser.Api.LiveTv
private void RemoveFields(DtoOptions options) private void RemoveFields(DtoOptions options)
{ {
options.Fields.Remove(ItemFields.CanDelete); var fields = options.Fields.ToList();
options.Fields.Remove(ItemFields.CanDownload);
options.Fields.Remove(ItemFields.DisplayPreferencesId); fields.Remove(ItemFields.CanDelete);
options.Fields.Remove(ItemFields.Etag); fields.Remove(ItemFields.CanDownload);
fields.Remove(ItemFields.DisplayPreferencesId);
fields.Remove(ItemFields.Etag);
options.Fields = fields.ToArray(fields.Count);
} }
public object Get(GetChannel request) public object Get(GetChannel request)

View File

@ -2,7 +2,6 @@
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
namespace MediaBrowser.Api namespace MediaBrowser.Api
@ -11,7 +10,7 @@ namespace MediaBrowser.Api
/// Class GetCultures /// Class GetCultures
/// </summary> /// </summary>
[Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")] [Route("/Localization/Cultures", "GET", Summary = "Gets known cultures")]
public class GetCultures : IReturn<List<CultureDto>> public class GetCultures : IReturn<CultureDto[]>
{ {
} }
@ -19,7 +18,7 @@ namespace MediaBrowser.Api
/// Class GetCountries /// Class GetCountries
/// </summary> /// </summary>
[Route("/Localization/Countries", "GET", Summary = "Gets known countries")] [Route("/Localization/Countries", "GET", Summary = "Gets known countries")]
public class GetCountries : IReturn<List<CountryInfo>> public class GetCountries : IReturn<CountryInfo[]>
{ {
} }
@ -27,7 +26,7 @@ namespace MediaBrowser.Api
/// Class ParentalRatings /// Class ParentalRatings
/// </summary> /// </summary>
[Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")] [Route("/Localization/ParentalRatings", "GET", Summary = "Gets known parental ratings")]
public class GetParentalRatings : IReturn<List<ParentalRating>> public class GetParentalRatings : IReturn<ParentalRating[]>
{ {
} }
@ -35,7 +34,7 @@ namespace MediaBrowser.Api
/// Class ParentalRatings /// Class ParentalRatings
/// </summary> /// </summary>
[Route("/Localization/Options", "GET", Summary = "Gets localization options")] [Route("/Localization/Options", "GET", Summary = "Gets localization options")]
public class GetLocalizationOptions : IReturn<List<LocalizatonOption>> public class GetLocalizationOptions : IReturn<LocalizatonOption[]>
{ {
} }
@ -66,14 +65,14 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public object Get(GetParentalRatings request) public object Get(GetParentalRatings request)
{ {
var result = _localization.GetParentalRatings().ToList(); var result = _localization.GetParentalRatings();
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
public object Get(GetLocalizationOptions request) public object Get(GetLocalizationOptions request)
{ {
var result = _localization.GetLocalizationOptions().ToList(); var result = _localization.GetLocalizationOptions();
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }

View File

@ -97,7 +97,6 @@
<Compile Include="Movies\MoviesService.cs" /> <Compile Include="Movies\MoviesService.cs" />
<Compile Include="NewsService.cs" /> <Compile Include="NewsService.cs" />
<Compile Include="NotificationsService.cs" /> <Compile Include="NotificationsService.cs" />
<Compile Include="PackageReviewService.cs" />
<Compile Include="PackageService.cs" /> <Compile Include="PackageService.cs" />
<Compile Include="PluginService.cs" /> <Compile Include="PluginService.cs" />
<Compile Include="Images\RemoteImageService.cs" /> <Compile Include="Images\RemoteImageService.cs" />

View File

@ -4,7 +4,6 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Collections; using MediaBrowser.Model.Collections;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
@ -71,8 +70,8 @@ namespace MediaBrowser.Api.Movies
IsLocked = request.IsLocked, IsLocked = request.IsLocked,
Name = request.Name, Name = request.Name,
ParentId = parentId, ParentId = parentId,
ItemIdList = (request.Ids ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => new Guid(i)).ToList(), ItemIdList = SplitValue(request.Ids, ','),
UserIds = new List<Guid> { new Guid(userId) } UserIds = new string[] { userId }
}).ConfigureAwait(false); }).ConfigureAwait(false);
@ -88,14 +87,14 @@ namespace MediaBrowser.Api.Movies
public void Post(AddToCollection request) public void Post(AddToCollection request)
{ {
var task = _collectionManager.AddToCollection(new Guid(request.Id), request.Ids.Split(',').Select(i => new Guid(i))); var task = _collectionManager.AddToCollection(new Guid(request.Id), SplitValue(request.Ids, ','));
Task.WaitAll(task); Task.WaitAll(task);
} }
public void Delete(RemoveFromCollection request) public void Delete(RemoveFromCollection request)
{ {
var task = _collectionManager.RemoveFromCollection(new Guid(request.Id), request.Ids.Split(',').Select(i => new Guid(i))); var task = _collectionManager.RemoveFromCollection(new Guid(request.Id), SplitValue(request.Ids, ','));
Task.WaitAll(task); Task.WaitAll(task);
} }

View File

@ -170,7 +170,7 @@ namespace MediaBrowser.Api.Movies
var result = new QueryResult<BaseItemDto> var result = new QueryResult<BaseItemDto>
{ {
Items = returnList.ToArray(returnList.Count), Items = returnList,
TotalRecordCount = itemsResult.Count TotalRecordCount = itemsResult.Count
}; };
@ -320,7 +320,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = name, BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"), CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type, RecommendationType = type,
Items = returnItems.ToArray(returnItems.Count) Items = returnItems
}; };
} }
} }
@ -360,7 +360,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = name, BaselineItemName = name,
CategoryId = name.GetMD5().ToString("N"), CategoryId = name.GetMD5().ToString("N"),
RecommendationType = type, RecommendationType = type,
Items = returnItems.ToArray(returnItems.Count) Items = returnItems
}; };
} }
} }
@ -397,7 +397,7 @@ namespace MediaBrowser.Api.Movies
BaselineItemName = item.Name, BaselineItemName = item.Name,
CategoryId = item.Id.ToString("N"), CategoryId = item.Id.ToString("N"),
RecommendationType = type, RecommendationType = type,
Items = returnItems.ToArray(returnItems.Count) Items = returnItems
}; };
} }
} }
@ -426,7 +426,7 @@ namespace MediaBrowser.Api.Movies
{ {
var people = _libraryManager.GetPeople(new InternalPeopleQuery var people = _libraryManager.GetPeople(new InternalPeopleQuery
{ {
PersonTypes = new List<string> PersonTypes = new string[]
{ {
PersonType.Director PersonType.Director
} }

View File

@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Collections;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
@ -11,7 +12,7 @@ using MediaBrowser.Model.Services;
namespace MediaBrowser.Api.Movies namespace MediaBrowser.Api.Movies
{ {
[Route("/Trailers", "GET", Summary = "Finds movies and trailers similar to a given trailer.")] [Route("/Trailers", "GET", Summary = "Finds movies and trailers similar to a given trailer.")]
public class Getrailers : BaseItemsRequest, IReturn<ItemsResult> public class Getrailers : BaseItemsRequest, IReturn<QueryResult<BaseItemDto>>
{ {
} }

View File

@ -8,6 +8,7 @@ using MediaBrowser.Model.Querying;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
@ -185,15 +186,20 @@ namespace MediaBrowser.Api.Music
{ {
var list = items; var list = items;
var result = new ItemsResult var result = new QueryResult<BaseItemDto>
{ {
TotalRecordCount = list.Count TotalRecordCount = list.Count
}; };
var returnList = (await _dtoService.GetBaseItemDtos(list.Take(request.Limit ?? list.Count), dtoOptions, user) if (request.Limit.HasValue)
{
list = list.Take(request.Limit.Value).ToList();
}
var returnList = (await _dtoService.GetBaseItemDtos(list, dtoOptions, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
result.Items = returnList.ToArray(returnList.Count); result.Items = returnList;
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }

View File

@ -99,7 +99,7 @@ namespace MediaBrowser.Api
public object Get(GetNotificationTypes request) public object Get(GetNotificationTypes request)
{ {
var result = _notificationManager.GetNotificationTypes().ToList(); var result = _notificationManager.GetNotificationTypes();
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }

View File

@ -1,162 +0,0 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Serialization;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
namespace MediaBrowser.Api
{
/// <summary>
/// Class InstallPackage
/// </summary>
[Route("/Packages/Reviews/{Id}", "POST", Summary = "Creates or updates a package review")]
public class CreateReviewRequest : IReturnVoid
{
/// <summary>
/// Gets or sets the Id.
/// </summary>
/// <value>The Id.</value>
[ApiMember(Name = "Id", Description = "Package Id", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "POST")]
public int Id { get; set; }
/// <summary>
/// Gets or sets the rating.
/// </summary>
/// <value>The review.</value>
[ApiMember(Name = "Rating", Description = "The rating value (1-5)", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "POST")]
public int Rating { get; set; }
/// <summary>
/// Gets or sets the recommend value.
/// </summary>
/// <value>Whether or not this review recommends this item.</value>
[ApiMember(Name = "Recommend", Description = "Whether or not this review recommends this item", IsRequired = true, DataType = "bool", ParameterType = "query", Verb = "POST")]
public bool Recommend { get; set; }
/// <summary>
/// Gets or sets the title.
/// </summary>
/// <value>The title.</value>
[ApiMember(Name = "Title", Description = "Optional short description of review.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string Title { get; set; }
/// <summary>
/// Gets or sets the full review.
/// </summary>
/// <value>The full review.</value>
[ApiMember(Name = "Review", Description = "Optional full review.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
public string Review { get; set; }
}
/// <summary>
/// Class InstallPackage
/// </summary>
[Route("/Packages/{Id}/Reviews", "GET", Summary = "Gets reviews for a package")]
public class ReviewRequest : IReturn<List<PackageReviewInfo>>
{
/// <summary>
/// Gets or sets the Id.
/// </summary>
/// <value>The Id.</value>
[ApiMember(Name = "Id", Description = "Package Id", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
public int Id { get; set; }
/// <summary>
/// Gets or sets the max rating.
/// </summary>
/// <value>The max rating.</value>
[ApiMember(Name = "MaxRating", Description = "Retrieve only reviews less than or equal to this", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int MaxRating { get; set; }
/// <summary>
/// Gets or sets the min rating.
/// </summary>
/// <value>The max rating.</value>
[ApiMember(Name = "MinRating", Description = "Retrieve only reviews greator than or equal to this", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int MinRating { get; set; }
/// <summary>
/// Only retrieve reviews with at least a short review.
/// </summary>
/// <value>True if should only get reviews with a title.</value>
[ApiMember(Name = "ForceTitle", Description = "Whether or not to restrict results to those with a title", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool ForceTitle { get; set; }
/// <summary>
/// Gets or sets the limit for the query.
/// </summary>
/// <value>The max rating.</value>
[ApiMember(Name = "Limit", Description = "Limit the result to this many reviews (ordered by latest)", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int Limit { get; set; }
}
[Authenticated]
public class PackageReviewService : BaseApiService
{
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _serializer;
private const string MbAdminUrl = "https://www.mb3admin.com/admin/";
private readonly IServerApplicationHost _appHost;
public PackageReviewService(IHttpClient httpClient, IJsonSerializer serializer, IServerApplicationHost appHost)
{
_httpClient = httpClient;
_serializer = serializer;
_appHost = appHost;
}
public async Task<object> Get(ReviewRequest request)
{
var parms = "?id=" + request.Id;
if (request.MaxRating > 0)
{
parms += "&max=" + request.MaxRating;
}
if (request.MinRating > 0)
{
parms += "&min=" + request.MinRating;
}
if (request.MinRating > 0)
{
parms += "&limit=" + request.Limit;
}
if (request.ForceTitle)
{
parms += "&title=true";
}
using (var result = await _httpClient.Get(MbAdminUrl + "/service/packageReview/retrieve" + parms, CancellationToken.None)
.ConfigureAwait(false))
{
var reviews = _serializer.DeserializeFromStream<List<PackageReviewInfo>>(result);
return ToOptimizedResult(reviews);
}
}
public void Post(CreateReviewRequest request)
{
var reviewText = WebUtility.HtmlEncode(request.Review ?? string.Empty);
var title = WebUtility.HtmlEncode(request.Title ?? string.Empty);
var review = new Dictionary<string, string>
{ { "id", request.Id.ToString(CultureInfo.InvariantCulture) },
{ "mac", _appHost.SystemId },
{ "rating", request.Rating.ToString(CultureInfo.InvariantCulture) },
{ "recommend", request.Recommend.ToString() },
{ "title", title },
{ "review", reviewText },
};
Task.WaitAll(_httpClient.Post(MbAdminUrl + "/service/packageReview/update", review, CancellationToken.None));
}
}
}

View File

@ -40,7 +40,7 @@ namespace MediaBrowser.Api
/// </summary> /// </summary>
[Route("/Packages", "GET", Summary = "Gets available packages")] [Route("/Packages", "GET", Summary = "Gets available packages")]
[Authenticated] [Authenticated]
public class GetPackages : IReturn<List<PackageInfo>> public class GetPackages : IReturn<PackageInfo[]>
{ {
/// <summary> /// <summary>
/// Gets or sets the name. /// Gets or sets the name.
@ -66,7 +66,7 @@ namespace MediaBrowser.Api
/// </summary> /// </summary>
[Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")] [Route("/Packages/Updates", "GET", Summary = "Gets available package updates for currently installed packages")]
[Authenticated(Roles = "Admin")] [Authenticated(Roles = "Admin")]
public class GetPackageVersionUpdates : IReturn<List<PackageVersionInfo>> public class GetPackageVersionUpdates : IReturn<PackageVersionInfo[]>
{ {
/// <summary> /// <summary>
/// Gets or sets the name. /// Gets or sets the name.
@ -148,24 +148,26 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public object Get(GetPackageVersionUpdates request) public object Get(GetPackageVersionUpdates request)
{ {
var result = new List<PackageVersionInfo>(); PackageVersionInfo[] result = null;
if (string.Equals(request.PackageType, "UserInstalled", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase)) if (string.Equals(request.PackageType, "UserInstalled", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
{ {
result.AddRange(_installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).Result.ToList()); result = _installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).Result.ToArray();
} }
else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase)) else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) ||
string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase))
{ {
var updateCheckResult = _appHost.CheckForApplicationUpdate(CancellationToken.None, new SimpleProgress<double>()).Result; var updateCheckResult = _appHost
.CheckForApplicationUpdate(CancellationToken.None, new SimpleProgress<double>()).Result;
if (updateCheckResult.IsUpdateAvailable) if (updateCheckResult.IsUpdateAvailable)
{ {
result.Add(updateCheckResult.Package); result = new PackageVersionInfo[] {updateCheckResult.Package};
} }
} }
return ToOptimizedResult(result); return ToOptimizedResult(result ?? new PackageVersionInfo[] { });
} }
/// <summary> /// <summary>
@ -176,10 +178,9 @@ namespace MediaBrowser.Api
public object Get(GetPackage request) public object Get(GetPackage request)
{ {
var packages = _installationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: _appHost.ApplicationVersion).Result; var packages = _installationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: _appHost.ApplicationVersion).Result;
var list = packages.ToList();
var result = list.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase)) var result = packages.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase))
?? list.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase)); ?? packages.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
return ToOptimizedResult(result); return ToOptimizedResult(result);
} }
@ -191,7 +192,7 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public async Task<object> Get(GetPackages request) public async Task<object> Get(GetPackages request)
{ {
var packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, _appHost.ApplicationVersion).ConfigureAwait(false); IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, _appHost.ApplicationVersion).ConfigureAwait(false);
if (!string.IsNullOrEmpty(request.TargetSystems)) if (!string.IsNullOrEmpty(request.TargetSystems))
{ {
@ -215,7 +216,7 @@ namespace MediaBrowser.Api
packages = packages.Where(p => p.enableInAppStore == request.IsAppStoreEnabled.Value); packages = packages.Where(p => p.enableInAppStore == request.IsAppStoreEnabled.Value);
} }
return ToOptimizedResult(packages.ToList()); return ToOptimizedResult(packages.ToArray());
} }
/// <summary> /// <summary>

View File

@ -1,11 +1,11 @@
using MediaBrowser.Controller.Dto; using System.Linq;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Playlists; using MediaBrowser.Model.Playlists;
using MediaBrowser.Model.Querying; using MediaBrowser.Model.Querying;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Extensions;
@ -149,7 +149,7 @@ namespace MediaBrowser.Api
var result = await _playlistManager.CreatePlaylist(new PlaylistCreationRequest var result = await _playlistManager.CreatePlaylist(new PlaylistCreationRequest
{ {
Name = request.Name, Name = request.Name,
ItemIdList = (request.Ids ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(), ItemIdList = SplitValue(request.Ids, ','),
UserId = request.UserId, UserId = request.UserId,
MediaType = request.MediaType MediaType = request.MediaType
@ -193,10 +193,8 @@ namespace MediaBrowser.Api
var dtoOptions = GetDtoOptions(_authContext, request); var dtoOptions = GetDtoOptions(_authContext, request);
var returnList = (await _dtoService.GetBaseItemDtos(items.Select(i => i.Item2), dtoOptions, user) var dtos = (await _dtoService.GetBaseItemDtos(items.Select(i => i.Item2).ToList(), dtoOptions, user)
.ConfigureAwait(false)); .ConfigureAwait(false));
var dtos = returnList
.ToArray(returnList.Count);
var index = 0; var index = 0;
foreach (var item in dtos) foreach (var item in dtos)
@ -205,7 +203,7 @@ namespace MediaBrowser.Api
index++; index++;
} }
var result = new ItemsResult var result = new QueryResult<BaseItemDto>
{ {
Items = dtos, Items = dtos,
TotalRecordCount = count TotalRecordCount = count

View File

@ -23,7 +23,7 @@ namespace MediaBrowser.Api
/// </summary> /// </summary>
[Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")] [Route("/Plugins", "GET", Summary = "Gets a list of currently installed plugins")]
[Authenticated] [Authenticated]
public class GetPlugins : IReturn<List<PluginInfo>> public class GetPlugins : IReturn<PluginInfo[]>
{ {
public bool? IsAppStoreEnabled { get; set; } public bool? IsAppStoreEnabled { get; set; }
} }
@ -195,14 +195,13 @@ namespace MediaBrowser.Api
/// <returns>System.Object.</returns> /// <returns>System.Object.</returns>
public async Task<object> Get(GetPlugins request) public async Task<object> Get(GetPlugins request)
{ {
var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToList(); var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToArray();
var requireAppStoreEnabled = request.IsAppStoreEnabled.HasValue && request.IsAppStoreEnabled.Value; var requireAppStoreEnabled = request.IsAppStoreEnabled.HasValue && request.IsAppStoreEnabled.Value;
// Don't fail just on account of image url's // Don't fail just on account of image url's
try try
{ {
var packages = (await _installationManager.GetAvailablePackagesWithoutRegistrationInfo(CancellationToken.None)) var packages = (await _installationManager.GetAvailablePackagesWithoutRegistrationInfo(CancellationToken.None));
.ToList();
foreach (var plugin in result) foreach (var plugin in result)
{ {
@ -223,7 +222,7 @@ namespace MediaBrowser.Api
return pkg != null && pkg.enableInAppStore; return pkg != null && pkg.enableInAppStore;
}) })
.ToList(); .ToArray();
} }
} }
catch catch
@ -232,7 +231,7 @@ namespace MediaBrowser.Api
// Play it safe here // Play it safe here
if (requireAppStoreEnabled) if (requireAppStoreEnabled)
{ {
result = new List<PluginInfo>(); result = new PluginInfo[] { };
} }
} }

View File

@ -533,7 +533,7 @@ namespace MediaBrowser.Api.Reports
break; break;
case HeaderMetadata.Tracks: case HeaderMetadata.Tracks:
option.Column = (i, r) => this.GetObject<MusicAlbum, List<Audio>>(i, (x) => x.Tracks.ToList(), new List<Audio>()).Count(); option.Column = (i, r) => this.GetObject<MusicAlbum, List<Audio>>(i, (x) => x.Tracks.Cast<Audio>().ToList(), new List<Audio>()).Count();
break; break;
case HeaderMetadata.Audio: case HeaderMetadata.Audio:

View File

@ -27,7 +27,7 @@ namespace MediaBrowser.Api.ScheduledTasks
/// Class GetScheduledTasks /// Class GetScheduledTasks
/// </summary> /// </summary>
[Route("/ScheduledTasks", "GET", Summary = "Gets scheduled tasks")] [Route("/ScheduledTasks", "GET", Summary = "Gets scheduled tasks")]
public class GetScheduledTasks : IReturn<List<TaskInfo>> public class GetScheduledTasks : IReturn<TaskInfo[]>
{ {
[ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "IsHidden", Description = "Optional filter tasks that are hidden, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool? IsHidden { get; set; } public bool? IsHidden { get; set; }
@ -158,7 +158,7 @@ namespace MediaBrowser.Api.ScheduledTasks
var infos = result var infos = result
.Select(ScheduledTaskHelpers.GetTaskInfo) .Select(ScheduledTaskHelpers.GetTaskInfo)
.ToList(); .ToArray();
return ToOptimizedResult(infos); return ToOptimizedResult(infos);
} }

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Drawing; using System.Linq;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
@ -7,7 +8,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Search; using MediaBrowser.Model.Search;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Services; using MediaBrowser.Model.Services;
@ -240,7 +240,7 @@ namespace MediaBrowser.Api
if (album != null) if (album != null)
{ {
result.Artists = album.Artists.ToArray(); result.Artists = album.Artists;
result.AlbumArtist = album.AlbumArtist; result.AlbumArtist = album.AlbumArtist;
} }
@ -250,7 +250,7 @@ namespace MediaBrowser.Api
{ {
result.Album = song.Album; result.Album = song.Album;
result.AlbumArtist = song.AlbumArtists.FirstOrDefault(); result.AlbumArtist = song.AlbumArtists.FirstOrDefault();
result.Artists = song.Artists.ToArray(); result.Artists = song.Artists;
} }
if (!string.IsNullOrWhiteSpace(item.ChannelId)) if (!string.IsNullOrWhiteSpace(item.ChannelId))

View File

@ -18,7 +18,7 @@ namespace MediaBrowser.Api.Session
/// </summary> /// </summary>
[Route("/Sessions", "GET", Summary = "Gets a list of sessions")] [Route("/Sessions", "GET", Summary = "Gets a list of sessions")]
[Authenticated] [Authenticated]
public class GetSessions : IReturn<List<SessionInfoDto>> public class GetSessions : IReturn<SessionInfoDto[]>
{ {
[ApiMember(Name = "ControllableByUserId", Description = "Optional. Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "ControllableByUserId", Description = "Optional. Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string ControllableByUserId { get; set; } public string ControllableByUserId { get; set; }
@ -313,14 +313,13 @@ namespace MediaBrowser.Api.Session
public void Delete(RevokeKey request) public void Delete(RevokeKey request)
{ {
var task = _sessionManager.RevokeToken(request.Key); _sessionManager.RevokeToken(request.Key);
Task.WaitAll(task);
} }
public void Post(CreateKey request) public void Post(CreateKey request)
{ {
var task = _authRepo.Create(new AuthenticationInfo _authRepo.Create(new AuthenticationInfo
{ {
AppName = request.App, AppName = request.App,
IsActive = true, IsActive = true,
@ -328,8 +327,6 @@ namespace MediaBrowser.Api.Session
DateCreated = DateTime.UtcNow DateCreated = DateTime.UtcNow
}, CancellationToken.None); }, CancellationToken.None);
Task.WaitAll(task);
} }
public void Post(ReportSessionEnded request) public void Post(ReportSessionEnded request)
@ -396,7 +393,7 @@ namespace MediaBrowser.Api.Session
}); });
} }
return ToOptimizedResult(result.Select(_sessionManager.GetSessionInfoDto).ToList()); return ToOptimizedResult(result.Select(_sessionManager.GetSessionInfoDto).ToArray());
} }
public void Post(SendPlaystateCommand request) public void Post(SendPlaystateCommand request)
@ -532,9 +529,9 @@ namespace MediaBrowser.Api.Session
} }
_sessionManager.ReportCapabilities(request.Id, new ClientCapabilities _sessionManager.ReportCapabilities(request.Id, new ClientCapabilities
{ {
PlayableMediaTypes = (request.PlayableMediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(), PlayableMediaTypes = SplitValue(request.PlayableMediaTypes, ','),
SupportedCommands = (request.SupportedCommands ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(), SupportedCommands = SplitValue(request.SupportedCommands, ','),
SupportsMediaControl = request.SupportsMediaControl, SupportsMediaControl = request.SupportsMediaControl,

View File

@ -30,7 +30,7 @@ namespace MediaBrowser.Api
public string ExcludeArtistIds { get; set; } public string ExcludeArtistIds { get; set; }
} }
public class BaseGetSimilarItems : IReturn<ItemsResult>, IHasDtoOptions public class BaseGetSimilarItems : IReturn<QueryResult<BaseItemDto>>, IHasDtoOptions
{ {
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")] [ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
public bool? EnableImages { get; set; } public bool? EnableImages { get; set; }
@ -97,18 +97,18 @@ namespace MediaBrowser.Api
var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore) var items = GetSimilaritems(item, libraryManager, inputItems, getSimilarityScore)
.ToList(); .ToList();
IEnumerable<BaseItem> returnItems = items; List<BaseItem> returnItems = items;
if (request.Limit.HasValue) if (request.Limit.HasValue)
{ {
returnItems = returnItems.Take(request.Limit.Value); returnItems = returnItems.Take(request.Limit.Value).ToList();
} }
var dtos = await dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ConfigureAwait(false); var dtos = await dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ConfigureAwait(false);
return new QueryResult<BaseItemDto> return new QueryResult<BaseItemDto>
{ {
Items = dtos.ToArray(dtos.Count), Items = dtos,
TotalRecordCount = items.Count TotalRecordCount = items.Count
}; };

View File

@ -121,8 +121,7 @@ namespace MediaBrowser.Api.Social
public void Delete(DeleteShare request) public void Delete(DeleteShare request)
{ {
var task = _sharingManager.DeleteShare(request.Id); _sharingManager.DeleteShare(request.Id);
Task.WaitAll(task);
} }
public async Task<object> Get(GetShareImage request) public async Task<object> Get(GetShareImage request)

Some files were not shown because too many files have changed in this diff Show More