mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-07-24 14:40:39 +02:00
Merge branch 'dev' of https://github.com/MediaBrowser/MediaBrowser into dev
Conflicts: MediaBrowser.Server.Implementations/Localization/Server/server.json
This commit is contained in:
commit
48e7ca8725
|
@ -648,10 +648,8 @@ namespace MediaBrowser.Api.Images
|
||||||
|
|
||||||
var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
|
var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
|
||||||
|
|
||||||
var clientFormats = GetClientSupportedFormats();
|
|
||||||
|
|
||||||
if (serverFormats.Contains(ImageFormat.Webp) &&
|
if (serverFormats.Contains(ImageFormat.Webp) &&
|
||||||
clientFormats.Contains(ImageFormat.Webp))
|
GetClientSupportedFormats().Contains(ImageFormat.Webp))
|
||||||
{
|
{
|
||||||
return ImageFormat.Webp;
|
return ImageFormat.Webp;
|
||||||
}
|
}
|
||||||
|
|
|
@ -617,36 +617,14 @@ namespace MediaBrowser.Api.Library
|
||||||
: (Folder)_libraryManager.RootFolder)
|
: (Folder)_libraryManager.RootFolder)
|
||||||
: _libraryManager.GetItemById(request.Id);
|
: _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var originalItem = item;
|
|
||||||
|
|
||||||
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||||
{
|
{
|
||||||
item = item.Parent;
|
item = item.Parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
var themeSongIds = GetThemeSongIds(item);
|
|
||||||
|
|
||||||
if (themeSongIds.Count == 0 && request.InheritFromParent)
|
|
||||||
{
|
|
||||||
var album = originalItem as MusicAlbum;
|
|
||||||
|
|
||||||
if (album != null)
|
|
||||||
{
|
|
||||||
var linkedItemWithThemes = album.SoundtrackIds
|
|
||||||
.Select(i => _libraryManager.GetItemById(i))
|
|
||||||
.FirstOrDefault(i => GetThemeSongIds(i).Count > 0);
|
|
||||||
|
|
||||||
if (linkedItemWithThemes != null)
|
|
||||||
{
|
|
||||||
themeSongIds = GetThemeSongIds(linkedItemWithThemes);
|
|
||||||
item = linkedItemWithThemes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var dtoOptions = GetDtoOptions(request);
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = themeSongIds.Select(_libraryManager.GetItemById)
|
var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||||
|
|
||||||
|
@ -682,41 +660,14 @@ namespace MediaBrowser.Api.Library
|
||||||
: (Folder)_libraryManager.RootFolder)
|
: (Folder)_libraryManager.RootFolder)
|
||||||
: _libraryManager.GetItemById(request.Id);
|
: _libraryManager.GetItemById(request.Id);
|
||||||
|
|
||||||
var originalItem = item;
|
|
||||||
|
|
||||||
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||||
{
|
{
|
||||||
item = item.Parent;
|
item = item.Parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
var themeVideoIds = GetThemeVideoIds(item);
|
|
||||||
|
|
||||||
if (themeVideoIds.Count == 0 && request.InheritFromParent)
|
|
||||||
{
|
|
||||||
var album = originalItem as MusicAlbum;
|
|
||||||
|
|
||||||
if (album == null)
|
|
||||||
{
|
|
||||||
album = originalItem.Parents.OfType<MusicAlbum>().FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (album != null)
|
|
||||||
{
|
|
||||||
var linkedItemWithThemes = album.SoundtrackIds
|
|
||||||
.Select(i => _libraryManager.GetItemById(i))
|
|
||||||
.FirstOrDefault(i => GetThemeVideoIds(i).Count > 0);
|
|
||||||
|
|
||||||
if (linkedItemWithThemes != null)
|
|
||||||
{
|
|
||||||
themeVideoIds = GetThemeVideoIds(linkedItemWithThemes);
|
|
||||||
item = linkedItemWithThemes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var dtoOptions = GetDtoOptions(request);
|
var dtoOptions = GetDtoOptions(request);
|
||||||
|
|
||||||
var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
|
var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback
|
namespace MediaBrowser.Api.Playback
|
||||||
{
|
{
|
||||||
|
@ -68,12 +69,14 @@ namespace MediaBrowser.Api.Playback
|
||||||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
||||||
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
||||||
protected IZipClient ZipClient { get; private set; }
|
protected IZipClient ZipClient { get; private set; }
|
||||||
|
protected IJsonSerializer JsonSerializer { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient)
|
protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer)
|
||||||
{
|
{
|
||||||
|
JsonSerializer = jsonSerializer;
|
||||||
ZipClient = zipClient;
|
ZipClient = zipClient;
|
||||||
MediaSourceManager = mediaSourceManager;
|
MediaSourceManager = mediaSourceManager;
|
||||||
DeviceManager = deviceManager;
|
DeviceManager = deviceManager;
|
||||||
|
@ -598,7 +601,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
|
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
|
// If a fixed width was requested
|
||||||
|
@ -618,7 +621,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a max width was requested
|
// If a max width was requested
|
||||||
else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
|
else if (request.MaxWidth.HasValue)
|
||||||
{
|
{
|
||||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
|
|
||||||
|
@ -626,35 +629,13 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a max height was requested
|
// If a max height was requested
|
||||||
else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
|
else if (request.MaxHeight.HasValue)
|
||||||
{
|
{
|
||||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (request.MaxWidth.HasValue ||
|
|
||||||
request.MaxHeight.HasValue ||
|
|
||||||
request.Width.HasValue ||
|
|
||||||
request.Height.HasValue)
|
|
||||||
{
|
|
||||||
if (state.VideoStream != null)
|
|
||||||
{
|
|
||||||
// Need to perform calculations manually
|
|
||||||
|
|
||||||
// Try to account for bad media info
|
|
||||||
var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
|
|
||||||
var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
|
|
||||||
|
|
||||||
var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
|
|
||||||
|
|
||||||
var manualWidthParam = outputSize.Width.ToString(UsCulture);
|
|
||||||
var manualHeightParam = outputSize.Height.ToString(UsCulture);
|
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
filters[filters.Count - 1] += ":flags=fast_bilinear";
|
filters[filters.Count - 1] += ":flags=fast_bilinear";
|
||||||
|
@ -1027,7 +1008,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
|
// FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
|
||||||
state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
|
state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
|
||||||
|
|
||||||
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
|
var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
|
||||||
await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
|
await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
|
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
|
||||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Dash
|
||||||
|
|
||||||
public class MpegDashService : BaseHlsService
|
public class MpegDashService : BaseHlsService
|
||||||
{
|
{
|
||||||
public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||||
{
|
{
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
|
||||||
namespace MediaBrowser.Api.Playback.Hls
|
namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
|
@ -21,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseHlsService : BaseStreamingService
|
public abstract class BaseHlsService : BaseStreamingService
|
||||||
{
|
{
|
||||||
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Extensions;
|
using MediaBrowser.Model.Extensions;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
public class DynamicHlsService : BaseHlsService
|
public class DynamicHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||||
{
|
{
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoHlsService : BaseHlsService
|
public class VideoHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioService : BaseProgressiveStreamingService
|
public class AudioService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
|
public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack.Web;
|
using ServiceStack.Web;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -27,7 +28,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
protected readonly IImageProcessor ImageProcessor;
|
protected readonly IImageProcessor ImageProcessor;
|
||||||
protected readonly IHttpClient HttpClient;
|
protected readonly IHttpClient HttpClient;
|
||||||
|
|
||||||
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
|
protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
|
||||||
{
|
{
|
||||||
ImageProcessor = imageProcessor;
|
ImageProcessor = imageProcessor;
|
||||||
HttpClient = httpClient;
|
HttpClient = httpClient;
|
||||||
|
|
|
@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
using ServiceStack;
|
using ServiceStack;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class VideoService : BaseProgressiveStreamingService
|
public class VideoService : BaseProgressiveStreamingService
|
||||||
{
|
{
|
||||||
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
|
public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,11 +58,8 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
<Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
|
<HintPath>..\packages\SimpleInjector.2.8.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||||
</Reference>
|
<Private>True</Private>
|
||||||
<Reference Include="SimpleInjector.Diagnostics, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
|
|
@ -6,16 +6,29 @@ using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Implementations.Networking
|
namespace MediaBrowser.Common.Implementations.Networking
|
||||||
{
|
{
|
||||||
public abstract class BaseNetworkManager
|
public abstract class BaseNetworkManager
|
||||||
{
|
{
|
||||||
protected ILogger Logger { get; private set; }
|
protected ILogger Logger { get; private set; }
|
||||||
|
private Timer _clearCacheTimer;
|
||||||
|
|
||||||
protected BaseNetworkManager(ILogger logger)
|
protected BaseNetworkManager(ILogger logger)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
|
||||||
|
// Can't use network change events due to a crash in Linux
|
||||||
|
_clearCacheTimer = new Timer(ClearCacheTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearCacheTimerCallback(object state)
|
||||||
|
{
|
||||||
|
lock (_localIpAddressSyncLock)
|
||||||
|
{
|
||||||
|
_localIpAddresses = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private volatile List<string> _localIpAddresses;
|
private volatile List<string> _localIpAddresses;
|
||||||
|
@ -36,7 +49,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
||||||
var addresses = GetLocalIpAddressesInternal().ToList();
|
var addresses = GetLocalIpAddressesInternal().ToList();
|
||||||
|
|
||||||
_localIpAddresses = addresses;
|
_localIpAddresses = addresses;
|
||||||
BindEvents();
|
|
||||||
|
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
|
@ -46,35 +58,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
||||||
return _localIpAddresses;
|
return _localIpAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BindEvents()
|
|
||||||
{
|
|
||||||
NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
|
|
||||||
NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
|
|
||||||
|
|
||||||
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
|
|
||||||
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
|
||||||
{
|
|
||||||
Logger.Debug("NetworkAvailabilityChanged fired. Resetting cached network info.");
|
|
||||||
|
|
||||||
lock (_localIpAddressSyncLock)
|
|
||||||
{
|
|
||||||
_localIpAddresses = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
Logger.Debug("NetworkAddressChanged fired. Resetting cached network info.");
|
|
||||||
|
|
||||||
lock (_localIpAddressSyncLock)
|
|
||||||
{
|
|
||||||
_localIpAddresses = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<string> GetLocalIpAddressesInternal()
|
private IEnumerable<string> GetLocalIpAddressesInternal()
|
||||||
{
|
{
|
||||||
var list = GetIPsDefault()
|
var list = GetIPsDefault()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="NLog" version="3.2.1" targetFramework="net45" />
|
<package id="NLog" version="3.2.1" targetFramework="net45" />
|
||||||
<package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
|
<package id="SimpleInjector" version="2.8.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
||||||
|
|
|
@ -52,34 +52,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
/// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
|
||||||
public bool HasEmbeddedImage { get; set; }
|
public bool HasEmbeddedImage { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to true if class should be grouped under a container in indicies
|
|
||||||
/// The container class should be defined via IndexContainer
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool GroupInIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to return the folder that should be used to construct a container
|
|
||||||
/// for this item in an index. GroupInIndex should be true as well.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The index container.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override Folder IndexContainer
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return LatestItemsIndexContainer ?? new MusicAlbum { Name = "Unknown Album" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
protected override bool SupportsOwnedItems
|
protected override bool SupportsOwnedItems
|
||||||
{
|
{
|
||||||
|
@ -94,7 +66,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Parents.OfType<MusicAlbum>().FirstOrDefault();
|
return AlbumEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +120,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
/// <value>The album.</value>
|
/// <value>The album.</value>
|
||||||
public string Album { get; set; }
|
public string Album { get; set; }
|
||||||
|
|
||||||
|
[IgnoreDataMember]
|
||||||
|
public MusicAlbum AlbumEntity
|
||||||
|
{
|
||||||
|
get { return FindParent<MusicAlbum>(); }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of the media.
|
/// Gets the type of the media.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -177,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
protected override string CreateUserDataKey()
|
protected override string CreateUserDataKey()
|
||||||
{
|
{
|
||||||
var parent = FindParent<MusicAlbum>();
|
var parent = AlbumEntity;
|
||||||
|
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
@ -14,11 +13,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
|
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
|
||||||
{
|
{
|
||||||
public List<Guid> SoundtrackIds { get; set; }
|
|
||||||
|
|
||||||
public MusicAlbum()
|
public MusicAlbum()
|
||||||
{
|
{
|
||||||
SoundtrackIds = new List<Guid>();
|
|
||||||
Artists = new List<string>();
|
Artists = new List<string>();
|
||||||
AlbumArtists = new List<string>();
|
AlbumArtists = new List<string>();
|
||||||
}
|
}
|
||||||
|
@ -77,49 +73,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||||
return Tracks;
|
return Tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Songs will group into us so don't also include us in the index
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool IncludeInIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to true if class should be grouped under a container in indicies
|
|
||||||
/// The container class should be defined via IndexContainer
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool GroupInIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The unknwon artist
|
|
||||||
/// </summary>
|
|
||||||
private static readonly MusicArtist UnknwonArtist = new MusicArtist { Name = "<Unknown>" };
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to return the folder that should be used to construct a container
|
|
||||||
/// for this item in an index. GroupInIndex should be true as well.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The index container.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override Folder IndexContainer
|
|
||||||
{
|
|
||||||
get { return Parent as MusicArtist ?? UnknwonArtist; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<string> Artists { get; set; }
|
public List<string> Artists { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -906,38 +906,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <value>The provider ids.</value>
|
/// <value>The provider ids.</value>
|
||||||
public Dictionary<string, string> ProviderIds { get; set; }
|
public Dictionary<string, string> ProviderIds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to false if class should be ignored for indexing purposes
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public virtual bool IncludeInIndex
|
|
||||||
{
|
|
||||||
get { return true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to true if class should be grouped under a container in indicies
|
|
||||||
/// The container class should be defined via IndexContainer
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public virtual bool GroupInIndex
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to return the folder that should be used to construct a container
|
|
||||||
/// for this item in an index. GroupInIndex should be true as well.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The index container.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public virtual Folder IndexContainer
|
|
||||||
{
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public virtual Folder LatestItemsIndexContainer
|
public virtual Folder LatestItemsIndexContainer
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,16 +45,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
/// <value>The index number.</value>
|
/// <value>The index number.</value>
|
||||||
public int? IndexNumberEnd { get; set; }
|
public int? IndexNumberEnd { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// We want to group into series not show individually in an index
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool GroupInIndex
|
|
||||||
{
|
|
||||||
get { return true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
protected override bool SupportsOwnedItems
|
protected override bool SupportsOwnedItems
|
||||||
{
|
{
|
||||||
|
@ -91,19 +81,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// We roll up into series
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The index container.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override Folder IndexContainer
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Season;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public override Folder LatestItemsIndexContainer
|
public override Folder LatestItemsIndexContainer
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using MediaBrowser.Controller.Localization;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Controller.Providers;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
using MediaBrowser.Model.Users;
|
using MediaBrowser.Model.Users;
|
||||||
|
@ -15,20 +14,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
|
public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Seasons are just containers
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool IncludeInIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public override bool SupportsAddingToPlaylist
|
public override bool SupportsAddingToPlaylist
|
||||||
{
|
{
|
||||||
|
@ -50,33 +35,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
get { return Series ?? Parent; }
|
get { return Series ?? Parent; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// We want to group into our Series
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool GroupInIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override this to return the folder that should be used to construct a container
|
|
||||||
/// for this item in an index. GroupInIndex should be true as well.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The index container.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override Folder IndexContainer
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Series;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Genre, Rating and Stuido will all be the same
|
// Genre, Rating and Stuido will all be the same
|
||||||
protected override IEnumerable<string> GetIndexByOptions()
|
protected override IEnumerable<string> GetIndexByOptions()
|
||||||
{
|
{
|
||||||
|
|
|
@ -94,19 +94,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Series aren't included directly in indices - Their Episodes will roll up to them
|
|
||||||
/// </summary>
|
|
||||||
/// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public override bool IncludeInIndex
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user data key.
|
/// Gets the user data key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -544,7 +544,9 @@ namespace MediaBrowser.Dlna
|
||||||
new DirectTvProfile(),
|
new DirectTvProfile(),
|
||||||
new DishHopperJoeyProfile(),
|
new DishHopperJoeyProfile(),
|
||||||
new DefaultProfile(),
|
new DefaultProfile(),
|
||||||
new PopcornHourProfile()
|
new PopcornHourProfile(),
|
||||||
|
new VlcProfile(),
|
||||||
|
new BubbleUpnpProfile()
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var item in list)
|
foreach (var item in list)
|
||||||
|
|
|
@ -77,10 +77,12 @@
|
||||||
<Compile Include="Common\DeviceService.cs" />
|
<Compile Include="Common\DeviceService.cs" />
|
||||||
<Compile Include="Didl\DidlBuilder.cs" />
|
<Compile Include="Didl\DidlBuilder.cs" />
|
||||||
<Compile Include="PlayTo\PlayToController.cs" />
|
<Compile Include="PlayTo\PlayToController.cs" />
|
||||||
|
<Compile Include="Profiles\BubbleUpnpProfile.cs" />
|
||||||
<Compile Include="Profiles\DefaultProfile.cs" />
|
<Compile Include="Profiles\DefaultProfile.cs" />
|
||||||
<Compile Include="Profiles\DirectTvProfile.cs" />
|
<Compile Include="Profiles\DirectTvProfile.cs" />
|
||||||
<Compile Include="Profiles\DishHopperJoeyProfile.cs" />
|
<Compile Include="Profiles\DishHopperJoeyProfile.cs" />
|
||||||
<Compile Include="Profiles\PopcornHourProfile.cs" />
|
<Compile Include="Profiles\PopcornHourProfile.cs" />
|
||||||
|
<Compile Include="Profiles\VlcProfile.cs" />
|
||||||
<Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
|
<Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
|
||||||
<Compile Include="Ssdp\Extensions.cs" />
|
<Compile Include="Ssdp\Extensions.cs" />
|
||||||
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
|
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
|
||||||
|
@ -204,6 +206,10 @@
|
||||||
<EmbeddedResource Include="Images\people480.jpg" />
|
<EmbeddedResource Include="Images\people480.jpg" />
|
||||||
<EmbeddedResource Include="Images\people480.png" />
|
<EmbeddedResource Include="Images\people480.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
|
||||||
|
<EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|
|
@ -296,7 +296,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
}
|
}
|
||||||
|
|
||||||
var post = AvCommands.BuildPost(command, service.ServiceType, url, dictionary);
|
var post = AvCommands.BuildPost(command, service.ServiceType, url, dictionary);
|
||||||
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header)
|
await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
await Task.Delay(50).ConfigureAwait(false);
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
|
@ -463,10 +463,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
if (service == null)
|
if (service == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Unable to find service");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
@ -496,10 +496,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
if (service == null)
|
if (service == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Unable to find service");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
@ -521,7 +521,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (service == null)
|
if (service == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType))
|
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType), false)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
@ -558,7 +558,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
throw new InvalidOperationException("Unable to find service");
|
throw new InvalidOperationException("Unable to find service");
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
@ -589,7 +589,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
throw new InvalidOperationException("Unable to find service");
|
throw new InvalidOperationException("Unable to find service");
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
|
var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (result == null || result.Document == null)
|
if (result == null || result.Document == null)
|
||||||
|
|
|
@ -768,8 +768,11 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl).ConfigureAwait(false);
|
await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl).ConfigureAwait(false);
|
||||||
|
|
||||||
if (newItem.StreamInfo.IsDirectStream)
|
if (newItem.StreamInfo.IsDirectStream && newPosition > 0)
|
||||||
{
|
{
|
||||||
|
// This is rather arbitrary, but give the player time to start playing
|
||||||
|
await Task.Delay(2000).ConfigureAwait(false);
|
||||||
|
|
||||||
await _device.Seek(TimeSpan.FromTicks(newPosition)).ConfigureAwait(false);
|
await _device.Seek(TimeSpan.FromTicks(newPosition)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Dlna.Common;
|
using MediaBrowser.Dlna.Common;
|
||||||
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -28,9 +28,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
DeviceService service,
|
DeviceService service,
|
||||||
string command,
|
string command,
|
||||||
string postData,
|
string postData,
|
||||||
|
bool logRequest = true,
|
||||||
string header = null)
|
string header = null)
|
||||||
{
|
{
|
||||||
var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header)
|
var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header, logRequest)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
using (var stream = response.Content)
|
using (var stream = response.Content)
|
||||||
|
@ -69,7 +70,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
|
||||||
LogErrorResponseBody = true
|
LogErrorResponseBody = true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,7 +87,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
|
||||||
LogErrorResponseBody = true
|
LogErrorResponseBody = true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,7 +104,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
private Task<HttpResponseInfo> PostSoapDataAsync(string url,
|
private Task<HttpResponseInfo> PostSoapDataAsync(string url,
|
||||||
string soapAction,
|
string soapAction,
|
||||||
string postData,
|
string postData,
|
||||||
string header = null)
|
string header,
|
||||||
|
bool logRequest)
|
||||||
{
|
{
|
||||||
if (!soapAction.StartsWith("\""))
|
if (!soapAction.StartsWith("\""))
|
||||||
soapAction = "\"" + soapAction + "\"";
|
soapAction = "\"" + soapAction + "\"";
|
||||||
|
@ -114,7 +114,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
Url = url,
|
Url = url,
|
||||||
UserAgent = USERAGENT,
|
UserAgent = USERAGENT,
|
||||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||||
LogErrorResponseBody = true
|
LogErrorResponseBody = true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
76
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
Normal file
76
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Dlna.Profiles
|
||||||
|
{
|
||||||
|
[XmlRoot("Profile")]
|
||||||
|
public class BubbleUpnpProfile : DefaultProfile
|
||||||
|
{
|
||||||
|
public BubbleUpnpProfile()
|
||||||
|
{
|
||||||
|
Name = "BubbleUPnp";
|
||||||
|
|
||||||
|
TimelineOffsetSeconds = 5;
|
||||||
|
|
||||||
|
Identification = new DeviceIdentification
|
||||||
|
{
|
||||||
|
ModelName = "BubbleUPnp",
|
||||||
|
|
||||||
|
Headers = new[]
|
||||||
|
{
|
||||||
|
new HttpHeaderInfo {Name = "User-Agent", Value = "BubbleUPnp", Match = HeaderMatchType.Substring}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TranscodingProfiles = new[]
|
||||||
|
{
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "mp3",
|
||||||
|
Type = DlnaProfileType.Audio,
|
||||||
|
AudioCodec = "mp3"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "ts",
|
||||||
|
Type = DlnaProfileType.Video,
|
||||||
|
VideoCodec = "h264",
|
||||||
|
AudioCodec = "aac"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "jpeg",
|
||||||
|
Type = DlnaProfileType.Photo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectPlayProfiles = new[]
|
||||||
|
{
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
|
||||||
|
Type = DlnaProfileType.Video
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "mp3,flac,asf,off,oga,aac",
|
||||||
|
Type = DlnaProfileType.Audio
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Type = DlnaProfileType.Photo,
|
||||||
|
|
||||||
|
Container = "jpeg,png,gif,bmp,tiff"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ResponseProfiles = new ResponseProfile[] { };
|
||||||
|
|
||||||
|
ContainerProfiles = new ContainerProfile[] { };
|
||||||
|
|
||||||
|
CodecProfiles = new CodecProfile[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
"http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
|
"http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
|
||||||
|
|
||||||
EnableSingleAlbumArtLimit = true;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
|
@ -293,6 +294,12 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
ManufacturerUrl = "http://www.microsoft.com/";
|
ManufacturerUrl = "http://www.microsoft.com/";
|
||||||
SonyAggregationFlags = "10";
|
SonyAggregationFlags = "10";
|
||||||
EnableSingleAlbumArtLimit = true;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
|
@ -310,6 +311,12 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
ManufacturerUrl = "http://www.microsoft.com/";
|
ManufacturerUrl = "http://www.microsoft.com/";
|
||||||
SonyAggregationFlags = "10";
|
SonyAggregationFlags = "10";
|
||||||
EnableSingleAlbumArtLimit = true;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
|
@ -250,6 +251,12 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
ManufacturerUrl = "http://www.microsoft.com/";
|
ManufacturerUrl = "http://www.microsoft.com/";
|
||||||
SonyAggregationFlags = "10";
|
SonyAggregationFlags = "10";
|
||||||
EnableSingleAlbumArtLimit = true;
|
EnableSingleAlbumArtLimit = true;
|
||||||
|
EnableAlbumArtInDidl = true;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
|
@ -284,6 +285,12 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
Condition = ProfileConditionType.LessThanEqual,
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
Property = ProfileConditionValue.Height,
|
Property = ProfileConditionValue.Height,
|
||||||
Value = "1080"
|
Value = "1080"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.LessThanEqual,
|
||||||
|
Property = ProfileConditionValue.VideoFramerate,
|
||||||
|
Value = "30"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
76
MediaBrowser.Dlna/Profiles/VlcProfile.cs
Normal file
76
MediaBrowser.Dlna/Profiles/VlcProfile.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Dlna.Profiles
|
||||||
|
{
|
||||||
|
[XmlRoot("Profile")]
|
||||||
|
public class VlcProfile : DefaultProfile
|
||||||
|
{
|
||||||
|
public VlcProfile()
|
||||||
|
{
|
||||||
|
Name = "Vlc";
|
||||||
|
|
||||||
|
TimelineOffsetSeconds = 5;
|
||||||
|
|
||||||
|
Identification = new DeviceIdentification
|
||||||
|
{
|
||||||
|
ModelName = "Vlc",
|
||||||
|
|
||||||
|
Headers = new[]
|
||||||
|
{
|
||||||
|
new HttpHeaderInfo {Name = "User-Agent", Value = "vlc", Match = HeaderMatchType.Substring}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TranscodingProfiles = new[]
|
||||||
|
{
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "mp3",
|
||||||
|
Type = DlnaProfileType.Audio,
|
||||||
|
AudioCodec = "mp3"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "ts",
|
||||||
|
Type = DlnaProfileType.Video,
|
||||||
|
VideoCodec = "h264",
|
||||||
|
AudioCodec = "aac"
|
||||||
|
},
|
||||||
|
new TranscodingProfile
|
||||||
|
{
|
||||||
|
Container = "jpeg",
|
||||||
|
Type = DlnaProfileType.Photo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectPlayProfiles = new[]
|
||||||
|
{
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
|
||||||
|
Type = DlnaProfileType.Video
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Container = "mp3,flac,asf,off,oga,aac",
|
||||||
|
Type = DlnaProfileType.Audio
|
||||||
|
},
|
||||||
|
|
||||||
|
new DirectPlayProfile
|
||||||
|
{
|
||||||
|
Type = DlnaProfileType.Photo,
|
||||||
|
|
||||||
|
Container = "jpeg,png,gif,bmp,tiff"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ResponseProfiles = new ResponseProfile[] { };
|
||||||
|
|
||||||
|
ContainerProfiles = new ContainerProfile[] { };
|
||||||
|
|
||||||
|
CodecProfiles = new CodecProfile[] { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ namespace MediaBrowser.Dlna.Profiles
|
||||||
Name = "WDTV Live";
|
Name = "WDTV Live";
|
||||||
|
|
||||||
TimelineOffsetSeconds = 5;
|
TimelineOffsetSeconds = 5;
|
||||||
IgnoreTranscodeByteRangeRequests = true;
|
|
||||||
|
|
||||||
Identification = new DeviceIdentification
|
Identification = new DeviceIdentification
|
||||||
{
|
{
|
||||||
|
|
50
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
Normal file
50
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
Normal file
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
43
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
Normal file
43
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
Normal file
File diff suppressed because one or more lines are too long
|
@ -14,7 +14,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
|
@ -79,6 +78,7 @@
|
||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
<CodecProfile type="VideoAudio" codec="ac3">
|
<CodecProfile type="VideoAudio" codec="ac3">
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
|
@ -82,6 +81,7 @@
|
||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
<CodecProfile type="VideoAudio" codec="ac3">
|
<CodecProfile type="VideoAudio" codec="ac3">
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
|
@ -67,6 +66,7 @@
|
||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
<CodecProfile type="VideoAudio" codec="ac3">
|
<CodecProfile type="VideoAudio" codec="ac3">
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>3.0</ModelNumber>
|
<ModelNumber>3.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||||
|
@ -72,6 +71,7 @@
|
||||||
<Conditions>
|
<Conditions>
|
||||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||||
|
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||||
</Conditions>
|
</Conditions>
|
||||||
</CodecProfile>
|
</CodecProfile>
|
||||||
</CodecProfiles>
|
</CodecProfiles>
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
50
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
Normal file
50
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
Normal file
File diff suppressed because one or more lines are too long
|
@ -15,7 +15,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>12.0</ModelNumber>
|
<ModelNumber>12.0</ModelNumber>
|
||||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
<ModelDescription>Emby</ModelDescription>
|
<ModelDescription>Emby</ModelDescription>
|
||||||
<ModelNumber>Emby</ModelNumber>
|
<ModelNumber>Emby</ModelNumber>
|
||||||
<ModelUrl>http://emby.media/</ModelUrl>
|
<ModelUrl>http://emby.media/</ModelUrl>
|
||||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
|
||||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||||
|
|
|
@ -27,14 +27,16 @@ namespace MediaBrowser.Dlna.Service
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
LogRequest(request);
|
LogRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = ProcessControlRequestInternal(request);
|
var response = ProcessControlRequestInternal(request);
|
||||||
|
|
||||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
LogResponse(response);
|
LogResponse(response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
public EndPoint FromEndPoint { get; private set; }
|
public EndPoint FromEndPoint { get; private set; }
|
||||||
public string Message { get; private set; }
|
public string Message { get; private set; }
|
||||||
public bool IgnoreBindFailure { get; private set; }
|
public bool IgnoreBindFailure { get; private set; }
|
||||||
|
public bool EnableDebugLogging { get; private set; }
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure)
|
public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure, bool enableDebugLogging)
|
||||||
{
|
{
|
||||||
Message = message;
|
Message = message;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
EnableDebugLogging = enableDebugLogging;
|
||||||
IgnoreBindFailure = ignoreBindFailure;
|
IgnoreBindFailure = ignoreBindFailure;
|
||||||
FromEndPoint = fromEndPoint;
|
FromEndPoint = fromEndPoint;
|
||||||
ToEndPoint = toEndPoint;
|
ToEndPoint = toEndPoint;
|
||||||
|
@ -37,8 +39,13 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
{
|
{
|
||||||
client.Bind(FromEndPoint);
|
client.Bind(FromEndPoint);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
if (EnableDebugLogging)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error binding datagram socket", ex);
|
||||||
|
}
|
||||||
|
|
||||||
if (!IgnoreBindFailure) throw;
|
if (!IgnoreBindFailure) throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +58,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (!IgnoreBindFailure)
|
if (!IgnoreBindFailure || EnableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
_logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
|
||||||
}
|
}
|
||||||
|
@ -62,8 +69,12 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
{
|
{
|
||||||
client.Close();
|
client.Close();
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
if (EnableDebugLogging)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error closing datagram socket", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, null);
|
}, null);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using MediaBrowser.Common.Events;
|
using MediaBrowser.Common.Events;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
@ -143,7 +142,10 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
args.EndPoint = endPoint;
|
args.EndPoint = endPoint;
|
||||||
args.LocalIp = localIp;
|
args.LocalIp = localIp;
|
||||||
|
|
||||||
TryCreateDevice(args);
|
if (!_ssdpHandler.IsSelfNotification(args))
|
||||||
|
{
|
||||||
|
TryCreateDevice(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,18 +205,25 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
string nts;
|
string nts;
|
||||||
args.Headers.TryGetValue("NTS", out nts);
|
args.Headers.TryGetValue("NTS", out nts);
|
||||||
|
|
||||||
|
if (String.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (String.Equals(args.Method, "NOTIFY", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
EventHelper.FireEventIfNotNull(DeviceLeft, this, args, _logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string usn;
|
string usn;
|
||||||
if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
|
if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
|
||||||
|
|
||||||
string nt;
|
string nt;
|
||||||
if (!args.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
|
if (!args.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
|
||||||
|
|
||||||
// Ignore when a device is indicating it's shutting down
|
|
||||||
if (string.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to be able to download device description
|
// Need to be able to download device description
|
||||||
string location;
|
string location;
|
||||||
if (!args.Headers.TryGetValue("Location", out location) ||
|
if (!args.Headers.TryGetValue("Location", out location) ||
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
}
|
}
|
||||||
|
|
||||||
return String.Format(
|
return String.Format(
|
||||||
"{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 MediaBrowser/{4}",
|
"{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}",
|
||||||
pstring,
|
pstring,
|
||||||
IntPtr.Size * 8,
|
IntPtr.Size * 8,
|
||||||
os.Version.Major,
|
os.Version.Major,
|
||||||
|
@ -88,24 +88,21 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
||||||
{
|
{
|
||||||
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
|
var headers = args.Headers;
|
||||||
{
|
string st;
|
||||||
var headers = args.Headers;
|
|
||||||
|
|
||||||
|
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase) && headers.TryGetValue("st", out st))
|
||||||
|
{
|
||||||
TimeSpan delay = GetSearchDelay(headers);
|
TimeSpan delay = GetSearchDelay(headers);
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
|
_logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(delay).ConfigureAwait(false);
|
await Task.Delay(delay).ConfigureAwait(false);
|
||||||
|
|
||||||
string st;
|
RespondToSearch(args.EndPoint, st);
|
||||||
if (headers.TryGetValue("st", out st))
|
|
||||||
{
|
|
||||||
RespondToSearch(args.EndPoint, st);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
||||||
|
@ -166,9 +163,11 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
||||||
var queued = false;
|
var queued = false;
|
||||||
|
|
||||||
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
for (var i = 0; i < sendCount; i++)
|
for (var i = 0; i < sendCount; i++)
|
||||||
{
|
{
|
||||||
var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure);
|
var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure, enableDebugLogging);
|
||||||
|
|
||||||
if (_messageQueue.Count == 0)
|
if (_messageQueue.Count == 0)
|
||||||
{
|
{
|
||||||
|
@ -212,10 +211,9 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
private void RespondToSearch(EndPoint endpoint, string deviceType)
|
private void RespondToSearch(EndPoint endpoint, string deviceType)
|
||||||
{
|
{
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
{
|
|
||||||
_logger.Debug("RespondToSearch");
|
var isLogged = false;
|
||||||
}
|
|
||||||
|
|
||||||
const string header = "HTTP/1.1 200 OK";
|
const string header = "HTTP/1.1 200 OK";
|
||||||
|
|
||||||
|
@ -224,6 +222,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase))
|
string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
if (!isLogged)
|
||||||
|
{
|
||||||
|
if (enableDebugLogging)
|
||||||
|
{
|
||||||
|
_logger.Debug("Responding to search from {0} for {1}", endpoint, deviceType);
|
||||||
|
}
|
||||||
|
isLogged = true;
|
||||||
|
}
|
||||||
|
|
||||||
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
values["CACHE-CONTROL"] = "max-age = 600";
|
values["CACHE-CONTROL"] = "max-age = 600";
|
||||||
|
@ -238,7 +245,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true, 1);
|
SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true, 1);
|
||||||
//SendDatagram(header, values, endpoint, null, true);
|
//SendDatagram(header, values, endpoint, null, true);
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.Debug("{1} - Responded to a {0} request to {2}", d.Type, endpoint, d.Address.ToString());
|
_logger.Debug("{1} - Responded to a {0} request to {2}", d.Type, endpoint, d.Address.ToString());
|
||||||
}
|
}
|
||||||
|
@ -316,7 +323,9 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
var received = (byte[])result.AsyncState;
|
var received = (byte[])result.AsyncState;
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.Debug(Encoding.ASCII.GetString(received));
|
_logger.Debug(Encoding.ASCII.GetString(received));
|
||||||
}
|
}
|
||||||
|
@ -324,7 +333,12 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
var args = SsdpHelper.ParseSsdpResponse(received);
|
var args = SsdpHelper.ParseSsdpResponse(received);
|
||||||
args.EndPoint = endpoint;
|
args.EndPoint = endpoint;
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (IsSelfNotification(args))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
|
||||||
var headerText = string.Join(",", headerTexts.ToArray());
|
var headerText = string.Join(",", headerTexts.ToArray());
|
||||||
|
@ -345,6 +359,44 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool IsSelfNotification(SsdpMessageEventArgs args)
|
||||||
|
{
|
||||||
|
// Avoid responding to self search messages
|
||||||
|
//string serverId;
|
||||||
|
//if (args.Headers.TryGetValue("X-EMBYSERVERID", out serverId) &&
|
||||||
|
// string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
//{
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
string server;
|
||||||
|
args.Headers.TryGetValue("SERVER", out server);
|
||||||
|
|
||||||
|
if (string.Equals(server, _serverSignature, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
//string usn;
|
||||||
|
//args.Headers.TryGetValue("USN", out usn);
|
||||||
|
|
||||||
|
//if (string.IsNullOrWhiteSpace(usn))
|
||||||
|
//{
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//_logger.Debug("IsSelfNotification test: " + usn);
|
||||||
|
|
||||||
|
//return RegisteredDevices.Any(i =>
|
||||||
|
//{
|
||||||
|
// var isSameDevice = string.Equals(usn, i.USN, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
// i.USN.IndexOf(usn, StringComparison.OrdinalIgnoreCase) != 1 ||
|
||||||
|
// usn.IndexOf(i.USN, StringComparison.OrdinalIgnoreCase) != 1;
|
||||||
|
|
||||||
|
// return isSameDevice;
|
||||||
|
//});
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
||||||
|
@ -399,17 +451,19 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
private void NotifyAll()
|
private void NotifyAll()
|
||||||
{
|
{
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||||
|
|
||||||
|
if (enableDebugLogging)
|
||||||
{
|
{
|
||||||
_logger.Debug("Sending alive notifications");
|
_logger.Debug("Sending alive notifications");
|
||||||
}
|
}
|
||||||
foreach (var d in RegisteredDevices)
|
foreach (var d in RegisteredDevices)
|
||||||
{
|
{
|
||||||
NotifyDevice(d, "alive", 1);
|
NotifyDevice(d, "alive", 1, enableDebugLogging);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NotifyDevice(UpnpDevice dev, string type, int sendCount)
|
private void NotifyDevice(UpnpDevice dev, string type, int sendCount, bool logMessage)
|
||||||
{
|
{
|
||||||
const string header = "NOTIFY * HTTP/1.1";
|
const string header = "NOTIFY * HTTP/1.1";
|
||||||
|
|
||||||
|
@ -424,7 +478,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
values["NT"] = dev.Type;
|
values["NT"] = dev.Type;
|
||||||
values["USN"] = dev.USN;
|
values["USN"] = dev.USN;
|
||||||
|
|
||||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
if (logMessage)
|
||||||
{
|
{
|
||||||
_logger.Debug("{0} said {1}", dev.USN, type);
|
_logger.Debug("{0} said {1}", dev.USN, type);
|
||||||
}
|
}
|
||||||
|
@ -457,7 +511,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
|
|
||||||
foreach (var d in dl.ToList())
|
foreach (var d in dl.ToList())
|
||||||
{
|
{
|
||||||
NotifyDevice(d, "byebye", 2);
|
NotifyDevice(d, "byebye", 2, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("Unregistered mount {0}", uuid);
|
_logger.Debug("Unregistered mount {0}", uuid);
|
||||||
|
@ -468,13 +522,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
||||||
private int _aliveNotifierIntervalMs;
|
private int _aliveNotifierIntervalMs;
|
||||||
private void ReloadAliveNotifier()
|
private void ReloadAliveNotifier()
|
||||||
{
|
{
|
||||||
if (!_config.GetDlnaConfiguration().BlastAliveMessages)
|
var config = _config.GetDlnaConfiguration();
|
||||||
|
|
||||||
|
if (!config.BlastAliveMessages)
|
||||||
{
|
{
|
||||||
DisposeNotificationTimer();
|
DisposeNotificationTimer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var intervalMs = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 1000;
|
var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
|
||||||
|
|
||||||
if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
|
if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -840,7 +840,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
|
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
|
// If a fixed width was requested
|
||||||
|
@ -860,7 +860,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a max width was requested
|
// If a max width was requested
|
||||||
else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
|
else if (request.MaxWidth.HasValue)
|
||||||
{
|
{
|
||||||
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
|
||||||
|
|
||||||
|
@ -868,35 +868,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a max height was requested
|
// If a max height was requested
|
||||||
else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
|
else if (request.MaxHeight.HasValue)
|
||||||
{
|
{
|
||||||
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (request.MaxWidth.HasValue ||
|
|
||||||
request.MaxHeight.HasValue ||
|
|
||||||
request.Width.HasValue ||
|
|
||||||
request.Height.HasValue)
|
|
||||||
{
|
|
||||||
if (state.VideoStream != null)
|
|
||||||
{
|
|
||||||
// Need to perform calculations manually
|
|
||||||
|
|
||||||
// Try to account for bad media info
|
|
||||||
var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
|
|
||||||
var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
|
|
||||||
|
|
||||||
var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
|
|
||||||
|
|
||||||
var manualWidthParam = outputSize.Width.ToString(UsCulture);
|
|
||||||
var manualHeightParam = outputSize.Height.ToString(UsCulture);
|
|
||||||
|
|
||||||
filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var output = string.Empty;
|
var output = string.Empty;
|
||||||
|
|
||||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
||||||
|
|
|
@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
StartProcess(processWrapper);
|
try
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_ffProbeResourcePool.Release();
|
|
||||||
|
|
||||||
_logger.ErrorException("Error starting ffprobe", ex);
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
process.BeginErrorReadLine();
|
|
||||||
|
|
||||||
var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
|
|
||||||
|
|
||||||
if (result != null)
|
|
||||||
{
|
{
|
||||||
if (result.streams != null)
|
StartProcess(processWrapper);
|
||||||
{
|
|
||||||
// Normalize aspect ratio if invalid
|
|
||||||
foreach (var stream in result.streams)
|
|
||||||
{
|
|
||||||
if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
stream.display_aspect_ratio = string.Empty;
|
|
||||||
}
|
|
||||||
if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
stream.sample_aspect_ratio = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
|
|
||||||
|
|
||||||
if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
|
|
||||||
{
|
|
||||||
foreach (var stream in mediaInfo.MediaStreams)
|
|
||||||
{
|
|
||||||
if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
|
|
||||||
// .ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error getting key frame interval", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mediaInfo;
|
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
catch
|
{
|
||||||
{
|
_ffProbeResourcePool.Release();
|
||||||
StopProcess(processWrapper, 100, true);
|
|
||||||
|
|
||||||
throw;
|
_logger.ErrorException("Error starting ffprobe", ex);
|
||||||
}
|
|
||||||
finally
|
throw;
|
||||||
{
|
}
|
||||||
_ffProbeResourcePool.Release();
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
process.BeginErrorReadLine();
|
||||||
|
|
||||||
|
var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (result.streams != null)
|
||||||
|
{
|
||||||
|
// Normalize aspect ratio if invalid
|
||||||
|
foreach (var stream in result.streams)
|
||||||
|
{
|
||||||
|
if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
stream.display_aspect_ratio = string.Empty;
|
||||||
|
}
|
||||||
|
if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
stream.sample_aspect_ratio = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
|
||||||
|
|
||||||
|
if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
|
||||||
|
{
|
||||||
|
foreach (var stream in mediaInfo.MediaStreams)
|
||||||
|
{
|
||||||
|
if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
|
||||||
|
// .ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.ErrorException("Error getting key frame interval", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mediaInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
StopProcess(processWrapper, 100, true);
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_ffProbeResourcePool.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
|
throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
|
||||||
|
@ -307,31 +308,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
|
|
||||||
StartProcess(processWrapper);
|
|
||||||
|
|
||||||
var lines = new List<int>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
process.BeginErrorReadLine();
|
StartProcess(processWrapper);
|
||||||
|
|
||||||
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
|
var lines = new List<int>();
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
try
|
||||||
{
|
|
||||||
if (cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
{
|
||||||
throw;
|
process.BeginErrorReadLine();
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
StopProcess(processWrapper, 100, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines;
|
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
StopProcess(processWrapper, 100, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken)
|
private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken)
|
||||||
|
@ -490,51 +492,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
bool ranToCompletion;
|
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
StartProcess(processWrapper);
|
bool ranToCompletion;
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
StartProcess(processWrapper);
|
||||||
|
|
||||||
#pragma warning disable 4014
|
#pragma warning disable 4014
|
||||||
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
// Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
|
||||||
process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
|
process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
|
||||||
#pragma warning restore 4014
|
#pragma warning restore 4014
|
||||||
|
|
||||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
||||||
process.BeginErrorReadLine();
|
process.BeginErrorReadLine();
|
||||||
|
|
||||||
ranToCompletion = process.WaitForExit(10000);
|
ranToCompletion = process.WaitForExit(10000);
|
||||||
|
|
||||||
if (!ranToCompletion)
|
if (!ranToCompletion)
|
||||||
|
{
|
||||||
|
StopProcess(processWrapper, 1000, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
finally
|
||||||
{
|
{
|
||||||
StopProcess(processWrapper, 1000, false);
|
resourcePool.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||||
|
|
||||||
|
if (exitCode == -1 || memoryStream.Length == 0)
|
||||||
|
{
|
||||||
|
memoryStream.Dispose();
|
||||||
|
|
||||||
|
var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
|
||||||
|
|
||||||
|
_logger.Error(msg);
|
||||||
|
|
||||||
|
throw new ApplicationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
return memoryStream;
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
resourcePool.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
|
||||||
|
|
||||||
if (exitCode == -1 || memoryStream.Length == 0)
|
|
||||||
{
|
|
||||||
memoryStream.Dispose();
|
|
||||||
|
|
||||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
|
|
||||||
|
|
||||||
_logger.Error(msg);
|
|
||||||
|
|
||||||
throw new ApplicationException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
return memoryStream;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetTimeParameter(long ticks)
|
public string GetTimeParameter(long ticks)
|
||||||
|
@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
bool ranToCompletion = false;
|
bool ranToCompletion = false;
|
||||||
|
|
||||||
var processWrapper = new ProcessWrapper(process, this);
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
StartProcess(processWrapper);
|
try
|
||||||
|
|
||||||
// Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
|
|
||||||
// but we still need to detect if the process hangs.
|
|
||||||
// Making the assumption that as long as new jpegs are showing up, everything is good.
|
|
||||||
|
|
||||||
bool isResponsive = true;
|
|
||||||
int lastCount = 0;
|
|
||||||
|
|
||||||
while (isResponsive)
|
|
||||||
{
|
{
|
||||||
if (process.WaitForExit(30000))
|
StartProcess(processWrapper);
|
||||||
|
|
||||||
|
// Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
|
||||||
|
// but we still need to detect if the process hangs.
|
||||||
|
// Making the assumption that as long as new jpegs are showing up, everything is good.
|
||||||
|
|
||||||
|
bool isResponsive = true;
|
||||||
|
int lastCount = 0;
|
||||||
|
|
||||||
|
while (isResponsive)
|
||||||
{
|
{
|
||||||
ranToCompletion = true;
|
if (process.WaitForExit(30000))
|
||||||
break;
|
{
|
||||||
|
ranToCompletion = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var jpegCount = Directory.GetFiles(targetDirectory)
|
||||||
|
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
isResponsive = (jpegCount > lastCount);
|
||||||
|
lastCount = jpegCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
if (!ranToCompletion)
|
||||||
|
{
|
||||||
var jpegCount = Directory.GetFiles(targetDirectory)
|
StopProcess(processWrapper, 1000, false);
|
||||||
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
}
|
||||||
|
|
||||||
isResponsive = (jpegCount > lastCount);
|
|
||||||
lastCount = jpegCount;
|
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
if (!ranToCompletion)
|
|
||||||
{
|
{
|
||||||
StopProcess(processWrapper, 1000, false);
|
resourcePool.Release();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
resourcePool.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||||
|
|
||||||
if (exitCode == -1)
|
if (exitCode == -1)
|
||||||
{
|
{
|
||||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
|
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
|
||||||
|
|
||||||
_logger.Error(msg);
|
_logger.Error(msg);
|
||||||
|
|
||||||
throw new ApplicationException(msg);
|
throw new ApplicationException(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +786,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProcessWrapper
|
private class ProcessWrapper : IDisposable
|
||||||
{
|
{
|
||||||
public readonly Process Process;
|
public readonly Process Process;
|
||||||
public bool HasExited;
|
public bool HasExited;
|
||||||
|
@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
process.Dispose();
|
process.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
private readonly object _syncLock = new object();
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
lock (_syncLock)
|
||||||
|
{
|
||||||
|
if (!_disposed)
|
||||||
|
{
|
||||||
|
if (Process != null)
|
||||||
|
{
|
||||||
|
Process.Exited -= Process_Exited;
|
||||||
|
Process.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using MediaBrowser.Common.IO;
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Controller.Channels;
|
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
|
@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
/// different directories and files.
|
/// different directories and files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The file watcher delay.</value>
|
/// <value>The file watcher delay.</value>
|
||||||
public int RealtimeMonitorDelay { get; set; }
|
public int RealtimeLibraryMonitorDelay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether [enable dashboard response caching].
|
/// Gets or sets a value indicating whether [enable dashboard response caching].
|
||||||
|
@ -233,7 +233,7 @@ namespace MediaBrowser.Model.Configuration
|
||||||
// 5 minutes
|
// 5 minutes
|
||||||
MinResumeDurationSeconds = 300;
|
MinResumeDurationSeconds = 300;
|
||||||
|
|
||||||
RealtimeMonitorDelay = 30;
|
RealtimeLibraryMonitorDelay = 40;
|
||||||
|
|
||||||
EnableInternetProviders = true;
|
EnableInternetProviders = true;
|
||||||
FindInternetTrailers = true;
|
FindInternetTrailers = true;
|
||||||
|
@ -261,8 +261,6 @@ namespace MediaBrowser.Model.Configuration
|
||||||
"Chromecast",
|
"Chromecast",
|
||||||
"iOS",
|
"iOS",
|
||||||
"Unknown app",
|
"Unknown app",
|
||||||
"MediaPortal",
|
|
||||||
"Media Portal",
|
|
||||||
"iPad",
|
"iPad",
|
||||||
"iPhone",
|
"iPhone",
|
||||||
"Windows Phone"
|
"Windows Phone"
|
||||||
|
|
|
@ -14,6 +14,9 @@ namespace MediaBrowser.Model.Dlna
|
||||||
[XmlAttribute("codec")]
|
[XmlAttribute("codec")]
|
||||||
public string Codec { get; set; }
|
public string Codec { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("container")]
|
||||||
|
public string Container { get; set; }
|
||||||
|
|
||||||
public CodecProfile()
|
public CodecProfile()
|
||||||
{
|
{
|
||||||
Conditions = new ProfileCondition[] {};
|
Conditions = new ProfileCondition[] {};
|
||||||
|
@ -29,8 +32,30 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsCodec(string codec)
|
public List<string> GetContainers()
|
||||||
{
|
{
|
||||||
|
List<string> list = new List<string>();
|
||||||
|
foreach (string i in (Container ?? string.Empty).Split(','))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(i)) list.Add(i);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ContainsContainer(string container)
|
||||||
|
{
|
||||||
|
List<string> containers = GetContainers();
|
||||||
|
|
||||||
|
return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsCodec(string codec, string container)
|
||||||
|
{
|
||||||
|
if (!ContainsContainer(container))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
List<string> codecs = GetCodecs();
|
List<string> codecs = GetCodecs();
|
||||||
|
|
||||||
return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);
|
return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
|
@ -164,7 +165,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
|
if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
|
||||||
{
|
{
|
||||||
orgPnValues.Add(mediaProfile.OrgPn);
|
orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,6 @@ namespace MediaBrowser.Model.Dlna
|
||||||
public string ModelNumber { get; set; }
|
public string ModelNumber { get; set; }
|
||||||
public string ModelUrl { get; set; }
|
public string ModelUrl { get; set; }
|
||||||
public string SerialNumber { get; set; }
|
public string SerialNumber { get; set; }
|
||||||
public bool IgnoreTranscodeByteRangeRequests { get; set; }
|
|
||||||
|
|
||||||
public bool EnableAlbumArtInDidl { get; set; }
|
public bool EnableAlbumArtInDidl { get; set; }
|
||||||
public bool EnableSingleAlbumArtLimit { get; set; }
|
public bool EnableSingleAlbumArtLimit { get; set; }
|
||||||
|
|
|
@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
List<ProfileCondition> conditions = new List<ProfileCondition>();
|
List<ProfileCondition> conditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
|
if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container))
|
||||||
{
|
{
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
|
@ -206,7 +206,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
|
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec))
|
if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
|
||||||
{
|
{
|
||||||
audioCodecProfiles.Add(i);
|
audioCodecProfiles.Add(i);
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
|
List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec))
|
if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
|
||||||
{
|
{
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
|
@ -437,7 +437,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
|
List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
foreach (CodecProfile i in options.Profile.CodecProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec))
|
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
|
||||||
{
|
{
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
|
@ -600,7 +600,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in profile.CodecProfiles)
|
foreach (CodecProfile i in profile.CodecProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
|
if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec, container))
|
||||||
{
|
{
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
|
@ -635,7 +635,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
conditions = new List<ProfileCondition>();
|
conditions = new List<ProfileCondition>();
|
||||||
foreach (CodecProfile i in profile.CodecProfiles)
|
foreach (CodecProfile i in profile.CodecProfiles)
|
||||||
{
|
{
|
||||||
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
|
if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec, container))
|
||||||
{
|
{
|
||||||
foreach (ProfileCondition c in i.Conditions)
|
foreach (ProfileCondition c in i.Conditions)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,13 +38,16 @@ namespace MediaBrowser.Providers.Manager
|
||||||
{
|
{
|
||||||
var hasChanges = false;
|
var hasChanges = false;
|
||||||
|
|
||||||
var images = providers.OfType<ILocalImageFileProvider>()
|
if (!(item is Photo))
|
||||||
.SelectMany(i => i.GetImages(item, directoryService))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (MergeImages(item, images))
|
|
||||||
{
|
{
|
||||||
hasChanges = true;
|
var images = providers.OfType<ILocalImageFileProvider>()
|
||||||
|
.SelectMany(i => i.GetImages(item, directoryService))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (MergeImages(item, images))
|
||||||
|
{
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasChanges;
|
return hasChanges;
|
||||||
|
@ -419,19 +422,14 @@ namespace MediaBrowser.Providers.Manager
|
||||||
var changed = false;
|
var changed = false;
|
||||||
|
|
||||||
var newImages = images.Where(i => i.Type == type).ToList();
|
var newImages = images.Where(i => i.Type == type).ToList();
|
||||||
if (newImages.Count > 0)
|
|
||||||
{
|
var newImageFileInfos = newImages
|
||||||
var newImageFileInfos = images.Where(i => i.Type == type)
|
|
||||||
.Select(i => i.FileInfo)
|
.Select(i => i.FileInfo)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (newImageFileInfos.Count > 0)
|
if (item.AddImages(type, newImageFileInfos))
|
||||||
{
|
{
|
||||||
if (item.AddImages(type, newImageFileInfos))
|
changed = true;
|
||||||
{
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
|
|
@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
|
|
||||||
private string GetAudioImagePath(Audio item)
|
private string GetAudioImagePath(Audio item)
|
||||||
{
|
{
|
||||||
var album = item.Parent as MusicAlbum;
|
var album = item.AlbumEntity;
|
||||||
|
|
||||||
var filename = item.Album ?? string.Empty;
|
var filename = item.Album ?? string.Empty;
|
||||||
filename += string.Join(",", item.Artists.ToArray());
|
filename += string.Join(",", item.Artists.ToArray());
|
||||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
using MediaBrowser.Model.Providers;
|
using MediaBrowser.Model.Providers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -29,12 +30,14 @@ namespace MediaBrowser.Providers.TV
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient)
|
public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient, ILogger logger)
|
||||||
{
|
{
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_config = config;
|
_config = config;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
|
_logger = logger;
|
||||||
Current = this;
|
Current = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +103,8 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds,
|
||||||
|
cancellationToken);
|
||||||
result.HasMetadata = result.Item != null;
|
result.HasMetadata = result.Item != null;
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException)
|
catch (FileNotFoundException)
|
||||||
|
@ -112,6 +116,10 @@ namespace MediaBrowser.Providers.TV
|
||||||
// Don't fail the provider because this will just keep on going and going.
|
// Don't fail the provider because this will just keep on going and going.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Debug("No series identity found for {0}", searchInfo.Name);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -265,7 +273,6 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
FetchMainEpisodeInfo(episode, file, cancellationToken);
|
FetchMainEpisodeInfo(episode, file, cancellationToken);
|
||||||
usingAbsoluteData = true;
|
usingAbsoluteData = true;
|
||||||
success = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var end = identity.IndexNumberEnd ?? episodeNumber;
|
var end = identity.IndexNumberEnd ?? episodeNumber;
|
||||||
|
@ -298,7 +305,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
episodeNumber++;
|
episodeNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success ? episode : null;
|
return episode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
|
|
@ -1193,7 +1193,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
{
|
{
|
||||||
dto.Album = audio.Album;
|
dto.Album = audio.Album;
|
||||||
|
|
||||||
var albumParent = audio.FindParent<MusicAlbum>();
|
var albumParent = audio.AlbumEntity;
|
||||||
|
|
||||||
if (albumParent != null)
|
if (albumParent != null)
|
||||||
{
|
{
|
||||||
|
@ -1208,15 +1208,6 @@ namespace MediaBrowser.Server.Implementations.Dto
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
var album = item as MusicAlbum;
|
|
||||||
|
|
||||||
if (album != null)
|
|
||||||
{
|
|
||||||
dto.SoundtrackIds = album.SoundtrackIds
|
|
||||||
.Select(i => i.ToString("N"))
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasArtist = item as IHasArtist;
|
var hasArtist = item as IHasArtist;
|
||||||
if (hasArtist != null)
|
if (hasArtist != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
|
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
|
||||||
// Seeing long delays in some situations, especially over the network.
|
// Seeing long delays in some situations, especially over the network.
|
||||||
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
|
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
|
||||||
await Task.Delay(1500).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
|
|
||||||
string val;
|
string val;
|
||||||
_tempIgnoredPaths.TryRemove(path, out val);
|
_tempIgnoredPaths.TryRemove(path, out val);
|
||||||
|
@ -437,11 +437,11 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
{
|
{
|
||||||
if (_updateTimer == null)
|
if (_updateTimer == null)
|
||||||
{
|
{
|
||||||
_updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
_updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
_updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -560,7 +560,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
private async Task ProcessPathChanges(List<string> paths)
|
private async Task ProcessPathChanges(List<string> paths)
|
||||||
{
|
{
|
||||||
var itemsToRefresh = paths.Select(Path.GetDirectoryName)
|
var itemsToRefresh = paths
|
||||||
.Select(GetAffectedBaseItem)
|
.Select(GetAffectedBaseItem)
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
|
|
|
@ -281,10 +281,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
||||||
|
|
||||||
if (newValue >= maxCount)
|
if (newValue >= maxCount)
|
||||||
{
|
{
|
||||||
_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
|
//_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
|
||||||
user.Policy.IsDisabled = true;
|
//user.Policy.IsDisabled = true;
|
||||||
|
|
||||||
fireLockout = true;
|
//fireLockout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
|
await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
|
||||||
|
|
|
@ -387,7 +387,6 @@
|
||||||
"ButtonSignOut": "Sign Out",
|
"ButtonSignOut": "Sign Out",
|
||||||
"ButtonMyProfile": "My Profile",
|
"ButtonMyProfile": "My Profile",
|
||||||
"ButtonMyPreferences": "My Preferences",
|
"ButtonMyPreferences": "My Preferences",
|
||||||
"MessageBrowserDoesNotSupportWebSockets": "This browser does not support web sockets. For a better experience, try a newer browser such as Chrome, Firefox, IE10+, Safari (iOS) or Opera.",
|
|
||||||
"LabelInstallingPackage": "Installing {0}",
|
"LabelInstallingPackage": "Installing {0}",
|
||||||
"LabelPackageInstallCompleted": "{0} installation completed.",
|
"LabelPackageInstallCompleted": "{0} installation completed.",
|
||||||
"LabelPackageInstallFailed": "{0} installation failed.",
|
"LabelPackageInstallFailed": "{0} installation failed.",
|
||||||
|
|
|
@ -440,7 +440,7 @@
|
||||||
"HeaderVideo": "Video",
|
"HeaderVideo": "Video",
|
||||||
"HeaderRuntime": "Runtime",
|
"HeaderRuntime": "Runtime",
|
||||||
"HeaderCommunityRating": "Community rating",
|
"HeaderCommunityRating": "Community rating",
|
||||||
"HeaderPasswordReset": "Password Reset",
|
"HeaderPasswordReset": "Password Reset",
|
||||||
"HeaderParentalRating": "Parental rating",
|
"HeaderParentalRating": "Parental rating",
|
||||||
"HeaderReleaseDate": "Release date",
|
"HeaderReleaseDate": "Release date",
|
||||||
"HeaderDateAdded": "Date added",
|
"HeaderDateAdded": "Date added",
|
||||||
|
@ -766,5 +766,10 @@
|
||||||
"SyncJobItemStatusRemovedFromDevice": "Removed from device",
|
"SyncJobItemStatusRemovedFromDevice": "Removed from device",
|
||||||
"SyncJobItemStatusCancelled": "Cancelled",
|
"SyncJobItemStatusCancelled": "Cancelled",
|
||||||
"LabelProfile": "Profile:",
|
"LabelProfile": "Profile:",
|
||||||
"LabelBitrateMbps": "Bitrate (Mbps):"
|
"LabelBitrateMbps": "Bitrate (Mbps):",
|
||||||
|
"EmbyIntroDownloadMessage": "To download and install Emby Server visit {0}.",
|
||||||
|
"ButtonNewServer": "New Server",
|
||||||
|
"ButtonSignInWithConnect": "Sign in with Emby Connect",
|
||||||
|
"HeaderNewServer": "New Server",
|
||||||
|
"MyDevice": "My Device"
|
||||||
}
|
}
|
||||||
|
|
|
@ -882,7 +882,7 @@
|
||||||
"MessageNoSubtitleSearchResultsFound": "No search results founds.",
|
"MessageNoSubtitleSearchResultsFound": "No search results founds.",
|
||||||
"TabDisplay": "Display",
|
"TabDisplay": "Display",
|
||||||
"TabLanguages": "Languages",
|
"TabLanguages": "Languages",
|
||||||
"TabWebClient": "Web Client",
|
"TabAppSettings": "App Settings",
|
||||||
"LabelEnableThemeSongs": "Enable theme songs",
|
"LabelEnableThemeSongs": "Enable theme songs",
|
||||||
"LabelEnableBackdrops": "Enable backdrops",
|
"LabelEnableBackdrops": "Enable backdrops",
|
||||||
"LabelEnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.",
|
"LabelEnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.",
|
||||||
|
@ -1436,10 +1436,17 @@
|
||||||
"LabelSelectViewStyles": "Enable enhanced presentations for:",
|
"LabelSelectViewStyles": "Enable enhanced presentations for:",
|
||||||
"LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.",
|
"LabelSelectViewStylesHelp": "If enabled, views will be built with metadata to offer categories such as Suggestions, Latest, Genres, and more. If disabled, they'll be displayed with simple folders.",
|
||||||
"TabPhotos": "Photos",
|
"TabPhotos": "Photos",
|
||||||
"TabVideos": "Videos",
|
"TabVideos": "Videos",
|
||||||
"OptionReportList": "List View",
|
"HeaderWelcomeToEmby": "Welcome to Emby",
|
||||||
"OptionReportStatistics": "Statistics",
|
"EmbyIntroMessage": "With Emby you can easily stream videos, music and photos to smart phones, tablets and other devices from your Emby Server.",
|
||||||
"OptionReportGrouping": "Grouping",
|
"ButtonSkip": "Skip",
|
||||||
"OptionReportExport": "Report Export",
|
"TextConnectToServerManually": "Connect to server manually",
|
||||||
"OptionReportColumns": "Report Columns"
|
"ButtonSignInWithConnect": "Sign in with Emby Connect",
|
||||||
|
"ButtonConnect": "Connect",
|
||||||
|
"LabelServerHost": "Host:",
|
||||||
|
"LabelServerHostHelp": "192.168.1.100 or https://myserver.com",
|
||||||
|
"LabelServerPort": "Port:",
|
||||||
|
"HeaderNewServer": "New Server",
|
||||||
|
"ButtonChangeServer": "Change Server",
|
||||||
|
"HeaderConnectToServer": "Connect to Server"
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,8 @@
|
||||||
<Reference Include="Interfaces.IO">
|
<Reference Include="Interfaces.IO">
|
||||||
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="MediaBrowser.Naming, Version=1.0.5509.27636, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="MediaBrowser.Naming">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.35\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
|
||||||
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.34\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Mono.Nat, Version=1.2.24.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Mono.Nat, Version=1.2.24.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
@ -226,6 +225,7 @@
|
||||||
<Compile Include="Localization\LocalizationManager.cs" />
|
<Compile Include="Localization\LocalizationManager.cs" />
|
||||||
<Compile Include="Logging\PatternsLogger.cs" />
|
<Compile Include="Logging\PatternsLogger.cs" />
|
||||||
<Compile Include="MediaEncoder\EncodingManager.cs" />
|
<Compile Include="MediaEncoder\EncodingManager.cs" />
|
||||||
|
<Compile Include="Persistence\BaseSqliteRepository.cs" />
|
||||||
<Compile Include="Sorting\StartDateComparer.cs" />
|
<Compile Include="Sorting\StartDateComparer.cs" />
|
||||||
<Compile Include="Sync\SyncHelper.cs" />
|
<Compile Include="Sync\SyncHelper.cs" />
|
||||||
<Compile Include="Sync\SyncJobOptions.cs" />
|
<Compile Include="Sync\SyncJobOptions.cs" />
|
||||||
|
@ -242,7 +242,6 @@
|
||||||
<Compile Include="Persistence\SqliteMediaStreamsRepository.cs" />
|
<Compile Include="Persistence\SqliteMediaStreamsRepository.cs" />
|
||||||
<Compile Include="Notifications\SqliteNotificationsRepository.cs" />
|
<Compile Include="Notifications\SqliteNotificationsRepository.cs" />
|
||||||
<Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
|
<Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
|
||||||
<Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
|
|
||||||
<Compile Include="Persistence\TypeMapper.cs" />
|
<Compile Include="Persistence\TypeMapper.cs" />
|
||||||
<Compile Include="Photos\BaseDynamicImageProvider.cs" />
|
<Compile Include="Photos\BaseDynamicImageProvider.cs" />
|
||||||
<Compile Include="Playlists\ManualPlaylistsFolder.cs" />
|
<Compile Include="Playlists\ManualPlaylistsFolder.cs" />
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
{
|
||||||
|
public abstract class BaseSqliteRepository : IDisposable
|
||||||
|
{
|
||||||
|
protected readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1);
|
||||||
|
protected ILogger Logger;
|
||||||
|
|
||||||
|
protected BaseSqliteRepository(ILogManager logManager)
|
||||||
|
{
|
||||||
|
Logger = logManager.GetLogger(GetType().Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly object _disposeLock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases unmanaged and - optionally - managed resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||||
|
protected virtual void Dispose(bool dispose)
|
||||||
|
{
|
||||||
|
if (dispose)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock (_disposeLock)
|
||||||
|
{
|
||||||
|
WriteLock.Wait();
|
||||||
|
|
||||||
|
CloseConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.ErrorException("Error disposing database", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void DisposeInternal()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void CloseConnection();
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,8 +32,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
_logger = logManager.GetLogger(GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the connection to the database
|
/// Opens the connection to the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -54,8 +52,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
_connection.RunQueries(queries, _logger);
|
_connection.RunQueries(queries, _logger);
|
||||||
|
|
||||||
PrepareStatements();
|
PrepareStatements();
|
||||||
|
|
||||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -286,12 +282,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
lock (_disposeLock)
|
||||||
{
|
{
|
||||||
if (_shrinkMemoryTimer != null)
|
|
||||||
{
|
|
||||||
_shrinkMemoryTimer.Dispose();
|
|
||||||
_shrinkMemoryTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_connection != null)
|
if (_connection != null)
|
||||||
{
|
{
|
||||||
if (_connection.IsOpen())
|
if (_connection.IsOpen())
|
||||||
|
|
|
@ -16,11 +16,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class SQLiteDisplayPreferencesRepository
|
/// Class SQLiteDisplayPreferencesRepository
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SqliteDisplayPreferencesRepository : IDisplayPreferencesRepository
|
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
|
||||||
{
|
{
|
||||||
private IDbConnection _connection;
|
private IDbConnection _connection;
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths) : base(logManager)
|
||||||
|
{
|
||||||
|
_jsonSerializer = jsonSerializer;
|
||||||
|
_appPaths = appPaths;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the repository
|
/// Gets the name of the repository
|
||||||
|
@ -44,36 +48,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
|
||||||
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="SqliteDisplayPreferencesRepository" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="appPaths">The app paths.</param>
|
|
||||||
/// <param name="jsonSerializer">The json serializer.</param>
|
|
||||||
/// <param name="logManager">The log manager.</param>
|
|
||||||
/// <exception cref="System.ArgumentNullException">
|
|
||||||
/// jsonSerializer
|
|
||||||
/// or
|
|
||||||
/// appPaths
|
|
||||||
/// </exception>
|
|
||||||
public SqliteDisplayPreferencesRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
|
|
||||||
{
|
|
||||||
if (jsonSerializer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("jsonSerializer");
|
|
||||||
}
|
|
||||||
if (appPaths == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("appPaths");
|
|
||||||
}
|
|
||||||
|
|
||||||
_jsonSerializer = jsonSerializer;
|
|
||||||
_appPaths = appPaths;
|
|
||||||
|
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the connection to the database
|
/// Opens the connection to the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -82,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
|
var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
|
||||||
|
|
||||||
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
|
_connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
|
||||||
|
|
||||||
string[] queries = {
|
string[] queries = {
|
||||||
|
|
||||||
|
@ -95,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
"pragma shrink_memory"
|
"pragma shrink_memory"
|
||||||
};
|
};
|
||||||
|
|
||||||
_connection.RunQueries(queries, _logger);
|
_connection.RunQueries(queries, Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -122,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
|
var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -157,7 +131,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to save display preferences:", e);
|
Logger.ErrorException("Failed to save display preferences:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -173,7 +147,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +168,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -235,7 +209,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to save display preferences:", e);
|
Logger.ErrorException("Failed to save display preferences:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -251,7 +225,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,45 +296,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected override void CloseConnection()
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (_connection != null)
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object _disposeLock = new object();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
|
||||||
protected virtual void Dispose(bool dispose)
|
|
||||||
{
|
|
||||||
if (dispose)
|
|
||||||
{
|
{
|
||||||
try
|
if (_connection.IsOpen())
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
_connection.Close();
|
||||||
{
|
}
|
||||||
if (_connection != null)
|
|
||||||
{
|
|
||||||
if (_connection.IsOpen())
|
|
||||||
{
|
|
||||||
_connection.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
_connection.Dispose();
|
_connection.Dispose();
|
||||||
_connection = null;
|
_connection = null;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error disposing database", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,10 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Persistence
|
namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
public class SqliteFileOrganizationRepository : IFileOrganizationRepository, IDisposable
|
public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
|
||||||
{
|
{
|
||||||
private IDbConnection _connection;
|
private IDbConnection _connection;
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
|
|
||||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
|
||||||
private readonly IServerApplicationPaths _appPaths;
|
private readonly IServerApplicationPaths _appPaths;
|
||||||
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
@ -30,11 +26,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
private IDbCommand _deleteResultCommand;
|
private IDbCommand _deleteResultCommand;
|
||||||
private IDbCommand _deleteAllCommand;
|
private IDbCommand _deleteAllCommand;
|
||||||
|
|
||||||
public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths)
|
public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths) : base(logManager)
|
||||||
{
|
{
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
|
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -45,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db");
|
var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db");
|
||||||
|
|
||||||
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
|
_connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
|
||||||
|
|
||||||
string[] queries = {
|
string[] queries = {
|
||||||
|
|
||||||
|
@ -58,11 +52,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
"pragma shrink_memory"
|
"pragma shrink_memory"
|
||||||
};
|
};
|
||||||
|
|
||||||
_connection.RunQueries(queries, _logger);
|
_connection.RunQueries(queries, Logger);
|
||||||
|
|
||||||
PrepareStatements();
|
PrepareStatements();
|
||||||
|
|
||||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PrepareStatements()
|
private void PrepareStatements()
|
||||||
|
@ -103,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -145,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to save FileOrganizationResult:", e);
|
Logger.ErrorException("Failed to save FileOrganizationResult:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -161,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +164,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
throw new ArgumentNullException("id");
|
throw new ArgumentNullException("id");
|
||||||
}
|
}
|
||||||
|
|
||||||
await _writeLock.WaitAsync().ConfigureAwait(false);
|
await WriteLock.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -199,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to delete FileOrganizationResult:", e);
|
Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -215,13 +207,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteAll()
|
public async Task DeleteAll()
|
||||||
{
|
{
|
||||||
await _writeLock.WaitAsync().ConfigureAwait(false);
|
await WriteLock.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -246,7 +238,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to delete results", e);
|
Logger.ErrorException("Failed to delete results", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -262,7 +254,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,51 +415,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected override void CloseConnection()
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (_connection != null)
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object _disposeLock = new object();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
|
||||||
protected virtual void Dispose(bool dispose)
|
|
||||||
{
|
|
||||||
if (dispose)
|
|
||||||
{
|
{
|
||||||
try
|
if (_connection.IsOpen())
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
_connection.Close();
|
||||||
{
|
|
||||||
if (_shrinkMemoryTimer != null)
|
|
||||||
{
|
|
||||||
_shrinkMemoryTimer.Dispose();
|
|
||||||
_shrinkMemoryTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_connection != null)
|
|
||||||
{
|
|
||||||
if (_connection.IsOpen())
|
|
||||||
{
|
|
||||||
_connection.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
_connection.Dispose();
|
|
||||||
_connection = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error disposing database", ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_connection.Dispose();
|
||||||
|
_connection = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,12 +130,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
_mediaStreamsRepository.Initialize();
|
_mediaStreamsRepository.Initialize();
|
||||||
_chapterRepository.Initialize();
|
_chapterRepository.Initialize();
|
||||||
|
|
||||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _write lock
|
/// The _write lock
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -430,12 +426,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
lock (_disposeLock)
|
||||||
{
|
{
|
||||||
if (_shrinkMemoryTimer != null)
|
|
||||||
{
|
|
||||||
_shrinkMemoryTimer.Dispose();
|
|
||||||
_shrinkMemoryTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_writeLock.Wait();
|
_writeLock.Wait();
|
||||||
|
|
||||||
if (_connection != null)
|
if (_connection != null)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Globalization;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
@ -21,8 +20,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
private IDbCommand _deleteStreamsCommand;
|
private IDbCommand _deleteStreamsCommand;
|
||||||
private IDbCommand _saveStreamCommand;
|
private IDbCommand _saveStreamCommand;
|
||||||
|
|
||||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
|
||||||
|
|
||||||
public SqliteMediaStreamsRepository(IDbConnection connection, ILogManager logManager)
|
public SqliteMediaStreamsRepository(IDbConnection connection, ILogManager logManager)
|
||||||
{
|
{
|
||||||
_connection = connection;
|
_connection = connection;
|
||||||
|
@ -64,8 +61,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
AddRefFramesCommand();
|
AddRefFramesCommand();
|
||||||
|
|
||||||
PrepareStatements();
|
PrepareStatements();
|
||||||
|
|
||||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddPixelFormatColumnCommand()
|
private void AddPixelFormatColumnCommand()
|
||||||
|
@ -563,12 +558,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
lock (_disposeLock)
|
||||||
{
|
{
|
||||||
if (_shrinkMemoryTimer != null)
|
|
||||||
{
|
|
||||||
_shrinkMemoryTimer.Dispose();
|
|
||||||
_shrinkMemoryTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_connection != null)
|
if (_connection != null)
|
||||||
{
|
{
|
||||||
if (_connection.IsOpen())
|
if (_connection.IsOpen())
|
||||||
|
|
|
@ -1,33 +1,28 @@
|
||||||
using System.Text;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Configuration;
|
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Persistence
|
namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
public class SqliteProviderInfoRepository : IProviderRepository
|
public class SqliteProviderInfoRepository : BaseSqliteRepository, IProviderRepository
|
||||||
{
|
{
|
||||||
private IDbConnection _connection;
|
private IDbConnection _connection;
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
private IDbCommand _saveStatusCommand;
|
private IDbCommand _saveStatusCommand;
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
|
||||||
public SqliteProviderInfoRepository(IApplicationPaths appPaths, ILogManager logManager)
|
public SqliteProviderInfoRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
|
||||||
{
|
{
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the repository
|
/// Gets the name of the repository
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -48,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
var dbFile = Path.Combine(_appPaths.DataPath, "refreshinfo.db");
|
var dbFile = Path.Combine(_appPaths.DataPath, "refreshinfo.db");
|
||||||
|
|
||||||
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
|
_connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
|
||||||
|
|
||||||
string[] queries = {
|
string[] queries = {
|
||||||
|
|
||||||
|
@ -61,13 +56,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
"pragma shrink_memory"
|
"pragma shrink_memory"
|
||||||
};
|
};
|
||||||
|
|
||||||
_connection.RunQueries(queries, _logger);
|
_connection.RunQueries(queries, Logger);
|
||||||
|
|
||||||
AddItemDateModifiedCommand();
|
AddItemDateModifiedCommand();
|
||||||
|
|
||||||
PrepareStatements();
|
PrepareStatements();
|
||||||
|
|
||||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] StatusColumns =
|
private static readonly string[] StatusColumns =
|
||||||
|
@ -113,14 +106,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
builder.AppendLine("alter table MetadataStatus");
|
builder.AppendLine("alter table MetadataStatus");
|
||||||
builder.AppendLine("add column ItemDateModified DateTime NULL");
|
builder.AppendLine("add column ItemDateModified DateTime NULL");
|
||||||
|
|
||||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
_connection.RunQueries(new[] { builder.ToString() }, Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _write lock
|
|
||||||
/// </summary>
|
|
||||||
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prepares the statements.
|
/// Prepares the statements.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -227,7 +215,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -264,7 +252,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to save provider info:", e);
|
Logger.ErrorException("Failed to save provider info:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -280,55 +268,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected override void CloseConnection()
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (_connection != null)
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object _disposeLock = new object();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
|
||||||
protected virtual void Dispose(bool dispose)
|
|
||||||
{
|
|
||||||
if (dispose)
|
|
||||||
{
|
{
|
||||||
try
|
if (_connection.IsOpen())
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
_connection.Close();
|
||||||
{
|
|
||||||
if (_shrinkMemoryTimer != null)
|
|
||||||
{
|
|
||||||
_shrinkMemoryTimer.Dispose();
|
|
||||||
_shrinkMemoryTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_connection != null)
|
|
||||||
{
|
|
||||||
if (_connection.IsOpen())
|
|
||||||
{
|
|
||||||
_connection.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
_connection.Dispose();
|
|
||||||
_connection = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error disposing database", ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_connection.Dispose();
|
||||||
|
_connection = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
using MediaBrowser.Model.Logging;
|
|
||||||
using System;
|
|
||||||
using System.Data;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Persistence
|
|
||||||
{
|
|
||||||
class SqliteShrinkMemoryTimer : IDisposable
|
|
||||||
{
|
|
||||||
private Timer _shrinkMemoryTimer;
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim _writeLock;
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
private readonly IDbConnection _connection;
|
|
||||||
|
|
||||||
public SqliteShrinkMemoryTimer(IDbConnection connection, SemaphoreSlim writeLock, ILogger logger)
|
|
||||||
{
|
|
||||||
_connection = connection;
|
|
||||||
_writeLock = writeLock;
|
|
||||||
_logger = logger;
|
|
||||||
|
|
||||||
_shrinkMemoryTimer = new Timer(TimerCallback, null, TimeSpan.FromMinutes(30), TimeSpan.FromMinutes(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void TimerCallback(object state)
|
|
||||||
{
|
|
||||||
await _writeLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
|
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
transaction = _connection.BeginTransaction();
|
|
||||||
|
|
||||||
using (var cmd = _connection.CreateCommand())
|
|
||||||
{
|
|
||||||
cmd.Transaction = transaction;
|
|
||||||
cmd.CommandText = "pragma shrink_memory";
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction.Commit();
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
if (transaction != null)
|
|
||||||
{
|
|
||||||
transaction.Rollback();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Failed to save items:", e);
|
|
||||||
|
|
||||||
if (transaction != null)
|
|
||||||
{
|
|
||||||
transaction.Rollback();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (transaction != null)
|
|
||||||
{
|
|
||||||
transaction.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_writeLock.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_shrinkMemoryTimer != null)
|
|
||||||
{
|
|
||||||
_shrinkMemoryTimer.Dispose();
|
|
||||||
_shrinkMemoryTimer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,13 +11,15 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.Persistence
|
namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
public class SqliteUserDataRepository : IUserDataRepository
|
public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
|
|
||||||
|
|
||||||
private IDbConnection _connection;
|
private IDbConnection _connection;
|
||||||
|
private readonly IApplicationPaths _appPaths;
|
||||||
|
|
||||||
|
public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
|
||||||
|
{
|
||||||
|
_appPaths = appPaths;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the repository
|
/// Gets the name of the repository
|
||||||
|
@ -31,32 +33,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The _app paths
|
|
||||||
/// </summary>
|
|
||||||
private readonly IApplicationPaths _appPaths;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="SqliteUserDataRepository" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="appPaths">The app paths.</param>
|
|
||||||
/// <param name="logManager">The log manager.</param>
|
|
||||||
/// <exception cref="System.ArgumentNullException">jsonSerializer
|
|
||||||
/// or
|
|
||||||
/// appPaths</exception>
|
|
||||||
public SqliteUserDataRepository(IApplicationPaths appPaths, ILogManager logManager)
|
|
||||||
{
|
|
||||||
if (appPaths == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("appPaths");
|
|
||||||
}
|
|
||||||
|
|
||||||
_appPaths = appPaths;
|
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the connection to the database
|
/// Opens the connection to the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -65,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db");
|
var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db");
|
||||||
|
|
||||||
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
|
_connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
|
||||||
|
|
||||||
string[] queries = {
|
string[] queries = {
|
||||||
|
|
||||||
|
@ -79,9 +55,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
"pragma shrink_memory"
|
"pragma shrink_memory"
|
||||||
};
|
};
|
||||||
|
|
||||||
_connection.RunQueries(queries, _logger);
|
_connection.RunQueries(queries, Logger);
|
||||||
|
|
||||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -143,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -182,7 +156,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to save user data:", e);
|
Logger.ErrorException("Failed to save user data:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -198,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +187,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -257,7 +231,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to save user data:", e);
|
Logger.ErrorException("Failed to save user data:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -273,7 +247,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,51 +353,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
return userData;
|
return userData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected override void CloseConnection()
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (_connection != null)
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object _disposeLock = new object();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
|
||||||
protected virtual void Dispose(bool dispose)
|
|
||||||
{
|
|
||||||
if (dispose)
|
|
||||||
{
|
{
|
||||||
try
|
if (_connection.IsOpen())
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
_connection.Close();
|
||||||
{
|
|
||||||
if (_shrinkMemoryTimer != null)
|
|
||||||
{
|
|
||||||
_shrinkMemoryTimer.Dispose();
|
|
||||||
_shrinkMemoryTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_connection != null)
|
|
||||||
{
|
|
||||||
if (_connection.IsOpen())
|
|
||||||
{
|
|
||||||
_connection.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
_connection.Dispose();
|
|
||||||
_connection = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error disposing database", ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_connection.Dispose();
|
||||||
|
_connection = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class SQLiteUserRepository
|
/// Class SQLiteUserRepository
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SqliteUserRepository : IUserRepository
|
public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
|
|
||||||
|
|
||||||
private IDbConnection _connection;
|
private IDbConnection _connection;
|
||||||
private readonly IServerApplicationPaths _appPaths;
|
private readonly IServerApplicationPaths _appPaths;
|
||||||
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
|
||||||
|
public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer) : base(logManager)
|
||||||
|
{
|
||||||
|
_appPaths = appPaths;
|
||||||
|
_jsonSerializer = jsonSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the repository
|
/// Gets the name of the repository
|
||||||
|
@ -36,32 +39,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the json serializer.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The json serializer.</value>
|
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="SqliteUserRepository" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="jsonSerializer">The json serializer.</param>
|
|
||||||
/// <param name="logManager">The log manager.</param>
|
|
||||||
/// <param name="appPaths">The app paths.</param>
|
|
||||||
/// <exception cref="System.ArgumentNullException">appPaths</exception>
|
|
||||||
public SqliteUserRepository(IJsonSerializer jsonSerializer, ILogManager logManager, IServerApplicationPaths appPaths)
|
|
||||||
{
|
|
||||||
if (jsonSerializer == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("jsonSerializer");
|
|
||||||
}
|
|
||||||
|
|
||||||
_jsonSerializer = jsonSerializer;
|
|
||||||
_appPaths = appPaths;
|
|
||||||
|
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the connection to the database
|
/// Opens the connection to the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -70,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
{
|
{
|
||||||
var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
|
var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
|
||||||
|
|
||||||
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
|
_connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
|
||||||
|
|
||||||
string[] queries = {
|
string[] queries = {
|
||||||
|
|
||||||
|
@ -84,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
"pragma shrink_memory"
|
"pragma shrink_memory"
|
||||||
};
|
};
|
||||||
|
|
||||||
_connection.RunQueries(queries, _logger);
|
_connection.RunQueries(queries, Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -107,8 +84,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -139,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to save user:", e);
|
Logger.ErrorException("Failed to save user:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -155,7 +132,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +176,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
IDbTransaction transaction = null;
|
IDbTransaction transaction = null;
|
||||||
|
|
||||||
|
@ -231,7 +208,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_logger.ErrorException("Failed to delete user:", e);
|
Logger.ErrorException("Failed to delete user:", e);
|
||||||
|
|
||||||
if (transaction != null)
|
if (transaction != null)
|
||||||
{
|
{
|
||||||
|
@ -247,49 +224,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
||||||
transaction.Dispose();
|
transaction.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeLock.Release();
|
WriteLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected override void CloseConnection()
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (_connection != null)
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object _disposeLock = new object();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
|
||||||
protected virtual void Dispose(bool dispose)
|
|
||||||
{
|
|
||||||
if (dispose)
|
|
||||||
{
|
{
|
||||||
try
|
if (_connection.IsOpen())
|
||||||
{
|
{
|
||||||
lock (_disposeLock)
|
_connection.Close();
|
||||||
{
|
}
|
||||||
if (_connection != null)
|
|
||||||
{
|
|
||||||
if (_connection.IsOpen())
|
|
||||||
{
|
|
||||||
_connection.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
_connection.Dispose();
|
_connection.Dispose();
|
||||||
_connection = null;
|
_connection = null;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.ErrorException("Error disposing database", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,8 @@ namespace MediaBrowser.Server.Implementations.Photos
|
||||||
throw new ArgumentException("Unexpected image type");
|
throw new ArgumentException("Unexpected image type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const int MaxImageAgeDays = 7;
|
||||||
|
|
||||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
||||||
{
|
{
|
||||||
if (!Supports(item))
|
if (!Supports(item))
|
||||||
|
@ -198,6 +200,11 @@ namespace MediaBrowser.Server.Implementations.Photos
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item is UserView)
|
||||||
|
{
|
||||||
|
return HasChanged(item, ImageType.Primary) || HasChanged(item, ImageType.Thumb);
|
||||||
|
}
|
||||||
|
|
||||||
var items = GetItemsWithImages(item).Result;
|
var items = GetItemsWithImages(item).Result;
|
||||||
var cacheKey = GetConfigurationCacheKey(items, item.Name);
|
var cacheKey = GetConfigurationCacheKey(items, item.Name);
|
||||||
|
|
||||||
|
@ -216,7 +223,6 @@ namespace MediaBrowser.Server.Implementations.Photos
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentPathCacheKey = (Path.GetFileNameWithoutExtension(image.Path) ?? string.Empty).Split('_').LastOrDefault();
|
var currentPathCacheKey = (Path.GetFileNameWithoutExtension(image.Path) ?? string.Empty).Split('_').LastOrDefault();
|
||||||
|
|
||||||
if (string.Equals(cacheKey, currentPathCacheKey, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(cacheKey, currentPathCacheKey, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -226,6 +232,27 @@ namespace MediaBrowser.Server.Implementations.Photos
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected bool HasChanged(IHasImages item, ImageType type)
|
||||||
|
{
|
||||||
|
var image = item.GetImageInfo(type, 0);
|
||||||
|
|
||||||
|
if (image != null)
|
||||||
|
{
|
||||||
|
if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var age = DateTime.UtcNow - image.DateModified;
|
||||||
|
if (age.TotalDays <= MaxImageAgeDays)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected List<BaseItem> GetFinalItems(List<BaseItem> items)
|
protected List<BaseItem> GetFinalItems(List<BaseItem> items)
|
||||||
{
|
{
|
||||||
return GetFinalItems(items, 4);
|
return GetFinalItems(items, 4);
|
||||||
|
@ -234,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.Photos
|
||||||
protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
|
protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
|
||||||
{
|
{
|
||||||
// Rotate the images once every x days
|
// Rotate the images once every x days
|
||||||
var random = DateTime.Now.DayOfYear % 7;
|
var random = DateTime.Now.DayOfYear % MaxImageAgeDays;
|
||||||
|
|
||||||
return items
|
return items
|
||||||
.OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())
|
.OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())
|
||||||
|
|
|
@ -11,7 +11,8 @@ namespace MediaBrowser.Server.Implementations.Photos
|
||||||
{
|
{
|
||||||
//public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>
|
//public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>
|
||||||
//{
|
//{
|
||||||
// public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor)
|
// public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor)
|
||||||
|
// : base(fileSystem, providerManager, applicationPaths, imageProcessor)
|
||||||
// {
|
// {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
|
@ -1550,7 +1550,7 @@ namespace MediaBrowser.Server.Implementations.Session
|
||||||
|
|
||||||
if (info.PrimaryImageTag == null)
|
if (info.PrimaryImageTag == null)
|
||||||
{
|
{
|
||||||
var album = audio.Parents.OfType<MusicAlbum>().FirstOrDefault();
|
var album = audio.AlbumEntity;
|
||||||
|
|
||||||
if (album != null && album.HasImage(ImageType.Primary))
|
if (album != null && album.HasImage(ImageType.Primary))
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,13 +21,11 @@ namespace MediaBrowser.Server.Implementations.UserViews
|
||||||
public class DynamicImageProvider : BaseDynamicImageProvider<UserView>
|
public class DynamicImageProvider : BaseDynamicImageProvider<UserView>
|
||||||
{
|
{
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public DynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, IUserManager userManager, ILibraryManager libraryManager)
|
public DynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, IUserManager userManager)
|
||||||
: base(fileSystem, providerManager, applicationPaths, imageProcessor)
|
: base(fileSystem, providerManager, applicationPaths, imageProcessor)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||||
|
@ -122,7 +120,7 @@ namespace MediaBrowser.Server.Implementations.UserViews
|
||||||
var audio = i as Audio;
|
var audio = i as Audio;
|
||||||
if (audio != null)
|
if (audio != null)
|
||||||
{
|
{
|
||||||
var album = audio.FindParent<MusicAlbum>();
|
var album = audio.AlbumEntity;
|
||||||
if (album != null && album.HasImage(ImageType.Primary))
|
if (album != null && album.HasImage(ImageType.Primary))
|
||||||
{
|
{
|
||||||
return album;
|
return album;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
|
<package id="Interfaces.IO" version="1.0.0.5" targetFramework="net45" />
|
||||||
<package id="MediaBrowser.Naming" version="1.0.0.34" targetFramework="net45" />
|
<package id="MediaBrowser.Naming" version="1.0.0.35" targetFramework="net45" />
|
||||||
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
|
<package id="Mono.Nat" version="1.2.24.0" targetFramework="net45" />
|
||||||
<package id="morelinq" version="1.1.0" targetFramework="net45" />
|
<package id="morelinq" version="1.1.0" targetFramework="net45" />
|
||||||
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
<package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
|
||||||
<package id="SocketHttpListener" version="1.0.0.5" targetFramework="net45" />
|
<package id="SocketHttpListener" version="1.0.0.6" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
|
@ -392,13 +392,13 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
UserRepository = await GetUserRepository().ConfigureAwait(false);
|
UserRepository = await GetUserRepository().ConfigureAwait(false);
|
||||||
RegisterSingleInstance(UserRepository);
|
RegisterSingleInstance(UserRepository);
|
||||||
|
|
||||||
DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager);
|
DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths);
|
||||||
RegisterSingleInstance(DisplayPreferencesRepository);
|
RegisterSingleInstance(DisplayPreferencesRepository);
|
||||||
|
|
||||||
ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
|
ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
|
||||||
RegisterSingleInstance(ItemRepository);
|
RegisterSingleInstance(ItemRepository);
|
||||||
|
|
||||||
ProviderRepository = new SqliteProviderInfoRepository(ApplicationPaths, LogManager);
|
ProviderRepository = new SqliteProviderInfoRepository(LogManager, ApplicationPaths);
|
||||||
RegisterSingleInstance(ProviderRepository);
|
RegisterSingleInstance(ProviderRepository);
|
||||||
|
|
||||||
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
|
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
|
||||||
|
@ -614,7 +614,7 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
/// <returns>Task{IUserRepository}.</returns>
|
/// <returns>Task{IUserRepository}.</returns>
|
||||||
private async Task<IUserRepository> GetUserRepository()
|
private async Task<IUserRepository> GetUserRepository()
|
||||||
{
|
{
|
||||||
var repo = new SqliteUserRepository(JsonSerializer, LogManager, ApplicationPaths);
|
var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer);
|
||||||
|
|
||||||
await repo.Initialize().ConfigureAwait(false);
|
await repo.Initialize().ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -704,7 +704,7 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
private async Task ConfigureUserDataRepositories()
|
private async Task ConfigureUserDataRepositories()
|
||||||
{
|
{
|
||||||
var repo = new SqliteUserDataRepository(ApplicationPaths, LogManager);
|
var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths);
|
||||||
|
|
||||||
await repo.Initialize().ConfigureAwait(false);
|
await repo.Initialize().ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
[Route("/dashboard/Package", "GET")]
|
[Route("/dashboard/Package", "GET")]
|
||||||
public class GetDashboardPackage
|
public class GetDashboardPackage
|
||||||
{
|
{
|
||||||
|
public string Mode { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -134,7 +135,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
{
|
{
|
||||||
var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
|
var page = ServerEntryPoint.Instance.PluginConfigurationPages.First(p => p.Name.Equals(request.Name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
return ResultFactory.GetStaticResult(Request, page.Plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml(page.GetHtmlStream(), null, false));
|
return ResultFactory.GetStaticResult(Request, page.Plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml(page.GetHtmlStream(), null, null, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -252,7 +253,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
var minify = _serverConfigurationManager.Configuration.EnableDashboardResourceMinification;
|
var minify = _serverConfigurationManager.Configuration.EnableDashboardResourceMinification;
|
||||||
|
|
||||||
return GetPackageCreator()
|
return GetPackageCreator()
|
||||||
.GetResource(path, localizationCulture, _appHost.ApplicationVersion.ToString(), minify);
|
.GetResource(path, null, localizationCulture, _appHost.ApplicationVersion.ToString(), minify);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackageCreator GetPackageCreator()
|
private PackageCreator GetPackageCreator()
|
||||||
|
@ -292,38 +293,40 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
var appVersion = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
|
var appVersion = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
await DumpHtml(creator.DashboardUIPath, path, culture, appVersion);
|
var mode = request.Mode;
|
||||||
await DumpJs(creator.DashboardUIPath, path, culture, appVersion);
|
|
||||||
|
|
||||||
await DumpFile("scripts/all.js", Path.Combine(path, "scripts", "all.js"), culture, appVersion).ConfigureAwait(false);
|
await DumpHtml(creator.DashboardUIPath, path, mode, culture, appVersion);
|
||||||
await DumpFile("css/all.css", Path.Combine(path, "css", "all.css"), culture, appVersion).ConfigureAwait(false);
|
await DumpJs(creator.DashboardUIPath, path, mode, culture, appVersion);
|
||||||
|
|
||||||
|
await DumpFile("scripts/all.js", Path.Combine(path, "scripts", "all.js"), mode, culture, appVersion).ConfigureAwait(false);
|
||||||
|
await DumpFile("css/all.css", Path.Combine(path, "css", "all.css"), mode, culture, appVersion).ConfigureAwait(false);
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DumpHtml(string source, string destination, string culture, string appVersion)
|
private async Task DumpHtml(string source, string destination, string mode, string culture, string appVersion)
|
||||||
{
|
{
|
||||||
foreach (var file in Directory.GetFiles(source, "*.html", SearchOption.TopDirectoryOnly))
|
foreach (var file in Directory.GetFiles(source, "*.html", SearchOption.TopDirectoryOnly))
|
||||||
{
|
{
|
||||||
var filename = Path.GetFileName(file);
|
var filename = Path.GetFileName(file);
|
||||||
|
|
||||||
await DumpFile(filename, Path.Combine(destination, filename), culture, appVersion).ConfigureAwait(false);
|
await DumpFile(filename, Path.Combine(destination, filename), mode, culture, appVersion).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DumpJs(string source, string destination, string culture, string appVersion)
|
private async Task DumpJs(string source, string mode, string destination, string culture, string appVersion)
|
||||||
{
|
{
|
||||||
foreach (var file in Directory.GetFiles(source, "*.js", SearchOption.TopDirectoryOnly))
|
foreach (var file in Directory.GetFiles(source, "*.js", SearchOption.TopDirectoryOnly))
|
||||||
{
|
{
|
||||||
var filename = Path.GetFileName(file);
|
var filename = Path.GetFileName(file);
|
||||||
|
|
||||||
await DumpFile("scripts/" + filename, Path.Combine(destination, "scripts", filename), culture, appVersion).ConfigureAwait(false);
|
await DumpFile("scripts/" + filename, Path.Combine(destination, "scripts", filename), mode, culture, appVersion).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string culture, string appVersion)
|
private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion)
|
||||||
{
|
{
|
||||||
using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, culture, appVersion, true).ConfigureAwait(false))
|
using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion, true).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,8 +32,10 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Stream> GetResource(string path,
|
public async Task<Stream> GetResource(string path,
|
||||||
|
string mode,
|
||||||
string localizationCulture,
|
string localizationCulture,
|
||||||
string appVersion, bool enableMinification)
|
string appVersion,
|
||||||
|
bool enableMinification)
|
||||||
{
|
{
|
||||||
var isHtml = IsHtml(path);
|
var isHtml = IsHtml(path);
|
||||||
|
|
||||||
|
@ -41,7 +43,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
|
if (path.Equals("scripts/all.js", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
resourceStream = await GetAllJavascript(localizationCulture, appVersion, enableMinification).ConfigureAwait(false);
|
resourceStream = await GetAllJavascript(mode, localizationCulture, appVersion, enableMinification).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
|
else if (path.Equals("css/all.css", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -58,7 +60,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
// jQuery ajax doesn't seem to handle if-modified-since correctly
|
// jQuery ajax doesn't seem to handle if-modified-since correctly
|
||||||
if (isHtml)
|
if (isHtml)
|
||||||
{
|
{
|
||||||
resourceStream = await ModifyHtml(resourceStream, localizationCulture, enableMinification).ConfigureAwait(false);
|
resourceStream = await ModifyHtml(resourceStream, mode, localizationCulture, enableMinification).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,10 +108,11 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
/// Modifies the HTML by adding common meta tags, css and js.
|
/// Modifies the HTML by adding common meta tags, css and js.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sourceStream">The source stream.</param>
|
/// <param name="sourceStream">The source stream.</param>
|
||||||
|
/// <param name="mode">The mode.</param>
|
||||||
/// <param name="localizationCulture">The localization culture.</param>
|
/// <param name="localizationCulture">The localization culture.</param>
|
||||||
/// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
|
/// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
|
||||||
/// <returns>Task{Stream}.</returns>
|
/// <returns>Task{Stream}.</returns>
|
||||||
public async Task<Stream> ModifyHtml(Stream sourceStream, string localizationCulture, bool enableMinification)
|
public async Task<Stream> ModifyHtml(Stream sourceStream, string mode, string localizationCulture, bool enableMinification)
|
||||||
{
|
{
|
||||||
using (sourceStream)
|
using (sourceStream)
|
||||||
{
|
{
|
||||||
|
@ -155,7 +158,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
var version = GetType().Assembly.GetName().Version;
|
var version = GetType().Assembly.GetName().Version;
|
||||||
|
|
||||||
html = html.Replace("<head>", "<head>" + GetMetaTags() + GetCommonCss(version) + GetCommonJavascript(version));
|
html = html.Replace("<head>", "<head>" + GetMetaTags(mode) + GetCommonCss(mode, version) + GetCommonJavascript(mode, version));
|
||||||
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(html);
|
var bytes = Encoding.UTF8.GetBytes(html);
|
||||||
|
|
||||||
|
@ -172,12 +175,19 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
/// Gets the meta tags.
|
/// Gets the meta tags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private static string GetMetaTags()
|
private static string GetMetaTags(string mode)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'\">");
|
||||||
|
}
|
||||||
|
|
||||||
sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
|
sb.Append("<meta http-equiv=\"X-UA-Compatibility\" content=\"IE=Edge\">");
|
||||||
sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">");
|
sb.Append("<meta name=\"format-detection\" content=\"telephone=no\">");
|
||||||
|
sb.Append("<meta name=\"msapplication-tap-highlight\" content=\"no\">");
|
||||||
|
sb.Append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no\">");
|
||||||
sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
|
sb.Append("<meta name=\"apple-mobile-web-app-capable\" content=\"yes\">");
|
||||||
sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
|
sb.Append("<meta name=\"mobile-web-app-capable\" content=\"yes\">");
|
||||||
sb.Append("<meta name=\"application-name\" content=\"Emby\">");
|
sb.Append("<meta name=\"application-name\" content=\"Emby\">");
|
||||||
|
@ -200,11 +210,12 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the common CSS.
|
/// Gets the common CSS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="mode">The mode.</param>
|
||||||
/// <param name="version">The version.</param>
|
/// <param name="version">The version.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetCommonCss(Version version)
|
private string GetCommonCss(string mode, Version version)
|
||||||
{
|
{
|
||||||
var versionString = "?v=" + version;
|
var versionString = !string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? "?v=" + version : string.Empty;
|
||||||
|
|
||||||
var files = new[]
|
var files = new[]
|
||||||
{
|
{
|
||||||
|
@ -223,20 +234,26 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the common javascript.
|
/// Gets the common javascript.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="mode">The mode.</param>
|
||||||
/// <param name="version">The version.</param>
|
/// <param name="version">The version.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private string GetCommonJavascript(Version version)
|
private string GetCommonJavascript(string mode, Version version)
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
var versionString = "?v=" + version;
|
var versionString = !string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? "?v=" + version : string.Empty;
|
||||||
|
|
||||||
var files = new[]
|
var files = new List<string>
|
||||||
{
|
{
|
||||||
"scripts/all.js" + versionString,
|
"scripts/all.js" + versionString,
|
||||||
"thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
|
"thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
files.Insert(0, "cordova.js");
|
||||||
|
}
|
||||||
|
|
||||||
var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
|
var tags = files.Select(s => string.Format("<script src=\"{0}\"></script>", s)).ToArray();
|
||||||
|
|
||||||
builder.Append(string.Join(string.Empty, tags));
|
builder.Append(string.Join(string.Empty, tags));
|
||||||
|
@ -248,7 +265,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
/// Gets a stream containing all concatenated javascript
|
/// Gets a stream containing all concatenated javascript
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task{Stream}.</returns>
|
/// <returns>Task{Stream}.</returns>
|
||||||
private async Task<Stream> GetAllJavascript(string culture, string version, bool enableMinification)
|
private async Task<Stream> GetAllJavascript(string mode, string culture, string version, bool enableMinification)
|
||||||
{
|
{
|
||||||
var memoryStream = new MemoryStream();
|
var memoryStream = new MemoryStream();
|
||||||
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
|
||||||
|
@ -264,9 +281,18 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
await AppendResource(memoryStream, "thirdparty/jstree3.0.8/jstree.js", newLineBytes).ConfigureAwait(false);
|
await AppendResource(memoryStream, "thirdparty/jstree3.0.8/jstree.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await AppendResource(memoryStream, "thirdparty/fastclick.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
await AppendResource(memoryStream, "thirdparty/headroom.js", newLineBytes).ConfigureAwait(false);
|
||||||
|
|
||||||
await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
|
await AppendLocalization(memoryStream, culture).ConfigureAwait(false);
|
||||||
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
await memoryStream.WriteAsync(newLineBytes, 0, newLineBytes.Length).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(mode))
|
||||||
|
{
|
||||||
|
var appModeBytes = Encoding.UTF8.GetBytes(string.Format("window.appMode='{0}';", mode));
|
||||||
|
await memoryStream.WriteAsync(appModeBytes, 0, appModeBytes.Length).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Write the version string for the dashboard comparison function
|
// Write the version string for the dashboard comparison function
|
||||||
var versionString = string.Format("window.dashboardVersion='{0}';", version);
|
var versionString = string.Format("window.dashboardVersion='{0}';", version);
|
||||||
var versionBytes = Encoding.UTF8.GetBytes(versionString);
|
var versionBytes = Encoding.UTF8.GetBytes(versionString);
|
||||||
|
@ -276,7 +302,7 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
|
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
foreach (var file in new[]
|
var apiClientFiles = new[]
|
||||||
{
|
{
|
||||||
"thirdparty/apiclient/logger.js",
|
"thirdparty/apiclient/logger.js",
|
||||||
"thirdparty/apiclient/md5.js",
|
"thirdparty/apiclient/md5.js",
|
||||||
|
@ -289,10 +315,20 @@ namespace MediaBrowser.WebDashboard.Api
|
||||||
"thirdparty/apiclient/events.js",
|
"thirdparty/apiclient/events.js",
|
||||||
"thirdparty/apiclient/deferred.js",
|
"thirdparty/apiclient/deferred.js",
|
||||||
"thirdparty/apiclient/apiclient.js",
|
"thirdparty/apiclient/apiclient.js",
|
||||||
"thirdparty/apiclient/connectservice.js",
|
"thirdparty/apiclient/connectservice.js"
|
||||||
"thirdparty/apiclient/serverdiscovery.js",
|
}.ToList();
|
||||||
"thirdparty/apiclient/connectionmanager.js"
|
|
||||||
})
|
if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
apiClientFiles.Add("thirdparty/apiclient/cordova/serverdiscovery.js");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
apiClientFiles.Add("thirdparty/apiclient/serverdiscovery.js");
|
||||||
|
}
|
||||||
|
apiClientFiles.Add("thirdparty/apiclient/connectionmanager.js");
|
||||||
|
|
||||||
|
foreach (var file in apiClientFiles)
|
||||||
{
|
{
|
||||||
using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
using (var fs = _fileSystem.GetFileStream(GetDashboardResourcePath(file), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,10 +90,13 @@
|
||||||
<Content Include="dashboard-ui\css\images\clients\androidtv-tile.png">
|
<Content Include="dashboard-ui\css\images\clients\androidtv-tile.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\css\images\empty.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\css\images\kids\bg.jpg">
|
<Content Include="dashboard-ui\css\images\kids\bg.jpg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="dashboard-ui\css\images\server.png">
|
<Content Include="dashboard-ui\css\images\logo536.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="dashboard-ui\css\images\splash.jpg">
|
<Content Include="dashboard-ui\css\images\splash.jpg">
|
||||||
|
@ -216,6 +219,9 @@
|
||||||
<Content Include="dashboard-ui\thirdparty\apiclient\connectservice.js">
|
<Content Include="dashboard-ui\thirdparty\apiclient\connectservice.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\thirdparty\apiclient\cordova\serverdiscovery.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\thirdparty\apiclient\deferred.js">
|
<Content Include="dashboard-ui\thirdparty\apiclient\deferred.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -996,6 +1002,9 @@
|
||||||
<Content Include="dashboard-ui\thirdparty\cast_sender.js">
|
<Content Include="dashboard-ui\thirdparty\cast_sender.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\thirdparty\fastclick.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
|
<Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -1005,6 +1014,9 @@
|
||||||
<Content Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.svg">
|
<Content Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.svg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="dashboard-ui\thirdparty\headroom.js">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
|
<Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency id="MediaBrowser.Common" version="3.0.622" />
|
<dependency id="MediaBrowser.Common" version="3.0.622" />
|
||||||
<dependency id="NLog" version="3.2.1" />
|
<dependency id="NLog" version="3.2.1" />
|
||||||
<dependency id="SimpleInjector" version="2.7.0" />
|
<dependency id="SimpleInjector" version="2.8.0" />
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
|
|
Loading…
Reference in a new issue