commit
c32d865638
|
@ -24,6 +24,7 @@ using MediaBrowser.Model.System;
|
|||
using MediaBrowser.Model.Threading;
|
||||
using Rssdp;
|
||||
using Rssdp.Infrastructure;
|
||||
using System.Threading;
|
||||
|
||||
namespace Emby.Dlna.Main
|
||||
{
|
||||
|
@ -252,7 +253,7 @@ namespace Emby.Dlna.Main
|
|||
var cacheLength = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds;
|
||||
_Publisher.SupportPnpRootDevice = false;
|
||||
|
||||
var addresses = (await _appHost.GetLocalIpAddresses().ConfigureAwait(false)).ToList();
|
||||
var addresses = (await _appHost.GetLocalIpAddresses(CancellationToken.None).ConfigureAwait(false)).ToList();
|
||||
|
||||
var udn = CreateUuid(_appHost.SystemId);
|
||||
|
||||
|
|
|
@ -831,7 +831,7 @@ namespace Emby.Dlna.PlayTo
|
|||
|
||||
#region From XML
|
||||
|
||||
private async Task GetAVProtocolAsync()
|
||||
private async Task GetAVProtocolAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
|
@ -845,12 +845,12 @@ namespace Emby.Dlna.PlayTo
|
|||
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
|
||||
|
||||
var httpClient = new SsdpHttpClient(_httpClient, _config);
|
||||
var document = await httpClient.GetDataAsync(url).ConfigureAwait(false);
|
||||
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
AvCommands = TransportCommands.Create(document);
|
||||
}
|
||||
|
||||
private async Task GetRenderingProtocolAsync()
|
||||
private async Task GetRenderingProtocolAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
|
@ -864,7 +864,7 @@ namespace Emby.Dlna.PlayTo
|
|||
string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
|
||||
|
||||
var httpClient = new SsdpHttpClient(_httpClient, _config);
|
||||
var document = await httpClient.GetDataAsync(url).ConfigureAwait(false);
|
||||
var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
RendererCommands = TransportCommands.Create(document);
|
||||
}
|
||||
|
@ -897,11 +897,11 @@ namespace Emby.Dlna.PlayTo
|
|||
set;
|
||||
}
|
||||
|
||||
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, ITimerFactory timerFactory)
|
||||
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, ITimerFactory timerFactory, CancellationToken cancellationToken)
|
||||
{
|
||||
var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
|
||||
|
||||
var document = await ssdpHttpClient.GetDataAsync(url.ToString()).ConfigureAwait(false);
|
||||
var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var deviceProperties = new DeviceInfo();
|
||||
|
||||
|
@ -987,8 +987,8 @@ namespace Emby.Dlna.PlayTo
|
|||
|
||||
if (device.GetAvTransportService() != null)
|
||||
{
|
||||
await device.GetRenderingProtocolAsync().ConfigureAwait(false);
|
||||
await device.GetAVProtocolAsync().ConfigureAwait(false);
|
||||
await device.GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
|
||||
await device.GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return device;
|
||||
|
|
|
@ -321,6 +321,12 @@ namespace Emby.Dlna.PlayTo
|
|||
AddItemFromId(Guid.Parse(id), items);
|
||||
}
|
||||
|
||||
var startIndex = command.StartIndex ?? 0;
|
||||
if (startIndex > 0)
|
||||
{
|
||||
items = items.Skip(startIndex).ToList();
|
||||
}
|
||||
|
||||
var playlist = new List<PlaylistItem>();
|
||||
var isFirst = true;
|
||||
|
||||
|
@ -424,7 +430,7 @@ namespace Emby.Dlna.PlayTo
|
|||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
|
||||
public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ using MediaBrowser.Model.Events;
|
|||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
|
@ -44,6 +45,8 @@ namespace Emby.Dlna.PlayTo
|
|||
private readonly List<string> _nonRendererUrls = new List<string>();
|
||||
private DateTime _lastRendererClear;
|
||||
private bool _disposed;
|
||||
private SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
|
||||
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory)
|
||||
{
|
||||
|
@ -90,6 +93,7 @@ namespace Emby.Dlna.PlayTo
|
|||
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
|
||||
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
|
||||
{
|
||||
//_logger.Debug("Upnp device {0} does not contain a MediaRenderer device (0).", location);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -98,92 +102,105 @@ namespace Emby.Dlna.PlayTo
|
|||
return;
|
||||
}
|
||||
|
||||
var cancellationToken = _disposeCancellationTokenSource.Token;
|
||||
|
||||
await _sessionLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
lock (_nonRendererUrls)
|
||||
{
|
||||
if ((DateTime.UtcNow - _lastRendererClear).TotalMinutes >= 10)
|
||||
{
|
||||
_nonRendererUrls.Clear();
|
||||
_lastRendererClear = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
if (_nonRendererUrls.Contains(location, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var uri = info.Location;
|
||||
_logger.Debug("Attempting to create PlayToController from location {0}", location);
|
||||
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, _timerFactory).ConfigureAwait(false);
|
||||
|
||||
if (device.RendererCommands == null)
|
||||
{
|
||||
lock (_nonRendererUrls)
|
||||
{
|
||||
_nonRendererUrls.Add(location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.Debug("Logging session activity from location {0}", location);
|
||||
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
|
||||
.ConfigureAwait(false);
|
||||
await AddDevice(info, location, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
var controller = sessionInfo.SessionController as PlayToController;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error creating PlayTo device.", ex);
|
||||
|
||||
if (controller == null)
|
||||
_nonRendererUrls.Add(location);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sessionLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddDevice(UpnpDeviceInfo info, string location, CancellationToken cancellationToken)
|
||||
{
|
||||
if ((DateTime.UtcNow - _lastRendererClear).TotalMinutes >= 10)
|
||||
{
|
||||
_nonRendererUrls.Clear();
|
||||
_lastRendererClear = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
if (_nonRendererUrls.Contains(location, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var uri = info.Location;
|
||||
_logger.Debug("Attempting to create PlayToController from location {0}", location);
|
||||
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, _timerFactory, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (device.RendererCommands == null)
|
||||
{
|
||||
//_logger.Debug("Upnp device {0} does not contain a MediaRenderer device (1).", location);
|
||||
_nonRendererUrls.Add(location);
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.Debug("Logging session activity from location {0}", location);
|
||||
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null).ConfigureAwait(false);
|
||||
|
||||
var controller = sessionInfo.SessionController as PlayToController;
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
string serverAddress;
|
||||
if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IpAddressInfo.Any) || info.LocalIpAddress.Equals(IpAddressInfo.IPv6Loopback))
|
||||
{
|
||||
if (_disposed)
|
||||
serverAddress = await GetServerAddress(null, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
serverAddress = await GetServerAddress(info.LocalIpAddress, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
string accessToken = null;
|
||||
|
||||
sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
|
||||
_sessionManager,
|
||||
_libraryManager,
|
||||
_logger,
|
||||
_dlnaManager,
|
||||
_userManager,
|
||||
_imageProcessor,
|
||||
serverAddress,
|
||||
accessToken,
|
||||
_deviceDiscovery,
|
||||
_userDataManager,
|
||||
_localization,
|
||||
_mediaSourceManager,
|
||||
_config,
|
||||
_mediaEncoder);
|
||||
|
||||
controller.Init(device);
|
||||
|
||||
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
|
||||
_dlnaManager.GetDefaultProfile();
|
||||
|
||||
_sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
|
||||
{
|
||||
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
|
||||
|
||||
SupportedCommands = new string[]
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string serverAddress;
|
||||
if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IpAddressInfo.Any) || info.LocalIpAddress.Equals(IpAddressInfo.IPv6Loopback))
|
||||
{
|
||||
serverAddress = await GetServerAddress(null).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
serverAddress = await GetServerAddress(info.LocalIpAddress).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
string accessToken = null;
|
||||
|
||||
sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
|
||||
_sessionManager,
|
||||
_libraryManager,
|
||||
_logger,
|
||||
_dlnaManager,
|
||||
_userManager,
|
||||
_imageProcessor,
|
||||
serverAddress,
|
||||
accessToken,
|
||||
_deviceDiscovery,
|
||||
_userDataManager,
|
||||
_localization,
|
||||
_mediaSourceManager,
|
||||
_config,
|
||||
_mediaEncoder);
|
||||
|
||||
controller.Init(device);
|
||||
|
||||
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
|
||||
_dlnaManager.GetDefaultProfile();
|
||||
|
||||
_sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
|
||||
{
|
||||
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
|
||||
|
||||
SupportedCommands = new string[]
|
||||
{
|
||||
GeneralCommandType.VolumeDown.ToString(),
|
||||
GeneralCommandType.VolumeUp.ToString(),
|
||||
GeneralCommandType.Mute.ToString(),
|
||||
|
@ -192,33 +209,23 @@ namespace Emby.Dlna.PlayTo
|
|||
GeneralCommandType.SetVolume.ToString(),
|
||||
GeneralCommandType.SetAudioStreamIndex.ToString(),
|
||||
GeneralCommandType.SetSubtitleStreamIndex.ToString()
|
||||
},
|
||||
},
|
||||
|
||||
SupportsMediaControl = true,
|
||||
SupportsMediaControl = true,
|
||||
|
||||
// xbox one creates a new uuid everytime it restarts
|
||||
SupportsPersistentIdentifier = (device.Properties.ModelName ?? string.Empty).IndexOf("xbox", StringComparison.OrdinalIgnoreCase) == -1
|
||||
});
|
||||
// xbox one creates a new uuid everytime it restarts
|
||||
SupportsPersistentIdentifier = (device.Properties.ModelName ?? string.Empty).IndexOf("xbox", StringComparison.OrdinalIgnoreCase) == -1
|
||||
});
|
||||
|
||||
_logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error creating PlayTo device.", ex);
|
||||
|
||||
lock (_nonRendererUrls)
|
||||
{
|
||||
_nonRendererUrls.Add(location);
|
||||
}
|
||||
_logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
|
||||
}
|
||||
}
|
||||
|
||||
private Task<string> GetServerAddress(IpAddressInfo address)
|
||||
private Task<string> GetServerAddress(IpAddressInfo address, CancellationToken cancellationToken)
|
||||
{
|
||||
if (address == null)
|
||||
{
|
||||
return _appHost.GetLocalApiUrl();
|
||||
return _appHost.GetLocalApiUrl(cancellationToken);
|
||||
}
|
||||
|
||||
return Task.FromResult(_appHost.GetLocalApiUrl(address));
|
||||
|
@ -226,6 +233,15 @@ namespace Emby.Dlna.PlayTo
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
_disposeCancellationTokenSource.Cancel();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
|
||||
GC.SuppressFinalize(this);
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Emby.Dlna.PlayTo
|
||||
{
|
||||
|
@ -89,7 +90,7 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<XDocument> GetDataAsync(string url)
|
||||
public async Task<XDocument> GetDataAsync(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
var options = new HttpRequestOptions
|
||||
{
|
||||
|
@ -99,7 +100,9 @@ namespace Emby.Dlna.PlayTo
|
|||
BufferContent = false,
|
||||
|
||||
// The periodic requests may keep some devices awake
|
||||
LogRequestAsDebug = true
|
||||
LogRequestAsDebug = true,
|
||||
|
||||
CancellationToken = cancellationToken
|
||||
};
|
||||
|
||||
options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
|
||||
|
|
|
@ -208,7 +208,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "mkv,ts",
|
||||
Container = "mkv,ts,mpegts",
|
||||
Type = DlnaProfileType.Video,
|
||||
MimeType = "video/mp4"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "avi,mp4,mkv,ts,m4v",
|
||||
Container = "avi,mp4,mkv,ts,mpegts,m4v",
|
||||
Type = DlnaProfileType.Video
|
||||
}
|
||||
};
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264,mpeg2video",
|
||||
AudioCodec = "aac,mp3,mp2",
|
||||
Type = DlnaProfileType.Video
|
||||
|
@ -205,7 +205,7 @@ namespace Emby.Dlna.Profiles
|
|||
new ResponseProfile
|
||||
{
|
||||
Type = DlnaProfileType.Video,
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
OrgPn = "MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts"
|
||||
},
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "aac,ac3,eac3,mp3,mp2,pcm"
|
||||
|
|
|
@ -12,6 +12,9 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
EnableAlbumArtInDidl = true;
|
||||
|
||||
// Without this, older samsungs fail to browse
|
||||
EnableSingleAlbumArtLimit = true;
|
||||
|
||||
Identification = new DeviceIdentification
|
||||
{
|
||||
ModelUrl = "samsung.com",
|
||||
|
@ -39,7 +42,7 @@ namespace Emby.Dlna.Profiles
|
|||
},
|
||||
new TranscodingProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
AudioCodec = "ac3",
|
||||
VideoCodec = "h264",
|
||||
Type = DlnaProfileType.Video,
|
||||
|
@ -300,7 +303,7 @@ namespace Emby.Dlna.Profiles
|
|||
new CodecProfile
|
||||
{
|
||||
Type = CodecType.VideoAudio,
|
||||
Codec = "ac3,wmav2,dca,aac,mp3,dts",
|
||||
Codec = "wmav2,dca,aac,mp3,dts",
|
||||
|
||||
Conditions = new[]
|
||||
{
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "mpeg1video,mpeg2video,h264",
|
||||
AudioCodec = "ac3,aac,mp3,pcm",
|
||||
Type = DlnaProfileType.Video
|
||||
|
@ -212,7 +212,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264,mpeg4,vc1",
|
||||
AudioCodec = "ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -236,7 +236,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
|
|
|
@ -69,14 +69,14 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "ac3,aac,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "mpeg1video,mpeg2video",
|
||||
AudioCodec = "mp3,mp2",
|
||||
Type = DlnaProfileType.Video
|
||||
|
@ -100,7 +100,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -126,7 +126,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/mpeg",
|
||||
|
@ -146,7 +146,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -156,7 +156,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="mpeg2video",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
|
||||
|
|
|
@ -66,14 +66,14 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "ac3,aac,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "mpeg2video",
|
||||
AudioCodec = "mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
|
@ -141,7 +141,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -167,7 +167,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/mpeg",
|
||||
|
@ -187,7 +187,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -197,7 +197,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="mpeg2video",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
|
||||
|
|
|
@ -66,14 +66,14 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "ac3,aac,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "mpeg2video",
|
||||
AudioCodec = "mp3,mp2",
|
||||
Type = DlnaProfileType.Video
|
||||
|
@ -129,7 +129,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -155,7 +155,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/mpeg",
|
||||
|
@ -175,7 +175,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -185,7 +185,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="mpeg2video",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
|
||||
|
|
|
@ -65,14 +65,14 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "ac3,eac3,aac,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "mpeg2video",
|
||||
AudioCodec = "mp3,mp2",
|
||||
Type = DlnaProfileType.Video
|
||||
|
@ -185,7 +185,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -211,7 +211,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/mpeg",
|
||||
|
@ -231,7 +231,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -241,7 +241,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="mpeg2video",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
|
||||
|
|
|
@ -65,14 +65,14 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264",
|
||||
AudioCodec = "ac3,eac3,aac,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "mpeg2video",
|
||||
AudioCodec = "mp3,mp2",
|
||||
Type = DlnaProfileType.Video
|
||||
|
@ -185,7 +185,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -211,7 +211,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/mpeg",
|
||||
|
@ -231,7 +231,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="h264",
|
||||
AudioCodec="ac3,aac,mp3",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
|
@ -241,7 +241,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec="mpeg2video",
|
||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||
OrgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO",
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Emby.Dlna.Profiles
|
|||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "mpeg1video,mpeg2video,h264",
|
||||
AudioCodec = "ac3,mp2,mp3,aac"
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Emby.Dlna.Profiles
|
|||
},
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "mpeg1video,mpeg2video,h264",
|
||||
AudioCodec = "ac3,mp2,mp3,aac"
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace Emby.Dlna.Profiles
|
|||
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts,m2ts",
|
||||
Container = "ts,m2ts,mpegts",
|
||||
Type = DlnaProfileType.Video,
|
||||
VideoCodec = "mpeg1video,mpeg2video,h264,vc1",
|
||||
AudioCodec = "ac3,eac3,dca,mp2,mp3,aac,dts"
|
||||
|
@ -155,7 +155,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new ResponseProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
OrgPn = "MPEG_TS_SD_NA",
|
||||
Type = DlnaProfileType.Video
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace Emby.Dlna.Profiles
|
|||
{
|
||||
new DirectPlayProfile
|
||||
{
|
||||
Container = "ts",
|
||||
Container = "ts,mpegts",
|
||||
VideoCodec = "h264,mpeg2video,hevc",
|
||||
AudioCodec = "ac3,aac,mp3",
|
||||
Type = DlnaProfileType.Video
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Generic Device</Name>
|
||||
<Manufacturer>Emby</Manufacturer>
|
||||
<ManufacturerUrl>http://emby.media/</ManufacturerUrl>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Denon AVR</Name>
|
||||
<Identification>
|
||||
<FriendlyName>Denon:\[AVR:.*</FriendlyName>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>DirecTV HD-DVR</Name>
|
||||
<Identification>
|
||||
<FriendlyName>^DIRECTV.*$</FriendlyName>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Dish Hopper-Joey</Name>
|
||||
<Identification>
|
||||
<Manufacturer>Echostar Technologies LLC</Manufacturer>
|
||||
|
@ -86,7 +86,7 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="mkv,ts" type="Video" mimeType="video/mp4">
|
||||
<ResponseProfile container="mkv,ts,mpegts" type="Video" mimeType="video/mp4">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
</ResponseProfiles>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>LG Smart TV</Name>
|
||||
<Identification>
|
||||
<FriendlyName>LG.*</FriendlyName>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Linksys DMA2100</Name>
|
||||
<Identification>
|
||||
<ModelName>DMA2100us</ModelName>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<XmlRootAttributes />
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
||||
<DirectPlayProfile container="avi,mp4,mkv,ts,m4v" type="Video" />
|
||||
<DirectPlayProfile container="avi,mp4,mkv,ts,mpegts,m4v" type="Video" />
|
||||
</DirectPlayProfiles>
|
||||
<TranscodingProfiles>
|
||||
<TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Marantz</Name>
|
||||
<Identification>
|
||||
<Manufacturer>Marantz</Manufacturer>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>MediaMonkey</Name>
|
||||
<Identification>
|
||||
<FriendlyName>MediaMonkey</FriendlyName>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Panasonic Viera</Name>
|
||||
<Identification>
|
||||
<FriendlyName>VIERA</FriendlyName>
|
||||
|
@ -40,7 +40,7 @@
|
|||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mpeg,mpg" audioCodec="ac3,mp3,pcm_dvd" videoCodec="mpeg2video,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,dca,mp3,mp2,pcm,dts" videoCodec="h264,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="aac,mp3,mp2" videoCodec="h264,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="aac,mp3,mp2" videoCodec="h264,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="mov" audioCodec="aac,pcm" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="pcm" videoCodec="mpeg4" type="Video" />
|
||||
|
@ -73,7 +73,7 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="m4v" type="Video" mimeType="video/mp4">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Popcorn Hour</Name>
|
||||
<Manufacturer>Emby</Manufacturer>
|
||||
<ManufacturerUrl>http://emby.media/</ManufacturerUrl>
|
||||
|
@ -30,7 +30,7 @@
|
|||
<XmlRootAttributes />
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="mp4,mov,m4v" audioCodec="aac" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="aac,ac3,eac3,mp3,mp2,pcm" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="aac,ac3,eac3,mp3,mp2,pcm" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="asf,wmv" audioCodec="wmav2,wmapro" videoCodec="wmv3,vc1" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="mp3,ac3,eac3,mp2,pcm" videoCodec="mpeg4,msmpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="aac,mp3,ac3,eac3,mp2,pcm" videoCodec="h264" type="Video" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Samsung Smart TV</Name>
|
||||
<Identification>
|
||||
<ModelUrl>samsung.com</ModelUrl>
|
||||
|
@ -14,7 +14,7 @@
|
|||
<ModelNumber>Emby</ModelNumber>
|
||||
<ModelUrl>http://emby.media/</ModelUrl>
|
||||
<EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
|
||||
<EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
|
||||
<EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
|
||||
<EnableSingleSubtitleLimit>false</EnableSingleSubtitleLimit>
|
||||
<SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
|
||||
<AlbumArtPn>JPEG_SM</AlbumArtPn>
|
||||
|
@ -51,7 +51,7 @@
|
|||
</DirectPlayProfiles>
|
||||
<TranscodingProfiles>
|
||||
<TranscodingProfile container="mp3" type="Audio" audioCodec="mp3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
|
||||
<TranscodingProfile container="ts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
|
||||
<TranscodingProfile container="ts,mpegts" type="Video" videoCodec="h264" audioCodec="ac3" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
|
||||
<TranscodingProfile container="jpeg" type="Photo" estimateContentLength="false" enableMpegtsM2TsMode="false" transcodeSeekInfo="Auto" copyTimestamps="false" context="Streaming" enableSubtitlesInManifest="false" minSegments="0" segmentLength="0" breakOnNonKeyFrames="false" />
|
||||
</TranscodingProfiles>
|
||||
<ContainerProfiles>
|
||||
|
@ -100,7 +100,7 @@
|
|||
</Conditions>
|
||||
<ApplyConditions />
|
||||
</CodecProfile>
|
||||
<CodecProfile type="VideoAudio" codec="ac3,wmav2,dca,aac,mp3,dts">
|
||||
<CodecProfile type="VideoAudio" codec="wmav2,dca,aac,mp3,dts">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="LessThanEqual" property="AudioChannels" value="6" isRequired="true" />
|
||||
</Conditions>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sharp Smart TV</Name>
|
||||
<Identification>
|
||||
<Manufacturer>Sharp</Manufacturer>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Blu-ray Player 2013</Name>
|
||||
<Identification>
|
||||
<ModelNumber>BDP-2013</ModelNumber>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Blu-ray Player 2014</Name>
|
||||
<Identification>
|
||||
<ModelNumber>BDP-2014</ModelNumber>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Blu-ray Player 2015</Name>
|
||||
<Identification>
|
||||
<ModelNumber>BDP-2015</ModelNumber>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Blu-ray Player 2016</Name>
|
||||
<Identification>
|
||||
<ModelNumber>BDP-2016</ModelNumber>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Blu-ray Player</Name>
|
||||
<Identification>
|
||||
<FriendlyName>Blu-ray Disc Player</FriendlyName>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="avi,mp4,m4v" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg4,h264" type="Video" />
|
||||
<DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
|
||||
|
@ -84,7 +84,7 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg4,vc1" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg4,vc1" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="avi" type="Video" mimeType="video/mpeg">
|
||||
|
@ -93,7 +93,7 @@
|
|||
<ResponseProfile container="mkv" type="Video" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" type="Video" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" type="Video" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="mp4" type="Video" mimeType="video/mpeg">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Bravia (2010)</Name>
|
||||
<Identification>
|
||||
<FriendlyName>KDL-\d{2}[EHLNPB]X\d[01]\d.*</FriendlyName>
|
||||
|
@ -39,8 +39,8 @@
|
|||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="mp3,mp2" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" />
|
||||
<DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />
|
||||
</DirectPlayProfiles>
|
||||
|
@ -106,21 +106,21 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Bravia (2011)</Name>
|
||||
<Identification>
|
||||
<FriendlyName>KDL-\d{2}([A-Z]X\d2\d|CX400).*</FriendlyName>
|
||||
|
@ -39,8 +39,8 @@
|
|||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="mp3" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="mp3" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="mp3" videoCodec="mpeg2video,mpeg1video" type="Video" />
|
||||
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" videoCodec="wmv2,wmv3,vc1" type="Video" />
|
||||
|
@ -109,21 +109,21 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Bravia (2012)</Name>
|
||||
<Identification>
|
||||
<FriendlyName>KDL-\d{2}[A-Z]X\d5(\d|G).*</FriendlyName>
|
||||
|
@ -39,8 +39,8 @@
|
|||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="mp3,mp2" videoCodec="mpeg2video,mpeg1video" type="Video" />
|
||||
|
@ -85,21 +85,21 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Bravia (2013)</Name>
|
||||
<Identification>
|
||||
<FriendlyName>KDL-\d{2}[WR][5689]\d{2}A.*</FriendlyName>
|
||||
|
@ -39,8 +39,8 @@
|
|||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mov" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,eac3,aac,mp3,mp2,pcm,vorbis" videoCodec="h264,mpeg4,vp8" type="Video" />
|
||||
|
@ -84,21 +84,21 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony Bravia (2014)</Name>
|
||||
<Identification>
|
||||
<FriendlyName>(KDL-\d{2}W[5-9]\d{2}B|KDL-\d{2}R480|XBR-\d{2}X[89]\d{2}B|KD-\d{2}[SX][89]\d{3}B).*</FriendlyName>
|
||||
|
@ -39,8 +39,8 @@
|
|||
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||
</XmlRootAttributes>
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,m4v" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="mov" audioCodec="ac3,eac3,aac,mp3,mp2" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,eac3,aac,mp3,mp2,pcm,vorbis" videoCodec="h264,mpeg4,vp8" type="Video" />
|
||||
|
@ -84,21 +84,21 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||
<Conditions>
|
||||
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||
</Conditions>
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="ts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<ResponseProfile container="ts,mpegts" videoCodec="mpeg2video" type="Video" orgPn="MPEG_TS_SD_EU,MPEG_TS_SD_NA,MPEG_TS_SD_KO" mimeType="video/vnd.dlna.mpeg-tts">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
<ResponseProfile container="mpeg" videoCodec="mpeg1video,mpeg2video" type="Video" orgPn="MPEG_PS_NTSC,MPEG_PS_PAL" mimeType="video/mpeg">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony PlayStation 3</Name>
|
||||
<Identification>
|
||||
<FriendlyName>PLAYSTATION 3</FriendlyName>
|
||||
|
@ -38,7 +38,7 @@
|
|||
<XmlRootAttributes />
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4" audioCodec="aac,ac3" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="aac,mp3,wav" type="Audio" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Sony PlayStation 4</Name>
|
||||
<Identification>
|
||||
<FriendlyName>PLAYSTATION 4</FriendlyName>
|
||||
|
@ -38,7 +38,7 @@
|
|||
<XmlRootAttributes />
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mp4,mkv,m4v" audioCodec="aac,ac3" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="aac,mp3,wav" type="Audio" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>WDTV Live</Name>
|
||||
<Identification>
|
||||
<ModelName>WD TV</ModelName>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<DirectPlayProfile container="avi" audioCodec="ac3,eac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,eac3,dca,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||
<DirectPlayProfile container="mkv" audioCodec="ac3,eac3,dca,aac,mp2,mp3,pcm,dts" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="ts,m2ts" audioCodec="ac3,eac3,dca,mp2,mp3,aac,dts" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="ts,m2ts,mpegts" audioCodec="ac3,eac3,dca,mp2,mp3,aac,dts" videoCodec="mpeg1video,mpeg2video,h264,vc1" type="Video" />
|
||||
<DirectPlayProfile container="mp4,mov,m4v" audioCodec="ac3,eac3,aac,mp2,mp3,dca,dts" videoCodec="h264,mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro" videoCodec="vc1" type="Video" />
|
||||
<DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
|
||||
|
@ -80,7 +80,7 @@
|
|||
</CodecProfile>
|
||||
</CodecProfiles>
|
||||
<ResponseProfiles>
|
||||
<ResponseProfile container="ts" type="Video" orgPn="MPEG_TS_SD_NA">
|
||||
<ResponseProfile container="ts,mpegts" type="Video" orgPn="MPEG_TS_SD_NA">
|
||||
<Conditions />
|
||||
</ResponseProfile>
|
||||
</ResponseProfiles>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>Xbox One</Name>
|
||||
<Identification>
|
||||
<ModelName>Xbox One</ModelName>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
|
||||
<XmlRootAttributes />
|
||||
<DirectPlayProfiles>
|
||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg2video,hevc" type="Video" />
|
||||
<DirectPlayProfile container="ts,mpegts" audioCodec="ac3,aac,mp3" videoCodec="h264,mpeg2video,hevc" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||
<DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
|
||||
<DirectPlayProfile container="mp4,mov,mkv,m4v" audioCodec="aac,ac3" videoCodec="h264,mpeg4,mpeg2video,hevc" type="Video" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0"?>
|
||||
<Profile xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Name>foobar2000</Name>
|
||||
<Identification>
|
||||
<FriendlyName>foobar</FriendlyName>
|
||||
|
|
|
@ -173,6 +173,8 @@ namespace Emby.Drawing.ImageMagick
|
|||
originalImage.CurrentImage.CompressionQuality = quality;
|
||||
originalImage.CurrentImage.StripImage();
|
||||
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
|
||||
|
||||
originalImage.SaveImage(outputPath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,9 +59,6 @@
|
|||
<Compile Include="StripCollageBuilder.cs" />
|
||||
<Compile Include="UnplayedCountIndicator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="fonts\robotoregular.ttf" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="SkiaSharp, Version=1.58.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SkiaSharp.1.58.1\lib\portable-net45+win8+wpa81+wp8\SkiaSharp.dll</HintPath>
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace Emby.Drawing.Skia
|
|||
{
|
||||
public class PlayedIndicatorDrawer
|
||||
{
|
||||
private const int FontSize = 42;
|
||||
private const int OffsetFromTopRightCorner = 38;
|
||||
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
|
@ -44,50 +43,25 @@ namespace Emby.Drawing.Skia
|
|||
{
|
||||
paint.Color = new SKColor(255, 255, 255, 255);
|
||||
paint.Style = SKPaintStyle.Fill;
|
||||
paint.Typeface = SKTypeface.FromFile(await DownloadFont("webdings.ttf", "https://github.com/MediaBrowser/Emby.Resources/raw/master/fonts/webdings.ttf",
|
||||
_appPaths, _iHttpClient, _fileSystem).ConfigureAwait(false));
|
||||
paint.TextSize = FontSize;
|
||||
|
||||
paint.TextSize = 30;
|
||||
paint.IsAntialias = true;
|
||||
|
||||
canvas.DrawText("a", (float)x-20, OffsetFromTopRightCorner + 12, paint);
|
||||
var text = "✔️";
|
||||
var emojiChar = StringUtilities.GetUnicodeCharacterCode(text, SKTextEncoding.Utf32);
|
||||
// or:
|
||||
//var emojiChar = 0x1F680;
|
||||
|
||||
// ask the font manager for a font with that character
|
||||
var fontManager = SKFontManager.Default;
|
||||
var emojiTypeface = fontManager.MatchCharacter(emojiChar);
|
||||
|
||||
paint.Typeface = emojiTypeface;
|
||||
|
||||
canvas.DrawText(text, (float)x-20, OffsetFromTopRightCorner + 12, paint);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ExtractFont(string name, IApplicationPaths paths, IFileSystem fileSystem)
|
||||
{
|
||||
var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
|
||||
|
||||
if (fileSystem.FileExists(filePath))
|
||||
{
|
||||
return filePath;
|
||||
}
|
||||
|
||||
var namespacePath = typeof(PlayedIndicatorDrawer).Namespace + ".fonts." + name;
|
||||
var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".ttf");
|
||||
fileSystem.CreateDirectory(fileSystem.GetDirectoryName(tempPath));
|
||||
|
||||
using (var stream = typeof(PlayedIndicatorDrawer).GetTypeInfo().Assembly.GetManifestResourceStream(namespacePath))
|
||||
{
|
||||
using (var fileStream = fileSystem.GetFileStream(tempPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
|
||||
{
|
||||
stream.CopyTo(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
fileSystem.CreateDirectory(fileSystem.GetDirectoryName(filePath));
|
||||
|
||||
try
|
||||
{
|
||||
fileSystem.CopyFile(tempPath, filePath, false);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
|
||||
internal static async Task<string> DownloadFont(string name, string url, IApplicationPaths paths, IHttpClient httpClient, IFileSystem fileSystem)
|
||||
{
|
||||
var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
|
||||
|
|
|
@ -528,6 +528,7 @@ namespace Emby.Drawing.Skia
|
|||
// If all we're doing is resizing then we can stop now
|
||||
if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
|
||||
{
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
|
||||
using (var outputStream = new SKFileWStream(outputPath))
|
||||
{
|
||||
resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
|
||||
|
@ -580,6 +581,7 @@ namespace Emby.Drawing.Skia
|
|||
DrawIndicator(canvas, width, height, options);
|
||||
}
|
||||
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath));
|
||||
using (var outputStream = new SKFileWStream(outputPath))
|
||||
{
|
||||
saveBitmap.Encode(outputStream, skiaOutputFormat, quality);
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Emby.Drawing.Skia
|
|||
{
|
||||
paint.Color = new SKColor(255, 255, 255, 255);
|
||||
paint.Style = SKPaintStyle.Fill;
|
||||
paint.Typeface = SKTypeface.FromFile(PlayedIndicatorDrawer.ExtractFont("robotoregular.ttf", _appPaths, _fileSystem));
|
||||
|
||||
paint.TextSize = 24;
|
||||
paint.IsAntialias = true;
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ namespace Emby.Drawing
|
|||
Type = originalImage.Type,
|
||||
Path = originalImagePath
|
||||
|
||||
}, requiresTransparency, item, options.ImageIndex, options.Enhancers).ConfigureAwait(false);
|
||||
}, requiresTransparency, item, options.ImageIndex, options.Enhancers, CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
originalImagePath = tuple.Item1;
|
||||
dateModified = tuple.Item2;
|
||||
|
@ -256,31 +256,29 @@ namespace Emby.Drawing
|
|||
var outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
|
||||
var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
|
||||
|
||||
CheckDisposed();
|
||||
|
||||
var lockInfo = GetLock(cacheFilePath);
|
||||
|
||||
await lockInfo.Lock.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
CheckDisposed();
|
||||
|
||||
if (!_fileSystem.FileExists(cacheFilePath))
|
||||
{
|
||||
var tmpPath = Path.ChangeExtension(Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")), Path.GetExtension(cacheFilePath));
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
|
||||
|
||||
if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath))
|
||||
{
|
||||
options.CropWhiteSpace = false;
|
||||
}
|
||||
|
||||
var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, tmpPath, autoOrient, orientation, quality, options, outputFormat);
|
||||
var resultPath = _imageEncoder.EncodeImage(originalImagePath, dateModified, cacheFilePath, autoOrient, orientation, quality, options, outputFormat);
|
||||
|
||||
if (string.Equals(resultPath, originalImagePath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
|
||||
}
|
||||
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath));
|
||||
CopyFile(tmpPath, cacheFilePath);
|
||||
|
||||
return new Tuple<string, string, DateTime>(tmpPath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(tmpPath));
|
||||
return new Tuple<string, string, DateTime>(cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
|
||||
}
|
||||
|
||||
return new Tuple<string, string, DateTime>(cacheFilePath, GetMimeType(outputFormat, cacheFilePath), _fileSystem.GetLastWriteTimeUtc(cacheFilePath));
|
||||
|
@ -302,6 +300,10 @@ namespace Emby.Drawing
|
|||
// Just spit out the original file if all the options are default
|
||||
return new Tuple<string, string, DateTime>(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ReleaseLock(cacheFilePath, lockInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private ImageFormat GetOutputFormat(ImageFormat[] clientSupportedFormats, bool requiresTransparency)
|
||||
|
@ -667,7 +669,7 @@ namespace Emby.Drawing
|
|||
|
||||
var inputImageSupportsTransparency = SupportsTransparency(imageInfo.Path);
|
||||
|
||||
var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers);
|
||||
var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers, CancellationToken.None);
|
||||
|
||||
return result.Item1;
|
||||
}
|
||||
|
@ -676,7 +678,8 @@ namespace Emby.Drawing
|
|||
bool inputImageSupportsTransparency,
|
||||
IHasMetadata item,
|
||||
int imageIndex,
|
||||
List<IImageEnhancer> enhancers)
|
||||
List<IImageEnhancer> enhancers,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var originalImagePath = image.Path;
|
||||
var dateModified = image.DateModified;
|
||||
|
@ -687,7 +690,7 @@ namespace Emby.Drawing
|
|||
var cacheGuid = GetImageCacheTag(item, image, enhancers);
|
||||
|
||||
// Enhance if we have enhancers
|
||||
var ehnancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid).ConfigureAwait(false);
|
||||
var ehnancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var ehnancedImagePath = ehnancedImageInfo.Item1;
|
||||
|
||||
|
@ -727,7 +730,8 @@ namespace Emby.Drawing
|
|||
ImageType imageType,
|
||||
int imageIndex,
|
||||
List<IImageEnhancer> supportedEnhancers,
|
||||
string cacheGuid)
|
||||
string cacheGuid,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(originalImagePath))
|
||||
{
|
||||
|
@ -755,29 +759,28 @@ namespace Emby.Drawing
|
|||
|
||||
var enhancedImagePath = GetCachePath(EnhancedImageCachePath, cacheGuid + cacheExtension);
|
||||
|
||||
// Check again in case of contention
|
||||
if (_fileSystem.FileExists(enhancedImagePath))
|
||||
{
|
||||
return new Tuple<string, bool>(enhancedImagePath, treatmentRequiresTransparency);
|
||||
}
|
||||
var lockInfo = GetLock(enhancedImagePath);
|
||||
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(enhancedImagePath));
|
||||
|
||||
var tmpPath = Path.Combine(_appPaths.TempDirectory, Path.ChangeExtension(Guid.NewGuid().ToString(), Path.GetExtension(enhancedImagePath)));
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(tmpPath));
|
||||
|
||||
await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, tmpPath, item, imageType, imageIndex).ConfigureAwait(false);
|
||||
await lockInfo.Lock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
_fileSystem.CopyFile(tmpPath, enhancedImagePath, true);
|
||||
// Check again in case of contention
|
||||
if (_fileSystem.FileExists(enhancedImagePath))
|
||||
{
|
||||
return new Tuple<string, bool>(enhancedImagePath, treatmentRequiresTransparency);
|
||||
}
|
||||
|
||||
_fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(enhancedImagePath));
|
||||
|
||||
await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false);
|
||||
|
||||
return new Tuple<string, bool>(enhancedImagePath, treatmentRequiresTransparency);
|
||||
}
|
||||
catch
|
||||
finally
|
||||
{
|
||||
|
||||
ReleaseLock(enhancedImagePath, lockInfo);
|
||||
}
|
||||
|
||||
return new Tuple<string, bool>(tmpPath, treatmentRequiresTransparency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -896,6 +899,45 @@ namespace Emby.Drawing
|
|||
return list;
|
||||
}
|
||||
|
||||
private Dictionary<string, LockInfo> _locks = new Dictionary<string, LockInfo>();
|
||||
private class LockInfo
|
||||
{
|
||||
public SemaphoreSlim Lock = new SemaphoreSlim(1, 1);
|
||||
public int Count = 1;
|
||||
}
|
||||
private LockInfo GetLock(string key)
|
||||
{
|
||||
lock (_locks)
|
||||
{
|
||||
LockInfo info;
|
||||
if (_locks.TryGetValue(key, out info))
|
||||
{
|
||||
info.Count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
info = new LockInfo();
|
||||
_locks[key] = info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleaseLock(string key, LockInfo info)
|
||||
{
|
||||
info.Lock.Release();
|
||||
|
||||
lock (_locks)
|
||||
{
|
||||
info.Count--;
|
||||
if (info.Count <= 0)
|
||||
{
|
||||
_locks.Remove(key);
|
||||
info.Lock.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposed;
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
@ -148,6 +148,34 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
}
|
||||
|
||||
public virtual bool CanLaunchWebBrowser
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Environment.UserInteractive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StartupOptions.ContainsOption("-service"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [has pending restart changed].
|
||||
/// </summary>
|
||||
|
@ -361,7 +389,7 @@ namespace Emby.Server.Implementations
|
|||
|
||||
protected IAuthService AuthService { get; private set; }
|
||||
|
||||
protected readonly StartupOptions StartupOptions;
|
||||
public StartupOptions StartupOptions { get; private set; }
|
||||
protected readonly string ReleaseAssetFilename;
|
||||
|
||||
internal IPowerManagement PowerManagement { get; private set; }
|
||||
|
@ -393,6 +421,7 @@ namespace Emby.Server.Implementations
|
|||
ISystemEvents systemEvents,
|
||||
INetworkManager networkManager)
|
||||
{
|
||||
|
||||
// hack alert, until common can target .net core
|
||||
BaseExtensions.CryptographyProvider = CryptographyProvider;
|
||||
|
||||
|
@ -423,6 +452,13 @@ namespace Emby.Server.Implementations
|
|||
SetBaseExceptionMessage();
|
||||
|
||||
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
|
||||
|
||||
NetworkManager.NetworkChanged += NetworkManager_NetworkChanged;
|
||||
}
|
||||
|
||||
private void NetworkManager_NetworkChanged(object sender, EventArgs e)
|
||||
{
|
||||
_validAddressResults.Clear();
|
||||
}
|
||||
|
||||
private Version _version;
|
||||
|
@ -1901,9 +1937,9 @@ namespace Emby.Server.Implementations
|
|||
/// Gets the system status.
|
||||
/// </summary>
|
||||
/// <returns>SystemInfo.</returns>
|
||||
public async Task<SystemInfo> GetSystemInfo()
|
||||
public async Task<SystemInfo> GetSystemInfo(CancellationToken cancellationToken)
|
||||
{
|
||||
var localAddress = await GetLocalApiUrl().ConfigureAwait(false);
|
||||
var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return new SystemInfo
|
||||
{
|
||||
|
@ -1928,6 +1964,7 @@ namespace Emby.Server.Implementations
|
|||
OperatingSystemDisplayName = OperatingSystemDisplayName,
|
||||
CanSelfRestart = CanSelfRestart,
|
||||
CanSelfUpdate = CanSelfUpdate,
|
||||
CanLaunchWebBrowser = CanLaunchWebBrowser,
|
||||
WanAddress = ConnectManager.WanApiAddress,
|
||||
HasUpdateAvailable = HasUpdateAvailable,
|
||||
SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
|
||||
|
@ -1942,6 +1979,21 @@ namespace Emby.Server.Implementations
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken)
|
||||
{
|
||||
var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return new PublicSystemInfo
|
||||
{
|
||||
Version = ApplicationVersion.ToString(),
|
||||
Id = SystemId,
|
||||
OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
|
||||
WanAddress = ConnectManager.WanApiAddress,
|
||||
ServerName = FriendlyName,
|
||||
LocalAddress = localAddress
|
||||
};
|
||||
}
|
||||
|
||||
public bool EnableHttps
|
||||
{
|
||||
get
|
||||
|
@ -1955,14 +2007,14 @@ namespace Emby.Server.Implementations
|
|||
get { return Certificate != null || ServerConfigurationManager.Configuration.IsBehindProxy; }
|
||||
}
|
||||
|
||||
public async Task<string> GetLocalApiUrl()
|
||||
public async Task<string> GetLocalApiUrl(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Return the first matched address, if found, or the first known local address
|
||||
var address = (await GetLocalIpAddresses().ConfigureAwait(false)).FirstOrDefault(i => !i.Equals(IpAddressInfo.Loopback) && !i.Equals(IpAddressInfo.IPv6Loopback));
|
||||
var addresses = await GetLocalIpAddressesInternal(false, 1, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (address != null)
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
return GetLocalApiUrl(address);
|
||||
}
|
||||
|
@ -1994,7 +2046,12 @@ namespace Emby.Server.Implementations
|
|||
HttpPort.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
public async Task<List<IpAddressInfo>> GetLocalIpAddresses()
|
||||
public Task<List<IpAddressInfo>> GetLocalIpAddresses(CancellationToken cancellationToken)
|
||||
{
|
||||
return GetLocalIpAddressesInternal(true, 0, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<List<IpAddressInfo>> GetLocalIpAddressesInternal(bool allowLoopback, int limit, CancellationToken cancellationToken)
|
||||
{
|
||||
var addresses = ServerConfigurationManager
|
||||
.Configuration
|
||||
|
@ -2006,22 +2063,33 @@ namespace Emby.Server.Implementations
|
|||
if (addresses.Count == 0)
|
||||
{
|
||||
addresses.AddRange(NetworkManager.GetLocalIpAddresses());
|
||||
}
|
||||
|
||||
var list = new List<IpAddressInfo>();
|
||||
var resultList = new List<IpAddressInfo>();
|
||||
|
||||
foreach (var address in addresses)
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
if (!allowLoopback)
|
||||
{
|
||||
var valid = await IsIpAddressValidAsync(address).ConfigureAwait(false);
|
||||
if (valid)
|
||||
if (address.Equals(IpAddressInfo.Loopback) || address.Equals(IpAddressInfo.IPv6Loopback))
|
||||
{
|
||||
list.Add(address);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
addresses = list;
|
||||
var valid = await IsIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false);
|
||||
if (valid)
|
||||
{
|
||||
resultList.Add(address);
|
||||
|
||||
if (limit > 0 && resultList.Count >= limit)
|
||||
{
|
||||
return resultList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addresses;
|
||||
return resultList;
|
||||
}
|
||||
|
||||
private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
|
||||
|
@ -2042,8 +2110,7 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
|
||||
private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
|
||||
private DateTime _lastAddressCacheClear;
|
||||
private async Task<bool> IsIpAddressValidAsync(IpAddressInfo address)
|
||||
private async Task<bool> IsIpAddressValidAsync(IpAddressInfo address, CancellationToken cancellationToken)
|
||||
{
|
||||
if (address.Equals(IpAddressInfo.Loopback) ||
|
||||
address.Equals(IpAddressInfo.IPv6Loopback))
|
||||
|
@ -2054,12 +2121,6 @@ namespace Emby.Server.Implementations
|
|||
var apiUrl = GetLocalApiUrl(address);
|
||||
apiUrl += "/system/ping";
|
||||
|
||||
if ((DateTime.UtcNow - _lastAddressCacheClear).TotalMinutes >= 15)
|
||||
{
|
||||
_lastAddressCacheClear = DateTime.UtcNow;
|
||||
_validAddressResults.Clear();
|
||||
}
|
||||
|
||||
bool cachedResult;
|
||||
if (_validAddressResults.TryGetValue(apiUrl, out cachedResult))
|
||||
{
|
||||
|
@ -2075,7 +2136,9 @@ namespace Emby.Server.Implementations
|
|||
LogErrors = false,
|
||||
LogRequest = false,
|
||||
TimeoutMs = 30000,
|
||||
BufferContent = false
|
||||
BufferContent = false,
|
||||
|
||||
CancellationToken = cancellationToken
|
||||
|
||||
}, "POST").ConfigureAwait(false))
|
||||
{
|
||||
|
@ -2085,14 +2148,19 @@ namespace Emby.Server.Implementations
|
|||
var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
_validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
|
||||
//Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid);
|
||||
Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid);
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, "Cancelled");
|
||||
throw;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false);
|
||||
Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false);
|
||||
|
||||
_validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false);
|
||||
return false;
|
||||
|
@ -2317,12 +2385,11 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
}
|
||||
|
||||
public void LaunchUrl(string url)
|
||||
public virtual void LaunchUrl(string url)
|
||||
{
|
||||
if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows &&
|
||||
EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX)
|
||||
if (!CanLaunchWebBrowser)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
var process = ProcessFactory.Create(new ProcessOptions
|
||||
|
|
|
@ -89,6 +89,24 @@ namespace Emby.Server.Implementations.Archiving
|
|||
}
|
||||
}
|
||||
|
||||
public void ExtractFirstFileFromGz(Stream source, string targetPath, string defaultFileName)
|
||||
{
|
||||
using (var reader = GZipReader.Open(source))
|
||||
{
|
||||
if (reader.MoveToNextEntry())
|
||||
{
|
||||
var entry = reader.Entry;
|
||||
|
||||
var filename = entry.Key;
|
||||
if (string.IsNullOrWhiteSpace(filename))
|
||||
{
|
||||
filename = defaultFileName;
|
||||
}
|
||||
reader.WriteEntryToFile(Path.Combine(targetPath, filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts all from7z.
|
||||
/// </summary>
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.Browser
|
|||
{
|
||||
appHost.LaunchUrl(url);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -4286,7 +4286,7 @@ namespace Emby.Server.Implementations.Data
|
|||
|
||||
if (query.MinParentalRating.HasValue)
|
||||
{
|
||||
whereClauses.Add("InheritedParentalRatingValue<=@MinParentalRating");
|
||||
whereClauses.Add("InheritedParentalRatingValue>=@MinParentalRating");
|
||||
if (statement != null)
|
||||
{
|
||||
statement.TryBind("@MinParentalRating", query.MinParentalRating.Value);
|
||||
|
@ -5264,7 +5264,13 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||
ItemIds = query.ItemIds,
|
||||
TopParentIds = query.TopParentIds,
|
||||
ParentId = query.ParentId,
|
||||
IsPlayed = query.IsPlayed
|
||||
IsPlayed = query.IsPlayed,
|
||||
IsAiring = query.IsAiring,
|
||||
IsMovie = query.IsMovie,
|
||||
IsSports = query.IsSports,
|
||||
IsKids = query.IsKids,
|
||||
IsNews = query.IsNews,
|
||||
IsSeries = query.IsSeries
|
||||
};
|
||||
|
||||
var innerWhereClauses = GetWhereClauses(innerQuery, null);
|
||||
|
|
|
@ -708,6 +708,8 @@
|
|||
<EmbeddedResource Include="Localization\Core\zh-CN.json" />
|
||||
<EmbeddedResource Include="Localization\Core\zh-HK.json" />
|
||||
<EmbeddedResource Include="Localization\Core\en-US.json" />
|
||||
<EmbeddedResource Include="Localization\Core\el.json" />
|
||||
<EmbeddedResource Include="Localization\Core\gsw.json" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="TextEncoding\NLangDetect\Profiles\afr" />
|
||||
<None Include="TextEncoding\NLangDetect\Profiles\ara" />
|
||||
|
|
|
@ -13,6 +13,7 @@ using MediaBrowser.Model.Logging;
|
|||
using MediaBrowser.Model.Threading;
|
||||
using Mono.Nat;
|
||||
using MediaBrowser.Model.Extensions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
|
@ -158,7 +159,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
|
||||
try
|
||||
{
|
||||
var localAddressString = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
|
||||
var localAddressString = await _appHost.GetLocalApiUrl(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
Uri uri;
|
||||
if (Uri.TryCreate(localAddressString, UriKind.Absolute, out uri))
|
||||
|
|
|
@ -260,7 +260,7 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
|
||||
}
|
||||
|
||||
var parent = e.Item.GetParent() as Folder;
|
||||
var parent = e.Parent as Folder;
|
||||
if (parent != null)
|
||||
{
|
||||
_foldersRemovedFrom.Add(parent);
|
||||
|
@ -363,10 +363,16 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
/// <param name="foldersRemovedFrom">The folders removed from.</param>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <returns>LibraryUpdateInfo.</returns>
|
||||
private LibraryUpdateInfo GetLibraryUpdateInfo(IEnumerable<BaseItem> itemsAdded, IEnumerable<BaseItem> itemsUpdated, IEnumerable<BaseItem> itemsRemoved, IEnumerable<Folder> foldersAddedTo, IEnumerable<Folder> foldersRemovedFrom, Guid userId)
|
||||
private LibraryUpdateInfo GetLibraryUpdateInfo(List<BaseItem> itemsAdded, List<BaseItem> itemsUpdated, List<BaseItem> itemsRemoved, List<Folder> foldersAddedTo, List<Folder> foldersRemovedFrom, Guid userId)
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
|
||||
var newAndRemoved = new List<BaseItem>();
|
||||
newAndRemoved.AddRange(foldersAddedTo);
|
||||
newAndRemoved.AddRange(foldersRemovedFrom);
|
||||
|
||||
var allUserRootChildren = _libraryManager.GetUserRootFolder().GetChildren(user, true).OfType<Folder>().ToList();
|
||||
|
||||
return new LibraryUpdateInfo
|
||||
{
|
||||
ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
|
||||
|
@ -377,7 +383,9 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
|
||||
FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
|
||||
|
||||
FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray()
|
||||
FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N")).Distinct().ToArray(),
|
||||
|
||||
CollectionFolders = GetTopParentIds(newAndRemoved, user, allUserRootChildren).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -396,6 +404,28 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
return item.SourceType == SourceType.Library;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetTopParentIds(List<BaseItem> items, User user, List<Folder> allUserRootChildren)
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
// If the physical root changed, return the user root
|
||||
if (item is AggregateFolder)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var collectionFolders = _libraryManager.GetCollectionFolders(item, allUserRootChildren);
|
||||
foreach (var folder in allUserRootChildren)
|
||||
{
|
||||
list.Add(folder.Id.ToString("N"));
|
||||
}
|
||||
}
|
||||
|
||||
return list.Distinct(StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates the physical item to user library.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,6 +3,7 @@ using Emby.Server.Implementations.Browser;
|
|||
using MediaBrowser.Controller;
|
||||
using MediaBrowser.Controller.Plugins;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
||||
namespace Emby.Server.Implementations.EntryPoints
|
||||
{
|
||||
|
@ -20,15 +21,13 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
/// </summary>
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StartupWizard" /> class.
|
||||
/// </summary>
|
||||
/// <param name="appHost">The app host.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public StartupWizard(IServerApplicationHost appHost, ILogger logger)
|
||||
private IServerConfigurationManager _config;
|
||||
|
||||
public StartupWizard(IServerApplicationHost appHost, ILogger logger, IServerConfigurationManager config)
|
||||
{
|
||||
_appHost = appHost;
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -36,18 +35,24 @@ namespace Emby.Server.Implementations.EntryPoints
|
|||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
if (!_appHost.CanLaunchWebBrowser)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_appHost.IsFirstRun)
|
||||
{
|
||||
LaunchStartupWizard();
|
||||
BrowserLauncher.OpenDashboardPage("wizardstart.html", _appHost);
|
||||
}
|
||||
}
|
||||
else if (_config.Configuration.IsStartupWizardCompleted && _config.Configuration.AutoRunWebApp)
|
||||
{
|
||||
var options = ((ApplicationHost)_appHost).StartupOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Launches the startup wizard.
|
||||
/// </summary>
|
||||
private void LaunchStartupWizard()
|
||||
{
|
||||
BrowserLauncher.OpenDashboardPage("wizardstart.html", _appHost);
|
||||
if (!options.ContainsOption("-noautorunwebapp"))
|
||||
{
|
||||
BrowserLauncher.OpenDashboardPage("index.html", _appHost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -237,7 +237,7 @@ namespace Emby.Server.Implementations.IO
|
|||
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
||||
void LibraryManager_ItemRemoved(object sender, ItemChangeEventArgs e)
|
||||
{
|
||||
if (e.Item.GetParent() is AggregateFolder)
|
||||
if (e.Parent is AggregateFolder)
|
||||
{
|
||||
StopWatchingPath(e.Item.Path);
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ namespace Emby.Server.Implementations.IO
|
|||
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
|
||||
void LibraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
|
||||
{
|
||||
if (e.Item.GetParent() is AggregateFolder)
|
||||
if (e.Parent is AggregateFolder)
|
||||
{
|
||||
StartWatching(e.Item);
|
||||
}
|
||||
|
@ -320,7 +320,8 @@ namespace Emby.Server.Implementations.IO
|
|||
IncludeSubdirectories = true
|
||||
};
|
||||
|
||||
if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
|
||||
if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows ||
|
||||
_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
|
||||
{
|
||||
newWatcher.InternalBufferSize = 32767;
|
||||
}
|
||||
|
|
|
@ -473,6 +473,11 @@ namespace Emby.Server.Implementations.IO
|
|||
|
||||
public void SetHidden(string path, bool isHidden)
|
||||
{
|
||||
if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_sharpCifsFileSystem.IsEnabledForPath(path))
|
||||
{
|
||||
_sharpCifsFileSystem.SetHidden(path, isHidden);
|
||||
|
@ -498,6 +503,11 @@ namespace Emby.Server.Implementations.IO
|
|||
|
||||
public void SetReadOnly(string path, bool isReadOnly)
|
||||
{
|
||||
if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_sharpCifsFileSystem.IsEnabledForPath(path))
|
||||
{
|
||||
_sharpCifsFileSystem.SetReadOnly(path, isReadOnly);
|
||||
|
@ -523,6 +533,11 @@ namespace Emby.Server.Implementations.IO
|
|||
|
||||
public void SetAttributes(string path, bool isHidden, bool isReadOnly)
|
||||
{
|
||||
if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_sharpCifsFileSystem.IsEnabledForPath(path))
|
||||
{
|
||||
_sharpCifsFileSystem.SetAttributes(path, isHidden, isReadOnly);
|
||||
|
|
|
@ -141,17 +141,6 @@ namespace Emby.Server.Implementations.Library
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore samples
|
||||
var sampleFilename = " " + filename.Replace(".", " ", StringComparison.OrdinalIgnoreCase)
|
||||
.Replace("-", " ", StringComparison.OrdinalIgnoreCase)
|
||||
.Replace("_", " ", StringComparison.OrdinalIgnoreCase)
|
||||
.Replace("!", " ", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (sampleFilename.IndexOf(" sample ", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -443,7 +443,7 @@ namespace Emby.Server.Implementations.Library
|
|||
BaseItem removed;
|
||||
_libraryItemsCache.TryRemove(item.Id, out removed);
|
||||
|
||||
ReportItemRemoved(item);
|
||||
ReportItemRemoved(item, parent);
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetMetadataPaths(BaseItem item, IEnumerable<BaseItem> children)
|
||||
|
@ -1804,7 +1804,7 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <returns>Task.</returns>
|
||||
public void CreateItem(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
CreateItems(new[] { item }, cancellationToken);
|
||||
CreateItems(new[] { item }, item.GetParent(), cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1813,7 +1813,7 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <param name="items">The items.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public void CreateItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
|
||||
public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
|
||||
{
|
||||
var list = items.ToList();
|
||||
|
||||
|
@ -1830,7 +1830,11 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
try
|
||||
{
|
||||
ItemAdded(this, new ItemChangeEventArgs { Item = item });
|
||||
ItemAdded(this, new ItemChangeEventArgs
|
||||
{
|
||||
Item = item,
|
||||
Parent = parent ?? item.GetParent()
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -1878,6 +1882,7 @@ namespace Emby.Server.Implementations.Library
|
|||
ItemUpdated(this, new ItemChangeEventArgs
|
||||
{
|
||||
Item = item,
|
||||
Parent = item.GetParent(),
|
||||
UpdateReason = updateReason
|
||||
});
|
||||
}
|
||||
|
@ -1892,13 +1897,17 @@ namespace Emby.Server.Implementations.Library
|
|||
/// Reports the item removed.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
public void ReportItemRemoved(BaseItem item)
|
||||
public void ReportItemRemoved(BaseItem item, BaseItem parent)
|
||||
{
|
||||
if (ItemRemoved != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
ItemRemoved(this, new ItemChangeEventArgs { Item = item });
|
||||
ItemRemoved(this, new ItemChangeEventArgs
|
||||
{
|
||||
Item = item,
|
||||
Parent = parent
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -125,10 +125,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
if (child.IsDirectory)
|
||||
{
|
||||
leftOver.Add(child);
|
||||
}
|
||||
else if (IsIgnored(child.Name))
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -298,22 +294,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
return item;
|
||||
}
|
||||
|
||||
private bool IsIgnored(string filename)
|
||||
{
|
||||
// Ignore samples
|
||||
var sampleFilename = " " + filename.Replace(".", " ", StringComparison.OrdinalIgnoreCase)
|
||||
.Replace("-", " ", StringComparison.OrdinalIgnoreCase)
|
||||
.Replace("_", " ", StringComparison.OrdinalIgnoreCase)
|
||||
.Replace("!", " ", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (sampleFilename.IndexOf(" sample ", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the initial item values.
|
||||
/// </summary>
|
||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Library;
|
|||
using MediaBrowser.Model.Globalization;
|
||||
using Emby.Naming.Common;
|
||||
using Emby.Naming.TV;
|
||||
using MediaBrowser.Model.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||
{
|
||||
|
@ -21,16 +22,18 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
|||
private readonly ILibraryManager _libraryManager;
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
private readonly ILocalizationManager _localization;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeasonResolver"/> class.
|
||||
/// </summary>
|
||||
/// <param name="config">The config.</param>
|
||||
public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
|
||||
public SeasonResolver(IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization, ILogger logger)
|
||||
{
|
||||
_config = config;
|
||||
_libraryManager = libraryManager;
|
||||
_localization = localization;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -45,20 +48,40 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
|||
var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
|
||||
var series = ((Series)args.Parent);
|
||||
|
||||
var path = args.Path;
|
||||
|
||||
var season = new Season
|
||||
{
|
||||
IndexNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(args.Path, true, true).SeasonNumber,
|
||||
IndexNumber = new SeasonPathParser(namingOptions, new RegexProvider()).Parse(path, true, true).SeasonNumber,
|
||||
SeriesId = series.Id,
|
||||
SeriesName = series.Name
|
||||
};
|
||||
|
||||
if (season.IndexNumber.HasValue)
|
||||
{
|
||||
var resolver = new Emby.Naming.TV.EpisodeResolver(namingOptions);
|
||||
|
||||
var episodeInfo = resolver.Resolve(path, true);
|
||||
|
||||
if (episodeInfo != null)
|
||||
{
|
||||
if (episodeInfo.EpisodeNumber.HasValue && episodeInfo.SeasonNumber.HasValue)
|
||||
{
|
||||
_logger.Info("Found folder underneath series with episode number: {0}. Season {1}. Episode {2}",
|
||||
path,
|
||||
episodeInfo.SeasonNumber.Value,
|
||||
episodeInfo.EpisodeNumber.Value);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var seasonNumber = season.IndexNumber.Value;
|
||||
|
||||
season.Name = seasonNumber == 0 ?
|
||||
args.LibraryOptions.SeasonZeroDisplayName :
|
||||
string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.ToString(UsCulture), args.GetLibraryOptions().PreferredMetadataLanguage);
|
||||
|
||||
}
|
||||
|
||||
return season;
|
||||
|
|
|
@ -191,7 +191,8 @@ namespace Emby.Server.Implementations.Library
|
|||
{
|
||||
ItemFields.AirTime,
|
||||
ItemFields.DateCreated,
|
||||
ItemFields.ChannelInfo
|
||||
ItemFields.ChannelInfo,
|
||||
ItemFields.ParentId
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -218,7 +218,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return builder.ToString();
|
||||
}
|
||||
|
||||
public async Task<User> AuthenticateUser(string username, string password, string hashedPassword, string passwordMd5, string remoteEndPoint)
|
||||
public async Task<User> AuthenticateUser(string username, string password, string hashedPassword, string passwordMd5, string remoteEndPoint, bool isUserSession)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
|
@ -288,8 +288,11 @@ namespace Emby.Server.Implementations.Library
|
|||
// Update LastActivityDate and LastLoginDate, then save
|
||||
if (success)
|
||||
{
|
||||
user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
|
||||
UpdateUser(user);
|
||||
if (isUserSession)
|
||||
{
|
||||
user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
|
||||
UpdateUser(user);
|
||||
}
|
||||
UpdateInvalidLoginAttemptCount(user, 0);
|
||||
}
|
||||
else
|
||||
|
@ -812,7 +815,7 @@ namespace Emby.Server.Implementations.Library
|
|||
|
||||
var text = new StringBuilder();
|
||||
|
||||
var localAddress = _appHost.GetLocalApiUrl().Result ?? string.Empty;
|
||||
var localAddress = _appHost.GetLocalApiUrl(CancellationToken.None).Result ?? string.Empty;
|
||||
|
||||
text.AppendLine("Use your web browser to visit:");
|
||||
text.AppendLine(string.Empty);
|
||||
|
|
|
@ -1512,6 +1512,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
}
|
||||
}
|
||||
|
||||
DeleteFileIfEmpty(recordPath);
|
||||
|
||||
TriggerRefresh(recordPath);
|
||||
_libraryMonitor.ReportFileSystemChangeComplete(recordPath, false);
|
||||
|
||||
|
@ -1542,6 +1544,23 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
}
|
||||
}
|
||||
|
||||
private void DeleteFileIfEmpty(string path)
|
||||
{
|
||||
var file = _fileSystem.GetFileInfo(path);
|
||||
|
||||
if (file.Exists && file.Length == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileSystem.DeleteFile(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Error deleting 0-byte failed recording file {0}", ex, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerRefresh(string path)
|
||||
{
|
||||
_logger.Info("Triggering refresh on {0}", path);
|
||||
|
@ -1897,7 +1916,15 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
imageSaveFilenameWithoutExtension = "logo";
|
||||
break;
|
||||
case ImageType.Thumb:
|
||||
imageSaveFilenameWithoutExtension = "landscape";
|
||||
if (program.IsSeries)
|
||||
{
|
||||
imageSaveFilenameWithoutExtension = Path.GetFileNameWithoutExtension(recordingPath) + "-thumb";
|
||||
}
|
||||
else
|
||||
{
|
||||
imageSaveFilenameWithoutExtension = "landscape";
|
||||
}
|
||||
|
||||
break;
|
||||
case ImageType.Backdrop:
|
||||
imageSaveFilenameWithoutExtension = "fanart";
|
||||
|
@ -1921,9 +1948,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
|
|||
|
||||
private async Task SaveRecordingImages(string recordingPath, LiveTvProgram program)
|
||||
{
|
||||
var image = program.GetImageInfo(ImageType.Primary, 0);
|
||||
var image = program.IsSeries ?
|
||||
(program.GetImageInfo(ImageType.Thumb, 0) ?? program.GetImageInfo(ImageType.Primary, 0)) :
|
||||
(program.GetImageInfo(ImageType.Primary, 0) ?? program.GetImageInfo(ImageType.Thumb, 0));
|
||||
|
||||
if (image != null && program.IsMovie)
|
||||
if (image != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -105,31 +105,64 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
|
||||
if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
using (var stream = _fileSystem.OpenRead(file))
|
||||
try
|
||||
{
|
||||
var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
|
||||
_fileSystem.CreateDirectory(tempFolder);
|
||||
var tempFolder = ExtractGz(file);
|
||||
return FindXmlFile(tempFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//_logger.ErrorException("Error extracting from gz file {0}", ex, file);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_zipClient.ExtractAllFromGz(stream, tempFolder, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If the extraction fails just return the original file, it could be a gz
|
||||
return file;
|
||||
}
|
||||
|
||||
return _fileSystem.GetFiles(tempFolder, true)
|
||||
.Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
|
||||
.Select(i => i.FullName)
|
||||
.FirstOrDefault();
|
||||
try
|
||||
{
|
||||
var tempFolder = ExtractFirstFileFromGz(file);
|
||||
return FindXmlFile(tempFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//_logger.ErrorException("Error extracting from zip file {0}", ex, file);
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
private string ExtractFirstFileFromGz(string file)
|
||||
{
|
||||
using (var stream = _fileSystem.OpenRead(file))
|
||||
{
|
||||
var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
|
||||
_fileSystem.CreateDirectory(tempFolder);
|
||||
|
||||
_zipClient.ExtractFirstFileFromGz(stream, tempFolder, "data.xml");
|
||||
|
||||
return tempFolder;
|
||||
}
|
||||
}
|
||||
|
||||
private string ExtractGz(string file)
|
||||
{
|
||||
using (var stream = _fileSystem.OpenRead(file))
|
||||
{
|
||||
var tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString());
|
||||
_fileSystem.CreateDirectory(tempFolder);
|
||||
|
||||
_zipClient.ExtractAllFromGz(stream, tempFolder, true);
|
||||
|
||||
return tempFolder;
|
||||
}
|
||||
}
|
||||
|
||||
private string FindXmlFile(string directory)
|
||||
{
|
||||
return _fileSystem.GetFiles(directory, true)
|
||||
.Where(i => string.Equals(i.Extension, ".xml", StringComparison.OrdinalIgnoreCase))
|
||||
.Select(i => i.FullName)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(channelId))
|
||||
|
@ -149,6 +182,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
_logger.Debug("Getting xmltv programs for channel {0}", channelId);
|
||||
|
||||
var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
|
||||
_logger.Debug("Opening XmlTvReader for {0}", path);
|
||||
var reader = new XmlTvReader(path, GetLanguage(info));
|
||||
|
||||
var results = reader.GetProgrammes(channelId, startDateUtc, endDateUtc, cancellationToken);
|
||||
|
@ -251,6 +285,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
{
|
||||
// In theory this should never be called because there is always only one lineup
|
||||
var path = await GetXml(info.Path, CancellationToken.None).ConfigureAwait(false);
|
||||
_logger.Debug("Opening XmlTvReader for {0}", path);
|
||||
var reader = new XmlTvReader(path, GetLanguage(info));
|
||||
var results = reader.GetChannels();
|
||||
|
||||
|
@ -262,6 +297,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
{
|
||||
// In theory this should never be called because there is always only one lineup
|
||||
var path = await GetXml(info.Path, cancellationToken).ConfigureAwait(false);
|
||||
_logger.Debug("Opening XmlTvReader for {0}", path);
|
||||
var reader = new XmlTvReader(path, GetLanguage(info));
|
||||
var results = reader.GetChannels();
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
public void AddParts(IEnumerable<ILiveTvService> services, IEnumerable<ITunerHost> tunerHosts, IEnumerable<IListingsProvider> listingProviders)
|
||||
{
|
||||
_services = services.ToArray();
|
||||
_tunerHosts.AddRange(tunerHosts);
|
||||
_tunerHosts.AddRange(tunerHosts.Where(i => i.IsSupported));
|
||||
_listingProviders.AddRange(listingProviders);
|
||||
|
||||
foreach (var service in _services)
|
||||
|
@ -947,6 +947,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
IsKids = query.IsKids,
|
||||
IsNews = query.IsNews,
|
||||
Genres = query.Genres,
|
||||
GenreIds = query.GenreIds,
|
||||
StartIndex = query.StartIndex,
|
||||
Limit = query.Limit,
|
||||
OrderBy = query.OrderBy,
|
||||
|
@ -1020,7 +1021,8 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
EnableTotalRecordCount = query.EnableTotalRecordCount,
|
||||
OrderBy = new[] { new Tuple<string, SortOrder>(ItemSortBy.StartDate, SortOrder.Ascending) },
|
||||
TopParentIds = new[] { topFolder.Id.ToString("N") },
|
||||
DtoOptions = options
|
||||
DtoOptions = options,
|
||||
GenreIds = query.GenreIds
|
||||
};
|
||||
|
||||
if (query.Limit.HasValue)
|
||||
|
@ -1421,7 +1423,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
|
||||
if (newPrograms.Count > 0)
|
||||
{
|
||||
_libraryManager.CreateItems(newPrograms, cancellationToken);
|
||||
_libraryManager.CreateItems(newPrograms, null, cancellationToken);
|
||||
}
|
||||
|
||||
// TODO: Do this in bulk
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||
}
|
||||
|
||||
var list = sources.ToList();
|
||||
var serverUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
|
||||
var serverUrl = await _appHost.GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var source in list)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
FileSystem = fileSystem;
|
||||
}
|
||||
|
||||
public virtual bool IsSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken);
|
||||
public abstract string Type { get; }
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ using MediaBrowser.Controller.Configuration;
|
|||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.System;
|
||||
using System.IO;
|
||||
|
||||
namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||
{
|
||||
|
@ -75,6 +76,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
return Task.FromResult(list);
|
||||
}
|
||||
|
||||
private string[] _disallowedSharedStreamExtensions = new string[]
|
||||
{
|
||||
".mkv",
|
||||
".mp4",
|
||||
".m3u8",
|
||||
".mpd"
|
||||
};
|
||||
|
||||
protected override async Task<ILiveStream> GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken)
|
||||
{
|
||||
var tunerCount = info.TunerCount;
|
||||
|
@ -95,7 +104,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
|
||||
if (mediaSource.Protocol == MediaProtocol.Http && !mediaSource.RequiresLooping)
|
||||
{
|
||||
return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment);
|
||||
var extension = Path.GetExtension(mediaSource.Path) ?? string.Empty;
|
||||
|
||||
if (!_disallowedSharedStreamExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return new SharedHttpStream(mediaSource, info, streamId, FileSystem, _httpClient, Logger, Config.ApplicationPaths, _appHost, _environment);
|
||||
}
|
||||
}
|
||||
|
||||
return new LiveStream(mediaSource, info, _environment, FileSystem, Logger, Config.ApplicationPaths);
|
||||
|
@ -152,6 +166,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
isRemote = !_networkManager.IsInLocalNetwork(uri.Host);
|
||||
}
|
||||
|
||||
var supportsDirectPlay = !info.EnableStreamLooping && info.TunerCount == 0;
|
||||
|
||||
var mediaSource = new MediaSourceInfo
|
||||
{
|
||||
Path = path,
|
||||
|
@ -183,7 +199,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
IsInfiniteStream = true,
|
||||
IsRemote = isRemote,
|
||||
|
||||
IgnoreDts = true
|
||||
IgnoreDts = true,
|
||||
SupportsDirectPlay = supportsDirectPlay
|
||||
};
|
||||
|
||||
mediaSource.InferTotalBitrate();
|
||||
|
|
|
@ -71,7 +71,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
}
|
||||
else if (contentType.IndexOf("mp4", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
contentType.IndexOf("dash", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
contentType.IndexOf("mpegURL", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
contentType.IndexOf("mpegURL", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||
contentType.IndexOf("text/", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
requiresRemux = true;
|
||||
}
|
||||
|
@ -88,6 +89,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
SetTempFilePath(extension);
|
||||
|
||||
var taskCompletionSource = new TaskCompletionSource<bool>();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
|
||||
|
||||
//OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
|
@ -97,11 +101,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
OpenedMediaSource.Path = _appHost.GetLocalApiUrl("127.0.0.1") + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
|
||||
OpenedMediaSource.Protocol = MediaProtocol.Http;
|
||||
|
||||
if (OpenedMediaSource.SupportsProbing)
|
||||
{
|
||||
await Task.Delay(3000).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
//OpenedMediaSource.Path = TempFilePath;
|
||||
//OpenedMediaSource.Protocol = MediaProtocol.File;
|
||||
|
||||
|
@ -111,6 +110,20 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
//OpenedMediaSource.SupportsDirectStream = true;
|
||||
//OpenedMediaSource.SupportsTranscoding = true;
|
||||
await taskCompletionSource.Task.ConfigureAwait(false);
|
||||
|
||||
if (OpenedMediaSource.SupportsProbing)
|
||||
{
|
||||
var elapsed = (DateTime.UtcNow - now).TotalMilliseconds;
|
||||
|
||||
var delay = Convert.ToInt32(3000 - elapsed);
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
Logger.Info("Delaying shared stream by {0}ms to allow the buffer to build.", delay);
|
||||
|
||||
await Task.Delay(delay).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CloseInternal()
|
||||
|
|
|
@ -1,74 +1,74 @@
|
|||
{
|
||||
"Latest": "Darreres",
|
||||
"ValueSpecialEpisodeName": "Especial - {0}",
|
||||
"Inherit": "Inherit",
|
||||
"Books": "Books",
|
||||
"Music": "Music",
|
||||
"Games": "Games",
|
||||
"Photos": "Photos",
|
||||
"MixedContent": "Mixed content",
|
||||
"MusicVideos": "Music videos",
|
||||
"HomeVideos": "Home videos",
|
||||
"Playlists": "Playlists",
|
||||
"HeaderRecordingGroups": "Recording Groups",
|
||||
"Inherit": "Heretat",
|
||||
"Books": "Llibres",
|
||||
"Music": "M\u00fasica",
|
||||
"Games": "Jocs",
|
||||
"Photos": "Fotos",
|
||||
"MixedContent": "Contingut mesclat",
|
||||
"MusicVideos": "V\u00eddeos musicals",
|
||||
"HomeVideos": "V\u00eddeos dom\u00e8stics",
|
||||
"Playlists": "Llistes de reproducci\u00f3",
|
||||
"HeaderRecordingGroups": "Grups d'Enregistrament",
|
||||
"HeaderContinueWatching": "Continua Veient",
|
||||
"HeaderFavoriteArtists": "Favorite Artists",
|
||||
"HeaderFavoriteSongs": "Favorite Songs",
|
||||
"HeaderFavoriteArtists": "Artistes Preferits",
|
||||
"HeaderFavoriteSongs": "Can\u00e7ons Preferides",
|
||||
"HeaderAlbumArtists": "Album Artists",
|
||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
||||
"HeaderFavoriteEpisodes": "Favorite Episodes",
|
||||
"HeaderFavoriteAlbums": "\u00c0lbums Preferits",
|
||||
"HeaderFavoriteEpisodes": "Episodis Preferits",
|
||||
"HeaderFavoriteShows": "Programes Preferits",
|
||||
"HeaderNextUp": "A continuaci\u00f3",
|
||||
"Favorites": "Favorites",
|
||||
"Collections": "Collections",
|
||||
"Channels": "Channels",
|
||||
"Movies": "Movies",
|
||||
"Albums": "Albums",
|
||||
"Artists": "Artists",
|
||||
"Folders": "Folders",
|
||||
"Songs": "Songs",
|
||||
"TvShows": "TV Shows",
|
||||
"Shows": "Shows",
|
||||
"Favorites": "Preferits",
|
||||
"Collections": "Col\u00b7leccions",
|
||||
"Channels": "Canals",
|
||||
"Movies": "Pel\u00b7l\u00edcules",
|
||||
"Albums": "\u00c0lbums",
|
||||
"Artists": "Artistes",
|
||||
"Folders": "Directoris",
|
||||
"Songs": "Can\u00e7ons",
|
||||
"TvShows": "Espectacles de TV",
|
||||
"Shows": "Espectacles",
|
||||
"Genres": "G\u00e8neres",
|
||||
"NameSeasonNumber": "Season {0}",
|
||||
"AppDeviceValues": "App: {0}, Device: {1}",
|
||||
"UserDownloadingItemWithValues": "{0} is downloading {1}",
|
||||
"HeaderLiveTV": "Live TV",
|
||||
"ChapterNameValue": "Chapter {0}",
|
||||
"ScheduledTaskFailedWithName": "{0} failed",
|
||||
"LabelRunningTimeValue": "Running time: {0}",
|
||||
"ScheduledTaskStartedWithName": "{0} started",
|
||||
"VersionNumber": "Version {0}",
|
||||
"PluginInstalledWithName": "{0} was installed",
|
||||
"StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly.",
|
||||
"PluginUpdatedWithName": "{0} was updated",
|
||||
"PluginUninstalledWithName": "{0} was uninstalled",
|
||||
"ItemAddedWithName": "{0} was added to the library",
|
||||
"ItemRemovedWithName": "{0} was removed from the library",
|
||||
"LabelIpAddressValue": "Ip address: {0}",
|
||||
"DeviceOnlineWithName": "{0} is connected",
|
||||
"UserOnlineFromDevice": "{0} is online from {1}",
|
||||
"ProviderValue": "Provider: {0}",
|
||||
"SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
|
||||
"UserCreatedWithName": "User {0} has been created",
|
||||
"UserPasswordChangedWithName": "Password has been changed for user {0}",
|
||||
"UserDeletedWithName": "User {0} has been deleted",
|
||||
"UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
|
||||
"MessageServerConfigurationUpdated": "Server configuration has been updated",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
|
||||
"MessageApplicationUpdated": "Emby Server has been updated",
|
||||
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
|
||||
"AuthenticationSucceededWithUserName": "{0} successfully authenticated",
|
||||
"UserOfflineFromDevice": "{0} has disconnected from {1}",
|
||||
"DeviceOfflineWithName": "{0} has disconnected",
|
||||
"UserStartedPlayingItemWithValues": "{0} has started playing {1}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
|
||||
"NotificationOptionPluginError": "Plugin failure",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Application update available",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Application update installed",
|
||||
"NotificationOptionPluginUpdateInstalled": "Plugin update installed",
|
||||
"NotificationOptionPluginInstalled": "Plugin installed",
|
||||
"NotificationOptionPluginUninstalled": "Plugin uninstalled",
|
||||
"NameSeasonNumber": "Temporada {0}",
|
||||
"AppDeviceValues": "App: {0}, Dispositiu: {1}",
|
||||
"UserDownloadingItemWithValues": "{0} est\u00e0 descarregant {1}",
|
||||
"HeaderLiveTV": "TV en Directe",
|
||||
"ChapterNameValue": "Episodi {0}",
|
||||
"ScheduledTaskFailedWithName": "{0} ha fallat",
|
||||
"LabelRunningTimeValue": "Temps en marxa: {0}",
|
||||
"ScheduledTaskStartedWithName": "{0} iniciat",
|
||||
"VersionNumber": "Versi\u00f3 {0}",
|
||||
"PluginInstalledWithName": "{0} ha estat instal\u00b7lat",
|
||||
"StartupEmbyServerIsLoading": "El Servidor d'Emby està carregant. Si et plau, prova de nou en breus.",
|
||||
"PluginUpdatedWithName": "{0} ha estat actualitzat",
|
||||
"PluginUninstalledWithName": "{0} ha estat desinstal\u00b7lat",
|
||||
"ItemAddedWithName": "{0} afegit a la biblioteca",
|
||||
"ItemRemovedWithName": "{0} eliminat de la biblioteca",
|
||||
"LabelIpAddressValue": "Adre\u00e7a IP: {0}",
|
||||
"DeviceOnlineWithName": "{0} est\u00e0 connectat",
|
||||
"UserOnlineFromDevice": "{0} est\u00e0 connectat des de {1}",
|
||||
"ProviderValue": "Prove\u00efdor: {0}",
|
||||
"SubtitlesDownloadedForItem": "Subt\u00edtols descarregats per a {0}",
|
||||
"UserCreatedWithName": "S'ha creat l'usuari {0}",
|
||||
"UserPasswordChangedWithName": "La contrasenya ha estat canviada per a l'usuari {0}",
|
||||
"UserDeletedWithName": "L'usuari {0} ha estat eliminat",
|
||||
"UserConfigurationUpdatedWithName": "La configuraci\u00f3 d'usuari ha estat actualitzada per a {0}",
|
||||
"MessageServerConfigurationUpdated": "S'ha actualitzat la configuraci\u00f3 del servidor",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "La secci\u00f3 de configuraci\u00f3 {0} ha estat actualitzada",
|
||||
"MessageApplicationUpdated": "El Servidor d'Emby ha estat actualitzat",
|
||||
"FailedLoginAttemptWithUserName": "Intent de connexi\u00f3 fallit des de {0}",
|
||||
"AuthenticationSucceededWithUserName": "{0} s'ha autenticat correctament",
|
||||
"UserOfflineFromDevice": "{0} s'ha desconnectat de {1}",
|
||||
"DeviceOfflineWithName": "{0} s'ha desconnectat",
|
||||
"UserStartedPlayingItemWithValues": "{0} ha comen\u00e7at a reproduir {1}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} ha parat de reproduir {1}",
|
||||
"NotificationOptionPluginError": "Un component ha fallat",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Actualitzaci\u00f3 d'aplicaci\u00f3 disponible",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Actualitzaci\u00f3 d'aplicaci\u00f3 instal\u00b7lada",
|
||||
"NotificationOptionPluginUpdateInstalled": "Actualitzaci\u00f3 de complement instal\u00b7lada",
|
||||
"NotificationOptionPluginInstalled": "Complement instal\u00b7lat",
|
||||
"NotificationOptionPluginUninstalled": "Complement desinstal\u00b7lat",
|
||||
"NotificationOptionVideoPlayback": "Video playback started",
|
||||
"NotificationOptionAudioPlayback": "Audio playback started",
|
||||
"NotificationOptionGamePlayback": "Game playback started",
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"Games": "Spiele",
|
||||
"Photos": "Fotos",
|
||||
"MixedContent": "Gemischte Inhalte",
|
||||
"MusicVideos": "Musik-Videos",
|
||||
"MusicVideos": "Musikvideos",
|
||||
"HomeVideos": "Heimvideos",
|
||||
"Playlists": "Wiedergabelisten",
|
||||
"HeaderRecordingGroups": "Aufnahme-Gruppen",
|
||||
|
@ -27,7 +27,7 @@
|
|||
"Artists": "Interpreten",
|
||||
"Folders": "Verzeichnisse",
|
||||
"Songs": "Songs",
|
||||
"TvShows": "TV Shows",
|
||||
"TvShows": "TV Sendungen",
|
||||
"Shows": "Serien",
|
||||
"Genres": "Genres",
|
||||
"NameSeasonNumber": "Staffel {0}",
|
||||
|
|
91
Emby.Server.Implementations/Localization/Core/el.json
Normal file
91
Emby.Server.Implementations/Localization/Core/el.json
Normal file
|
@ -0,0 +1,91 @@
|
|||
{
|
||||
"Latest": "\u03a4\u03b5\u03bb\u03b5\u03c5\u03c4\u03b1\u03af\u03b1",
|
||||
"ValueSpecialEpisodeName": "\u0395\u03b9\u03b4\u03b9\u03ba\u03ac - {0} ",
|
||||
"Inherit": "Inherit",
|
||||
"Books": "\u0392\u03b9\u03b2\u03bb\u03af\u03b1",
|
||||
"Music": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae",
|
||||
"Games": "\u03a0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9\u03b1",
|
||||
"Photos": "\u03a6\u03c9\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03af\u03b5\u03c2",
|
||||
"MixedContent": "\u0391\u03bd\u03ac\u03bc\u03b5\u03b9\u03ba\u03c4\u03bf \u03a0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf",
|
||||
"MusicVideos": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u03b2\u03af\u03bd\u03c4\u03b5\u03bf",
|
||||
"HomeVideos": "\u03a0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ac \u0392\u03af\u03bd\u03c4\u03b5\u03bf",
|
||||
"Playlists": "\u039b\u03af\u03c3\u03c4\u03b5\u03c2 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2",
|
||||
"HeaderRecordingGroups": "\u0393\u03ba\u03c1\u03bf\u03c5\u03c0 \u0395\u03b3\u03b3\u03c1\u03b1\u03c6\u03ce\u03bd",
|
||||
"HeaderContinueWatching": "\u03a3\u03c5\u03bd\u03b5\u03c7\u03af\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c0\u03b1\u03c1\u03b1\u03ba\u03bf\u03bb\u03bf\u03cd\u03b8\u03b7\u03c3\u03b7",
|
||||
"HeaderFavoriteArtists": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03bf\u03b9 \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
|
||||
"HeaderFavoriteSongs": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
|
||||
"HeaderAlbumArtists": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc \u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03b5\u03c7\u03bd\u03ce\u03bd",
|
||||
"HeaderFavoriteAlbums": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
|
||||
"HeaderFavoriteEpisodes": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1 \u03b5\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
|
||||
"HeaderFavoriteShows": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b5\u03c2 \u03a3\u03b5\u03b9\u03c1\u03ad\u03c2",
|
||||
"HeaderNextUp": "\u0395\u03c0\u03cc\u03bc\u03b5\u03bd\u03bf",
|
||||
"Favorites": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1",
|
||||
"Collections": "\u03a3\u03c5\u03bb\u03bb\u03bf\u03b3\u03ad\u03c2",
|
||||
"Channels": "\u039a\u03b1\u03bd\u03ac\u03bb\u03b9\u03b1",
|
||||
"Movies": "\u03a4\u03b1\u03b9\u03bd\u03af\u03b5\u03c2",
|
||||
"Albums": "\u0386\u03bb\u03bc\u03c0\u03bf\u03c5\u03bc",
|
||||
"Artists": "\u039a\u03b1\u03bb\u03bb\u03b9\u03c4\u03ad\u03c7\u03bd\u03b5\u03c2",
|
||||
"Folders": "\u03a6\u03ac\u03ba\u03b5\u03bb\u03bf\u03b9",
|
||||
"Songs": "\u03a4\u03c1\u03b1\u03b3\u03bf\u03cd\u03b4\u03b9\u03b1",
|
||||
"TvShows": "\u03a4\u03b7\u03bb\u03b5\u03bf\u03c0\u03c4\u03b9\u03ba\u03ac \u03c0\u03c1\u03bf\u03b3\u03c1\u03ac\u03bc\u03bc\u03b1\u03c4\u03b1",
|
||||
"Shows": "\u03a3\u03b5\u03b9\u03c1\u03ad\u03c2",
|
||||
"Genres": "\u0395\u03af\u03b4\u03b7",
|
||||
"NameSeasonNumber": "\u039a\u03cd\u03ba\u03bb\u03bf\u03c2 {0}",
|
||||
"AppDeviceValues": "\u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae: {0}, \u03a3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae: {1}",
|
||||
"UserDownloadingItemWithValues": "{0} \u03ba\u03b1\u03c4\u03b5\u03b2\u03ac\u03b6\u03b5\u03b9 {1}",
|
||||
"HeaderLiveTV": "\u0396\u03c9\u03bd\u03c4\u03b1\u03bd\u03ae \u03a4\u03b7\u03bb\u03b5\u03cc\u03c1\u03b1\u03c3\u03b7",
|
||||
"ChapterNameValue": "\u039a\u03b5\u03c6\u03ac\u03bb\u03b1\u03b9\u03bf {0}",
|
||||
"ScheduledTaskFailedWithName": "{0} \u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1",
|
||||
"LabelRunningTimeValue": "\u0394\u03b9\u03ac\u03c1\u03ba\u03b5\u03b9\u03b1: {0}",
|
||||
"ScheduledTaskStartedWithName": "{0} \u03ad\u03bd\u03b1\u03c1\u03be\u03b7",
|
||||
"VersionNumber": "\u0388\u03ba\u03b4\u03bf\u03c3\u03b7 {0}",
|
||||
"PluginInstalledWithName": "{0} \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ae\u03b8\u03b7\u03ba\u03b5",
|
||||
"StartupEmbyServerIsLoading": "\u039f \u03a3\u03ad\u03c1\u03b2\u03b5\u03c1 \u03c6\u03bf\u03c1\u03c4\u03ce\u03bd\u03b5\u03b9. \u03a0\u03b1\u03c1\u03b1\u03ba\u03b1\u03bb\u03ce \u03b4\u03bf\u03ba\u03b9\u03bc\u03ac\u03c3\u03c4\u03b5 \u03c3\u03b5 \u03bb\u03af\u03b3\u03bf",
|
||||
"PluginUpdatedWithName": "{0} \u03ad\u03c7\u03b5\u03b9 \u03b1\u03bd\u03b1\u03b2\u03b1\u03b8\u03bc\u03b9\u03c3\u03c4\u03b5\u03af",
|
||||
"PluginUninstalledWithName": "{0} \u03ad\u03c7\u03b5\u03b9 \u03b1\u03c0\u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03b1\u03b8\u03b5\u03af",
|
||||
"ItemAddedWithName": "{0} \u03c0\u03c1\u03bf\u03c3\u03c4\u03ad\u03b8\u03b7\u03ba\u03b5 \u03c3\u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7",
|
||||
"ItemRemovedWithName": "{0} \u03b4\u03b9\u03b1\u03b3\u03c1\u03ac\u03c6\u03b7\u03ba\u03b5 \u03b1\u03c0\u03cc \u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7",
|
||||
"LabelIpAddressValue": "\u0394\u03b9\u03b5\u03cd\u03b8\u03c5\u03bd\u03c3\u03b7 IP: {0}",
|
||||
"DeviceOnlineWithName": "{0} \u03c3\u03c5\u03bd\u03b4\u03ad\u03b8\u03b7\u03ba\u03b5",
|
||||
"UserOnlineFromDevice": "{0} \u03b5\u03af\u03bd\u03b1\u03b9 \u03c3\u03c5\u03bd\u03b4\u03b5\u03b4\u03b5\u03bc\u03ad\u03bd\u03bf\u03c2 \u03b1\u03c0\u03bf {1}",
|
||||
"ProviderValue": "\u03a0\u03ac\u03c1\u03bf\u03c7\u03bf\u03c2: {0}",
|
||||
"SubtitlesDownloadedForItem": "\u03a5\u03c0\u03cc\u03c4\u03b9\u03c4\u03bb\u03bf\u03b9 \u03bb\u03ae\u03c6\u03b8\u03b7\u03ba\u03b1\u03bd \u03b1\u03c0\u03cc {0}",
|
||||
"UserCreatedWithName": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03b8\u03b7\u03ba\u03b5 \u03bf \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 {0}",
|
||||
"UserPasswordChangedWithName": "\u039f \u03ba\u03c9\u03b4\u03b9\u03ba\u03cc\u03c2 \u03c4\u03bf\u03c5 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7 {0} \u03b1\u03bb\u03bb\u03ac\u03c7\u03b8\u03b7\u03ba\u03b5",
|
||||
"UserDeletedWithName": "\u039f \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 {0} \u03b4\u03b9\u03b5\u03b3\u03c1\u03ac\u03c6\u03b5\u03b9",
|
||||
"UserConfigurationUpdatedWithName": "\u039f\u03b9 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03c4\u03bf\u03c5 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7 {0} \u03ad\u03c7\u03bf\u03c5\u03bd \u03b1\u03bb\u03bb\u03ac\u03be\u03b5\u03b9",
|
||||
"MessageServerConfigurationUpdated": "Server configuration has been updated",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "\u039f\u03b9 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03c4\u03bf\u03bc\u03ad\u03b1 \u03c4\u03bf\u03c5 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae {0} \u03ad\u03c7\u03bf\u03c5\u03bd \u03b1\u03bb\u03bb\u03ac\u03be\u03b5\u03b9",
|
||||
"MessageApplicationUpdated": "\u039f \u03a3\u03ad\u03c1\u03b2\u03b5\u03c1 \u03ad\u03c7\u03b5\u03b9 \u03b1\u03bd\u03b1\u03b2\u03b1\u03b8\u03bc\u03b9\u03c3\u03c4\u03b5\u03af",
|
||||
"FailedLoginAttemptWithUserName": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03c0\u03ac\u03b8\u03b5\u03b9\u03b1 \u03b5\u03b9\u03c3\u03cc\u03b4\u03bf\u03c5 \u03b1\u03c0\u03cc {0}",
|
||||
"AuthenticationSucceededWithUserName": "{0} \u03b5\u03c0\u03b9\u03c4\u03c5\u03c7\u03b5\u03af\u03c2 \u03c3\u03cd\u03bd\u03b4\u03b5\u03c3\u03b7",
|
||||
"UserOfflineFromDevice": "{0} \u03b1\u03c0\u03bf\u03c3\u03c5\u03bd\u03b4\u03ad\u03b8\u03b7\u03ba\u03b5 \u03b1\u03c0\u03cc {1}",
|
||||
"DeviceOfflineWithName": "{0} \u03b1\u03c0\u03bf\u03c3\u03c5\u03bd\u03b4\u03ad\u03b8\u03b7\u03ba\u03b5",
|
||||
"UserStartedPlayingItemWithValues": "{0} \u03be\u03b5\u03ba\u03af\u03bd\u03b7\u03c3\u03b5 \u03bd\u03b1 \u03c0\u03b1\u03af\u03b6\u03b5\u03b9 {1}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} \u03c3\u03c4\u03b1\u03bc\u03ac\u03c4\u03b7\u03c3\u03b5 \u03bd\u03b1 \u03c0\u03b1\u03af\u03b6\u03b5\u03b9 {1}",
|
||||
"NotificationOptionPluginError": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c0\u03c1\u03bf\u03c3\u03b8\u03ad\u03c4\u03bf\u03c5",
|
||||
"NotificationOptionApplicationUpdateAvailable": "\u03a5\u03c0\u03ac\u03c1\u03c7\u03b5\u03b9 \u03b1\u03bd\u03b1\u03b2\u03ac\u03b8\u03bc\u03b9\u03c3\u03b7",
|
||||
"NotificationOptionApplicationUpdateInstalled": "\u0397 \u03b1\u03bd\u03b1\u03b2\u03ac\u03b8\u03bc\u03b9\u03c3\u03b7 \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5",
|
||||
"NotificationOptionPluginUpdateInstalled": "\u0397 \u03b1\u03bd\u03b1\u03b2\u03ac\u03b8\u03bc\u03b9\u03c3\u03b7 \u03c4\u03bf\u03c5 plugin \u03bf\u03bb\u03bf\u03ba\u03bb\u03b7\u03c1\u03ce\u03b8\u03b7\u03ba\u03b5",
|
||||
"NotificationOptionPluginInstalled": "\u03a4\u03bf plugin \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ac\u03b8\u03b7\u03ba\u03b5",
|
||||
"NotificationOptionPluginUninstalled": "\u03a4\u03bf plugin \u03b1\u03c0\u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ac\u03b8\u03b7\u03ba\u03b5",
|
||||
"NotificationOptionVideoPlayback": "\u03a4\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c0\u03c1\u03bf\u03b2\u03ac\u03bb\u03bb\u03b5\u03c4\u03b1\u03b9",
|
||||
"NotificationOptionAudioPlayback": "\u0397 \u03bc\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae \u03c0\u03b1\u03af\u03b6\u03b5\u03b9",
|
||||
"NotificationOptionGamePlayback": "\u03a4\u03bf \u03c0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9 \u03be\u03b5\u03ba\u03af\u03bd\u03b7\u03c3\u03b5",
|
||||
"NotificationOptionVideoPlaybackStopped": "\u03a4\u03bf \u03b2\u03af\u03bd\u03c4\u03b5\u03bf \u03c3\u03c4\u03b1\u03bc\u03ac\u03c4\u03b7\u03c3\u03b5",
|
||||
"NotificationOptionAudioPlaybackStopped": "\u0397 \u03bc\u03bf\u03c5\u03c3\u03b9\u03ba\u03ae \u03c3\u03c4\u03b1\u03bc\u03ac\u03c4\u03b7\u03c3\u03b5",
|
||||
"NotificationOptionGamePlaybackStopped": "\u03a4\u03bf \u03c0\u03b1\u03b9\u03c7\u03bd\u03af\u03b4\u03b9 \u03c3\u03c4\u03b1\u03bc\u03ac\u03c4\u03b7\u03c3\u03b5",
|
||||
"NotificationOptionTaskFailed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03c0\u03c1\u03bf\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1\u03c4\u03b9\u03c3\u03bc\u03ad\u03bd\u03b7\u03c2 \u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1\u03c2",
|
||||
"NotificationOptionInstallationFailed": "\u0391\u03c0\u03bf\u03c4\u03c5\u03c7\u03af\u03b1 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7\u03c2",
|
||||
"NotificationOptionNewLibraryContent": "\u03a0\u03c1\u03bf\u03c3\u03c4\u03ad\u03b8\u03b7\u03ba\u03b5 \u03bd\u03ad\u03bf \u03c0\u03b5\u03c1\u03b9\u03b5\u03c7\u03cc\u03bc\u03b5\u03bd\u03bf",
|
||||
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
|
||||
"NotificationOptionUserLockedOut": "\u039f \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 \u03b1\u03c0\u03bf\u03ba\u03bb\u03b5\u03af\u03c3\u03c4\u03b7\u03ba\u03b5",
|
||||
"NotificationOptionServerRestartRequired": "\u0391\u03c0\u03b1\u03b9\u03c4\u03b5\u03af\u03c4\u03b1\u03b9 \u03b5\u03c0\u03b1\u03bd\u03b5\u03ba\u03ba\u03af\u03bd\u03b7\u03c3\u03b7 \u03c4\u03bf\u03c5 \u03b4\u03b9\u03b1\u03ba\u03bf\u03bc\u03b9\u03c3\u03c4\u03ae",
|
||||
"UserLockedOutWithName": "\u039f \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2 {0} \u03b1\u03c0\u03bf\u03ba\u03bb\u03b5\u03af\u03c3\u03c4\u03b7\u03ba\u03b5",
|
||||
"SubtitleDownloadFailureForItem": "\u0391\u03b4\u03c5\u03bd\u03b1\u03bc\u03af\u03b1 \u03bb\u03ae\u03c8\u03b7\u03c2 \u03c5\u03c0\u03bf\u03c4\u03af\u03c4\u03bb\u03c9\u03bd \u03b1\u03c0\u03cc {0}",
|
||||
"Sync": "\u03a3\u03c5\u03b3\u03c7\u03c1\u03bf\u03bd\u03b9\u03c3\u03bc\u03cc\u03c2",
|
||||
"User": "\u03a7\u03c1\u03ae\u03c3\u03c4\u03b7\u03c2",
|
||||
"System": "\u03a3\u03cd\u03c3\u03c4\u03b7\u03bc\u03b1",
|
||||
"Application": "\u0395\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae",
|
||||
"Plugin": "\u03a0\u03c1\u03cc\u03c3\u03b8\u03b5\u03c4\u03bf"
|
||||
}
|
|
@ -83,7 +83,7 @@
|
|||
"NotificationOptionServerRestartRequired": "Se necesita reiniciar el Servidor",
|
||||
"UserLockedOutWithName": "El usuario {0} ha sido bloqueado",
|
||||
"SubtitleDownloadFailureForItem": "Fall\u00f3 la descarga de subt\u00edtulos para {0}",
|
||||
"Sync": "Sinc.",
|
||||
"Sync": "Sincronizar",
|
||||
"User": "Usuario",
|
||||
"System": "Sistema",
|
||||
"Application": "Aplicaci\u00f3n",
|
||||
|
|
91
Emby.Server.Implementations/Localization/Core/gsw.json
Normal file
91
Emby.Server.Implementations/Localization/Core/gsw.json
Normal file
|
@ -0,0 +1,91 @@
|
|||
{
|
||||
"Latest": "Letschte",
|
||||
"ValueSpecialEpisodeName": "Spezial - {0}",
|
||||
"Inherit": "Hinzuef\u00fcege",
|
||||
"Books": "B\u00fcecher",
|
||||
"Music": "Musig",
|
||||
"Games": "Spiel",
|
||||
"Photos": "Fotis",
|
||||
"MixedContent": "Gmischte Inhalt",
|
||||
"MusicVideos": "Musigfilm",
|
||||
"HomeVideos": "Heimfilmli",
|
||||
"Playlists": "Abspielliste",
|
||||
"HeaderRecordingGroups": "Ufnahmegruppe",
|
||||
"HeaderContinueWatching": "Wiiterluege",
|
||||
"HeaderFavoriteArtists": "Besti Interpret",
|
||||
"HeaderFavoriteSongs": "Besti Lieder",
|
||||
"HeaderAlbumArtists": "Albuminterprete",
|
||||
"HeaderFavoriteAlbums": "Favorite Albums",
|
||||
"HeaderFavoriteEpisodes": "Favorite Episodes",
|
||||
"HeaderFavoriteShows": "Favorite Shows",
|
||||
"HeaderNextUp": "Next Up",
|
||||
"Favorites": "Favorites",
|
||||
"Collections": "Collections",
|
||||
"Channels": "Channels",
|
||||
"Movies": "Movies",
|
||||
"Albums": "Albums",
|
||||
"Artists": "Artists",
|
||||
"Folders": "Folders",
|
||||
"Songs": "Songs",
|
||||
"TvShows": "TV Shows",
|
||||
"Shows": "Shows",
|
||||
"Genres": "Genres",
|
||||
"NameSeasonNumber": "Season {0}",
|
||||
"AppDeviceValues": "App: {0}, Device: {1}",
|
||||
"UserDownloadingItemWithValues": "{0} is downloading {1}",
|
||||
"HeaderLiveTV": "Live TV",
|
||||
"ChapterNameValue": "Chapter {0}",
|
||||
"ScheduledTaskFailedWithName": "{0} failed",
|
||||
"LabelRunningTimeValue": "Running time: {0}",
|
||||
"ScheduledTaskStartedWithName": "{0} started",
|
||||
"VersionNumber": "Version {0}",
|
||||
"PluginInstalledWithName": "{0} was installed",
|
||||
"StartupEmbyServerIsLoading": "Emby Server is loading. Please try again shortly.",
|
||||
"PluginUpdatedWithName": "{0} was updated",
|
||||
"PluginUninstalledWithName": "{0} was uninstalled",
|
||||
"ItemAddedWithName": "{0} was added to the library",
|
||||
"ItemRemovedWithName": "{0} was removed from the library",
|
||||
"LabelIpAddressValue": "Ip address: {0}",
|
||||
"DeviceOnlineWithName": "{0} is connected",
|
||||
"UserOnlineFromDevice": "{0} is online from {1}",
|
||||
"ProviderValue": "Provider: {0}",
|
||||
"SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
|
||||
"UserCreatedWithName": "User {0} has been created",
|
||||
"UserPasswordChangedWithName": "Password has been changed for user {0}",
|
||||
"UserDeletedWithName": "User {0} has been deleted",
|
||||
"UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
|
||||
"MessageServerConfigurationUpdated": "Server configuration has been updated",
|
||||
"MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
|
||||
"MessageApplicationUpdated": "Emby Server has been updated",
|
||||
"FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
|
||||
"AuthenticationSucceededWithUserName": "{0} successfully authenticated",
|
||||
"UserOfflineFromDevice": "{0} has disconnected from {1}",
|
||||
"DeviceOfflineWithName": "{0} has disconnected",
|
||||
"UserStartedPlayingItemWithValues": "{0} has started playing {1}",
|
||||
"UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
|
||||
"NotificationOptionPluginError": "Plugin failure",
|
||||
"NotificationOptionApplicationUpdateAvailable": "Application update available",
|
||||
"NotificationOptionApplicationUpdateInstalled": "Application update installed",
|
||||
"NotificationOptionPluginUpdateInstalled": "Plugin update installed",
|
||||
"NotificationOptionPluginInstalled": "Plugin installed",
|
||||
"NotificationOptionPluginUninstalled": "Plugin uninstalled",
|
||||
"NotificationOptionVideoPlayback": "Video playback started",
|
||||
"NotificationOptionAudioPlayback": "Audio playback started",
|
||||
"NotificationOptionGamePlayback": "Game playback started",
|
||||
"NotificationOptionVideoPlaybackStopped": "Video playback stopped",
|
||||
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
|
||||
"NotificationOptionGamePlaybackStopped": "Game playback stopped",
|
||||
"NotificationOptionTaskFailed": "Scheduled task failure",
|
||||
"NotificationOptionInstallationFailed": "Installation failure",
|
||||
"NotificationOptionNewLibraryContent": "New content added",
|
||||
"NotificationOptionCameraImageUploaded": "Camera image uploaded",
|
||||
"NotificationOptionUserLockedOut": "User locked out",
|
||||
"NotificationOptionServerRestartRequired": "Server restart required",
|
||||
"UserLockedOutWithName": "User {0} has been locked out",
|
||||
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
|
||||
"Sync": "Sync",
|
||||
"User": "User",
|
||||
"System": "System",
|
||||
"Application": "Application",
|
||||
"Plugin": "Plugin"
|
||||
}
|
|
@ -27,7 +27,7 @@
|
|||
"Artists": "Artistas",
|
||||
"Folders": "Pastas",
|
||||
"Songs": "M\u00fasicas",
|
||||
"TvShows": "TV Shows",
|
||||
"TvShows": "S\u00e9ries de TV",
|
||||
"Shows": "S\u00e9ries",
|
||||
"Genres": "G\u00eaneros",
|
||||
"NameSeasonNumber": "Temporada {0}",
|
||||
|
|
|
@ -76,6 +76,21 @@ namespace Emby.Server.Implementations.MediaEncoder
|
|||
return false;
|
||||
}
|
||||
|
||||
if (video.VideoType == VideoType.Iso)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (video.IsShortcut)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!video.IsCompleteMedia)
|
||||
{
|
||||
return false;
|
||||
|
@ -118,16 +133,6 @@ namespace Emby.Server.Implementations.MediaEncoder
|
|||
{
|
||||
if (extractImages)
|
||||
{
|
||||
if (video.VideoType == VideoType.Iso)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Add some time for the first chapter to make sure we don't end up with a black image
|
||||
|
|
|
@ -17,11 +17,54 @@ namespace Emby.Server.Implementations.Networking
|
|||
public class NetworkManager : INetworkManager
|
||||
{
|
||||
protected ILogger Logger { get; private set; }
|
||||
private DateTime _lastRefresh;
|
||||
|
||||
public event EventHandler NetworkChanged;
|
||||
|
||||
public NetworkManager(ILogger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
|
||||
try
|
||||
{
|
||||
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error binding to NetworkAddressChanged event", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.ErrorException("Error binding to NetworkChange_NetworkAvailabilityChanged event", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
|
||||
{
|
||||
Logger.Debug("NetworkAvailabilityChanged");
|
||||
OnNetworkChanged();
|
||||
}
|
||||
|
||||
private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Debug("NetworkAddressChanged");
|
||||
OnNetworkChanged();
|
||||
}
|
||||
|
||||
private void OnNetworkChanged()
|
||||
{
|
||||
lock (_localIpAddressSyncLock)
|
||||
{
|
||||
_localIpAddresses = null;
|
||||
}
|
||||
if (NetworkChanged != null)
|
||||
{
|
||||
NetworkChanged(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IpAddressInfo> _localIpAddresses;
|
||||
|
@ -29,34 +72,28 @@ namespace Emby.Server.Implementations.Networking
|
|||
|
||||
public List<IpAddressInfo> GetLocalIpAddresses()
|
||||
{
|
||||
const int cacheMinutes = 10;
|
||||
|
||||
lock (_localIpAddressSyncLock)
|
||||
{
|
||||
var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes;
|
||||
|
||||
if (_localIpAddresses == null || forceRefresh)
|
||||
if (_localIpAddresses == null)
|
||||
{
|
||||
var addresses = GetLocalIpAddressesInternal().Select(ToIpAddressInfo).ToList();
|
||||
var addresses = GetLocalIpAddressesInternal().Result.Select(ToIpAddressInfo).ToList();
|
||||
|
||||
_localIpAddresses = addresses;
|
||||
_lastRefresh = DateTime.UtcNow;
|
||||
|
||||
return addresses;
|
||||
}
|
||||
return _localIpAddresses;
|
||||
}
|
||||
|
||||
return _localIpAddresses;
|
||||
}
|
||||
|
||||
private IEnumerable<IPAddress> GetLocalIpAddressesInternal()
|
||||
private async Task<List<IPAddress>> GetLocalIpAddressesInternal()
|
||||
{
|
||||
var list = GetIPsDefault()
|
||||
.ToList();
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
list.AddRange(GetLocalIpAddressesFallback().Result);
|
||||
list.AddRange(await GetLocalIpAddressesFallback().ConfigureAwait(false));
|
||||
}
|
||||
|
||||
var listClone = list.ToList();
|
||||
|
@ -65,7 +102,8 @@ namespace Emby.Server.Implementations.Networking
|
|||
.OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1)
|
||||
.ThenBy(i => listClone.IndexOf(i))
|
||||
.Where(FilterIpAddress)
|
||||
.DistinctBy(i => i.ToString());
|
||||
.DistinctBy(i => i.ToString())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private bool FilterIpAddress(IPAddress address)
|
||||
|
|
|
@ -117,6 +117,10 @@ namespace Emby.Server.Implementations.Session
|
|||
{
|
||||
dict["SubtitleStreamIndex"] = command.SubtitleStreamIndex.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
if (command.StartIndex.HasValue)
|
||||
{
|
||||
dict["StartIndex"] = command.StartIndex.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(command.MediaSourceId))
|
||||
{
|
||||
dict["MediaSourceId"] = command.MediaSourceId;
|
||||
|
@ -147,7 +151,7 @@ namespace Emby.Server.Implementations.Session
|
|||
return SendMessage("LibraryChanged", info, cancellationToken);
|
||||
}
|
||||
|
||||
public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
|
||||
public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
|
||||
{
|
||||
return SendMessage("RestartRequired", cancellationToken);
|
||||
}
|
||||
|
|
|
@ -1182,13 +1182,11 @@ namespace Emby.Server.Implementations.Session
|
|||
{
|
||||
var sessions = Sessions.Where(i => i.IsActive && i.SessionController != null).ToList();
|
||||
|
||||
var info = await _appHost.GetSystemInfo().ConfigureAwait(false);
|
||||
|
||||
var tasks = sessions.Select(session => Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await session.SessionController.SendRestartRequiredNotification(info, cancellationToken).ConfigureAwait(false);
|
||||
await session.SessionController.SendRestartRequiredNotification(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -1423,7 +1421,7 @@ namespace Emby.Server.Implementations.Session
|
|||
|
||||
if (enforcePassword)
|
||||
{
|
||||
var result = await _userManager.AuthenticateUser(request.Username, request.Password, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint).ConfigureAwait(false);
|
||||
var result = await _userManager.AuthenticateUser(request.Username, request.Password, request.PasswordSha1, request.PasswordMd5, request.RemoteEndPoint, true).ConfigureAwait(false);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
|
|
|
@ -145,12 +145,12 @@ namespace Emby.Server.Implementations.Session
|
|||
/// <param name="info">The information.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task SendRestartRequiredNotification(SystemInfo info, CancellationToken cancellationToken)
|
||||
public Task SendRestartRequiredNotification(CancellationToken cancellationToken)
|
||||
{
|
||||
return SendMessagesInternal(new WebSocketMessage<SystemInfo>
|
||||
return SendMessagesInternal(new WebSocketMessage<string>
|
||||
{
|
||||
MessageType = "RestartRequired",
|
||||
Data = info
|
||||
Data = string.Empty
|
||||
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Social;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Emby.Server.Implementations.Social
|
||||
|
@ -42,7 +43,7 @@ namespace Emby.Server.Implementations.Social
|
|||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
var externalUrl = (await _appHost.GetSystemInfo().ConfigureAwait(false)).WanAddress;
|
||||
var externalUrl = (await _appHost.GetPublicSystemInfo(CancellationToken.None).ConfigureAwait(false)).WanAddress;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(externalUrl))
|
||||
{
|
||||
|
@ -73,7 +74,7 @@ namespace Emby.Server.Implementations.Social
|
|||
{
|
||||
var info = _repository.GetShareInfo(id);
|
||||
|
||||
AddShareInfo(info, _appHost.GetSystemInfo().Result.WanAddress);
|
||||
AddShareInfo(info, _appHost.GetPublicSystemInfo(CancellationToken.None).Result.WanAddress);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Udp
|
|||
|
||||
private bool _isDisposed;
|
||||
|
||||
private readonly List<Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, Task>>> _responders = new List<Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, Task>>>();
|
||||
private readonly List<Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>> _responders = new List<Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>>();
|
||||
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly IJsonSerializer _json;
|
||||
|
@ -44,9 +44,9 @@ namespace Emby.Server.Implementations.Udp
|
|||
AddMessageResponder("who is MediaBrowserServer_v2?", false, RespondToV2Message);
|
||||
}
|
||||
|
||||
private void AddMessageResponder(string message, bool isSubstring, Func<string, IpEndPointInfo, Encoding, Task> responder)
|
||||
private void AddMessageResponder(string message, bool isSubstring, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task> responder)
|
||||
{
|
||||
_responders.Add(new Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, Task>>(message, isSubstring, responder));
|
||||
_responders.Add(new Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>(message, isSubstring, responder));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,9 +67,15 @@ namespace Emby.Server.Implementations.Udp
|
|||
|
||||
if (responder != null)
|
||||
{
|
||||
var cancellationToken = CancellationToken.None;
|
||||
|
||||
try
|
||||
{
|
||||
await responder.Item2.Item3(responder.Item1, message.RemoteEndPoint, encoding).ConfigureAwait(false);
|
||||
await responder.Item2.Item3(responder.Item1, message.RemoteEndPoint, encoding, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -78,7 +84,7 @@ namespace Emby.Server.Implementations.Udp
|
|||
}
|
||||
}
|
||||
|
||||
private Tuple<string, Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, Task>>> GetResponder(byte[] buffer, int bytesReceived, Encoding encoding)
|
||||
private Tuple<string, Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>> GetResponder(byte[] buffer, int bytesReceived, Encoding encoding)
|
||||
{
|
||||
var text = encoding.GetString(buffer, 0, bytesReceived);
|
||||
var responder = _responders.FirstOrDefault(i =>
|
||||
|
@ -94,14 +100,14 @@ namespace Emby.Server.Implementations.Udp
|
|||
{
|
||||
return null;
|
||||
}
|
||||
return new Tuple<string, Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, Task>>>(text, responder);
|
||||
return new Tuple<string, Tuple<string, bool, Func<string, IpEndPointInfo, Encoding, CancellationToken, Task>>>(text, responder);
|
||||
}
|
||||
|
||||
private async Task RespondToV2Message(string messageText, IpEndPointInfo endpoint, Encoding encoding)
|
||||
private async Task RespondToV2Message(string messageText, IpEndPointInfo endpoint, Encoding encoding, CancellationToken cancellationToken)
|
||||
{
|
||||
var parts = messageText.Split('|');
|
||||
|
||||
var localUrl = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
|
||||
var localUrl = await _appHost.GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!string.IsNullOrEmpty(localUrl))
|
||||
{
|
||||
|
@ -112,7 +118,7 @@ namespace Emby.Server.Implementations.Udp
|
|||
Name = _appHost.FriendlyName
|
||||
};
|
||||
|
||||
await SendAsync(encoding.GetBytes(_json.SerializeToString(response)), endpoint).ConfigureAwait(false);
|
||||
await SendAsync(encoding.GetBytes(_json.SerializeToString(response)), endpoint, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
|
@ -248,7 +254,7 @@ namespace Emby.Server.Implementations.Udp
|
|||
}
|
||||
}
|
||||
|
||||
public async Task SendAsync(byte[] bytes, IpEndPointInfo remoteEndPoint)
|
||||
public async Task SendAsync(byte[] bytes, IpEndPointInfo remoteEndPoint, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
|
@ -267,7 +273,7 @@ namespace Emby.Server.Implementations.Udp
|
|||
|
||||
try
|
||||
{
|
||||
await _udpClient.SendToAsync(bytes, 0, bytes.Length, remoteEndPoint, CancellationToken.None).ConfigureAwait(false);
|
||||
await _udpClient.SendToAsync(bytes, 0, bytes.Length, remoteEndPoint, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_logger.Info("Udp message sent to {0}", remoteEndPoint);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -11,7 +12,7 @@ using MediaBrowser.Model.Services;
|
|||
namespace MediaBrowser.Api
|
||||
{
|
||||
[Route("/Items/Filters", "GET", Summary = "Gets branding configuration")]
|
||||
public class GetQueryFilters : IReturn<QueryFilters>
|
||||
public class GetQueryFiltersLegacy : IReturn<QueryFiltersLegacy>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
|
@ -40,6 +41,43 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
}
|
||||
|
||||
[Route("/Items/Filters2", "GET", Summary = "Gets branding configuration")]
|
||||
public class GetQueryFilters : IReturn<QueryFilters>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
/// <value>The user id.</value>
|
||||
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[ApiMember(Name = "ParentId", Description = "Specify this to localize the search to a specific item or folder. Omit to use the root", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string ParentId { get; set; }
|
||||
|
||||
[ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string IncludeItemTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "MediaTypes", Description = "Optional filter by MediaType. Allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
|
||||
public string MediaTypes { get; set; }
|
||||
|
||||
public string[] GetMediaTypes()
|
||||
{
|
||||
return (MediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetIncludeItemTypes()
|
||||
{
|
||||
return (IncludeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public bool? IsAiring { get; set; }
|
||||
public bool? IsMovie { get; set; }
|
||||
public bool? IsSports { get; set; }
|
||||
public bool? IsKids { get; set; }
|
||||
public bool? IsNews { get; set; }
|
||||
public bool? IsSeries { get; set; }
|
||||
}
|
||||
|
||||
[Authenticated]
|
||||
public class FilterService : BaseApiService
|
||||
{
|
||||
|
@ -57,18 +95,96 @@ namespace MediaBrowser.Api
|
|||
var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId);
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, typeof(Trailer).Name, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "Program", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parentItem = null;
|
||||
}
|
||||
|
||||
var filters = new QueryFilters();
|
||||
|
||||
var genreQuery = new InternalItemsQuery(user)
|
||||
{
|
||||
AncestorIds = parentItem == null ? new string[] { } : new string[] { parentItem.Id.ToString("N") },
|
||||
IncludeItemTypes = request.GetIncludeItemTypes(),
|
||||
DtoOptions = new Controller.Dto.DtoOptions
|
||||
{
|
||||
Fields = new ItemFields[] { },
|
||||
EnableImages = false,
|
||||
EnableUserData = false
|
||||
},
|
||||
IsAiring = request.IsAiring,
|
||||
IsMovie = request.IsMovie,
|
||||
IsSports = request.IsSports,
|
||||
IsKids = request.IsKids,
|
||||
IsNews = request.IsNews,
|
||||
IsSeries = request.IsSeries
|
||||
};
|
||||
|
||||
if (string.Equals(request.IncludeItemTypes, "MusicAlbum", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "MusicVideo", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "MusicArtist", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "Audio", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
filters.Genres = _libraryManager.GetMusicGenres(genreQuery).Items.Select(i => new NameIdPair
|
||||
{
|
||||
Name = i.Item1.Name,
|
||||
Id = i.Item1.Id.ToString("N")
|
||||
|
||||
}).ToArray();
|
||||
}
|
||||
else if (string.Equals(request.IncludeItemTypes, "Game", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "GameSystem", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
filters.Genres = _libraryManager.GetGameGenres(genreQuery).Items.Select(i => new NameIdPair
|
||||
{
|
||||
Name = i.Item1.Name,
|
||||
Id = i.Item1.Id.ToString("N")
|
||||
|
||||
}).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
filters.Genres = _libraryManager.GetGenres(genreQuery).Items.Select(i => new NameIdPair
|
||||
{
|
||||
Name = i.Item1.Name,
|
||||
Id = i.Item1.Id.ToString("N")
|
||||
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
return ToOptimizedResult(filters);
|
||||
}
|
||||
|
||||
public object Get(GetQueryFiltersLegacy request)
|
||||
{
|
||||
var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId);
|
||||
var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null;
|
||||
|
||||
if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, typeof(Trailer).Name, StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(request.IncludeItemTypes, "Program", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parentItem = null;
|
||||
}
|
||||
|
||||
var item = string.IsNullOrEmpty(request.ParentId) ?
|
||||
user == null ? _libraryManager.RootFolder : user.RootFolder :
|
||||
parentItem;
|
||||
|
||||
var result = ((Folder)item).GetItemList(GetItemsQuery(request, user));
|
||||
|
||||
return ToOptimizedResult(GetFilters(result));
|
||||
var filters = GetFilters(result);
|
||||
|
||||
return ToOptimizedResult(filters);
|
||||
}
|
||||
|
||||
private QueryFilters GetFilters(BaseItem[] items)
|
||||
private QueryFiltersLegacy GetFilters(BaseItem[] items)
|
||||
{
|
||||
var result = new QueryFilters();
|
||||
var result = new QueryFiltersLegacy();
|
||||
|
||||
result.Years = items.Select(i => i.ProductionYear ?? -1)
|
||||
.Where(i => i > 0)
|
||||
|
@ -97,7 +213,7 @@ namespace MediaBrowser.Api
|
|||
return result;
|
||||
}
|
||||
|
||||
private InternalItemsQuery GetItemsQuery(GetQueryFilters request, User user)
|
||||
private InternalItemsQuery GetItemsQuery(GetQueryFiltersLegacy request, User user)
|
||||
{
|
||||
var query = new InternalItemsQuery
|
||||
{
|
||||
|
|
|
@ -379,6 +379,9 @@ namespace MediaBrowser.Api.LiveTv
|
|||
[ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
|
||||
public string Genres { get; set; }
|
||||
|
||||
[ApiMember(Name = "GenreIds", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
|
||||
public string GenreIds { get; set; }
|
||||
|
||||
[ApiMember(Name = "EnableImages", Description = "Optional, include image information in output", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "GET")]
|
||||
public bool? EnableImages { get; set; }
|
||||
|
||||
|
@ -456,6 +459,9 @@ namespace MediaBrowser.Api.LiveTv
|
|||
[ApiMember(Name = "EnableImageTypes", Description = "Optional. The image types to include in the output.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string EnableImageTypes { get; set; }
|
||||
|
||||
[ApiMember(Name = "GenreIds", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
|
||||
public string GenreIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fields to return within the items, in addition to basic information
|
||||
/// </summary>
|
||||
|
@ -1003,6 +1009,7 @@ namespace MediaBrowser.Api.LiveTv
|
|||
query.IsSports = request.IsSports;
|
||||
query.SeriesTimerId = request.SeriesTimerId;
|
||||
query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
query.GenreIds = (request.GenreIds ?? String.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.LibrarySeriesId))
|
||||
{
|
||||
|
@ -1036,6 +1043,8 @@ namespace MediaBrowser.Api.LiveTv
|
|||
EnableTotalRecordCount = request.EnableTotalRecordCount
|
||||
};
|
||||
|
||||
query.GenreIds = (request.GenreIds ?? String.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var result = _liveTvManager.GetRecommendedPrograms(query, GetDtoOptions(_authContext, request), CancellationToken.None);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
|
|
|
@ -3,9 +3,10 @@ using MediaBrowser.Model.Logging;
|
|||
using MediaBrowser.Model.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Api.ScheduledTasks
|
||||
{
|
||||
|
@ -63,7 +64,7 @@ namespace MediaBrowser.Api.ScheduledTasks
|
|||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>Task{IEnumerable{TaskInfo}}.</returns>
|
||||
protected override Task<IEnumerable<TaskInfo>> GetDataToSend(WebSocketListenerState state)
|
||||
protected override Task<IEnumerable<TaskInfo>> GetDataToSend(WebSocketListenerState state, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(TaskManager.ScheduledTasks
|
||||
.OrderBy(i => i.Name)
|
||||
|
|
|
@ -248,9 +248,20 @@ namespace MediaBrowser.Api
|
|||
|
||||
if (song != null)
|
||||
{
|
||||
result.Album = song.Album;
|
||||
result.AlbumArtist = song.AlbumArtists.FirstOrDefault();
|
||||
result.Artists = song.Artists;
|
||||
|
||||
album = song.AlbumEntity;
|
||||
|
||||
if (album != null)
|
||||
{
|
||||
result.Album = album.Name;
|
||||
result.AlbumId = album.Id.ToString("N");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Album = song.Album;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.ChannelId))
|
||||
|
|
|
@ -5,8 +5,9 @@ using MediaBrowser.Model.Logging;
|
|||
using MediaBrowser.Model.Session;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Api.Session
|
||||
{
|
||||
|
@ -86,7 +87,7 @@ namespace MediaBrowser.Api.Session
|
|||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>Task{SystemInfo}.</returns>
|
||||
protected override Task<IEnumerable<SessionInfoDto>> GetDataToSend(WebSocketListenerState state)
|
||||
protected override Task<IEnumerable<SessionInfoDto>> GetDataToSend(WebSocketListenerState state, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(_sessionManager.Sessions.Where(i => i.IsActive).Select(_sessionManager.GetSessionInfoDto));
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace MediaBrowser.Api
|
|||
public void Post(ReportStartupWizardComplete request)
|
||||
{
|
||||
_config.Configuration.IsStartupWizardCompleted = true;
|
||||
_config.Configuration.AutoRunWebApp = true;
|
||||
_config.SetOptimalValues();
|
||||
_config.SaveConfiguration();
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Api.System
|
||||
{
|
||||
|
@ -43,7 +44,7 @@ namespace MediaBrowser.Api.System
|
|||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>Task{SystemInfo}.</returns>
|
||||
protected override Task<List<ActivityLogEntry>> GetDataToSend(WebSocketListenerState state)
|
||||
protected override Task<List<ActivityLogEntry>> GetDataToSend(WebSocketListenerState state, CancellationToken CancellationToken)
|
||||
{
|
||||
return Task.FromResult(new List<ActivityLogEntry>());
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using MediaBrowser.Model.Logging;
|
|||
using MediaBrowser.Model.System;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Threading;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Api.System
|
||||
{
|
||||
|
@ -40,9 +41,9 @@ namespace MediaBrowser.Api.System
|
|||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <returns>Task{SystemInfo}.</returns>
|
||||
protected override Task<SystemInfo> GetDataToSend(WebSocketListenerState state)
|
||||
protected override Task<SystemInfo> GetDataToSend(WebSocketListenerState state, CancellationToken cancellationToken)
|
||||
{
|
||||
return _appHost.GetSystemInfo();
|
||||
return _appHost.GetSystemInfo(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ using MediaBrowser.Controller.IO;
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Services;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Api.System
|
||||
{
|
||||
|
@ -164,26 +165,16 @@ namespace MediaBrowser.Api.System
|
|||
/// <returns>System.Object.</returns>
|
||||
public async Task<object> Get(GetSystemInfo request)
|
||||
{
|
||||
var result = await _appHost.GetSystemInfo().ConfigureAwait(false);
|
||||
var result = await _appHost.GetSystemInfo(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
public async Task<object> Get(GetPublicSystemInfo request)
|
||||
{
|
||||
var result = await _appHost.GetSystemInfo().ConfigureAwait(false);
|
||||
var result = await _appHost.GetPublicSystemInfo(CancellationToken.None).ConfigureAwait(false);
|
||||
|
||||
var publicInfo = new PublicSystemInfo
|
||||
{
|
||||
Id = result.Id,
|
||||
ServerName = result.ServerName,
|
||||
Version = result.Version,
|
||||
LocalAddress = result.LocalAddress,
|
||||
WanAddress = result.WanAddress,
|
||||
OperatingSystem = result.OperatingSystem
|
||||
};
|
||||
|
||||
return ToOptimizedResult(publicInfo);
|
||||
return ToOptimizedResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -473,7 +473,7 @@ namespace MediaBrowser.Api
|
|||
}
|
||||
else
|
||||
{
|
||||
var success = await _userManager.AuthenticateUser(user.Name, request.CurrentPw, request.CurrentPassword, null, Request.RemoteIp).ConfigureAwait(false);
|
||||
var success = await _userManager.AuthenticateUser(user.Name, request.CurrentPw, request.CurrentPassword, null, Request.RemoteIp, false).ConfigureAwait(false);
|
||||
|
||||
if (success == null)
|
||||
{
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Net;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Common.Net
|
||||
{
|
||||
public interface INetworkManager
|
||||
{
|
||||
event EventHandler NetworkChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a random port number that is currently available
|
||||
/// </summary>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user