Merge pull request #2364 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2016-12-22 18:54:45 -05:00 committed by GitHub
commit 026e58eb16
19 changed files with 190 additions and 161 deletions

View file

@ -10,11 +10,17 @@ namespace Emby.Common.Implementations.EnvironmentInfo
public class EnvironmentInfo : IEnvironmentInfo
{
public MediaBrowser.Model.System.Architecture? CustomArchitecture { get; set; }
public MediaBrowser.Model.System.OperatingSystem? CustomOperatingSystem { get; set; }
public MediaBrowser.Model.System.OperatingSystem OperatingSystem
{
get
{
if (CustomOperatingSystem.HasValue)
{
return CustomOperatingSystem.Value;
}
#if NET46
switch (Environment.OSVersion.Platform)
{

View file

@ -282,9 +282,12 @@ namespace Emby.Common.Implementations.ScheduledTasks
throw new ArgumentNullException("value");
}
SaveTriggers(value);
// This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly
var triggerList = value.Where(i => i != null).ToArray();
InternalTriggers = value.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
SaveTriggers(triggerList);
InternalTriggers = triggerList.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
}
}
@ -535,7 +538,8 @@ namespace Emby.Common.Implementations.ScheduledTasks
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
private Tuple<TaskTriggerInfo, ITaskTrigger>[] LoadTriggers()
{
var settings = LoadTriggerSettings();
// This null check is not great, but is needed to handle bad user input, or user mucking with the config file incorrectly
var settings = LoadTriggerSettings().Where(i => i != null).ToArray();
return settings.Select(i => new Tuple<TaskTriggerInfo, ITaskTrigger>(i, GetTrigger(i))).ToArray();
}
@ -544,8 +548,12 @@ namespace Emby.Common.Implementations.ScheduledTasks
{
try
{
return JsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath())
.ToArray();
var list = JsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath());
if (list != null)
{
return list.ToArray();
}
}
catch (FileNotFoundException)
{
@ -555,8 +563,8 @@ namespace Emby.Common.Implementations.ScheduledTasks
catch (DirectoryNotFoundException)
{
// File doesn't exist. No biggie. Return defaults.
return ScheduledTask.GetDefaultTriggers().ToArray();
}
return ScheduledTask.GetDefaultTriggers().ToArray();
}
/// <summary>

View file

@ -1583,7 +1583,8 @@ namespace Emby.Server.Core
public void LaunchUrl(string url)
{
if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows)
if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows &&
EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX)
{
throw new NotImplementedException();
}
@ -1591,7 +1592,7 @@ namespace Emby.Server.Core
var process = ProcessFactory.Create(new ProcessOptions
{
FileName = url,
EnableRaisingEvents = true,
//EnableRaisingEvents = true,
UseShellExecute = true,
ErrorDialog = false
});

View file

@ -203,20 +203,12 @@ namespace Emby.Server.Implementations.HttpServer
// Do not use the memoryStreamFactory here, they don't place nice with compression
using (var ms = new MemoryStream())
{
using (var compressionStream = GetCompressionStream(ms, compressionType))
{
ContentTypes.Instance.SerializeToStream(request, dto, compressionStream);
compressionStream.Dispose();
ContentTypes.Instance.SerializeToStream(request, dto, ms);
ms.Position = 0;
var compressedBytes = ms.ToArray();
var responseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var httpResult = new StreamWriter(compressedBytes, request.ResponseContentType, _logger);
//httpResult.Headers["Content-Length"] = compressedBytes.Length.ToString(UsCulture);
httpResult.Headers["Content-Encoding"] = compressionType;
return httpResult;
}
return GetCompressedResult(ms, compressionType, responseHeaders, false, request.ResponseContentType).Result;
}
}
@ -591,45 +583,53 @@ namespace Emby.Server.Implementations.HttpServer
};
}
string content;
using (var stream = await factoryFn().ConfigureAwait(false))
{
using (var reader = new StreamReader(stream))
{
content = await reader.ReadToEndAsync().ConfigureAwait(false);
}
return await GetCompressedResult(stream, requestedCompressionType, responseHeaders, isHeadRequest, contentType).ConfigureAwait(false);
}
var contents = Compress(content, requestedCompressionType);
responseHeaders["Content-Length"] = contents.Length.ToString(UsCulture);
responseHeaders["Content-Encoding"] = requestedCompressionType;
if (isHeadRequest)
{
return GetHttpResult(new byte[] { }, contentType, true);
}
return GetHttpResult(contents, contentType, true, responseHeaders);
}
private byte[] Compress(string text, string compressionType)
private async Task<IHasHeaders> GetCompressedResult(Stream stream,
string requestedCompressionType,
IDictionary<string,string> responseHeaders,
bool isHeadRequest,
string contentType)
{
using (var reader = new MemoryStream())
{
await stream.CopyToAsync(reader).ConfigureAwait(false);
reader.Position = 0;
var content = reader.ToArray();
if (content.Length >= 1024)
{
content = Compress(content, requestedCompressionType);
responseHeaders["Content-Encoding"] = requestedCompressionType;
}
responseHeaders["Content-Length"] = content.Length.ToString(UsCulture);
if (isHeadRequest)
{
return GetHttpResult(new byte[] { }, contentType, true);
}
return GetHttpResult(content, contentType, true, responseHeaders);
}
}
private byte[] Compress(byte[] bytes, string compressionType)
{
if (compressionType == "deflate")
return Deflate(text);
return Deflate(bytes);
if (compressionType == "gzip")
return GZip(text);
return GZip(bytes);
throw new NotSupportedException(compressionType);
}
private byte[] Deflate(string text)
{
return Deflate(Encoding.UTF8.GetBytes(text));
}
private byte[] Deflate(byte[] bytes)
{
// In .NET FX incompat-ville, you can't access compressed bytes without closing DeflateStream
@ -644,11 +644,6 @@ namespace Emby.Server.Implementations.HttpServer
}
}
private byte[] GZip(string text)
{
return GZip(Encoding.UTF8.GetBytes(text));
}
private byte[] GZip(byte[] buffer)
{
using (var ms = new MemoryStream())

View file

@ -74,21 +74,21 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
{
return ResolveVideos<MusicVideo>(parent, files, directoryService, false);
return ResolveVideos<MusicVideo>(parent, files, directoryService, false, collectionType);
}
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
{
return ResolveVideos<Video>(parent, files, directoryService, false);
return ResolveVideos<Video>(parent, files, directoryService, false, collectionType);
}
if (string.IsNullOrEmpty(collectionType))
if (string.IsNullOrWhiteSpace(collectionType))
{
// Owned items should just use the plain video type
if (parent == null)
{
return ResolveVideos<Video>(parent, files, directoryService, false);
return ResolveVideos<Video>(parent, files, directoryService, false, collectionType);
}
if (parent is Series || parent.GetParents().OfType<Series>().Any())
@ -96,18 +96,18 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
return null;
}
return ResolveVideos<Movie>(parent, files, directoryService, false);
return ResolveVideos<Movie>(parent, files, directoryService, false, collectionType);
}
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
{
return ResolveVideos<Movie>(parent, files, directoryService, true);
return ResolveVideos<Movie>(parent, files, directoryService, true, collectionType);
}
return null;
}
private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions)
private MultiItemResolverResult ResolveVideos<T>(Folder parent, IEnumerable<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, bool suppportMultiEditions, string collectionType)
where T : Video, new()
{
var files = new List<FileSystemMetadata>();
@ -117,6 +117,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
// Loop through each child file/folder and see if we find a video
foreach (var child in fileSystemEntries)
{
// This is a hack but currently no better way to resolve a sometimes ambiguous situation
if (string.IsNullOrWhiteSpace(collectionType))
{
if (string.Equals(child.Name, "tvshow.nfo", StringComparison.OrdinalIgnoreCase) ||
string.Equals(child.Name, "season.nfo", StringComparison.OrdinalIgnoreCase))
{
return null;
}
}
if (child.IsDirectory)
{
leftOver.Add(child);
@ -408,7 +418,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
!string.Equals(collectionType, CollectionType.Photos) &&
!string.Equals(collectionType, CollectionType.MusicVideos);
var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion);
var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType) ??
new MultiItemResolverResult();
if (result.Items.Count == 1)
{

View file

@ -422,7 +422,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
var showType = details.showType ?? string.Empty;
var info = new ProgramInfo
{
ChannelId = channel,
@ -440,10 +440,23 @@ namespace Emby.Server.Implementations.LiveTv.Listings
IsKids = string.Equals(details.audience, "children", StringComparison.OrdinalIgnoreCase),
IsSports = showType.IndexOf("sports", StringComparison.OrdinalIgnoreCase) != -1,
IsMovie = showType.IndexOf("movie", StringComparison.OrdinalIgnoreCase) != -1 || showType.IndexOf("film", StringComparison.OrdinalIgnoreCase) != -1,
ShowId = programInfo.programID,
Etag = programInfo.md5
};
var showId = programInfo.programID ?? string.Empty;
// According to SchedulesDirect, these are generic, unidentified episodes
// SH005316560000
var hasUniqueShowId = !showId.StartsWith("SH", StringComparison.OrdinalIgnoreCase) ||
!showId.EndsWith("0000", StringComparison.OrdinalIgnoreCase);
if (!hasUniqueShowId)
{
showId = newID;
}
info.ShowId = showId;
if (programInfo.videoProperties != null)
{
info.IsHD = programInfo.videoProperties.Contains("hdtv", StringComparer.OrdinalIgnoreCase);

View file

@ -2647,7 +2647,7 @@ namespace Emby.Server.Implementations.LiveTv
public GuideInfo GetGuideInfo()
{
var startDate = DateTime.UtcNow;
var endDate = startDate.AddDays(14);
var endDate = startDate.AddDays(GetGuideDays());
return new GuideInfo
{

View file

@ -1042,10 +1042,7 @@ namespace Emby.Server.Implementations.Sync
throw new ArgumentException("Operation is not valid for this job item");
}
if (jobItem.Status != SyncJobItemStatus.Synced)
{
jobItem.Status = SyncJobItemStatus.Cancelled;
}
jobItem.Status = SyncJobItemStatus.Cancelled;
jobItem.Progress = 0;
jobItem.IsMarkedForRemoval = true;
@ -1071,18 +1068,18 @@ namespace Emby.Server.Implementations.Sync
_logger.ErrorException("Error deleting directory {0}", ex, path);
}
//var jobItemsResult = GetJobItems(new SyncJobItemQuery
//{
// AddMetadata = false,
// JobId = jobItem.JobId,
// Limit = 0,
// Statuses = new[] { SyncJobItemStatus.Converting, SyncJobItemStatus.Failed, SyncJobItemStatus.Queued, SyncJobItemStatus.ReadyToTransfer, SyncJobItemStatus.Synced, SyncJobItemStatus.Transferring }
//});
var jobItemsResult = GetJobItems(new SyncJobItemQuery
{
AddMetadata = false,
JobId = jobItem.JobId,
Limit = 0,
Statuses = new[] { SyncJobItemStatus.Converting, SyncJobItemStatus.Queued, SyncJobItemStatus.ReadyToTransfer, SyncJobItemStatus.Synced, SyncJobItemStatus.Transferring }
});
//if (jobItemsResult.TotalRecordCount == 0)
//{
// await CancelJob(jobItem.JobId).ConfigureAwait(false);
//}
if (jobItemsResult.TotalRecordCount == 0)
{
await CancelJob(jobItem.JobId).ConfigureAwait(false);
}
}
public Task MarkJobItemForRemoval(string id)

View file

@ -38,6 +38,18 @@ namespace Emby.Server.Implementations.Sync
}
}
if (item.Status == SyncJobItemStatus.Cancelled)
{
try
{
await _sessionManager.SendMessageToUserDeviceSessions(item.TargetId, "SyncJobItemCancelled", item, CancellationToken.None).ConfigureAwait(false);
}
catch
{
}
}
}
public void Dispose()

View file

@ -153,7 +153,7 @@ namespace MediaBrowser.Api.Playback.Progressive
if (!state.RunTimeTicks.HasValue)
{
args += " -fflags +genpts -flags +global_header";
args += " -flags -global_header -fflags +genpts";
}
return args;

View file

@ -95,6 +95,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
int defaultImageExtractionTimeoutMs,
bool enableEncoderFontFile, IEnvironmentInfo environmentInfo)
{
if (jsonSerializer == null)
{
throw new ArgumentNullException("jsonSerializer");
}
_logger = logger;
_jsonSerializer = jsonSerializer;
ConfigurationManager = configurationManager;
@ -632,7 +637,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
if (result.streams == null && result.format == null)
if (result == null || (result.streams == null && result.format == null))
{
throw new Exception("ffprobe failed - streams and format are both null.");
}

View file

@ -238,7 +238,7 @@ namespace MediaBrowser.Providers.TV
var targetSeries = DetermineAppropriateSeries(series, tuple.Item1);
var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(targetSeries.ProviderIds) ?? ((targetSeries.AnimeSeriesIndex ?? 1) - 1);
var unairedThresholdDays = 1;
var unairedThresholdDays = 2;
now = now.AddDays(0 - unairedThresholdDays);
if (airDate.Value < now)

View file

@ -142,7 +142,10 @@ namespace MediaBrowser.Server.Mac
private static EnvironmentInfo GetEnvironmentInfo()
{
var info = new EnvironmentInfo();
var info = new EnvironmentInfo()
{
CustomOperatingSystem = MediaBrowser.Model.System.OperatingSystem.OSX
};
var uname = GetUnixName();

View file

@ -51,8 +51,11 @@ namespace MediaBrowser.Server.Mono
}
else if (environment.OperatingSystem == Model.System.OperatingSystem.Linux)
{
info.FFMpegFilename = "ffmpeg";
info.FFProbeFilename = "ffprobe";
info.ArchiveType = "7z";
info.Version = "20160215";
info.DownloadUrls = GetDownloadUrls();
}
// No version available - user requirement
@ -61,6 +64,25 @@ namespace MediaBrowser.Server.Mono
return info;
}
private string[] GetDownloadUrls()
{
switch (EnvironmentInfo.SystemArchitecture)
{
case Architecture.X64:
return new[]
{
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-git-20160215-64bit-static.7z"
};
case Architecture.X86:
return new[]
{
"https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-git-20160215-32bit-static.7z"
};
}
return new string[] { };
}
protected override void RestartInternal()
{
MainClass.Restart(StartupOptions);

View file

@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;
using System.Text;
using MediaBrowser.Model.IO;
@ -52,7 +53,7 @@ namespace MediaBrowser.ServerApplication.Native
/// <summary>
/// The STG m_ READ
/// </summary>
public const uint STGM_READ = 0;
public const int STGM_READ = 0;
}
/// <summary>
@ -319,72 +320,6 @@ namespace MediaBrowser.ServerApplication.Native
}
/// <summary>
/// Interface IPersist
/// </summary>
[ComImport, Guid("0000010c-0000-0000-c000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersist
{
/// <summary>
/// Gets the class ID.
/// </summary>
/// <param name="pClassID">The p class ID.</param>
[PreserveSig]
void GetClassID(out Guid pClassID);
}
/// <summary>
/// Interface IPersistFile
/// </summary>
[ComImport, Guid("0000010b-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersistFile : IPersist
{
/// <summary>
/// Gets the class ID.
/// </summary>
/// <param name="pClassID">The p class ID.</param>
new void GetClassID(out Guid pClassID);
/// <summary>
/// Determines whether this instance is dirty.
/// </summary>
[PreserveSig]
int IsDirty();
/// <summary>
/// Loads the specified PSZ file name.
/// </summary>
/// <param name="pszFileName">Name of the PSZ file.</param>
/// <param name="dwMode">The dw mode.</param>
[PreserveSig]
void Load([In, MarshalAs(UnmanagedType.LPWStr)]
string pszFileName, uint dwMode);
/// <summary>
/// Saves the specified PSZ file name.
/// </summary>
/// <param name="pszFileName">Name of the PSZ file.</param>
/// <param name="remember">if set to <c>true</c> [remember].</param>
[PreserveSig]
void Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName,
[In, MarshalAs(UnmanagedType.Bool)] bool remember);
/// <summary>
/// Saves the completed.
/// </summary>
/// <param name="pszFileName">Name of the PSZ file.</param>
[PreserveSig]
void SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName);
/// <summary>
/// Gets the cur file.
/// </summary>
/// <param name="ppszFileName">Name of the PPSZ file.</param>
[PreserveSig]
void GetCurFile([In, MarshalAs(UnmanagedType.LPWStr)] string ppszFileName);
}
// CLSID_ShellLink from ShlGuid.h
/// <summary>
/// Class ShellLink

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
using Emby.Server.Core;
using Emby.Server.Implementations;
using Emby.Server.Implementations.EntryPoints;
@ -93,21 +94,30 @@ namespace MediaBrowser.ServerApplication
protected override void ConfigureAutoRunInternal(bool autorun)
{
var shortcutPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.StartMenu), "Emby", "Emby Server.lnk");
var startupPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Startup);
if (autorun)
if (autorun && !MainStartup.IsRunningAsService)
{
//Copy our shortut into the startup folder for this user
var targetPath = Path.Combine(startupPath, Path.GetFileName(shortcutPath) ?? "Emby Server.lnk");
FileSystemManager.CreateDirectory(Path.GetDirectoryName(targetPath));
File.Copy(shortcutPath, targetPath, true);
var targetPath = Path.Combine(startupPath, "Emby Server.lnk");
IShellLinkW link = (IShellLinkW)new ShellLink();
var appPath = Process.GetCurrentProcess().MainModule.FileName;
// setup shortcut information
link.SetDescription(Name);
link.SetPath(appPath);
link.SetWorkingDirectory(Path.GetDirectoryName(appPath));
// save it
IPersistFile file = (IPersistFile)link;
file.Save(targetPath, false);
}
else
{
//Remove our shortcut from the startup folder for this user
FileSystemManager.DeleteFile(Path.Combine(startupPath, Path.GetFileName(shortcutPath) ?? "Emby Server.lnk"));
FileSystemManager.DeleteFile(Path.Combine(startupPath, "Emby Server.lnk"));
}
}

View file

@ -209,7 +209,7 @@ namespace SocketHttpListener.Net
// TODO: can we get this stream before reading the input?
if (o_stream == null)
{
context.Response.DetermineIfChunked();
//context.Response.DetermineIfChunked();
if (context.Response.SendChunked || isExpect100Continue || context.Request.IsWebSocketRequest || true)
{
@ -508,7 +508,7 @@ namespace SocketHttpListener.Net
{
force_close |= !context.Request.KeepAlive;
if (!force_close)
force_close = (context.Response.Headers["connection"] == "close");
force_close = (string.Equals(context.Response.Headers["connection"], "close", StringComparison.OrdinalIgnoreCase));
/*
if (!force_close) {
// bool conn_close = (status_code == 400 || status_code == 408 || status_code == 411 ||

View file

@ -386,7 +386,7 @@ namespace SocketHttpListener.Net
if (content_type != null)
{
if (content_encoding != null && content_type.IndexOf("charset=", StringComparison.Ordinal) == -1)
if (content_encoding != null && content_type.IndexOf("charset=", StringComparison.OrdinalIgnoreCase) == -1)
{
string enc_name = content_encoding.WebName;
headers.SetInternal("Content-Type", content_type + "; charset=" + enc_name);
@ -429,9 +429,10 @@ namespace SocketHttpListener.Net
* HttpStatusCode.InternalServerError 500
* HttpStatusCode.ServiceUnavailable 503
*/
bool conn_close = (status_code == 408 || status_code == 411 ||
bool conn_close = status_code == 400 || status_code == 408 || status_code == 411 ||
status_code == 413 || status_code == 414 ||
status_code == 503);
status_code == 500 ||
status_code == 503;
if (conn_close == false)
conn_close = !context.Request.KeepAlive;

View file

@ -136,6 +136,11 @@ namespace SocketHttpListener.Net
if (disposed)
throw new ObjectDisposedException(GetType().ToString());
if (count == 0)
{
//return;
}
byte[] bytes = null;
MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false);
bool chunked = response.SendChunked;
@ -176,6 +181,11 @@ namespace SocketHttpListener.Net
if (disposed)
throw new ObjectDisposedException(GetType().ToString());
if (count == 0)
{
//return;
}
byte[] bytes = null;
MemoryStream ms = GetHeaders(response, _memoryStreamFactory, false);
bool chunked = response.SendChunked;
@ -206,7 +216,7 @@ namespace SocketHttpListener.Net
await stream.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
}
if (response.SendChunked)
if (chunked)
stream.Write(crlf, 0, 2);
}