mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 03:26:07 +02:00
commit
ba9577f380
78 changed files with 975 additions and 835 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -281,11 +281,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
{
|
||||
var isLiveStream = (state.RunTimeTicks ?? 0) == 0;
|
||||
|
||||
if (state.VideoRequest.ForceLiveStream)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return isLiveStream;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -291,7 +291,8 @@ namespace MediaBrowser.Api.Sync
|
|||
{
|
||||
Fields = new List<ItemFields>
|
||||
{
|
||||
ItemFields.SyncInfo
|
||||
ItemFields.SyncInfo,
|
||||
ItemFields.BasicSyncInfo
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace MediaBrowser.Common.Implementations.Updates
|
|||
EnableKeepAlive = false,
|
||||
CancellationToken = cancellationToken,
|
||||
UserAgent = "Emby/3.0"
|
||||
|
||||
};
|
||||
|
||||
if (_cacheLength.Ticks > 0)
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -106,6 +106,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
{
|
||||
LibraryOptions[path] = options;
|
||||
|
||||
options.SchemaVersion = 1;
|
||||
XmlSerializer.SerializeToFile(options, GetLibraryOptionsPath(path));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,5 +134,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
|
||||
Task UpdateEncoderPath(string path, string pathType);
|
||||
bool SupportsEncoder(string encoder);
|
||||
bool IsDefaultEncoderPath { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
MaxStreamingBitrate = 20000000;
|
||||
MaxStaticBitrate = 20000000;
|
||||
MusicStreamingTranscodingBitrate = 192000;
|
||||
MusicSyncBitrate = 192000;
|
||||
|
||||
EnableAlbumArtInDidl = false;
|
||||
|
||||
|
|
|
@ -11,9 +11,7 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Name = "Kodi";
|
||||
|
||||
MaxStreamingBitrate = 100000000;
|
||||
MaxStaticBitrate = 100000000;
|
||||
MusicStreamingTranscodingBitrate = 1280000;
|
||||
MusicSyncBitrate = 1280000;
|
||||
|
||||
TimelineOffsetSeconds = 5;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
/// Gets the maximum bitrate.
|
||||
/// </summary>
|
||||
/// <returns>System.Nullable<System.Int32>.</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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace MediaBrowser.Model.Entities
|
|||
TvRage = 15,
|
||||
AudioDbArtist = 16,
|
||||
AudioDbAlbum = 17,
|
||||
MusicBrainzTrack = 18
|
||||
MusicBrainzTrack = 18,
|
||||
TvMaze = 19
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -241,7 +241,7 @@ namespace MediaBrowser.Model.Net
|
|||
}
|
||||
if (StringHelper.EqualsIgnoreCase(ext, ".opus"))
|
||||
{
|
||||
return "audio/opus";
|
||||
return "audio/ogg";
|
||||
}
|
||||
|
||||
// Playlists
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 () =>
|
||||
{
|
||||
|
|
|
@ -85,6 +85,11 @@ namespace MediaBrowser.Server.Implementations.Sync
|
|||
{
|
||||
Name = "Low",
|
||||
Id = "low"
|
||||
},
|
||||
new SyncQualityOption
|
||||
{
|
||||
Name = "Custom",
|
||||
Id = "custom"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -118,7 +118,9 @@ namespace MediaBrowser.XbmcMetadata.Savers
|
|||
"airsbefore_season",
|
||||
"DVD_episodenumber",
|
||||
"DVD_season",
|
||||
"absolute_number"
|
||||
"absolute_number",
|
||||
"displayseason",
|
||||
"displayepisode"
|
||||
};
|
||||
|
||||
return list;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue