add cinema mode feature

pull/702/head
Luke Pulverenti 10 years ago
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&lt;QueryResult&lt;BaseItem&gt;&gt;.</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" />

@ -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>

@ -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>

@ -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&lt;IEnumerable&lt;IntroInfo&gt;&gt;.</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…
Cancel
Save