Merge pull request #1082 from MediaBrowser/dev

3.0.5582.2
This commit is contained in:
Luke 2015-04-15 23:29:34 -04:00
commit 73688e3fcc
26 changed files with 415 additions and 329 deletions

View file

@ -34,7 +34,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\ImageMagickSharp.1.0.0.14\lib\net45\ImageMagickSharp.dll</HintPath> <HintPath>..\packages\ImageMagickSharp.1.0.0.15\lib\net45\ImageMagickSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@ -65,9 +65,6 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ImageMagick\UnplayedCountIndicator.cs" /> <Compile Include="ImageMagick\UnplayedCountIndicator.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="ImageMagick\fonts\MontserratLight.otf" /> <EmbeddedResource Include="ImageMagick\fonts\MontserratLight.otf" />
<EmbeddedResource Include="ImageMagick\fonts\robotoregular.ttf" /> <EmbeddedResource Include="ImageMagick\fonts\robotoregular.ttf" />
@ -87,6 +84,9 @@
<Name>MediaBrowser.Model</Name> <Name>MediaBrowser.Model</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="ImageMagickSharp" version="1.0.0.14" targetFramework="net45" /> <package id="ImageMagickSharp" version="1.0.0.15" targetFramework="net45" />
</packages> </packages>

View file

@ -156,6 +156,7 @@
<Compile Include="UserLibrary\PlaystateService.cs" /> <Compile Include="UserLibrary\PlaystateService.cs" />
<Compile Include="UserLibrary\StudiosService.cs" /> <Compile Include="UserLibrary\StudiosService.cs" />
<Compile Include="UserLibrary\UserLibraryService.cs" /> <Compile Include="UserLibrary\UserLibraryService.cs" />
<Compile Include="UserLibrary\UserViewsService.cs" />
<Compile Include="UserLibrary\YearsService.cs" /> <Compile Include="UserLibrary\YearsService.cs" />
<Compile Include="UserService.cs" /> <Compile Include="UserService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View file

@ -38,20 +38,6 @@ namespace MediaBrowser.Api.UserLibrary
public string Id { get; set; } public string Id { get; set; }
} }
[Route("/Users/{UserId}/Views", "GET")]
public class GetUserViews : IReturn<QueryResult<BaseItemDto>>
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string UserId { get; set; }
[ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
public bool? IncludeExternalContent { get; set; }
}
/// <summary> /// <summary>
/// Class GetItem /// Class GetItem
/// </summary> /// </summary>
@ -345,37 +331,6 @@ namespace MediaBrowser.Api.UserLibrary
return ToOptimizedResult(dtos.ToList()); return ToOptimizedResult(dtos.ToList());
} }
public async Task<object> Get(GetUserViews request)
{
var user = _userManager.GetUserById(request.UserId);
var query = new UserViewQuery
{
UserId = request.UserId
};
if (request.IncludeExternalContent.HasValue)
{
query.IncludeExternalContent = request.IncludeExternalContent.Value;
}
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
var dtoOptions = GetDtoOptions(request);
var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
{
Items = dtos,
TotalRecordCount = dtos.Length
};
return ToOptimizedResult(result);
}
private List<BaseItemDto> GetAsync(GetSpecialFeatures request) private List<BaseItemDto> GetAsync(GetSpecialFeatures request)
{ {
var user = _userManager.GetUserById(request.UserId); var user = _userManager.GetUserById(request.UserId);

View file

@ -0,0 +1,121 @@
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Api.UserLibrary
{
[Route("/Users/{UserId}/Views", "GET")]
public class GetUserViews : IReturn<QueryResult<BaseItemDto>>
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string UserId { get; set; }
[ApiMember(Name = "IncludeExternalContent", Description = "Whether or not to include external views such as channels or live tv", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")]
public bool? IncludeExternalContent { get; set; }
}
[Route("/Users/{UserId}/SpecialViewOptions", "GET")]
public class GetSpecialViewOptions : IReturn<List<SpecialViewOption>>
{
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string UserId { get; set; }
}
public class UserViewsService : BaseApiService
{
private readonly IUserManager _userManager;
private readonly IUserViewManager _userViewManager;
private readonly IDtoService _dtoService;
public UserViewsService(IUserManager userManager, IUserViewManager userViewManager, IDtoService dtoService)
{
_userManager = userManager;
_userViewManager = userViewManager;
_dtoService = dtoService;
}
public async Task<object> Get(GetUserViews request)
{
var query = new UserViewQuery
{
UserId = request.UserId
};
if (request.IncludeExternalContent.HasValue)
{
query.IncludeExternalContent = request.IncludeExternalContent.Value;
}
var folders = await _userViewManager.GetUserViews(query, CancellationToken.None).ConfigureAwait(false);
var dtoOptions = GetDtoOptions(request);
var user = _userManager.GetUserById(request.UserId);
var dtos = folders.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user))
.ToArray();
var result = new QueryResult<BaseItemDto>
{
Items = dtos,
TotalRecordCount = dtos.Length
};
return ToOptimizedResult(result);
}
public async Task<object> Get(GetSpecialViewOptions request)
{
var user = _userManager.GetUserById(request.UserId);
var views = user.RootFolder
.GetChildren(user, true)
.OfType<CollectionFolder>()
.Where(i => IsEligibleForSpecialView(i))
.ToList();
var list = views
.Select(i => new SpecialViewOption
{
Name = i.Name,
Id = i.Id.ToString("N")
})
.OrderBy(i => i.Name)
.ToList();
return ToOptimizedResult(list);
}
private bool IsEligibleForSpecialView(CollectionFolder view)
{
var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music };
return types.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
}
}
class SpecialViewOption
{
public string Name { get; set; }
public string Id { get; set; }
}
}

View file

@ -1894,12 +1894,12 @@ namespace MediaBrowser.Controller.Entities
return video.RefreshMetadata(newOptions, cancellationToken); return video.RefreshMetadata(newOptions, cancellationToken);
} }
public string GetEtag() public string GetEtag(User user)
{ {
return string.Join("|", GetEtagValues().ToArray()).GetMD5().ToString("N"); return string.Join("|", GetEtagValues(user).ToArray()).GetMD5().ToString("N");
} }
protected virtual List<string> GetEtagValues() protected virtual List<string> GetEtagValues(User user)
{ {
return new List<string> return new List<string>
{ {

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Entities namespace MediaBrowser.Controller.Entities
{ {
@ -9,6 +10,8 @@ namespace MediaBrowser.Controller.Entities
{ {
string CollectionType { get; } string CollectionType { get; }
string Path { get; } string Path { get; }
string Name { get; }
Guid Id { get; }
IEnumerable<string> PhysicalLocations { get; } IEnumerable<string> PhysicalLocations { get; }
} }
} }

View file

@ -247,7 +247,16 @@ namespace MediaBrowser.Controller.Entities
return GetFavoriteSongs(queryParent, user, query); return GetFavoriteSongs(queryParent, user, query);
default: default:
return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query); {
if (queryParent is UserView)
{
return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query);
}
else
{
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
}
}
} }
} }

View file

@ -2,40 +2,78 @@
using MoreLinq; using MoreLinq;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Linq; using System.Linq;
namespace MediaBrowser.Controller.Library namespace MediaBrowser.Controller.Library
{ {
public static class NameExtensions public static class NameExtensions
{ {
public static bool AreEqual(string name1, string name2) public static bool AreEqual(string x, string y)
{ {
name1 = NormalizeForComparison(name1); if (string.IsNullOrWhiteSpace(x) && string.IsNullOrWhiteSpace(y))
name2 = NormalizeForComparison(name2); {
return true;
}
return string.Equals(name1, name2, StringComparison.OrdinalIgnoreCase); return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) == 0;
} }
public static bool EqualsAny(IEnumerable<string> names, string name) public static bool EqualsAny(IEnumerable<string> names, string x)
{ {
name = NormalizeForComparison(name); x = NormalizeForComparison(x);
return names.Any(i => string.Equals(NormalizeForComparison(i), name, StringComparison.OrdinalIgnoreCase)); return names.Any(y => string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) == 0);
} }
private static string NormalizeForComparison(string name) private static string NormalizeForComparison(string name)
{ {
if (string.IsNullOrWhiteSpace(name)) if (name == null)
{ {
return string.Empty; return string.Empty;
} }
return name;
//return name.RemoveDiacritics();
}
private static string RemoveDiacritics(string name)
{
if (name == null)
{
return string.Empty;
}
//return name;
return name.RemoveDiacritics(); return name.RemoveDiacritics();
} }
public static IEnumerable<string> DistinctNames(this IEnumerable<string> names) public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
{ {
return names.DistinctBy(NormalizeForComparison, StringComparer.OrdinalIgnoreCase); return names.DistinctBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase);
}
}
class TextComparer : IComparer<string>, IEqualityComparer<string>
{
public int Compare(string x, string y)
{
if (string.IsNullOrWhiteSpace(x) && string.IsNullOrWhiteSpace(y))
{
return 0;
}
return string.Compare(x, y, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace);
}
public bool Equals(string x, string y)
{
return Compare(x, y) == 0;
}
public int GetHashCode(string obj)
{
return (obj ?? string.Empty).GetHashCode();
} }
} }
} }

View file

@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.Persistence
/// </summary> /// </summary>
/// <param name="type">The type.</param> /// <param name="type">The type.</param>
/// <returns>IEnumerable{Guid}.</returns> /// <returns>IEnumerable{Guid}.</returns>
IEnumerable<Guid> GetItemsOfType(Type type); IEnumerable<Guid> GetItemIdsOfType(Type type);
/// <summary> /// <summary>
/// Saves the children. /// Saves the children.
@ -133,6 +133,13 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken); Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
/// <summary>
/// Gets the type of the items of.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>IEnumerable&lt;BaseItem&gt;.</returns>
IEnumerable<BaseItem> GetItemsOfType(Type type);
} }
} }

View file

@ -489,32 +489,37 @@ namespace MediaBrowser.MediaEncoding.Encoder
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
var processWrapper = new ProcessWrapper(process, this); var processWrapper = new ProcessWrapper(process, this);
bool ranToCompletion;
StartProcess(processWrapper);
var memoryStream = new MemoryStream(); var memoryStream = new MemoryStream();
try
{
StartProcess(processWrapper);
#pragma warning disable 4014 #pragma warning disable 4014
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
process.StandardOutput.BaseStream.CopyToAsync(memoryStream); process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
#pragma warning restore 4014 #pragma warning restore 4014
// MUST read both stdout and stderr asynchronously or a deadlock may occurr // MUST read both stdout and stderr asynchronously or a deadlock may occurr
process.BeginErrorReadLine(); process.BeginErrorReadLine();
var ranToCompletion = process.WaitForExit(10000); ranToCompletion = process.WaitForExit(10000);
if (!ranToCompletion) if (!ranToCompletion)
{
StopProcess(processWrapper, 1000, false);
}
}
finally
{ {
StopProcess(processWrapper, 1000, false); resourcePool.Release();
} }
resourcePool.Release();
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
process.Dispose();
if (exitCode == -1 || memoryStream.Length == 0) if (exitCode == -1 || memoryStream.Length == 0)
{ {
memoryStream.Dispose(); memoryStream.Dispose();
@ -594,7 +599,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
bool ranToCompletion; bool ranToCompletion = false;
var processWrapper = new ProcessWrapper(process, this); var processWrapper = new ProcessWrapper(process, this);
@ -609,19 +614,23 @@ namespace MediaBrowser.MediaEncoding.Encoder
bool isResponsive = true; bool isResponsive = true;
int lastCount = 0; int lastCount = 0;
while (isResponsive && !process.WaitForExit(30000)) while (isResponsive)
{ {
if (process.WaitForExit(30000))
{
ranToCompletion = true;
break;
}
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
int jpegCount = Directory.GetFiles(targetDirectory) var jpegCount = Directory.GetFiles(targetDirectory)
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase)); .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
isResponsive = (jpegCount > lastCount); isResponsive = (jpegCount > lastCount);
lastCount = jpegCount; lastCount = jpegCount;
} }
ranToCompletion = process.HasExited;
if (!ranToCompletion) if (!ranToCompletion)
{ {
StopProcess(processWrapper, 1000, false); StopProcess(processWrapper, 1000, false);
@ -634,8 +643,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
process.Dispose();
if (exitCode == -1) if (exitCode == -1)
{ {
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument); var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);

View file

@ -49,7 +49,7 @@ namespace MediaBrowser.Model.Configuration
/// </summary> /// </summary>
/// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value> /// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value>
public bool EnableUserSpecificUserViews { get; set; } public bool EnableUserSpecificUserViews { get; set; }
/// <summary> /// <summary>
/// Gets or sets the value pointing to the file system where the ssl certiifcate is located.. /// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
/// </summary> /// </summary>

View file

@ -46,6 +46,7 @@ namespace MediaBrowser.Model.Configuration
public bool EnableCinemaMode { get; set; } public bool EnableCinemaMode { get; set; }
public string[] LatestItemsExcludes { get; set; } public string[] LatestItemsExcludes { get; set; }
public string[] PlainFolderViews { get; set; }
public bool HidePlayedInLatest { get; set; } public bool HidePlayedInLatest { get; set; }
@ -62,6 +63,7 @@ namespace MediaBrowser.Model.Configuration
DisplayChannelsWithinViews = new string[] { }; DisplayChannelsWithinViews = new string[] { };
ExcludeFoldersFromGrouping = new string[] { }; ExcludeFoldersFromGrouping = new string[] { };
PlainFolderViews = new string[] { };
DisplayCollectionsView = true; DisplayCollectionsView = true;
IncludeTrailersInSuggestions = true; IncludeTrailersInSuggestions = true;

View file

@ -1,153 +0,0 @@
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Providers.Genres;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Providers.FolderImages
{
public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
{
private readonly IHttpClient _httpClient;
public DefaultImageProvider(IHttpClient httpClient)
{
_httpClient = httpClient;
}
public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
{
return new List<ImageType>
{
ImageType.Primary,
ImageType.Thumb
};
}
public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
{
var view = item as UserView;
if (view != null)
{
return GetImages(view.ViewType, view.ParentId != Guid.Empty, cancellationToken);
}
var folder = (ICollectionFolder)item;
return GetImages(folder.CollectionType, false, cancellationToken);
}
private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, bool isSubView, CancellationToken cancellationToken)
{
var url = GetImageUrl(viewType, isSubView);
var list = new List<RemoteImageInfo>();
if (!string.IsNullOrWhiteSpace(url))
{
list.AddRange(new List<RemoteImageInfo>
{
new RemoteImageInfo
{
ProviderName = Name,
Url = url,
Type = ImageType.Primary
},
new RemoteImageInfo
{
ProviderName = Name,
Url = url,
Type = ImageType.Thumb
}
});
}
return Task.FromResult<IEnumerable<RemoteImageInfo>>(list);
}
private string GetImageUrl(string viewType, bool isSubView)
{
const string urlPrefix = "https://raw.githubusercontent.com/MediaBrowser/MediaBrowser.Resources/master/images/folders/";
if (string.Equals(viewType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (string.Equals(viewType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (string.Equals(viewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (string.Equals(viewType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (string.Equals(viewType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (string.Equals(viewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (string.Equals(viewType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
return null;
}
if (isSubView)
{
return null;
}
return urlPrefix + "generic.png";
}
public string Name
{
get { return "Default Image Provider"; }
}
public bool Supports(IHasImages item)
{
return item is ICollectionFolder || item is UserView;
}
public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
{
return _httpClient.GetResponse(new HttpRequestOptions
{
CancellationToken = cancellationToken,
Url = url,
ResourcePool = GenreImageProvider.ImageDownloadResourcePool
});
}
public bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService)
{
return GetSupportedImages(item).Any(i => !item.HasImage(i));
}
public int Order
{
get
{
// Run after the dynamic image provider
return 1;
}
}
}
}

View file

@ -83,7 +83,6 @@
<Compile Include="BoxSets\MovieDbBoxSetProvider.cs" /> <Compile Include="BoxSets\MovieDbBoxSetProvider.cs" />
<Compile Include="Channels\ChannelMetadataService.cs" /> <Compile Include="Channels\ChannelMetadataService.cs" />
<Compile Include="Chapters\ChapterManager.cs" /> <Compile Include="Chapters\ChapterManager.cs" />
<Compile Include="FolderImages\DefaultImageProvider.cs" />
<Compile Include="Folders\FolderMetadataService.cs" /> <Compile Include="Folders\FolderMetadataService.cs" />
<Compile Include="Channels\AudioChannelItemMetadataService.cs" /> <Compile Include="Channels\AudioChannelItemMetadataService.cs" />
<Compile Include="Folders\UserViewMetadataService.cs" /> <Compile Include="Folders\UserViewMetadataService.cs" />

View file

@ -6,6 +6,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -20,13 +21,15 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly IMediaEncoder _mediaEncoder; private readonly IMediaEncoder _mediaEncoder;
private readonly IServerConfigurationManager _config; private readonly IServerConfigurationManager _config;
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager) public VideoImageProvider(IIsoManager isoManager, IMediaEncoder mediaEncoder, IServerConfigurationManager config, ILibraryManager libraryManager, ILogger logger)
{ {
_isoManager = isoManager; _isoManager = isoManager;
_mediaEncoder = mediaEncoder; _mediaEncoder = mediaEncoder;
_config = config; _config = config;
_libraryManager = libraryManager; _libraryManager = libraryManager;
_logger = logger;
} }
/// <summary> /// <summary>
@ -74,6 +77,7 @@ namespace MediaBrowser.Providers.MediaInfo
// Can't extract if we didn't find a video stream in the file // Can't extract if we didn't find a video stream in the file
if (!video.DefaultVideoStreamIndex.HasValue) if (!video.DefaultVideoStreamIndex.HasValue)
{ {
_logger.Debug("Skipping image extraction due to missing DefaultVideoStreamIndex for {0}.", video.Path ?? string.Empty);
return Task.FromResult(new DynamicImageResponse { HasImage = false }); return Task.FromResult(new DynamicImageResponse { HasImage = false });
} }

View file

@ -357,7 +357,10 @@ namespace MediaBrowser.Server.Implementations.Dto
: item.CanDownload(user); : item.CanDownload(user);
} }
if (fields.Contains(ItemFields.Etag))
{
dto.Etag = item.GetEtag(user);
}
return dto; return dto;
} }

View file

@ -1678,11 +1678,6 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("name"); throw new ArgumentNullException("name");
} }
if (string.IsNullOrWhiteSpace(viewType))
{
throw new ArgumentNullException("viewType");
}
var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView)); var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView));
var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N")); var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
@ -1716,6 +1711,12 @@ namespace MediaBrowser.Server.Implementations.Library
isNew = true; isNew = true;
} }
if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase))
{
item.ViewType = viewType;
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
}
var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 12; var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 12;
if (refresh) if (refresh)

View file

@ -53,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.Library
.ToList(); .ToList();
var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList(); var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
var plainFolderIds = user.Configuration.PlainFolderViews.Select(i => new Guid(i)).ToList();
var standaloneFolders = folders var standaloneFolders = folders
.Where(i => UserView.IsExcludedFromGrouping(i) || excludeFolderIds.Contains(i.Id)) .Where(i => UserView.IsExcludedFromGrouping(i) || excludeFolderIds.Contains(i.Id))
@ -72,13 +73,17 @@ namespace MediaBrowser.Server.Implementations.Library
var collectionFolder = folder as ICollectionFolder; var collectionFolder = folder as ICollectionFolder;
var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType; var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
if (string.IsNullOrWhiteSpace(folderViewType)) if (plainFolderIds.Contains(folder.Id))
{ {
list.Add(folder); list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, false, string.Empty, user, cancellationToken).ConfigureAwait(false));
}
else if (!string.IsNullOrWhiteSpace(folderViewType))
{
list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, true, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
else else
{ {
list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, string.Empty, user, cancellationToken).ConfigureAwait(false)); list.Add(folder);
} }
} }
} }
@ -87,44 +92,57 @@ namespace MediaBrowser.Server.Implementations.Library
list.AddRange(standaloneFolders); list.AddRange(standaloneFolders);
} }
if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) || var parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType))) .ToList();
if (parents.Count > 0)
{ {
list.Add(await GetUserView(CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false)); list.Add(await GetUserView(parents, CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) || parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase) || string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))) .ToList();
if (parents.Count > 0)
{ {
list.Add(await GetUserView(CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false)); list.Add(await GetUserView(parents, CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) || parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || string.IsNullOrWhiteSpace(i.CollectionType))
foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType))) .ToList();
if (parents.Count > 0)
{ {
list.Add(await GetUserView(CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false)); list.Add(await GetUserView(parents, CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))) parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
.ToList();
if (parents.Count > 0)
{ {
list.Add(await GetUserView(CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false)); list.Add(await GetUserView(parents, CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))) parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase))
.ToList();
if (parents.Count > 0)
{ {
//list.Add(_collectionManager.GetCollectionsFolder(user.Id.ToString("N"))); list.Add(await GetUserView(parents, CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))) parents = foldersWithViewTypes.Where(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
.ToList();
if (parents.Count > 0)
{ {
//list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N"))); list.Add(await GetUserView(parents, CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
if (user.Configuration.DisplayFoldersView) if (user.Configuration.DisplayFoldersView)
{ {
list.Add(await GetUserView(CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false)); list.Add(await GetUserView(new List<ICollectionFolder>(), CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false));
} }
if (query.IncludeExternalContent) if (query.IncludeExternalContent)
@ -151,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Library
if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId)) if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId))
{ {
//list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false)); //list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false));
list.Add(await GetUserView(CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false)); list.Add(await GetUserView(new List<ICollectionFolder>(), CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false));
} }
} }
@ -182,16 +200,42 @@ namespace MediaBrowser.Server.Implementations.Library
return GetUserSubView(name, parentId, type, user, sortName, cancellationToken); return GetUserSubView(name, parentId, type, user, sortName, cancellationToken);
} }
public Task<UserView> GetUserView(string type, string sortName, User user, CancellationToken cancellationToken) public async Task<UserView> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, CancellationToken cancellationToken)
{ {
var name = _localizationManager.GetLocalizedString("ViewType" + type); if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
{
var name = parents[0].Name;
var parentId = parents[0].Id;
return _libraryManager.GetNamedView(user, name, type, sortName, cancellationToken); var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase);
if (_config.Configuration.EnableUserSpecificUserViews)
{
viewType = enableRichView ? viewType : null;
var view = await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
if (view.ParentId != parentId)
{
view.ParentId = parentId;
await view.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
}
return view;
}
viewType = enableRichView ? viewType : CollectionType.Folders;
return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
}
else
{
var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
}
} }
public Task<UserView> GetUserView(Guid parentId, string name, string type, string sortName, User user, CancellationToken cancellationToken) public Task<UserView> GetUserView(Guid parentId, string name, string viewType, bool enableRichView, string sortName, User user, CancellationToken cancellationToken)
{ {
return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), type, sortName, cancellationToken); return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), viewType, sortName, cancellationToken);
} }
public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request) public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
@ -317,7 +361,7 @@ namespace MediaBrowser.Server.Implementations.Library
.RootFolder .RootFolder
.GetRecursiveChildren(filter); .GetRecursiveChildren(filter);
} }
private IEnumerable<BaseItem> GetItemsConfiguredForLatest(User user, Func<BaseItem, bool> filter) private IEnumerable<BaseItem> GetItemsConfiguredForLatest(User user, Func<BaseItem, bool> filter)
{ {
// Avoid implicitly captured closure // Avoid implicitly captured closure

View file

@ -54,11 +54,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
new ConcurrentDictionary<string, LiveStreamData>(); new ConcurrentDictionary<string, LiveStreamData>();
private List<Guid> _channelIdList = new List<Guid>(); private List<Guid> _channelIdList = new List<Guid>();
private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>(); private Dictionary<Guid, LiveTvProgram> _programs;
private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>(); private readonly ConcurrentDictionary<Guid, bool> _refreshedPrograms = new ConcurrentDictionary<Guid, bool>();
private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager) public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager)
{ {
_config = config; _config = config;
@ -109,6 +107,37 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>(); _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
} }
private readonly object _programsDataLock = new object();
private Dictionary<Guid, LiveTvProgram> GetProgramsDictionary()
{
if (_programs == null)
{
lock (_programsDataLock)
{
if (_programs == null)
{
var dict = new Dictionary<Guid, LiveTvProgram>();
foreach (var item in _itemRepo.GetItemsOfType(typeof (LiveTvProgram))
.Cast<LiveTvProgram>()
.ToList())
{
dict[item.Id] = item;
}
_programs = dict;
}
}
}
return _programs;
}
private IEnumerable<LiveTvProgram> GetPrograms()
{
return GetProgramsDictionary().Values;
}
public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken) public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken)
{ {
var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
@ -260,7 +289,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
LiveTvProgram obj = null; LiveTvProgram obj = null;
_programs.TryGetValue(guid, out obj); GetProgramsDictionary().TryGetValue(guid, out obj);
if (obj != null) if (obj != null)
{ {
@ -597,7 +626,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
item.ProductionYear = info.ProductionYear; item.ProductionYear = info.ProductionYear;
item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate;
await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
return item; return item;
@ -691,7 +720,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken) public async Task<QueryResult<ProgramInfoDto>> GetPrograms(ProgramQuery query, CancellationToken cancellationToken)
{ {
IEnumerable<LiveTvProgram> programs = _programs.Values; IEnumerable<LiveTvProgram> programs = GetPrograms();
if (query.MinEndDate.HasValue) if (query.MinEndDate.HasValue)
{ {
@ -806,7 +835,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken) public async Task<QueryResult<LiveTvProgram>> GetRecommendedProgramsInternal(RecommendedProgramQuery query, CancellationToken cancellationToken)
{ {
IEnumerable<LiveTvProgram> programs = _programs.Values; IEnumerable<LiveTvProgram> programs = GetPrograms();
var user = _userManager.GetUserById(query.UserId); var user = _userManager.GetUserById(query.UserId);
@ -995,24 +1024,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken) internal async Task RefreshChannels(IProgress<double> progress, CancellationToken cancellationToken)
{ {
await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); var innerProgress = new ActionableProgress<double>();
innerProgress.RegisterAction(p => progress.Report(p * .9));
await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false);
try innerProgress = new ActionableProgress<double>();
{ innerProgress.RegisterAction(p => progress.Report(90 + (p * .1)));
var innerProgress = new ActionableProgress<double>(); await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false);
innerProgress.RegisterAction(p => progress.Report(p * .9));
await RefreshChannelsInternal(innerProgress, cancellationToken).ConfigureAwait(false);
innerProgress = new ActionableProgress<double>(); RefreshIfNeeded(GetPrograms().Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1).ToList());
innerProgress.RegisterAction(p => progress.Report(90 + (p * .1)));
await CleanDatabaseInternal(progress, cancellationToken).ConfigureAwait(false);
RefreshIfNeeded(_programs.Values.Where(i => (i.StartDate - DateTime.UtcNow).TotalDays <= 1).ToList());
}
finally
{
_refreshSemaphore.Release();
}
} }
private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken) private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken)
@ -1136,7 +1156,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
progress.Report(80 * percent + 10); progress.Report(80 * percent + 10);
} }
_programs = programs.ToDictionary(i => i.Id); lock (_programsDataLock)
{
_programs = programs.ToDictionary(i => i.Id);
}
_refreshedPrograms.Clear(); _refreshedPrograms.Clear();
progress.Report(90); progress.Report(90);
@ -1147,28 +1171,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
progress.Report(100); progress.Report(100);
} }
public async Task CleanDatabase(IProgress<double> progress, CancellationToken cancellationToken)
{
await _refreshSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
await DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken).ConfigureAwait(false);
}
finally
{
_refreshSemaphore.Release();
}
}
private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken) private Task CleanDatabaseInternal(IProgress<double> progress, CancellationToken cancellationToken)
{ {
return DeleteOldPrograms(_programs.Keys.ToList(), progress, cancellationToken); return DeleteOldPrograms(GetProgramsDictionary().Keys.ToList(), progress, cancellationToken);
} }
private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken) private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken)
{ {
var list = _itemRepo.GetItemsOfType(typeof(LiveTvProgram)).ToList(); var list = _itemRepo.GetItemIdsOfType(typeof(LiveTvProgram)).ToList();
var numComplete = 0; var numComplete = 0;
@ -1549,7 +1559,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{ {
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var program = _programs.Values var program = GetPrograms()
.Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase)) .Where(i => string.Equals(externalChannelId, i.ExternalChannelId, StringComparison.OrdinalIgnoreCase))
.OrderBy(i => i.StartDate) .OrderBy(i => i.StartDate)
.SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue)) .SkipWhile(i => now >= (i.EndDate ?? DateTime.MinValue))
@ -1742,7 +1752,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{ {
var dtoOptions = new DtoOptions(); var dtoOptions = new DtoOptions();
dtoOptions.Fields.Remove(ItemFields.SyncInfo); dtoOptions.Fields.Remove(ItemFields.SyncInfo);
var recordingResult = await GetRecordings(new RecordingQuery var recordingResult = await GetRecordings(new RecordingQuery
{ {
UserId = query.UserId UserId = query.UserId
@ -1855,13 +1865,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv
public GuideInfo GetGuideInfo() public GuideInfo GetGuideInfo()
{ {
var programs = _programs.ToList(); var programs = GetPrograms().OrderBy(i => i.StartDate).ToList();
var startDate = _programs.Count == 0 ? DateTime.MinValue : var startDate = programs.Count == 0 ?
programs.Select(i => i.Value.StartDate).Min(); DateTime.MinValue :
programs[0].StartDate;
var endDate = programs.Count == 0 ? DateTime.MinValue : var endDate = programs.Count == 0 ?
programs.Select(i => i.Value.StartDate).Max(); DateTime.MinValue :
programs[programs.Count - 1].StartDate;
return new GuideInfo return new GuideInfo
{ {

View file

@ -1430,5 +1430,8 @@
"ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.", "ButtonMyPreferencesWelcomeNo": "No thanks, I'll do it later.",
"MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.", "MyPreferencesWelcomeMessage1": "We've presented your library in a way we think you'll enjoy. The appearance and grouping of content can be changed anytime by adjusting your preferences. Your preferences will apply to all Emby apps.",
"MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?", "MyPreferencesWelcomeMessage2": "Would you like to set your preferences now?",
"ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences." "ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
"HeaderViewStyles": "View Styles",
"LabelSelectViewStyles": "Enable rich presentations for:",
"LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
} }

View file

@ -522,7 +522,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
} }
} }
public IEnumerable<Guid> GetItemsOfType(Type type) public IEnumerable<BaseItem> GetItemsOfType(Type type)
{ {
if (type == null) if (type == null)
{ {
@ -530,7 +530,37 @@ namespace MediaBrowser.Server.Implementations.Persistence
} }
CheckDisposed(); CheckDisposed();
using (var cmd = _connection.CreateCommand())
{
cmd.CommandText = "select type,data from TypedBaseItems where type = @type";
cmd.Parameters.Add(cmd, "@type", DbType.String).Value = type.FullName;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
{
while (reader.Read())
{
var item = GetItem(reader);
if (item != null)
{
yield return item;
}
}
}
}
}
public IEnumerable<Guid> GetItemIdsOfType(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
CheckDisposed();
using (var cmd = _connection.CreateCommand()) using (var cmd = _connection.CreateCommand())
{ {
cmd.CommandText = "select guid from TypedBaseItems where type = @type"; cmd.CommandText = "select guid from TypedBaseItems where type = @type";

View file

@ -205,7 +205,7 @@ namespace MediaBrowser.Server.Implementations.Sync
{ {
Condition = ProfileConditionType.LessThanEqual, Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels, Property = ProfileConditionValue.AudioChannels,
Value = "5", Value = "6",
IsRequired = false IsRequired = false
}, },
new ProfileCondition new ProfileCondition

View file

@ -62,7 +62,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\ImageMagickSharp.1.0.0.14\lib\net45\ImageMagickSharp.dll</HintPath> <HintPath>..\packages\ImageMagickSharp.1.0.0.15\lib\net45\ImageMagickSharp.dll</HintPath>
</Reference> </Reference>
<Reference Include="MediaBrowser.IsoMounter"> <Reference Include="MediaBrowser.IsoMounter">
<HintPath>..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll</HintPath> <HintPath>..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll</HintPath>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="ImageMagickSharp" version="1.0.0.14" targetFramework="net45" /> <package id="ImageMagickSharp" version="1.0.0.15" targetFramework="net45" />
<package id="MediaBrowser.IsoMounting" version="3.0.69" targetFramework="net45" /> <package id="MediaBrowser.IsoMounting" version="3.0.69" targetFramework="net45" />
<package id="System.Data.SQLite.Core" version="1.0.94.0" targetFramework="net45" /> <package id="System.Data.SQLite.Core" version="1.0.94.0" targetFramework="net45" />
</packages> </packages>

View file

@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
//[assembly: AssemblyVersion("3.0.*")] //[assembly: AssemblyVersion("3.0.*")]
[assembly: AssemblyVersion("3.0.5582.1")] [assembly: AssemblyVersion("3.0.5582.2")]