Merge pull request #2101 from MediaBrowser/beta

Beta
This commit is contained in:
Luke 2016-08-25 14:46:19 -04:00 committed by GitHub
commit ba9577f380
78 changed files with 975 additions and 835 deletions

View file

@ -33,7 +33,9 @@ namespace Emby.Drawing.GDI
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingMode = CompositingMode.SourceCopy;
// SourceCopy causes the image to be blank in OSX
//graphics.CompositingMode = CompositingMode.SourceCopy;
for (var row = 0; row < rows; row++)
{
@ -44,19 +46,9 @@ namespace Emby.Drawing.GDI
if (files.Count > index)
{
using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
using (var imgtemp = Image.FromFile(files[index]))
{
using (var memoryStream = new MemoryStream())
{
fileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
using (var imgtemp = Image.FromStream(memoryStream, true, false))
{
graphics.DrawImage(imgtemp, x, y, cellWidth, cellHeight);
}
}
graphics.DrawImage(imgtemp, x, y, cellWidth, cellHeight);
}
}
@ -90,7 +82,9 @@ namespace Emby.Drawing.GDI
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingMode = CompositingMode.SourceCopy;
// SourceCopy causes the image to be blank in OSX
//graphics.CompositingMode = CompositingMode.SourceCopy;
for (var row = 0; row < rows; row++)
{
@ -99,21 +93,10 @@ namespace Emby.Drawing.GDI
var x = col * singleSize;
var y = row * singleSize;
using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
using (var imgtemp = Image.FromFile(files[index]))
{
using (var memoryStream = new MemoryStream())
{
fileStream.CopyTo(memoryStream);
memoryStream.Position = 0;
using (var imgtemp = Image.FromStream(memoryStream, true, false))
{
graphics.DrawImage(imgtemp, x, y, singleSize, singleSize);
}
}
graphics.DrawImage(imgtemp, x, y, singleSize, singleSize);
}
index++;
}
}
@ -121,16 +104,5 @@ namespace Emby.Drawing.GDI
}
}
}
private static Stream GetStream(Image image)
{
var ms = new MemoryStream();
image.Save(ms, ImageFormat.Png);
ms.Position = 0;
return ms;
}
}
}

View file

@ -119,9 +119,11 @@ namespace Emby.Drawing.GDI
thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
thumbnailGraph.CompositingMode = !hasPostProcessing ?
CompositingMode.SourceCopy :
CompositingMode.SourceOver;
// SourceCopy causes the image to be blank in OSX
//thumbnailGraph.CompositingMode = !hasPostProcessing ?
// CompositingMode.SourceCopy :
// CompositingMode.SourceOver;
SetBackgroundColor(thumbnailGraph, options);

View file

@ -154,9 +154,12 @@ namespace MediaBrowser.Api.Library
public void Post(PerformOrganization request)
{
// Don't await this
var task = _iFileOrganizationService.PerformOrganization(request.Id);
Task.WaitAll(task);
// Async processing (close dialog early instead of waiting until the file has been copied)
// Wait 2s for exceptions that may occur to have them forwarded to the client for immediate error display
task.Wait(2000);
}
public void Post(OrganizeEpisode request)
@ -168,6 +171,7 @@ namespace MediaBrowser.Api.Library
dicNewProviderIds = request.NewSeriesProviderIds;
}
// Don't await this
var task = _iFileOrganizationService.PerformEpisodeOrganization(new EpisodeFileOrganizationRequest
{
EndingEpisodeNumber = request.EndingEpisodeNumber,
@ -182,11 +186,9 @@ namespace MediaBrowser.Api.Library
TargetFolder = request.TargetFolder
});
// For async processing (close dialog early instead of waiting until the file has been copied)
//var tasks = new Task[] { task };
//Task.WaitAll(tasks, 8000);
Task.WaitAll(task);
// Async processing (close dialog early instead of waiting until the file has been copied)
// Wait 2s for exceptions that may occur to have them forwarded to the client for immediate error display
task.Wait(2000);
}
public object Get(GetSmartMatchInfos request)

View file

@ -192,7 +192,8 @@ namespace MediaBrowser.Api.Movies
SortOrder = SortOrder.Descending,
Limit = 7,
ParentId = parentIdGuid,
Recursive = true
Recursive = true,
IsPlayed = true
};
var recentlyPlayedMovies = _libraryManager.GetItemList(query).ToList();

View file

@ -298,7 +298,8 @@ namespace MediaBrowser.Api.Playback
// Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
if (state.VideoType == VideoType.VideoFile)
{
var hwType = ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType;
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
var hwType = encodingOptions.HardwareAccelerationType;
if (string.Equals(hwType, "qsv", StringComparison.OrdinalIgnoreCase) ||
string.Equals(hwType, "h264_qsv", StringComparison.OrdinalIgnoreCase))
@ -314,6 +315,10 @@ namespace MediaBrowser.Api.Playback
{
return GetAvailableEncoder("h264_omx", defaultEncoder);
}
if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(encodingOptions.VaapiDevice))
{
return GetAvailableEncoder("h264_vaapi", defaultEncoder);
}
}
return defaultEncoder;
@ -427,7 +432,8 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(state.VideoRequest.Profile))
{
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
param += " -profile:v " + state.VideoRequest.Profile;
@ -482,7 +488,8 @@ namespace MediaBrowser.Api.Playback
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
@ -548,59 +555,97 @@ namespace MediaBrowser.Api.Playback
var filters = new List<string>();
if (state.DeInterlace)
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
filters.Add("format=nv12|vaapi");
filters.Add("hwupload");
}
else if (state.DeInterlace && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
filters.Add("yadif=0:-1:0");
}
// If fixed dimensions were supplied
if (request.Width.HasValue && request.Height.HasValue)
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
var widthParam = request.Width.Value.ToString(UsCulture);
var heightParam = request.Height.Value.ToString(UsCulture);
// Work around vaapi's reduced scaling features
var scaler = "scale_vaapi";
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", widthParam, heightParam));
// Given the input dimensions (inputWidth, inputHeight), determine the output dimensions
// (outputWidth, outputHeight). The user may request precise output dimensions or maximum
// output dimensions. Output dimensions are guaranteed to be even.
decimal inputWidth = Convert.ToDecimal(state.VideoStream.Width);
decimal inputHeight = Convert.ToDecimal(state.VideoStream.Height);
decimal outputWidth = request.Width.HasValue ? Convert.ToDecimal(request.Width.Value) : inputWidth;
decimal outputHeight = request.Height.HasValue ? Convert.ToDecimal(request.Height.Value) : inputHeight;
decimal maximumWidth = request.MaxWidth.HasValue ? Convert.ToDecimal(request.MaxWidth.Value) : outputWidth;
decimal maximumHeight = request.MaxHeight.HasValue ? Convert.ToDecimal(request.MaxHeight.Value) : outputHeight;
if (outputWidth > maximumWidth || outputHeight > maximumHeight)
{
var scale = Math.Min(maximumWidth / outputWidth, maximumHeight / outputHeight);
outputWidth = Math.Min(maximumWidth, Math.Truncate(outputWidth * scale));
outputHeight = Math.Min(maximumHeight, Math.Truncate(outputHeight * scale));
}
outputWidth = 2 * Math.Truncate(outputWidth / 2);
outputHeight = 2 * Math.Truncate(outputHeight / 2);
if (outputWidth != inputWidth || outputHeight != inputHeight)
{
filters.Add(string.Format("{0}=w={1}:h={2}", scaler, outputWidth.ToString(UsCulture), outputHeight.ToString(UsCulture)));
}
}
// If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
else if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
else
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
// If fixed dimensions were supplied
if (request.Width.HasValue && request.Height.HasValue)
{
var widthParam = request.Width.Value.ToString(UsCulture);
var heightParam = request.Height.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
}
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", widthParam, heightParam));
}
// If a fixed width was requested
else if (request.Width.HasValue)
{
var widthParam = request.Width.Value.ToString(UsCulture);
// If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
else if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
filters.Add(string.Format("scale={0}:trunc(ow/a/2)*2", widthParam));
}
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
}
// If a fixed height was requested
else if (request.Height.HasValue)
{
var heightParam = request.Height.Value.ToString(UsCulture);
// If a fixed width was requested
else if (request.Width.HasValue)
{
var widthParam = request.Width.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(oh*a/2)*2:{0}", heightParam));
}
filters.Add(string.Format("scale={0}:trunc(ow/a/2)*2", widthParam));
}
// If a max width was requested
else if (request.MaxWidth.HasValue)
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
// If a fixed height was requested
else if (request.Height.HasValue)
{
var heightParam = request.Height.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam));
}
filters.Add(string.Format("scale=trunc(oh*a/2)*2:{0}", heightParam));
}
// If a max height was requested
else if (request.MaxHeight.HasValue)
{
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
// If a max width was requested
else if (request.MaxWidth.HasValue)
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam));
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam));
}
// If a max height was requested
else if (request.MaxHeight.HasValue)
{
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(max(iw/dar\\,ih)\\,{0})", maxHeightParam));
}
}
var output = string.Empty;
@ -935,6 +980,17 @@ namespace MediaBrowser.Api.Playback
}
}
if (state.VideoRequest != null)
{
var encodingOptions = ApiEntryPoint.Instance.GetEncodingOptions();
if (GetVideoEncoder(state).IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1)
{
arg = "-hwaccel vaapi -hwaccel_output_format vaapi -vaapi_device " + encodingOptions.VaapiDevice + " " + arg;
}
}
arg += string.Format(" -ss {0}", MediaEncoder.GetTimeParameter(TimeSpan.FromSeconds(1).Ticks));
return arg.Trim();
}
@ -1589,13 +1645,6 @@ namespace MediaBrowser.Api.Playback
}
}
else if (i == 25)
{
if (videoRequest != null)
{
videoRequest.ForceLiveStream = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
}
}
else if (i == 26)
{
if (!string.IsNullOrWhiteSpace(val) && videoRequest != null)
{
@ -1606,18 +1655,18 @@ namespace MediaBrowser.Api.Playback
}
}
}
else if (i == 27)
else if (i == 26)
{
request.TranscodingMaxAudioChannels = int.Parse(val, UsCulture);
}
else if (i == 28)
else if (i == 27)
{
if (videoRequest != null)
{
videoRequest.EnableSubtitlesInManifest = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
}
}
else if (i == 29)
else if (i == 28)
{
request.Tag = val;
}
@ -2218,7 +2267,6 @@ namespace MediaBrowser.Api.Playback
if (state.VideoRequest != null)
{
state.VideoRequest.CopyTimestamps = transcodingProfile.CopyTimestamps;
state.VideoRequest.ForceLiveStream = transcodingProfile.ForceLiveStream;
state.VideoRequest.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
}
}
@ -2244,7 +2292,7 @@ namespace MediaBrowser.Api.Playback
return Task.FromResult(true);
}
if (!string.Equals(MediaEncoder.EncoderLocationType, "Default", StringComparison.OrdinalIgnoreCase))
if (!MediaEncoder.IsDefaultEncoderPath)
{
return Task.FromResult(true);
}

View file

@ -281,11 +281,6 @@ namespace MediaBrowser.Api.Playback.Hls
{
var isLiveStream = (state.RunTimeTicks ?? 0) == 0;
if (state.VideoRequest.ForceLiveStream)
{
return true;
}
return isLiveStream;
}
}

View file

@ -193,8 +193,6 @@ namespace MediaBrowser.Api.Playback
[ApiMember(Name = "CopyTimestamps", Description = "Whether or not to copy timestamps when transcoding with an offset. Defaults to false.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool CopyTimestamps { get; set; }
public bool ForceLiveStream { get; set; }
public bool EnableSubtitlesInManifest { get; set; }
public VideoStreamRequest()

View file

@ -275,8 +275,6 @@ namespace MediaBrowser.Api.Reports
case ItemFilter.IsPlayed:
query.IsPlayed = true;
break;
case ItemFilter.IsRecentlyAdded:
break;
case ItemFilter.IsResumable:
query.IsResumable = true;
break;

View file

@ -24,6 +24,19 @@ namespace MediaBrowser.Api.Sync
}
break;
}
if (item.IsAudio)
{
options.Add(SyncJobOption.Quality);
options.Add(SyncJobOption.Profile);
break;
}
if (item.IsMusicGenre || item.IsArtist|| item.IsType("musicalbum"))
{
options.Add(SyncJobOption.Quality);
options.Add(SyncJobOption.Profile);
options.Add(SyncJobOption.ItemLimit);
break;
}
if (item.IsFolderItem && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre)
{
options.Add(SyncJobOption.Quality);

View file

@ -291,7 +291,8 @@ namespace MediaBrowser.Api.Sync
{
Fields = new List<ItemFields>
{
ItemFields.SyncInfo
ItemFields.SyncInfo,
ItemFields.BasicSyncInfo
}
};

View file

@ -164,8 +164,6 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsPlayed:
query.IsPlayed = true;
break;
case ItemFilter.IsRecentlyAdded:
break;
case ItemFilter.IsResumable:
query.IsResumable = true;
break;

View file

@ -149,24 +149,6 @@ namespace MediaBrowser.Api.UserLibrary
item = user == null ? _libraryManager.RootFolder : user.RootFolder;
}
if (!string.IsNullOrEmpty(request.Ids))
{
var query = GetItemsQuery(request, user);
var specificItems = _libraryManager.GetItemList(query).ToArray();
if (query.SortBy.Length == 0)
{
var ids = query.ItemIds.ToList();
// Try to preserve order
specificItems = specificItems.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
}
return new QueryResult<BaseItem>
{
Items = specificItems.ToArray(),
TotalRecordCount = specificItems.Length
};
}
// Default list type = children
var folder = item as Folder;
@ -289,8 +271,6 @@ namespace MediaBrowser.Api.UserLibrary
case ItemFilter.IsPlayed:
query.IsPlayed = true;
break;
case ItemFilter.IsRecentlyAdded:
break;
case ItemFilter.IsResumable:
query.IsResumable = true;
break;

View file

@ -33,7 +33,6 @@ namespace MediaBrowser.Common.Implementations.Updates
EnableKeepAlive = false,
CancellationToken = cancellationToken,
UserAgent = "Emby/3.0"
};
if (_cacheLength.Ticks > 0)

View file

@ -281,6 +281,20 @@ namespace MediaBrowser.Controller.Entities
}
}
public Task UpdateIsOffline(bool newValue)
{
var item = this;
if (item.IsOffline != newValue)
{
item.IsOffline = newValue;
// this is creating too many repeated db updates
//return item.UpdateToRepository(ItemUpdateType.None, CancellationToken.None);
}
return Task.FromResult(true);
}
/// <summary>
/// Gets or sets the type of the location.
/// </summary>
@ -290,10 +304,10 @@ namespace MediaBrowser.Controller.Entities
{
get
{
if (IsOffline)
{
return LocationType.Offline;
}
//if (IsOffline)
//{
// return LocationType.Offline;
//}
if (string.IsNullOrWhiteSpace(Path))
{

View file

@ -106,6 +106,7 @@ namespace MediaBrowser.Controller.Entities
{
LibraryOptions[path] = options;
options.SchemaVersion = 1;
XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path));
}
}

View file

@ -375,7 +375,7 @@ namespace MediaBrowser.Controller.Entities
if (currentChildren.TryGetValue(child.Id, out currentChild) && IsValidFromResolver(currentChild, child))
{
await UpdateIsOffline(currentChild, false).ConfigureAwait(false);
await currentChild.UpdateIsOffline(false).ConfigureAwait(false);
validChildren.Add(currentChild);
continue;
@ -404,7 +404,7 @@ namespace MediaBrowser.Controller.Entities
else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path))
{
await UpdateIsOffline(item, true).ConfigureAwait(false);
await item.UpdateIsOffline(true).ConfigureAwait(false);
}
else
{
@ -461,17 +461,6 @@ namespace MediaBrowser.Controller.Entities
progress.Report(100);
}
private Task UpdateIsOffline(BaseItem item, bool newValue)
{
if (item.IsOffline != newValue)
{
item.IsOffline = newValue;
return item.UpdateToRepository(ItemUpdateType.None, CancellationToken.None);
}
return Task.FromResult(true);
}
private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
{
var children = ActualChildren.ToList();
@ -902,16 +891,16 @@ namespace MediaBrowser.Controller.Entities
{
if (query.ItemIds.Length > 0)
{
var specificItems = query.ItemIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList();
var result = LibraryManager.GetItemsResult(query);
if (query.SortBy.Length == 0)
{
var ids = query.ItemIds.ToList();
// Try to preserve order
specificItems = specificItems.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToList();
result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray();
}
return Task.FromResult(PostFilterAndSort(specificItems, query, true, true));
return Task.FromResult(result);
}
return GetItemsInternal(query);

View file

@ -135,7 +135,11 @@ namespace MediaBrowser.Controller.Entities.TV
[IgnoreDataMember]
public Series Series
{
get { return FindParent<Series>(); }
get
{
var seriesId = SeriesId ?? FindSeriesId();
return seriesId.HasValue ? (LibraryManager.GetItemById(seriesId.Value) as Series) : null;
}
}
[IgnoreDataMember]
@ -143,24 +147,8 @@ namespace MediaBrowser.Controller.Entities.TV
{
get
{
var season = FindParent<Season>();
// Episodes directly in series folder
if (season == null)
{
var series = Series;
if (series != null && ParentIndexNumber.HasValue)
{
var findNumber = ParentIndexNumber.Value;
season = series.Children
.OfType<Season>()
.FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == findNumber);
}
}
return season;
var seasonId = SeasonId ?? FindSeasonId();
return seasonId.HasValue ? (LibraryManager.GetItemById(seasonId.Value) as Season) : null;
}
}
@ -193,7 +181,23 @@ namespace MediaBrowser.Controller.Entities.TV
public Guid? FindSeasonId()
{
var season = Season;
var season = FindParent<Season>();
// Episodes directly in series folder
if (season == null)
{
var series = Series;
if (series != null && ParentIndexNumber.HasValue)
{
var findNumber = ParentIndexNumber.Value;
season = series.Children
.OfType<Season>()
.FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == findNumber);
}
}
return season == null ? (Guid?)null : season.Id;
}
@ -263,7 +267,7 @@ namespace MediaBrowser.Controller.Entities.TV
public Guid? FindSeriesId()
{
var series = Series;
var series = FindParent<Series>();
return series == null ? (Guid?)null : series.Id;
}

View file

@ -99,7 +99,11 @@ namespace MediaBrowser.Controller.Entities.TV
[IgnoreDataMember]
public Series Series
{
get { return FindParent<Series>(); }
get
{
var seriesId = SeriesId ?? FindSeriesId();
return seriesId.HasValue ? (LibraryManager.GetItemById(seriesId.Value) as Series) : null;
}
}
[IgnoreDataMember]
@ -241,7 +245,7 @@ namespace MediaBrowser.Controller.Entities.TV
public Guid? FindSeriesId()
{
var series = Series;
var series = FindParent<Series>();
return series == null ? (Guid?)null : series.Id;
}

View file

@ -1,5 +1,7 @@
using MediaBrowser.Model.FileOrganization;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.FileOrganization;
using MediaBrowser.Model.Querying;
using System;
using System.Threading;
using System.Threading.Tasks;
@ -7,6 +9,11 @@ namespace MediaBrowser.Controller.FileOrganization
{
public interface IFileOrganizationService
{
event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemAdded;
event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemUpdated;
event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemRemoved;
event EventHandler LogReset;
/// <summary>
/// Processes the new files.
/// </summary>
@ -81,5 +88,20 @@ namespace MediaBrowser.Controller.FileOrganization
/// <param name="ItemName">Item name.</param>
/// <param name="matchString">The match string to delete.</param>
void DeleteSmartMatchEntry(string ItemName, string matchString);
/// <summary>
/// Attempts to add a an item to the list of currently processed items.
/// </summary>
/// <param name="result">The result item.</param>
/// <param name="fullClientRefresh">Passing true will notify the client to reload all items, otherwise only a single item will be refreshed.</param>
/// <returns>True if the item was added, False if the item is already contained in the list.</returns>
bool AddToInProgressList(FileOrganizationResult result, bool fullClientRefresh);
/// <summary>
/// Removes an item from the list of currently processed items.
/// </summary>
/// <param name="result">The result item.</param>
/// <returns>True if the item was removed, False if the item was not contained in the list.</returns>
bool RemoveFromInprogressList(FileOrganizationResult result);
}
}

View file

@ -134,5 +134,6 @@ namespace MediaBrowser.Controller.MediaEncoding
Task UpdateEncoderPath(string path, string pathType);
bool SupportsEncoder(string encoder);
bool IsDefaultEncoderPath { get; }
}
}

View file

@ -36,8 +36,13 @@ namespace MediaBrowser.Controller.MediaEncoding
return new[] {videoPath};
}
public static List<string> GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, IEnumerable<string> filenames)
private static List<string> GetPlayableStreamFiles(IFileSystem fileSystem, string rootPath, List<string> filenames)
{
if (filenames.Count == 0)
{
return new List<string>();
}
var allFiles = fileSystem
.GetFilePaths(rootPath, true)
.ToList();

View file

@ -724,6 +724,15 @@ namespace MediaBrowser.Controller.Providers
}
break;
}
case "TvMazeId":
{
var id = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(id))
{
item.SetProviderId(MetadataProviders.TvMaze, id);
}
break;
}
case "AudioDbArtistId":
{
var id = reader.ReadElementContentAsString();

View file

@ -172,15 +172,21 @@ namespace MediaBrowser.Controller.Session
Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken);
/// <summary>
/// Sends the message to user sessions.
/// Sends the message to admin sessions.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="userId">The user identifier.</param>
/// <param name="name">The name.</param>
/// <param name="data">The data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SendMessageToUserSessions<T>(string userId, string name, T data, CancellationToken cancellationToken);
Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken);
/// <summary>
/// Sends the message to user sessions.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>Task.</returns>
Task SendMessageToUserSessions<T>(List<string> userIds, string name, T data, CancellationToken cancellationToken);
/// <summary>
/// Sends the message to user device sessions.

View file

@ -479,17 +479,17 @@ namespace MediaBrowser.Dlna.PlayTo
_successiveStopCount++;
_connectFailureCount++;
if (_successiveStopCount >= maxSuccessiveStopReturns)
{
RestartTimerInactive();
}
if (_connectFailureCount >= maxSuccessiveStopReturns)
if (_connectFailureCount >= 3)
{
if (OnDeviceUnavailable != null)
{
OnDeviceUnavailable();
}
}
if (_successiveStopCount >= maxSuccessiveStopReturns)
{
RestartTimerInactive();
}
}
catch (Exception ex)
{

View file

@ -99,11 +99,11 @@ namespace MediaBrowser.Dlna.PlayTo
public void Init(Device device)
{
_device = device;
_device.OnDeviceUnavailable = OnDeviceUnavailable;
_device.PlaybackStart += _device_PlaybackStart;
_device.PlaybackProgress += _device_PlaybackProgress;
_device.PlaybackStopped += _device_PlaybackStopped;
_device.MediaChanged += _device_MediaChanged;
_device.OnDeviceUnavailable = OnDeviceUnavailable;
_device.Start();

View file

@ -33,7 +33,6 @@ namespace MediaBrowser.Dlna.Profiles
MaxStreamingBitrate = 20000000;
MaxStaticBitrate = 20000000;
MusicStreamingTranscodingBitrate = 192000;
MusicSyncBitrate = 192000;
EnableAlbumArtInDidl = false;

View file

@ -11,9 +11,7 @@ namespace MediaBrowser.Dlna.Profiles
Name = "Kodi";
MaxStreamingBitrate = 100000000;
MaxStaticBitrate = 100000000;
MusicStreamingTranscodingBitrate = 1280000;
MusicSyncBitrate = 1280000;
TimelineOffsetSeconds = 5;

View file

@ -553,6 +553,13 @@ namespace MediaBrowser.LocalMetadata.Savers
builder.Append("<TVRageId>" + SecurityElement.Escape(externalId) + "</TVRageId>");
}
externalId = item.GetProviderId(MetadataProviders.TvMaze);
if (!string.IsNullOrEmpty(externalId))
{
builder.Append("<TvMazeId>" + SecurityElement.Escape(externalId) + "</TvMazeId>");
}
var hasTagline = item as IHasTaglines;
if (hasTagline != null)
{

View file

@ -680,7 +680,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.IsNullOrEmpty(state.Options.Profile))
{
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase))
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
// not supported by h264_omx
param += " -profile:v " + state.Options.Profile;
@ -737,7 +738,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (!string.Equals(videoCodec, "h264_omx", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
!string.Equals(videoCodec, "h264_nvenc", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
param = "-pix_fmt yuv420p " + param;
}
@ -887,66 +889,96 @@ namespace MediaBrowser.MediaEncoding.Encoder
var filters = new List<string>();
if (state.DeInterlace)
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
filters.Add("format=nv12|vaapi");
filters.Add("hwupload");
}
else if (state.DeInterlace && !string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
filters.Add("yadif=0:-1:0");
}
// If fixed dimensions were supplied
if (request.Width.HasValue && request.Height.HasValue)
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
{
var widthParam = request.Width.Value.ToString(UsCulture);
var heightParam = request.Height.Value.ToString(UsCulture);
// Work around vaapi's reduced scaling features
var scaler = "scale_vaapi";
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", widthParam, heightParam));
}
// Given the input dimensions (inputWidth, inputHeight), determine the output dimensions
// (outputWidth, outputHeight). The user may request precise output dimensions or maximum
// output dimensions. Output dimensions are guaranteed to be even.
decimal inputWidth = Convert.ToDecimal(state.VideoStream.Width);
decimal inputHeight = Convert.ToDecimal(state.VideoStream.Height);
decimal outputWidth = request.Width.HasValue ? Convert.ToDecimal(request.Width.Value) : inputWidth;
decimal outputHeight = request.Height.HasValue ? Convert.ToDecimal(request.Height.Value) : inputHeight;
decimal maximumWidth = request.MaxWidth.HasValue ? Convert.ToDecimal(request.MaxWidth.Value) : outputWidth;
decimal maximumHeight = request.MaxHeight.HasValue ? Convert.ToDecimal(request.MaxHeight.Value) : outputHeight;
// If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
else if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
}
// If a fixed width was requested
else if (request.Width.HasValue)
{
var widthParam = request.Width.Value.ToString(UsCulture);
filters.Add(string.Format("scale={0}:trunc(ow/a/2)*2", widthParam));
}
// If a fixed height was requested
else if (request.Height.HasValue)
{
var heightParam = request.Height.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(oh*a/2)*2:{0}", heightParam));
}
// If a max width was requested
else if (request.MaxWidth.HasValue)
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam));
}
// If a max height was requested
else if (request.MaxHeight.HasValue)
{
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam));
}
if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
{
if (filters.Count > 1)
if (outputWidth > maximumWidth || outputHeight > maximumHeight)
{
//filters[filters.Count - 1] += ":flags=fast_bilinear";
var scale = Math.Min(maximumWidth / outputWidth, maximumHeight / outputHeight);
outputWidth = Math.Min(maximumWidth, Math.Truncate(outputWidth * scale));
outputHeight = Math.Min(maximumHeight, Math.Truncate(outputHeight * scale));
}
outputWidth = 2 * Math.Truncate(outputWidth / 2);
outputHeight = 2 * Math.Truncate(outputHeight / 2);
if (outputWidth != inputWidth || outputHeight != inputHeight)
{
filters.Add(string.Format("{0}=w={1}:h={2}", scaler, outputWidth.ToString(UsCulture), outputHeight.ToString(UsCulture)));
}
}
else
{
// If fixed dimensions were supplied
if (request.Width.HasValue && request.Height.HasValue)
{
var widthParam = request.Width.Value.ToString(UsCulture);
var heightParam = request.Height.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", widthParam, heightParam));
}
// If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
else if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
}
// If a fixed width was requested
else if (request.Width.HasValue)
{
var widthParam = request.Width.Value.ToString(UsCulture);
filters.Add(string.Format("scale={0}:trunc(ow/a/2)*2", widthParam));
}
// If a fixed height was requested
else if (request.Height.HasValue)
{
var heightParam = request.Height.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(oh*a/2)*2:{0}", heightParam));
}
// If a max width was requested
else if (request.MaxWidth.HasValue)
{
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam));
}
// If a max height was requested
else if (request.MaxHeight.HasValue)
{
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(max(iw/dar\\,ih)\\,{0})", maxHeightParam));
}
}

View file

@ -586,6 +586,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
return GetAvailableEncoder(mediaEncoder, "h264_omx", defaultEncoder);
}
if (string.Equals(hwType, "vaapi", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrWhiteSpace(options.VaapiDevice))
{
return GetAvailableEncoder(mediaEncoder, "h264_vaapi", defaultEncoder);
}
}
return defaultEncoder;

View file

@ -123,20 +123,20 @@ namespace MediaBrowser.MediaEncoding.Encoder
return "System";
}
if (IsDefaultPath(FFMpegPath))
{
return "Default";
}
return "Custom";
}
}
private bool IsDefaultPath(string path)
public bool IsDefaultEncoderPath
{
var parentPath = Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "ffmpeg", "20160410");
get
{
var path = FFMpegPath;
return FileSystem.ContainsSubPath(parentPath, path);
var parentPath = Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "ffmpeg", "20160410");
return FileSystem.ContainsSubPath(parentPath, path);
}
}
private bool IsSystemInstalledPath(string path)

View file

@ -10,6 +10,7 @@ namespace MediaBrowser.Model.Configuration
public int ThrottleDelaySeconds { get; set; }
public string HardwareAccelerationType { get; set; }
public string EncoderAppPath { get; set; }
public string VaapiDevice { get; set; }
public EncodingOptions()
{
@ -17,6 +18,7 @@ namespace MediaBrowser.Model.Configuration
EnableThrottling = true;
ThrottleDelaySeconds = 180;
EncodingThreadCount = -1;
VaapiDevice = "/dev/dri/card0";
}
}
}

View file

@ -4,10 +4,13 @@
{
public bool EnableArchiveMediaFiles { get; set; }
public bool EnablePhotos { get; set; }
public bool EnableRealtimeMonitor { get; set; }
public int SchemaVersion { get; set; }
public LibraryOptions()
{
EnablePhotos = true;
EnableRealtimeMonitor = true;
}
}
}

View file

@ -74,6 +74,8 @@ namespace MediaBrowser.Model.Configuration
/// <value>The metadata path.</value>
public string MetadataPath { get; set; }
public string LastVersion { get; set; }
/// <summary>
/// Gets or sets the display name of the season zero.
/// </summary>

View file

@ -27,8 +27,6 @@ namespace MediaBrowser.Model.Configuration
public bool DisplayMissingEpisodes { get; set; }
public bool DisplayUnairedEpisodes { get; set; }
public bool GroupMoviesIntoBoxSets { get; set; }
public string[] ExcludeFoldersFromGrouping { get; set; }
public string[] GroupedFolders { get; set; }
@ -48,7 +46,6 @@ namespace MediaBrowser.Model.Configuration
public bool RememberAudioSelections { get; set; }
public bool RememberSubtitleSelections { get; set; }
public bool EnableNextEpisodeAutoPlay { get; set; }
public bool DisplayFoldersView { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="UserConfiguration" /> class.

View file

@ -59,7 +59,7 @@ namespace MediaBrowser.Model.Dlna
/// Gets the maximum bitrate.
/// </summary>
/// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
public int? GetMaxBitrate()
public int? GetMaxBitrate(bool isAudio)
{
if (MaxBitrate.HasValue)
{
@ -70,6 +70,10 @@ namespace MediaBrowser.Model.Dlna
{
if (Context == EncodingContext.Static)
{
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
{
return Profile.MaxStaticMusicBitrate;
}
return Profile.MaxStaticBitrate;
}

View file

@ -55,7 +55,7 @@ namespace MediaBrowser.Model.Dlna
public int? MaxStaticBitrate { get; set; }
public int? MusicStreamingTranscodingBitrate { get; set; }
public int? MusicSyncBitrate { get; set; }
public int? MaxStaticMusicBitrate { get; set; }
/// <summary>
/// Controls the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace.
@ -115,7 +115,6 @@ namespace MediaBrowser.Model.Dlna
MaxStreamingBitrate = 8000000;
MaxStaticBitrate = 8000000;
MusicStreamingTranscodingBitrate = 128000;
MusicSyncBitrate = 128000;
}
public List<string> GetSupportedMediaTypes()

View file

@ -55,7 +55,7 @@ namespace MediaBrowser.Model.Dlna
stream.DeviceProfileId = options.Profile.Id;
}
return GetOptimalStream(streams, options.GetMaxBitrate());
return GetOptimalStream(streams, options.GetMaxBitrate(true));
}
public StreamInfo BuildVideoItem(VideoOptions options)
@ -88,7 +88,7 @@ namespace MediaBrowser.Model.Dlna
stream.DeviceProfileId = options.Profile.Id;
}
return GetOptimalStream(streams, options.GetMaxBitrate());
return GetOptimalStream(streams, options.GetMaxBitrate(false));
}
private StreamInfo GetOptimalStream(List<StreamInfo> streams, int? maxBitrate)
@ -275,24 +275,32 @@ namespace MediaBrowser.Model.Dlna
playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue);
}
int configuredBitrate = options.AudioTranscodingBitrate ??
(options.Context == EncodingContext.Static ? options.Profile.MusicSyncBitrate : options.Profile.MusicStreamingTranscodingBitrate) ??
int transcodingBitrate = options.AudioTranscodingBitrate ??
options.Profile.MusicStreamingTranscodingBitrate ??
128000;
playlistItem.AudioBitrate = Math.Min(configuredBitrate, playlistItem.AudioBitrate ?? configuredBitrate);
int? configuredBitrate = options.GetMaxBitrate(true);
if (configuredBitrate.HasValue)
{
transcodingBitrate = Math.Min(configuredBitrate.Value, transcodingBitrate);
}
playlistItem.AudioBitrate = Math.Min(transcodingBitrate, playlistItem.AudioBitrate ?? transcodingBitrate);
}
return playlistItem;
}
private int? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options)
private int? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options, bool isAudio)
{
if (item.Protocol == MediaProtocol.File)
{
return options.Profile.MaxStaticBitrate;
}
return options.GetMaxBitrate();
return options.GetMaxBitrate(isAudio);
}
private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
@ -312,7 +320,7 @@ namespace MediaBrowser.Model.Dlna
if (directPlayProfile != null)
{
// While options takes the network and other factors into account. Only applies to direct stream
if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate()) && options.EnableDirectStream)
if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate(true)) && options.EnableDirectStream)
{
playMethods.Add(PlayMethod.DirectStream);
}
@ -320,7 +328,7 @@ namespace MediaBrowser.Model.Dlna
// The profile describes what the device supports
// If device requirements are satisfied then allow both direct stream and direct play
if (item.SupportsDirectPlay &&
IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options)) && options.EnableDirectPlay)
IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true)) && options.EnableDirectPlay)
{
playMethods.Add(PlayMethod.DirectPlay);
}
@ -403,8 +411,8 @@ namespace MediaBrowser.Model.Dlna
MediaStream videoStream = item.VideoStream;
// TODO: This doesn't accout for situation of device being able to handle media bitrate, but wifi connection not fast enough
bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options), subtitleStream, options, PlayMethod.DirectPlay));
bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || IsEligibleForDirectPlay(item, options.GetMaxBitrate(), subtitleStream, options, PlayMethod.DirectStream));
bool isEligibleForDirectPlay = options.EnableDirectPlay && (options.ForceDirectPlay || IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options, true), subtitleStream, options, PlayMethod.DirectPlay));
bool isEligibleForDirectStream = options.EnableDirectStream && (options.ForceDirectStream || IsEligibleForDirectPlay(item, options.GetMaxBitrate(false), subtitleStream, options, PlayMethod.DirectStream));
_logger.Info("Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}",
options.Profile.Name ?? "Unknown Profile",
@ -469,7 +477,6 @@ namespace MediaBrowser.Model.Dlna
playlistItem.VideoCodec = transcodingProfile.VideoCodec;
playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps;
playlistItem.ForceLiveStream = transcodingProfile.ForceLiveStream;
playlistItem.EnableSubtitlesInManifest = transcodingProfile.EnableSubtitlesInManifest;
if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels))
@ -570,10 +577,10 @@ namespace MediaBrowser.Model.Dlna
playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue);
}
int audioBitrate = GetAudioBitrate(playlistItem.SubProtocol, options.GetMaxBitrate(), playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec, audioStream);
int audioBitrate = GetAudioBitrate(playlistItem.SubProtocol, options.GetMaxBitrate(false), playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec, audioStream);
playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate);
int? maxBitrateSetting = options.GetMaxBitrate();
int? maxBitrateSetting = options.GetMaxBitrate(false);
// Honor max rate
if (maxBitrateSetting.HasValue)
{
@ -595,19 +602,16 @@ namespace MediaBrowser.Model.Dlna
private int GetAudioBitrate(string subProtocol, int? maxTotalBitrate, int? targetAudioChannels, string targetAudioCodec, MediaStream audioStream)
{
var defaultBitrate = 128000;
if (StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3"))
var defaultBitrate = audioStream.BitRate ?? 192000;
// Reduce the bitrate if we're downmixing
if (targetAudioChannels.HasValue && audioStream != null && audioStream.Channels.HasValue && targetAudioChannels.Value < audioStream.Channels.Value)
{
defaultBitrate = 192000;
}
if (!string.IsNullOrEmpty(targetAudioCodec) && audioStream != null && StringHelper.EqualsIgnoreCase(audioStream.Codec, targetAudioCodec))
{
defaultBitrate = audioStream.BitRate ?? defaultBitrate;
defaultBitrate = StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3") ? 192000 : 128000;
}
if (targetAudioChannels.HasValue)
{
if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 1500000)
if (targetAudioChannels.Value >= 5 && (maxTotalBitrate ?? 0) >= 1200000)
{
if (StringHelper.EqualsIgnoreCase(targetAudioCodec, "ac3"))
{

View file

@ -36,7 +36,6 @@ namespace MediaBrowser.Model.Dlna
public string VideoProfile { get; set; }
public bool CopyTimestamps { get; set; }
public bool ForceLiveStream { get; set; }
public bool EnableSubtitlesInManifest { get; set; }
public string[] AudioCodecs { get; set; }
@ -216,7 +215,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxWidth.Value) : string.Empty));
list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty));
if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls") && !item.ForceLiveStream)
if (StringHelper.EqualsIgnoreCase(item.SubProtocol, "hls"))
{
list.Add(new NameValuePair("StartTimeTicks", string.Empty));
}
@ -246,7 +245,6 @@ namespace MediaBrowser.Model.Dlna
}
list.Add(new NameValuePair("CopyTimestamps", item.CopyTimestamps.ToString().ToLower()));
list.Add(new NameValuePair("ForceLiveStream", item.ForceLiveStream.ToString().ToLower()));
list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : string.Empty));
list.Add(new NameValuePair("TranscodingMaxAudioChannels", item.TranscodingMaxAudioChannels.HasValue ? StringHelper.ToStringCultureInvariant(item.TranscodingMaxAudioChannels.Value) : string.Empty));

View file

@ -35,9 +35,6 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("context")]
public EncodingContext Context { get; set; }
[XmlAttribute("forceLiveStream")]
public bool ForceLiveStream { get; set; }
[XmlAttribute("enableSubtitlesInManifest")]
public bool EnableSubtitlesInManifest { get; set; }

View file

@ -39,6 +39,7 @@ namespace MediaBrowser.Model.Entities
TvRage = 15,
AudioDbArtist = 16,
AudioDbAlbum = 17,
MusicBrainzTrack = 18
MusicBrainzTrack = 18,
TvMaze = 19
}
}

View file

@ -95,6 +95,12 @@ namespace MediaBrowser.Model.FileOrganization
/// <value>The size of the file.</value>
public long FileSize { get; set; }
/// <summary>
/// Indicates if the item is currently being processed.
/// </summary>
/// <remarks>Runtime property not persisted to the store.</remarks>
public bool IsInProgress { get; set; }
public FileOrganizationResult()
{
DuplicatePaths = new List<string>();

View file

@ -241,7 +241,7 @@ namespace MediaBrowser.Model.Net
}
if (StringHelper.EqualsIgnoreCase(ext, ".opus"))
{
return "audio/opus";
return "audio/ogg";
}
// Playlists

View file

@ -27,10 +27,6 @@ namespace MediaBrowser.Model.Querying
/// </summary>
IsFavorite = 5,
/// <summary>
/// The is recently added
/// </summary>
IsRecentlyAdded = 6,
/// <summary>
/// The item is resumable
/// </summary>
IsResumable = 7,

View file

@ -167,10 +167,13 @@ namespace MediaBrowser.Providers.MediaInfo
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var file = directoryService.GetFile(item.Path);
if (file != null && file.LastWriteTimeUtc != item.DateModified)
if (item.EnableRefreshOnDateModifiedChange && !string.IsNullOrWhiteSpace(item.Path) && item.LocationType == LocationType.FileSystem)
{
return true;
var file = directoryService.GetFile(item.Path);
if (file != null && file.LastWriteTimeUtc != item.DateModified)
{
return true;
}
}
return false;

View file

@ -171,7 +171,7 @@ namespace MediaBrowser.Providers.MediaInfo
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
if (item.EnableRefreshOnDateModifiedChange && !string.IsNullOrWhiteSpace(item.Path))
if (item.EnableRefreshOnDateModifiedChange && !string.IsNullOrWhiteSpace(item.Path) && item.LocationType == LocationType.FileSystem)
{
var file = directoryService.GetFile(item.Path);
if (file != null && file.LastWriteTimeUtc != item.DateModified)

View file

@ -194,7 +194,7 @@ namespace MediaBrowser.Providers.MediaInfo
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
if (item.EnableRefreshOnDateModifiedChange)
if (item.EnableRefreshOnDateModifiedChange && !string.IsNullOrWhiteSpace(item.Path) && item.LocationType == LocationType.FileSystem)
{
var file = directoryService.GetFile(item.Path);
if (file != null && file.LastWriteTimeUtc != item.DateModified)

View file

@ -154,10 +154,13 @@ namespace MediaBrowser.Providers.Photos
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
{
var file = directoryService.GetFile(item.Path);
if (file != null && file.LastWriteTimeUtc != item.DateModified)
if (item.EnableRefreshOnDateModifiedChange && !string.IsNullOrWhiteSpace(item.Path) && item.LocationType == LocationType.FileSystem)
{
return true;
var file = directoryService.GetFile(item.Path);
if (file != null && file.LastWriteTimeUtc != item.DateModified)
{
return true;
}
}
return false;

View file

@ -54,18 +54,15 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
private async void SendMessage(string name, TimerEventInfo info)
{
var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).ToList();
var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).Select(i => i.Id.ToString("N")).ToList();
foreach (var user in users)
try
{
try
{
await _sessionManager.SendMessageToUserSessions<TimerEventInfo>(user.Id.ToString("N"), name, info, CancellationToken.None);
}
catch (Exception ex)
{
_logger.ErrorException("Error sending message", ex);
}
await _sessionManager.SendMessageToUserSessions<TimerEventInfo>(users, name, info, CancellationToken.None);
}
catch (Exception ex)
{
_logger.ErrorException("Error sending message", ex);
}
}

View file

@ -11,6 +11,7 @@ using MediaBrowser.Controller.Sync;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Sync;
using System;
using System.Collections.Generic;
using System.Threading;
namespace MediaBrowser.Server.Implementations.EntryPoints
@ -164,7 +165,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
private async void SendMessageToUserSession<T>(User user, string name, T data)
{
await _sessionManager.SendMessageToUserSessions(user.Id.ToString("N"), name, data, CancellationToken.None);
await _sessionManager.SendMessageToUserSessions(new List<string> { user.Id.ToString("N") }, name, data, CancellationToken.None);
}
/// <summary>

View file

@ -272,6 +272,18 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
var originalExtractedSeriesString = result.ExtractedName;
bool isNew = string.IsNullOrWhiteSpace(result.Id);
if (isNew)
{
await _organizationService.SaveResult(result, cancellationToken);
}
if (!_organizationService.AddToInProgressList(result, isNew))
{
throw new Exception("File is currently processed otherwise. Please try again later.");
}
try
{
// Proceed to sort the file
@ -363,6 +375,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
_logger.Warn(ex.Message);
return;
}
finally
{
_organizationService.RemoveFromInprogressList(result);
}
if (rememberCorrection)
{

View file

@ -0,0 +1,68 @@
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.FileOrganization;
using MediaBrowser.Controller.Session;
using System.Threading;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
/// <summary>
/// Class SessionInfoWebSocketListener
/// </summary>
class FileOrganizationNotifier : IServerEntryPoint
{
private readonly IFileOrganizationService _organizationService;
private readonly ISessionManager _sessionManager;
public FileOrganizationNotifier(ILogger logger, IFileOrganizationService organizationService, ISessionManager sessionManager)
{
_organizationService = organizationService;
_sessionManager = sessionManager;
}
public void Run()
{
_organizationService.ItemAdded += _organizationService_ItemAdded;
_organizationService.ItemRemoved += _organizationService_ItemRemoved;
_organizationService.ItemUpdated += _organizationService_ItemUpdated;
_organizationService.LogReset += _organizationService_LogReset;
}
private void _organizationService_LogReset(object sender, EventArgs e)
{
_sessionManager.SendMessageToAdminSessions("AutoOrganizeUpdate", (FileOrganizationResult)null, CancellationToken.None);
}
private void _organizationService_ItemUpdated(object sender, GenericEventArgs<FileOrganizationResult> e)
{
_sessionManager.SendMessageToAdminSessions("AutoOrganizeUpdate", e.Argument, CancellationToken.None);
}
private void _organizationService_ItemRemoved(object sender, GenericEventArgs<FileOrganizationResult> e)
{
_sessionManager.SendMessageToAdminSessions("AutoOrganizeUpdate", (FileOrganizationResult)null, CancellationToken.None);
}
private void _organizationService_ItemAdded(object sender, GenericEventArgs<FileOrganizationResult> e)
{
_sessionManager.SendMessageToAdminSessions("AutoOrganizeUpdate", (FileOrganizationResult)null, CancellationToken.None);
}
public void Dispose()
{
_organizationService.ItemAdded -= _organizationService_ItemAdded;
_organizationService.ItemRemoved -= _organizationService_ItemRemoved;
_organizationService.ItemUpdated -= _organizationService_ItemUpdated;
_organizationService.LogReset -= _organizationService_LogReset;
}
}
}

View file

@ -3,16 +3,21 @@ using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.FileOrganization;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommonIO;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Events;
using MediaBrowser.Common.Events;
namespace MediaBrowser.Server.Implementations.FileOrganization
{
@ -26,6 +31,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
private readonly IServerConfigurationManager _config;
private readonly IFileSystem _fileSystem;
private readonly IProviderManager _providerManager;
private readonly ConcurrentDictionary<string, bool> _inProgressItemIds = new ConcurrentDictionary<string, bool>();
public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemAdded;
public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemUpdated;
public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemRemoved;
public event EventHandler LogReset;
public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager)
{
@ -58,12 +69,26 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query)
{
return _repo.GetResults(query);
var results = _repo.GetResults(query);
foreach (var result in results.Items)
{
result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
}
return results;
}
public FileOrganizationResult GetResult(string id)
{
return _repo.GetResult(id);
var result = _repo.GetResult(id);
if (result != null)
{
result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id);
}
return result;
}
public FileOrganizationResult GetResultBySourcePath(string path)
@ -78,11 +103,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
return GetResult(id);
}
public Task DeleteOriginalFile(string resultId)
public async Task DeleteOriginalFile(string resultId)
{
var result = _repo.GetResult(resultId);
_logger.Info("Requested to delete {0}", result.OriginalPath);
if (!AddToInProgressList(result, false))
{
throw new Exception("Path is currently processed otherwise. Please try again later.");
}
try
{
_fileSystem.DeleteFile(result.OriginalPath);
@ -91,8 +122,14 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
_logger.ErrorException("Error deleting {0}", ex, result.OriginalPath);
}
finally
{
RemoveFromInprogressList(result);
}
return _repo.Delete(resultId);
await _repo.Delete(resultId);
EventHelper.FireEventIfNotNull(ItemRemoved, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
}
private AutoOrganizeOptions GetAutoOrganizeOptions()
@ -121,9 +158,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}
}
public Task ClearLog()
public async Task ClearLog()
{
return _repo.DeleteAll();
await _repo.DeleteAll();
EventHelper.FireEventIfNotNull(LogReset, this, EventArgs.Empty, _logger);
}
public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
@ -189,5 +227,55 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
_config.SaveAutoOrganizeOptions(options);
}
}
/// <summary>
/// Attempts to add a an item to the list of currently processed items.
/// </summary>
/// <param name="result">The result item.</param>
/// <param name="isNewItem">Passing true will notify the client to reload all items, otherwise only a single item will be refreshed.</param>
/// <returns>True if the item was added, False if the item is already contained in the list.</returns>
public bool AddToInProgressList(FileOrganizationResult result, bool isNewItem)
{
if (string.IsNullOrWhiteSpace(result.Id))
{
result.Id = result.OriginalPath.GetMD5().ToString("N");
}
if (!_inProgressItemIds.TryAdd(result.Id, false))
{
return false;
}
result.IsInProgress = true;
if (isNewItem)
{
EventHelper.FireEventIfNotNull(ItemAdded, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
}
else
{
EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
}
return true;
}
/// <summary>
/// Removes an item from the list of currently processed items.
/// </summary>
/// <param name="result">The result item.</param>
/// <returns>True if the item was removed, False if the item was not contained in the list.</returns>
public bool RemoveFromInprogressList(FileOrganizationResult result)
{
bool itemValue;
var retval = _inProgressItemIds.TryRemove(result.Id, out itemValue);
result.IsInProgress = false;
EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger);
return retval;
}
}
}

View file

@ -428,8 +428,24 @@ namespace MediaBrowser.Server.Implementations.HttpServer
if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase) ||
localPath.IndexOf("mediabrowser/web", StringComparison.OrdinalIgnoreCase) != -1 ||
localPath.IndexOf("dashboard/", StringComparison.OrdinalIgnoreCase) != -1)
localPath.IndexOf("mediabrowser/web", StringComparison.OrdinalIgnoreCase) != -1)
{
httpRes.StatusCode = 200;
httpRes.ContentType = "text/html";
var newUrl = urlString.Replace("mediabrowser", "emby", StringComparison.OrdinalIgnoreCase)
.Replace("/dashboard/", "/web/", StringComparison.OrdinalIgnoreCase);
if (!string.Equals(newUrl, urlString, StringComparison.OrdinalIgnoreCase))
{
httpRes.Write("<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + newUrl + "\">" + newUrl + "</a></body></html>");
httpRes.Close();
return;
}
}
if (localPath.IndexOf("dashboard/", StringComparison.OrdinalIgnoreCase) != -1 &&
localPath.IndexOf("web/dashboard", StringComparison.OrdinalIgnoreCase) == -1)
{
httpRes.StatusCode = 200;
httpRes.ContentType = "text/html";

View file

@ -172,27 +172,29 @@ namespace MediaBrowser.Server.Implementations.IO
}
}
public void Start()
private bool IsLibraryMonitorEnabaled(BaseItem item)
{
if (EnableLibraryMonitor)
var options = LibraryManager.GetLibraryOptions(item);
if (options != null && options.SchemaVersion >= 1)
{
StartInternal();
return options.EnableRealtimeMonitor;
}
return EnableLibraryMonitor;
}
/// <summary>
/// Starts this instance.
/// </summary>
private void StartInternal()
public void Start()
{
LibraryManager.ItemAdded += LibraryManager_ItemAdded;
LibraryManager.ItemRemoved += LibraryManager_ItemRemoved;
var pathsToWatch = new List<string> { LibraryManager.RootFolder.Path };
var pathsToWatch = new List<string> { };
var paths = LibraryManager
.RootFolder
.Children
.Where(IsLibraryMonitorEnabaled)
.OfType<Folder>()
.SelectMany(f => f.PhysicalLocations)
.Distinct(StringComparer.OrdinalIgnoreCase)
@ -213,6 +215,14 @@ namespace MediaBrowser.Server.Implementations.IO
}
}
private void StartWatching(BaseItem item)
{
if (IsLibraryMonitorEnabaled(item))
{
StartWatchingPath(item.Path);
}
}
/// <summary>
/// Handles the ItemRemoved event of the LibraryManager control.
/// </summary>
@ -235,7 +245,7 @@ namespace MediaBrowser.Server.Implementations.IO
{
if (e.Item.GetParent() is AggregateFolder)
{
StartWatchingPath(e.Item.Path);
StartWatching(e.Item);
}
}
@ -382,14 +392,6 @@ namespace MediaBrowser.Server.Implementations.IO
Logger.ErrorException("Error in Directory watcher for: " + dw.Path, ex);
DisposeWatcher(dw);
if (ConfigurationManager.Configuration.EnableLibraryMonitor == AutoOnOff.Auto)
{
Logger.Info("Disabling realtime monitor to prevent future instability");
ConfigurationManager.Configuration.EnableLibraryMonitor = AutoOnOff.Disabled;
Stop();
}
}
/// <summary>
@ -420,8 +422,8 @@ namespace MediaBrowser.Server.Implementations.IO
var filename = Path.GetFileName(path);
var monitorPath = !string.IsNullOrEmpty(filename) &&
!_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) &&
var monitorPath = !string.IsNullOrEmpty(filename) &&
!_alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase) &&
!_alwaysIgnoreExtensions.Contains(Path.GetExtension(path) ?? string.Empty, StringComparer.OrdinalIgnoreCase);
// Ignore certain files

View file

@ -203,12 +203,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
/// <returns>Video.</returns>
protected override Video Resolve(ItemResolveArgs args)
{
if (args.Path != null && args.Path.IndexOf("disney", StringComparison.OrdinalIgnoreCase) != -1)
{
var b = true;
var a = b;
}
var collectionType = args.GetCollectionType();
if (IsInvalid(args.Parent, collectionType))

View file

@ -149,6 +149,7 @@
<Compile Include="EntryPoints\UsageReporter.cs" />
<Compile Include="FileOrganization\EpisodeFileOrganizer.cs" />
<Compile Include="FileOrganization\Extensions.cs" />
<Compile Include="FileOrganization\FileOrganizationNotifier.cs" />
<Compile Include="FileOrganization\FileOrganizationService.cs" />
<Compile Include="FileOrganization\NameUtils.cs" />
<Compile Include="FileOrganization\TvFolderOrganizer.cs" />
@ -271,6 +272,7 @@
<Compile Include="Sorting\StartDateComparer.cs" />
<Compile Include="Sync\SyncHelper.cs" />
<Compile Include="Sync\SyncJobOptions.cs" />
<Compile Include="Sync\SyncNotificationEntryPoint.cs" />
<Compile Include="UserViews\CollectionFolderImageProvider.cs" />
<Compile Include="UserViews\DynamicImageProvider.cs" />
<Compile Include="News\NewsEntryPoint.cs" />

View file

@ -123,7 +123,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
{
if (extractImages)
{
if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso || video.VideoType == VideoType.BluRay)
if (video.VideoType == VideoType.HdDvd || video.VideoType == VideoType.Iso || video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd)
{
continue;
}

View file

@ -313,8 +313,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
if (Folder.IsPathOffline(path))
{
libraryItem.IsOffline = true;
await libraryItem.UpdateToRepository(ItemUpdateType.None, cancellationToken).ConfigureAwait(false);
await libraryItem.UpdateIsOffline(true).ConfigureAwait(false);
continue;
}

View file

@ -211,7 +211,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
_connection.AddColumn(Logger, "TypedBaseItems", "ProductionYear", "INT");
_connection.AddColumn(Logger, "TypedBaseItems", "ParentId", "GUID");
_connection.AddColumn(Logger, "TypedBaseItems", "Genres", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "ParentalRatingValue", "INT");
_connection.AddColumn(Logger, "TypedBaseItems", "SchemaVersion", "INT");
_connection.AddColumn(Logger, "TypedBaseItems", "SortName", "Text");
_connection.AddColumn(Logger, "TypedBaseItems", "RunTimeTicks", "BIGINT");
@ -488,7 +487,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
"ProductionYear",
"ParentId",
"Genres",
"ParentalRatingValue",
"InheritedParentalRatingValue",
"SchemaVersion",
"SortName",
@ -795,7 +793,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
_saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Genres.ToArray());
_saveItemCommand.GetParameter(index++).Value = item.GetParentalRatingValue() ?? 0;
_saveItemCommand.GetParameter(index++).Value = item.GetInheritedParentalRatingValue() ?? 0;
_saveItemCommand.GetParameter(index++).Value = LatestSchemaVersion;
@ -4286,6 +4283,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
var index = 0;
foreach (var image in images)
{
if (string.IsNullOrWhiteSpace(image.Path))
{
// Invalid
continue;
}
_saveImagesCommand.GetParameter(0).Value = itemId;
_saveImagesCommand.GetParameter(1).Value = image.Type;
_saveImagesCommand.GetParameter(2).Value = image.Path;

View file

@ -1869,10 +1869,17 @@ namespace MediaBrowser.Server.Implementations.Session
return GetSessionByAuthenticationToken(info, deviceId, remoteEndpoint, null);
}
public Task SendMessageToUserSessions<T>(string userId, string name, T data,
public Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken)
{
var adminUserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id.ToString("N")).ToList();
return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken);
}
public Task SendMessageToUserSessions<T>(List<string> userIds, string name, T data,
CancellationToken cancellationToken)
{
var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null && i.ContainsUser(userId)).ToList();
var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null && userIds.Any(i.ContainsUser)).ToList();
var tasks = sessions.Select(session => Task.Run(async () =>
{

View file

@ -85,6 +85,11 @@ namespace MediaBrowser.Server.Implementations.Sync
{
Name = "Low",
Id = "low"
},
new SyncQualityOption
{
Name = "Custom",
Id = "custom"
}
};
}

View file

@ -0,0 +1,48 @@
using System.Threading;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sync;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Sync;
namespace MediaBrowser.Server.Implementations.Sync
{
public class SyncNotificationEntryPoint : IServerEntryPoint
{
private readonly ISessionManager _sessionManager;
private readonly ISyncManager _syncManager;
public SyncNotificationEntryPoint(ISyncManager syncManager, ISessionManager sessionManager)
{
_syncManager = syncManager;
_sessionManager = sessionManager;
}
public void Run()
{
_syncManager.SyncJobItemUpdated += _syncManager_SyncJobItemUpdated;
}
private async void _syncManager_SyncJobItemUpdated(object sender, GenericEventArgs<SyncJobItem> e)
{
var item = e.Argument;
if (item.Status == SyncJobItemStatus.ReadyToTransfer)
{
try
{
await _sessionManager.SendMessageToUserDeviceSessions(item.TargetId, "SyncJobItemReady", item, CancellationToken.None).ConfigureAwait(false);
}
catch
{
}
}
}
public void Dispose()
{
_syncManager.SyncJobItemUpdated -= _syncManager_SyncJobItemUpdated;
}
}
}

View file

@ -390,6 +390,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\autoorganizetv.html">
<Link>Resources\dashboard-ui\autoorganizetv.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\camerauploadsettings.html">
<Link>Resources\dashboard-ui\camerauploadsettings.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\channelitems.html">
<Link>Resources\dashboard-ui\channelitems.html</Link>
</BundleResource>
@ -1128,9 +1131,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\multidownload.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\multidownload.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\objectassign.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\objectassign.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playmenu.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playmenu.js</Link>
</BundleResource>
@ -1155,6 +1155,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\shortcuts.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\thememediaplayer.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\thememediaplayer.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\visibleinviewport.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\visibleinviewport.js</Link>
</BundleResource>
@ -1566,6 +1569,15 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\playlisteditor\playlisteditor.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\playlisteditor\playlisteditor.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\polyfills\array.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\polyfills\array.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\polyfills\bind.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\polyfills\bind.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\polyfills\objectassign.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\polyfills\objectassign.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\prompt\nativeprompt.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\prompt\nativeprompt.js</Link>
</BundleResource>
@ -1773,6 +1785,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\subtitleeditor\subtitleeditor.template.html">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\subtitleeditor\subtitleeditor.template.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\sync\sync.js">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\sync\sync.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\emby-webcomponents\toast\toast.css">
<Link>Resources\dashboard-ui\bower_components\emby-webcomponents\toast\toast.css</Link>
</BundleResource>
@ -1860,36 +1875,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fetch\fetch.js">
<Link>Resources\dashboard-ui\bower_components\fetch\fetch.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\.bower.json">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\.bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\CONTRIBUTING.md">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\CONTRIBUTING.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\FAQ.md">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\FAQ.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\README.md">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\README.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\bower.json">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\fingerprint2.js">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\fingerprint2.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\gulpfile.js">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\gulpfile.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\index.html">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\package.json">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\package.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\fingerprintjs2\dist\fingerprint2.min.js">
<Link>Resources\dashboard-ui\bower_components\fingerprintjs2\dist\fingerprint2.min.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\font-roboto\.bower.json">
<Link>Resources\dashboard-ui\bower_components\font-roboto\.bower.json</Link>
</BundleResource>
@ -2094,45 +2079,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-a11y-keys-behavior\test\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-a11y-keys-behavior\test\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\.bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\.gitignore">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\.gitignore</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\.travis.yml">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\.travis.yml</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\CONTRIBUTING.md">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\CONTRIBUTING.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\README.md">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\README.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\hero.svg">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\hero.svg</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\iron-autogrow-textarea.html">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\iron-autogrow-textarea.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\.github\ISSUE_TEMPLATE.md">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\.github\ISSUE_TEMPLATE.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\demo\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\test\basic.html">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\test\basic.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-autogrow-textarea\test\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-autogrow-textarea\test\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-behaviors\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-behaviors\.bower.json</Link>
</BundleResource>
@ -2502,51 +2448,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-iconset-svg\test\iron-iconset-svg.html">
<Link>Resources\dashboard-ui\bower_components\iron-iconset-svg\test\iron-iconset-svg.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-input\.bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\.gitignore">
<Link>Resources\dashboard-ui\bower_components\iron-input\.gitignore</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\.travis.yml">
<Link>Resources\dashboard-ui\bower_components\iron-input\.travis.yml</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\CONTRIBUTING.md">
<Link>Resources\dashboard-ui\bower_components\iron-input\CONTRIBUTING.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\README.md">
<Link>Resources\dashboard-ui\bower_components\iron-input\README.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-input\bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\hero.svg">
<Link>Resources\dashboard-ui\bower_components\iron-input\hero.svg</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\iron-input.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\iron-input.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\.github\ISSUE_TEMPLATE.md">
<Link>Resources\dashboard-ui\bower_components\iron-input\.github\ISSUE_TEMPLATE.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\demo\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\test\disabled-input.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\test\disabled-input.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\test\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\test\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\test\iron-input.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\test\iron-input.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-input\test\letters-only.html">
<Link>Resources\dashboard-ui\bower_components\iron-input\test\letters-only.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-meta\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-meta\.bower.json</Link>
</BundleResource>
@ -2574,6 +2475,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-meta\iron-meta.html">
<Link>Resources\dashboard-ui\bower_components\iron-meta\iron-meta.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-meta\.github\ISSUE_TEMPLATE.md">
<Link>Resources\dashboard-ui\bower_components\iron-meta\.github\ISSUE_TEMPLATE.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-meta\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-meta\demo\index.html</Link>
</BundleResource>
@ -2586,45 +2490,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-meta\test\iron-meta.html">
<Link>Resources\dashboard-ui\bower_components\iron-meta\test\iron-meta.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\.bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\.gitignore">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\.gitignore</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\.travis.yml">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\.travis.yml</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\CONTRIBUTING.md">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\CONTRIBUTING.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\README.md">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\README.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\iron-range-behavior.html">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\iron-range-behavior.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\.github\ISSUE_TEMPLATE.md">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\.github\ISSUE_TEMPLATE.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\demo\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\test\basic.html">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\test\basic.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\test\index.html">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\test\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-range-behavior\test\x-progressbar.html">
<Link>Resources\dashboard-ui\bower_components\iron-range-behavior\test\x-progressbar.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\iron-validatable-behavior\.bower.json">
<Link>Resources\dashboard-ui\bower_components\iron-validatable-behavior\.bower.json</Link>
</BundleResource>
@ -3252,126 +3117,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-icon-button\test\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-icon-button\test\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\.bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-input\.bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\.gitignore">
<Link>Resources\dashboard-ui\bower_components\paper-input\.gitignore</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\.travis.yml">
<Link>Resources\dashboard-ui\bower_components\paper-input\.travis.yml</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\CONTRIBUTING.md">
<Link>Resources\dashboard-ui\bower_components\paper-input\CONTRIBUTING.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\README.md">
<Link>Resources\dashboard-ui\bower_components\paper-input\README.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\all-imports.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\all-imports.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-input\bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\hero.svg">
<Link>Resources\dashboard-ui\bower_components\paper-input\hero.svg</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-input-addon-behavior.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-input-addon-behavior.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-input-behavior.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-input-behavior.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-input-char-counter.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-input-char-counter.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-input-container.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-input-container.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-input-error.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-input-error.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-input.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-input.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\paper-textarea.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\paper-textarea.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\.github\ISSUE_TEMPLATE.md">
<Link>Resources\dashboard-ui\bower_components\paper-input\.github\ISSUE_TEMPLATE.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\demo\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\demo\ssn-input.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\demo\ssn-input.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\demo\ssn-validator.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\demo\ssn-validator.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\test\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\test\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\test\letters-only.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\test\letters-only.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\test\paper-input-char-counter.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\test\paper-input-char-counter.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\test\paper-input-container.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\test\paper-input-container.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\test\paper-input-error.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\test\paper-input-error.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\test\paper-input.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\test\paper-input.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-input\test\paper-textarea.html">
<Link>Resources\dashboard-ui\bower_components\paper-input\test\paper-textarea.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\.bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-progress\.bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\.gitignore">
<Link>Resources\dashboard-ui\bower_components\paper-progress\.gitignore</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\.travis.yml">
<Link>Resources\dashboard-ui\bower_components\paper-progress\.travis.yml</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\CONTRIBUTING.md">
<Link>Resources\dashboard-ui\bower_components\paper-progress\CONTRIBUTING.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\README.md">
<Link>Resources\dashboard-ui\bower_components\paper-progress\README.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-progress\bower.json</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\hero.svg">
<Link>Resources\dashboard-ui\bower_components\paper-progress\hero.svg</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-progress\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\paper-progress.html">
<Link>Resources\dashboard-ui\bower_components\paper-progress\paper-progress.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\.github\ISSUE_TEMPLATE.md">
<Link>Resources\dashboard-ui\bower_components\paper-progress\.github\ISSUE_TEMPLATE.md</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\demo\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-progress\demo\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\test\basic.html">
<Link>Resources\dashboard-ui\bower_components\paper-progress\test\basic.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-progress\test\index.html">
<Link>Resources\dashboard-ui\bower_components\paper-progress\test\index.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\bower_components\paper-ripple\.bower.json">
<Link>Resources\dashboard-ui\bower_components\paper-ripple\.bower.json</Link>
</BundleResource>
@ -3729,6 +3474,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\components\tvproviders\xmltv.template.html">
<Link>Resources\dashboard-ui\components\tvproviders\xmltv.template.html</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\autoorganizetable.css">
<Link>Resources\dashboard-ui\css\autoorganizetable.css</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\chromecast.css">
<Link>Resources\dashboard-ui\css\chromecast.css</Link>
</BundleResource>
@ -3801,6 +3549,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\rotten.png">
<Link>Resources\dashboard-ui\css\images\rotten.png</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\throbber.gif">
<Link>Resources\dashboard-ui\css\images\throbber.gif</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\userflyoutdefault.png">
<Link>Resources\dashboard-ui\css\images\userflyoutdefault.png</Link>
</BundleResource>
@ -3987,6 +3738,48 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\css\images\userdata\password.png">
<Link>Resources\dashboard-ui\css\images\userdata\password.png</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\aboutpage.js">
<Link>Resources\dashboard-ui\dashboard\aboutpage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\autoorganizelog.js">
<Link>Resources\dashboard-ui\dashboard\autoorganizelog.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\autoorganizesmart.js">
<Link>Resources\dashboard-ui\dashboard\autoorganizesmart.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\autoorganizetv.js">
<Link>Resources\dashboard-ui\dashboard\autoorganizetv.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\cinemamodeconfiguration.js">
<Link>Resources\dashboard-ui\dashboard\cinemamodeconfiguration.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\dashboardgeneral.js">
<Link>Resources\dashboard-ui\dashboard\dashboardgeneral.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\dashboardhosting.js">
<Link>Resources\dashboard-ui\dashboard\dashboardhosting.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\devicesupload.js">
<Link>Resources\dashboard-ui\dashboard\devicesupload.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\librarydisplay.js">
<Link>Resources\dashboard-ui\dashboard\librarydisplay.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\librarysettings.js">
<Link>Resources\dashboard-ui\dashboard\librarysettings.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\livetvtunerprovider-satip.js">
<Link>Resources\dashboard-ui\dashboard\livetvtunerprovider-satip.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\logpage.js">
<Link>Resources\dashboard-ui\dashboard\logpage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\wizardcomponents.js">
<Link>Resources\dashboard-ui\dashboard\wizardcomponents.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\dashboard\wizardfinishpage.js">
<Link>Resources\dashboard-ui\dashboard\wizardfinishpage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\devices\android\android.css">
<Link>Resources\dashboard-ui\devices\android\android.css</Link>
</BundleResource>
@ -4008,9 +3801,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\legacy\selectmenu.js">
<Link>Resources\dashboard-ui\legacy\selectmenu.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\aboutpage.js">
<Link>Resources\dashboard-ui\scripts\aboutpage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\addpluginpage.js">
<Link>Resources\dashboard-ui\scripts\addpluginpage.js</Link>
</BundleResource>
@ -4020,14 +3810,8 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\autobackdrops.js">
<Link>Resources\dashboard-ui\scripts\autobackdrops.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\autoorganizelog.js">
<Link>Resources\dashboard-ui\scripts\autoorganizelog.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\autoorganizesmart.js">
<Link>Resources\dashboard-ui\scripts\autoorganizesmart.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\autoorganizetv.js">
<Link>Resources\dashboard-ui\scripts\autoorganizetv.js</Link>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\camerauploadsettings.js">
<Link>Resources\dashboard-ui\scripts\camerauploadsettings.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\channelitems.js">
<Link>Resources\dashboard-ui\scripts\channelitems.js</Link>
@ -4041,18 +3825,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\chromecast.js">
<Link>Resources\dashboard-ui\scripts\chromecast.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\cinemamodeconfiguration.js">
<Link>Resources\dashboard-ui\scripts\cinemamodeconfiguration.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\connectlogin.js">
<Link>Resources\dashboard-ui\scripts\connectlogin.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\dashboardgeneral.js">
<Link>Resources\dashboard-ui\scripts\dashboardgeneral.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\dashboardhosting.js">
<Link>Resources\dashboard-ui\scripts\dashboardhosting.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\dashboardpage.js">
<Link>Resources\dashboard-ui\scripts\dashboardpage.js</Link>
</BundleResource>
@ -4062,9 +3837,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\devices.js">
<Link>Resources\dashboard-ui\scripts\devices.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\devicesupload.js">
<Link>Resources\dashboard-ui\scripts\devicesupload.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\dlnaprofile.js">
<Link>Resources\dashboard-ui\scripts\dlnaprofile.js</Link>
</BundleResource>
@ -4140,18 +3912,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\librarybrowser.js">
<Link>Resources\dashboard-ui\scripts\librarybrowser.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\librarydisplay.js">
<Link>Resources\dashboard-ui\scripts\librarydisplay.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\librarymenu.js">
<Link>Resources\dashboard-ui\scripts\librarymenu.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\librarypathmapping.js">
<Link>Resources\dashboard-ui\scripts\librarypathmapping.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\librarysettings.js">
<Link>Resources\dashboard-ui\scripts\librarysettings.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvchannel.js">
<Link>Resources\dashboard-ui\scripts\livetvchannel.js</Link>
</BundleResource>
@ -4197,18 +3963,12 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvtunerprovider-m3u.js">
<Link>Resources\dashboard-ui\scripts\livetvtunerprovider-m3u.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\livetvtunerprovider-satip.js">
<Link>Resources\dashboard-ui\scripts\livetvtunerprovider-satip.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\localsync.js">
<Link>Resources\dashboard-ui\scripts\localsync.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\loginpage.js">
<Link>Resources\dashboard-ui\scripts\loginpage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\logpage.js">
<Link>Resources\dashboard-ui\scripts\logpage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\mediacontroller.js">
<Link>Resources\dashboard-ui\scripts\mediacontroller.js</Link>
</BundleResource>
@ -4371,9 +4131,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\supporterkeypage.js">
<Link>Resources\dashboard-ui\scripts\supporterkeypage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\sync.js">
<Link>Resources\dashboard-ui\scripts\sync.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\syncactivity.js">
<Link>Resources\dashboard-ui\scripts\syncactivity.js</Link>
</BundleResource>
@ -4386,9 +4143,6 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\taskbutton.js">
<Link>Resources\dashboard-ui\scripts\taskbutton.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\thememediaplayer.js">
<Link>Resources\dashboard-ui\scripts\thememediaplayer.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\tvgenres.js">
<Link>Resources\dashboard-ui\scripts\tvgenres.js</Link>
</BundleResource>
@ -4431,15 +4185,9 @@
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardagreement.js">
<Link>Resources\dashboard-ui\scripts\wizardagreement.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardcomponents.js">
<Link>Resources\dashboard-ui\scripts\wizardcomponents.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardcontroller.js">
<Link>Resources\dashboard-ui\scripts\wizardcontroller.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardfinishpage.js">
<Link>Resources\dashboard-ui\scripts\wizardfinishpage.js</Link>
</BundleResource>
<BundleResource Include="..\MediaBrowser.WebDashboard\dashboard-ui\scripts\wizardlivetvguide.js">
<Link>Resources\dashboard-ui\scripts\wizardlivetvguide.js</Link>
</BundleResource>

View file

@ -132,7 +132,7 @@ namespace MediaBrowser.Server.Mono.Native
{
get
{
return Environment.OperatingSystem != Startup.Common.OperatingSystem.Osx;
return Environment.OperatingSystem != Startup.Common.OperatingSystem.Osx;
}
}
@ -187,7 +187,7 @@ namespace MediaBrowser.Server.Mono.Native
{
info.SystemArchitecture = Architecture.X64;
}
else
else
{
info.SystemArchitecture = Architecture.X86;
}
@ -273,32 +273,11 @@ namespace MediaBrowser.Server.Mono.Native
break;
}
info.DownloadUrls = GetDownloadUrls(environment);
// No version available - user requirement
info.DownloadUrls = new string[] { };
return info;
}
private static string[] GetDownloadUrls(NativeEnvironment environment)
{
switch (environment.OperatingSystem)
{
case OperatingSystem.Linux:
switch (environment.SystemArchitecture)
{
case Architecture.X64:
return new[]
{
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-git-20160215-64bit-static.7z"
};
}
break;
}
// No version available
return new string[] { };
}
}
public class NullPowerManagement : IPowerManagement

View file

@ -385,8 +385,7 @@ namespace MediaBrowser.Server.Startup.Common
new OmdbEpisodeProviderMigration(ServerConfigurationManager),
new MovieDbEpisodeProviderMigration(ServerConfigurationManager),
new DbMigration(ServerConfigurationManager, TaskManager),
new FolderViewSettingMigration(ServerConfigurationManager, UserManager),
new CollectionGroupingMigration(ServerConfigurationManager, UserManager),
new UpdateLevelMigration(ServerConfigurationManager, this, HttpClient, JsonSerializer, _releaseAssetFilename),
new CollectionsViewMigration(ServerConfigurationManager, UserManager)
};

View file

@ -70,13 +70,12 @@
<Compile Include="FFMpeg\FFMpegInfo.cs" />
<Compile Include="INativeApp.cs" />
<Compile Include="MbLinkShortcutHandler.cs" />
<Compile Include="Migrations\CollectionGroupingMigration.cs" />
<Compile Include="Migrations\CollectionsViewMigration.cs" />
<Compile Include="Migrations\FolderViewSettingMigration.cs" />
<Compile Include="Migrations\IVersionMigration.cs" />
<Compile Include="Migrations\DbMigration.cs" />
<Compile Include="Migrations\MovieDbEpisodeProviderMigration.cs" />
<Compile Include="Migrations\OmdbEpisodeProviderMigration.cs" />
<Compile Include="Migrations\UpdateLevelMigration.cs" />
<Compile Include="NativeEnvironment.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StartupOptions.cs" />

View file

@ -1,40 +0,0 @@
using System.Linq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Server.Startup.Common.Migrations
{
public class CollectionGroupingMigration : IVersionMigration
{
private readonly IServerConfigurationManager _config;
private readonly IUserManager _userManager;
public CollectionGroupingMigration(IServerConfigurationManager config, IUserManager userManager)
{
_config = config;
_userManager = userManager;
}
public void Run()
{
var migrationKey = this.GetType().Name;
var migrationKeyList = _config.Configuration.Migrations.ToList();
if (!migrationKeyList.Contains(migrationKey))
{
if (_config.Configuration.IsStartupWizardCompleted)
{
if (_userManager.Users.Any(i => i.Configuration.GroupMoviesIntoBoxSets))
{
_config.Configuration.EnableGroupingIntoCollections = true;
}
}
migrationKeyList.Add(migrationKey);
_config.Configuration.Migrations = migrationKeyList.ToArray();
_config.SaveConfiguration();
}
}
}
}

View file

@ -1,40 +0,0 @@
using System.Linq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Server.Startup.Common.Migrations
{
public class FolderViewSettingMigration : IVersionMigration
{
private readonly IServerConfigurationManager _config;
private readonly IUserManager _userManager;
public FolderViewSettingMigration(IServerConfigurationManager config, IUserManager userManager)
{
_config = config;
_userManager = userManager;
}
public void Run()
{
var migrationKey = this.GetType().Name;
var migrationKeyList = _config.Configuration.Migrations.ToList();
if (!migrationKeyList.Contains(migrationKey))
{
if (_config.Configuration.IsStartupWizardCompleted)
{
if (_userManager.Users.Any(i => i.Configuration.DisplayFoldersView))
{
_config.Configuration.EnableFolderView = true;
}
}
migrationKeyList.Add(migrationKey);
_config.Configuration.Migrations = migrationKeyList.ToArray();
_config.SaveConfiguration();
}
}
}
}

View file

@ -0,0 +1,97 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Implementations.Updates;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Server.Startup.Common.Migrations
{
public class UpdateLevelMigration : IVersionMigration
{
private readonly IServerConfigurationManager _config;
private readonly IServerApplicationHost _appHost;
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _jsonSerializer;
private readonly string _releaseAssetFilename;
public UpdateLevelMigration(IServerConfigurationManager config, IServerApplicationHost appHost, IHttpClient httpClient, IJsonSerializer jsonSerializer, string releaseAssetFilename)
{
_config = config;
_appHost = appHost;
_httpClient = httpClient;
_jsonSerializer = jsonSerializer;
_releaseAssetFilename = releaseAssetFilename;
}
public async void Run()
{
var lastVersion = _config.Configuration.LastVersion;
var currentVersion = _appHost.ApplicationVersion;
if (string.Equals(lastVersion, currentVersion.ToString(), StringComparison.OrdinalIgnoreCase))
{
return;
}
try
{
var updateLevel = _config.Configuration.SystemUpdateLevel;
// Go down a level
if (updateLevel == PackageVersionClass.Release)
{
updateLevel = PackageVersionClass.Beta;
}
else if (updateLevel == PackageVersionClass.Beta)
{
updateLevel = PackageVersionClass.Dev;
}
else if (updateLevel == PackageVersionClass.Dev)
{
// It's already dev, there's nothing to check
return;
}
await CheckVersion(currentVersion, updateLevel, CancellationToken.None).ConfigureAwait(false);
}
catch
{
}
}
private async Task CheckVersion(Version currentVersion, PackageVersionClass updateLevel, CancellationToken cancellationToken)
{
var result = await new GithubUpdater(_httpClient, _jsonSerializer, TimeSpan.FromMinutes(5))
.CheckForUpdateResult("MediaBrowser", "Emby", currentVersion, PackageVersionClass.Beta, _releaseAssetFilename, "MBServer", "Mbserver.zip",
cancellationToken).ConfigureAwait(false);
if (result != null && result.IsUpdateAvailable)
{
_config.Configuration.SystemUpdateLevel = updateLevel;
_config.SaveConfiguration();
return;
}
// Go down a level
if (updateLevel == PackageVersionClass.Release)
{
updateLevel = PackageVersionClass.Beta;
}
else if (updateLevel == PackageVersionClass.Beta)
{
updateLevel = PackageVersionClass.Dev;
}
else
{
return;
}
await CheckVersion(currentVersion, updateLevel, cancellationToken).ConfigureAwait(false);
}
}
}

View file

@ -157,11 +157,21 @@ namespace MediaBrowser.WebDashboard.Api
var creator = GetPackageCreator();
var directory = creator.DashboardUIPath;
var skipExtensions = GetUndeployedExtensions();
var skipExtensions = GetDeployIgnoreExtensions();
var skipNames = GetDeployIgnoreFilenames();
return
Directory.GetFiles(directory, "*", SearchOption.AllDirectories)
.Where(i => !skipExtensions.Contains(Path.GetExtension(i) ?? string.Empty, StringComparer.OrdinalIgnoreCase))
.Where(i => !skipNames.Any(s =>
{
if (s.Item2)
{
return string.Equals(s.Item1, Path.GetFileName(i), StringComparison.OrdinalIgnoreCase);
}
return (Path.GetFileName(i) ?? string.Empty).IndexOf(s.Item1, StringComparison.OrdinalIgnoreCase) != -1;
}))
.Select(i => i.Replace(directory, string.Empty, StringComparison.OrdinalIgnoreCase).Replace("\\", "/").TrimStart('/') + "?v=" + _appHost.ApplicationVersion.ToString())
.ToList();
}
@ -300,7 +310,7 @@ namespace MediaBrowser.WebDashboard.Api
return new PackageCreator(_fileSystem, _localization, Logger, _serverConfigurationManager, _jsonSerializer);
}
private List<string> GetUndeployedExtensions()
private List<string> GetDeployIgnoreExtensions()
{
var list = new List<string>();
@ -315,6 +325,28 @@ namespace MediaBrowser.WebDashboard.Api
return list;
}
private List<Tuple<string,bool>> GetDeployIgnoreFilenames()
{
var list = new List<Tuple<string, bool>>();
list.Add(new Tuple<string, bool>("copying", true));
list.Add(new Tuple<string, bool>("license", true));
list.Add(new Tuple<string, bool>("license-mit", true));
list.Add(new Tuple<string, bool>("gitignore", false));
list.Add(new Tuple<string, bool>("npmignore", false));
list.Add(new Tuple<string, bool>("jshintrc", false));
list.Add(new Tuple<string, bool>("gruntfile", false));
list.Add(new Tuple<string, bool>("bowerrc", false));
list.Add(new Tuple<string, bool>("jscsrc", false));
list.Add(new Tuple<string, bool>("hero.svg", false));
list.Add(new Tuple<string, bool>("travis.yml", false));
list.Add(new Tuple<string, bool>("build.js", false));
list.Add(new Tuple<string, bool>("editorconfig", false));
list.Add(new Tuple<string, bool>("gitattributes", false));
return list;
}
public async Task<object> Get(GetDashboardPackage request)
{
var path = Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath,
@ -344,30 +376,12 @@ namespace MediaBrowser.WebDashboard.Api
// Try to trim the output size a bit
var bowerPath = Path.Combine(path, "bower_components");
if (!string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
{
//var versionedBowerPath = Path.Combine(Path.GetDirectoryName(bowerPath), "bower_components" + _appHost.ApplicationVersion);
//Directory.Move(bowerPath, versionedBowerPath);
//bowerPath = versionedBowerPath;
}
GetUndeployedExtensions().ForEach(i => DeleteFilesByExtension(bowerPath, i));
GetDeployIgnoreExtensions().ForEach(i => DeleteFilesByExtension(bowerPath, i));
DeleteFilesByExtension(bowerPath, ".json", "strings\\");
DeleteFilesByName(bowerPath, "copying", true);
DeleteFilesByName(bowerPath, "license", true);
DeleteFilesByName(bowerPath, "license-mit", true);
DeleteFilesByName(bowerPath, "gitignore");
DeleteFilesByName(bowerPath, "npmignore");
DeleteFilesByName(bowerPath, "jshintrc");
DeleteFilesByName(bowerPath, "gruntfile");
DeleteFilesByName(bowerPath, "bowerrc");
DeleteFilesByName(bowerPath, "jscsrc");
DeleteFilesByName(bowerPath, "hero.svg");
DeleteFilesByName(bowerPath, "travis.yml");
DeleteFilesByName(bowerPath, "build.js");
DeleteFilesByName(bowerPath, "editorconfig");
DeleteFilesByName(bowerPath, "gitattributes");
GetDeployIgnoreFilenames().ForEach(i => DeleteFilesByName(bowerPath, i.Item1, i.Item2));
DeleteFoldersByName(bowerPath, "demo");
DeleteFoldersByName(bowerPath, "test");
DeleteFoldersByName(bowerPath, "guides");
@ -382,8 +396,6 @@ namespace MediaBrowser.WebDashboard.Api
}
_fileSystem.DeleteDirectory(Path.Combine(bowerPath, "jquery", "src"), true);
//_fileSystem.DeleteDirectory(Path.Combine(bowerPath, "fingerprintjs2", "flash"), true);
//_fileSystem.DeleteDirectory(Path.Combine(bowerPath, "fingerprintjs2", "specs"), true);
DeleteCryptoFiles(Path.Combine(bowerPath, "cryptojslib", "components"));

View file

@ -101,6 +101,9 @@
<Content Include="dashboard-ui\autoorganizesmart.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\camerauploadsettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\components\appfooter\appfooter.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -182,6 +185,12 @@
<Content Include="dashboard-ui\components\tvproviders\xmltv.template.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\throbber.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\camerauploadsettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\userpasswordpage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -191,6 +200,9 @@
<Content Include="dashboard-ui\css\dashboard.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\autoorganizetable.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -320,7 +332,7 @@
<Content Include="dashboard-ui\scripts\homeupcoming.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\librarydisplay.js">
<Content Include="dashboard-ui\dashboard\librarydisplay.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\livetvguideprovider.js">
@ -332,7 +344,7 @@
<Content Include="dashboard-ui\scripts\livetvtunerprovider-m3u.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\livetvtunerprovider-satip.js">
<Content Include="dashboard-ui\dashboard\livetvtunerprovider-satip.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\localsync.js">
@ -350,7 +362,7 @@
<Content Include="dashboard-ui\scripts\mysyncsettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\autoorganizesmart.js">
<Content Include="dashboard-ui\dashboard\autoorganizesmart.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\searchpage.js">
@ -371,7 +383,7 @@
<Content Include="dashboard-ui\scripts\tvlatest.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\wizardcomponents.js">
<Content Include="dashboard-ui\dashboard\wizardcomponents.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\wizardcontroller.js">
@ -497,7 +509,7 @@
<Content Include="dashboard-ui\photos.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\dashboardhosting.js">
<Content Include="dashboard-ui\dashboard\dashboardhosting.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\forgotpassword.js">
@ -857,13 +869,13 @@
<Content Include="dashboard-ui\scripts\chromecast.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\cinemamodeconfiguration.js">
<Content Include="dashboard-ui\dashboard\cinemamodeconfiguration.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\connectlogin.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\dashboardgeneral.js">
<Content Include="dashboard-ui\dashboard\dashboardgeneral.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\syncactivity.js">
@ -875,7 +887,7 @@
<Content Include="dashboard-ui\scripts\devices.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\devicesupload.js">
<Content Include="dashboard-ui\dashboard\devicesupload.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\dlnaprofile.js">
@ -890,10 +902,10 @@
<Content Include="dashboard-ui\scripts\encodingsettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\autoorganizetv.js">
<Content Include="dashboard-ui\dashboard\autoorganizetv.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\autoorganizelog.js">
<Content Include="dashboard-ui\dashboard\autoorganizelog.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\externalplayer.js">
@ -989,12 +1001,6 @@
<Content Include="dashboard-ui\scripts\livetvsuggested.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\sync.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\thememediaplayer.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\tvupcoming.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -1086,7 +1092,7 @@
<Content Include="dashboard-ui\scripts\edititemmetadata.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\librarysettings.js">
<Content Include="dashboard-ui\dashboard\librarysettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\musicrecommended.js">
@ -1353,7 +1359,7 @@
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="dashboard-ui\scripts\logpage.js">
<Content Include="dashboard-ui\dashboard\logpage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
@ -1426,7 +1432,7 @@
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="dashboard-ui\scripts\aboutpage.js">
<Content Include="dashboard-ui\dashboard\aboutpage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\supporter\supporterflag.png">
@ -1438,7 +1444,7 @@
<Content Include="dashboard-ui\itemlist.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\scripts\wizardfinishpage.js">
<Content Include="dashboard-ui\dashboard\wizardfinishpage.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\items\detail\video.png">

View file

@ -827,6 +827,15 @@ namespace MediaBrowser.XbmcMetadata.Parsers
}
break;
}
case "tvmazeid":
{
var id = reader.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(id))
{
item.SetProviderId(MetadataProviders.TvMaze, id);
}
break;
}
case "audiodbartistid":
{
var id = reader.ReadElementContentAsString();

View file

@ -822,6 +822,12 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("tvrageid", externalId);
}
externalId = item.GetProviderId(MetadataProviders.TvMaze);
if (!string.IsNullOrEmpty(externalId))
{
writer.WriteElementString("tvmazeid", externalId);
}
if (options.SaveImagePathsInNfo)
{
AddImages(item, writer, libraryManager, config);

View file

@ -118,7 +118,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
"airsbefore_season",
"DVD_episodenumber",
"DVD_season",
"absolute_number"
"absolute_number",
"displayseason",
"displayepisode"
};
return list;

View file

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common.Internal</id>
<version>3.0.654</version>
<version>3.0.655</version>
<title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.654" />
<dependency id="MediaBrowser.Common" version="3.0.655" />
<dependency id="NLog" version="4.3.6" />
<dependency id="SimpleInjector" version="3.2.0" />
</dependencies>

View file

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MediaBrowser.Common</id>
<version>3.0.654</version>
<version>3.0.655</version>
<title>MediaBrowser.Common</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>

View file

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>MediaBrowser.Server.Core</id>
<version>3.0.654</version>
<version>3.0.655</version>
<title>Media Browser.Server.Core</title>
<authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Emby Server.</description>
<copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.654" />
<dependency id="MediaBrowser.Common" version="3.0.655" />
<dependency id="Interfaces.IO" version="1.0.0.5" />
</dependencies>
</metadata>