add cinema mode feature
This commit is contained in:
parent
ac201a6cdb
commit
1afb28b487
|
@ -314,17 +314,16 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <param name="deleteFiles">The delete files.</param>
|
||||
/// <param name="acquireLock">if set to <c>true</c> [acquire lock].</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="ArgumentNullException">deviceId</exception>
|
||||
internal Task KillTranscodingJobs(string deviceId, Func<string, bool> deleteFiles, bool acquireLock)
|
||||
internal Task KillTranscodingJobs(string deviceId, Func<string, bool> deleteFiles)
|
||||
{
|
||||
if (string.IsNullOrEmpty(deviceId))
|
||||
{
|
||||
throw new ArgumentNullException("deviceId");
|
||||
}
|
||||
|
||||
return KillTranscodingJobs(j => string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase), deleteFiles, acquireLock);
|
||||
return KillTranscodingJobs(j => string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase), deleteFiles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -332,9 +331,8 @@ namespace MediaBrowser.Api
|
|||
/// </summary>
|
||||
/// <param name="killJob">The kill job.</param>
|
||||
/// <param name="deleteFiles">The delete files.</param>
|
||||
/// <param name="acquireLock">if set to <c>true</c> [acquire lock].</param>
|
||||
/// <returns>Task.</returns>
|
||||
internal async Task KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles, bool acquireLock)
|
||||
internal async Task KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles)
|
||||
{
|
||||
var jobs = new List<TranscodingJob>();
|
||||
|
||||
|
@ -350,10 +348,7 @@ namespace MediaBrowser.Api
|
|||
return;
|
||||
}
|
||||
|
||||
if (acquireLock)
|
||||
{
|
||||
await TranscodingStartLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
await TranscodingStartLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -364,10 +359,7 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
finally
|
||||
{
|
||||
if (acquireLock)
|
||||
{
|
||||
TranscodingStartLock.Release();
|
||||
}
|
||||
TranscodingStartLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
// If the playlist doesn't already exist, startup ffmpeg
|
||||
try
|
||||
{
|
||||
await ApiEntryPoint.Instance.KillTranscodingJobs(j => j.Type == TranscodingJobType.Hls && string.Equals(j.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase), p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase), false).ConfigureAwait(false);
|
||||
await ApiEntryPoint.Instance.KillTranscodingJobs(j => j.Type == TranscodingJobType.Hls && string.Equals(j.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase), p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase)).ConfigureAwait(false);
|
||||
|
||||
if (currentTranscodingIndex.HasValue)
|
||||
{
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
public void Delete(StopEncodingProcess request)
|
||||
{
|
||||
var task = ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, path => true, true);
|
||||
var task = ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, path => true);
|
||||
|
||||
Task.WaitAll(task);
|
||||
}
|
||||
|
|
|
@ -566,13 +566,13 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>System.Object.</returns>
|
||||
public object Get(GetIntros request)
|
||||
public async Task<object> Get(GetIntros request)
|
||||
{
|
||||
var user = _userManager.GetUserById(request.UserId);
|
||||
|
||||
var item = string.IsNullOrEmpty(request.Id) ? user.RootFolder : _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var items = _libraryManager.GetIntros(item, user);
|
||||
var items = await _libraryManager.GetIntros(item, user).ConfigureAwait(false);
|
||||
|
||||
// Get everything
|
||||
var fields = Enum.GetNames(typeof(ItemFields))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
@ -54,6 +55,28 @@ namespace MediaBrowser.Common.Extensions
|
|||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the accent.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public static string RemoveAccent(this string text)
|
||||
{
|
||||
var normalizedString = text.Normalize(NormalizationForm.FormD);
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
foreach (var c in normalizedString)
|
||||
{
|
||||
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
|
||||
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
|
||||
{
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the M d5.
|
||||
/// </summary>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
@ -9,7 +10,7 @@ using System.Linq;
|
|||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public class ChannelVideoItem : Video, IChannelMediaItem
|
||||
public class ChannelVideoItem : Video, IChannelMediaItem, IHasLookupInfo<ChannelItemLookupInfo>
|
||||
{
|
||||
public string ExternalId { get; set; }
|
||||
|
||||
|
@ -87,5 +88,14 @@ namespace MediaBrowser.Controller.Channels
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
public ChannelItemLookupInfo GetLookupInfo()
|
||||
{
|
||||
var info = GetItemLookupInfo<ChannelItemLookupInfo>();
|
||||
|
||||
info.ContentType = ContentType;
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,14 @@ namespace MediaBrowser.Controller.Channels
|
|||
/// <returns>Task{QueryResult{BaseItemDto}}.</returns>
|
||||
Task<QueryResult<BaseItemDto>> GetChannels(ChannelQuery query, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all media internal.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task<QueryResult<BaseItem>>.</returns>
|
||||
Task<QueryResult<BaseItem>> GetAllMediaInternal(AllChannelMediaQuery query, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all media.
|
||||
/// </summary>
|
||||
|
|
|
@ -5,8 +5,6 @@ namespace MediaBrowser.Controller.Channels
|
|||
{
|
||||
public interface IChannelMediaItem : IChannelItem
|
||||
{
|
||||
bool IsInfiniteStream { get; set; }
|
||||
|
||||
long? RunTimeTicks { get; set; }
|
||||
string MediaType { get; }
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
public string Container { get; set; }
|
||||
public int? TotalBitrate { get; set; }
|
||||
public List<string> Tags { get; set; }
|
||||
public ExtraType ExtraType { get; set; }
|
||||
|
||||
public bool IsThemeMedia { get; set; }
|
||||
|
||||
|
|
|
@ -41,16 +41,25 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <summary>
|
||||
/// The supported image extensions
|
||||
/// </summary>
|
||||
public static readonly string[] SupportedImageExtensions = new[] { ".png", ".jpg", ".jpeg", ".tbn" };
|
||||
public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn" };
|
||||
|
||||
/// <summary>
|
||||
/// The trailer folder name
|
||||
/// </summary>
|
||||
public const string TrailerFolderName = "trailers";
|
||||
public const string ThemeSongsFolderName = "theme-music";
|
||||
public const string ThemeSongFilename = "theme";
|
||||
public const string ThemeVideosFolderName = "backdrops";
|
||||
public const string XbmcTrailerFileSuffix = "-trailer";
|
||||
public static string TrailerFolderName = "trailers";
|
||||
public static string ThemeSongsFolderName = "theme-music";
|
||||
public static string ThemeSongFilename = "theme";
|
||||
public static string ThemeVideosFolderName = "backdrops";
|
||||
|
||||
public static List<KeyValuePair<string, ExtraType>> ExtraSuffixes = new List<KeyValuePair<string, ExtraType>>
|
||||
{
|
||||
new KeyValuePair<string,ExtraType>("-trailer", ExtraType.Trailer),
|
||||
new KeyValuePair<string,ExtraType>("-deleted", ExtraType.DeletedScene),
|
||||
new KeyValuePair<string,ExtraType>("-behindthescenes", ExtraType.BehindTheScenes),
|
||||
new KeyValuePair<string,ExtraType>("-interview", ExtraType.Interview),
|
||||
new KeyValuePair<string,ExtraType>("-scene", ExtraType.Scene),
|
||||
new KeyValuePair<string,ExtraType>("-sample", ExtraType.Sample)
|
||||
};
|
||||
|
||||
public List<ItemImageInfo> ImageInfos { get; set; }
|
||||
|
||||
|
@ -167,7 +176,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
// Local trailer, special feature, theme video, etc.
|
||||
// An item that belongs to another item but is not part of the Parent-Child tree
|
||||
return !IsFolder && Parent == null;
|
||||
return !IsFolder && Parent == null && LocationType == LocationType.FileSystem;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,11 +561,24 @@ namespace MediaBrowser.Controller.Entities
|
|||
.Where(i => string.Equals(i.Name, TrailerFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
.SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
|
||||
.ToList();
|
||||
|
||||
// Support plex/xbmc convention
|
||||
|
||||
var extraTypes = new List<ExtraType> { ExtraType.Trailer };
|
||||
var suffixes = ExtraSuffixes.Where(i => extraTypes.Contains(i.Value))
|
||||
.Select(i => i.Key)
|
||||
.ToList();
|
||||
|
||||
files.AddRange(fileSystemChildren.OfType<FileInfo>()
|
||||
.Where(i => FileSystem.GetFileNameWithoutExtension(i).EndsWith(XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) && !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase))
|
||||
);
|
||||
.Where(i =>
|
||||
{
|
||||
var nameEithoutExtension = FileSystem.GetFileNameWithoutExtension(i);
|
||||
|
||||
if (!suffixes.Any(s => nameEithoutExtension.EndsWith(s, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase);
|
||||
}));
|
||||
|
||||
return LibraryManager.ResolvePaths<Trailer>(files, directoryService, null).Select(video =>
|
||||
{
|
||||
|
@ -568,12 +590,79 @@ namespace MediaBrowser.Controller.Entities
|
|||
video = dbItem;
|
||||
}
|
||||
|
||||
if (video != null)
|
||||
{
|
||||
video.ExtraType = ExtraType.Trailer;
|
||||
}
|
||||
|
||||
return video;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
}).OrderBy(i => i.Path).ToList();
|
||||
}
|
||||
|
||||
protected IEnumerable<Video> LoadSpecialFeatures(List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
|
||||
{
|
||||
var files = fileSystemChildren.OfType<DirectoryInfo>()
|
||||
.Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase))
|
||||
.SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly))
|
||||
.ToList();
|
||||
|
||||
var extraTypes = new List<ExtraType> { ExtraType.BehindTheScenes, ExtraType.DeletedScene, ExtraType.Interview, ExtraType.Sample, ExtraType.Scene, ExtraType.Clip };
|
||||
var suffixes = ExtraSuffixes.Where(i => extraTypes.Contains(i.Value))
|
||||
.Select(i => i.Key)
|
||||
.ToList();
|
||||
|
||||
files.AddRange(fileSystemChildren.OfType<FileInfo>()
|
||||
.Where(i =>
|
||||
{
|
||||
var nameEithoutExtension = FileSystem.GetFileNameWithoutExtension(i);
|
||||
|
||||
if (!suffixes.Any(s => nameEithoutExtension.EndsWith(s, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !string.Equals(Path, i.FullName, StringComparison.OrdinalIgnoreCase);
|
||||
}));
|
||||
|
||||
return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video =>
|
||||
{
|
||||
// Try to retrieve it from the db. If we don't find it, use the resolved version
|
||||
var dbItem = LibraryManager.GetItemById(video.Id) as Video;
|
||||
|
||||
if (dbItem != null)
|
||||
{
|
||||
video = dbItem;
|
||||
}
|
||||
|
||||
if (video != null)
|
||||
{
|
||||
SetExtraTypeFromFilename(video);
|
||||
}
|
||||
|
||||
return video;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
}).OrderBy(i => i.Path).ToList();
|
||||
}
|
||||
|
||||
private void SetExtraTypeFromFilename(Video item)
|
||||
{
|
||||
var name = System.IO.Path.GetFileNameWithoutExtension(item.Path) ?? string.Empty;
|
||||
|
||||
foreach (var suffix in ExtraSuffixes)
|
||||
{
|
||||
if (name.EndsWith(suffix.Key, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.ExtraType = suffix.Value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
item.ExtraType = ExtraType.Clip;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the theme songs.
|
||||
/// </summary>
|
||||
|
@ -600,6 +689,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
audio = dbItem;
|
||||
}
|
||||
|
||||
if (audio != null)
|
||||
{
|
||||
audio.ExtraType = ExtraType.ThemeSong;
|
||||
}
|
||||
|
||||
return audio;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
|
@ -626,6 +720,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
item = dbItem;
|
||||
}
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
item.ExtraType = ExtraType.ThemeVideo;
|
||||
}
|
||||
|
||||
return item;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
|
|
|
@ -25,16 +25,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
var current = item.RemoteTrailers.FirstOrDefault(i => string.Equals(i.Url, url, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (current != null)
|
||||
{
|
||||
current.IsDirectLink = isDirectLink;
|
||||
}
|
||||
else
|
||||
if (current == null)
|
||||
{
|
||||
item.RemoteTrailers.Add(new MediaUrl
|
||||
{
|
||||
Url = url,
|
||||
IsDirectLink = isDirectLink
|
||||
Url = url
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
return hasChanges;
|
||||
}
|
||||
|
||||
private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, IEnumerable<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
|
||||
private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemInfo> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var newItems = LoadSpecialFeatures(fileSystemChildren, options.DirectoryService).ToList();
|
||||
var newItemIds = newItems.Select(i => i.Id).ToList();
|
||||
|
@ -141,32 +141,6 @@ namespace MediaBrowser.Controller.Entities.Movies
|
|||
return itemsChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the special features.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{Video}.</returns>
|
||||
private IEnumerable<Video> LoadSpecialFeatures(IEnumerable<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
|
||||
{
|
||||
var files = fileSystemChildren.OfType<DirectoryInfo>()
|
||||
.Where(i => string.Equals(i.Name, "extras", StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, "specials", StringComparison.OrdinalIgnoreCase))
|
||||
.SelectMany(i => i.EnumerateFiles("*", SearchOption.TopDirectoryOnly));
|
||||
|
||||
return LibraryManager.ResolvePaths<Video>(files, directoryService, null).Select(video =>
|
||||
{
|
||||
// Try to retrieve it from the db. If we don't find it, use the resolved version
|
||||
var dbItem = LibraryManager.GetItemById(video.Id) as Video;
|
||||
|
||||
if (dbItem != null)
|
||||
{
|
||||
video = dbItem;
|
||||
}
|
||||
|
||||
return video;
|
||||
|
||||
// Sort them so that the list can be easily compared for changes
|
||||
}).OrderBy(i => i.Path).ToList();
|
||||
}
|
||||
|
||||
protected override bool GetBlockUnratedValue(UserConfiguration config)
|
||||
{
|
||||
return config.BlockUnratedItems.Contains(UnratedItem.Movie);
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
public string Container { get; set; }
|
||||
public int? TotalBitrate { get; set; }
|
||||
public string ShortOverview { get; set; }
|
||||
public ExtraType ExtraType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
|
@ -14,12 +15,18 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="item">The item.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
IEnumerable<IntroInfo> GetIntros(BaseItem item, User user);
|
||||
Task<IEnumerable<IntroInfo>> GetIntros(BaseItem item, User user);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all intro files.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
IEnumerable<string> GetAllIntroFiles();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ namespace MediaBrowser.Controller.Library
|
|||
/// <param name="item">The item.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
IEnumerable<Video> GetIntros(BaseItem item, User user);
|
||||
Task<IEnumerable<Video>> GetIntros(BaseItem item, User user);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all intro files.
|
||||
|
|
|
@ -234,6 +234,7 @@
|
|||
<Compile Include="Providers\DirectoryService.cs" />
|
||||
<Compile Include="Providers\ICustomMetadataProvider.cs" />
|
||||
<Compile Include="Providers\IExternalId.cs" />
|
||||
<Compile Include="Providers\IExtrasProvider.cs" />
|
||||
<Compile Include="Providers\IForcedProvider.cs" />
|
||||
<Compile Include="Providers\IHasChangeMonitor.cs" />
|
||||
<Compile Include="Entities\IHasMetadata.cs" />
|
||||
|
|
39
MediaBrowser.Controller/Providers/IExtrasProvider.cs
Normal file
39
MediaBrowser.Controller/Providers/IExtrasProvider.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public interface IExtrasProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Supportses the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||
bool Supports(IHasMetadata item);
|
||||
}
|
||||
|
||||
public enum ExtraSource
|
||||
{
|
||||
Local = 1,
|
||||
Metadata = 2,
|
||||
Remote = 3
|
||||
}
|
||||
|
||||
public class ExtraInfo
|
||||
{
|
||||
public string Path { get; set; }
|
||||
|
||||
public LocationType LocationType { get; set; }
|
||||
|
||||
public bool IsDownloadable { get; set; }
|
||||
|
||||
public ExtraType ExtraType { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -236,4 +237,9 @@ namespace MediaBrowser.Controller.Providers
|
|||
|
||||
public int SeasonIndex { get; set; }
|
||||
}
|
||||
|
||||
public class ChannelItemLookupInfo : ItemLookupInfo
|
||||
{
|
||||
public ChannelMediaContentType ContentType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,9 +158,10 @@ namespace MediaBrowser.Controller.Resolvers
|
|||
// Normalize
|
||||
// Remove whitespace
|
||||
filename = filename.Replace("-", string.Empty);
|
||||
filename = filename.Replace(".", string.Empty);
|
||||
filename = Regex.Replace(filename, @"\s+", "");
|
||||
|
||||
var prefixes = new[] { "disc", "cd", "disk" };
|
||||
var prefixes = new[] { "disc", "cd", "disk", "vol", "volume" };
|
||||
|
||||
foreach (var prefix in prefixes)
|
||||
{
|
||||
|
@ -210,7 +211,7 @@ namespace MediaBrowser.Controller.Resolvers
|
|||
{
|
||||
if (includeCreationTime)
|
||||
{
|
||||
item.DateCreated = fileSystem.GetCreationTimeUtc(childData);
|
||||
item.DateCreated = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
item.DateModified = fileSystem.GetLastWriteTimeUtc(childData);
|
||||
|
@ -223,7 +224,7 @@ namespace MediaBrowser.Controller.Resolvers
|
|||
{
|
||||
if (includeCreationTime)
|
||||
{
|
||||
item.DateCreated = fileSystem.GetCreationTimeUtc(fileData);
|
||||
item.DateCreated = DateTime.UtcNow;
|
||||
}
|
||||
item.DateModified = fileSystem.GetLastWriteTimeUtc(fileData);
|
||||
}
|
||||
|
@ -233,7 +234,7 @@ namespace MediaBrowser.Controller.Resolvers
|
|||
{
|
||||
if (includeCreationTime)
|
||||
{
|
||||
item.DateCreated = fileSystem.GetCreationTimeUtc(args.FileInfo);
|
||||
item.DateCreated = DateTime.UtcNow;
|
||||
}
|
||||
item.DateModified = fileSystem.GetLastWriteTimeUtc(args.FileInfo);
|
||||
}
|
||||
|
|
|
@ -374,6 +374,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Entities\EmptyRequestResult.cs">
|
||||
<Link>Entities\EmptyRequestResult.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Entities\ExtraType.cs">
|
||||
<Link>Entities\ExtraType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Entities\IHasProviderIds.cs">
|
||||
<Link>Entities\IHasProviderIds.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -334,6 +334,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Entities\EmptyRequestResult.cs">
|
||||
<Link>Entities\EmptyRequestResult.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Entities\ExtraType.cs">
|
||||
<Link>Entities\ExtraType.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Entities\IHasProviderIds.cs">
|
||||
<Link>Entities\IHasProviderIds.cs</Link>
|
||||
</Compile>
|
||||
|
|
23
MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
Normal file
23
MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
namespace MediaBrowser.Model.Configuration
|
||||
{
|
||||
public class CinemaModeConfiguration
|
||||
{
|
||||
public bool EnableIntrosForMovies { get; set; }
|
||||
public bool EnableIntrosForEpisodes { get; set; }
|
||||
public bool EnableIntrosForWatchedContent { get; set; }
|
||||
public bool EnableIntrosFromUpcomingTrailers { get; set; }
|
||||
public bool EnableIntrosFromMoviesInLibrary { get; set; }
|
||||
public bool EnableCustomIntro { get; set; }
|
||||
public bool EnableIntrosParentalControl { get; set; }
|
||||
|
||||
public CinemaModeConfiguration()
|
||||
{
|
||||
EnableIntrosForMovies = true;
|
||||
EnableCustomIntro = true;
|
||||
EnableIntrosFromMoviesInLibrary = true;
|
||||
EnableIntrosFromUpcomingTrailers = true;
|
||||
EnableIntrosParentalControl = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -179,6 +179,8 @@ namespace MediaBrowser.Model.Configuration
|
|||
|
||||
public bool SaveMetadataHidden { get; set; }
|
||||
|
||||
public bool FindInternetTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
|
||||
/// </summary>
|
||||
|
@ -204,7 +206,8 @@ namespace MediaBrowser.Model.Configuration
|
|||
|
||||
RealtimeMonitorDelay = 30;
|
||||
|
||||
EnableInternetProviders = true;
|
||||
EnableInternetProviders = true;
|
||||
FindInternetTrailers = true;
|
||||
|
||||
PathSubstitutions = new PathSubstitution[] { };
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
public bool SyncConnectName { get; set; }
|
||||
public bool SyncConnectImage { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.
|
||||
/// </summary>
|
||||
|
|
16
MediaBrowser.Model/Entities/ExtraType.cs
Normal file
16
MediaBrowser.Model/Entities/ExtraType.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
namespace MediaBrowser.Model.Entities
|
||||
{
|
||||
public enum ExtraType
|
||||
{
|
||||
Clip = 1,
|
||||
Trailer = 2,
|
||||
BehindTheScenes = 3,
|
||||
DeletedScene = 4,
|
||||
Interview = 5,
|
||||
Scene = 6,
|
||||
Sample = 7,
|
||||
ThemeSong = 8,
|
||||
ThemeVideo = 9
|
||||
}
|
||||
}
|
|
@ -6,6 +6,5 @@ namespace MediaBrowser.Model.Entities
|
|||
public string Url { get; set; }
|
||||
public string Name { get; set; }
|
||||
public VideoSize? VideoSize { get; set; }
|
||||
public bool IsDirectLink { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,11 +79,13 @@
|
|||
<Compile Include="Collections\CollectionCreationResult.cs" />
|
||||
<Compile Include="Configuration\ChannelOptions.cs" />
|
||||
<Compile Include="Configuration\ChapterOptions.cs" />
|
||||
<Compile Include="Configuration\CinemaModeConfiguration.cs" />
|
||||
<Compile Include="Configuration\XbmcMetadataOptions.cs" />
|
||||
<Compile Include="Configuration\SubtitlePlaybackMode.cs" />
|
||||
<Compile Include="Connect\UserLinkType.cs" />
|
||||
<Compile Include="Drawing\ImageOrientation.cs" />
|
||||
<Compile Include="Dto\StreamOptions.cs" />
|
||||
<Compile Include="Entities\ExtraType.cs" />
|
||||
<Compile Include="FileOrganization\AutoOrganizeOptions.cs" />
|
||||
<Compile Include="FileOrganization\TvFileOrganizationOptions.cs" />
|
||||
<Compile Include="Configuration\BaseApplicationConfiguration.cs" />
|
||||
|
|
|
@ -50,10 +50,6 @@ namespace MediaBrowser.Providers.BoxSets
|
|||
{
|
||||
var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb);
|
||||
|
||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
||||
|
||||
if (!string.IsNullOrEmpty(tmdbId))
|
||||
{
|
||||
await EnsureInfo(tmdbId, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
|
||||
|
@ -62,7 +58,11 @@ namespace MediaBrowser.Providers.BoxSets
|
|||
var info = _json.DeserializeFromFile<RootObject>(dataFilePath);
|
||||
|
||||
var images = (info.images ?? new Images()).posters ?? new List<Poster>();
|
||||
|
||||
|
||||
var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
||||
|
||||
var result = new RemoteSearchResult
|
||||
{
|
||||
Name = info.name,
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Providers.Manager;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Providers.Channels
|
||||
{
|
||||
public class VideoChannelItemMetadataService : MetadataService<ChannelVideoItem, ItemLookupInfo>
|
||||
public class VideoChannelItemMetadataService : MetadataService<ChannelVideoItem, ChannelItemLookupInfo>
|
||||
{
|
||||
public VideoChannelItemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem)
|
||||
: base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem)
|
||||
|
|
|
@ -489,6 +489,8 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
if (result.HasMetadata)
|
||||
{
|
||||
NormalizeRemoteResult(result.Item);
|
||||
|
||||
MergeData(result.Item, temp, new List<MetadataFields>(), false, false);
|
||||
|
||||
refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
|
||||
|
@ -522,6 +524,19 @@ namespace MediaBrowser.Providers.Manager
|
|||
return refreshResult;
|
||||
}
|
||||
|
||||
private void NormalizeRemoteResult(TItemType item)
|
||||
{
|
||||
if (!ServerConfigurationManager.Configuration.FindInternetTrailers)
|
||||
{
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
hasTrailers.RemoteTrailers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void AfterRemoteRefresh(TItemType item)
|
||||
{
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
|
|
@ -251,7 +251,6 @@ namespace MediaBrowser.Providers.Movies
|
|||
hasTrailers.RemoteTrailers = movieData.trailers.youtube.Select(i => new MediaUrl
|
||||
{
|
||||
Url = string.Format("http://www.youtube.com/watch?v={0}", i.source),
|
||||
IsDirectLink = false,
|
||||
Name = i.name,
|
||||
VideoSize = string.Equals("hd", i.size, StringComparison.OrdinalIgnoreCase) ? VideoSize.HighDefinition : VideoSize.StandardDefinition
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
@ -45,6 +47,13 @@ namespace MediaBrowser.Providers.Movies
|
|||
return !trailer.IsLocalTrailer;
|
||||
}
|
||||
|
||||
var channelItem = item as ChannelVideoItem;
|
||||
|
||||
if (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Trailer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't support local trailers
|
||||
return item is Movie || item is MusicVideo;
|
||||
}
|
||||
|
|
|
@ -56,10 +56,6 @@ namespace MediaBrowser.Providers.Movies
|
|||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetMovieSearchResults(ItemLookupInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
||||
|
||||
var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb);
|
||||
|
||||
if (!string.IsNullOrEmpty(tmdbId))
|
||||
|
@ -72,6 +68,10 @@ namespace MediaBrowser.Providers.Movies
|
|||
|
||||
var obj = _jsonSerializer.DeserializeFromFile<CompleteMovieData>(dataFilePath);
|
||||
|
||||
var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var tmdbImageUrl = tmdbSettings.images.base_url + "original";
|
||||
|
||||
var remoteResult = new RemoteSearchResult
|
||||
{
|
||||
Name = obj.title ?? obj.original_title ?? obj.name,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -9,7 +11,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Providers.Movies
|
||||
{
|
||||
public class MovieDbTrailerProvider : IRemoteMetadataProvider<Trailer, TrailerInfo>, IHasOrder
|
||||
public class MovieDbTrailerProvider : IRemoteMetadataProvider<Trailer, TrailerInfo>, IHasOrder, IRemoteMetadataProvider<ChannelVideoItem, ChannelItemLookupInfo>
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
|
@ -28,6 +30,26 @@ namespace MediaBrowser.Providers.Movies
|
|||
return MovieDbProvider.Current.GetMovieSearchResults(searchInfo, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<MetadataResult<ChannelVideoItem>> GetMetadata(ChannelItemLookupInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
if (info.ContentType != Model.Channels.ChannelMediaContentType.Trailer)
|
||||
{
|
||||
return Task.FromResult(new MetadataResult<ChannelVideoItem>());
|
||||
}
|
||||
|
||||
return MovieDbProvider.Current.GetItemMetadata<ChannelVideoItem>(info, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ChannelItemLookupInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
if (searchInfo.ContentType != ChannelMediaContentType.Trailer)
|
||||
{
|
||||
return Task.FromResult<IEnumerable<RemoteSearchResult>>(new List<RemoteSearchResult>());
|
||||
}
|
||||
|
||||
return MovieDbProvider.Current.GetMovieSearchResults(searchInfo, cancellationToken);
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return MovieDbProvider.Current.Name; }
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Providers.Movies
|
||||
|
@ -25,6 +27,13 @@ namespace MediaBrowser.Providers.Movies
|
|||
|
||||
public bool Supports(IHasProviderIds item)
|
||||
{
|
||||
var channelItem = item as ChannelVideoItem;
|
||||
|
||||
if (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Trailer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return item is Movie || item is Trailer || item is MusicVideo;
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +149,13 @@ namespace MediaBrowser.Providers.Movies
|
|||
|
||||
public bool Supports(IHasProviderIds item)
|
||||
{
|
||||
var channelItem = item as ChannelVideoItem;
|
||||
|
||||
if (channelItem != null && channelItem.ContentType == ChannelMediaContentType.Trailer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return item is Movie || item is Trailer || item is MusicVideo || item is Series || item is Episode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
@ -17,7 +19,7 @@ using System.Threading.Tasks;
|
|||
namespace MediaBrowser.Providers.Omdb
|
||||
{
|
||||
public class OmdbItemProvider : IRemoteMetadataProvider<Series, SeriesInfo>,
|
||||
IRemoteMetadataProvider<Movie, MovieInfo>, IRemoteMetadataProvider<Trailer, TrailerInfo>
|
||||
IRemoteMetadataProvider<Movie, MovieInfo>, IRemoteMetadataProvider<Trailer, TrailerInfo>, IRemoteMetadataProvider<ChannelVideoItem, ChannelItemLookupInfo>
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
@ -45,6 +47,21 @@ namespace MediaBrowser.Providers.Omdb
|
|||
return new List<RemoteSearchResult>();
|
||||
}
|
||||
|
||||
public Task<MetadataResult<ChannelVideoItem>> GetMetadata(ChannelItemLookupInfo info, CancellationToken cancellationToken)
|
||||
{
|
||||
if (info.ContentType != ChannelMediaContentType.Trailer)
|
||||
{
|
||||
return Task.FromResult(new MetadataResult<ChannelVideoItem>());
|
||||
}
|
||||
|
||||
return GetMovieResult<ChannelVideoItem>(info, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ChannelItemLookupInfo searchInfo, CancellationToken cancellationToken)
|
||||
{
|
||||
return new List<RemoteSearchResult>();
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "The Open Movie Database"; }
|
||||
|
|
|
@ -332,7 +332,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
{
|
||||
return new ITaskTrigger[]
|
||||
{
|
||||
new IntervalTrigger{ Interval = TimeSpan.FromHours(6)},
|
||||
new IntervalTrigger{ Interval = TimeSpan.FromHours(3)},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
{
|
||||
get
|
||||
{
|
||||
return TimeSpan.FromHours(12);
|
||||
return TimeSpan.FromHours(6);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -663,7 +663,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
|
||||
private async Task<IEnumerable<ChannelItemInfo>> GetLatestItems(ISupportsLatestMedia indexable, IChannel channel, string userId, CancellationToken cancellationToken)
|
||||
{
|
||||
var cacheLength = TimeSpan.FromHours(12);
|
||||
var cacheLength = CacheLength;
|
||||
var cachePath = GetChannelDataCachePath(channel, userId, "channelmanager-latest", null, false);
|
||||
|
||||
try
|
||||
|
@ -720,7 +720,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<QueryResult<BaseItemDto>> GetAllMedia(AllChannelMediaQuery query, CancellationToken cancellationToken)
|
||||
public async Task<QueryResult<BaseItem>> GetAllMediaInternal(AllChannelMediaQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = string.IsNullOrWhiteSpace(query.UserId)
|
||||
? null
|
||||
|
@ -798,19 +798,43 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false);
|
||||
await RefreshIfNeeded(internalItems, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var returnItemArray = internalItems.Select(i => _dtoService.GetBaseItemDto(i, query.Fields, user))
|
||||
.ToArray();
|
||||
var returnItemArray = internalItems.ToArray();
|
||||
|
||||
return new QueryResult<BaseItemDto>
|
||||
return new QueryResult<BaseItem>
|
||||
{
|
||||
TotalRecordCount = totalCount,
|
||||
Items = returnItemArray
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<QueryResult<BaseItemDto>> GetAllMedia(AllChannelMediaQuery query, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = string.IsNullOrWhiteSpace(query.UserId)
|
||||
? null
|
||||
: _userManager.GetUserById(query.UserId);
|
||||
|
||||
var internalResult = await GetAllMediaInternal(query, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Get everything
|
||||
var fields = Enum.GetNames(typeof(ItemFields))
|
||||
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
|
||||
.ToList();
|
||||
|
||||
var returnItems = internalResult.Items.Select(i => _dtoService.GetBaseItemDto(i, fields, user))
|
||||
.ToArray();
|
||||
|
||||
var result = new QueryResult<BaseItemDto>
|
||||
{
|
||||
Items = returnItems,
|
||||
TotalRecordCount = internalResult.TotalRecordCount
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<ChannelItemResult> GetAllItems(IIndexableChannel indexable, IChannel channel, string userId, CancellationToken cancellationToken)
|
||||
{
|
||||
var cacheLength = TimeSpan.FromHours(12);
|
||||
var cacheLength = CacheLength;
|
||||
var cachePath = GetChannelDataCachePath(channel, userId, "channelmanager-allitems", null, false);
|
||||
|
||||
try
|
||||
|
@ -1199,7 +1223,6 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
item.Genres = info.Genres;
|
||||
item.Studios = info.Studios;
|
||||
item.CommunityRating = info.CommunityRating;
|
||||
item.OfficialRating = info.OfficialRating;
|
||||
item.Overview = info.Overview;
|
||||
item.IndexNumber = info.IndexNumber;
|
||||
item.ParentIndexNumber = info.ParentIndexNumber;
|
||||
|
@ -1207,6 +1230,7 @@ namespace MediaBrowser.Server.Implementations.Channels
|
|||
item.PremiereDate = info.PremiereDate;
|
||||
item.ProductionYear = info.ProductionYear;
|
||||
item.ProviderIds = info.ProviderIds;
|
||||
item.OfficialRating = info.OfficialRating;
|
||||
|
||||
item.DateCreated = info.DateCreated.HasValue ?
|
||||
info.DateCreated.Value :
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
using System.Collections.Generic;
|
||||
using MediaBrowser.Common.Progress;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Channels
|
||||
{
|
||||
public class ChannelPostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
private readonly IChannelManager _channelManager;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public ChannelPostScanTask(IChannelManager channelManager, IUserManager userManager, ILogger logger)
|
||||
{
|
||||
_channelManager = channelManager;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
var users = _userManager.Users
|
||||
.Select(i => i.Id.ToString("N"))
|
||||
.ToList();
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
double percentPerUser = 1;
|
||||
percentPerUser /= users.Count;
|
||||
var startingPercent = numComplete * percentPerUser * 100;
|
||||
|
||||
var innerProgress = new ActionableProgress<double>();
|
||||
innerProgress.RegisterAction(p => progress.Report(startingPercent + (percentPerUser * p)));
|
||||
|
||||
await DownloadContent(user, cancellationToken, innerProgress).ConfigureAwait(false);
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= users.Count;
|
||||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task DownloadContent(string user, CancellationToken cancellationToken, IProgress<double> progress)
|
||||
{
|
||||
var channels = await _channelManager.GetChannelsInternal(new ChannelQuery
|
||||
{
|
||||
UserId = user
|
||||
|
||||
}, cancellationToken);
|
||||
|
||||
var numComplete = 0;
|
||||
|
||||
foreach (var channel in channels.Items)
|
||||
{
|
||||
try
|
||||
{
|
||||
await GetAllItems(user, channel.Id.ToString("N"), null, false, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting channel content", ex);
|
||||
}
|
||||
|
||||
numComplete++;
|
||||
double percent = numComplete;
|
||||
percent /= channels.Items.Length;
|
||||
progress.Report(percent * 100);
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
|
||||
}
|
||||
|
||||
private async Task GetAllItems(string user, string channelId, string folderId, bool recursive, CancellationToken cancellationToken)
|
||||
{
|
||||
var folderItems = new List<string>();
|
||||
|
||||
var result = await _channelManager.GetChannelItemsInternal(new ChannelItemQuery
|
||||
{
|
||||
ChannelId = channelId,
|
||||
UserId = user,
|
||||
FolderId = folderId
|
||||
|
||||
}, cancellationToken);
|
||||
|
||||
folderItems.AddRange(result.Items.Where(i => i.IsFolder).Select(i => i.Id.ToString("N")));
|
||||
|
||||
var totalRetrieved = result.Items.Length;
|
||||
var totalCount = result.TotalRecordCount;
|
||||
|
||||
while (totalRetrieved < totalCount)
|
||||
{
|
||||
result = await _channelManager.GetChannelItemsInternal(new ChannelItemQuery
|
||||
{
|
||||
ChannelId = channelId,
|
||||
UserId = user,
|
||||
StartIndex = totalRetrieved,
|
||||
FolderId = folderId
|
||||
|
||||
}, cancellationToken);
|
||||
|
||||
folderItems.AddRange(result.Items.Where(i => i.IsFolder).Select(i => i.Id.ToString("N")));
|
||||
|
||||
totalRetrieved += result.Items.Length;
|
||||
totalCount = result.TotalRecordCount;
|
||||
}
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
foreach (var folder in folderItems)
|
||||
{
|
||||
try
|
||||
{
|
||||
await GetAllItems(user, channelId, folder, false, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting channel content", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -402,11 +402,11 @@ namespace MediaBrowser.Server.Implementations.Connect
|
|||
}
|
||||
else if (!string.IsNullOrWhiteSpace(query.Name))
|
||||
{
|
||||
url = url + "?nameoremail=" + WebUtility.UrlEncode(query.Name);
|
||||
url = url + "?name=" + WebUtility.UrlEncode(query.Name);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(query.Email))
|
||||
{
|
||||
url = url + "?nameoremail=" + WebUtility.UrlEncode(query.Email);
|
||||
url = url + "?name=" + WebUtility.UrlEncode(query.Email);
|
||||
}
|
||||
|
||||
var options = new HttpRequestOptions
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Security;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Localization;
|
||||
using MediaBrowser.Model.Channels;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Intros
|
||||
{
|
||||
public class DefaultIntroProvider : IIntroProvider
|
||||
{
|
||||
private readonly ISecurityManager _security;
|
||||
private readonly IChannelManager _channelManager;
|
||||
private readonly ILocalizationManager _localization;
|
||||
private readonly IConfigurationManager _serverConfig;
|
||||
|
||||
public DefaultIntroProvider(ISecurityManager security, IChannelManager channelManager, ILocalizationManager localization, IConfigurationManager serverConfig)
|
||||
{
|
||||
_security = security;
|
||||
_channelManager = channelManager;
|
||||
_localization = localization;
|
||||
_serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<IntroInfo>> GetIntros(BaseItem item, User user)
|
||||
{
|
||||
var config = GetOptions();
|
||||
|
||||
if (item is Movie)
|
||||
{
|
||||
if (!config.EnableIntrosForMovies)
|
||||
{
|
||||
return new List<IntroInfo>();
|
||||
}
|
||||
}
|
||||
else if (item is Episode)
|
||||
{
|
||||
if (!config.EnableIntrosForEpisodes)
|
||||
{
|
||||
return new List<IntroInfo>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<IntroInfo>();
|
||||
}
|
||||
|
||||
if (!IsSupporter)
|
||||
{
|
||||
return new List<IntroInfo>();
|
||||
}
|
||||
|
||||
var ratingLevel = string.IsNullOrWhiteSpace(item.OfficialRating)
|
||||
? (int?)null
|
||||
: _localization.GetRatingLevel(item.OfficialRating);
|
||||
|
||||
var libaryItems = user.RootFolder.GetRecursiveChildren(user, false)
|
||||
.ToList();
|
||||
|
||||
var random = new Random(Environment.TickCount + Guid.NewGuid().GetHashCode());
|
||||
|
||||
var candidates = new List<ItemWithTrailer>();
|
||||
|
||||
if (config.EnableIntrosFromMoviesInLibrary)
|
||||
{
|
||||
var itemsWithTrailers = libaryItems
|
||||
.Where(i =>
|
||||
{
|
||||
var hasTrailers = i as IHasTrailers;
|
||||
|
||||
if (hasTrailers != null && hasTrailers.LocalTrailerIds.Count > 0)
|
||||
{
|
||||
if (i is Movie)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
candidates.AddRange(itemsWithTrailers.Select(i => new ItemWithTrailer
|
||||
{
|
||||
Item = i,
|
||||
Type = ItemWithTrailerType.ItemWithTrailer,
|
||||
User = user,
|
||||
WatchingItem = item,
|
||||
Random = random
|
||||
}));
|
||||
}
|
||||
|
||||
if (config.EnableIntrosFromUpcomingTrailers)
|
||||
{
|
||||
var channelTrailers = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
|
||||
{
|
||||
ContentTypes = new[] { ChannelMediaContentType.Trailer },
|
||||
UserId = user.Id.ToString("N")
|
||||
|
||||
}, CancellationToken.None);
|
||||
|
||||
candidates.AddRange(channelTrailers.Items.Select(i => new ItemWithTrailer
|
||||
{
|
||||
Item = i,
|
||||
Type = ItemWithTrailerType.ChannelTrailer,
|
||||
User = user,
|
||||
WatchingItem = item,
|
||||
Random = random
|
||||
}));
|
||||
|
||||
candidates.AddRange(libaryItems.Where(i => i is Trailer).Select(i => new ItemWithTrailer
|
||||
{
|
||||
Item = i,
|
||||
Type = ItemWithTrailerType.LibraryTrailer,
|
||||
User = user,
|
||||
WatchingItem = item,
|
||||
Random = random
|
||||
}));
|
||||
}
|
||||
|
||||
var customIntros = config.EnableCustomIntro ?
|
||||
GetCustomIntros(item) :
|
||||
new List<IntroInfo>();
|
||||
|
||||
var trailerLimit = 2;
|
||||
if (customIntros.Count > 0)
|
||||
{
|
||||
trailerLimit--;
|
||||
}
|
||||
|
||||
// Avoid implicitly captured closure
|
||||
var currentUser = user;
|
||||
return candidates.Where(i =>
|
||||
{
|
||||
if (config.EnableIntrosParentalControl && !FilterByParentalRating(ratingLevel, i.Item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!config.EnableIntrosForWatchedContent && i.IsPlayed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.OrderByDescending(i => i.Score)
|
||||
.ThenBy(i => Guid.NewGuid())
|
||||
.ThenByDescending(i => (i.IsPlayed ? 0 : 1))
|
||||
.Select(i => i.IntroInfo)
|
||||
.Take(trailerLimit)
|
||||
.Concat(customIntros.Take(1));
|
||||
}
|
||||
|
||||
private CinemaModeConfiguration GetOptions()
|
||||
{
|
||||
return _serverConfig.GetConfiguration<CinemaModeConfiguration>("cinemamode");
|
||||
}
|
||||
|
||||
private List<IntroInfo> GetCustomIntros(BaseItem item)
|
||||
{
|
||||
return new List<IntroInfo>();
|
||||
}
|
||||
|
||||
private bool FilterByParentalRating(int? ratingLevel, BaseItem item)
|
||||
{
|
||||
// Only content rated same or lower
|
||||
if (ratingLevel.HasValue)
|
||||
{
|
||||
var level = string.IsNullOrWhiteSpace(item.OfficialRating)
|
||||
? (int?)null
|
||||
: _localization.GetRatingLevel(item.OfficialRating);
|
||||
|
||||
return level.HasValue && level.Value <= ratingLevel.Value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static int GetSimiliarityScore(BaseItem item1, BaseItem item2, Random random)
|
||||
{
|
||||
var points = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(item1.OfficialRating) && string.Equals(item1.OfficialRating, item2.OfficialRating, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
points += 10;
|
||||
}
|
||||
|
||||
// Find common genres
|
||||
points += item1.Genres.Where(i => item2.Genres.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
|
||||
|
||||
// Find common tags
|
||||
points += GetTags(item1).Where(i => GetTags(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
|
||||
|
||||
// Find common keywords
|
||||
points += GetKeywords(item1).Where(i => GetKeywords(item2).Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 10);
|
||||
|
||||
// Find common studios
|
||||
points += item1.Studios.Where(i => item2.Studios.Contains(i, StringComparer.OrdinalIgnoreCase)).Sum(i => 5);
|
||||
|
||||
var item2PeopleNames = item2.People.Select(i => i.Name)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
points += item1.People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i =>
|
||||
{
|
||||
if (string.Equals(i.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
if (string.Equals(i.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Actor, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
if (string.Equals(i.Type, PersonType.Composer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Composer, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
if (string.Equals(i.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
if (string.Equals(i.Type, PersonType.Writer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
// Add some randomization so that you're not always seeing the same ones for a given movie
|
||||
points += random.Next(0, 50);
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetTags(BaseItem item)
|
||||
{
|
||||
var hasTags = item as IHasTags;
|
||||
if (hasTags != null)
|
||||
{
|
||||
return hasTags.Tags;
|
||||
}
|
||||
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetKeywords(BaseItem item)
|
||||
{
|
||||
var hasTags = item as IHasKeywords;
|
||||
if (hasTags != null)
|
||||
{
|
||||
return hasTags.Keywords;
|
||||
}
|
||||
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetAllIntroFiles()
|
||||
{
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
private bool IsSupporter
|
||||
{
|
||||
get { return _security.IsMBSupporter; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "Default"; }
|
||||
}
|
||||
|
||||
internal class ItemWithTrailer
|
||||
{
|
||||
internal BaseItem Item;
|
||||
internal ItemWithTrailerType Type;
|
||||
internal User User;
|
||||
internal BaseItem WatchingItem;
|
||||
internal Random Random;
|
||||
|
||||
private bool? _isPlayed;
|
||||
public bool IsPlayed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_isPlayed.HasValue)
|
||||
{
|
||||
_isPlayed = Item.IsPlayed(User);
|
||||
}
|
||||
return _isPlayed.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private int? _score;
|
||||
public int Score
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_score.HasValue)
|
||||
{
|
||||
_score = GetSimiliarityScore(WatchingItem, Item, Random);
|
||||
}
|
||||
return _score.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public IntroInfo IntroInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
var id = Item.Id;
|
||||
|
||||
if (Type == ItemWithTrailerType.ItemWithTrailer)
|
||||
{
|
||||
var hasTrailers = Item as IHasTrailers;
|
||||
|
||||
if (hasTrailers != null)
|
||||
{
|
||||
id = hasTrailers.LocalTrailerIds.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
return new IntroInfo
|
||||
{
|
||||
ItemId = id
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum ItemWithTrailerType
|
||||
{
|
||||
LibraryTrailer,
|
||||
ChannelTrailer,
|
||||
ItemWithTrailer
|
||||
}
|
||||
}
|
||||
|
||||
public class CinemaModeConfigurationFactory : IConfigurationFactory
|
||||
{
|
||||
public IEnumerable<ConfigurationStore> GetConfigurations()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new ConfigurationStore
|
||||
{
|
||||
ConfigurationType = typeof(CinemaModeConfiguration),
|
||||
Key = "cinemamode"
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -95,8 +95,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
return true;
|
||||
}
|
||||
|
||||
// Don't misidentify xbmc trailers as a movie
|
||||
if (filename.IndexOf(BaseItem.XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (BaseItem.ExtraSuffixes.Any(i => filename.IndexOf(i.Key, StringComparison.OrdinalIgnoreCase) != -1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1193,13 +1193,42 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
/// <param name="item">The item.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
public IEnumerable<Video> GetIntros(BaseItem item, User user)
|
||||
public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
|
||||
{
|
||||
return IntroProviders.SelectMany(i => i.GetIntros(item, user))
|
||||
var tasks = IntroProviders
|
||||
.OrderBy(i => (i.GetType().Name.IndexOf("Default", StringComparison.OrdinalIgnoreCase) == -1 ? 1 : 0))
|
||||
.Take(1)
|
||||
.Select(i => GetIntros(i, item, user));
|
||||
|
||||
var items = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
return items
|
||||
.SelectMany(i => i.ToArray())
|
||||
.Select(ResolveIntro)
|
||||
.Where(i => i != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the intros.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>Task<IEnumerable<IntroInfo>>.</returns>
|
||||
private async Task<IEnumerable<IntroInfo>> GetIntros(IIntroProvider provider, BaseItem item, User user)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await provider.GetIntros(item, user).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error getting intros", ex);
|
||||
|
||||
return new List<IntroInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all intro files.
|
||||
/// </summary>
|
||||
|
@ -1487,7 +1516,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
var item = GetItemById(id) as UserView;
|
||||
|
||||
if (item == null ||
|
||||
if (item == null ||
|
||||
!string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
||||
{
|
||||
|
@ -41,9 +43,15 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
|
|||
}
|
||||
|
||||
// Support xbmc local trailer convention, but only when looking for local trailers (hence the parent == null check)
|
||||
if (args.Parent == null && _fileSystem.GetFileNameWithoutExtension(args.Path).EndsWith(BaseItem.XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase))
|
||||
if (args.Parent == null)
|
||||
{
|
||||
return base.Resolve(args);
|
||||
var nameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(args.Path);
|
||||
var suffix = BaseItem.ExtraSuffixes.First(i => i.Value == ExtraType.Trailer);
|
||||
|
||||
if (nameWithoutExtension.EndsWith(suffix.Key, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return base.Resolve(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,8 +111,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
}
|
||||
|
||||
var filename = Path.GetFileName(args.Path);
|
||||
// Don't misidentify xbmc trailers as a movie
|
||||
if (filename.IndexOf(BaseItem.XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
// Don't misidentify extras or trailers
|
||||
if (BaseItem.ExtraSuffixes.Any(i => filename.IndexOf(i.Key, StringComparison.OrdinalIgnoreCase) != -1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -229,8 +229,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
|||
continue;
|
||||
}
|
||||
|
||||
// Don't misidentify xbmc trailers as a movie
|
||||
if (filename.IndexOf(BaseItem.XbmcTrailerFileSuffix, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
// Don't misidentify extras or trailers as a movie
|
||||
if (BaseItem.ExtraSuffixes.Any(i => filename.IndexOf(i.Key, StringComparison.OrdinalIgnoreCase) != -1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -569,5 +569,6 @@
|
|||
"MediaInfoStreamTypeVideo": "Video",
|
||||
"MediaInfoStreamTypeSubtitle": "Subtitle",
|
||||
"MediaInfoStreamTypeEmbeddedImage": "Embedded Image",
|
||||
"MediaInfoRefFrames": "Ref frames"
|
||||
"MediaInfoRefFrames": "Ref frames",
|
||||
"TabPlayback": "Playback"
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@
|
|||
"ButtonAutoScroll": "Auto-scroll",
|
||||
"LabelImageSavingConvention": "Image saving convention:",
|
||||
"LabelImageSavingConventionHelp": "Media Browser recognizes images from most major media applications. Choosing your downloading convention is useful if you also use other products.",
|
||||
"OptionImageSavingCompatible": "Compatible - Media Browser/Xbmc/Plex",
|
||||
"OptionImageSavingCompatible": "Compatible - Media Browser/Kodi/Plex",
|
||||
"OptionImageSavingStandard": "Standard - MB2",
|
||||
"ButtonSignIn": "Sign In",
|
||||
"TitleSignIn": "Sign In",
|
||||
|
@ -883,22 +883,22 @@
|
|||
"OptionLatestTvRecordings": "Latest recordings",
|
||||
"LabelProtocolInfo": "Protocol info:",
|
||||
"LabelProtocolInfoHelp": "The value that will be used when responding to GetProtocolInfo requests from the device.",
|
||||
"TabXbmcMetadata": "Xbmc",
|
||||
"HeaderXbmcMetadataHelp": "Media Browser includes native support for Xbmc Nfo metadata and images. To enable or disable Xbmc metadata, use the Advanced tab to configure options for your media types.",
|
||||
"LabelXbmcMetadataUser": "Add user watch data to nfo's for:",
|
||||
"LabelXbmcMetadataUserHelp": "Enable this to keep watch data in sync between Media Browser and Xbmc.",
|
||||
"LabelXbmcMetadataDateFormat": "Release date format:",
|
||||
"LabelXbmcMetadataDateFormatHelp": "All dates within nfo's will be read and written to using this format.",
|
||||
"LabelXbmcMetadataSaveImagePaths": "Save image paths within nfo files",
|
||||
"LabelXbmcMetadataSaveImagePathsHelp": "This is recommended if you have image file names that don't conform to Xbmc guidelines.",
|
||||
"LabelXbmcMetadataEnablePathSubstitution": "Enable path substitution",
|
||||
"LabelXbmcMetadataEnablePathSubstitutionHelp": "Enables path substitution of image paths using the server's path substitution settings.",
|
||||
"LabelXbmcMetadataEnablePathSubstitutionHelp2": "See path substitution.",
|
||||
"TabKodiMetadata": "Kodi",
|
||||
"HeaderKodiMetadataHelp": "Media Browser includes native support for Kodi Nfo metadata and images. To enable or disable Kodi metadata, use the Advanced tab to configure options for your media types.",
|
||||
"LabelKodiMetadataUser": "Add user watch data to nfo's for:",
|
||||
"LabelKodiMetadataUserHelp": "Enable this to keep watch data in sync between Media Browser and Kodi.",
|
||||
"LabelKodiMetadataDateFormat": "Release date format:",
|
||||
"LabelKodiMetadataDateFormatHelp": "All dates within nfo's will be read and written to using this format.",
|
||||
"LabelKodiMetadataSaveImagePaths": "Save image paths within nfo files",
|
||||
"LabelKodiMetadataSaveImagePathsHelp": "This is recommended if you have image file names that don't conform to Kodi guidelines.",
|
||||
"LabelKodiMetadataEnablePathSubstitution": "Enable path substitution",
|
||||
"LabelKodiMetadataEnablePathSubstitutionHelp": "Enables path substitution of image paths using the server's path substitution settings.",
|
||||
"LabelKodiMetadataEnablePathSubstitutionHelp2": "See path substitution.",
|
||||
"LabelGroupChannelsIntoViews": "Display the following channels directly within my views:",
|
||||
"LabelGroupChannelsIntoViewsHelp": "If enabled, these channels will be displayed directly alongside other views. If disabled, they'll be displayed within a separate Channels view.",
|
||||
"LabelDisplayCollectionsView": "Display a collections view to show movie collections",
|
||||
"LabelXbmcMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs",
|
||||
"LabelXbmcMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Xbmc skin compatibility.",
|
||||
"LabelKodiMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs",
|
||||
"LabelKodiMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Kodi skin compatibility.",
|
||||
"TabServices": "Services",
|
||||
"TabLogs": "Logs",
|
||||
"HeaderServerLogFiles": "Server log files:",
|
||||
|
@ -1179,5 +1179,21 @@
|
|||
"OptionExternallyDownloaded": "External download",
|
||||
"OptionHlsSegmentedSubtitles": "Hls segmented subtitles",
|
||||
"LabelSubtitleFormatHelp": "Example: srt",
|
||||
"ButtonLearnMore": "Learn more"
|
||||
"ButtonLearnMore": "Learn more",
|
||||
"TabPlayback": "Playback",
|
||||
"HeaderTrailersAndExtras": "Trailers & Extras",
|
||||
"OptionFindTrailers": "Find trailers from the internet automatically",
|
||||
"HeaderLanguagePreferences": "Language Preferences",
|
||||
"TabCinemaMode": "Cinema Mode",
|
||||
"TitlePlayback": "Playback",
|
||||
"LabelEnableCinemaModeFor": "Enable cinema mode for:",
|
||||
"CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
|
||||
"LabelEnableTheFollowingIntros": "Enable the following types of intros:",
|
||||
"OptionTrailersFromMyMovies": "Trailers from movies in my library",
|
||||
"OptionUpcomingMoviesInTheaters": "Trailers from upcoming movies",
|
||||
"LabelLimitIntrosToUnwatchedContent": "Only use trailers from unwatched content",
|
||||
"LabelEnableIntroParentalControl": "Enable smart parental control",
|
||||
"LabelEnableIntroParentalControlHelp": "Intros will only used from content with a parental rating equal to or less than the content being watched.",
|
||||
"LabelEnableTheFollowingIntrosHelp": "Trailers from existing movies requires setup of local trailers. Theater trailers require installation of the Trailer channel plugin.",
|
||||
"ButtonThisFeatureRequiresSupporter": "This feature requires an active supporter membership"
|
||||
}
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
<Compile Include="Channels\ChannelImageProvider.cs" />
|
||||
<Compile Include="Channels\ChannelItemImageProvider.cs" />
|
||||
<Compile Include="Channels\ChannelManager.cs" />
|
||||
<Compile Include="Channels\ChannelPostScanTask.cs" />
|
||||
<Compile Include="Channels\RefreshChannelsScheduledTask.cs" />
|
||||
<Compile Include="Collections\CollectionManager.cs" />
|
||||
<Compile Include="Collections\CollectionsDynamicFolder.cs" />
|
||||
|
@ -173,6 +174,7 @@
|
|||
<Compile Include="HttpServer\SocketSharp\WebSocketSharpRequest.cs" />
|
||||
<Compile Include="HttpServer\SocketSharp\WebSocketSharpResponse.cs" />
|
||||
<Compile Include="HttpServer\ThrottledStream.cs" />
|
||||
<Compile Include="Intros\DefaultIntroProvider.cs" />
|
||||
<Compile Include="IO\LibraryMonitor.cs" />
|
||||
<Compile Include="Library\CoreResolutionIgnoreRule.cs" />
|
||||
<Compile Include="Library\LibraryManager.cs" />
|
||||
|
|
|
@ -571,7 +571,11 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
"edititemmetadata.js",
|
||||
"edititemimages.js",
|
||||
"edititemsubtitles.js",
|
||||
|
||||
"playbackconfiguration.js",
|
||||
"cinemamodeconfiguration.js",
|
||||
"encodingsettings.js",
|
||||
|
||||
"externalplayer.js",
|
||||
"favorites.js",
|
||||
"gamesrecommendedpage.js",
|
||||
|
@ -610,7 +614,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
"metadataconfigurationpage.js",
|
||||
"metadataimagespage.js",
|
||||
"metadatasubtitles.js",
|
||||
"metadataxbmc.js",
|
||||
"metadatakodi.js",
|
||||
"moviegenres.js",
|
||||
"moviecollections.js",
|
||||
"movies.js",
|
||||
|
|
|
@ -101,6 +101,9 @@
|
|||
<Content Include="dashboard-ui\channelslatest.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\cinemamodeconfiguration.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\css\chromecast.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -161,7 +164,7 @@
|
|||
<Content Include="dashboard-ui\css\images\clients\playstore.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\css\images\clients\xbmc.png">
|
||||
<Content Include="dashboard-ui\css\images\clients\kodi.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\css\images\favicon.ico">
|
||||
|
@ -335,7 +338,7 @@
|
|||
<Content Include="dashboard-ui\librarypathmapping.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\metadataxbmc.html">
|
||||
<Content Include="dashboard-ui\metadatakodi.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\mypreferencesdisplay.html">
|
||||
|
@ -350,6 +353,9 @@
|
|||
<Content Include="dashboard-ui\notificationlist.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\playbackconfiguration.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\playlistedit.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -608,6 +614,9 @@
|
|||
<Content Include="dashboard-ui\scripts\chromecast.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\cinemamodeconfiguration.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\dashboardgeneral.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -659,7 +668,7 @@
|
|||
<Content Include="dashboard-ui\scripts\librarypathmapping.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\metadataxbmc.js">
|
||||
<Content Include="dashboard-ui\scripts\metadatakodi.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\mypreferencesdisplay.js">
|
||||
|
@ -674,6 +683,9 @@
|
|||
<Content Include="dashboard-ui\scripts\notificationlist.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\playbackconfiguration.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\playlistedit.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -800,9 +812,6 @@
|
|||
<Content Include="dashboard-ui\thirdparty\cast_sender.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\jquery-2.0.3.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common.Internal</id>
|
||||
<version>3.0.434</version>
|
||||
<version>3.0.435</version>
|
||||
<title>MediaBrowser.Common.Internal</title>
|
||||
<authors>Luke</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
|
||||
<copyright>Copyright © Media Browser 2013</copyright>
|
||||
<dependencies>
|
||||
<dependency id="MediaBrowser.Common" version="3.0.434" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.435" />
|
||||
<dependency id="NLog" version="3.1.0.0" />
|
||||
<dependency id="SimpleInjector" version="2.5.2" />
|
||||
<dependency id="sharpcompress" version="0.10.2" />
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Common</id>
|
||||
<version>3.0.434</version>
|
||||
<version>3.0.435</version>
|
||||
<title>MediaBrowser.Common</title>
|
||||
<authors>Media Browser Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Model.Signed</id>
|
||||
<version>3.0.434</version>
|
||||
<version>3.0.435</version>
|
||||
<title>MediaBrowser.Model - Signed Edition</title>
|
||||
<authors>Media Browser Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>MediaBrowser.Server.Core</id>
|
||||
<version>3.0.434</version>
|
||||
<version>3.0.435</version>
|
||||
<title>Media Browser.Server.Core</title>
|
||||
<authors>Media Browser Team</authors>
|
||||
<owners>ebr,Luke,scottisafool</owners>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<description>Contains core components required to build plugins for Media Browser Server.</description>
|
||||
<copyright>Copyright © Media Browser 2013</copyright>
|
||||
<dependencies>
|
||||
<dependency id="MediaBrowser.Common" version="3.0.434" />
|
||||
<dependency id="MediaBrowser.Common" version="3.0.435" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
|
Loading…
Reference in New Issue
Block a user