mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-07-09 15:20:34 +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 clientFormats = GetClientSupportedFormats();
|
||||
|
||||
if (serverFormats.Contains(ImageFormat.Webp) &&
|
||||
clientFormats.Contains(ImageFormat.Webp))
|
||||
GetClientSupportedFormats().Contains(ImageFormat.Webp))
|
||||
{
|
||||
return ImageFormat.Webp;
|
||||
}
|
||||
|
|
|
@ -617,36 +617,14 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var originalItem = item;
|
||||
|
||||
while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||
{
|
||||
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 dtos = themeSongIds.Select(_libraryManager.GetItemById)
|
||||
var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
||||
|
@ -682,41 +660,14 @@ namespace MediaBrowser.Api.Library
|
|||
: (Folder)_libraryManager.RootFolder)
|
||||
: _libraryManager.GetItemById(request.Id);
|
||||
|
||||
var originalItem = item;
|
||||
|
||||
while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
|
||||
{
|
||||
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 dtos = themeVideoIds.Select(_libraryManager.GetItemById)
|
||||
var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
|
||||
.OrderBy(i => i.SortName)
|
||||
.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Api.Playback
|
||||
{
|
||||
|
@ -68,12 +69,14 @@ namespace MediaBrowser.Api.Playback
|
|||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
||||
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
||||
protected IZipClient ZipClient { get; private set; }
|
||||
protected IJsonSerializer JsonSerializer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
|
||||
/// </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;
|
||||
MediaSourceManager = mediaSourceManager;
|
||||
DeviceManager = deviceManager;
|
||||
|
@ -598,7 +601,7 @@ namespace MediaBrowser.Api.Playback
|
|||
var maxWidthParam = request.MaxWidth.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
|
||||
|
@ -618,7 +621,7 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -626,35 +629,13 @@ namespace MediaBrowser.Api.Playback
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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))
|
||||
{
|
||||
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.
|
||||
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);
|
||||
|
||||
process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
|
||||
|
|
|
@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Dash
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ using System.IO;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace MediaBrowser.Api.Playback.Hls
|
||||
{
|
||||
|
@ -21,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// </summary>
|
||||
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.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Dlna;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
|
||||
|
@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Hls
|
|||
/// </summary>
|
||||
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.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// </summary>
|
||||
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.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack.Web;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -27,7 +28,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
protected readonly IImageProcessor ImageProcessor;
|
||||
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;
|
||||
HttpClient = httpClient;
|
||||
|
|
|
@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using ServiceStack;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive
|
|||
/// </summary>
|
||||
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 Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||
</Reference>
|
||||
<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>
|
||||
<HintPath>..\packages\SimpleInjector.2.8.0\lib\net45\SimpleInjector.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
|
|
|
@ -6,16 +6,29 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Common.Implementations.Networking
|
||||
{
|
||||
public abstract class BaseNetworkManager
|
||||
{
|
||||
protected ILogger Logger { get; private set; }
|
||||
private Timer _clearCacheTimer;
|
||||
|
||||
protected BaseNetworkManager(ILogger 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;
|
||||
|
@ -36,7 +49,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||
var addresses = GetLocalIpAddressesInternal().ToList();
|
||||
|
||||
_localIpAddresses = addresses;
|
||||
BindEvents();
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
@ -46,35 +58,6 @@ namespace MediaBrowser.Common.Implementations.Networking
|
|||
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()
|
||||
{
|
||||
var list = GetIPsDefault()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<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>
|
||||
|
|
|
@ -52,34 +52,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
|
||||
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]
|
||||
protected override bool SupportsOwnedItems
|
||||
{
|
||||
|
@ -94,7 +66,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
{
|
||||
get
|
||||
{
|
||||
return Parents.OfType<MusicAlbum>().FirstOrDefault();
|
||||
return AlbumEntity;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +120,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <value>The album.</value>
|
||||
public string Album { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public MusicAlbum AlbumEntity
|
||||
{
|
||||
get { return FindParent<MusicAlbum>(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
|
@ -177,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// <returns>System.String.</returns>
|
||||
protected override string CreateUserDataKey()
|
||||
{
|
||||
var parent = FindParent<MusicAlbum>();
|
||||
var parent = AlbumEntity;
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
|
@ -14,11 +13,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
/// </summary>
|
||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
|
||||
{
|
||||
public List<Guid> SoundtrackIds { get; set; }
|
||||
|
||||
public MusicAlbum()
|
||||
{
|
||||
SoundtrackIds = new List<Guid>();
|
||||
Artists = new List<string>();
|
||||
AlbumArtists = new List<string>();
|
||||
}
|
||||
|
@ -77,49 +73,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
|||
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; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -906,38 +906,6 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <value>The provider ids.</value>
|
||||
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]
|
||||
public virtual Folder LatestItemsIndexContainer
|
||||
{
|
||||
|
|
|
@ -45,16 +45,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
/// <value>The index number.</value>
|
||||
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]
|
||||
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]
|
||||
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.Querying;
|
||||
using MediaBrowser.Model.Users;
|
||||
|
@ -15,20 +14,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
/// </summary>
|
||||
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]
|
||||
public override bool SupportsAddingToPlaylist
|
||||
{
|
||||
|
@ -50,33 +35,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
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
|
||||
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>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
|
|
|
@ -544,7 +544,9 @@ namespace MediaBrowser.Dlna
|
|||
new DirectTvProfile(),
|
||||
new DishHopperJoeyProfile(),
|
||||
new DefaultProfile(),
|
||||
new PopcornHourProfile()
|
||||
new PopcornHourProfile(),
|
||||
new VlcProfile(),
|
||||
new BubbleUpnpProfile()
|
||||
};
|
||||
|
||||
foreach (var item in list)
|
||||
|
|
|
@ -77,10 +77,12 @@
|
|||
<Compile Include="Common\DeviceService.cs" />
|
||||
<Compile Include="Didl\DidlBuilder.cs" />
|
||||
<Compile Include="PlayTo\PlayToController.cs" />
|
||||
<Compile Include="Profiles\BubbleUpnpProfile.cs" />
|
||||
<Compile Include="Profiles\DefaultProfile.cs" />
|
||||
<Compile Include="Profiles\DirectTvProfile.cs" />
|
||||
<Compile Include="Profiles\DishHopperJoeyProfile.cs" />
|
||||
<Compile Include="Profiles\PopcornHourProfile.cs" />
|
||||
<Compile Include="Profiles\VlcProfile.cs" />
|
||||
<Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
|
||||
<Compile Include="Ssdp\Extensions.cs" />
|
||||
<Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
|
||||
|
@ -204,6 +206,10 @@
|
|||
<EmbeddedResource Include="Images\people480.jpg" />
|
||||
<EmbeddedResource Include="Images\people480.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
|
||||
<EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- 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.
|
||||
|
|
|
@ -296,7 +296,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
await Task.Delay(50).ConfigureAwait(false);
|
||||
|
@ -463,10 +463,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
|
||||
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);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -496,10 +496,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
|
||||
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);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -521,7 +521,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
if (service == 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);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -558,7 +558,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
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);
|
||||
|
||||
if (result == null || result.Document == null)
|
||||
|
@ -589,7 +589,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Dlna.Common;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
@ -28,9 +28,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
DeviceService service,
|
||||
string command,
|
||||
string postData,
|
||||
bool logRequest = true,
|
||||
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);
|
||||
|
||||
using (var stream = response.Content)
|
||||
|
@ -69,7 +70,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
LogErrorResponseBody = true
|
||||
};
|
||||
|
||||
|
@ -87,7 +87,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
LogErrorResponseBody = true
|
||||
};
|
||||
|
||||
|
@ -105,7 +104,8 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
private Task<HttpResponseInfo> PostSoapDataAsync(string url,
|
||||
string soapAction,
|
||||
string postData,
|
||||
string header = null)
|
||||
string header,
|
||||
bool logRequest)
|
||||
{
|
||||
if (!soapAction.StartsWith("\""))
|
||||
soapAction = "\"" + soapAction + "\"";
|
||||
|
@ -114,7 +114,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||
{
|
||||
Url = url,
|
||||
UserAgent = USERAGENT,
|
||||
LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLogging,
|
||||
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";
|
||||
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -293,6 +294,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
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/";
|
||||
SonyAggregationFlags = "10";
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -310,6 +311,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
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/";
|
||||
SonyAggregationFlags = "10";
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -250,6 +251,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
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/";
|
||||
SonyAggregationFlags = "10";
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
TranscodingProfiles = new[]
|
||||
{
|
||||
|
@ -284,6 +285,12 @@ namespace MediaBrowser.Dlna.Profiles
|
|||
Condition = ProfileConditionType.LessThanEqual,
|
||||
Property = ProfileConditionValue.Height,
|
||||
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";
|
||||
|
||||
TimelineOffsetSeconds = 5;
|
||||
IgnoreTranscodeByteRangeRequests = true;
|
||||
|
||||
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>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<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>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -79,6 +78,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3">
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -82,6 +81,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3">
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -67,6 +66,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3">
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>3.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_TN</AlbumArtPn>
|
||||
|
@ -72,6 +71,7 @@
|
|||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
|
||||
<ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
|
||||
</Conditions>
|
||||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<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>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>12.0</ModelNumber>
|
||||
<ModelUrl>http://www.microsoft.com/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
<ModelDescription>Emby</ModelDescription>
|
||||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<SupportedMediaTypes>Audio</SupportedMediaTypes>
|
||||
|
|
|
@ -27,14 +27,16 @@ namespace MediaBrowser.Dlna.Service
|
|||
{
|
||||
try
|
||||
{
|
||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
LogRequest(request);
|
||||
}
|
||||
|
||||
var response = ProcessControlRequestInternal(request);
|
||||
|
||||
if (Config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
LogResponse(response);
|
||||
}
|
||||
|
|
|
@ -12,13 +12,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
public EndPoint FromEndPoint { get; private set; }
|
||||
public string Message { get; private set; }
|
||||
public bool IgnoreBindFailure { get; private set; }
|
||||
public bool EnableDebugLogging { get; private set; }
|
||||
|
||||
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;
|
||||
_logger = logger;
|
||||
EnableDebugLogging = enableDebugLogging;
|
||||
IgnoreBindFailure = ignoreBindFailure;
|
||||
FromEndPoint = fromEndPoint;
|
||||
ToEndPoint = toEndPoint;
|
||||
|
@ -37,8 +39,13 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
{
|
||||
client.Bind(FromEndPoint);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (EnableDebugLogging)
|
||||
{
|
||||
_logger.ErrorException("Error binding datagram socket", ex);
|
||||
}
|
||||
|
||||
if (!IgnoreBindFailure) throw;
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +58,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!IgnoreBindFailure)
|
||||
if (!IgnoreBindFailure || EnableDebugLogging)
|
||||
{
|
||||
_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();
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (EnableDebugLogging)
|
||||
{
|
||||
_logger.ErrorException("Error closing datagram socket", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using MediaBrowser.Common.Events;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
|
@ -143,7 +142,10 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
args.EndPoint = endPoint;
|
||||
args.LocalIp = localIp;
|
||||
|
||||
TryCreateDevice(args);
|
||||
if (!_ssdpHandler.IsSelfNotification(args))
|
||||
{
|
||||
TryCreateDevice(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,18 +205,25 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
string 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;
|
||||
if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
|
||||
|
||||
string nt;
|
||||
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
|
||||
string location;
|
||||
if (!args.Headers.TryGetValue("Location", out location) ||
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
}
|
||||
|
||||
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,
|
||||
IntPtr.Size * 8,
|
||||
os.Version.Major,
|
||||
|
@ -88,24 +88,21 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
private async void OnMessageReceived(SsdpMessageEventArgs args)
|
||||
{
|
||||
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var headers = args.Headers;
|
||||
var headers = args.Headers;
|
||||
string st;
|
||||
|
||||
if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase) && headers.TryGetValue("st", out st))
|
||||
{
|
||||
TimeSpan delay = GetSearchDelay(headers);
|
||||
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
{
|
||||
_logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
|
||||
}
|
||||
|
||||
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
|
||||
string st;
|
||||
if (headers.TryGetValue("st", out st))
|
||||
{
|
||||
RespondToSearch(args.EndPoint, st);
|
||||
}
|
||||
RespondToSearch(args.EndPoint, st);
|
||||
}
|
||||
|
||||
EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
|
||||
|
@ -166,9 +163,11 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
var msg = new SsdpMessageBuilder().BuildMessage(header, values);
|
||||
var queued = false;
|
||||
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -212,10 +211,9 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
private void RespondToSearch(EndPoint endpoint, string deviceType)
|
||||
{
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
{
|
||||
_logger.Debug("RespondToSearch");
|
||||
}
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
var isLogged = false;
|
||||
|
||||
const string header = "HTTP/1.1 200 OK";
|
||||
|
||||
|
@ -224,6 +222,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
if (string.Equals(deviceType, "ssdp:all", 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);
|
||||
|
||||
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, null, true);
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
_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;
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
_logger.Debug(Encoding.ASCII.GetString(received));
|
||||
}
|
||||
|
@ -324,7 +333,12 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
var args = SsdpHelper.ParseSsdpResponse(received);
|
||||
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 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()
|
||||
{
|
||||
_config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
|
||||
|
@ -399,17 +451,19 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
private void NotifyAll()
|
||||
{
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
|
||||
|
||||
if (enableDebugLogging)
|
||||
{
|
||||
_logger.Debug("Sending alive notifications");
|
||||
}
|
||||
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";
|
||||
|
||||
|
@ -424,7 +478,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
values["NT"] = dev.Type;
|
||||
values["USN"] = dev.USN;
|
||||
|
||||
if (_config.GetDlnaConfiguration().EnableDebugLogging)
|
||||
if (logMessage)
|
||||
{
|
||||
_logger.Debug("{0} said {1}", dev.USN, type);
|
||||
}
|
||||
|
@ -457,7 +511,7 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
|
||||
foreach (var d in dl.ToList())
|
||||
{
|
||||
NotifyDevice(d, "byebye", 2);
|
||||
NotifyDevice(d, "byebye", 2, true);
|
||||
}
|
||||
|
||||
_logger.Debug("Unregistered mount {0}", uuid);
|
||||
|
@ -468,13 +522,15 @@ namespace MediaBrowser.Dlna.Ssdp
|
|||
private int _aliveNotifierIntervalMs;
|
||||
private void ReloadAliveNotifier()
|
||||
{
|
||||
if (!_config.GetDlnaConfiguration().BlastAliveMessages)
|
||||
var config = _config.GetDlnaConfiguration();
|
||||
|
||||
if (!config.BlastAliveMessages)
|
||||
{
|
||||
DisposeNotificationTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
var intervalMs = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 1000;
|
||||
var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
|
||||
|
||||
if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
|
||||
{
|
||||
|
|
|
@ -840,7 +840,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
var maxWidthParam = request.MaxWidth.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
|
||||
|
@ -860,7 +860,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -868,35 +868,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
|
||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)
|
||||
|
|
|
@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
}
|
||||
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)
|
||||
try
|
||||
{
|
||||
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;
|
||||
StartProcess(processWrapper);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
StopProcess(processWrapper, 100, true);
|
||||
catch (Exception ex)
|
||||
{
|
||||
_ffProbeResourcePool.Release();
|
||||
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_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)
|
||||
{
|
||||
// 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));
|
||||
|
@ -307,31 +308,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
_logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
|
||||
StartProcess(processWrapper);
|
||||
|
||||
var lines = new List<int>();
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
process.BeginErrorReadLine();
|
||||
StartProcess(processWrapper);
|
||||
|
||||
await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
var lines = new List<int>();
|
||||
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
StopProcess(processWrapper, 100, true);
|
||||
}
|
||||
process.BeginErrorReadLine();
|
||||
|
||||
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)
|
||||
|
@ -490,51 +492,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
bool ranToCompletion;
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
bool ranToCompletion;
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
try
|
||||
{
|
||||
StartProcess(processWrapper);
|
||||
|
||||
#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
|
||||
process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
|
||||
// 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);
|
||||
#pragma warning restore 4014
|
||||
|
||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
||||
process.BeginErrorReadLine();
|
||||
// MUST read both stdout and stderr asynchronously or a deadlock may occurr
|
||||
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)
|
||||
|
@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
bool ranToCompletion = false;
|
||||
|
||||
var processWrapper = new ProcessWrapper(process, this);
|
||||
|
||||
try
|
||||
using (var processWrapper = new ProcessWrapper(process, this))
|
||||
{
|
||||
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)
|
||||
try
|
||||
{
|
||||
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;
|
||||
break;
|
||||
if (process.WaitForExit(30000))
|
||||
{
|
||||
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();
|
||||
|
||||
var jpegCount = Directory.GetFiles(targetDirectory)
|
||||
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
isResponsive = (jpegCount > lastCount);
|
||||
lastCount = jpegCount;
|
||||
if (!ranToCompletion)
|
||||
{
|
||||
StopProcess(processWrapper, 1000, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ranToCompletion)
|
||||
finally
|
||||
{
|
||||
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)
|
||||
{
|
||||
var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
|
||||
if (exitCode == -1)
|
||||
{
|
||||
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 bool HasExited;
|
||||
|
@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||
|
||||
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.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
|
|
@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
/// different directories and files.
|
||||
/// </summary>
|
||||
/// <value>The file watcher delay.</value>
|
||||
public int RealtimeMonitorDelay { get; set; }
|
||||
public int RealtimeLibraryMonitorDelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [enable dashboard response caching].
|
||||
|
@ -233,7 +233,7 @@ namespace MediaBrowser.Model.Configuration
|
|||
// 5 minutes
|
||||
MinResumeDurationSeconds = 300;
|
||||
|
||||
RealtimeMonitorDelay = 30;
|
||||
RealtimeLibraryMonitorDelay = 40;
|
||||
|
||||
EnableInternetProviders = true;
|
||||
FindInternetTrailers = true;
|
||||
|
@ -261,8 +261,6 @@ namespace MediaBrowser.Model.Configuration
|
|||
"Chromecast",
|
||||
"iOS",
|
||||
"Unknown app",
|
||||
"MediaPortal",
|
||||
"Media Portal",
|
||||
"iPad",
|
||||
"iPhone",
|
||||
"Windows Phone"
|
||||
|
|
|
@ -14,6 +14,9 @@ namespace MediaBrowser.Model.Dlna
|
|||
[XmlAttribute("codec")]
|
||||
public string Codec { get; set; }
|
||||
|
||||
[XmlAttribute("container")]
|
||||
public string Container { get; set; }
|
||||
|
||||
public CodecProfile()
|
||||
{
|
||||
Conditions = new ProfileCondition[] {};
|
||||
|
@ -29,8 +32,30 @@ namespace MediaBrowser.Model.Dlna
|
|||
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();
|
||||
|
||||
return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using MediaBrowser.Model.MediaInfo;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Model.Dlna
|
||||
|
@ -164,7 +165,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
|
||||
if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
|
||||
{
|
||||
orgPnValues.Add(mediaProfile.OrgPn);
|
||||
orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -34,7 +34,6 @@ namespace MediaBrowser.Model.Dlna
|
|||
public string ModelNumber { get; set; }
|
||||
public string ModelUrl { get; set; }
|
||||
public string SerialNumber { get; set; }
|
||||
public bool IgnoreTranscodeByteRangeRequests { get; set; }
|
||||
|
||||
public bool EnableAlbumArtInDidl { get; set; }
|
||||
public bool EnableSingleAlbumArtLimit { get; set; }
|
||||
|
|
|
@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<ProfileCondition> conditions = new List<ProfileCondition>();
|
||||
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)
|
||||
{
|
||||
|
@ -206,7 +206,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
|
||||
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);
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
|
||||
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)
|
||||
{
|
||||
|
@ -437,7 +437,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
|
||||
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)
|
||||
{
|
||||
|
@ -600,7 +600,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
conditions = new List<ProfileCondition>();
|
||||
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)
|
||||
{
|
||||
|
@ -635,7 +635,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
conditions = new List<ProfileCondition>();
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -38,13 +38,16 @@ namespace MediaBrowser.Providers.Manager
|
|||
{
|
||||
var hasChanges = false;
|
||||
|
||||
var images = providers.OfType<ILocalImageFileProvider>()
|
||||
.SelectMany(i => i.GetImages(item, directoryService))
|
||||
.ToList();
|
||||
|
||||
if (MergeImages(item, images))
|
||||
if (!(item is Photo))
|
||||
{
|
||||
hasChanges = true;
|
||||
var images = providers.OfType<ILocalImageFileProvider>()
|
||||
.SelectMany(i => i.GetImages(item, directoryService))
|
||||
.ToList();
|
||||
|
||||
if (MergeImages(item, images))
|
||||
{
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
|
@ -419,19 +422,14 @@ namespace MediaBrowser.Providers.Manager
|
|||
var changed = false;
|
||||
|
||||
var newImages = images.Where(i => i.Type == type).ToList();
|
||||
if (newImages.Count > 0)
|
||||
{
|
||||
var newImageFileInfos = images.Where(i => i.Type == type)
|
||||
|
||||
var newImageFileInfos = newImages
|
||||
.Select(i => i.FileInfo)
|
||||
.ToList();
|
||||
|
||||
if (newImageFileInfos.Count > 0)
|
||||
{
|
||||
if (item.AddImages(type, newImageFileInfos))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (item.AddImages(type, newImageFileInfos))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||
|
||||
private string GetAudioImagePath(Audio item)
|
||||
{
|
||||
var album = item.Parent as MusicAlbum;
|
||||
var album = item.AlbumEntity;
|
||||
|
||||
var filename = item.Album ?? string.Empty;
|
||||
filename += string.Join(",", item.Artists.ToArray());
|
||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
|
|||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.Providers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -29,12 +30,14 @@ namespace MediaBrowser.Providers.TV
|
|||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
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;
|
||||
_config = config;
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
Current = this;
|
||||
}
|
||||
|
||||
|
@ -100,7 +103,8 @@ namespace MediaBrowser.Providers.TV
|
|||
|
||||
try
|
||||
{
|
||||
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||
result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds,
|
||||
cancellationToken);
|
||||
result.HasMetadata = result.Item != null;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
|
@ -112,6 +116,10 @@ namespace MediaBrowser.Providers.TV
|
|||
// 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;
|
||||
}
|
||||
|
@ -265,7 +273,6 @@ namespace MediaBrowser.Providers.TV
|
|||
|
||||
FetchMainEpisodeInfo(episode, file, cancellationToken);
|
||||
usingAbsoluteData = true;
|
||||
success = true;
|
||||
}
|
||||
|
||||
var end = identity.IndexNumberEnd ?? episodeNumber;
|
||||
|
@ -298,7 +305,7 @@ namespace MediaBrowser.Providers.TV
|
|||
episodeNumber++;
|
||||
}
|
||||
|
||||
return success ? episode : null;
|
||||
return episode;
|
||||
}
|
||||
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
|
|
@ -1193,7 +1193,7 @@ namespace MediaBrowser.Server.Implementations.Dto
|
|||
{
|
||||
dto.Album = audio.Album;
|
||||
|
||||
var albumParent = audio.FindParent<MusicAlbum>();
|
||||
var albumParent = audio.AlbumEntity;
|
||||
|
||||
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;
|
||||
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.
|
||||
// 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.
|
||||
await Task.Delay(1500).ConfigureAwait(false);
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
|
||||
string val;
|
||||
_tempIgnoredPaths.TryRemove(path, out val);
|
||||
|
@ -437,11 +437,11 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||
{
|
||||
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
|
||||
{
|
||||
_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>
|
||||
private async Task ProcessPathChanges(List<string> paths)
|
||||
{
|
||||
var itemsToRefresh = paths.Select(Path.GetDirectoryName)
|
||||
var itemsToRefresh = paths
|
||||
.Select(GetAffectedBaseItem)
|
||||
.Where(item => item != null)
|
||||
.Distinct()
|
||||
|
|
|
@ -281,10 +281,10 @@ namespace MediaBrowser.Server.Implementations.Library
|
|||
|
||||
if (newValue >= maxCount)
|
||||
{
|
||||
_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
|
||||
user.Policy.IsDisabled = true;
|
||||
//_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
|
||||
//user.Policy.IsDisabled = true;
|
||||
|
||||
fireLockout = true;
|
||||
//fireLockout = true;
|
||||
}
|
||||
|
||||
await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
|
||||
|
|
|
@ -387,7 +387,6 @@
|
|||
"ButtonSignOut": "Sign Out",
|
||||
"ButtonMyProfile": "My Profile",
|
||||
"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}",
|
||||
"LabelPackageInstallCompleted": "{0} installation completed.",
|
||||
"LabelPackageInstallFailed": "{0} installation failed.",
|
||||
|
|
|
@ -440,7 +440,7 @@
|
|||
"HeaderVideo": "Video",
|
||||
"HeaderRuntime": "Runtime",
|
||||
"HeaderCommunityRating": "Community rating",
|
||||
"HeaderPasswordReset": "Password Reset",
|
||||
"HeaderPasswordReset": "Password Reset",
|
||||
"HeaderParentalRating": "Parental rating",
|
||||
"HeaderReleaseDate": "Release date",
|
||||
"HeaderDateAdded": "Date added",
|
||||
|
@ -766,5 +766,10 @@
|
|||
"SyncJobItemStatusRemovedFromDevice": "Removed from device",
|
||||
"SyncJobItemStatusCancelled": "Cancelled",
|
||||
"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.",
|
||||
"TabDisplay": "Display",
|
||||
"TabLanguages": "Languages",
|
||||
"TabWebClient": "Web Client",
|
||||
"TabAppSettings": "App Settings",
|
||||
"LabelEnableThemeSongs": "Enable theme songs",
|
||||
"LabelEnableBackdrops": "Enable backdrops",
|
||||
"LabelEnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.",
|
||||
|
@ -1436,10 +1436,17 @@
|
|||
"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.",
|
||||
"TabPhotos": "Photos",
|
||||
"TabVideos": "Videos",
|
||||
"OptionReportList": "List View",
|
||||
"OptionReportStatistics": "Statistics",
|
||||
"OptionReportGrouping": "Grouping",
|
||||
"OptionReportExport": "Report Export",
|
||||
"OptionReportColumns": "Report Columns"
|
||||
"TabVideos": "Videos",
|
||||
"HeaderWelcomeToEmby": "Welcome to Emby",
|
||||
"EmbyIntroMessage": "With Emby you can easily stream videos, music and photos to smart phones, tablets and other devices from your Emby Server.",
|
||||
"ButtonSkip": "Skip",
|
||||
"TextConnectToServerManually": "Connect to server manually",
|
||||
"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">
|
||||
<HintPath>..\packages\Interfaces.IO.1.0.0.5\lib\portable-net45+sl4+wp71+win8+wpa81\Interfaces.IO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MediaBrowser.Naming, Version=1.0.5509.27636, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.34\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
|
||||
<Reference Include="MediaBrowser.Naming">
|
||||
<HintPath>..\packages\MediaBrowser.Naming.1.0.0.35\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Nat, Version=1.2.24.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
|
@ -226,6 +225,7 @@
|
|||
<Compile Include="Localization\LocalizationManager.cs" />
|
||||
<Compile Include="Logging\PatternsLogger.cs" />
|
||||
<Compile Include="MediaEncoder\EncodingManager.cs" />
|
||||
<Compile Include="Persistence\BaseSqliteRepository.cs" />
|
||||
<Compile Include="Sorting\StartDateComparer.cs" />
|
||||
<Compile Include="Sync\SyncHelper.cs" />
|
||||
<Compile Include="Sync\SyncJobOptions.cs" />
|
||||
|
@ -242,7 +242,6 @@
|
|||
<Compile Include="Persistence\SqliteMediaStreamsRepository.cs" />
|
||||
<Compile Include="Notifications\SqliteNotificationsRepository.cs" />
|
||||
<Compile Include="Persistence\SqliteProviderInfoRepository.cs" />
|
||||
<Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
|
||||
<Compile Include="Persistence\TypeMapper.cs" />
|
||||
<Compile Include="Photos\BaseDynamicImageProvider.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);
|
||||
}
|
||||
|
||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
|
@ -54,8 +52,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
_connection.RunQueries(queries, _logger);
|
||||
|
||||
PrepareStatements();
|
||||
|
||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -286,12 +282,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
if (_shrinkMemoryTimer != null)
|
||||
{
|
||||
_shrinkMemoryTimer.Dispose();
|
||||
_shrinkMemoryTimer = null;
|
||||
}
|
||||
|
||||
if (_connection != null)
|
||||
{
|
||||
if (_connection.IsOpen())
|
||||
|
|
|
@ -16,11 +16,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
/// <summary>
|
||||
/// Class SQLiteDisplayPreferencesRepository
|
||||
/// </summary>
|
||||
public class SqliteDisplayPreferencesRepository : IDisplayPreferencesRepository
|
||||
public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository
|
||||
{
|
||||
private IDbConnection _connection;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths) : base(logManager)
|
||||
{
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the repository
|
||||
|
@ -44,36 +48,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
/// </summary>
|
||||
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>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
|
@ -82,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
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 = {
|
||||
|
||||
|
@ -95,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
"pragma shrink_memory"
|
||||
};
|
||||
|
||||
_connection.RunQueries(queries, _logger);
|
||||
_connection.RunQueries(queries, Logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -122,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -157,7 +131,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to save display preferences:", e);
|
||||
Logger.ErrorException("Failed to save display preferences:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -173,7 +147,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,7 +168,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -235,7 +209,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to save display preferences:", e);
|
||||
Logger.ErrorException("Failed to save display preferences:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -251,7 +225,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,45 +296,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
protected override void CloseConnection()
|
||||
{
|
||||
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)
|
||||
if (_connection != null)
|
||||
{
|
||||
try
|
||||
if (_connection.IsOpen())
|
||||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
if (_connection != null)
|
||||
{
|
||||
if (_connection.IsOpen())
|
||||
{
|
||||
_connection.Close();
|
||||
}
|
||||
_connection.Close();
|
||||
}
|
||||
|
||||
_connection.Dispose();
|
||||
_connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error disposing database", ex);
|
||||
}
|
||||
_connection.Dispose();
|
||||
_connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,10 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace MediaBrowser.Server.Implementations.Persistence
|
||||
{
|
||||
public class SqliteFileOrganizationRepository : IFileOrganizationRepository, IDisposable
|
||||
public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable
|
||||
{
|
||||
private IDbConnection _connection;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
|
||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
||||
private readonly IServerApplicationPaths _appPaths;
|
||||
|
||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||
|
@ -30,11 +26,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
private IDbCommand _deleteResultCommand;
|
||||
private IDbCommand _deleteAllCommand;
|
||||
|
||||
public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths)
|
||||
public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths) : base(logManager)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
|
||||
_logger = logManager.GetLogger(GetType().Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -45,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
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 = {
|
||||
|
||||
|
@ -58,11 +52,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
"pragma shrink_memory"
|
||||
};
|
||||
|
||||
_connection.RunQueries(queries, _logger);
|
||||
_connection.RunQueries(queries, Logger);
|
||||
|
||||
PrepareStatements();
|
||||
|
||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
||||
}
|
||||
|
||||
private void PrepareStatements()
|
||||
|
@ -103,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -145,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to save FileOrganizationResult:", e);
|
||||
Logger.ErrorException("Failed to save FileOrganizationResult:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -161,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +164,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
throw new ArgumentNullException("id");
|
||||
}
|
||||
|
||||
await _writeLock.WaitAsync().ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -199,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to delete FileOrganizationResult:", e);
|
||||
Logger.ErrorException("Failed to delete FileOrganizationResult:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -215,13 +207,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteAll()
|
||||
{
|
||||
await _writeLock.WaitAsync().ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -246,7 +238,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to delete results", e);
|
||||
Logger.ErrorException("Failed to delete results", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -262,7 +254,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,51 +415,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
protected override void CloseConnection()
|
||||
{
|
||||
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)
|
||||
if (_connection != null)
|
||||
{
|
||||
try
|
||||
if (_connection.IsOpen())
|
||||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
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.Close();
|
||||
}
|
||||
|
||||
_connection.Dispose();
|
||||
_connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,12 +130,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
_mediaStreamsRepository.Initialize();
|
||||
_chapterRepository.Initialize();
|
||||
|
||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
||||
}
|
||||
|
||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
||||
|
||||
/// <summary>
|
||||
/// The _write lock
|
||||
/// </summary>
|
||||
|
@ -430,12 +426,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
if (_shrinkMemoryTimer != null)
|
||||
{
|
||||
_shrinkMemoryTimer.Dispose();
|
||||
_shrinkMemoryTimer = null;
|
||||
}
|
||||
|
||||
_writeLock.Wait();
|
||||
|
||||
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.Logging;
|
||||
using System;
|
||||
|
@ -21,8 +20,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
private IDbCommand _deleteStreamsCommand;
|
||||
private IDbCommand _saveStreamCommand;
|
||||
|
||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
||||
|
||||
public SqliteMediaStreamsRepository(IDbConnection connection, ILogManager logManager)
|
||||
{
|
||||
_connection = connection;
|
||||
|
@ -64,8 +61,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
AddRefFramesCommand();
|
||||
|
||||
PrepareStatements();
|
||||
|
||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
||||
}
|
||||
|
||||
private void AddPixelFormatColumnCommand()
|
||||
|
@ -563,12 +558,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
if (_shrinkMemoryTimer != null)
|
||||
{
|
||||
_shrinkMemoryTimer.Dispose();
|
||||
_shrinkMemoryTimer = null;
|
||||
}
|
||||
|
||||
if (_connection != null)
|
||||
{
|
||||
if (_connection.IsOpen())
|
||||
|
|
|
@ -1,33 +1,28 @@
|
|||
using System.Text;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Server.Implementations.Persistence
|
||||
{
|
||||
public class SqliteProviderInfoRepository : IProviderRepository
|
||||
public class SqliteProviderInfoRepository : BaseSqliteRepository, IProviderRepository
|
||||
{
|
||||
private IDbConnection _connection;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private IDbCommand _saveStatusCommand;
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
||||
public SqliteProviderInfoRepository(IApplicationPaths appPaths, ILogManager logManager)
|
||||
public SqliteProviderInfoRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
_logger = logManager.GetLogger(GetType().Name);
|
||||
}
|
||||
|
||||
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the repository
|
||||
/// </summary>
|
||||
|
@ -48,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
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 = {
|
||||
|
||||
|
@ -61,13 +56,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
"pragma shrink_memory"
|
||||
};
|
||||
|
||||
_connection.RunQueries(queries, _logger);
|
||||
_connection.RunQueries(queries, Logger);
|
||||
|
||||
AddItemDateModifiedCommand();
|
||||
|
||||
PrepareStatements();
|
||||
|
||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
||||
}
|
||||
|
||||
private static readonly string[] StatusColumns =
|
||||
|
@ -113,14 +106,9 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
builder.AppendLine("alter table MetadataStatus");
|
||||
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>
|
||||
/// Prepares the statements.
|
||||
/// </summary>
|
||||
|
@ -227,7 +215,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -264,7 +252,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to save provider info:", e);
|
||||
Logger.ErrorException("Failed to save provider info:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -280,55 +268,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
protected override void CloseConnection()
|
||||
{
|
||||
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)
|
||||
if (_connection != null)
|
||||
{
|
||||
try
|
||||
if (_connection.IsOpen())
|
||||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
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.Close();
|
||||
}
|
||||
|
||||
_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
|
||||
{
|
||||
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 readonly IApplicationPaths _appPaths;
|
||||
|
||||
public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
|
@ -65,7 +41,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
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 = {
|
||||
|
||||
|
@ -79,9 +55,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
"pragma shrink_memory"
|
||||
};
|
||||
|
||||
_connection.RunQueries(queries, _logger);
|
||||
|
||||
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
|
||||
_connection.RunQueries(queries, Logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -143,7 +117,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -182,7 +156,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to save user data:", e);
|
||||
Logger.ErrorException("Failed to save user data:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -198,7 +172,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,7 +187,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -257,7 +231,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to save user data:", e);
|
||||
Logger.ErrorException("Failed to save user data:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -273,7 +247,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,51 +353,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
return userData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
protected override void CloseConnection()
|
||||
{
|
||||
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)
|
||||
if (_connection != null)
|
||||
{
|
||||
try
|
||||
if (_connection.IsOpen())
|
||||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
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.Close();
|
||||
}
|
||||
|
||||
_connection.Dispose();
|
||||
_connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,14 +15,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
/// <summary>
|
||||
/// Class SQLiteUserRepository
|
||||
/// </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 readonly IServerApplicationPaths _appPaths;
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer) : base(logManager)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
/// Opens the connection to the database
|
||||
/// </summary>
|
||||
|
@ -70,7 +47,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
{
|
||||
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 = {
|
||||
|
||||
|
@ -84,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
"pragma shrink_memory"
|
||||
};
|
||||
|
||||
_connection.RunQueries(queries, _logger);
|
||||
_connection.RunQueries(queries, Logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -107,8 +84,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
try
|
||||
|
@ -139,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to save user:", e);
|
||||
Logger.ErrorException("Failed to save user:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -155,7 +132,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +176,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
IDbTransaction transaction = null;
|
||||
|
||||
|
@ -231,7 +208,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.ErrorException("Failed to delete user:", e);
|
||||
Logger.ErrorException("Failed to delete user:", e);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
|
@ -247,49 +224,21 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||
transaction.Dispose();
|
||||
}
|
||||
|
||||
_writeLock.Release();
|
||||
WriteLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
protected override void CloseConnection()
|
||||
{
|
||||
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)
|
||||
if (_connection != null)
|
||||
{
|
||||
try
|
||||
if (_connection.IsOpen())
|
||||
{
|
||||
lock (_disposeLock)
|
||||
{
|
||||
if (_connection != null)
|
||||
{
|
||||
if (_connection.IsOpen())
|
||||
{
|
||||
_connection.Close();
|
||||
}
|
||||
_connection.Close();
|
||||
}
|
||||
|
||||
_connection.Dispose();
|
||||
_connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error disposing database", ex);
|
||||
}
|
||||
_connection.Dispose();
|
||||
_connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -191,6 +191,8 @@ namespace MediaBrowser.Server.Implementations.Photos
|
|||
throw new ArgumentException("Unexpected image type");
|
||||
}
|
||||
|
||||
private const int MaxImageAgeDays = 7;
|
||||
|
||||
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
|
||||
{
|
||||
if (!Supports(item))
|
||||
|
@ -198,6 +200,11 @@ namespace MediaBrowser.Server.Implementations.Photos
|
|||
return false;
|
||||
}
|
||||
|
||||
if (item is UserView)
|
||||
{
|
||||
return HasChanged(item, ImageType.Primary) || HasChanged(item, ImageType.Thumb);
|
||||
}
|
||||
|
||||
var items = GetItemsWithImages(item).Result;
|
||||
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();
|
||||
|
||||
if (string.Equals(cacheKey, currentPathCacheKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
|
@ -226,6 +232,27 @@ namespace MediaBrowser.Server.Implementations.Photos
|
|||
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)
|
||||
{
|
||||
return GetFinalItems(items, 4);
|
||||
|
@ -234,7 +261,7 @@ namespace MediaBrowser.Server.Implementations.Photos
|
|||
protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
|
||||
{
|
||||
// Rotate the images once every x days
|
||||
var random = DateTime.Now.DayOfYear % 7;
|
||||
var random = DateTime.Now.DayOfYear % MaxImageAgeDays;
|
||||
|
||||
return items
|
||||
.OrderBy(i => (random + "" + items.IndexOf(i)).GetMD5())
|
||||
|
|
|
@ -11,7 +11,8 @@ namespace MediaBrowser.Server.Implementations.Photos
|
|||
{
|
||||
//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)
|
||||
{
|
||||
var album = audio.Parents.OfType<MusicAlbum>().FirstOrDefault();
|
||||
var album = audio.AlbumEntity;
|
||||
|
||||
if (album != null && album.HasImage(ImageType.Primary))
|
||||
{
|
||||
|
|
|
@ -21,13 +21,11 @@ namespace MediaBrowser.Server.Implementations.UserViews
|
|||
public class DynamicImageProvider : BaseDynamicImageProvider<UserView>
|
||||
{
|
||||
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)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
|
||||
|
@ -122,7 +120,7 @@ namespace MediaBrowser.Server.Implementations.UserViews
|
|||
var audio = i as Audio;
|
||||
if (audio != null)
|
||||
{
|
||||
var album = audio.FindParent<MusicAlbum>();
|
||||
var album = audio.AlbumEntity;
|
||||
if (album != null && album.HasImage(ImageType.Primary))
|
||||
{
|
||||
return album;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<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="morelinq" version="1.1.0" 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>
|
|
@ -392,13 +392,13 @@ namespace MediaBrowser.Server.Startup.Common
|
|||
UserRepository = await GetUserRepository().ConfigureAwait(false);
|
||||
RegisterSingleInstance(UserRepository);
|
||||
|
||||
DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager);
|
||||
DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(LogManager, JsonSerializer, ApplicationPaths);
|
||||
RegisterSingleInstance(DisplayPreferencesRepository);
|
||||
|
||||
ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
|
||||
RegisterSingleInstance(ItemRepository);
|
||||
|
||||
ProviderRepository = new SqliteProviderInfoRepository(ApplicationPaths, LogManager);
|
||||
ProviderRepository = new SqliteProviderInfoRepository(LogManager, ApplicationPaths);
|
||||
RegisterSingleInstance(ProviderRepository);
|
||||
|
||||
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
|
||||
|
@ -614,7 +614,7 @@ namespace MediaBrowser.Server.Startup.Common
|
|||
/// <returns>Task{IUserRepository}.</returns>
|
||||
private async Task<IUserRepository> GetUserRepository()
|
||||
{
|
||||
var repo = new SqliteUserRepository(JsonSerializer, LogManager, ApplicationPaths);
|
||||
var repo = new SqliteUserRepository(LogManager, ApplicationPaths, JsonSerializer);
|
||||
|
||||
await repo.Initialize().ConfigureAwait(false);
|
||||
|
||||
|
@ -704,7 +704,7 @@ namespace MediaBrowser.Server.Startup.Common
|
|||
/// <returns>Task.</returns>
|
||||
private async Task ConfigureUserDataRepositories()
|
||||
{
|
||||
var repo = new SqliteUserDataRepository(ApplicationPaths, LogManager);
|
||||
var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths);
|
||||
|
||||
await repo.Initialize().ConfigureAwait(false);
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
[Route("/dashboard/Package", "GET")]
|
||||
public class GetDashboardPackage
|
||||
{
|
||||
public string Mode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -134,7 +135,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
{
|
||||
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>
|
||||
|
@ -252,7 +253,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
var minify = _serverConfigurationManager.Configuration.EnableDashboardResourceMinification;
|
||||
|
||||
return GetPackageCreator()
|
||||
.GetResource(path, localizationCulture, _appHost.ApplicationVersion.ToString(), minify);
|
||||
.GetResource(path, null, localizationCulture, _appHost.ApplicationVersion.ToString(), minify);
|
||||
}
|
||||
|
||||
private PackageCreator GetPackageCreator()
|
||||
|
@ -292,38 +293,40 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
|
||||
var appVersion = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
await DumpHtml(creator.DashboardUIPath, path, culture, appVersion);
|
||||
await DumpJs(creator.DashboardUIPath, path, culture, appVersion);
|
||||
var mode = request.Mode;
|
||||
|
||||
await DumpFile("scripts/all.js", Path.Combine(path, "scripts", "all.js"), culture, appVersion).ConfigureAwait(false);
|
||||
await DumpFile("css/all.css", Path.Combine(path, "css", "all.css"), culture, appVersion).ConfigureAwait(false);
|
||||
await DumpHtml(creator.DashboardUIPath, path, mode, culture, appVersion);
|
||||
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 "";
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
|
|
@ -32,8 +32,10 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
}
|
||||
|
||||
public async Task<Stream> GetResource(string path,
|
||||
string mode,
|
||||
string localizationCulture,
|
||||
string appVersion, bool enableMinification)
|
||||
string appVersion,
|
||||
bool enableMinification)
|
||||
{
|
||||
var isHtml = IsHtml(path);
|
||||
|
||||
|
@ -41,7 +43,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
|
||||
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))
|
||||
{
|
||||
|
@ -58,7 +60,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
// jQuery ajax doesn't seem to handle if-modified-since correctly
|
||||
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.
|
||||
/// </summary>
|
||||
/// <param name="sourceStream">The source stream.</param>
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <param name="localizationCulture">The localization culture.</param>
|
||||
/// <param name="enableMinification">if set to <c>true</c> [enable minification].</param>
|
||||
/// <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)
|
||||
{
|
||||
|
@ -155,7 +158,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
|
||||
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);
|
||||
|
||||
|
@ -172,12 +175,19 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
/// Gets the meta tags.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
private static string GetMetaTags()
|
||||
private static string GetMetaTags(string mode)
|
||||
{
|
||||
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 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=\"mobile-web-app-capable\" content=\"yes\">");
|
||||
sb.Append("<meta name=\"application-name\" content=\"Emby\">");
|
||||
|
@ -200,11 +210,12 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
/// <summary>
|
||||
/// Gets the common CSS.
|
||||
/// </summary>
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <param name="version">The version.</param>
|
||||
/// <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[]
|
||||
{
|
||||
|
@ -223,20 +234,26 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
/// <summary>
|
||||
/// Gets the common javascript.
|
||||
/// </summary>
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <param name="version">The version.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private string GetCommonJavascript(Version version)
|
||||
private string GetCommonJavascript(string mode, Version version)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
|
||||
var versionString = "?v=" + version;
|
||||
var versionString = !string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase) ? "?v=" + version : string.Empty;
|
||||
|
||||
var files = new[]
|
||||
{
|
||||
"scripts/all.js" + versionString,
|
||||
"thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString
|
||||
var files = new List<string>
|
||||
{
|
||||
"scripts/all.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();
|
||||
|
||||
builder.Append(string.Join(string.Empty, tags));
|
||||
|
@ -248,7 +265,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
/// Gets a stream containing all concatenated javascript
|
||||
/// </summary>
|
||||
/// <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 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/fastclick.js", newLineBytes).ConfigureAwait(false);
|
||||
await AppendResource(memoryStream, "thirdparty/headroom.js", newLineBytes).ConfigureAwait(false);
|
||||
|
||||
await AppendLocalization(memoryStream, culture).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
|
||||
var versionString = string.Format("window.dashboardVersion='{0}';", version);
|
||||
var versionBytes = Encoding.UTF8.GetBytes(versionString);
|
||||
|
@ -276,7 +302,7 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
foreach (var file in new[]
|
||||
var apiClientFiles = new[]
|
||||
{
|
||||
"thirdparty/apiclient/logger.js",
|
||||
"thirdparty/apiclient/md5.js",
|
||||
|
@ -289,10 +315,20 @@ namespace MediaBrowser.WebDashboard.Api
|
|||
"thirdparty/apiclient/events.js",
|
||||
"thirdparty/apiclient/deferred.js",
|
||||
"thirdparty/apiclient/apiclient.js",
|
||||
"thirdparty/apiclient/connectservice.js",
|
||||
"thirdparty/apiclient/serverdiscovery.js",
|
||||
"thirdparty/apiclient/connectionmanager.js"
|
||||
})
|
||||
"thirdparty/apiclient/connectservice.js"
|
||||
}.ToList();
|
||||
|
||||
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))
|
||||
{
|
||||
|
|
|
@ -90,10 +90,13 @@
|
|||
<Content Include="dashboard-ui\css\images\clients\androidtv-tile.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\css\images\empty.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\css\images\kids\bg.jpg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\css\images\server.png">
|
||||
<Content Include="dashboard-ui\css\images\logo536.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\css\images\splash.jpg">
|
||||
|
@ -216,6 +219,9 @@
|
|||
<Content Include="dashboard-ui\thirdparty\apiclient\connectservice.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\apiclient\cordova\serverdiscovery.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\apiclient\deferred.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -996,6 +1002,9 @@
|
|||
<Content Include="dashboard-ui\thirdparty\cast_sender.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\fastclick.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -1005,6 +1014,9 @@
|
|||
<Content Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\headroom.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<dependencies>
|
||||
<dependency id="MediaBrowser.Common" version="3.0.622" />
|
||||
<dependency id="NLog" version="3.2.1" />
|
||||
<dependency id="SimpleInjector" version="2.7.0" />
|
||||
<dependency id="SimpleInjector" version="2.8.0" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
|
Loading…
Reference in a new issue