aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Common.Implementations/BaseApplicationHost.cs26
-rw-r--r--Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs2
-rw-r--r--Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs53
-rw-r--r--Emby.Dlna/Profiles/WdtvLiveProfile.cs3
-rw-r--r--Emby.Dlna/Profiles/Xml/WDTV Live.xml2
-rw-r--r--Emby.Dlna/Ssdp/DeviceDiscovery.cs46
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj4
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs12
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs21
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs28
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs34
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs14
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs15
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs15
-rw-r--r--Emby.Server.Implementations/packages.config2
-rw-r--r--MediaBrowser.Api/LiveTv/LiveTvService.cs2
-rw-r--r--MediaBrowser.Api/StartupWizardService.cs1
-rw-r--r--MediaBrowser.Common/Net/HttpRequestOptions.cs1
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvManager.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs5
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs12
-rw-r--r--MediaBrowser.Model/Entities/MetadataProviders.cs4
-rw-r--r--MediaBrowser.Model/System/IEnvironmentInfo.cs3
-rw-r--r--MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs2
-rw-r--r--MediaBrowser.Providers/Omdb/OmdbProvider.cs17
-rw-r--r--MediaBrowser.Server.Mono/Program.cs13
-rw-r--r--MediaBrowser.WebDashboard/Api/DashboardService.cs107
-rw-r--r--MediaBrowser.WebDashboard/Api/PackageCreator.cs50
-rw-r--r--MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs8
-rw-r--r--RSSDP/SsdpDeviceLocatorBase.cs173
32 files changed, 338 insertions, 345 deletions
diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs
index 87b97863b..147a43fa1 100644
--- a/Emby.Common.Implementations/BaseApplicationHost.cs
+++ b/Emby.Common.Implementations/BaseApplicationHost.cs
@@ -527,7 +527,7 @@ return null;
RegisterSingleInstance(FileSystemManager);
- HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory);
+ HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
RegisterSingleInstance(HttpClient);
RegisterSingleInstance(NetworkManager);
@@ -549,6 +549,30 @@ return null;
return Task.FromResult(true);
}
+ private string GetDefaultUserAgent()
+ {
+ var name = FormatAttribute(Name);
+
+ return name + "/" + ApplicationVersion.ToString();
+ }
+
+ private string FormatAttribute(string str)
+ {
+ var arr = str.ToCharArray();
+
+ arr = Array.FindAll<char>(arr, (c => (char.IsLetterOrDigit(c)
+ || char.IsWhiteSpace(c))));
+
+ var result = new string(arr);
+
+ if (string.IsNullOrWhiteSpace(result))
+ {
+ result = "Emby";
+ }
+
+ return result;
+ }
+
/// <summary>
/// Gets a list of types within an assembly
/// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
diff --git a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs
index dcc974413..5da1ae2dc 100644
--- a/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs
+++ b/Emby.Common.Implementations/EnvironmentInfo/EnvironmentInfo.cs
@@ -12,7 +12,7 @@ namespace Emby.Common.Implementations.EnvironmentInfo
public MediaBrowser.Model.System.Architecture? CustomArchitecture { get; set; }
public MediaBrowser.Model.System.OperatingSystem? CustomOperatingSystem { get; set; }
- public MediaBrowser.Model.System.OperatingSystem OperatingSystem
+ public virtual MediaBrowser.Model.System.OperatingSystem OperatingSystem
{
get
{
diff --git a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs
index 06af5af53..23f33f06c 100644
--- a/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Common.Implementations/HttpClientManager/HttpClientManager.cs
@@ -18,6 +18,7 @@ using System.Threading;
using System.Threading.Tasks;
using Emby.Common.Implementations.HttpClientManager;
using MediaBrowser.Model.IO;
+using MediaBrowser.Common;
namespace Emby.Common.Implementations.HttpClientManager
{
@@ -43,17 +44,12 @@ namespace Emby.Common.Implementations.HttpClientManager
private readonly IFileSystem _fileSystem;
private readonly IMemoryStreamFactory _memoryStreamProvider;
+ private readonly Func<string> _defaultUserAgentFn;
/// <summary>
/// Initializes a new instance of the <see cref="HttpClientManager" /> class.
/// </summary>
- /// <param name="appPaths">The app paths.</param>
- /// <param name="logger">The logger.</param>
- /// <param name="fileSystem">The file system.</param>
- /// <exception cref="System.ArgumentNullException">appPaths
- /// or
- /// logger</exception>
- public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IMemoryStreamFactory memoryStreamProvider)
+ public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IMemoryStreamFactory memoryStreamProvider, Func<string> defaultUserAgentFn)
{
if (appPaths == null)
{
@@ -68,6 +64,7 @@ namespace Emby.Common.Implementations.HttpClientManager
_fileSystem = fileSystem;
_memoryStreamProvider = memoryStreamProvider;
_appPaths = appPaths;
+ _defaultUserAgentFn = defaultUserAgentFn;
#if NET46
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
@@ -257,6 +254,8 @@ namespace Emby.Common.Implementations.HttpClientManager
private void AddRequestHeaders(HttpWebRequest request, HttpRequestOptions options)
{
+ var hasUserAgent = false;
+
foreach (var header in options.RequestHeaders.ToList())
{
if (string.Equals(header.Key, "Accept", StringComparison.OrdinalIgnoreCase))
@@ -265,11 +264,8 @@ namespace Emby.Common.Implementations.HttpClientManager
}
else if (string.Equals(header.Key, "User-Agent", StringComparison.OrdinalIgnoreCase))
{
-#if NET46
- request.UserAgent = header.Value;
-#elif NETSTANDARD1_6
- request.Headers["User-Agent"] = header.Value;
-#endif
+ SetUserAgent(request, header.Value);
+ hasUserAgent = true;
}
else
{
@@ -280,6 +276,20 @@ namespace Emby.Common.Implementations.HttpClientManager
#endif
}
}
+
+ if (!hasUserAgent && options.EnableDefaultUserAgent)
+ {
+ SetUserAgent(request, _defaultUserAgentFn());
+ }
+ }
+
+ private void SetUserAgent(HttpWebRequest request, string userAgent)
+ {
+#if NET46
+ request.UserAgent = userAgent;
+#elif NETSTANDARD1_6
+ request.Headers["User-Agent"] = userAgent;
+#endif
}
/// <summary>
@@ -448,15 +458,22 @@ namespace Emby.Common.Implementations.HttpClientManager
!string.IsNullOrEmpty(options.RequestContent) ||
string.Equals(httpMethod, "post", StringComparison.OrdinalIgnoreCase))
{
- var bytes = options.RequestContentBytes ??
- Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
+ try
+ {
+ var bytes = options.RequestContentBytes ??
+ Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
- httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded";
+ httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded";
#if NET46
- httpWebRequest.ContentLength = bytes.Length;
-#endif
- (await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)).Write(bytes, 0, bytes.Length);
+ httpWebRequest.ContentLength = bytes.Length;
+#endif
+ (await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)).Write(bytes, 0, bytes.Length);
+ }
+ catch (Exception ex)
+ {
+ throw new HttpException(ex.Message) { IsTimedOut = true };
+ }
}
if (options.ResourcePool != null)
diff --git a/Emby.Dlna/Profiles/WdtvLiveProfile.cs b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
index 6cef2d965..756882592 100644
--- a/Emby.Dlna/Profiles/WdtvLiveProfile.cs
+++ b/Emby.Dlna/Profiles/WdtvLiveProfile.cs
@@ -125,8 +125,7 @@ namespace Emby.Dlna.Profiles
new DirectPlayProfile
{
- Container = "flac",
- AudioCodec = "flac",
+ Container = "flac,ac3",
Type = DlnaProfileType.Audio
},
diff --git a/Emby.Dlna/Profiles/Xml/WDTV Live.xml b/Emby.Dlna/Profiles/Xml/WDTV Live.xml
index 1cf3ef597..775d25302 100644
--- a/Emby.Dlna/Profiles/Xml/WDTV Live.xml
+++ b/Emby.Dlna/Profiles/Xml/WDTV Live.xml
@@ -45,7 +45,7 @@
<DirectPlayProfile container="asf" audioCodec="mp2,ac3" videoCodec="mpeg2video" type="Video" />
<DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
<DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />
- <DirectPlayProfile container="flac" audioCodec="flac" type="Audio" />
+ <DirectPlayProfile container="flac,ac3" type="Audio" />
<DirectPlayProfile container="asf" audioCodec="wmav2,wmapro,wmavoice" type="Audio" />
<DirectPlayProfile container="ogg" audioCodec="vorbis" type="Audio" />
<DirectPlayProfile container="jpeg,png,gif,bmp,tiff" type="Photo" />
diff --git a/Emby.Dlna/Ssdp/DeviceDiscovery.cs b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
index 7852669c9..bd5ad31c2 100644
--- a/Emby.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/Emby.Dlna/Ssdp/DeviceDiscovery.cs
@@ -19,13 +19,12 @@ using Rssdp.Infrastructure;
namespace Emby.Dlna.Ssdp
{
- public class DeviceDiscovery : IDeviceDiscovery, IDisposable
+ public class DeviceDiscovery : IDeviceDiscovery
{
private bool _disposed;
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
- private readonly CancellationTokenSource _tokenSource;
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered;
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceLeft;
@@ -37,8 +36,6 @@ namespace Emby.Dlna.Ssdp
public DeviceDiscovery(ILogger logger, IServerConfigurationManager config, ISocketFactory socketFactory, ITimerFactory timerFactory)
{
- _tokenSource = new CancellationTokenSource();
-
_logger = logger;
_config = config;
_socketFactory = socketFactory;
@@ -59,39 +56,10 @@ namespace Emby.Dlna.Ssdp
_deviceLocator.DeviceAvailable += deviceLocator_DeviceAvailable;
_deviceLocator.DeviceUnavailable += _DeviceLocator_DeviceUnavailable;
- // Perform a search so we don't have to wait for devices to broadcast notifications
- // again to get any results right away (notifications are broadcast periodically).
- StartAsyncSearch();
- }
-
- private void StartAsyncSearch()
- {
- Task.Factory.StartNew(async (o) =>
- {
- while (!_tokenSource.IsCancellationRequested)
- {
- try
- {
- // Enable listening for notifications (optional)
- _deviceLocator.StartListeningForNotifications();
-
- await _deviceLocator.SearchAsync(_tokenSource.Token).ConfigureAwait(false);
+ var dueTime = TimeSpan.FromSeconds(5);
+ var interval = TimeSpan.FromSeconds(_config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds);
- var delay = _config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds * 1000;
-
- await Task.Delay(delay, _tokenSource.Token).ConfigureAwait(false);
- }
- catch (OperationCanceledException)
- {
-
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error searching for devices", ex);
- }
- }
-
- }, CancellationToken.None, TaskCreationOptions.LongRunning);
+ _deviceLocator.RestartBroadcastTimer(dueTime, interval);
}
// Process each found device in the event handler
@@ -141,7 +109,11 @@ namespace Emby.Dlna.Ssdp
if (!_disposed)
{
_disposed = true;
- _tokenSource.Cancel();
+ if (_deviceLocator != null)
+ {
+ _deviceLocator.Dispose();
+ _deviceLocator = null;
+ }
}
}
}
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 195d24b21..a1bd67f1f 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -309,8 +309,8 @@
<Project>{4f26d5d8-a7b0-42b3-ba42-7cb7d245934e}</Project>
<Name>SocketHttpListener.Portable</Name>
</ProjectReference>
- <Reference Include="Emby.XmlTv, Version=1.0.6241.4924, Culture=neutral, processorArchitecture=MSIL">
- <HintPath>..\packages\Emby.XmlTv.1.0.5\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
+ <Reference Include="Emby.XmlTv, Version=1.0.6249.32870, Culture=neutral, processorArchitecture=MSIL">
+ <HintPath>..\packages\Emby.XmlTv.1.0.6\lib\portable-net45+win8\Emby.XmlTv.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MediaBrowser.Naming, Version=1.0.6201.24431, Culture=neutral, processorArchitecture=MSIL">
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index de3a1664e..616c6c1a2 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -2627,6 +2627,18 @@ namespace Emby.Server.Implementations.Library
}
}
+ foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
+ {
+ if (!string.IsNullOrWhiteSpace(map.From))
+ {
+ var substitutionResult = SubstitutePathInternal(path, map.From, map.To);
+ if (substitutionResult.Item2)
+ {
+ return substitutionResult.Item1;
+ }
+ }
+ }
+
return path;
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index 6cf201990..2971405b9 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -74,21 +74,20 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
return new MusicArtist();
}
- return null;
- //if (_config.Configuration.EnableSimpleArtistDetection)
- //{
- // return null;
- //}
+ if (_config.Configuration.EnableSimpleArtistDetection)
+ {
+ return null;
+ }
- //// Avoid mis-identifying top folders
- //if (args.Parent.IsRoot) return null;
+ // Avoid mis-identifying top folders
+ if (args.Parent.IsRoot) return null;
- //var directoryService = args.DirectoryService;
+ var directoryService = args.DirectoryService;
- //var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
+ var albumResolver = new MusicAlbumResolver(_logger, _fileSystem, _libraryManager);
- //// If we contain an album assume we are an artist folder
- //return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
+ // If we contain an album assume we are an artist folder
+ return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
}
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 89ef87c8e..bbb060203 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -423,6 +423,11 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
tunerChannel.Name = epgChannel.Name;
}
+ if (!string.IsNullOrWhiteSpace(epgChannel.ImageUrl))
+ {
+ tunerChannel.ImageUrl = epgChannel.ImageUrl;
+ tunerChannel.HasImage = true;
+ }
}
}
}
@@ -469,16 +474,20 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public ChannelInfo GetEpgChannelFromTunerChannel(List<NameValuePair> mappings, ChannelInfo tunerChannel, List<ChannelInfo> epgChannels)
{
- if (!string.IsNullOrWhiteSpace(tunerChannel.TunerChannelId))
+ var tunerChannelId = string.IsNullOrWhiteSpace(tunerChannel.TunerChannelId)
+ ? tunerChannel.Id
+ : tunerChannel.TunerChannelId;
+
+ if (!string.IsNullOrWhiteSpace(tunerChannelId))
{
- var tunerChannelId = GetMappedChannel(tunerChannel.TunerChannelId, mappings);
+ var mappedTunerChannelId = GetMappedChannel(tunerChannelId, mappings);
- if (string.IsNullOrWhiteSpace(tunerChannelId))
+ if (string.IsNullOrWhiteSpace(mappedTunerChannelId))
{
- tunerChannelId = tunerChannel.TunerChannelId;
+ mappedTunerChannelId = tunerChannelId;
}
- var channel = epgChannels.FirstOrDefault(i => string.Equals(tunerChannelId, i.Id, StringComparison.OrdinalIgnoreCase));
+ var channel = epgChannels.FirstOrDefault(i => string.Equals(mappedTunerChannelId, i.Id, StringComparison.OrdinalIgnoreCase));
if (channel != null)
{
@@ -1163,7 +1172,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
};
var isAudio = false;
- await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
+ await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, false, cancellationToken).ConfigureAwait(false);
return new List<MediaSourceInfo>
{
@@ -2092,13 +2101,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
writer.WriteElementString("credits", person);
}
- var rt = item.GetProviderId(MetadataProviders.RottenTomatoes);
-
- if (!string.IsNullOrEmpty(rt))
- {
- writer.WriteElementString("rottentomatoesid", rt);
- }
-
var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection);
if (!string.IsNullOrEmpty(tmdbCollection))
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 1f739b3c6..9a8282250 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -155,7 +155,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
var inputModifiers = "-fflags +genpts -async 1 -vsync -1";
var mapArgs = string.Equals(OutputFormat, "mkv", StringComparison.OrdinalIgnoreCase) ? "-map 0" : "-sn";
- // temporary
mapArgs = "-sn";
var commandLineArgs = "-i \"{0}\"{4} " + mapArgs + " {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 1b7a1c8c6..0d7a26553 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -152,7 +152,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
responseString);
var programDict = programDetails.ToDictionary(p => p.programID, y => y);
- var images = await GetImageForPrograms(info, programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID).ToList(), cancellationToken);
+ var programIdsWithImages =
+ programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
+ .ToList();
+
+ var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken);
var schedules = dailySchedules.SelectMany(d => d.programs);
foreach (ScheduleDirect.Program schedule in schedules)
@@ -439,13 +443,20 @@ namespace Emby.Server.Implementations.LiveTv.Listings
List<string> programIds,
CancellationToken cancellationToken)
{
+ if (programIds.Count == 0)
+ {
+ return new List<ScheduleDirect.ShowImages>();
+ }
+
var imageIdString = "[";
foreach (var i in programIds)
{
- if (!imageIdString.Contains(i.Substring(0, 10)))
+ var imageId = i.Substring(0, 10);
+
+ if (!imageIdString.Contains(imageId))
{
- imageIdString += "\"" + i.Substring(0, 10) + "\",";
+ imageIdString += "\"" + imageId + "\",";
}
}
@@ -461,14 +472,21 @@ namespace Emby.Server.Implementations.LiveTv.Listings
// The data can be large so give it some extra time
TimeoutMs = 60000
};
- List<ScheduleDirect.ShowImages> images;
- using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false))
+
+ try
{
- images = _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.ShowImages>>(
- innerResponse2.Content);
+ using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false))
+ {
+ return _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.ShowImages>>(
+ innerResponse2.Content);
+ }
}
+ catch (Exception ex)
+ {
+ _logger.ErrorException("Error getting image info from schedules direct", ex);
- return images;
+ return new List<ScheduleDirect.ShowImages>();
+ }
}
public async Task<List<NameIdPair>> GetHeadends(ListingsProviderInfo info, string country, string location, CancellationToken cancellationToken)
diff --git a/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs b/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs
index 0313e6fde..2ee6869f6 100644
--- a/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveStreamHelper.cs
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
namespace Emby.Server.Implementations.LiveTv
@@ -21,7 +22,7 @@ namespace Emby.Server.Implementations.LiveTv
_logger = logger;
}
- public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, CancellationToken cancellationToken)
+ public async Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, bool assumeInterlaced, CancellationToken cancellationToken)
{
var originalRuntime = mediaSource.RunTimeTicks;
@@ -95,6 +96,17 @@ namespace Emby.Server.Implementations.LiveTv
videoStream.IsAVC = null;
}
+ if (assumeInterlaced)
+ {
+ foreach (var mediaStream in mediaSource.MediaStreams)
+ {
+ if (mediaStream.Type == MediaStreamType.Video)
+ {
+ mediaStream.IsInterlaced = true;
+ }
+ }
+ }
+
// Try to estimate this
mediaSource.InferTotalBitrate(true);
}
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index e59a8f93c..e30280967 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -246,9 +246,9 @@ namespace Emby.Server.Implementations.LiveTv
return info.Item1;
}
- public async Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken)
+ public Task<Tuple<MediaSourceInfo, IDirectStreamProvider, bool>> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken)
{
- return await GetLiveStream(id, mediaSourceId, true, cancellationToken).ConfigureAwait(false);
+ return GetLiveStream(id, mediaSourceId, true, cancellationToken);
}
private string GetItemExternalId(BaseItem item)
@@ -308,7 +308,7 @@ namespace Emby.Server.Implementations.LiveTv
return _services.FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
}
- private async Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStream(string id, string mediaSourceId, bool isChannel, CancellationToken cancellationToken)
+ private async Task<Tuple<MediaSourceInfo, IDirectStreamProvider, bool>> GetLiveStream(string id, string mediaSourceId, bool isChannel, CancellationToken cancellationToken)
{
if (string.Equals(id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
{
@@ -319,6 +319,7 @@ namespace Emby.Server.Implementations.LiveTv
bool isVideo;
ILiveTvService service;
IDirectStreamProvider directStreamProvider = null;
+ var assumeInterlaced = false;
if (isChannel)
{
@@ -365,10 +366,14 @@ namespace Emby.Server.Implementations.LiveTv
}
}
- _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
Normalize(info, service, isVideo);
- return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info, directStreamProvider);
+ if (!(service is EmbyTV.EmbyTV))
+ {
+ assumeInterlaced = true;
+ }
+
+ return new Tuple<MediaSourceInfo, IDirectStreamProvider, bool>(info, directStreamProvider, assumeInterlaced);
}
private void Normalize(MediaSourceInfo mediaSource, ILiveTvService service, bool isVideo)
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
index dd95660c7..e25e28484 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -126,12 +126,14 @@ namespace Emby.Server.Implementations.LiveTv
var keys = openToken.Split(new[] { StreamIdDelimeter }, 3);
var mediaSourceId = keys.Length >= 3 ? keys[2] : null;
IDirectStreamProvider directStreamProvider = null;
+ var assumeInterlaced = false;
if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase))
{
var info = await _liveTvManager.GetChannelStream(keys[1], mediaSourceId, cancellationToken).ConfigureAwait(false);
stream = info.Item1;
directStreamProvider = info.Item2;
+ assumeInterlaced = info.Item3;
}
else
{
@@ -146,7 +148,7 @@ namespace Emby.Server.Implementations.LiveTv
}
else
{
- await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, cancellationToken).ConfigureAwait(false);
+ await new LiveStreamHelper(_mediaEncoder, _logger).AddMediaInfoWithProbe(stream, isAudio, assumeInterlaced, cancellationToken).ConfigureAwait(false);
}
}
catch (Exception ex)
@@ -154,6 +156,7 @@ namespace Emby.Server.Implementations.LiveTv
_logger.ErrorException("Error probing live tv stream", ex);
}
+ _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(stream));
return new Tuple<MediaSourceInfo, IDirectStreamProvider>(stream, directStreamProvider);
}
diff --git a/Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs b/Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs
index 5a0389b16..5cff88a67 100644
--- a/Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/ProgramImageProvider.cs
@@ -50,13 +50,16 @@ namespace Emby.Server.Implementations.LiveTv
{
var channel = _liveTvManager.GetInternalChannel(liveTvItem.ChannelId);
- var response = await service.GetProgramImageAsync(GetItemExternalId(liveTvItem), GetItemExternalId(channel), cancellationToken).ConfigureAwait(false);
-
- if (response != null)
+ if (channel != null)
{
- imageResponse.HasImage = true;
- imageResponse.Stream = response.Stream;
- imageResponse.Format = response.Format;
+ var response = await service.GetProgramImageAsync(GetItemExternalId(liveTvItem), GetItemExternalId(channel), cancellationToken).ConfigureAwait(false);
+
+ if (response != null)
+ {
+ imageResponse.HasImage = true;
+ imageResponse.Stream = response.Stream;
+ imageResponse.Format = response.Format;
+ }
}
}
catch (NotImplementedException)
diff --git a/Emby.Server.Implementations/packages.config b/Emby.Server.Implementations/packages.config
index 5249577e6..3c82e979b 100644
--- a/Emby.Server.Implementations/packages.config
+++ b/Emby.Server.Implementations/packages.config
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="Emby.XmlTv" version="1.0.5" targetFramework="portable45-net45+win8" />
+ <package id="Emby.XmlTv" version="1.0.6" targetFramework="portable45-net45+win8" />
<package id="MediaBrowser.Naming" version="1.0.4" targetFramework="portable45-net45+win8" />
<package id="SQLitePCL.pretty" version="1.1.0" targetFramework="portable45-net45+win8" />
<package id="SQLitePCLRaw.core" version="1.1.1" targetFramework="portable45-net45+win8" />
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index 04983553b..909fc0623 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -791,7 +791,7 @@ namespace MediaBrowser.Api.LiveTv
ProviderChannels = providerChannels.Select(i => new NameIdPair
{
Name = i.Name,
- Id = i.TunerChannelId
+ Id = string.IsNullOrWhiteSpace(i.TunerChannelId) ? i.Id : i.TunerChannelId
}).ToList(),
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index f5fd94d0e..e010f122c 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -119,6 +119,7 @@ namespace MediaBrowser.Api
config.SkipDeserializationForAudio = true;
config.EnableSeriesPresentationUniqueKey = true;
config.EnableLocalizedGuids = true;
+ config.EnableSimpleArtistDetection = true;
}
public void Post(UpdateStartupConfiguration request)
diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs
index e1ecd6595..4a894e662 100644
--- a/MediaBrowser.Common/Net/HttpRequestOptions.cs
+++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs
@@ -100,6 +100,7 @@ namespace MediaBrowser.Common.Net
public int TimeoutMs { get; set; }
public bool PreferIpv4 { get; set; }
+ public bool EnableDefaultUserAgent { get; set; }
private string GetHeaderValue(string name)
{
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index 08e4956ad..a908d2d3f 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -157,7 +157,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="mediaSourceId">The media source identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{StreamResponseInfo}.</returns>
- Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken);
+ Task<Tuple<MediaSourceInfo, IDirectStreamProvider, bool>> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken);
/// <summary>
/// Gets the program.
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index ee3482a70..e7737b6a6 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -725,11 +725,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (video.Protocol != MediaProtocol.File)
{
- // If it's mpeg based, assume true
- if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) != -1)
- {
- return true;
- }
return false;
}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index f9df776df..c2b1e3c89 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -192,6 +192,10 @@ namespace MediaBrowser.Model.Configuration
public bool EnableExternalContentInSuggestions { get; set; }
public int ImageExtractionTimeoutMs { get; set; }
+
+ public PathSubstitution[] PathSubstitutions { get; set; }
+ public bool EnableSimpleArtistDetection { get; set; }
+
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
/// </summary>
@@ -202,6 +206,8 @@ namespace MediaBrowser.Model.Configuration
Migrations = new string[] { };
ImageExtractionTimeoutMs = 0;
EnableLocalizedGuids = true;
+ PathSubstitutions = new PathSubstitution[] { };
+ EnableSimpleArtistDetection = true;
DisplaySpecialsWithinSeasons = true;
EnableExternalContentInSuggestions = true;
@@ -563,4 +569,10 @@ namespace MediaBrowser.Model.Configuration
};
}
}
+
+ public class PathSubstitution
+ {
+ public string From { get; set; }
+ public string To { get; set; }
+ }
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Entities/MetadataProviders.cs b/MediaBrowser.Model/Entities/MetadataProviders.cs
index 1e7bde934..efd4339d5 100644
--- a/MediaBrowser.Model/Entities/MetadataProviders.cs
+++ b/MediaBrowser.Model/Entities/MetadataProviders.cs
@@ -24,10 +24,6 @@ namespace MediaBrowser.Model.Entities
/// </summary>
Tvcom = 5,
/// <summary>
- /// The rotten tomatoes
- /// </summary>
- RottenTomatoes = 6,
- /// <summary>
/// Tmdb Collection Id
/// </summary>
TmdbCollection = 7,
diff --git a/MediaBrowser.Model/System/IEnvironmentInfo.cs b/MediaBrowser.Model/System/IEnvironmentInfo.cs
index abe39fa03..2c57df97c 100644
--- a/MediaBrowser.Model/System/IEnvironmentInfo.cs
+++ b/MediaBrowser.Model/System/IEnvironmentInfo.cs
@@ -17,6 +17,7 @@ namespace MediaBrowser.Model.System
{
Windows,
Linux,
- OSX
+ OSX,
+ BSD
}
}
diff --git a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
index 3f969b609..96eab63cd 100644
--- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
+++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
@@ -142,7 +142,7 @@ namespace MediaBrowser.Providers.Music
if (fileInfo.Exists)
{
- if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 7)
+ if ((DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(fileInfo)).TotalDays <= 3)
{
return _cachedTask;
}
diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
index 07b35c45a..fdd334e6e 100644
--- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs
@@ -347,7 +347,8 @@ namespace MediaBrowser.Providers.Omdb
Url = url,
ResourcePool = ResourcePool,
CancellationToken = cancellationToken,
- BufferContent = true
+ BufferContent = true,
+ EnableDefaultUserAgent = true
});
}
@@ -384,10 +385,11 @@ namespace MediaBrowser.Providers.Omdb
{
T item = itemResult.Item;
+ var isConfiguredForEnglish = IsConfiguredForEnglish(item);
+
// Grab series genres because imdb data is better than tvdb. Leave movies alone
// But only do it if english is the preferred language because this data will not be localized
- if (ShouldFetchGenres(item) &&
- !string.IsNullOrWhiteSpace(result.Genre))
+ if (isConfiguredForEnglish && !string.IsNullOrWhiteSpace(result.Genre))
{
item.Genres.Clear();
@@ -417,8 +419,11 @@ namespace MediaBrowser.Providers.Omdb
hasAwards.AwardSummary = WebUtility.HtmlDecode(result.Awards);
}
- // Imdb plots are usually pretty short
- item.Overview = result.Plot;
+ if (isConfiguredForEnglish)
+ {
+ // Omdb is currently english only, so for other languages skip this and let secondary providers fill it in
+ item.Overview = result.Plot;
+ }
//if (!string.IsNullOrWhiteSpace(result.Director))
//{
@@ -461,7 +466,7 @@ namespace MediaBrowser.Providers.Omdb
//}
}
- private bool ShouldFetchGenres(BaseItem item)
+ private bool IsConfiguredForEnglish(BaseItem item)
{
var lang = item.GetPreferredMetadataLanguage();
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index 8100dec8d..4790378a9 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -319,5 +319,18 @@ namespace MediaBrowser.Server.Mono
{
return Syscall.getuid().ToString(CultureInfo.InvariantCulture);
}
+
+ public override Model.System.OperatingSystem OperatingSystem
+ {
+ get
+ {
+ if (IsBsd)
+ {
+ return Model.System.OperatingSystem.BSD;
+ }
+
+ return base.OperatingSystem;
+ }
+ }
}
}
diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs
index 91c23f871..c6cdeb354 100644
--- a/MediaBrowser.WebDashboard/Api/DashboardService.cs
+++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs
@@ -139,6 +139,23 @@ namespace MediaBrowser.WebDashboard.Api
_memoryStreamFactory = memoryStreamFactory;
}
+ /// <summary>
+ /// Gets the dashboard UI path.
+ /// </summary>
+ /// <value>The dashboard UI path.</value>
+ public string DashboardUIPath
+ {
+ get
+ {
+ if (!string.IsNullOrEmpty(_serverConfigurationManager.Configuration.DashboardSourcePath))
+ {
+ return _serverConfigurationManager.Configuration.DashboardSourcePath;
+ }
+
+ return Path.Combine(_serverConfigurationManager.ApplicationPaths.ApplicationResourcesPath, "dashboard-ui");
+ }
+ }
+
public object Get(GetFavIcon request)
{
return Get(new GetDashboardResource
@@ -176,7 +193,7 @@ namespace MediaBrowser.WebDashboard.Api
if (plugin != null && stream != null)
{
- return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator().ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersion.ToString(), null));
+ return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator(DashboardUIPath).ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersion.ToString(), null));
}
throw new ResourceNotFoundException();
@@ -274,9 +291,11 @@ namespace MediaBrowser.WebDashboard.Api
path = path.Replace("bower_components" + _appHost.ApplicationVersion, "bower_components", StringComparison.OrdinalIgnoreCase);
var contentType = MimeTypes.GetMimeType(path);
+ var basePath = DashboardUIPath;
// Bounce them to the startup wizard if it hasn't been completed yet
- if (!_serverConfigurationManager.Configuration.IsStartupWizardCompleted && path.IndexOf("wizard", StringComparison.OrdinalIgnoreCase) == -1 && GetPackageCreator().IsCoreHtml(path))
+ if (!_serverConfigurationManager.Configuration.IsStartupWizardCompleted &&
+ path.IndexOf("wizard", StringComparison.OrdinalIgnoreCase) == -1 && GetPackageCreator(basePath).IsCoreHtml(path))
{
// But don't redirect if an html import is being requested.
if (path.IndexOf("bower_components", StringComparison.OrdinalIgnoreCase) == -1)
@@ -296,7 +315,7 @@ namespace MediaBrowser.WebDashboard.Api
!contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase) &&
!contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase))
{
- var stream = await GetResourceStream(path, localizationCulture).ConfigureAwait(false);
+ var stream = await GetResourceStream(basePath, path, localizationCulture).ConfigureAwait(false);
return _resultFactory.GetResult(stream, contentType);
}
@@ -311,7 +330,7 @@ namespace MediaBrowser.WebDashboard.Api
var cacheKey = (_appHost.ApplicationVersion + (localizationCulture ?? string.Empty) + path).GetMD5();
- return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(path, localizationCulture)).ConfigureAwait(false);
+ return await _resultFactory.GetStaticResult(Request, cacheKey, null, cacheDuration, contentType, () => GetResourceStream(basePath, path, localizationCulture)).ConfigureAwait(false);
}
private string GetLocalizationCulture()
@@ -322,86 +341,72 @@ namespace MediaBrowser.WebDashboard.Api
/// <summary>
/// Gets the resource stream.
/// </summary>
- /// <param name="path">The path.</param>
- /// <param name="localizationCulture">The localization culture.</param>
- /// <returns>Task{Stream}.</returns>
- private Task<Stream> GetResourceStream(string path, string localizationCulture)
+ private Task<Stream> GetResourceStream(string basePath, string virtualPath, string localizationCulture)
{
- return GetPackageCreator()
- .GetResource(path, null, localizationCulture, _appHost.ApplicationVersion.ToString());
+ return GetPackageCreator(basePath)
+ .GetResource(virtualPath, null, localizationCulture, _appHost.ApplicationVersion.ToString());
}
- private PackageCreator GetPackageCreator()
+ private PackageCreator GetPackageCreator(string basePath)
{
- return new PackageCreator(_fileSystem, _logger, _serverConfigurationManager, _memoryStreamFactory);
+ return new PackageCreator(basePath, _fileSystem, _logger, _serverConfigurationManager, _memoryStreamFactory);
}
public async Task<object> Get(GetDashboardPackage request)
{
var mode = request.Mode;
- var path = !string.IsNullOrWhiteSpace(mode) ?
- Path.Combine(_serverConfigurationManager.ApplicationPaths.ProgramDataPath, "webclient-dump")
+ var inputPath = string.IsNullOrWhiteSpace(mode) ?
+ DashboardUIPath
+ : "C:\\dev\\emby-web-mobile-master\\dist";
+
+ var targetPath = !string.IsNullOrWhiteSpace(mode) ?
+ inputPath
: "C:\\dev\\emby-web-mobile\\src";
- try
- {
- _fileSystem.DeleteDirectory(path, true);
- }
- catch (IOException)
- {
+ var packageCreator = GetPackageCreator(inputPath);
- }
+ if (!string.Equals(inputPath, targetPath, StringComparison.OrdinalIgnoreCase))
+ {
+ try
+ {
+ _fileSystem.DeleteDirectory(targetPath, true);
+ }
+ catch (IOException)
+ {
- var creator = GetPackageCreator();
+ }
- CopyDirectory(creator.DashboardUIPath, path);
+ CopyDirectory(inputPath, targetPath);
+ }
string culture = null;
var appVersion = _appHost.ApplicationVersion.ToString();
- // Try to trim the output size a bit
- var bowerPath = Path.Combine(path, "bower_components");
-
- if (!string.IsNullOrWhiteSpace(mode))
- {
- // Delete things that are unneeded in an attempt to keep the output as trim as possible
-
- DeleteFoldersByName(Path.Combine(bowerPath, "emby-webcomponents", "fonts"), "roboto");
- _fileSystem.DeleteDirectory(Path.Combine(path, "css", "images", "tour"), true);
- }
-
- await DumpHtml(creator.DashboardUIPath, path, mode, culture, appVersion);
+ await DumpHtml(packageCreator, inputPath, targetPath, mode, culture, appVersion);
return "";
}
- private void DeleteFoldersByName(string path, string name)
- {
- var directories = _fileSystem.GetDirectories(path, true)
- .Where(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase))
- .ToList();
-
- foreach (var directory in directories)
- {
- _fileSystem.DeleteDirectory(directory.FullName, true);
- }
- }
-
- private async Task DumpHtml(string source, string destination, string mode, string culture, string appVersion)
+ private async Task DumpHtml(PackageCreator packageCreator, string source, string destination, string mode, string culture, string appVersion)
{
foreach (var file in _fileSystem.GetFiles(source))
{
var filename = file.Name;
- await DumpFile(filename, Path.Combine(destination, filename), mode, culture, appVersion).ConfigureAwait(false);
+ if (!string.Equals(file.Extension, ".html", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ await DumpFile(packageCreator, filename, Path.Combine(destination, filename), mode, culture, appVersion).ConfigureAwait(false);
}
}
- private async Task DumpFile(string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion)
+ private async Task DumpFile(PackageCreator packageCreator, string resourceVirtualPath, string destinationFilePath, string mode, string culture, string appVersion)
{
- using (var stream = await GetPackageCreator().GetResource(resourceVirtualPath, mode, culture, appVersion).ConfigureAwait(false))
+ using (var stream = await packageCreator.GetResource(resourceVirtualPath, mode, culture, appVersion).ConfigureAwait(false))
{
using (var fs = _fileSystem.GetFileStream(destinationFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read))
{
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 453f46edd..f124b6e4b 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -19,31 +19,33 @@ namespace MediaBrowser.WebDashboard.Api
private readonly ILogger _logger;
private readonly IServerConfigurationManager _config;
private readonly IMemoryStreamFactory _memoryStreamFactory;
+ private readonly string _basePath;
- public PackageCreator(IFileSystem fileSystem, ILogger logger, IServerConfigurationManager config, IMemoryStreamFactory memoryStreamFactory)
+ public PackageCreator(string basePath, IFileSystem fileSystem, ILogger logger, IServerConfigurationManager config, IMemoryStreamFactory memoryStreamFactory)
{
_fileSystem = fileSystem;
_logger = logger;
_config = config;
_memoryStreamFactory = memoryStreamFactory;
+ _basePath = basePath;
}
- public async Task<Stream> GetResource(string path,
+ public async Task<Stream> GetResource(string virtualPath,
string mode,
string localizationCulture,
string appVersion)
{
- var resourceStream = GetRawResourceStream(path);
+ var resourceStream = GetRawResourceStream(virtualPath);
if (resourceStream != null)
{
// Don't apply any caching for html pages
// jQuery ajax doesn't seem to handle if-modified-since correctly
- if (IsFormat(path, "html"))
+ if (IsFormat(virtualPath, "html"))
{
- if (IsCoreHtml(path))
+ if (IsCoreHtml(virtualPath))
{
- resourceStream = await ModifyHtml(path, resourceStream, mode, appVersion, localizationCulture).ConfigureAwait(false);
+ resourceStream = await ModifyHtml(virtualPath, resourceStream, mode, appVersion, localizationCulture).ConfigureAwait(false);
}
}
}
@@ -63,32 +65,12 @@ namespace MediaBrowser.WebDashboard.Api
}
/// <summary>
- /// Gets the dashboard UI path.
- /// </summary>
- /// <value>The dashboard UI path.</value>
- public string DashboardUIPath
- {
- get
- {
- if (!string.IsNullOrEmpty(_config.Configuration.DashboardSourcePath))
- {
- return _config.Configuration.DashboardSourcePath;
- }
-
- return Path.Combine(_config.ApplicationPaths.ApplicationResourcesPath, "dashboard-ui");
- }
- }
-
- /// <summary>
/// Gets the dashboard resource path.
/// </summary>
- /// <param name="virtualPath">The virtual path.</param>
/// <returns>System.String.</returns>
private string GetDashboardResourcePath(string virtualPath)
{
- var rootPath = DashboardUIPath;
-
- var fullPath = Path.Combine(rootPath, virtualPath.Replace('/', _fileSystem.DirectorySeparatorChar));
+ var fullPath = Path.Combine(_basePath, virtualPath.Replace('/', _fileSystem.DirectorySeparatorChar));
try
{
@@ -100,7 +82,7 @@ namespace MediaBrowser.WebDashboard.Api
}
// Don't allow file system access outside of the source folder
- if (!_fileSystem.ContainsSubPath(rootPath, fullPath))
+ if (!_fileSystem.ContainsSubPath(_basePath, fullPath))
{
throw new SecurityException("Access denied");
}
@@ -118,10 +100,8 @@ namespace MediaBrowser.WebDashboard.Api
path = GetDashboardResourcePath(path);
var parent = Path.GetDirectoryName(path);
- var basePath = DashboardUIPath;
-
- return string.Equals(basePath, parent, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(Path.Combine(basePath, "voice"), parent, StringComparison.OrdinalIgnoreCase);
+ return string.Equals(_basePath, parent, StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(Path.Combine(_basePath, "voice"), parent, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@@ -319,11 +299,9 @@ namespace MediaBrowser.WebDashboard.Api
/// <summary>
/// Gets the raw resource stream.
/// </summary>
- /// <param name="path">The path.</param>
- /// <returns>Task{Stream}.</returns>
- private Stream GetRawResourceStream(string path)
+ private Stream GetRawResourceStream(string virtualPath)
{
- return _fileSystem.GetFileStream(GetDashboardResourcePath(path), FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, true);
+ return _fileSystem.GetFileStream(GetDashboardResourcePath(virtualPath), FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, true);
}
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 4f7715874..5a1c7bf13 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -579,14 +579,6 @@ namespace MediaBrowser.XbmcMetadata.Savers
writer.WriteElementString("website", item.HomePageUrl);
}
- var rt = item.GetProviderId(MetadataProviders.RottenTomatoes);
-
- if (!string.IsNullOrEmpty(rt))
- {
- writer.WriteElementString("rottentomatoesid", rt);
- writtenProviderIds.Add(MetadataProviders.RottenTomatoes.ToString());
- }
-
var tmdbCollection = item.GetProviderId(MetadataProviders.TmdbCollection);
if (!string.IsNullOrEmpty(tmdbCollection))
diff --git a/RSSDP/SsdpDeviceLocatorBase.cs b/RSSDP/SsdpDeviceLocatorBase.cs
index 4f5eae616..1adb95cdf 100644
--- a/RSSDP/SsdpDeviceLocatorBase.cs
+++ b/RSSDP/SsdpDeviceLocatorBase.cs
@@ -24,11 +24,9 @@ namespace Rssdp.Infrastructure
private List<DiscoveredSsdpDevice> _Devices;
private ISsdpCommunicationsServer _CommunicationsServer;
- private IList<DiscoveredSsdpDevice> _SearchResults;
- private object _SearchResultsSynchroniser;
-
- private ITimer _ExpireCachedDevicesTimer;
+ private ITimer _BroadcastTimer;
private ITimerFactory _timerFactory;
+ private object _timerLock = new object();
private static readonly TimeSpan DefaultSearchWaitTime = TimeSpan.FromSeconds(4);
private static readonly TimeSpan OneSecond = TimeSpan.FromSeconds(1);
@@ -48,7 +46,6 @@ namespace Rssdp.Infrastructure
_timerFactory = timerFactory;
_CommunicationsServer.ResponseReceived += CommsServer_ResponseReceived;
- _SearchResultsSynchroniser = new object();
_Devices = new List<DiscoveredSsdpDevice>();
}
@@ -92,11 +89,52 @@ namespace Rssdp.Infrastructure
#region Search Overloads
+ public void RestartBroadcastTimer(TimeSpan dueTime, TimeSpan period)
+ {
+ lock (_timerLock)
+ {
+ if (_BroadcastTimer == null)
+ {
+ _BroadcastTimer = _timerFactory.Create(OnBroadcastTimerCallback, null, dueTime, period);
+ }
+ else
+ {
+ _BroadcastTimer.Change(dueTime, period);
+ }
+ }
+ }
+
+ public void DisposeBroadcastTimer()
+ {
+ lock (_timerLock)
+ {
+ if (_BroadcastTimer != null)
+ {
+ _BroadcastTimer.Dispose();
+ _BroadcastTimer = null;
+ }
+ }
+ }
+
+ private async void OnBroadcastTimerCallback(object state)
+ {
+ StartListeningForNotifications();
+ RemoveExpiredDevicesFromCache();
+
+ try
+ {
+ await SearchAsync(CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+
+ }
+ }
+
/// <summary>
/// Performs a search for all devices using the default search timeout.
/// </summary>
- /// <returns>A task whose result is an <see cref="IEnumerable{T}"/> of <see cref="DiscoveredSsdpDevice" /> instances, representing all found devices.</returns>
- public Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(CancellationToken cancellationToken)
+ private Task SearchAsync(CancellationToken cancellationToken)
{
return SearchAsync(SsdpConstants.SsdpDiscoverAllSTHeader, DefaultSearchWaitTime, cancellationToken);
}
@@ -111,8 +149,7 @@ namespace Rssdp.Infrastructure
/// <item><term>Device type</term><description>Fully qualified device type starting with urn: i.e urn:schemas-upnp-org:Basic:1</description></item>
/// </list>
/// </param>
- /// <returns>A task whose result is an <see cref="IEnumerable{T}"/> of <see cref="DiscoveredSsdpDevice" /> instances, representing all found devices.</returns>
- public Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(string searchTarget)
+ private Task SearchAsync(string searchTarget)
{
return SearchAsync(searchTarget, DefaultSearchWaitTime, CancellationToken.None);
}
@@ -121,13 +158,12 @@ namespace Rssdp.Infrastructure
/// Performs a search for all devices using the specified search timeout.
/// </summary>
/// <param name="searchWaitTime">The amount of time to wait for network responses to the search request. Longer values will likely return more devices, but increase search time. A value between 1 and 5 seconds is recommended by the UPnP 1.1 specification, this method requires the value be greater 1 second if it is not zero. Specify TimeSpan.Zero to return only devices already in the cache.</param>
- /// <returns>A task whose result is an <see cref="IEnumerable{T}"/> of <see cref="DiscoveredSsdpDevice" /> instances, representing all found devices.</returns>
- public Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(TimeSpan searchWaitTime)
+ private Task SearchAsync(TimeSpan searchWaitTime)
{
return SearchAsync(SsdpConstants.SsdpDiscoverAllSTHeader, searchWaitTime, CancellationToken.None);
}
- public async Task<IEnumerable<DiscoveredSsdpDevice>> SearchAsync(string searchTarget, TimeSpan searchWaitTime, CancellationToken cancellationToken)
+ private Task SearchAsync(string searchTarget, TimeSpan searchWaitTime, CancellationToken cancellationToken)
{
if (searchTarget == null) throw new ArgumentNullException("searchTarget");
if (searchTarget.Length == 0) throw new ArgumentException("searchTarget cannot be an empty string.", "searchTarget");
@@ -136,48 +172,7 @@ namespace Rssdp.Infrastructure
ThrowIfDisposed();
- if (_SearchResults != null) throw new InvalidOperationException("Search already in progress. Only one search at a time is allowed.");
- _SearchResults = new List<DiscoveredSsdpDevice>();
-
- // If searchWaitTime == 0 then we are only going to report unexpired cached items, not actually do a search.
- if (searchWaitTime > TimeSpan.Zero)
- await BroadcastDiscoverMessage(searchTarget, SearchTimeToMXValue(searchWaitTime), cancellationToken).ConfigureAwait(false);
-
- lock (_SearchResultsSynchroniser)
- {
- foreach (var device in GetUnexpiredDevices().Where(NotificationTypeMatchesFilter))
- {
- DeviceFound(device, false, null);
- }
- }
-
- if (searchWaitTime != TimeSpan.Zero)
- await Task.Delay(searchWaitTime, cancellationToken).ConfigureAwait(false);
-
- IEnumerable<DiscoveredSsdpDevice> retVal = null;
-
- try
- {
- lock (_SearchResultsSynchroniser)
- {
- retVal = _SearchResults;
- _SearchResults = null;
- }
-
- RemoveExpiredDevicesFromCache();
- }
- finally
- {
- var server = _CommunicationsServer;
- try
- {
- if (server != null) // In case we were disposed while searching.
- server.StopListeningForResponses();
- }
- catch (ObjectDisposedException) { }
- }
-
- return retVal;
+ return BroadcastDiscoverMessage(searchTarget, SearchTimeToMXValue(searchWaitTime), cancellationToken);
}
#endregion
@@ -287,9 +282,7 @@ namespace Rssdp.Infrastructure
if (disposing)
{
- var timer = _ExpireCachedDevicesTimer;
- if (timer != null)
- timer.Dispose();
+ DisposeBroadcastTimer();
var commsServer = _CommunicationsServer;
_CommunicationsServer = null;
@@ -332,40 +325,9 @@ namespace Rssdp.Infrastructure
private void DeviceFound(DiscoveredSsdpDevice device, bool isNewDevice, IpAddressInfo localIpAddress)
{
- // Don't raise the event if we've already done it for a cached
- // version of this device, and the cached version isn't
- // "significantly" different, i.e location and cachelifetime
- // haven't changed.
- var raiseEvent = false;
-
if (!NotificationTypeMatchesFilter(device)) return;
- lock (_SearchResultsSynchroniser)
- {
- if (_SearchResults != null)
- {
- var existingDevice = FindExistingDeviceNotification(_SearchResults, device.NotificationType, device.Usn);
- if (existingDevice == null)
- {
- _SearchResults.Add(device);
- raiseEvent = true;
- }
- else
- {
- if (existingDevice.DescriptionLocation != device.DescriptionLocation || existingDevice.CacheLifetime != device.CacheLifetime)
- {
- _SearchResults.Remove(existingDevice);
- _SearchResults.Add(device);
- raiseEvent = true;
- }
- }
- }
- else
- raiseEvent = true;
- }
-
- if (raiseEvent)
- OnDeviceAvailable(device, isNewDevice, localIpAddress);
+ OnDeviceAvailable(device, isNewDevice, localIpAddress);
}
private bool NotificationTypeMatchesFilter(DiscoveredSsdpDevice device)
@@ -450,8 +412,6 @@ namespace Rssdp.Infrastructure
};
AddOrUpdateDiscoveredDevice(device, localIpAddress);
-
- ResetExpireCachedDevicesTimer();
}
}
@@ -477,26 +437,9 @@ namespace Rssdp.Infrastructure
if (NotificationTypeMatchesFilter(deadDevice))
OnDeviceUnavailable(deadDevice, false);
}
-
- ResetExpireCachedDevicesTimer();
}
}
- private void ResetExpireCachedDevicesTimer()
- {
- if (IsDisposed) return;
-
- if (_ExpireCachedDevicesTimer == null)
- _ExpireCachedDevicesTimer = _timerFactory.Create(this.ExpireCachedDevices, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
-
- _ExpireCachedDevicesTimer.Change(60000, System.Threading.Timeout.Infinite);
- }
-
- private void ExpireCachedDevices(object state)
- {
- RemoveExpiredDevicesFromCache();
- }
-
#region Header/Message Processing Utilities
private static string GetFirstHeaderStringValue(string headerName, HttpResponseMessage message)
@@ -624,20 +567,6 @@ namespace Rssdp.Infrastructure
if (existingDevices != null && existingDevices.Any())
{
- lock (_SearchResultsSynchroniser)
- {
- if (_SearchResults != null)
- {
- var resultsToRemove = (from result in _SearchResults where result.Usn == deviceUsn select result).ToArray();
- foreach (var result in resultsToRemove)
- {
- if (this.IsDisposed) return true;
-
- _SearchResults.Remove(result);
- }
- }
- }
-
foreach (var removedDevice in existingDevices)
{
if (NotificationTypeMatchesFilter(removedDevice))