Conflicts:
	MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
This commit is contained in:
Tavares André 2015-04-20 19:07:29 +02:00
commit 64b8be1b39
24 changed files with 204 additions and 126 deletions

View File

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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View 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;
}
}
}

View File

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

View File

@ -384,7 +384,6 @@ namespace MediaBrowser.Providers.Manager
else
{
currentImage.DateModified = _fileSystem.GetLastWriteTimeUtc(image.FileInfo);
currentImage.Length = ((FileInfo) image.FileInfo).Length;
}
}
else

View File

@ -482,6 +482,11 @@ namespace MediaBrowser.Providers.Manager
protected virtual bool IsFullLocalMetadata(TItemType item)
{
if (string.IsNullOrWhiteSpace(item.Name))
{
return false;
}
return true;
}

View File

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

View File

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

View File

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

View File

@ -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)
});
}

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

@ -470,6 +470,7 @@ namespace MediaBrowser.WebDashboard.Api
"notificationlist.js",
"notificationsetting.js",
"notificationsettings.js",
"photos.js",
"playlists.js",
"playlistedit.js",

View File

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