Conflicts:
	MediaBrowser.Server.Implementations/Localization/Server/server.json
This commit is contained in:
Tavares André 2015-05-07 19:12:56 +02:00
commit 48e7ca8725
97 changed files with 1100 additions and 1174 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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[] { };
}
}
}

View file

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

View file

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

View file

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

View file

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

View 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[] { };
}
}
}

View file

@ -11,7 +11,6 @@ namespace MediaBrowser.Dlna.Profiles
Name = "WDTV Live";
TimelineOffsetSeconds = 5;
IgnoreTranscodeByteRangeRequests = true;
Identification = new DeviceIdentification
{

File diff suppressed because one or more lines are too long

View file

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

View file

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

View file

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

View file

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

File diff suppressed because one or more lines are too long

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because one or more lines are too long

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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