Merge branch 'dev' of https://github.com/MediaBrowser/MediaBrowser into dev
Conflicts: MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
This commit is contained in:
commit
64b8be1b39
|
@ -158,22 +158,19 @@ namespace Emby.Drawing
|
|||
}
|
||||
|
||||
var dateModified = options.Image.DateModified;
|
||||
var length = options.Image.Length;
|
||||
|
||||
if (options.CropWhiteSpace)
|
||||
{
|
||||
var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified, length).ConfigureAwait(false);
|
||||
var tuple = await GetWhitespaceCroppedImage(originalImagePath, dateModified).ConfigureAwait(false);
|
||||
|
||||
originalImagePath = tuple.Item1;
|
||||
dateModified = tuple.Item2;
|
||||
length = tuple.Item3;
|
||||
}
|
||||
|
||||
if (options.Enhancers.Count > 0)
|
||||
{
|
||||
var tuple = await GetEnhancedImage(new ItemImageInfo
|
||||
{
|
||||
Length = length,
|
||||
DateModified = dateModified,
|
||||
Type = options.Image.Type,
|
||||
Path = originalImagePath
|
||||
|
@ -182,7 +179,6 @@ namespace Emby.Drawing
|
|||
|
||||
originalImagePath = tuple.Item1;
|
||||
dateModified = tuple.Item2;
|
||||
length = tuple.Item3;
|
||||
}
|
||||
|
||||
var originalImageSize = GetImageSize(originalImagePath, dateModified);
|
||||
|
@ -199,7 +195,7 @@ namespace Emby.Drawing
|
|||
var quality = options.Quality ?? 90;
|
||||
|
||||
var outputFormat = GetOutputFormat(options.OutputFormat);
|
||||
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, length, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
|
||||
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
|
||||
|
||||
var semaphore = GetLock(cacheFilePath);
|
||||
|
||||
|
@ -240,11 +236,10 @@ namespace Emby.Drawing
|
|||
/// <summary>
|
||||
/// Crops whitespace from an image, caches the result, and returns the cached path
|
||||
/// </summary>
|
||||
private async Task<Tuple<string, DateTime, long>> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified, long length)
|
||||
private async Task<Tuple<string, DateTime>> GetWhitespaceCroppedImage(string originalImagePath, DateTime dateModified)
|
||||
{
|
||||
var name = originalImagePath;
|
||||
name += "datemodified=" + dateModified.Ticks;
|
||||
name += "length=" + length;
|
||||
|
||||
var croppedImagePath = GetCachePath(CroppedWhitespaceImageCachePath, name, Path.GetExtension(originalImagePath));
|
||||
|
||||
|
@ -270,7 +265,7 @@ namespace Emby.Drawing
|
|||
// We have to have a catch-all here because some of the .net image methods throw a plain old Exception
|
||||
_logger.ErrorException("Error cropping image {0}", ex, originalImagePath);
|
||||
|
||||
return new Tuple<string, DateTime, long>(originalImagePath, dateModified, length);
|
||||
return new Tuple<string, DateTime>(originalImagePath, dateModified);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -280,11 +275,9 @@ namespace Emby.Drawing
|
|||
return GetResult(croppedImagePath);
|
||||
}
|
||||
|
||||
private Tuple<string, DateTime, long> GetResult(string path)
|
||||
private Tuple<string, DateTime> GetResult(string path)
|
||||
{
|
||||
var file = new FileInfo(path);
|
||||
|
||||
return new Tuple<string, DateTime, long>(path, _fileSystem.GetLastWriteTimeUtc(file), file.Length);
|
||||
return new Tuple<string, DateTime>(path, _fileSystem.GetLastWriteTimeUtc(path));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -295,7 +288,7 @@ namespace Emby.Drawing
|
|||
/// <summary>
|
||||
/// Gets the cache file path based on a set of parameters
|
||||
/// </summary>
|
||||
private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, long length, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
|
||||
private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
|
||||
{
|
||||
var filename = originalPath;
|
||||
|
||||
|
@ -306,7 +299,6 @@ namespace Emby.Drawing
|
|||
filename += "quality=" + quality;
|
||||
|
||||
filename += "datemodified=" + dateModified.Ticks;
|
||||
filename += "length=" + length;
|
||||
|
||||
filename += "f=" + format;
|
||||
|
||||
|
@ -492,17 +484,16 @@ namespace Emby.Drawing
|
|||
var originalImagePath = image.Path;
|
||||
var dateModified = image.DateModified;
|
||||
var imageType = image.Type;
|
||||
var length = image.Length;
|
||||
|
||||
// Optimization
|
||||
if (imageEnhancers.Count == 0)
|
||||
{
|
||||
return (originalImagePath + dateModified.Ticks + string.Empty + length).GetMD5().ToString("N");
|
||||
return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N");
|
||||
}
|
||||
|
||||
// Cache name is created with supported enhancers combined with the last config change so we pick up new config changes
|
||||
var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
|
||||
cacheKeys.Add(originalImagePath + dateModified.Ticks + string.Empty + length);
|
||||
cacheKeys.Add(originalImagePath + dateModified.Ticks);
|
||||
|
||||
return string.Join("|", cacheKeys.ToArray()).GetMD5().ToString("N");
|
||||
}
|
||||
|
@ -525,7 +516,7 @@ namespace Emby.Drawing
|
|||
return result.Item1;
|
||||
}
|
||||
|
||||
private async Task<Tuple<string, DateTime, long>> GetEnhancedImage(ItemImageInfo image,
|
||||
private async Task<Tuple<string, DateTime>> GetEnhancedImage(ItemImageInfo image,
|
||||
IHasImages item,
|
||||
int imageIndex,
|
||||
List<IImageEnhancer> enhancers)
|
||||
|
@ -533,7 +524,6 @@ namespace Emby.Drawing
|
|||
var originalImagePath = image.Path;
|
||||
var dateModified = image.DateModified;
|
||||
var imageType = image.Type;
|
||||
var length = image.Length;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -553,7 +543,7 @@ namespace Emby.Drawing
|
|||
_logger.Error("Error enhancing image", ex);
|
||||
}
|
||||
|
||||
return new Tuple<string, DateTime, long>(originalImagePath, dateModified, length);
|
||||
return new Tuple<string, DateTime>(originalImagePath, dateModified);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -331,7 +331,6 @@ namespace MediaBrowser.Api
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Lower this hls timeout
|
||||
var timerDuration = job.Type == TranscodingJobType.Progressive ?
|
||||
1000 :
|
||||
1800000;
|
||||
|
@ -342,14 +341,17 @@ namespace MediaBrowser.Api
|
|||
timerDuration = 60000;
|
||||
}
|
||||
|
||||
job.PingTimeout = timerDuration;
|
||||
job.LastPingDate = DateTime.UtcNow;
|
||||
|
||||
// Don't start the timer for playback checkins with progressive streaming
|
||||
if (job.Type != TranscodingJobType.Progressive || !isProgressCheckIn)
|
||||
{
|
||||
job.StartKillTimer(timerDuration, OnTranscodeKillTimerStopped);
|
||||
job.StartKillTimer(OnTranscodeKillTimerStopped);
|
||||
}
|
||||
else
|
||||
{
|
||||
job.ChangeKillTimerIfStarted(timerDuration);
|
||||
job.ChangeKillTimerIfStarted();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,6 +363,15 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
var job = (TranscodingJob)state;
|
||||
|
||||
if (!job.HasExited && job.Type != TranscodingJobType.Progressive)
|
||||
{
|
||||
if ((DateTime.UtcNow - job.LastPingDate).TotalMilliseconds < job.PingTimeout)
|
||||
{
|
||||
job.StartKillTimer(OnTranscodeKillTimerStopped);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Debug("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId);
|
||||
|
||||
KillTranscodingJob(job, path => true);
|
||||
|
@ -627,6 +638,9 @@ namespace MediaBrowser.Api
|
|||
|
||||
private readonly object _timerLock = new object();
|
||||
|
||||
public DateTime LastPingDate { get; set; }
|
||||
public int PingTimeout { get; set; }
|
||||
|
||||
public TranscodingJob(ILogger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -655,12 +669,14 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
}
|
||||
|
||||
public void StartKillTimer(int intervalMs, TimerCallback callback)
|
||||
public void StartKillTimer(TimerCallback callback)
|
||||
{
|
||||
CheckHasExited();
|
||||
|
||||
lock (_timerLock)
|
||||
{
|
||||
var intervalMs = PingTimeout;
|
||||
|
||||
if (KillTimer == null)
|
||||
{
|
||||
Logger.Debug("Starting kill timer at {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
|
||||
|
@ -674,7 +690,7 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
}
|
||||
|
||||
public void ChangeKillTimerIfStarted(int intervalMs)
|
||||
public void ChangeKillTimerIfStarted()
|
||||
{
|
||||
CheckHasExited();
|
||||
|
||||
|
@ -682,6 +698,8 @@ namespace MediaBrowser.Api
|
|||
{
|
||||
if (KillTimer != null)
|
||||
{
|
||||
var intervalMs = PingTimeout;
|
||||
|
||||
Logger.Debug("Changing kill timer to {0}ms. JobId {1} PlaySessionId {2}", intervalMs, Id, PlaySessionId);
|
||||
KillTimer.Change(intervalMs, Timeout.Infinite);
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
|
||||
var views = user.RootFolder
|
||||
.GetChildren(user, true)
|
||||
.OfType<CollectionFolder>()
|
||||
.OfType<ICollectionFolder>()
|
||||
.Where(i => IsEligibleForSpecialView(i))
|
||||
.ToList();
|
||||
|
||||
|
@ -105,9 +105,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||
return ToOptimizedResult(list);
|
||||
}
|
||||
|
||||
private bool IsEligibleForSpecialView(CollectionFolder view)
|
||||
private bool IsEligibleForSpecialView(ICollectionFolder view)
|
||||
{
|
||||
var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music };
|
||||
var types = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Games, CollectionType.Music, CollectionType.Photos };
|
||||
|
||||
return types.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
|
|
@ -1512,7 +1512,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
image.Path = file.FullName;
|
||||
image.DateModified = imageInfo.DateModified;
|
||||
image.Length = imageInfo.Length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1622,14 +1621,11 @@ namespace MediaBrowser.Controller.Entities
|
|||
return null;
|
||||
}
|
||||
|
||||
var fileInfo = new FileInfo(path);
|
||||
|
||||
return new ItemImageInfo
|
||||
{
|
||||
Path = path,
|
||||
DateModified = FileSystem.GetLastWriteTimeUtc(fileInfo),
|
||||
Type = imageType,
|
||||
Length = fileInfo.Length
|
||||
DateModified = FileSystem.GetLastWriteTimeUtc(path),
|
||||
Type = imageType
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1690,7 +1686,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
else
|
||||
{
|
||||
existing.DateModified = FileSystem.GetLastWriteTimeUtc(newImage);
|
||||
existing.Length = ((FileInfo)newImage).Length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1716,8 +1711,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
Path = file.FullName,
|
||||
Type = type,
|
||||
DateModified = FileSystem.GetLastWriteTimeUtc(file),
|
||||
Length = ((FileInfo)file).Length
|
||||
DateModified = FileSystem.GetLastWriteTimeUtc(file)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1756,15 +1750,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
|
||||
FileSystem.SwapFiles(path1, path2);
|
||||
|
||||
var file1 = new FileInfo(info1.Path);
|
||||
var file2 = new FileInfo(info2.Path);
|
||||
|
||||
// Refresh these values
|
||||
info1.DateModified = FileSystem.GetLastWriteTimeUtc(file1);
|
||||
info2.DateModified = FileSystem.GetLastWriteTimeUtc(file2);
|
||||
|
||||
info1.Length = file1.Length;
|
||||
info2.Length = file2.Length;
|
||||
info1.DateModified = FileSystem.GetLastWriteTimeUtc(info1.Path);
|
||||
info2.DateModified = FileSystem.GetLastWriteTimeUtc(info2.Path);
|
||||
|
||||
return UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None);
|
||||
}
|
||||
|
|
|
@ -11,12 +11,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value>The path.</value>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the length.
|
||||
/// </summary>
|
||||
/// <value>The length.</value>
|
||||
public long Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type.
|
||||
/// </summary>
|
||||
|
|
|
@ -121,7 +121,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
|
||||
case CollectionType.Books:
|
||||
case CollectionType.Photos:
|
||||
case CollectionType.HomeVideos:
|
||||
case CollectionType.MusicVideos:
|
||||
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
|
||||
|
@ -138,6 +137,9 @@ namespace MediaBrowser.Controller.Entities
|
|||
case CollectionType.BoxSets:
|
||||
return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.Photos:
|
||||
return await GetPhotosView(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
case CollectionType.TvShows:
|
||||
return await GetTvView(queryParent, user, query).ConfigureAwait(false);
|
||||
|
||||
|
@ -247,16 +249,16 @@ namespace MediaBrowser.Controller.Entities
|
|||
return GetFavoriteSongs(queryParent, user, query);
|
||||
|
||||
default:
|
||||
{
|
||||
if (queryParent is UserView)
|
||||
{
|
||||
return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query);
|
||||
if (queryParent is UserView)
|
||||
{
|
||||
return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -645,6 +647,19 @@ namespace MediaBrowser.Controller.Entities
|
|||
}), parent, query);
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetPhotosView(Folder queryParent, User user, InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive)
|
||||
{
|
||||
var mediaTypes = new[] { MediaType.Video, MediaType.Photo };
|
||||
var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Photos, string.Empty }, i => (i is PhotoAlbum || mediaTypes.Contains(i.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) && FilterItem(i, query));
|
||||
|
||||
return PostFilterAndSort(items, queryParent, null, query);
|
||||
}
|
||||
|
||||
return GetResult(queryParent.GetChildren(user, true), queryParent, query);
|
||||
}
|
||||
|
||||
private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive)
|
||||
|
|
|
@ -488,6 +488,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Dto\ItemIndex.cs">
|
||||
<Link>Dto\ItemIndex.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\ItemLayout.cs">
|
||||
<Link>Dto\ItemLayout.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\MediaSourceInfo.cs">
|
||||
<Link>Dto\MediaSourceInfo.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -453,6 +453,9 @@
|
|||
<Compile Include="..\MediaBrowser.Model\Dto\ItemIndex.cs">
|
||||
<Link>Dto\ItemIndex.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\ItemLayout.cs">
|
||||
<Link>Dto\ItemLayout.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\MediaBrowser.Model\Dto\MediaSourceInfo.cs">
|
||||
<Link>Dto\MediaSourceInfo.cs</Link>
|
||||
</Compile>
|
||||
|
|
|
@ -98,7 +98,7 @@ namespace MediaBrowser.Model.ApiClient
|
|||
{
|
||||
var index = 0;
|
||||
|
||||
foreach (var server in servers)
|
||||
foreach (ServerInfo server in servers)
|
||||
{
|
||||
if (StringHelper.EqualsIgnoreCase(id, server.Id))
|
||||
{
|
||||
|
@ -110,5 +110,18 @@ namespace MediaBrowser.Model.ApiClient
|
|||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ServerInfo GetServer(string id)
|
||||
{
|
||||
foreach (ServerInfo server in Servers)
|
||||
{
|
||||
if (StringHelper.EqualsIgnoreCase(id, server.Id))
|
||||
{
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
72
MediaBrowser.Model/Dto/ItemLayout.cs
Normal file
72
MediaBrowser.Model/Dto/ItemLayout.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.Dto
|
||||
{
|
||||
public static class ItemLayout
|
||||
{
|
||||
public static double? GetDisplayAspectRatio(BaseItemDto item)
|
||||
{
|
||||
List<BaseItemDto> items = new List<BaseItemDto>();
|
||||
items.Add(item);
|
||||
return GetDisplayAspectRatio(items);
|
||||
}
|
||||
|
||||
public static double? GetDisplayAspectRatio(List<BaseItemDto> items)
|
||||
{
|
||||
List<double> values = new List<double>();
|
||||
|
||||
foreach (BaseItemDto item in items)
|
||||
{
|
||||
if (item.PrimaryImageAspectRatio.HasValue)
|
||||
{
|
||||
values.Add(item.PrimaryImageAspectRatio.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (values.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
values.Sort();
|
||||
|
||||
double halfDouble = values.Count;
|
||||
halfDouble /= 2;
|
||||
int half = Convert.ToInt32(Math.Floor(halfDouble));
|
||||
|
||||
double result;
|
||||
|
||||
if (values.Count % 2 > 0)
|
||||
result = values[half];
|
||||
else
|
||||
result = (values[half - 1] + values[half]) / 2.0;
|
||||
|
||||
// If really close to 2:3 (poster image), just return 2:3
|
||||
if (Math.Abs(0.66666666667 - result) <= .15)
|
||||
{
|
||||
return 0.66666666667;
|
||||
}
|
||||
|
||||
// If really close to 16:9 (episode image), just return 16:9
|
||||
if (Math.Abs(1.777777778 - result) <= .2)
|
||||
{
|
||||
return 1.777777778;
|
||||
}
|
||||
|
||||
// If really close to 1 (square image), just return 1
|
||||
if (Math.Abs(1 - result) <= .15)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
// If really close to 4:3 (poster image), just return 2:3
|
||||
if (Math.Abs(1.33333333333 - result) <= .15)
|
||||
{
|
||||
return 1.33333333333;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -139,6 +139,7 @@
|
|||
<Compile Include="Drawing\ImageOrientation.cs" />
|
||||
<Compile Include="Dto\IHasServerId.cs" />
|
||||
<Compile Include="Dto\IHasSyncInfo.cs" />
|
||||
<Compile Include="Dto\ItemLayout.cs" />
|
||||
<Compile Include="Dto\MetadataEditorInfo.cs" />
|
||||
<Compile Include="Dto\NameIdPair.cs" />
|
||||
<Compile Include="Dto\NameValuePair.cs" />
|
||||
|
|
|
@ -384,7 +384,6 @@ namespace MediaBrowser.Providers.Manager
|
|||
else
|
||||
{
|
||||
currentImage.DateModified = _fileSystem.GetLastWriteTimeUtc(image.FileInfo);
|
||||
currentImage.Length = ((FileInfo) image.FileInfo).Length;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -482,6 +482,11 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
protected virtual bool IsFullLocalMetadata(TItemType item)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item.Name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,10 +36,6 @@ namespace MediaBrowser.Providers.Movies
|
|||
|
||||
protected override bool IsFullLocalMetadata(Movie item)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item.Name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(item.Overview))
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -77,10 +77,6 @@ namespace MediaBrowser.Providers.TV
|
|||
|
||||
protected override bool IsFullLocalMetadata(Series item)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item.Name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(item.Overview))
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -243,7 +243,15 @@ namespace MediaBrowser.Providers.TV
|
|||
await SanitizeXmlFile(file).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await ExtractEpisodes(seriesDataPath, Path.Combine(seriesDataPath, saveAsMetadataLanguage + ".xml"), lastTvDbUpdateTime).ConfigureAwait(false);
|
||||
var downloadLangaugeXmlFile = Path.Combine(seriesDataPath, preferredMetadataLanguage + ".xml");
|
||||
var saveAsLanguageXmlFile = Path.Combine(seriesDataPath, saveAsMetadataLanguage + ".xml");
|
||||
|
||||
if (!string.Equals(downloadLangaugeXmlFile, saveAsLanguageXmlFile, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
File.Copy(downloadLangaugeXmlFile, saveAsLanguageXmlFile, true);
|
||||
}
|
||||
|
||||
await ExtractEpisodes(seriesDataPath, downloadLangaugeXmlFile, lastTvDbUpdateTime).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public TvdbOptions GetTvDbOptions()
|
||||
|
|
|
@ -828,14 +828,11 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
|
||||
if (!string.IsNullOrEmpty(chapterInfo.ImagePath))
|
||||
{
|
||||
var file = new FileInfo(chapterInfo.ImagePath);
|
||||
|
||||
dto.ImageTag = GetImageCacheTag(item, new ItemImageInfo
|
||||
{
|
||||
Path = chapterInfo.ImagePath,
|
||||
Type = ImageType.Chapter,
|
||||
DateModified = _fileSystem.GetLastWriteTimeUtc(file),
|
||||
Length = file.Length
|
||||
DateModified = _fileSystem.GetLastWriteTimeUtc(chapterInfo.ImagePath)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Linq;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
@ -139,55 +138,24 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
|
|||
// On some systems the device discovered event seems to fire repeatedly
|
||||
// This check will help ensure we're not trying to port map the same device over and over
|
||||
|
||||
List<Mapping> currentMappings = null;
|
||||
|
||||
try
|
||||
{
|
||||
currentMappings = device.GetAllMappings().ToList();
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
}
|
||||
|
||||
var address = device.LocalAddress.ToString();
|
||||
|
||||
if (!_createdRules.Contains(address))
|
||||
{
|
||||
_createdRules.Add(address);
|
||||
|
||||
CreatePortMap(device, currentMappings, _appHost.HttpPort, _config.Configuration.PublicPort);
|
||||
CreatePortMap(device, currentMappings, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort);
|
||||
CreatePortMap(device, _appHost.HttpPort, _config.Configuration.PublicPort);
|
||||
CreatePortMap(device, _appHost.HttpsPort, _config.Configuration.PublicHttpsPort);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreatePortMap(INatDevice device, List<Mapping> currentMappings, int privatePort, int publicPort)
|
||||
private void CreatePortMap(INatDevice device, int privatePort, int publicPort)
|
||||
{
|
||||
var hasMapping = false;
|
||||
|
||||
if (currentMappings != null)
|
||||
_logger.Debug("Creating port map on port {0}", privatePort);
|
||||
device.CreatePortMap(new Mapping(Protocol.Tcp, privatePort, publicPort)
|
||||
{
|
||||
hasMapping = currentMappings.Any(i => i.PublicPort == publicPort && i.PrivatePort == privatePort);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var mapping = device.GetSpecificMapping(Protocol.Tcp, publicPort);
|
||||
hasMapping = mapping != null;
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasMapping)
|
||||
{
|
||||
_logger.Debug("Creating port map on port {0}", privatePort);
|
||||
device.CreatePortMap(new Mapping(Protocol.Tcp, privatePort, publicPort)
|
||||
{
|
||||
Description = _appHost.Name
|
||||
});
|
||||
}
|
||||
Description = _appHost.Name
|
||||
});
|
||||
}
|
||||
|
||||
// As I said before, this method will be never invoked. You can remove it.
|
||||
|
|
|
@ -1723,7 +1723,7 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 12;
|
||||
var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
|
|
|
@ -202,9 +202,15 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
public async Task<UserView> GetUserView(List<ICollectionFolder> parents, string viewType, string sortName, User user, CancellationToken cancellationToken)
|
||||
{
|
||||
var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
|
||||
|
||||
if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var name = parents[0].Name;
|
||||
if (!string.IsNullOrWhiteSpace(parents[0].Name))
|
||||
{
|
||||
name = parents[0].Name;
|
||||
}
|
||||
|
||||
var parentId = parents[0].Id;
|
||||
|
||||
var enableRichView = !user.Configuration.PlainFolderViews.Contains(parentId.ToString("N"), StringComparer.OrdinalIgnoreCase);
|
||||
|
@ -226,8 +232,6 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
}
|
||||
else
|
||||
{
|
||||
var name = _localizationManager.GetLocalizedString("ViewType" + viewType);
|
||||
|
||||
return await _libraryManager.GetNamedView(user, name, viewType, sortName, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
|
||||
private async Task AddMediaInfo(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
|
||||
{
|
||||
var inputPaths = new[] { mediaSource.Path };
|
||||
var originalRuntime = mediaSource.RunTimeTicks;
|
||||
|
||||
var info = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
|
||||
{
|
||||
|
@ -131,8 +131,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
|
||||
ExtractChapters = false
|
||||
|
||||
}, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
mediaSource.Bitrate = info.Bitrate;
|
||||
mediaSource.Container = info.Container;
|
||||
|
@ -146,6 +145,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv
|
|||
|
||||
mediaSource.DefaultSubtitleStreamIndex = null;
|
||||
|
||||
// Null this out so that it will be treated like a live stream
|
||||
if (!originalRuntime.HasValue)
|
||||
{
|
||||
mediaSource.RunTimeTicks = null;
|
||||
}
|
||||
|
||||
var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == Model.Entities.MediaStreamType.Audio);
|
||||
|
||||
if (audioStream == null || audioStream.Index == -1)
|
||||
|
|
|
@ -1433,5 +1433,7 @@
|
|||
"ToAccessPreferencesHelp": "To access your preferences later, click your user icon in the top right header and select My Preferences.",
|
||||
"HeaderViewStyles": "View Styles",
|
||||
"LabelSelectViewStyles": "Enable rich presentations for:",
|
||||
"LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders."
|
||||
"LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.",
|
||||
"TabPhotos": "Photos",
|
||||
"TabVideos": "Videos"
|
||||
}
|
||||
|
|
|
@ -470,6 +470,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
"notificationlist.js",
|
||||
"notificationsetting.js",
|
||||
"notificationsettings.js",
|
||||
"photos.js",
|
||||
"playlists.js",
|
||||
"playlistedit.js",
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
<Content Include="dashboard-ui\mysyncjob.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\ReportManager.html">
|
||||
<Content Include="dashboard-ui\photos.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\dashboardhosting.js">
|
||||
|
@ -150,7 +150,7 @@
|
|||
<Content Include="dashboard-ui\scripts\livetvitems.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\reportmanager.js">
|
||||
<Content Include="dashboard-ui\scripts\photos.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\scripts\selectserver.js">
|
||||
|
|
Loading…
Reference in New Issue
Block a user